/* ═══════════════════════════════════════════════════════════════════
   QExtract App — Premium Dark Theme (Full Tab)
   ═══════════════════════════════════════════════════════════════════ */

/* ── Reset & Variables ─────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --bg:       #0c0c12;
  --surface:  #14141f;
  --surface2: #1c1c2e;
  --surface3: #252540;
  --border:   #2a2a45;
  --text:     #f8f8ff;
  --text2:    #b0b0d0;
  --text3:    #9090b0;
  --accent:   #7c5cfc;
  --accent-readable: #8b75ff;
  --accent2:  #6040e0;
  --green:    #34d399;
  --green-dark: #059669;
  --yellow:   #fbbf24;
  --red:      #f87171;
  --red-dark: #dc2626;
  --radius:   12px;
  --font:     'Segoe UI', system-ui, -apple-system, sans-serif;
}

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  overflow-y: scroll;
}

.app {
  max-width: 900px;
  margin: 0 auto;
  padding: 40px 20px;
  display: flex;
  flex-direction: column;
  gap: 30px;
  min-height: 100vh;
}

.version { 
  font-size: 0.7rem; 
  font-weight: 600; 
  background: rgba(124, 92, 252, 0.1); 
  color: #7c5cfc; 
  padding: 2px 6px; 
  border-radius: 4px; 
  vertical-align: middle; 
  margin-left: 8px; 
}

/* ── Header ────────────────────────────────────────────────────── */
.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--border);
  user-select: none;
  -webkit-user-select: none;
}

.brand { display: flex; align-items: center; gap: 14px; }
.logo svg { width: 44px; height: 44px; }
.brand-name { font-size: 1.6rem; font-weight: 700; background: linear-gradient(135deg, var(--accent), var(--green)); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; letter-spacing: -0.5px; }
.brand-tag { font-size: 0.9rem; color: var(--text2); letter-spacing: 0.3px; margin-top: -2px; }

.tabs { display: flex; background: var(--surface2); padding: 4px; border-radius: 8px; border: 1px solid var(--border); }
.tab { background: transparent; border: none; color: var(--text2); padding: 8px 16px; border-radius: 6px; font-size: 0.9rem; font-weight: 600; cursor: pointer; transition: all 0.2s; }
.tab:hover { color: var(--text); }
.tab.active { background: var(--surface3); color: #a58fff; box-shadow: 0 2px 8px rgba(0,0,0,0.2); }

.version { font-size: 0.8rem; color: var(--text3); background: var(--surface2); padding: 4px 12px; border-radius: 20px; border: 1px solid var(--border); font-weight: 600; }

/* ── Main Layout ───────────────────────────────────────────────── */
.main-content { flex: 1; display: flex; flex-direction: column; }
.view-section { animation: fadeIn 0.4s ease; display: flex; flex-direction: column; gap: 24px; }
@keyframes fadeIn { from { opacity: 1; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

/* ── Setup View (Upload Zone) ──────────────────────────────────── */
.upload-container { max-width: 600px; margin: 40px auto 0; width: 100%; display: flex; flex-direction: column; gap: 16px; }

.upload-zone {
  border: 2px dashed var(--border); border-radius: var(--radius); padding: 48px 20px; text-align: center; cursor: pointer; transition: all 0.3s ease; background: var(--surface); position: relative; overflow: hidden;
  user-select: none; -webkit-user-select: none;
}
.upload-zone::before { content: ''; position: absolute; inset: 0; background: radial-gradient(circle at 50% 120%, rgba(124,92,252,0.06), transparent 70%); pointer-events: none; }
.upload-zone:hover, .upload-zone.drag-over { border-color: var(--accent); background: var(--surface2); transform: translateY(-2px); box-shadow: 0 8px 32px rgba(124,92,252,0.15); }
.upload-zone:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.upload-icon { width: 64px; height: 64px; margin: 0 auto 16px; color: var(--text3); transition: color 0.3s; }
.upload-zone:hover .upload-icon { color: var(--accent); }
.upload-text { font-size: 1.1rem; color: var(--text2); margin-bottom: 8px; font-weight: 500; }
.upload-link { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.upload-hint { font-size: 0.85rem; color: var(--text3); margin-bottom: 8px; }
.sample-downloads { display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 0.8rem; color: var(--text3); margin-top: 4px; }
/* WCAG 2.2 AA (2.5.8 Target Size Minimum): these are standalone controls in a
   row, not links inside a sentence, so the inline exception does not apply.
   At padding 2px they measured 19px tall against the 24px floor. 5px vertical
   padding clears it without changing the type or colour. */
.link-btn { background: none; border: none; color: #a58fff; text-decoration: underline; cursor: pointer; padding: 5px 6px; min-height: 24px; font-size: inherit; font-weight: 600; transition: color 0.2s; }
.link-btn:hover { color: var(--green); }

/* File Info */
.file-info { display: flex; align-items: center; gap: 14px; padding: 16px 20px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); animation: slideIn 0.3s ease; }
@keyframes slideIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }
.file-icon { font-size: 1.8rem; }
.file-meta { flex: 1; min-width: 0; }
.file-name { font-size: 1rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text); }
.file-size { font-size: 0.8rem; color: var(--text3); margin-top: 2px; }

/* Buttons */
.btn { padding: 14px 24px; border: none; border-radius: var(--radius); font-family: var(--font); font-size: 1rem; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 8px; transition: all 0.25s ease; position: relative; overflow: hidden; }
.btn-primary { background: linear-gradient(135deg, var(--accent), var(--accent2)); color: #fff; box-shadow: 0 4px 16px rgba(124,92,252,0.25); }
.btn-primary:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(124,92,252,0.4); }
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; transform: none; box-shadow: none; }
.btn-primary.processing { pointer-events: none; }
.btn-secondary { background: var(--surface2); color: var(--text); border: 1px solid var(--border); }
.btn-secondary:hover { background: var(--surface3); border-color: var(--text3); }
.btn-success { background: linear-gradient(135deg, var(--green), var(--green-dark)); color: #fff; box-shadow: 0 4px 16px rgba(52,211,153,0.25); }
.btn-success:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(52,211,153,0.4); }

.btn-icon { width: 32px; height: 32px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface2); color: var(--text3); cursor: pointer; font-size: 1rem; display: flex; align-items: center; justify-content: center; transition: all 0.2s; }
.btn-icon:hover { border-color: var(--red); color: var(--red); background: rgba(248,113,113,0.1); }

.btn-spinner { width: 18px; height: 18px; border: 2px solid rgba(255,255,255,0.3); border-top-color: #fff; border-radius: 50%; animation: spin 0.7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Stats Bar */
.stats { display: flex; gap: 16px; margin-top: 10px; }
.stat { flex: 1; text-align: center; padding: 16px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); }
.stat-value { display: block; font-size: 2rem; font-weight: 700; background: linear-gradient(135deg, var(--accent), var(--green)); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 4px; }
.stat-label { font-size: 0.75rem; color: var(--text3); text-transform: uppercase; letter-spacing: 0.8px; font-weight: 600; }

/* Log Panel */
.log-panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; margin-top: 10px; }
.log-toggle { display: flex; align-items: center; justify-content: space-between; padding: 14px 20px; font-size: 0.9rem; font-weight: 600; color: var(--text2); cursor: pointer; user-select: none; transition: background 0.2s, color 0.2s; }
.log-toggle:hover { color: var(--text); background: var(--surface2); }
.log-count { background: var(--surface3); padding: 2px 10px; border-radius: 12px; font-size: 0.75rem; color: var(--text3); }
.log-container { max-height: 240px; overflow-y: auto; padding: 0 20px 16px; border-top: 1px solid var(--border); }
.log-entry { font-size: 0.85rem; padding: 6px 0; border-bottom: 1px solid rgba(42,42,69,0.5); line-height: 1.5; color: var(--text2); font-family: 'Cascadia Code', 'Consolas', monospace; }
.log-time { color: var(--text3); margin-right: 8px; font-size: 0.75rem; }
.log-info { color: var(--text2); } .log-warn { color: var(--yellow); } .log-error { color: var(--red); } .log-success { color: var(--green); }

/* ── Review View ───────────────────────────────────────────────── */
.review-header { display: flex; justify-content: space-between; align-items: flex-start; padding-bottom: 16px; border-bottom: 1px dashed var(--border); margin-bottom: 24px; gap: 20px; flex-wrap: wrap; }
.review-header h2 { font-size: 1.5rem; font-weight: 600; color: var(--text); margin-bottom: 6px; }
.review-subtitle { font-size: 0.95rem; color: var(--text2); max-width: 500px; line-height: 1.5; }
.review-actions { display: flex; gap: 10px; flex-shrink: 0; align-items: center; flex-wrap: wrap; width: 100%; justify-content: flex-end; }
.review-actions .btn { padding: 0 16px; height: 42px; font-size: 0.9rem; white-space: nowrap; }

/* Review-action grouping: collapse many export formats behind one dropdown */
.export-menu { position: relative; display: inline-block; }
.export-menu > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 4px;
}
.export-menu > summary::-webkit-details-marker { display: none; }
.export-menu[open] > summary { background: var(--surface3); }
.export-menu-panel {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 60;
  display: flex; flex-direction: column; gap: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius, 8px); padding: 8px;
  min-width: 230px; max-height: 340px; overflow-y: auto;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
}
.export-menu-panel .btn { width: 100%; justify-content: flex-start; height: 38px; min-height: 38px; flex: 0 0 auto; }
/* Review panels & re-OCR controls sit on their own row below the action bar */
.report-card-panel, .explain-panel-host { width: 100%; margin-top: 12px; }
.reocr-controls { display: flex; gap: 8px; width: 100%; margin-top: 8px; flex-wrap: wrap; }

/* v2.2 U2 — the rating ask. Sits inline under the primary actions rather than
   as a modal: a dialog that steals focus the moment a download finishes is a
   nag, and this gets exactly one appearance per device. */
.rating-prompt { display: flex; align-items: center; justify-content: space-between; gap: 16px; width: 100%; margin-top: 12px; background: var(--surface); border: 1px solid var(--border); border-left: 4px solid var(--green); border-radius: var(--radius); padding: 14px 16px; flex-wrap: wrap; }
/* `display: flex` above BEATS the user-agent's `[hidden]{display:none}`, exactly
   as it did for .parse-failure-report — see the note at the bottom of this file.
   Without this the ask renders on every review screen from the first run, which
   is what the visual-regression gate caught. */
.rating-prompt[hidden] { display: none; }
.rating-prompt-text { margin: 0; color: var(--text2); font-size: 0.9rem; flex: 1 1 260px; }
.rating-prompt-actions { display: flex; gap: 8px; flex-wrap: wrap; }
/* The ask is an <a> so it is an ordinary navigation the user starts rather than
   something the extension does — but it is presented as a button, so it should
   not also wear a link underline. */
.rating-prompt-actions .btn { text-decoration: none; }

.parse-diagnostics { background: var(--surface); border: 1px solid var(--border); border-left: 4px solid var(--yellow); border-radius: var(--radius); padding: 16px; margin-bottom: 20px; }
.diag-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 12px; }
.diag-head h3 { margin: 0 0 4px; color: var(--text); font-size: 1rem; font-weight: 700; }
.diag-head p { margin: 0; color: var(--text2); font-size: 0.85rem; }
.diag-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-bottom: 12px; }
.diag-stat { background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; min-width: 0; }
.diag-stat span { display: block; color: var(--text); font-size: 1.25rem; font-weight: 800; line-height: 1; }
.diag-stat label { display: block; color: var(--text3); font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; margin-top: 5px; }
.diag-reasons { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; }
.diag-reason-group { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; color: var(--text2); font-size: 0.82rem; }
.diag-reason-group strong { color: var(--text); margin-right: 2px; }
.diag-reason-group span { background: rgba(251,191,36,0.08); border: 1px solid rgba(251,191,36,0.18); color: var(--text2); border-radius: 999px; padding: 4px 8px; }
.diag-samples { margin-top: 12px; color: var(--text2); font-size: 0.84rem; }
.diag-samples summary { cursor: pointer; color: var(--text); font-weight: 700; }
.diag-samples ul { margin: 10px 0 0; padding-left: 18px; }
.diag-samples li { margin-bottom: 8px; }
.diag-sample-text { display: block; color: var(--text2); line-height: 1.4; }
.diag-sample-reason { display: inline-block; color: var(--red); font-size: 0.78rem; margin-top: 3px; }

.web-attribution {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--green);
  border-radius: var(--radius);
  padding: 12px 16px;
  margin-bottom: 20px;
  color: var(--text2);
  font-size: 0.86rem;
}
.web-attribution div {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.web-attribution strong {
  color: var(--text);
  white-space: nowrap;
}
.web-attribution span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.web-attribution a {
  color: #a58fff;
  font-weight: 700;
  text-decoration: none;
  overflow-wrap: anywhere;
}
.web-attribution small {
  color: var(--text3);
  font-size: 0.78rem;
}

.parser-debug-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 16px;
  margin-bottom: 20px;
  color: var(--text2);
  font-size: 0.85rem;
}

.parser-debug-panel summary {
  cursor: pointer;
  color: var(--text);
  font-weight: 800;
}

.parser-debug-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
  margin-top: 12px;
}

.parser-debug-grid div {
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px;
}

.parser-debug-grid strong,
.parser-debug-grid span {
  display: block;
}

.parser-debug-grid strong {
  color: var(--text3);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  margin-bottom: 4px;
}

.parser-debug-grid span {
  color: var(--text);
  font-weight: 700;
}

.parser-debug-actions {
  margin-top: 12px;
}

.processing-options { display: flex; justify-content: center; margin-bottom: 16px; }
.ai-toggle { display: flex; align-items: center; gap: 8px; font-size: 0.85rem; color: var(--text2); cursor: pointer; background: var(--surface2); padding: 6px 14px; border-radius: 20px; border: 1px solid var(--border); transition: all 0.2s; }
.ai-toggle:hover { border-color: var(--accent); color: var(--text); }
.ai-toggle input { width: 14px; height: 14px; accent-color: var(--accent); }
.badge-mini { background: linear-gradient(135deg, var(--accent), var(--accent2)); color: #fff; font-size: 0.6rem; padding: 2px 6px; border-radius: 4px; text-transform: uppercase; font-weight: 700; letter-spacing: 0.5px; animation: pulse 2s infinite; }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(124,92,252,0.4); } 70% { box-shadow: 0 0 0 6px rgba(124,92,252,0); } 100% { box-shadow: 0 0 0 0 rgba(124,92,252,0); } }

.toggle-option { display: flex; align-items: center; gap: 8px; color: var(--text2); font-size: 0.9rem; cursor: pointer; user-select: none; background: var(--surface2); padding: 0 16px; height: 42px; border-radius: 8px; border: 1px solid var(--border); transition: all 0.2s; }
.toggle-option input { accent-color: var(--accent); transform: scale(1.1); cursor: pointer; }
.toggle-option:hover { color: var(--text); border-color: var(--accent); }

.questions-list { display: flex; flex-direction: column; gap: 24px; }

/* Question Edit Card */
.q-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; position: relative; transition: border-color 0.2s; }
.q-card:focus-within { border-color: var(--accent); box-shadow: 0 4px 20px rgba(124,92,252,0.1); }

.q-card-header { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px 12px; min-width: 0; margin-bottom: 16px; }
.q-meta-badges { display: flex; gap: 8px; align-items: center; flex: 1 1 420px; min-width: 0; max-width: 100%; flex-wrap: wrap; }
.q-badge { background: var(--surface2); color: #b59fff; border: 1px solid var(--border); padding: 4px 12px; border-radius: 16px; font-size: 0.8rem; font-weight: 700; letter-spacing: 0.5px; display: inline-flex; align-items: center; max-width: 100%; min-width: 0; }
.q-badge,
.q-type-badge { overflow-wrap: anywhere; }
.q-type-badge { padding: 3px 10px; border-radius: 4px; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; border: 1px solid transparent; }
.q-type-badge.mcq { background: rgba(124,92,252,0.1); color: var(--accent); border-color: rgba(124,92,252,0.2); }
.q-type-badge.tf { background: rgba(52,211,153,0.1); color: var(--green); border-color: rgba(52,211,153,0.2); }
.q-type-badge.blank { background: rgba(251,191,36,0.1); color: var(--yellow); border-color: rgba(251,191,36,0.2); }
.q-type-badge.math { background: #dbeafe; color: #1e40af; border-color: #bfdbfe; }

/* v1.2.0 Deep Parse Badges */
.q-badge.section-badge { background: var(--surface2); color: var(--text2); border: 1px solid var(--border); font-weight: 500; }
.q-badge.marks-badge { background: rgba(52,211,153,0.1); color: var(--green); border: 1px solid rgba(52,211,153,0.2); font-weight: 600; }
.q-badge.topic-badge { background: rgba(124,92,252,0.05); color: var(--accent); border: 1px solid rgba(124,92,252,0.2); font-weight: 500; font-size: 0.7rem; text-transform: capitalize; }
.q-badge.warning-badge { background: rgba(248,113,113,0.1); color: var(--red); border: 1px solid rgba(248,113,113,0.3); font-weight: 700; cursor: help; }
.needs-review { border-color: rgba(248,113,113,0.4); border-left: 4px solid var(--red); }
.q-issues-hint { font-size: 0.8rem; color: var(--red); margin-top: -10px; margin-bottom: 12px; font-weight: 500; padding: 6px 12px; background: rgba(248,113,113,0.05); border-radius: 6px; }


.math-tex { font-family: "Cambria Math", "Latin Modern Math", "Times New Roman", serif; font-style: italic; }
.math-tex sub, .math-tex sup { font-style: normal; font-size: 0.8em; }

.q-type-badge.descriptive { background: var(--surface2); color: var(--text3); border-color: var(--border); }
.type-hint { font-size: 0.85rem; color: var(--text3); font-style: italic; margin-top: 10px; }
.rubric-preview { margin-top: 12px; padding: 12px 14px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface2); color: var(--text2); font-size: 0.85rem; }
.rubric-preview summary { cursor: pointer; color: var(--text); font-weight: 700; }
.rubric-preview ul { margin: 10px 0 0; padding-left: 20px; }
.rubric-preview li { margin: 4px 0; }
.passage-preview { max-width: 100%; min-width: 0; box-sizing: border-box; overflow-wrap: anywhere; word-break: break-word; white-space: pre-wrap; }
.passage-preview .katex { display: inline-block; max-width: 100%; box-sizing: border-box; overflow-x: auto; overflow-y: hidden; vertical-align: middle; }
.passage-preview .katex-display { max-width: 100%; overflow-x: auto; overflow-y: hidden; }
.passage-preview .katex-display > .katex { display: block; }
.q-delete-btn { background: transparent; color: var(--text3); border: 1px solid transparent; border-radius: 6px; padding: 6px 12px; font-size: 0.85rem; cursor: pointer; transition: all 0.2s; display: flex; gap: 6px; align-items: center; font-weight: 500; flex: 0 0 auto; }
.q-delete-btn:hover { background: rgba(248,113,113,0.1); color: var(--red); border-color: rgba(248,113,113,0.3); }

/* Textareas & Inputs */
.input-field { width: 100%; background: var(--bg); color: var(--text); border: 1px solid var(--surface3); border-radius: 8px; padding: 12px 16px; font-family: var(--font); font-size: 0.95rem; line-height: 1.5; transition: border-color 0.2s; outline: none; }
.input-field:focus { border-color: var(--accent); }
.q-text-input { resize: vertical; min-height: 80px; margin-bottom: 16px; font-weight: 500; }

.opts-container { display: flex; flex-direction: column; gap: 10px; margin-left: 12px; padding-left: 16px; border-left: 2px solid var(--surface2); }
.opt-row { display: flex; align-items: center; gap: 12px; padding: 4px 0; }
.opt-correct-radio { cursor: pointer; transform: scale(1.2); accent-color: var(--green); }
.opt-label { font-weight: 700; color: var(--text3); width: 24px; text-align: right; }
.opt-input { flex: 1; padding: 10px 14px; background: var(--surface2); border: 1px solid var(--surface3); }
.opt-input:focus { background: var(--bg); border-color: var(--accent); }
.opt-delete { background: transparent; color: var(--text3); border: none; cursor: pointer; padding: 8px; border-radius: 6px; transition: all 0.2s; display: flex; align-items: center; justify-content: center; }
.opt-delete:hover { color: var(--red); background: rgba(248,113,113,0.1); }
.opt-add {
  align-self: flex-start; margin-top: 2px;
  background: transparent; color: var(--accent-readable); border: 1px dashed var(--border);
  cursor: pointer; padding: 6px 12px; border-radius: var(--radius, 8px);
  font-size: 0.85rem; font-weight: 600; transition: all 0.15s;
}
.opt-add:hover { background: var(--surface2); border-color: var(--accent); }
.opt-add:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Empty State */
.empty-state { text-align: center; padding: 60px 20px; background: var(--surface); border: 1px dashed var(--border); border-radius: var(--radius); }
.empty-state p { font-size: 1.1rem; color: var(--text2); margin-bottom: 16px; }

/* ── Footer ────────────────────────────────────────────────────── */
.footer { text-align: center; padding-top: 20px; margin-top: auto; border-top: 1px solid var(--border); user-select: none; -webkit-user-select: none; }
.footer p { font-size: 0.8rem; color: var(--text3); display: flex; align-items: center; justify-content: center; gap: 6px; }
.footer p::before { content: '🔒'; font-size: 0.75rem; }

/* Extracted Images */
.extracted-img {
  max-width: 100%;
  height: auto;
  border-radius: 8px;
  border: 1px solid var(--border);
  margin-top: 10px;
  background: #fff; /* White background for diagram readability */
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  display: block;
}

.q-image-preview {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.q-image-attachment {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: start;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface2);
}

.q-image-frame {
  min-width: 0;
}

.q-image-frame .extracted-img,
.q-image-frame .reconstructed-svg-container {
  margin: 0;
}

.q-image-controls {
  display: flex;
  justify-content: flex-start;
}

.q-image-add-btn,
.q-image-pick-btn,
.q-image-remove {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface2);
  color: var(--text2);
  cursor: pointer;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 700;
  min-height: 32px;
  padding: 0 12px;
  transition: all 0.2s;
}

.q-image-add-btn:hover,
.q-image-pick-btn:hover {
  border-color: var(--accent);
  color: var(--text);
  background: var(--surface3);
}

.q-image-remove:hover {
  border-color: rgba(248,113,113,0.35);
  color: var(--red);
  background: rgba(248,113,113,0.1);
}

.source-image-picker {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0,0,0,0.72);
}

.source-picker-panel {
  width: min(860px, 100%);
  max-height: 82vh;
  overflow: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  box-shadow: 0 24px 60px rgba(0,0,0,0.45);
}

.source-picker-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.source-picker-close {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface2);
  color: var(--text2);
  cursor: pointer;
  min-height: 32px;
  padding: 0 12px;
}

.source-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
}

.source-image-pick {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface2);
  color: var(--text);
  cursor: pointer;
  padding: 10px;
  text-align: left;
}

.source-image-thumb {
  display: block;
  min-height: 80px;
  max-height: 160px;
  overflow: hidden;
  background: #fff;
  border-radius: 6px;
  margin-bottom: 8px;
}

.source-image-thumb .extracted-img,
.source-image-thumb .reconstructed-svg-container {
  margin: 0;
  max-height: 160px;
  object-fit: contain;
}

.source-image-meta {
  color: var(--text3);
  font-size: 0.78rem;
  font-weight: 700;
}

/* Utilities */
.hidden { display: none !important; }
#btnProcess, #btnEvaluate { width: 100%; }

/* Responsive Layout */
@media (max-width: 850px) {
  .review-header { flex-direction: column; align-items: flex-start; gap: 16px; }
  .review-actions { width: 100%; justify-content: flex-start; }
}

/* v2.3 LIC2: the header on narrow screens. The brand and the display toolbar
   share the first row, the three tabs fill the second, each on one line, so
   that with the trial banner below it the page's own content still starts
   near the top of a phone's screen. */
@media (max-width: 780px) {
  .header { flex-wrap: wrap; gap: 14px 12px; padding-bottom: 16px; }
  .brand { flex: 1 1 auto; min-width: 0; }
  .a11y-toolbar { flex: 0 0 auto; }
  .tabs { order: 3; flex: 1 1 100%; }
  /* No nowrap: the labels fit on one line at every width (the shortest
     screens shorten them), and a wider font may wrap one rather than push
     the tabs off the side. */
  .tab { flex: 1 1 0; padding: 10px 6px; text-align: center; }
}
@media (max-width: 600px) {
  .app { padding: 20px 16px; gap: 20px; }
  .logo svg { width: 36px; height: 36px; }
  .brand { gap: 10px; }
  .brand-name { font-size: 1.3rem; }
  .brand-tag { font-size: 0.78rem; }
  .tab { min-height: 44px; }
}
/* The shortest screens: the tabs read Create / Take / Evaluate (their
   accessible names are unchanged), and the key link "Get free key". */
@media (max-width: 420px) {
  .tab-word, .trial-word { display: none; }
}
@media (max-width: 360px) {
  .brand-tag { display: none; }
}

@media (max-width: 600px) {
  .version { display: none; }
  
  .review-actions { flex-direction: column; align-items: stretch; }
  .review-actions .btn, .review-actions .toggle-option { width: 100%; justify-content: center; }
  .diag-grid { grid-template-columns: 1fr; }
  
  .q-card-header { flex-direction: column; align-items: flex-start; gap: 12px; }
  .q-meta-badges { flex-wrap: wrap; }
  .q-image-attachment { grid-template-columns: 1fr; }
  .q-image-remove { width: 100%; }
}

/* ── 13.12: Error fingerprint chip in diagnostics ──────────────────────────── */
.diag-fingerprint {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 12px;
  padding: 10px 12px;
  border: 1px dashed var(--border);
  border-radius: 8px;
  font-size: 0.85rem;
  color: var(--text2);
}
.diag-fingerprint-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: var(--surface2, rgba(127, 127, 127, 0.12));
  padding: 2px 8px;
  border-radius: 6px;
  cursor: pointer;
  user-select: all;
}
.diag-fingerprint-code:hover,
.diag-fingerprint-code:focus-visible {
  outline: 1px solid var(--border);
}

/* ── Enrichment badges: Bloom's / difficulty / readability ─────────────────── */
.bloom-badge select,
.difficulty-badge select {
  background: transparent;
  border: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  padding: 0;
  max-width: 100%;
  min-width: 0;
}
.difficulty-badge.difficulty-easy { background: rgba(46, 160, 67, 0.15); color: #2ea043; }
.difficulty-badge.difficulty-medium { background: rgba(210, 153, 34, 0.15); color: #d29922; }
.difficulty-badge.difficulty-hard { background: rgba(248, 81, 73, 0.15); color: #f85149; }
.readability-badge { background: rgba(56, 139, 253, 0.12); }

/* ── 11.1: Question bank standards filter ──────────────────────────────────── */
.bank-filter-bar {
  display: flex;
  gap: 10px;
  align-items: center;
  margin: 14px 0;
  flex-wrap: wrap;
}
/* 160, not 220: the bar carries four controls since v2.2 P31 and a 220px floor
   on the search box pushed the last toggle onto its own line at the width the
   review pane actually has. It still grows to fill whatever is left over. */
.bank-filter-bar input[type="search"] { flex: 1; min-width: 160px; }
.bank-filter-bar select {
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface2);
  color: var(--text1);
  max-width: 340px;
}
.bank-filter-count { font-size: 0.85rem; color: var(--text2); }
.standards-badge { background: rgba(163, 113, 247, 0.14); }

/* The review queue (v2.2 P27). Styled as a control, not a badge: it does
   something when clicked, and a warning-coloured pill that also happens to be
   clickable reads as decoration.
   `--red` on purpose, not a new token: it is the exact colour of the
   "⚠️ Needs Review" badge and the card's left border, and a filter that finds
   those questions in a different colour reads as a different concept. */
.bank-review-toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface2);
  color: var(--text);
  font-size: 0.85rem;
  cursor: pointer;
  white-space: nowrap;
  user-select: none;
}
.bank-review-toggle input { cursor: pointer; margin: 0; accent-color: var(--red); }
.bank-review-toggle:has(input:checked) {
  border-color: rgba(248, 113, 113, 0.5);
  background: rgba(248, 113, 113, 0.12);
}
/* Zero flagged questions is a RESULT, not an absence: the control stays put and
   says so. Removing it would leave the user unsure whether the parser checked. */
.bank-review-toggle:has(input:disabled) { opacity: 0.55; cursor: default; }
.bank-review-toggle:has(input:disabled) input { cursor: default; }
/* Focus lives on the checkbox, so lift the ring to the whole control or
   keyboard users cannot see where they are.
   `:focus-visible`, not `:focus-within`: with the latter a mouse click leaves a
   purple ring sitting on top of the red checked state, and the two read as two
   different things having happened. Keyboard focus still shows it. */
.bank-review-toggle:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The duplicates queue (v2.2 P31). Same control, different finding, so it
   reuses .bank-review-toggle and only re-tints: a near-duplicate is not a
   parse failure, and colouring it the same red as "Needs review" would say it
   is. Accent, which the card badge below matches. */
.bank-dupe-toggle input { accent-color: var(--accent); }
.bank-dupe-toggle:has(input:checked) {
  border-color: rgba(124, 92, 252, 0.55);
  background: rgba(124, 92, 252, 0.14);
}
/* Names its partner by POSITION, so it stays true as the bank is reordered. */
.q-badge.dupe-badge {
  background: rgba(124, 92, 252, 0.14);
  color: var(--accent-readable);
  border: 1px solid rgba(124, 92, 252, 0.35);
  cursor: help;
}

/* The bulk bar (v2.2 P32). Appears only once something is selected, so an
   untouched bank carries no destructive control at all. */
.bulk-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 14px;
  padding: 10px 14px;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.bulk-count { font-size: 0.85rem; color: var(--text); font-weight: 700; margin-right: 4px; }
.bulk-btn {
  padding: 6px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 0.82rem;
  cursor: pointer;
}
.bulk-btn:hover { background: var(--surface3); }
.bulk-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The destructive one is the only one that looks destructive. Colouring the
   whole bar red would make "Clear selection" read as dangerous too. */
.bulk-danger { border-color: rgba(248, 113, 113, 0.45); color: var(--red); }
.bulk-danger:hover { background: rgba(248, 113, 113, 0.12); }
.bulk-undo { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; }
.bulk-undo span { font-size: 0.82rem; color: var(--text2); }
/* The per-card checkbox. Sits before the badges so it reads as belonging to the
   whole card rather than to "Question N". */
.q-select { margin: 0 2px 0 0; cursor: pointer; accent-color: var(--accent); flex: none; }

/* Shown when a filter matched nothing. A list that has gone blank has to say
   why — silence there reads as a crash rather than as a filter doing its job. */
.bank-filter-empty {
  margin: 4px 0 14px;
  padding: 14px 16px;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text2);
  font-size: 0.9rem;
}


/* ── A11y: light theme (WCAG AA contrast), dyslexic font, toolbar ─────────── */
html[data-theme="light"] {
  --bg:       #f5f6f9;
  --surface:  #ffffff;
  --surface2: #eef0f5;
  --surface3: #e3e6ef;
  --border:   #c9cede;
  --text:     #16181f;
  --text2:    #3c4254;
  --text3:    #555d73;
  --accent:   #5235d8;
  --accent-readable: #5235d8;
  --accent2:  #4326c4;
  --green:    #0e7a55;
  --yellow:   #8a5b00;
  --red:      #b3261e;
}
html[data-font="dyslexic"] body,
html[data-font="dyslexic"] input,
html[data-font="dyslexic"] button,
html[data-font="dyslexic"] textarea,
html[data-font="dyslexic"] select {
  font-family: 'OpenDyslexic', 'Comic Sans MS', 'Comic Sans', Verdana, sans-serif !important;
  letter-spacing: 0.04em;
  word-spacing: 0.12em;
}
.a11y-toolbar { display: flex; gap: 8px; align-items: center; }
.a11y-tool-btn {
  background: var(--surface2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 8px;
  padding: 6px 10px;
  cursor: pointer;
  font-size: 1rem;
}
.a11y-tool-btn[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(124,92,252,0.3); }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* ── Sortable review cards ─────────────────────────────────────────────────── */
.q-card-order-controls { display: inline-flex; gap: 4px; margin-right: 8px; flex: 0 0 auto; }
.q-move-btn {
  background: var(--surface2);
  border: 1px solid var(--border);
  color: var(--text2);
  border-radius: 6px;
  width: 26px; height: 26px;
  cursor: pointer;
  line-height: 1;
}
.q-move-btn:hover { color: var(--text); border-color: var(--accent); }
.q-card.drag-source { opacity: 0.45; }
.q-card.drag-target { outline: 2px dashed var(--accent); outline-offset: 4px; }
.q-tts-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text2);
  border-radius: 6px;
  padding: 3px 8px;
  cursor: pointer;
  flex: 0 0 auto;
}
.q-tts-btn[aria-pressed="true"] { color: var(--green); border-color: var(--green); }


/* ── Modal dialogs ─────────────────────────────────────────────────────────
   ONE rule for every dialog, keyed off .overlay rather than off each id.
   It used to be written per-id — #cameraModal.overlay and #assembleModal.overlay
   — so #studyModal, added later with the same markup and the same class, got no
   positioning at all and rendered as a plain block in document flow at the
   bottom of the page. It was never a modal. Nobody noticed because the same
   release also made it unopenable, so it was never seen on screen.
   A new dialog now only has to carry class="overlay hidden" to behave. */
.overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.65); display: flex; align-items: center; justify-content: center; z-index: 200; }
.camera-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; width: min(560px, 92vw); }
/* max-height + scroll keeps a dialog usable at 320px and at 200% zoom, both of
   which the a11y behaviour suite checks. */
.assemble-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; width: min(520px, 92vw); max-height: 90vh; overflow-y: auto; }
/* The diagnostic preview shows the WHOLE file before it is written. It is
   monospaced because the report's evidence is alignment and punctuation, and
   proportional text would hide the very thing the reader is checking. */
/* pre-wrap, not pre: the notice a user has to READ before deciding is prose and
   runs past the card, and nobody scrolls a preview sideways to finish a
   sentence. Wrapping keeps the leading indentation that carries the sample
   alignment, which is the only part where columns matter. */
.diagnose-preview { background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; margin: 0; max-height: 300px; overflow-y: auto; overflow-x: hidden; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .75rem; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; color: var(--text1); }
/* Wider than the other dialogs on purpose — the preview is the feature, and a
   file the user is asked to approve should not be read through a keyhole. */
.diagnose-card { width: min(680px, 94vw); }
/* The destination link (A11Y-RP): the browser's default link blue fails WCAG
   contrast on the dark card, so it takes the theme's readable accent, which
   passes in both themes. */
#diagnoseDestination a { color: var(--accent-readable); font-weight: 600; }
/* Per-section counts in the practice-paper dialog. A grid so the section names
   and their number boxes line up however long the names are. */
.assemble-sections { display: grid; grid-template-columns: 1fr auto; gap: 8px 12px; align-items: center; }
.assemble-sections label { font-size: .85rem; color: var(--text1); }
.assemble-sections .assemble-section-meta { color: var(--text2); font-size: .78rem; }
.assemble-sections input { width: 72px; padding: 6px 8px; text-align: right; background: var(--bg2); color: var(--text1); border: 1px solid var(--border); border-radius: 6px; }
/* The setup-view failure prompt. Deliberately calm: a user whose file just
   failed is already annoyed, and an alarm-coloured panel reads as blame. */
.parse-failure-report { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 20px; padding: 14px 16px; background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius); }
/* `display: flex` on the line above BEATS the user-agent's `[hidden]{display:none}`,
   so without this the panel is visible from page load and the parse-failed
   prompt sits on a screen where nothing has failed. Same class of defect as the
   v1.9.2 dialogs: CSS quietly defeating a visibility mechanism the JS believes
   in. Any element styled with display:* must restate its own hidden rule. */
.parse-failure-report[hidden] { display: none; }
.parse-failure-report p { margin: 0; flex: 1 1 260px; font-size: .9rem; color: var(--text2); }

/* ── Source view (v2.3 P2.1): a question's page, its region highlighted ──── */
/* Wide on purpose: the page is the content, and a region read through a
   keyhole is no check at all. */
.source-card { width: min(920px, 96vw); display: flex; flex-direction: column; }
.source-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.source-head h3 { margin: 0; font-size: 1rem; overflow-wrap: anywhere; }
.source-status { font-size: .85rem; color: var(--text2); margin: 8px 0 10px; }
/* The gutter is reserved up front: the page is sized to the width left once
   the vertical scrollbar exists, or the scrollbar would push it into a
   horizontal scroll of its own. */
.source-scroll { overflow: auto; scrollbar-gutter: stable; max-height: 72vh; border: 1px solid var(--border); border-radius: 8px; background: var(--surface2); }
.source-page { position: relative; width: max-content; margin: 0 auto; }
.source-page canvas { display: block; background: #fff; }
/* An outline, not a fill: the words under it must stay readable. */
.source-highlight { position: absolute; border: 3px solid var(--accent); border-radius: 4px; box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.18); pointer-events: none; }
.q-source-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text2);
  border-radius: 6px;
  padding: 3px 8px;
  cursor: pointer;
  flex: 0 0 auto;
  margin-right: 6px;
}
.q-source-btn:hover { color: var(--text); border-color: var(--accent); }
/* v2.3 LIC2: the trial banner (days left, the end date, the way to the free
   key) and the license dialog. The tone colours the edge, the bar and, near
   the end, the headline; the words carry the meaning on their own. */
.trial-banner { --tone: var(--accent); display: flex; align-items: center; justify-content: space-between; gap: 14px 24px; flex-wrap: wrap; margin-top: -12px; padding: 14px 18px; background: var(--surface); border: 1px solid var(--border); border-left: 4px solid var(--tone); border-radius: var(--radius); }
.trial-banner[data-tone="soon"] { --tone: var(--yellow); }
.trial-banner[data-tone="last"] { --tone: var(--red); }
.trial-banner-main { flex: 1 1 320px; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.trial-banner-title { margin: 0; font-weight: 700; font-size: 1rem; color: var(--text); }
.trial-banner[data-tone="soon"] .trial-banner-title, .trial-banner[data-tone="last"] .trial-banner-title { color: var(--tone); }
.trial-banner-detail { margin: 0; color: var(--text2); font-size: 0.875rem; line-height: 1.5; }
.trial-progress { height: 6px; max-width: 360px; border-radius: 3px; background: var(--surface3); overflow: hidden; }
.trial-progress-fill { height: 100%; width: 0; border-radius: 3px; background: var(--tone); }
.trial-banner-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.trial-banner-actions .btn { flex: 1 1 auto; padding: 10px 16px; font-size: 0.9rem; white-space: nowrap; text-decoration: none; }
/* Narrow screens: a tighter banner whose two buttons share a row while they
   fit, and stack once they do not (the shortest screens shorten the link's
   words; see the header rules). */
@media (max-width: 600px) {
  .trial-banner { margin-top: -6px; padding: 12px 14px; gap: 12px; }
  .trial-banner-title { font-size: 0.95rem; }
  .trial-banner-detail { font-size: 0.82rem; }
  .trial-banner-actions { width: 100%; }
  .trial-banner-actions .btn { padding: 10px 12px; font-size: 0.85rem; min-height: 44px; }
}
.license-sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.license-overlay { z-index: 400; }
.license-card { max-width: 500px; width: calc(100% - 32px); max-height: calc(100vh - 32px); overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
.license-intro, .license-privacy { margin: 0; color: var(--text2); font-size: 0.9rem; line-height: 1.5; }
.license-steps { margin: 4px 0 0; padding: 0; list-style: none; counter-reset: license-step; display: flex; flex-direction: column; gap: 16px; }
.license-steps > li { counter-increment: license-step; position: relative; padding-left: 38px; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.license-steps > li::before { content: counter(license-step); position: absolute; left: 0; top: -3px; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; font-size: 0.85rem; font-weight: 700; color: var(--text); background: var(--surface3); border: 1px solid var(--border); }
.license-step-text { font-weight: 600; font-size: 0.9rem; line-height: 1.4; color: var(--text); }
.license-get { text-decoration: none; }
.license-input { width: 100%; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 0.8rem; word-break: break-all; resize: vertical; }
.license-hint { font-size: 0.8rem; color: var(--text3); }
.license-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.license-status { margin: 0; min-height: 1.2em; font-size: 0.85rem; color: var(--text); }
.license-status[data-ok="true"] { color: var(--green); font-weight: 600; }
body.license-locked { overflow: hidden; }
