/* ── Design tokens — ported verbatim from initial-docs/dashboard.html & mockup.html (DESIGN §5) ── */
:root{
  --bg:#FBFAF7; --s1:#FFFFFF; --s2:#F1EFE8;
  --t1:#211E1A; --t2:#6B6459; --t3:#9A9384;
  --line:rgba(30,26,20,.09); --line2:rgba(30,26,20,.17);
  --grow:#3E7C6B; --grow-bg:#E7F0EC;
  --gram-t:#B23A3A; --gram-bg:#F8E9E7;
  --phon-t:#8F6112; --phon-bg:#F5ECDB;
  --serif:'Newsreader',Georgia,'Iowan Old Style','Times New Roman',serif;
  --sans:ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  /* Role tokens (additive — DESIGN §5 role-signalling). Do not rename the
     tokens above; these are a second, role-scoped layer used only where
     content needs to say what kind of thing it is (ink + dot, never a fill). */
  --font-mono:ui-monospace,SFMono-Regular,Menlo,monospace;
  --role-good:#356B52; --role-issue:#9A5544;
  --role-grammar:#8A681F; --role-word:#536F82;
  --surface-rewrite:#EDF3EC;
}
[data-theme="dark"]{
  --bg:#14130E; --s1:#1C1B15; --s2:#24221B;
  --t1:#F2EFE7; --t2:#B4AD9E; --t3:#807A6C;
  --line:rgba(255,255,255,.10); --line2:rgba(255,255,255,.18);
  --grow:#6FB8A2; --grow-bg:#13291F;
  --gram-t:#E68A86; --gram-bg:#331615;
  --phon-t:#D9A24A; --phon-bg:#2C2310;
  --role-good:#83B99A; --role-issue:#C98A78;
  --role-grammar:#D9A24A; --role-word:#8AA6B8;
  --surface-rewrite:#1B2A22;
}

*{box-sizing:border-box}
body{
  margin:0;background:var(--bg);color:var(--t1);font-family:var(--sans);
  font-size:15px;line-height:1.5;-webkit-font-smoothing:antialiased;
  transition:background .25s ease,color .25s ease;
}
/* Single column, content-first, mobile-safe (DESIGN §4). Padding stays safe at 380px. */
.wrap{max-width:600px;margin:0 auto;padding:0 20px 72px}
button{font-family:inherit;cursor:pointer}
a{color:inherit}
.ic{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;vertical-align:-3px}

/* ── Masthead ── */
.mast{
  display:flex;align-items:center;gap:12px;padding:18px 0 14px;
  position:sticky;top:0;background:var(--bg);z-index:5;border-bottom:1px solid var(--line);
}
/* The wordmark always pushes everything else to the right edge, so the theme
   toggle stays right-aligned whether or not the mode switch is showing. It's
   also the "go home" control (gate-fix 1) — cursor + a quiet opacity hover,
   never a filled/underlined link treatment, so it stays calm per DESIGN. */
.word{font-family:var(--serif);font-size:21px;font-weight:500;letter-spacing:-.01em;white-space:nowrap;margin-right:auto;cursor:pointer}
.word:hover{opacity:.75}
.word em{font-style:italic;color:var(--grow);font-weight:400}

.switch{display:flex;gap:2px;background:var(--s2);border-radius:10px;padding:3px}
.switch button{border:0;background:transparent;color:var(--t2);font-size:13px;padding:6px 12px;border-radius:8px;white-space:nowrap}
.switch button.on{background:var(--s1);color:var(--t1);font-weight:500}
.switch[hidden]{display:none}

.av{
  width:30px;height:30px;border-radius:50%;background:var(--grow-bg);color:var(--grow);
  display:inline-flex;align-items:center;justify-content:center;
  font-family:var(--serif);font-size:14px;font-weight:500;flex:none;text-transform:uppercase;
}
.av[hidden]{display:none}

.tgl{
  width:32px;height:32px;border-radius:9px;border:1px solid var(--line2);background:transparent;
  color:var(--t2);display:inline-flex;align-items:center;justify-content:center;flex:none;
}
/* Show the moon in light mode (tap → go dark), the sun in dark mode (tap → go light). */
.ic-moon{display:inline-flex}
.ic-sun{display:none}
[data-theme="dark"] .ic-moon{display:none}
[data-theme="dark"] .ic-sun{display:inline-flex}

/* ── Shared shell text ── */
.loading{color:var(--t3);font-size:14px;margin:40px 0}
.greet{font-family:var(--serif);font-size:26px;font-weight:500;letter-spacing:-.01em;margin:30px 0 6px}
.sub{color:var(--t2);font-size:15px;line-height:1.6;margin:0}

.foot{font-family:var(--serif);font-style:italic;color:var(--t3);font-size:15px;text-align:center;margin-top:40px}

.signout{
  display:inline-flex;align-items:center;gap:7px;margin-top:30px;
  background:transparent;border:0;color:var(--t3);font-size:13.5px;padding:0;
}
.signout:hover{color:var(--t2)}

/* ── Login card ── */
.login{
  background:var(--s1);border:1px solid var(--line);border-radius:16px;
  padding:30px 26px;margin:40px 0 0;
}
.login h1{font-family:var(--serif);font-size:24px;font-weight:500;letter-spacing:-.01em;margin:0 0 8px}
.login .lead{color:var(--t2);font-size:15px;line-height:1.6;margin:0 0 22px}
.field{display:flex;flex-direction:column;gap:10px}
.field input{
  width:100%;font-family:inherit;font-size:15px;color:var(--t1);background:var(--bg);
  border:1px solid var(--line2);border-radius:11px;padding:13px 14px;
}
.field input::placeholder{color:var(--t3)}
.field input:focus{outline:none;border-color:var(--grow)}
.field button{
  width:100%;background:var(--t1);color:var(--bg);border:0;border-radius:11px;
  padding:13px 0;font-size:14.5px;font-weight:500;
}
.field button:disabled{opacity:.55;cursor:default}

.notice{
  display:flex;gap:9px;font-size:13.5px;line-height:1.5;color:var(--phon-t);background:var(--phon-bg);
  border-radius:10px;padding:11px 13px;margin:0 0 20px;
}
.notice .ic{flex:none;color:var(--phon-t);width:16px;height:16px}

.sent{margin:8px 0 0;text-align:center}
.sent h1{font-family:var(--serif);font-size:23px;font-weight:500;letter-spacing:-.01em;margin:0 0 10px}
.sent p{color:var(--t2);font-size:15px;line-height:1.65;margin:0 0 6px}
.sent .mail{color:var(--t1);font-weight:500}
.sent .again{
  display:inline-block;margin-top:18px;background:transparent;border:0;
  color:var(--grow);font-size:14px;padding:0;
}

.err{color:var(--gram-t);font-size:13.5px;margin:12px 0 0}

/* ── Admin settings screen ──
   Owner-only. Reuses the shell's tokens verbatim. Single column, stacked rows
   (never a wide table) so it stays safe at 380px with no horizontal scroll. */
.settings-head{margin:30px 0 4px}
.settings-head h1{font-family:var(--serif);font-size:26px;font-weight:500;letter-spacing:-.01em;margin:0 0 6px}
.settings-head p{color:var(--t2);font-size:15px;line-height:1.6;margin:0}

.sect{margin:30px 0 0}
.sect > h2{font-family:var(--serif);font-size:20px;font-weight:500;letter-spacing:-.005em;margin:0 0 4px}
.sect > .hint{color:var(--t3);font-size:13.5px;line-height:1.5;margin:0 0 14px}

/* A credential / task item — a stacked card, never a table row. */
.item{
  background:var(--s1);border:1px solid var(--line);border-radius:12px;
  padding:16px 16px;margin:0 0 12px;
}
.item .row1{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.item .name{font-family:var(--serif);font-size:17px;font-weight:500;color:var(--t1)}
.item .meta{color:var(--t2);font-size:13px}
.item .kv{color:var(--t3);font-size:12.5px;margin-top:4px;word-break:break-word}
.item .acts{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}

/* Small quiet buttons for item actions. */
.mini{
  background:transparent;border:1px solid var(--line2);border-radius:8px;
  color:var(--t2);font-size:13px;padding:6px 11px;font-family:var(--sans);
}
.mini:hover{color:var(--t1)}
.mini.danger{color:var(--gram-t);border-color:var(--gram-bg)}
.mini:disabled{opacity:.5;cursor:default}

/* Enabled pill — reuses the growth-green thread. */
.pill{font-size:11.5px;border-radius:999px;padding:2px 9px;white-space:nowrap}
.pill.on{background:var(--grow-bg);color:var(--grow)}
.pill.off{background:var(--s2);color:var(--t3)}

/* Forms — stacked fields, full width, mobile-safe. */
.form{
  background:var(--s1);border:1px solid var(--line);border-radius:12px;
  padding:18px 16px;margin:0 0 12px;
}
.form h3{font-family:var(--serif);font-size:16px;font-weight:500;margin:0 0 14px}
.form label{display:block;font-size:13px;color:var(--t2);margin:0 0 5px}
.form .grp{margin:0 0 13px}
.form input,.form select,.form textarea{
  width:100%;font-family:inherit;font-size:14.5px;color:var(--t1);background:var(--bg);
  border:1px solid var(--line2);border-radius:10px;padding:11px 12px;
}
.form textarea{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;min-height:66px;resize:vertical}
.form input:focus,.form select:focus,.form textarea:focus{outline:none;border-color:var(--grow)}
.form .note{color:var(--t3);font-size:12px;margin:5px 0 0;line-height:1.45}
.form .submit{
  width:100%;background:var(--t1);color:var(--bg);border:0;border-radius:10px;
  padding:12px 0;font-size:14px;font-weight:500;margin-top:4px;
}
.form .submit:disabled{opacity:.55;cursor:default}

/* Per-task selector — stacked, not a grid, so it survives 380px. */
.task{
  background:var(--s1);border:1px solid var(--line);border-radius:12px;
  padding:16px 16px;margin:0 0 12px;
}
.task .tname{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;color:var(--t2);margin:0 0 10px}
.task .trow{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:10px}
.task .trow .test{flex:none}
.task select,.task input{
  width:100%;font-family:inherit;font-size:14px;color:var(--t1);background:var(--bg);
  border:1px solid var(--line2);border-radius:9px;padding:10px 11px;
}
.task .save{
  background:var(--t1);color:var(--bg);border:0;border-radius:9px;
  padding:9px 16px;font-size:13.5px;font-weight:500;
}
.task .test{
  background:transparent;border:1px solid var(--line2);border-radius:9px;
  color:var(--t2);font-size:13.5px;padding:9px 14px;font-family:var(--sans);
}
.task .save:disabled,.task .test:disabled{opacity:.55;cursor:default}

/* Inline result / error lines — reuse the semantic tokens. */
.result{font-size:13px;border-radius:9px;padding:9px 11px;margin:11px 0 0;line-height:1.5;word-break:break-word}
.result.ok{background:var(--grow-bg);color:var(--grow)}
.result.bad{background:var(--gram-bg);color:var(--gram-t)}
.result pre{margin:6px 0 0;white-space:pre-wrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}

.settings-empty{color:var(--t3);font-size:14px;font-style:italic;margin:0 0 12px}

/* Settings tabs — reuse the masthead segmented-switch idiom, full width. */
.switch.tabs{margin:22px 0 20px;width:100%}
.switch.tabs button{flex:1;text-align:center;font-size:14px;padding:8px 0}

/* The per-task "other…" model input sits just under its select. */
.task select + input[data-role="field"]{margin-top:8px}

/* Advanced (config) — collapsed by default so the form reads friendly. */
.adv{margin:0 0 13px}
.adv > summary{
  cursor:pointer;color:var(--t2);font-size:13px;list-style:none;
  padding:8px 0;border-top:1px solid var(--line);
}
.adv > summary::-webkit-details-marker{display:none}
.adv > summary::before{content:"+ ";color:var(--t3)}
.adv[open] > summary::before{content:"– "}
/* The "other provider" text input reveals under its select. */
#cProviderOther{margin-top:8px}

/* Dev-only sign-in shortcut — amber to read as a build affordance, not the real path. */
.devlogin{
  display:block;width:100%;margin:18px 0 0;background:var(--phon-bg);color:var(--phon-t);
  border:1px dashed var(--phon-t);border-radius:10px;padding:10px 0;font-size:13px;
}
.devlogin:disabled{opacity:.6;cursor:default}

/* ── Cards surface (Today) — add a card, deck list, full card ──
   Ports the mockup's .card/.term/.stress/.def/.ex/.marks/.prov idioms verbatim
   into the shipped token set. Single column, safe at 380px. */

/* Omnibar (SPEC-14 FR-1) — ONE input replaces the old Add / Look up / Search
   boxes. It carries the learner's raw typed word, so it takes the MONO artifact
   role (DESIGN §5 role table). A single quiet inline field, no card chrome:
   typing IS the search (live-filters the deck below); the inline definition +
   Add CTA render into #omniPanel in C-14-002. ≥15px, both themes, 380px-safe. */
.omnibar{margin:24px 0 0}
.omnibar input.mono{
  display:block;width:100%;box-sizing:border-box;min-width:0;
  font-family:var(--font-mono);font-size:15px;color:var(--t1);background:var(--bg);
  border:1px solid var(--line2);border-radius:11px;padding:13px 15px;
}
.omnibar input.mono::placeholder{color:var(--t3);font-family:var(--font-mono)}
.omnibar input.mono:focus{outline:none;border-color:var(--grow)}
/* The inline-definition panel region (filled in C-14-002); empty here. */
#omniPanel:empty{display:none}

/* The looked-up entry panel — a quieter, compact cousin of .card: same term/
   ipa/def idioms, no audio button (no card id, no audio URL on this route),
   no marks/related/yours. Single column, safe at 380px. */
.lookupentry{margin-top:16px;padding-left:16px;border-left:2px solid var(--line2)}
.lookupentry .lhead{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.lookupentry .term{font-family:var(--serif);font-size:22px;font-weight:500;letter-spacing:-.01em;color:var(--t1)}
.lookupentry .ipa{font-size:13.5px;color:var(--t3)}
.lookupentry .lsense{margin-top:14px}
.lookupentry .lsense:first-of-type{margin-top:12px}
.lookupentry .lpos{
  display:inline-block;font-family:var(--sans);font-size:12px;color:var(--t3);
  margin-right:8px;
}
.lookupentry .def{font-family:var(--serif);font-size:18px;line-height:1.5;color:var(--t1);margin:0;letter-spacing:-.005em}
.lookupentry .lex{font-family:var(--serif);font-size:15px;line-height:1.55;color:var(--t2);margin:6px 0 0}

/* The inline-panel actions (SPEC-14 FR-5): a quiet Add/Generate CTA below the
   definition — a text button in the grow ink, never a filled pill (DESIGN role
   language). Sits under the definition's left rail so it reads as one panel.
   The mint error is a quiet inline line (D16), not a toast. Safe at 380px. */
.omniactions{display:flex;align-items:baseline;flex-wrap:wrap;gap:6px 14px;
  margin:16px 0 0;padding-left:16px}
.omnicta{
  font-family:var(--sans);font-size:14px;font-weight:500;letter-spacing:.005em;
  color:var(--grow);background:none;border:none;border-radius:0;padding:2px 0;
  cursor:pointer;
}
.omnicta:hover{color:var(--t1);text-decoration:underline;text-underline-offset:3px}
.omnicta:disabled{color:var(--t3);cursor:default;text-decoration:none}
.omnierr{font-family:var(--sans);font-size:13px;color:var(--role-issue);font-style:italic}

/* The calm minting state while generation runs. */
.minting{
  display:flex;align-items:center;gap:10px;color:var(--t2);font-size:14.5px;
  font-family:var(--serif);font-style:italic;margin:24px 2px 0;
}
.minting .dot{
  width:8px;height:8px;border-radius:50%;background:var(--grow);flex:none;
}
@media (prefers-reduced-motion:no-preference){
  .minting .dot{animation:pulse 1.1s ease-in-out infinite}
  @keyframes pulse{0%,100%{opacity:.3}50%{opacity:1}}
}

/* Deck list — compact rows, term + a meaning snippet. */
.deck{margin:30px 0 0}
.deck h3{font-family:var(--serif);font-size:17px;font-weight:500;letter-spacing:-.005em;margin:0 0 12px;color:var(--t2)}
.deck .empty{color:var(--t3);font-size:14px;font-style:italic;margin:0}
.deckrow{
  display:block;width:100%;text-align:left;background:var(--s1);border:1px solid var(--line);
  border-radius:12px;padding:13px 15px;margin:0 0 9px;font-family:var(--sans);
}
.deckrow:hover{border-color:var(--line2)}
.deckrow .dterm{font-family:var(--serif);font-size:17px;font-weight:500;color:var(--t1);letter-spacing:-.005em}
/* The meaning snippet is content the learner reads, not meta — readability
   floor: 15px, --t2 (DESIGN §5). */
.deckrow .dsnip{color:var(--t2);font-size:15px;line-height:1.5;margin-top:3px;
  display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}

/* Deck header — title, count, set-picker, sort, and "Manage sets", in that
   order. The count is pushed to the right; set-picker/sort/manage wrap onto
   their own line as a group at narrow widths (flex-wrap + each control's own
   flex:0 0 auto) rather than overflowing. Verified at 380px. */
.deckhead{display:flex;align-items:baseline;flex-wrap:wrap;gap:8px 10px;margin:0 0 14px}
.deckhead h3{margin:0}
.deckcount{color:var(--t3);font-size:13px;white-space:nowrap;margin-left:auto}
.decksort{
  flex:0 0 auto;font-family:var(--sans);font-size:14px;color:var(--t1);
  background:var(--bg);border:1px solid var(--line2);border-radius:10px;padding:8px 10px;
}
.decksort:focus{outline:none;border-color:var(--grow)}

/* Set switcher (SPEC-16 FR-7/TRD-2, gate-fix 1) — a quiet "Set:" label next
   to the <select> so it reads as a picker, not a second sort control (it was
   styled identically to .decksort with only "All" showing at 0 sets, so the
   operator couldn't tell it was how you choose a set). Label + select stay
   one inline unit that wraps together at 380px. */
.setpicker{display:inline-flex;align-items:center;gap:5px;flex:0 0 auto}
.setpicklabel{color:var(--t3);font-family:var(--sans);font-size:12.5px;white-space:nowrap}
.setpick{max-width:120px}

/* "Manage sets" (SPEC-16 FR-7/TRD-2) — a header control beside the sort
   select, same quiet <select> idiom (never a per-row deck badge, CON-3).
   "Manage sets" is a plain text button, not a filled control. */
.setsmanage{
  flex:0 0 auto;background:transparent;border:0;padding:8px 2px;
  color:var(--t2);font-family:var(--sans);font-size:13.5px;
  border-bottom:1px solid var(--line2);cursor:pointer;
}
.setsmanage:hover{color:var(--t1);border-bottom-color:var(--grow)}

/* The Manage sets panel — reuses .form/.item/.mini idioms verbatim. Its own
   header row (title + close) sits OUTSIDE .form so it stays pinned above the
   scrollable set list — the only way to close the panel was the header
   "Manage sets" button, which scrolls out of view once the list is long
   (gate-fix 1). */
#setsPanel{margin:0 0 16px}
#setsPanel[hidden]{display:none}
.setspanelhead{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin:0 0 10px}
.setspanelhead h3{font-family:var(--serif);font-size:16px;font-weight:500;margin:0;color:var(--t1)}
.setsclose{
  flex:none;background:transparent;border:0;color:var(--t3);font-size:15px;
  padding:2px 4px;line-height:1;cursor:pointer;
}
.setsclose:hover{color:var(--t1)}
.setsform .grp{margin:0 0 10px}
/* "shared" marker on the built-in set's row — micro-caps ink tag, mirrors
   .fbprofileitem .tag (not .card-scoped, so it needs its own rule here). */
#setsList .tag{
  display:inline-flex;align-items:center;gap:5px;font-family:var(--sans);font-size:10px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--role-word);
}
#setsList .tag::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}

/* A row inside a shared-set browse (FR-6) — same term/snippet layout as a
   deckrow, but not a button (it isn't clickable to open) and ends with an
   explicit "Add to my deck" action instead of an implicit open-row tap. */
.deckrow.sharedrow{
  display:flex;align-items:center;gap:12px;cursor:default;flex-wrap:wrap;
}
.deckrow.sharedrow .dterm{flex:0 0 auto}
.deckrow.sharedrow .dsnip{flex:1 1 160px;margin-top:0}
.deckrow.sharedrow .mini{flex:0 0 auto}

/* Load-more pager — full-width quiet button below the list. */
.deckmore{
  display:block;width:100%;margin:2px 0 0;font-family:var(--sans);font-size:14px;
  color:var(--t2);background:var(--s1);border:1px solid var(--line);border-radius:10px;
  padding:11px 14px;cursor:pointer;
}
.deckmore:hover{border-color:var(--line2);color:var(--t1)}
.deckmore[hidden]{display:none}

/* Back link above an opened card. */
.cardback{
  display:inline-flex;align-items:center;gap:6px;margin:26px 0 0;
  background:transparent;border:0;color:var(--t3);font-size:13.5px;padding:0;font-family:var(--sans);
}
.cardback:hover{color:var(--t2)}

/* ── The full Card component (mockup .card idioms, ported verbatim) ── */
.card{margin-top:22px;padding-left:18px;border-left:2px solid var(--line2)}
.card .chead{display:flex;align-items:baseline;gap:11px;flex-wrap:wrap}
.card .term{font-family:var(--serif);font-size:27px;font-weight:500;letter-spacing:-.01em;color:var(--t1)}
.card .pos{font-size:12.5px;color:var(--t3);font-style:italic}
.card .ipa{font-size:14px;color:var(--t3)}
.card .stress{font-size:13px;color:var(--t3);letter-spacing:.06em}
.card .stress b{font-weight:600;color:var(--t2)}
.card .say{display:flex;align-items:center;gap:7px;margin-left:auto}
/* Density toggle (SPEC-17 FR-4) — a quiet two-state ink control, NEVER a
   filled pill: plain text, the active state just darkens + underlines. Sits
   under the head, tertiary weight (--sans, small, --t3 default). */
.card .denstoggle{display:flex;gap:14px;margin-top:10px}
.card .denstog{
  background:transparent;border:0;padding:0;font-family:var(--sans);
  font-size:12.5px;color:var(--t3);cursor:pointer;
}
.card .denstog:hover{color:var(--t2)}
.card .denstog.on{color:var(--t1);border-bottom:1px solid var(--t1)}
/* Legible inline note for a silent outcome (no audio / retry), so a quiet
   result is never a mystery fade. */
.card .say .saynote{font-size:12px;color:var(--t3);font-style:italic;white-space:nowrap}
.card .rnd{
  width:28px;height:28px;border-radius:50%;border:1px solid var(--line2);background:transparent;
  color:var(--t2);display:inline-flex;align-items:center;justify-content:center;font-size:11px;
  cursor:pointer;transition:border-color .15s,color .15s;position:relative;
}
.card .rnd:hover{border-color:var(--t3);color:var(--t1)}
.card .rnd .ic{width:14px;height:14px}
/* Icons swap by state: play (▶) idle/playing, spinner loading, a dot pulse
   while generating — three distinct pictures so the states read differently
   at a glance, not just by color. */
.card .rnd .ic-spin,.card .rnd .ic-gen{display:none}
.card .rnd[data-state="loading"]{cursor:default}
.card .rnd[data-state="loading"] .ic-play{display:none}
.card .rnd[data-state="loading"] .ic-spin{display:block;animation:spin .7s linear infinite}
/* Playing: accent ring + colour so it's unmistakably active, not just clicked. */
.card .rnd[data-state="playing"]{border-color:var(--grow);color:var(--grow)}
.card .rnd[data-state="playing"] .ic-play{animation:pulse 1s ease-in-out infinite}
/* Generating (FR-5b): a render is in flight server-side. Distinct from plain
   "loading" — amber (the app's existing in-progress/build color, --phon-t),
   a slower dot-pulse, and a visible dashed ring so it never reads as a dead
   or stuck button while we poll. */
.card .rnd[data-state="generating"]{cursor:default;border-style:dashed;border-color:var(--phon-t);color:var(--phon-t)}
.card .rnd[data-state="generating"] .ic-play{display:none}
.card .rnd[data-state="generating"] .ic-gen{display:block;animation:genpulse 1.1s ease-in-out infinite}
.card .rnd[data-state="generating"] ~ .saynote{color:var(--phon-t)}
/* No native recording — the one terminal, quietly dimmed state. */
.card .rnd[data-state="noaudio"]{opacity:.35;cursor:default}
/* Slow-stress drill button (SPEC-09 FR-3/C-09-005): a quiet oval beside the
   round play button, not another circle — "slow" is a text label (no icon
   language reads as clearly as the word itself), so it needs its own pill
   shape rather than squeezing text into the 28px .rnd circle. Same
   idle/loading/playing/generating/noaudio state machine — the underlying
   .rnd rules above (border, hover, per-state coloring) still apply; this
   only overrides shape + adds the text label sizing. */
.card .rnd.slow{width:auto;padding:0 10px;border-radius:99px;gap:4px;font-size:11px;letter-spacing:.02em}
.card .rnd.slow .ic-slow{font-size:11px;line-height:1;color:inherit}
.card .rnd.slow[data-state="loading"] .ic-slow,
.card .rnd.slow[data-state="generating"] .ic-slow{display:none}
/* Prominent (word_stress-risk cards): this IS the drill this control exists
   for — filled amber rather than just outlined, so it's the visually
   louder control on a card where stress is the actual error to fix. */
.card .rnd.slow.prominent{background:var(--phon-bg);border-color:var(--phon-t);color:var(--phon-t)}
.card .rnd.slow.prominent:hover{border-color:var(--phon-t);color:var(--phon-t)}
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes genpulse{0%,100%{opacity:.35;transform:scale(.85)}50%{opacity:1;transform:scale(1.15)}}
.card .def{font-family:var(--serif);font-size:23px;line-height:1.4;color:var(--t1);margin:16px 0 0;letter-spacing:-.005em}
.card .vi{
  display:inline-block;margin-top:8px;font-size:13px;color:var(--t3);
  border-bottom:1px dashed var(--line2);cursor:pointer;
}
.card .vitext{font-size:15px;color:var(--t2);margin:8px 0 0;display:none;line-height:1.6}
.card .vitext.on{display:block}
.card .vitext .vlabel{color:var(--t3);font-size:13px}
/* Richer density (SPEC-17 FR-5a): ALL synonyms, word (--serif, matches .coll
   b's word-as-headword treatment) + a quiet muted nuance_vi gloss. Rides
   inside .vitext, so it shares the show-Vietnamese gate — no new toggle. */
.card .synlist{margin-top:8px;display:flex;flex-direction:column;gap:4px}
.card .synword{font-family:var(--serif);color:var(--t1);font-size:15px}
.card .synvi{color:var(--t3);font-size:13px;margin-left:8px}
.card .coll{font-size:15px;color:var(--t2);margin:16px 0 0;line-height:1.55}
.card .coll b{font-weight:500;color:var(--t1)}
.card .ex{margin:20px 0 0;display:flex;flex-direction:column;gap:14px}
.card .ex .row{display:grid;grid-template-columns:64px 1fr auto;gap:6px;align-items:baseline}
.card .ex .reg{font-size:12.5px;color:var(--t3);padding-top:3px}
.card .ex .sent{font-family:var(--serif);font-size:18px;line-height:1.55;color:var(--t2);text-align:left}
/* The target span: a 2px --grow underline, never bold+color (DESIGN §5). */
.card .ex .sent .target{border-bottom:2px solid var(--grow);color:var(--t1)}
/* Per-example play button — same .rnd + .say idiom as the word pronounce
   button (feature 08), just placed at the end of the example row. On a narrow
   (380px) row it stays a fixed small circle via `auto` grid col, never squeezing
   the sentence text. */
.card .ex .row .say{margin-left:0;align-self:start}
.card .ex .row .say .saynote{white-space:normal}
.card .marks{display:flex;flex-wrap:wrap;gap:14px;align-items:center;margin-top:22px}
/* error_type / phonetic_risk — micro-caps ink tag + dot (DESIGN §6 Badge,
   role-signalling idiom from the feedback tracer's .fbtype/.fbrisk), never a
   filled pill: no background, no radius, text carries the meaning. */
.card .tag{
  display:inline-flex;align-items:center;gap:5px;font-family:var(--sans);
  font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;
}
.card .tag::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
.card .tag.g{color:var(--role-grammar)}
.card .tag.p{color:var(--phon-t)}
/* topics (SPEC-17 FR-5c, richer density) — same micro-caps ink idiom, but a
   NEUTRAL ink color: topics carry no error/risk meaning, so they must not
   reuse .g/.p/.b's role-bound colors. --t2 is the plain secondary-ink token
   (not role-scoped), same as e.g. .coll's body text. */
.card .tag.n{color:var(--t2)}
/* A band tag on the learner's own minted band rewrite (Feature-B) — the same
   micro-caps ink idiom, in the aspirational/good role colour. Sits inline after
   the quoted serif sentence; nudged onto the baseline. */
.card .tag.b{color:var(--role-good);margin-left:8px;vertical-align:baseline}
.card .prov{
  color:var(--grow);display:inline-flex;align-items:center;gap:6px;font-size:13.5px;margin-left:4px;
}
.card .prov .ic{width:14px;height:14px}
/* Related neighbors — a quiet line of linked terms. */
.card .related{margin-top:18px;color:var(--t3);font-size:13.5px;line-height:1.7}
.card .related .rlabel{margin-right:4px}
.card .related .nb{
  color:var(--grow);border-bottom:1px solid var(--line2);cursor:pointer;
  background:transparent;border-top:0;border-left:0;border-right:0;padding:0;
  font-family:var(--sans);font-size:13.5px;margin-right:10px;
}
.card .related .nb:hover{border-bottom-color:var(--grow)}

@media (prefers-reduced-motion:no-preference){.card.reveal-anim{animation:cardup .35s ease}}
@keyframes cardup{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* ── "In sets" toggle control (SPEC-16 FR-2) — lives on the OPENED card only,
   never a per-row deck badge (CON-3). Quiet ink toggles, not filled pills:
   an outlined dot fills solid + the label darkens when a set is active. */
.card .insets{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:18px}
.card .insetslabel{color:var(--t3);font-size:12px;letter-spacing:.04em}
.card .insetsnone{color:var(--t3);font-size:13.5px;font-style:italic}
.card .insetstoggle{
  display:inline-flex;align-items:center;gap:6px;background:transparent;border:0;padding:0;
  color:var(--t2);font-family:var(--sans);font-size:13.5px;cursor:pointer;
}
.card .insetstoggle:hover{color:var(--t1)}
.card .insetstoggle:disabled{opacity:.5;cursor:default}
.card .insetsdot{
  width:9px;height:9px;border-radius:50%;border:1.5px solid var(--t3);flex:none;
  background:transparent;transition:background-color .15s,border-color .15s;
}
.card .insetstoggle.on{color:var(--grow)}
.card .insetstoggle.on .insetsdot{background:var(--grow);border-color:var(--grow)}

/* ── The learner's own private notes — the "yours" section (FR-5) ──
   Quiet and clearly distinct from the AI content above: a muted "yours"
   eyebrow + a soft --line left rule, calm. Own sentences are plain quoted
   serif text — NO --grow target underline (that's AI-content only). Single
   column, safe at 380px; reuses :root tokens + the .form input idioms. */
.card .yours{margin-top:26px;padding-left:14px;border-left:2px solid var(--line)}
.card .youlabel{
  display:block;font-family:var(--sans);font-size:12px;color:var(--t3);
  margin:0 0 8px;letter-spacing:.04em;
}
/* An own example — plain quoted serif, quieter than the AI examples. */
.card .youex{font-family:var(--serif);font-size:17px;line-height:1.55;color:var(--t2);margin:0 0 8px}
/* The learner's note to self. */
.card .younote{font-size:14.5px;line-height:1.6;color:var(--t2);margin:10px 0 0;white-space:pre-wrap}
/* The quiet add/edit affordance — a text button, never a filled control. */
.card .youedit{
  display:inline-block;margin-top:10px;background:transparent;border:0;padding:0;
  color:var(--grow);font-family:var(--sans);font-size:13.5px;
  border-bottom:1px solid var(--line2);cursor:pointer;
}
.card .youedit:hover{border-bottom-color:var(--grow)}

/* ── The inline edit form for "yours" — reuses the .form field idioms ── */
.card .youform{margin-top:12px}
.card .youelist{list-style:none;margin:0 0 10px;padding:0}
.card .youelist[hidden]{display:none}
.card .youerow{display:flex;align-items:baseline;gap:8px;margin:0 0 7px}
.card .youetext{flex:1 1 auto;font-family:var(--serif);font-size:16px;line-height:1.5;color:var(--t2)}
.card .youex-rm{
  flex:none;background:transparent;border:0;color:var(--t3);font-size:13px;
  padding:0 2px;line-height:1;cursor:pointer;
}
.card .youex-rm:hover{color:var(--gram-t)}
.card .youadd,.card .younotein{
  width:100%;font-family:inherit;font-size:14.5px;color:var(--t1);background:var(--bg);
  border:1px solid var(--line2);border-radius:10px;padding:11px 12px;margin:0 0 10px;
}
.card .younotein{line-height:1.55;resize:vertical;min-height:66px}
.card .youadd::placeholder,.card .younotein::placeholder{color:var(--t3)}
.card .youadd:focus,.card .younotein:focus{outline:none;border-color:var(--grow)}
.card .youacts{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.card .yousave{
  background:var(--t1);color:var(--bg);border:0;border-radius:10px;
  padding:9px 18px;font-size:13.5px;font-weight:500;font-family:var(--sans);
}
.card .yousave:disabled{opacity:.55;cursor:default}
.card .youcancel{
  background:transparent;border:0;padding:9px 4px;color:var(--t3);
  font-size:13.5px;font-family:var(--sans);cursor:pointer;
}
.card .youcancel:hover{color:var(--t2)}
.card .youerr{color:var(--gram-t);font-size:13.5px;margin:10px 0 0}

/* ── Reading surface (Read mode) — the input hero (DESIGN §6, FR-7) ──
   Add a source, list sources, and read a source's sentences as prose. Ports
   the mockup's .passage/.target idioms into the shipped token set. Single
   column, safe at 380px — a long passage wraps, controls stack. */

/* Add-a-source box: title + textarea + button, stacked. */
.addsrc{
  background:var(--s1);border:1px solid var(--line);border-radius:16px;
  padding:20px 18px;margin:26px 0 0;
}
.addsrc h2{font-family:var(--serif);font-size:20px;font-weight:500;letter-spacing:-.005em;margin:0 0 14px}
.addsrc .grp{margin:0 0 11px}
.addsrc input,.addsrc textarea{
  width:100%;font-family:inherit;font-size:15px;color:var(--t1);background:var(--bg);
  border:1px solid var(--line2);border-radius:11px;padding:12px 14px;
}
.addsrc textarea{line-height:1.6;resize:vertical;min-height:120px}
.addsrc input::placeholder,.addsrc textarea::placeholder{color:var(--t3)}
.addsrc input:focus,.addsrc textarea:focus{outline:none;border-color:var(--grow)}
.addsrc .add{
  background:var(--t1);color:var(--bg);border:0;border-radius:11px;
  padding:12px 20px;font-size:14.5px;font-weight:500;
}
.addsrc .add:disabled{opacity:.55;cursor:default}
.addsrc .err{color:var(--gram-t);font-size:13.5px;margin:12px 0 0}

/* Sources list — title + a quiet meta line, one row per source. Reused as-is
   for the "Your writing" list in Write mode (SPEC-12 FR-4, #writingList) —
   same calm row idiom, own data (title + date instead of sentence/card
   counts). Token-based (--s1/--t1/--t2/--t3/--line*), so both themes and the
   380px single-column measure hold with no writing-specific overrides. */
.sources{margin:30px 0 0}
.sources h3{font-family:var(--serif);font-size:17px;font-weight:500;letter-spacing:-.005em;margin:0 0 12px;color:var(--t2)}
.sources .empty{color:var(--t3);font-size:14px;font-style:italic;margin:0}
.sources .loading{margin:12px 0 0}
.srcrow{
  display:block;width:100%;text-align:left;background:var(--s1);border:1px solid var(--line);
  border-radius:12px;padding:14px 15px;margin:0 0 9px;font-family:var(--sans);
}
.srcrow:hover{border-color:var(--line2)}
.srcrow .stitle{display:block;font-family:var(--serif);font-size:17px;font-weight:500;color:var(--t1);letter-spacing:-.005em}
.srcrow .smeta{display:block;color:var(--t3);font-size:13px;margin-top:3px}

/* ── The reading pane (DESIGN §6 hero) ──
   Serif --font-read, line-height 1.85, max reading measure ~62ch. Sentences
   flow as prose; each is a selectable .seg. Saved → persistent left --grow
   border; mined (has_card) → the --grow target underline from the mockup. */
.head{margin:26px 0 18px}
.head h2{font-family:var(--serif);font-size:24px;font-weight:500;margin:0;letter-spacing:-.01em;color:var(--t1)}

.passage{
  font-family:var(--serif);font-size:21px;line-height:1.85;color:var(--t2);
  margin:2px 0 0;max-width:62ch;
}
/* A sentence — selectable prose. Quiet by default; selection lifts it to --t1. */
.seg{cursor:pointer;border-radius:4px;transition:background .15s ease,color .15s ease}
.seg:hover{color:var(--t1)}
.seg:focus{outline:none}
.seg:focus-visible{outline:2px solid var(--grow);outline-offset:2px}
.seg.on{color:var(--t1);background:var(--s2)}
/* Saved: a persistent left --grow accent (the one green thread). */
.seg.saved{
  box-shadow:inset 2px 0 0 var(--grow);
  padding-left:7px;border-radius:0 4px 4px 0;
}
/* Mined: the target underline treatment from the mockup (.target). */
.seg.mined .segtext{border-bottom:2px solid var(--grow);color:var(--t1)}

/* A tappable word inside a sentence (SPEC-08 FR-3 / C-08-003). No visible
   chrome at rest — the prose must read exactly as calm as before tapping
   (measure/line-height untouched); only hover/focus hint it's interactive,
   and a dotted underline is quieter than the sentence's own --grow treatment
   so it never competes with the mined target underline. */
.word-tap{cursor:pointer;border-radius:2px}
.word-tap:hover,.word-tap:focus-visible{
  color:var(--t1);border-bottom:1px dotted var(--line2);outline:none;
}

/* The inline lookup panel — DESIGN §6 "inset / Reader margin note" variant:
   left-border accent, reduced fields (term + IPA + short meaning), no full
   card border. Renders IN FLOW right after the tapped word's sentence —
   never position:fixed/absolute (DESIGN anti-pattern, line ~159). Reuses the
   .lookupentry idiom (term/ipa/def) from the Today lookup panel. */
.wordpanel{
  position:relative;display:block;margin:14px 0 18px;padding:12px 34px 14px 16px;
  border-left:2px solid var(--grow);background:var(--s2);border-radius:0 10px 10px 0;
  max-width:62ch;
}
.wordpanel .lhead{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.wordpanel .term{font-family:var(--serif);font-size:19px;font-weight:500;letter-spacing:-.01em;color:var(--t1)}
.wordpanel .ipa{font-size:13px;color:var(--t3)}
.wordpanel .def{font-family:var(--serif);font-size:16px;line-height:1.5;color:var(--t2);margin:8px 0 0}
.wordpanel .empty{color:var(--t3);font-size:14px;font-style:italic;margin:0}
.wpactions{display:flex;align-items:center;gap:14px;margin-top:12px}
.wpok{color:var(--grow);font-family:var(--sans);font-size:13px}
.wperr{color:var(--gram-t);font-size:13px;margin:10px 0 0}
.wpclose{
  position:absolute;top:10px;right:10px;background:transparent;border:0;padding:4px;
  color:var(--t3);line-height:0;cursor:pointer;
}
.wpclose:hover{color:var(--t1)}
.wpclose .ic{width:13px;height:13px}

/* Quiet per-sentence controls, below the passage (never floating). */
.segtools{display:flex;gap:20px;margin:20px 2px 0;flex-wrap:wrap}
.segtool{
  display:inline-flex;align-items:center;gap:7px;background:transparent;border:0;
  color:var(--t2);font-family:var(--sans);font-size:14px;padding:0;
}
.segtool:hover{color:var(--t1)}
.segtool:disabled{opacity:.5;cursor:default}
.segtool .ic{width:16px;height:16px}
.segerr{color:var(--gram-t);font-size:13.5px;margin:12px 2px 0}

/* The inline card minted from a sentence sits below the controls. */
.segcard{margin-top:4px}

/* ── Listening pane (Listen mode, an audio source) — SPEC-09 FR-8, PRD D10 ──
   Player + attempt prompt first; transcript stays HIDDEN behind a single
   quiet "reveal transcript" text control until the learner attempts it by
   ear. No floating overlay — everything stacks below the player, single
   column, safe at 380px. Reuses the .passage/.seg idioms for the revealed
   transcript so it reads exactly like the reading pane. */
.listenpane{margin:2px 0 0;max-width:62ch}
.player{width:100%;display:block;margin:0 0 16px}
/* Content the learner reads (an instruction, not meta) — readability floor:
   --t2 secondary ink, never --t3 muted (DESIGN §5). */
.attemptprompt{
  font-family:var(--serif);font-size:16px;line-height:1.6;color:var(--t2);
  font-style:italic;margin:0 0 16px;
}
/* The reveal control — a single quiet text button (DESIGN reveal-control
   idiom), not a button-styled CTA: revealing the transcript is a deliberate,
   low-emphasis choice, not the primary action of the screen. */
.reveal{
  background:transparent;border:0;padding:0;color:var(--grow);
  font-family:var(--sans);font-size:14.5px;font-weight:500;cursor:pointer;
}
.reveal:hover{color:var(--t1)}

/* A transcript row (once revealed) mirrors .seg exactly; .listenseg adds the
   inline low_conf marker + slow button that only apply to timed audio rows. */
.listenseg{position:relative;padding-right:2px}
.listenseg.untimed{cursor:default}
.lowconf{color:var(--grow);font-size:9px;margin-right:5px;vertical-align:middle}
.segslow{
  display:inline-block;background:transparent;border:0;padding:0 0 0 6px;
  color:var(--t3);font-family:var(--sans);font-size:11.5px;letter-spacing:.02em;
  text-transform:uppercase;cursor:pointer;vertical-align:middle;
}
.segslow:hover{color:var(--t1)}

/* ── Review surface (Review mode) — Focus, deck browser, source→cards ──
   Ports the mockup's REVIEW idioms verbatim: .rv centered card, .rv .term 38px,
   .flip, .grades/.grade (a=Again --gram tint, neutral Good, e=Easy --grow tint),
   .kbd hint (DESIGN §6/U2). NO streak/points/goal UI (§7); the surfaced signal
   is "seen in N sources". Single column, safe at 380px — the three grade cells
   and filter controls stack/wrap cleanly. */

/* Review home — a quiet card with the counts + entries. */
.reviewhome{margin:26px 0 0}
.reviewhome .empty{color:var(--t3);font-size:14px;font-style:italic;margin:24px 0 0}
.rvcard{
  background:var(--s1);border:1px solid var(--line);border-radius:16px;
  padding:24px 20px;
}
/* The Focus set switcher (SPEC-16 FR-7/TRD-2) — a header control, right-
   aligned above the counts. Same quiet <select> idiom as Today's #deckSet. */
.rvsethead{display:flex;justify-content:flex-end;margin:0 0 14px}
.rvsethead .decksort{background:var(--bg)}
/* Count line — plain acquisition state, no streak/goal framing (§7). */
.rvcounts{display:flex;flex-wrap:wrap;gap:16px;margin:0 0 20px}
.rvcount{color:var(--t2);font-size:14px}
.rvcount b{font-family:var(--serif);font-size:20px;font-weight:500;color:var(--t1);margin-right:5px}
.rvstart{
  display:block;width:100%;background:var(--t1);color:var(--bg);border:0;border-radius:12px;
  padding:14px 0;font-size:15px;font-weight:500;font-family:var(--sans);
}
.rvstart:disabled{opacity:.5;cursor:default}
.rventries{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}
.rventry{
  flex:1 1 140px;background:transparent;border:1px solid var(--line2);border-radius:11px;
  color:var(--t2);font-size:14px;padding:11px 0;font-family:var(--sans);
}
.rventry:hover{color:var(--t1);border-color:var(--t3)}

/* ── Focus card (mockup .rv idioms, ported) ── */
.rv{
  background:var(--s1);border:1px solid var(--line);border-radius:20px;
  padding:44px 24px;text-align:center;margin-top:24px;
}
.rv .term{font-family:var(--serif);font-size:38px;font-weight:500;letter-spacing:-.01em;color:var(--t1);line-height:1.15}
.rv .meta{display:flex;gap:12px;align-items:center;justify-content:center;margin-top:12px;flex-wrap:wrap}
.rv .meta .ipa{font-size:14px;color:var(--t3)}
.rv .meta .stress{font-size:13px;color:var(--t3);letter-spacing:.06em}
.rv .meta .stress b{font-weight:600;color:var(--t2)}
.rv .def{font-family:var(--serif);font-size:22px;line-height:1.4;color:var(--t1);max-width:400px;margin:26px auto 0;letter-spacing:-.005em}
.rv .ex{max-width:420px;margin:22px auto 0;text-align:left;display:flex;flex-direction:column;gap:14px}
.rv .ex .row{display:grid;grid-template-columns:64px 1fr;gap:6px;align-items:baseline}
.rv .ex .reg{font-size:12.5px;color:var(--t3);padding-top:3px}
.rv .ex .sent{font-family:var(--serif);font-size:18px;line-height:1.55;color:var(--t2);text-align:left}
.rv .ex .sent .target{border-bottom:2px solid var(--grow);color:var(--t1)}
/* error_type / phonetic_risk — same ink + dot micro-caps tag idiom as the
   Card component (DESIGN §6 Badge, role-signalling), never a filled pill. */
.rv .marks{display:flex;flex-wrap:wrap;gap:14px;align-items:center;justify-content:center;margin-top:22px}
.rv .tag{
  display:inline-flex;align-items:center;gap:5px;font-family:var(--sans);
  font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;
}
.rv .tag::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
.rv .tag.g{color:var(--role-grammar)}
.rv .tag.p{color:var(--phon-t)}
/* topics (SPEC-17 FR-5c, richer density) — neutral ink, mirrors .card .tag.n. */
.rv .tag.n{color:var(--t2)}

/* The flip button — the recall→reveal control. */
.flip{
  border:1px solid var(--line2);background:transparent;color:var(--t1);
  font-size:14.5px;padding:11px 20px;border-radius:11px;margin-top:34px;font-family:var(--sans);
}
.flip .kbd{font-size:12px;color:var(--t3);margin-left:7px}

/* Three equal grade cells (DESIGN §6): Again=--gram tint, Good=neutral,
   Easy=--grow tint. Grid of 3 — wraps cleanly under 380px via minmax. */
.grades{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:11px;max-width:430px;margin:30px auto 0}
.grade{
  padding:14px 4px;border-radius:12px;border:1px solid var(--line);background:var(--s2);
  color:var(--t1);font-size:14.5px;font-family:var(--sans);
}
.grade.a{background:var(--gram-bg);color:var(--gram-t);border-color:transparent}
.grade.e{background:var(--grow-bg);color:var(--grow);border-color:transparent}
.grade:disabled{opacity:.55;cursor:default}

.rvhint{text-align:center;color:var(--t3);font-size:13px;margin-top:18px}

/* The calm "all caught up" end state — no streak, just done (§7). */
.rvdone{
  background:var(--s1);border:1px solid var(--line);border-radius:20px;
  padding:44px 24px;text-align:center;margin-top:24px;
}
.rvdone h2{font-family:var(--serif);font-size:24px;font-weight:500;letter-spacing:-.01em;margin:0 0 10px;color:var(--t1)}
.rvdone p{color:var(--t2);font-size:15px;line-height:1.6;margin:0 auto;max-width:360px}
.rvback{
  display:inline-block;margin-top:22px;background:transparent;border:1px solid var(--line2);
  border-radius:11px;color:var(--t2);font-size:14px;padding:10px 18px;font-family:var(--sans);
}
.rvback:hover{color:var(--t1)}

.hide{display:none!important}

/* ── Swipe mode (SPEC-17 FR-1/2/3/7) ──
   A card stack: at most 2 .swcard nodes at once (current on top, next
   peeking behind), same .rv-scoped content idioms (term/def/ex/marks/tag)
   reused via the shared cardBodyHtml — see the .rv rules above for those.
   The stack itself is position:relative so current/next can overlap without
   the whole column reflowing when a card is removed (FR-7: no full-stack
   relayout). Safe at 380px — the card fills the column, the peeking "next"
   card is capped so it never forces horizontal scroll. */
.swstack{position:relative;margin-top:24px}
/* .swcard is ALSO .card (Task 1: full card, reusing .card's head/audio/body
   rules verbatim — see .card .chead/.rnd/.say/.ex etc above). Reset the
   generic-detail-page .card look (left rule, top margin) that doesn't suit
   a centered stack card; everything below layers swipe's own centered
   treatment on top, same specificity/later-in-source so it wins. */
.swcard{
  margin-top:0;background:var(--s1);border:1px solid var(--line);
  border-radius:20px;padding:36px 24px;text-align:center;touch-action:none;
  will-change:transform,opacity;
}
/* The current card is in flow, so the stack sizes to IT — no fixed min-height,
   so a term-only (un-flipped) card stays compact and the legend sits right
   under it (not 360px below). The next card is absolute BEHIND it. */
.swcard.next{
  position:absolute;top:0;left:0;right:0;
  transform:scale(.96) translateY(10px);visibility:hidden;z-index:1;
}
.swcard.current{position:relative;z-index:2;cursor:grab}
.swcard.current.dragging{cursor:grabbing;transition:none}
@media (prefers-reduced-motion:no-preference){
  .swcard.current{transition:transform .25s ease,opacity .25s ease}
}
.swcard .term{font-family:var(--serif);font-size:38px;font-weight:500;letter-spacing:-.01em;color:var(--t1);line-height:1.15}
/* .swchead is .chead (Task 1's full head: term + pos/ipa/stress + word-audio
   play/slow) laid out centered instead of .card .chead's left-aligned flow —
   same children, swipe's own justify/wrap. */
.swchead{justify-content:center;margin-top:0}
.swchead .say{margin-left:0}
.swcard .meta{display:flex;gap:12px;align-items:center;justify-content:center;margin-top:12px;flex-wrap:wrap}
.swcard .meta .ipa{font-size:14px;color:var(--t3)}
.swcard .meta .stress{font-size:13px;color:var(--t3);letter-spacing:.06em}
.swcard .meta .stress b{font-weight:600;color:var(--t2)}
.swcard .denstoggle{display:flex;gap:14px;justify-content:center;margin-top:14px}
.swcard .denstog{
  background:none;border:0;border-bottom:1px solid transparent;color:var(--t3);
  font-family:var(--sans);font-size:12.5px;padding:0 0 1px;
}
.swcard .denstog:hover{color:var(--t2)}
.swcard .denstog.on{color:var(--t1);border-bottom-color:var(--t1)}
.swcard .def{font-family:var(--serif);font-size:22px;line-height:1.4;color:var(--t1);max-width:400px;margin:26px auto 0;letter-spacing:-.005em}
.swcard .vi{color:var(--t3);font-size:13px;cursor:pointer;border-bottom:1px dotted var(--t3);display:inline-block;margin-top:10px}
.swcard .vitext{font-size:15px;color:var(--t2);margin:8px auto 0;display:none;line-height:1.6;max-width:400px}
.swcard .vitext.on{display:block}
.swcard .coll{font-size:15px;color:var(--t2);margin:16px auto 0;line-height:1.55;max-width:400px}
.swcard .coll b{font-weight:500;color:var(--t1)}
.swcard .ex{max-width:420px;margin:22px auto 0;text-align:left;display:flex;flex-direction:column;gap:14px}
.swcard .ex .row{display:grid;grid-template-columns:64px 1fr;gap:6px;align-items:baseline}
.swcard .ex .reg{font-size:12.5px;color:var(--t3);padding-top:3px}
.swcard .ex .sent{font-family:var(--serif);font-size:18px;line-height:1.55;color:var(--t2);text-align:left}
.swcard .ex .sent .target{border-bottom:2px solid var(--grow);color:var(--t1)}
.swcard .marks{display:flex;flex-wrap:wrap;gap:14px;align-items:center;justify-content:center;margin-top:22px}
.swcard .tag{
  display:inline-flex;align-items:center;gap:5px;font-family:var(--sans);
  font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;
}
.swcard .tag::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
.swcard .tag.g{color:var(--role-grammar)}
.swcard .tag.p{color:var(--phon-t)}
.swcard .tag.n{color:var(--t2)}
.swback{margin-top:0}

/* The three-direction legend — a discoverable but quiet caption, never the
   bold .grades treatment (that's Focus's explicit-click affordance; swipe's
   primary path is the gesture itself). ≥15px per the readability floor for
   real content the learner reads on every card (DESIGN §5). */
.swlegend{
  display:flex;justify-content:center;gap:18px;flex-wrap:wrap;margin-top:20px;
  font-family:var(--sans);font-size:15px;color:var(--t2);
}
/* Tappable grade buttons (also drag + 1/2/3 keys). Quiet — a text button, not a
   filled pill (DESIGN role language); hover/active give the tap affordance. */
.swleg{
  background:none;border:0;font-family:var(--sans);font-size:15px;cursor:pointer;
  padding:6px 10px;border-radius:8px;transition:background .12s;
}
.swleg:hover{background:var(--s1)}
.swleg .kbd{font-size:12px;color:var(--t3);margin-left:4px}
.swleg.a{color:var(--gram-t)}
.swleg.e{color:var(--grow)}
.swleg.g{color:var(--t2)}

/* STUDY mode's per-card footer (FEATURE-16): replaces the grade legend with
   an Add + Next pair, revealed alongside the card body on flip (shares
   .hide with .swback — see swcardHtml/flipSwipeCard). Both buttons reuse
   the existing quiet .mini role (DESIGN role language: a text-ish button,
   never a filled pill) rather than inventing a new visual weight — Add is
   an optional per-card action, not the primary "next" affordance (the drag
   gesture is), so it stays visually quiet like .mini everywhere else. */
.swstudyfoot{
  display:flex;justify-content:center;gap:10px;margin-top:28px;flex-wrap:wrap;
}

/* Always-visible Prev/Next pair (SPEC-16 swipe upgrade, task 2/3): a
   persistent nav control, never hidden-until-flip — sits below whatever
   footer is showing (legend/studyfoot), same quiet .mini role language (a
   text-ish button, never a filled pill), so it reads as a secondary,
   always-available way to move through the stack alongside the primary
   drag gesture. Prev is disabled (not hidden) with no history yet, so the
   control's presence stays predictable card to card. */
.swnav{
  display:flex;justify-content:center;gap:10px;margin-top:16px;flex-wrap:wrap;
}
.swnav .mini:disabled{opacity:.35}

/* ── Deck browser ── */
.deckfilters{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;
  margin:26px 0 4px;
}
.deckfilters .fgrp{display:flex;flex-direction:column;gap:5px}
.deckfilters label{font-size:13px;color:var(--t2)}
.deckfilters select,.deckfilters input{
  width:100%;font-family:inherit;font-size:14px;color:var(--t1);background:var(--bg);
  border:1px solid var(--line2);border-radius:10px;padding:10px 11px;
}
.deckfilters select:focus,.deckfilters input:focus{outline:none;border-color:var(--grow)}

/* A deck-browser row — term + bucket, snippet, badges, provenance. */
.dbrow{
  display:block;width:100%;text-align:left;background:var(--s1);border:1px solid var(--line);
  border-radius:12px;padding:14px 15px;margin:0 0 9px;font-family:var(--sans);
}
.dbrow:hover{border-color:var(--line2)}
.dbhead{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.dbrow .dterm{font-family:var(--serif);font-size:17px;font-weight:500;color:var(--t1);letter-spacing:-.005em}
.dbrow .dbucket{font-size:12px;color:var(--t3)}
/* The meaning snippet is content the learner reads, not meta — readability
   floor: 15px, --t2 (DESIGN §5). */
.dbrow .dsnip{
  display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden;
  color:var(--t2);font-size:15px;line-height:1.5;margin-top:3px;
}
/* error_type / phonetic_risk — same ink + dot micro-caps tag idiom as the
   Card component (DESIGN §6 Badge, role-signalling), never a filled pill. */
.dbrow .dbmarks{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-top:9px}
.dbrow .dbmarks .tag{
  display:inline-flex;align-items:center;gap:5px;font-family:var(--sans);
  font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;
}
.dbrow .dbmarks .tag::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
.dbrow .dbmarks .tag.g{color:var(--role-grammar)}
.dbrow .dbmarks .tag.p{color:var(--phon-t)}
.dbrow .dbprov{display:block;color:var(--grow);font-size:12.5px;margin-top:8px}

/* Review-by-source picker — reuses the sources list idiom below the home card. */
.srcpick{margin:24px 0 0}
.srcpick h3{font-family:var(--serif);font-size:17px;font-weight:500;letter-spacing:-.005em;margin:0 0 12px;color:var(--t2)}
.srcpick .empty{color:var(--t3);font-size:14px;font-style:italic;margin:0}

/* ── Writing surface (Write mode) — SPEC-10 FR-6, DESIGN §6/§7 ──
   Compose (.addsrc, reused as-is) → saved text as plain .seg prose (no mined/
   saved chrome — a writing source isn't read-and-mine, it's compose-and-
   reflect) → "Get feedback" → the calm parallel view. NOT a grader (D13):
   no score/band anywhere, no red-ink; changes are quiet, tappable rows.
   Single column, safe at 380px. */
.wrseg{cursor:default}
.wrseg:hover{color:inherit}

/* Feedback screen (DESIGN §6 "Feedback / correction" — the role-signalling
   tracer). Four roles must read apart at a glance: mono input, serif ideal
   on the ONE surface tint on this screen, sans explanation, micro-caps ink
   tags. No borders/boxes beyond the rewrite tint + the left rail. */
.feedback{margin:24px 0 0;max-width:62ch}
.fbsentence{margin:0 0 48px}
.fbsentence:last-child{margin-bottom:0}
.fbline{margin:0 0 8px}
.fbline .fblabel{
  display:block;font-family:var(--sans);font-size:11px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--t3);margin:0 0 4px;
}
/* User input — the artifact voice: mono, secondary ink, on the flat inset
   surface (never the reading serif — this is raw material, not prose). */
.fboriginal{
  font-family:var(--font-mono);font-size:14px;line-height:1.6;color:var(--t2);
  background:var(--s2);border-radius:8px;padding:10px 12px;margin:0 0 8px;
}
.fboriginal .fblabel{margin-bottom:6px}
/* Ideal/suggested — the editorial conclusion: serif 500, primary ink, on the
   one surface tint this screen uses (elevation = importance), with a short
   role-good rule instead of a border box. */
.fbsuggested{
  font-family:var(--serif);font-weight:500;font-size:17px;line-height:1.6;color:var(--t1);
  background:var(--surface-rewrite);border-radius:8px;padding:10px 12px 10px 14px;
  border-left:2px solid var(--role-good);margin:0;
}

/* Each change lives on a left annotation rail — not a wrapped card. The rail
   is a hairline by default; it warms to role-good on hover/focus so the
   active item reads as "attend here" without a box appearing. */
.fbchanges{display:flex;flex-direction:column;gap:24px;margin-top:24px}
.fbchange{
  max-width:100%;padding-left:14px;border-left:2px solid var(--line);
}
.fbchange:hover,.fbchange:focus-within{border-left-color:var(--role-good)}
/* Category tag — micro-caps ink + dot, never a filled pill. Color signals
   the kind (grammar/mechanics vs word-choice/style) via text, not a fill. */
.fbtype{
  display:flex;align-items:center;gap:5px;font-family:var(--sans);font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--role-grammar);margin:0 0 8px;
}
.fbtype::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
.fbchange-aspirational .fbtype{color:var(--role-word)}
/* Word-level diff — only the changed span carries color, never the row. */
.fbdiff{font-family:var(--sans);font-size:14px;line-height:1.5;color:var(--t1)}
.fbspan{color:var(--role-issue);text-decoration:line-through;text-decoration-thickness:1px}
.fbarrow{color:var(--t3);margin:0 6px}
.fbsug{color:var(--role-good);font-weight:500;text-decoration:underline;text-decoration-style:dotted;text-underline-offset:2px}
/* Appropriacy-risk tag (D14) — ink, not a fill; a gentle "use with care" for
   high risk, never the grammar/issue tone (an aspirational suggestion isn't
   wrong, just risky to use loosely). */
.fbrisk{display:inline-flex;align-items:center;gap:5px;font-size:10.5px;letter-spacing:.03em;margin-left:10px;color:var(--t3)}
.fbrisk::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
.fbrisk-high{color:var(--phon-t)}
.fbrisk-low{color:var(--t3)}
/* Explanation prose is the SUBSTANCE the learner reads to understand the
   mistake — annotation ROLE (sans), but readable, not throwaway meta. 15px
   body size, comfortable line-height, secondary ink (--t2), never the muted
   --t3 (that faded/small combo was unreadable — the "mờ" bug). */
.fbwhy{font-family:var(--sans);color:var(--t2);font-size:15px;line-height:1.6;margin:8px 0 0}
.fbvi{font-family:var(--sans);color:var(--t2);font-size:15px;line-height:1.6;margin:8px 0 0}
/* Action — tertiary, small sans, never competing with the diff above it. */
.fbaction{
  display:inline-block;background:none;border:0;padding:0;margin:10px 0 0;
  font-family:var(--sans);font-size:12.5px;color:var(--t3);text-decoration:underline;
  text-decoration-style:dotted;text-underline-offset:2px;
}
.fbaction:hover{color:var(--t1)}
.fbaction:disabled{opacity:.6;cursor:default}
.fbok{display:block;color:var(--grow);font-family:var(--sans);font-size:12.5px;margin:10px 0 0}

/* ── Feature-13: feedback profiles (switcher, tiered band ladder, editors) ── */

/* Profile switcher — the lens picker. Ink micro-caps buttons in a quiet inset
   track (reuses the .switch idiom's shape); the active lens carries a surface
   lift + role-good text, never a filled pill. */
/* Lens toggle — a segmented control that reads as SELECTABLE (Tony's gate
   feedback: the old flat version looked like a static label). A "Lens:" caption
   labels it, each segment has a visible border + hover, and the selected one is
   filled. Picking a lens only SELECTS (no LLM) — the "Get feedback" button runs. */
.fbprofiles{
  display:flex;flex-wrap:wrap;gap:6px;align-items:center;
  margin:20px 0 14px;
}
.fbprofiles[hidden]{display:none}
.fbprofiles::before{
  content:"Lens:";font-family:var(--sans);font-size:11px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--t3);margin-right:2px;
}
.fbprofile{
  border:1px solid var(--line);background:var(--s1);color:var(--t2);
  font-family:var(--sans);font-size:13px;padding:7px 13px;border-radius:8px;
  white-space:nowrap;cursor:pointer;transition:border-color .12s,background .12s;
}
.fbprofile:hover{border-color:var(--t3);color:var(--t1)}
.fbprofile.on{
  background:var(--t1);border-color:var(--t1);color:var(--bg);font-weight:500;
}
.fbprofile.on:hover{color:var(--bg)}
.fbprofile .fbmine{
  font-size:9.5px;letter-spacing:.05em;text-transform:uppercase;color:var(--role-good);
  margin-left:6px;
}
.fbprofile.on .fbmine{color:var(--bg);opacity:.85}
/* Re-run — a tertiary text action beside "Get feedback" (the exception path). */
.fbrerun{
  border:0;background:none;color:var(--t3);font-family:var(--sans);font-size:13px;
  text-decoration:underline;text-decoration-style:dotted;text-underline-offset:2px;margin-left:2px;
}
.fbrerun:hover{color:var(--t1)}
.fbrerun[hidden]{display:none}

/* Tiered shape — corrected line + note + the band ladder (SPEC-13 FR-3). */
/* Corrected: serif ideal (the grammar-clean version), the changed spans lit. */
.fbcorrected{
  font-family:var(--serif);font-weight:500;font-size:17px;line-height:1.6;color:var(--t1);
  background:var(--surface-rewrite);border-radius:8px;padding:10px 12px 10px 14px;
  border-left:2px solid var(--role-good);margin:0 0 10px;
}
.fbmark{color:var(--role-good);font-style:italic}
/* What-was-wrong note — annotation role, readable (--t2, 15px), never faded. */
.fbnote{font-family:var(--sans);color:var(--t2);font-size:15px;line-height:1.6;margin:8px 0 0}
.fbnote-clean{color:var(--role-good)}

/* "Reads well" positive state on a clean change-list sentence (replaces the
   old "no changes noted" dead-end) — a quiet good-role note, not a throwaway. */
.fbwell{font-family:var(--sans);color:var(--role-good);font-size:15px;line-height:1.6;margin:8px 0 0}

/* Band ladder — three RISING rows that must read apart at a glance (DESIGN law,
   AC-1). The rise is encoded three ways so it's unmistakable in both themes:
   an ascending left-rail weight, a stepped indent, and a band label micro-cap
   that brightens with the band. Not a filled pill anywhere. */
.fbladder{display:flex;flex-direction:column;gap:16px;margin:20px 0 0}
.fbband{
  padding-left:14px;border-left:2px solid var(--line);position:relative;
}
.fbband-0{border-left-color:var(--line2)}
.fbband-1{border-left-color:var(--role-word);margin-left:10px}
.fbband-2{border-left-color:var(--role-good);border-left-width:3px;margin-left:20px}
.fbband-3{border-left-color:var(--phon-t);margin-left:20px}
/* Band tag — micro-caps ink + a rising sub-label, never a pill. */
.fbbandtag{display:flex;align-items:baseline;gap:8px;margin:0 0 6px}
.fbbandlabel{
  font-family:var(--sans);font-size:11px;letter-spacing:.07em;text-transform:uppercase;
  font-weight:600;color:var(--t2);
}
.fbband-1 .fbbandlabel{color:var(--role-word)}
.fbband-2 .fbbandlabel{color:var(--role-good)}
.fbband-3 .fbbandlabel{color:var(--phon-t)}
.fbbandsub{font-family:var(--sans);font-size:11px;letter-spacing:.03em;color:var(--t3)}
/* The rewrite itself — serif ideal, primary ink, ascending emphasis. */
.fbbandtext{font-family:var(--serif);font-size:16px;line-height:1.55;color:var(--t1);margin:0}
.fbband-2 .fbbandtext{font-size:17px;font-weight:500}

/* Unknown-shape fallback (D16) — every field shown as readable annotation with
   its key as a quiet micro-cap. Never blank, never broken. */
.fbfallback{font-family:var(--sans);color:var(--t2);font-size:15px;line-height:1.6;margin:0 0 10px}
.fbfallbackkey{
  display:block;font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--t3);margin:0 0 3px;
}

/* Profile editor (learner "My profiles" + admin shared) — reuses .item/.form/
   .mini/.pill. The prompt/schema inputs are MONO (role language: raw material,
   not prose). A quiet text link opens the learner panel. */
.fbprofilelink{margin:32px 0 0;border-top:1px solid var(--line);padding-top:16px}
.fbeditlink{
  border:0;background:none;color:var(--t2);font-family:var(--sans);font-size:13.5px;
  text-decoration:underline;text-decoration-style:dotted;text-underline-offset:2px;padding:0;
}
.fbeditlink:hover{color:var(--t1)}
.fbeditor{margin:16px 0 0}
.fbeditor > h3{font-family:var(--serif);font-size:18px;font-weight:500;margin:0 0 4px}
.fbeditor > .hint{color:var(--t3);font-size:13.5px;line-height:1.5;margin:0 0 14px}
.form textarea.mono{font-family:var(--font-mono);font-size:12.5px;line-height:1.5}
/* Micro-caps ink tag for a profile row (mirrors .card .tag; not card-scoped). */
.fbprofileitem .tag{
  display:inline-flex;align-items:center;gap:5px;font-family:var(--sans);font-size:10px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--role-good);
}
.fbprofileitem .tag::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
.fbeditslot{margin-top:14px}
.fbeditslot[hidden]{display:none}
