document.addEventListener("DOMContentLoaded", function () {
    const form = document.getElementById("upload-form");
    const uploadStatus = document.getElementById("upload-status");

    const questionListContainer = document.getElementById("question-list-container");
    const selectAllBtn = document.getElementById("select-all-btn");
    const clearSelectionBtn = document.getElementById("clear-selection-btn");
    const selectionCount = document.getElementById("selection-count");

    const startVariantGenerationBtn = document.getElementById("start-variant-generation-btn");
    const variantGenerationStatus = document.getElementById("variant-generation-status");

    const sourceCounter = document.getElementById("source-counter");
    const prevSourceBtn = document.getElementById("prev-source-btn");
    const nextSourceBtn = document.getElementById("next-source-btn");
    const sourceCounterOriginal = document.getElementById("source-counter-original");
    const prevSourceBtnOriginal = document.getElementById("prev-source-btn-original");
    const nextSourceBtnOriginal = document.getElementById("next-source-btn-original");
    const jumpSelect = document.getElementById("jump-select");

    const currentIncludeCheckbox = document.getElementById("current-include-checkbox");
    const includeQuestionWrapper = document.getElementById("include-question-wrapper");
    const originalIncludeToolsRow = document.getElementById("original-include-tools-row");

    const originalQuestionBody = document.getElementById("original-question-body");
    const generatedQuestionBody = document.getElementById("generated-question-body");
    const nextDraftBtn = document.getElementById("next-draft-btn");

    const openExportModalBtn = document.getElementById("open-export-modal-btn");
    const exportModal = document.getElementById("export-modal-overlay");
    const closeExportModalBtn = document.getElementById("export-modal-close");
    const exportOptions = document.querySelectorAll(".export-option");
    const clearWorkspaceBtn = document.getElementById("clear-workspace-btn");

    const editPanel = document.getElementById("edit-panel");
    const editPanelWrapper = document.getElementById("edit-panel-wrapper");
    const closeEditPanelBtn = document.getElementById("close-edit-panel");
    const modalOverlay = document.getElementById("app-modal-overlay");
    const modalTitle = document.getElementById("app-modal-title");
    const modalMessage = document.getElementById("app-modal-message");
    const modalClose = document.getElementById("app-modal-close");
    const modalCancel = document.getElementById("app-modal-cancel");
    const modalConfirm = document.getElementById("app-modal-confirm");
    const modalOk = document.getElementById("app-modal-ok");
    let modalConfirmAction = null;
    let modalOkAction = null;

    const instructionsPanel = document.getElementById("instructions-panel");
    const originalPanel = document.getElementById("original-question-panel");
    const generatedPanel = document.getElementById("generated-question-panel");
    const variantAiReviewCard = document.getElementById("variant-ai-review-card");
    const variantAiReviewPanel = document.getElementById("variant-ai-review-panel");
    const variantAiReviewColumnNote = document.getElementById("variant-ai-review-column-note");

    const VARIANT_OPTIONAL_FINGERPRINT_FIELDS = [
        "title",
        "stem",
        "lead_in",
        "option_a",
        "option_b",
        "option_c",
        "option_d",
        "option_e",
        "correct_answer_letter",
        "correct_answer",
        "justification"
    ];

    const VARIANT_EDIT_PANEL_FIELD_IDS = {
        title: "variant-edit-title",
        stem: "variant-edit-stem",
        lead_in: "variant-edit-lead-in",
        option_a: "variant-edit-option-a",
        option_b: "variant-edit-option-b",
        option_c: "variant-edit-option-c",
        option_d: "variant-edit-option-d",
        option_e: "variant-edit-option-e",
        correct_answer_letter: "variant-edit-correct-letter",
        justification: "variant-edit-justification"
    };

    const variantOptionalReviewRequestsInFlight = new Set();

    let uploadedQuestionDetails = [];
    let reviewQuestions = [];
    let selectedRows = new Set();
    let generatedVariantsByRow = {};
    let currentFilter = "All";
    let currentIndex = 0;

    let generationStarted = false;
    let generationInProgress = false;
    let currentEditRowNumber = null;

    const VARIANT_SOURCE_TOOL = "variant_generator";
    const VARIANT_STATE_STORAGE_KEY = "mla_variant_batch_state";
    const VARIANT_STATE_LEGACY_KEYS = ["variant_generator_state_v2", "variant_generator_state_v1"];

    function migrateVariantLocalStorageKeys() {
        if (localStorage.getItem(VARIANT_STATE_STORAGE_KEY)) {
            return;
        }
        for (let i = 0; i < VARIANT_STATE_LEGACY_KEYS.length; i++) {
            const legacyKey = VARIANT_STATE_LEGACY_KEYS[i];
            const legacyRaw = localStorage.getItem(legacyKey);
            if (!legacyRaw) {
                continue;
            }
            try {
                const legacyState = JSON.parse(legacyRaw);
                if (legacyState && typeof legacyState === "object") {
                    legacyState.source_tool = VARIANT_SOURCE_TOOL;
                    localStorage.setItem(VARIANT_STATE_STORAGE_KEY, JSON.stringify(legacyState));
                }
            } catch (error) {
                console.error("Could not migrate legacy variant page state.", error);
            }
            return;
        }
    }

    function sanitizeVariantRecord(variant) {
        if (!variant || typeof variant !== "object") {
            return null;
        }
        if (String(variant.source_type || "").toLowerCase() === "variant") {
            return { ...variant, source_tool: VARIANT_SOURCE_TOOL };
        }
        if (String(variant.source_tool || "").toLowerCase() === VARIANT_SOURCE_TOOL) {
            return { ...variant, source_type: variant.source_type || "variant", source_tool: VARIANT_SOURCE_TOOL };
        }
        return null;
    }

    function sanitizeGeneratedVariantsByRow(byRow) {
        const input = byRow && typeof byRow === "object" ? byRow : {};
        const sanitized = {};
        Object.keys(input).forEach(function (rowKey) {
            const variant = sanitizeVariantRecord(input[rowKey]);
            if (variant) {
                sanitized[rowKey] = variant;
            }
        });
        return sanitized;
    }

    function ensureWorkspace() {
        let workspaceId = localStorage.getItem("workspace_id");

        if (workspaceId) {
            return Promise.resolve(workspaceId);
        }

        return fetch("../app/api/create_workspace.php")
            .then(res => res.text())
            .then(text => {
                const match = text.match(/Workspace created:\s*(\w+)/);

                if (!match) {
                    throw new Error("Could not create workspace");
                }

                const newId = match[1];
                localStorage.setItem("workspace_id", newId);
                return newId;
            });
    }

    function clearWorkspaceOnServer() {
        const workspaceId = localStorage.getItem("workspace_id");

        if (!workspaceId) {
            return Promise.resolve();
        }

        return fetch("../app/api/clear_workspace_questions.php", {
            method: "POST",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            body: new URLSearchParams({
                workspace_id: workspaceId
            })
        }).then(res => res.text());
    }

    function resetWorkspace() {
        return fetch("../app/api/create_workspace.php")
            .then(res => res.text())
            .then(text => {
                const match = text.match(/Workspace created:\s*(\w+)/);

                if (!match) {
                    throw new Error("Could not reset workspace");
                }

                const newId = match[1];
                localStorage.setItem("workspace_id", newId);
                return newId;
            });
    }

    function escapeHtml(value) {
        if (value === null || value === undefined) {
            return "";
        }

        return String(value)
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;")
            .replace(/'/g, "&#039;");
    }

    function getQuestionTitle(question) {
        if (!question || !question.data) {
            return "(Untitled question)";
        }
        return question.data["Question title"] || "(Untitled question)";
    }

    function formatJumpOptionLabel(question, displayIndex) {
        const fullTitle = String(getQuestionTitle(question) || "Untitled question").trim() || "Untitled question";
        return `Q${displayIndex} · ${fullTitle}`;
    }

    function statusChip(label, value, tone) {
        const toneClass = tone ? ` question-status-chip--${tone}` : "";
        const labelPart =
            label && String(label).trim() !== ""
                ? `<span class="question-status-chip-label">${escapeHtml(label)}:</span> `
                : "";
        return `<span class="question-status-chip${toneClass}">${labelPart}${escapeHtml(value)}</span>`;
    }

    function getVariantDraftStatusLabel(variant) {
        const status = String((variant && variant.status) || "Draft");
        if (status === "Rejected") {
            return { value: "Rejected", tone: "danger" };
        }
        if (status === "Done") {
            return { value: "Approved", tone: "success" };
        }
        return { value: "Draft", tone: "neutral" };
    }

    function getSourceAnswerFromData(data, letter) {
        if (!data) {
            return "";
        }
        return (
            data["Option " + letter] ||
            data["Answer " + letter] ||
            data["Answer " + letter + " text"] ||
            data["Answer " + letter + " option"] ||
            data["Option " + letter + " text"] ||
            data["Distractor " + letter] ||
            ""
        );
    }

    function renderSourceQuestionMetadata(question) {
        const data = (question && question.data) || {};
        const parts = [
            data["Skill"] ? `Skill: ${data["Skill"]}` : "",
            data["Specialty"] ? `Specialty: ${data["Specialty"]}` : "",
            data["Core condition"] ? `Condition: ${data["Core condition"]}` : "",
            data["Presentation"] ? `Presentation: ${data["Presentation"]}` : ""
        ].filter(Boolean);

        if (parts.length === 0) {
            return "";
        }

        const items = parts
            .map(part => `<span class="question-meta-item">${escapeHtml(part)}</span>`)
            .join("");
        return `<div class="question-card-meta" role="group" aria-label="Question metadata">${items}</div>`;
    }

    function renderVariantQuestionMetadata(variant) {
        if (!variant) {
            return "";
        }

        const parts = [];
        const tags = buildTagsString(variant);
        if (tags) {
            parts.push(`Tags: ${tags}`);
        }
        if (variant.year_level) {
            parts.push(`Year: ${variant.year_level}`);
        }

        if (parts.length === 0) {
            return "";
        }

        const items = parts
            .map(part => `<span class="question-meta-item">${escapeHtml(part)}</span>`)
            .join("");
        return `<div class="question-card-meta" role="group" aria-label="Question metadata">${items}</div>`;
    }

    function renderVariantQuestionStatusBar(variant) {
        const mainStatus = getVariantDraftStatusLabel(variant);
        return `<div class="question-status-bar" role="status" aria-label="Question status">
            ${statusChip("", mainStatus.value, mainStatus.tone)}
        </div>`;
    }

    function updateFilterButtons() {
        const buttons = document.querySelectorAll(".filter-btn");
        const statusFiltersDisabled = reviewQuestions.length === 0 || !generationStarted;

        buttons.forEach(button => {
            const filterValue = button.getAttribute("data-filter");
            button.disabled = statusFiltersDisabled;

            if (filterValue === currentFilter) {
                button.classList.add("active-filter");
            } else {
                button.classList.remove("active-filter");
            }
        });
    }

    function updateVariantFilterChrome() {
        const hasUploaded = uploadedQuestionDetails.length > 0;
        const filteredCount = getFilteredReviewQuestions().length;
        const multiFiltered = filteredCount > 1;

        const questionListEmpty = document.getElementById("question-list-empty");
        const questionListControls = document.getElementById("question-list-controls");
        const jumpContainer = document.getElementById("jump-container");
        const selectionControls = document.getElementById("variant-selection-controls");

        if (questionListEmpty) {
            questionListEmpty.classList.toggle("hidden", hasUploaded);
        }
        if (questionListControls) {
            questionListControls.classList.toggle("hidden", !hasUploaded);
            questionListControls.setAttribute("aria-hidden", !hasUploaded ? "true" : "false");
        }
        if (jumpContainer) {
            jumpContainer.classList.toggle("hidden", !multiFiltered);
        }
        if (selectionControls) {
            selectionControls.classList.toggle("hidden", generationStarted);
        }

        updateFilterButtons();
    }

    function applyFilter() {
        currentIndex = 0;
        updateVariantFilterChrome();
        renderCurrentReview();
        saveVariantPageState();
    }

    function findSourceQuestionByRow(rowNumber) {
        return uploadedQuestionDetails.find(item => Number(item.row_number) === Number(rowNumber)) || null;
    }

    function getFilteredReviewQuestions() {
        if (currentFilter === "All") {
            return reviewQuestions;
        }

        return reviewQuestions.filter(question => {
            const rowNumber = Number(question.row_number);
            const variant = generatedVariantsByRow[rowNumber];

            if (!variant) {
                return false;
            }

            const status = String(variant.status || "Draft");
            return status === currentFilter;
        });
    }

    function getCurrentQuestion() {
        const filteredQuestions = getFilteredReviewQuestions();
        return filteredQuestions[currentIndex] || null;
    }

    function openEditPanel() {
        if (!editPanelWrapper) return;
        editPanelWrapper.classList.add("open");
        document.body.classList.add("edit-panel-open");
    }

    function closeEditPanel() {
        if (!editPanelWrapper || !editPanel) return;
        editPanelWrapper.classList.remove("open");
        document.body.classList.remove("edit-panel-open");
        editPanel.innerHTML = "";
        currentEditRowNumber = null;
    }

    function setVariantEditSaveStatus(message, stateClass) {
        const statusEl = document.getElementById("variant-edit-save-status");
        if (!statusEl) {
            return;
        }
        statusEl.textContent = message;
        statusEl.className = "autosave-status " + (stateClass || "");
    }

    function openPanel(panel) {
        if (!panel) return;
        panel.classList.add("open");
    }

    function closePanel(panel) {
        if (!panel) return;
        panel.classList.remove("open");
    }

    function setDefaultPanelState() {
        openPanel(instructionsPanel);
        closePanel(originalPanel);
        closePanel(generatedPanel);
    }

    function expandOriginalPanelAfterUpload() {
        openPanel(originalPanel);
    }

    function focusGeneratedPanelAfterStart() {
        closePanel(instructionsPanel);
        closePanel(originalPanel);
        openPanel(generatedPanel);
    }

    function setUploadStatus(html) {
        if (uploadStatus) {
            uploadStatus.innerHTML = html;
        }
    }

    function renderVariantPipelineStatusHtml(stage, message) {
        const stageClass = {
            generating: "variant-pipeline-status--generating",
            repairing: "variant-pipeline-status--repairing",
            complete: "variant-pipeline-status--complete",
            warning: "variant-pipeline-status--warning"
        }[stage];

        if (!stageClass) {
            return "";
        }

        let iconHtml = "";
        if (stage === "generating" || stage === "repairing") {
            iconHtml =
                '<span class="variant-pipeline-status__icon" aria-hidden="true"><span class="progress-spinner progress-spinner--small"></span></span>';
        } else if (stage === "complete") {
            iconHtml =
                '<span class="variant-pipeline-status__icon" aria-hidden="true"><svg class="variant-pipeline-status__check-icon" width="14" height="14" viewBox="0 0 24 24" focusable="false"><path fill="currentColor" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg></span>';
        }

        const liveAttr = stage === "generating" || stage === "repairing" ? ' aria-live="polite"' : "";

        return `<p class="variant-pipeline-status ${stageClass}" role="status"${liveAttr}>${iconHtml}<span class="variant-pipeline-status__text">${escapeHtml(
            message
        )}</span></p>`;
    }

    function setGenerationIdle(message) {
        if (!variantGenerationStatus) return;
        variantGenerationStatus.innerHTML = `<p class="variant-generation-idle-msg">${escapeHtml(message)}</p>`;
    }

    function setGenerationWorking(title, detail) {
        if (!variantGenerationStatus) return;
        const message = detail ? `${title}. ${detail}` : title;
        variantGenerationStatus.innerHTML = renderVariantPipelineStatusHtml("generating", message);
    }

    function setGenerationSuccess(title, detail) {
        if (!variantGenerationStatus) return;
        const message = detail ? `${title} ${detail}` : title;
        variantGenerationStatus.innerHTML = renderVariantPipelineStatusHtml("complete", message);
    }

    function setGenerationError(message, rawText = "") {
        if (!variantGenerationStatus) return;
        variantGenerationStatus.innerHTML = `
            <div class="variant-error-status">
                <strong>${escapeHtml(message)}</strong>
                ${rawText ? `<pre class="variant-debug-pre">${escapeHtml(rawText)}</pre>` : ""}
            </div>
        `;
    }

    function showInfoModal(title, message) {
        if (!modalOverlay || !modalTitle || !modalMessage || !modalOk || !modalCancel || !modalConfirm) {
            alert(message);
            return;
        }

        modalOkAction = null;
        modalTitle.textContent = title;
        modalMessage.textContent = message;

        modalCancel.classList.add("hidden");
        modalConfirm.classList.add("hidden");
        modalOk.classList.remove("hidden");

        modalOverlay.classList.remove("hidden");
    }

    function closeModal() {
        if (!modalOverlay) return;
        modalOverlay.classList.add("hidden");
        modalConfirmAction = null;
        modalOkAction = null;
        if (modalOk) {
            modalOk.textContent = "OK";
        }
        if (modalConfirm) {
            modalConfirm.textContent = "Confirm";
        }
    }

    function getInfoContent(type) {
        if (type === "upload") {
            return {
                title: "Upload Source File",
                message: "Upload a RISR .xlsx file to load source questions for review and variant generation."
            };
        }

        if (type === "export-ready") {
            return {
                title: "Export Ready",
                message: "This list shows generated variants marked Done. Use Export to download them."
            };
        }

        if (type === "instructions") {
            return {
                title: "Instructions",
                message: "Upload a source file, choose the questions you want to include, run generation, then review each generated variant."
            };
        }

        if (type === "filter") {
            return {
                title: "Filter Questions",
                message: "Use All and Clear to manage source-question selection, then use Jump to move to a specific source question."
            };
        }

        if (type === "original") {
            return {
                title: "Original Question",
                message: "This panel shows the current source question being reviewed before or during variant generation."
            };
        }

        if (type === "generated") {
            return {
                title: "Generated Question",
                message: "This panel shows the generated variant for the current source question, including actions to edit, regenerate, reject, or mark done."
            };
        }

        return {
            title: "Information",
            message: "No additional information is available for this section."
        };
    }

    function showConfirmModal(title, message, onConfirm) {
        if (!modalOverlay || !modalTitle || !modalMessage || !modalOk || !modalCancel || !modalConfirm) {
            if (confirm(message)) {
                onConfirm();
            }
            return;
        }

        modalOkAction = null;
        modalTitle.textContent = title;
        modalMessage.textContent = message;

        modalOk.classList.add("hidden");
        modalCancel.classList.remove("hidden");
        modalConfirm.classList.remove("hidden");
        modalConfirmAction = onConfirm;

        modalOverlay.classList.remove("hidden");
    }

    function clearExportPanelError() {
        const el = document.getElementById("export-panel-error");
        if (!el) {
            return;
        }
        el.textContent = "";
        el.classList.add("hidden");
    }

    function showExportPanelError(message) {
        const el = document.getElementById("export-panel-error");
        if (el) {
            el.textContent = message;
            el.classList.remove("hidden");
        }
        showInfoModal("Export failed", message);
    }

    function openExportModal() {
        if (!exportModal) {
            return;
        }
        clearExportPanelError();
        exportModal.classList.remove("hidden");
    }

    function closeExportModal() {
        if (!exportModal) {
            return;
        }
        exportModal.classList.add("hidden");
    }

    function formatDateTimeForHeader() {
        const now = new Date();
        return now.toLocaleString("en-GB", {
            day: "2-digit",
            month: "2-digit",
            year: "numeric",
            hour: "2-digit",
            minute: "2-digit"
        });
    }

    function getExportReadyItems() {
        return Object.values(generatedVariantsByRow).filter(variant => (variant.status || "Draft") === "Done");
    }

    function getVariantExportCounts() {
        const all = Object.values(generatedVariantsByRow);
        return {
            total: all.length,
            draft: all.filter(function (variant) {
                return (variant.status || "Draft") === "Draft";
            }).length,
            done: all.filter(function (variant) {
                return variant.status === "Done";
            }).length,
            rejected: all.filter(function (variant) {
                return variant.status === "Rejected";
            }).length
        };
    }

    function updateVariantExportReadinessPanel() {
        const counts = getVariantExportCounts();
        const total = counts.total;
        const draft = counts.draft;
        const done = counts.done;
        const rejected = counts.rejected;

        const summaryCompact = document.getElementById("export-summary-compact");
        const readyCompact = document.getElementById("export-ready-compact");
        const exportBtnEl = openExportModalBtn;
        const totalEl = document.getElementById("export-total");
        const draftEl = document.getElementById("export-draft");
        const doneEl = document.getElementById("export-done");
        const rejectedEl = document.getElementById("export-rejected");
        const listEl = document.getElementById("export-ready-items");

        if (summaryCompact) {
            summaryCompact.textContent = `Draft: ${draft} · Approved: ${done} · Rejected: ${rejected}`;
        }
        if (readyCompact) {
            readyCompact.textContent =
                done > 0 ? `Ready for export: ${done}` : "No questions ready for export yet.";
            readyCompact.classList.toggle("sidebar-compact-line--muted", done === 0);
        }
        if (exportBtnEl) {
            exportBtnEl.classList.toggle("hidden", done === 0);
        }

        if (totalEl) {
            totalEl.innerText = "Total: " + total;
        }
        if (draftEl) {
            draftEl.innerText = "Draft: " + draft;
        }
        if (doneEl) {
            doneEl.innerText = "Approved: " + done;
        }
        if (rejectedEl) {
            rejectedEl.innerText = "Rejected: " + rejected;
        }

        if (!listEl) {
            return;
        }

        listEl.innerHTML = "";
        const readyItems = getExportReadyItems();
        if (readyItems.length === 0) {
            listEl.innerHTML = '<li class="export-ready-empty">None</li>';
            return;
        }

        readyItems.forEach(function (item) {
            const li = document.createElement("li");
            li.className = "export-ready-item";
            const titleSpan = document.createElement("span");
            titleSpan.className = "export-ready-title";
            titleSpan.innerText = item.title || "(Untitled question)";
            const removeBtn = document.createElement("button");
            removeBtn.type = "button";
            removeBtn.className = "export-remove-btn btn-quiet btn--small";
            removeBtn.innerText = "Remove";
            removeBtn.title = "Move to Rejected";
            removeBtn.setAttribute("data-question-id", String(item.id));
            removeBtn.addEventListener("click", function () {
                moveVariantDoneToRejected(item.id);
            });
            li.appendChild(titleSpan);
            li.appendChild(removeBtn);
            listEl.appendChild(li);
        });
    }

    function moveVariantDoneToRejected(questionId) {
        showConfirmModal(
            "Move question to Rejected",
            "This will remove the question from the Ready for export list and change its status to Rejected. Continue?",
            function () {
                const matchRow = Object.keys(generatedVariantsByRow).find(function (rowKey) {
                    return String(generatedVariantsByRow[rowKey].id) === String(questionId);
                });

                if (!matchRow) {
                    return;
                }

                fetch("../app/api/update_question_status.php", {
                    method: "POST",
                    body: new URLSearchParams({
                        question_id: questionId,
                        status: "Rejected"
                    })
                })
                    .then(function (response) {
                        return response.json();
                    })
                    .then(function (data) {
                        if (data.status === "success") {
                            generatedVariantsByRow[matchRow].status = "Rejected";
                            updateVariantExportReadinessPanel();
                            renderCurrentReview();
                            saveVariantPageState();
                        } else {
                            showInfoModal("Update failed", data.message || "Error updating question status.");
                        }
                    })
                    .catch(function (error) {
                        console.error(error);
                        showInfoModal("Update failed", "Error updating question status.");
                    });
            }
        );
    }

    function buildTagsString(question) {
        if (!question) return "";
        const parts = [
            question.skill || "",
            question.specialty || "",
            question.condition_name || "",
            question.presentation || ""
        ]
            .map(part => String(part || "").trim())
            .filter(Boolean);

        return parts.join(" | ");
    }

    function saveVariantPageState() {
        try {
            const state = {
                source_tool: VARIANT_SOURCE_TOOL,
                uploadedQuestionDetails: uploadedQuestionDetails,
                reviewQuestions: reviewQuestions,
                selectedRows: Array.from(selectedRows),
                generatedVariantsByRow: sanitizeGeneratedVariantsByRow(generatedVariantsByRow),
                currentFilter: currentFilter,
                currentIndex: currentIndex,
                generationStarted: generationStarted,
                generationInProgress: generationInProgress,
                panelState: {
                    instructionsOpen: instructionsPanel ? instructionsPanel.classList.contains("open") : false,
                    originalOpen: originalPanel ? originalPanel.classList.contains("open") : false,
                    generatedOpen: generatedPanel ? generatedPanel.classList.contains("open") : false
                }
            };

            localStorage.setItem(VARIANT_STATE_STORAGE_KEY, JSON.stringify(state));
        } catch (error) {
            console.error("Error saving variant page state.", error);
        }
    }

    function clearVariantPageState() {
        try {
            localStorage.removeItem(VARIANT_STATE_STORAGE_KEY);
            VARIANT_STATE_LEGACY_KEYS.forEach(function (legacyKey) {
                localStorage.removeItem(legacyKey);
            });
        } catch (error) {
            console.error("Error clearing variant page state.", error);
        }
    }

    function readVariantPageStateRaw() {
        const raw = localStorage.getItem(VARIANT_STATE_STORAGE_KEY);
        if (raw) {
            return raw;
        }
        for (let i = 0; i < VARIANT_STATE_LEGACY_KEYS.length; i++) {
            const legacyRaw = localStorage.getItem(VARIANT_STATE_LEGACY_KEYS[i]);
            if (legacyRaw) {
                return legacyRaw;
            }
        }
        return null;
    }

    function restoreVariantPageState() {
        try {
            migrateVariantLocalStorageKeys();
            const raw = readVariantPageStateRaw();

            if (!raw) {
                return false;
            }

            const state = JSON.parse(raw);

            if (state.source_tool && state.source_tool !== VARIANT_SOURCE_TOOL) {
                clearVariantPageState();
                return false;
            }

            uploadedQuestionDetails = Array.isArray(state.uploadedQuestionDetails) ? state.uploadedQuestionDetails : [];
            reviewQuestions = Array.isArray(state.reviewQuestions) ? state.reviewQuestions : [];
            selectedRows = new Set(Array.isArray(state.selectedRows) ? state.selectedRows.map(Number) : []);
            generatedVariantsByRow = sanitizeGeneratedVariantsByRow(state.generatedVariantsByRow);
            const allowedFilters = ["All", "Draft", "Done", "Rejected"];
            currentFilter = allowedFilters.includes(state.currentFilter) ? state.currentFilter : "All";
            currentIndex = Number.isInteger(state.currentIndex) ? state.currentIndex : 0;
            generationStarted = !!state.generationStarted;
            generationInProgress = false;

            if (reviewQuestions.length === 0 && uploadedQuestionDetails.length > 0) {
                reviewQuestions = [...uploadedQuestionDetails];
            }

            if (uploadedQuestionDetails.length > 0 && selectedRows.size === 0 && !generationStarted) {
                selectedRows = new Set(uploadedQuestionDetails.map(item => Number(item.row_number)));
            }

            if (reviewQuestions.length === 0) {
                currentIndex = 0;
            } else if (currentIndex < 0) {
                currentIndex = 0;
            } else if (currentIndex > reviewQuestions.length - 1) {
                currentIndex = reviewQuestions.length - 1;
            }

            if (state.panelState) {
                if (instructionsPanel) instructionsPanel.classList.toggle("open", !!state.panelState.instructionsOpen);
                if (originalPanel) originalPanel.classList.toggle("open", !!state.panelState.originalOpen);
                if (generatedPanel) generatedPanel.classList.toggle("open", !!state.panelState.generatedOpen);
            } else {
                setDefaultPanelState();
            }

            return uploadedQuestionDetails.length > 0 || reviewQuestions.length > 0 || Object.keys(generatedVariantsByRow).length > 0;
        } catch (error) {
            console.error("Error restoring variant page state.", error);
            clearVariantPageState();
            return false;
        }
    }

    function exportDoneVariantQuestions() {
        const workspaceId = localStorage.getItem("workspace_id");

        if (!workspaceId) {
            showExportPanelError("Export failed: no workspace found.");
            return;
        }

        const readyItems = getExportReadyItems();

        if (readyItems.length === 0) {
            showInfoModal("Nothing to export", "There are no variants marked Done (approved for export) yet.");
            return;
        }

        try {
            const url = `../app/api/export_done_variant_questions.php?workspace_id=${encodeURIComponent(workspaceId)}`;
            const link = document.createElement("a");
            link.href = url;
            link.download = "mla-question-variants-risr.csv";
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            clearExportPanelError();
            showInfoModal("Export complete", "RISR export downloaded successfully.");
        } catch (error) {
            console.error("[variant_export_risr]", error);
            showExportPanelError("RISR export failed. Your variants and approval status are unchanged.");
        }
    }

    function exportVariantsToWord() {
        const doneQuestions = getExportReadyItems();

        if (doneQuestions.length === 0) {
            showInfoModal("Nothing to export", "There are no variants marked Done (approved for export) yet.");
            return;
        }

        try {
            const exportDate = formatDateTimeForHeader();

            let htmlContent = `
            <html>
            <head>
                <meta charset="utf-8">
                <title>MLA Question Variants Export</title>
                <style>
                    body { font-family: Arial, sans-serif; line-height: 1.5; }
                    h1 { color: #010057; }
                    h2 { color: #010057; margin-top: 28px; }
                    p, li { font-size: 12pt; }
                    ul { margin-top: 6px; }
                    .question-block { margin-bottom: 28px; page-break-inside: avoid; }
                    .export-meta { margin-bottom: 22px; }
                </style>
            </head>
            <body>
                <h1>MLA Question Variants Export</h1>
                <div class="export-meta">
                    <p><strong>Exported:</strong> ${escapeHtml(exportDate)}</p>
                    <p><strong>Number of variants exported:</strong> ${doneQuestions.length}</p>
                </div>
        `;

            doneQuestions.forEach(function (q, index) {
                htmlContent += `
                <div class="question-block">
                    <h2>Variant ${index + 1}</h2>
                    <p><strong>Title:</strong> ${escapeHtml(q.title || "")}</p>
                    <p><strong>Tags:</strong> ${escapeHtml(buildTagsString(q))}</p>
                    <p><strong>Stem:</strong> ${escapeHtml(q.stem || "")}</p>
                    <p><strong>Lead-in:</strong> ${escapeHtml(q.lead_in || "")}</p>
                    <ul>
                        <li>A. ${escapeHtml(q.option_a || "")}</li>
                        <li>B. ${escapeHtml(q.option_b || "")}</li>
                        <li>C. ${escapeHtml(q.option_c || "")}</li>
                        <li>D. ${escapeHtml(q.option_d || "")}</li>
                        <li>E. ${escapeHtml(q.option_e || "")}</li>
                    </ul>
                    <p><strong>Correct Answer:</strong> ${escapeHtml(q.correct_answer_letter || "")} - ${escapeHtml(q.correct_answer || "")}</p>
                    <p><strong>Justification:</strong> ${escapeHtml(q.justification || "")}</p>
                </div>
            `;
            });

            htmlContent += `
            </body>
            </html>
        `;

            const blob = new Blob([htmlContent], { type: "application/msword" });
            const url = URL.createObjectURL(blob);
            const link = document.createElement("a");
            link.href = url;
            link.download = "mla-question-variants.doc";
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            URL.revokeObjectURL(url);
            clearExportPanelError();
            showInfoModal("Export complete", "Word export completed successfully.");
        } catch (error) {
            console.error("[variant_export_word]", error);
            showExportPanelError("Word export failed. Your variants and approval status are unchanged.");
        }
    }

    function exportVariantsToMicrosoftForms() {
        const workspaceId = localStorage.getItem("workspace_id");
        const doneQuestions = getExportReadyItems();

        if (!workspaceId) {
            showExportPanelError("Export failed: no workspace found.");
            return;
        }

        if (doneQuestions.length === 0) {
            showInfoModal("Nothing to export", "There are no variants marked Done (approved for export) yet.");
            return;
        }

        const url = `../app/api/export_forms_docx.php?workspace_id=${encodeURIComponent(workspaceId)}&source=variant`;

        fetch(url)
            .then(function (response) {
                if (!response.ok) {
                    return response.text().then(function (text) {
                        throw new Error(text || "Microsoft Forms export failed.");
                    });
                }
                return response.blob();
            })
            .then(function (blob) {
                const objectUrl = URL.createObjectURL(blob);
                const link = document.createElement("a");
                link.href = objectUrl;
                link.download = "mla-question-variants-forms.docx";
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                URL.revokeObjectURL(objectUrl);
                clearExportPanelError();
                showInfoModal(
                "Export complete",
                "Microsoft Forms quiz .docx exported (Answer and Points lines included). Import as a Quiz, then confirm all questions are Required before sharing."
            );
            })
            .catch(function (error) {
                console.error("[variant_export_forms]", error);
                showExportPanelError("Microsoft Forms export failed. Your variants and approval status are unchanged.");
            });
    }

    function exportVariantsToLearnUltra() {
        const doneQuestions = getExportReadyItems();

        if (doneQuestions.length === 0) {
            showInfoModal("Nothing to export", "There are no variants marked Done (approved for export) yet.");
            return;
        }

        try {
            const exportDate = formatDateTimeForHeader();

            let textContent = "";
            textContent += "Learn Ultra Question Export — Variants\n";
            textContent += "=====================================\n";
            textContent += "Exported: " + exportDate + "\n";
            textContent += "Number of variants exported: " + doneQuestions.length + "\n\n";

            doneQuestions.forEach(function (q, index) {
                textContent += "VARIANT " + (index + 1) + "\n";
                textContent += "Title: " + (q.title || "") + "\n";
                textContent += "Tags: " + buildTagsString(q) + "\n";
                textContent += "Type: Multiple Choice\n";
                textContent += "Stem: " + (q.stem || "") + "\n";
                textContent += "Lead-in: " + (q.lead_in || "") + "\n";
                textContent += "A. " + (q.option_a || "") + "\n";
                textContent += "B. " + (q.option_b || "") + "\n";
                textContent += "C. " + (q.option_c || "") + "\n";
                textContent += "D. " + (q.option_d || "") + "\n";
                textContent += "E. " + (q.option_e || "") + "\n";
                textContent += "Correct Answer Letter: " + (q.correct_answer_letter || "") + "\n";
                textContent += "Correct Answer Text: " + (q.correct_answer || "") + "\n";
                textContent += "Explanation: " + (q.justification || "") + "\n";
                if (q.tutor_comments) {
                    textContent += "Tutor comments: " + q.tutor_comments + "\n";
                }
                textContent += "\n----------------------------------------\n\n";
            });

            const blob = new Blob([textContent], { type: "text/plain;charset=utf-8;" });
            const url = URL.createObjectURL(blob);
            const link = document.createElement("a");
            link.href = url;
            link.download = "mla-question-variants-ultra.txt";
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            URL.revokeObjectURL(url);
            clearExportPanelError();
            showInfoModal("Export complete", "Learn Ultra structured export completed successfully.");
        } catch (error) {
            console.error("[variant_export_ultra]", error);
            showExportPanelError("Learn Ultra export failed. Your variants and approval status are unchanged.");
        }
    }

    function renderExportReadyList() {
        updateVariantExportReadinessPanel();
    }

    function variantWorkspaceHasDraft() {
        return Object.values(generatedVariantsByRow).some(function (variant) {
            return (variant.status || "Draft") === "Draft";
        });
    }

    function jumpToNextVariantDraft() {
        if (!generationStarted || reviewQuestions.length === 0) {
            showInfoModal("No Draft questions", "There are no Draft variants left to review.");
            return;
        }

        const currentQuestion = getCurrentQuestion();
        let absoluteStart = -1;

        if (currentQuestion) {
            absoluteStart = reviewQuestions.findIndex(function (q) {
                return Number(q.row_number) === Number(currentQuestion.row_number);
            });
        }

        function goToDraftAtReviewIndex(reviewIndex) {
            currentFilter = "All";
            const filtered = getFilteredReviewQuestions();
            const nextIndex = filtered.findIndex(function (q) {
                return Number(q.row_number) === Number(reviewQuestions[reviewIndex].row_number);
            });
            currentIndex = nextIndex >= 0 ? nextIndex : 0;
            renderCurrentReview();
            saveVariantPageState();
        }

        for (let i = absoluteStart + 1; i < reviewQuestions.length; i++) {
            const rowNumber = Number(reviewQuestions[i].row_number);
            const variant = generatedVariantsByRow[rowNumber];
            if (variant && (variant.status || "Draft") === "Draft") {
                goToDraftAtReviewIndex(i);
                return;
            }
        }

        for (let j = 0; j <= absoluteStart; j++) {
            const rowNumber = Number(reviewQuestions[j].row_number);
            const variant = generatedVariantsByRow[rowNumber];
            if (variant && (variant.status || "Draft") === "Draft") {
                goToDraftAtReviewIndex(j);
                return;
            }
        }

        showInfoModal("No Draft questions", "There are no Draft variants left to review.");
    }

    function updateSelectionSummary() {
        if (selectionCount) {
            if (generationStarted) {
                selectionCount.innerText = reviewQuestions.length + " source question(s) in review";
            } else {
                selectionCount.innerText = selectedRows.size + " selected of " + uploadedQuestionDetails.length;
            }
        }

        if (startVariantGenerationBtn) {
            const disableGenerate =
                uploadedQuestionDetails.length === 0 ||
                selectedRows.size === 0 ||
                generationInProgress ||
                generationStarted;

            startVariantGenerationBtn.disabled = disableGenerate;

            if (generationStarted) {
                startVariantGenerationBtn.innerText = generationInProgress ? "Generating..." : "Variants Generated";
            } else {
                startVariantGenerationBtn.innerText = "Generate Variants";
            }
        }

        if (selectAllBtn) {
            selectAllBtn.disabled = uploadedQuestionDetails.length === 0 || generationStarted;
        }

        if (clearSelectionBtn) {
            clearSelectionBtn.disabled = uploadedQuestionDetails.length === 0 || generationStarted;
        }

        updateVariantFilterChrome();
    }

    function updateNavigationButtons() {
        const filteredQuestions = getFilteredReviewQuestions();

        if (filteredQuestions.length === 0) {
            currentIndex = 0;
        } else if (currentIndex >= filteredQuestions.length) {
            currentIndex = Math.max(0, filteredQuestions.length - 1);
        }

        if (prevSourceBtn) {
            prevSourceBtn.disabled = filteredQuestions.length === 0 || currentIndex <= 0;
        }

        if (nextSourceBtn) {
            nextSourceBtn.disabled = filteredQuestions.length === 0 || currentIndex >= filteredQuestions.length - 1;
        }

        if (prevSourceBtnOriginal) {
            prevSourceBtnOriginal.disabled = filteredQuestions.length === 0 || currentIndex <= 0;
        }

        if (nextSourceBtnOriginal) {
            nextSourceBtnOriginal.disabled = filteredQuestions.length === 0 || currentIndex >= filteredQuestions.length - 1;
        }

        if (nextDraftBtn) {
            nextDraftBtn.disabled = !variantWorkspaceHasDraft();
        }
    }

    function updateCounter() {
        const filteredQuestions = getFilteredReviewQuestions();
        const filteredCount = filteredQuestions.length;
        const multiFiltered = filteredCount > 1;
        const showGeneratedEmpty = !generationStarted || reviewQuestions.length === 0;
        const hasDraft = variantWorkspaceHasDraft();

        if (filteredQuestions.length === 0) {
            currentIndex = 0;
        } else if (currentIndex >= filteredQuestions.length) {
            currentIndex = Math.max(0, filteredQuestions.length - 1);
        }

        const questionNav = document.getElementById("question-navigation");
        const reviewTools = document.getElementById("review-tools-row");
        const originalNav = document.getElementById("original-question-navigation");
        const hasUploaded = uploadedQuestionDetails.length > 0;

        if (generatedPanel) {
            generatedPanel.classList.toggle("card--empty-state", showGeneratedEmpty);
        }

        if (questionNav) {
            questionNav.classList.toggle("hidden", !multiFiltered || showGeneratedEmpty);
        }
        if (reviewTools) {
            reviewTools.classList.toggle("hidden", !hasDraft || showGeneratedEmpty);
        }
        if (originalNav) {
            originalNav.classList.toggle("hidden", !multiFiltered || !hasUploaded);
        }

        const counterText =
            filteredCount === 0
                ? "Question 0 of 0"
                : `Question ${currentIndex + 1} of ${filteredCount}`;

        if (sourceCounter) {
            if (filteredCount <= 1 || showGeneratedEmpty) {
                sourceCounter.classList.add("hidden");
            } else {
                sourceCounter.classList.remove("hidden");
            }
            sourceCounter.textContent = counterText;
        }

        if (sourceCounterOriginal) {
            if (filteredCount <= 1) {
                sourceCounterOriginal.classList.add("hidden");
            } else {
                sourceCounterOriginal.classList.remove("hidden");
                sourceCounterOriginal.textContent = counterText;
            }
        }
    }

    function renderJumpSelect() {
        if (!jumpSelect) return;
        const filteredQuestions = getFilteredReviewQuestions();

        jumpSelect.setAttribute("aria-label", "Select question");

        if (filteredQuestions.length === 0) {
            currentIndex = 0;
        } else if (currentIndex >= filteredQuestions.length) {
            currentIndex = Math.max(0, filteredQuestions.length - 1);
        }

        if (!filteredQuestions || filteredQuestions.length === 0) {
            jumpSelect.innerHTML = `<option value="">No questions loaded</option>`;
            return;
        }

        jumpSelect.innerHTML = filteredQuestions
            .map(function (question, index) {
                const label = formatJumpOptionLabel(question, index + 1);
                return `<option value="${index}">${escapeHtml(label)}</option>`;
            })
            .join("");

        jumpSelect.value = String(currentIndex);
    }

    function renderQuestionList() {
        if (!questionListContainer) return;

        const items = generationStarted ? reviewQuestions : uploadedQuestionDetails;

        if (!items || items.length === 0) {
            questionListContainer.innerHTML = "<p>No uploaded questions yet.</p>";
            return;
        }

        let html = "<div class='variant-source-list'>";

        items.forEach(question => {
            const rowNumber = Number(question.row_number);
            const title = escapeHtml(getQuestionTitle(question));
            const isActive = getCurrentQuestion() && Number(getCurrentQuestion().row_number) === rowNumber;
            const isChecked = selectedRows.has(rowNumber);

            html += `
                <div class="variant-source-item ${isActive ? "active" : ""}">
                    ${generationStarted ? `
                        <div class="variant-source-item-indicator">•</div>
                    ` : `
                        <label class="variant-source-item-checkbox">
                            <input type="checkbox" class="variant-source-checkbox" data-row="${rowNumber}" ${isChecked ? "checked" : ""}>
                        </label>
                    `}
                    <button type="button" class="variant-source-jump-btn" data-row="${rowNumber}">
                        <span class="variant-source-row-label">Row ${rowNumber}</span>
                        <span class="variant-source-row-title">${title}</span>
                    </button>
                </div>
            `;
        });

        html += "</div>";
        questionListContainer.innerHTML = html;
        updateVariantFilterChrome();

        document.querySelectorAll(".variant-source-jump-btn").forEach(button => {
            button.addEventListener("click", function () {
                const rowNumber = Number(this.getAttribute("data-row"));
                const targetIndex = reviewQuestions.findIndex(q => Number(q.row_number) === rowNumber);

                if (targetIndex !== -1) {
                    currentIndex = targetIndex;
                } else if (!generationStarted) {
                    const uploadedIndex = uploadedQuestionDetails.findIndex(q => Number(q.row_number) === rowNumber);
                    if (uploadedIndex !== -1) {
                        currentIndex = uploadedIndex;
                    }
                }

                renderCurrentReview();
                renderQuestionList();
                renderJumpSelect();
                saveVariantPageState();
            });
        });

        document.querySelectorAll(".variant-source-checkbox").forEach(checkbox => {
            checkbox.addEventListener("change", function () {
                const rowNumber = Number(this.getAttribute("data-row"));

                if (this.checked) {
                    selectedRows.add(rowNumber);
                } else {
                    selectedRows.delete(rowNumber);
                }

                updateSelectionSummary();
                syncCurrentCheckbox();
                saveVariantPageState();
            });
        });
    }

    function renderOriginalQuestionBody(question) {
        if (!question) {
            return "<p class='workspace-empty workspace-empty--compact'>Upload a RISR file to begin.</p>";
        }

        const data = question.data || {};
        const correctLetter = String(data["Correct answer letter"] || "").trim().toUpperCase();
        const stemText = String(data["Question text"] || data["Stem"] || "").trim();
        const leadIn = String(data["Lead-in"] || data["Lead in"] || "").trim();
        const leadInHtml = leadIn
            ? `<p class="question-read-leadin"><strong>${escapeHtml(leadIn)}</strong></p>`
            : "";
        const tutorComments = String(data["Examiner notes"] || data["Comments"] || "").trim();
        const tutorCommentsHtml =
            tutorComments && tutorComments !== "-"
                ? `<p class="question-read-tutor-note"><strong>Tutor comments:</strong> ${escapeHtml(tutorComments)}</p>`
                : "";
        const correctAnswerText = String(data["Correct answer"] || "").trim();
        const correctKeyHtml =
            correctLetter || correctAnswerText
                ? `<p class="question-read-key"><strong>Correct answer:</strong> ${escapeHtml(correctLetter)}${
                      correctAnswerText !== "" ? ` — ${escapeHtml(correctAnswerText)}` : ""
                  }</p>`
                : "";
        const justificationHtml = data["Justification"]
            ? `<p class="question-read-justification"><strong>Justification:</strong> ${escapeHtml(
                  data["Justification"]
              )}</p>`
            : "";
        const typeYearParts = [];
        if (data["Summative/Formative"]) {
            typeYearParts.push(`Type: ${data["Summative/Formative"]}`);
        }
        if (data["Year"]) {
            typeYearParts.push(`Year: ${data["Year"]}`);
        }
        const typeYearMeta =
            typeYearParts.length > 0
                ? `<div class="question-card-meta" role="group" aria-label="Assessment metadata">${typeYearParts
                      .map(part => `<span class="question-meta-item">${escapeHtml(part)}</span>`)
                      .join("")}</div>`
                : "";

        return `
            <div class="question-card question-card-compact">
                <div class="question-card-content">
                    <header class="question-card-header">
                        <hr class="question-card-divider question-card-divider--top" aria-hidden="true">
                        <h3 class="question-card-title">${escapeHtml(data["Question title"] || getQuestionTitle(question))}</h3>
                        ${renderSourceQuestionMetadata(question)}
                        ${typeYearMeta}
                        <div class="question-status-bar" role="status" aria-label="Source question">
                            ${statusChip("Source", `Row ${question.row_number}`, "info")}
                        </div>
                        <hr class="question-card-divider question-card-divider--after-status" aria-hidden="true">
                    </header>

                    <article class="question-read-body">
                        <p class="question-read-stem">${escapeHtml(stemText)}</p>
                        ${leadInHtml}
                        <ul class="question-read-options">
                            ${["A", "B", "C", "D", "E"]
                                .map(letter => {
                                    const text = getSourceAnswerFromData(data, letter);
                                    return `<li><span class="question-opt-label">${letter}.</span> ${escapeHtml(
                                        text || "[No text found in spreadsheet column]"
                                    )}</li>`;
                                })
                                .join("")}
                        </ul>
                        ${correctKeyHtml}
                        ${justificationHtml}
                        ${tutorCommentsHtml}
                    </article>
                </div>
            </div>
        `;
    }

    function variantReviewRepairPipelineComplete(variant) {
        return (
            variant &&
            !variant.advisory_review_loading &&
            (variant.advisory_review !== null ||
                variant.repair_error ||
                variant.repair_applied === true ||
                variant.repair_applied === false)
        );
    }

    function renderVariantRepairCompactNotice(variant) {
        if (!variant) {
            return "";
        }

        if (variant.advisory_review_loading) {
            return renderVariantPipelineStatusHtml("repairing", "Running review and repair…");
        }

        const repairError = String(variant.repair_error || variant.advisory_review_error || "").trim();

        if (repairError) {
            return renderVariantPipelineStatusHtml(
                "warning",
                "Variant question generated. Automatic repair unavailable. Tutor review is required."
            );
        }

        if (variantReviewRepairPipelineComplete(variant)) {
            return renderVariantPipelineStatusHtml(
                "complete",
                "Variant question generated. Tutor review is still required."
            );
        }

        return renderVariantPipelineStatusHtml("repairing", "Running review and repair…");
    }

    function renderVariantChangeLogSection(variant) {
        if (!variant || variant.repair_applied !== true) {
            return "";
        }

        const changeLog = Array.isArray(variant.change_log) ? variant.change_log : [];
        if (changeLog.length === 0) {
            return `<p class="variant-advisory-review-muted">No individual change log entries were returned.</p>`;
        }

        return `
            <div class="variant-repair-details-section">
                <p class="variant-advisory-subheading"><strong>Change log</strong></p>
                <ul class="variant-advisory-list variant-change-log">${changeLog
                    .map((line) => `<li>${escapeHtml(String(line))}</li>`)
                    .join("")}</ul>
            </div>
        `;
    }

    function renderVariantRepairDetailsContent(variant) {
        if (!variant) {
            return "";
        }

        const parts = [];
        const repairError = String(variant.repair_error || variant.advisory_review_error || "").trim();
        const repairApplied = variant.repair_applied === true;
        const pipelineComplete = variantReviewRepairPipelineComplete(variant);

        if (repairError) {
            parts.push(`
                <div class="variant-repair-details-section variant-repair-details-section--error">
                    <p class="variant-advisory-subheading"><strong>Repair error details</strong></p>
                    <p class="variant-repair-details-error-msg">${escapeHtml(repairError)}</p>
                </div>
            `);
        }

        if (variant.repair_blocked === true) {
            parts.push(`
                <p class="variant-repair-details-msg">Automatic repair was not applied due to clinical safety concerns. The Draft variant above is unchanged.</p>
            `);
        }

        if (pipelineComplete && !repairApplied && !repairError && !variant.repair_blocked) {
            parts.push(`
                <p class="variant-repair-details-msg">No automatic repair changes were applied.</p>
            `);
        }

        const changeLogHtml = renderVariantChangeLogSection(variant);
        if (changeLogHtml) {
            parts.push(changeLogHtml);
        }

        const preRepairHtml = renderVariantPreRepairReviewBlock(variant);
        if (preRepairHtml) {
            parts.push(preRepairHtml);
        }

        return parts.join("");
    }

    function renderVariantRepairDetailsDropdown(variant) {
        if (!variant || variant.advisory_review_loading) {
            return "";
        }

        if (!variantReviewRepairPipelineComplete(variant)) {
            return "";
        }

        const inner = renderVariantRepairDetailsContent(variant);
        if (inner.trim() === "") {
            return "";
        }

        return `
            <details class="variant-repair-details">
                <summary class="variant-repair-details-summary">What changed and why?</summary>
                <div class="variant-repair-details-body">
                    ${inner}
                </div>
            </details>
        `;
    }

    function renderVariantDraftHeading(variant) {
        if (!variant || variant.advisory_review_loading) {
            return "";
        }

        const stemGrammarWarn = String(variant.stem_observation_grammar_warning || "").trim();
        const stemGrammarWarnHtml =
            stemGrammarWarn !== ""
                ? `<p class="variant-draft-label-note variant-draft-label-note--warn" role="note">${escapeHtml(stemGrammarWarn)}</p>`
                : "";

        if (variant.repair_applied === true) {
            return `
                <div class="variant-draft-label variant-draft-label--repaired">
                    <h4 class="variant-draft-label-heading">Current repaired Draft variant</h4>
                    <p class="variant-draft-label-note">Automatic repair does not approve this question. Tutor review and manual <strong>Done</strong> are still required before export.</p>
                    ${stemGrammarWarnHtml}
                </div>
            `;
        }

        if (variantReviewRepairPipelineComplete(variant)) {
            return `
                <div class="variant-draft-label">
                    <h4 class="variant-draft-label-heading">Current Draft variant</h4>
                    <p class="variant-draft-label-note">Tutor review and manual <strong>Done</strong> are still required before export.</p>
                    ${stemGrammarWarnHtml}
                </div>
            `;
        }

        return `
            <div class="variant-draft-label">
                <h4 class="variant-draft-label-heading">Current Draft variant</h4>
            </div>
        `;
    }

    function renderVariantPreRepairReviewBlock(variant) {
        const review = variant && variant.advisory_review;
        if (!review || typeof review !== "object" || variant.advisory_review_loading) {
            return "";
        }

        if (!variantReviewRepairPipelineComplete(variant)) {
            return "";
        }

        const repairApplied = variant.repair_applied === true;
        const priority = String(review.tutor_review_priority || "medium").toLowerCase();
        const priorityLabel = priority.charAt(0).toUpperCase() + priority.slice(1);
        const priorityClass =
            priority === "high" ? "variant-advisory-priority--high" : priority === "low" ? "variant-advisory-priority--low" : "variant-advisory-priority--medium";

        const scoreLine = (label, value) => {
            const v = escapeHtml(String(value || "—"));
            return `<span class="variant-advisory-score"><strong>${escapeHtml(label)}:</strong> ${v}</span>`;
        };

        const issues = Array.isArray(review.issues) ? review.issues : [];
        const issuesHtml =
            issues.length > 0
                ? `<ul class="variant-advisory-list">${issues.map((line) => `<li>${escapeHtml(String(line))}</li>`).join("")}</ul>`
                : `<p class="variant-advisory-review-muted">No issues listed.</p>`;

        const preRepairNote = repairApplied
            ? `<p class="variant-pre-repair-note">These findings describe the <strong>first generated draft</strong> before automatic repair. See <strong>Post-repair reviewer</strong> below for feedback on the current repaired Draft.</p>`
            : `<p class="variant-pre-repair-note">These findings describe the <strong>first generated draft</strong>. See <strong>Post-repair reviewer</strong> below if available.</p>`;

        return `
            <div class="variant-advisory-review variant-advisory-review--pre-repair variant-repair-details-section">
                <h4 class="variant-advisory-review-heading">Pre-repair review findings</h4>
                ${preRepairNote}
                <p class="variant-advisory-priority ${priorityClass}"><strong>Tutor review priority (pre-repair draft):</strong> ${escapeHtml(priorityLabel)}</p>
                <p class="variant-advisory-summary">${escapeHtml(String(review.summary || ""))}</p>
                <div class="variant-advisory-scores">
                    ${scoreLine("Same concept", review.same_tested_concept)}
                    ${scoreLine("Key preserved", review.correct_answer_preserved)}
                    ${scoreLine("Difference", review.difference_from_original)}
                    ${scoreLine("MS AKT style", review.ms_akt_style)}
                    ${scoreLine("Clinical safety", review.clinical_safety)}
                </div>
                <div class="variant-advisory-subsection">
                    <p class="variant-advisory-subheading"><strong>Issues in the pre-repair draft</strong></p>
                    ${issuesHtml}
                </div>
            </div>
        `;
    }

    function clearVariantReviewRepairState(variant) {
        if (!variant || typeof variant !== "object") {
            return;
        }
        variant.advisory_review = null;
        variant.advisory_review_loading = false;
        variant.advisory_review_error = null;
        variant.repair_applied = null;
        variant.change_log = null;
        variant.repair_error = null;
        variant.repair_blocked = false;
        variant.advisory_review_phase = null;
        variant.variant_pre_repair_snapshot = null;
        variant.post_repair_review = null;
        variant.post_repair_review_loading = false;
        variant.post_repair_review_error = null;
        variant.post_repair_review_phase = null;
        variant.stem_observation_grammar_warning = null;
        clearVariantOptionalReviewState(variant);
    }

    function clearVariantOptionalReviewState(variant) {
        if (!variant || typeof variant !== "object") {
            return;
        }
        variant.optional_review = null;
        variant.optional_review_loading = false;
        variant.optional_review_error = null;
        variant.optional_review_content_hash = "";
        variant.optional_suggestion_ignored_fields = {};
    }

    function normalizeVariantFingerprintText(value) {
        return String(value ?? "")
            .replace(/\r\n/g, "\n")
            .trim();
    }

    function hashVariantStringDjb2(str) {
        let hash = 5381;
        for (let i = 0; i < str.length; i++) {
            hash = ((hash << 5) + hash) ^ str.charCodeAt(i);
        }
        return (hash >>> 0).toString(16);
    }

    function getVariantContentFingerprint(variant) {
        if (!variant || typeof variant !== "object") {
            return "";
        }
        const parts = VARIANT_OPTIONAL_FINGERPRINT_FIELDS.map(function (field) {
            return normalizeVariantFingerprintText(variant[field]);
        });
        return hashVariantStringDjb2(parts.join("\u001f"));
    }

    function getVariantDraftFieldValue(variant, panelField) {
        if (!variant) {
            return "";
        }
        if (panelField === "correct_answer_letter") {
            return String(variant.correct_answer_letter || "").trim().toUpperCase();
        }
        return String(variant[panelField] || "");
    }

    function mapOptionalReviewFieldToEditPanel(field) {
        const f = String(field || "")
            .toLowerCase()
            .trim()
            .replace(/\s+/g, "_");
        if (f === "correct_answer" || f === "correct_answer_letter") {
            return "correct_answer_letter";
        }
        if (f === "lead-in" || f === "lead_in") {
            return "lead_in";
        }
        if (
            f === "title" ||
            f === "stem" ||
            f === "lead_in" ||
            f === "option_a" ||
            f === "option_b" ||
            f === "option_c" ||
            f === "option_d" ||
            f === "option_e" ||
            f === "justification"
        ) {
            return f;
        }
        return "";
    }

    function isUnmappedOptionalSuggestionField(field) {
        const f = String(field || "")
            .toLowerCase()
            .trim();
        return f === "general" || f === "tags" || f === "tutor_comments" || mapOptionalReviewFieldToEditPanel(field) === "";
    }

    function optionalSuggestionHasContent(edit) {
        if (!edit || typeof edit !== "object") {
            return false;
        }
        return (
            String(edit.suggested_text ?? "").trim() !== "" || String(edit.reason ?? "").trim() !== ""
        );
    }

    const VARIANT_PARTIAL_SUGGESTION_NOTE =
        "Suggestion not applied automatically because it may be a partial edit.";

    const VARIANT_STYLE_SUGGESTION_NOTE =
        "Suggestion not offered for one-click acceptance because it may introduce a style issue.";

    const VARIANT_OBSERVATION_SUGGESTION_NOTE =
        "Suggestion not applied because it may introduce observation wording issues. Please edit manually if required.";
    const VARIANT_OBSERVATION_ACCEPT_BLOCKED_MSG =
        "Suggestion not applied because it may introduce observation wording issues. Please edit manually if required.";
    const VARIANT_STEM_SAVE_BLOCKED_MSG = "Please correct observation wording before saving.";

    const VARIANT_WORDING_SUGGESTION_NOTE =
        "Suggestion not offered for one-click acceptance because it may introduce a wording issue.";

    const OPTIONAL_STYLE_REJECT_REASONS = new Set([
        "style_grammar_fragment",
        "style_species_caps",
        "style_condition_caps",
        "style_what_to_which",
        "style_mixed_observation",
        "cosmetic_rewrite",
        "good_item_low_priority",
        "good_item_cosmetic",
        "good_item_unclear_benefit"
    ]);

    const OPTIONAL_OBSERVATION_REJECT_REASONS = new Set([
        "stem_observation_wording",
        "stem_observation_clipped"
    ]);

    const OPTIONAL_WORDING_REJECT_REASONS = new Set(["wording_incomplete", "stem_examination_wording"]);

    function normalizeOptionalSuggestionText(value) {
        return String(value ?? "")
            .replace(/\r\n/g, "\n")
            .trim();
    }

    function getOptionalSuggestionCurrentValue(variant, panelField, edit) {
        const fromEdit = normalizeOptionalSuggestionText(edit && edit.current_text);
        if (fromEdit !== "") {
            return fromEdit;
        }
        return normalizeOptionalSuggestionText(getVariantDraftFieldValue(variant, panelField));
    }

    function textHasPatientContext(text) {
        return /\b(\d{1,3}[-\s]?year[-\s]?old|aged\s+\d{1,3}|\d{1,3}[-\s]?year|year[-\s]old|\bpatient\b|\b(man|woman|boy|girl)\b)/i.test(
            text
        );
    }

    function textHasClinicalDetailMarkers(text) {
        return /\b(examin(ation|e|ed)|palpat|auscult|murmur|lymph|mass|lump|tender|swelling|nipple|discharge|investigation|finding|temperature|blood pressure|heart rate|pulse|ecg|x-?ray|ultrasound|mammogram|mmol|g\/l|×\s*10|hb\b|wcc\b)/i.test(
            text
        );
    }

    function looksLikeVignetteOpening(text) {
        const t = normalizeOptionalSuggestionText(text);
        if (t === "") {
            return false;
        }
        return (
            /^(A|An|The)\s+(\d{1,3}[-\s]?year|woman|man|boy|girl|patient)/i.test(t) ||
            /^\d{1,3}[-\s]?year[-\s]?old/i.test(t)
        );
    }

    function looksLikeMidVignetteFragment(text) {
        const t = normalizeOptionalSuggestionText(text);
        return /^(She|He|They|The patient)\s+(has|had|is|was|denies|reports|presents)/i.test(t);
    }

    function isVariantOptionalReviewDebugEnabled() {
        return (
            (typeof window !== "undefined" && window.VARIANT_OPTIONAL_REVIEW_DEBUG === true) ||
            (typeof location !== "undefined" &&
                /^(localhost|127\.0\.0\.1)$/i.test(String(location.hostname || "")))
        );
    }

    function logOptionalSuggestionBlocked(field, reason, edit) {
        if (!isVariantOptionalReviewDebugEnabled()) {
            return;
        }
        console.debug("[variant_optional_review] blocked suggestion", {
            field: field,
            reason: reason,
            preview: String((edit && edit.suggested_text) || "").slice(0, 160)
        });
    }

    function optionalSuggestionRejectIsLogged(reason) {
        return (
            OPTIONAL_STYLE_REJECT_REASONS.has(reason) ||
            OPTIONAL_OBSERVATION_REJECT_REASONS.has(reason) ||
            OPTIONAL_WORDING_REJECT_REASONS.has(reason)
        );
    }

    function hasIncompleteSentenceFragment(text) {
        const t = normalizeOptionalSuggestionText(text);
        if (t === "") {
            return false;
        }
        const explicitPatterns = [
            /\band\s+(?:his|her|their)\s+normal\b/i,
            /\b(?:his|her|their)\s+normal\s*(?:[.,;)]|$)/i,
            /\band\s+is\s+normal\b/i,
            /\b(?:his|her|their)\s+is\s+normal\b/i,
            /\band\s+(?:his|her|their)\s+(?:is|are)\s+normal\b/i,
            /\b(?:his|her|their)\s+(?:observations|examination|pulse|bp|blood\s+pressure|respiratory\s+rate|visual\s+acuity|heart\s+sounds|chest|mass|masses)\s+normal\b/i,
            /\b(?:his|her|their)\s+(?:observations|examination)\s+(?:is|are)\s*$/i,
            /\band\s+(?:his|her|their)\s+(?:abnormal|tender|distended|soft)\s*[.,;)]/i
        ];
        for (let i = 0; i < explicitPatterns.length; i++) {
            if (explicitPatterns[i].test(t)) {
                return true;
            }
        }
        if (/\b(?:his|her|their)\s+normal\b/i.test(t) && !/\b(?:observations|examination)\s+(?:is|are)\s+normal\b/i.test(t)) {
            return true;
        }
        return false;
    }

    function hasDroppedClinicalNoun(current, suggested) {
        const cur = normalizeOptionalSuggestionText(current).toLowerCase();
        const sug = normalizeOptionalSuggestionText(suggested).toLowerCase();
        if (cur === "" || sug === "") {
            return false;
        }
        const protectedNouns = [
            "observations",
            "observation",
            "examination",
            "pulse",
            "blood pressure",
            "respiratory rate",
            "visual acuity",
            "heart sounds",
            "chest",
            "masses",
            "mass",
            "temperature"
        ];
        for (let i = 0; i < protectedNouns.length; i++) {
            const noun = protectedNouns[i];
            if (!cur.includes(noun) || sug.includes(noun)) {
                continue;
            }
            if (hasIncompleteSentenceFragment(suggested)) {
                return true;
            }
            if (noun === "observations" || noun === "observation") {
                if (/\b(?:his|her|their)\s+normal\b/i.test(suggested) && /\bobservations?\s+are\s+normal\b/i.test(current)) {
                    return true;
                }
            }
            if (/\b(?:his|her|their)\s+(?:is|are)?\s*normal\b/i.test(sug) && /\b(?:is|are)\s+normal\b/i.test(cur)) {
                return true;
            }
        }
        return false;
    }

    function stemSuggestionContainsExaminationTerms(text) {
        const t = normalizeOptionalSuggestionText(text).toLowerCase();
        if (t === "") {
            return false;
        }
        return /\b(?:examin|observ|palpat|auscult|auscultat|normal|abnormal|heart\s+sounds|visual\s+acuity|lymph|tender|swelling|mass|hyperpigmentation)\b/i.test(
            t
        );
    }

    function stemSuggestionChangesClinicalExaminationWording(current, suggested) {
        const cur = normalizeOptionalSuggestionText(current);
        const sug = normalizeOptionalSuggestionText(suggested);
        if (cur === "" || sug === "" || cur === sug) {
            return false;
        }
        if (!stemSuggestionContainsExaminationTerms(cur) && !stemSuggestionContainsExaminationTerms(sug)) {
            return false;
        }
        return stemSuggestionContainsExaminationTerms(sug) || cur.toLowerCase() !== sug.toLowerCase();
    }

    function isClearlyCompleteGrammaticalReplacement(suggested) {
        const t = normalizeOptionalSuggestionText(suggested);
        if (t === "" || hasIncompleteSentenceFragment(t)) {
            return false;
        }
        if (/\b(?:his|her|their)\s+normal\b/i.test(t) && !/\b(?:observations|examination)\s+(?:is|are)\s+normal\b/i.test(t)) {
            return false;
        }
        return true;
    }

    function validateFieldWordingIntegrity(suggested, current, panelField) {
        if (hasIncompleteSentenceFragment(suggested)) {
            return { valid: false, reason: "wording_incomplete" };
        }
        if (hasDroppedClinicalNoun(current, suggested)) {
            return { valid: false, reason: "wording_incomplete" };
        }
        if (panelField === "stem" && stemSuggestionChangesClinicalExaminationWording(current, suggested)) {
            if (!isClearlyCompleteGrammaticalReplacement(suggested)) {
                return { valid: false, reason: "stem_examination_wording" };
            }
        }
        return { valid: true, reason: "" };
    }

    function stemSuggestionContainsObservationTerms(text) {
        const t = normalizeOptionalSuggestionText(text).toLowerCase();
        if (t === "") {
            return false;
        }
        return /\b(?:pulse|heart\s+rate|hr|bp|blood\s+pressure|respiratory\s+rate|rr|oxygen\s+saturation|spo2|o2\s+sat|o2\s+saturation)\b/i.test(
            t
        );
    }

    function hasBarePulseInPossessiveContext(text) {
        const t = normalizeOptionalSuggestionText(text);
        if (!/\b(?:His|Her|Their)\s+/i.test(t)) {
            return false;
        }
        if (/\b(?:His|Her|Their)\s+pulse\s+is\s+\d/i.test(t) || /,\s*pulse\s+is\s+\d/i.test(t)) {
            return false;
        }
        return /,\s*pulse\s+(?!is\s)\d+\s+bpm/i.test(t) || /\band\s+pulse\s+(?!is\s)\d+\s+bpm/i.test(t);
    }

    /**
     * Stem suggestions that change observation wording: allow one-click accept only if normalisation
     * produces safe grammatical wording; otherwise advisory-only.
     */
    function validateStemObservationWordingPolicy(suggested, current) {
        if (!stemSuggestionContainsObservationTerms(suggested)) {
            return { valid: true, reason: "" };
        }
        const norm = normalizeVariantStemObservationGrammar(suggested);
        if (norm.needsReview) {
            return { valid: false, reason: "stem_observation_clipped" };
        }
        if (current && regressesObservationGrammar(current, suggested) && !norm.changed) {
            return { valid: false, reason: "stem_observation_clipped" };
        }
        return { valid: true, reason: "" };
    }

    function startsWithPossessiveObservationSentence(text) {
        const t = normalizeOptionalSuggestionText(text);
        return /^(?:On examination[,:]?\s+)?(?:His|Her|Their)\s+/i.test(t);
    }

    function hasClippedPossessivePulse(text) {
        const t = normalizeOptionalSuggestionText(text);
        return /\b(?:His|Her|Their|The)\s+pulse\s+(?!is\s)\d+/i.test(t);
    }

    function hasClippedPossessiveBp(text) {
        const t = normalizeOptionalSuggestionText(text);
        return /\b(?:His|Her|Their)\s+BP\s+\d+\s*\/\s*\d+/i.test(t);
    }

    function hasClippedPossessiveBloodPressure(text) {
        const t = normalizeOptionalSuggestionText(text);
        return /\b(?:His|Her|Their)\s+blood\s+pressure\s+(?!is\s)\d+/i.test(t);
    }

    function hasBareBloodPressureOrBpInPossessiveContext(text) {
        const t = normalizeOptionalSuggestionText(text);
        if (!/\b(?:His|Her|Their)\s+/i.test(t)) {
            return false;
        }
        const hasProperBp =
            /\b(?:His|Her|Their)\s+BP\s+is\s+\d/i.test(t) ||
            /\b(?:His|Her|Their)\s+blood\s+pressure\s+is\s+\d/i.test(t) ||
            /\bblood\s+pressure\s+is\s+\d/i.test(t) ||
            /\bBP\s+is\s+\d/i.test(t);
        if (hasProperBp) {
            return false;
        }
        return (
            /,\s*(?:blood pressure|BP)\s+\d/i.test(t) ||
            /\band\s+BP\s+\d/i.test(t) ||
            /\band\s+blood\s+pressure\s+(?!is\s)\d/i.test(t)
        );
    }

    function hasPossessiveVitalGrammarFragment(text) {
        const t = normalizeOptionalSuggestionText(text);
        if (t === "") {
            return false;
        }
        if (hasClippedPossessivePulse(t)) {
            return true;
        }
        if (hasClippedPossessiveBp(t)) {
            return true;
        }
        if (hasClippedPossessiveBloodPressure(t)) {
            return true;
        }
        if (hasBareBloodPressureOrBpInPossessiveContext(t)) {
            return true;
        }
        if (hasBarePulseInPossessiveContext(t)) {
            return true;
        }
        const otherClipped = [
            /\b(?:His|Her|Their)\s+(?:heart\s+rate|HR)\s+(?!is\s)\d+/i,
            /\b(?:His|Her|Their)\s+(?:temperature|temp)\s+(?!is\s)\d+/i,
            /\b(?:His|Her|Their)\s+(?:respiratory\s+rate|RR)\s+(?!is\s)\d+/i,
            /\b(?:His|Her|Their)\s+oxygen\s+saturation\s+(?!is\s)\d+/i
        ];
        for (let i = 0; i < otherClipped.length; i++) {
            if (otherClipped[i].test(t)) {
                return true;
            }
        }
        return false;
    }

    function hasClippedObservationGrammar(text) {
        return hasPossessiveVitalGrammarFragment(text);
    }

    function isListStyleObservationPhrase(text) {
        const t = normalizeOptionalSuggestionText(text);
        if (t === "" || startsWithPossessiveObservationSentence(t) || hasPossessiveVitalGrammarFragment(t)) {
            return false;
        }
        const segments = t.split(/[.;]\s+/).filter(function (part) {
            return part.trim() !== "";
        });
        for (let s = 0; s < segments.length; s++) {
            const seg = segments[s];
            const listMatches = seg.match(
                /(?:^|,\s*)(?:temperature|temp|pulse|heart rate|HR|BP|blood pressure|respiratory rate|RR|oxygen saturation)\s+[\d./%°]+/gi
            );
            if (listMatches && listMatches.length >= 2) {
                return true;
            }
        }
        return false;
    }

    function regressesObservationGrammar(current, suggested) {
        const cur = normalizeOptionalSuggestionText(current);
        const sug = normalizeOptionalSuggestionText(suggested);
        if (cur === "" || sug === "") {
            return false;
        }
        if (/\b(?:His|Her|Their)\s+pulse\s+is\s+\d+/i.test(cur) && hasClippedPossessivePulse(sug)) {
            return true;
        }
        if (/\bblood\s+pressure\s+is\s+\d+/i.test(cur) && hasClippedPossessiveBloodPressure(sug)) {
            return true;
        }
        if (/\bBP\s+is\s+\d+/i.test(cur) && hasClippedPossessiveBp(sug)) {
            return true;
        }
        if (
            /\b(?:His|Her|Their)\s+blood\s+pressure\s+is\s+\d+/i.test(cur) &&
            (hasClippedPossessiveBloodPressure(sug) || hasBareBloodPressureOrBpInPossessiveContext(sug))
        ) {
            return true;
        }
        return false;
    }

    function validateStemObservationGrammar(suggested, current) {
        const sug = normalizeOptionalSuggestionText(suggested);
        if (sug === "") {
            return { valid: true, reason: "" };
        }

        if (isListStyleObservationPhrase(sug)) {
            return { valid: true, reason: "" };
        }

        if (startsWithPossessiveObservationSentence(sug) || /\b(?:His|Her|Their)\s+pulse\s/i.test(sug)) {
            if (hasClippedPossessivePulse(sug)) {
                return { valid: false, reason: "style_grammar_fragment" };
            }
            if (hasClippedPossessiveBp(sug)) {
                return { valid: false, reason: "style_grammar_fragment" };
            }
            if (hasClippedPossessiveBloodPressure(sug)) {
                return { valid: false, reason: "style_grammar_fragment" };
            }
            if (hasBareBloodPressureOrBpInPossessiveContext(sug)) {
                return { valid: false, reason: "style_grammar_fragment" };
            }
        } else if (hasClippedObservationGrammar(sug)) {
            return { valid: false, reason: "style_grammar_fragment" };
        }

        if (regressesObservationGrammar(current, sug)) {
            return { valid: false, reason: "style_grammar_fragment" };
        }

        if (hasMixedObservationStyle(sug)) {
            return { valid: false, reason: "style_mixed_observation" };
        }

        return { valid: true, reason: "" };
    }

    function suggestedObservationGrammarIsUnsafe(current, suggested, panelField) {
        const sug = normalizeOptionalSuggestionText(suggested);
        if (sug === "") {
            return false;
        }
        if (panelField === "stem") {
            return !validateStemObservationGrammar(sug, current).valid;
        }
        if (hasClippedObservationGrammar(sug)) {
            return true;
        }
        if (isListStyleObservationPhrase(sug)) {
            return false;
        }
        const cur = normalizeOptionalSuggestionText(current);
        if (regressesObservationGrammar(cur, sug)) {
            return true;
        }
        if (hasClippedObservationGrammar(cur) && hasMixedObservationStyle(sug)) {
            return true;
        }
        return false;
    }

    function hasMixedObservationStyle(text) {
        const t = normalizeOptionalSuggestionText(text);
        if (t === "") {
            return false;
        }
        const hasSentenceStyle = /\b(His|Her|Their)\s+\w[\w\s]{0,20}\s+is\s+\d/i.test(t);
        const hasBareListVitals =
            /(?:^|[.;]\s+)(?:temperature|pulse|BP|blood pressure|heart rate|respiratory rate|oxygen saturation)\s+\d/i.test(
                t
            );
        if (hasSentenceStyle && hasBareListVitals && hasPossessiveVitalGrammarFragment(t)) {
            return true;
        }
        if (hasSentenceStyle && hasBareListVitals) {
            const listCount = (t.match(
                /(?:^|[,;]\s+)(?:temperature|pulse|BP|blood pressure|heart rate|oxygen saturation)\s+\d/gi
            ) || []).length;
            const sentenceCount = (t.match(/\b(His|Her|Their)\s+\S+\s+is\s+\d/gi) || []).length;
            if (listCount >= 1 && sentenceCount >= 1 && !/\b(BP|pulse|heart rate)\s+is\s+\d/i.test(t)) {
                return true;
            }
        }
        return false;
    }

    function tokenizeForOptionalCompare(text) {
        return normalizeOptionalSuggestionText(text)
            .toLowerCase()
            .replace(/[^\w\s%/°.-]/g, " ")
            .split(/\s+/)
            .filter(Boolean);
    }

    function isCosmeticRewrite(current, suggested) {
        const a = tokenizeForOptionalCompare(current);
        const b = tokenizeForOptionalCompare(suggested);
        if (a.length === 0 || b.length === 0) {
            return false;
        }
        if (a.join(" ") === b.join(" ")) {
            return true;
        }
        const setA = new Set(a);
        let shared = 0;
        b.forEach(function (token) {
            if (setA.has(token)) {
                shared += 1;
            }
        });
        const overlap = shared / Math.max(a.length, b.length);
        return overlap >= 0.9 && Math.abs(a.length - b.length) <= 4;
    }

    function isOptionalReviewOverallGood(variant) {
        return String((variant && variant.optional_review && variant.optional_review.overall_review) || "")
            .toLowerCase()
            .trim() === "good";
    }

    function reasonStatesClearImprovement(reason) {
        const r = String(reason || "").toLowerCase();
        return /\b(clinical|safety|unsafe|incorrect|wrong|misleading|guideline|diagnosis|answer|best answer|distractor|single best|stem|lead-?in|mla|concept|equivalence|patient|contraindicat|dosage|investigation|treatment)\b/.test(
            r
        );
    }

    function reasonStatesTitleImprovement(reason) {
        const r = String(reason || "").toLowerCase();
        return /\b(title|vague|too broad|broad|misleading|inconsistent|item.?bank|organisation|organization|unclear|does not describe|does not reflect|not useful|item bank|wording only|organisation)\b/.test(
            r
        );
    }

    function validateSuggestionClearImprovement(variant, edit, panelField) {
        const current = getOptionalSuggestionCurrentValue(variant, panelField, edit);
        const suggested = normalizeOptionalSuggestionText(edit.suggested_text);
        const priority = String((edit && edit.priority) || "medium").toLowerCase();

        if (isCosmeticRewrite(current, suggested)) {
            return { valid: false, reason: "cosmetic_rewrite" };
        }

        if (isOptionalReviewOverallGood(variant)) {
            if (panelField === "title") {
                if (!reasonStatesTitleImprovement(edit && edit.reason) && !reasonStatesClearImprovement(edit && edit.reason)) {
                    return { valid: false, reason: "good_item_unclear_benefit" };
                }
                return { valid: true, reason: "" };
            }
            if (priority !== "high") {
                return { valid: false, reason: "good_item_low_priority" };
            }
            if (isCosmeticRewrite(current, suggested)) {
                return { valid: false, reason: "good_item_cosmetic" };
            }
            if (!reasonStatesClearImprovement(edit && edit.reason)) {
                return { valid: false, reason: "good_item_unclear_benefit" };
            }
        } else if (priority === "low" && isCosmeticRewrite(current, suggested)) {
            return { valid: false, reason: "cosmetic_rewrite" };
        }

        return { valid: true, reason: "" };
    }

    function hasIncorrectSpeciesCapitalisation(text) {
        return /\bE\.\s*Coli\b/.test(normalizeOptionalSuggestionText(text));
    }

    function hasMidSentenceCapitalizedCondition(text) {
        const t = normalizeOptionalSuggestionText(text);
        return /\b(?:the|a|an|with|of|for|and|or|to|in|on|at|from|has|have|had|is|was|are|were)\s+(Mastitis|Hypertension|Pneumonia|Laryngitis|Bronchitis|Sepsis|Anaemia|Anemia|Diabetes|Asthma|Gout|Eczema|Psoriasis|Dermatitis|Cellulitis|Appendicitis|Gastritis|Colitis|Cystitis|Meningitis|Encephalitis|Thrombosis|Embolism|Infarction|Abscess|Gingivitis|Pharyngitis|Tonsillitis|Sinusitis|Otitis|Urethritis|Prostatitis|Endocarditis|Pericarditis|Myocarditis|Pancreatitis|Cholecystitis|Hepatitis|Nephritis|Glomerulonephritis)\b/.test(
            t
        );
    }

    function isWhatToWhichRegression(current, suggested) {
        const cur = normalizeOptionalSuggestionText(current).toLowerCase();
        const sug = normalizeOptionalSuggestionText(suggested).toLowerCase();
        if (cur === "" || sug === "") {
            return false;
        }
        const currentHasWhat = /\bwhat\b/.test(cur);
        const suggestedHasWhichOnly = /\bwhich\b/.test(sug) && !/\bwhat\b/.test(sug);
        return currentHasWhat && suggestedHasWhichOnly;
    }

    function validateOptionalStyleRegression(suggested, current, panelField) {
        const text = normalizeOptionalSuggestionText(suggested);
        if (text === "") {
            return { valid: true, reason: "" };
        }
        if (panelField === "stem") {
            const stemObs = validateStemObservationGrammar(text, current);
            if (!stemObs.valid) {
                return stemObs;
            }
        } else if (suggestedObservationGrammarIsUnsafe(current, text, panelField)) {
            return { valid: false, reason: "style_grammar_fragment" };
        }
        if (panelField !== "stem" && hasMixedObservationStyle(text)) {
            return { valid: false, reason: "style_mixed_observation" };
        }
        if (hasIncorrectSpeciesCapitalisation(text)) {
            return { valid: false, reason: "style_species_caps" };
        }
        if (hasMidSentenceCapitalizedCondition(text)) {
            return { valid: false, reason: "style_condition_caps" };
        }
        if (panelField === "lead_in" && isWhatToWhichRegression(current, text)) {
            return { valid: false, reason: "style_what_to_which" };
        }
        return { valid: true, reason: "" };
    }

    function isLikelyPartialSubstring(current, suggested) {
        if (!current || !suggested) {
            return false;
        }
        if (suggested.length >= current.length * 0.85) {
            return false;
        }
        const sLower = suggested.toLowerCase();
        const cLower = current.toLowerCase();
        if (sLower.length >= 30 && cLower.includes(sLower)) {
            return true;
        }
        const probe = sLower.slice(0, Math.min(48, sLower.length));
        if (probe.length >= 24) {
            const idx = cLower.indexOf(probe);
            if (idx > 30) {
                return true;
            }
        }
        return false;
    }

    function validateStemOptionalSuggestion(variant, edit) {
        const suggested = normalizeOptionalSuggestionText(edit.suggested_text);
        const current = getOptionalSuggestionCurrentValue(variant, "stem", edit);

        if (suggested === "") {
            return { valid: false, reason: "empty_suggested" };
        }
        const wordingCheck = validateFieldWordingIntegrity(suggested, current, "stem");
        if (!wordingCheck.valid) {
            return wordingCheck;
        }
        const observationPolicy = validateStemObservationWordingPolicy(suggested, current);
        if (!observationPolicy.valid) {
            return observationPolicy;
        }
        if (isLikelyPartialSubstring(current, suggested)) {
            return { valid: false, reason: "partial_substring" };
        }
        if (current.length >= 80 && suggested.length < current.length * 0.55) {
            return { valid: false, reason: "much_shorter" };
        }
        if (looksLikeVignetteOpening(current) && looksLikeMidVignetteFragment(suggested)) {
            return { valid: false, reason: "mid_vignette_fragment" };
        }
        if (
            textHasPatientContext(current) &&
            !textHasPatientContext(suggested) &&
            current.length > suggested.length * 1.15
        ) {
            return { valid: false, reason: "missing_patient_context" };
        }
        if (
            textHasClinicalDetailMarkers(current) &&
            !textHasClinicalDetailMarkers(suggested) &&
            suggested.length < current.length * 0.7
        ) {
            return { valid: false, reason: "missing_clinical_details" };
        }
        if (
            looksLikeVignetteOpening(current) &&
            !looksLikeVignetteOpening(suggested) &&
            looksLikeMidVignetteFragment(suggested)
        ) {
            return { valid: false, reason: "not_vignette_opening" };
        }
        const styleCheck = validateOptionalStyleRegression(suggested, current, "stem");
        if (!styleCheck.valid) {
            return styleCheck;
        }
        const normStem = normalizeVariantStemObservationGrammar(suggested);
        const stemObs = validateStemObservationGrammar(normStem.stem, current);
        if (!stemObs.valid) {
            return stemObs;
        }
        return { valid: true, reason: "" };
    }

    function validateLeadInOptionalSuggestion(variant, edit) {
        const suggested = normalizeOptionalSuggestionText(edit.suggested_text);
        const current = getOptionalSuggestionCurrentValue(variant, "lead_in", edit);

        if (suggested === "") {
            return { valid: false, reason: "empty_suggested" };
        }
        if (isLikelyPartialSubstring(current, suggested) && current.length > 30) {
            return { valid: false, reason: "partial_substring" };
        }
        if (current.length > 50 && suggested.length < current.length * 0.5) {
            return { valid: false, reason: "much_shorter" };
        }
        const styleCheck = validateOptionalStyleRegression(suggested, current, "lead_in");
        if (!styleCheck.valid) {
            return styleCheck;
        }
        return { valid: true, reason: "" };
    }

    function validateTitleOptionalSuggestion(variant, edit) {
        const suggested = normalizeOptionalSuggestionText(edit.suggested_text);
        const current = getOptionalSuggestionCurrentValue(variant, "title", edit);

        if (suggested === "") {
            return { valid: false, reason: "empty_suggested" };
        }
        if (suggested.length < 8) {
            return { valid: false, reason: "title_too_short" };
        }
        if (suggested.length > 160) {
            return { valid: false, reason: "title_too_long" };
        }
        if (
            current !== "" &&
            normalizeOptionalSuggestionText(current).toLowerCase() === suggested.toLowerCase()
        ) {
            return { valid: false, reason: "unchanged" };
        }
        if (isLikelyPartialSubstring(current, suggested) && current.length > 20) {
            return { valid: false, reason: "partial_substring" };
        }
        if (hasIncorrectSpeciesCapitalisation(suggested)) {
            return { valid: false, reason: "style_species_caps" };
        }
        return { valid: true, reason: "" };
    }

    function validateJustificationOptionalSuggestion(variant, edit) {
        const suggested = normalizeOptionalSuggestionText(edit.suggested_text);
        const current = getOptionalSuggestionCurrentValue(variant, "justification", edit);

        if (suggested === "" || suggested.length < 12) {
            return { valid: false, reason: "fragmentary" };
        }
        const styleCheck = validateOptionalStyleRegression(suggested, current, "justification");
        if (!styleCheck.valid) {
            return styleCheck;
        }
        return { valid: true, reason: "" };
    }

    function validateOptionOptionalSuggestion(variant, edit) {
        const suggested = normalizeOptionalSuggestionText(edit.suggested_text);

        if (suggested === "") {
            return { valid: false, reason: "empty_suggested" };
        }
        if (/\n\s*[B-E]\s*[.)]/i.test(suggested)) {
            return { valid: false, reason: "multiple_options" };
        }
        if (/(?:^|\n)\s*[A-E]\s*[.)]\s*\S.+\n\s*[A-E]\s*[.)]/i.test(suggested)) {
            return { valid: false, reason: "multiple_options" };
        }
        const stripped = suggested.replace(/^[A-E]\s*[.)]\s*/i, "").trim();
        if (stripped === "" || /^[A-E]\s*[.)]?\s*$/i.test(suggested)) {
            return { valid: false, reason: "empty_option" };
        }
        if (stripped.length > 420) {
            return { valid: false, reason: "too_long_for_option" };
        }
        const panelField = mapOptionalReviewFieldToEditPanel(edit.field) || "option_a";
        const current = getOptionalSuggestionCurrentValue(variant, panelField, edit);
        const styleCheck = validateOptionalStyleRegression(stripped, current, panelField);
        if (!styleCheck.valid) {
            return styleCheck;
        }
        return { valid: true, reason: "" };
    }

    function validateCorrectAnswerOptionalSuggestion(variant, edit) {
        const suggested = normalizeOptionalSuggestionText(edit.suggested_text);

        if (suggested === "") {
            return { valid: false, reason: "empty_suggested" };
        }
        if (/^[A-E]$/i.test(suggested)) {
            return { valid: true, reason: "" };
        }
        if (/\b[A-E]\b/i.test(suggested) && suggested.length <= 120) {
            return { valid: true, reason: "" };
        }
        return { valid: false, reason: "unclear_answer" };
    }

    function validateOptionalFieldSuggestion(variant, edit) {
        const panelField = mapOptionalReviewFieldToEditPanel(edit && edit.field);
        if (!panelField) {
            return { valid: false, reason: "unmapped", panelField: "" };
        }

        const suggestedText = normalizeOptionalSuggestionText(edit && edit.suggested_text);
        const currentText = getOptionalSuggestionCurrentValue(variant, panelField, edit);
        if (panelField !== "correct_answer_letter" && suggestedText !== "") {
            const wordingIntegrity = validateFieldWordingIntegrity(suggestedText, currentText, panelField);
            if (!wordingIntegrity.valid) {
                if (optionalSuggestionRejectIsLogged(wordingIntegrity.reason)) {
                    logOptionalSuggestionBlocked(panelField, wordingIntegrity.reason, edit);
                }
                return {
                    valid: false,
                    reason: wordingIntegrity.reason,
                    panelField: panelField
                };
            }
        }

        let result;
        if (panelField === "stem") {
            result = validateStemOptionalSuggestion(variant, edit);
        } else if (panelField === "lead_in") {
            result = validateLeadInOptionalSuggestion(variant, edit);
        } else if (panelField === "title") {
            result = validateTitleOptionalSuggestion(variant, edit);
        } else if (panelField === "justification") {
            result = validateJustificationOptionalSuggestion(variant, edit);
        } else if (panelField === "correct_answer_letter") {
            result = validateCorrectAnswerOptionalSuggestion(variant, edit);
        } else if (panelField.indexOf("option_") === 0) {
            result = validateOptionOptionalSuggestion(variant, edit);
        } else {
            result = { valid: true, reason: "" };
        }

        if (!result.valid) {
            if (optionalSuggestionRejectIsLogged(result.reason)) {
                logOptionalSuggestionBlocked(panelField, result.reason, edit);
            }
            return { valid: result.valid, reason: result.reason, panelField: panelField };
        }

        const improvementCheck = validateSuggestionClearImprovement(variant, edit, panelField);
        if (!improvementCheck.valid && optionalSuggestionRejectIsLogged(improvementCheck.reason)) {
            logOptionalSuggestionBlocked(panelField, improvementCheck.reason, edit);
        }
        return {
            valid: improvementCheck.valid,
            reason: improvementCheck.reason,
            panelField: panelField
        };
    }

    function isOptionalFieldSuggestionAcceptable(variant, edit) {
        if (!optionalSuggestionHasContent(edit)) {
            return false;
        }
        const panelField = mapOptionalReviewFieldToEditPanel(edit.field);
        if (!panelField) {
            return false;
        }
        if (normalizeOptionalSuggestionText(edit.suggested_text) === "") {
            return false;
        }
        return validateOptionalFieldSuggestion(variant, edit).valid;
    }

    function getGeneralAndAdvisoryOptionalSuggestions(variant) {
        const review = variant && variant.optional_review;
        if (!review || !Array.isArray(review.suggestions)) {
            return [];
        }
        const ignored = variant.optional_suggestion_ignored_fields || {};
        const out = [];
        review.suggestions.forEach(function (edit, index) {
            if (!optionalSuggestionHasContent(edit)) {
                return;
            }
            const field = String((edit && edit.field) || "").toLowerCase();
            const panelField = mapOptionalReviewFieldToEditPanel(edit.field);
            const acceptableOnField = panelField && isOptionalFieldSuggestionAcceptable(variant, edit);

            if (acceptableOnField) {
                return;
            }

            if (ignored["general:" + index] === true) {
                return;
            }

            const validation = panelField ? validateOptionalFieldSuggestion(variant, edit) : { valid: true, reason: "" };
            let advisoryKind = "general";
            if (panelField && !validation.valid) {
                if (OPTIONAL_OBSERVATION_REJECT_REASONS.has(validation.reason)) {
                    advisoryKind = "observation";
                } else if (OPTIONAL_WORDING_REJECT_REASONS.has(validation.reason)) {
                    advisoryKind = "wording";
                } else if (OPTIONAL_STYLE_REJECT_REASONS.has(validation.reason)) {
                    advisoryKind = "style";
                } else {
                    advisoryKind = "partial";
                }
            }

            out.push({
                edit: edit,
                sourceIndex: index,
                advisoryKind: advisoryKind
            });
        });
        return out;
    }

    function getUnmappedOptionalSuggestions(variant) {
        return getGeneralAndAdvisoryOptionalSuggestions(variant);
    }

    function countMappableOptionalSuggestions(variant) {
        const review = variant && variant.optional_review;
        if (!review || !Array.isArray(review.suggestions) || isVariantOptionalReviewStale(variant)) {
            return 0;
        }
        const ignored = variant.optional_suggestion_ignored_fields || {};
        let count = 0;
        const seen = new Set();
        review.suggestions.forEach(function (edit) {
            const panelField = mapOptionalReviewFieldToEditPanel(edit && edit.field);
            if (
                !panelField ||
                ignored[panelField] ||
                !isOptionalFieldSuggestionAcceptable(variant, edit)
            ) {
                return;
            }
            if (seen.has(panelField)) {
                return;
            }
            seen.add(panelField);
            count += 1;
        });
        return count;
    }

    function getOptionalReviewEditForPanelField(variant, panelField) {
        const review = variant && variant.optional_review;
        if (!review || !Array.isArray(review.suggestions)) {
            return null;
        }
        for (let i = 0; i < review.suggestions.length; i++) {
            const edit = review.suggestions[i];
            if (!edit || typeof edit !== "object") {
                continue;
            }
            if (mapOptionalReviewFieldToEditPanel(edit.field) !== panelField) {
                continue;
            }
            if (isOptionalFieldSuggestionAcceptable(variant, edit)) {
                return edit;
            }
        }
        return null;
    }

    function prepareVariantStemForEdit(stemText) {
        return normalizeVariantStemObservationGrammar(normalizeOptionalSuggestionText(stemText));
    }

    function getOptionalSuggestionValueFromEdit(edit, panelField) {
        if (!edit) {
            return "";
        }
        const suggested = normalizeOptionalSuggestionText(edit.suggested_text);
        if (panelField === "correct_answer_letter") {
            const exact = suggested.match(/^[A-E]$/i);
            if (exact) {
                return exact[0].toUpperCase();
            }
            const embedded = suggested.match(/\b([A-E])\b/i);
            if (embedded) {
                return embedded[1].toUpperCase();
            }
        }
        if (panelField.indexOf("option_") === 0) {
            return suggested.replace(/^[A-E]\s*[.)]\s*/i, "").trim();
        }
        if (panelField === "stem") {
            return prepareVariantStemForEdit(suggested).stem;
        }
        return suggested;
    }

    function optionalReviewFieldSuggestionDiffers(variant, edit) {
        if (!edit || typeof edit !== "object") {
            return false;
        }
        const panelField = mapOptionalReviewFieldToEditPanel(edit.field);
        if (!panelField) {
            return false;
        }
        const suggested = String(edit.suggested_text ?? "").trim();
        if (suggested === "") {
            return false;
        }
        const current = getVariantDraftFieldValue(variant, panelField);
        if (panelField === "correct_answer_letter") {
            const letter = suggested.match(/^[A-E]$/i) ? suggested.toUpperCase() : "";
            if (letter !== "") {
                return normalizeVariantFingerprintText(current) !== letter;
            }
        }
        return normalizeVariantFingerprintText(current) !== normalizeVariantFingerprintText(suggested);
    }

    function isVariantOptionalReviewStale(variant) {
        if (!variant || !variant.optional_review || typeof variant.optional_review !== "object") {
            return false;
        }
        if (!variant.optional_review_content_hash) {
            return false;
        }
        return variant.optional_review_content_hash !== getVariantContentFingerprint(variant);
    }

    function isVariantOptionalReviewCompleteForCurrentVersion(variant) {
        if (
            !variant ||
            !variant.optional_review ||
            typeof variant.optional_review !== "object" ||
            variant.optional_review_loading ||
            variant.optional_review_error
        ) {
            return false;
        }
        if (!variant.optional_review_content_hash) {
            return false;
        }
        return variant.optional_review_content_hash === getVariantContentFingerprint(variant);
    }

    function canRequestVariantOptionalReview(variant) {
        if (!variant || !variant.id) {
            return false;
        }
        if ((variant.status || "Draft") !== "Draft") {
            return false;
        }
        if (!variantReviewRepairPipelineComplete(variant)) {
            return false;
        }
        if (variant.optional_review_loading || variantOptionalReviewRequestsInFlight.has(String(variant.id))) {
            return false;
        }
        if (variant.optional_review_error) {
            return true;
        }
        if (!variant.optional_review || typeof variant.optional_review !== "object") {
            return true;
        }
        return isVariantOptionalReviewStale(variant);
    }

    function countVariantOptionalSuggestions(variant) {
        if (isVariantOptionalReviewStale(variant)) {
            return 0;
        }
        return countMappableOptionalSuggestions(variant) + getUnmappedOptionalSuggestions(variant).length;
    }

    function variantOptionalOverallLabel(overall) {
        const o = String(overall || "").toLowerCase();
        if (o === "good") {
            return "Good";
        }
        if (o === "minor_edit_needed") {
            return "Minor edit needed";
        }
        if (o === "major_edit_needed") {
            return "Major edit needed";
        }
        if (o === "regenerate") {
            return "Regenerate suggested";
        }
        return "Review needed";
    }

    function variantOptionalOverallTone(overall) {
        const o = String(overall || "").toLowerCase();
        if (o === "good") {
            return "success";
        }
        if (o === "minor_edit_needed") {
            return "warn";
        }
        if (o === "regenerate" || o === "major_edit_needed") {
            return "danger";
        }
        return "neutral";
    }

    function renderVariantOptionalKeyConcerns(review) {
        if (!review || typeof review !== "object") {
            return "";
        }
        const checks = review.checks && typeof review.checks === "object" ? review.checks : {};
        const labels = {
            clinical_equivalence: "Clinical equivalence",
            correct_answer_concept: "Answer concept",
            guideline_sensitive_details: "Guideline details",
            mla_style: "MLA style",
            single_best_answer: "Single best answer",
            distractor_quality: "Distractor quality",
            clinical_realism: "Clinical realism"
        };
        const items = [];
        Object.keys(labels).forEach(function (key) {
            const val = String(checks[key] || "").toLowerCase();
            if (val === "pass" || val === "good" || val === "") {
                return;
            }
            if (!["concern", "minor_issues", "major_issues", "unclear"].includes(val)) {
                return;
            }
            items.push(
                `<li><strong>${escapeHtml(labels[key])}:</strong> ${escapeHtml(val.replace(/_/g, " "))}</li>`
            );
        });
        const generalSuggestions = (Array.isArray(review.suggestions) ? review.suggestions : []).filter(function (s) {
            const f = String((s && s.field) || "").toLowerCase();
            return (f === "general" || f === "tags") && String(s.reason || "").trim() !== "";
        });
        generalSuggestions.slice(0, 3).forEach(function (s) {
            items.push(`<li>${escapeHtml(String(s.reason))}</li>`);
        });
        if (items.length === 0) {
            return "";
        }
        return `<div class="ai-support-key-concerns"><p class="ai-support-key-concerns-heading"><strong>Key concerns</strong></p><ul class="generator-ai-review-bullets">${items.join(
            ""
        )}</ul></div>`;
    }

    function renderVariantOptionalReviewPanelContent(variant, rowNumber) {
        if (!generationStarted || reviewQuestions.length === 0) {
            return `<p class="ai-review-empty workspace-empty workspace-empty--compact">Generate a variant to run optional AI review.</p>`;
        }

        if (!variant || !variant.id) {
            return `<p class="ai-support-empty">Generate a variant for this question to run optional AI review.</p>`;
        }

        if (!variantReviewRepairPipelineComplete(variant)) {
            return `<p class="ai-support-empty">Optional AI review is available after automatic repair completes.</p>`;
        }

        const repairCaution = renderVariantOptionalReviewRepairCaution(variant);

        if (variant.optional_review_loading) {
            return `<div class="ai-review-panel-content" aria-live="polite">
                ${repairCaution}
                <div class="ai-support-loading ai-support-loading--with-spinner">
                    <span class="progress-spinner progress-spinner--small" aria-hidden="true"></span>
                    <span class="ai-support-loading-label">Running AI review…</span>
                </div>
            </div>`;
        }

        if (variant.optional_review_error) {
            const canRetry = canRequestVariantOptionalReview(variant);
            return `<div class="ai-review-panel-content">
                ${repairCaution}
                <p class="ai-support-error">${escapeHtml(variant.optional_review_error)}</p>
                <button type="button" class="variant-optional-review-run-btn btn btn-secondary" data-row="${rowNumber}"${
                canRetry ? "" : " disabled"
            }>Review variant and suggest edits</button>
            </div>`;
        }

        const review = variant.optional_review;
        if (!review || typeof review !== "object") {
            const canRun = canRequestVariantOptionalReview(variant);
            return `<div class="ai-review-panel-content">
                ${repairCaution}
                <p class="ai-support-empty">AI review has not been run for this variant.</p>
                <button type="button" class="variant-optional-review-run-btn btn btn-secondary" data-row="${rowNumber}"${
                canRun ? "" : " disabled"
            }>Review variant and suggest edits</button>
            </div>`;
        }

        const stale = isVariantOptionalReviewStale(variant);
        const complete = isVariantOptionalReviewCompleteForCurrentVersion(variant);
        const suggestionCount = countVariantOptionalSuggestions(variant);
        const canRun = canRequestVariantOptionalReview(variant);
        const tone = variantOptionalOverallTone(review.overall_review);
        const judgement = variantOptionalOverallLabel(review.overall_review);

        let versionStatusHtml = "";
        if (stale) {
            versionStatusHtml = `<p class="ai-review-version-status ai-review-version-status--stale">Variant has changed since AI review.</p>
                <p class="ai-review-version-note">Previous suggestions may no longer match the current repaired draft.</p>`;
        } else if (complete) {
            versionStatusHtml = `<p class="ai-review-version-status ai-review-version-status--complete">AI review completed for this version.</p>`;
        }

        const keyConcerns = renderVariantOptionalKeyConcerns(review);
        const summaryBlock = review.summary
            ? `<p class="ai-support-summary"><strong>Summary:</strong> ${escapeHtml(String(review.summary))}</p>`
            : "";
        const judgementBlock = `<p class="ai-support-status-line ai-support-status--${escapeHtml(tone)}"><strong>Overall:</strong> ${escapeHtml(
            judgement
        )}</p>`;
        const countLine =
            suggestionCount > 0
                ? `<p class="ai-support-summary">${suggestionCount} suggested field${
                      suggestionCount === 1 ? "" : "s"
                  }</p>`
                : `<p class="ai-support-reminder">No field-level suggestions for the current draft.</p>`;

        const actions = [];
        if (canRun) {
            actions.push(
                `<button type="button" class="variant-optional-review-run-btn btn btn-secondary" data-row="${rowNumber}">${
                    stale ? "Review updated variant" : "Review variant and suggest edits"
                }</button>`
            );
        }
        if (!stale && complete) {
            actions.push(
                `<button type="button" class="variant-open-edit-suggestions-btn btn btn-secondary" data-row="${rowNumber}">Open edit panel with suggestions</button>`
            );
        }
        const actionsRow =
            actions.length > 0
                ? `<div class="ai-support-tab-actions">${actions.join("")}</div>`
                : "";

        return `<div class="ai-review-panel-content">
            ${repairCaution}
            ${versionStatusHtml}
            ${judgementBlock}
            ${summaryBlock}
            ${keyConcerns}
            ${countLine}
            ${actionsRow}
        </div>`;
    }

    function renderVariantOptionalReviewPanel() {
        if (!variantAiReviewPanel) {
            return;
        }

        const question = getCurrentQuestion();
        const rowNumber = question ? Number(question.row_number) : null;
        const variant = rowNumber !== null ? generatedVariantsByRow[rowNumber] || null : null;
        const hasVariant = !!(variant && variant.id && variantReviewRepairPipelineComplete(variant));

        if (variantAiReviewCard) {
            variantAiReviewCard.classList.toggle("card--empty-state", !hasVariant);
        }
        if (variantAiReviewColumnNote) {
            variantAiReviewColumnNote.classList.toggle("hidden", !hasVariant);
        }

        variantAiReviewPanel.innerHTML = renderVariantOptionalReviewPanelContent(variant, rowNumber);

        variantAiReviewPanel.querySelectorAll(".variant-optional-review-run-btn").forEach(function (btn) {
            btn.addEventListener("click", function () {
                const targetRow = Number(this.getAttribute("data-row"));
                requestVariantOptionalReview(targetRow);
            });
        });

        variantAiReviewPanel.querySelectorAll(".variant-open-edit-suggestions-btn").forEach(function (btn) {
            btn.addEventListener("click", function (event) {
                event.preventDefault();
                event.stopPropagation();
                const targetRow = Number(this.getAttribute("data-row"));
                if (Number.isNaN(targetRow)) {
                    const question = getCurrentQuestion();
                    if (question) {
                        openVariantEditPanel(Number(question.row_number), { withSuggestions: true });
                    }
                    return;
                }
                openVariantEditPanel(targetRow, { withSuggestions: true });
            });
        });
    }

    function variantHasRepairFailure(variant) {
        if (!variant) {
            return false;
        }
        const repairError = String(variant.repair_error || variant.advisory_review_error || "").trim();
        if (repairError !== "") {
            return true;
        }
        return variant.repair_applied === false && variantReviewRepairPipelineComplete(variant);
    }

    function buildVariantOptionalReviewSourcePayload(source, variant) {
        const payload = JSON.parse(JSON.stringify(source));
        payload._optional_review_repair_context = {
            repair_applied: variant.repair_applied === true,
            repair_failed: variantHasRepairFailure(variant),
            repair_error: String(variant.repair_error || variant.advisory_review_error || "").trim()
        };
        return payload;
    }

    function applyVariantOptionalReviewSafetyGuards(variant, review) {
        if (!review || typeof review !== "object") {
            return review;
        }
        const out = Object.assign({}, review, {
            checks: Object.assign({}, review.checks || {})
        });
        if (!variantHasRepairFailure(variant)) {
            return out;
        }
        if (String(out.overall_review || "").toLowerCase() === "good") {
            out.overall_review = "major_edit_needed";
        }
        if (out.checks.single_best_answer === "pass") {
            out.checks.single_best_answer = "concern";
        }
        if (out.checks.clinical_realism === "pass") {
            out.checks.clinical_realism = "concern";
        }
        const note =
            "Automatic repair was unavailable; the unrepaired draft may lack key clinical evidence.";
        const summary = String(out.summary || "").trim();
        if (summary === "" || summary.toLowerCase().indexOf("automatic repair") === -1) {
            out.summary = summary === "" ? note : summary + " " + note;
        }
        return out;
    }

    function renderVariantOptionalReviewRepairCaution(variant) {
        if (!variantHasRepairFailure(variant)) {
            return "";
        }
        return `<p class="ai-support-alert ai-support-alert--warn variant-optional-repair-caution" role="note">Automatic repair was unavailable for this variant. AI review should be treated with extra caution.</p>`;
    }

    function requestVariantOptionalReview(rowNumber) {
        const variant = generatedVariantsByRow[rowNumber];
        const source = findSourceQuestionByRow(rowNumber);

        if (!variant || !variant.id || !source) {
            if (variant) {
                variant.optional_review_error =
                    "AI review unavailable. Variant unchanged. Tutor review is still required.";
            }
            renderVariantOptionalReviewPanel();
            saveVariantPageState();
            return;
        }

        if (!canRequestVariantOptionalReview(variant)) {
            return;
        }

        const idKey = String(variant.id);
        if (variantOptionalReviewRequestsInFlight.has(idKey)) {
            return;
        }

        const reviewedHash = getVariantContentFingerprint(variant);
        variantOptionalReviewRequestsInFlight.add(idKey);
        variant.optional_review_loading = true;
        variant.optional_review_error = null;
        saveVariantPageState();
        renderVariantOptionalReviewPanel();

        const body = new FormData();
        body.append("question_id", idKey);
        body.append("source_question_json", JSON.stringify(buildVariantOptionalReviewSourcePayload(source, variant)));

        fetch("../app/api/review_variant_optional.php", {
            method: "POST",
            body: body
        })
            .then(function (response) {
                return response.text();
            })
            .then(function (text) {
                let data;
                try {
                    data = JSON.parse(text);
                } catch (parseError) {
                    console.error("[variant_optional_review] JSON parse error", parseError, text);
                    variant.optional_review = null;
                    variant.optional_review_error =
                        "AI review unavailable. Variant unchanged. Tutor review is still required.";
                    return;
                }

                if (data.ok === true && data.optional_review) {
                    variant.optional_review = applyVariantOptionalReviewSafetyGuards(
                        variant,
                        data.optional_review
                    );
                    variant.optional_review_content_hash = reviewedHash;
                    variant.optional_review_error = null;
                    variant.optional_suggestion_ignored_fields = {};
                } else {
                    variant.optional_review = null;
                    variant.optional_review_error =
                        String(data.tutor_message || "").trim() ||
                        "AI review unavailable. Variant unchanged. Tutor review is still required.";
                    console.error("[variant_optional_review]", data.detail || data.error || "");
                }
            })
            .catch(function (error) {
                console.error("[variant_optional_review] network error", error);
                variant.optional_review = null;
                variant.optional_review_error =
                    "AI review unavailable. Variant unchanged. Tutor review is still required.";
            })
            .finally(function () {
                variant.optional_review_loading = false;
                variantOptionalReviewRequestsInFlight.delete(idKey);
                saveVariantPageState();
                renderVariantOptionalReviewPanel();
                renderGeneratedQuestionOnly();
            });
    }

    function variantPostRepairQualityLabel(quality) {
        const q = String(quality || "").toLowerCase();
        if (q === "good") {
            return "Good";
        }
        if (q === "minor_edit_needed") {
            return "Minor edit needed";
        }
        if (q === "major_edit_needed") {
            return "Major edit needed";
        }
        if (q === "regenerate") {
            return "Regenerate suggested";
        }
        return "Review needed";
    }

    function variantPostRepairQualityTone(quality) {
        const q = String(quality || "").toLowerCase();
        if (q === "good") {
            return "good";
        }
        if (q === "minor_edit_needed") {
            return "minor";
        }
        if (q === "regenerate") {
            return "regenerate";
        }
        return "major";
    }

    function variantPostRepairPipelineComplete(variant) {
        return (
            variant &&
            !variant.post_repair_review_loading &&
            (variant.post_repair_review !== null || !!variant.post_repair_review_error)
        );
    }

    function renderVariantPostRepairCompactLine(variant) {
        if (!variant) {
            return "";
        }

        if (variant.post_repair_review_loading) {
            return `
                <p class="variant-post-repair-line variant-post-repair-line--loading" aria-live="polite">
                    <span class="variant-repair-notice-spinner-wrap" aria-hidden="true"><span class="progress-spinner progress-spinner--small"></span></span>
                    Post-repair reviewer running…
                </p>
            `;
        }

        if (variant.post_repair_review_error) {
            return `
                <p class="variant-post-repair-line variant-post-repair-line--unavailable" role="status">
                    Post-repair reviewer unavailable
                </p>
            `;
        }

        const review = variant.post_repair_review;
        if (!review || typeof review !== "object") {
            if (variant.advisory_review_loading) {
                return "";
            }
            return "";
        }

        const quality = variantPostRepairQualityLabel(review.post_repair_quality);
        const tone = variantPostRepairQualityTone(review.post_repair_quality);

        return `
            <p class="variant-post-repair-line variant-post-repair-line--${escapeHtml(tone)}" role="status">
                <strong>Post-repair reviewer:</strong> ${escapeHtml(quality)}
            </p>
            <p class="variant-post-repair-advisory-note">Suggestions are advisory only. Tutor review and manual <strong>Done</strong> are still required before export.</p>
        `;
    }

    function renderVariantPostRepairSuggestionsDropdown(variant, rowNumber) {
        if (!variant) {
            return "";
        }

        if (variant.post_repair_review_loading) {
            return "";
        }

        const review = variant.post_repair_review;
        const hasReview = review && typeof review === "object";
        const hasError = !!variant.post_repair_review_error;

        if (!hasReview && !hasError) {
            return "";
        }

        let inner = "";

        if (hasError) {
            inner += `
                <div class="variant-post-repair-details-section">
                    <p class="variant-post-repair-details-error">${escapeHtml(String(variant.post_repair_review_error))}</p>
                </div>
            `;
        }

        if (hasReview) {
            const scoreLine = (label, value) => {
                const v = escapeHtml(String(value || "—"));
                return `<span class="variant-advisory-score"><strong>${escapeHtml(label)}:</strong> ${v}</span>`;
            };

            const suggestions = Array.isArray(review.suggestions) ? review.suggestions : [];
            const suggestionsHtml =
                suggestions.length > 0
                    ? `<ul class="variant-post-repair-suggestions-list">${suggestions
                          .map((s) => {
                              const area = escapeHtml(String(s.area || "general"));
                              const priority = escapeHtml(String(s.priority || "medium"));
                              const current = escapeHtml(String(s.current_text || ""));
                              const suggested = escapeHtml(String(s.suggested_text || ""));
                              const reason = escapeHtml(String(s.reason || ""));
                              return `<li class="variant-post-repair-suggestion-item">
                                <span class="variant-post-repair-suggestion-meta"><strong>${area}</strong> · ${priority} priority</span>
                                ${current ? `<p class="variant-post-repair-suggestion-current"><strong>Current:</strong> ${current}</p>` : ""}
                                ${suggested ? `<p class="variant-post-repair-suggestion-suggested"><strong>Suggested:</strong> ${suggested}</p>` : ""}
                                ${reason ? `<p class="variant-post-repair-suggestion-reason">${reason}</p>` : ""}
                            </li>`;
                          })
                          .join("")}</ul>`
                    : `<p class="variant-advisory-review-muted">No field-level suggestions.</p>`;

            inner += `
                <p class="variant-post-repair-summary">${escapeHtml(String(review.summary || ""))}</p>
                <p class="variant-advisory-subheading"><strong>Quality:</strong> ${escapeHtml(variantPostRepairQualityLabel(review.post_repair_quality))}</p>
                <div class="variant-advisory-scores variant-post-repair-scores">
                    ${scoreLine("Clinical equivalence", review.clinical_equivalence)}
                    ${scoreLine("Answer concept", review.correct_answer_concept)}
                    ${scoreLine("Guideline details", review.guideline_sensitive_details)}
                    ${scoreLine("MLA style", review.mla_style)}
                    ${scoreLine("Single best answer", review.single_best_answer)}
                    ${scoreLine("Clinical realism", review.clinical_realism)}
                </div>
                <div class="variant-post-repair-details-section">
                    <p class="variant-advisory-subheading"><strong>Suggestions</strong></p>
                    ${suggestionsHtml}
                </div>
                <div class="variant-post-repair-actions">
                    <button type="button" class="btn btn-secondary variant-open-edit-panel-btn" data-row="${rowNumber}">Open edit panel</button>
                </div>
            `;
        }

        return `
            <details class="variant-post-repair-details">
                <summary class="variant-post-repair-details-summary">Reviewer suggestions</summary>
                <div class="variant-post-repair-details-body">
                    <p class="variant-post-repair-details-note">Advisory only — apply edits manually in the edit panel. This does not approve the question.</p>
                    ${inner}
                </div>
            </details>
        `;
    }

    function renderVariantPostRepairReviewSection(variant, rowNumber) {
        if (!variant) {
            return "";
        }
        if (!variant.advisory_review_loading && !variantReviewRepairPipelineComplete(variant) && !variant.post_repair_review_loading && !variantPostRepairPipelineComplete(variant)) {
            return "";
        }

        return `
            <div class="variant-post-repair-panel">
                ${renderVariantPostRepairCompactLine(variant)}
                ${renderVariantPostRepairSuggestionsDropdown(variant, rowNumber)}
            </div>
        `;
    }

    function variantSnapshotForRepair(variant) {
        return {
            title: variant.title || "",
            stem: variant.stem || "",
            lead_in: variant.lead_in || "",
            option_a: variant.option_a || "",
            option_b: variant.option_b || "",
            option_c: variant.option_c || "",
            option_d: variant.option_d || "",
            option_e: variant.option_e || "",
            correct_answer_letter: variant.correct_answer_letter || "",
            correct_answer: variant.correct_answer || "",
            justification: variant.justification || ""
        };
    }

    /**
     * Variant-only post-repair / post-generate stem normalisation for clipped observation grammar.
     * @returns {{ stem: string, changed: boolean, needsReview: boolean }}
     */
    function normalizeVariantStemObservationGrammar(stem) {
        let s = String(stem || "");
        const original = s;

        if (s === "" || (isListStyleObservationPhrase(s) && !hasPossessiveVitalGrammarFragment(s))) {
            return {
                stem: s,
                changed: false,
                needsReview: hasPossessiveVitalGrammarFragment(s)
            };
        }

        const hasPossessiveContext =
            /\b(?:His|Her|Their|The)\s+pulse\s/i.test(s) ||
            /\b(?:His|Her|Their)\s+/i.test(s) ||
            hasPossessiveVitalGrammarFragment(s);

        if (!hasPossessiveContext) {
            return {
                stem: s,
                changed: false,
                needsReview: hasPossessiveVitalGrammarFragment(s)
            };
        }

        s = s.replace(/\b(His|Her|Their|The)\s+pulse\s+(\d+)/gi, "$1 pulse is $2");
        s = s.replace(/,\s*pulse\s+(?!is\s)(\d+)\s+bpm/gi, ", pulse is $1 bpm");
        s = s.replace(/\band\s+pulse\s+(?!is\s)(\d+)\s+bpm/gi, "and pulse is $1 bpm");
        s = s.replace(/\b(His|Her|Their)\s+BP\s+(\d+\s*\/\s*\d+)/gi, "$1 blood pressure is $2");
        s = s.replace(/\b(His|Her|Their)\s+blood\s+pressure\s+(\d+\s*\/\s*\d+)/gi, "$1 blood pressure is $2");
        s = s.replace(/,\s*BP\s+(\d+\s*\/\s*\d+)/gi, ", blood pressure is $1");
        s = s.replace(/,\s*blood\s+pressure\s+(?!is\s)(\d+\s*\/\s*\d+)/gi, ", blood pressure is $1");
        s = s.replace(/\band\s+BP\s+(\d+\s*\/\s*\d+)/gi, "and blood pressure is $1");
        s = s.replace(/\band\s+blood\s+pressure\s+(?!is\s)(\d+\s*\/\s*\d+)/gi, "and blood pressure is $1");
        s = s.replace(/,\s*respiratory\s+rate\s+(?!is\s)(\d+)\s+breaths/gi, ", respiratory rate is $1 breaths");
        s = s.replace(/\band\s+respiratory\s+rate\s+(?!is\s)(\d+)\s+breaths/gi, "and respiratory rate is $1 breaths");
        s = s.replace(/\b(His|Her|Their)\s+(heart\s+rate|HR)\s+(?!is\s)(\d+)/gi, "$1 $2 is $3");
        s = s.replace(/\b(His|Her|Their)\s+(temperature|temp)\s+(?!is\s)(\d+)/gi, "$1 $2 is $3");
        s = s.replace(/\b(His|Her|Their)\s+(respiratory\s+rate|RR)\s+(?!is\s)(\d+)/gi, "$1 $2 is $3");
        s = s.replace(/\b(His|Her|Their)\s+oxygen\s+saturation\s+(?!is\s)(\d+)/gi, "$1 oxygen saturation is $2");

        return {
            stem: s,
            changed: s !== original,
            needsReview: hasPossessiveVitalGrammarFragment(s)
        };
    }

    function applyVariantStemObservationGrammarToVariant(variant) {
        if (!variant || typeof variant !== "object") {
            return;
        }
        const norm = normalizeVariantStemObservationGrammar(variant.stem || "");
        variant.stem = norm.stem;
        variant.stem_observation_grammar_warning = norm.needsReview
            ? "Observation wording in the stem may need manual review (for example pulse or blood pressure phrasing). Tutor check is still required."
            : null;
    }

    function mergeRepairedVariantFields(variant, question) {
        if (!question || typeof question !== "object") {
            return;
        }
        const fields = [
            "title",
            "stem",
            "lead_in",
            "option_a",
            "option_b",
            "option_c",
            "option_d",
            "option_e",
            "correct_answer_letter",
            "correct_answer",
            "justification"
        ];
        fields.forEach((field) => {
            if (Object.prototype.hasOwnProperty.call(question, field)) {
                variant[field] = question[field];
            }
        });
        applyVariantStemObservationGrammarToVariant(variant);
        if (Object.prototype.hasOwnProperty.call(question, "status")) {
            variant.status = question.status;
        } else {
            variant.status = "Draft";
        }
    }

    function requestVariantRepairFromReview(rowNumber, variant, advisoryReview) {
        const source = findSourceQuestionByRow(rowNumber);
        if (!variant || !variant.id || !source || !advisoryReview) {
            variant.repair_error =
                "Automatic repair unavailable. Variant remains Draft and tutor review is still required.";
            return Promise.resolve();
        }

        const body = new FormData();
        body.append("question_id", String(variant.id));
        body.append("source_question_json", JSON.stringify(source));
        body.append("advisory_review_json", JSON.stringify(advisoryReview));

        return fetch("../app/api/repair_variant_from_review.php", {
            method: "POST",
            body: body
        })
            .then((response) => response.text())
            .then((text) => {
                let data;
                try {
                    data = JSON.parse(text);
                } catch (parseError) {
                    console.error("[variant_repair] JSON parse error", parseError, text);
                    variant.repair_error =
                        "Automatic repair unavailable. Variant remains Draft and tutor review is still required.";
                    return;
                }

                if (data.ok === true) {
                    variant.repair_applied = data.repair_applied === true;
                    variant.change_log = Array.isArray(data.change_log) ? data.change_log : [];
                    variant.repair_error = String(data.repair_error || "").trim() || null;
                    if (data.repair_applied === true && data.question) {
                        mergeRepairedVariantFields(variant, data.question);
                    }
                    if (data.repair_blocked === true && !variant.repair_error) {
                        variant.repair_applied = false;
                        variant.change_log = [];
                        variant.repair_blocked = true;
                    } else {
                        variant.repair_blocked = false;
                    }
                } else {
                    variant.repair_applied = false;
                    variant.change_log = [];
                    variant.repair_error =
                        String(data.repair_error || "").trim() ||
                        "Automatic repair unavailable. Variant remains Draft and tutor review is still required.";
                    console.error("[variant_repair]", data.detail || data.error || "");
                }
            })
            .catch((error) => {
                console.error("[variant_repair] network error", error);
                variant.repair_applied = false;
                variant.change_log = [];
                variant.repair_error =
                    "Automatic repair unavailable. Variant remains Draft and tutor review is still required.";
            });
    }

    function requestVariantPostRepairReview(rowNumber, variant) {
        const source = findSourceQuestionByRow(rowNumber);
        if (!variant || !variant.id || !source) {
            variant.post_repair_review_error = "Post-repair reviewer unavailable.";
            return Promise.resolve();
        }

        variant.post_repair_review_loading = true;
        variant.post_repair_review_error = null;
        saveVariantPageState();
        renderCurrentReview();
        renderGeneratedQuestionOnly();

        const body = new FormData();
        body.append("question_id", String(variant.id));
        body.append("source_question_json", JSON.stringify(source));
        if (Array.isArray(variant.change_log)) {
            body.append("change_log_json", JSON.stringify(variant.change_log));
        }
        if (variant.advisory_review && typeof variant.advisory_review === "object") {
            body.append("advisory_review_json", JSON.stringify(variant.advisory_review));
        }

        return fetch("../app/api/review_repaired_variant.php", {
            method: "POST",
            body: body
        })
            .then((response) => response.text())
            .then((text) => {
                let data;
                try {
                    data = JSON.parse(text);
                } catch (parseError) {
                    console.error("[variant_post_repair_review] JSON parse error", parseError, text);
                    variant.post_repair_review = null;
                    variant.post_repair_review_error = "Post-repair reviewer unavailable.";
                    return;
                }

                if (data.ok === true && data.post_repair_review) {
                    variant.post_repair_review = data.post_repair_review;
                    variant.post_repair_review_phase = data.review_phase || "post_repair";
                    variant.post_repair_review_error = null;
                } else {
                    variant.post_repair_review = null;
                    variant.post_repair_review_error =
                        String(data.tutor_message || "").trim() || "Post-repair reviewer unavailable.";
                    console.error("[variant_post_repair_review]", data.detail || data.error || "");
                }
            })
            .catch((error) => {
                console.error("[variant_post_repair_review] network error", error);
                variant.post_repair_review = null;
                variant.post_repair_review_error = "Post-repair reviewer unavailable.";
            })
            .finally(() => {
                variant.post_repair_review_loading = false;
                saveVariantPageState();
                renderCurrentReview();
                renderGeneratedQuestionOnly();
            });
    }

    function requestVariantReviewAndRepair(rowNumber, variant) {
        const source = findSourceQuestionByRow(rowNumber);
        if (!variant || !variant.id || !source) {
            if (variant) {
                variant.advisory_review_loading = false;
                variant.repair_error =
                    "Automatic repair unavailable. Variant remains Draft and tutor review is still required.";
                saveVariantPageState();
                renderCurrentReview();
            }
            return Promise.resolve();
        }

        clearVariantReviewRepairState(variant);
        variant.variant_pre_repair_snapshot = variantSnapshotForRepair(variant);
        variant.advisory_review_loading = true;
        saveVariantPageState();
        renderCurrentReview();

        const reviewBody = new FormData();
        reviewBody.append("question_id", String(variant.id));
        reviewBody.append("source_question_json", JSON.stringify(source));

        return fetch("../app/api/review_variant_advisory.php", {
            method: "POST",
            body: reviewBody
        })
            .then((response) => response.text())
            .then((text) => {
                let data;
                try {
                    data = JSON.parse(text);
                } catch (parseError) {
                    console.error("[variant_advisory_review] JSON parse error", parseError, text);
                    variant.advisory_review = null;
                    variant.repair_error =
                        "Automatic repair unavailable. Variant remains Draft and tutor review is still required.";
                    return;
                }

                if (data.ok === true && data.advisory_review) {
                    variant.advisory_review = data.advisory_review;
                    variant.advisory_review_phase = data.review_phase || "pre_repair";
                    variant.advisory_review_error = null;
                    return requestVariantRepairFromReview(rowNumber, variant, data.advisory_review).then(function () {
                        return requestVariantPostRepairReview(rowNumber, variant);
                    });
                }

                variant.advisory_review = null;
                variant.repair_error =
                    String(data.tutor_message || "").trim() ||
                    "Automatic repair unavailable. Variant remains Draft and tutor review is still required.";
                console.error("[variant_advisory_review]", data.detail || data.error || "");
                return requestVariantPostRepairReview(rowNumber, variant);
            })
            .catch((error) => {
                console.error("[variant_review_repair] network error", error);
                variant.advisory_review = null;
                variant.repair_error =
                    "Automatic repair unavailable. Variant remains Draft and tutor review is still required.";
                return requestVariantPostRepairReview(rowNumber, variant);
            })
            .finally(() => {
                variant.advisory_review_loading = false;
                saveVariantPageState();
                renderCurrentReview();
                renderGeneratedQuestionOnly();
                renderExportReadyList();
            });
    }

    function continueVariantGenerationLoop(jobId, data) {
        if (data.job_status === "running") {
            generateNextVariant(jobId);
            return;
        }

        generationInProgress = false;
        updateSelectionSummary();
        setGenerationSuccess(
            "Generation complete.",
            "Total generated: " + (data.num_questions || 0) + " question(s)"
        );
        saveVariantPageState();
    }

    function renderVariantBody(variant, rowNumber) {
        if (!variant) {
            if (generationStarted && generationInProgress) {
                return renderVariantPipelineStatusHtml("generating", "Generating variant question…");
            }

            if (generationStarted) {
                return "<p class='variant-placeholder'>No variant available for this question.</p>";
            }

            return "<p class='variant-placeholder'>No variant generated yet.</p>";
        }

        const letter = String(variant.correct_answer_letter || "").trim().toUpperCase();
        const expectedByLetter = {
            A: String(variant.option_a || ""),
            B: String(variant.option_b || ""),
            C: String(variant.option_c || ""),
            D: String(variant.option_d || ""),
            E: String(variant.option_e || "")
        };
        const expectedAnswer = Object.prototype.hasOwnProperty.call(expectedByLetter, letter)
            ? expectedByLetter[letter]
            : "";
        const storedAnswer = String(variant.correct_answer || "");
        const showMismatchWarning = expectedAnswer !== "" && storedAnswer.trim() !== expectedAnswer.trim();
        const mismatchWarningHtml = showMismatchWarning
            ? `<p class="question-inline-warn">The saved correct-answer text does not match the letter selected. Use <strong>Edit</strong> to fix.</p>`
            : "";

        return `
            <div class="question-card question-card-compact" data-row="${rowNumber}">
                <div class="question-card-content">
                    ${renderVariantRepairCompactNotice(variant)}

                    <header class="question-card-header">
                        <hr class="question-card-divider question-card-divider--top" aria-hidden="true">
                        <h3 class="question-card-title">${escapeHtml(variant.title || "Untitled question")}</h3>
                        ${renderVariantQuestionMetadata(variant)}
                        ${renderVariantQuestionStatusBar(variant)}
                        <hr class="question-card-divider question-card-divider--after-status" aria-hidden="true">
                    </header>

                    <article class="question-read-body">
                        <p class="question-read-stem">${escapeHtml(variant.stem || "")}</p>
                        <p class="question-read-leadin"><strong>${escapeHtml(variant.lead_in || "")}</strong></p>
                        <ul class="question-read-options">
                            <li><span class="question-opt-label">A.</span> ${escapeHtml(variant.option_a || "")}</li>
                            <li><span class="question-opt-label">B.</span> ${escapeHtml(variant.option_b || "")}</li>
                            <li><span class="question-opt-label">C.</span> ${escapeHtml(variant.option_c || "")}</li>
                            <li><span class="question-opt-label">D.</span> ${escapeHtml(variant.option_d || "")}</li>
                            <li><span class="question-opt-label">E.</span> ${escapeHtml(variant.option_e || "")}</li>
                        </ul>
                        <p class="question-read-key"><strong>Correct answer:</strong> ${escapeHtml(
                            letter || variant.correct_answer_letter || ""
                        )}${storedAnswer !== "" ? ` — ${escapeHtml(storedAnswer)}` : ""}</p>
                        ${mismatchWarningHtml}
                        <p class="question-read-justification"><strong>Justification:</strong> ${escapeHtml(
                            variant.justification || ""
                        )}</p>
                    </article>

                    <hr class="question-card-divider question-card-divider--before-actions" aria-hidden="true">
                    <div class="question-actions question-actions-primary">
                        <button type="button" class="mark-done-btn btn btn-primary btn--small" data-row="${rowNumber}">Approve for export</button>
                        <button type="button" class="edit-variant-btn btn btn-secondary btn--small" data-row="${rowNumber}">Edit</button>
                        <button type="button" class="reject-btn btn btn-danger btn--small" data-row="${rowNumber}">Reject</button>
                        <button type="button" class="regenerate-btn btn btn-secondary btn--small" data-row="${rowNumber}">Regenerate</button>
                    </div>
                </div>
            </div>
        `;
    }

    function updateOriginalIncludeToolsVisibility() {
        const show = reviewQuestions.length > 0 && !!getCurrentQuestion();
        if (originalIncludeToolsRow) {
            originalIncludeToolsRow.classList.toggle("hidden", !show);
        }
    }

    function syncCurrentCheckbox() {
        const question = getCurrentQuestion();

        if (!question || !currentIncludeCheckbox) {
            updateOriginalIncludeToolsVisibility();
            return;
        }

        currentIncludeCheckbox.checked = selectedRows.has(Number(question.row_number));
        currentIncludeCheckbox.disabled = generationStarted;
        if (includeQuestionWrapper) {
            includeQuestionWrapper.classList.toggle("disabled", generationStarted);
        }
        updateOriginalIncludeToolsVisibility();
    }

    function renderOriginalQuestionOnly() {
        if (!originalQuestionBody) return;

        if (reviewQuestions.length === 0) {
            originalQuestionBody.innerHTML =
                "<p class='workspace-empty workspace-empty--compact'>Upload a RISR file to begin.</p>";
            updateOriginalIncludeToolsVisibility();
            return;
        }

        const question = getCurrentQuestion();

        if (!question) {
            originalQuestionBody.innerHTML = "<p class='variant-review-empty'>No question available.</p>";
            updateOriginalIncludeToolsVisibility();
            return;
        }

        originalQuestionBody.innerHTML = renderOriginalQuestionBody(question);
        syncCurrentCheckbox();
    }

    function renderGeneratedQuestionOnly() {
        if (!generatedQuestionBody) return;

        if (reviewQuestions.length === 0) {
            generatedQuestionBody.innerHTML =
                "<p class='workspace-empty workspace-empty--compact'>No variant generated yet.</p>";
            return;
        }

        const question = getCurrentQuestion();

        if (!question) {
            generatedQuestionBody.innerHTML =
                "<p class='workspace-empty workspace-empty--compact'>No variant generated yet.</p>";
            return;
        }

        const rowNumber = Number(question.row_number);
        const variant = generatedVariantsByRow[rowNumber] || null;

        generatedQuestionBody.innerHTML = renderVariantBody(variant, rowNumber);

        const editButton = generatedQuestionBody.querySelector(".edit-variant-btn");
        if (editButton) {
            editButton.addEventListener("click", function () {
                const targetRow = Number(this.getAttribute("data-row"));
                openVariantEditPanel(targetRow);
            });
        }

        const doneButton = generatedQuestionBody.querySelector(".mark-done-btn");
        if (doneButton) {
            doneButton.addEventListener("click", function () {
                const targetRow = Number(this.getAttribute("data-row"));
                updateVariantStatus(targetRow, "Done");
            });
        }

        const rejectButton = generatedQuestionBody.querySelector(".reject-btn");
        if (rejectButton) {
            rejectButton.addEventListener("click", function () {
                const targetRow = Number(this.getAttribute("data-row"));
                updateVariantStatus(targetRow, "Rejected");
            });
        }

        const regenerateButton = generatedQuestionBody.querySelector(".regenerate-btn");
        if (regenerateButton) {
            regenerateButton.addEventListener("click", function () {
                const targetRow = Number(this.getAttribute("data-row"));
                regenerateVariant(targetRow);
            });
        }
    }

    function renderCurrentReview() {
        updateVariantFilterChrome();
        updateCounter();
        updateNavigationButtons();
        renderJumpSelect();
        renderExportReadyList();
        renderOriginalQuestionOnly();
        renderGeneratedQuestionOnly();
        renderVariantOptionalReviewPanel();
    }

    function fieldHasActiveOptionalSuggestion(variant, panelField, withSuggestions) {
        if (!withSuggestions || !variant || isVariantOptionalReviewStale(variant)) {
            return false;
        }
        const ignored = variant.optional_suggestion_ignored_fields || {};
        if (ignored[panelField]) {
            return false;
        }
        return !!getOptionalReviewEditForPanelField(variant, panelField);
    }

    function getOptionalSuggestionValueForEditField(variant, panelField) {
        const edit = getOptionalReviewEditForPanelField(variant, panelField);
        if (!edit || !isOptionalFieldSuggestionAcceptable(variant, edit)) {
            return "";
        }
        return getOptionalSuggestionValueFromEdit(edit, panelField);
    }

    function syncVariantCorrectAnswerTextFromLetter() {
        const letterEl = document.getElementById("variant-edit-correct-letter");
        const answerEl = document.getElementById("variant-edit-correct-answer");
        if (!letterEl || !answerEl) {
            return;
        }
        const letter = String(letterEl.value || "").trim().toUpperCase();
        const optionMap = {
            A: "variant-edit-option-a",
            B: "variant-edit-option-b",
            C: "variant-edit-option-c",
            D: "variant-edit-option-d",
            E: "variant-edit-option-e"
        };
        const optionId = optionMap[letter];
        if (optionId) {
            answerEl.value = document.getElementById(optionId)?.value || "";
        }
    }

    function renderVariantEditFieldSuggestionBlock(variant, panelField, withSuggestions) {
        if (!fieldHasActiveOptionalSuggestion(variant, panelField, withSuggestions)) {
            return "";
        }
        const edit = getOptionalReviewEditForPanelField(variant, panelField);
        let displaySuggested = String((edit && edit.suggested_text) || "").trim();
        if (displaySuggested === "") {
            displaySuggested = getOptionalSuggestionValueForEditField(variant, panelField) || "(empty)";
        }
        const priority = escapeHtml(String((edit && edit.priority) || "medium"));
        const currentHtml =
            edit && edit.current_text
                ? `<p class="variant-edit-suggestion-current"><strong>Current:</strong> ${escapeHtml(
                      String(edit.current_text)
                  )}</p>`
                : "";
        const reasonHtml = edit && edit.reason
            ? `<p class="edit-suggestion-reason">${escapeHtml(String(edit.reason))} <span class="edit-suggestion-priority">(${priority})</span></p>`
            : "";

        return `<div class="edit-field-suggestion" data-field="${escapeHtml(panelField)}">
            <p class="edit-suggestion-heading"><strong>Suggested edit</strong></p>
            ${currentHtml}
            <p class="edit-suggestion-proposed">${escapeHtml(displaySuggested)}</p>
            ${reasonHtml}
            <div class="edit-suggestion-actions">
                <button type="button" class="variant-use-suggestion-btn btn btn-secondary btn--subtle" data-field="${escapeHtml(
                    panelField
                )}">Accept suggestion</button>
                <button type="button" class="variant-keep-current-btn btn btn-secondary btn--subtle" data-field="${escapeHtml(
                    panelField
                )}">Keep current</button>
            </div>
        </div>`;
    }

    function renderVariantEditPanelAlerts(variant, withSuggestions) {
        if (!withSuggestions) {
            return "";
        }
        if (isVariantOptionalReviewStale(variant)) {
            return `<p class="ai-support-alert ai-support-alert--warn" role="note">This variant has changed since AI review. Re-run review or edit without applying stale suggestions.</p>`;
        }
        return `<p class="ai-support-reminder" role="note">Suggestions are advisory. Nothing is saved until you click <strong>Save Changes</strong>.</p>`;
    }

    function renderVariantEditGeneralSuggestions(variant, withSuggestions) {
        if (!withSuggestions || !variant || isVariantOptionalReviewStale(variant)) {
            return "";
        }
        const unmapped = getUnmappedOptionalSuggestions(variant);
        const mappableCount = countMappableOptionalSuggestions(variant);
        let html = "";

        if (mappableCount === 0 && unmapped.length === 0) {
            html += `<p class="variant-edit-no-field-suggestions" role="status">No field-specific suggestions are available for this variant.</p>`;
        }

        if (unmapped.length === 0) {
            return html;
        }

        const items = unmapped
            .map(function (entry) {
                const edit = entry.edit;
                const sourceIndex = entry.sourceIndex;
                const fieldLabel = escapeHtml(String(edit.field || "general"));
                const priority = escapeHtml(String(edit.priority || "medium"));
                const suggested = escapeHtml(String(edit.suggested_text || "").trim() || "(no replacement text)");
                const reason = edit.reason
                    ? `<p class="edit-suggestion-reason">${escapeHtml(String(edit.reason))}</p>`
                    : "";
                const current = edit.current_text
                    ? `<p class="variant-edit-general-current"><strong>Current:</strong> ${escapeHtml(
                          String(edit.current_text)
                      )}</p>`
                    : "";
                let advisoryNoteHtml = "";
                if (entry.advisoryKind === "observation") {
                    advisoryNoteHtml = `<p class="variant-edit-partial-advisory-note variant-edit-observation-advisory-note" role="note">${escapeHtml(
                        VARIANT_OBSERVATION_SUGGESTION_NOTE
                    )}</p>`;
                } else if (entry.advisoryKind === "wording") {
                    advisoryNoteHtml = `<p class="variant-edit-partial-advisory-note variant-edit-wording-advisory-note" role="note">${escapeHtml(
                        VARIANT_WORDING_SUGGESTION_NOTE
                    )}</p>`;
                } else if (entry.advisoryKind === "style") {
                    advisoryNoteHtml = `<p class="variant-edit-partial-advisory-note variant-edit-style-advisory-note" role="note">${escapeHtml(
                        VARIANT_STYLE_SUGGESTION_NOTE
                    )}</p>`;
                } else if (entry.advisoryKind === "partial") {
                    advisoryNoteHtml = `<p class="variant-edit-partial-advisory-note" role="note">${escapeHtml(
                        VARIANT_PARTIAL_SUGGESTION_NOTE
                    )}</p>`;
                }
                return `<div class="edit-field-suggestion variant-edit-general-suggestion variant-edit-general-suggestion--advisory" data-general-index="${sourceIndex}">
                    <p class="edit-suggestion-heading"><strong>${fieldLabel}</strong> <span class="edit-suggestion-priority">(${priority})</span></p>
                    ${advisoryNoteHtml}
                    ${current}
                    <p class="edit-suggestion-proposed">${suggested}</p>
                    ${reason}
                    <div class="edit-suggestion-actions">
                        <button type="button" class="variant-dismiss-general-suggestion-btn btn btn-secondary btn--subtle" data-general-index="${sourceIndex}">Dismiss</button>
                    </div>
                </div>`;
            })
            .join("");

        return `${html}
            <div class="variant-edit-general-suggestions" role="region" aria-label="General suggestions">
                <p class="variant-edit-general-heading"><strong>General suggestions</strong></p>
                ${items}
            </div>`;
    }

    function buildEditPanelHtml(sourceQuestion, variant, options) {
        const withSuggestions = !!(options && options.withSuggestions);
        const fields = [
            ["title", "Title", "textarea", 2],
            ["stem", "Stem", "textarea", 5],
            ["lead_in", "Lead-in", "textarea", 3],
            ["option_a", "Option A", "input"],
            ["option_b", "Option B", "input"],
            ["option_c", "Option C", "input"],
            ["option_d", "Option D", "input"],
            ["option_e", "Option E", "input"]
        ];

        let fieldsHtml = fields
            .map(function (spec) {
                const panelField = spec[0];
                const label = spec[1];
                const inputId = VARIANT_EDIT_PANEL_FIELD_IDS[panelField];
                const value = escapeHtml(getVariantDraftFieldValue(variant, panelField));
                let control = "";
                if (spec[2] === "textarea") {
                    control = `<textarea id="${inputId}" rows="${spec[3]}">${value}</textarea>`;
                } else {
                    control = `<input type="text" id="${inputId}" value="${value}">`;
                }
                return `<div class="edit-field-group">
                    <label for="${inputId}">${escapeHtml(label)}</label>
                    ${control}
                    ${renderVariantEditFieldSuggestionBlock(variant, panelField, withSuggestions)}
                </div>`;
            })
            .join("");

        return `
            <div class="variant-edit-panel variant-edit-panel-standalone">
                <div class="variant-edit-layout">
                    <div class="variant-edit-column">
                        <h4>Variant (Editable)</h4>
                        ${renderVariantEditPanelAlerts(variant, withSuggestions)}
                        ${renderVariantEditGeneralSuggestions(variant, withSuggestions)}

                        ${fieldsHtml}

                        <div class="edit-field-group">
                            <label for="variant-edit-correct-letter">Correct answer letter</label>
                            <input type="text" id="variant-edit-correct-letter" maxlength="1" value="${escapeHtml(
                                variant.correct_answer_letter || ""
                            )}">
                            ${renderVariantEditFieldSuggestionBlock(variant, "correct_answer_letter", withSuggestions)}
                        </div>

                        <div class="edit-field-group">
                            <label for="variant-edit-correct-answer">Correct answer text</label>
                            <input type="text" id="variant-edit-correct-answer" value="${escapeHtml(
                                variant.correct_answer || ""
                            )}" readonly>
                        </div>

                        <div class="edit-field-group">
                            <label for="variant-edit-justification">Justification</label>
                            <textarea id="variant-edit-justification" rows="5">${escapeHtml(
                                variant.justification || ""
                            )}</textarea>
                            ${renderVariantEditFieldSuggestionBlock(variant, "justification", withSuggestions)}
                        </div>

                        <div class="variant-edit-actions">
                            <span id="variant-edit-save-status" class="autosave-status" role="status" aria-live="polite"></span>
                            <button type="button" id="save-variant-btn" class="btn btn-primary">Save Changes</button>
                        </div>
                    </div>
                </div>
            </div>
        `;
    }

    function attachVariantEditPanelHandlers(rowNumber, variant, withSuggestions) {
        ["variant-edit-option-a", "variant-edit-option-b", "variant-edit-option-c", "variant-edit-option-d", "variant-edit-option-e", "variant-edit-correct-letter"].forEach(
            function (id) {
                const el = document.getElementById(id);
                if (el) {
                    el.addEventListener("input", syncVariantCorrectAnswerTextFromLetter);
                    el.addEventListener("change", syncVariantCorrectAnswerTextFromLetter);
                }
            }
        );

        if (!withSuggestions || !editPanel) {
            return;
        }

        editPanel.querySelectorAll(".variant-use-suggestion-btn").forEach(function (btn) {
            btn.addEventListener("click", function () {
                const panelField = btn.getAttribute("data-field") || "";
                const edit = getOptionalReviewEditForPanelField(variant, panelField);
                if (!edit || !isOptionalFieldSuggestionAcceptable(variant, edit)) {
                    return;
                }
                const acceptCheck = validateOptionalFieldSuggestion(variant, edit);
                if (!acceptCheck.valid) {
                    logOptionalSuggestionBlocked(panelField, acceptCheck.reason, edit);
                    if (
                        panelField === "stem" &&
                        OPTIONAL_OBSERVATION_REJECT_REASONS.has(acceptCheck.reason)
                    ) {
                        showInfoModal("Suggestion not applied", VARIANT_OBSERVATION_ACCEPT_BLOCKED_MSG);
                    }
                    return;
                }
                let value = getOptionalSuggestionValueFromEdit(edit, panelField);
                if (panelField === "stem") {
                    const stemPrep = prepareVariantStemForEdit(edit.suggested_text);
                    if (stemPrep.needsReview) {
                        showInfoModal("Suggestion not applied", VARIANT_OBSERVATION_ACCEPT_BLOCKED_MSG);
                        return;
                    }
                    value = stemPrep.stem;
                }
                const inputId = VARIANT_EDIT_PANEL_FIELD_IDS[panelField];
                const el = inputId ? document.getElementById(inputId) : null;
                if (el) {
                    el.value = value;
                    if (panelField === "correct_answer_letter") {
                        syncVariantCorrectAnswerTextFromLetter();
                    }
                }
                const block = btn.closest(".edit-field-suggestion");
                if (block) {
                    block.classList.add("edit-field-suggestion--accepted");
                    block.setAttribute("hidden", "hidden");
                }
            });
        });

        editPanel.querySelectorAll(".variant-keep-current-btn").forEach(function (btn) {
            btn.addEventListener("click", function () {
                const panelField = btn.getAttribute("data-field") || "";
                const block = btn.closest(".edit-field-suggestion");
                if (block) {
                    block.classList.add("edit-field-suggestion--kept");
                    block.setAttribute("hidden", "hidden");
                }
                if (!variant.optional_suggestion_ignored_fields) {
                    variant.optional_suggestion_ignored_fields = {};
                }
                variant.optional_suggestion_ignored_fields[panelField] = true;
                saveVariantPageState();
            });
        });

        editPanel.querySelectorAll(".variant-dismiss-general-suggestion-btn").forEach(function (btn) {
            btn.addEventListener("click", function () {
                const generalIndex = btn.getAttribute("data-general-index") || "";
                const block = btn.closest(".edit-field-suggestion");
                if (block) {
                    block.classList.add("edit-field-suggestion--kept");
                    block.setAttribute("hidden", "hidden");
                }
                if (!variant.optional_suggestion_ignored_fields) {
                    variant.optional_suggestion_ignored_fields = {};
                }
                variant.optional_suggestion_ignored_fields["general:" + generalIndex] = true;
                saveVariantPageState();
            });
        });
    }

    function resolveVariantEditRowNumber(rowNumber) {
        if (Number.isFinite(rowNumber) && rowNumber > 0 && generatedVariantsByRow[rowNumber]) {
            return rowNumber;
        }
        const question = getCurrentQuestion();
        if (question) {
            return Number(question.row_number);
        }
        return null;
    }

    function openVariantEditPanel(rowNumber, options) {
        const withSuggestions = !!(options && options.withSuggestions);
        const resolvedRow = resolveVariantEditRowNumber(Number(rowNumber));
        const sourceQuestion = resolvedRow !== null ? findSourceQuestionByRow(resolvedRow) : null;
        const variant = resolvedRow !== null ? generatedVariantsByRow[resolvedRow] : null;

        if (!sourceQuestion || !variant || !editPanel) {
            showInfoModal("Load failed", "Variant details could not be loaded.");
            return;
        }

        if (withSuggestions) {
            if (!variant.optional_review || typeof variant.optional_review !== "object") {
                showInfoModal(
                    "Suggestions unavailable",
                    "Run AI review on this variant first using Review variant and suggest edits."
                );
                return;
            }
            if (isVariantOptionalReviewStale(variant)) {
                showInfoModal(
                    "Suggestions unavailable",
                    "This variant has changed since AI review. Re-run review on the current version first."
                );
                return;
            }
        }

        currentEditRowNumber = resolvedRow;
        editPanel.innerHTML = buildEditPanelHtml(sourceQuestion, variant, { withSuggestions: withSuggestions });
        attachVariantEditPanelHandlers(resolvedRow, variant, withSuggestions);
        openEditPanel();

        const saveButton = document.getElementById("save-variant-btn");
        if (!saveButton) return;

        saveButton.addEventListener("click", function () {
            const saveRow = resolvedRow;
            const stemEl = document.getElementById("variant-edit-stem");
            const stemPrep = prepareVariantStemForEdit(stemEl ? stemEl.value : "");
            if (stemEl) {
                stemEl.value = stemPrep.stem;
            }
            if (stemPrep.needsReview) {
                setVariantEditSaveStatus("Save blocked", "error");
                showInfoModal("Cannot save", VARIANT_STEM_SAVE_BLOCKED_MSG);
                return;
            }
            setVariantEditSaveStatus("Saving...", "saving");
            const payload = {
                question_id: variant.id,
                title: document.getElementById("variant-edit-title")?.value || "",
                stem: stemPrep.stem,
                lead_in: document.getElementById("variant-edit-lead-in")?.value || "",
                option_a: document.getElementById("variant-edit-option-a")?.value || "",
                option_b: document.getElementById("variant-edit-option-b")?.value || "",
                option_c: document.getElementById("variant-edit-option-c")?.value || "",
                option_d: document.getElementById("variant-edit-option-d")?.value || "",
                option_e: document.getElementById("variant-edit-option-e")?.value || "",
                correct_answer_letter: document.getElementById("variant-edit-correct-letter")?.value || "",
                correct_answer: document.getElementById("variant-edit-correct-answer")?.value || "",
                justification: document.getElementById("variant-edit-justification")?.value || ""
            };

            fetch("../app/api/update_question_content.php", {
                method: "POST",
                body: new URLSearchParams(payload)
            })
                .then(response => response.json())
                .then(data => {
                    if (data.status === "success") {
                        return fetch(`../app/api/get_question.php?question_id=${encodeURIComponent(payload.question_id)}`)
                            .then(response => response.json())
                            .then(reloadData => {
                                if (reloadData.status === "success" && reloadData.question) {
                                    generatedVariantsByRow[saveRow] = {
                                        ...generatedVariantsByRow[saveRow],
                                        ...reloadData.question
                                    };
                                    applyVariantStemObservationGrammarToVariant(
                                        generatedVariantsByRow[saveRow]
                                    );
                                } else {
                                    generatedVariantsByRow[saveRow] = {
                                        ...generatedVariantsByRow[saveRow],
                                        ...payload
                                    };
                                }

                                saveVariantPageState();
                                setVariantEditSaveStatus("Variant saved", "saved");
                                closeEditPanel();
                                renderCurrentReview();
                            })
                            .catch(error => {
                                console.error(error);
                                generatedVariantsByRow[saveRow] = {
                                    ...generatedVariantsByRow[saveRow],
                                    ...payload
                                };
                                saveVariantPageState();
                                setVariantEditSaveStatus("Variant saved", "saved");
                                closeEditPanel();
                                renderCurrentReview();
                            });
                    } else {
                        setVariantEditSaveStatus("Save failed", "error");
                        showInfoModal("Save failed", data.message || "Error saving");
                    }
                })
                .catch(error => {
                    console.error(error);
                    setVariantEditSaveStatus("Save failed", "error");
                    showInfoModal("Save failed", "Error saving");
                });
        });
    }

    function updateVariantStatus(rowNumber, newStatus) {
        const variant = generatedVariantsByRow[rowNumber];

        if (!variant || !variant.id) {
            showInfoModal("Update failed", "Variant not found.");
            return;
        }

        fetch("../app/api/update_question_status.php", {
            method: "POST",
            body: new URLSearchParams({
                question_id: variant.id,
                status: newStatus
            })
        })
            .then(response => response.json())
            .then(data => {
                if (data.status === "success") {
                    generatedVariantsByRow[rowNumber].status = newStatus;
                    renderExportReadyList();
                    renderCurrentReview();
                    saveVariantPageState();
                } else {
                    showInfoModal("Update failed", data.message || "Error updating question status.");
                }
            })
            .catch(error => {
                console.error(error);
                showInfoModal("Update failed", "Error updating question status.");
            });
    }

    function startSingleReplacementGeneration(sourceQuestion) {
        const workspaceId = localStorage.getItem("workspace_id");

        if (!workspaceId) {
            setGenerationError("Preparing workspace...");
            return;
        }

        const formData = new FormData();
        formData.append("workspace_id", workspaceId);
        formData.append("variants_per_question", 1);
        formData.append("selected_questions_json", JSON.stringify([sourceQuestion]));

        fetch("../app/api/start_variant_generation_job.php", {
            method: "POST",
            body: formData
        })
            .then(response => response.json())
            .then(jobData => {
                if (jobData.status === "success") {
                    generationInProgress = true;
                    updateSelectionSummary();
                    setGenerationWorking("Generating replacement variant", "Source row: " + sourceQuestion.row_number);
                    openPanel(generatedPanel);
                    saveVariantPageState();
                    generateNextVariant(jobData.job_id);
                } else {
                    setGenerationError(jobData.message || "Could not start generation job.");
                }
            })
            .catch(error => {
                console.error(error);
                setGenerationError("Could not start generation job.");
            });
    }

    function regenerateVariant(rowNumber) {
        const sourceQuestion = findSourceQuestionByRow(rowNumber);
        const variant = generatedVariantsByRow[rowNumber];

        if (!sourceQuestion || !variant || !variant.id) {
            showInfoModal("Regeneration failed", "Could not recover the source question for regeneration.");
            return;
        }

        showConfirmModal(
            "Confirm regeneration",
            "Delete this variant and generate a replacement?",
            function () {
                fetch("../app/api/delete_question.php", {
                    method: "POST",
                    body: new URLSearchParams({
                        question_id: variant.id
                    })
                })
                    .then(response => response.json())
                    .then(data => {
                        if (data.status !== "success") {
                            showInfoModal("Delete failed", data.message || "Error deleting variant question.");
                            return;
                        }

                        delete generatedVariantsByRow[rowNumber];

                        if (currentEditRowNumber && Number(currentEditRowNumber) === Number(rowNumber)) {
                            closeEditPanel();
                        }

                        renderExportReadyList();
                        renderGeneratedQuestionOnly();
                        saveVariantPageState();
                        startSingleReplacementGeneration(sourceQuestion);
                    })
                    .catch(error => {
                        console.error(error);
                        showInfoModal("Delete failed", "Error deleting variant question.");
                    });
            }
        );
    }

    function generateNextVariant(jobId) {
        const formData = new FormData();
        formData.append("job_id", jobId);

        fetch("../app/api/generate_next_variant.php", {
            method: "POST",
            body: formData
        })
            .then(response => response.text())
            .then(text => {
                let data;

                try {
                    data = JSON.parse(text);
                } catch (error) {
                    console.error(error);
                    generationInProgress = false;
                    updateSelectionSummary();
                    setGenerationError("Generation failed: backend returned invalid JSON.", text);
                    saveVariantPageState();
                    return;
                }

                if (data.status === "success") {
                    const question = data.question || {};
                    const rowNumber = Number(question.source_question_id);

                    if (rowNumber) {
                        question._source_question = findSourceQuestionByRow(rowNumber);
                        clearVariantReviewRepairState(question);
                        question.advisory_review_loading = true;
                        question.source_type = question.source_type || "variant";
                        question.source_tool = VARIANT_SOURCE_TOOL;
                        const sanitized = sanitizeVariantRecord(question);
                        if (sanitized) {
                            applyVariantStemObservationGrammarToVariant(sanitized);
                            generatedVariantsByRow[rowNumber] = sanitized;
                        }
                    }

                    renderExportReadyList();
                    renderCurrentReview();

                    setGenerationWorking(
                        "Generating variants",
                        "Completed: " + (data.questions_completed || 0) + " of " + (data.num_questions || 0)
                    );

                    openPanel(generatedPanel);
                    saveVariantPageState();

                    const generationData = data;
                    if (rowNumber && generatedVariantsByRow[rowNumber]) {
                        requestVariantReviewAndRepair(rowNumber, generatedVariantsByRow[rowNumber]).finally(
                            function () {
                                continueVariantGenerationLoop(jobId, generationData);
                            }
                        );
                    } else {
                        continueVariantGenerationLoop(jobId, generationData);
                    }
                } else if (data.status === "complete") {
                    generationInProgress = false;
                    updateSelectionSummary();
                    setGenerationSuccess("Generation complete.");
                    saveVariantPageState();
                } else {
                    generationInProgress = false;
                    updateSelectionSummary();

                    let raw = "";
                    if (data.raw_response) {
                        raw = typeof data.raw_response === "string"
                            ? data.raw_response
                            : JSON.stringify(data.raw_response, null, 2);
                    }

                    setGenerationError(data.message || "Generation failed while creating variants.", raw);
                    saveVariantPageState();
                }
            })
            .catch(error => {
                console.error(error);
                generationInProgress = false;
                updateSelectionSummary();
                setGenerationError("Generation failed while creating variants.");
                saveVariantPageState();
            });
    }

    function resetUploadView(clearSavedState = false) {
        uploadedQuestionDetails = [];
        reviewQuestions = [];
        selectedRows = new Set();
        generatedVariantsByRow = {};
        currentIndex = 0;
        currentFilter = "All";
        generationStarted = false;
        generationInProgress = false;

        if (questionListContainer) {
            questionListContainer.innerHTML = "<p class='empty-state'>No uploaded questions yet.</p>";
        }

        if (originalQuestionBody) {
            originalQuestionBody.innerHTML =
                "<p class='workspace-empty workspace-empty--compact'>Upload a RISR file to begin.</p>";
        }

        if (generatedQuestionBody) {
            generatedQuestionBody.innerHTML =
                "<p class='workspace-empty workspace-empty--compact'>No variant generated yet.</p>";
        }

        if (jumpSelect) {
            jumpSelect.innerHTML = `<option value="">No questions loaded</option>`;
        }

        if (originalIncludeToolsRow) {
            originalIncludeToolsRow.classList.add("hidden");
        }

        closeEditPanel();
        renderExportReadyList();
        updateSelectionSummary();
        updateVariantFilterChrome();
        updateCounter();
        updateNavigationButtons();
        setDefaultPanelState();

        if (clearSavedState) {
            clearVariantPageState();
        }
    }

    if (form) {
        form.addEventListener("submit", function (event) {
            event.preventDefault();

            const formData = new FormData(form);
            resetUploadView();

            setUploadStatus("<p>Uploading file...</p>");
            setGenerationIdle("No variant generation in progress.");

            fetch("../app/api/upload_risr_file.php", {
                method: "POST",
                body: formData
            })
                .then(response => response.json())
                .then(data => {
                    if (data.status === "success") {
                        uploadedQuestionDetails = Array.isArray(data.question_details) ? data.question_details : [];
                        reviewQuestions = [...uploadedQuestionDetails];
                        selectedRows = new Set(uploadedQuestionDetails.map(item => Number(item.row_number)));
                        currentIndex = 0;

                        setUploadStatus(
                            "<p><strong>File uploaded successfully.</strong></p>" +
                            "<p>Number of questions: " + escapeHtml(uploadedQuestionDetails.length || 0) + "</p>"
                        );

                        renderQuestionList();
                        renderCurrentReview();
                        updateSelectionSummary();
                        expandOriginalPanelAfterUpload();
                        saveVariantPageState();
                    } else {
                        setUploadStatus("<p>" + escapeHtml(data.message || "Upload failed.") + "</p>");
                        updateSelectionSummary();
                    }
                })
                .catch(error => {
                    console.error(error);
                    setUploadStatus("<p>Error uploading file.</p>");
                    updateSelectionSummary();
                });
        });
    }

    if (selectAllBtn) {
        selectAllBtn.addEventListener("click", function () {
            if (generationStarted) {
                return;
            }

            selectedRows = new Set(uploadedQuestionDetails.map(item => Number(item.row_number)));
            updateSelectionSummary();
            renderQuestionList();
            syncCurrentCheckbox();
            saveVariantPageState();
        });
    }

    if (clearSelectionBtn) {
        clearSelectionBtn.addEventListener("click", function () {
            if (generationStarted) {
                return;
            }

            selectedRows.clear();
            updateSelectionSummary();
            renderQuestionList();
            syncCurrentCheckbox();
            saveVariantPageState();
        });
    }

    if (currentIncludeCheckbox) {
        currentIncludeCheckbox.addEventListener("change", function () {
            const question = getCurrentQuestion();
            if (!question || generationStarted) return;

            const rowNumber = Number(question.row_number);

            if (this.checked) {
                selectedRows.add(rowNumber);
            } else {
                selectedRows.delete(rowNumber);
            }

            updateSelectionSummary();
            renderQuestionList();
            saveVariantPageState();
        });
    }

    if (startVariantGenerationBtn) {
        startVariantGenerationBtn.addEventListener("click", function () {
            const workspaceId = localStorage.getItem("workspace_id");

            if (!workspaceId) {
                setGenerationError("Preparing workspace...");
                return;
            }

            if (uploadedQuestionDetails.length === 0) {
                setGenerationError("Please upload a RISR file first.");
                return;
            }

            if (selectedRows.size === 0) {
                setGenerationError("Please select at least one uploaded question.");
                return;
            }

            const selectedQuestions = uploadedQuestionDetails.filter(item => selectedRows.has(Number(item.row_number)));

            if (selectedQuestions.length === 0) {
                setGenerationError("No valid uploaded questions were matched from the selected rows.");
                return;
            }

            generationStarted = true;
            generationInProgress = true;
            reviewQuestions = selectedQuestions;
            currentIndex = 0;
            generatedVariantsByRow = {};
            closeEditPanel();

            renderQuestionList();
            renderCurrentReview();
            updateSelectionSummary();
            focusGeneratedPanelAfterStart();

            setGenerationWorking("Creating variant generation job", "Selected questions: " + selectedQuestions.length);
            saveVariantPageState();

            const formData = new FormData();
            formData.append("workspace_id", workspaceId);
            formData.append("variants_per_question", 1);
            formData.append("selected_questions_json", JSON.stringify(selectedQuestions));

            fetch("../app/api/start_variant_generation_job.php", {
                method: "POST",
                body: formData
            })
                .then(response => response.json())
                .then(data => {
                    if (data.status === "success") {
                        setGenerationWorking(
                            "Variant job created",
                            "Selected questions: " + (data.selected_question_count || 0) + " | Total variants: " + (data.total_variants || 0)
                        );

                        saveVariantPageState();
                        generateNextVariant(data.job_id);
                    } else {
                        generationInProgress = false;
                        updateSelectionSummary();
                        setGenerationError(data.message || "Could not start generation job.");
                        saveVariantPageState();
                    }
                })
                .catch(error => {
                    console.error(error);
                    generationInProgress = false;
                    updateSelectionSummary();
                    setGenerationError("Could not start generation job.");
                    saveVariantPageState();
                });
        });
    }

    if (prevSourceBtn) {
        prevSourceBtn.addEventListener("click", function () {
            const filteredQuestions = getFilteredReviewQuestions();

            if (filteredQuestions.length === 0) {
                currentIndex = 0;
                renderCurrentReview();
                renderQuestionList();
                saveVariantPageState();
                return;
            }

            if (currentIndex >= filteredQuestions.length) {
                currentIndex = Math.max(0, filteredQuestions.length - 1);
            }

            if (currentIndex > 0) {
                currentIndex--;
                renderCurrentReview();
                renderQuestionList();
                saveVariantPageState();
            }
        });
    }

    if (nextSourceBtn) {
        nextSourceBtn.addEventListener("click", function () {
            const filteredQuestions = getFilteredReviewQuestions();

            if (filteredQuestions.length === 0) {
                currentIndex = 0;
                renderCurrentReview();
                renderQuestionList();
                saveVariantPageState();
                return;
            }

            if (currentIndex >= filteredQuestions.length) {
                currentIndex = Math.max(0, filteredQuestions.length - 1);
            }

            if (currentIndex < filteredQuestions.length - 1) {
                currentIndex++;
                renderCurrentReview();
                renderQuestionList();
                saveVariantPageState();
            }
        });
    }

    if (nextDraftBtn) {
        nextDraftBtn.addEventListener("click", function () {
            jumpToNextVariantDraft();
        });
    }

    if (prevSourceBtnOriginal) {
        prevSourceBtnOriginal.addEventListener("click", function () {
            const filteredQuestions = getFilteredReviewQuestions();

            if (filteredQuestions.length === 0) {
                currentIndex = 0;
                renderCurrentReview();
                renderQuestionList();
                saveVariantPageState();
                return;
            }

            if (currentIndex >= filteredQuestions.length) {
                currentIndex = Math.max(0, filteredQuestions.length - 1);
            }

            if (currentIndex > 0) {
                currentIndex--;
                renderCurrentReview();
                renderQuestionList();
                saveVariantPageState();
            }
        });
    }

    if (nextSourceBtnOriginal) {
        nextSourceBtnOriginal.addEventListener("click", function () {
            const filteredQuestions = getFilteredReviewQuestions();

            if (filteredQuestions.length === 0) {
                currentIndex = 0;
                renderCurrentReview();
                renderQuestionList();
                saveVariantPageState();
                return;
            }

            if (currentIndex >= filteredQuestions.length) {
                currentIndex = Math.max(0, filteredQuestions.length - 1);
            }

            if (currentIndex < filteredQuestions.length - 1) {
                currentIndex++;
                renderCurrentReview();
                renderQuestionList();
                saveVariantPageState();
            }
        });
    }

    if (jumpSelect) {
        jumpSelect.addEventListener("change", function () {
            const filteredQuestions = getFilteredReviewQuestions();
            const targetIndex = Number(this.value);

            if (!Number.isNaN(targetIndex) && targetIndex >= 0 && targetIndex < filteredQuestions.length) {
                currentIndex = targetIndex;
                renderCurrentReview();
                renderQuestionList();
                saveVariantPageState();
            }
        });
    }

    if (closeEditPanelBtn) {
        closeEditPanelBtn.addEventListener("click", function () {
            closeEditPanel();
        });
    }

    if (modalClose) {
        modalClose.addEventListener("click", function () {
            closeModal();
        });
    }

    if (modalOk) {
        modalOk.addEventListener("click", function () {
            if (typeof modalOkAction === "function") {
                const fn = modalOkAction;
                modalOkAction = null;
                modalConfirmAction = null;
                fn();
            }
            closeModal();
        });
    }

    if (modalCancel) {
        modalCancel.addEventListener("click", function () {
            closeModal();
        });
    }

    if (modalConfirm) {
        modalConfirm.addEventListener("click", function () {
            if (typeof modalConfirmAction === "function") {
                modalConfirmAction();
            }
            closeModal();
        });
    }

    if (modalOverlay) {
        modalOverlay.addEventListener("click", function (event) {
            if (event.target === modalOverlay) {
                closeModal();
            }
        });
    }

    const filterButtons = document.querySelectorAll(".filter-btn");

    filterButtons.forEach(button => {
        button.addEventListener("click", function () {
            if (this.disabled || reviewQuestions.length === 0 || !generationStarted) {
                return;
            }

            currentFilter = this.getAttribute("data-filter");
            applyFilter();
        });
    });

    if (clearWorkspaceBtn) {
        clearWorkspaceBtn.addEventListener("click", function () {
            showConfirmModal(
                "Clear Workspace",
                "Clear the current workspace from this browser and reset the variant page?",
                function () {
                    clearWorkspaceOnServer()
                        .then(() => {
                            resetUploadView(true);
                            return resetWorkspace();
                        })
                        .then(() => {
                            setUploadStatus(
                                '<p role="status">Workspace cleared.</p><p class="empty-state">No file uploaded yet.</p>'
                            );
                            setGenerationIdle("No variant generation in progress.");
                        })
                        .catch(error => {
                            console.error(error);
                            showInfoModal("Reset failed", "Error resetting workspace.");
                        });
                }
            );
        });
    }

    document.querySelectorAll(".collapsible-header").forEach(header => {
        header.addEventListener("click", function (event) {
            if (event.target.closest("input, label, button, select, textarea")) {
                return;
            }

            const panel = this.closest(".collapsible");
            if (!panel) return;

            panel.classList.toggle("open");
            saveVariantPageState();
        });
    });

    document.addEventListener("click", function (event) {
        if (!editPanelWrapper || !editPanelWrapper.classList.contains("open")) {
            return;
        }

        const clickedInsidePanel = editPanelWrapper.contains(event.target);
        const clickedEditButton =
            event.target.closest(".edit-variant-btn") ||
            event.target.closest(".variant-open-edit-panel-btn") ||
            event.target.closest(".variant-open-edit-suggestions-btn");

        if (!clickedInsidePanel && !clickedEditButton) {
            closeEditPanel();
        }
    });

    document.addEventListener("keydown", function (event) {
        if (event.key === "Escape") {
            if (exportModal && !exportModal.classList.contains("hidden")) {
                closeExportModal();
                return;
            }

            if (modalOverlay && !modalOverlay.classList.contains("hidden")) {
                closeModal();
                return;
            }

            if (editPanelWrapper && editPanelWrapper.classList.contains("open")) {
                closeEditPanel();
            }
        }
    });

    const infoIcons = document.querySelectorAll(".info-icon");
    infoIcons.forEach(icon => {
        icon.addEventListener("click", function (event) {
            event.stopPropagation();
            const type = this.getAttribute("data-info");
            const info = getInfoContent(type);
            showInfoModal(info.title, info.message);
        });
    });

    if (openExportModalBtn) {
        openExportModalBtn.addEventListener("click", function () {
            const workspaceId = localStorage.getItem("workspace_id");

            if (!workspaceId) {
                showExportPanelError("Export failed: no workspace found.");
                return;
            }

            if (getExportReadyItems().length === 0) {
                showInfoModal("Nothing to export", "There are no variants marked Done (approved for export) yet.");
                return;
            }

            openExportModal();
        });
    }

    if (closeExportModalBtn) {
        closeExportModalBtn.onclick = closeExportModal;
    }

    if (exportModal) {
        exportModal.addEventListener("click", function (event) {
            if (event.target === exportModal) {
                closeExportModal();
            }
        });
    }

    if (exportOptions && exportOptions.length) {
        exportOptions.forEach(function (button) {
            button.onclick = function () {
                const format = button.getAttribute("data-format");

                if (format === "risr") {
                    exportDoneVariantQuestions();
                } else if (format === "word") {
                    exportVariantsToWord();
                } else if (format === "forms") {
                    exportVariantsToMicrosoftForms();
                } else if (format === "ultra") {
                    exportVariantsToLearnUltra();
                }

                closeExportModal();
            };
        });
    }

    resetUploadView();
    migrateVariantLocalStorageKeys();

    ensureWorkspace()
        .then(() => {
            const restoredState = restoreVariantPageState();

            if (restoredState) {
                setUploadStatus(
                    "<p><strong>File restored from this browser session.</strong></p>" +
                    "<p>Number of questions: " + escapeHtml(reviewQuestions.length || uploadedQuestionDetails.length || 0) + "</p>"
                );

                renderQuestionList();
                renderCurrentReview();
                updateSelectionSummary();

                if (generationStarted) {
                    setGenerationSuccess("Restored previous session.", "You can continue reviewing your current variants.");
                } else {
                    setGenerationIdle("Previous uploaded session restored.");
                }
            } else {
                setGenerationIdle("No variant generation in progress.");
            }
        })
        .catch(error => {
            console.error(error);
            setGenerationError("Could not create a workspace for this page.");
        });
});