/* ============================================================================
   Band9 Studio — design system.
   Two pages: the writing sheet (index.html) and the report (report.html).
   Every value below is a token. No component invents its own.
   No color-mix(), no :has(), no nesting, no container queries — the target is
   a mid-range Android WebView.
   ========================================================================== */

:root{
  color-scheme:light;

  /* paper & ink */
  --paper:#faf8f4; --paper-2:#f4f1ea; --sheet:#ffffff;
  --ink:#141f2b; --ink-2:#3d4c5c; --ink-3:#5c6b78; --ink-4:#8a97a2;
  --rule:rgba(20,31,43,.14); --rule-soft:rgba(20,31,43,.07);

  /* one accent, used sparingly */
  --accent:#4338ca; --accent-ink:#312a9e; --accent-soft:#eeecfb; --accent-line:#d9d5f4;

  /* muted, print-like pigments — never neon */
  --red:#a83a3a;   --red-soft:#f8ecea;
  --amber:#96661a; --amber-soft:#f8f0e2;
  --green:#1f6f4a; --green-soft:#e8f2ec;

  /* band mapping. overall is a half-band float; criterion bands are whole 1-9 */
  --band-low:#a83a3a; --band-mid:#96661a; --band-good:#4338ca; --band-high:#1f6f4a;

  /* type */
  --font-display:"Fraunces",Georgia,"Times New Roman",serif;
  --font-body:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
  /* What the essay itself is set in — see [data-wfont] below. */
  --font-write:var(--font-body); --fvs-write:normal;
  --t-band:clamp(64px,12vw,92px);
  --t-h1:28px; --t-h2:21px; --t-h3:17px;
  --t-body:16px;            /* never smaller on an input — iOS zooms below 16 */
  --t-sm:14px; --t-xs:13px; --t-micro:11px;
  --lh-tight:1.12; --lh-head:1.25; --lh-body:1.62;
  --lh-write:28px;          /* the ruled sheet: matches the ruling step exactly */
  --measure:66ch;

  /* spacing: 4px base, use the steps */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px;
  --s6:32px; --s7:48px; --s8:64px; --s9:96px;

  --r-xs:4px; --r-sm:8px; --r-md:12px; --r-lg:18px; --r-pill:999px;

  /* paper stacked on paper, never glow */
  --sh-1:0 1px 1px rgba(20,31,43,.04), 0 2px 6px rgba(20,31,43,.05);
  --sh-2:0 1px 2px rgba(20,31,43,.05), 0 6px 18px rgba(20,31,43,.06);

  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-settle:cubic-bezier(.34,1.28,.64,1);   /* the band reveal ONLY */
  --d1:120ms; --d2:200ms; --d3:320ms; --d4:640ms; --d-reveal:1100ms;

  --topbar-h:56px; --actionbar-h:64px;
  --gutter:clamp(16px,4vw,48px);
  --col:1180px;
}

/* ============================================================ DARK
   Not the logo's pure black: a student stares at this for forty minutes, and
   white-on-black at full contrast leaves after-images on a phone. Warm near-
   black paper, warm off-white ink, and every pigment lifted until it reads on a
   dark ground — the muted print reds and greens turn to mud otherwise.

   The system preference only decides the FIRST visit. After that the student's
   own choice wins, which is why the same block is repeated for the explicit
   attribute rather than nested inside the media query. */
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    color-scheme:dark;
    --paper:#14171c; --paper-2:#1b1f27; --sheet:#1e232c;
    --ink:#e9e5dd; --ink-2:#bcc3cc; --ink-3:#8d96a1; --ink-4:#69727d;
    --rule:rgba(233,229,221,.16); --rule-soft:rgba(233,229,221,.08);
    --accent:#a9a3f7; --accent-ink:#c3bffa; --accent-soft:#23233d; --accent-line:#3b3a63;
    --red:#e08a86; --red-soft:#2e2020; --amber:#dbab5e; --amber-soft:#2c2418;
    --green:#6fc79b; --green-soft:#182a22;
    --band-low:#e08a86; --band-mid:#dbab5e; --band-good:#a9a3f7; --band-high:#6fc79b;
  }
}
:root[data-theme="dark"]{
  color-scheme:dark;
  --paper:#14171c; --paper-2:#1b1f27; --sheet:#1e232c;
  --ink:#e9e5dd; --ink-2:#bcc3cc; --ink-3:#8d96a1; --ink-4:#69727d;
  --rule:rgba(233,229,221,.16); --rule-soft:rgba(233,229,221,.08);
  --accent:#a9a3f7; --accent-ink:#c3bffa; --accent-soft:#23233d; --accent-line:#3b3a63;
  --red:#e08a86; --red-soft:#2e2020; --amber:#dbab5e; --amber-soft:#2c2418;
  --green:#6fc79b; --green-soft:#182a22;
  --band-low:#e08a86; --band-mid:#dbab5e; --band-good:#a9a3f7; --band-high:#6fc79b;
}
/* ============================================================ RESET */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font:400 var(--t-body)/var(--lh-body) var(--font-body);
  -webkit-font-smoothing:antialiased;
  overflow-wrap:break-word;
}
h1,h2,h3,p,ul,ol,figure,blockquote,dl,dd{margin:0}
ul,ol{padding:0;list-style:none}
button,input,textarea,select{font:inherit;color:inherit}
button{background:none;border:0;padding:0;cursor:pointer}
img,svg{display:block;max-width:100%}
a{color:var(--accent-ink)}
[hidden]{display:none !important}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--r-xs)}
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ============================================================ LAYOUT */
.wrap{max-width:var(--col);margin:0 auto;padding-left:var(--gutter);padding-right:var(--gutter)}
.row{display:flex;align-items:center;gap:var(--s3)}
.spacer{flex:1 1 auto}
.stack{display:flex;flex-direction:column}

.eyebrow{
  display:block;font-size:var(--t-micro);font-weight:600;
  text-transform:uppercase;letter-spacing:.12em;color:var(--ink-3);
}
.meta{font-size:var(--t-xs);color:var(--ink-3)}
.num{font-family:var(--font-display);font-weight:600;font-variation-settings:"opsz" 40;line-height:1}

/* ============================================================ BUTTONS */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  min-height:44px;padding:0 var(--s4);
  border:1px solid transparent;border-radius:var(--r-sm);
  font-size:var(--t-sm);font-weight:500;white-space:nowrap;
  transition:background-color var(--d1) var(--ease),border-color var(--d1) var(--ease),color var(--d1) var(--ease);
}
.btn:disabled{cursor:not-allowed;color:var(--ink-4)}
.btn-primary{background:var(--accent);border-color:var(--accent);color:#fff}
.btn-primary:disabled{background:var(--paper-2);border-color:var(--rule)}
.btn-quiet{background:var(--sheet);border-color:var(--rule);color:var(--ink)}
.btn-quiet:hover:not(:disabled){border-color:var(--accent-line)}
.btn-ghost{color:var(--ink-2)}
.btn-ghost:hover:not(:disabled){color:var(--ink)}
.btn-sm{min-height:34px;padding:0 var(--s3);font-size:var(--t-xs)}
.btn:active:not(:disabled){transform:translateY(1px)}

.chip{
  display:inline-flex;align-items:center;gap:var(--s2);
  min-height:34px;padding:0 var(--s3);
  border:1px solid var(--rule);border-radius:var(--r-pill);
  background:var(--sheet);font-size:var(--t-xs);color:var(--ink-2);
}
.chip[aria-pressed="true"]{border-color:var(--accent);background:var(--accent-soft);color:var(--accent-ink)}

.pill{
  display:inline-flex;align-items:center;padding:2px var(--s2);
  border-radius:var(--r-pill);font-size:var(--t-micro);font-weight:600;
  letter-spacing:.06em;text-transform:uppercase;white-space:nowrap;
}
.pill-ok{background:var(--green-soft);color:var(--green)}
.pill-warn{background:var(--amber-soft);color:var(--amber)}
.pill-off{background:var(--paper-2);color:var(--ink-3)}

.seg{display:inline-flex;padding:3px;background:var(--paper-2);border-radius:var(--r-sm);gap:2px}
.seg button{
  min-height:32px;padding:0 var(--s3);border-radius:6px;
  font-size:var(--t-xs);color:var(--ink-3);
  transition:background-color var(--d1) var(--ease),color var(--d1) var(--ease);
}
.seg button[aria-pressed="true"]{background:var(--sheet);color:var(--ink);font-weight:600;box-shadow:var(--sh-1)}
/* The typeface picker sets each button in the face it selects — the label is
   the sample. Full width because it sits in a sheet, not in a toolbar. */
.seg-font{display:flex;width:100%}
.seg-font button{flex:1;font-size:var(--t-sm)}
.seg-font button[data-wf="sans"]{font-family:var(--font-body)}
.seg-font button[data-wf="serif"]{font-family:var(--font-display);font-variation-settings:"opsz" 14}
.seg-font button[data-wf="mono"]{font-family:var(--font-mono)}

/* ============================================================ FIELDS */
.field{display:flex;flex-direction:column;gap:var(--s2)}
.field-label{font-size:var(--t-sm);font-weight:500}
.field input,.field textarea{
  width:100%;padding:var(--s3);
  background:var(--sheet);border:1px solid var(--rule);border-radius:var(--r-sm);
  font-size:var(--t-body);
}
.field input:focus,.field textarea:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.field-hint{font-size:var(--t-xs);color:var(--ink-3)}
.field-error{font-size:var(--t-xs);color:var(--red)}

/* ============================================================ NOTICE */
.notice{
  display:flex;flex-direction:column;gap:var(--s2);
  padding:var(--s4);border-left:3px solid var(--rule);
  background:var(--paper-2);border-radius:0 var(--r-sm) var(--r-sm) 0;
  font-size:var(--t-sm);color:var(--ink-2);
}
.notice-title{font-family:var(--font-display);font-size:var(--t-h3);font-variation-settings:"opsz" 14;color:var(--ink)}
.notice-info{border-left-color:var(--accent);background:var(--accent-soft)}
.notice-warn{border-left-color:var(--amber);background:var(--amber-soft)}
.notice-error{border-left-color:var(--red);background:var(--red-soft)}
.notice-ok{border-left-color:var(--green);background:var(--green-soft)}
.notice-actions{display:flex;flex-wrap:wrap;gap:var(--s2);padding-top:var(--s1)}

/* ============================================================ TOPBAR */
.topbar{
  position:sticky;top:0;z-index:40;
  display:flex;align-items:center;gap:var(--s3);
  min-height:var(--topbar-h);padding:0 var(--gutter);
  background:var(--paper);border-bottom:1px solid var(--rule);
}
.wordmark{
  display:inline-flex;align-items:center;gap:.45rem;
  font-family:var(--font-display);font-weight:600;font-size:var(--t-h3);
  font-variation-settings:"opsz" 14;letter-spacing:-.02em;color:var(--ink);
  text-decoration:none;white-space:nowrap;
}
/* Inlined, so it takes its colour from .wordmark and follows the theme. Optical
   nudge: the bulb's cord makes it sit high against a cap-height wordmark. */
.wordmark .mark{flex:0 0 auto;margin-top:.08em}
.timer{font-family:var(--font-display);font-weight:600;font-size:var(--t-h3);font-variation-settings:"opsz" 14;font-variant-numeric:tabular-nums}
.timer.is-warn{color:var(--amber)}
.timer.is-late{color:var(--red)}

/* ============================================================ SHEET (dialog) */
.backdrop{
  position:fixed;inset:0;z-index:60;
  display:flex;align-items:flex-end;justify-content:center;
  background:rgba(20,31,43,.32);
  opacity:0;transition:opacity var(--d2) var(--ease);
}
.backdrop.is-open{opacity:1}
.sheet{
  width:100%;max-width:620px;max-height:88vh;
  display:flex;flex-direction:column;
  background:var(--sheet);border-radius:var(--r-lg) var(--r-lg) 0 0;
  box-shadow:var(--sh-2);
  transform:translateY(12px);transition:transform var(--d2) var(--ease);
}
.backdrop.is-open .sheet{transform:none}
.sheet-head{display:flex;align-items:center;gap:var(--s3);padding:var(--s5) var(--s5) var(--s3)}
.sheet-head h2{font-family:var(--font-display);font-size:var(--t-h2);font-variation-settings:"opsz" 40}
.sheet-body{padding:0 var(--s5) var(--s5);overflow-y:auto;display:flex;flex-direction:column;gap:var(--s3)}
.sheet-foot{display:flex;gap:var(--s2);padding:var(--s3) var(--s5) var(--s5);border-top:1px solid var(--rule-soft)}
@media (min-width:700px){
  .backdrop{align-items:center}
  .sheet{border-radius:var(--r-lg);max-height:82vh}
}

/* ============================================================================
   PAGE 1 — THE QUIET SHEET
   Minimal means: paper, the question, the words you have written, and one
   button. Everything else is one tap away and nothing else is on screen.
   ========================================================================== */
.write{display:flex;flex-direction:column;min-height:100dvh}
.write main{flex:1 1 auto;padding-bottom:var(--s7)}

/* the question — quiet, collapsible, never competing with the sheet */
.qcard{
  margin:var(--s5) auto 0;max-width:var(--col);
  padding:0 var(--gutter);
}
.qcard summary{
  display:flex;align-items:center;gap:var(--s2);
  list-style:none;cursor:pointer;color:var(--ink-3);font-size:var(--t-xs);
}
.qcard summary::-webkit-details-marker{display:none}
.qcard summary .caret{transition:transform var(--d1) var(--ease)}
.qcard[open] summary .caret{transform:rotate(90deg)}
.qtext{
  font-family:var(--font-display);font-size:var(--t-h3);
  font-variation-settings:"opsz" 14;line-height:var(--lh-head);
  color:var(--ink);max-width:var(--measure);margin-top:var(--s3);
}
.qempty{color:var(--ink-3);font-family:var(--font-body);font-size:var(--t-sm)}

/* the writing surface */
.paper{
  max-width:var(--col);margin:var(--s4) auto 0;
  padding:0 var(--gutter);
}
.paper-inner{
  position:relative;background:var(--sheet);
  border:1px solid var(--rule);border-radius:var(--r-md);
  padding:var(--s5);box-shadow:var(--sh-1);
}
.paper-inner:focus-within{border-color:var(--accent-line)}
#essay{
  display:block;width:100%;min-height:52vh;resize:vertical;
  border:0;outline:none;background:transparent;padding:0;
  font-family:var(--font-write);
  font-size:var(--t-body);line-height:var(--lh-write);
  font-variation-settings:var(--fvs-write);
  color:var(--ink);
  /* Tab inserts four spaces, so a tab that arrives by paste must measure the
     same four — otherwise the same indent is two widths on one page. */
  tab-size:4;
}
/* the ruling is drawn only once the metrics are settled, or it misaligns */
.fonts-ready .paper-inner{
  background-image:repeating-linear-gradient(
    to bottom,transparent 0,transparent calc(var(--lh-write) - 1px),
    var(--rule-soft) calc(var(--lh-write) - 1px),var(--rule-soft) var(--lh-write));
  background-position:0 var(--s5);
  background-clip:content-box;
}
#essay::placeholder{color:var(--ink-4)}

/* The three writing faces. Set on <html> so the report page picks up the same
   choice and a student reads their marked essay in the face they wrote it in.
   Only the family changes — size and leading stay on the ruling. */
:root[data-wfont="serif"]{
  --font-write:var(--font-display);
  /* Fraunces at display size has thin hairlines; opsz 14 is the reading cut. */
  --fvs-write:"opsz" 14;
}
:root[data-wfont="mono"]{ --font-write:var(--font-mono); --fvs-write:normal }

/* Tab only exists where there is a keyboard. */
.tabhint{display:none}
@media (hover:hover) and (pointer:fine){ .tabhint{display:inline} }

.sheet-foot-meta{
  display:flex;gap:var(--s4);max-width:var(--col);
  margin:var(--s2) auto 0;padding:0 var(--gutter);
  font-size:var(--t-xs);color:var(--ink-3);
}
.saved{color:var(--green)}

/* the only persistent control */
.actionbar{
  position:sticky;bottom:0;z-index:30;
  background:var(--paper);border-top:1px solid var(--rule);
}
.actionbar-inner{
  display:flex;align-items:center;gap:var(--s3);
  max-width:var(--col);margin:0 auto;
  min-height:var(--actionbar-h);padding:var(--s2) var(--gutter);
}
.wc{display:flex;align-items:baseline;gap:var(--s2);white-space:nowrap}
.wc-num{font-family:var(--font-display);font-weight:600;font-size:var(--t-h2);font-variation-settings:"opsz" 40;font-variant-numeric:tabular-nums;line-height:1}
.wc-num.is-met{color:var(--band-high)}

/* task 1 figures */
.figure{margin:var(--s4) 0 0;display:flex;flex-direction:column;gap:var(--s2)}
.figure figcaption{font-size:var(--t-xs);font-weight:600;color:var(--ink-2)}
.chart svg{width:100%;height:auto}
.ch-grid{stroke:var(--rule-soft);stroke-width:1}
.ch-axis{stroke:var(--rule);stroke-width:1}
.ch-tick{font-family:var(--font-body);font-size:11px;fill:var(--ink-3);text-anchor:middle}
.ch-tick-y{text-anchor:end}
.ch-bar,.ch-slice,.ch-dot{fill:var(--ch-c)}
.ch-line{fill:none;stroke:var(--ch-c);stroke-width:2.5;stroke-linejoin:round;stroke-linecap:round}
.ch-slice{stroke:var(--sheet);stroke-width:2}
.ch-s1{--ch-c:var(--accent)} .ch-s2{--ch-c:var(--green)}
.ch-s3{--ch-c:var(--amber)} .ch-s4{--ch-c:var(--ink-3)}
.ch-legend{display:flex;flex-wrap:wrap;gap:var(--s2) var(--s4);font-size:var(--t-xs);color:var(--ink-2)}
.ch-legend li{display:flex;align-items:center;gap:var(--s2)}
.ch-key{width:10px;height:10px;border-radius:var(--r-xs);background:var(--ch-c)}
.ch-scroll{overflow-x:auto}

.upload{
  display:flex;flex-direction:column;gap:var(--s3);margin-top:var(--s4);
  padding:var(--s4);border:1px dashed var(--rule);border-radius:var(--r-sm);
  background:var(--paper-2);
}
.upload.is-over{border-color:var(--accent);background:var(--accent-soft)}
.upload img{border:1px solid var(--rule);border-radius:var(--r-xs);background:var(--sheet)}

/* question picker rows */
.qrow{
  display:flex;flex-direction:column;gap:var(--s1);width:100%;text-align:left;
  padding:var(--s3);background:var(--sheet);
  border:1px solid var(--rule);border-radius:var(--r-sm);
  transition:border-color var(--d1) var(--ease),background-color var(--d1) var(--ease);
}
.qrow:hover{border-color:var(--accent-line);background:var(--accent-soft)}
.qrow .meta{font-size:var(--t-micro);text-transform:uppercase;letter-spacing:.1em}
.qrow span:last-child{font-family:var(--font-display);font-size:var(--t-sm);font-variation-settings:"opsz" 14;color:var(--ink)}

/* waiting */
.wait{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--s4);min-height:70dvh;text-align:center;padding:var(--s5);
}
.wait h2{font-family:var(--font-display);font-size:var(--t-h2);font-variation-settings:"opsz" 40}
.wait-bar{width:min(320px,80vw);height:3px;background:var(--rule-soft);border-radius:var(--r-pill);overflow:hidden}
.wait-bar i{display:block;height:100%;width:35%;background:var(--accent);border-radius:var(--r-pill);animation:slide 1600ms var(--ease) infinite}
@keyframes slide{0%{transform:translateX(-100%)}100%{transform:translateX(300%)}}

/* ============================================================================
   PAGE 2 — THE REPORT
   Dense is allowed here; unscannable is not. Every section is a <section> with
   an eyebrow, and every number on this page was computed in code.
   ========================================================================== */
.report{padding-bottom:var(--s9)}
.sec{padding:var(--s6) 0;border-top:1px solid var(--rule-soft)}
.sec:first-of-type{border-top:0}
.sec > .eyebrow{margin-bottom:var(--s3)}
.sec h2{
  font-family:var(--font-display);font-size:var(--t-h2);
  font-variation-settings:"opsz" 40;line-height:var(--lh-head);margin-bottom:var(--s3);
}
.sec-note{font-size:var(--t-sm);color:var(--ink-2);max-width:var(--measure)}
.empty{font-size:var(--t-sm);color:var(--ink-3)}

/* ---- 1 · the band ---- */
.band-row{display:grid;grid-template-columns:auto minmax(0,1fr);gap:var(--s7);align-items:start;padding-top:var(--s4)}
.band-side{display:flex;flex-direction:column;align-items:center;gap:var(--s2);text-align:center}
.ring{position:relative;width:184px;height:184px}
.ring svg{width:100%;height:100%;transform:rotate(-90deg)}
.ring-track{fill:none;stroke:var(--rule-soft);stroke-width:9}
.ring-arc{fill:none;stroke-width:9;stroke-linecap:round;transition:stroke-dashoffset var(--d-reveal) var(--ease)}
.ring-mid{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px}
.ring-num{
  font-family:var(--font-display);font-weight:600;font-size:var(--t-band);
  font-variation-settings:"opsz" 100;letter-spacing:-.03em;line-height:var(--lh-tight);
  font-variant-numeric:tabular-nums;
}
.ring-word{font-size:var(--t-sm);color:var(--ink-3)}
.ring-note{font-size:var(--t-xs);color:var(--ink-3);max-width:30ch}
.facts{display:flex;flex-direction:column;gap:var(--s1);font-size:var(--t-xs);color:var(--ink-3);margin-top:var(--s2)}

.crit{display:flex;flex-direction:column;gap:var(--s2);padding:var(--s4) 0;border-top:1px solid var(--rule-soft)}
.crit:first-child{border-top:0}
.crit-head{display:flex;align-items:baseline;gap:var(--s3);cursor:pointer}
.crit-name{font-size:var(--t-sm);font-weight:600}
.crit-gloss{font-size:var(--t-xs);color:var(--ink-3)}
.crit-band{margin-left:auto;font-family:var(--font-display);font-weight:600;font-size:var(--t-h2);font-variation-settings:"opsz" 40;line-height:1}
.crit-track{height:3px;background:var(--rule-soft);border-radius:var(--r-pill);overflow:hidden}
.crit-fill{display:block;height:100%;border-radius:var(--r-pill);transform:scaleX(0);transform-origin:left;transition:transform var(--d4) var(--ease)}
.crit-fill.is-in{transform:scaleX(var(--fill,0))}
.crit-body{display:flex;flex-direction:column;gap:var(--s3);padding-top:var(--s2)}
.crit-uz{font-size:var(--t-sm);color:var(--ink-2);max-width:var(--measure)}
.crit-en{font-size:var(--t-xs);color:var(--ink-3);max-width:var(--measure)}
.crit-quotes{display:flex;flex-direction:column;gap:var(--s2);padding-left:var(--s4);border-left:1px solid var(--rule)}
.crit-quotes li{font-family:var(--font-display);font-size:var(--t-sm);font-variation-settings:"opsz" 14;color:var(--ink-2)}
.crit-weak .crit-name{color:var(--amber)}
.crit-cap{font-size:var(--t-xs);color:var(--amber)}

/* ---- 2 · the three-sentence verdict ---- */
.verdict{
  padding:var(--s5);background:var(--paper-2);
  border-left:3px solid var(--accent-line);border-radius:0 var(--r-sm) var(--r-sm) 0;
}
.verdict p{
  font-family:var(--font-display);font-size:var(--t-h3);
  font-variation-settings:"opsz" 24;line-height:var(--lh-head);
  max-width:var(--measure);
}

/* ---- 4 · the marked essay ---- */
.marked{
  /* Their own words, read back in the face they wrote them in. */
  font-family:var(--font-write);font-variation-settings:var(--fvs-write);
  font-size:var(--t-body);line-height:var(--lh-write);
  max-width:var(--measure);
  background:var(--sheet);border:1px solid var(--rule);border-radius:var(--r-md);
  padding:var(--s5);
}
.marked p + p{margin-top:var(--lh-write)}
.mark{
  background:linear-gradient(to top,var(--mark-c) 0,var(--mark-c) 2px,transparent 2px);
  cursor:pointer;padding-bottom:1px;
}
.mark-red{--mark-c:var(--red)}
.mark-amber{--mark-c:var(--amber)}
.mark-green{--mark-c:var(--green);cursor:default}
.mark.is-open{background-color:var(--amber-soft)}
.markcount{display:flex;gap:var(--s4);font-size:var(--t-xs);color:var(--ink-3);margin-bottom:var(--s3)}

/* ---- 5 · corrections ---- */
.fix{
  display:grid;grid-template-columns:92px minmax(0,1fr);gap:var(--s2) var(--s4);
  padding:var(--s4) 0;border-top:1px solid var(--rule);position:relative;
}
.fix-label{font-size:var(--t-micro);font-weight:600;text-transform:uppercase;letter-spacing:.12em;color:var(--ink-3)}
.fix-was{color:var(--ink-2);text-decoration:line-through;text-decoration-color:rgba(168,58,58,.55)}
.fix-is{font-weight:500;text-decoration:underline;text-decoration-color:var(--green);text-decoration-thickness:2px;text-underline-offset:4px}
.fix-why{font-size:var(--t-sm);color:var(--ink-2);max-width:var(--measure)}
.fix-en{font-size:var(--t-xs);color:var(--ink-3)}
.fix-tags{position:absolute;top:var(--s4);right:0;display:flex;gap:var(--s2)}
.fix-missing{font-size:var(--t-xs);color:var(--ink-3)}
.fix.is-flash{background:var(--amber-soft)}

/* ---- 6 · error patterns ---- */
.pat{display:flex;flex-direction:column;gap:var(--s2);padding:var(--s3) 0;border-top:1px solid var(--rule-soft)}
.pat-head{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap}
.pat-name{font-weight:600;font-size:var(--t-sm)}
.pat-en{font-size:var(--t-xs);color:var(--ink-3)}
.pat-n{margin-left:auto;font-family:var(--font-display);font-weight:600;font-size:var(--t-h3);font-variation-settings:"opsz" 14}
.pat-rule{font-size:var(--t-sm);color:var(--ink-2);max-width:var(--measure)}

/* ---- 7 · sentence strip ---- */
.strip{display:flex;gap:2px;align-items:flex-end;height:34px;margin:var(--s3) 0}
.strip i{
  display:block;height:100%;min-width:6px;border-radius:2px;
  background:var(--accent-line);
}
.strip i.bad{background:transparent;border:1.5px solid var(--red)}
.strip-legend{display:flex;gap:var(--s4);font-size:var(--t-xs);color:var(--ink-3)}

/* ---- 8-12 · lists ---- */
.kv{display:flex;flex-wrap:wrap;gap:var(--s2)}
.vocab{padding:var(--s3) 0;border-top:1px solid var(--rule-soft);display:flex;flex-direction:column;gap:var(--s1)}
.vocab-host{font-size:var(--t-sm);color:var(--ink-2)}
.vocab-host b{color:var(--ink);font-weight:600}
.vocab-swap{color:var(--green);font-weight:600}
.vocab-note{font-size:var(--t-xs);color:var(--ink-3)}
.twocol{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s5)}
.bar2{display:flex;height:8px;border-radius:var(--r-pill);overflow:hidden;background:var(--rule-soft)}
.bar2 i{display:block;height:100%}
.bar2 .b1{background:var(--amber)} .bar2 .b2{background:var(--green)}
.pxray{padding:var(--s3) 0;border-top:1px solid var(--rule-soft);display:flex;flex-direction:column;gap:var(--s2)}
.pxray-topic{padding-left:var(--s3);border-left:2px solid var(--rule);font-family:var(--font-display);font-size:var(--t-sm);font-variation-settings:"opsz" 14;color:var(--ink-2)}
.ticks{display:flex;gap:var(--s3);font-size:var(--t-xs)}
.tick-y{color:var(--green)} .tick-n{color:var(--ink-4)}
.check{display:flex;align-items:baseline;gap:var(--s3);padding:var(--s2) 0;border-top:1px solid var(--rule-soft);font-size:var(--t-sm)}
.check-y{color:var(--green)} .check-n{color:var(--red)}

/* ---- 13 · the band-8 rewrite ---- */
.rewrite{display:grid;gap:var(--s4)}
.rewrite-col{background:var(--sheet);border:1px solid var(--rule);border-radius:var(--r-md);padding:var(--s4)}
.rewrite-col p{font-size:var(--t-sm);line-height:var(--lh-body);color:var(--ink-2)}
.rewrite-col.is-new p{color:var(--ink)}
.ann{display:flex;gap:var(--s3);padding:var(--s2) 0;border-top:1px solid var(--rule-soft);font-size:var(--t-sm)}
.ann-n{font-family:var(--font-display);font-weight:600;color:var(--accent-ink);min-width:18px}
.ann u{text-decoration-color:var(--accent-line);text-decoration-thickness:2px;text-underline-offset:3px}
@media (min-width:1000px){.rewrite{grid-template-columns:repeat(2,minmax(0,1fr))}}

/* ---- 14 · drills ---- */
.drill{padding:var(--s4) 0;border-top:1px solid var(--rule);display:flex;flex-direction:column;gap:var(--s2)}
.drill-head{display:flex;align-items:baseline;gap:var(--s3)}
.drill-head h3{font-family:var(--font-display);font-size:var(--t-h3);font-variation-settings:"opsz" 14}
.drill-time{margin-left:auto;font-size:var(--t-xs);color:var(--ink-3)}
.drill-items{display:flex;flex-direction:column;gap:var(--s2)}
.drill-items li{display:flex;gap:var(--s3);font-size:var(--t-sm);color:var(--ink-2)}
.one-task{
  margin-top:var(--s5);padding:var(--s5);background:var(--accent-soft);
  border-radius:var(--r-md);font-family:var(--font-display);
  font-size:var(--t-h3);font-variation-settings:"opsz" 24;line-height:var(--lh-head);
}

/* ---- 15 · history ---- */
.hist{width:100%;border-collapse:collapse;font-size:var(--t-sm)}
.hist th{text-align:left;font-size:var(--t-micro);text-transform:uppercase;letter-spacing:.1em;color:var(--ink-3);padding:var(--s2) var(--s3);border-bottom:1px solid var(--rule)}
.hist td{padding:var(--s2) var(--s3);border-bottom:1px solid var(--rule-soft);color:var(--ink-2)}
.hist .b{font-family:var(--font-display);font-weight:600;font-size:var(--t-h3);font-variation-settings:"opsz" 14}
.trend-up{color:var(--green)} .trend-down{color:var(--red)} .trend-flat{color:var(--ink-3)}

/* ---- 16 · honesty ---- */
.honest{font-size:var(--t-xs);color:var(--ink-3);display:flex;flex-direction:column;gap:var(--s1);max-width:var(--measure)}

/* skeleton while DEPTH is still in flight */
.skel{background:var(--paper-2);border-radius:var(--r-xs);height:12px;animation:pulse 1500ms ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.45}}
.skel-rows{display:flex;flex-direction:column;gap:var(--s2)}

/* ============================================================ MOBILE */
@media (max-width:860px){
  .band-row{grid-template-columns:minmax(0,1fr);gap:var(--s5);justify-items:center}
  .band-crits{width:100%}
  .twocol{grid-template-columns:minmax(0,1fr);gap:var(--s4)}
}
@media (max-width:560px){
  .ring{width:150px;height:150px}
  .fix{grid-template-columns:minmax(0,1fr);gap:var(--s1)}
  .fix-tags{position:static;order:-1}
  .topbar{gap:var(--s2)}
  .marked{padding:var(--s4)}
}

/* ============================================================ PRINT */
@media print{
  .topbar,.actionbar,.backdrop,.no-print{display:none !important}
  body{background:#fff;font-size:11pt}
  .sec{break-inside:avoid;border-top:1px solid #ccc}
  .marked,.rewrite-col,.paper-inner{border:1px solid #ccc;box-shadow:none}
  a{text-decoration:none;color:#000}
}

/* ============================================================ MOTION */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important}
  .crit-fill{transform:scaleX(var(--fill,0))}
}
/* Self-hosted subsets from Google Fonts. The -ext files carry U+02BB/U+02BC,
   the Uzbek okina and tutuq belgisi — without them Uzbek text renders as boxes. */
@font-face{font-family:"Inter";src:url("/fonts/inter-400-ext.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap;
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:"Inter";src:url("/fonts/inter-400-latin.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap;
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:"Inter";src:url("/fonts/inter-500-ext.woff2") format("woff2");
  font-weight:500;font-style:normal;font-display:swap;
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:"Inter";src:url("/fonts/inter-500-latin.woff2") format("woff2");
  font-weight:500;font-style:normal;font-display:swap;
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:"Inter";src:url("/fonts/inter-600-ext.woff2") format("woff2");
  font-weight:600;font-style:normal;font-display:swap;
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:"Inter";src:url("/fonts/inter-600-latin.woff2") format("woff2");
  font-weight:600;font-style:normal;font-display:swap;
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:"Fraunces";src:url("/fonts/fraunces-400-700-ext.woff2") format("woff2");
  font-weight:400 700;font-style:normal;font-display:swap;
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:"Fraunces";src:url("/fonts/fraunces-400-700-latin.woff2") format("woff2");
  font-weight:400 700;font-style:normal;font-display:swap;
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}

/* The one message a student must see before writing, not after submitting. */
/* .notice is a column; this one needs the retry button beside the reason. */
.offline-bar{flex-direction:row;align-items:center;flex-wrap:wrap;margin-bottom:var(--s4)}
.offline-bar .notice-title{flex:0 0 100%}
.offline-bar span:not(.notice-title){flex:1 1 12rem;min-width:0}
.offline-bar .btn{margin-left:auto;flex:0 0 auto}

/* Topic chips in the question sheet. Horizontal scroll rather than wrap: on a
   phone a wrapped row of eight pushes the questions themselves below the fold. */
.chips{
  /* .sheet-body is a column flex container, so without flex:0 0 auto this row
     is squashed to a few pixels by the question list below it. */
  flex:0 0 auto;
  display:flex;gap:var(--s2);overflow-x:auto;padding-bottom:var(--s2);
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
}
.chips::-webkit-scrollbar{display:none}
.chip{
  flex:0 0 auto;padding:.4rem .8rem;border:1px solid var(--rule);
  border-radius:999px;background:transparent;color:var(--ink-2);
  font:inherit;font-size:var(--t-sm);cursor:pointer;white-space:nowrap;
}
.chip:hover{border-color:var(--accent-line);color:var(--ink)}
.chip.is-on{background:var(--accent-soft);border-color:var(--accent-line);color:var(--accent-ink)}

/* The scrim is tuned for dimming a light page. On a dark one it barely darkens
   anything, so the sheet stops reading as a layer above the page. */
:root[data-theme="dark"] .backdrop{background:rgba(0,0,0,.62)}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .backdrop{background:rgba(0,0,0,.62)}
}

/* ============================================================ TASK 1 FIGURE
   A chart is a thing to read closely, not decoration. It gets its own scroll
   box so zooming in does not push the writing surface off the screen, and the
   box keeps a fixed height so the page does not jump as the student zooms. */
.figwrap{margin-top:var(--s3)}
.figbar{
  display:flex;align-items:center;gap:var(--s2);
  margin-bottom:var(--s2);
}
.figbar .meta{min-width:3.5em;text-align:center;font-variant-numeric:tabular-nums}
.figbox{
  overflow:auto;background:var(--sheet);
  border:1px solid var(--rule);border-radius:var(--r-sm);
  padding:var(--s3);max-height:52vh;
  -webkit-overflow-scrolling:touch;
}
/* Zoom is a width, not a transform: a scaled element keeps its old box, so the
   scrollbars never appear and the student cannot reach what they zoomed to.
   It has to land on the svg/img themselves — the reset clamps both to
   max-width:100%, so growing only the wrapper would leave the picture behind. */
/* The zoom width is written in pixels from JS onto the box's direct child, and
   everything inside simply fills it. Three things were learned the hard way:
   the svg is a flex item of the figure so a width set on it is ignored; a
   percentage width does not resolve inside this scroll container; and a
   min-width:100% on the same element that JS resizes fights the resize and
   pins it at the first step. The reset's max-width:100% must also be lifted or
   the picture stays clamped whatever the box does. */
/* Zoom is a transform, not a width. Widths were tried first and lost to three
   separate quirks in this structure — the svg is a flex item so a width on it
   is ignored, percentages do not resolve inside the scroll container, and a
   min-width on the resized element pins it after one step. A transform has
   none of that. It also does not affect layout, which is why .figzoom carries
   an explicit size: without it the box has nothing to scroll. */
.figzoom{transform-origin:top left;transition:transform var(--d1) var(--ease)}
.figbox .chart svg{width:100%;height:auto;display:block}
.figbox img{max-width:none;width:100%;height:auto;display:block}

/* ============================================================ SPLIT VIEW
   Task 1 asks the student to read figures and write about them at the same
   time. Stacked, that is a scroll up, remember, scroll down for every number.
   Side by side only above 1000px — below it there is no room for two columns
   and the stacked order (question, then paper) is already the right one. */
@media (min-width:1000px){
  main.split{
    display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);
    gap:var(--s5);align-items:start;
    max-width:calc(var(--col) + 320px);margin-inline:auto;
  }
  main.split > .qcard,
  main.split > .paper{max-width:none;margin-inline:0}
  main.split > .offline-bar{grid-column:1 / -1}
  /* The question column scrolls with the page but stays put while the student
     writes — the figures need to be visible, not remembered. */
  main.split > .qcard{position:sticky;top:var(--s4)}
  main.split .figbox{max-height:60vh}
  main.split #essay{min-height:64vh}

  /* Fold the question away and the split has nothing to split: the left column
     keeps its half of the screen, the paper is squeezed into a strip, and the
     student is typing into a column narrower than the phone layout gives them.
     Closing the figure is a request for room, so give the room back. */
  /* width:100% is not redundant. <main> is a flex item, and the margin-inline:
     auto that centres it also cancels the stretch, so without an explicit width
     the block shrinks to the folded question's own width — a 443px column in
     the middle of a 1280px screen, which is the bug this is fixing. */
  main.split:has(> .qcard:not([open])){
    display:block;width:100%;max-width:var(--col);
  }
  main.split:has(> .qcard:not([open])) > .qcard{position:static}
  main.split:has(> .qcard:not([open])) > .paper{margin-top:var(--s4)}
}

/* ============================================================ PROCESS
   The one Task 1 type with nothing to plot. Numbered steps down the page, each
   with a rule to its left, read like the exam's own diagrams and stay legible
   at any width — a drawn flowchart would not survive a phone. */
.ps{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:0}
.ps-step{
  display:flex;gap:var(--s3);align-items:flex-start;
  padding:var(--s3) 0 var(--s3) var(--s3);
  border-left:2px solid var(--rule);
  position:relative;
}
.ps-step:first-child{padding-top:var(--s2)}
.ps-step:last-child{padding-bottom:var(--s2)}
.ps-n{
  flex:0 0 auto;width:1.65rem;height:1.65rem;margin-left:calc(var(--s3) * -1 - 1.65rem / 2 - 1px);
  display:flex;align-items:center;justify-content:center;
  border-radius:999px;background:var(--accent-soft);color:var(--accent-ink);
  border:1px solid var(--accent-line);
  font-size:var(--t-xs);font-weight:600;font-variant-numeric:tabular-nums;
}
.ps-body{display:flex;flex-direction:column;gap:.15rem;min-width:0}
.ps-body b{font-size:var(--t-sm);color:var(--ink)}
.ps-detail{font-size:var(--t-xs);color:var(--ink-2);line-height:var(--lh-body)}

/* ============================================== QUESTION ROW WITH A CHART
   Which chart you get is most of what distinguishes one Task 1 question from
   another, so the picker shows it. Small enough to scan a list by, not to read
   figures from — the student picks, then reads it full size. */
.qrow.has-fig{flex-direction:row;align-items:flex-start;gap:var(--s3)}
.qrow-text{display:flex;flex-direction:column;gap:var(--s1);min-width:0;flex:1 1 auto}
.qthumb{
  flex:0 0 auto;width:132px;
  border:1px solid var(--rule-soft);border-radius:var(--r-xs);
  background:var(--paper);padding:var(--s2);overflow:hidden;
  pointer-events:none;
}
.qthumb .figure{margin:0;gap:2px}
.qthumb figcaption{display:none}          /* the prompt already says what it shows */
.qthumb .ch-legend{font-size:9px;gap:2px 6px}
.qthumb .ch-key{width:6px;height:6px}
.qthumb .ch-tick{font-size:7px}
.qthumb svg{width:100%;height:auto}
.qthumb table{font-size:8px;width:100%}
.qthumb table th,.qthumb table td{padding:1px 2px}
/* A process diagram cannot be read at this size, so it shows its shape instead:
   the step count and the first stages, which is what tells them apart. */
.qthumb .ps{gap:0}
.qthumb .ps-step{padding:2px 0 2px var(--s2);border-left-width:1px}
.qthumb .ps-n{width:.9rem;height:.9rem;font-size:7px;margin-left:calc(var(--s2) * -1 - .45rem - 1px)}
.qthumb .ps-body b{font-size:8px}
.qthumb .ps-detail{display:none}
@media (max-width:520px){
  .qthumb{width:96px}
}
