diff --git a/index.html b/index.html
index 08ac339..bcb20c8 100644
--- a/index.html
+++ b/index.html
@@ -243,6 +243,71 @@
.players-grid{grid-template-columns:repeat(auto-fill,minmax(110px,1fr));}
.avatar-grid{grid-template-columns:repeat(4,1fr);}
}
+
+ /* ── Nivell 7 · Milionari ── */
+ #screen-mill {
+ background: linear-gradient(180deg, #08082a 0%, #140a3e 100%);
+ min-height: 100vh;
+ padding-bottom: 40px;
+ }
+ /* Option buttons — show style */
+ .mill-opt {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 13px 14px;
+ border-radius: 12px;
+ font-family: inherit;
+ font-size: .92rem;
+ font-weight: 600;
+ border: 2px solid #3d7fd4;
+ background: linear-gradient(135deg, #0a2152, #153a7a);
+ color: #e8eeff;
+ cursor: pointer;
+ text-align: left;
+ transition: border-color .15s, background .15s;
+ min-height: 52px;
+ line-height: 1.3;
+ }
+ .mill-opt:hover:not(.disabled) {
+ border-color: #FFD700;
+ background: linear-gradient(135deg, #12295e, #1d4a9a);
+ }
+ .mill-opt.correct {
+ border-color: #2ecc71;
+ background: linear-gradient(135deg, #0a3d1f, #145e2d);
+ color: #b2ffce;
+ }
+ .mill-opt.wrong {
+ border-color: #e74c3c;
+ background: linear-gradient(135deg, #3d0a0a, #6e1212);
+ color: #ffb2b2;
+ }
+ .mill-opt.disabled { cursor: default; }
+ /* Letter badge (A/B/C/D) */
+ .opt-letter {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ border: 2px solid currentColor;
+ font-size: .82rem;
+ font-weight: 800;
+ flex-shrink: 0;
+ }
+ /* Progress dots */
+ .mill-dot {
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ border: 2px solid #555;
+ background: #222;
+ transition: background .3s, border-color .3s;
+ }
+ .mill-dot.done { background: #FFD700; border-color: #FFD700; }
+ .mill-dot.current { background: #fff; border-color: #fff; }
@@ -333,6 +398,11 @@
Nivell 6 · Mapa Cec
Sense noms al mapa. El repte màxim!
+
+
💰
+
Nivell 7 · Milionari
+
Qui vol ser milionari? 4 opcions, 10 preguntes!
+
+
+
+
+
+
+
+
+
+
0/0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1249,7 +1349,8 @@ function startLevel(n){
sessionStart=Date.now();
if(n===1)initL1();else if(n===2)initL2();else if(n===3)initL3();
else if(n===4)initL4();else if(n===5){mapBlind=false;initMap();}
- else{mapBlind=true;initMap();}
+ else if(n===6){mapBlind=true;initMap();}
+ else{initMill();}
}
function repeatLevel(){ startLevel(currentLevel); }
@@ -1459,6 +1560,216 @@ function handleMapClick(path){
setTimeout(()=>{path.classList.remove('wrong-shake');currentQ++;nextMapQ();},2400);
}
}
+
+/* ══════════════════════════════════════════════════════
+ NIVELL 7 · MILIONARI
+ "Qui vol ser milionari?" — 10 questions, 4 options A/B/C/D,
+ alternating between two question types:
+ type A: "Quina és la capital de ?" → options = 4 capitals
+ type B: "De quina comarca és capital ?" → options = 4 comarca names
+ A mini SVG map highlights the target comarca in gold.
+══════════════════════════════════════════════════════ */
+
+const MILL_TOTAL = 10; // questions per session
+let millQuestions = []; // selected slice from shuffled pool
+let millQ = 0; // current question index (0-based)
+let millScore = 0; // correct answers count
+
+/** Escape HTML special chars for safe insertion into data-attributes. */
+function escapeHtml(s) {
+ return String(s)
+ .replace(/&/g,'&')
+ .replace(//g,'>')
+ .replace(/"/g,'"')
+ .replace(/'/g,''');
+}
+
+/** Entry point called by startLevel(7). */
+function initMill() {
+ millQ = 0;
+ millScore = 0;
+ // millQuestions already assigned as shuffled mapComarques in startLevel()
+ millQuestions = questions.slice(0, MILL_TOTAL);
+ showScreen('screen-mill');
+ renderMill();
+}
+
+/** Render the current question. */
+function renderMill() {
+ const comarca = millQuestions[millQ];
+
+ // ── Progress dots ──────────────────────────────────────────
+ const dotsEl = document.getElementById('mill-dots');
+ dotsEl.innerHTML = '';
+ for (let i = 0; i < millQuestions.length; i++) {
+ const d = document.createElement('div');
+ d.className = 'mill-dot' + (i < millQ ? ' done' : i === millQ ? ' current' : '');
+ dotsEl.appendChild(d);
+ }
+
+ // ── Score header ──────────────────────────────────────────
+ document.getElementById('mill-score-hdr').textContent = `${millScore}/${millQ}`;
+
+ // ── Mini map ──────────────────────────────────────────────
+ buildMillSVG(comarca);
+
+ // ── Decide question type — alternate randomly ─────────────
+ // type 'capital': "Quina és la capital de ?" → options = capitals
+ // type 'comarca': "De quina comarca és capital ?" → options = comarca names
+ const qType = Math.random() < 0.5 ? 'capital' : 'comarca';
+
+ let questionText, correctAnswer, pool, optionFn;
+
+ if (qType === 'capital') {
+ questionText = `Quina és la capital de ${comarca.emoji} ${comarca.name}?`;
+ correctAnswer = comarca.capital;
+ // Distractors: other capitals from the same questions pool
+ pool = millQuestions.filter(c => c.name !== comarca.name);
+ optionFn = c => c.capital;
+ } else {
+ questionText = `De quina comarca és capital 📍 ${comarca.capital}?`;
+ correctAnswer = comarca.name;
+ pool = millQuestions.filter(c => c.name !== comarca.name);
+ optionFn = c => c.name;
+ }
+
+ document.getElementById('mill-qtext').textContent = questionText;
+
+ // Build 4 options: 1 correct + 3 random distractors
+ const distractors = shuffle(pool).slice(0, 3).map(optionFn);
+ const options = shuffle([correctAnswer, ...distractors]);
+ const letters = ['A', 'B', 'C', 'D'];
+
+ const optsEl = document.getElementById('mill-opts');
+ optsEl.innerHTML = options.map((opt, i) => `
+ `).join('');
+
+ // Hide the Next button until an answer is chosen
+ document.getElementById('mill-next').style.display = 'none';
+}
+
+/** Handle option click. Disables all options, colours correct/wrong, shows Next. */
+function millAnswer(btn) {
+ const chosen = btn.dataset.opt;
+ const correct = btn.dataset.correct;
+
+ // Disable all option buttons
+ document.querySelectorAll('.mill-opt').forEach(b => {
+ b.classList.add('disabled');
+ b.onclick = null;
+ });
+
+ if (chosen === correct) {
+ btn.classList.add('correct');
+ millScore++;
+ score++; // global score used by showResult()
+ showFeedback(true);
+ } else {
+ btn.classList.add('wrong');
+ // Highlight the correct answer in green
+ document.querySelectorAll('.mill-opt').forEach(b => {
+ if (b.dataset.opt === correct) b.classList.add('correct');
+ });
+ showFeedback(false);
+ }
+
+ millQ++; // advance AFTER recording the answer
+
+ // Update score header immediately
+ document.getElementById('mill-score-hdr').textContent = `${millScore}/${millQ}`;
+
+ // Show Next / Result button
+ const nextBtn = document.getElementById('mill-next');
+ nextBtn.style.display = 'block';
+ nextBtn.textContent = millQ >= millQuestions.length ? '🏆 Veure resultat' : '➡ Següent';
+}
+
+/** Advance to next question or show final result. */
+function millNext() {
+ if (millQ >= millQuestions.length) {
+ // questions.length must match millQuestions.length for showResult() pct calc
+ questions = millQuestions;
+ showResult(7);
+ } else {
+ renderMill();
+ }
+}
+
+/**
+ * Build the mini SVG preview map for the Milionari screen.
+ * Target comarca: gold (#FFD700), others: dark blue (#1c3a5e).
+ * Red double-circle marks the capital centroid.
+ * ViewBox zoomed to comarca centroid ±110×82.5 units (220×165 window), clamped.
+ */
+function buildMillSVG(comarca) {
+ const svg = document.getElementById('mill-map-svg');
+ svg.innerHTML = '';
+
+ const info = COMARCA_PATHS[comarca.name];
+
+ // ── Background sea ──────────────────────────────────────────
+ const sea = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
+ sea.setAttribute('width', '820');
+ sea.setAttribute('height', '600');
+ sea.setAttribute('fill', '#08082a');
+ svg.appendChild(sea);
+
+ // ── All comarca paths ────────────────────────────────────────
+ for (const [name, pInfo] of Object.entries(COMARCA_PATHS)) {
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+ path.setAttribute('d', pInfo.d);
+ if (name === comarca.name) {
+ path.setAttribute('fill', '#FFD700');
+ path.setAttribute('stroke', '#fff');
+ path.setAttribute('stroke-width', '1.5');
+ } else {
+ path.setAttribute('fill', '#1c3a5e');
+ path.setAttribute('stroke', '#0a1e38');
+ path.setAttribute('stroke-width', '0.6');
+ }
+ svg.appendChild(path);
+ }
+
+ // ── Capital marker: outer ring + inner dot (no CSS animation needed) ─
+ if (info) {
+ const cx = info.cx;
+ const cy = info.cy;
+
+ // Outer ring (semi-transparent red)
+ const outer = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
+ outer.setAttribute('cx', cx);
+ outer.setAttribute('cy', cy);
+ outer.setAttribute('r', '9');
+ outer.setAttribute('fill', 'rgba(220,50,50,0.35)');
+ outer.setAttribute('stroke', '#e03030');
+ outer.setAttribute('stroke-width', '1.5');
+ svg.appendChild(outer);
+
+ // Inner dot (solid red)
+ const inner = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
+ inner.setAttribute('cx', cx);
+ inner.setAttribute('cy', cy);
+ inner.setAttribute('r', '4');
+ inner.setAttribute('fill', '#e03030');
+ svg.appendChild(inner);
+
+ // ── Zoom viewBox centred on target comarca ────────────────
+ // Window: 220 × 165 units; clamp to [0,820] × [0,600]
+ const W = 220, H = 165;
+ const x0 = Math.max(0, Math.min(820 - W, cx - W / 2));
+ const y0 = Math.max(0, Math.min(600 - H, cy - H / 2));
+ svg.setAttribute('viewBox', `${x0} ${y0} ${W} ${H}`);
+ } else {
+ // Fallback: full map view if no centroid data
+ svg.setAttribute('viewBox', '0 0 820 600');
+ }
+}