// // quiz.js
// /**
//  * mkdocs-superquiz - Logique principale JavaScript
//  */

// window.QUIZ_CONFIG = window.QUIZ_CONFIG || {};

// function t(key, fallback = "") {
//     const keys = key.split('.');
//     let value = window.QUIZ_CONFIG?.i18n;

//     for (const k of keys) {
//         if (value && typeof value === 'object') {
//             value = value[k];
//         } else {
//             return fallback || key;
//         }
//     }
//     return value || fallback || key;
// }

// let currentUnlockContext = null;

// function createUnlockModal() {
//     const modal = document.createElement('div');
//     modal.id = 'mkq-unlock-modal';
//     modal.className = 'mkq-modal';
//     modal.innerHTML = `
//         <div class="mkq-modal-content">
//             <button class="mkq-modal-close" onclick="closeUnlockModal()">×</button>
//             <h3 id="mkq-unlock-title">${t("ui.unlock_title", "Unlock Correction")}</h3>
//             <div class="qr-code-section">
//                 <p>${t("ui.unlock_qr_instruction", "Ask your teacher to scan this QR code:")}</p>
//                 <div id="qr-code-container"></div>
//             </div>
//             <div class="unlock-input-section">
//                 <label for="mkq-unlock-code-input">${t("ui.unlock_code_label", "Unlock code (provided by teacher):")}</label>
//                 <input type="text" id="mkq-unlock-code-input" placeholder="${t("ui.unlock_code_placeholder", "e.g., A7F3E9C2")}">
//                 <button onclick="validateUnlockCode()">${t("ui.unlock_validate", "Validate")}</button>
//             </div>
//         </div>
//     `;
//     document.body.appendChild(modal);
// }

// function getSiteUrl() {
//     const currentOrigin = window.location.origin;
//     const currentPath = window.location.pathname;

//     const baseElement = document.querySelector('base');
//     if (baseElement && baseElement.href) {
//         const baseUrl = new URL(baseElement.href);
//         return baseUrl.origin + baseUrl.pathname.replace(/\/$/, '');
//     }

//     const pathParts = currentPath.split('/').filter(p => p);

//     if (pathParts.length > 0) {
//         const firstPart = pathParts[0];

//         const isProjectName = !firstPart.includes('.html') &&
//             !firstPart.includes('.') &&
//             firstPart !== 'search' &&
//             firstPart !== 'assets';

//         if (currentPath.includes('/mkdocs-superquiz/')) {
//             return currentOrigin + '/mkdocs-superquiz';
//         }

//         const knownPages = ['index', 'sample_quiz', 'search', 'sitemap'];
//         if (isProjectName && !knownPages.includes(firstPart)) {
//             return currentOrigin + '/' + firstPart;
//         }
//     }
//     return currentOrigin;
// }

// function showUnlockModal(type, exerciseId = null, questionId = null) {
//     const modal = document.getElementById('mkq-unlock-modal');
//     if (!modal) return;

//     const pageUuid = document.querySelector('.mkdocs-superquiz')?.dataset.pageUuid;
//     if (!pageUuid) return;

//     const siteUrl = getSiteUrl();

//     const data = {
//         type: type,
//         page_id: pageUuid,
//         page_title: document.title,
//         site_url: siteUrl
//     };

//     if (type === 'exercise' || type === 'question') {
//         data.exercise_id = exerciseId;

//         const exerciseElement = document.querySelector(`[data-quiz-id="${exerciseId}"]`);
//         if (exerciseElement) {
//             const titleElement = exerciseElement.querySelector('.admonition-title');
//             let title = titleElement ? titleElement.textContent.trim() : '';
//             title = title
//                 .replace(/🔒/g, '').replace(/🔓/g, '').replace(/❌/g, '').replace(/🔐/g, '').replace(/✅/g, '')
//                 .replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
//             data.exercise_title = title;
//         }
//     }

//     if (type === 'question') {
//         data.question_id = questionId;
//         const questionElement = document.querySelector(`[data-quiz-id="${exerciseId}"] [data-question-id="${questionId}"]`);
//         if (questionElement) {
//             const textElement = questionElement.querySelector('.mkq-question-text');
//             let questionText = textElement ? textElement.textContent.trim() : '';
//             questionText = questionText
//                 .replace(/🔒/g, '').replace(/🔓/g, '').replace(/❌/g, '').replace(/🔐/g, '').replace(/✅/g, '')
//                 .replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
//             data.question_text = questionText;
//         }
//     }

//     currentUnlockContext = data;

//     const titleElement = document.getElementById('mkq-unlock-title');
//     if (titleElement) {
//         if (type === 'page') {
//             titleElement.textContent = t("ui.unlock_page_title", "Unlock All Page Quizzes");
//         } else if (type === 'exercise') {
//             titleElement.textContent = `${t("ui.unlock_quiz", "Unlock Quiz")} ${exerciseId}`;
//         } else {
//             titleElement.textContent = `${t("ui.unlock_quiz_question", "Unlock this quiz question")} ${questionId}`;
//         }
//     }

//     generateQRCode(data);
//     modal.classList.add('active');
// }

// function generateQRCode(data) {
//     const container = document.getElementById('qr-code-container');
//     if (!container) return;

//     const jsonString = JSON.stringify(data);
//     const utf8Bytes = new TextEncoder().encode(jsonString);
//     let binaryString = '';
//     for (let i = 0; i < utf8Bytes.length; i++) {
//         binaryString += String.fromCharCode(utf8Bytes[i]);
//     }
//     const encodedData = btoa(binaryString);

//     const unlockUrl = `${data.site_url}/quiz-unlock.html?data=${encodedData}`;

//     if (typeof qrcode === 'undefined') {
//         container.innerHTML = `<p style="color:red;">${t("ui.error_no_library", "Error: No QR Code library has been downloaded")}</p>`;
//         return;
//     }

//     try {
//         const qr = qrcode(0, 'H');
//         qr.addData(unlockUrl);
//         qr.make();

//         const cellSize = 4;
//         const margin = 4;
//         const svgTag = qr.createSvgTag(cellSize, margin);

//         container.innerHTML = svgTag;

//         const svg = container.querySelector('svg');
//         if (svg) {
//             svg.style.display = 'block';
//             svg.style.maxWidth = '256px';
//             svg.style.height = 'auto';
//             svg.style.margin = '0 auto';
//             svg.style.padding = '10px';
//             svg.style.background = 'white';
//             svg.style.borderRadius = '8px';
//             svg.style.boxShadow = '0 2px 8px rgba(0,0,0,0.1)';
//         }
//     } catch (error) {
//         container.innerHTML = `<p style="color:red;">${t("ui.error_generating_qrcode", "Error generating QR Code")}</p>`;
//     }
// }

// function closeUnlockModal() {
//     const modal = document.getElementById('mkq-unlock-modal');
//     if (modal) modal.classList.remove('active');
//     const input = document.getElementById('mkq-unlock-code-input');
//     if (input) input.value = '';
// }

// async function validateUnlockCode() {
//     const input = document.getElementById('mkq-unlock-code-input');
//     if (!input) return;

//     const code = input.value.trim().toUpperCase();
//     if (!code) {
//         alert(t("ui.please_enter_code", "Please enter a code"));
//         return;
//     }
//     if (!currentUnlockContext) {
//         alert(t("ui.error_no_unlocking_context", "Error: Unlocking context not found"));
//         return;
//     }

//     const expectedCode = await calculateUnlockCode(currentUnlockContext);

//     if (code === expectedCode) {
//         unlockCorrections(currentUnlockContext);
//         saveUnlockState(currentUnlockContext);
//         closeUnlockModal();
//     } else {
//         alert(t("ui.error_incorrect_code", "Incorrect code. Check with your teacher."));
//     }
// }

// async function calculateUnlockCode(context) {
//     const teacherCodeHash = window.QUIZ_CONFIG.teacher_code_hash || '';
//     let payload = teacherCodeHash + context.page_id + context.type;

//     if (context.type === 'exercise' || context.type === 'question') {
//         payload += (context.exercise_id || '');
//     }
//     if (context.type === 'question') {
//         payload += (context.question_id || '');
//     }

//     const hash = await sha256(payload);
//     return hash.substring(0, 8).toUpperCase();
// }

// async function sha256(str) {
//     const buffer = new TextEncoder().encode(str);
//     const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
//     const hashArray = Array.from(new Uint8Array(hashBuffer));
//     return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
// }

// function updateLockIcon(element, unlocked) {
//     if (!element) return;

//     if (unlocked) {
//         element.textContent = '🔓';
//         element.classList.remove('locked');
//         element.classList.add('unlocked');
//         element.setAttribute('data-lock-state', 'unlocked');
//         element.setAttribute('title', t("ui.unlocked_corrections", "Unlocked corrections"));
//         element.onclick = null;
//         element.style.cursor = 'default';
//     } else {
//         element.textContent = '🔒';
//         element.classList.remove('unlocked');
//         element.classList.add('locked');
//         element.setAttribute('data-lock-state', 'locked');
//         element.setAttribute('title', t("ui.lock_tooltip_locked", "Click to unlock corrections"));
//     }
// }

// function shouldShowCorrections(quiz) {
//     const lockIndicator = quiz.querySelector('.mkq-lock-indicator, .mkq-unlock-btn');

//     if (!lockIndicator) return true;

//     const lockState = lockIndicator.getAttribute('data-lock-state');

//     if (lockState === 'locked-permanent') return false;
//     if (lockState === 'unlocked') return true;

//     if (lockState === 'locked') {
//         const pageUuid = quiz.dataset.pageUuid;
//         const quizId = quiz.dataset.quizId;
//         const unlocks = JSON.parse(localStorage.getItem('mkq_unlocks') || '[]');
//         const isUnlocked = unlocks.some(unlock =>
//             unlock.page_id === pageUuid &&
//             (unlock.type === 'page' || unlock.exercise_id === quizId)
//         );
//         return isUnlocked;
//     }

//     return true;
// }

// function unlockCorrections(context) {
//     if (context.type === 'page') {
//         document.querySelectorAll('.mkq-unlock-btn').forEach(btn => updateLockIcon(btn, true));
//         document.querySelectorAll('.mkdocs-superquiz').forEach(quiz => {
//             const quizId = quiz.dataset.quizId;
//             if (quizId) validateQuiz(quizId);
//         });
//     } else if (context.type === 'exercise') {
//         const exercise = document.querySelector(`[data-quiz-id="${context.exercise_id}"]`);
//         if (exercise) {
//             const lockBtn = exercise.querySelector('.mkq-unlock-btn');
//             updateLockIcon(lockBtn, true);
//             validateQuiz(context.exercise_id);
//         }
//     } else if (context.type === 'question') {
//         const exercise = document.querySelector(`[data-quiz-id="${context.exercise_id}"]`);
//         if (exercise) {
//             const question = exercise.querySelector(`[data-question-id="${context.question_id}"]`);
//             if (question) {
//                 const lockBtn = question.querySelector('.mkq-unlock-btn');
//                 updateLockIcon(lockBtn, true);
//             }
//             validateQuiz(context.exercise_id);
//         }
//     }
// }

// function saveUnlockState(context) {
//     const unlocks = JSON.parse(localStorage.getItem('mkq_unlocks') || '[]');
//     unlocks.push({
//         page_id: context.page_id,
//         type: context.type,
//         exercise_id: context.exercise_id,
//         question_id: context.question_id,
//         timestamp: new Date().toISOString()
//     });
//     localStorage.setItem('mkq_unlocks', JSON.stringify(unlocks));
// }

// function restoreUnlockedCorrections() {
//     const unlocks = JSON.parse(localStorage.getItem('mkq_unlocks') || '[]');
//     const currentPageUuid = document.querySelector('.mkdocs-superquiz')?.dataset.pageUuid;
//     if (!currentPageUuid) return;

//     unlocks.forEach(unlock => {
//         if (unlock.page_id === currentPageUuid) unlockCorrections(unlock);
//     });
// }

// // ─────────────────────────────────────────────────────────────────────────────
// // Scoring helpers
// // ─────────────────────────────────────────────────────────────────────────────

// /**
//  * Clamp score with correct semantics:
//  *
//  * min_score rules (from QUIZ_CONFIG or question data):
//  *   - null  → no minimum (negative scores allowed, e.g. with proportional mode)
//  *   - 0     → default: no negative scores
//  *   - N     → minimum N, BUT only applied if N < pointsMax
//  *             (aberrant case: min_score >= pointsMax is silently ignored)
//  *
//  * Clamp order: max ALWAYS first, then min (so max always wins on aberrant cases)
//  */
// function clampScore(score, pointsMax, minScore, clampMax) {
//     let s = score;

//     // 1. Clamp max (always first)
//     if (clampMax) {
//         s = Math.min(s, pointsMax);
//     }

//     // 2. Clamp min (only if defined AND strictly less than pointsMax)
//     if (minScore !== null && minScore !== undefined) {
//         const min = Number(minScore);
//         if (min < pointsMax) {
//             s = Math.max(s, min);
//         }
//         // if min >= pointsMax: aberrant value, silently ignored
//     }

//     return s;
// }

// function arraysEqual(a, b) {
//     if (a.length !== b.length) return false;
//     for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
//     return true;
// }

// function normalizeUnicodeAccents(str) {
//     try {
//         return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
//     } catch {
//         return str;
//     }
// }

// function normalizeLatexLoose(str) {
//     return str
//         .replace(/\s+/g, '')
//         .replace(/\*/g, '')
//         .replace(/²/g, '^2')
//         .replace(/³/g, '^3');
// }

// // compareAnswers now uses compare_answers config (per quiz payload preferred)
// function compareAnswers(userAnswer, correctAnswer, compareConfig) {
//     const cfg = compareConfig || window.QUIZ_CONFIG.gapfill || {};

//     // Back-compat if old flags exist but compare_answers missing
//     const ca = cfg.compare_answers && typeof cfg.compare_answers === 'object' ? cfg.compare_answers : cfg;

//     let user = String(userAnswer ?? '');
//     let correct = String(correctAnswer ?? '');

//     const stripSpaces = (ca.strip_spaces !== false);
//     if (stripSpaces) {
//         user = user.trim();
//         correct = correct.trim();
//     }

//     if (ca.ignore_spaces) {
//         user = user.replace(/\s+/g, '');
//         correct = correct.replace(/\s+/g, '');
//     }

//     // case mode
//     const caseSensitive = (ca.case_sensitive === true && ca.ignore_case !== true);
//     if (!caseSensitive) {
//         user = user.toLowerCase();
//         correct = correct.toLowerCase();
//     }

//     if (ca.ignore_accents) {
//         user = normalizeUnicodeAccents(user);
//         correct = normalizeUnicodeAccents(correct);
//     }

//     // latex
//     const latex = ca.latex && typeof ca.latex === 'object' ? ca.latex : { mode: ca.strict_latex ? 'strict' : 'loose' };
//     const latexMode = latex.mode || 'loose';
//     if (latexMode !== 'strict') {
//         user = normalizeLatexLoose(user);
//         correct = normalizeLatexLoose(correct);
//     } else {
//         // strict: do nothing
//     }

//     return user === correct;
// }

// // Parse losing_mode keys for mcquiz: key like "[Paris, Londres]" -> list of strings
// function parseBracketKey(key) {
//     const s = String(key).trim();
//     if (!s.startsWith('[') || !s.endsWith(']')) return null;
//     const inner = s.slice(1, -1).trim();
//     if (!inner) return [];
//     return inner.split(',').map(x => x.trim()).filter(Boolean);
// }

// function scoreChoiceQuestion(questionData, selectedIndices) {
//     const points = Number(questionData.points || 1);
//     const scoringMode = questionData.scoring_mode || 'all_or_nothing';
//     const defaultFalse = Number(questionData.default_false ?? 0);

//     const correct = Array.isArray(questionData.correct_answers) ? questionData.correct_answers : [];
//     const correctSet = new Set(correct);

//     let nbGood = 0;
//     let nbFalse = 0;
//     selectedIndices.forEach(i => {
//         if (correctSet.has(i)) nbGood++;
//         else nbFalse++;
//     });

//     const nbGoodTotal = correct.length || 1;

//     // base score
//     let base = 0;
//     const selSorted = [...selectedIndices].sort((a,b)=>a-b);
//     const corSorted = [...correct].sort((a,b)=>a-b);
//     const exact = arraysEqual(selSorted, corSorted);

//     if (scoringMode === 'all_or_nothing') {
//         base = exact ? points : 0;
//     } else if (scoringMode === 'some_or_nothing') {
//         if (nbFalse > 0) base = 0;
//         else base = points * (nbGood / nbGoodTotal);
//     } else { // proportional
//         base = points * ((nbGood / nbGoodTotal) - (nbFalse / nbGoodTotal));
//     }

//     // ✅ default_false s'applique si réponse incorrecte ET pas de losing_mode
//     const lm = questionData.losing_mode || null;
//     const hasLosingMode = lm && Array.isArray(lm.rules) && lm.rules.length > 0;

//     if (!exact && !hasLosingMode && defaultFalse !== 0) {
//         base = defaultFalse;
//     }

//     // losing_mode override — uniquement si la réponse n'est PAS exacte
//     if (!exact && hasLosingMode) {
//         const answersText = Array.isArray(questionData.answers_text) ? questionData.answers_text : [];
//         const selectedTexts = selectedIndices.map(i => answersText[i] ?? '').filter(Boolean);

//         let matchedRule = null;
//         for (const r of lm.rules) {
//             const key = r.key;
//             const list = parseBracketKey(key);
//             if (!list) continue;
//             const a = [...selectedTexts].map(x => x.trim()).sort();
//             const b = [...list].map(x => x.trim()).sort();
//             if (arraysEqual(a, b)) {
//                 matchedRule = r;
//                 break;
//             }
//         }

//         if (matchedRule) {
//             base = Number(matchedRule.score);
//         } else {
//             if (lm.default_false !== null && lm.default_false !== undefined) {
//                 base = Number(lm.default_false);
//             } else if (defaultFalse !== 0) {
//                 // ✅ fallback sur default_false du quiz si losing_mode n'en définit pas
//                 base = defaultFalse;
//             }
//         }
//     }

//     const minScore = questionData.min_score !== undefined
//         ? questionData.min_score
//         : window.QUIZ_CONFIG.min_score !== undefined
//             ? window.QUIZ_CONFIG.min_score
//             : 0;
//     const clampMax = (questionData.clamp_max_score ?? window.QUIZ_CONFIG.clamp_max_score ?? true);
//     return clampScore(base, points, minScore, clampMax);
// }

// function scoreScQuizQuestion(questionData, selectedIndex) {
//     const points = Number(questionData.points || 1);
//     const correct = Array.isArray(questionData.correct_answers) ? questionData.correct_answers : [];
//     const correctIndex = correct.length ? correct[0] : 0;
//     const defaultFalse = Number(questionData.default_false ?? 0);

//     const exact = (selectedIndex === correctIndex);
//     let base = exact ? points : 0;

//     const lm = questionData.losing_mode || null;
//     const hasLosingMode = lm && Array.isArray(lm.rules) && lm.rules.length > 0;

//     // ✅ default_false s'applique si réponse incorrecte ET pas de losing_mode
//     if (!exact && !hasLosingMode && defaultFalse !== 0) {
//         base = defaultFalse;
//     }

//     // losing_mode override — uniquement si la réponse n'est PAS exacte
//     if (!exact && hasLosingMode) {
//         const answersText = Array.isArray(questionData.answers_text) ? questionData.answers_text : [];
//         const selectedText = (selectedIndex >= 0 && selectedIndex < answersText.length) ? answersText[selectedIndex] : '';

//         let matched = null;
//         for (const r of lm.rules) {
//             if (String(r.key).trim() === String(selectedText).trim()) {
//                 matched = r;
//                 break;
//             }
//         }

//         if (matched) {
//             base = Number(matched.score);
//         } else {
//             if (lm.default_false !== null && lm.default_false !== undefined) {
//                 base = Number(lm.default_false);
//             } else if (defaultFalse !== 0) {
//                 base = defaultFalse;
//             }
//         }
//     }

//     const minScore = questionData.min_score !== undefined
//         ? questionData.min_score
//         : window.QUIZ_CONFIG.min_score !== undefined
//             ? window.QUIZ_CONFIG.min_score
//             : 0;
//     const clampMax = (questionData.clamp_max_score ?? window.QUIZ_CONFIG.clamp_max_score ?? true);
//     return clampScore(base, points, minScore, clampMax);
// }



// function scoreGapfillQuestion(questionData, userAnswers) {
//     const points = Number(questionData.points || 1);
//     const gaps = Array.isArray(questionData.gaps) ? questionData.gaps : [];
//     const n = gaps.length || 1;

//     const scoringMode = questionData.scoring_mode || 'proportional';
//     const perGap = points / n;

//     const lm = questionData.losing_mode || { gaps: [] };
//     const compareCfg =
//         questionData.compare_answers ||
//         window.QUIZ_CONFIG.gapfill?.compare_answers ||
//         window.QUIZ_CONFIG.gapfill ||
//         {};

//     let correctCount = 0;
//     let anyWrongNonEmpty = false;
//     const gapStates = [];

//     for (let i = 0; i < gaps.length; i++) {
//         const gap = gaps[i];
//         const ua = String(userAnswers[i] ?? '').trim();
//         const accepted = Array.isArray(gap.answers) ? gap.answers : [];

//         const isEmpty = (ua === '');
//         const isCorrect = !isEmpty && accepted.some(ans => compareAnswers(ua, ans, compareCfg));

//         if (isCorrect) correctCount++;
//         if (!isCorrect && !isEmpty) anyWrongNonEmpty = true;

//         gapStates.push({ isCorrect, isEmpty, ua });
//     }

//     let total = 0;

//     if (scoringMode === 'all_or_nothing') {
//         total = (correctCount === gaps.length) ? points : 0;
//     } else if (scoringMode === 'some_or_nothing') {
//         total = anyWrongNonEmpty ? 0 : (perGap * correctCount);
//     } else {
//         // proportional
//         total = perGap * correctCount;
//     }

//     for (let i = 0; i < gaps.length; i++) {
//         const st = gapStates[i];
//         if (st.isCorrect) continue;

//         const gLm = (lm.gaps && lm.gaps[i]) ? lm.gaps[i] : null;
//         if (!gLm) continue;

//         const rules = Array.isArray(gLm.rules) ? gLm.rules : [];
//         const defFalse =
//             (gLm.default_false !== null && gLm.default_false !== undefined) ? Number(gLm.default_false)
//             : ((gLm.default !== null && gLm.default !== undefined) ? Number(gLm.default) : null);

//         let matched = null;
//         for (const r of rules) {
//             if (compareAnswers(st.ua, r.answer, compareCfg)) {
//                 matched = r;
//                 break;
//             }
//         }

//         if (matched) {
//             total += Number(matched.score);
//         } else if (defFalse !== null) {
//             total += defFalse;
//         }
//     }

//     const minScore = questionData.min_score ?? window.QUIZ_CONFIG.min_score ?? 0;
//     const clampMax = (questionData.clamp_max_score ?? window.QUIZ_CONFIG.clamp_max_score ?? true);
//     return clampScore(total, points, minScore, clampMax);
// }

// function scoreDropdownQuestion(questionData, selectedIndices) {
//     const actual = Array.isArray(questionData.dropdowns) ? questionData.dropdowns : (questionData.dropdowns || questionData.dropdown ? [questionData.dropdown] : []);
//     const n = actual.length || 1;
//     const per = actual.length > 0 ? Number(questionData.points || 1) / actual.length : Number(questionData.points || 1);
//     const points = Number(questionData.points || 1);

//     const scoringMode = questionData.scoring_mode || 'all_or_nothing';
//     let total = 0;
//     let anyWrong = false;

//     const lm = questionData.losing_mode || { dropdowns: [] };

//     for (let i = 0; i < actual.length; i++) {
//         const dd = actual[i] || {};
//         const correctIndex = Number(dd.correct_index ?? 0);
//         const sel = (selectedIndices[i] ?? -1);

//         const isCorrect = (sel >= 0 && sel === correctIndex);
//         if (isCorrect) {
//             total += per;
//         } else {
//             anyWrong = true;

//             const ddLm = (lm.dropdowns && lm.dropdowns[i]) ? lm.dropdowns[i] : null;
//             const opts = Array.isArray(dd.options) ? dd.options : [];
//             const chosenText = (sel >= 0 && sel < opts.length) ? String(opts[sel]) : '';

//             if (ddLm && Array.isArray(ddLm.rules) && chosenText) {
//                 let matched = null;
//                 for (const r of ddLm.rules) {
//                     if (String(r.option).trim() === chosenText.trim()) {
//                         matched = r;
//                         break;
//                     }
//                 }
//                 if (matched) {
//                     total += Number(matched.score);
//                 } else {
//                     if (ddLm.default_false !== null && ddLm.default_false !== undefined) {
//                         total += Number(ddLm.default_false);
//                     }
//                 }
//             }
//         }
//     }

//     if (scoringMode === 'all_or_nothing') {
//         total = (total >= points - 1e-9) ? points : 0;
//     } else if (scoringMode === 'some_or_nothing') {
//         if (anyWrong) total = 0;
//     }
//     // proportional: total already computed per-dropdown

//     const minScore = questionData.min_score ?? window.QUIZ_CONFIG.min_score ?? 0;
//     const clampMax = (questionData.clamp_max_score ?? window.QUIZ_CONFIG.clamp_max_score ?? true);
//     return clampScore(total, points, minScore, clampMax);
// }

// // ─────────────────────────────────────────────────────────────────────────────
// // Validation
// // ─────────────────────────────────────────────────────────────────────────────

// function validateQuiz(quizId) {
//     const quiz = document.querySelector(`[data-quiz-id="${quizId}"]`);
//     if (!quiz) return;

//     const quizType = quiz.dataset.quizType;

//     if (quizType === 'gapfill') {
//         validateGapfillQuiz(quiz, quizId);
//     } else if (quizType === 'dropdown') {
//         validateDropdownQuiz(quiz, quizId);
//     } else {
//         validateChoiceQuiz(quiz, quizId);
//     }

//     saveAnswers(quizId);
// }

// function validateChoiceQuiz(quiz, quizId) {
//     const questions = quiz.querySelectorAll('.mkq-question[data-question-id]');
//     let totalPoints = 0;
//     let earnedPoints = 0;

//     const encryptedData = quiz.dataset.encrypted;
//     const correctionData = decryptAnswers(encryptedData);

//     if (!correctionData) {
//         alert(t("ui.error_downloading_corrections", "Error downloading corrections"));
//         return;
//     }

//     const showCorrection = shouldShowCorrections(quiz);

//     questions.forEach((questionEl) => {
//         const questionId = parseInt(questionEl.dataset.questionId, 10);
//         const qData = correctionData.questions.find(q => q.number === questionId);
//         if (!qData) return;

//         totalPoints += Number(qData.points || 1);

//         const inputs = questionEl.querySelectorAll('input[type="checkbox"], input[type="radio"]');
//         const selected = [];
//         inputs.forEach((input, idx) => {
//             if (input.checked) selected.push(idx);
//         });

//         let score = 0;
//         if (correctionData.quiz_type === 'scquiz') {
//             const selectedIndex = selected.length ? selected[0] : -1;
//             score = scoreScQuizQuestion(qData, selectedIndex);
//         } else {
//             score = scoreChoiceQuestion(qData, selected);
//         }

//         earnedPoints += score;

//         if (showCorrection) {
//             const correctIndices = qData.correct_answers || [];
//             inputs.forEach((input, idx) => {
//                 const label = input.closest('.mkq-answer');
//                 const feedback = label.querySelector('.mkq-answer-feedback');

//                 label.classList.remove('correct', 'incorrect');
//                 if (feedback) {
//                     feedback.style.display = 'none';
//                     feedback.textContent = '';
//                     feedback.classList.remove('correct', 'incorrect');
//                 }

//                 if (correctIndices.includes(idx)) {
//                     label.classList.add('correct');
//                     if (feedback) {
//                         feedback.textContent = t("feedback.correct", "Correct");
//                         feedback.classList.add('correct');
//                         feedback.style.display = 'inline';
//                     }
//                 } else if (selected.includes(idx)) {
//                     label.classList.add('incorrect');
//                     if (feedback) {
//                         feedback.textContent = t("feedback.incorrect", "Incorrect");
//                         feedback.classList.add('incorrect');
//                         feedback.style.display = 'inline';
//                     }
//                 }
//             });
//         }
//     });

//     displayScorePoints(quizId, earnedPoints, totalPoints);
// }

// function validateGapfillQuiz(quiz, quizId) {
//     const questions = quiz.querySelectorAll('.mkq-question[data-question-id]');
//     let totalPoints = 0;
//     let earnedPoints = 0;

//     const encryptedData = quiz.dataset.encrypted;
//     const correctionData = decryptAnswers(encryptedData);
//     if (!correctionData) {
//         alert(t("ui.error_downloading_corrections", "Error downloading corrections"));
//         return;
//     }

//     const showCorrection = shouldShowCorrections(quiz);
//     const droppedElements = [];

//     questions.forEach((questionEl) => {
//         const questionId = parseInt(questionEl.dataset.questionId, 10);
//         const qData = correctionData.questions.find(q => q.number === questionId);
//         if (!qData) return;

//         totalPoints += Number(qData.points || 1);

//         const gapInputs = questionEl.querySelectorAll('.mkq-gap-input');
//         const userAnswers = [];
//         gapInputs.forEach((input) => userAnswers.push(input.value));

//         const score = scoreGapfillQuestion(qData, userAnswers);
//         earnedPoints += score;

//         if (!showCorrection) return;

//         gapInputs.forEach((input, gapIndex) => {
//             const userAnswer = input.value.trim();
//             const gap = qData.gaps[gapIndex];
//             if (!gap) return;

//             const compareCfg = qData.compare_answers || correctionData.compare_answers || window.QUIZ_CONFIG.gapfill?.compare_answers || window.QUIZ_CONFIG.gapfill;
//             const isCorrect = gap.answers.some(answer => compareAnswers(userAnswer, answer, compareCfg));

//             const nextSibling = input.nextSibling;
//             if (nextSibling && nextSibling.classList?.contains('mkq-gap-correction-wrapper')) {
//                 nextSibling.remove();
//             }

//             if (isCorrect) {
//                 input.style.display = '';
//                 input.classList.add('correct');
//                 input.classList.remove('incorrect');
//             } else {
//                 input.style.display = 'none';
//                 input.classList.remove('correct');
//                 input.classList.add('incorrect');

//                 const wrapper = document.createElement('span');
//                 wrapper.className = 'mkq-gap-correction-wrapper';

//                 const label = document.createElement('span');
//                 label.className = 'mkq-gap-wrong-label';
//                 label.innerHTML = `<s>${userAnswer || t("ui.empty_answer", "(empty)")}</s>`;
//                 wrapper.appendChild(label);

//                 const dropdownId = `mkq-dropdown-${quizId}-q${questionId}-gap${gapIndex}`;
//                 const dropdown = createGapfillMathJaxDropdown(dropdownId, gap.answers);
//                 wrapper.appendChild(dropdown);

//                 input.after(wrapper);
//                 droppedElements.push(wrapper);
//             }
//         });
//     });

//     displayScorePoints(quizId, earnedPoints, totalPoints);

//     if (droppedElements.length > 0) {
//         setTimeout(() => {
//             if (window.MathJax?.typesetPromise) {
//                 MathJax.typesetPromise(droppedElements).catch(() => {});
//             }
//         }, 150);
//     }
// }

// function validateDropdownQuiz(quiz, quizId) {
//     const questions = quiz.querySelectorAll('.mkq-question[data-question-id]');
//     let totalPoints = 0;
//     let earnedPoints = 0;

//     const encryptedData = quiz.dataset.encrypted;
//     const correctionData = decryptAnswers(encryptedData);
//     if (!correctionData) {
//         alert(t("ui.error_downloading_corrections", "Error downloading corrections"));
//         return;
//     }

//     const showCorrection = shouldShowCorrections(quiz);

//     questions.forEach((questionEl) => {
//         const questionId = parseInt(questionEl.dataset.questionId, 10);
//         const qData = correctionData.questions.find(q => q.number === questionId);
//         if (!qData) return;

//         totalPoints += Number(qData.points || 1);

//         const dropdownEls = Array.from(questionEl.querySelectorAll('.mkq-custom-dropdown'));
//         const ddDataList = Array.isArray(qData.dropdowns) ? qData.dropdowns : (qData.dropdown ? [qData.dropdown] : []);

//         const count = Math.min(dropdownEls.length, ddDataList.length);
//         const selected = [];

//         for (let i = 0; i < count; i++) {
//             const dropdown = dropdownEls[i];
//             const rawValue = dropdown.dataset.selectedValue;
//             const isEmpty = (rawValue === undefined || rawValue === null || rawValue === '');
//             selected.push(isEmpty ? -1 : parseInt(rawValue, 10));
//         }

//         const score = scoreDropdownQuestion(qData, selected);
//         earnedPoints += score;

//         if (!showCorrection) return;

//         for (let i = 0; i < count; i++) {
//             const dropdown = dropdownEls[i];
//             const ddData = ddDataList[i];

//             const rawValue = dropdown.dataset.selectedValue;
//             const isEmpty = (rawValue === undefined || rawValue === null || rawValue === '');
//             const selectedIndex = isEmpty ? -1 : parseInt(rawValue, 10);

//             const correctIndex = ddData.correct_index;
//             const allOptions = ddData.options || [];
//             const correctOption = allOptions[correctIndex] || '';

//             const isCorrect = !isEmpty && (selectedIndex === correctIndex);

//             const next = dropdown.nextSibling;
//             if (next && next.classList?.contains('mkq-dropdown-correction-wrapper') && next.dataset?.forId === dropdown.id) {
//                 next.remove();
//             }

//             if (isCorrect) {
//                 dropdown.style.display = '';
//                 dropdown.classList.remove('incorrect');
//                 dropdown.classList.add('correct');
//             } else {
//                 let wrongAnswerHTML;
//                 if (isEmpty) {
//                     wrongAnswerHTML = t("ui.empty_answer", "(empty)");
//                 } else {
//                     const rawOptionText = allOptions[selectedIndex];
//                     wrongAnswerHTML = rawOptionText ? convertLatexDelimiters(rawOptionText) : t("ui.empty_answer", "(empty)");
//                 }

//                 dropdown.style.display = 'none';

//                 const wrapper = document.createElement('span');
//                 wrapper.className = 'mkq-dropdown-correction-wrapper';
//                 wrapper.dataset.forId = dropdown.id;
//                 wrapper.style.cssText = `display:inline-flex;align-items:center;gap:.5em;position:relative;`;

//                 const wrongLabel = document.createElement('span');
//                 wrongLabel.className = 'mkq-gap-wrong-label';
//                 wrongLabel.innerHTML = wrongAnswerHTML;
//                 wrapper.appendChild(wrongLabel);

//                 const correctDropdown = document.createElement('div');
//                 correctDropdown.className = 'mkq-custom-dropdown correct';
//                 correctDropdown.style.cssText = `display:inline-block;pointer-events:none;`;

//                 const correctBtn = document.createElement('button');
//                 correctBtn.type = 'button';
//                 correctBtn.className = 'mkq-custom-dropdown-btn correct';
//                 correctBtn.style.cursor = 'default';

//                 const correctValueSpan = document.createElement('span');
//                 correctValueSpan.className = 'mkq-custom-dropdown-value';
//                 correctValueSpan.innerHTML = convertLatexDelimiters(correctOption);

//                 const arrow = document.createElement('span');
//                 arrow.className = 'mkq-custom-dropdown-arrow';
//                 arrow.textContent = '✓';
//                 arrow.style.color = 'green';

//                 correctBtn.appendChild(correctValueSpan);
//                 correctBtn.appendChild(arrow);
//                 correctDropdown.appendChild(correctBtn);
//                 wrapper.appendChild(correctDropdown);

//                 dropdown.after(wrapper);

//                 setTimeout(() => {
//                     if (window.MathJax?.typesetPromise) {
//                         MathJax.typesetPromise([wrapper]).catch(() => {});
//                     }
//                 }, 150);
//             }
//         }
//     });

//     displayScorePoints(quizId, earnedPoints, totalPoints);
// }

// // ─────────────────────────────────────────────────────────────────────────────
// // Dropdown interactions
// // ─────────────────────────────────────────────────────────────────────────────

// function toggleDropdownQuiz(button) {
//     const dropdown = button.closest('.mkq-custom-dropdown');
//     const options = dropdown.querySelector('.mkq-custom-dropdown-options');
//     const isOpen = options.style.display === 'block';

//     document.querySelectorAll('.mkq-custom-dropdown-options').forEach(opt => opt.style.display = 'none');
//     options.style.display = isOpen ? 'none' : 'block';
// }

// function selectDropdownQuizOption(optionElement) {
//     const dropdown = optionElement.closest('.mkq-custom-dropdown');
//     const button = dropdown.querySelector('.mkq-custom-dropdown-btn');
//     const valueSpan = button.querySelector('.mkq-custom-dropdown-value');
//     const optionsDiv = dropdown.querySelector('.mkq-custom-dropdown-options');

//     valueSpan.innerHTML = optionElement.innerHTML;

//     dropdown.querySelectorAll('.mkq-custom-dropdown-option').forEach(opt => opt.classList.remove('selected'));
//     optionElement.classList.add('selected');

//     dropdown.dataset.selectedValue = optionElement.dataset.value;
//     optionsDiv.style.display = 'none';

//     if (window.MathJax?.typesetPromise) {
//         MathJax.typesetPromise([valueSpan]).catch(() => {});
//     }
// }

// document.addEventListener('click', (e) => {
//     if (!e.target.closest('.mkq-custom-dropdown')) {
//         document.querySelectorAll('.mkq-custom-dropdown-options').forEach(opt => opt.style.display = 'none');
//     }
// });

// // ─────────────────────────────────────────────────────────────────────────────
// // Gapfill correction dropdown helpers
// // ─────────────────────────────────────────────────────────────────────────────

// function convertLatexDelimiters(text) {
//     let result = text;
//     result = result.replace(/\$\$(.*?)\$\$/g, '\\[$1\\]');
//     result = result.replace(/\$([^\$]+)\$/g, '\\($1\\)');
//     return result;
// }

// function createGapfillMathJaxDropdown(id, answers) {
//     const container = document.createElement('div');
//     container.className = 'mkq-custom-select';
//     container.id = id;
//     container.setAttribute('role', 'combobox');
//     container.setAttribute('aria-haspopup', 'listbox');
//     container.setAttribute('aria-expanded', 'false');

//     const button = document.createElement('button');
//     button.className = 'mkq-custom-select-btn';
//     button.type = 'button';
//     button.setAttribute('aria-controls', `${id}-listbox`);

//     const valueSpan = document.createElement('span');
//     valueSpan.className = 'mkq-custom-select-value';
//     valueSpan.innerHTML = convertLatexDelimiters(answers[0]);
//     button.appendChild(valueSpan);

//     const arrow = document.createElement('span');
//     arrow.className = 'mkq-custom-select-arrow';
//     arrow.textContent = '▾';
//     arrow.setAttribute('aria-hidden', 'true');

//     const listbox = document.createElement('div');
//     listbox.className = 'mkq-custom-select-listbox';
//     listbox.id = `${id}-listbox`;
//     listbox.setAttribute('role', 'listbox');
//     listbox.setAttribute('tabindex', '-1');

//     answers.forEach((answer, index) => {
//         const option = document.createElement('div');
//         option.className = 'mkq-custom-select-option';
//         option.setAttribute('role', 'option');
//         option.setAttribute('tabindex', index === 0 ? '0' : '-1');
//         option.setAttribute('aria-selected', index === 0 ? 'true' : 'false');
//         option.dataset.value = answer;
//         option.innerHTML = convertLatexDelimiters(answer);

//         option.addEventListener('click', () => {
//             selectGapfillOption(container, button, valueSpan, listbox, option);
//         });

//         option.addEventListener('keydown', (e) => {
//             if (e.key === 'Enter' || e.key === ' ') {
//                 e.preventDefault();
//                 selectGapfillOption(container, button, valueSpan, listbox, option);
//             }
//         });

//         listbox.appendChild(option);
//     });

//     button.addEventListener('click', () => {
//         toggleGapfillDropdown(container, listbox);
//     });

//     listbox.addEventListener('keydown', (e) => {
//         handleGapfillKeyboardNav(e, container, listbox);
//     });

//     container.appendChild(button);
//     container.appendChild(arrow);
//     container.appendChild(listbox);

//     document.addEventListener('click', (e) => {
//         if (!container.contains(e.target)) {
//             container.setAttribute('aria-expanded', 'false');
//         }
//     });

//     setTimeout(() => {
//         if (window.MathJax?.typesetPromise) {
//             MathJax.typesetPromise([container]).catch(() => {});
//         }
//     }, 50);

//     return container;
// }

// function toggleGapfillDropdown(container, listbox) {
//     const isOpen = container.getAttribute('aria-expanded') === 'true';
//     container.setAttribute('aria-expanded', !isOpen ? 'true' : 'false');
//     if (!isOpen) listbox.focus();
// }

// function selectGapfillOption(container, button, valueSpan, listbox, option) {
//     listbox.querySelectorAll('.mkq-custom-select-option').forEach(opt => opt.setAttribute('aria-selected', 'false'));
//     option.setAttribute('aria-selected', 'true');

//     valueSpan.innerHTML = option.innerHTML;

//     if (valueSpan.innerHTML.includes('\\(') || valueSpan.innerHTML.includes('\\[')) {
//         if (window.MathJax?.typesetPromise) {
//             MathJax.typesetPromise([button]).catch(() => {});
//         }
//     }

//     container.setAttribute('aria-expanded', 'false');
//     button.focus();
// }

// function handleGapfillKeyboardNav(e, container, listbox) {
//     const options = Array.from(listbox.querySelectorAll('.mkq-custom-select-option'));
//     const current = document.activeElement.classList.contains('mkq-custom-select-option')
//         ? document.activeElement
//         : options[0];

//     let idx = options.indexOf(current);

//     if (e.key === 'Escape') {
//         e.preventDefault();
//         container.setAttribute('aria-expanded', 'false');
//         container.querySelector('.mkq-custom-select-btn').focus();
//     }
//     if (e.key === 'ArrowDown') {
//         e.preventDefault();
//         options[Math.min(idx + 1, options.length - 1)].focus();
//     }
//     if (e.key === 'ArrowUp') {
//         e.preventDefault();
//         options[Math.max(idx - 1, 0)].focus();
//     }
// }

// // ─────────────────────────────────────────────────────────────────────────────
// // Display score (points)
// // ─────────────────────────────────────────────────────────────────────────────

// function displayScorePoints(quizId, earned, total) {
//     const scoreElement = document.getElementById(`score-${quizId}`);
//     if (!scoreElement) return;

//     const e = Number(earned);
//     const ttot = Number(total) > 0 ? Number(total) : 0;
//     const pct = ttot > 0 ? (e / ttot) * 100 : 0;

//     scoreElement.textContent = `${t("ui.score_label", "Score")}: ${e.toFixed(2)}/${ttot.toFixed(2)} (${pct.toFixed(1)}%)`;
//     scoreElement.style.display = 'block';

//     scoreElement.classList.remove('good', 'medium', 'bad');
//     if (pct >= 75) scoreElement.classList.add('good');
//     else if (pct >= 50) scoreElement.classList.add('medium');
//     else scoreElement.classList.add('bad');
// }

// // ─────────────────────────────────────────────────────────────────────────────
// // Crypto / storage
// // ─────────────────────────────────────────────────────────────────────────────

// function decryptAnswers(encryptedData) {
//     try {
//         const key = window.QUIZ_CONFIG.encryption_key || 'default-key-change-me';
//         const encrypted = atob(encryptedData);

//         const keyBytes = new TextEncoder().encode(key);
//         const encryptedBytes = new Uint8Array(encrypted.split('').map(c => c.charCodeAt(0)));

//         const decrypted = new Uint8Array(encryptedBytes.length);
//         for (let i = 0; i < encryptedBytes.length; i++) {
//             decrypted[i] = encryptedBytes[i] ^ keyBytes[i % keyBytes.length];
//         }

//         const jsonStr = new TextDecoder().decode(decrypted);
//         return JSON.parse(jsonStr);
//     } catch (e) {
//         console.error(t("ui.error_decrypting", "Decrypting Error"), e);
//         return null;
//     }
// }

// function saveAnswers(quizId) {
//     const quiz = document.querySelector(`[data-quiz-id="${quizId}"]`);
//     if (!quiz) return;

//     const answers = {};

//     const checkedInputs = quiz.querySelectorAll('input[type="checkbox"]:checked, input[type="radio"]:checked');
//     checkedInputs.forEach(input => { answers[input.id] = true; });

//     const gapInputs = quiz.querySelectorAll('.mkq-gap-input');
//     gapInputs.forEach(input => {
//         if (input.value.trim() !== '') answers[input.id] = input.value;
//     });

//     const dropdowns = quiz.querySelectorAll('.mkq-custom-dropdown');
//     dropdowns.forEach(dropdown => {
//         if (dropdown.dataset.selectedValue) answers[dropdown.id] = dropdown.dataset.selectedValue;
//     });

//     if (Object.keys(answers).length > 0) {
//         localStorage.setItem(`mkq_answers_${quizId}`, JSON.stringify(answers));
//     } else {
//         localStorage.removeItem(`mkq_answers_${quizId}`);
//     }
// }

// function loadSavedAnswers() {
//     const quizzes = document.querySelectorAll('.mkdocs-superquiz');

//     quizzes.forEach(quiz => {
//         const quizId = quiz.dataset.quizId;

//         try {
//             const savedAnswersJson = localStorage.getItem(`mkq_answers_${quizId}`);
//             if (!savedAnswersJson) return;

//             const savedAnswers = JSON.parse(savedAnswersJson);
//             if (!savedAnswers || typeof savedAnswers !== 'object') {
//                 localStorage.removeItem(`mkq_answers_${quizId}`);
//                 return;
//             }

//             Object.keys(savedAnswers).forEach(inputId => {
//                 const input = document.getElementById(inputId);
//                 if (!input) return;

//                 const savedValue = savedAnswers[inputId];

//                 if (input.type === 'checkbox' || input.type === 'radio') {
//                     if (typeof savedValue === 'boolean') input.checked = savedValue;
//                 } else if (input.classList.contains('mkq-gap-input')) {
//                     input.value = String(savedValue);
//                 } else if (input.classList.contains('mkq-custom-dropdown')) {
//                     input.dataset.selectedValue = savedValue;
//                     const valueSpan = input.querySelector('.mkq-custom-dropdown-value');
//                     const selectedOption = input.querySelector(`[data-value="${savedValue}"]`);
//                     if (valueSpan && selectedOption) valueSpan.innerHTML = selectedOption.innerHTML;
//                 }
//             });

//         } catch (error) {
//             localStorage.removeItem(`mkq_answers_${quizId}`);
//         }
//     });
// }

// function refreshAllQuizzes() {
//     const quizzes = document.querySelectorAll('.mkdocs-superquiz');
//     if (quizzes.length === 0) return;

//     const pageUuid = quizzes[0]?.dataset.pageUuid;

//     quizzes.forEach(quiz => {
//         const quizId = quiz.dataset.quizId;
//         const quizType = quiz.dataset.quizType;

//         if (quizType === 'gapfill') {
//             quiz.querySelectorAll('.mkq-gap-correction-wrapper').forEach(wrapper => wrapper.remove());
//             quiz.querySelectorAll('.mkq-gap-input').forEach(input => {
//                 input.value = '';
//                 input.style.display = '';
//                 input.classList.remove('correct', 'incorrect');
//             });

//         } else if (quizType === 'dropdown') {
//             quiz.querySelectorAll('.mkq-dropdown-correction-wrapper').forEach(wrapper => wrapper.remove());
//             quiz.querySelectorAll('.mkq-custom-dropdown').forEach(dropdown => {
//                 dropdown.style.display = '';
//                 dropdown.dataset.selectedValue = '';
//                 const valueSpan = dropdown.querySelector('.mkq-custom-dropdown-value');
//                 if (valueSpan) valueSpan.textContent = '--';
//                 dropdown.querySelectorAll('.mkq-custom-dropdown-option').forEach(opt => opt.classList.remove('selected'));
//                 dropdown.classList.remove('correct', 'incorrect');
//             });

//         } else {
//             quiz.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(input => {
//                 input.checked = false;
//             });
//         }

//         quiz.querySelectorAll('.mkq-answer').forEach(answer => {
//             answer.classList.remove('correct', 'incorrect');
//             const feedback = answer.querySelector('.mkq-answer-feedback');
//             if (feedback) {
//                 feedback.style.display = 'none';
//                 feedback.textContent = '';
//                 feedback.classList.remove('correct', 'incorrect');
//             }
//         });

//         const scoreElement = document.getElementById(`score-${quizId}`);
//         if (scoreElement) {
//             scoreElement.style.display = 'none';
//             scoreElement.textContent = '';
//             scoreElement.classList.remove('good', 'medium', 'bad');
//         }

//         const lockBtn = quiz.querySelector('.mkq-unlock-btn, .mkq-lock-indicator');
//         if (lockBtn && !lockBtn.classList.contains('unlocked')) {
//             const originalState = lockBtn.getAttribute('data-lock-state');
//             if (originalState === 'locked') updateLockIcon(lockBtn, false);
//         }

//         localStorage.removeItem(`mkq_answers_${quizId}`);
//     });

//     if (pageUuid) {
//         const unlocks = JSON.parse(localStorage.getItem('mkq_unlocks') || '[]');
//         const filteredUnlocks = unlocks.filter(unlock => unlock.page_id !== pageUuid);
//         localStorage.setItem('mkq_unlocks', JSON.stringify(filteredUnlocks));
//     }

//     showRefreshNotification();
// }

// function showRefreshNotification() {
//     const notification = document.createElement('div');
//     notification.textContent = `✅ ${t("ui.all_quizzes_have_been_reset", "All Quizzes have been reset")}`;
//     notification.style.cssText = `
//         position: fixed;
//         top: 20px;
//         right: 20px;
//         background: #4caf50;
//         color: white;
//         padding: 1rem 1.5rem;
//         border-radius: 6px;
//         box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
//         z-index: 10000;
//         font-weight: 500;
//         font-size: 2em;
//         animation: slideIn 0.3s ease-out;
//     `;
//     document.body.appendChild(notification);
//     setTimeout(() => {
//         notification.style.opacity = '0';
//         notification.style.transition = 'opacity 0.3s';
//         setTimeout(() => notification.remove(), 300);
//     }, 2000);
// }

// function addRefreshButton() {
//     const pageTitle = document.querySelector('.md-content h1');
//     if (!pageTitle) return;

//     const quizzes = document.querySelectorAll('.mkdocs-superquiz');
//     if (quizzes.length === 0) return;

//     const refreshBtn = document.createElement('button');
//     refreshBtn.className = 'mkq-refresh-page-btn';
//     refreshBtn.title = t("ui.reset_all_quizzes", "Reset all quizzes");
//     refreshBtn.innerHTML = `
//         <span class="mkq-btn-icon">🔄</span>
//         <span class="mkq-btn-text">${t("ui.reset_all_quizzes", "Reset all quizzes")}</span>
//     `;
//     refreshBtn.addEventListener('click', () => refreshAllQuizzes());

//     const unlockPageBtn = document.createElement('button');
//     unlockPageBtn.className = 'mkq-unlock-page-btn';
//     unlockPageBtn.title = t("ui.unlock_all_page_quizzes", "Unlock all page quizzes");
//     unlockPageBtn.innerHTML = `
//         <span class="mkq-btn-icon">🔓</span>
//         <span class="mkq-btn-text">${t("ui.unlock_all_page_quizzes", "Unlock all page quizzes")}</span>
//     `;
//     unlockPageBtn.addEventListener('click', () => showUnlockModal('page'));

//     const buttonsContainer = document.createElement('div');
//     buttonsContainer.className = 'mkq-page-buttons';
//     buttonsContainer.appendChild(unlockPageBtn);
//     buttonsContainer.appendChild(refreshBtn);

//     pageTitle.appendChild(buttonsContainer);
// }

// function clearAllQuizData() {
//     const keys = Object.keys(localStorage);
//     const quizKeys = keys.filter(key => key.startsWith('mkq_'));
//     quizKeys.forEach(key => localStorage.removeItem(key));
//     setTimeout(() => location.reload(), 1000);
// }
// window.clearAllQuizData = clearAllQuizData;

// function initQuizPlugin() {
//     if (!window.QUIZ_CONFIG || !window.QUIZ_CONFIG.i18n) return;

//     createUnlockModal();
//     restoreUnlockedCorrections();
//     loadSavedAnswers();
//     addRefreshButton();
// }

// if (document.readyState === 'loading') {
//     document.addEventListener('DOMContentLoaded', initQuizPlugin);
// } else {
//     initQuizPlugin();
// }

// ===============================================================================================================
// ===============================================================================================================
// ===============================================================================================================

// quiz.js
/**
 * mkdocs-superquiz - Logique principale JavaScript
 */

window.QUIZ_CONFIG = window.QUIZ_CONFIG || {};

function t(key, fallback = "") {
    const keys = key.split('.');
    let value = window.QUIZ_CONFIG?.i18n;
    for (const k of keys) {
        if (value && typeof value === 'object') value = value[k];
        else return fallback || key;
    }
    return value || fallback || key;
}

let currentUnlockContext = null;

function createUnlockModal() {
    const modal = document.createElement('div');
    modal.id = 'mkq-unlock-modal';
    modal.className = 'mkq-modal';
    modal.innerHTML = `
        <div class="mkq-modal-content">
            <button class="mkq-modal-close" onclick="closeUnlockModal()">×</button>
            <h3 id="mkq-unlock-title">${t("ui.unlock_title", "Unlock Correction")}</h3>
            <div class="qr-code-section">
                <p>${t("ui.unlock_qr_instruction", "Ask your teacher to scan this QR code:")}</p>
                <div id="qr-code-container"></div>
            </div>
            <div class="unlock-input-section">
                <label for="mkq-unlock-code-input">${t("ui.unlock_code_label", "Unlock code (provided by teacher):")}</label>
                <input type="text" id="mkq-unlock-code-input" placeholder="${t("ui.unlock_code_placeholder", "e.g., A7F3E9C2")}">
                <button onclick="validateUnlockCode()">${t("ui.unlock_validate", "Validate")}</button>
            </div>
        </div>
    `;
    document.body.appendChild(modal);
}

function getSiteUrl() {
    const currentOrigin = window.location.origin;
    const currentPath = window.location.pathname;
    const baseElement = document.querySelector('base');
    if (baseElement && baseElement.href) {
        const baseUrl = new URL(baseElement.href);
        return baseUrl.origin + baseUrl.pathname.replace(/\/$/, '');
    }
    const pathParts = currentPath.split('/').filter(p => p);
    if (pathParts.length > 0) {
        const firstPart = pathParts[0];
        const isProjectName = !firstPart.includes('.html') && !firstPart.includes('.') &&
            firstPart !== 'search' && firstPart !== 'assets';
        if (currentPath.includes('/mkdocs-superquiz/')) return currentOrigin + '/mkdocs-superquiz';
        const knownPages = ['index', 'sample_quiz', 'search', 'sitemap'];
        if (isProjectName && !knownPages.includes(firstPart)) return currentOrigin + '/' + firstPart;
    }
    return currentOrigin;
}

function showUnlockModal(type, exerciseId = null, questionId = null) {
    const modal = document.getElementById('mkq-unlock-modal');
    if (!modal) return;
    const pageUuid = document.querySelector('.mkdocs-superquiz')?.dataset.pageUuid;
    if (!pageUuid) return;
    const siteUrl = getSiteUrl();
    const data = { type, page_id: pageUuid, page_title: document.title, site_url: siteUrl };
    if (type === 'exercise' || type === 'question') {
        data.exercise_id = exerciseId;
        const exerciseElement = document.querySelector(`[data-quiz-id="${exerciseId}"]`);
        if (exerciseElement) {
            const titleElement = exerciseElement.querySelector('.admonition-title');
            let title = titleElement ? titleElement.textContent.trim() : '';
            title = title.replace(/🔒|🔓|❌|🔐|✅/g, '').replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
            data.exercise_title = title;
        }
    }
    if (type === 'question') {
        data.question_id = questionId;
        const questionElement = document.querySelector(`[data-quiz-id="${exerciseId}"] [data-question-id="${questionId}"]`);
        if (questionElement) {
            const textElement = questionElement.querySelector('.mkq-question-text');
            let questionText = textElement ? textElement.textContent.trim() : '';
            questionText = questionText.replace(/🔒|🔓|❌|🔐|✅/g, '').replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
            data.question_text = questionText;
        }
    }
    currentUnlockContext = data;
    const titleElement = document.getElementById('mkq-unlock-title');
    if (titleElement) {
        if (type === 'page') titleElement.textContent = t("ui.unlock_page_title", "Unlock All Page Quizzes");
        else if (type === 'exercise') titleElement.textContent = `${t("ui.unlock_quiz", "Unlock Quiz")} ${exerciseId}`;
        else titleElement.textContent = `${t("ui.unlock_quiz_question", "Unlock this quiz question")} ${questionId}`;
    }
    generateQRCode(data);
    modal.classList.add('active');
}

function generateQRCode(data) {
    const container = document.getElementById('qr-code-container');
    if (!container) return;
    const jsonString = JSON.stringify(data);
    const utf8Bytes = new TextEncoder().encode(jsonString);
    let binaryString = '';
    for (let i = 0; i < utf8Bytes.length; i++) binaryString += String.fromCharCode(utf8Bytes[i]);
    const encodedData = btoa(binaryString);
    const unlockUrl = `${data.site_url}/quiz-unlock.html?data=${encodedData}`;
    if (typeof qrcode === 'undefined') {
        container.innerHTML = `<p style="color:red;">${t("ui.error_no_library", "Error: No QR Code library has been downloaded")}</p>`;
        return;
    }
    try {
        const qr = qrcode(0, 'H');
        qr.addData(unlockUrl);
        qr.make();
        container.innerHTML = qr.createSvgTag(4, 4);
        const svg = container.querySelector('svg');
        if (svg) {
            svg.style.display = 'block'; svg.style.maxWidth = '256px'; svg.style.height = 'auto';
            svg.style.margin = '0 auto'; svg.style.padding = '10px'; svg.style.background = 'white';
            svg.style.borderRadius = '8px'; svg.style.boxShadow = '0 2px 8px rgba(0,0,0,0.1)';
        }
    } catch (error) {
        container.innerHTML = `<p style="color:red;">${t("ui.error_generating_qrcode", "Error generating QR Code")}</p>`;
    }
}

function closeUnlockModal() {
    const modal = document.getElementById('mkq-unlock-modal');
    if (modal) modal.classList.remove('active');
    const input = document.getElementById('mkq-unlock-code-input');
    if (input) input.value = '';
}

async function validateUnlockCode() {
    const input = document.getElementById('mkq-unlock-code-input');
    if (!input) return;
    const code = input.value.trim().toUpperCase();
    if (!code) { alert(t("ui.please_enter_code", "Please enter a code")); return; }
    if (!currentUnlockContext) { alert(t("ui.error_no_unlocking_context", "Error: Unlocking context not found")); return; }
    const expectedCode = await calculateUnlockCode(currentUnlockContext);
    if (code === expectedCode) {
        unlockCorrections(currentUnlockContext);
        saveUnlockState(currentUnlockContext);
        closeUnlockModal();
    } else {
        alert(t("ui.error_incorrect_code", "Incorrect code. Check with your teacher."));
    }
}

async function calculateUnlockCode(context) {
    const teacherCodeHash = window.QUIZ_CONFIG.teacher_code_hash || '';
    let payload = teacherCodeHash + context.page_id + context.type;
    if (context.type === 'exercise' || context.type === 'question') payload += (context.exercise_id || '');
    if (context.type === 'question') payload += (context.question_id || '');
    const hash = await sha256(payload);
    return hash.substring(0, 8).toUpperCase();
}

async function sha256(str) {
    const buffer = new TextEncoder().encode(str);
    const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

function updateLockIcon(element, unlocked) {
    if (!element) return;
    if (unlocked) {
        element.textContent = '🔓';
        element.classList.remove('locked'); element.classList.add('unlocked');
        element.setAttribute('data-lock-state', 'unlocked');
        element.setAttribute('title', t("ui.unlocked_corrections", "Unlocked corrections"));
        element.onclick = null; element.style.cursor = 'default';
    } else {
        element.textContent = '🔒';
        element.classList.remove('unlocked'); element.classList.add('locked');
        element.setAttribute('data-lock-state', 'locked');
        element.setAttribute('title', t("ui.lock_tooltip_locked", "Click to unlock corrections"));
    }
}

function shouldShowCorrections(quiz) {
    const lockIndicator = quiz.querySelector('.mkq-lock-indicator, .mkq-unlock-btn');
    if (!lockIndicator) return true;
    const lockState = lockIndicator.getAttribute('data-lock-state');
    if (lockState === 'locked-permanent') return false;
    if (lockState === 'unlocked') return true;
    if (lockState === 'locked') {
        const pageUuid = quiz.dataset.pageUuid;
        const quizId = quiz.dataset.quizId;
        const unlocks = JSON.parse(localStorage.getItem('mkq_unlocks') || '[]');
        return unlocks.some(u => u.page_id === pageUuid && (u.type === 'page' || u.exercise_id === quizId));
    }
    return true;
}

function unlockCorrections(context) {
    if (context.type === 'page') {
        document.querySelectorAll('.mkq-unlock-btn').forEach(btn => updateLockIcon(btn, true));
        document.querySelectorAll('.mkdocs-superquiz').forEach(quiz => {
            const quizId = quiz.dataset.quizId;
            if (quizId) validateQuiz(quizId);
        });
    } else if (context.type === 'exercise') {
        const exercise = document.querySelector(`[data-quiz-id="${context.exercise_id}"]`);
        if (exercise) {
            updateLockIcon(exercise.querySelector('.mkq-unlock-btn'), true);
            validateQuiz(context.exercise_id);
        }
    } else if (context.type === 'question') {
        const exercise = document.querySelector(`[data-quiz-id="${context.exercise_id}"]`);
        if (exercise) {
            const question = exercise.querySelector(`[data-question-id="${context.question_id}"]`);
            if (question) updateLockIcon(question.querySelector('.mkq-unlock-btn'), true);
            validateQuiz(context.exercise_id);
        }
    }
}

function saveUnlockState(context) {
    const unlocks = JSON.parse(localStorage.getItem('mkq_unlocks') || '[]');
    unlocks.push({
        page_id: context.page_id, type: context.type,
        exercise_id: context.exercise_id, question_id: context.question_id,
        timestamp: new Date().toISOString()
    });
    localStorage.setItem('mkq_unlocks', JSON.stringify(unlocks));
}

function restoreUnlockedCorrections() {
    const unlocks = JSON.parse(localStorage.getItem('mkq_unlocks') || '[]');
    const currentPageUuid = document.querySelector('.mkdocs-superquiz')?.dataset.pageUuid;
    if (!currentPageUuid) return;
    unlocks.forEach(unlock => { if (unlock.page_id === currentPageUuid) unlockCorrections(unlock); });
}

// ─────────────────────────────────────────────────────────────────────────────
// Scoring helpers
// ─────────────────────────────────────────────────────────────────────────────

function clampScore(score, pointsMax, minScore, clampMax) {
    let s = score;
    if (clampMax) s = Math.min(s, pointsMax);
    if (minScore !== null && minScore !== undefined) {
        const min = Number(minScore);
        if (min < pointsMax) s = Math.max(s, min);
    }
    return s;
}

function arraysEqual(a, b) {
    if (a.length !== b.length) return false;
    for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
    return true;
}

function normalizeLatexLoose(str) {
    return str.replace(/\s+/g, '').replace(/\*/g, '').replace(/²/g, '^2').replace(/³/g, '^3');
}

// ─────────────────────────────────────────────────────────────────────────────
// compareAnswers — NEW FORMAT ONLY
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Normalize a compare_answers config to canonical format.
 * Only new format: { ignore: { spaces, characters, case, diacritics }, equivalence: {...} }
 * Missing keys fall back to defaults.
 */
function normalizeCompareConfig(cfg) {
    const DEFAULTS = {
        spaces:     'all',
        characters: '?,.;/:!¡-_',
        case:       true,
        diacritics: false
    };

    if (!cfg || typeof cfg !== 'object') {
        return { ignore: Object.assign({}, DEFAULTS), equivalence: {} };
    }

    const ignore = Object.assign({}, DEFAULTS, cfg.ignore || {});

    const validSpaces = ['all', 'inside', 'outside', 'none'];
    if (!validSpaces.includes(ignore.spaces)) ignore.spaces = 'all';

    const rawEquiv = cfg.equivalence || {};
    const equivalence = {};
    for (const [k, v] of Object.entries(rawEquiv)) {
        equivalence[k] = Array.isArray(v) ? v.map(String) : [String(v)];
    }

    return { ignore, equivalence };
}

/**
 * Normalize a single string according to ignore rules.
 * Order: characters → spaces → case → diacritics
 */
function normalizeAnswer(str, ignore) {
    if (typeof str !== 'string') str = String(str ?? '');

    // 1. Strip characters
    const chars = (ignore.characters != null) ? String(ignore.characters) : '?,.;/:!¡-_';
    if (chars.length > 0) {
        const charSet = new Set([...chars]);
        str = [...str].filter(c => !charSet.has(c)).join('');
    }

    // 2. Spaces
    const spacesMode = ignore.spaces ?? 'all';
    if (spacesMode === 'all') {
        str = str.replace(/\s+/g, '');
    } else if (spacesMode === 'outside') {
        str = str.trim();
    } else if (spacesMode === 'inside') {
        const leading  = str.match(/^\s*/)[0];
        const trailing = str.match(/\s*$/)[0];
        const inner    = str.slice(leading.length, str.length - (trailing.length || undefined));
        str = leading + inner.replace(/\s+/g, '') + trailing;
    }
    // 'none': do nothing

    // 3. Case
    if (ignore.case !== false) str = str.toLowerCase();

    // 4. Diacritics
    if (ignore.diacritics === true) str = str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');

    return str;
}

/**
 * Apply equivalence rules bidirectionally after normalization.
 * Equivalences WIN over diacritics (more specific).
 * Greedy match: longest equivalence keys matched first.
 */
function applyEquivalences(str, equivalence, caseInsensitive) {
    if (!equivalence || typeof equivalence !== 'object') return str;

    const repMap = new Map();
    for (const [canonical, variants] of Object.entries(equivalence)) {
        const canonKey = caseInsensitive ? canonical.toLowerCase() : canonical;
        for (const v of (Array.isArray(variants) ? variants : [variants])) {
            const vKey = caseInsensitive ? String(v).toLowerCase() : String(v);
            repMap.set(vKey, canonKey);
        }
    }
    if (repMap.size === 0) return str;

    const sortedKeys = [...repMap.keys()].sort((a, b) => b.length - a.length);
    const escaped = sortedKeys.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
    const re = new RegExp(escaped.join('|'), 'g');
    return str.replace(re, match => repMap.get(match) ?? match);
}

/**
 * Main comparison function.
 * Config resolution priority:
 *   1. per-question compare_answers (from encrypted payload)
 *   2. per-quiz compare_answers (from encrypted payload)
 *   3. window.QUIZ_CONFIG.gapfill.compare_answers (global)
 *   4. {} → all defaults
 */
function compareAnswers(userAnswer, correctAnswer, compareConfig) {
    const rawCfg = compareConfig
        || window.QUIZ_CONFIG?.gapfill?.compare_answers
        || {};

    const cfg = normalizeCompareConfig(rawCfg);
    const { ignore, equivalence } = cfg;
    const caseInsensitive = (ignore.case !== false);

    let user    = normalizeAnswer(String(userAnswer    ?? ''), ignore);
    let correct = normalizeAnswer(String(correctAnswer ?? ''), ignore);

    // Apply equivalences AFTER normalization (wins over diacritics)
    user    = applyEquivalences(user,    equivalence, caseInsensitive);
    correct = applyEquivalences(correct, equivalence, caseInsensitive);

    return user === correct;
}

// ─────────────────────────────────────────────────────────────────────────────
// Parse losing_mode keys for mcquiz: "[Paris, Londres]" → list
// ─────────────────────────────────────────────────────────────────────────────

function parseBracketKey(key) {
    const s = String(key).trim();
    if (!s.startsWith('[') || !s.endsWith(']')) return null;
    const inner = s.slice(1, -1).trim();
    if (!inner) return [];
    return inner.split(',').map(x => x.trim()).filter(Boolean);
}

// ─────────────────────────────────────────────────────────────────────────────
// Score functions
// ─────────────────────────────────────────────────────────────────────────────

function scoreChoiceQuestion(questionData, selectedIndices) {
    const points = Number(questionData.points || 1);
    const scoringMode = questionData.scoring_mode || 'all_or_nothing';
    const defaultFalse = Number(questionData.default_false ?? 0);
    const correct = Array.isArray(questionData.correct_answers) ? questionData.correct_answers : [];
    const correctSet = new Set(correct);
    let nbGood = 0, nbFalse = 0;
    selectedIndices.forEach(i => { if (correctSet.has(i)) nbGood++; else nbFalse++; });
    const nbGoodTotal = correct.length || 1;
    let base = 0;
    const selSorted = [...selectedIndices].sort((a,b) => a-b);
    const corSorted = [...correct].sort((a,b) => a-b);
    const exact = arraysEqual(selSorted, corSorted);
    if (scoringMode === 'all_or_nothing') {
        base = exact ? points : 0;
    } else if (scoringMode === 'some_or_nothing') {
        base = nbFalse > 0 ? 0 : points * (nbGood / nbGoodTotal);
    } else { // proportional
        base = points * ((nbGood / nbGoodTotal) - (nbFalse / nbGoodTotal));
    }
    const lm = questionData.losing_mode || null;
    const hasLosingMode = lm && Array.isArray(lm.rules) && lm.rules.length > 0;
    if (!exact && !hasLosingMode && defaultFalse !== 0) base = defaultFalse;
    if (!exact && hasLosingMode) {
        const answersText = Array.isArray(questionData.answers_text) ? questionData.answers_text : [];
        const selectedTexts = selectedIndices.map(i => answersText[i] ?? '').filter(Boolean);
        let matchedRule = null;
        for (const r of lm.rules) {
            const list = parseBracketKey(r.key);
            if (!list) continue;
            const a = [...selectedTexts].map(x => x.trim()).sort();
            const b = [...list].map(x => x.trim()).sort();
            if (arraysEqual(a, b)) { matchedRule = r; break; }
        }
        if (matchedRule) base = Number(matchedRule.score);
        else if (lm.default_false !== null && lm.default_false !== undefined) base = Number(lm.default_false);
        else if (defaultFalse !== 0) base = defaultFalse;
    }
    const minScore = questionData.min_score !== undefined ? questionData.min_score
        : window.QUIZ_CONFIG.min_score !== undefined ? window.QUIZ_CONFIG.min_score : 0;
    const clampMax = (questionData.clamp_max_score ?? window.QUIZ_CONFIG.clamp_max_score ?? true);
    return clampScore(base, points, minScore, clampMax);
}

function scoreScQuizQuestion(questionData, selectedIndex) {
    const points = Number(questionData.points || 1);
    const correct = Array.isArray(questionData.correct_answers) ? questionData.correct_answers : [];
    const correctIndex = correct.length ? correct[0] : 0;
    const defaultFalse = Number(questionData.default_false ?? 0);
    const exact = (selectedIndex === correctIndex);
    let base = exact ? points : 0;
    const lm = questionData.losing_mode || null;
    const hasLosingMode = lm && Array.isArray(lm.rules) && lm.rules.length > 0;
    if (!exact && !hasLosingMode && defaultFalse !== 0) base = defaultFalse;
    if (!exact && hasLosingMode) {
        const answersText = Array.isArray(questionData.answers_text) ? questionData.answers_text : [];
        const selectedText = (selectedIndex >= 0 && selectedIndex < answersText.length) ? answersText[selectedIndex] : '';
        let matched = null;
        for (const r of lm.rules) { if (String(r.key).trim() === String(selectedText).trim()) { matched = r; break; } }
        if (matched) base = Number(matched.score);
        else if (lm.default_false !== null && lm.default_false !== undefined) base = Number(lm.default_false);
        else if (defaultFalse !== 0) base = defaultFalse;
    }
    const minScore = questionData.min_score !== undefined ? questionData.min_score
        : window.QUIZ_CONFIG.min_score !== undefined ? window.QUIZ_CONFIG.min_score : 0;
    const clampMax = (questionData.clamp_max_score ?? window.QUIZ_CONFIG.clamp_max_score ?? true);
    return clampScore(base, points, minScore, clampMax);
}

function scoreGapfillQuestion(questionData, userAnswers) {
    const points = Number(questionData.points || 1);
    const gaps = Array.isArray(questionData.gaps) ? questionData.gaps : [];
    const n = gaps.length || 1;
    const scoringMode = questionData.scoring_mode || 'proportional';
    const perGap = points / n;
    const lm = questionData.losing_mode || { gaps: [] };
    // Priority: per-question > per-quiz > global
    const compareCfg = questionData.compare_answers
        || window.QUIZ_CONFIG.gapfill?.compare_answers
        || {};
    let correctCount = 0, anyWrongNonEmpty = false;
    const gapStates = [];
    for (let i = 0; i < gaps.length; i++) {
        const gap = gaps[i];
        const ua = String(userAnswers[i] ?? '').trim();
        const accepted = Array.isArray(gap.answers) ? gap.answers : [];
        const isEmpty = (ua === '');
        const isCorrect = !isEmpty && accepted.some(ans => compareAnswers(ua, ans, compareCfg));
        if (isCorrect) correctCount++;
        if (!isCorrect && !isEmpty) anyWrongNonEmpty = true;
        gapStates.push({ isCorrect, isEmpty, ua });
    }
    let total = 0;
    if (scoringMode === 'all_or_nothing') total = (correctCount === gaps.length) ? points : 0;
    else if (scoringMode === 'some_or_nothing') total = anyWrongNonEmpty ? 0 : (perGap * correctCount);
    else total = perGap * correctCount; // proportional
    for (let i = 0; i < gaps.length; i++) {
        const st = gapStates[i];
        if (st.isCorrect) continue;
        const gLm = (lm.gaps && lm.gaps[i]) ? lm.gaps[i] : null;
        if (!gLm) continue;
        const rules = Array.isArray(gLm.rules) ? gLm.rules : [];
        const defFalse = (gLm.default_false !== null && gLm.default_false !== undefined) ? Number(gLm.default_false)
            : ((gLm.default !== null && gLm.default !== undefined) ? Number(gLm.default) : null);
        let matched = null;
        for (const r of rules) { if (compareAnswers(st.ua, r.answer, compareCfg)) { matched = r; break; } }
        if (matched) total += Number(matched.score);
        else if (defFalse !== null) total += defFalse;
    }
    const minScore = questionData.min_score ?? window.QUIZ_CONFIG.min_score ?? 0;
    const clampMax = (questionData.clamp_max_score ?? window.QUIZ_CONFIG.clamp_max_score ?? true);
    return clampScore(total, points, minScore, clampMax);
}

function scoreDropdownQuestion(questionData, selectedIndices) {
    const actual = Array.isArray(questionData.dropdowns) ? questionData.dropdowns
        : (questionData.dropdown ? [questionData.dropdown] : []);
    const per = actual.length > 0 ? Number(questionData.points || 1) / actual.length : Number(questionData.points || 1);
    const points = Number(questionData.points || 1);
    const scoringMode = questionData.scoring_mode || 'all_or_nothing';
    let total = 0, anyWrong = false;
    const lm = questionData.losing_mode || { dropdowns: [] };
    for (let i = 0; i < actual.length; i++) {
        const dd = actual[i] || {};
        const correctIndex = Number(dd.correct_index ?? 0);
        const sel = (selectedIndices[i] ?? -1);
        const isCorrect = (sel >= 0 && sel === correctIndex);
        if (isCorrect) {
            total += per;
        } else {
            anyWrong = true;
            const ddLm = (lm.dropdowns && lm.dropdowns[i]) ? lm.dropdowns[i] : null;
            const opts = Array.isArray(dd.options) ? dd.options : [];
            const chosenText = (sel >= 0 && sel < opts.length) ? String(opts[sel]) : '';
            if (ddLm && Array.isArray(ddLm.rules) && chosenText) {
                let matched = null;
                for (const r of ddLm.rules) { if (String(r.option).trim() === chosenText.trim()) { matched = r; break; } }
                if (matched) total += Number(matched.score);
                else if (ddLm.default_false !== null && ddLm.default_false !== undefined) total += Number(ddLm.default_false);
            }
        }
    }
    if (scoringMode === 'all_or_nothing') total = (total >= points - 1e-9) ? points : 0;
    else if (scoringMode === 'some_or_nothing') { if (anyWrong) total = 0; }
    // proportional: total already computed per-dropdown
    const minScore = questionData.min_score ?? window.QUIZ_CONFIG.min_score ?? 0;
    const clampMax = (questionData.clamp_max_score ?? window.QUIZ_CONFIG.clamp_max_score ?? true);
    return clampScore(total, points, minScore, clampMax);
}

// ─────────────────────────────────────────────────────────────────────────────
// Validation
// ─────────────────────────────────────────────────────────────────────────────

function validateQuiz(quizId) {
    const quiz = document.querySelector(`[data-quiz-id="${quizId}"]`);
    if (!quiz) return;
    const quizType = quiz.dataset.quizType;
    if (quizType === 'gapfill') validateGapfillQuiz(quiz, quizId);
    else if (quizType === 'dropdown') validateDropdownQuiz(quiz, quizId);
    else validateChoiceQuiz(quiz, quizId);
    saveAnswers(quizId);
}

function validateChoiceQuiz(quiz, quizId) {
    const questions = quiz.querySelectorAll('.mkq-question[data-question-id]');
    let totalPoints = 0, earnedPoints = 0;
    const correctionData = decryptAnswers(quiz.dataset.encrypted);
    if (!correctionData) { alert(t("ui.error_downloading_corrections", "Error downloading corrections")); return; }
    const showCorrection = shouldShowCorrections(quiz);
    questions.forEach((questionEl) => {
        const questionId = parseInt(questionEl.dataset.questionId, 10);
        const qData = correctionData.questions.find(q => q.number === questionId);
        if (!qData) return;
        totalPoints += Number(qData.points || 1);
        const inputs = questionEl.querySelectorAll('input[type="checkbox"], input[type="radio"]');
        const selected = [];
        inputs.forEach((input, idx) => { if (input.checked) selected.push(idx); });
        let score = correctionData.quiz_type === 'scquiz'
            ? scoreScQuizQuestion(qData, selected.length ? selected[0] : -1)
            : scoreChoiceQuestion(qData, selected);
        earnedPoints += score;
        if (showCorrection) {
            const correctIndices = qData.correct_answers || [];
            inputs.forEach((input, idx) => {
                const label = input.closest('.mkq-answer');
                const feedback = label.querySelector('.mkq-answer-feedback');
                label.classList.remove('correct', 'incorrect');
                if (feedback) { feedback.style.display = 'none'; feedback.textContent = ''; feedback.classList.remove('correct', 'incorrect'); }
                if (correctIndices.includes(idx)) {
                    label.classList.add('correct');
                    if (feedback) { feedback.textContent = t("feedback.correct", "Correct"); feedback.classList.add('correct'); feedback.style.display = 'inline'; }
                } else if (selected.includes(idx)) {
                    label.classList.add('incorrect');
                    if (feedback) { feedback.textContent = t("feedback.incorrect", "Incorrect"); feedback.classList.add('incorrect'); feedback.style.display = 'inline'; }
                }
            });
        }
    });
    displayScorePoints(quizId, earnedPoints, totalPoints);
}

function validateGapfillQuiz(quiz, quizId) {
    const questions = quiz.querySelectorAll('.mkq-question[data-question-id]');
    let totalPoints = 0, earnedPoints = 0;
    const correctionData = decryptAnswers(quiz.dataset.encrypted);
    if (!correctionData) { alert(t("ui.error_downloading_corrections", "Error downloading corrections")); return; }
    const showCorrection = shouldShowCorrections(quiz);
    const droppedElements = [];
    questions.forEach((questionEl) => {
        const questionId = parseInt(questionEl.dataset.questionId, 10);
        const qData = correctionData.questions.find(q => q.number === questionId);
        if (!qData) return;
        totalPoints += Number(qData.points || 1);
        const gapInputs = questionEl.querySelectorAll('.mkq-gap-input');
        const userAnswers = [];
        gapInputs.forEach((input) => userAnswers.push(input.value));
        earnedPoints += scoreGapfillQuestion(qData, userAnswers);
        if (!showCorrection) return;
        gapInputs.forEach((input, gapIndex) => {
            const userAnswer = input.value.trim();
            const gap = qData.gaps[gapIndex];
            if (!gap) return;
            const compareCfg = qData.compare_answers
                || correctionData.compare_answers
                || window.QUIZ_CONFIG.gapfill?.compare_answers
                || {};
            const isCorrect = gap.answers.some(answer => compareAnswers(userAnswer, answer, compareCfg));
            const nextSibling = input.nextSibling;
            if (nextSibling && nextSibling.classList?.contains('mkq-gap-correction-wrapper')) nextSibling.remove();
            if (isCorrect) {
                input.style.display = ''; input.classList.add('correct'); input.classList.remove('incorrect');
            } else {
                input.style.display = 'none'; input.classList.remove('correct'); input.classList.add('incorrect');
                const wrapper = document.createElement('span');
                wrapper.className = 'mkq-gap-correction-wrapper';
                const label = document.createElement('span');
                label.className = 'mkq-gap-wrong-label';
                label.innerHTML = `<s>${userAnswer || t("ui.empty_answer", "(empty)")}</s>`;
                wrapper.appendChild(label);
                const dropdown = createGapfillMathJaxDropdown(
                    `mkq-dropdown-${quizId}-q${questionId}-gap${gapIndex}`, gap.answers
                );
                wrapper.appendChild(dropdown);
                input.after(wrapper);
                droppedElements.push(wrapper);
            }
        });
    });
    displayScorePoints(quizId, earnedPoints, totalPoints);
    if (droppedElements.length > 0) {
        setTimeout(() => { if (window.MathJax?.typesetPromise) MathJax.typesetPromise(droppedElements).catch(() => {}); }, 150);
    }
}

function validateDropdownQuiz(quiz, quizId) {
    const questions = quiz.querySelectorAll('.mkq-question[data-question-id]');
    let totalPoints = 0, earnedPoints = 0;
    const correctionData = decryptAnswers(quiz.dataset.encrypted);
    if (!correctionData) { alert(t("ui.error_downloading_corrections", "Error downloading corrections")); return; }
    const showCorrection = shouldShowCorrections(quiz);
    questions.forEach((questionEl) => {
        const questionId = parseInt(questionEl.dataset.questionId, 10);
        const qData = correctionData.questions.find(q => q.number === questionId);
        if (!qData) return;
        totalPoints += Number(qData.points || 1);
        const dropdownEls = Array.from(questionEl.querySelectorAll('.mkq-custom-dropdown'));
        const ddDataList = Array.isArray(qData.dropdowns) ? qData.dropdowns : (qData.dropdown ? [qData.dropdown] : []);
        const count = Math.min(dropdownEls.length, ddDataList.length);
        const selected = [];
        for (let i = 0; i < count; i++) {
            const rawValue = dropdownEls[i].dataset.selectedValue;
            selected.push((rawValue === undefined || rawValue === null || rawValue === '') ? -1 : parseInt(rawValue, 10));
        }
        earnedPoints += scoreDropdownQuestion(qData, selected);
        if (!showCorrection) return;
        for (let i = 0; i < count; i++) {
            const dropdown = dropdownEls[i];
            const ddData = ddDataList[i];
            const rawValue = dropdown.dataset.selectedValue;
            const isEmpty = (rawValue === undefined || rawValue === null || rawValue === '');
            const selectedIndex = isEmpty ? -1 : parseInt(rawValue, 10);
            const correctIndex = ddData.correct_index;
            const allOptions = ddData.options || [];
            const correctOption = allOptions[correctIndex] || '';
            const isCorrect = !isEmpty && (selectedIndex === correctIndex);
            const next = dropdown.nextSibling;
            if (next && next.classList?.contains('mkq-dropdown-correction-wrapper') && next.dataset?.forId === dropdown.id) next.remove();
            if (isCorrect) {
                dropdown.style.display = ''; dropdown.classList.remove('incorrect'); dropdown.classList.add('correct');
            } else {
                let wrongAnswerHTML = isEmpty ? t("ui.empty_answer", "(empty)")
                    : (allOptions[selectedIndex] ? convertLatexDelimiters(allOptions[selectedIndex]) : t("ui.empty_answer", "(empty)"));
                dropdown.style.display = 'none';
                const wrapper = document.createElement('span');
                wrapper.className = 'mkq-dropdown-correction-wrapper';
                wrapper.dataset.forId = dropdown.id;
                wrapper.style.cssText = 'display:inline-flex;align-items:center;gap:.5em;position:relative;';
                const wrongLabel = document.createElement('span');
                wrongLabel.className = 'mkq-gap-wrong-label'; wrongLabel.innerHTML = wrongAnswerHTML;
                wrapper.appendChild(wrongLabel);
                const correctDropdown = document.createElement('div');
                correctDropdown.className = 'mkq-custom-dropdown correct';
                correctDropdown.style.cssText = 'display:inline-block;pointer-events:none;';
                const correctBtn = document.createElement('button');
                correctBtn.type = 'button'; correctBtn.className = 'mkq-custom-dropdown-btn correct'; correctBtn.style.cursor = 'default';
                const correctValueSpan = document.createElement('span');
                correctValueSpan.className = 'mkq-custom-dropdown-value';
                correctValueSpan.innerHTML = convertLatexDelimiters(correctOption);
                const arrow = document.createElement('span');
                arrow.className = 'mkq-custom-dropdown-arrow'; arrow.textContent = '✓'; arrow.style.color = 'green';
                correctBtn.appendChild(correctValueSpan); correctBtn.appendChild(arrow);
                correctDropdown.appendChild(correctBtn); wrapper.appendChild(correctDropdown);
                dropdown.after(wrapper);
                setTimeout(() => { if (window.MathJax?.typesetPromise) MathJax.typesetPromise([wrapper]).catch(() => {}); }, 150);
            }
        }
    });
    displayScorePoints(quizId, earnedPoints, totalPoints);
}

// ─────────────────────────────────────────────────────────────────────────────
// Dropdown interactions
// ─────────────────────────────────────────────────────────────────────────────

function toggleDropdownQuiz(button) {
    const dropdown = button.closest('.mkq-custom-dropdown');
    const options = dropdown.querySelector('.mkq-custom-dropdown-options');
    const isOpen = options.style.display === 'block';
    document.querySelectorAll('.mkq-custom-dropdown-options').forEach(opt => opt.style.display = 'none');
    options.style.display = isOpen ? 'none' : 'block';
}

function selectDropdownQuizOption(optionElement) {
    const dropdown = optionElement.closest('.mkq-custom-dropdown');
    const button = dropdown.querySelector('.mkq-custom-dropdown-btn');
    const valueSpan = button.querySelector('.mkq-custom-dropdown-value');
    const optionsDiv = dropdown.querySelector('.mkq-custom-dropdown-options');
    valueSpan.innerHTML = optionElement.innerHTML;
    dropdown.querySelectorAll('.mkq-custom-dropdown-option').forEach(opt => opt.classList.remove('selected'));
    optionElement.classList.add('selected');
    dropdown.dataset.selectedValue = optionElement.dataset.value;
    optionsDiv.style.display = 'none';
    if (window.MathJax?.typesetPromise) MathJax.typesetPromise([valueSpan]).catch(() => {});
}

document.addEventListener('click', (e) => {
    if (!e.target.closest('.mkq-custom-dropdown'))
        document.querySelectorAll('.mkq-custom-dropdown-options').forEach(opt => opt.style.display = 'none');
});

// ─────────────────────────────────────────────────────────────────────────────
// Gapfill correction dropdown helpers
// ─────────────────────────────────────────────────────────────────────────────

function convertLatexDelimiters(text) {
    let result = text;
    result = result.replace(/\$\$(.*?)\$\$/g, '\\[$1\\]');
    result = result.replace(/\$([^\$]+)\$/g, '\\($1\\)');
    return result;
}

function createGapfillMathJaxDropdown(id, answers) {
    const container = document.createElement('div');
    container.className = 'mkq-custom-select'; container.id = id;
    container.setAttribute('role', 'combobox'); container.setAttribute('aria-haspopup', 'listbox');
    container.setAttribute('aria-expanded', 'false');
    const button = document.createElement('button');
    button.className = 'mkq-custom-select-btn'; button.type = 'button';
    button.setAttribute('aria-controls', `${id}-listbox`);
    const valueSpan = document.createElement('span');
    valueSpan.className = 'mkq-custom-select-value';
    valueSpan.innerHTML = convertLatexDelimiters(answers[0]);
    button.appendChild(valueSpan);
    const arrow = document.createElement('span');
    arrow.className = 'mkq-custom-select-arrow'; arrow.textContent = '▾'; arrow.setAttribute('aria-hidden', 'true');
    const listbox = document.createElement('div');
    listbox.className = 'mkq-custom-select-listbox'; listbox.id = `${id}-listbox`;
    listbox.setAttribute('role', 'listbox'); listbox.setAttribute('tabindex', '-1');
    answers.forEach((answer, index) => {
        const option = document.createElement('div');
        option.className = 'mkq-custom-select-option'; option.setAttribute('role', 'option');
        option.setAttribute('tabindex', index === 0 ? '0' : '-1');
        option.setAttribute('aria-selected', index === 0 ? 'true' : 'false');
        option.dataset.value = answer; option.innerHTML = convertLatexDelimiters(answer);
        option.addEventListener('click', () => selectGapfillOption(container, button, valueSpan, listbox, option));
        option.addEventListener('keydown', (e) => {
            if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); selectGapfillOption(container, button, valueSpan, listbox, option); }
        });
        listbox.appendChild(option);
    });
    button.addEventListener('click', () => toggleGapfillDropdown(container, listbox));
    listbox.addEventListener('keydown', (e) => handleGapfillKeyboardNav(e, container, listbox));
    container.appendChild(button); container.appendChild(arrow); container.appendChild(listbox);
    document.addEventListener('click', (e) => { if (!container.contains(e.target)) container.setAttribute('aria-expanded', 'false'); });
    setTimeout(() => { if (window.MathJax?.typesetPromise) MathJax.typesetPromise([container]).catch(() => {}); }, 50);
    return container;
}

function toggleGapfillDropdown(container, listbox) {
    const isOpen = container.getAttribute('aria-expanded') === 'true';
    container.setAttribute('aria-expanded', !isOpen ? 'true' : 'false');
    if (!isOpen) listbox.focus();
}

function selectGapfillOption(container, button, valueSpan, listbox, option) {
    listbox.querySelectorAll('.mkq-custom-select-option').forEach(opt => opt.setAttribute('aria-selected', 'false'));
    option.setAttribute('aria-selected', 'true');
    valueSpan.innerHTML = option.innerHTML;
    if (valueSpan.innerHTML.includes('\\(') || valueSpan.innerHTML.includes('\\[')) {
        if (window.MathJax?.typesetPromise) MathJax.typesetPromise([button]).catch(() => {});
    }
    container.setAttribute('aria-expanded', 'false'); button.focus();
}

function handleGapfillKeyboardNav(e, container, listbox) {
    const options = Array.from(listbox.querySelectorAll('.mkq-custom-select-option'));
    const current = document.activeElement.classList.contains('mkq-custom-select-option') ? document.activeElement : options[0];
    let idx = options.indexOf(current);
    if (e.key === 'Escape') { e.preventDefault(); container.setAttribute('aria-expanded', 'false'); container.querySelector('.mkq-custom-select-btn').focus(); }
    if (e.key === 'ArrowDown') { e.preventDefault(); options[Math.min(idx + 1, options.length - 1)].focus(); }
    if (e.key === 'ArrowUp') { e.preventDefault(); options[Math.max(idx - 1, 0)].focus(); }
}

// ─────────────────────────────────────────────────────────────────────────────
// Display score
// ─────────────────────────────────────────────────────────────────────────────

function displayScorePoints(quizId, earned, total) {
    const scoreElement = document.getElementById(`score-${quizId}`);
    if (!scoreElement) return;
    const e = Number(earned), ttot = Number(total) > 0 ? Number(total) : 0;
    const pct = ttot > 0 ? (e / ttot) * 100 : 0;
    scoreElement.textContent = `${t("ui.score_label", "Score")}: ${e.toFixed(2)}/${ttot.toFixed(2)} (${pct.toFixed(1)}%)`;
    scoreElement.style.display = 'block';
    scoreElement.classList.remove('good', 'medium', 'bad');
    if (pct >= 75) scoreElement.classList.add('good');
    else if (pct >= 50) scoreElement.classList.add('medium');
    else scoreElement.classList.add('bad');
}

// ─────────────────────────────────────────────────────────────────────────────
// Crypto / storage
// ─────────────────────────────────────────────────────────────────────────────

function decryptAnswers(encryptedData) {
    try {
        const key = window.QUIZ_CONFIG.encryption_key || 'default-key-change-me';
        const encrypted = atob(encryptedData);
        const keyBytes = new TextEncoder().encode(key);
        const encryptedBytes = new Uint8Array(encrypted.split('').map(c => c.charCodeAt(0)));
        const decrypted = new Uint8Array(encryptedBytes.length);
        for (let i = 0; i < encryptedBytes.length; i++) decrypted[i] = encryptedBytes[i] ^ keyBytes[i % keyBytes.length];
        return JSON.parse(new TextDecoder().decode(decrypted));
    } catch (e) {
        console.error(t("ui.error_decrypting", "Decrypting Error"), e);
        return null;
    }
}

function saveAnswers(quizId) {
    const quiz = document.querySelector(`[data-quiz-id="${quizId}"]`);
    if (!quiz) return;
    const answers = {};
    quiz.querySelectorAll('input[type="checkbox"]:checked, input[type="radio"]:checked').forEach(input => { answers[input.id] = true; });
    quiz.querySelectorAll('.mkq-gap-input').forEach(input => { if (input.value.trim() !== '') answers[input.id] = input.value; });
    quiz.querySelectorAll('.mkq-custom-dropdown').forEach(dropdown => { if (dropdown.dataset.selectedValue) answers[dropdown.id] = dropdown.dataset.selectedValue; });
    if (Object.keys(answers).length > 0) localStorage.setItem(`mkq_answers_${quizId}`, JSON.stringify(answers));
    else localStorage.removeItem(`mkq_answers_${quizId}`);
}

function loadSavedAnswers() {
    document.querySelectorAll('.mkdocs-superquiz').forEach(quiz => {
        const quizId = quiz.dataset.quizId;
        try {
            const savedAnswersJson = localStorage.getItem(`mkq_answers_${quizId}`);
            if (!savedAnswersJson) return;
            const savedAnswers = JSON.parse(savedAnswersJson);
            if (!savedAnswers || typeof savedAnswers !== 'object') { localStorage.removeItem(`mkq_answers_${quizId}`); return; }
            Object.keys(savedAnswers).forEach(inputId => {
                const input = document.getElementById(inputId);
                if (!input) return;
                const savedValue = savedAnswers[inputId];
                if (input.type === 'checkbox' || input.type === 'radio') { if (typeof savedValue === 'boolean') input.checked = savedValue; }
                else if (input.classList.contains('mkq-gap-input')) input.value = String(savedValue);
                else if (input.classList.contains('mkq-custom-dropdown')) {
                    input.dataset.selectedValue = savedValue;
                    const valueSpan = input.querySelector('.mkq-custom-dropdown-value');
                    const selectedOption = input.querySelector(`[data-value="${savedValue}"]`);
                    if (valueSpan && selectedOption) valueSpan.innerHTML = selectedOption.innerHTML;
                }
            });
        } catch (error) { localStorage.removeItem(`mkq_answers_${quizId}`); }
    });
}

function refreshAllQuizzes() {
    const quizzes = document.querySelectorAll('.mkdocs-superquiz');
    if (quizzes.length === 0) return;
    const pageUuid = quizzes[0]?.dataset.pageUuid;
    quizzes.forEach(quiz => {
        const quizId = quiz.dataset.quizId;
        const quizType = quiz.dataset.quizType;
        if (quizType === 'gapfill') {
            quiz.querySelectorAll('.mkq-gap-correction-wrapper').forEach(w => w.remove());
            quiz.querySelectorAll('.mkq-gap-input').forEach(input => { input.value = ''; input.style.display = ''; input.classList.remove('correct', 'incorrect'); });
        } else if (quizType === 'dropdown') {
            quiz.querySelectorAll('.mkq-dropdown-correction-wrapper').forEach(w => w.remove());
            quiz.querySelectorAll('.mkq-custom-dropdown').forEach(dropdown => {
                dropdown.style.display = ''; dropdown.dataset.selectedValue = '';
                const valueSpan = dropdown.querySelector('.mkq-custom-dropdown-value');
                if (valueSpan) valueSpan.textContent = '--';
                dropdown.querySelectorAll('.mkq-custom-dropdown-option').forEach(opt => opt.classList.remove('selected'));
                dropdown.classList.remove('correct', 'incorrect');
            });
        } else {
            quiz.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(input => { input.checked = false; });
        }
        quiz.querySelectorAll('.mkq-answer').forEach(answer => {
            answer.classList.remove('correct', 'incorrect');
            const feedback = answer.querySelector('.mkq-answer-feedback');
            if (feedback) { feedback.style.display = 'none'; feedback.textContent = ''; feedback.classList.remove('correct', 'incorrect'); }
        });
        const scoreElement = document.getElementById(`score-${quizId}`);
        if (scoreElement) { scoreElement.style.display = 'none'; scoreElement.textContent = ''; scoreElement.classList.remove('good', 'medium', 'bad'); }
        const lockBtn = quiz.querySelector('.mkq-unlock-btn, .mkq-lock-indicator');
        if (lockBtn && !lockBtn.classList.contains('unlocked')) {
            if (lockBtn.getAttribute('data-lock-state') === 'locked') updateLockIcon(lockBtn, false);
        }
        localStorage.removeItem(`mkq_answers_${quizId}`);
    });
    if (pageUuid) {
        const unlocks = JSON.parse(localStorage.getItem('mkq_unlocks') || '[]');
        localStorage.setItem('mkq_unlocks', JSON.stringify(unlocks.filter(u => u.page_id !== pageUuid)));
    }
    showRefreshNotification();
}

function showRefreshNotification() {
    const notification = document.createElement('div');
    notification.textContent = `✅ ${t("ui.all_quizzes_have_been_reset", "All Quizzes have been reset")}`;
    notification.style.cssText = 'position:fixed;top:20px;right:20px;background:#4caf50;color:white;padding:1rem 1.5rem;border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,0.15);z-index:10000;font-weight:500;font-size:2em;animation:slideIn 0.3s ease-out;';
    document.body.appendChild(notification);
    setTimeout(() => {
        notification.style.opacity = '0'; notification.style.transition = 'opacity 0.3s';
        setTimeout(() => notification.remove(), 300);
    }, 2000);
}

function addRefreshButton() {
    const pageTitle = document.querySelector('.md-content h1');
    if (!pageTitle) return;
    const quizzes = document.querySelectorAll('.mkdocs-superquiz');
    if (quizzes.length === 0) return;
    const refreshBtn = document.createElement('button');
    refreshBtn.className = 'mkq-refresh-page-btn'; refreshBtn.title = t("ui.reset_all_quizzes", "Reset all quizzes");
    refreshBtn.innerHTML = `<span class="mkq-btn-icon">🔄</span><span class="mkq-btn-text">${t("ui.reset_all_quizzes", "Reset all quizzes")}</span>`;
    refreshBtn.addEventListener('click', () => refreshAllQuizzes());
    const unlockPageBtn = document.createElement('button');
    unlockPageBtn.className = 'mkq-unlock-page-btn'; unlockPageBtn.title = t("ui.unlock_all_page_quizzes", "Unlock all page quizzes");
    unlockPageBtn.innerHTML = `<span class="mkq-btn-icon">🔓</span><span class="mkq-btn-text">${t("ui.unlock_all_page_quizzes", "Unlock all page quizzes")}</span>`;
    unlockPageBtn.addEventListener('click', () => showUnlockModal('page'));
    const buttonsContainer = document.createElement('div');
    buttonsContainer.className = 'mkq-page-buttons';
    buttonsContainer.appendChild(unlockPageBtn); buttonsContainer.appendChild(refreshBtn);
    pageTitle.appendChild(buttonsContainer);
}

function clearAllQuizData() {
    Object.keys(localStorage).filter(key => key.startsWith('mkq_')).forEach(key => localStorage.removeItem(key));
    setTimeout(() => location.reload(), 1000);
}
window.clearAllQuizData = clearAllQuizData;

function initQuizPlugin() {
    if (!window.QUIZ_CONFIG || !window.QUIZ_CONFIG.i18n) return;
    createUnlockModal();
    restoreUnlockedCorrections();
    loadSavedAnswers();
    addRefreshButton();
}

if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initQuizPlugin);
else initQuizPlugin();