/* Speaking Master.
   Light by default, card-based: a soft lilac-grey ground, white cards with
   quiet shadows, one indigo accent for interface state, and a single red that
   means the microphone is live.
   Every colour comes from the two token blocks below. scripts/check-colors.mjs
   fails the build on a bare hex anywhere else, or on a token defined in one
   theme but not the other. */

/* ── Colour tokens ──────────────────────────────────────────────────────────
   Measured rather than assumed: every text pairing clears WCAG AA in both
   themes, and the four part hues sit within 1.13 (light) and 0.59 (dark) of
   each other in contrast, so no part shouts louder than another.

   --rec is used for ONE thing: the microphone is live. Not errors, not
   destructive actions. With a record button on all 484 questions, "red = I am
   being recorded" has to be learnable and never contradicted. */

:root {
  color-scheme: light;

  --bg: #F5F5FA;
  --card: #FFFFFF;
  --sunken: #F0F0F7;
  --text: #191A2C;
  --text-2: #5B5D72;
  --text-3: #686A80;
  --line: #E6E6EF;

  --p1: #4A44CE;  --p1-tint: #EDECFC;   /* Part 1 · indigo */
  --p2: #8B3FC2;  --p2-tint: #F6EDFB;   /* Part 2 · violet */
  --p3: #0E6F4E;  --p3-tint: #E6F6EF;   /* Part 3 · green  */
  --p4: #A24A08;  --p4-tint: #FDF0E1;   /* Mock   · amber  */

  --rec: #DC2B24;
  --meter: #0E6F4E;
  --ok: #0E6F4E;
  --warn: #A24A08;
  --err: #B4243F;

  --on-fill: #FFFFFF;
  --on-rec: #FFFFFF;

  /* The brand mark. Its own scale, because a logo is not interface colour —
     but declared as tokens so it can adapt to the dark theme. */
  --logo-a: #6C5CE7;
  --logo-b: #3A2BB5;
  --logo-bar: #A99BF5;
  --logo-ink: #4338CA;
  --scrim: rgb(25 26 44 / 0.45);
  /* The sticky landing bar's ground once it leaves the top of the page: the
     page background, thinned so the content blurs through it. */
  --veil: rgb(245 245 250 / 0.82);
  --shadow-1: 0 1px 2px rgb(25 26 44 / 0.05), 0 1px 3px rgb(25 26 44 / 0.04);
  --shadow-2: 0 2px 4px rgb(25 26 44 / 0.05), 0 8px 20px rgb(25 26 44 / 0.06);
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #121220;
  --card: #1B1B2C;
  --sunken: #232337;
  --text: #F0F0F6;
  --text-2: #A6A7BD;
  --text-3: #8E90A8;
  --line: #2E2E44;

  --p1: #ABA5F8;  --p1-tint: #22213A;
  --p2: #D0A0EC;  --p2-tint: #2A1E38;
  --p3: #55C594;  --p3-tint: #16281F;
  --p4: #DDA047;  --p4-tint: #2E2312;

  --rec: #FF5E52;
  --meter: #55C594;
  --ok: #55C594;
  --warn: #DDA047;
  --err: #F58BA6;

  --on-fill: #121220;
  --on-rec: #FFFFFF;

  --logo-a: #A79BF8;
  --logo-b: #6C5CE7;
  --logo-bar: #CFC8FB;
  --logo-ink: #A79BF8;
  --scrim: rgb(8 8 14 / 0.6);
  --veil: rgb(18 18 32 / 0.82);
  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.4);
  --shadow-2: 0 2px 6px rgb(0 0 0 / 0.4), 0 10px 24px rgb(0 0 0 / 0.3);
}

/* No prefers-color-scheme rule: light is the product's default look whatever
   the operating system is set to, and dark is an explicit choice that persists.
   A system preference silently overriding it would mean most people never see
   the app as designed. */

/* ── Scale ──────────────────────────────────────────────────────────────── */

:root {
  --t-2xl: 28px;
  --t-xl: 22px;
  --t-lg: 18px;
  --t-md: 16px;
  --t-base: 14px;
  --t-sm: 13px;
  --t-xs: 11px;

  --s1: 4px;  --s2: 8px;   --s3: 12px;  --s4: 16px;
  --s5: 20px; --s6: 24px;  --s8: 32px;  --s12: 48px; --s16: 64px;

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-full: 999px;

  --dur: 140ms;
  --ease: cubic-bezier(.2, 0, .2, 1);

  --side: 268px;
  --ai-w: 360px;
  --measure: 780px;
  --bar-h: 60px;

  --ui: "General Sans", ui-sans-serif, system-ui, sans-serif;
  --reading: "Source Serif 4", Georgia, "Times New Roman", serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --accent: var(--p1);
  --accent-tint: var(--p1-tint);
}

:root[data-part="2"] { --accent: var(--p2); --accent-tint: var(--p2-tint); }
:root[data-part="3"] { --accent: var(--p3); --accent-tint: var(--p3-tint); }
:root[data-part="4"] { --accent: var(--p4); --accent-tint: var(--p4-tint); }

@font-face {
  font-family: "General Sans";
  src: url("assets/fonts/general-sans-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "General Sans";
  src: url("assets/fonts/general-sans-500.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "General Sans";
  src: url("assets/fonts/general-sans-600.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "General Sans";
  src: url("assets/fonts/general-sans-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Source Serif 4";
  src: url("assets/fonts/source-serif-4-var.woff2") format("woff2-variations");
  font-weight: 200 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Source Serif 4";
  src: url("assets/fonts/source-serif-4-var-italic.woff2") format("woff2-variations");
  font-weight: 200 900; font-style: italic; font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("assets/fonts/jetbrains-mono-500.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; height: 100%; }

body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--ui);
  font-size: var(--t-base);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

body.theme-switching * { transition: none !important; }

h1, h2, h3 { margin: 0; font-weight: 600; line-height: 1.25; letter-spacing: -0.01em; }
p { margin: 0; }
ul, ol { margin: 0; }
button { font: inherit; color: inherit; }
a { color: var(--accent); }

.eyebrow, .subject-label {
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
}

.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
:focus:not(:focus-visible) { outline: none; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: var(--s4);
  top: -80px;
  z-index: 100;
  padding: var(--s2) var(--s4);
  background: var(--card);
  border: 1px solid var(--accent);
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  text-decoration: none;
  transition: top var(--dur) var(--ease);
}
.skip-link:focus { top: var(--s4); }

.icon { width: 20px; height: 20px; flex: none; display: block; }
.icon-sm { width: 16px; height: 16px; }
.icon-lg { width: 26px; height: 26px; }

/* ── Loading screen ─────────────────────────────────────────────────────────
   Rebuilt in markup rather than shipped as an image: it has to paint before any
   script runs, fill any screen shape without letterboxing, and animate. */

#boot {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--bg);
  opacity: 1;
  transition: opacity 260ms var(--ease);
}
/* Author CSS beats the UA stylesheet, so without this the [hidden] attribute
   leaves a transparent full-viewport layer swallowing every click. */
#boot[hidden] { display: none; }
#boot.is-done { opacity: 0; }

/* The rings sit behind everything and are deliberately almost invisible. */
.boot-orbits {
  position: absolute;
  inset: 50% auto auto 50%;
  width: max(900px, 105vmax);
  height: max(900px, 105vmax);
  transform: translate(-50%, -50%);
  color: var(--logo-a);
  opacity: 0.16;
  stroke-width: 1.2;
  animation: orbit-drift 90s linear infinite;
}

@keyframes orbit-drift { to { transform: translate(-50%, -50%) rotate(360deg); } }

.boot-tile {
  position: absolute;
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  border-radius: 13px;
  background: var(--card);
  color: var(--logo-a);
  box-shadow: var(--shadow-1);
  opacity: 0.75;
  animation: tile-float 7s var(--ease) infinite;
}
.boot-tile svg { width: 20px; height: 20px; }

/* Placed roughly where they sit in the lockup: on the rings, off the corners. */
.boot-tile-a { top: 21%; left: 18%; animation-delay: 0s; }
.boot-tile-b { top: 37%; right: 15%; animation-delay: 1.6s; }
.boot-tile-c { bottom: 26%; left: 20%; animation-delay: 3.2s; }
.boot-tile-d { bottom: 22%; right: 19%; animation-delay: 4.8s; }

@keyframes tile-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}

.boot-centre {
  position: relative;
  z-index: 2;
  display: grid;
  justify-items: center;
  gap: var(--s3);
  padding: var(--s6);
  text-align: center;
}

.boot-mark { width: 76px; height: 76px; }

.wordmark { font-weight: 700; letter-spacing: -0.02em; color: var(--text); }
.wordmark span { color: var(--logo-a); }

.boot-word { font-size: 34px; line-height: 1.1; margin-top: var(--s2); }

.boot-tag {
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-3);
}
.boot-tag i { font-style: normal; color: var(--logo-a); margin: 0 2px; }

.boot-bar {
  width: min(320px, 60vw);
  height: 6px;
  margin-top: var(--s6);
  border-radius: var(--r-full);
  background: var(--sunken);
  overflow: hidden;
}
/* Indeterminate on purpose: the loader does not know how much of the question
   bank has arrived, and a bar that pretends to would be lying. */
.boot-bar-fill {
  width: 45%;
  height: 100%;
  border-radius: var(--r-full);
  background: linear-gradient(90deg, var(--logo-a), var(--logo-b));
  animation: boot-sweep 1.6s var(--ease) infinite;
}

@keyframes boot-sweep {
  0% { transform: translateX(-105%); }
  100% { transform: translateX(235%); }
}

.boot-note { font-size: var(--t-base); color: var(--text-2); }

.boot-wave {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  width: 100%;
  height: min(230px, 30vh);
  fill: var(--logo-a);
  opacity: 0.07;
}
.boot-wave-2 { opacity: 0.6; }

@media (max-width: 560px) {
  .boot-word { font-size: 26px; }
  .boot-mark { width: 60px; height: 60px; }
  .boot-tile { width: 38px; height: 38px; border-radius: 11px; }
  .boot-tile-a { left: 8%; }
  .boot-tile-b { right: 6%; }
  .boot-tile-c { left: 9%; }
  .boot-tile-d { right: 8%; }
}

/* ── Frame ──────────────────────────────────────────────────────────────── */

.app {
  display: grid;
  grid-template-rows: var(--bar-h) 1fr;
  height: 100dvh;
}

/* When the bar is hidden it leaves the grid entirely, and the panes slide up
   into the fixed 60px track meant for the bar — collapsing the working area to
   a 60px sliver. Both the mock test and focus mode hide the bar, so both hit
   this. Dropping to a single row is the fix for both. */
body.mock-running .app,
body.focus-mode .app { grid-template-rows: 1fr; }

.bar {
  display: flex;
  align-items: center;
  /* 8px packed the five right-hand controls into one undifferentiated block. */
  gap: var(--s3);
  padding: 0 var(--s6);
  background: var(--card);
  border-bottom: 1px solid var(--line);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--s3);
  color: var(--text);
  text-decoration: none;
  font-weight: 600;
  font-size: var(--t-md);
}
/* The mark carries its own colours, so it needs no tile behind it and never
   tints with the part you happen to be in. */
.brandmark { width: 30px; height: 30px; flex: none; }
.brand .wordmark { font-size: var(--t-md); }
.bar-spacer { flex: 1; }

.bar-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  height: 36px;
  padding: 0 var(--s3);
  background: transparent;
  border: none;
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text-2);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .bar-btn:hover { background: var(--sunken); color: var(--text); }
}
.bar-btn[aria-pressed="true"] { background: var(--accent-tint); color: var(--accent); }
.bar-btn.icon-only { padding: 0 var(--s2); }

.count-badge {
  min-width: 18px;
  padding: 0 5px;
  border-radius: var(--r-full);
  background: var(--accent);
  color: var(--on-fill);
  font-family: var(--mono);
  font-size: var(--t-xs);
  line-height: 18px;
  text-align: center;
}

.theme-toggle .icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }

.menu-btn { display: none; }

/* ── Panes ──────────────────────────────────────────────────────────────── */

.panes {
  display: grid;
  /* Three tracks: topics, the AI Helper, the working pane. The middle one is
     `auto`, so it is exactly as wide as the panel - which is zero until the
     panel opens, and animating the panel's own width animates the track. */
  grid-template-columns: var(--side) auto 1fr;
  min-height: 0;
}

.side {
  display: flex;
  flex-direction: column;
  min-height: 0;
  /* The head, the list and the footer together can exceed a short laptop
     window. Without this the list is what gets squeezed, because it is the
     only flexible child — and a topic list with no topics in it is the one
     part of this column that must never happen. */
  overflow-y: auto;
  background: var(--card);
  border-right: 1px solid var(--line);
}

.side-head {
  padding: var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s4);
}

/* ── Part pills ─────────────────────────────────────────────────────────── */

.parts { display: flex; flex-direction: column; gap: var(--s2); }

.part {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) var(--s3);
  background: var(--sunken);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
  cursor: pointer;
  text-align: left;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.part-mark {
  display: grid;
  place-items: center;
  width: 28px; height: 28px;
  border-radius: 7px;
  background: var(--card);
  color: var(--text-3);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}

/* Each part keeps its own colour so you can tell at a glance which section you
   are in. Identity is never colour alone: the selected pill is also the only
   one with a border and full-strength label, and the part is spelled out. */
.part[data-part="1"][aria-selected="true"] { background: var(--p1-tint); color: var(--p1); border-color: color-mix(in srgb, var(--p1) 30%, transparent); }
.part[data-part="2"][aria-selected="true"] { background: var(--p2-tint); color: var(--p2); border-color: color-mix(in srgb, var(--p2) 30%, transparent); }
.part[data-part="3"][aria-selected="true"] { background: var(--p3-tint); color: var(--p3); border-color: color-mix(in srgb, var(--p3) 30%, transparent); }
.part[data-part="4"][aria-selected="true"] { background: var(--p4-tint); color: var(--p4); border-color: color-mix(in srgb, var(--p4) 30%, transparent); }
.part[aria-selected="true"] .part-mark { background: var(--card); color: inherit; }

@media (hover: hover) and (pointer: fine) {
  .part:hover { color: var(--text); }
  .part:hover .part-mark { color: var(--text); }
}

/* ── Filters ────────────────────────────────────────────────────────────── */

.filters { display: flex; gap: var(--s2); flex-wrap: wrap; }

.filter {
  padding: var(--s2) var(--s3);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text-2);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .filter:hover { border-color: var(--text-3); color: var(--text); }
}
.filter[aria-pressed="true"] {
  background: var(--text);
  border-color: var(--text);
  color: var(--card);
}

.subject-field { display: flex; flex-direction: column; gap: var(--s2); }
.subject {
  width: 100%;
  padding: var(--s2) var(--s3);
  background: var(--card);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font: inherit;
  font-size: var(--t-sm);
  cursor: pointer;
}

.rail-row { display: flex; flex-direction: column; gap: var(--s2); }
.rail-count { align-self: flex-end; font-size: var(--t-xs); color: var(--text-3); }
.rail-track { height: 4px; background: var(--sunken); border-radius: var(--r-full); overflow: hidden; }
.rail-fill { height: 100%; background: var(--accent); border-radius: var(--r-full); transition: width var(--dur) var(--ease); }

/* ── Topic list ─────────────────────────────────────────────────────────── */

.topics { flex: 1; min-height: 160px; overflow-y: auto; padding: 0 var(--s3) var(--s4); }
.topics ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--s1); }

.topic {
  display: flex;
  align-items: center;
  gap: var(--s3);
  width: 100%;
  padding: var(--s3);
  background: none;
  border: none;
  border-radius: var(--r-sm);
  text-align: left;
  font-size: var(--t-base);
  color: var(--text-2);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.topic .icon { color: var(--text-3); transition: color var(--dur) var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .topic:hover { background: var(--sunken); color: var(--text); }
  .topic:hover .icon { color: var(--text-2); }
}
.topic[aria-current="true"] {
  background: var(--accent-tint);
  color: var(--accent);
  font-weight: 600;
}
.topic[aria-current="true"] .icon { color: var(--accent); }

.topic-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topic-count { font-size: var(--t-sm); color: var(--text-3); font-variant-numeric: tabular-nums; }
.topic-flags { display: flex; gap: var(--s1); }
.topic-flags .icon { width: 13px; height: 13px; }
.topic-flag.is-star { color: var(--accent); }
.topic-flag.is-rec { color: var(--meter); }

.side-empty { padding: var(--s6) var(--s3); color: var(--text-3); font-size: var(--t-sm); }

/* ── Working pane ───────────────────────────────────────────────────────── */

.pane {
  overflow-y: auto;
  /* The pane's padding IS the gutter between the AI panel and the workspace;
     there is no gap on .panes because the sidebar and the panel are full-height
     surfaces that have to reach the window edges. */
  padding: var(--s6) var(--s8);
  scroll-behavior: smooth;
}
.pane > * { max-width: var(--measure); margin-inline: auto; }

.pane-empty {
  display: grid;
  justify-items: center;
  gap: var(--s2);
  /* 16vh when this was two lines of label. With the part's advice below it,
     that much lead pushed the tips under the fold on a laptop. */
  padding-top: 9vh;
  color: var(--text-3);
}
.pane-empty .icon { width: 30px; height: 30px; opacity: 0.5; }
.pane-empty p { font-size: var(--t-lg); color: var(--text-2); }
.pane-empty .sub { font-size: var(--t-sm); }

/* ── Topic header card ──────────────────────────────────────────────────── */

.topic-head {
  position: relative;
  display: flex;
  gap: var(--s4);
  padding: var(--s6);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  overflow: hidden;
  margin-bottom: var(--s6);
}

.topic-tile {
  display: grid;
  place-items: center;
  width: 56px; height: 56px;
  flex: none;
  border-radius: var(--r-md);
  background: var(--accent);
  color: var(--on-fill);
}

.topic-head-body { position: relative; z-index: 1; min-width: 0; flex: 1; }
.topic-head h2 { font-size: var(--t-2xl); }
.topic-head .theme { margin-top: var(--s2); font-weight: 600; color: var(--text); }
.topic-head .desc { margin-top: var(--s2); color: var(--text-2); max-width: 46ch; }
.topic-head .badge-row { display: flex; align-items: center; gap: var(--s2); margin-bottom: var(--s2); }

.part-chip {
  padding: 3px var(--s2);
  border-radius: var(--r-full);
  background: var(--accent-tint);
  color: var(--accent);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.period-chip { font-size: var(--t-xs); color: var(--text-3); text-transform: uppercase; letter-spacing: 0.08em; }

/* Twelve flat scenes, shared across the 162 topics and tinted by the current
   part. Drawn entirely in currentColor at varying opacity, so one scene works
   in both themes and in all four part colours without a second version. */
.scene {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 232px;
  height: 112px;
  color: var(--accent);
  pointer-events: none;
  /* Fades the scene out towards the text so it never competes with it. Only the
     alpha of this gradient matters — it is a mask, not a colour — so the
     keyword carries no design decision and belongs to no theme. */
  -webkit-mask-image: linear-gradient(to left, black 55%, transparent);
  mask-image: linear-gradient(to left, black 55%, transparent);
}

/* Above the scene: the illustration is painted last, so without this it covers
   the controls. It has pointer-events:none, so they still worked — they just
   looked buried. */
.head-actions { position: relative; z-index: 1; display: flex; gap: var(--s1); align-self: flex-start; }

.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 36px; height: 36px;
  background: none;
  border: none;
  border-radius: var(--r-sm);
  color: var(--text-3);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .icon-btn:hover { background: var(--sunken); color: var(--text); }
}
.icon-btn[aria-pressed="true"] { color: var(--accent); background: var(--accent-tint); }

/* ── Progress ───────────────────────────────────────────────────────────── */

.progress {
  padding: var(--s4) var(--s5);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  margin-bottom: var(--s6);
}
.progress-top { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: var(--s3); }
.progress-label { font-size: var(--t-xs); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent); }
.progress-count { font-family: var(--mono); font-size: var(--t-sm); color: var(--text-2); }

/* Segments, not a percentage. Equal widths, so three of five always looks like
   three of five however wide the pane is. */
.seg-track { display: flex; gap: var(--s2); }
.seg {
  flex: 1;
  height: 6px;
  border-radius: var(--r-full);
  background: var(--sunken);
  transition: background var(--dur) var(--ease);
}
.seg.is-done { background: var(--accent); }

/* ── Question cards ─────────────────────────────────────────────────────── */

.q-list { display: flex; flex-direction: column; gap: var(--s6); }

.q {
  padding: var(--s6);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  transition: box-shadow var(--dur) var(--ease);
}
.q:focus-within { box-shadow: var(--shadow-2); }

.q-top { display: flex; align-items: flex-start; gap: var(--s3); margin-bottom: var(--s5); }

.q-badge {
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  flex: none;
  border-radius: var(--r-sm);
  background: var(--accent-tint);
  color: var(--accent);
  font-family: var(--mono);
  font-size: var(--t-sm);
  font-weight: 500;
}

.q-text { flex: 1; font-size: var(--t-xl); font-weight: 600; line-height: 1.35; padding-top: 2px; }

.q-menu { position: relative; }
.menu-pop {
  position: absolute;
  right: 0;
  top: 38px;
  z-index: 20;
  min-width: 190px;
  padding: var(--s1);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-2);
}
.menu-pop[hidden] { display: none; }
.menu-pop button {
  display: flex;
  align-items: center;
  gap: var(--s2);
  width: 100%;
  padding: var(--s2) var(--s3);
  background: none;
  border: none;
  border-radius: 6px;
  font-size: var(--t-sm);
  color: var(--text-2);
  text-align: left;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .menu-pop button:hover { background: var(--sunken); color: var(--text); }
}

/* ── The recorder ───────────────────────────────────────────────────────── */

.rec {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: var(--s4);
  padding: var(--s3) var(--s4);
  background: var(--sunken);
  border-radius: var(--r-md);
  margin-bottom: var(--s3);
}

/* Large, filled, and the only red in the interface — you should never have to
   look for it. */
.rec-btn {
  display: grid;
  place-items: center;
  width: 52px; height: 52px;
  background: var(--rec);
  border: none;
  border-radius: var(--r-full);
  color: var(--on-rec);
  cursor: pointer;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--rec) 40%, transparent);
}
@media (hover: hover) and (pointer: fine) {
  .rec-btn:hover { transform: scale(1.05); }
}
.rec-btn .icon { width: 24px; height: 24px; }
.rec-btn .icon-stop { display: none; }
.rec[data-state="live"] .rec-btn .icon-mic { display: none; }
.rec[data-state="live"] .rec-btn .icon-stop { display: block; }
.rec[data-state="live"] .rec-btn { animation: rec-pulse 1.8s var(--ease) infinite; }

@keyframes rec-pulse {
  0%, 100% { box-shadow: 0 2px 8px color-mix(in srgb, var(--rec) 40%, transparent); }
  50% { box-shadow: 0 2px 8px color-mix(in srgb, var(--rec) 40%, transparent), 0 0 0 8px color-mix(in srgb, var(--rec) 14%, transparent); }
}

/* The label and the waveform share one grid cell — they are two states of the
   same thing, and giving the canvas its own column would push the timer onto a
   second row. */
/* One cell, laid out as a row: the label keeps its place and the meter grows
   into whatever is left. They used to be stacked in this cell, which is why
   the label had to be hidden the moment recording started. */
.rec-mid { display: flex; align-items: center; gap: var(--s4); min-width: 0; }

.rec-body { min-width: 0; }
.rec-label { font-weight: 500; }
.rec-hint { font-size: var(--t-sm); color: var(--text-3); }
.rec-hint:empty { display: none; }

.rec-wave { flex: 1; max-width: 220px; height: 34px; color: var(--meter); opacity: 0; transition: opacity var(--dur) var(--ease); }
.rec[data-state="live"] .rec-wave { opacity: 1; }

.rec-time { font-family: var(--mono); font-size: var(--t-md); color: var(--text-3); white-space: nowrap; }
.rec-time .elapsed { color: var(--text-2); }
.rec[data-state="live"] .rec-time .elapsed { color: var(--rec); }
/* Past the target the elapsed time goes amber. It is a guide, not a limit —
   nothing stops the recording. */
.rec[data-over="true"] .rec-time .elapsed { color: var(--warn); }

.rec-saved {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--line);
}
.rec-saved audio { flex: 1; min-width: 0; height: 34px; }
.rec-size { font-family: var(--mono); font-size: var(--t-xs); color: var(--text-3); }

/* ── Fold rows ──────────────────────────────────────────────────────────── */

.q-folds { display: flex; flex-direction: column; }

.fold { border-top: 1px solid var(--line); }
.fold:first-child { border-top: none; }
.fold summary {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s4) var(--s1);
  font-size: var(--t-base);
  font-weight: 500;
  color: var(--text-2);
  cursor: pointer;
  list-style: none;
  transition: color var(--dur) var(--ease);
}
.fold summary::-webkit-details-marker { display: none; }
@media (hover: hover) and (pointer: fine) {
  .fold summary:hover { color: var(--text); }
}
.fold summary .icon:first-child { color: var(--accent); }
.fold-note { margin-left: auto; font-size: var(--t-xs); font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-3); }
.fold-saved { font-size: var(--t-xs); color: var(--meter); opacity: 0; transition: opacity var(--dur) var(--ease); }
.fold-saved.is-on { opacity: 1; }
.fold-caret { color: var(--text-3); transition: transform var(--dur) var(--ease); }
.fold[open] .fold-caret { transform: rotate(90deg); }
.fold-body { padding: 0 var(--s1) var(--s4); }
.fold-body.reading { font-family: var(--reading); font-size: var(--t-md); line-height: 1.75; color: var(--text); }

/* A row that matches a disclosure summary but is not one: either a real button
   that opens a dialog, or static text where there is nothing to open. */
.fold-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  width: 100%;
  padding: var(--s4) var(--s1);
  background: none;
  border: none;
  border-top: 1px solid var(--line);
  font-size: var(--t-base);
  font-weight: 500;
  color: var(--text-2);
  text-align: left;
  cursor: pointer;
  transition: color var(--dur) var(--ease);
}
.fold-row:first-child { border-top: none; }
.fold-row .icon:first-child { color: var(--accent); }
.fold-row.is-static { cursor: default; color: var(--text-3); }
.fold-row.is-static .icon:first-child { color: var(--text-3); }
@media (hover: hover) and (pointer: fine) {
  .fold-row:not(.is-static):hover { color: var(--text); }
}

/* Part 2's bullets sit inside the question card, under the prompt. */
.q .cue-label { margin: 0 0 var(--s2); font-size: var(--t-xs); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-3); }
.cue-bullets { padding-left: var(--s5); margin-bottom: var(--s4); font-family: var(--reading); font-size: var(--t-md); line-height: 1.9; color: var(--text-2); }

/* Standalone screens — bookmarks, the mock placeholder, the error boundary. */
.pane-head { margin-bottom: var(--s5); }
.pane-title { font-size: var(--t-2xl); }
.pane p { color: var(--text-2); max-width: 62ch; }

.empty-note { margin-left: auto; font-size: var(--t-sm); color: var(--text-3); }

textarea {
  width: 100%;
  min-height: 90px;
  padding: var(--s3);
  background: var(--sunken);
  color: var(--text);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font-family: var(--ui);
  font-size: var(--t-base);
  line-height: 1.6;
  resize: vertical;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
textarea:focus { border-color: var(--accent); background: var(--card); }

/* ── Part 2 ─────────────────────────────────────────────────────────────── */

.cue {
  padding: var(--s6);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  margin-bottom: var(--s5);
}
.cue-prompt { font-family: var(--reading); font-size: var(--t-2xl); line-height: 1.3; }
.cue-label { margin: var(--s5) 0 var(--s2); font-size: var(--t-xs); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-3); }
.cue ul { padding-left: var(--s5); font-family: var(--reading); font-size: var(--t-md); line-height: 1.9; color: var(--text-2); }

.leads {
  padding: var(--s5);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  margin-top: var(--s5);
}
.leads-label { font-size: var(--t-xs); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent); }
.leads h3 { font-size: var(--t-lg); margin: var(--s2) 0 var(--s3); }
.leads ol { padding-left: var(--s5); font-family: var(--reading); font-size: var(--t-md); line-height: 1.8; color: var(--text-2); }
.leads .btn { margin-top: var(--s4); }

.chips { display: flex; gap: var(--s2); flex-wrap: wrap; align-items: center; margin-bottom: var(--s3); }
.chip {
  padding: var(--s2) var(--s3);
  background: var(--sunken);
  border: 1px solid transparent;
  border-radius: var(--r-full);
  font-size: var(--t-sm);
  color: var(--text);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .chip:hover { border-color: var(--accent); color: var(--accent); }
}
.branch-set { font-size: var(--t-sm); color: var(--text-3); margin-bottom: var(--s3); }
.branch-set em { font-style: normal; color: var(--text); font-weight: 500; }

.link-btn {
  background: none; border: none; padding: 0 var(--s1);
  color: var(--accent); text-decoration: underline; cursor: pointer; font-size: inherit;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s2) var(--s4);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .btn:hover { border-color: var(--accent); }
}
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--on-fill); }

/* ── Modal ──────────────────────────────────────────────────────────────── */

.backdrop {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: var(--s4);
  background: var(--scrim);
}
.backdrop[hidden] { display: none; }

.modal {
  width: min(940px, 100%);
  max-height: min(88vh, 900px);
  display: flex;
  flex-direction: column;
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-2);
}
.modal-head { display: flex; align-items: flex-start; gap: var(--s3); padding: var(--s5); border-bottom: 1px solid var(--line); }
.modal-head h2 { font-size: var(--t-xl); }
.modal-head .eyebrow { margin-bottom: var(--s2); }
.modal-body { padding: var(--s6); overflow-y: auto; }

.compare { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--s6); }
.compare-col { display: flex; flex-direction: column; gap: var(--s3); }
.compare-col h3 {
  display: flex; align-items: baseline; gap: var(--s2);
  font-size: var(--t-xs); letter-spacing: 0.1em; text-transform: uppercase;
}
.compare-col h3 .wc { margin-left: auto; color: var(--text-3); font-weight: 400; font-family: var(--mono); }
.compare-col .answer {
  font-family: var(--reading);
  font-size: var(--t-md);
  line-height: 1.75;
  padding: var(--s4);
  background: var(--sunken);
  border-radius: var(--r-sm);
}
.compare-col .why { font-size: var(--t-sm); color: var(--text-2); line-height: 1.6; }
.compare-col .why b { color: var(--text); }

.col-8 h3 { color: var(--ok); }
.col-8 .answer { border-left: 3px solid var(--ok); }
.col-5 h3 { color: var(--err); }
.col-5 .answer { border-left: 3px solid var(--err); }

.compare-note { margin-top: var(--s6); padding-top: var(--s4); border-top: 1px solid var(--line); font-size: var(--t-sm); color: var(--text-3); }

.kbd-list { display: grid; grid-template-columns: auto 1fr; gap: var(--s3) var(--s5); align-items: baseline; }
kbd {
  font-family: var(--mono); font-size: var(--t-xs);
  padding: 3px var(--s2);
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--sunken); white-space: nowrap;
}

/* ── Bookmarks ──────────────────────────────────────────────────────────── */

.bm-list { display: flex; flex-direction: column; gap: var(--s3); }
.bm-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s4) var(--s5);
  background: var(--card);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-1);
  cursor: pointer;
  transition: box-shadow var(--dur) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .bm-row:hover { box-shadow: var(--shadow-2); }
}
.bm-part { font-family: var(--mono); font-size: var(--t-xs); color: var(--text-3); }
.bm-title { flex: 1; font-weight: 500; }

.empty-state {
  padding: var(--s12) var(--s5);
  text-align: center;
  color: var(--text-3);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}

/* ── Mock test ──────────────────────────────────────────────────────────── */

/* The mock test seals the room: while a test runs there is one way out, and it
   asks for confirmation because leaving discards the run (§23). */
body.mock-running .side,
body.mock-running .bar,
body.mock-running .resume-banner { display: none; }
body.mock-running .panes { grid-template-columns: 1fr; }

.mock-setup {
  display: flex;
  flex-direction: column;
  gap: var(--s5);
  padding: var(--s6);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}
.field { display: flex; flex-direction: column; gap: var(--s2); }
.field label { font-size: var(--t-sm); font-weight: 500; color: var(--text-2); }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); }

.text-input {
  width: 100%;
  padding: var(--s3);
  background: var(--sunken);
  color: var(--text);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font: inherit;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.text-input:focus { border-color: var(--accent); background: var(--card); }

.btn-lg { padding: var(--s3) var(--s5); font-size: var(--t-md); justify-content: center; }
.mock-note { font-size: var(--t-sm); color: var(--text-3); }
.mock-note.is-warn {
  display: flex;
  align-items: flex-start;
  gap: var(--s2);
  padding: var(--s3);
  background: var(--p4-tint);
  border-radius: var(--r-sm);
  color: var(--text-2);
}
.mock-note.is-warn .icon { color: var(--warn); flex: none; margin-top: 1px; }

.mock-screen {
  padding: var(--s8) var(--s6);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}

.mock-eyebrow {
  font-size: var(--t-xs); font-weight: 600; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--accent);
}
.mock-intro h2 { font-size: var(--t-2xl); margin: var(--s2) 0; }
.mock-timing { font-family: var(--mono); font-size: var(--t-sm); color: var(--text-3); }
.mock-chip {
  display: inline-block;
  margin: var(--s4) 0;
  padding: var(--s2) var(--s3);
  background: var(--accent-tint);
  color: var(--accent);
  border-radius: var(--r-full);
  font-size: var(--t-sm);
  font-weight: 500;
}
.mock-lead { font-size: var(--t-md); color: var(--text-2); max-width: 56ch; }
.mock-focus {
  margin: var(--s5) 0;
  padding-left: var(--s5);
  display: flex; flex-direction: column; gap: var(--s2);
  color: var(--text-2);
  max-width: 56ch;
}

.mock-answer { margin: var(--s5) 0; display: flex; flex-direction: column; gap: var(--s2); }
.mock-answer label { font-weight: 600; }
.answer-row { display: flex; gap: var(--s3); }
.answer-row .text-input { flex: 1; }

.examiner-row {
  display: flex; align-items: center; gap: var(--s3);
  padding-bottom: var(--s4);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--s5);
}
.examiner-mark {
  display: grid; place-items: center;
  width: 32px; height: 32px;
  border-radius: var(--r-full);
  background: var(--accent-tint); color: var(--accent);
}
.examiner-name { font-weight: 600; }
.examiner-status { margin-left: auto; font-size: var(--t-sm); color: var(--text-3); }

.mock-q {
  font-size: var(--t-2xl);
  font-weight: 600;
  line-height: 1.3;
  margin-bottom: var(--s5);
  max-width: 30ch;
}
.mock-cue { margin-bottom: var(--s5); }
.mock-cue ul { padding-left: var(--s5); font-family: var(--reading); font-size: var(--t-md); line-height: 1.9; color: var(--text-2); }

.mock-guidance {
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--s3) var(--s4);
  background: var(--sunken);
  border-radius: var(--r-sm);
  margin-bottom: var(--s5);
  font-size: var(--t-sm);
  color: var(--text-2);
}
.mock-guidance strong { color: var(--text); }

/* ── Stage: the student's half of the turn ─────────────────────────────── */

.stage {
  display: grid;
  justify-items: center;
  gap: var(--s2);
  padding: var(--s6) 0 var(--s2);
}
.ring-wrap { position: relative; width: 120px; height: 120px; }
.ring { width: 120px; height: 120px; transform: rotate(-90deg); }
.ring-track { fill: none; stroke: var(--sunken); stroke-width: 8; }
.ring-fill {
  fill: none;
  stroke: var(--accent);
  stroke-width: 8;
  stroke-linecap: round;
  transition: stroke-dashoffset 60ms linear;
}
.ring-time {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-size: var(--t-xl);
}
.stage-wave { width: min(100%, 320px); height: 60px; color: var(--meter); }
.stage-time { font-size: var(--t-xl); color: var(--rec); }
.stage-label { font-weight: 600; }
.stage-hint { font-size: var(--t-sm); color: var(--text-3); text-align: center; max-width: 42ch; }
.stage-error { color: var(--err); text-align: center; max-width: 44ch; }

.mock-footer {
  display: flex; align-items: center; gap: var(--s3);
  margin-top: var(--s5);
  padding: var(--s4) var(--s6);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}

/* ── Summary ────────────────────────────────────────────────────────────── */

.mock-summary h2 { font-size: var(--t-2xl); margin-bottom: var(--s3); }
.sum-group { margin-top: var(--s6); }
.sum-group h3 { font-size: var(--t-sm); letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-3); margin-bottom: var(--s3); }
.sum-group ul { list-style: none; padding: 0; display: flex; flex-direction: column; }
.sum-group li {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) 0;
  border-top: 1px solid var(--line);
}
.sum-num { color: var(--text-3); min-width: 20px; }
.sum-q { flex: 1; min-width: 0; }
.sum-state { display: flex; align-items: center; gap: var(--s1); font-size: var(--t-sm); color: var(--text-3); white-space: nowrap; }
.sum-state.has { color: var(--meter); }
.sum-actions { display: flex; flex-wrap: wrap; gap: var(--s3); margin-top: var(--s6); }

.resume-banner {
  display: flex; align-items: center; justify-content: center; gap: var(--s3);
  flex-wrap: wrap;
}

@media (max-width: 560px) {
  .field-row { grid-template-columns: 1fr; }
  .mock-screen { padding: var(--s5) var(--s4); }
  .mock-q { font-size: var(--t-xl); }
  .mock-footer { padding: var(--s3); flex-wrap: wrap; }
}

/* ── Toast, banner, focus ───────────────────────────────────────────────── */

.toast {
  position: fixed;
  left: 50%;
  bottom: var(--s6);
  z-index: 70;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--s3);
  max-width: min(520px, calc(100vw - var(--s8)));
  padding: var(--s3) var(--s4);
  background: var(--card);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
  font-size: var(--t-sm);
  opacity: 1;
  transition: opacity var(--dur) var(--ease);
}
.toast[hidden] { display: none; }
.toast.is-leaving { opacity: 0; }
.toast[data-kind="success"] .icon { color: var(--ok); }
.toast[data-kind="warning"] .icon { color: var(--warn); }
.toast[data-kind="error"] .icon { color: var(--err); }

.banner {
  padding: var(--s3) var(--s5);
  background: var(--p4-tint);
  color: var(--text);
  border-bottom: 1px solid var(--line);
  font-size: var(--t-sm);
  text-align: center;
}
.banner[hidden] { display: none; }

body.focus-mode .side,
body.focus-mode .bar,
body.focus-mode .q-folds,
body.focus-mode .topic-head,
body.focus-mode .progress { display: none; }
body.focus-mode .panes { grid-template-columns: 1fr; }

.focus-flag {
  position: fixed;
  right: var(--s5);
  bottom: var(--s5);
  z-index: 50;
  display: none;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) var(--s3);
  background: var(--card);
  border-radius: var(--r-full);
  box-shadow: var(--shadow-2);
  font-size: var(--t-sm);
}
body.focus-mode .focus-flag { display: flex; }

.fatal {
  max-width: var(--measure);
  margin: var(--s16) auto;
  padding: var(--s6);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}
.fatal h1 { font-size: var(--t-xl); margin-bottom: var(--s3); }
.fatal p { color: var(--text-2); margin-bottom: var(--s4); }

/* ── Narrow: the sidebar becomes a slide-over drawer ────────────────────── */



/* The part's own advice, sitting where an empty pane used to be. Read at the
   moment a student is choosing what to practise, which is when it is worth
   most. */
.empty-tips {
  width: 100%;
  max-width: 520px;
  margin-top: var(--s6);
  padding: var(--s5);
  text-align: left;
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}
.empty-tips-lead {
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--text-2);
  padding-bottom: var(--s4);
  margin-bottom: var(--s4);
  border-bottom: 1px solid var(--line);
}
.empty-tips ul {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  padding: 0;
  list-style: none;
}
.empty-tips li {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--text-2);
}
.empty-tips li .icon { flex: none; margin-top: 2px; color: var(--accent); }


/* Only while recording. Idle, there is nothing to finish, and a permanently
   visible Finish button next to a record button is two ways to say one thing. */
.rec-finish {
  display: none;
  align-items: center;
  gap: var(--s2);
  padding: var(--s2) var(--s4);
  background: var(--text);
  color: var(--card);
  border: none;
  border-radius: var(--r-sm);
  font: inherit;
  font-size: var(--t-sm);
  font-weight: 600;
  cursor: pointer;
}
.rec[data-state="live"] .rec-finish { display: inline-flex; }
/* The global kbd rule fills a chip with the pale --sunken. On this dark button
   that put near-white text on a near-white ground and the key was unreadable.
   On a dark surface the chip has to be an outline, not a fill. */
.rec-finish kbd {
  padding: 1px var(--s2);
  border-radius: 4px;
  background: none;
  border: 1px solid currentColor;
  color: inherit;
  opacity: 0.72;
  font-family: var(--mono);
  font-size: var(--t-xs);
  font-weight: 500;
}




/* -- Check what you wrote -------------------------------------------------- */

.analysis {
  margin-top: var(--s5);
  padding: var(--s4);
  background: var(--bg);
  border-radius: var(--r-md);
}
.analysis-head { font-size: var(--t-sm); font-weight: 600; color: var(--text); }
.analysis-cats { display: flex; flex-wrap: wrap; gap: var(--s2); margin: var(--s3) 0; }
.analysis-cat {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s2) var(--s3);
  background: var(--card);
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  color: var(--text-2);
}
.analysis-cat .icon { color: var(--accent); }
.analysis-note {
  font-size: var(--t-xs);
  line-height: 1.5;
  color: var(--text-3);
  margin-bottom: var(--s3);
  max-width: 56ch;
}

/* -- Useful vocabulary ------------------------------------------------------
   One card per topic, under the questions. The phrases are generated once and
   kept, so this is empty until asked for and instant every time after. */

.vocab {
  margin-top: var(--s6);
  padding: var(--s5);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}
.vocab-head {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--s3);
}
.vocab-note {
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--text-2);
  margin-bottom: var(--s4);
  max-width: 60ch;
}
.vocab-chips { flex-wrap: wrap; gap: var(--s2); }
.vocab-chip[aria-expanded="true"] {
  background: var(--accent);
  color: var(--on-fill);
  border-color: var(--accent);
}

.vocab-detail {
  margin-top: var(--s4);
  padding: var(--s4);
  background: var(--bg);
  border-radius: var(--r-md);
}
.vocab-detail[hidden] { display: none; }
.vocab-word {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-md);
  font-weight: 600;
  color: var(--text);
}
.vocab-word .icon-btn { width: 30px; height: 30px; }
.vocab-meaning { font-size: var(--t-sm); color: var(--text-2); margin-top: var(--s2); }
.vocab-example {
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--text-2);
  margin-top: var(--s2);
  padding-left: var(--s3);
  border-left: 2px solid var(--accent);
  font-style: italic;
}

/* -- Sidebar footer: streak, total, today's goal --------------------------- */

.side-foot {
  flex: none;
  padding: var(--s3) var(--s4) var(--s4);
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.stat-row { display: flex; gap: var(--s2); }
.stat {
  flex: 1;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 var(--s2);
  padding: var(--s3);
  background: var(--sunken);
  border-radius: var(--r-sm);
  font-size: var(--t-xs);
  color: var(--text-3);
}
.stat .icon { width: 15px; height: 15px; align-self: center; }
.stat-flame { color: var(--p4); }
.stat b {
  font-size: var(--t-lg);
  font-weight: 700;
  color: var(--text);
  line-height: 1.1;
}
.stat span { flex-basis: 100%; }

.goal {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3);
  background: var(--accent-tint);
  border-radius: var(--r-md);
}
.goal-body { min-width: 0; }
.goal-title { font-size: var(--t-sm); font-weight: 600; color: var(--text); }
.goal-title span { color: var(--accent); }
.goal-note { font-size: var(--t-xs); line-height: 1.4; color: var(--text-2); margin-top: 2px; }

.goal-ring { width: 38px; height: 38px; flex: none; transform: rotate(-90deg); }
.goal-track, .goal-fill {
  fill: none;
  stroke-width: 3.5;
  stroke-linecap: round;
}
.goal-track { stroke: var(--card); }
/* pathLength="100" makes the dash array a literal percentage, so the markup
   sets one number and no geometry has to be recomputed here. */
.goal-fill { stroke: var(--accent); transition: stroke-dasharray var(--dur) var(--ease); }

/* -- AI Helper --------------------------------------------------------------
   A slide-over between the topic list and the working pane. Deliberately NOT a
   dialog: the question and its recorder stay visible and usable while it is
   open, because the answer still has to be said out loud afterwards. */

.ai-ask {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  flex: none;
  height: 30px;
  padding: 0 var(--s3);
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  color: var(--text-3);
  font: inherit;
  font-size: var(--t-xs);
  font-weight: 600;
  cursor: pointer;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              background var(--dur) var(--ease);
}
.ai-ask .icon { width: 14px; height: 14px; }
@media (hover: hover) and (pointer: fine) {
  .ai-ask:hover { color: var(--accent); border-color: var(--accent); background: var(--accent-tint); }
}

.ai {
  width: 0;
  visibility: hidden;
  overflow: hidden;
  background: var(--card);
  transition: width 220ms var(--ease), visibility 220ms var(--ease);
}
body.ai-open .ai {
  width: var(--ai-w);
  visibility: visible;
  border-right: 1px solid var(--line);
}

/* The contents keep their full width while the track is still narrowing, so
   the panel slides out from under an edge rather than reflowing as it goes. */
.ai-in {
  display: flex;
  flex-direction: column;
  width: var(--ai-w);
  height: 100%;
  min-height: 0;
}

.ai-scrim { display: none; }

.ai-head {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  padding: var(--s4);
  border-bottom: 1px solid var(--line);
}
.ai-head-body { flex: 1; min-width: 0; }
.ai-head h2 {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-base);
  font-weight: 600;
}
.ai-head p { font-size: var(--t-xs); color: var(--text-3); margin-top: 2px; }

.ai-mark {
  display: grid;
  place-items: center;
  width: 32px; height: 32px;
  flex: none;
  border-radius: var(--r-sm);
  background: var(--accent-tint);
  color: var(--accent);
}

.ai-beta {
  padding: 1px var(--s2);
  border-radius: var(--r-full);
  background: var(--accent-tint);
  color: var(--accent);
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.ai-thread {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.ai-context-label {
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
}
.ai-context {
  padding: var(--s3);
  border-left: 2px solid var(--accent);
  background: var(--bg);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  font-size: var(--t-sm);
  line-height: 1.5;
  color: var(--text-2);
}

.ai-actions { display: flex; flex-direction: column; gap: var(--s2); }

.ai-action {
  display: flex;
  align-items: center;
  gap: var(--s3);
  width: 100%;
  padding: var(--s3);
  background: var(--bg);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  color: var(--text);
  font: inherit;
  font-size: var(--t-sm);
  text-align: left;
  cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.ai-action-label { flex: 1; }
.ai-action-mark {
  display: grid;
  place-items: center;
  width: 28px; height: 28px;
  flex: none;
  border-radius: var(--r-sm);
  background: var(--card);
  color: var(--accent);
}
.ai-action-caret { color: var(--text-3); flex: none; }
@media (hover: hover) and (pointer: fine) {
  .ai-action:hover { background: var(--accent-tint); border-color: var(--accent); }
}


/* Quick tips, under the actions. Same words as the empty pane and the mock
   intro; see library/partGuide.js. */
.ai-tips {
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg);
}
.ai-tips-head {
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin-bottom: var(--s3);
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--text);
}
.ai-tips-head .icon { color: var(--accent); }
.ai-tips ul {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  padding: 0;
  list-style: none;
}
.ai-tips li {
  display: flex;
  align-items: flex-start;
  gap: var(--s2);
  font-size: var(--t-sm);
  line-height: 1.5;
  color: var(--text-2);
}
.ai-tips li .icon { flex: none; margin-top: 2px; color: var(--accent); }


/* -- AI panel tabs and Pro tip --------------------------------------------- */

.ai-tabs {
  display: flex;
  gap: var(--s1);
  padding: var(--s2) var(--s4) 0;
  border-bottom: 1px solid var(--line);
}
.ai-tab {
  padding: var(--s2) var(--s3) var(--s3);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  color: var(--text-3);
  font: inherit;
  font-size: var(--t-sm);
  font-weight: 600;
  cursor: pointer;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.ai-tab[aria-selected="true"] { color: var(--accent); border-bottom-color: var(--accent); }

.ai-pro {
  padding: var(--s4);
  background: var(--accent-tint);
  border-radius: var(--r-md);
}
.ai-pro-head {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--accent);
}
.ai-pro-head .icon { color: var(--p4); }
.ai-pro-lead { font-size: var(--t-sm); color: var(--text-2); margin: var(--s2) 0 var(--s3); }
.ai-pro-flow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s2);
  margin-bottom: var(--s3);
}
.ai-pro-flow b { font-size: var(--t-sm); font-weight: 600; color: var(--text); }
.ai-pro-flow i { color: var(--accent); font-style: normal; }

/* -- Messages -------------------------------------------------------------- */

.ai-msg { font-size: var(--t-sm); line-height: 1.6; }
.ai-msg p + p, .ai-msg ul + p, .ai-msg p + ul { margin-top: var(--s2); }
.ai-msg ul { padding-left: var(--s4); display: flex; flex-direction: column; gap: var(--s1); }
.ai-msg strong { font-weight: 600; color: var(--text); }

.ai-msg-me {
  align-self: flex-end;
  max-width: 88%;
  padding: var(--s3);
  border-radius: var(--r-md) var(--r-md) var(--r-sm) var(--r-md);
  background: var(--accent);
  color: var(--on-fill);
}
.ai-msg-ai { color: var(--text-2); }

.ai-msg-error {
  display: flex;
  gap: var(--s2);
  padding: var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg);
  color: var(--text-2);
}
.ai-msg-error .icon { flex: none; color: var(--text-3); }

.ai-thinking { display: flex; gap: 5px; padding: var(--s2) 0; }
.ai-thinking span {
  width: 6px; height: 6px;
  border-radius: var(--r-full);
  background: var(--text-3);
  animation: ai-pulse 1.1s var(--ease) infinite;
}
.ai-thinking span:nth-child(2) { animation-delay: 0.15s; }
.ai-thinking span:nth-child(3) { animation-delay: 0.3s; }
@keyframes ai-pulse {
  0%, 60%, 100% { opacity: 0.25; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}

/* -- Composer -------------------------------------------------------------- */

.ai-composer {
  display: flex;
  align-items: flex-end;
  gap: var(--s1);
  margin: 0 var(--s4);
  padding: var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg);
}
.ai-composer:focus-within { border-color: var(--accent); }
.ai-composer textarea {
  flex: 1;
  min-width: 0;
  /* The notes textarea sets a 90px min-height globally, and it wins over any
     height set here — the composer starts as one line and grows with the text. */
  min-height: 0;
  height: 34px;
  padding: var(--s2);
  background: none;
  border: none;
  resize: none;
  color: var(--text);
  font: inherit;
  font-size: var(--t-sm);
  line-height: 1.4;
}
.ai-composer textarea:focus { outline: none; }
.ai-send { color: var(--accent); }
.ai-mic[aria-pressed="true"] { color: var(--accent); background: var(--accent-tint); }

.ai-fine {
  padding: var(--s2) var(--s4) var(--s4);
  font-size: var(--t-xs);
  line-height: 1.5;
  color: var(--text-3);
}

@media (max-width: 900px) {
  .panes { grid-template-columns: 1fr; }
  .menu-btn { display: inline-flex; }

  .side {
    position: fixed;
    inset: var(--bar-h) auto 0 0;
    z-index: 40;
    width: min(var(--side), 86vw);
    transform: translateX(-100%);
    transition: transform 200ms var(--ease);
    box-shadow: var(--shadow-2);
  }
  .side[data-open="true"] { transform: translateX(0); }

  .scrim {
    position: fixed;
    inset: var(--bar-h) 0 0 0;
    z-index: 35;
    background: var(--scrim);
  }
  .scrim[hidden] { display: none; }

  .ai {
    position: fixed;
    inset: var(--bar-h) auto 0 0;
    z-index: 45;
    width: min(var(--ai-w), 92vw);
    transform: translateX(-100%);
    transition: transform 200ms var(--ease), visibility 200ms var(--ease);
    box-shadow: var(--shadow-2);
  }
  body.ai-open .ai { width: min(var(--ai-w), 92vw); transform: none; }
  .ai-in { width: 100%; }

  body.ai-open .ai-scrim {
    display: block;
    position: fixed;
    inset: var(--bar-h) 0 0 0;
    z-index: 42;
    background: var(--scrim);
  }

  .pane { padding: var(--s4); }
  .topic-head { padding: var(--s5); }
  .topic-head h2 { font-size: var(--t-xl); }
  .scene { display: none; }
  .cue-prompt { font-size: var(--t-xl); }
}

@media (max-width: 560px) {
  /* The bar's five right-hand controls plus their text labels are wider than a
     phone. The labels go and the icons stay: every one of them has an
     aria-label already, so nothing is lost but the width. */
  .bar { gap: var(--s1); padding: 0 var(--s3); }
  .bar-btn .label { display: none; }
  .bar-coach { display: none; }
  /* The mark alone carries the brand at this width. Holding the wordmark on one
     line instead cost 52px and put the bar back over the viewport; letting it
     wrap to two lines looked broken. The link keeps its name via aria-label. */
  .bar .wordmark { display: none; }

  .topic-head { flex-direction: column; }
  .head-actions { align-self: stretch; }
  .rec { grid-template-columns: auto 1fr; gap: var(--s3); }
  .rec-time { grid-column: 2; text-align: right; }
  .rec-finish { grid-column: 1 / -1; justify-content: center; }
  .rec-finish kbd { display: none; }
  .rec-wave { display: none; }
  .q-text { font-size: var(--t-md); }
  .q { padding: var(--s4); }
}

@media (pointer: coarse) {
  .icon-btn, .bar-btn, .part, .topic, .filter { min-height: 44px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
  .pane { scroll-behavior: auto; }
  #boot .brandmark .bar { animation: none; opacity: 0.6; }
  /* The decorative pulse stops; the waveform and timer still carry the
     "you are live" signal, because those are information. */
  .rec[data-state="live"] .rec-btn { animation: none; }
}

/* ── Account ────────────────────────────────────────────────────────────── */

/* The guest notice. Card-weight, not alert-weight: nothing has gone wrong, and
   a red banner over a working app teaches people to dismiss banners. */
.guest-note {
  display: flex;
  gap: var(--s3);
  align-items: flex-start;
  max-width: 720px;
  margin: 0 0 var(--s5);
  padding: var(--s4);
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-1);
}
.guest-note-mark { color: var(--accent); flex: none; margin-top: 1px; }
.guest-note-body { display: flex; flex-direction: column; gap: var(--s2); }
.guest-note-title { font-weight: 600; }
.guest-note-text { font-size: var(--t-sm); color: var(--text-2); line-height: 1.55; }
.guest-note-actions { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s1); }

/* The standing reminder under the streak. Quiet on purpose — it is a fact
   about where the data lives, and it is read once and then lived with. */
.guest-mini {
  display: flex;
  gap: var(--s2);
  align-items: flex-start;
  margin-top: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--line);
  font-size: var(--t-xs);
  line-height: 1.45;
  color: var(--text-3);
}
.guest-mini svg { flex: none; color: var(--warn); margin-top: 1px; }

/* The dialog is sized for a band comparison, which is two columns of prose.
   Three short fields stretched to that width read as a form for something far
   more serious than an email address. */
.backdrop:has(.auth-form) .modal { max-width: 420px; }

.auth-form { display: flex; flex-direction: column; gap: var(--s4); }
.auth-lead { font-size: var(--t-sm); color: var(--text-2); line-height: 1.55; }
.auth-form .field > span { font-size: var(--t-sm); font-weight: 500; color: var(--text-2); }
.auth-form .field em { font-style: normal; font-weight: 400; color: var(--text-3); }

.auth-error {
  padding: var(--s3);
  background: var(--sunken);
  border-left: 3px solid var(--err);
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  color: var(--text);
}

.auth-actions { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; }
.btn-quiet { background: none; border-color: transparent; color: var(--text-2); }
.btn-quiet:hover { color: var(--text); background: var(--sunken); }

.auth-fine {
  display: flex;
  gap: var(--s2);
  align-items: flex-start;
  font-size: var(--t-xs);
  line-height: 1.5;
  color: var(--text-3);
}
.auth-fine svg { flex: none; color: var(--ok); margin-top: 1px; }
