/* Memory & Storage — OCR J277 1.2
 *
 * Every font size is in em, never px, so the "Text size" control (which sets
 * --ui-scale on :root) actually scales the whole interface. A px size
 * anywhere is a control that silently stops working for the pupil who needs
 * it most.
 *
 * No inline styles and no external fonts: the Caddy CSP for this host is
 * style-src 'self' with no unsafe-inline.
 */

:root {
  --ui-scale: 1;

  --ink: #17202a;
  --ink-soft: #4a5866;
  --muted: #6b7885;
  --line: var(--line);
  --line-soft: #e8edf2;
  --paper: #ffffff;
  --ground: #f4f7fa;

  --brand: #1c5c9e;
  --brand-dark: #14456f;
  --good: #1c7a4a;
  --good-bg: #e8f6ee;
  --part: #8a6100;
  --part-bg: #fdf4e0;
  --bad: #a32929;
  --bad-bg: #fdeded;
  --prov: #5b4b8a;
  --prov-bg: #f1ecfa;
  /* Accent surfaces, named so a theme can move them. Before these, a
     dark theme produced pale boxes with pale text inside them. */
  --warn-bg: #fffaf0;
  --warn-line: #e6d089;
  --tint-brand: #e8f0f9;

  font-size: calc(16px * var(--ui-scale));
}

* { box-sizing: border-box; }

/* The hidden ATTRIBUTE has to beat every display rule further down this file.
   The UA stylesheet gives [hidden] display:none, but any author rule outranks
   it — so .login-wrap (display:flex) stayed on screen behind the exam after a
   pupil signed in, and a filtered-out result card would not have hidden
   either. Everything in this interface is toggled with .hidden = true/false,
   so it has to mean what it says. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 1em;
  line-height: 1.55;
}

.skip {
  position: absolute; left: -9999px;
  background: var(--brand); color: #fff; padding: .6em 1em;
}
.skip:focus { left: .5em; top: .5em; z-index: 50; }

/* ── header ──────────────────────────────────────────────────────────── */
.top {
  display: flex; flex-wrap: wrap; gap: .75em;
  align-items: center; justify-content: space-between;
  padding: .7em 1.1em;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}
.brand { color: var(--brand); text-decoration: none; font-weight: 600; font-size: .92em; }
.brand:hover { text-decoration: underline; }
.top-right { display: flex; align-items: center; gap: 1em; flex-wrap: wrap; }
.scale-control { display: flex; align-items: center; gap: .5em; font-size: .82em; color: var(--muted); }
.scale-control input { width: 7em; }
.who { font-weight: 600; font-size: .9em; }

/* ── buttons ─────────────────────────────────────────────────────────── */
.btn-primary, .btn-quiet, .btn-mark, .certificate-btn {
  font: inherit; cursor: pointer; border-radius: .4em;
  padding: .5em 1em; border: 1px solid transparent;
  /* A button with no colour of its own takes the browser's, which is dark
     text — invisible on a dark theme. The mark buttons lost their numbers
     entirely this way. Rules below still override where they mean to. */
  color: var(--ink);
}

/* Same trap for form controls: a native select or date field with no colour
   set renders with the UA's, which does not follow the theme. Checkboxes,
   radios and ranges are left alone — they are drawn by the browser. */
select,
input[type="text"], input[type="number"], input[type="search"],
input[type="password"], input[type="date"], input[type="datetime-local"],
textarea {
  background: var(--paper);
  color: var(--ink);
}
.btn-primary { background: var(--brand); color: #fff; font-weight: 600; }
.btn-primary:hover { background: var(--brand-dark); }
.btn-primary:disabled { background: var(--muted); cursor: default; }
.btn-quiet { background: var(--paper); color: var(--ink-soft); border-color: var(--line); }
.btn-quiet:hover { border-color: var(--brand); color: var(--brand); }
.btn-mark {
  background: var(--paper); border-color: var(--line);
  min-width: 2.6em; font-weight: 600;
}
.btn-mark:hover { border-color: var(--brand); background: var(--brand); color: #fff; }

:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }

/* ── sign in ─────────────────────────────────────────────────────────── */
.login-wrap { display: flex; justify-content: center; padding: 3em 1em; }
.login-card {
  background: var(--paper); border: 1px solid var(--line); border-radius: .6em;
  padding: 2em; width: 100%; max-width: 24em;
}
.login-card h1 { margin: 0 0 .15em; font-size: 1.5em; }
.login-card .sub { margin: 0 0 1em; color: var(--brand); font-weight: 600; font-size: .9em; }
.login-card label { display: block; margin: .9em 0 .3em; font-weight: 600; font-size: .88em; }
.login-card input {
  width: 100%; font: inherit; padding: .55em .7em;
  border: 1px solid var(--line); border-radius: .35em; background: var(--paper); color: var(--ink);
}
.login-card button { width: 100%; margin-top: 1.3em; }

/* ── tabs ────────────────────────────────────────────────────────────── */
.tabs {
  display: flex; flex-wrap: wrap; gap: .3em;
  padding: .8em 1.1em 0; background: var(--paper);
  border-bottom: 1px solid var(--line);
}
.tab {
  font: inherit; font-size: .92em; cursor: pointer;
  background: none; border: 1px solid transparent; border-bottom: none;
  padding: .55em 1em; border-radius: .4em .4em 0 0; color: var(--ink-soft);
  position: relative;
}
.tab:hover { color: var(--brand); }
.tab[aria-selected="true"] {
  background: var(--ground); border-color: var(--line);
  color: var(--brand); font-weight: 600;
  margin-bottom: -1px; border-bottom: 1px solid var(--ground);
}
.badge {
  display: inline-block; margin-left: .5em; min-width: 1.5em;
  padding: 0 .35em; border-radius: 1em;
  background: var(--bad); color: #fff; font-size: .75em; text-align: center;
}

/* ── panels ──────────────────────────────────────────────────────────── */
main { max-width: 60em; margin: 0 auto; padding: 1.5em 1.1em 4em; }
.panel-head h2 { margin: 0 0 .2em; font-size: 1.35em; }
.panel-head .muted { margin: 0 0 1.2em; }
.muted { color: var(--muted); }
.small { font-size: .85em; }
.error-text { color: var(--bad); font-weight: 600; }

/* ── filters ─────────────────────────────────────────────────────────── */
.filters { display: flex; flex-wrap: wrap; gap: .4em; margin-bottom: 1.3em; }
.chip {
  font: inherit; font-size: .82em; cursor: pointer;
  background: var(--paper); border: 1px solid var(--line);
  border-radius: 1.2em; padding: .3em .9em; color: var(--ink-soft);
}
.chip:hover { border-color: var(--brand); color: var(--brand); }
.chip-on { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 600; }

/* ── question cards ──────────────────────────────────────────────────── */
.q-list { display: flex; flex-direction: column; gap: 1.1em; }
.q-card {
  background: var(--paper); border: 1px solid var(--line);
  border-radius: .55em; padding: 1.2em;
}
.q-head {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5em;
  margin-bottom: .8em; font-size: .78em;
}
.q-num { font-weight: 700; color: var(--brand); font-size: 1.15em; }
.q-marks, .q-spec, .q-level, .q-tag {
  padding: .15em .6em; border-radius: 1em; border: 1px solid var(--line-soft);
  background: var(--ground); color: var(--ink-soft);
}
.q-spec { font-variant-numeric: tabular-nums; }
.level-1 { background: var(--good-bg); color: var(--good); border-color: var(--good); }
.level-2 { background: var(--part-bg); color: var(--part); border-color: var(--part); }
.level-3 { background: var(--bad-bg); color: var(--bad); border-color: var(--bad); }
/* A genuine past-paper question and an adaptation of one must never look the
   same: a pupil who thinks they have seen the real thing when they have not
   is being misled about what the exam looks like. */
.tag-genuine { background: var(--tint-brand); color: var(--brand-dark); border-color: var(--brand); font-weight: 600; }
.tag-adapted { background: var(--prov-bg); color: var(--prov); border-color: var(--prov); font-style: italic; }
.q-status { margin-left: auto; font-weight: 600; }
.q-status.solved { color: var(--good); }
.q-status.trying { color: var(--part); }

.q-stem { margin-bottom: 1em; white-space: normal; }

/* Binary and hex in a stem must line up in columns. */
.q-stem { font-variant-numeric: tabular-nums; }

/* ── answer inputs ───────────────────────────────────────────────────── */
.answer { margin-bottom: 1em; }
.opt {
  display: flex; align-items: flex-start; gap: .6em;
  padding: .45em .6em; border: 1px solid var(--line-soft);
  border-radius: .35em; margin-bottom: .35em; cursor: pointer;
}
.opt:hover { border-color: var(--brand); background: var(--ground); }
.opt input { margin-top: .25em; flex: none; }

.single-input, .cell-input, .prose-input {
  font: inherit; padding: .5em .65em;
  border: 1px solid var(--line); border-radius: .35em;
  background: var(--paper); color: var(--ink); width: 100%;
}
.single-input { max-width: 18em; font-variant-numeric: tabular-nums; }
.single-row { display: flex; align-items: center; gap: .6em; flex-wrap: wrap; }
.unit { color: var(--muted); font-size: .9em; }
.prose-input { resize: vertical; }

/* Program answers. Monospace with a visible tab stop, because OCR Reference
   Language is read on indentation and a proportional font hides it. */
.code-input {
  width: 100%;
  box-sizing: border-box;
  font-family: ui-monospace, "Cascadia Mono", "Consolas", "Courier New", monospace;
  font-size: 0.95em;
  line-height: 1.5;
  tab-size: 2;
  resize: vertical;
  padding: 0.6em 0.7em;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--ground);
  color: var(--ink);
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}
.code-input:focus { outline: 2px solid #2f6fd0; outline-offset: 1px; }
.field { margin-bottom: .7em; }
.field label { display: block; font-weight: 600; font-size: .85em; margin-bottom: .25em; }

.answer-grid { border-collapse: collapse; width: 100%; font-size: .9em; }
.answer-grid th, .answer-grid td {
  border: 1px solid var(--line); padding: .45em .6em; text-align: left;
}
.answer-grid thead th { background: var(--ground); font-size: .88em; }
.answer-grid .row-label { font-weight: 400; background: var(--ground); }
.answer-grid td.given { background: var(--ground); font-variant-numeric: tabular-nums; }
.cell-input { max-width: 12em; font-variant-numeric: tabular-nums; }
/* A choice cell holds whole statements, not a short value, so it must
   not be squeezed into the 12em meant for numbers and single words. */
select.cell-input { max-width: none; min-width: 14em; }

.gap-body { line-height: 2.4; }
.gap-select {
  font: inherit; font-size: .92em; padding: .25em .4em;
  border: 1px solid var(--brand); border-radius: .3em;
  background: var(--paper); color: var(--ink); margin: 0 .15em;
}

/* ── click-to-connect diagram ─────────────────────────────────────────── */
.net-stage {
  position: relative; width: 100%; max-width: 34em;
  aspect-ratio: 400 / 260; margin: .6em 0 1em;
  background: var(--ground); border: 1px solid var(--line); border-radius: .5em;
}
.net-links { position: absolute; inset: 0; width: 100%; height: 100%; }
.net-link { stroke: var(--brand); stroke-width: 2.5; }
.net-nodes { position: absolute; inset: 0; }
.net-node {
  position: absolute; transform: translate(-50%, -50%);
  font: inherit; font-size: .75em; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: .1em;
  background: var(--paper); border: 2px solid var(--line);
  border-radius: .45em; padding: .35em .5em; min-width: 4.6em;
  color: var(--ink); line-height: 1.2;
}
.net-node:hover { border-color: var(--brand); }
.net-node-on { border-color: var(--brand); background: var(--tint-brand); box-shadow: 0 0 0 3px var(--brand); }
.net-icon { font-size: 1.5em; line-height: 1; }
.net-label { white-space: nowrap; }

.net-palette { display: flex; flex-wrap: wrap; gap: .4em; margin-bottom: .6em; }
.net-chip {
  font: inherit; font-size: .8em; cursor: pointer;
  background: var(--paper); border: 1px dashed var(--line);
  border-radius: 1.2em; padding: .3em .85em; color: var(--ink-soft);
}
.net-chip:hover { border-color: var(--brand); color: var(--brand); }
.net-chip-on {
  border-style: solid; border-color: var(--brand);
  background: var(--brand); color: #fff; font-weight: 600;
}
.net-status { margin: 0 0 .5em; font-size: .82em; color: var(--muted); }

.cell-prose {
  font: inherit; padding: .45em .6em; width: 100%; min-width: 12em;
  border: 1px solid var(--line); border-radius: .35em;
  background: var(--paper); color: var(--ink); resize: vertical;
}

@media (max-width: 560px) {
  .net-node { font-size: .68em; min-width: 4em; padding: .25em .35em; }
  .net-icon { font-size: 1.25em; }
}

/* ── wireframe builder ────────────────────────────────────────────────── */
.wf-page {
  border: 1px solid var(--line); border-radius: .5em; background: var(--ground);
  padding: .4em; margin: .6em 0 1em; max-width: 26em;
}
.wf-row { display: flex; gap: .3em; min-height: 2.1em; margin-bottom: .25em; }
.wf-block, .wf-slot {
  flex: 1; font: inherit; font-size: .8em; cursor: pointer;
  border-radius: .3em; padding: .4em .6em; text-align: center;
}
.wf-block { background: var(--tint-brand); border: 2px solid var(--brand); color: var(--brand-dark); font-weight: 600; }
.wf-block:hover { background: var(--tint-brand); filter: brightness(.95); }
.wf-slot { background: transparent; border: 1px dashed var(--line); color: var(--muted); }
.wf-slot:disabled { cursor: default; color: var(--muted); }
.wf-slot:not(:disabled):hover { border-color: var(--brand); color: var(--brand); background: var(--tint-brand); }
.wf-palette { display: flex; flex-wrap: wrap; gap: .4em; margin-bottom: .5em; }
.wf-chip {
  font: inherit; font-size: .8em; cursor: pointer;
  background: var(--paper); border: 1px dashed var(--line);
  border-radius: 1.2em; padding: .3em .85em; color: var(--ink-soft);
}
.wf-chip:hover { border-color: var(--brand); color: var(--brand); }
.wf-chip-on { border-style: solid; border-color: var(--brand); background: var(--brand); color: #fff; font-weight: 600; }
.wf-chip-used { opacity: .4; cursor: default; text-decoration: line-through; }

/* ── mock exam ────────────────────────────────────────────────────────── */
.exam-warning {
  background: var(--warn-bg); border: 1px solid var(--warn-line); border-radius: .5em;
  padding: 1em 1.2em; margin-bottom: 1.4em; font-size: .92em; line-height: 1.6;
}
.paper-list { display: flex; flex-direction: column; gap: .9em; margin-bottom: 2em; }
.paper-card {
  background: var(--paper); border: 1px solid var(--line); border-radius: .55em;
  padding: 1.1em 1.2em; display: flex; flex-wrap: wrap; align-items: center; gap: .8em;
}
.paper-head { flex: 1; display: flex; flex-direction: column; gap: .2em; min-width: 14em; }

.exam-bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; flex-wrap: wrap; align-items: center; gap: 1em;
  background: var(--paper); border-bottom: 2px solid var(--line);
  padding: .8em 1.1em; margin: -1.5em -1.1em 1.4em;
}
.exam-bar-title { flex: 1; display: flex; flex-direction: column; min-width: 12em; }
.exam-bar-actions { display: flex; align-items: center; gap: .8em; }
.exam-timer {
  display: flex; flex-direction: column; align-items: center;
  padding: .3em 1em; border-radius: .45em; background: var(--ground);
  border: 2px solid var(--line);
}
.timer-label { font-size: .68em; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }
.timer-value { font-size: 1.5em; font-weight: 700; font-variant-numeric: tabular-nums; }
.timer-warn { border-color: var(--part); background: var(--part-bg); }
.timer-warn .timer-value { color: var(--part); }
.timer-critical { border-color: var(--bad); background: var(--bad-bg); }
.timer-critical .timer-value { color: var(--bad); }

.exam-section {
  margin: 2em 0 .8em; font-size: .8em; font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em; color: var(--muted);
  border-bottom: 1px solid var(--line); padding-bottom: .4em;
}
.exam-card { margin-bottom: 1em; }
/* A question the pupil tried to submit without answering. */
.exam-card.missing { border-color: var(--bad); box-shadow: 0 0 0 3px var(--bad-bg); }
.exam-answered.solved { color: var(--good); }
.submit-warning {
  background: var(--bad-bg); border-left: 4px solid var(--bad);
  padding: .9em 1.1em; border-radius: .4em; font-weight: 600; margin-bottom: 1.2em;
}
.exam-foot { margin: 2em 0 4em; text-align: center; }

.result-summary { display: flex; flex-wrap: wrap; gap: 1em; margin-bottom: 1em; }
.score-block {
  flex: 1; min-width: 12em; background: var(--paper); border: 1px solid var(--line);
  border-radius: .5em; padding: 1em 1.2em; display: flex; flex-direction: column; gap: .2em;
}
.score-self { border-style: dashed; }
.score-label { font-size: .78em; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }
.score-value { font-size: 1.8em; font-weight: 700; font-variant-numeric: tabular-nums; }
.result-card { border-left-width: 4px; margin-bottom: 1em; }
.result-right { border-left-color: var(--good); }
.result-part  { border-left-color: var(--part); }
.result-wrong { border-left-color: var(--bad); }
.result-blank { border-left-color: var(--muted); }
.result-prov  { border-left-color: var(--prov); }
.your-answer { margin: .6em 0; }
.exam-feedback {
  background: var(--ground); border-radius: .4em; padding: .7em .9em;
  font-size: .9em; margin: .6em 0;
}

@media (max-width: 700px) {
  /* The bar STAYS sticky on a phone. It used to go static here, which meant
     the timer scrolled off the top and a pupil sitting a timed paper on a
     phone could not see the clock without scrolling back up. Compacted
     instead: title dropped, timer on one line, submit still reachable. */
  .exam-bar {
    margin: 0 0 1.2em;
    padding: .45em .6em;
    gap: .5em;
    align-items: center;
  }
  .exam-bar-title { display: none; }
  .exam-timer {
    flex-direction: row; align-items: baseline; gap: .35em;
    padding: .15em .5em; white-space: nowrap;
  }
  /* The timer and the submit button have to share one row on a 375px phone,
     or the sticky bar grows to three rows and eats a quarter of the screen
     for the whole paper. Measured: they miss fitting by a few pixels at the
     default sizes. */
  .exam-timer .timer-label { font-size: .6em; }
  .exam-timer .timer-value { font-size: 1.15em; }
  #time-call, #pace { font-size: .82em; }
  .exam-bar-actions { margin-left: auto; gap: .4em; }
  #save-state { display: none; }
  #time-call, #pace { flex-basis: 100%; margin: .25em 0 0; }
}

/* ── actions and feedback ────────────────────────────────────────────── */
.q-actions { display: flex; gap: .6em; flex-wrap: wrap; }
.hint {
  margin: .8em 0 0; padding: .7em .9em;
  background: var(--warn-bg); border-left: 3px solid var(--warn-line); border-radius: .3em;
  font-size: .9em;
}

.feedback {
  margin-top: 1em; padding: .9em 1.1em;
  border-radius: .4em; border-left: 4px solid var(--line);
}
.feedback.good { background: var(--good-bg); border-left-color: var(--good); }
.feedback.part { background: var(--part-bg); border-left-color: var(--part); }
.feedback.bad  { background: var(--bad-bg);  border-left-color: var(--bad); }
.feedback.provisional { background: var(--prov-bg); border-left-color: var(--prov); }
.score { margin: 0 0 .4em; font-weight: 700; font-size: 1.05em; }
.note { margin: .3em 0; font-size: .9em; }
.provisional-warning {
  margin: .5em 0; font-size: .88em; color: var(--prov); font-weight: 600;
}

.ms-block, .working-block { margin-top: .7em; }
.ms-block summary, .working-block summary {
  cursor: pointer; font-weight: 600; font-size: .9em; color: var(--brand);
}
.ms-text, .working-text, .prose-answer {
  white-space: pre-wrap; overflow-wrap: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .85em; background: var(--paper);
  border: 1px solid var(--line-soft); border-radius: .35em;
  padding: .7em .85em; margin: .5em 0 0;
}

.self-assess { margin-top: .9em; padding-top: .8em; border-top: 1px dashed var(--line); }
.self-assess p { margin: 0 0 .5em; font-size: .9em; }
.self-row { display: flex; gap: .4em; flex-wrap: wrap; }
.self-done { color: var(--good); font-weight: 600; }

.topic-heading {
  margin: 0 0 1.1em; font-size: 1.5em; color: var(--brand-dark);
  border-bottom: 2px solid var(--line); padding-bottom: .4em;
}
.topic-heading:empty { display: none; }

/* ── certificates ────────────────────────────────────────────────────── */
.certificate-banner {
  background: linear-gradient(180deg, #fffdf2, #fff8e0);
  border: 1px solid var(--warn-line); border-radius: .55em;
  padding: 1.1em 1.3em; margin-bottom: 1.5em;
}
.certificate-banner p { margin: 0 0 .7em; font-weight: 600; }
#certificate-links { display: flex; gap: .6em; flex-wrap: wrap; }
.certificate-btn {
  background: var(--brand); color: #fff; text-decoration: none;
  font-weight: 600; font-size: .9em; display: inline-block;
}
.certificate-btn:hover { background: var(--brand-dark); }

/* ── progress ────────────────────────────────────────────────────────── */
.prog-block {
  background: var(--paper); border: 1px solid var(--line);
  border-radius: .55em; padding: 1.2em; margin-bottom: 1.2em;
}
.prog-block h3 { margin: 0 0 .6em; font-size: 1.05em; }
.bar { height: .7em; background: var(--line-soft); border-radius: 1em; overflow: hidden; }
.bar-fill { height: 100%; background: var(--good); border-radius: 1em; }
.topic-table { width: 100%; margin-top: .9em; border-collapse: collapse; font-size: .9em; }
.topic-table td { padding: .3em .2em; border-bottom: 1px solid var(--line-soft); }
.topic-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.topic-done td { color: var(--good); font-weight: 600; }

/* ── teacher ─────────────────────────────────────────────────────────── */
.admin-block {
  background: var(--paper); border: 1px solid var(--line);
  border-radius: .55em; padding: 1.2em; margin-bottom: 1.3em;
}
.admin-block h3 { margin: 0 0 .5em; font-size: 1.05em; }
.cert-count { font-size: .8em; font-weight: 400; margin-left: .5em; }
.cert-count-new { color: var(--bad); font-weight: 700; }

.data-table { width: 100%; border-collapse: collapse; font-size: .88em; margin-top: .7em; }
.data-table th, .data-table td {
  text-align: left; padding: .45em .6em; border-bottom: 1px solid var(--line-soft);
}
.data-table th { background: var(--ground); font-size: .9em; }
.row-new td { background: var(--warn-bg); font-weight: 600; }

.prose-item { border-bottom: 1px solid var(--line-soft); padding: .5em 0; }
.prose-item summary { cursor: pointer; display: flex; gap: .8em; flex-wrap: wrap; font-size: .9em; }
.prose-who { font-weight: 600; }
.prose-q { color: var(--muted); font-family: ui-monospace, monospace; font-size: .9em; }
.prose-score { margin-left: auto; color: var(--prov); font-size: .88em; }
.prose-stem { font-size: .9em; color: var(--ink-soft); margin: .5em 0; }

/* The class grid is 50 columns wide — it has to scroll inside its own box
   rather than pushing the page sideways. */
.grid-wrap { overflow-x: auto; }
.prog-grid { border-collapse: collapse; font-size: .8em; }
.prog-grid th, .prog-grid td { border: 1px solid var(--line-soft); padding: .2em .35em; }
.prog-grid .sticky {
  position: sticky; left: 0; background: var(--paper);
  text-align: left; white-space: nowrap; font-weight: 600; z-index: 1;
}
.prog-grid .tiny { font-size: .85em; color: var(--muted); font-weight: 400; min-width: 1.5em; }
.prog-grid .num { text-align: center; font-variant-numeric: tabular-nums; font-weight: 600; }
.cell { width: 1.2em; height: 1.2em; padding: 0; }
.cell-yes { background: var(--good); }
.cell-no { background: var(--line-soft); }

/* ── footer ──────────────────────────────────────────────────────────── */
.foot {
  max-width: 60em; margin: 0 auto; padding: 2em 1.1em 3em;
  border-top: 1px solid var(--line); text-align: center; font-size: .88em;
}
.foot a { color: var(--brand); }

.bug-report-btn {
  position: fixed; right: 1em; bottom: 1em;
  background: var(--paper); border: 1px solid var(--line);
  border-radius: 1.5em; padding: .45em .9em;
  font-size: .82em; text-decoration: none; color: var(--ink-soft);
  box-shadow: 0 1px 4px rgba(0,0,0,.1);
}
.bug-report-btn:hover { border-color: var(--brand); color: var(--brand); }

/* ── narrow screens ──────────────────────────────────────────────────── */
@media (max-width: 700px) {
  .q-head { font-size: .74em; }
  .q-status { margin-left: 0; width: 100%; }
  .answer-grid { font-size: .82em; }
  .answer-grid th, .answer-grid td { padding: .35em .4em; }
  .cell-input { max-width: 100%; }
  .prose-score { margin-left: 0; width: 100%; }
  .bug-report-btn { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  * { scroll-behavior: auto !important; }
}

/* The teacher's add-a-question form. One column, because it is filled in
   from top to bottom and a two-column form would only invite tabbing into
   the wrong box. */
.authored-form { display: grid; gap: 0.45em; max-width: 46em; margin: 0.8em 0; }
.authored-form label { font-weight: 600; font-size: 0.95em; }
.authored-form label .muted { font-weight: 400; }
.authored-form input,
.authored-form select,
.authored-form textarea {
  width: 100%;
  box-sizing: border-box;
  font: inherit;
  padding: 0.45em 0.55em;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--paper);
}
.authored-form textarea { resize: vertical; }
.authored-form button { justify-self: start; margin-top: 0.4em; }

/* Result page: the indicative grade and what to do next. The grade is
   deliberately the largest thing on the page, because it is the number a
   pupil actually acts on — but it carries its basis underneath it, because
   a mock is not the paper the boundaries came from. */
.score-grade { background: var(--tint-brand); border-color: var(--brand); color: var(--ink); }
.grade-value { font-size: 2.2em; line-height: 1.1; }
.score-sub { display: block; font-size: 0.9em; font-weight: 600; color: #2f6fd0; }
.score-basis { display: block; font-size: 0.78em; color: #5b6875; margin-top: 0.3em; }

.result-next { margin: 1.6em 0; }
.next-steps { margin: 0.6em 0 0; padding-left: 1.3em; }
.next-step { margin: 0 0 1em; }
.next-head { display: flex; flex-wrap: wrap; gap: 0.6em; align-items: baseline; }
.next-lost { color: #a4331f; font-weight: 600; font-size: 0.92em; }
.next-topics { margin: 0.25em 0 0.5em; color: #46525f; font-size: 0.95em; }
.next-link { display: inline-block; margin-top: 0.2em; }

/* Question navigator. Sticky, because its whole purpose is to be reachable
   from anywhere in a thirty-question scroll. */
.q-nav {
  /* Sits BELOW the exam bar, which is also sticky. Both were at top:0, so the
     navigator slid up underneath the bar and the pupil lost the one control
     meant to be reachable from anywhere. --exam-bar-h is measured by
     exam-app.js because the bar wraps at some widths and text sizes; the
     fallback covers the moment before the script has measured it. */
  position: sticky; top: var(--exam-bar-h, 3.6em); z-index: 5;
  background: var(--paper); border: 1px solid var(--line); border-radius: 8px;
  padding: 0.6em 0.75em; margin: 0 0 1em;
}
.q-nav-head { display: flex; justify-content: space-between; align-items: center; gap: 1em; }
.q-nav-grid { display: flex; flex-wrap: wrap; gap: 0.3em; margin: 0.5em 0; }
.q-nav-cell {
  min-width: 2.1em; padding: 0.28em 0.4em;
  font: inherit; font-size: 0.88em; font-weight: 600;
  border-radius: 5px; border: 1px solid var(--line); cursor: pointer;
}
.nav-todo { background: var(--paper); color: var(--ink-soft); }
.nav-done { background: var(--good-bg); border-color: var(--good); color: var(--good); }
.nav-flag { box-shadow: inset 0 -3px 0 #e0a32e; }
.q-nav-cell:hover { border-color: #2f6fd0; }

.q-flag {
  margin-left: auto; background: none; border: none; cursor: pointer;
  font-size: 1.1em; line-height: 1; color: #b9c2cc; padding: 0 0.2em;
}
.q-flag-on { color: #e0a32e; }
.card-flagged { border-left: 3px solid #e0a32e; }

.timer-final { color: #a4331f; font-weight: 700; }
.time-call { background: var(--warn-bg); border-color: var(--warn-line); color: var(--part); }

.extra-time-note {
  /* Was a hardcoded pale blue with the browser's default text colour on top —
     which is dark, so the whole notice disappeared in dark mode. */
  background: var(--tint-brand); border: 1px solid var(--brand);
  color: var(--ink); border-radius: var(--r-sm);
  padding: 0.55em 0.75em; margin: 0 0 0.8em; font-size: 0.95em;
}

.extra-time-input { width: 5em; font: inherit; padding: 0.25em 0.4em;
  border: 1px solid var(--line); border-radius: 5px; }
.facility { font-weight: 700; text-align: right; }
.fac-low  { color: #a4331f; }
.fac-mid  { color: #8a6100; }
.fac-high { color: #1d6b38; }

.section-advice {
  margin: -0.4em 0 0.9em; padding: 0.4em 0.7em;
  background: var(--paper-2); border-left: 3px solid var(--brand); color: var(--ink);
  font-size: 0.92em; color: var(--ink-soft);
}

/* ── exam bar extras ──────────────────────────────────────────────────── */
/* Time calls and the pace line each get their own row, and their own element:
   sharing #submit-warning meant one could wipe the other off the screen. */
#time-call, #pace { flex-basis: 100%; margin: .4em 0 0; font-size: .9em; }
#time-call {
  padding: .4em .7em; border-radius: .4em; font-weight: 600;
  background: var(--warn-bg); border: 1px solid var(--warn-line); color: var(--part);
}
.pace { padding: .2em 0; color: var(--muted); }
.pace-ahead  { color: var(--good); font-weight: 600; }
.pace-on     { color: var(--ink-soft); }
.pace-behind { color: var(--part); font-weight: 600; }

/* What used to be alert(). */
.app-notice {
  margin: 0 0 1em; padding: .7em 1em; border-radius: .5em;
  background: var(--bad-bg); border: 1px solid var(--bad); color: var(--bad);
  font-weight: 600;
}

/* How much to write. Sits above the box, quiet enough not to compete with
   the question itself. */
.answer-guide {
  margin: 0 0 .4em; font-size: .85em; color: var(--muted); font-style: italic;
}

/* ── results ──────────────────────────────────────────────────────────── */
.score-compare .cmp-up    { color: var(--good); }
.score-compare .cmp-down  { color: var(--bad); }
.score-compare .cmp-level { color: var(--muted); }

.self-queue {
  margin: 0 0 1.2em; padding: .9em 1.1em; border-radius: .5em;
  background: var(--prov-bg); border: 1px solid var(--prov);
}
.self-queue p { margin: .35em 0 .7em; }

.result-toolbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6em;
  margin: 1.2em 0 .8em; padding-top: .8em; border-top: 1px solid var(--line);
}
.result-filter { display: flex; flex-wrap: wrap; gap: .4em; flex: 1; }
.filter-btn { font-size: .88em; }
.filter-btn[disabled] { opacity: .45; cursor: default; }
.filter-on {
  background: var(--brand); border-color: var(--brand); color: #fff;
}

/* ── teacher ──────────────────────────────────────────────────────────── */
.teacher-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6em;
  margin: 1.4em 0 .8em; padding: .6em .9em;
  background: var(--ground); border: 1px solid var(--line); border-radius: .5em;
}
.teacher-bar label { font-weight: 600; }
.teacher-bar select { font: inherit; padding: .25em .4em; }

.block-actions { display: flex; flex-wrap: wrap; gap: .4em; margin: .5em 0 .8em; }

.pill {
  display: inline-block; margin-left: .5em; padding: .05em .55em;
  border-radius: 1em; font-size: .72em; font-weight: 700; vertical-align: middle;
}
.pill-todo { background: var(--part-bg); color: var(--part); }
.pill-done { background: var(--good-bg); color: var(--good); }

.marking-controls {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6em; margin: .6em 0;
}
.marking-toggle { display: flex; align-items: center; gap: .35em; font-size: .9em; }
.mark-card { border-left: 4px solid var(--prov); }
.mark-note { margin: .4em 0 0; }
/* The mark the PUPIL gave themselves, so a teacher can see at a glance what
   they are being asked to agree with. */
.btn-mark-self { outline: 2px solid var(--prov); outline-offset: 1px; }
.btn-mark-on { background: var(--brand); border-color: var(--brand); color: #fff; }
.teacher-marked { color: var(--prov); }

.to-mark { color: var(--part); font-weight: 700; }
.unmarked-key { color: var(--part); font-weight: 600; }

.access-controls, .bulk-group {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6em; margin: .6em 0;
}
.access-controls input[type="search"], .bulk-group input[type="text"],
.bulk-group input:not([type]) {
  font: inherit; padding: .3em .5em;
  border: 1px solid var(--line); border-radius: .35em;
}
.bulk-group {
  padding: .6em .8em; background: var(--ground);
  border: 1px solid var(--line); border-radius: .5em;
}
.bulk-group button[disabled] { opacity: .45; cursor: default; }

.idle { color: var(--part); font-weight: 600; }
.prose-todo > summary { border-left: 3px solid var(--part); padding-left: .5em; }

#pupil-block { position: relative; }
#pupil-close { position: absolute; top: 1em; right: 1em; }
#pupil-detail h4 { margin: 1.2em 0 .4em; }

.analysis-row td { vertical-align: top; }
.analysis-detail {
  position: relative; margin-top: 1em; padding: 1em;
  background: var(--ground); border: 1px solid var(--line); border-radius: .5em;
}
.analysis-detail h4 { margin: 0 0 .4em; }
.detail-close { position: absolute; top: .6em; right: .6em; }
.prose-answer-small { font-size: .85em; margin: 0; max-width: 32em; }

/* ── reading settings ─────────────────────────────────────────────────── */
/* Theme, tint, typeface and line spacing are data attributes on <html>, set
   by exam-app.js. Everything below reads them. Doing it this way rather than
   with inline styles is not a preference: the CSP for these hosts is
   style-src 'self' with no unsafe-inline, so an inline style simply would not
   apply. */

:root[data-theme="dark"] {
  --ink: #e8edf2;
  --ink-soft: #c2cbd4;
  --muted: #9aa7b4;
  --line: #3a444f;
  --line-soft: #2c343d;
  --paper: #1b2128;
  --ground: #12171c;
  --brand: #6aa9e9;
  --brand-dark: #8cbdf0;
  --good: #6fd39b;   --good-bg: #16301f;
  --part: #e0b064;   --part-bg: #33260f;
  --bad: #f08a8a;    --bad-bg: #3a1b1b;
  --prov: #b9a6e8;   --prov-bg: #241c33;
  --warn-bg: #332a12; --warn-line: #7a6323; --tint-brand: #16293c;
}

/* Not merely "dark": maximum separation, for a pupil who needs it rather than
   prefers it. */
:root[data-theme="contrast"] {
  --ink: #ffffff;
  --ink-soft: #ffffff;
  --muted: #d8d8d8;
  --line: #ffffff;
  --line-soft: #999999;
  --paper: #000000;
  --ground: #000000;
  --brand: #6fd3ff;
  --brand-dark: #a8e5ff;
  --good: #5cff9d;   --good-bg: #00230f;
  --part: #ffd166;   --part-bg: #241a00;
  --bad: #ff8f8f;    --bad-bg: #2a0000;
  --prov: #d3b8ff;   --prov-bg: #1a0f2b;
  --warn-bg: #241a00; --warn-line: #ffd166; --tint-brand: #001a26;
}
:root[data-theme="contrast"] body { background: #000; }
:root[data-theme="contrast"] .q-card,
:root[data-theme="contrast"] .paper-card { border-width: 2px; }

/* Tints sit UNDER the theme: a pupil who needs a coloured overlay usually
   needs it on a light ground, so a tint quietly returns the page to light. */
:root[data-tint="cream"] { --paper: #fdf6e3; --ground: #f5ecd6; --ink: #1a1a1a; }
:root[data-tint="blue"]  { --paper: #e8f2fb; --ground: #dbe9f6; --ink: #10222f; }
:root[data-tint="rose"]  { --paper: #fdeef1; --ground: #f7e0e6; --ink: #2b1218; }
:root[data-tint="green"] { --paper: #ecf7ec; --ground: #ddeedd; --ink: #12250f; }

:root[data-font="readable"] body {
  /* No web font: the CSP blocks external ones and a missing font is worse
     than a plain one. These are the most legible faces already on a school
     machine, with generous tracking. */
  font-family: "Atkinson Hyperlegible", "Verdana", "Trebuchet MS", system-ui, sans-serif;
  letter-spacing: .012em;
  word-spacing: .06em;
}
:root[data-font="mono"] body {
  font-family: ui-monospace, "Cascadia Mono", "Consolas", monospace;
}

body { line-height: var(--leading, 1.55); }

.reading-panel {
  padding: 1em 1.1em;
  background: var(--paper);
  border-bottom: 2px solid var(--line);
}
.reading-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6em; margin: 0 0 .6em;
}
.reading-label { min-width: 7.5em; font-weight: 600; }
.seg { display: flex; flex-wrap: wrap; gap: .3em; }
.seg-btn {
  font: inherit; font-size: .88em; padding: .3em .7em; cursor: pointer;
  background: var(--ground); color: var(--ink);
  border: 1px solid var(--line); border-radius: .35em;
}
.seg-on { background: var(--brand); border-color: var(--brand); color: #fff; }

/* ── offline ──────────────────────────────────────────────────────────── */
.offline-note {
  margin: 0 0 1em; padding: .7em 1em; border-radius: .5em; font-weight: 600;
}
.offline-warn { background: var(--part-bg); border: 1px solid var(--part); color: var(--part); }
.offline-bad  { background: var(--bad-bg);  border: 1px solid var(--bad);  color: var(--bad); }

/* ── paper cards: windows and shorter goes ────────────────────────────── */
.paper-note {
  margin: .3em 0; padding: .4em .7em; border-radius: .4em;
  background: var(--prov-bg); border: 1px solid var(--prov); color: var(--prov);
  font-size: .9em;
}
.section-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: .4em; margin-top: .6em;
}

/* ── review before submitting ─────────────────────────────────────────── */
.review-panel {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(0, 0, 0, .45);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 4vh 1em; overflow-y: auto;
}
.review-inner {
  position: relative; width: 100%; max-width: 40em;
  padding: 1.4em 1.5em; border-radius: .6em;
  background: var(--paper); border: 1px solid var(--line);
}
.review-close { position: absolute; top: .8em; right: .8em; }
.review-inner h2 { margin: 0 0 .6em; }
.review-inner h3 { margin: 1.1em 0 .4em; font-size: 1em; }
.review-summary { margin: 0 0 .4em; }
.review-chips { display: flex; flex-wrap: wrap; gap: .3em; }
.review-inner .btn-primary { margin-top: 1.2em; }

/* ── results ──────────────────────────────────────────────────────────── */
.q-time { margin: .4em 0 0; font-size: .85em; color: var(--muted); }
.q-time-slow { color: var(--part); font-weight: 600; }

.teacher-comment {
  margin: .6em 0; padding: .6em .9em; border-radius: .45em;
  background: var(--prov-bg); border-left: 4px solid var(--prov);
}
.teacher-comment p { margin: .2em 0 0; }

.result-certs {
  margin: 0 0 1.2em; padding: .9em 1.1em; border-radius: .5em;
  background: var(--good-bg); border: 1px solid var(--good);
}
.cert-row { display: flex; flex-wrap: wrap; gap: .4em; margin-top: .6em; }
.cert-new { border-color: var(--good); font-weight: 700; }

/* ── revision mode ────────────────────────────────────────────────────── */
.revise-card { border-left: 4px solid var(--brand); }

@media (max-width: 700px) {
  .reading-label { min-width: 100%; }
  .review-inner { padding: 1.1em; }
}

/* ── teacher: scheduling, marking by question, boundaries ─────────────── */
.assign-form {
  display: grid; grid-template-columns: auto 1fr; gap: .5em .8em;
  align-items: center; max-width: 42em; margin: .8em 0;
}
.assign-form label { font-weight: 600; }
.assign-form input, .assign-form select {
  font: inherit; padding: .3em .5em;
  border: 1px solid var(--line); border-radius: .35em;
  background: var(--paper); color: var(--ink);
}
.assign-form button, .assign-form p { grid-column: 1 / -1; justify-self: start; }

.mark-done { border-left-color: var(--good); opacity: .75; }
.mark-comment {
  font: inherit; font-size: .9em; padding: .3em .5em; min-width: 16em; flex: 1;
  border: 1px solid var(--line); border-radius: .35em;
  background: var(--paper); color: var(--ink);
}
.bound-input {
  font: inherit; padding: .25em .4em; width: 6em;
  border: 1px solid var(--line); border-radius: .3em;
  background: var(--paper); color: var(--ink);
}
.voided-row td { text-decoration: line-through; }
.voided-row td:last-child { text-decoration: none; }

/* Printing a paper. Everything that only makes sense on screen goes away;
   a question must not be split across a page break mid-stem. */
@media print {
  .top, .q-nav, .exam-bar, .exam-foot, .exam-warning,
  #submit-warning, #time-call, #pace, #app-notice,
  #extra-time-note, .q-flag, .scale-control,
  .result-toolbar, .landing-back, .self-row,
  .btn-quiet, .btn-primary, .foot { display: none !important; }
  /* A printed result is a record — for a parents' evening, or a folder. The
     mark scheme and the worked answer are the useful half of it, so the
     details blocks are opened by the print handler and must not collapse
     back to a summary line on paper. */
  .ms-block, .working-block { break-inside: avoid; page-break-inside: avoid; }
  .result-summary { break-after: avoid; page-break-after: avoid; }
  .self-queue { border: 1px solid #999; }
  body { background: #fff; }
  .q-card, .exam-card { break-inside: avoid; page-break-inside: avoid;
    border: 1px solid #999; margin: 0 0 0.6em; }
  .exam-section { break-before: page; page-break-before: always; }
  .exam-section:first-of-type { break-before: auto; page-break-before: auto; }
  textarea, input, select { border: 1px solid #999 !important; background: #fff !important; }
  .code-input { min-height: 8em; }
}

/* ════════════════════════════════════════════════════════════════════════
   ASCENDERE — visual refresh, 2026-09-13
   ════════════════════════════════════════════════════════════════════════

   ONE CONTIGUOUS BLOCK, ON PURPOSE. Everything below overrides the original
   rules rather than editing them in place, so the whole refresh can be lifted
   out again by deleting from this banner to the one at the end — and the tools
   go back to exactly how they looked before. That is the revert.

   WHAT IT CHANGES
     * A softer palette. The old one was navy-on-cold-grey at full strength;
       this is the same information at lower contrast between surfaces, with
       contrast kept where it carries meaning (text, marks, right and wrong).
     * Depth instead of borders. Cards sit on the page rather than being boxed
       in by 1px lines.
     * Rounder corners, more air, and motion that is felt rather than seen.
     * A per-tool accent, set from the topic code by the page itself, so the
       nine topic tools and the mocks are recognisably different rooms in the
       same building.

   WHAT IT DOES NOT CHANGE
     * Any layout a pupil has learned. Nothing moves; things are shaped and
       coloured differently.
     * Contrast where it means something. The high-contrast theme is untouched
       by the softening — see the guard on the surface rules.
   ════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── surfaces ── */
  --ground: #f5f6fa;
  --paper: #ffffff;
  --paper-2: #fbfcfe;          /* a step in, for nested panels */
  --line: #e6e9f0;
  --line-soft: #f0f2f7;

  /* ── ink ── */
  --ink: #1e2531;
  --ink-soft: #4c5768;
  --muted: #71809a;

  /* ── accents ── */
  --brand: #5566dd;
  --brand-dark: #3f4dc0;
  --brand-soft: #eef0fd;

  --good: #0f7a5f;  --good-bg: #e7f6f1;
  --part: #a76a10;  --part-bg: #fdf3e2;
  --bad:  #c23a4b;  --bad-bg:  #fdecee;
  --prov: #6f57a3;  --prov-bg: #f1ecfa;

  --warn-bg: #fdf6e6;
  --warn-line: #e7c877;
  --tint-brand: var(--brand-soft);

  /* Each tool sets its own hue from its topic code; this is the fallback. */
  --tool-accent: var(--brand);
  --tool-accent-soft: var(--brand-soft);

  /* ── shape and depth ── */
  --r-sm: .45rem;
  --r: .8rem;
  --r-lg: 1.2rem;
  --shadow-1: 0 1px 2px rgba(24, 33, 56, .06);
  --shadow-2: 0 2px 6px rgba(24, 33, 56, .06), 0 8px 22px -12px rgba(24, 33, 56, .18);
  --shadow-3: 0 4px 10px rgba(24, 33, 56, .08), 0 18px 40px -18px rgba(24, 33, 56, .28);
  --ring: 0 0 0 3px var(--tool-accent-soft);
  --ease: cubic-bezier(.2, .7, .3, 1);
}

/* ── theme: follow the device unless told otherwise ───────────────────────
   data-theme="auto" is the default the page sets when nobody has chosen. The
   explicit light / dark / contrast values still win, and are unaffected by
   what the operating system thinks. */
@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] {
    --ground: #0f1218;
    --paper: #171b23;
    --paper-2: #1c212b;
    --line: #29303c;
    --line-soft: #212733;
    --ink: #e8ecf3;
    --ink-soft: #c0c8d6;
    --muted: #93a0b4;
    --brand: #8e9bf5;
    --brand-dark: #a9b3f8;
    --brand-soft: #1d2340;
    --good: #4fcfa4;  --good-bg: #10291f;
    --part: #e0ad63;  --part-bg: #2d2310;
    --bad:  #f08b93;  --bad-bg:  #33191d;
    --prov: #b6a4e8;  --prov-bg: #221c33;
    --warn-bg: #2b2310; --warn-line: #6f5b25;
    --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-2: 0 2px 6px rgba(0, 0, 0, .35), 0 8px 22px -12px rgba(0, 0, 0, .6);
    --shadow-3: 0 4px 10px rgba(0, 0, 0, .4), 0 18px 40px -18px rgba(0, 0, 0, .7);
  }
}

/* The chosen-dark palette matches the automatic one, so switching between
   "auto" and "dark" on a dark laptop changes nothing visible. */
:root[data-theme="dark"] {
  --ground: #0f1218;
  --paper: #171b23;
  --paper-2: #1c212b;
  --line: #29303c;
  --line-soft: #212733;
  --ink: #e8ecf3;
  --ink-soft: #c0c8d6;
  --muted: #93a0b4;
  --brand: #8e9bf5;
  --brand-dark: #a9b3f8;
  --brand-soft: #1d2340;
  --good: #4fcfa4;  --good-bg: #10291f;
  --part: #e0ad63;  --part-bg: #2d2310;
  --bad:  #f08b93;  --bad-bg:  #33191d;
  --prov: #b6a4e8;  --prov-bg: #221c33;
  --warn-bg: #2b2310; --warn-line: #6f5b25;
  --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-2: 0 2px 6px rgba(0, 0, 0, .35), 0 8px 22px -12px rgba(0, 0, 0, .6);
  --shadow-3: 0 4px 10px rgba(0, 0, 0, .4), 0 18px 40px -18px rgba(0, 0, 0, .7);
}

/* High contrast opts OUT of the soft treatment entirely: no shadows, hard
   borders, maximum separation. Softness is the opposite of what it is for. */
:root[data-theme="contrast"] {
  --r-sm: .2rem; --r: .3rem; --r-lg: .3rem;
  --shadow-1: none; --shadow-2: none; --shadow-3: none;
  --brand-soft: #001a26;
  --tool-accent: var(--brand);
  --tool-accent-soft: #001a26;
}
:root[data-theme="contrast"] .q-card,
:root[data-theme="contrast"] .paper-card,
:root[data-theme="contrast"] .admin-block { border-width: 2px; }

body { background: var(--ground); }

/* ── page furniture ───────────────────────────────────────────────────── */
.top {
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow-1);
}
.brand {
  font-weight: 700; letter-spacing: .02em;
  border-radius: var(--r-sm);
  transition: color .18s var(--ease);
}
.brand:hover { color: var(--tool-accent); }

/* ── the hero each tool now opens with ────────────────────────────────── */
.tool-hero {
  display: flex; align-items: center; gap: 1.1em;
  margin: 1.4em 0 1.6em;
  padding: 1.3em 1.5em;
  border-radius: var(--r-lg);
  background:
    linear-gradient(135deg, var(--tool-accent-soft), transparent 62%),
    var(--paper);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-2);
}
/* The monogram. A topic code in a tile, rather than twelve illustrations
   nobody has drawn — it scales to a thirteenth tool for free. */
.tool-badge {
  flex: none;
  display: grid; place-items: center;
  min-width: 3.4em; height: 3.4em; padding: 0 .5em;
  border-radius: var(--r);
  background: linear-gradient(150deg, var(--tool-accent), var(--brand-dark));
  color: #fff;
  font-weight: 800; font-size: 1.05em; letter-spacing: .02em;
  box-shadow: var(--shadow-2);
}
.tool-hero-text { min-width: 0; }
.tool-hero h1 {
  margin: 0; font-size: clamp(1.3em, 3.4vw, 1.7em);
  line-height: 1.2; letter-spacing: -.01em;
}
.tool-hero .tool-sub { margin: .25em 0 0; color: var(--muted); font-size: .92em; }
.tool-hero-stats {
  margin-left: auto; display: flex; gap: 1.4em; flex-wrap: wrap; text-align: right;
}
.tool-stat { display: flex; flex-direction: column; }
.tool-stat b { font-size: 1.3em; line-height: 1.1; color: var(--tool-accent); }
.tool-stat span { font-size: .76em; color: var(--muted); text-transform: uppercase;
                  letter-spacing: .06em; }

/* ── tabs ─────────────────────────────────────────────────────────────── */
.tabs {
  gap: .25em;
  border-bottom: 1px solid var(--line);
}
.tab {
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  padding: .6em 1em;
  transition: background .18s var(--ease), color .18s var(--ease);
}
.tab:hover { background: var(--tool-accent-soft); color: var(--tool-accent); }
.tab[aria-selected="true"] {
  color: var(--tool-accent);
  border-bottom-color: var(--tool-accent);
  background: var(--tool-accent-soft);
}

/* ── cards ────────────────────────────────────────────────────────────── */
.q-card, .paper-card, .admin-block, .login-card {
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--paper);
  box-shadow: var(--shadow-2);
  transition: box-shadow .22s var(--ease), transform .22s var(--ease);
}
.q-card { padding: 1.4em 1.5em; }
.paper-card:hover { box-shadow: var(--shadow-3); transform: translateY(-2px); }

/* A quiet accent rail, so a card has a left edge that means something. */
.q-card { border-left: 3px solid transparent; }
.q-card:focus-within { border-left-color: var(--tool-accent); }
.result-right { border-left-color: var(--good); }
.result-part  { border-left-color: var(--part); }
.result-wrong { border-left-color: var(--bad); }
.result-blank { border-left-color: var(--muted); }
.result-prov  { border-left-color: var(--prov); }

.q-num {
  display: inline-grid; place-items: center;
  min-width: 1.9em; height: 1.9em; padding: 0 .35em;
  border-radius: 50em;
  background: var(--tool-accent-soft); color: var(--tool-accent);
  font-weight: 700;
}
.q-marks {
  border-radius: 50em; padding: .12em .7em;
  background: var(--line-soft); color: var(--ink-soft); font-weight: 600;
}

/* ── paper chooser ────────────────────────────────────────────────────── */
.paper-card { padding: 1.3em 1.4em; }
.paper-head strong { font-size: 1.12em; letter-spacing: -.005em; }
.paper-chips { display: flex; flex-wrap: wrap; gap: .4em; margin: .5em 0 .2em; }
.paper-chip {
  border-radius: 50em; padding: .2em .75em;
  background: var(--line-soft); color: var(--ink-soft);
  font-size: .82em; font-weight: 600;
}
.paper-chip-accent { background: var(--tool-accent-soft); color: var(--tool-accent); }

/* ── controls ─────────────────────────────────────────────────────────── */
.btn-primary, .btn-quiet, .btn-mark, .certificate-btn, .seg-btn, .tab {
  transition: background .18s var(--ease), color .18s var(--ease),
              border-color .18s var(--ease), box-shadow .18s var(--ease),
              transform .12s var(--ease);
}
.btn-primary, .btn-quiet, .btn-mark, .certificate-btn {
  border-radius: var(--r-sm);
}
.btn-primary {
  background: linear-gradient(160deg, var(--tool-accent), var(--brand-dark));
  border-color: transparent;
  box-shadow: var(--shadow-1);
}
.btn-primary:hover:not([disabled]) { box-shadow: var(--shadow-2); transform: translateY(-1px); }
.btn-primary:active:not([disabled]) { transform: translateY(0); }
.btn-primary[disabled] { opacity: .5; filter: saturate(.4); transform: none; }
.btn-quiet:hover:not([disabled]) {
  background: var(--tool-accent-soft); border-color: var(--tool-accent);
  color: var(--tool-accent);
}
.btn-mark:hover { background: var(--tool-accent); border-color: var(--tool-accent); }

/* One visible focus ring everywhere, for the keyboard and for anyone who
   needs to know where they are. */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, summary:focus-visible {
  outline: 2px solid var(--tool-accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

.single-input, .cell-input, .prose-input, .code-input, .cell-prose,
.gap-select, .mark-comment, .bound-input, .extra-time-input {
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.single-input:focus, .cell-input:focus, .prose-input:focus, .code-input:focus,
.cell-prose:focus, .gap-select:focus, .mark-comment:focus {
  border-color: var(--tool-accent);
  box-shadow: var(--ring);
  outline: none;
}

/* ── tables ───────────────────────────────────────────────────────────── */
.data-table, .topic-table {
  border-radius: var(--r); overflow: hidden;
  box-shadow: var(--shadow-1);
}
.data-table th, .topic-table th {
  background: var(--paper-2); color: var(--ink-soft);
  font-size: .84em; text-transform: uppercase; letter-spacing: .05em;
}
.data-table tr:hover td { background: var(--tool-accent-soft); }

/* ── the exam bar and navigator ───────────────────────────────────────── */
.exam-bar {
  border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow-1);
  background: var(--paper);
}
.exam-timer { border-radius: var(--r); background: var(--line-soft); }
.timer-warn  { background: var(--part-bg); color: var(--part); }
.timer-final, .timer-critical { background: var(--bad-bg); color: var(--bad); }
.q-nav { border-radius: var(--r); box-shadow: var(--shadow-1); }
.q-nav-cell {
  border-radius: var(--r-sm);
  transition: transform .12s var(--ease), background .18s var(--ease),
              border-color .18s var(--ease);
}
.q-nav-cell:hover { transform: translateY(-1px); border-color: var(--tool-accent); }
.nav-done { background: var(--good-bg); color: var(--good); border-color: transparent; }
.nav-flag { box-shadow: inset 0 -3px 0 var(--part); }

/* ── motion, for those who want it ────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
  }
  .paper-card:hover, .btn-primary:hover, .q-nav-cell:hover { transform: none; }
}

@media (max-width: 700px) {
  .tool-hero { flex-wrap: wrap; padding: 1.1em 1.2em; }
  .tool-hero-stats { margin-left: 0; width: 100%; text-align: left; gap: 1.1em; }
}

/* ════════════ end of the Ascendere refresh — delete to here to revert ═══ */


/* ---- marks in the class grid ---- */
/* The grid used to be solved / not solved. It now shows the mark, so it
   needs a shade per state. Every cell also carries the number itself and
   a hover title, so it still reads without relying on colour. */
.prog-grid .cell {
  text-align: center;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  min-width: 1.6em;
}

.cell-part { background: var(--warn, #d98324); color: #fff; }
.cell-zero { background: var(--bad, #c0504d); color: #fff; }

/* Waiting on the teacher is deliberately NOT a warm colour: it is not a
   poor score, and shading it like one would misrepresent the pupil. */
.cell-wait {
  background: repeating-linear-gradient(135deg,
    rgba(120,160,220,.45), rgba(120,160,220,.45) 4px,
    transparent 4px, transparent 8px);
}

/* Seeing the mark scheme is context, not a penalty: marked quietly. */
.cell-seen { text-decoration: underline; text-underline-offset: 2px; }

/* A restored answer says so. Silently refilling a box would be worse than
   leaving it empty: the pupil needs to know the words in front of them are
   their own from last time, not a model answer. */
.restored-note {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 10px 0 0;
  padding: 7px 12px;
  border-radius: 8px;
  border: 1px solid rgba(127, 127, 127, 0.28);
  background: rgba(127, 127, 127, 0.08);
  font-size: 0.86rem;
}
.restored-text { opacity: 0.85; }
.restored-clear { font-size: 0.8rem; padding: 4px 10px; }

/* ---------------------------------------------- wireframe: shape and notes */
/* OCR marks these LAYOUT /4 + CONTENT /4, and the layout descriptors name
   half-width placement, relative size, deliberate whitespace and annotations.
   Every one of those needs somewhere to live on the page. */
.wf-shape {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .35em;
  margin-bottom: .5em;
}

.wf-span {
  padding: .2em .6em;
  font: inherit;
  font-size: .85em;
  border: 1px dashed var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}

.wf-span:hover { border-color: var(--brand); color: var(--brand); }

.wf-span-on {
  border-style: solid;
  border-color: var(--brand);
  background: var(--brand);
  color: #fff;
  font-weight: 600;
}

/* A row is now a strip two blocks can share, so the halves need real width. */
.wf-blockwrap { position: relative; display: flex; }
.wf-full  { flex: 1 1 100%; }
.wf-left  { flex: 0 1 50%; }
.wf-right { flex: 0 1 50%; margin-left: auto; }
.wf-tall  { min-height: 4.4em; }
.wf-carried { visibility: hidden; }

.wf-blockwrap .wf-block {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: .15em;
  text-align: left;
}

.wf-block-label { font-weight: 600; }

/* The annotation. This is the mark pupils most often miss, so it is shown on
   the block rather than hidden behind a hover. */
.wf-note {
  font-weight: 400;
  font-size: .82em;
  font-style: italic;
  opacity: .85;
  line-height: 1.3;
}

.wf-notebtn {
  position: absolute;
  top: .15em;
  right: .3em;
  padding: 0 .4em;
  font: inherit;
  font-size: .72em;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bg);
  color: var(--muted);
  cursor: pointer;
}

.wf-notebtn:hover { border-color: var(--brand); color: var(--brand); }

/* An empty row is a layout choice the mark scheme credits, not a gap to be
   tidied away, so it stays visible and unremarkable. */
.wf-gap {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--line);
  border: 1px dashed transparent;
}

.wf-slot.wf-left, .wf-slot.wf-right { flex: 0 1 50%; }
.wf-slot.wf-full { flex: 1 1 100%; }

/* ---- the same wireframe, shown back read-only (teacher view, review) ---- */
.wf-view { margin: .4em 0; }
.wf-page-view { pointer-events: none; }

.wf-block-view {
  cursor: default;
  width: 100%;
  padding: .35em .6em;
  border: 2px solid var(--brand);
  border-radius: 4px;
  background: var(--tint-brand);
  color: var(--brand-dark);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .15em;
  text-align: left;
}

/* ---------------------------------- what the Teacher number is made of ---- */
/* The badge used to count new certificates and say so only in a title
   attribute -- which cannot be read on a tablet, cannot be reached from the
   keyboard, and vanishes when the mouse moves. So a bare red number beside a
   teacher icon got read as unmarked work, which is not what it was. */
.badge { cursor: pointer; }

.teacher-summary {
  margin: 0 0 1.1em;
  padding: .75em .9em;
  border: 1px solid var(--line);
  border-left: 4px solid var(--brand);
  border-radius: .5em;
  background: var(--ground);
}

.ts-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .6em;
  margin-bottom: .55em;
}

.ts-help {
  font: inherit;
  font-size: .85em;
  padding: .15em .7em;
  border: 1px solid var(--brand);
  border-radius: 1em;
  background: transparent;
  color: var(--brand);
  cursor: pointer;
}

.ts-help:hover { background: var(--tint-brand); }

.ts-items { display: flex; flex-wrap: wrap; gap: .5em; }

.ts-item {
  display: flex;
  align-items: baseline;
  gap: .4em;
  padding: .25em .6em;
  border: 1px solid var(--line);
  border-radius: .4em;
  font-size: .88em;
  background: var(--bg);
}

/* Only the things actually waiting on the teacher are coloured. A chip that
   shouts when nothing is wrong teaches people to ignore the chip. */
.ts-item-on { border-color: var(--bad); }
.ts-item-on .ts-n { color: var(--bad); }

.ts-n { font-weight: 700; font-variant-numeric: tabular-nums; }
.ts-note { color: var(--muted); font-size: .9em; font-style: italic; }

/* ---- the explanation itself ---- */
.help-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25em;
  background: rgba(16, 24, 40, .45);
}

body.help-open { overflow: hidden; }

.help-panel {
  width: min(38em, 100%);
  max-height: min(80vh, 46em);
  overflow-y: auto;
  padding: 1.1em 1.2em 1em;
  border-radius: .8em;
  border: 1px solid var(--line);
  background: var(--bg);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .3);
}

.help-head { display: flex; align-items: flex-start; gap: .75em; }
.help-head h3 { margin: 0; font-size: 1.15em; }

.help-close {
  margin-left: auto;
  width: 1.9em;
  height: 1.9em;
  flex: none;
  font: inherit;
  font-size: 1.1em;
  line-height: 1;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: inherit;
  cursor: pointer;
}

.help-close:hover { background: var(--tint-brand); }

.help-sum {
  margin: .6em 0 1em;
  padding: .5em .7em;
  border-radius: .4em;
  background: var(--ground);
  font-size: .92em;
}

.help-row {
  display: flex;
  gap: .8em;
  padding: .7em 0;
  border-top: 1px solid var(--line);
}

.help-n {
  flex: none;
  min-width: 2.2em;
  font-size: 1.3em;
  font-weight: 700;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--bad);
}

/* Greyed because it is counted but deliberately not in the badge. */
.help-row-off .help-n { color: var(--muted); }

.help-label { font-weight: 600; margin-bottom: .2em; }
.help-what { margin: 0 0 .3em; font-size: .92em; }
.help-when { margin: 0; font-size: .85em; color: var(--muted); font-style: italic; }
.help-foot { margin: .9em 0 0; font-size: .85em; color: var(--muted); }

/* --------------------------------- Cambridge National boundaries, derived */
/* Three marks in, seven grades out. OCR sets only Distinction and Pass at
   Level 2 and Pass at Level 1 by judgement; the other four are arithmetic it
   publishes, so they are not the teacher's to type -- and a Merit typed in
   the wrong place is not a Cambridge National grade at all. */
.bounds-derive {
  margin: 0 0 1em;
  padding: .8em .9em;
  border: 1px solid var(--line);
  border-left: 4px solid var(--brand);
  border-radius: .5em;
  background: var(--ground);
}
.bounds-derive h4 { margin: 0 0 .3em; font-size: 1em; }
.derive-row { display: flex; flex-wrap: wrap; gap: .7em; margin: .6em 0; }
.derive-field { display: flex; flex-direction: column; gap: .2em; }
.derive-input {
  width: 6em; font: inherit; padding: .3em .4em;
  border: 1px solid var(--line); border-radius: .3em;
  background: var(--bg); color: inherit;
}

/* ------------------------------ what a score is made of ------------------ */
/* Self-marks count towards the total. This says how much of the total they
   are, because a score that is nine tenths a pupil's own judgement reads
   identically to one a teacher has been through, and they are not the same
   number. Quiet by design: it qualifies the figure above, it is not a
   warning. */
.marking-make-up {
  margin: -.6em 0 1.1em;
  font-size: .82em;
  color: var(--muted);
}

/* ═══════════════════════════════════════════════════════════════════════
   PRINTING A RESULT — IN COLOUR
   ═══════════════════════════════════════════════════════════════════════
   The earlier print block flattened everything to grey borders on white,
   which is right for printing a blank paper to sit an exam on but wrong for
   printing a marked one. On a result the colour IS information: the stripe
   down each card says right, partly, wrong or written at a glance, and a
   parents' evening printout without it is just a wall of text.

   Browsers drop backgrounds when printing unless told not to, so every
   surface that carries meaning asks for them explicitly. This block sits
   last so it beats the earlier print rules. */
@media print {
  /* Ask for the ink. Without this the tints and stripes vanish and the
     cards come out identical to each other. */
  #result-view,
  #result-view * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* The earlier block puts a flat grey box round every card, which
     overwrites the coloured edge. Give it back. */
  #result-questions .q-card {
    border: 1px solid var(--line-soft) !important;
    border-left-width: 5px !important;
  }
  #result-questions .result-right { border-left-color: var(--good) !important; }
  #result-questions .result-part  { border-left-color: var(--part) !important; }
  #result-questions .result-wrong { border-left-color: var(--bad) !important; }
  #result-questions .result-prov  { border-left-color: var(--prov) !important; }
  #result-questions .result-blank { border-left-color: var(--muted) !important; }

  /* The summary, the grade and the advice all carry their tints through. */
  .result-summary .score-block { border: 1px solid var(--line-soft) !important; }
  .result-summary .score-grade {
    background: var(--tint-brand) !important;
    border-color: var(--brand) !important;
  }
  .result-next .next-step { border-left: 4px solid var(--brand) !important; }
  .q-tag { border: 1px solid currentColor !important; }

  /* Feedback and mark schemes are the half worth keeping, so they keep their
     ground rather than printing as unmarked text. */
  .feedback, .ms-text, .prose-answer, .working-block pre {
    background: var(--ground) !important;
    border: 1px solid var(--line-soft) !important;
  }

  /* Wireframe answers are drawn, not written. Print the drawing. */
  .wf-block-view {
    background: var(--tint-brand) !important;
    border: 2px solid var(--brand) !important;
    color: var(--brand-dark) !important;
  }

  /* A result is a record someone files, so say what it is on paper. The
     screen already carries the title in the heading. */
  .marking-make-up { color: var(--ink-soft) !important; }

  /* Keep a question and its feedback together, and never split a card. */
  #result-questions .q-card { break-inside: avoid; page-break-inside: avoid; }
  .result-next { break-inside: avoid; page-break-inside: avoid; }

  /* Print in the light palette whatever the pupil is using on screen:
     a dark theme on paper is a page of solid ink. */
  :root, :root[data-theme="dark"] {
    --ink: #17202a; --ink-soft: #4a5866; --muted: #6b7885;
    --line-soft: #d7dee6; --paper: #ffffff; --ground: #f4f7fa;
    --brand: #1c5c9e; --brand-dark: #14456f;
    --good: #1c7a4a; --part: #8a6100; --bad: #a32929; --prov: #5b4b8a;
    --tint-brand: #e8f0f9;
  }
  body { background: #fff !important; color: var(--ink) !important; }
}

/* The hint before it is earned. Quiet on purpose: it is an instruction to
   go and try, not a warning that something is wrong. */
.hint-locked {
  margin: .4rem 0 .2rem;
  font-size: .9em;
  color: var(--muted);
  font-style: italic;
}

/* The running score. Prominent enough to be the thing a pupil looks at
   after answering, quiet enough not to shout while it says zero. */
.score-strip {
  margin: 0 0 1rem;
  padding: .55rem .8rem;
  border: 1px solid var(--line, #d7dbe0);
  border-left: 4px solid var(--brand, #1d4ed8);
  border-radius: .45rem;
  background: var(--ground, #f7f8fa);
  font-weight: 600;
}
.score-strip.score-empty {
  font-weight: 400;
  color: var(--muted, #667);
  border-left-color: var(--line, #d7dbe0);
}

/* This tool's leaderboard, in the My progress tab. */
.board-box { margin: 0 0 1.4rem; padding: .8rem .9rem;
  border: 1px solid var(--line); border-radius: .5rem; background: var(--ground); }
.board-box h3 { margin: 0 0 .2rem; font-size: 1.02rem; }
.board-table { border-collapse: collapse; margin-top: .5rem; min-width: 18rem; }
.board-table th, .board-table td { padding: .3rem .7rem .3rem 0; text-align: left; }
.board-table th { font-size: .85em; color: var(--muted); font-weight: 600; }
/* The pupil's own row. On an anonymous board `student42` means nothing to
   anyone else and everything to student42. */
.board-table tr.board-me td { font-weight: 700; }
/* The leaderboard heading pulses, slowly and visibly.
   Four seconds. The glow nearly vanishes and then blooms, and the text
   brightens with it -- an earlier version moved only the shadow, by a few
   pixels, and could not be seen at all unless you were already looking at
   the word. Slow and obvious beats fast or subliminal in a classroom. */
/* Teal, and legible on BOTH themes -- see the note where this was changed:
   the old gold measured 1.66:1 on the light theme, which is most pupils. */
/* Gold is reserved for the LEADERBOARD headings, so the colour marks the
   boards rather than decorating every heading alike. Darker than the original
   #e7c57a, which measured 1.66:1 on a white card and all but disappeared at
   the dim end of the cycle; these measure 3.89:1 and 3.25:1 on white and
   4.17:1 and 4.98:1 on the tools' dark theme. */
@keyframes board-pulse {
  0%, 100% {
    color: #a8790c;
    text-shadow: 0 0 2px rgba(255,190,60,.19);
  }
  50% {
    color: #b8860b;
    text-shadow: 0 0 8px rgba(255,214,96,.75), 0 0 20px rgba(255,180,40,.64),
                 0 0 35px rgba(255,160,20,.38);
  }
}
.board-box h3 {
  animation: board-pulse 4s ease-in-out infinite;
  font-size: 1.15rem;
}
/* Someone who has asked their machine to stop moving things gets a steady
   glow, not a slower flash. */
@media (prefers-reduced-motion: reduce) {
  .board-pulse, .cohort-head, .me-page h2.landing-group,
  .board-box h3, #sql-board .grid-heading, #board .lbl { animation: none; }
}

/* A pupil's avatar, to the RIGHT of their username on the leaderboard. The
   pictures are served from this tool's own origin: img-src is 'self', so one
   linked from the main site would be silently blocked and the row would just
   look empty. */
/* To the RIGHT of the username, on every board: the pupil's own page, the
   per-tool cards, and the teacher's full lists.

   Drawn at 48px from a 144px file, so the hover below lands on real pixels
   rather than blowing up a thumbnail. */
.board-face {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  vertical-align: -16px;
  margin-left: .45rem;
  /* Both needed so the zoomed picture rises above the rows under it instead
     of being clipped by them. */
  position: relative;
  z-index: 1;
  transition: transform .18s ease-out, box-shadow .18s ease-out;
}
/* Hover zooms to three times the drawn size -- 48px becomes 144px, which is
   exactly the file's own resolution.

   A transform, not width/height: a transform is composited and reflows
   nothing, where animating the width would shove every row below it down the
   page each time the cursor crossed a face. */
.board-face:hover,
.board-face:focus-visible {
  transform: scale(3);
  z-index: 20;
  box-shadow: 0 6px 22px rgba(15, 23, 42, .35);
}
/* Someone who has asked their machine to stop moving things gets the size
   change without the slide. */
@media (prefers-reduced-motion: reduce) {
  .board-face { transition: none; }
}
