:root {
  --bg: #ffffff;
  --fg: #16181d;
  --muted: #5b6270;
  --line: #dfe3ea;
  --card: #f7f8fa;
  --accent: #1f5fd0;
  --ok: #1b7f4d;
  --bad: #b4232a;
  --scorer: #fff8e6;
  --scorer-line: #e5c76b;
}
* { box-sizing: border-box; }
body {
  margin: 0;
  padding: 28px 24px 60px;
  background: var(--bg);
  color: var(--fg);
  font: 16px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}
header.page { max-width: 900px; margin: 0 auto 26px; }
header.page h1 { font-size: 22px; margin: 0 0 4px; letter-spacing: -0.01em; }
header.page .sub { color: var(--muted); font-size: 13.5px; margin: 0; }
header.page .sub code { background: var(--card); padding: 1px 5px; border-radius: 4px; }
main { max-width: 900px; margin: 0 auto; display: grid; gap: 20px; }

.item {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 18px 20px 20px;
  background: var(--bg);
}
.item > h2 { font-size: 15px; margin: 0 0 2px; }
.item .meta { font-size: 12.5px; color: var(--muted); margin: 0 0 14px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.item .meta b { color: var(--fg); font-weight: 600; }
.stem p { margin: 0 0 10px; }

.region {
  margin-top: 14px;
  padding: 12px 14px;
  background: var(--card);
  border-radius: 8px;
  border: 1px solid var(--line);
}
.region .rlabel {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--muted); font-weight: 700; margin-bottom: 6px;
}
.region .rlabel .kind {
  background: #e6ecf7; color: #2c4b86; border-radius: 3px; padding: 1px 6px; margin-left: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; text-transform: none; letter-spacing: 0;
}
.region .prompt { margin: 0 0 8px; }
input[type="text"], input[type="number"] {
  font: inherit; padding: 5px 8px; border: 1px solid #b9c0cc; border-radius: 6px; width: 5.5em;
  background: #fff;
}
textarea { font: inherit; width: 100%; padding: 7px 9px; border: 1px solid #b9c0cc; border-radius: 6px; background: #fff; }
label.choice { display: block; margin: 3px 0; }
button.check {
  margin-top: 18px; font: 600 14px/1 inherit; padding: 9px 16px; border-radius: 7px;
  border: 1px solid var(--accent); background: var(--accent); color: #fff; cursor: pointer;
}
.fb { margin-top: 7px; font-size: 13.5px; font-weight: 600; }
.fb.ok { color: var(--ok); }
.fb.bad { color: var(--bad); }
.fb.manual { color: var(--muted); font-weight: 500; }

.rubric, .scorer {
  background: var(--scorer); border: 1px solid var(--scorer-line);
  border-radius: 8px; padding: 10px 14px; font-size: 13.5px; margin-top: 12px;
}
.rubric .rlabel, .scorer .rlabel { color: #8a6d1b; }
.rubric ul, .scorer ul { margin: 6px 0 0; padding-left: 20px; }

/* Visually hidden but present for assistive tech: the grid's instructions and
   its polite live region. Not display:none — that would remove them from the
   accessibility tree, which is the whole point of having them. */
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
.gridwrap { position: relative; }

svg.grid { background: #fff; border: 1px solid var(--line); border-radius: 6px; cursor: crosshair; touch-action: none; }
/* Focus indicator. Dark ring, 3px, offset clear of the 1px border so it is not
   read as part of the chrome. Measured 16.71:1 against the card background it
   sits on, 17.76:1 against white — WCAG 1.4.11 wants 3:1.
   Cursor ring measured against every colour it can land on: 17.76:1 on the grid
   background, 14.74:1 on a gridline, 3.05:1 on a placed point (the worst case,
   which is why the white halo is there — that boundary measures 5.82:1). */
svg.grid:focus-visible { outline: 3px solid var(--fg); outline-offset: 3px; }
/* Fallback for engines without :focus-visible; harmless where both apply. */
svg.grid:focus:not(:focus-visible) { outline: 3px solid var(--fg); outline-offset: 3px; }

/* Keyboard cursor: a dark ring inside a white halo, so it stays visible over
   the gridlines, the axes, a placed point and the plotted line alike. */
svg.grid .cur-outer { fill: none; stroke: #ffffff; stroke-width: 5; }
svg.grid .cur-inner { fill: none; stroke: var(--fg); stroke-width: 2; }
svg.grid .cur-cross { stroke: var(--fg); stroke-width: 1.5; }
svg.grid .gl { stroke: #e7eaf0; stroke-width: 1; }
svg.grid .axis { stroke: #7b828f; stroke-width: 1.5; }
svg.grid .tick { font: 10px ui-monospace, Menlo, monospace; fill: #6b7280; text-anchor: middle; }
svg.grid .tick.end { text-anchor: end; }
svg.grid .axlabel { font: 11px -apple-system, sans-serif; fill: #4b5563; text-anchor: middle; }
svg.grid .axlabel.end { text-anchor: start; }
svg.grid .pt { fill: var(--accent); }
svg.grid .plot { stroke: var(--accent); stroke-width: 2.5; }

.err { color: var(--bad); font-family: ui-monospace, Menlo, monospace; font-size: 13px; white-space: pre-wrap; }
.katex { font-size: 1.03em; }
.katex-display { margin: 10px 0; }

/* ── student view ────────────────────────────────────────────────────────────
   Everything below is scoped to body.student (render/student-player.html) so the
   diagnostic renderer and its committed screenshots are unaffected. */

body.student header.page h1 { font-size: 20px; }
body.student .item { padding: 20px 22px 18px; }
body.student .item > h2 {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--muted); margin: 0 0 10px;
}
body.student .stem p { margin: 0 0 12px; font-size: 17px; }
body.student .region { margin-top: 16px; }
body.student .region .part {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--muted); font-weight: 700; margin-bottom: 6px;
}
body.student .answerrow { display: flex; align-items: center; gap: 8px; }
body.student .answerrow .unit { color: var(--muted); font-size: 14px; }

/* Native fieldset chrome would draw a second box inside the region card. */
body.student fieldset.choices { border: 0; margin: 0; padding: 0; min-width: 0; }
body.student fieldset.choices > legend { padding: 0; margin: 0 0 8px; }
body.student label.choice { display: block; margin: 5px 0; cursor: pointer; }
body.student label.choice input { margin-right: 4px; }

body.student .foot { margin-top: 18px; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
body.student button.check { margin-top: 0; }
body.student button.check[disabled] { opacity: 0.6; cursor: default; }
body.student .status { margin: 0; font-size: 13px; color: var(--muted); }

/* Verdict colours. The vocabulary is NWDCheck's status field, not the diagnostic
   renderer's ok/bad/manual, because these carry no score. */
body.student .fb { margin-top: 9px; }
body.student .fb.correct { color: var(--ok); }
body.student .fb.incorrect { color: var(--bad); }
body.student .fb.blank,
body.student .fb.incomplete { color: var(--muted); font-weight: 500; }
body.student .fb.saved,
body.student .fb.recorded { color: var(--muted); font-weight: 500; }
body.student .fb.error { color: var(--bad); font-weight: 500; }

/* Focus indicator on the non-grid controls, matching what grid.js already does
   for the plotter: 3px, dark, offset clear of the control's own border. */
body.student input[type="text"]:focus-visible,
body.student input[type="radio"]:focus-visible,
body.student textarea:focus-visible,
body.student button.check:focus-visible {
  outline: 3px solid var(--fg); outline-offset: 2px;
}
