/* ═══════════════════════════════════════════════════════════
   My Prep — notebook page
   paper + blue rules + red margin + highlighter yellow
   ═══════════════════════════════════════════════════════════ */

:root {
  /* type: three registers — workbook cover / textbook / answer key */
  --sans: "Avenir Next", Avenir, Futura, "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
  --serif: Charter, "Iowan Old Style", "Palatino Linotype", Georgia, "Times New Roman", serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  --rail-w: 5rem;
  --sheet-max: 46rem;
  --sheet-pad: 1.6rem;           /* the gutter items can hang back into */
  --lh: 2rem;                    /* the ruled line height — text sits on it */
  --r: 10px;

  --ease: cubic-bezier(.2, .7, .3, 1);
}

html[data-theme="paper"] {
  /* Tells the browser to paint its OWN widgets to match: the autofill dropdown,
     the password reveal control, scrollbars, and form controls we do not style.
     Without it the chalk theme showed a light grey autofill panel over a dark
     page. */
  color-scheme: light;
  --paper:    #FBFCFD;
  --panel:    #EFF4F9;
  --panel-2:  #E4ECF4;
  --rule:     #C6DCEF;
  /* A visible edge for form controls. --rule is a hairline for decoration and
     measures 1.37:1 against paper, which is fine for a rule and not fine for
     the only thing marking where you type. */
  --edge:     #8594A1;
  --hair:     #DCE5EE;
  --margin:   #E0574E;
  --ink:      #16202E;
  --graphite: #58657A;
  --mark:     #FFDD57;
  --mark-2:   #F3C623;
  --pen-green:#1B9159;
  --pen-red:  #CE4038;
  /* Text-weight variants. The pair above are used for BORDERS, where the bar
     is 3:1 and they clear it. As text on their own tint they measured 3.60:1
     and 4.12:1 — under the 4.5:1 WCAG AA needs for normal text, on the one
     character that tells a student which option was right. */
  --pen-green-ink:#177d4c;
  --pen-red-ink:  #c23c35;
  --tint-green:#E8F6EE;
  --tint-red: #FCEBE9;
  --shadow:   0 1px 0 rgba(22,32,46,.05), 0 8px 24px -14px rgba(22,32,46,.28);
}

html[data-theme="chalk"] {
  color-scheme: dark;
  --paper:    #161B23;
  --panel:    #1D242E;
  --panel-2:  #252D39;
  --rule:     #2B3644;
  /* Same reasoning as the light theme: --rule is a hairline (1.41:1 here) and
     --edge is what marks a form control. The green and red already clear 4.5:1
     against their tints in this theme — 7.07 and 6.16 — so they need no
     text-weight variant, but the names must exist or the light values leak in. */
  --edge:     #636B75;
  --pen-green-ink:#4ACE93;
  --pen-red-ink:  #FF7D71;
  --hair:     #29313D;
  --margin:   #E0574E;
  --ink:      #E9EEF4;
  --graphite: #92A0B4;
  --mark:     #FFDD57;
  --mark-2:   #FFD027;
  --pen-green:#4ACE93;
  --pen-red:  #FF7D71;
  --tint-green:#16302A;
  --tint-red: #33201F;
  --shadow:   0 1px 0 rgba(0,0,0,.3), 0 10px 30px -18px rgba(0,0,0,.9);
}

* { box-sizing: border-box; }

/* The UA rule for [hidden] is only `display: none`, so ANY author rule that
   sets display (.choices is a grid, .btn is inline-flex, .tag-followup is
   inline-block) silently beats it and the element stays on screen. The app
   toggles visibility entirely through the hidden property, so this rule is
   load-bearing, not a tidy-up. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

button, input { font: inherit; color: inherit; }

.skip {
  position: absolute; left: -999px; top: 0;
  background: var(--ink); color: var(--paper);
  padding: .6rem 1rem; z-index: 50; border-radius: 0 0 var(--r) 0;
}
.skip:focus { left: 0; }

:focus-visible {
  outline: 2.5px solid var(--margin);
  outline-offset: 2px;
  border-radius: 3px;
}

/* ─────────────────────────  top bar  ───────────────────────── */

.topbar {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(10px);
  border-bottom: 1px solid var(--hair);
}
.topbar-in {
  max-width: calc(var(--sheet-max) + var(--rail-w) + 4rem);
  margin: 0 auto;
  padding: .6rem 1.25rem;
  display: flex; align-items: center; gap: 1rem;
}

.brand {
  display: flex; align-items: center; gap: .6rem;
  background: none; border: 0; padding: .25rem; margin-left: -.25rem;
  cursor: pointer; font-family: var(--sans);
  font-weight: 700; letter-spacing: -.01em; font-size: .95rem;
}
.brand-mark {
  width: 1.05rem; height: 1.35rem; border-radius: 2px;
  background: var(--panel-2);
  border-left: 3px solid var(--margin);
  box-shadow: inset 0 -4px 0 -3px var(--rule), inset 0 -9px 0 -8px var(--rule);
}
.brand-txt { color: var(--ink); white-space: nowrap; }

.topnav { margin-left: auto; display: flex; align-items: center; gap: .15rem; }

.navlink {
  background: none; border: 0; cursor: pointer;
  font-family: var(--sans); font-size: .82rem; font-weight: 600;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--graphite);
  padding: .5rem .7rem; border-radius: 7px;
}
.navlink:hover { color: var(--ink); background: var(--panel); }
.navlink[aria-current="true"] {
  color: var(--ink);
  box-shadow: inset 0 -.55em 0 -.1em var(--mark);
}
.navlink.icon { padding: .45rem; }
.theme-dot {
  display: block; width: 1rem; height: 1rem; border-radius: 50%;
  background: linear-gradient(135deg, var(--ink) 0 50%, var(--panel-2) 50% 100%);
  border: 1px solid var(--graphite);
}

/* ── the account menu ─────────────────────────────────────────────
   One silhouette, three account-level actions behind it. Two of them are
   destructive and one is irreversible, so they are deliberately not a row of
   buttons in the bar: "Delete account" next to "Sign out" is one slip from
   losing everything. Opening a menu is the deliberate act that separates
   them. */
.accountmenu { position: relative; display: flex; }
.silhouette {
  display: block; width: 1.15rem; height: 1.15rem;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
.menu {
  position: absolute; top: calc(100% + .4rem); right: 0; z-index: 40;
  min-width: 12.5rem; padding: .3rem;
  background: var(--paper); border: 1px solid var(--rule);
  border-radius: .5rem; box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: .1rem;
}
.menu[hidden] { display: none; }
/* The address is data, not a control, so it keeps the mono face the app uses
   for figures and labels rather than shouting in uppercase beside the items. */
.menu-who {
  margin: 0; padding: .45rem .7rem .5rem;
  font-family: var(--mono); font-size: .66rem; color: var(--graphite);
  border-bottom: 1px solid var(--hair); overflow-wrap: anywhere;
}
/* Set from .navlink rather than from `font: inherit`. These sit under the nav
   and read as part of it, so they carry the same uppercase sans the rest of
   the bar uses — inheriting picked up the page's serif instead, and the menu
   read as a different piece of software. */
.menu-item {
  appearance: none; border: 0; background: none; cursor: pointer;
  text-align: left; padding: .5rem .7rem; border-radius: .35rem;
  font-family: var(--sans); font-size: .82rem; font-weight: 600;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--graphite);
}
.menu-item:hover, .menu-item:focus-visible { color: var(--ink); }
.menu-item:hover, .menu-item:focus-visible { background: var(--panel); }
/* Destructive actions are named in the ink used for a wrong answer, which is
   the one colour in this app that already means "this went badly". */
.menu-item.is-danger { color: var(--pen-red); }
.menu-item.is-danger:hover, .menu-item.is-danger:focus-visible {
  background: var(--tint-red);
}
.btn.is-danger { color: var(--pen-red); border-color: var(--pen-red); }
.btn.is-danger:hover { background: var(--tint-red); }

/* ── the school's pictures ────────────────────────────────────────── */
.logo-list { display: flex; flex-wrap: wrap; gap: .6rem; margin: .5rem 0 .9rem; }
.logo-item {
  display: flex; flex-direction: column; align-items: center; gap: .3rem;
  padding: .45rem; border: 1px solid var(--hair); border-radius: .45rem;
}
.logo-item canvas { image-rendering: pixelated; width: 68px; height: 68px; }
.logo-item .logo-n {
  font-family: var(--mono); font-size: .6rem; color: var(--graphite);
  text-transform: uppercase; letter-spacing: .04em;
}
.logo-preview { margin: .3rem 0 .6rem; }
.logo-preview canvas { image-rendering: pixelated; width: 190px; height: 190px; }

/* ─────────────────────────  page + rail  ───────────────────────── */

.page {
  max-width: calc(var(--sheet-max) + var(--rail-w) + 4rem);
  margin: 0 auto;
  padding: 2.5rem 2rem 4rem;
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
}

/* the signature: a red margin rule with the student's own annotations in it */
.rail {
  border-right: 1.5px solid var(--margin);
  padding-right: .9rem;
  position: relative;
}
.rail-stack {
  position: sticky; top: 5rem;
  display: flex; flex-direction: column; align-items: flex-end; gap: .1rem;
  text-align: right;
}
.rail-lbl {
  font-family: var(--mono); font-size: .58rem; text-transform: uppercase;
  letter-spacing: .14em; color: var(--graphite); opacity: .8;
}
.rail-num {
  font-family: var(--mono); font-size: 1.5rem; font-weight: 500;
  line-height: 1.1; color: var(--ink); font-variant-numeric: tabular-nums;
}
/* the score is a ratio like "4/6", so it needs to fit the rail */
#q-score { font-size: 1.15rem; }
.rail-div { width: 1.4rem; height: 1px; background: var(--hair); margin: .55rem 0 .35rem; }
.tally { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; margin: .1rem 0 .3rem; max-width: 3.2rem; }
.tally svg { display: block; }
.tally svg line { stroke: var(--ink); stroke-width: 1.6; stroke-linecap: round; }

.sheet { padding-left: var(--sheet-pad); min-width: 0; }

/* ─────────────────────────  headings  ───────────────────────── */

.eyebrow {
  font-family: var(--mono); font-size: .68rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: .16em;
  color: var(--graphite); margin: 0 0 .8rem;
}

.hero { margin-bottom: 2rem; }
.hero-h {
  font-family: var(--sans);
  font-size: clamp(2rem, 6.5vw, 3.1rem);
  font-weight: 700; letter-spacing: -.035em; line-height: 1.02;
  margin: 0 0 .9rem;
}
.hero-sub {
  margin: 0; max-width: 34rem; color: var(--graphite); font-size: 1.02rem;
}

.rule-h {
  font-family: var(--mono); font-size: .68rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: .16em; color: var(--graphite);
  margin: 3rem 0 1rem;
  display: flex; align-items: center; gap: .9rem;
}
.rule-h::after {
  content: ""; flex: 1; height: 1px; background: var(--hair);
}

/* ─────────────────────────  buttons  ───────────────────────── */

.quick { display: flex; flex-wrap: wrap; gap: .7rem; }

.btn {
  font-family: var(--sans); font-weight: 650; font-size: .95rem;
  letter-spacing: -.01em;
  padding: .72rem 1.15rem; border-radius: var(--r);
  border: 1.5px solid transparent; cursor: pointer;
  display: inline-flex; align-items: baseline; gap: .55rem;
  transition: transform .12s var(--ease), background-color .15s, border-color .15s;
}
.btn:active { transform: translateY(1px); }
.btn-note {
  font-family: var(--mono); font-size: .66rem; font-weight: 400;
  letter-spacing: .06em; text-transform: uppercase; opacity: .65;
}

.btn-primary { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.btn-primary:hover { background: color-mix(in srgb, var(--ink) 85%, var(--margin)); border-color: color-mix(in srgb, var(--ink) 85%, var(--margin)); }

.btn-ghost { background: transparent; border-color: var(--ink); color: var(--ink); }
.btn-ghost:hover { background: var(--panel); }

.btn-quiet { background: transparent; border-color: var(--hair); color: var(--graphite); }
.btn-quiet:hover { border-color: var(--graphite); color: var(--ink); }

.btn[disabled] { opacity: .45; cursor: default; transform: none; }

/* ─────────────────────────  subject list  ───────────────────────── */

.subjects { list-style: none; margin: 0; padding: 0; }

.subject {
  width: 100%; text-align: left; background: none; cursor: pointer;
  border: 0; border-bottom: 1px solid var(--hair);
  padding: 1.05rem .5rem 1.05rem 0;
  display: grid; grid-template-columns: 1fr auto; gap: .3rem 1.2rem;
  align-items: center;
}
.subject:hover:not([disabled]) .subject-name { box-shadow: inset 0 -.6em 0 -.05em var(--mark); }
.subject:hover:not([disabled]) { background: linear-gradient(to right, var(--panel), transparent 70%); }

/* a subject with nothing due — resting, not finished, so no strike-through */
.subject[disabled] { cursor: default; opacity: .55; }

.subject-name {
  font-family: var(--sans); font-size: 1.22rem; font-weight: 650;
  letter-spacing: -.02em; grid-column: 1;
  transition: box-shadow .18s var(--ease);
  padding: 0 .12em;
  /* Grid items are blockified, so `display: inline` here is ignored and the
     box stretches the full column — which would draw the highlighter as a
     full-width bar under the text. Shrink it back to its content instead. */
  justify-self: start;
}
.subject-meta {
  grid-column: 1; font-family: var(--mono); font-size: .7rem;
  letter-spacing: .05em; color: var(--graphite); text-transform: uppercase;
}
.subject-right { grid-column: 2; grid-row: 1 / span 2; text-align: right; }

/* mastery drawn as a highlighter stroke, not a progress bar */
.swipe {
  width: 7.5rem; height: .8rem; background: var(--panel-2);
  border-radius: 3px 7px 4px 8px; overflow: hidden; margin-bottom: .3rem;
}
.swipe-fill {
  height: 100%; background: var(--mark);
  border-radius: 3px 8px 5px 7px;
  transform: rotate(-.5deg) scaleY(1.08);
  transform-origin: left center;
  transition: width .5s var(--ease);
}
.swipe-num {
  font-family: var(--mono); font-size: .72rem; color: var(--graphite);
  font-variant-numeric: tabular-nums;
}

/* ─────────────────────────  recent rounds  ───────────────────────── */

.rounds { list-style: none; margin: 0; padding: 0; font-family: var(--mono); font-size: .78rem; }
.rounds li {
  display: flex; gap: 1rem; padding: .45rem 0;
  border-bottom: 1px dotted var(--hair); color: var(--graphite);
}
.rounds .r-when { width: 6.5rem; flex: none; }
.rounds .r-what { flex: 1; color: var(--ink); }
.rounds .r-score { font-variant-numeric: tabular-nums; }

.empty {
  font-family: var(--mono); font-size: .8rem; color: var(--graphite);
  padding: .9rem 0; margin: 0;
}

/* ─────────────────────────  quiz  ───────────────────────── */

.sheet-quiz { padding-bottom: 2rem; }

.qhead { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.2rem; }
.qhead .eyebrow { margin: 0; }

.qmeter { margin-left: auto; display: flex; gap: 3px; }
.qmeter i {
  display: block; width: 12px; height: 5px; border-radius: 2px;
  background: var(--panel-2);
}
.qmeter i.hit { background: var(--pen-green); }
.qmeter i.miss { background: var(--pen-red); }
.qmeter i.now { background: var(--ink); }

.prompt-wrap { position: relative; margin-bottom: 1.6rem; }

.tag-followup {
  display: inline-block; margin: 0 0 .6rem;
  font-family: var(--mono); font-size: .64rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink);
  background: var(--mark); padding: .22rem .5rem; border-radius: 4px;
}

/* the question literally sits on ruled paper */
/* The repeating notebook rules that used to sit behind this text were
   removed deliberately: --rule is a blue that read as an underline on the
   text rather than as paper. The serif face, size and line-height stay —
   they were doing the typographic work, the gradient was only decoration.
   .rounds lost the same gradient, since half-ruled reads as a bug. */
.ruled {
  font-family: var(--serif);
  font-size: 1.32rem;
  line-height: var(--lh);
  padding: .25rem 0 0;
}
.ruled p { margin: 0; }
.ruled .math { font-family: var(--mono); font-size: .95em; letter-spacing: -.01em; }
.ruled .quote {
  display: block; font-style: italic; color: var(--graphite);
  padding-left: 1rem; border-left: 2px solid var(--rule);
}

/* choices */
.choices { display: grid; gap: .55rem; margin-bottom: 1.3rem; }

.choice {
  display: grid; grid-template-columns: auto 1fr; gap: .8rem; align-items: baseline;
  width: 100%; text-align: left; cursor: pointer;
  background: var(--panel); border: 1.5px solid transparent;
  border-radius: var(--r); padding: .8rem .95rem;
  font-family: var(--serif); font-size: 1.02rem; line-height: 1.45;
  position: relative; overflow: hidden;
  transition: border-color .14s, background-color .14s, transform .12s var(--ease);
}
.choice:hover { border-color: var(--graphite); }
.choice:active { transform: translateY(1px); }
.choice-key {
  font-family: var(--mono); font-size: .74rem; font-weight: 500;
  color: var(--graphite); border: 1px solid var(--hair);
  border-radius: 4px; padding: .1rem .38rem; align-self: center;
}
.choice-txt { position: relative; z-index: 1; }
.choice-txt .math { font-family: var(--mono); font-size: .95em; }

.choice[aria-checked="true"] { border-color: var(--ink); background: var(--panel-2); }
.choice[aria-checked="true"] .choice-key { border-color: var(--ink); color: var(--ink); }

/* after checking */
.choice.is-right { border-color: var(--pen-green); background: var(--tint-green); }
.choice.is-right .choice-key { border-color: var(--pen-green); color: var(--pen-green-ink); }
.choice.is-wrong { border-color: var(--pen-red); background: var(--tint-red); }
.choice.is-wrong .choice-key { border-color: var(--pen-red); color: var(--pen-red-ink); }
.choice[disabled] { cursor: default; }
.choice[disabled]:hover { border-color: transparent; }
.choice.is-right[disabled]:hover { border-color: var(--pen-green); }
.choice.is-wrong[disabled]:hover { border-color: var(--pen-red); }

/* highlighter swipe across the correct answer */
.choice.is-right::after {
  content: ""; position: absolute; left: 0; top: 50%;
  height: 1.5em; width: 0; transform: translateY(-50%) rotate(-.4deg);
  background: color-mix(in srgb, var(--mark) 55%, transparent);
  border-radius: 4px 9px 5px 10px;
  animation: swipe .42s var(--ease) forwards;
}
@keyframes swipe { to { width: 100%; } }

/* free-entry answers */
.entry { margin-bottom: 1.3rem; }
.entry-lbl {
  display: block; font-family: var(--mono); font-size: .66rem;
  text-transform: uppercase; letter-spacing: .12em; color: var(--graphite);
  margin-bottom: .4rem;
}
.entry-in {
  width: 100%; max-width: 22rem; font-family: var(--mono); font-size: 1.15rem;
  background: transparent; border: 0; border-bottom: 2px solid var(--edge);
  padding: .4rem .1rem; border-radius: 0;
}
.entry-in:focus { border-bottom-color: var(--ink); }
/* No outline:none here. It used to remove the ring on precisely the fields a
   typed-answer question needs, leaving a border-colour change as the only cue
   — the global :focus-visible rule now applies to these too. */

.entry-note {
  margin: .5rem 0 0; max-width: 30rem;
  font-family: var(--sans); font-size: .78rem; color: var(--graphite);
}
.entry-note code {
  font-family: var(--mono); font-size: .95em;
  background: var(--panel); border-radius: 3px; padding: .05em .3em;
}

.actions { display: flex; flex-wrap: wrap; gap: .6rem; align-items: center; }

.hintbox {
  margin-top: 1.2rem; padding: .85rem 1rem;
  background: color-mix(in srgb, var(--mark) 22%, var(--paper));
  border-left: 3px solid var(--mark-2); border-radius: 0 var(--r) var(--r) 0;
  font-size: .97rem;
}
.hintbox strong {
  font-family: var(--mono); font-size: .66rem; letter-spacing: .12em;
  text-transform: uppercase; display: block; margin-bottom: .25rem; color: var(--graphite);
}

/* end-round confirmation */

.confirm {
  padding: 1.05rem 1.2rem; border-radius: var(--r);
  background: var(--panel); border: 1.5px solid var(--margin);
  animation: rise .2s var(--ease);
}
.confirm-q {
  margin: 0 0 .3rem; font-family: var(--sans); font-weight: 700;
  font-size: 1.05rem; letter-spacing: -.015em;
}
.confirm-note {
  margin: 0 0 .9rem; font-size: .93rem; color: var(--graphite);
}
.confirm-row { display: flex; flex-wrap: wrap; gap: .6rem; }

/* verdict / explanation */
.verdict {
  margin-top: 1.6rem; padding: 1.15rem 1.25rem;
  border-radius: var(--r); background: var(--panel);
  border-left: 3px solid var(--graphite);
  animation: rise .26s var(--ease);
}
.verdict.good { border-left-color: var(--pen-green); }
.verdict.bad  { border-left-color: var(--pen-red); }
@keyframes rise { from { opacity: 0; transform: translateY(7px); } }

.verdict-head { display: flex; align-items: center; gap: .6rem; margin-bottom: .7rem; }
.verdict-mark { font-family: var(--mono); font-size: 1.15rem; line-height: 1; }
.verdict.good .verdict-mark { color: var(--pen-green); }
.verdict.bad  .verdict-mark { color: var(--pen-red); }
.verdict-title {
  margin: 0; font-family: var(--sans); font-weight: 700; font-size: 1.05rem;
  letter-spacing: -.015em;
}
.verdict-body { font-size: 1rem; }
.verdict-body p { margin: 0 0 .7rem; }
.verdict-body p:last-child { margin-bottom: 0; }
.verdict-body .math { font-family: var(--mono); font-size: .93em; }
.verdict-body .step {
  display: block; font-family: var(--mono); font-size: .9em;
  padding: .1rem 0 .1rem .9rem; border-left: 2px solid var(--rule);
  margin: .35rem 0;
}
.verdict-skill {
  font-family: var(--mono); font-size: .68rem; text-transform: uppercase;
  letter-spacing: .1em; color: var(--graphite); margin: .9rem 0 1rem;
}
.verdict .btn { margin-top: .2rem; }

/* ─────────────────────────  results  ───────────────────────── */

.scorecard {
  display: flex; align-items: baseline; gap: .5rem;
  font-family: var(--mono); margin: 0 0 1.6rem;
}
.score-big { font-size: 3.4rem; font-weight: 500; letter-spacing: -.04em; line-height: 1; }
.score-of { font-size: 1.1rem; color: var(--graphite); }
.score-pct {
  margin-left: auto; font-size: .8rem; color: var(--graphite);
  text-transform: uppercase; letter-spacing: .1em;
}

.reviewlist { list-style: none; margin: 0 0 2rem; padding: 0; }
.reviewlist li {
  display: grid; grid-template-columns: 1.4rem 1fr; gap: .7rem;
  padding: .6rem 0; border-bottom: 1px dotted var(--hair);
  font-size: .95rem; align-items: baseline;
}
.reviewlist .rv-mark { font-family: var(--mono); }
.reviewlist .rv-mark.ok { color: var(--pen-green); }
.reviewlist .rv-mark.no { color: var(--pen-red); }
.reviewlist .rv-skill {
  display: block; font-family: var(--mono); font-size: .66rem;
  text-transform: uppercase; letter-spacing: .1em; color: var(--graphite);
  margin-top: .12rem;
}

/* ─────────────────────────  stats  ───────────────────────── */

.statgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 1px; background: var(--hair); border: 1px solid var(--hair);
  border-radius: var(--r); overflow: hidden; margin-bottom: 1rem;
}
.stat { background: var(--paper); padding: 1rem .95rem; }
.stat-n {
  font-family: var(--mono); font-size: 1.85rem; font-weight: 500;
  letter-spacing: -.03em; line-height: 1.1; display: block;
  font-variant-numeric: tabular-nums;
}
.stat-l {
  font-family: var(--mono); font-size: .62rem; text-transform: uppercase;
  letter-spacing: .13em; color: var(--graphite);
}
/* the "/ 216" after a count — deliberately not .stat-l, which labels the tile */
.stat-sub { font-size: .55em; color: var(--graphite); letter-spacing: 0; }

/* ── the score estimate ──
   Printed like the top of a score report: the total large, the two section
   scores under it, and — the part a real report does not have — a bar saying
   how much of each number is evidence rather than the 500 it was seeded
   with. */
.scorepanel {
  border: 1px solid var(--hair); border-radius: var(--r);
  padding: 1.15rem 1.2rem; margin-bottom: 1.2rem;
  background: linear-gradient(to bottom, var(--panel), transparent 60%);
}
.score-total {
  display: flex; align-items: baseline; gap: .5rem;
  font-family: var(--mono); margin-bottom: 1rem;
}
.score-tag {
  margin-left: auto; font-family: var(--mono); font-size: .62rem;
  text-transform: uppercase; letter-spacing: .13em; color: var(--graphite);
}
.score-row {
  display: grid; grid-template-columns: 1fr 3.2rem 5rem; gap: .3rem .9rem;
  align-items: center; padding: .5rem 0; border-top: 1px dotted var(--hair);
}
.score-sec { font-family: var(--sans); font-weight: 650; font-size: .98rem; letter-spacing: -.015em; }
.score-val {
  font-family: var(--mono); font-size: 1.25rem; text-align: right;
  font-variant-numeric: tabular-nums;
}
.score-bar {
  grid-column: 3; grid-row: 1;
  height: .45rem; background: var(--panel-2); border-radius: 3px; overflow: hidden;
}
.score-bar i { display: block; height: 100%; background: var(--graphite); }
.score-bar.is-firm i { background: var(--pen-green); }
.score-conf {
  grid-column: 1 / -1; grid-row: 2;
  font-family: var(--mono); font-size: .62rem; text-transform: uppercase;
  letter-spacing: .1em; color: var(--graphite);
}
.score-note {
  margin: .9rem 0 0; font-size: .88rem; color: var(--graphite); max-width: 34rem;
}

@media (max-width: 640px) {
  .score-row { grid-template-columns: 1fr 3rem; }
  .score-bar { grid-column: 1 / -1; grid-row: 2; }
  .score-conf { grid-row: 3; }
}

.skills { list-style: none; margin: 0; padding: 0; }
.skills li {
  display: grid; grid-template-columns: 1fr 7rem 3.2rem; gap: .9rem;
  align-items: center; padding: .55rem 0; border-bottom: 1px dotted var(--hair);
}
.sk-name { font-size: .97rem; min-width: 0; }
.sk-sub {
  display: block; font-family: var(--mono); font-size: .62rem;
  text-transform: uppercase; letter-spacing: .1em; color: var(--graphite);
}
.sk-num {
  font-family: var(--mono); font-size: .78rem; text-align: right;
  color: var(--graphite); font-variant-numeric: tabular-nums;
}
.skills .swipe { margin-bottom: 0; width: 100%; }
.sk-cold .swipe-fill { background: var(--panel-2); }

.subjhead {
  font-family: var(--sans); font-weight: 700; font-size: 1.05rem;
  letter-spacing: -.02em; margin: 1.6rem 0 .4rem;
}

/* ─────────────────────────  faq  ───────────────────────── */

/* A glossary set the way a student annotates a textbook: the term hangs out
   into the red margin, the explanation sits in the body column. The red tick
   is the same signal as the margin rule on every other page, so a definition
   reads as something written in, not printed. */
.faq { margin: 0 0 1rem; }

.faq dt {
  position: relative;
  font-family: var(--sans); font-weight: 700; font-size: 1.05rem;
  letter-spacing: -.015em; color: var(--ink);
  margin: 1.9rem 0 .5rem;
}
.faq dt:first-of-type { margin-top: 0; }
.faq dt::before {
  content: ""; position: absolute;
  left: calc(var(--sheet-pad) * -1); top: .3em;
  width: 3px; height: 1.05em; border-radius: 1px;
  background: var(--margin);
}

.faq dd {
  margin: 0; max-width: 34rem;
  font-family: var(--serif); font-size: 1rem; line-height: 1.62;
  color: var(--graphite);
}
.faq dd p { margin: 0 0 .7rem; }
.faq dd p:last-child { margin-bottom: 0; }
.faq dd strong { color: var(--ink); font-weight: 600; }
.faq dd em { color: var(--ink); font-style: normal; font-weight: 600; }

/* the rest schedule, printed like the table it is */
.ladder {
  border-collapse: collapse; margin: 1rem 0 1.1rem;
  font-family: var(--mono); font-size: .74rem;
}
.ladder caption {
  text-align: left; color: var(--graphite);
  font-size: .68rem; text-transform: uppercase; letter-spacing: .16em;
  padding-bottom: .5rem;
}
.ladder th, .ladder td {
  text-align: left; padding: .38rem 1.4rem .38rem 0;
  border-bottom: 1px solid var(--hair); white-space: nowrap;
}
.ladder th {
  font-weight: 500; color: var(--graphite);
  text-transform: uppercase; letter-spacing: .08em; font-size: .66rem;
}
.ladder td { color: var(--ink); font-variant-numeric: tabular-nums; }
.ladder tbody tr:last-child td { border-bottom: none; }

/* The top rung is the goal, so it is marked rather than left to blend in. */
.ladder tbody tr:last-child td:first-child {
  box-shadow: inset 0 -.55em 0 -.05em var(--mark);
}

/* ─────────────────────────  footer  ───────────────────────── */

.foot {
  border-top: 1px solid var(--hair);
  padding: 1.5rem 2rem 2.5rem;
  max-width: calc(var(--sheet-max) + var(--rail-w) + 4rem);
  margin: 0 auto;
  font-family: var(--mono); font-size: .7rem; color: var(--graphite);
}
.foot p { margin: 0 0 .35rem; }

/* Global, not .foot-scoped — the FAQ names the same keys the footer does, and
   a key should look like a key wherever it is mentioned. */
kbd {
  font-family: var(--mono); font-size: .95em;
  border: 1px solid var(--hair); border-bottom-width: 2px;
  border-radius: 4px; padding: 0 .3em; color: var(--ink);
}

/* ─────────────────────────  responsive  ───────────────────────── */

@media (max-width: 640px) {
  /* 2.6rem left ~34px of usable rail once padding was taken, which capped the
     Hint and End round buttons at 32px wide — over the 24px WCAG 2.5.8 floor
     but well under the 44px that stops a thumb catching the wrong one when
     both are stacked. 3.4rem buys the width back and costs the text column
     about 13px, which is the better side of that trade on the one screen a
     student taps repeatedly. */
  :root { --rail-w: 3.4rem; --sheet-pad: .9rem; }
  body { font-size: 16px; }
  .page { padding: 1.6rem 1rem 3rem; }
  .rail { padding-right: .5rem; }
  .rail-num { font-size: 1.05rem; }
  .rail-lbl { font-size: .5rem; letter-spacing: .08em; }
  .tally { max-width: 1.9rem; gap: 3px; }
  .ruled { font-size: 1.15rem; }
  .subject { grid-template-columns: 1fr; }
  .subject-right { grid-column: 1; grid-row: auto; text-align: left; margin-top: .4rem; }
  .swipe { width: 6rem; }
  .skills li { grid-template-columns: 1fr 4.5rem 2.8rem; gap: .6rem; }
  .foot { padding: 1.25rem 1rem 2rem; }
  .btn { width: 100%; justify-content: space-between; }
  .actions .btn, .quick .btn { flex: 1 1 100%; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
  .choice.is-right::after { width: 100%; }
}

@media print { .topbar, .foot, .actions, .rail { display: none; } }

/* the sign-in form's feedback line */
.account-msg {
  margin: .9rem 0 0; font-family: var(--sans); font-size: .9rem;
  color: var(--graphite);
}
.account-msg.is-bad { color: var(--pen-red); font-weight: 600; }
#account-form .entry { max-width: 22rem; }

/* where progress is being saved — never let this fail silently */
.storage-mode { margin: 0 0 .35rem; }
.storage-mode.is-none {
  color: var(--pen-red); font-weight: 600;
}
.storage-mode.is-browser { color: var(--graphite); }
.storage-mode.is-supabase { color: var(--pen-green); }

/* ─────────────────────────  reward picture  ───────────────────────── */

.rw { display: flex; align-items: flex-start; gap: 1rem; flex-wrap: wrap; }

/* exactly 20 x 20 cells of 10px — a true 200x200 image */
.rw-grid {
  width: 200px; height: 200px;
  display: grid;
  grid-template-columns: repeat(10, 20px);
  grid-template-rows: repeat(10, 20px);
  background: #fff;                     /* white behind, so only the sprite reads */
  border-radius: 4px;
  overflow: hidden;
  flex: none;
}
/* The finished-picture grid sizes its cells as percentages so it can carry
   20 columns in the same box; these fixed sizes are for the 10-tile reveal
   only, hence the :not(). Leaving them to specificity would break the day
   someone adds a more specific ancestor rule. */
.rw-grid:not(.rw-art) i { display: block; width: 20px; height: 20px; }

/* A covered cell is simply white — no grid, no outline. The sprite appears to
   materialise out of a blank square rather than filling in a checkerboard. */
.rw-off { background: transparent; }
.rw-on  { animation: rw-in .35s var(--ease); }
.rw-new { animation: rw-pop .6s var(--ease); }

@keyframes rw-in  { from { opacity: 0; } }
@keyframes rw-pop {
  0%   { transform: scale(.4); opacity: 0; }
  60%  { transform: scale(1.25); }
  100% { transform: scale(1); opacity: 1; }
}

.rw-meta { display: flex; flex-direction: column; gap: .2rem; padding-top: .1rem; }
.rw-name {
  font-family: var(--sans); font-weight: 700; font-size: 1.02rem;
  letter-spacing: -.015em;
}
.rw-count {
  font-family: var(--mono); font-size: .78rem; color: var(--graphite);
  font-variant-numeric: tabular-nums;
}
.rw-note { font-size: .9rem; color: var(--graphite); max-width: 15rem; }

/* the compact version that sits under a question */
/* In the quiz it lives in the left rail, beside every question, so progress is
   visible without taking room from the question itself. */
.rw-mini { display: block; margin-top: 1rem; }
.rw-mini .rw { flex-direction: column; gap: .3rem; align-items: flex-end; }
.rw-mini .rw-grid {
  width: 60px; height: 60px;
  grid-template-columns: repeat(10, 6px); grid-template-rows: repeat(10, 6px);
  border-radius: 3px;
}
.rw-mini .rw-grid:not(.rw-art) i { width: 6px; height: 6px; }
.rw-mini .rw-meta { align-items: flex-end; gap: 0; }
.rw-mini .rw-name { font-size: .6rem; font-family: var(--mono);
  text-transform: uppercase; letter-spacing: .08em; color: var(--graphite);
  font-weight: 500; }
.rw-mini .rw-count { font-size: .6rem; }
.rw-mini .rw-banner { font-size: .62rem; padding: .05rem .25rem; align-self: flex-end; }

@media (max-width: 640px) {
  .rw-mini .rw-grid { width: 40px; height: 40px;
    grid-template-columns: repeat(10, 4px); grid-template-rows: repeat(10, 4px); }
  .rw-mini .rw-grid:not(.rw-art) i { width: 4px; height: 4px; }
  /* Both captions stay. The name of a finished picture is the payoff for
     having covered it up, and the count is what ticks up between questions;
     at .6rem they stack under a 40px sprite without crowding the question. */
}

@media (prefers-reduced-motion: reduce) {
  .rw-on, .rw-new { animation: none; }
}

/* ── a finished picture: full 20×20 detail, and it moves ── */

/* The reveal grid is 10 tiles across; the finished artwork is 20 cells across
   in the same 200px, so the sprite sharpens the moment the last tile comes
   off. Both frames occupy the same grid cell and take turns. */
.rw-art { position: relative; display: block; padding: 0; }
.rw-frame {
  position: absolute; inset: 0;
  display: grid;
  grid-template-columns: repeat(20, 5%); grid-template-rows: repeat(20, 5%);
  animation: rw-frame 1s steps(1, end) infinite;
  animation-delay: calc(var(--f) * -0.5s);
}
.rw-frame i { display: block; width: 100%; height: 100%; }

/* Two frames, half a second each: frame 0 shows for the first half of the
   cycle, frame 1 for the second, using the negative delay above to offset
   them. steps(1) keeps it a hard cut — a cross-fade would read as a blur
   rather than as animation. */
@keyframes rw-frame {
  0%, 50%   { opacity: 1; }
  50.01%, 100% { opacity: 0; }
}

/* ── completion: the finished sprite plays for three seconds ── */

/* The name belongs directly under the picture it names, not off to one side. */
.rw-done { flex-direction: column; align-items: center; gap: .55rem; }
.rw-done .rw-meta { align-items: center; text-align: center; }
.rw-done .rw-name { font-size: 1.15rem; }
.rw-mini .rw-done .rw-name {
  font-size: .68rem; font-family: var(--sans); text-transform: none;
  letter-spacing: -.01em; color: var(--ink); font-weight: 700;
}
.rw-done .rw-banner { align-self: center; }

.rw-done .rw-grid {
  animation: rw-celebrate .5s var(--ease) infinite alternate;
  border-color: var(--mark-2);
  box-shadow: 0 0 0 3px var(--mark);
}
@keyframes rw-celebrate {
  from { transform: scale(1)    rotate(-1.2deg); }
  to   { transform: scale(1.06) rotate(1.2deg); }
}

.rw-banner {
  font-family: var(--sans); font-weight: 700; font-size: 1.15rem;
  letter-spacing: -.02em; color: var(--ink);
  align-self: flex-start;
  background: var(--mark); border-radius: 4px; padding: .1rem .45rem;
  animation: rw-flash .45s steps(2) 6;
}
@keyframes rw-flash { 50% { opacity: .35; } }

/* ── the gallery of pictures already finished ── */

.rw-gallery { display: flex; flex-wrap: wrap; gap: 1.1rem; }
.rw-gallery .rw { flex-direction: column; gap: .4rem; }
.rw-gallery .rw-grid {
  width: 100px; height: 100px;
  grid-template-columns: repeat(10, 10px); grid-template-rows: repeat(10, 10px);
}
.rw-gallery .rw-grid:not(.rw-art) i { width: 10px; height: 10px; }
.rw-gallery .rw-name { font-size: .82rem; }

@media (prefers-reduced-motion: reduce) {
  .rw-done .rw-grid, .rw-banner { animation: none; }
}


/* ── the school's shared weekly picture ──
   Drawn to a canvas at one device pixel per logo pixel, then scaled up with
   pixelated rendering so a 102x102 mark stays crisp rather than being
   smoothed into mush. */
.school { display: flex; gap: 1.4rem; flex-wrap: wrap; align-items: flex-start; }
.school-canvas {
  width: 208px; height: 208px; flex: none;
  image-rendering: pixelated;
  border: 1px solid var(--hair); border-radius: 6px; background: #F6F8FA;
}
.school-meta { min-width: 14rem; }
.school-name {
  font-family: var(--sans); font-weight: 700; font-size: 1.1rem;
  letter-spacing: -.02em; margin: 0 0 .3rem;
}
.school-stat {
  font-family: var(--mono); font-size: .78rem; color: var(--graphite);
  margin: 0 0 .2rem; font-variant-numeric: tabular-nums;
}
/* Your own share, called out — with a roster of three hundred, a student who
   cannot see their own contribution has no reason to believe it mattered. */
.school-mine {
  font-family: var(--sans); font-weight: 650; font-size: .95rem;
  color: var(--pen-green); margin: .5rem 0 0;
}

.roster { list-style: none; margin: 0; padding: 0; }
.roster li {
  display: grid; grid-template-columns: 1fr 5rem 6rem auto; gap: .8rem;
  align-items: center; padding: .5rem 0; border-bottom: 1px dotted var(--hair);
  font-size: .92rem;
}
.roster .r-mail { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.roster .r-num {
  font-family: var(--mono); font-size: .78rem; color: var(--graphite);
  text-align: right; font-variant-numeric: tabular-nums;
}
.roster select { font-size: .78rem; }
.roster .r-quiet { color: var(--pen-red); }

@media (max-width: 640px) {
  .school-canvas { width: 100%; height: auto; aspect-ratio: 1; }
  .roster li { grid-template-columns: 1fr auto; }
}

/* ═══════════════════════════════════════════════════════════
   connection bar

   Shown when the network drops, because the app carries on without one and
   a student who is not told will assume their work is being lost. Sits above
   everything and does not shift the layout under a question mid-answer.
   ═══════════════════════════════════════════════════════════ */
.connbar {
  position: sticky;
  top: 0;
  z-index: 40;
  margin: 0;
  padding: .55rem var(--sheet-pad);
  font: 500 .9rem/1.4 var(--sans);
  text-align: center;
  border-bottom: 1px solid var(--hair);
}
.connbar.is-off  { background: var(--tint-red);   color: var(--ink); }
.connbar.is-back { background: var(--tint-green); color: var(--ink); }

@media (prefers-reduced-motion: no-preference) {
  .connbar { animation: connbar-in .18s var(--ease) both; }
  @keyframes connbar-in { from { opacity: 0; transform: translateY(-100%); } }
}

/* ═══════════════════════════════════════════════════════════
   the front page is the same sheet of paper as the practice page

   The quiz view's signature is prose in the serif register sitting on the
   blue rules — that is what makes the app look like a notebook rather than
   a dashboard. The front page was sans-serif on plain white, which read as
   a different product entirely.

   The big headline stays in the sans "workbook cover" register; it is the
   cover, not the page. What moves onto the paper is the prose beneath it
   and the round history, so the eye meets the same surface before and
   during practice.
   ═══════════════════════════════════════════════════════════ */
.hero-sub.ruled {
  /* A shade smaller than a question: this is the caption on the cover, not
     the text being studied, and matching the question size exactly made the
     hero read as two competing headlines. */
  font-size: 1.12rem;
  max-width: 34rem;
  color: var(--graphite);
}

/* Round history on the rules too, so the page below the fold is the same
   surface as the one above it. */
.rounds {
  list-style: none; margin: 0; padding: .25rem 0 0;
  font-family: var(--serif); font-size: 1.02rem;
  line-height: var(--lh);
}
.rounds li {
  display: grid; grid-template-columns: 7rem 1fr auto; gap: .8rem;
  align-items: baseline;
}
.rounds .r-when { font-family: var(--mono); font-size: .74rem; color: var(--graphite); }
.rounds .r-score { font-family: var(--mono); font-size: .82rem; }

.empty { font-family: var(--serif); color: var(--graphite); margin: .3rem 0 0; }

/* An inline "actually, I do have a code" control. A button because it acts,
   not navigates, but it reads as part of the sentence around it. */
.linkish {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: var(--ink);
  text-decoration: underline; text-decoration-color: var(--mark-2);
  text-decoration-thickness: 2px; text-underline-offset: 3px;
}
.linkish:hover { text-decoration-color: var(--ink); }

/* ── the top bar on a phone ────────────────────────────────────────
   Signed in at 406px the bar overflowed by 2px, so the whole page scrolled
   sideways, and the brand collapsed onto two lines — "My / Prep" — because
   nothing stopped it wrapping as the flex row ran out of room. Six things
   share that bar once somebody is signed in: brand, Practice, Progress, FAQ,
   the theme dot and the account menu.

   Tightened rather than hidden. Every item is still reachable, which matters
   more than elegance on the one screen a student cannot avoid, and none of the
   tap targets drops below the 24px WCAG 2.5.8 floor — measured, not assumed. */
@media (max-width: 640px) {
  .topbar-in { padding: .5rem .7rem; gap: .5rem; }
  .navlink { font-size: .74rem; padding: .45rem .42rem; letter-spacing: .02em; }
  .navlink.icon { padding: .4rem; }
  .brand { font-size: .9rem; gap: .45rem; }
  /* The bar is the one row that must never be the reason the page scrolls. */
  .topnav { gap: 0; min-width: 0; }
}

/* Below this the three words do not fit next to the brand at any weight, so
   the brand becomes its mark alone. The mark is the red-ruled sheet, which is
   the app's signature and reads as the logo without the words. */
@media (max-width: 400px) {
  .brand-txt { display: none; }
}

/* ── touch ─────────────────────────────────────────────────────────
   Applied to everything tappable rather than element by element, because the
   one that gets forgotten is always the one a student taps most.

   touch-action: manipulation removes the ~300ms delay iOS holds every tap for
   while it waits to see whether a second tap is coming. Nothing here responds
   to a double-tap, so the wait buys nothing and costs a third of a second on
   every answer.

   The tap highlight is set deliberately rather than left default: iOS paints a
   translucent grey block over the whole element on touch, which on .choice —
   the answer button — flashes across the option text. :active and :hover
   already show the press, so the system flash is redundant. */
.btn, .navlink, .choice, .subject, .linkish, .brand,
button, [role="button"], summary {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

/* ── notch and home indicator ──────────────────────────────────────
   index.html sets viewport-fit=cover, which is what lets the page paint edge
   to edge — and also what puts content under the notch, the rounded corners
   and the home indicator unless these insets are honoured. Declaring cover
   without the insets is strictly worse than not declaring it.

   env() resolves to 0px on every device without a cutout, so these need no
   media query. */
.topbar-in {
  padding-left: max(1.25rem, env(safe-area-inset-left));
  padding-right: max(1.25rem, env(safe-area-inset-right));
}
.page, .plainpage {
  padding-left: max(2rem, env(safe-area-inset-left));
  padding-right: max(2rem, env(safe-area-inset-right));
}
body {
  /* The home indicator sits over the last ~34px. Without this the final answer
     button on a round is under it. */
  padding-bottom: env(safe-area-inset-bottom);
}

@media (max-width: 640px) {
  .topbar-in {
    padding-left: max(.7rem, env(safe-area-inset-left));
    padding-right: max(.7rem, env(safe-area-inset-right));
  }
  .page, .plainpage {
    padding-left: max(1.1rem, env(safe-area-inset-left));
    padding-right: max(1.1rem, env(safe-area-inset-right));
  }
}

/* Headings set their own rag where a hard <br> is not used. */
.hero-h, h1, h2 { text-wrap: balance; }

/* The picture's progress count, hidden in the quiz rail only.
   The grid itself already shows how far along it is — that is the whole
   point of uncovering an image — and a number beside it turns a reward into
   another target to watch while answering. The count stays on Progress,
   where the picture is the subject rather than the scenery. */
.rw-mini .rw-count { display: none; }

/* End round, demoted. Small, quiet, and in the margin with the counters
   rather than in the row of things to press. */
.rail-quit {
  margin-top: 1rem;
  font-size: .68rem;
  padding: .3rem .5rem;
  white-space: nowrap;
}
@media (max-width: 640px) {
  /* The rail is a 42px margin strip on a phone, and "End round" on one line
     is 70-odd. nowrap kept the box at 32px and let the text spill outside it,
     which measured as no overflow and looked broken. Wrapping to two short
     lines fits the strip and needs no second label to keep in step. */
  .rail-quit {
    font-size: .6rem;
    padding: .25rem .3rem;
    margin-top: .75rem;
    white-space: normal;
    line-height: 1.15;
    max-width: 100%;
    /* 24px is the WCAG 2.5.8 floor; two wrapped lines clear it comfortably,
       but say so rather than rely on the line height happening to. */
    min-height: 24px;
  }
}

/* ── the quiz screen on a phone ────────────────────────────────────
   A reading question is a passage, four options and the controls, and on a
   715px screen the three came to 1,036px — 321px past the fold. Scrolling
   between the passage and the options is the one thing this screen should
   not ask for, because the student is holding the passage in their head
   while they read the options.

   Everything below is trimmed padding and type, not content. The passage is
   never abridged and no option is truncated. */
@media (max-width: 640px) {
  .page { padding-top: 1rem; padding-bottom: 1.5rem; }

  /* 76px per option, four of them, is where the height actually goes. */
  .choice { padding: .55rem .7rem; font-size: .96rem; line-height: 1.35; gap: .55rem; }
  .choices { gap: .4rem; margin-bottom: .85rem; }

  #q-prompt { font-size: 1.06rem; line-height: 1.42; }
  .actions { gap: .45rem; }
  .actions .btn { padding: .6rem 1rem; }
}

/* Both rail buttons fill the rail and centre their label. Left as inline
   boxes they sat right-aligned against right-aligned numerals, which read as
   crooked even though the text inside was already centred. */
.rail-quit {
  width: 100%;
  text-align: center;
  display: block;
  /* 44px is the comfortable target, not the 24px minimum. These two sit
     directly above one another in a narrow column, so the failure being
     designed out is catching End round while reaching for Hint. */
  min-height: 44px;
}
/* Keeps a thumb's worth of dead space between the two, so a near miss lands
   on neither rather than on the wrong one. */
#btn-hint + .rail-quit { margin-top: .55rem; }

/* The date beside a sent invitation. Quieter than the address, which is the
   part being scanned for. */
.invite-when { opacity: .7; }
