/* ============================================================
   THE ANNOTATED NOTEBOOK — Topic Questions / AI grader study
   surface (Phase 3 Wave 1, Task 4 — the most complex surface).

   Page-scoped: it legitimately styles the FROZEN grader.js /
   question-pager.js / tab-indicator.js DOM classes (.qg, .tq-*,
   .qg-*, .questions-mode-tab*, .qmt-indicator, .esa-dots,
   .note-pagination …) — restyle, never rename. nb pages load
   ONLY the nb layers (no grader.css / tab-indicator.css /
   noteviewer.css), so every rule those legacy sheets owned is
   reproduced here in ink: the FOUC pre-paginate guard, the
   segmented-control base skin + indicator, the pager, the
   loading dots.

   Discipline (test-enforced by pages/tests_notebook.py):
   · zero raw colors — every color enters as var(--nb-*)/color-mix.
   (NOT on the nb-prefix ratchet: a page layer may style frozen
    foreign classes.)

   Design voice (DESIGN.md three-ink rule):
   · Student BLUE = all interaction (answer field, Mark button,
     pager, links, focus).
   · Examiner RED, serif italic = judgment moments ONLY: the mark
     allocation "— / 3", the score, the awarded-marks verdict, the
     "Examiner feedback" band. This voice appears NOWHERE else.
   · Functional errors (.qg-hint) use --nb-error + sans, never the
     examiner treatment.

   Contents
     1 · FOUC guard + column
     2 · Content-type switcher (mode tabs + indicator)
     3 · Question paper card (.qg / .tq-paper)
     4 · Question head + mark allocation (examiner voice)
     5 · Answer form (label / counter / textarea / hint / foot)
     6 · Mark button + saved badge
     7 · Grade card (header / skeleton / keypoints)
     8 · Score + examiner feedback band
     9 · Model-answer reveal
    10 · Pager (question-pager.js)
    11 · Loading dots (.esa-dots)
    12 · Empty state + prev/next
    13 · Mobile
    14 · Reduced motion
   ============================================================ */

/* ---------- 1 · FOUC guard + column --------------------------- */
/* Load-bearing anti-FOUC rule, reproduced from grader.css. html.tq-js is set
   synchronously in <head>; before question-pager.js adds .is-paged this hides
   every question but the first, so they never flash stacked on load. */
html.tq-js .question-list:not(.is-paged) > .qg:not(:first-child) {
  display: none;
}

/* The grader column keeps the exam sheet centered in a comfortable measure. */
.nb-qg-column {
  max-width: 760px;
}
/* Wide desktops: the notes column's left bias (right for prose) strands the
   exam sheet beside a huge right void at 1920+ — center the stage in the
   track beside the docked rail instead (item-5 sizing pass, 2026-07-03). */
@media (min-width: 1440px) {
  .nb-qg-column {
    margin-inline: auto;
  }
}

.nb-qg-agg {
  display: inline-block;
  margin-left: var(--nb-s2);
  padding: var(--nb-s1) var(--nb-s3);
  vertical-align: middle;
  background: var(--nb-paper-sunken);
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-pill);
  font: var(--nb-type-label);
  letter-spacing: 0.02em;
  color: var(--nb-ink-2);
}

.nb-notes-header .nb-qg-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--nb-s3);
  margin-top: var(--nb-s5);
}
.nb-qg-back {
  padding-left: var(--nb-s2);
  padding-right: var(--nb-s2);
}
.nb-qg-whole {
  margin-left: auto; /* flush right */
}

.nb-qg-body {
  margin-top: var(--nb-s6);
}

/* ---------- 2 · Content-type switcher ------------------------- */
/* nb pages don't load noteviewer.css (base skin) or tab-indicator.css
   (indicator), so BOTH are reproduced here. A segmented control seated in a
   sunken paper well; the active tab reads through the sliding pen wash the
   indicator paints (tab-indicator.js injects .qmt-indicator as first child). */
.questions-mode-tabs {
  position: relative;
  display: inline-flex;
  gap: var(--nb-s1);
  margin: 0 0 var(--nb-s6);
  padding: var(--nb-s1);
  background: var(--nb-paper-sunken);
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-md);
}
.questions-mode-tab {
  position: relative;
  z-index: 1;
  padding: var(--nb-s2) var(--nb-s4);
  border-radius: var(--nb-r-sm);
  font: var(--nb-type-control);
  text-decoration: none;
  white-space: nowrap;
  color: var(--nb-ink-2);
  transition:
    color var(--nb-dur-1) var(--nb-ease),
    background-color var(--nb-dur-1) var(--nb-ease);
}
.questions-mode-tab:hover {
  color: var(--nb-ink);
}
.questions-mode-tab.is-active {
  background: var(--nb-selection-wash);
  box-shadow: inset 0 -2px 0 var(--nb-selection-soft-border);
  color: var(--nb-selection-soft-ink);
}
.questions-mode-tab:focus-visible {
  outline: 2px solid var(--nb-blue);
  outline-offset: 2px;
}
/* The sliding indicator (tab-indicator.js writes left/width) carries the
   persistent selection; hover and focus remain interaction blue. */
.qmt-indicator {
  position: absolute;
  top: var(--nb-s1);
  bottom: var(--nb-s1);
  left: 0;
  width: 0;
  border-radius: var(--nb-r-sm);
  background: var(--nb-selection-wash);
  border: 1px solid var(--nb-selection-soft-border);
  box-shadow: inset 0 -3px 0 var(--nb-selection-marker);
  pointer-events: none;
  z-index: 0;
  will-change: left, width; /* hint for the one-shot entrance glide */
}
/* When the indicator is wired, the active tab shows through it (no double fill). */
.questions-mode-tabs.has-indicator .questions-mode-tab.is-active {
  background: transparent;
  box-shadow: none;
}

/* Tactile press — CSS-only, matching the legacy behaviour (transform-only). */
@media (prefers-reduced-motion: no-preference) {
  .questions-mode-tab {
    transition:
      color var(--nb-dur-1) var(--nb-ease),
      background-color var(--nb-dur-1) var(--nb-ease),
      transform var(--nb-dur-1) var(--nb-ease);
  }
  .questions-mode-tab:active {
    transform: scale(0.97);
  }
}

/* ---------- 3 · Question paper card --------------------------- */
/* The list stacks its questions; the pager (is-paged) shows one at a time. */
.question-list {
  display: flex;
  flex-direction: column;
  gap: var(--nb-s7);
}
/* One-question-per-page — load-bearing (reproduced from grader.css). pager.js
   adds .is-paged, then toggles .is-current on the active card; the pager itself
   never sets display, so CSS hides every non-current .qg once paged. Without
   these two rules all questions stack visible under the pager. No-JS shows all
   (progressive enhancement — .is-paged is never added). */
.question-list.is-paged {
  gap: 0;
}
.question-list.is-paged > .qg {
  display: none;
}
.question-list.is-paged > .qg.is-current {
  display: block;
}
.question-list.is-paged .qg:focus {
  outline: none; /* the card takes programmatic focus on nav; ring is noise */
}
.qg[hidden] {
  display: none;
}

/* The exam sheet: a raised page. .tq-paper is the article; the .qg wrapper is
   transparent so the paper reads as the object. */
.qg {
  min-width: 0;
  /* question-pager.js scrolls the active card into view; clear the shared
     .topbar so the breadcrumb / eyebrow / H1 / back-link stay above it.
     block:'start' moves honour this; the centerOnOpen block:'center' init is
     finished by the nonce'd correction script in nb_question_index.html. */
  scroll-margin-top: calc(var(--nb-chrome-h) + var(--nb-s5));
}
.tq-paper {
  position: relative;
  padding: var(--nb-s7) var(--nb-s7) var(--nb-s6);
  background: var(--nb-paper-raised);
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-lg);
  box-shadow: var(--nb-shadow-1);
  font-family: var(--nb-sans);
  color: var(--nb-ink);
}
/* Stable measure so the pager (Prev/Next) doesn't jump vertically as you step
   between questions of different content heights (site-owner fix). Scoped to
   the GRADABLE card only — its answer form + Mark button already fill this
   height, so the floor just evens out the 1-line vs 2-line question wobble
   (idle ~386-411px) with no empty space. The ungraded card (question + a short
   note) stays its natural short height so it never shows a big empty gap; all
   ungraded cards are uniform among themselves, so they don't jump either.
   Longer questions still grow past the floor (min-height, not height). Mobile
   floor is a shade taller in the 720px block below. */
.qg--gradable .tq-paper {
  min-height: 420px;
}

/* ---------- 4 · Question head + mark allocation --------------- */
/* Number in the margin, question centre, marks in the right margin — the
   exam-paper reading order. */
.tq-q-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--nb-s4);
}
/* Q-number: quiet index in the margin. */
.tq-q-no {
  font: var(--nb-type-label);
  letter-spacing: 0.04em;
  color: var(--nb-ink-2);
  font-variant-numeric: tabular-nums;
}
.tq-q-main {
  min-width: 0;
}
/* The question text (div[role=heading], not <h2>, to escape base h2 styles). */
.tq-question {
  margin: 0;
  font-family: var(--nb-sans);
  font-size: var(--nb-text-md);
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: -0.005em;
  color: var(--nb-ink);
  overflow-wrap: break-word;
}
.tq-question p {
  margin: 0 0 var(--nb-s3);
}
.tq-question p:last-child {
  margin-bottom: 0;
}
.tq-question .katex {
  color: var(--nb-ink);
}

/* Mark allocation — the examiner's voice: serif italic, examiner red, like a
   "[4]" pencilled into the exam-paper margin. Both the idle "— / 3" and the
   read-only "N marks" (ungraded) variant. */
.tq-q-marks {
  font-family: var(--nb-serif);
  font-style: italic;
  font-weight: 600;
  font-size: var(--nb-text-sm);
  color: var(--nb-red);
  white-space: nowrap;
}
.tq-q-marks b {
  font-weight: 700;
}
/* The premium score division "— / 3" → "2 / 3" on marking. */
.tq-q-marks--score {
  font-size: var(--nb-text-md);
}
.tq-q-marks--score .qg-score {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.tq-q-slash {
  color: var(--nb-red);
  opacity: 0.7;
}

/* The margin rule under the question — the notebook's hairline. */
.tq-rule {
  height: 1px;
  margin: var(--nb-s5) 0;
  background: var(--nb-border);
}

/* ---------- 5 · Answer form ----------------------------------- */
.qg-form {
  margin: 0;
}
.tq-answer-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--nb-s3);
  margin-bottom: var(--nb-s2);
}
.tq-answer-label {
  font: var(--nb-type-label);
  color: var(--nb-ink-2);
}
.tq-char-count {
  font: var(--nb-type-label);
  font-variant-numeric: tabular-nums;
  color: var(--nb-ink-2);
  transition: color var(--nb-dur-1) var(--nb-ease);
}
.tq-char-count.is-near {
  color: var(--nb-ink-2);
}
.tq-char-count.is-max {
  color: var(--nb-error);
  font-weight: 600;
}

/* The writing area — a raised paper field in the student's own voice. */
.tq-input-wrap {
  position: relative;
}
.qg-input,
.tq-signin-hint,
.nb-qg-empty .nb-empty-note {
  font: var(--nb-type-ui);
}
.qg-input {
  display: block;
  width: 100%;
  min-height: 108px;
  padding: var(--nb-s3) var(--nb-s4);
  background: var(--nb-paper);
  border: 1px solid var(--nb-control-border);
  border-radius: var(--nb-r-md);
  box-shadow: var(--nb-shadow-1);
  color: var(--nb-ink);
  resize: vertical;
  transition:
    border-color var(--nb-dur-1) var(--nb-ease),
    background-color var(--nb-dur-1) var(--nb-ease);
}
.qg-input::placeholder {
  color: var(--nb-ink-2);
}
.qg-input:hover:not(:focus):not(.is-locked) {
  border-color: var(--nb-border-strong);
}
html.theme-light .qg-input:hover:not(:focus):not(.is-locked) {
  border-color: var(--nb-control-border);
}
.qg-input:focus-visible {
  outline: 2px solid var(--nb-blue);
  outline-offset: 2px;
  border-color: var(--nb-blue);
}
/* Locked while grading — reads inert, not broken. */
.qg-input.is-locked {
  background: var(--nb-paper-sunken);
  color: var(--nb-ink-2);
  cursor: progress;
}

/* Functional hint (validation) — plain UI error voice, never the examiner. */
.qg-hint {
  margin: var(--nb-s2) 0 0;
  font: var(--nb-type-label);
  color: var(--nb-error);
}
.qg-hint[hidden] {
  display: none;
}

.tq-answer-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--nb-s3);
  margin-top: var(--nb-s4);
}
.tq-foot-meta {
  display: inline-flex;
  align-items: center;
  gap: var(--nb-s3);
  font: var(--nb-type-label);
  color: var(--nb-ink-2);
}
/* "Worth N marks" — the examiner's allocation, so it wears the serif-italic red. */
.tq-worth {
  display: inline-flex;
  align-items: center;
  gap: var(--nb-s2);
  font-family: var(--nb-serif);
  font-style: italic;
  color: var(--nb-red);
}
.tq-worth svg {
  color: var(--nb-red);
}
.tq-foot-sep {
  display: inline-block;
  width: 1px;
  height: 0.9em;
  background: var(--nb-border-strong);
}
/* "Saved just now" — a plain UI confirmation (success voice), not a judgment. */
.qg-saved {
  display: inline-flex;
  align-items: center;
  gap: var(--nb-s2);
  font: var(--nb-type-label);
  color: var(--nb-success);
}
.qg-saved svg {
  color: var(--nb-success);
}
.qg-saved[hidden] {
  display: none;
}

/* ---------- 6 · Mark button ----------------------------------- */
/* The primary action — the student's blue pen. Inherits nothing from nb-btn
   (the fragment carries no nb-btn class), so it is built fully here. */
.tq-mark-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--nb-s2);
  padding: 10px var(--nb-s5);
  background: var(--nb-blue);
  border: 1px solid var(--nb-blue);
  border-radius: var(--nb-r-sm);
  color: var(--nb-on-blue);
  font: var(--nb-type-control);
  cursor: pointer;
  transition:
    background-color var(--nb-dur-1) var(--nb-ease),
    transform var(--nb-dur-1) var(--nb-ease);
}
.tq-mark-btn:hover:not(:disabled) {
  background: var(--nb-blue-strong);
  border-color: var(--nb-blue-strong);
  transform: translateY(-1px);
}
.tq-mark-btn:active:not(:disabled) {
  transform: translateY(0);
}
.tq-mark-btn:focus-visible {
  outline: 2px solid var(--nb-blue);
  outline-offset: 2px;
}
.tq-mark-btn:disabled {
  background: var(--nb-paper-sunken);
  border-color: var(--nb-border);
  color: var(--nb-ink-2);
  cursor: not-allowed;
}
.tq-mark-icon {
  flex-shrink: 0;
}
/* Spinner slot (fragment carries .qg-spinner; grader.js swaps the label text). */
.qg-spinner {
  display: none;
}

/* ---------- 7 · Grade card ------------------------------------ */
/* The marked answer — written on the exam sheet itself, not in a nested well.
   A red hairline (the examiner's rule under your work) opens the marking;
   everything below it is pen on the same paper. Revealed on grade
   (grader.js un-hides). */
.tq-grade-card {
  margin-top: var(--nb-s6);
  padding: var(--nb-s5) 0 0;
  background: transparent;
  border: 0;
  border-top: 1px solid color-mix(in srgb, var(--nb-red) 35%, transparent);
}
.tq-grade-card[hidden] {
  display: none;
}
.qg-live,
.qg-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.tq-grade-head {
  display: flex;
  align-items: baseline;
  gap: var(--nb-s3);
  margin-bottom: var(--nb-s4);
}
/* The old icon-in-a-circle seal is retired — the examiner's voice is the serif
   title itself. The element stays (fragment markup is shared with the legacy
   page) but paints nothing here. */
.tq-grade-badge {
  display: none;
}
.tq-grade-head-text {
  display: flex;
  align-items: baseline;
  column-gap: var(--nb-s3);
  flex-wrap: wrap;
  min-width: 0;
  margin-right: auto;
}
/* "Marked answer" — the examiner's title, serif italic red. */
.tq-grade-title {
  font-family: var(--nb-serif);
  font-style: italic;
  font-weight: 600;
  font-size: var(--nb-text-md);
  color: var(--nb-red);
}
.tq-grade-sub {
  font: var(--nb-type-label);
  color: var(--nb-ink-2);
}
/* Reset — a quiet secondary action (blue interaction). */
.tq-grade-reset {
  display: inline-flex;
  align-items: center;
  gap: var(--nb-s2);
  padding: var(--nb-s1) var(--nb-s3);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--nb-blue) 40%, transparent);
  border-radius: var(--nb-r-sm);
  color: var(--nb-blue);
  font: var(--nb-type-control);
  cursor: pointer;
  transition:
    color var(--nb-dur-1) var(--nb-ease),
    border-color var(--nb-dur-1) var(--nb-ease),
    background-color var(--nb-dur-1) var(--nb-ease);
}
.tq-grade-reset:hover {
  color: var(--nb-blue-strong);
  border-color: var(--nb-blue-strong);
  background: var(--nb-blue-wash);
}
.tq-grade-reset:focus-visible {
  outline: 2px solid var(--nb-blue);
  outline-offset: 2px;
}

/* Skeleton (Motion shimmer placeholder while the grade is in flight). */
.tq-grade-skeleton {
  display: none;
}
.tq-grade-card.is-loading .tq-grade-skeleton {
  display: block;
}
.tq-grade-card.is-loading .tq-grade-body {
  display: none;
}
.tq-sk-list {
  list-style: none;
  margin: 0 0 var(--nb-s4);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--nb-s3);
}
.tq-sk-bar,
.tq-sk-line,
.tq-sk-chip {
  position: relative;
  display: block;
  overflow: hidden;
  /* sunken placeholder on the raised sheet (the card well is gone) */
  background: var(--nb-paper-sunken);
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-sm);
}
.tq-sk-bar {
  height: var(--nb-s5);
}
.tq-sk-bar--label {
  width: 40%;
}
.tq-sk-bar--title {
  width: 55%;
  margin-bottom: var(--nb-s3);
}
.tq-sk-line {
  height: var(--nb-s4);
  margin-bottom: var(--nb-s2);
}
.tq-sk-line--short {
  width: 60%;
}
.tq-sk-chip {
  height: var(--nb-s5);
  width: var(--nb-s8);
}
.tq-sk-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nb-s3);
  margin-bottom: var(--nb-s4);
}
.tq-sk-band {
  padding-top: var(--nb-s3);
  border-top: 1px solid var(--nb-border);
}
/* The shine grader.js appends inside each skeleton surface. */
.tq-sk-shine {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent,
    var(--nb-blue-wash),
    transparent
  );
}

/* Keypoints — the mark scheme as a ruled checklist on the paper itself:
   hairline-separated rows (notebook lines), no nested boxes. The examiner's
   pen (tick + verdict) is the only colour. */
.tq-keypoints {
  margin: 0;
}
.tq-kp-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.tq-kp {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--nb-s4);
  padding: var(--nb-s3) var(--nb-s1);
  border-bottom: 1px solid var(--nb-border);
  transition: background-color var(--nb-dur-1) var(--nb-ease);
}
.tq-kp:last-child {
  border-bottom: 0;
}
/* Awarded — the examiner ticked this point. The red tick + serif verdict carry
   the state; the paper itself stays paper (no wash — it muddied dark mode). */
.tq-kp-label {
  position: relative;
  min-width: 0;
  padding-left: var(--nb-s5);
  font: var(--nb-type-prose);
  color: var(--nb-ink);
}
/* Examiner marks in the margin (restored from legacy by owner request).
   Owner call 2026-07-11: verdicts wear the functional pass/fail voice —
   green ✓ = awarded, red ✕ = not awarded (examiner-red ticks read as
   "wrong"). ✓ keeps the serif tick at the canonical −4°, stamped in with a
   quick ink-press when grader.js flips .is-matched. The keyframe runs on
   class-add; --nb-dur-2 zeroes under reduced motion. */
.tq-kp-label::before {
  content: "\2715"; /* ✕ */
  position: absolute;
  left: 0;
  top: 0;
  font-size: 0.85em;
  font-weight: 700;
  line-height: 1.6;
  color: var(--nb-error);
}
.tq-kp.is-matched .tq-kp-label::before {
  content: "\2713"; /* ✓ */
  font-family: var(--nb-serif);
  font-size: 1em;
  font-weight: 700;
  color: var(--nb-success);
  transform: rotate(-4deg);
  animation: nb-kp-stamp var(--nb-dur-2) var(--nb-ease) both;
}
@keyframes nb-kp-stamp {
  from { opacity: 0; transform: rotate(-4deg) scale(0.4); }
  60%  { opacity: 1; transform: rotate(-4deg) scale(1.15); }
  to   { opacity: 1; transform: rotate(-4deg) scale(1); }
}
/* The verdict per point — serif italic, in the same pass/fail voice as the
   margin marks: "1 mark" = green (earned), "Not mentioned" = red (lost). */
.tq-kp-status {
  flex-shrink: 0;
  font-family: var(--nb-serif);
  font-style: italic;
  font-size: var(--nb-text-sm);
  white-space: nowrap;
  color: var(--nb-error);
}
.tq-kp.is-matched .tq-kp-status {
  color: var(--nb-success);
  font-weight: 600;
}

/* ---------- 8 · Score + examiner feedback band ---------------- */
/* The margin score division (.tq-total-value carries is-full/is-partial). It
   is written in the question head (.tq-q-marks--score); the class-toggle just
   re-weights it. */
.tq-total-value.is-full,
.tq-total-value.is-partial {
  font-weight: 700;
}

/* The full-width examiner feedback — the comment the examiner writes under the
   double rule at the end of your work (the classic totting-up line). No alert
   box: pen on the sheet. Outside the grade card; grader.js un-hides it on
   grade. The strongest examiner moment on the page. */
.tq-feedback-band {
  margin-top: var(--nb-s6);
  padding: var(--nb-s5) 0 0;
  background: transparent;
  border: 0;
  border-top: 3px double color-mix(in srgb, var(--nb-red) 55%, transparent);
}
.tq-feedback-band[hidden] {
  display: none;
}
.tq-block-title {
  display: inline-flex;
  align-items: center;
  gap: var(--nb-s2);
  margin-bottom: var(--nb-s3);
  font-family: var(--nb-serif);
  font-style: italic;
  font-weight: 600;
  font-size: var(--nb-text-sm);
  letter-spacing: 0.01em;
}
.tq-block-title--accent {
  color: var(--nb-red);
}
.tq-block-title--accent svg {
  color: var(--nb-red);
}
/* The comment itself reads in the examiner's hand: the notebook serif, ink. */
.tq-block-body {
  margin: 0;
  font: var(--nb-type-examiner);
  color: var(--nb-ink);
  max-width: 68ch;
}
.qg-feedback-text strong {
  font-weight: 700;
  /* key terms in the examiner's note stay in the reading ink, just bolder */
  color: var(--nb-ink);
}

/* ---------- 9 · Model-answer reveal --------------------------- */
.tq-reveal {
  margin-top: var(--nb-s5);
}
/* The toggle — a quiet blue secondary; chevron rotates when open. */
.tq-reveal-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--nb-s2);
  padding: var(--nb-s2) var(--nb-s4);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--nb-blue) 40%, transparent);
  border-radius: var(--nb-r-sm);
  color: var(--nb-blue);
  font: var(--nb-type-control);
  cursor: pointer;
  transition:
    color var(--nb-dur-1) var(--nb-ease),
    border-color var(--nb-dur-1) var(--nb-ease),
    background-color var(--nb-dur-1) var(--nb-ease);
}
.tq-reveal-btn:hover {
  color: var(--nb-blue-strong);
  border-color: var(--nb-blue-strong);
  background: var(--nb-blue-wash);
}
.tq-reveal-btn:focus-visible {
  outline: 2px solid var(--nb-blue);
  outline-offset: 2px;
}
.tq-reveal-chevron {
  transition: transform var(--nb-dur-2) var(--nb-ease);
}
.tq-reveal.is-open .tq-reveal-chevron {
  transform: rotate(180deg);
}
/* The panel — the model answer as a sunken quote sheet. */
.tq-reveal-panel {
  margin-top: var(--nb-s4);
  padding: var(--nb-s5) var(--nb-s6);
  background: color-mix(in srgb, var(--nb-adm-def) var(--nb-adm-tint), var(--nb-paper));
  border: 1px solid color-mix(in srgb, var(--nb-adm-def) 28%, transparent);
  border-radius: var(--nb-r-md);
}
.tq-reveal-panel[hidden] {
  display: none;
}
.tq-model-body {
  font: var(--nb-type-prose);
  color: var(--nb-ink);
}
.tq-model-body :first-child {
  margin-top: 0;
}
.tq-model-body :last-child {
  margin-bottom: 0;
}
.tq-model-body .katex {
  color: var(--nb-ink);
}

/* Non-gradable variant (free / no-scheme / signed-out): the exam sheet minus
   the marking form; a quiet upgrade note where the answer space would be. */
.tq-paper--ungraded {
  background: var(--nb-paper);
  /* Its own, much smaller stable floor (these cards are short: question +
     a one-line note). Evens out the 1- vs 2-line question wobble so the pager
     stays put here too, WITHOUT the big empty box the gradable floor would
     leave. Idle range ~183-234px, so this fits snugly. */
  min-height: 240px;
}
.tq-signin-hint {
  margin: 0;
  color: var(--nb-ink-2);
}

/* ---------- 10 · Pager (question-pager.js) -------------------- */
/* Injected after .noteviewer-body. Previous | windowed numbers + progress |
   Next. All interaction, so all blue. */
.qg-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nb-s4);
  margin-top: var(--nb-s6);
  padding-top: var(--nb-s5);
  border-top: 1px solid var(--nb-border);
}
.qg-pager-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--nb-s2);
  padding: var(--nb-s2) var(--nb-s4);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--nb-blue) 40%, transparent);
  border-radius: var(--nb-r-sm);
  color: var(--nb-blue);
  font: var(--nb-type-control);
  cursor: pointer;
  white-space: nowrap;
  transition:
    color var(--nb-dur-1) var(--nb-ease),
    border-color var(--nb-dur-1) var(--nb-ease),
    background-color var(--nb-dur-1) var(--nb-ease);
}
html.theme-light .qg-pager-btn:not(:disabled) {
  border-color: var(--nb-control-border);
}
/* Hover style guarded to :not(:disabled) — preserves the June-24 label-hide
   fix (a disabled button must not adopt the hover treatment). */
.qg-pager-btn:hover:not(:disabled) {
  color: var(--nb-blue-strong);
  border-color: var(--nb-blue-strong);
  background: var(--nb-blue-wash);
}
.qg-pager-btn:focus-visible {
  outline: 2px solid var(--nb-blue);
  outline-offset: 2px;
}
.qg-pager-btn:disabled {
  color: var(--nb-ink-2);
  border-color: var(--nb-border);
  cursor: not-allowed;
}
.qg-load-error-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--nb-s3);
  max-width: 34rem;
  text-align: center;
}
.qg-load-error-inner p {
  margin: 0;
  color: var(--nb-error);
  font: var(--nb-type-ui);
}
.qg-load-retry {
  justify-content: center;
  min-block-size: 44px;
}
.qg-pager-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--nb-s2);
  min-width: 0;
}
.qg-pager-nums {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--nb-s1);
  margin: 0;
  padding: 0;
  list-style: none;
}
.qg-pager-gap {
  padding: 0 var(--nb-s1);
  color: var(--nb-ink-3);
}
.qg-pager-num {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--nb-s7);
  height: var(--nb-s7);
  padding: 0 var(--nb-s2);
  overflow: hidden;
  background: transparent;
  border: 1px solid var(--nb-control-border);
  border-radius: var(--nb-r-sm);
  color: var(--nb-ink-2);
  font: var(--nb-type-control);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition:
    color var(--nb-dur-1) var(--nb-ease),
    border-color var(--nb-dur-1) var(--nb-ease),
    background-color var(--nb-dur-1) var(--nb-ease);
}
.qg-pager-num:hover:not(.is-current) {
  border-color: var(--nb-border-strong);
  color: var(--nb-ink);
}
html.theme-light .qg-pager-num:hover:not(.is-current) {
  border-color: var(--nb-control-border);
}
.qg-pager-num:focus-visible {
  outline: 2px solid var(--nb-blue);
  outline-offset: 2px;
}
.qg-pager-num.is-current {
  background: var(--nb-selection-fill);
  border-color: var(--nb-selection-border);
  color: var(--nb-selection-ink);
  box-shadow: inset 0 -3px 0 var(--nb-selection-marker);
}
.qg-pager-num-n {
  position: relative;
  z-index: 1;
}
/* Grade-state chip colour (server-derived bucket) — cosmetic, an examiner
   mark echoed onto the pager. full/partial wear examiner red at two weights;
   zero stays neutral. The current-question chip keeps the selection fill on top. */
.qg-pager-num[data-grade-state="full"] {
  border-color: var(--nb-red);
  color: var(--nb-red);
}
.qg-pager-num[data-grade-state="partial"] {
  border-color: color-mix(in srgb, var(--nb-red) 45%, transparent);
  color: var(--nb-red);
}
.qg-pager-num[data-grade-state="zero"] {
  border-color: var(--nb-border-strong);
  color: var(--nb-ink-2);
}
.qg-pager-num.is-current[data-grade-state] {
  color: var(--nb-selection-ink);
  border-color: var(--nb-selection-border);
}
/* playGrade() transient fill + confetti dots (grader/pager animation). */
.qg-pf-fill {
  position: absolute;
  inset: 0;
  transform-origin: bottom;
  background: var(--nb-red-wash);
}
.qg-pf-dot {
  position: absolute;
  width: 5px;
  height: 5px;
  border-radius: var(--nb-r-pill);
  background: var(--nb-red);
  pointer-events: none;
}

/* Progress meter — student's ink track. */
.qg-pager-progress {
  display: flex;
  align-items: center;
  gap: var(--nb-s3);
}
.qg-pager-track {
  position: relative;
  display: block;
  width: 96px;
  height: 3px;
  background: var(--nb-border);
  border-radius: var(--nb-r-pill);
  overflow: hidden;
}
.qg-pager-fill {
  position: absolute;
  inset: 0 auto 0 0;
  height: 100%;
  background: var(--nb-blue);
  border-radius: var(--nb-r-pill);
  /* question-pager.js (FROZEN) writes `style="width:N%"` straight onto this
     span in renderPager() — NOT a transform, and it never sets a custom prop —
     so the transition MUST be on `width` (a transform/scaleX approach the
     linter prefers is impossible without editing the frozen JS). The bar is a
     3px absolutely-positioned cosmetic line inside a fixed-height track, so the
     width transition causes no meaningful layout thrash. Same documented
     exception as .nb-fc-progress-fill in notebook-flashcards.css. */
  transition: width var(--nb-dur-3) var(--nb-ease);
}
.qg-pager-count {
  font: var(--nb-type-label);
  color: var(--nb-ink-2);
  white-space: nowrap;
}
.qg-pager-count b {
  color: var(--nb-ink);
  font-variant-numeric: tabular-nums;
}

/* ---------- 11 · Loading dots (.esa-dots) --------------------- */
/* pager.js injects the 3-dot loader while a not-yet-loaded question is fetched.
   nb doesn't load lazy-loading.css, so the loader is defined here in ink. */
.qg-loading {
  display: none;
}
.qg-loading.is-current {
  display: block;
}
.esa-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 180px;
}
.esa-dots {
  display: inline-flex;
  gap: var(--nb-s1);
  align-items: center;
  line-height: 0;
  color: var(--nb-ink-3);
}
.esa-dots > span {
  width: var(--nb-s2);
  height: var(--nb-s2);
  border-radius: var(--nb-r-pill);
  background: currentColor;
  opacity: 0.35;
  animation: nb-qg-dots 1.1s infinite ease-in-out both;
}
.esa-dots > span:nth-child(2) { animation-delay: 0.16s; }
.esa-dots > span:nth-child(3) { animation-delay: 0.32s; }
@keyframes nb-qg-dots {
  0%, 80%, 100% { opacity: 0.3; transform: translateY(0) scale(0.8); }
  40%           { opacity: 1;   transform: translateY(-4px) scale(1); }
}

/* ---------- 12 · Empty state + prev/next --------------------- */
.nb-qg-empty {
  margin-top: var(--nb-s4);
}

/* Prev/next topic nav (hidden by pager.js when the pager is active). */
.nb-qg-pagination {
  display: flex;
  gap: var(--nb-s4);
  margin-top: var(--nb-s7);
  padding-top: var(--nb-s5);
  border-top: 1px solid var(--nb-border);
}
.nb-pagenav {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  align-items: flex-start;
  text-align: left;
}
.nb-pagenav--next {
  align-items: flex-end;
  text-align: right;
  margin-left: auto;
}
.nb-pagenav-dir {
  font: var(--nb-type-label);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--nb-blue);
}
.nb-pagenav-title {
  font: var(--nb-type-label);
  color: var(--nb-ink-2);
}

/* Paywall placement */
.nb-paywall-wrap {
  display: flex;
  justify-content: center;
  margin-top: var(--nb-s8);
}

/* ---------- 13 · Mobile --------------------------------------- */
@media (max-width: 720px) {
  .tq-paper {
    padding: var(--nb-s5) var(--nb-s5) var(--nb-s5);
  }
  /* Narrow paper wraps the question to more lines + the answer form is taller,
     so the gradable floor is a shade higher than desktop (gradable cards idle
     ~411-462px here). Keeps the pager put on mobile too. */
  .qg--gradable .tq-paper {
    min-height: 470px;
  }
  .tq-q-head {
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--nb-s3);
  }
  /* Marks drop under the number+question on narrow paper. */
  .tq-q-marks {
    grid-column: 1 / -1;
    justify-self: start;
  }
  .nb-qg-actions {
    flex-direction: column;
    align-items: stretch;
  }
  .nb-qg-whole {
    margin-left: 0;
  }
  .qg-pager {
    flex-wrap: wrap;
    justify-content: center;
  }
  .qg-pager-center {
    order: -1;
    width: 100%;
  }
  .tq-answer-foot {
    align-items: flex-start;
  }
}

/* ---------- 14 · Reduced motion — duration-only guard --------- */
@media (prefers-reduced-motion: reduce) {
  .esa-dots > span { animation: none; opacity: 0.55; }
}

/* Confirmed high-frequency study controls keep their compact desktop rhythm,
   but gain a reliable finger-sized hit area on touch-primary devices. */
@media (pointer: coarse) {
  .questions-mode-tab {
    min-block-size: 44px;
  }
  .tq-reveal-btn {
    min-block-size: 44px;
  }
  .qg-pager-btn {
    min-block-size: 44px;
  }
  .qg-pager-num {
    min-inline-size: 44px;
    min-block-size: 44px;
  }
}
