/* NO LOOK TYPING — the look.
   A calm printed-page palette a school, a parent and a 13-year-old can all
   sit in front of. The one deliberately loud thing is the KEYBOARD: neon
   letters on dark keycaps, which reads as a backlit board under a daylight
   page — and which Bennett asked to keep. No webfonts: on a school
   Chromebook the page has to be up instantly, every time. */

:root {
  --ground: #eceef0;
  --card: #f8f9fa;
  --card-2: #e2e6ea;
  --line: #7d848a;   /* measured 3.06:1 on card, 3.31:1 on ground */
  --ink: #16202a;
  --soft: #4b5a68;
  --dim: #4f5d6b;   /* 5.38:1 on card-2, where 12px notes live */   /* WCAG AA on card, ground AND card-2; #7b8894 failed all three */
  --accent: #0e5b60;
  --accent-ink: #ffffff;   /* text that sits ON the accent */
  --bad-ink: #ffffff;
  --accent-2: #12787f;
  --good: #1d6b43;
  --bad: #9a2a20;
  --warn: #7a5410;
  --gold: #7a5a10;
  --shadow: 0 1px 2px rgba(20, 30, 40, 0.06), 0 6px 18px rgba(20, 30, 40, 0.06);

  --board: #10151c;
  --board-2: #1b2430;
  --board-line: #2b3949;
  --neon: #45d6d6;
  --neon-2: #6ff0e6;

  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;

  --gap: 18px;
  --radius: 10px;
}

[data-theme="midnight"] {
  /* dark ink ON the bright accent: white on #45d6d6 is 1.77:1 */
  --accent-ink: #06120d;
  --bad-ink: #2a0705;      /* white on the midnight red is 2.85:1 */
  --ground: #0b1017;
  --card: #131b25;
  --card-2: #1b2530;
  --line: #59708a;   /* measured 3.09:1 on the midnight card */
  --ink: #e8eef4;
  --soft: #a3b2c0;
  --dim: #8b9aa8;   /* AA on the midnight panels */
  --accent: #45d6d6;
  --accent-2: #6ff0e6;
  --good: #56c98a;
  --bad: #f0736b;
  --warn: #e5b45c;
  --gold: #e5c05c;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.3);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

button {
  font: inherit;
  color: inherit;
  cursor: pointer;
  border: 1px solid var(--line);
  background: var(--card);
  border-radius: var(--radius);
  padding: 10px 16px;
  transition: border-color 0.12s, background 0.12s, transform 0.06s;
}
button:hover:not(:disabled) { border-color: var(--accent); }
button:active:not(:disabled) { transform: translateY(1px); }
button:disabled { opacity: 0.45; cursor: default; }
button:focus-visible { outline: 3px solid var(--accent-2); outline-offset: 2px; }

h1, h2, h3 { margin: 0; text-wrap: balance; letter-spacing: -0.01em; }
p { margin: 0; }

/* Tim: "most sites use the whole space". They do — but a reading measure has
   a limit: past about 90 characters a line the eye loses its place coming
   back. So the SHELL goes wide and the dense panels get more room, while the
   text inside them stays readable. */
.wrap { max-width: 1680px; margin: 0 auto; padding: 0 32px 60px; }
@media (max-width: 1200px) { .wrap { padding: 0 20px 60px; } }

/* ------------------------------------------------------------ the header */

.top {
  display: flex;
  align-items: center;
  gap: var(--gap);
  flex-wrap: wrap;
  padding: 18px 0 14px;
}
.logo { margin: 0;
  font-size: 22px;
  font-weight: 650;
  letter-spacing: 0.14em;
}
.logo span { color: var(--accent); }
.brand { margin-right: 4px; }
.tagline {
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--dim);
  margin-top: -2px;
}
.who {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--soft);
  flex-wrap: wrap;
}
.who b { color: var(--ink); font-weight: 600; }
.pill {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 12px;
  letter-spacing: 0.04em;
}
.today {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--soft);
}
.meter {
  width: 140px;
  height: 8px;
  background: var(--card-2);
  border-radius: 999px;
  overflow: hidden;
}
.meter i { display: block; height: 100%; background: var(--accent); }

/* -------------------------------------------------------------- the tabs */

.tabs {
  display: flex;
  gap: 6px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 22px;
  flex-wrap: wrap;
}
.tabs button {
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: var(--radius) var(--radius) 0 0;
  background: transparent;
  color: var(--soft);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.08em;
  padding: 10px 18px;
  margin-bottom: -1px;
}
.tabs button[aria-selected="true"] {
  background: var(--card);
  border-color: var(--line);
  border-bottom: 1px solid var(--card);
  color: var(--ink);
}

/* ------------------------------------------------------------- the cards */

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: var(--shadow);
}
.card > p.note { max-width: 92ch; }
.card h2 {
  font-size: 12px;
  letter-spacing: 0.12em;
  color: var(--dim);
  font-weight: 650;
  margin-bottom: 10px;
}
.grid { display: grid; gap: var(--gap); }
.cols-3 { grid-template-columns: repeat(3, 1fr); }
.cols-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1280px) { .cols-4 { grid-template-columns: repeat(2, 1fr); } }
.cols-2 { grid-template-columns: 1fr 1fr; }
@media (max-width: 900px) {
  .cols-3, .cols-2 { grid-template-columns: 1fr; }
}

.hero { display: flex; gap: var(--gap); align-items: stretch; flex-wrap: wrap; }
.hero .card { flex: 1 1 420px; }
.hero .go {
  flex: 0 0 300px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  justify-content: center;
}
.big {
  background: var(--accent);
  border-color: var(--accent);
  /* NOT #fff. In midnight --accent flips to a bright cyan and white on it is
     1.77:1 — the single most important button in the app, close to illegible.
     A token that flips with the theme fixes it in both directions at once. */
  color: var(--accent-ink);
  font-size: 19px;
  font-weight: 650;
  letter-spacing: 0.06em;
  padding: 20px;
}
.big:hover:not(:disabled) { background: var(--accent-2); border-color: var(--accent-2); }
.secondary { font-size: 13px; color: var(--soft); text-align: center; }
.secondary button {
  background: none;
  border: none;
  padding: 2px;
  color: var(--accent);
  text-decoration: underline;
  font-size: 13px;
}

.hero h3 { font-size: 26px; margin-bottom: 4px; }
.hero .sub { color: var(--soft); font-size: 14px; max-width: 70ch; }
.tag {
  display: inline-block;
  font-size: 11px;
  letter-spacing: 0.1em;
  font-weight: 650;
  color: var(--accent);
  margin-bottom: 8px;
}

/* rows you pick from */
.rows { display: flex; flex-direction: column; gap: 6px; }
.row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  text-align: left;
  width: 100%;
  padding: 9px 12px;
  font-size: 14px;
  background: var(--card-2);
  border-color: transparent;
}
.row .name { font-weight: 600; }
.row .note { color: var(--dim); font-size: 12px; margin-left: auto; white-space: nowrap; }
.row[aria-pressed="true"] {
  background: var(--card);
  border-color: var(--accent);
  box-shadow: inset 3px 0 0 var(--accent);
}
.row:disabled { opacity: 0.55; }
.row.won .name::after {
  content: " PASSED";
  color: var(--good);
  font-size: 11px;
  letter-spacing: 0.08em;
}

.blurb { font-size: 13px; color: var(--soft); margin-top: 10px; max-width: 78ch; }

/* four pips per level: one for each difficulty you have passed it on */
.pips { margin-left: auto; display: flex; gap: 4px; align-items: center; }
.pips i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  display: block;
  border: 1px solid var(--line);
}
.pips i.on { background: var(--good); border-color: var(--good); }

/* ------------------------------------------------------------- the stats */

.figures { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.fig .n { font-size: 30px; font-weight: 650; font-variant-numeric: tabular-nums; }
.fig .l {
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--dim);
  text-transform: uppercase;
}
.fig .n.good { color: var(--good); }

table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 7px 8px; border-bottom: 1px solid var(--line); }
th { font-size: 11px; letter-spacing: 0.08em; color: var(--dim); font-weight: 650; }
td.num { text-align: right; font-variant-numeric: tabular-nums; }

.bar { height: 8px; background: var(--card-2); border-radius: 999px; overflow: hidden; }
.bar i { display: block; height: 100%; background: var(--accent); }
.bar i.good { background: var(--good); }
.bar i.bad { background: var(--bad); }

/* ------------------------------------------------------------- the board */

.board {
  position: relative;
  background: var(--board);
  border: 1px solid var(--board-line);
  border-radius: 12px;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  align-items: center;
  user-select: none;
}
.krow { display: flex; gap: 7px; }
.key {
  width: 44px;
  height: 44px;
  border-radius: 7px;
  background: #243244;
  border: 1px solid #3b506a;
  color: var(--neon);
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 14px;
  transition: transform 0.07s, box-shadow 0.12s, color 0.12s;
}
.key.wide { width: 250px; }
.key { text-shadow: 0 0 10px rgba(69, 214, 214, 0.5); font-weight: 600; }
.key.home { box-shadow: inset 0 -3px 0 var(--neon-2); }
.key.next {
  color: #06121a;
  font-weight: 700;
  transform: translateY(-2px);
}
.key.hit { animation: pop 0.22s ease-out; }
.key.miss { animation: shake 0.24s ease-out; background: #4a1c19; color: #ffb4ad; }
@keyframes pop {
  0% { transform: scale(1); }
  40% { transform: scale(1.16); box-shadow: 0 0 0 6px rgba(90, 230, 200, 0.18); }
  100% { transform: scale(1); }
}
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}
.board.hidden .key { color: transparent; }
.board.hidden .key.next { color: transparent; }

/* the home key this finger has to come back to */
.key.from {
  border-width: 2px;
  border-style: solid;
  background: rgba(255, 255, 255, 0.10);
  box-shadow: 0 0 0 3px currentColor inset;
  font-weight: 700;
}

/* the arrow from the home key to the key you owe */
/* the arrow has to sit ABOVE the keys — the lit key is transformed, which
   makes it a positioned element that would otherwise paint over the top */
.reach {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
  z-index: 5;
}
.reach-path {
  fill: none;
  stroke-width: 4.5;
  stroke-linecap: round;
  paint-order: stroke;
  filter: drop-shadow(0 0 8px rgba(0, 0, 0, 0.9));
}
.reach-dot { opacity: 0.95; }

/* ------------------------------------------------------ the two hands */

.deck {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
}
.handbox { width: 158px; flex: 0 0 auto; transition: opacity 0.2s; }
.hand {
  width: 100%;
  height: auto;
  display: block;
}
.handbox .palm {
  fill: #2a3a4e;
  stroke: #55708f;
  stroke-width: 2;
}
.handbox .finger {
  fill: #2a3a4e;
  stroke: #55708f;
  stroke-width: 2;
  transition: fill 0.12s, transform 0.12s;
}
/* the finger you need lifts slightly and takes its own colour */
/* the finger you need: full colour, lifted clear of the others, ringed in
   white so it reads instantly against any of them */
.handbox .finger.on {
  stroke: #ffffff;
  stroke-width: 2.5;
  transform: translateY(-12px);
  filter: drop-shadow(0 0 14px var(--glow, var(--neon)));
}
.handbox .finger.on.shift { opacity: 0.85; }
/* the hand that is not doing anything stays calm */
.handbox { opacity: 0.8; }
.handbox.live { opacity: 1; }

/* the hands SHRINK rather than vanish — for a beginner they are the most
   useful thing on the screen, so they are the last thing to go */
@media (max-width: 1200px) {
  .handbox { width: 112px; }
  .deck { gap: 10px; }
}
@media (max-width: 900px) {
  .handbox { width: 74px; }
  .deck { gap: 6px; }
}
@media (max-width: 620px) {
  .handbox { display: none; }
}
/* THE FINGER LINE — "Your RIGHT INDEX, up from J to U".
   This is the most important teaching text in the product, and it was set in
   --neon, a colour chosen back when this line sat on the dark keyboard. On the
   daylight page that is 1.52:1: technically present, effectively invisible.
   It is also the text equivalent for the on-screen board, which is hidden from
   screen readers, so it has to be readable by everyone else. */
.hand {
  text-align: center;
  font-size: 13px;
  letter-spacing: 0.06em;
  color: var(--accent);
  font-weight: 600;
  min-height: 20px;
}

/* --------------------------------------------------------------- the run */

.run {
  position: fixed;
  inset: 0;
  background: var(--ground);
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 22px 20px;
  overflow-y: auto;
}
.run .strip {
  width: 100%;
  max-width: 1000px;
  display: flex;
  align-items: center;
  gap: 26px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.run .strip .fig .n { font-size: 26px; }
.run .strip .right { margin-left: auto; display: flex; gap: 26px; }

.paper {
  width: 100%;
  /* the one thing that must never go full width: a line of text you are
     reading character by character */
  max-width: 1000px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 26px 28px;
  box-shadow: var(--shadow);
}
.paper .head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}
.paper .head h3 { font-size: 15px; letter-spacing: 0.1em; }
.paper .head .cap { font-size: 13px; color: var(--dim); margin-left: auto; }

#text {
  font-family: var(--mono);
  font-size: 26px;
  line-height: 1.85;
  letter-spacing: 0.01em;
  word-break: break-word;
}
#text .w { white-space: nowrap; }
#text .ch { position: relative; padding: 2px 0; }
/* THE EMPHASIS WAS BACKWARDS.
   Completed characters were saturated green and upcoming ones were flat grey,
   so the text you never need to read again was the most colourful thing in the
   block and the text you are about to type was the faintest. Done work gets
   out of the way; what is coming gets full ink. */
#text .ch.ok { color: var(--dim); opacity: 0.5; }
#text .ch.fixed { color: var(--warn); }
#text .ch.bad {
  color: var(--bad);
  background: rgba(154, 42, 32, 0.14);
  border-radius: 3px;
}
#text .ch.todo { color: var(--ink); }
/* the character you owe is INVERTED — at a glance, from across a room */
#text .ch.at {
  color: var(--accent-ink);
  background: var(--accent);
  border-radius: 3px;
  box-shadow: 0 0 0 2px rgba(14, 91, 96, 0.22);
}
/* the sibling of .ch.at, and it kept the hardcoded white: 2.85:1 */
#text .ch.bad.at { background: var(--bad); color: var(--bad-ink, #fff); }
#text .ch.ghost { box-shadow: inset 0 -4px 0 var(--gold); }

/* spelling: blanks, not the word */
.sentence {
  font-size: 22px;
  line-height: 1.7;
  color: var(--ink);
  margin-bottom: 18px;
}
.slots { display: flex; flex-wrap: wrap; gap: 9px; }
.slot {
  width: 34px;
  height: 46px;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 26px;
  border-bottom: 3px solid var(--line);
  color: var(--good);
}
.slot.at { border-bottom-color: var(--accent); background: var(--card-2); }
.slot.bad { border-bottom-color: var(--bad); }
.spellhint { margin-top: 16px; font-size: 14px; color: var(--soft); }
.lastword {
  margin-top: 14px;
  font-size: 14px;
  padding: 8px 12px;
  border-radius: var(--radius);
  background: var(--card-2);
}
.lastword.good { color: var(--good); }
.lastword.miss { color: var(--warn); }

.ghostline {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--soft);
  margin-top: 14px;
  min-height: 20px;
}
.ghostline b.ahead { color: var(--good); }
.ghostline b.behind { color: var(--warn); }

.coachband {
  width: 100%;
  max-width: 1000px;
  margin-top: 12px;
  padding: 10px 14px;
  border-left: 3px solid var(--warn);
  background: var(--card-2);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: 14px;
}

.run .bottom {
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}
.streakpill {
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--good);
  min-height: 20px;
  font-variant-numeric: tabular-nums;
}
.quit { font-size: 12px; color: var(--dim); }

/* ------------------------------------------------------------- overlays */

.sheet {
  position: fixed;
  inset: 0;
  background: rgba(16, 22, 30, 0.55);
  display: grid;
  place-items: center;
  padding: 20px;
  z-index: 50;
}
.sheet .card { max-width: 720px; width: 100%; max-height: 88vh; overflow-y: auto; }

/* THE WAY OUT MUST ALWAYS BE VISIBLE.
   The result card scrolls, and on a 900px-tall laptop the GO AGAIN / TEACH ME
   THIS / DONE row sat about a hundred pixels below the fold with no cue that
   there was anything under it. The very first result a person ever sees had no
   visible way forward. Pinning the row to the bottom of the card means the
   content scrolls under it and the exit is always there. */
.sheet .card > .buttons:last-child {
  position: sticky;
  bottom: -20px;
  margin: 18px -20px -20px;
  padding: 16px 20px;
  background: linear-gradient(to bottom, transparent, var(--card) 22%);
  border-top: 1px solid var(--line);
  border-radius: 0 0 10px 10px;
}
.sheet h3 { font-size: 24px; margin-bottom: 6px; }
.sheet .reason {
  font-size: 13px;
  letter-spacing: 0.1em;
  color: var(--dim);
  margin-bottom: 16px;
}
.wins { list-style: none; padding: 0; margin: 0 0 16px; }
.wins li {
  padding: 5px 0 5px 22px;
  position: relative;
  font-size: 14px;
}
.wins li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 12px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--good);
}
.fixthis {
  border-left: 3px solid var(--accent);
  background: var(--card-2);
  padding: 12px 14px;
  border-radius: 0 var(--radius) var(--radius) 0;
  margin-bottom: 16px;
}
.fixthis h4 { margin: 0 0 4px; font-size: 15px; }
.fixthis p { font-size: 14px; color: var(--soft); }
.fixthis .cost { font-size: 13px; color: var(--gold); margin-top: 6px; }
.buttons { display: flex; gap: 10px; flex-wrap: wrap; }

/* the slow spots, shown inside the words they happened in */
.join {
  font-family: var(--mono);
  font-weight: 600;
  letter-spacing: 0.06em;
}
.slowwords { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.slowwords .sw {
  font-family: var(--mono);
  font-size: 19px;
  background: var(--card-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 4px 9px;
  letter-spacing: 0.02em;
}
.slowwords .sw .hit {
  color: var(--bad);
  font-weight: 700;
  border-bottom: 3px solid var(--gold);
}

/* --------------------------------------------------------------- charts */

.chart { width: 100%; height: auto; display: block; }
.cal {
  display: grid;
  grid-template-columns: repeat(14, 1fr);
  gap: 4px;
  max-width: 340px;
}
.cal i {
  display: block;
  aspect-ratio: 1;
  border-radius: 3px;
  background: var(--card-2);
}
.cal i[data-on="1"] { background: #a7cbb8; }
.cal i[data-on="2"] { background: #58a37c; }
.cal i[data-on="3"] { background: var(--good); }
.cal i.today { outline: 2px solid var(--accent); outline-offset: 1px; }

.reccode {
  font-family: var(--mono);
  font-size: 30px;
  letter-spacing: 0.14em;
  text-align: center;
  padding: 20px;
  margin-top: 14px;
  background: var(--card-2);
  border: 2px dashed var(--accent);
  border-radius: var(--radius);
  user-select: all;
}

.badges { display: flex; flex-wrap: wrap; gap: 8px; }

/* what you're into */
.chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border-radius: 999px;
  padding: 5px 12px;
  font-size: 13px;
  background: var(--card-2);
  border-color: transparent;
}
.chip b { color: var(--dim); font-weight: 600; }
.chip:hover b { color: var(--bad); }
.chip.ghost { background: transparent; border: 1px dashed var(--line); color: var(--soft); }
.storybox {
  font-family: var(--mono);
  font-size: 15px;
  line-height: 1.9;
  margin-top: 8px;
  padding: 12px 14px;
  background: var(--card-2);
  border-radius: var(--radius);
}
/* a letter this level has not been taught yet: there, but not yours */
.storybox .locked { opacity: 0.28; }
.badge {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 12px;
  font-size: 12px;
  color: var(--dim);
}
.badge.won { border-color: var(--good); color: var(--good); font-weight: 600; }

.note { font-size: 13px; color: var(--dim); }
.warnline { color: var(--warn); font-size: 13px; }
.goodline { color: var(--good); font-size: 13px; font-weight: 600; }

label.field { display: block; font-size: 13px; color: var(--soft); margin-bottom: 6px; }
input[type="text"], input[type="password"], textarea, select {
  font: inherit;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 9px 12px;
  width: 100%;
}
textarea { font-family: var(--mono); font-size: 12px; min-height: 90px; }

.stack { display: flex; flex-direction: column; gap: 12px; }
.inline { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* ---------------------------------------------------------------- lesson */

.lesson .step {
  font-family: var(--mono);
  font-size: 34px;
  letter-spacing: 0.12em;
  text-align: center;
  padding: 26px 0 10px;
}
.lesson .step .done { color: var(--good); }
.lesson .step .at { color: var(--ink); box-shadow: inset 0 -4px 0 var(--accent); }
.lesson .step .todo { color: var(--dim); }
.lesson .dots { display: flex; gap: 6px; justify-content: center; margin-top: 10px; }
.lesson .dots i {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--card-2); display: block;
}
.lesson .dots i.on { background: var(--accent); }
.lesson .dots i.done { background: var(--good); }

@media (max-width: 700px) {
  #text { font-size: 21px; line-height: 1.8; }
  .key { width: 30px; height: 34px; font-size: 11px; }
  .key.wide { width: 150px; }
  .hero .go { flex: 1 1 100%; }
}


/* ------------------------------------------------------- the certificate */

.certwrap { max-width: 760px; }
.cert {
  border: 2px solid var(--accent);
  border-radius: 6px;
  padding: 34px 38px;
  background: var(--card);
}
.certtop {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  border-bottom: 1px solid var(--line);
  padding-bottom: 12px;
}
.certtop .logo { margin: 0; font-size: 15px; letter-spacing: 0.16em; }
.certdate { font-size: 12px; color: var(--dim); }
.certkind {
  font-size: 12px;
  letter-spacing: 0.22em;
  color: var(--accent);
  margin-top: 26px;
  font-weight: 650;
}
.certname {
  font-size: 42px;
  font-weight: 650;
  letter-spacing: 0.02em;
  margin: 6px 0 10px;
}
.certsays { font-size: 16px; color: var(--soft); max-width: 46ch; }
.certgrid {
  margin-top: 26px;
  border-top: 1px solid var(--line);
}
.certline {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
}
.certline .l { color: var(--soft); }
.certline b { font-variant-numeric: tabular-nums; }
.certfoot { margin-top: 20px; font-size: 11px; color: var(--dim); line-height: 1.6; }

@media print {
  body { background: #fff; }
  .wrap, .noprint { display: none !important; }
  .sheet { position: static; background: none; padding: 0; display: block; }
  .sheet .card { box-shadow: none; border: none; max-width: none; padding: 0; }
  .cert { border-color: #111; }
  .certkind { color: #111; }
}


/* shown only on the old address, to hand progress over to the new one */
.moved {
  border: 2px solid var(--warn);
  border-radius: var(--radius);
  background: var(--card);
  padding: 14px 16px;
  margin-bottom: 18px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.moved b { color: var(--warn); }
.moved span { font-size: 14px; color: var(--soft); }
.gobtn {
  display: inline-block;
  background: var(--accent);
  color: #fff;
  text-decoration: none;
  border-radius: var(--radius);
  padding: 10px 16px;
  font-size: 14px;
  font-weight: 600;
}


/* 3 - 2 - 1 - GO */
.count {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
  z-index: 30;
}
.count:empty { display: none; }
/* a disc behind the number so it reads over the text you are about to type,
   on either theme, without hiding it */
.count::before {
  content: "";
  position: absolute;
  width: 230px;
  height: 230px;
  border-radius: 50%;
  background: var(--card);
  border: 3px solid var(--accent);
  box-shadow: 0 10px 50px rgba(20, 30, 40, 0.22);
}
.count {
  font-size: 132px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--accent);
}
.count > * { position: relative; }
.count.live { animation: countpop 0.42s cubic-bezier(0.2, 1.3, 0.4, 1); }
@keyframes countpop {
  0% { transform: scale(0.6); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}
.run .strip .fig .l { white-space: nowrap; }


/* the basics lesson holds the same deck the run screen does — two hands and a
   keyboard — so its card has to be wide enough for all three, and the pieces
   have to shrink together rather than spill over the edge */
/* `.sheet .card` sets max-width 720 and is two classes deep, so a single-class
   rule here loses the cascade and the hands get clipped. Three classes wins. */
.sheet.basics .card.basicscard,
.sheet.lesson .card.basicscard {
  max-width: 980px;
  width: 100%;
}
.basics .deck { max-width: 100%; }
.basics .handbox { width: 120px; }
@media (max-width: 1000px) {
  .basics .handbox { width: 92px; }
  .basics .deck { gap: 8px; }
}
@media (max-width: 820px) {
  .basics .handbox { width: 68px; }
  .basics .key { width: 34px; height: 36px; font-size: 12px; }
  .basics .key.wide { width: 170px; }
}
@media (max-width: 640px) {
  .basics .handbox { display: none; }
}


/* a letter that just landed: it should be obvious you pressed it */
.lesson .step .struck { animation: struck 0.32s ease-out; }
/* and a whole repetition done, for the steps that are a single key */
.lesson .step.repdone { animation: repdone 0.4s ease-out; }
@keyframes repdone {
  0% { transform: scale(1); }
  35% { transform: scale(1.12); filter: drop-shadow(0 0 14px rgba(29, 107, 67, 0.55)); }
  100% { transform: scale(1); }
}
.reps {
  text-align: center;
  font-size: 13px;
  color: var(--good);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
  margin-top: 4px;
}
@keyframes struck {
  0% { transform: translateY(0) scale(1); color: var(--good); }
  30% { transform: translateY(-8px) scale(1.25); color: var(--good);
        text-shadow: 0 0 18px rgba(29, 107, 67, 0.5); }
  100% { transform: translateY(0) scale(1); }
}
/* and the lesson deck follows the same shrinking rules as the basics one */
.lesson .deck { max-width: 100%; }
.lesson .handbox { width: 120px; }
@media (max-width: 1000px) {
  .lesson .handbox { width: 92px; }
  .lesson .deck { gap: 8px; }
}
@media (max-width: 820px) {
  .lesson .handbox { width: 68px; }
  .lesson .key { width: 34px; height: 36px; font-size: 12px; }
  .lesson .key.wide { width: 170px; }
}
@media (max-width: 640px) {
  .lesson .handbox { display: none; }
}


/* the line that says why this is worth doing, between passages */
.worth {
  width: 100%;
  max-width: 1000px;
  margin-top: 12px;
  padding: 10px 14px;
  border-left: 3px solid var(--gold);
  background: var(--card-2);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: 14px;
  color: var(--soft);
  opacity: 0;
  transition: opacity 0.5s;
}
.worth:empty { display: none; }
.worth.show { animation: worthin 9s ease-in-out forwards; }
@keyframes worthin {
  0% { opacity: 0; transform: translateY(6px); }
  8% { opacity: 1; transform: translateY(0); }
  88% { opacity: 1; }
  100% { opacity: 0; }
}


/* announced to screen readers, invisible to everyone else */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}
[inert] { pointer-events: none; }
#overlay[hidden] { display: none; }


/* A phone is where a parent checks in, and the coach list was unreadable on
   one: `white-space: nowrap` on the note pushed it 70px past the row, which
   crushed the name column to 43px and stacked it one word per line. */
@media (max-width: 700px) {
  .row { flex-wrap: wrap; align-items: flex-start; }
  .row .note { white-space: normal; margin-left: 0; flex-basis: 100%; }
  .tabs button { padding: 10px 12px; font-size: 12px; letter-spacing: 0.04em; }
}

/* a mistyped SPACE rendered as a solid red block with nothing in it, so you
   could not tell what you owed */
#text .ch.sp.bad::after {
  content: "\00b7";
  color: var(--accent-ink);
  opacity: .7;
}


/* ------------------------------------------------ the practice settings line
   The three-column picker became one line of chips. It states what you are
   about to do without asking you to read three lists to find out. */
.setline {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding: 12px 16px; margin-top: -4px;
  background: var(--card); border: 1px solid var(--line); border-radius: 8px;
}
.setline .chips { display: flex; gap: 18px; flex-wrap: wrap; align-items: baseline; }
.setline .chip { display: inline-flex; gap: 7px; align-items: baseline; }
.setline .chip i {
  font-style: normal; font-size: 11px; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--dim);
}
.setline .chip b { font-size: 14px; font-weight: 650; color: var(--ink); }

button.linky, button.disclose {
  background: none; border: 0; padding: 6px 2px;
  color: var(--accent); font-size: 13.5px; font-weight: 600;
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
button.disclose {
  width: 100%; text-align: left; padding: 12px 16px;
  border: 1px dashed var(--line); border-radius: 8px; text-decoration: none;
}
button.disclose:hover { border-color: var(--accent); }
button.linky:hover, button.disclose:hover { color: var(--accent-2); }

.row.quietrow { opacity: .7; }
.row.quietrow:hover { opacity: 1; }


/* two peers, not a button and a whisper */
.go.twoup { display: flex; flex-direction: column; gap: 10px; }
.big.ghostbtn {
  background: transparent;
  color: var(--accent);
  border-color: var(--line);
}
.big.ghostbtn:hover { border-color: var(--accent); }


/* THE OLD SPEED AS A FINISH LINE, NOT A CEILING.
   The chart drew the baseline as a dashed line across the top that the data
   never reached, so for weeks the picture was "you are under the line". A
   track with the target marked on it says the same thing and means the
   opposite. */
.trackbar {
  position: relative; height: 34px; margin: 14px 0 12px;
  background: var(--card-2); border: 1px solid var(--line); border-radius: 17px;
  overflow: hidden;
}
.trackbar i {
  display: block; height: 100%;
  background: var(--accent); opacity: .85;
  border-radius: 17px 0 0 17px;
  transition: width .5s ease-out;
}
.trackbar b {
  position: absolute; right: 12px; top: 0; line-height: 34px;
  font-size: 12px; font-weight: 700; letter-spacing: .08em; color: var(--dim);
}
@media (prefers-reduced-motion: reduce) { .trackbar i { transition: none; } }


/* THE CURRENT WORD. Only the single character was marked, so on a line of
   short words the eye had no chunk to hold on to — and a word is the unit a
   typist actually thinks in. */
#text .w.here {
  background: var(--card-2);
  border-radius: 5px;
  box-shadow: 0 0 0 3px var(--card-2);
}

/* a completed character settles rather than snapping — under 150ms, no scale,
   no bounce: it reads as responsiveness, not as a reward */
@keyframes settle {
  from { color: var(--accent); opacity: 1; transform: translateY(-1px); }
  to   { color: var(--dim); opacity: 0.5; transform: none; }
}
#text .ch.ok.just { animation: settle 0.14s ease-out; }
@media (prefers-reduced-motion: reduce) { #text .ch.ok.just { animation: none; } }


/* A blind round has to look deliberate. At 0.35 opacity the board reads as
   broken rather than switched off, so say what is happening and mean it. */
.blindnote {
  margin: 0 0 12px;
  padding: 9px 14px;
  font-size: 13.5px;
  color: var(--ink);
  background: var(--accent-wash, var(--card-2));
  border-left: 3px solid var(--accent);
  border-radius: 0 5px 5px 0;
}
.blindnote b { letter-spacing: 0.08em; color: var(--accent); }
.board.hidden { opacity: 0.16; }


/* ------------------------------------------------- state that is not colour
   Level pips, badges and the practice calendar carried their meaning in fill
   colour alone, which excludes anyone who cannot separate those hues — and
   the "not passed" pip was a 1.36:1 border, i.e. invisible to everybody. */
.pips i {
  border: 1.5px solid var(--soft);
  position: relative;
}
.pips i.on::after {
  content: "\2713";
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-size: 8px; line-height: 1; color: var(--accent-ink);
}
.badge { border: 1px solid var(--line); }
.badge.won {
  background: var(--card-2);
  border-color: var(--accent);
  border-width: 1.5px;
}
.badge.won::after {
  content: " \2713";
  font-weight: 700;
  color: var(--accent);
}
/* the calendar's four shades get a matching border weight, so intensity is
   readable without relying on how green a square is */
.cal i[data-on="1"] { border: 1px solid var(--line); }
.cal i[data-on="2"] { border: 1.5px solid var(--soft); }
.cal i[data-on="3"] { border: 2px solid var(--accent); }


/* ------------------------------------------------------- MOTION, ACTUALLY OFF
   I claimed this was honoured after adding two scoped rules that happened to
   cover the decorations added in the same commit. Seven keyframe animations,
   seven transitions and an SVG animation that repeats for ever were untouched.
   A blanket rule at the end of the stylesheet is the only version of this that
   is true, because it cannot be outrun by the next animation somebody adds. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}


.swatch {
  display: inline-block; width: 9px; height: 9px; border-radius: 2px;
  margin-right: 7px; vertical-align: baseline;
  border: 1px solid rgba(0, 0, 0, 0.25);
}
