/* ===================================================================
   Language Study — a hairline grid.

   Everything is a rectangle sitting on a shared 1px rule. Adjacent
   blocks overlap by exactly one pixel so their borders collapse into
   a single line and the page reads as one ruled sheet rather than a
   pile of floating cards. Selected states invert — accent fill, page
   background for text — because a hard flip is legible at a glance
   and needs no shadow to sell it.
   =================================================================== */

*, *::before, *::after {
  box-sizing: border-box;
  /* The house rule. Nothing below may reintroduce a curve. */
  border-radius: 0;
}

:root {
  --bg: #0f1117;
  --bg-sunken: #0a0c11;
  --fg: #e8eaf0;
  --fg-warm: #f0e8d0;
  --fg-muted: #a8adba;
  --fg-dim: #757c8c;
  --line: #262a35;
  --line-strong: #3a404f;
  --surface: #151822;
  --surface-hi: #1d212d;
  --accent: #d4b455;
  --accent-ink: #0f1117;
  --accent-soft: #3a3320;
  --ok: #4ade80;
  --ok-soft: #14301f;
  --warn: #fbbf24;
  --warn-soft: #3a2f10;
  --bad: #f87171;
  --bad-soft: #3a1a1a;
  --s1: #ef4444;
  --s2: #f97316;
  --s3: #eab308;
  --s4: #22c55e;
  --s5: #3b82f6;
  /* A grammar pattern in a reading text, beside the accent a word gets. */
  --pattern: #7aa2f7;
  --pattern-soft: #1c2640;

  --sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --mono: ui-monospace, 'Cascadia Mono', 'SF Mono', Consolas, 'Liberation Mono', monospace;

  --gutter: 24px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

:root[data-theme='light'] {
  --bg: #f5f3ec;
  --bg-sunken: #eceadf;
  --fg: #1a1826;
  --fg-warm: #2b1f0e;
  --fg-muted: #565463;
  --fg-dim: #76737f;
  --line: #d3cfc0;
  --line-strong: #b3ae9c;
  --surface: #fbfaf5;
  --surface-hi: #eeebe0;
  --accent: #8a5e12;
  --accent-ink: #fffdf6;
  --accent-soft: #e8dcc0;
  --ok: #157f3c;
  --ok-soft: #d8ecdc;
  --warn: #8a6100;
  --warn-soft: #f2e6c8;
  --bad: #b3261e;
  --bad-soft: #f4dbd8;
  --s1: #c62828;
  --s2: #d3660c;
  --s3: #a47c00;
  --s4: #1c7c3c;
  --s5: #2456a8;
  --pattern: #2456a8;
  --pattern-soft: #dbe3f2;
}

html { color-scheme: dark; }
:root[data-theme='light'] { color-scheme: light; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 14px/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, ul, ol, figure { margin: 0; }
button, input, select, textarea { font: inherit; color: inherit; }

::selection { background: var(--accent); color: var(--accent-ink); }

:where(a):focus-visible,
:where(button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

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

.bar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 var(--gutter);
  height: 52px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

.brand {
  font-weight: 700;
  letter-spacing: 0.14em;
  font-size: 12px;
  text-transform: uppercase;
  color: var(--fg-warm);
  white-space: nowrap;
}
.brand b { color: var(--accent); font-weight: 700; }

.bar-status {
  margin-left: auto;
  font: 11px/1 var(--mono);
  color: var(--fg-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bar-status.is-live { color: var(--ok); }
.bar-status.is-off { color: var(--fg-dim); }

/* ── tabs ─────────────────────────────────────────────────────── */

.tabs {
  display: flex;
  border-bottom: 1px solid var(--line);
  background: var(--bg-sunken);
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }

.tab {
  appearance: none;
  background: none;
  border: 0;
  border-right: 1px solid var(--line);
  padding: 13px 22px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fg-dim);
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.12s, background 0.12s;
}
.tab:hover { color: var(--fg); background: var(--surface-hi); }
.tab[aria-selected='true'] {
  background: var(--accent);
  color: var(--accent-ink);
}
/* Empty space between setup (Settings, Flashcards) and the practice modes,
   so the strip reads as two groups rather than one long row. */
.tab--gap { margin-left: 40px; border-left: 1px solid var(--line); }

/* ── layout ───────────────────────────────────────────────────── */

main { padding: 0 0 96px; }
.panel[hidden] { display: none; }

.wrap {
  max-width: 920px;
  margin: 0 auto;
  padding: 28px var(--gutter);
}
.wrap--wide { max-width: 1180px; }

/* Blocks share their borders: each one pulls up a pixel so two
   stacked rules become one. */
.block {
  border: 1px solid var(--line);
  background: var(--surface);
  margin-top: -1px;
}
.block:first-of-type { margin-top: 0; }

.block-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-sunken);
}
.block-head h2 {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-warm);
}
.block-head .hint {
  font: 11px/1.4 var(--mono);
  color: var(--fg-dim);
  margin-left: auto;
  text-align: right;
}
.block-body { padding: 16px; }
.block-body > * + * { margin-top: 14px; }

.note {
  font-size: 12.5px;
  color: var(--fg-muted);
}
.note strong { color: var(--fg); font-weight: 600; }
.note code, code {
  font: 12px/1.4 var(--mono);
  background: var(--surface-hi);
  border: 1px solid var(--line);
  padding: 1px 4px;
}

/* ── settings sections ────────────────────────────────────────── */

/* Settings is one accordion: a <details> per section, ruled like a block,
   with a one-line summary of what it holds beside the title so a closed
   section still says something. Overlapping by a pixel collapses the rules
   between neighbours, as the blocks do. */
.sec-tools { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 14px; }
.sec-tools input { flex: 1 1 220px; min-width: 0; }
.sec-none { margin-bottom: 14px; }
.sec-group {
  margin: 26px 0 8px;
  font: 600 10.5px/1 var(--sans);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-dim);
}
.sec-group:first-of-type { margin-top: 6px; }
.sec-group[hidden], .sec[hidden] { display: none; }
.sec { border: 1px solid var(--line); background: var(--surface); }
.sec + .sec { margin-top: -1px; }
.sec > summary {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 13px 16px;
  cursor: pointer;
  list-style: none;
}
.sec > summary::-webkit-details-marker, .sec-prompts > summary::-webkit-details-marker { display: none; }
.sec > summary::before, .sec-prompts > summary::before {
  content: '▸';
  flex: none;
  width: 10px;
  color: var(--fg-dim);
  font-size: 11px;
}
.sec[open] > summary::before, .sec-prompts[open] > summary::before { content: '▾'; }
.sec > summary:hover { background: var(--surface-hi); }
.sec[open] > summary { border-bottom: 1px solid var(--line); background: var(--bg-sunken); }
.sec-title {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-warm);
  flex: none;
}
.sec-sum {
  margin-left: auto;
  min-width: 0;
  font: 11px/1.4 var(--mono);
  color: var(--fg-dim);
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sec-body { padding: 16px; }
.sec-body > * + * { margin-top: 14px; }
#voice-device > * + *, #voice-azure > * + * { margin-top: 14px; }
#voice-device[hidden], #voice-azure[hidden] { display: none; }
.sec-sub {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-top: 22px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  font: 600 11px/1.4 var(--sans);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.sec-body > .sec-sub:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.sec-sub .hint { margin-left: auto; font: 11px/1.4 var(--mono); color: var(--fg-dim); text-transform: none; letter-spacing: 0; }
.sec-prompts { border: 1px solid var(--line); background: var(--bg-sunken); }
.sec-prompts > summary {
  display: flex;
  gap: 10px;
  align-items: baseline;
  padding: 10px 12px;
  cursor: pointer;
  list-style: none;
  font: 600 11px/1.4 var(--sans);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.sec-count { font: 11px/1.4 var(--mono); color: var(--fg-dim); }
.sec-prompts-body { padding: 4px 12px 14px; }
.sec-prompts-body > * + * { margin-top: 14px; }

@media (max-width: 560px) {
  .sec > summary { flex-wrap: wrap; }
  .sec-sum { margin-left: 22px; flex-basis: 100%; text-align: left; white-space: normal; }
}

/* ── form controls ────────────────────────────────────────────── */

.field-sub { display: block; margin-top: 4px; font-size: 11.5px; font-style: normal; color: var(--fg-dim); }

.field { display: block; }
.field > span,
.field-head > label {
  display: block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--fg-dim);
  margin-bottom: 5px;
}

input[type='text'],
input[type='password'],
input[type='number'],
select,
textarea {
  width: 100%;
  background: var(--bg-sunken);
  border: 1px solid var(--line-strong);
  color: var(--fg);
  padding: 8px 10px;
  transition: border-color 0.12s;
}
input:hover, select:hover, textarea:hover { border-color: var(--fg-dim); }
input:focus, select:focus, textarea:focus {
  border-color: var(--accent);
  outline: none;
}
input::placeholder, textarea::placeholder { color: var(--fg-dim); }
input:disabled, textarea:disabled, button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
textarea { resize: vertical; font: 13px/1.6 var(--mono); }

/* A field whose label shares its line with a control, such as the Edit and
   Preview switch over each prompt. The label keeps the look of a plain
   field's; the control sits at the right edge, level with it. */
.field-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 5px;
}
.field-head > label { margin-bottom: 0; }
.field-head .seg { flex: none; }
/* Card text quoted in a label keeps its own case: uppercasing a word being
   learnt changes what it says. */
.field > span .as-written {
  text-transform: none;
  letter-spacing: 0;
  font-size: 12px;
  color: var(--fg-muted);
}

/* A prompt as it will be sent. It stands where the prompt was, so it is set
   apart by its background rather than by its place: text that cannot be
   typed into should not look as if it can. */
.prompt-preview { background: var(--surface-hi); color: var(--fg-muted); }
.prompt-preview:hover, .prompt-preview:focus { border-color: var(--line-strong); }
.prompt-warn { color: var(--warn); }

.grid {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.grid--tight { gap: 10px; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }

.row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.row[hidden] { display: none; }
.row--end { justify-content: flex-end; }
.spacer { flex: 1 1 auto; }

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

.btn {
  appearance: none;
  background: var(--surface-hi);
  border: 1px solid var(--line-strong);
  color: var(--fg);
  padding: 8px 14px;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.btn:hover:not(:disabled) { border-color: var(--fg-dim); background: var(--surface); }
.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.btn--primary:hover:not(:disabled) { background: var(--accent); filter: brightness(1.1); }
.btn--danger:hover:not(:disabled) { border-color: var(--bad); color: var(--bad); }
.btn--sm { padding: 5px 9px; font-size: 11.5px; }

/* Segmented control: one strip, hard dividers, inverted selection. */
.seg { display: inline-flex; border: 1px solid var(--line-strong); }
.seg[hidden] { display: none; }
.seg button {
  appearance: none;
  background: none;
  border: 0;
  border-left: 1px solid var(--line-strong);
  padding: 6px 12px;
  font-size: 11.5px;
  /* A fixed line box, so a segment holding an icon is exactly as tall as one
     holding text, whatever font metrics the browser uses. */
  line-height: 16px;
  font-weight: 600;
  color: var(--fg-dim);
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.seg button:first-child { border-left: 0; }
.seg button:hover { color: var(--fg); background: var(--surface-hi); }
.seg button[aria-pressed='true'] { background: var(--accent); color: var(--accent-ink); }

/* ── status line ──────────────────────────────────────────────── */

.status {
  font: 11.5px/1.5 var(--mono);
  color: var(--fg-dim);
  border-top: 1px solid var(--line);
  padding: 8px 16px;
  background: var(--bg-sunken);
}
.status.is-ok { color: var(--ok); }
.status.is-warn { color: var(--warn); }
.status.is-bad { color: var(--bad); }

.banner {
  border: 1px solid var(--line-strong);
  padding: 10px 12px;
  font-size: 12.5px;
  background: var(--bg-sunken);
}
.banner.is-bad { border-color: var(--bad); background: var(--bad-soft); color: var(--fg); }
.banner.is-warn { border-color: var(--warn); background: var(--warn-soft); color: var(--fg); }
/* The backup reminder sits above the tabs' panels, message then buttons. */
.backup-due { padding-top: 16px; padding-bottom: 0; }
.backup-due .banner { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; justify-content: space-between; }

/* ── score squares: the practice window, drawn literally ──────── */

.sq-row { display: inline-flex; gap: 2px; vertical-align: middle; }
.sq {
  width: 11px;
  height: 11px;
  border: 1px solid var(--line-strong);
}
.sq--hit { background: var(--ok); border-color: var(--ok); }
.sq--miss { background: var(--bad); border-color: var(--bad); }
.sq--empty { background: none; }

.score-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font: 11px/1 var(--mono);
  color: var(--fg-muted);
}
.score-dot { width: 9px; height: 9px; display: inline-block; }
.s-1 { background: var(--s1); }
.s-2 { background: var(--s2); }
.s-3 { background: var(--s3); }
.s-4 { background: var(--s4); }
.s-5 { background: var(--s5); }

/* ── the model catalogue ──────────────────────────────────────── */

/* A ruled table, built from the same hairlines as everything else: an id that
   takes whatever width is left, two narrow number columns, and the remove
   button. The header row is labels only, so it carries no border of its own
   and sits directly on the first row's rule. */
.model-list {
  border: 1px solid var(--line);
}
.model-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 96px 96px 30px;
  gap: 8px;
  align-items: center;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
}
.model-row:last-child { border-bottom: 0; }
/* A grid item will not shrink below the intrinsic width of an <input>, which
   for a number field is wider than the column it is given — so every cell is
   told it may. */
.model-row > * { min-width: 0; }
.model-row input[type='text'] { font-family: var(--mono); font-size: 12.5px; }
.model-row input[type='number'] { text-align: right; }
/* The column headings carry these two on a wide screen, so the labels beside
   the fields would only repeat them. On a phone the headings are gone and
   these are the only thing saying which number is which. */
.model-rpm > span, .model-rpd > span { display: none; }

.model-head {
  padding-top: 7px;
  padding-bottom: 6px;
  background: var(--surface-hi);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--fg-dim);
}
.model-head span:nth-child(2), .model-head span:nth-child(3) { text-align: right; }

/* Which jobs this model is doing, under its id. It is the one thing that makes
   a shared model legible at a glance — and the reason a row cannot be removed. */
.model-jobs {
  display: block;
  font-size: 11px;
  color: var(--fg-dim);
  margin-top: 3px;
  min-height: 14px;
}
.model-jobs.is-idle { color: var(--fg-dim); font-style: italic; }

.model-drop {
  background: none;
  border: 1px solid transparent;
  color: var(--fg-dim);
  font: 15px/1 var(--sans);
  padding: 5px 0;
  cursor: pointer;
}
.model-drop:hover:not(:disabled) { color: var(--bad); border-color: var(--bad); }
.model-drop:disabled { opacity: 0.3; cursor: not-allowed; }

/* ── what the budget has been spent on ────────────────────────── */

.usage {
  border: 1px solid var(--line);
  font: 12px/1.5 var(--mono);
}
.usage-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  align-items: baseline;
  padding: 7px 10px;
  border-bottom: 1px solid var(--line);
}
.usage-row:last-child { border-bottom: 0; }
.usage-id { color: var(--fg-warm); flex: 1 1 200px; min-width: 0; overflow-wrap: anywhere; }
.usage-num { color: var(--fg-muted); }
.usage-row.is-blocked .usage-id { color: var(--bad); }
.usage-jobs { color: var(--fg-dim); font-family: var(--sans); font-size: 11px; }

@media (max-width: 560px) {
  /* The numbers keep their width; a model id is long enough that squeezing it
     into what is left would show four characters of it. So it takes the first
     line whole and the two limits sit under it, pushed right against the
     remove button — which is where the header would have put them anyway. */
  .model-row {
    grid-template-columns: minmax(0, 1fr) 76px 76px 26px;
    column-gap: 6px;
    row-gap: 6px;
  }
  .model-id { grid-column: 1 / -1; grid-row: 1; }
  .model-rpm { grid-column: 2; grid-row: 2; }
  .model-rpd { grid-column: 3; grid-row: 2; }
  .model-drop { grid-column: 4; grid-row: 2; align-self: end; }
  .model-head { display: none; }
  .model-rpm > span, .model-rpd > span {
    display: block;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--fg-dim);
    text-align: right;
    margin-bottom: 4px;
  }
}

/* ── voices ───────────────────────────────────────────────────── */

.voice-grid {
  display: grid;
  gap: 0;
  grid-template-columns: repeat(auto-fill, minmax(178px, 1fr));
  border: 1px solid var(--line);
  max-height: 260px;
  overflow: auto;
}
.voice {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  font-size: 12.5px;
  cursor: pointer;
}
.voice:hover { background: var(--surface-hi); }
.voice input { width: auto; accent-color: var(--accent); }
.voice em { font-style: normal; color: var(--fg-dim); font-size: 11px; margin-left: auto; }

/* ── the deck menu ────────────────────────────────────────────── */

/* A <select> can hold one answer; this control holds two — which decks are in
   practice, and which one the editor is showing — so it is built by hand. */
.deck-picker { position: relative; }
.deck-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 12px;
  background: var(--bg-sunken);
  border: 1px solid var(--line-strong);
  color: var(--fg);
  font: inherit;
  font-size: 13.5px;
  text-align: left;
  cursor: pointer;
}
.deck-toggle:hover:not(:disabled) { border-color: var(--fg-dim); }
.deck-toggle[aria-expanded='true'] { border-color: var(--accent); }
.deck-toggle:disabled { opacity: .5; cursor: not-allowed; }
.deck-toggle-name { font-family: var(--mono); color: var(--fg-warm); }
.deck-toggle-sub { color: var(--fg-dim); font-size: 11.5px; }
.deck-toggle-caret { margin-left: auto; color: var(--fg-dim); }

.deck-menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 3px);
  left: 0;
  right: 0;
  max-height: 260px;
  overflow: auto;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .35);
}
.deck-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 2px 10px 2px 11px;
  border-bottom: 1px solid var(--line);
}
.deck-row:last-child { border-bottom: 0; }
.deck-row.is-open { background: var(--surface-hi); }
.deck-row input { width: auto; flex: none; accent-color: var(--accent); cursor: pointer; }
.deck-name {
  flex: 1 1 auto;
  padding: 7px 4px;
  background: none;
  border: 0;
  color: var(--fg);
  font: 13px/1.4 var(--mono);
  text-align: left;
  cursor: pointer;
}
.deck-name:hover { color: var(--accent); }
.deck-row.is-open .deck-name { color: var(--fg-warm); }
.deck-count { color: var(--fg-dim); font-size: 11px; white-space: nowrap; }

/* ── the JSON deck editor ─────────────────────────────────────── */

.editor { min-height: 460px; background: var(--bg-sunken); }
.editor-status { display: flex; gap: 10px; align-items: center; }

/* ── practice card ────────────────────────────────────────────── */

.card {
  border: 1px solid var(--line-strong);
  background: var(--surface);
}
.card-meta {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  padding: 9px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-sunken);
  font: 11px/1.4 var(--mono);
  color: var(--fg-dim);
}
.card-meta .is-warn { color: var(--warn); }
.card-body { padding: 26px 20px; }

.prompt-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-dim);
  margin-bottom: 8px;
}
.prompt {
  font-size: 27px;
  line-height: 1.3;
  font-weight: 600;
  color: var(--fg-warm);
  overflow-wrap: anywhere;
}
.icon-btn { display: inline-flex; align-items: center; justify-content: center; }
.icon-btn svg { display: block; width: 16px; height: 16px; }

/* Voice and speed, dropping down under the speaker button. */
.speech-ctl { position: relative; }
.speech-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 20;
  width: min(300px, calc(100vw - 32px));
  display: grid;
  gap: 10px;
  padding: 12px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
.speech-panel[hidden] { display: none; }
.rate { width: 100%; accent-color: var(--accent); }
.prompt-sub { margin-top: 8px; font-size: 13px; color: var(--fg-muted); }

.answer-input {
  font-size: 19px;
  padding: 11px 12px;
  margin-top: 18px;
}
.answer-input.is-ok { border-color: var(--ok); background: var(--ok-soft); }
.answer-input.is-bad { border-color: var(--bad); background: var(--bad-soft); }

.verdict {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  font-size: 15px;
  font-weight: 600;
  /* The one authored motion moment: the judgement settles in. */
  animation: settle 0.26s var(--ease) both;
}
.verdict.is-ok { color: var(--ok); }
.verdict.is-bad { color: var(--bad); }
.verdict.is-warn { color: var(--warn); }
.verdict .reveal { color: var(--fg-warm); font-weight: 700; }

@keyframes settle {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .verdict { animation: none; }
  * { transition-duration: 0.01ms !important; }
}

.typed-back {
  font-size: 13px;
  color: var(--fg-dim);
  font-family: var(--mono);
}
.typed-back s { color: var(--bad); }
.ch-bad {
  background: var(--warn-soft);
  border-bottom: 2px solid var(--warn);
  color: var(--fg-warm);
}

.notes-box {
  border: 1px solid var(--line);
  background: var(--bg-sunken);
  padding: 10px 12px;
  font-size: 13px;
  color: var(--fg-muted);
}
.notes-box { white-space: pre-wrap; }
.card-edit { display: grid; gap: 10px; }
.notes-edit {
  width: 100%;
  font: inherit;
  font-size: 13px;
  padding: 10px 12px;
  background: var(--bg-sunken);
  color: var(--fg);
  border: 1px solid var(--accent);
  resize: vertical;
}

.prev {
  border: 1px solid var(--line);
  background: var(--bg-sunken);
  padding: 12px 14px;
  font-size: 12.5px;
  color: var(--fg-muted);
}
.prev h3 {
  font: 600 10.5px/1 var(--sans);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fg-dim);
  margin-bottom: 8px;
}
/* Verdict reads from a square marker in the heading, not a coloured
   edge — the same square vocabulary as the history row. */
.prev h3::before {
  content: '';
  width: 8px;
  height: 8px;
  display: inline-block;
  margin-right: 7px;
  background: var(--fg-dim);
}
.prev.is-ok h3::before { background: var(--ok); }
.prev.is-bad h3::before { background: var(--bad); }
.prev.is-warn h3::before { background: var(--warn); }

.tally {
  display: flex;
  gap: 0;
  border: 1px solid var(--line);
}
.tally div {
  flex: 1;
  padding: 8px 12px;
  border-left: 1px solid var(--line);
  background: var(--bg-sunken);
}
.tally div:first-child { border-left: 0; }
.tally b {
  display: block;
  font: 700 19px/1.2 var(--mono);
  color: var(--fg-warm);
}
.tally span {
  font-size: 10.5px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--fg-dim);
}
.tally .is-ok { color: var(--ok); }
.tally .is-bad { color: var(--bad); }

/* ── dictation ────────────────────────────────────────────────── */

.play {
  width: 56px;
  height: 56px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 20px;
  cursor: pointer;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  transition: filter 0.12s;
}
.play:hover:not(:disabled) { filter: brightness(1.12); }

.term-chips { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.chip {
  border: 1px solid var(--line-strong);
  padding: 3px 9px;
  font: 12.5px/1.5 var(--mono);
  color: var(--fg-muted);
  background: var(--bg-sunken);
}
.chip--masked {
  color: var(--fg-dim);
  letter-spacing: 3px;
  user-select: none;
}
.chip--ok { border-color: var(--ok); color: var(--ok); background: var(--ok-soft); }
.chip--bad { border-color: var(--bad); color: var(--bad); background: var(--bad-soft); }
.chip-count {
  font: 11px/1.5 var(--mono);
  color: var(--fg-dim);
  margin-left: 2px;
}

.diff {
  font: 16px/2 var(--mono);
  border: 1px solid var(--line);
  background: var(--bg-sunken);
  padding: 12px 14px;
  overflow-wrap: anywhere;
}
.w { padding: 1px 3px; }
.w-accent { background: var(--warn-soft); border-bottom: 2px solid var(--warn); }
.w-missing { background: var(--bad-soft); border-bottom: 2px solid var(--bad); }
.w-extra { color: var(--fg-dim); text-decoration: line-through; }

.legend { display: flex; gap: 14px; flex-wrap: wrap; font: 11px/1.4 var(--mono); color: var(--fg-dim); }
.legend i { font-style: normal; padding: 0 4px; }

.quota {
  font: 11.5px/1.5 var(--mono);
  color: var(--fg-dim);
}
.quota.is-ok { color: var(--ok); }
.quota.is-bad { color: var(--bad); }

.spinner {
  width: 11px;
  height: 11px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  display: inline-block;
  margin-right: 7px;
  animation: spin 0.7s linear infinite;
  vertical-align: -1px;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── shadowing ────────────────────────────────────────────────── */

/* A smaller play button than the dictation one: there are up to twenty of
   them on a set, two to a line, and the full-size circle would be the only
   thing on the screen. */
.play--sm { width: 34px; height: 34px; font-size: 13px; }
/* "Play your take" sits there from the moment a line is drawn, so it has to
   look inert until there is a take to play. */
.play:disabled { opacity: 0.3; cursor: not-allowed; }

.sh-row {
  border: 1px solid var(--line);
  background: var(--bg-sunken);
  padding: 10px 12px;
}
.sh-row + .sh-row { margin-top: 8px; }
/* A line with a take on it reads as done at a glance, without a tick column
   that would be empty for most of the set most of the time. */
.sh-row.is-done { border-left: 2px solid var(--ok); }

.sh-main { display: flex; gap: 12px; align-items: center; }
.sh-text { flex: 1 1 200px; min-width: 0; }
.sh-line {
  font-size: 15px;
  color: var(--fg-warm);
  overflow-wrap: anywhere;
}
.sh-gloss { font-size: 12px; color: var(--fg-dim); margin-top: 3px; overflow-wrap: anywhere; }
.sh-acts { display: flex; gap: 8px; align-items: center; flex: 0 0 auto; }
.sh-acts .btn { min-width: 84px; }

/* Recording is the one state on this page worth making impossible to miss —
   a microphone you think is off is how a take gets lost. */
.is-rec { animation: rec-pulse 1.1s ease-in-out infinite; }
@keyframes rec-pulse { 50% { opacity: 0.55; } }

.sh-comment {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
  font-size: 13px;
  line-height: 1.6;
  color: var(--fg-muted);
}

.sh-meta { font: 11px/1.5 var(--mono); color: var(--fg-dim); }

/* Rating a note: the four ratings as one segmented strip, and the reason box
   beside it only once a rating asks for one. It wraps under the strip on a
   narrow screen rather than squeezing it. */
.sh-rate { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 8px; }
.sh-rate input { flex: 1 1 200px; min-width: 0; font-size: 12.5px; padding: 5px 8px; }

/* The news that the listening rules changed: what happened, then the buttons. */
.sh-news { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: flex-start; justify-content: space-between; margin-top: 10px; }
.sh-news > div:first-child { flex: 1 1 260px; min-width: 0; }
.sh-news .note { margin-top: 4px; }
.sh-news details { margin-top: 6px; font-size: 12.5px; }
.sh-news summary { cursor: pointer; color: var(--fg-muted); }
.sh-news ul { margin: 6px 0 0 18px; }

/* A hand-in: the lines it carried and its own summary, boxed together so a
   summary is plainly about those lines and no others. */
.sh-handin {
  border: 1px solid var(--line-strong);
  padding: 10px;
}
.sh-handin + .sh-handin { margin-top: 12px; }
.sh-handin--rest { border-style: dashed; }
.sh-handin-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  margin: 0 2px 8px;
  font-size: 13px;
  color: var(--fg-warm);
}
.sh-overall {
  margin-top: 10px;
  padding: 10px 12px;
  background: var(--bg-sunken);
  border-left: 2px solid var(--accent);
  font-size: 13px;
  line-height: 1.6;
  color: var(--fg-muted);
}
.sh-overall p { margin-top: 6px; }
.sh-row--old .sh-line { flex: 1 1 auto; font-size: 13px; color: var(--fg-dim); }
.sh-num {
  display: inline-block;
  min-width: 1.6em;
  font: 11px/1 var(--mono);
  color: var(--fg-dim);
}
.sh-hist-handins { display: flex; flex-direction: column; gap: 4px; margin: 4px 0 0 18px; }
.sh-hist-handin {
  text-align: left;
  border: 1px solid var(--line);
  background: none;
  color: var(--fg-dim);
  font-size: 11.5px;
  padding: 5px 10px;
  cursor: pointer;
}
.sh-hist-handin:hover { border-color: var(--fg-dim); color: var(--fg); }

/* Which lines the next hand-in carries. A quiet line under the take, not a
   column: it matters when handing in, and the words are what you listen to. */
.sh-pick {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  font-size: 11.5px;
  color: var(--fg-dim);
  cursor: pointer;
}
.sh-pick input { margin: 0; }
/* .seg is inline-flex, which would otherwise win over the hidden attribute
   and show the tick shortcuts on a set with nothing recorded yet. */
#sh-pick[hidden] { display: none; }
.sh-pick input:disabled + span { opacity: 0.6; }

/* A note about a take that has since been recorded over: still yours to
   read, but plainly not about what you would hear if you pressed play. */
.sh-comment.is-stale { color: var(--fg-dim); }
.sh-stale {
  display: block;
  font: 11px/1.5 var(--mono);
  color: var(--warn);
  margin-bottom: 4px;
}

/* .notes-box keeps pre-wrap so a dictation sentence shows exactly as written.
   These boxes hold ordinary prose in real elements, so the newlines between
   those elements are markup, not content. */
.sh-box { white-space: normal; }
.sh-box p { font-size: 13px; line-height: 1.65; color: var(--fg-muted); }

.sh-hist { display: flex; gap: 8px; align-items: stretch; }
.sh-hist + .sh-hist,
.sh-hist-handins + .sh-hist { margin-top: 6px; }
.sh-hist-open {
  flex: 1 1 auto;
  text-align: left;
  border: 1px solid var(--line);
  background: var(--bg-sunken);
  color: inherit;
  padding: 8px 10px;
  cursor: pointer;
  display: block;
  min-width: 0;
}
.sh-hist-open:hover { border-color: var(--fg-dim); background: var(--surface-hi); }
.sh-hist-id { font: 12.5px/1.5 var(--mono); color: var(--fg-warm); display: block; }
.sh-hist-sub { font-size: 11.5px; color: var(--fg-dim); display: block; margin-top: 2px; }

@media (max-width: 560px) {
  .sh-main { flex-wrap: wrap; }
  .sh-text { flex: 1 1 100%; order: -1; }
  .sh-acts { margin-left: auto; }
}

/* ── empty / gate states ──────────────────────────────────────── */

.gate {
  border: 1px solid var(--line);
  background: var(--bg-sunken);
  padding: 40px var(--gutter);
  text-align: center;
}
.gate h3 { font-size: 15px; color: var(--fg-warm); margin-bottom: 8px; }
.gate p { font-size: 13px; color: var(--fg-muted); max-width: 54ch; margin: 0 auto 14px; }

/* ── the selection popup ──────────────────────────────────────── */

/* Opens under selected text on any tab, so it is the one thing on the page
   that floats: it gets the menu's shadow, and otherwise the same hairline
   rectangles as everything else. Placed in page coordinates by
   lookup-popup.js, which also keeps it inside the page's gutter. */
.lookup-pop {
  position: absolute;
  z-index: 30;
  width: min(360px, calc(100vw - 32px));
  background: var(--surface);
  border: 1px solid var(--line-strong);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .35);
}
.lookup-pop[hidden] { display: none; }
/* What a selection made by touch gets instead of the form: one button at
   the foot of the window, where it covers no text, no selection handle and
   not the browser's own Copy menu. It keeps clear of a phone's home bar. */
.lookup-chip {
  position: fixed;
  z-index: 30;
  left: 50%;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  max-width: calc(100vw - 32px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .35);
  user-select: none;
  -webkit-user-select: none;
}
.lookup-chip[hidden] { display: none; }

/* ── export ───────────────────────────────────────────────────── */

/* The row under a kept record: Export, the tickbox for its recordings,
   and a line saying what the file is, then what was saved. */
.export-row { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.export-audio {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--fg-muted);
  cursor: pointer;
}
.export-audio[hidden] { display: none; }
.export-audio input { width: auto; margin: 0; accent-color: var(--accent); }
.lookup-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 6px 6px 12px;
  border-bottom: 1px solid var(--line);
  font-size: 11.5px;
  color: var(--fg-dim);
}
.lookup-deck b { font-family: var(--mono); font-weight: 400; color: var(--fg-warm); }
.lookup-close {
  appearance: none;
  background: none;
  border: 0;
  color: var(--fg-dim);
  font-size: 18px;
  line-height: 1;
  padding: 2px 8px;
  cursor: pointer;
}
.lookup-close:hover { color: var(--fg); }
.lookup-body { display: grid; gap: 10px; padding: 12px; }
/* The word, then its translation, each on a line of its own and the full
   width of the popup: side by side they were some 150px each, too narrow to
   read a phrase in. The swap button sits between the two it swaps. */
.lookup-pair { display: grid; gap: 4px; }
.lookup-pair textarea {
  font: 14px/1.45 var(--sans);
  resize: none;
  max-height: 6.4em;
  overflow-y: auto;
}
#lp-front { color: var(--fg-warm); }
.lookup-swap { justify-self: center; padding: 3px 12px; line-height: 1; }
.lookup-pattern {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--fg-muted);
  cursor: pointer;
}
.lookup-pattern input { width: auto; margin: 0; accent-color: var(--accent); }
.lookup-pattern em { font-style: normal; color: var(--fg-dim); font-size: 11px; margin-left: auto; }
.lookup-pop textarea { font: 13px/1.5 var(--sans); }
.lookup-pop .status { padding: 7px 12px; }
.lookup-pop .status:empty { display: none; }

/* ── reading ──────────────────────────────────────────────────── */

/* The stage is one box inside the block, so the block's own spacing does
   not reach the rows in it. */
#rd-stage > * + * { margin-top: 14px; }
#rd-stage > .note { margin-top: 6px; }
/* Three preset buttons do not fit beside the label on a phone; they go
   under it, together, rather than one of them dropping to a line alone. */
.rd-request-head { flex-wrap: wrap; }
#rd-presets { gap: 6px; }
.rd-go { align-items: flex-end; }
.rd-terms { flex: 0 0 110px; }
.rd-title {
  font-size: 21px;
  line-height: 1.35;
  color: var(--fg-warm);
  margin-bottom: 14px;
  overflow-wrap: anywhere;
}
.rd-text {
  font-size: 17px;
  line-height: 1.8;
  color: var(--fg);
  max-width: 68ch;
  overflow-wrap: anywhere;
}
.rd-text p + p { margin-top: 0.9em; }

/* Words and patterns are told apart by colour and by the line under them,
   so the difference does not rest on colour alone: a word is underlined
   solid, a pattern dashed. Once answered, a mark takes the verdict's colour
   and keeps its line. */
.rd-mark {
  font-style: normal;
  padding: 0 1px;
  cursor: pointer;
  border-bottom: 2px solid;
}
.rd-mark--word { background: var(--accent-soft); border-bottom-color: var(--accent); }
.rd-mark--pattern { background: var(--pattern-soft); border-bottom: 2px dashed var(--pattern); }
.rd-mark.is-ok { background: var(--ok-soft); border-bottom-color: var(--ok); }
.rd-mark.is-bad { background: var(--bad-soft); border-bottom-color: var(--bad); }
.rd-text .rd-mark:hover { filter: brightness(1.2); }
.rd-legend { margin-top: 18px; }
.rd-legend .rd-mark { cursor: default; }
.rd-summary {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: 13px;
  color: var(--fg-muted);
}
.rd-summary .note { margin-top: 6px; }

/* The list of kept texts borrows Shadowing's history rows. Whether a text
   has audio is said in words on a badge of its own, filled when there is
   audio and hollow when there is not, so it reads at a glance either way. */
.rd-row-head { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.rd-row-title { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.rd-badge {
  flex: none;
  font: 10.5px/1.4 var(--mono);
  letter-spacing: 0.04em;
  padding: 1px 6px;
  border: 1px solid var(--line-strong);
  color: var(--fg-dim);
}
.rd-badge--audio { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.rd-row.is-open .sh-hist-open { border-color: var(--accent); }

.rd-audio-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  padding-bottom: 16px;
  margin-bottom: 18px;
  border-bottom: 1px solid var(--line);
}
.rd-audio-bar { align-items: flex-end; }
.rd-audio-bar .note { flex: 1 1 220px; align-self: center; }
.rd-voice { flex: 0 1 240px; min-width: 0; }
.rd-audio-bar .note[hidden], .rd-audio-bar .btn[hidden] { display: none; }
.rd-player { display: grid; gap: 8px; width: 100%; }
.rd-player[hidden] { display: none; }
.rd-player audio { width: 100%; }

/* The word popup is the selection popup's box; these are what goes in it. */
.rd-pop-front { font-size: 17px; font-weight: 600; color: var(--fg-warm); overflow-wrap: anywhere; }
.rd-pop-ask { font-size: 13px; color: var(--fg-muted); }
.rd-verdict { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.rd-pop-meaning { font-size: 15px; color: var(--fg); overflow-wrap: anywhere; }
.rd-pop-alts { font-size: 12.5px; color: var(--fg-dim); overflow-wrap: anywhere; }
.rd-pop-notes {
  font-size: 13px;
  line-height: 1.55;
  color: var(--fg-muted);
  white-space: pre-wrap;
  border-left: 2px solid var(--line-strong);
  padding-left: 10px;
  overflow-wrap: anywhere;
}
.rd-pop-score { font: 11.5px/1.5 var(--mono); color: var(--fg-dim); }
.rd-pop-score .is-bad { color: var(--bad); }

/* ── writing ──────────────────────────────────────────────────── */

.wr-topic-row { align-items: flex-end; }
.wr-topic-row .field { flex: 1 1 260px; min-width: 0; }
.wr-brief {
  font-size: 19px;
  line-height: 1.45;
  color: var(--fg-warm);
  overflow-wrap: anywhere;
}
.wr-source { margin-top: 12px; font-size: 13px; }
.wr-source summary { cursor: pointer; color: var(--fg-muted); }
.wr-source-text {
  margin-top: 8px;
  padding: 10px 12px;
  max-height: 320px;
  overflow: auto;
  background: var(--bg-sunken);
  border-left: 2px solid var(--line-strong);
  font-size: 14px;
  line-height: 1.65;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.wr-try { margin-top: 14px; }
#wr-bounds { margin: 12px 0 8px; }
.wr-text { width: 100%; font-size: 15px; line-height: 1.6; }
.wr-written {
  padding: 12px 14px;
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  font-size: 15px;
  line-height: 1.6;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
#wr-count-row { margin-top: 8px; }
.wr-count { font: 12px/1.5 var(--mono); color: var(--fg-dim); }
.wr-count.is-bad { color: var(--bad); }
.wr-count.is-ok { color: var(--ok); }

/* The feedback: short sections, each under a small heading, in the order a
   teacher would go through them. */
.wr-fb { margin-top: 18px; font-size: 14px; line-height: 1.6; color: var(--fg-muted); }
.wr-fb p + p { margin-top: 6px; }
.wr-fb h4 {
  margin: 18px 0 8px;
  font: 600 10.5px/1 var(--sans);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fg-dim);
}
.wr-level { color: var(--fg); }
.wr-level b { color: var(--fg-warm); font-family: var(--mono); }
.wr-points, .wr-list, .wr-cards { list-style: none; padding: 0; display: grid; gap: 8px; }
.wr-points li { display: flex; gap: 8px; align-items: baseline; }
.wr-mark { font-family: var(--mono); flex: none; }
.wr-points .is-ok .wr-mark { color: var(--ok); }
.wr-points .is-bad .wr-mark { color: var(--bad); }
.wr-list li, .wr-cards li { overflow-wrap: anywhere; }
.wr-list b { color: var(--fg); font-weight: 600; }
.wr-sub { display: block; font-size: 12.5px; color: var(--fg-dim); margin-top: 2px; }
.wr-tag {
  font: 10.5px/1.4 var(--mono);
  letter-spacing: 0.04em;
  padding: 1px 6px;
  margin-right: 4px;
  border: 1px solid var(--line-strong);
  color: var(--fg-dim);
}
.wr-cards li { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.wr-cards .wr-sub { flex-basis: 100%; }
.wr-verdict { font: 12px/1.5 var(--mono); color: var(--fg-dim); }
.note.is-bad { color: var(--bad); }
#wr-again-row { margin-top: 16px; }

/* ── translate ────────────────────────────────────────────────── */

.tr-list { list-style: decimal; padding-left: 22px; display: grid; gap: 18px; }
.tr-list li::marker { font: 12px var(--mono); color: var(--fg-dim); }
.tr-en { font-size: 16px; line-height: 1.5; color: var(--fg-warm); margin-bottom: 6px; overflow-wrap: anywhere; }
.tr-input { width: 100%; }
.tr-verdict { margin-top: 8px; display: grid; gap: 6px; font-size: 13.5px; color: var(--fg-muted); }
.tr-head { display: flex; gap: 10px; align-items: center; overflow-wrap: anywhere; }
.tr-head b { color: var(--fg); font-weight: 600; }
.tr-ok { color: var(--ok); }
.tr-item.is-ungraded .tr-head { color: var(--warn); }
.tr-why { font-size: 13px; color: var(--fg-dim); }
.tr-go { margin-top: 18px; }
.tr-summary { flex: 1 1 200px; }
.tr-summary .is-bad { color: var(--bad); }

/* ── conversation ─────────────────────────────────────────────── */

.cv-brief { display: grid; grid-template-columns: max-content 1fr; gap: 4px 14px; font-size: 14px; }
.cv-brief dt { color: var(--fg-dim); font-size: 12.5px; padding-top: 1px; }
.cv-brief dd { margin: 0; color: var(--fg-warm); overflow-wrap: anywhere; }
.cv-facts { margin-top: 14px; padding: 10px 12px; border: 1px solid var(--line); background: var(--bg-sunken); font-size: 13.5px; }
.cv-facts-head { font: 600 10.5px/1.4 var(--sans); letter-spacing: 0.09em; text-transform: uppercase; color: var(--fg-dim); margin-bottom: 6px; }
.cv-facts ul { list-style: none; padding: 0; display: grid; gap: 4px; }
.cv-facts li { display: flex; gap: 8px; align-items: baseline; color: var(--fg-muted); }
.cv-facts li.is-ok { color: var(--fg); }
.cv-facts li.is-ok .wr-mark { color: var(--ok); }
/* The cards to try to use, in Writing and Conversation: each one's front
   and its meaning, in plain view. */
.try-list li { display: flex; flex-wrap: wrap; gap: 2px 10px; align-items: baseline; }
.try-front { color: var(--fg-warm); font-weight: 600; }
.try-back { font-size: 12.5px; color: var(--fg-dim); }
.try-list[hidden] { display: none; }

/* The chat: the other person on the left, you on the right, each line in a
   ruled box rather than a rounded bubble, as everything here is. */
.cv-chat { display: grid; gap: 10px; margin: 18px 0 14px; }
.cv-bubble {
  max-width: 82%;
  padding: 8px 12px;
  border: 1px solid var(--line-strong);
  background: var(--surface-hi);
  display: grid;
  gap: 2px;
}
.cv-bubble--them { justify-self: start; }
.cv-bubble--me { justify-self: end; border-color: var(--accent); background: var(--accent-soft); }
.cv-who { font: 10.5px/1.4 var(--mono); letter-spacing: 0.04em; color: var(--fg-dim); }
.cv-said { font-size: 15px; line-height: 1.5; color: var(--fg); white-space: pre-wrap; overflow-wrap: anywhere; }
.cv-thinking .cv-said { color: var(--fg-dim); font-size: 13px; }
.cv-turn { font: 12px/1.5 var(--mono); color: var(--fg-dim); margin-bottom: 6px; }
#cv-input-area .row { margin-top: 8px; }
.cv-turns { padding-left: 22px; display: grid; gap: 10px; }
.cv-natural { margin-top: 2px; }
.cv-natural b { color: var(--ok); font-weight: 600; }
#cv-done-row { margin-top: 16px; }
.cv-speak { margin-bottom: 8px; }
.cv-take { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 8px; }
.cv-take audio { flex: 1 1 240px; min-width: 0; }
.cv-take[hidden] { display: none; }
.cv-play {
  margin-left: 6px;
  padding: 0 5px;
  border: 1px solid var(--line-strong);
  background: none;
  color: var(--fg-muted);
  font-size: 10px;
  cursor: pointer;
}
.cv-play:hover { color: var(--fg); border-color: var(--fg-dim); }

/* A live conversation: two dots that swell as each side speaks (the other
   person ruled, you in the accent, as in the chat), the clock and a bar of
   time used. */
.lv-stage { margin-top: 18px; padding: 16px; border: 1px solid var(--line); background: var(--bg-sunken); display: grid; gap: 10px; justify-items: center; text-align: center; }
.lv-stage[hidden] { display: none; }
.lv-stage .note { max-width: 56ch; }
.lv-meters { display: flex; gap: 28px; padding: 10px 0; }
.lv-meter { width: 34px; height: 34px; display: grid; place-items: center; }
.lv-meter i { display: block; width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--fg-dim); transition: transform 80ms linear; }
.lv-meter--me i { border-color: var(--accent); background: var(--accent-soft); }
.lv-stage.is-live .lv-meter i { border-color: var(--fg); }
.lv-stage.is-live .lv-meter--me i { border-color: var(--accent); }
.lv-clock { font: 600 28px/1 var(--mono); color: var(--fg-warm); }
.lv-clock[hidden], .lv-timebar[hidden] { display: none; }
.lv-timebar { width: min(320px, 100%); height: 4px; background: var(--line); overflow: hidden; }
.lv-timebar span { display: block; height: 100%; background: var(--accent); transform: scaleX(0); transform-origin: left; transition: transform 250ms linear; }
.lv-controls { justify-content: center; }

/* Its feedback: the percentage and the four marks, then the conversation
   written out with a teacher's pen, struck through and written over. */
.lv-score { display: flex; align-items: baseline; gap: 12px; margin-bottom: 8px; }
.lv-pct { font: 600 34px/1 var(--mono); color: var(--fg-warm); }
.lv-pct-label { font-size: 13px; color: var(--fg-dim); }
.lv-bands { list-style: none; padding: 0; display: grid; gap: 6px; margin-bottom: 12px; }
.lv-bands li { display: flex; flex-wrap: wrap; gap: 2px 12px; align-items: baseline; }
.lv-band-name { min-width: 110px; color: var(--fg); }
.lv-dots { font-family: var(--mono); letter-spacing: 0.1em; color: var(--accent); }
.lv-bands .wr-sub { flex-basis: 100%; margin-top: 0; }
.lv-lines { list-style: none; padding: 0; display: grid; gap: 10px; }
.lv-line { display: grid; gap: 2px; padding: 8px 12px; border: 1px solid var(--line-strong); }
.lv-line--me { border-color: var(--accent); background: var(--accent-soft); }
.lv-fix { margin-top: 2px; }
.lv-fix del { color: var(--bad); }
.lv-fix ins { color: var(--ok); text-decoration: none; font-weight: 600; }
.lv-notes { padding-left: 18px; display: grid; gap: 4px; }
.lv-notes b { color: var(--fg-warm); margin-right: 4px; }

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

@media (max-width: 720px) {
  :root { --gutter: 16px; }
  .bar { height: auto; padding: 10px var(--gutter); flex-wrap: wrap; gap: 8px; }
  .bar-status { width: 100%; margin-left: 0; order: 3; }
  .tab { padding: 12px 15px; font-size: 11px; }
  .tab--gap { margin-left: 20px; }
  .prompt { font-size: 22px; }
  .wrap { padding: 18px var(--gutter); }
  /* Three short labels still fit across a phone; wrapping them would leave
     half a row empty. */
  .tally div { padding: 8px; }
  .tally b { font-size: 17px; }
}
