
:root {
  /* Dark theme — the original CantoTone palette, preserved in
     styles.dark-backup.css. Variables only; component styles below
     reference these. Switch palettes by adding/removing `theme-light`
     on the <html> element. */
  --gold: #caa23a;         /* tamed pricing/TTS gold (dark base) */
  --gold-hover: #d8b24c;
  --gold-fg: #221902;
  --gold-border: #caa23a;
  --bg: #0f1115;
  --panel: #171a21;
  --panel-2: #1e222c;
  --border: #2a2f3a;
  --text: #e7e9ee;
  --muted: #9aa1b1;
  --accent: #ff6b6b;
  --accent-2: #4ec9b0;
  --target: #6aa9ff;
  /* Derived shades — kept as vars so light theme can override cleanly */
  --hover: #262b37;
  --primary-fg: #1a0a0a;
  --recording: #ff3838;
  --native-bg: #1f4d3f;
  --native-bg-hover: #266753;
  --native-fg-hover: #d6f5ec;
  --tts-fg: #d6b384;
  --tts-fg-hover: #f0dcb8;
  --tts-border: #b89154;
  --tts-bg: #4a3b1c;
  --tts-bg-hover: #5f4c24;
  --shadow-card: 0 6px 18px rgba(0, 0, 0, 0.25);
  --shadow-panel: 0 0 0 transparent;
  --chart-axis: #9aa1b1;
  --chart-grid: #2a2f3a;
  --chart-text: #e7e9ee;
}

:root.theme-light {
  /* Brand "Cream" theme — the primary WingTone look and the default the app
     boots into. Cohesive with the 翼音 landing page: warm cream surfaces,
     warm ink text, gold accents. Brand red / teal / blue keep their semantic
     roles (red = record/primary, teal = active/native, blue = target line). */
  --bg: #f6f0e6;           /* cream — landing surface */
  --panel: #fffdf9;        /* warm near-white card */
  --panel-2: #f1e8d8;      /* warm cream inset */
  --border: #e3d9c8;       /* warm hairline */
  --text: #2a2418;         /* warm ink */
  --muted: #75695a;        /* warm muted */
  --accent: #c8324a;       /* brand red — record / primary / sign-in */
  --accent-2: #0d8a6c;     /* brand teal — active / native */
  --target: #2563eb;       /* brand blue — target tone line */
  --hover: #ece1cf;        /* warm cream hover */
  --primary-fg: #ffffff;
  --recording: #d92020;
  --native-bg: #dcefe4;    /* soft teal tint on cream */
  --native-bg-hover: #c9e6d7;
  --native-fg-hover: #0a5d4a;
  --tts-fg: #8a5d12;       /* gold-brown ink */
  --tts-fg-hover: #6b4709;
  --tts-border: #d4b877;   /* warm gold */
  --tts-bg: #f6e8ca;       /* warm gold tint */
  --tts-bg-hover: #efdcb2;
  --shadow-card: 0 10px 28px rgba(122, 94, 30, 0.12);   /* warm brown */
  --shadow-panel: 0 1px 2px rgba(122, 94, 30, 0.06);
  --chart-axis: #75695a;
  --chart-grid: #e6dcc9;
  --chart-text: #2a2418;
  /* Tamed gold (pricing / TTS / calibrate) — matches the landing gold. */
  --gold: #d29420;
  --gold-hover: #e0a52f;
  --gold-fg: #2a1d02;
  --gold-border: #d29420;
}

:root.theme-pastel {
  /* "Light" theme — a clean, crisp white look (the neutral counterpart to the
     warm Cream default). Cool near-white surfaces, near-black ink; brand red /
     teal / blue keep their semantic roles (record / native / target). Internal
     id stays `pastel` for backwards-compatible saved prefs. */
  --gold: #d29420;         /* warm pricing/TTS gold (reads on white) */
  --gold-hover: #e0a52f;
  --gold-fg: #2a1d02;
  --gold-border: #d29420;
  --bg: #f7f8fa;           /* clean near-white page */
  --panel: #ffffff;        /* pure white card (pops off the bg) */
  --panel-2: #eef0f3;      /* light grey inset */
  --border: #e4e6eb;       /* cool hairline */
  --text: #1c1f26;         /* near-black ink */
  --muted: #616776;        /* cool grey */
  --accent: #c8324a;       /* brand red — record / primary / sign-in */
  --accent-2: #0d8a6c;     /* brand teal — active / native */
  --target: #2563eb;       /* brand blue — target tone line */
  --hover: #eef0f3;
  --primary-fg: #ffffff;
  --recording: #d92020;
  --native-bg: #e6f4ee;    /* soft teal tint on white */
  --native-bg-hover: #d5ece0;
  --native-fg-hover: #0a5d4a;
  --tts-fg: #8a5d12;       /* gold-brown ink */
  --tts-fg-hover: #6b4709;
  --tts-border: #d4b877;   /* warm gold */
  --tts-bg: #faf3e2;       /* warm gold tint */
  --tts-bg-hover: #f3e9cf;
  --shadow-card: 0 6px 20px rgba(20, 24, 40, 0.08);   /* cool neutral */
  --shadow-panel: 0 1px 2px rgba(20, 24, 40, 0.05);
  --chart-axis: #616776;
  --chart-grid: #eaecf0;
  --chart-text: #1c1f26;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: "Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  height: 100vh;
}

/* Pin the whole app to the viewport — only the sidebar word list and the
   readout panel scroll, never the body. This keeps the word card, the
   pitch chart, and the controls all in view as the learner pages through
   a category. */
body {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
header, footer { flex: 0 0 auto; }
.tab-panel {
  flex: 1 1 auto;
  min-height: 0;
}

header {
  padding: 18px 24px 8px;
  border-bottom: 1px solid var(--border);
  position: relative;
}
.header-actions {
  position: absolute;
  top: 14px;
  right: 18px;
  display: flex;
  gap: 6px;
}
.script-toggle {
  display: inline-flex; align-items: stretch; flex: 0 0 auto;
  border: 1px solid var(--border); border-radius: 6px; overflow: hidden;
  background: var(--panel-2);
}
.script-toggle .script-btn {
  background: transparent; color: var(--muted);
  border: none; padding: 2px 9px; font-size: 14px; font-weight: 600;
  cursor: pointer; line-height: 1.4;
}
.script-toggle .script-btn + .script-btn { border-left: 1px solid var(--border); }
.script-toggle .script-btn:hover { color: var(--text); }
.script-toggle .script-btn.active {
  background: var(--accent-2); color: var(--panel);
}

/* Language switcher (粵/普) — segmented control, hidden until the flag is on. */
.lang-toggle {
  display: inline-flex; align-items: stretch; margin: 6px auto 2px;
  border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
  background: var(--panel-2);
}
.lang-toggle[hidden] { display: none; }
.lang-toggle .lang-btn {
  background: transparent; color: var(--muted); border: none;
  padding: 6px 13px; font-size: 13px; font-weight: 600; cursor: pointer;
  line-height: 1.2; display: inline-flex; align-items: center; gap: 6px;
}
.lang-toggle .lang-btn + .lang-btn { border-left: 1px solid var(--border); }
.lang-toggle .lang-btn:hover { color: var(--text); }
.lang-toggle .lang-btn.active { background: var(--accent-2); color: #fff; }
.lang-toggle .lang-glyph { font-size: 15px; line-height: 1; }

.btn-theme, .btn-cal, .btn-intro, .btn-settings {
  flex: 0 0 auto;
  white-space: nowrap;
}

.settings-wrap { position: relative; display: inline-flex; }
.settings-panel {
  position: absolute; top: calc(100% + 6px); right: 0;
  z-index: 50;
  min-width: 240px;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 12px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.35);
  display: flex; flex-direction: column; gap: 12px;
}
.settings-panel.hidden { display: none; }
.settings-group { display: flex; flex-direction: column; gap: 6px; }
.settings-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--muted); font-weight: 600;
}
.settings-row {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px; cursor: pointer;
}
.settings-row input[type="checkbox"] { cursor: pointer; }
.settings-hint {
  font-size: 11px; color: var(--muted); margin: 2px 0 0; line-height: 1.4;
}
.settings-panel .btn-theme { align-self: flex-start; }

/* Settings modal — the elaborate popup menu */
.settings-modal { display: flex; flex-direction: column; gap: 16px; max-height: 85vh; overflow-y: auto; }
.settings-modal-head { display: flex; align-items: center; justify-content: space-between; }
.settings-modal-head h2 { margin: 0; }
.modal-close {
  background: none; border: none; color: var(--muted);
  font-size: 24px; line-height: 1; cursor: pointer; padding: 0 4px;
}
.modal-close:hover { color: var(--text); }
.settings-label .info-btn {
  margin-left: 6px; width: 16px; height: 16px; padding: 0;
  border-radius: 50%; border: 1px solid var(--border);
  background: var(--panel-2); color: var(--muted);
  font-size: 10px; font-weight: 700; line-height: 1; cursor: pointer;
  vertical-align: middle;
}
.settings-label .info-btn:hover { color: var(--text); border-color: var(--accent-2); }
.settings-info {
  font-size: 12px; color: var(--muted); line-height: 1.5; margin: 4px 0 0;
  background: var(--panel-2); border-left: 2px solid var(--accent-2);
  border-radius: 4px; padding: 8px 10px;
}
.theme-choices { display: flex; gap: 8px; flex-wrap: wrap; }
.theme-btn {
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  padding: 6px 12px; font-size: 13px; cursor: pointer;
}
.theme-btn:hover { background: var(--hover); }
.theme-btn.active { border-color: var(--accent-2); color: var(--accent-2); font-weight: 600; }

/* Header account / sign-in button — special colour, right of Settings.
   Use .btn-mini.btn-account so it beats the later .btn-mini base rule. */
.btn-mini.btn-account { background: var(--accent); color: var(--primary-fg); border-color: var(--accent); font-weight: 600; flex: 0 0 auto; }
.btn-mini.btn-account:hover { filter: brightness(1.1); background: var(--accent); color: var(--primary-fg); }
.btn-mini.btn-account.signed-in {
  background: var(--accent-2); border-color: var(--accent-2);
  max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.btn-mini.btn-account.signed-in:hover { background: var(--accent-2); color: var(--primary-fg); }
#btn-manage-sub { display: block; margin: 8px 0; }

/* Mobile: the absolutely-positioned header actions overlap the title — drop them
   into normal flow and let them wrap above it on narrow screens. */
@media (max-width: 640px) {
  .header-actions {
    position: static; top: auto; right: auto;
    justify-content: flex-end; flex-wrap: wrap; margin-bottom: 10px;
  }
}

/* Transient toast (purchase / status feedback) */

/* Transient toast (purchase / status feedback) */
.wt-toast {
  position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%) translateY(20px);
  background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  border-radius: 10px; padding: 12px 18px; font-size: 14px; max-width: 90vw;
  box-shadow: var(--shadow-card); z-index: 250; opacity: 0;
  transition: opacity .3s, transform .3s;
}
.wt-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.wt-toast-success { border-color: var(--accent-2); }
.wt-toast-error { border-color: var(--recording); }

.btn-signin {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--border); background: var(--panel-2);
  cursor: pointer; padding: 4px 10px;
}
.btn-signin:hover { background: var(--accent-2); color: var(--panel); }
.g-glyph {
  display: inline-block; width: 16px; height: 16px;
  border-radius: 50%; background: #fff; color: #4285F4;
  font-weight: 700; text-align: center; line-height: 16px; font-size: 11px;
}
.account-email {
  font-size: 12px; color: var(--text); word-break: break-all;
  padding: 2px 0 4px;
}

.magic-divider {
  display: flex; align-items: center; gap: 8px;
  font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.6px;
  margin: 8px 0 4px;
}
.magic-divider::before, .magic-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--border);
}
.magic-form {
  display: flex; flex-direction: column; gap: 4px;
}
.magic-form input[type="email"] {
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 4px 8px; font: inherit; font-size: 13px;
  width: 100%; box-sizing: border-box;
}
.magic-status { min-height: 14px; }
.magic-status.ok { color: var(--accent-2); }
.magic-status.err { color: #ff8888; }

.cal-status {
  display: inline-block;
  margin-left: 6px;
  font-size: 11px;
  padding: 1px 8px;
  border-radius: 9px;
  background: var(--native-bg);
  color: var(--accent-2);
  letter-spacing: 0.2px;
}
.cal-status.default { background: var(--panel-2); color: var(--muted); }

/* --- Calibration modal --- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: 100;
  display: none;
  align-items: center;
  justify-content: center;
}
.modal-backdrop.open { display: flex; }
.modal {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 24px 28px 20px;
  max-width: 520px;
  width: 92%;
  box-shadow: var(--shadow-card);
}
.modal h2 { margin: 0 0 12px; font-size: 18px; }
.cal-intro { color: var(--muted); font-size: 13px; line-height: 1.5; margin: 0 0 16px; }
.cal-intro b { color: var(--text); }
.cal-prompt {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px;
  text-align: center;
  margin-bottom: 16px;
}
.cal-hanzi {
  font-family: "Noto Sans HK", "PingFang TC", "Microsoft JhengHei", sans-serif;
  font-size: 26px;
  color: var(--text);
}
.cal-jp { color: var(--accent-2); font-size: 13px; margin-top: 4px; }
.cal-meaning { color: var(--muted); font-size: 12px; margin-top: 2px; }
.cal-demo-btn { margin-top: 10px; }
.cal-controls {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}
.cal-result {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 13px;
  color: var(--text);
  margin: 8px 0 12px;
}
.cal-result.hidden { display: none; }
.cal-result .row {
  display: flex;
  justify-content: space-between;
  padding: 3px 0;
}
.cal-result .row span { color: var(--muted); }
.cal-footer {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-top: 8px;
}
header h1 { margin: 0; font-size: 22px; letter-spacing: 0.2px; }
header .tag { margin: 4px 0 0; color: var(--muted); font-size: 13px; }

main {
  display: grid;
  grid-template-columns: 320px 1fr;
  /* Force the single row to fill the flex allocation we get from <body>,
     and let it shrink (min: 0) so children can be smaller than their
     intrinsic content. Without this the sidebar+stage would overflow
     downward and break the no-body-scroll guarantee. */
  grid-template-rows: minmax(0, 1fr);
  gap: 0;
  min-height: 0;
}
aside#library, section#stage {
  min-height: 0;
  height: 100%;
}

aside#library {
  border-right: 1px solid var(--border);
  background: var(--panel);
  display: flex;
  flex-direction: column;
}
/* Mobile-only word-list drawer toggle + backdrop (activated in the mobile @media). */
.btn-browse { display: none; }
.lib-backdrop { display: none; }
.lib-head {
  padding: 12px;
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
#filter {
  width: 100%;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 13px;
}
.lib-actions {
  display: flex;
  gap: 6px;
}
.btn-mini {
  flex: 1;
  background: var(--panel-2);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 5px 8px;
  font-size: 11px;
  letter-spacing: 0.2px;
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.btn-mini:hover { background: var(--hover); color: var(--text); }
.btn-mini:active { transform: translateY(1px); }

/* Step / pager buttons flanking the hanzi in the word card */
.btn-step {
  background: var(--panel-2);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 50%;
  width: 38px;
  height: 38px;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s, color 0.12s, transform 0.05s;
  flex-shrink: 0;
}
.btn-step:hover { background: var(--hover); color: var(--text); }
.btn-step:active { transform: translateY(1px); }
.btn-step[disabled] { opacity: 0.35; cursor: not-allowed; }
#word-list {
  overflow-y: auto;
  padding: 8px 0 20px;
  flex: 1;
}
/* Collapsible category groups in the sidebar */
.cat-group {
  border-top: 1px solid var(--border);
}
.cat-group:first-of-type { border-top: none; }
.cat-group > summary.category {
  list-style: none;
  cursor: pointer;
  user-select: none;
  padding: 9px 14px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.cat-group > summary.category::-webkit-details-marker { display: none; }
.cat-group > summary.category::before {
  content: "▸";
  display: inline-block;
  width: 12px;
  text-align: center;
  font-size: 10px;
  color: var(--muted);
  transition: transform 0.12s ease;
  margin-right: 4px;
}
.cat-group[open] > summary.category::before {
  transform: rotate(90deg);
}
.cat-group > summary.category:hover { background: var(--panel-2); color: var(--text); }
.cat-group > summary.category .cat-name { flex: 1; }
.cat-group > summary.category .cat-count {
  background: var(--panel-2);
  color: var(--muted);
  font-size: 10px;
  font-weight: 600;
  padding: 1px 7px;
  border-radius: 9px;
  letter-spacing: 0;
  text-transform: none;
}
.cat-group.browse > summary.category { color: var(--muted); opacity: 0.8; }
.cat-group.browse > summary.category .cat-count { background: var(--hover); }

.word-item {
  padding: 7px 14px 7px 30px;
  cursor: pointer;
  border-left: 3px solid transparent;
  /* Grid keeps hanzi + jyutping on one row (no mid-word breaks) and lets
     the meaning shrink with an ellipsis when it would overflow.
     minmax(0, ...) on every column is the magic that lets each cell
     truncate instead of pushing siblings off-screen. */
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, auto) minmax(0, 1fr);
  column-gap: 10px;
  align-items: baseline;
  overflow: hidden;
}
.word-item:hover { background: var(--panel-2); }
.word-item.active {
  background: var(--panel-2);
  border-left-color: var(--accent);
}
.word-item .h {
  font-size: 18px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.word-item .j {
  color: var(--accent-2);
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.word-item .m {
  color: var(--muted);
  font-size: 12px;
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
/* Words without a native recording are visually muted in the list. */
.word-item.no-audio .h { opacity: 0.55; }
.word-item.no-audio .j { opacity: 0.6; }

/* Paid items when not subscribed: dim the text, overlay a lock on the
   right without disturbing the 3-column grid. */
.word-item.locked { position: relative; }
.word-item.locked .h,
.word-item.locked .j,
.word-item.locked .m { opacity: 0.45; }
.word-item.locked .lock {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.8em;
  opacity: 0.85;
}

/* Locked story sentences (paid drill tiers when not subscribed). */
#story-sentences li.locked { opacity: 0.6; cursor: pointer; }
#story-sentences li.locked .badge { opacity: 0.9; }

/* Account: upgrade button + pro status. */
.account-pro { margin-top: 8px; }
.account-pro.ok { color: var(--accent); font-weight: 600; }
.btn-upgrade {
  display: inline-block;
  padding: 7px 14px;
  border: 0;
  border-radius: 6px;
  background: var(--accent);
  color: #fff;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.btn-upgrade:hover { filter: brightness(1.08); }

section#stage {
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-height: 0;
  /* Internal scroll if content exceeds viewport — the body itself never
     scrolls (locked above), and the sticky card below pins to the top of
     this scroll container so the controls always stay visible. */
  overflow-y: auto;
}

#card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 20px;
  flex: 0 0 auto;
  position: sticky;
  top: 0;
  z-index: 5;
  box-shadow: var(--shadow-card);
}
.card-row { display: flex; gap: 16px; align-items: center; }
.card-row.top { gap: 24px; }
.card-row.controls { margin-top: 18px; flex-wrap: wrap; }
.card-row.free { margin-top: 18px; display: block; }
.card-row.free label { display: block; color: var(--muted); font-size: 12px; margin-bottom: 6px; }
.free-row { display: flex; gap: 8px; flex-wrap: wrap; }
.free-row input[type=text] {
  flex: 1;
  min-width: 180px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  padding: 8px 10px;
  font-size: 14px;
}
.free-row select {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
}

.hanzi {
  font-size: 64px;
  font-weight: 500;
  line-height: 1;
  /* Simplified Chinese fonts interleaved with Traditional ones so any
     character — Traditional, Simplified, or shared — renders at the
     same weight. Without an explicit SC font, characters like 纪 fall
     back to system default which doesn't have a bold weight, producing
     the "one regular char in a row of bold chars" artifact. */
  font-family: "Noto Sans HK", "Noto Sans SC", "PingFang TC", "PingFang SC",
               "Microsoft JhengHei", "Microsoft YaHei",
               "Source Han Sans HK", "Source Han Sans SC",
               "Noto Sans CJK HK", "Noto Sans CJK SC",
               "Noto Sans TC", "Hiragino Sans GB", sans-serif;
}
.word-item .h {
  font-family: "Noto Sans HK", "Noto Sans SC", "PingFang TC", "PingFang SC",
               "Microsoft JhengHei", "Microsoft YaHei",
               "Source Han Sans HK", "Source Han Sans SC",
               "Noto Sans CJK HK", "Noto Sans CJK SC",
               "Noto Sans TC", sans-serif;
}
.meta .jyutping { color: var(--accent-2); font-size: 18px; }
.meta .meaning { color: var(--muted); margin-top: 2px; }
.meta .target { margin-top: 4px; font-size: 13px; }
.meta .target b { color: var(--target); }

.btn {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 9px 14px;
  font-size: 14px;
  cursor: pointer;
  transition: background 0.15s, transform 0.05s;
}
.btn:hover { background: var(--hover); }
.btn:active { transform: translateY(1px); }
.btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--primary-fg); font-weight: 600; }
.btn.primary:hover { background: var(--accent); filter: brightness(1.1); }
.btn.recording { background: var(--recording); color: #fff; }

/* Native-recording button: green = real human voice */
.btn.audio-native {
  background: var(--native-bg);
  border-color: var(--accent-2);
  color: var(--accent-2);
  font-weight: 600;
}
.btn.audio-native:hover:not([disabled]) { background: var(--native-bg-hover); color: var(--native-fg-hover); }
.btn.audio-native[disabled] {
  background: var(--panel-2);
  border-color: var(--border);
  color: var(--muted);
}

/* TTS button: filled amber — mirrors the native button's treatment so the two
   sit together, but yellow instead of green to flag it as synthetic. */
.btn.audio-tts {
  background: var(--tts-bg);
  border: 1px solid var(--tts-border);
  color: var(--tts-fg);
  font-weight: 600;
}
.btn.audio-tts:hover:not([disabled]) { background: var(--tts-bg-hover); color: var(--tts-fg-hover); }
.btn.audio-tts[disabled] {
  background: var(--panel-2);
  border-color: var(--border);
  color: var(--muted);
}

.ai-voice-group {
  display: inline-flex; align-items: center; gap: 4px;
}
/* Small leading label so it's obvious this group is the AI/TTS voice. */
.ai-voice-group .ai-voice-tag {
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--tts-fg);
  border: 1px dashed var(--tts-border); border-radius: 999px;
  padding: 2px 7px; white-space: nowrap;
}
.ai-voice-group .ai-voice-pick {
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 2px 6px; font: inherit; font-size: 12px;
  max-width: 180px;
}
.ai-voice-group .ai-voice-pick:disabled { opacity: 0.6; cursor: not-allowed; }

.status { color: var(--muted); font-size: 13px; }

#result {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 20px;
  flex: 0 0 auto;
}
.chart-wrap {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px;
  min-height: 320px;
  height: 320px;            /* fixed: prevents Chart.js feedback growing */
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.chart-wrap > canvas { flex: 1; min-height: 0; }
.chart-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--muted);
  margin-bottom: 6px;
  flex: 0 0 auto;
}
.result-row {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 20px;
  flex: 0 0 auto;
}
.result-row-pad { /* spacer to align with the readout column above */ }
#result-yin {
  height: 320px;
  min-height: 320px;
}
#readout {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px;
}
#readout .row {
  display: flex;
  justify-content: space-between;
  padding: 6px 0;
  border-bottom: 1px dashed var(--border);
  font-size: 14px;
}
#readout .row:last-of-type { border-bottom: none; }
#readout .row span { color: var(--muted); }
.feedback {
  margin-top: 12px;
  padding: 10px 12px;
  background: var(--panel-2);
  border-radius: 8px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
  min-height: 40px;
}

footer {
  padding: 12px 24px;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 11px;
  text-align: center;
}

@media (max-width: 900px) {
  main { grid-template-columns: 1fr; }
  aside#library { border-right: none; border-bottom: 1px solid var(--border); max-height: 240px; }
  #result { grid-template-columns: 1fr; }
  .hanzi { font-size: 48px; }
}

/* Mobile responsive overrides are consolidated in the @media block at the END of
   this file, so they fall after the base component rules and win on source order. */

/* -------- Speed selector (Story tab) -------- */
.speed-group {
  display: inline-flex;
  gap: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}
.speed-group .btn.speed {
  border: none;
  border-radius: 0;
  border-right: 1px solid var(--border);
  padding: 7px 10px;
  font-size: 12px;
  color: var(--muted);
  background: var(--panel-2);
  font-variant-numeric: tabular-nums;
}
.speed-group .btn.speed:last-child { border-right: none; }
.speed-group .btn.speed:hover { color: var(--text); background: var(--hover); }
.speed-group .btn.speed.active {
  background: var(--accent-2);
  color: var(--bg);
  font-weight: 600;
}

/* -------- Tabs -------- */
.tabs {
  margin-top: 10px;
  display: flex;
  gap: 6px;
}
.tab-btn {
  background: transparent;
  color: var(--muted);
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 6px 6px 0 0;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  letter-spacing: 0.3px;
}
.tab-btn:hover { color: var(--text); background: var(--panel-2); }
.tab-btn.active {
  color: var(--text);
  background: var(--panel);
  border-color: var(--border);
  border-bottom-color: var(--panel);
  margin-bottom: -1px;
  position: relative;
}
.tab-panel { display: grid; }
.tab-panel.hidden { display: none; }

/* -------- Story tab -------- */
#tab-story {
  grid-template-columns: 1fr;
  padding: 24px;
  gap: 18px;
}
#story-stage {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
#story-picker-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--muted);
}
#story-picker-row select {
  flex: 1;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 10px;
  font: inherit;
}
#story-head { padding-bottom: 4px; }
.story-title {
  font-size: 28px;
  font-weight: 600;
  font-family: "Noto Sans HK", "Noto Sans SC", "PingFang TC", "PingFang SC",
               "Microsoft JhengHei", "Microsoft YaHei", sans-serif;
}
.story-sub { color: var(--muted); font-size: 13px; margin-top: 2px; }

#story-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 18px 20px;
}
#story-card .hanzi { font-size: 40px; }
#story-card .meta .jyutping { font-size: 16px; }

#story-result {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 18px;
}
#story-readout {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px;
}
#story-readout .row {
  display: flex;
  justify-content: space-between;
  padding: 6px 0;
  border-bottom: 1px dashed var(--border);
  font-size: 14px;
}
#story-readout .row:last-of-type { border-bottom: none; }
#story-readout .row span { color: var(--muted); }

#story-sentences {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  max-height: 420px;
  overflow-y: auto;
}
#story-sentences li {
  display: grid;
  grid-template-columns: 28px 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 10px 14px;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
  border-left: 3px solid transparent;
}
#story-sentences li:last-child { border-bottom: none; }
#story-sentences li:hover { background: var(--panel-2); }
#story-sentences li.active {
  background: var(--panel-2);
  border-left-color: var(--accent);
}
#story-sentences .num {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
#story-sentences .text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
#story-sentences .text .h {
  font-family: "Noto Sans HK", "Noto Sans SC", "PingFang TC", "PingFang SC",
               "Microsoft JhengHei", "Microsoft YaHei", sans-serif;
  font-size: 18px;
}
#story-sentences .text .j { color: var(--accent-2); font-size: 12px; }
#story-sentences .text .m { color: var(--muted); font-size: 12px; }
#story-sentences .badge {
  font-size: 11px;
  color: var(--muted);
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
  white-space: nowrap;
}
#story-sentences li.practiced .badge {
  color: var(--accent-2);
  border-color: var(--accent-2);
}

@media (max-width: 900px) {
  #story-result { grid-template-columns: 1fr; }
  #story-card .hanzi { font-size: 32px; }
}

/* Global utility — used by quiz/stats/onboarding to toggle sub-sections. */
.hidden { display: none !important; }

/* ============ Streak pill ============ */
.streak-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}
.streak-icon { font-size: 14px; }
.streak-pill.hidden { display: none; }

/* Quiz, Stats, Help tabs are single-column. Override the Words-tab
   grid (320px sidebar + 1fr) inherited from `main`. Without this the
   stage gets squeezed into the first 320px track. Also opt into
   per-tab vertical scroll because <body> has overflow:hidden, which
   would otherwise clip long content like the Help Q&A. */
#tab-quiz, #tab-stats, #tab-help {
  grid-template-columns: 1fr;
  overflow-y: auto;
}

/* ============ Help tab ============ */
#help-stage {
  display: flex; flex-direction: column; gap: 20px;
  max-width: 880px; margin: 0 auto; padding: 8px 24px;
  width: 100%;
}
.help-h { margin: 0; font-size: 22px; }
.help-sub { color: var(--muted); font-size: 14px; margin: 0; }
.help-h3 { margin: 0 0 8px 0; font-size: 15px; color: var(--accent-2); letter-spacing: 0.03em; }
.help-section {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 10px; padding: 16px 18px;
  display: flex; flex-direction: column; gap: 8px;
}
.qa { border-top: 1px solid var(--border); padding: 8px 0; }
.qa:first-of-type { border-top: none; padding-top: 4px; }
.qa summary {
  cursor: pointer; font-size: 14px; font-weight: 500;
  padding: 6px 0; list-style: none; display: flex; align-items: center; gap: 8px;
}
.qa summary::-webkit-details-marker { display: none; }
.qa summary::before {
  content: "▸"; color: var(--accent-2); transition: transform 0.15s;
  font-size: 11px; flex: 0 0 auto;
}
.qa[open] summary::before { transform: rotate(90deg); }
.qa summary:hover { color: var(--accent-2); }
.qa-body {
  padding: 6px 18px 10px;
  font-size: 13px; color: var(--text); line-height: 1.55;
}
.qa-body p { margin: 6px 0; }
.qa-body ul, .qa-body ol { margin: 6px 0 6px 18px; padding: 0; }
.qa-body li { margin: 4px 0; }
.qa-body kbd {
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 3px; padding: 1px 6px; font-size: 11px; font-family: monospace;
}
.qa-body code {
  background: var(--panel-2); padding: 1px 5px;
  border-radius: 3px; font-size: 12px;
}
.qa-body a { color: var(--accent-2); }
.help-foot { color: var(--muted); font-size: 12px; font-style: italic; }

/* ============ Quiz tab ============ */
#quiz-stage {
  display: flex; flex-direction: column; gap: 18px;
  max-width: 1180px; margin: 0 auto; padding: 8px 24px;
  width: 100%;
}
.quiz-toggles {
  display: flex; flex-wrap: wrap; gap: 14px;
}
.qtog {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; color: var(--text); cursor: pointer;
}
.qtog input[type="checkbox"] { accent-color: var(--accent); }
#quiz-count-custom-wrap {
  display: flex; align-items: center; gap: 12px;
  margin-top: 8px;
}
#quiz-count-custom {
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 10px; font: inherit; width: 100px;
}
.quiz-meaning {
  color: var(--muted); font-size: 14px; min-height: 18px; margin-top: -6px;
}
.quiz-chart-wrap {
  height: 320px; background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 8px; padding: 8px; display: flex;
}
.quiz-chart-wrap > canvas { flex: 1; min-height: 0; }
.quiz-readouts {
  display: flex; gap: 24px; flex-wrap: wrap;
  padding: 8px 4px; color: var(--text); font-size: 13px;
}
.quiz-readouts b { color: var(--muted); font-weight: 600; }
.quiz-h { margin: 0 0 4px 0; font-size: 22px; }
.quiz-sub { color: var(--muted); margin: 0 0 12px 0; }
.quiz-field { display: flex; flex-direction: column; gap: 6px; padding: 12px 0; border-top: 1px solid var(--border); }
.quiz-field label { font-size: 13px; color: var(--muted); }
.quiz-field select {
  background: var(--panel); color: var(--text); border: 1px solid var(--border);
  border-radius: 6px; padding: 8px 10px; font: inherit;
}
.quiz-hint { color: var(--muted); font-size: 12px; margin: 0; }
.seg {
  display: inline-flex; border: 1px solid var(--border); border-radius: 8px;
  overflow: hidden; background: var(--panel);
}
.seg-btn {
  border: none; padding: 8px 14px; background: transparent; color: var(--text);
  font: inherit; cursor: pointer; border-right: 1px solid var(--border);
}
.seg-btn:last-child { border-right: none; }
.seg-btn:hover { background: var(--hover); }
.seg-btn.active { background: var(--accent); color: var(--primary-fg); }
.quiz-actions { display: flex; gap: 12px; align-items: center; padding-top: 6px; }
/* In the quiz flex containers the default `.btn-mini { flex: 1 }`
   stretches small buttons (Skip, Quit) to fill the row. Override. */
.quiz-controls .btn-mini, #quiz-progress .btn-mini { flex: 0 0 auto; }
.quiz-controls .btn { flex: 0 0 auto; }
#quiz-progress {
  display: flex; align-items: center; gap: 12px;
  padding-bottom: 8px;
}
#quiz-pos { font-variant-numeric: tabular-nums; color: var(--muted); }
.quiz-bar {
  flex: 1; height: 6px; background: var(--panel-2); border-radius: 3px; overflow: hidden;
}
#quiz-bar-fill { height: 100%; background: var(--accent-2); transition: width 0.3s; }
.quiz-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  padding: 24px; text-align: center; display: flex; flex-direction: column; gap: 16px;
}
.quiz-prompt {
  font-size: 56px; font-weight: 500; line-height: 1;
  font-family: "Noto Sans HK", "Noto Sans SC", "PingFang TC", "PingFang SC",
               "Microsoft JhengHei", "Microsoft YaHei", sans-serif;
}
.quiz-jp { color: var(--accent-2); font-size: 16px; min-height: 20px; }
.quiz-controls { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.quiz-listen-choices {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 8px;
}
.tone-choice {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 14px; background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 8px; cursor: pointer; color: var(--text); font: inherit;
  transition: background 0.15s, border-color 0.15s;
}
.tone-choice:hover:not(:disabled) { background: var(--hover); }
.tone-choice .tc-num { font-size: 20px; font-weight: 600; }
.tone-choice .tc-label { font-size: 11px; color: var(--muted); }
.tone-choice.correct { background: var(--native-bg); border-color: var(--accent-2); color: var(--native-fg-hover); }
.tone-choice.wrong { background: rgba(255,107,107,0.18); border-color: var(--accent); }
.tone-choice:disabled { cursor: default; opacity: 0.7; }
.quiz-feedback { min-height: 22px; font-size: 14px; color: var(--muted); }
.quiz-feedback.good { color: var(--accent-2); font-weight: 600; }
.quiz-feedback.bad { color: var(--accent); font-weight: 600; }
#quiz-results-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 14px 0;
}
#quiz-results-detail {
  display: flex; flex-direction: column; gap: 4px; max-height: 320px;
  overflow-y: auto; border: 1px solid var(--border); border-radius: 8px; padding: 6px;
}
.quiz-result-row {
  display: grid;
  grid-template-columns: 36px 1.4fr 1fr 50px 60px;
  gap: 10px; align-items: center; padding: 6px 10px;
  border-radius: 6px; font-size: 13px;
}
.quiz-result-row.good { background: rgba(78,201,176,0.08); }
.quiz-result-row.bad { background: rgba(255,107,107,0.08); }
.quiz-result-row.skip { color: var(--muted); }
.qr-hanzi {
  font-family: "Noto Sans HK", "Noto Sans SC", "PingFang TC", "PingFang SC",
               "Microsoft JhengHei", "Microsoft YaHei", sans-serif;
  font-size: 15px;
}
.qr-jp { color: var(--accent-2); }
.qr-tone, .qr-dist { font-variant-numeric: tabular-nums; text-align: right; }

/* ============ Stats tab ============ */
#stats-stage {
  display: flex; flex-direction: column; gap: 20px;
  max-width: 1180px; margin: 0 auto; padding: 8px 24px;
  width: 100%;
}
.stats-h { margin: 0; font-size: 22px; }
.stats-h3 { margin: 0 0 4px 0; font-size: 16px; }
.stats-sub { color: var(--muted); font-size: 12px; margin: 0 0 10px 0; }
#stats-top {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
}
.stat-card {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 10px; padding: 16px; text-align: center;
  display: flex; flex-direction: column; gap: 4px;
}
.stat-num { font-size: 32px; font-weight: 600; line-height: 1.1; font-variant-numeric: tabular-nums; }
.stat-label { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.stat-sub { font-size: 11px; color: var(--muted); }
.stat-card-due { border-color: var(--accent-2); }
.stat-card-due .btn-mini { margin-top: 6px; }
.stat-card-due .btn-mini:disabled { opacity: 0.5; cursor: default; }
.stats-section {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 10px; padding: 16px;
}
.tone-table { width: 100%; border-collapse: collapse; font-size: 13px; table-layout: fixed; }
.tone-table th, .tone-table td { padding: 8px 10px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: middle; }
.tone-table th { color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; }
.tone-table tr:last-child td { border-bottom: none; }
.tone-table .muted { color: var(--muted); font-weight: 400; }
/* Per-tone diagnostic: keep first column compact, give Diagnosis the slack. */
.stats-section .tone-table th:nth-child(1),
.stats-section .tone-table td:nth-child(1) { width: 22%; }
.stats-section .tone-table th:nth-child(2),
.stats-section .tone-table td:nth-child(2) { width: 11%; }
.stats-section .tone-table th:nth-child(3),
.stats-section .tone-table td:nth-child(3) { width: 11%; }
.stats-section .tone-table th:nth-child(4),
.stats-section .tone-table td:nth-child(4) { width: 14%; }
.stats-section .tone-table th:nth-child(5),
.stats-section .tone-table td:nth-child(5) { width: 42%; }

/* ============ Onboarding ============ */
.onboard-modal { max-width: 520px; }
.onb-step { padding: 8px 0; }
.onb-demo {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
  margin: 18px 0;
}
.onb-triple {
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 8px; padding: 14px 12px; text-align: center;
  display: flex; flex-direction: column; gap: 4px;
  color: var(--text); cursor: pointer; font: inherit;
  transition: background 0.15s, border-color 0.15s, transform 0.05s;
}
.onb-triple:hover { background: var(--hover); border-color: var(--accent-2); }
.onb-triple:active { transform: translateY(1px); }
.onb-play {
  margin-top: 6px; color: var(--accent-2); font-size: 11px;
  text-transform: uppercase; letter-spacing: 0.05em;
}
.onb-char {
  font-family: "Noto Sans HK", "Noto Sans SC", "PingFang TC", "PingFang SC",
               "Microsoft JhengHei", "Microsoft YaHei", sans-serif;
  font-size: 32px; font-weight: 500;
}
.onb-jp { display: block; color: var(--accent-2); font-size: 13px; margin-top: 4px; }
.onb-meaning { color: var(--muted); font-size: 12px; margin-top: 4px; }
.onb-tip { color: var(--muted); font-style: italic; font-size: 13px; }
.onb-bullets { list-style: none; padding: 0; margin: 12px 0; display: flex; flex-direction: column; gap: 8px; font-size: 14px; }
.onb-controls {
  display: flex; align-items: center; gap: 10px;
  border-top: 1px solid var(--border); padding-top: 14px; margin-top: 8px;
}
.onb-controls .onb-dot { flex: 1; text-align: center; color: var(--muted); font-size: 12px; }

/* Pricing button (header) — tamed brand gold (replaces neon #f5b301). */
.btn-mini.btn-pricing { background: var(--gold, #d29420); border-color: var(--gold-border, #d29420); color: var(--gold-fg, #2a1d02); font-weight: 600; }
.btn-mini.btn-pricing:hover { background: var(--gold-hover, #e0a52f); border-color: var(--gold-hover, #e0a52f); }

/* Pricing modal */
.pricing-plans { display: flex; flex-direction: column; gap: 8px; margin: 6px 0 16px; }
.pricing-plan {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding: 12px 14px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel-2);
}
.pricing-plan .pp-name { font-weight: 600; }
.pricing-plan .pp-price { margin-left: auto; font-weight: 600; }
.pricing-plan .pp-per { font-weight: 400; color: var(--muted); }
.pricing-plan .pp-trial { flex-basis: 100%; font-size: 12px; color: #1f9e86; }
.pricing-loading { color: var(--muted); font-size: 14px; padding: 8px 0; }
.pricing-subscribe { width: 100%; }
.pricing-manage { width: 100%; margin-top: 8px; }
.pricing-foot { text-align: center; margin-top: 12px; }

/* Uncalibrated warning banner (over the practice screens). */
.cal-warning {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  max-width: 1100px; margin: 12px auto 0; padding: 10px 16px;
  background: rgba(210, 148, 32, 0.12); border: 1px solid rgba(210, 148, 32, 0.5);
  border-radius: 10px; color: var(--text); font-size: 14px;
}
.cal-warning.hidden { display: none; }
.cal-warning button { margin-left: auto; white-space: nowrap; }
/* Dismiss × in the banner's top-right corner. */
.cal-warning { position: relative; }
body .cal-warning { padding-right: 34px; }
.cal-warning-close {
  position: absolute; top: 6px; right: 8px;
  width: 22px; height: 22px; padding: 0; line-height: 1; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--muted);
  font-size: 20px; border-radius: 50%; cursor: pointer;
}
.cal-warning-close:hover { background: var(--hover); color: var(--text); }

/* Hosted RevenueCat paywall: contain it in a centered card so its buttons don't
   stretch across the whole page. */
.rc-paywall-backdrop {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(0, 0, 0, 0.5);
  display: grid; place-items: center; padding: 16px; overflow: auto;
}
.rc-paywall-host {
  width: 100%; max-width: 440px; max-height: 92vh; overflow: auto;
  background: #fff; border-radius: 16px;
}

/* Pricing plans are now tappable buttons (purchase directly, on-brand). */
.pricing-plan { cursor: pointer; width: 100%; text-align: left; font: inherit; color: var(--text);
  transition: border-color .12s, background .12s; }
.pricing-plan:hover { border-color: var(--accent); background: var(--hover); }
.pricing-subscribe { display: none; }

/* Record buttons: on touch, a press-and-hold otherwise triggers text selection,
   the long-press callout menu, or starts a page scroll. Suppress all three so
   hold-to-talk feels clean. */
#btn-record, #s-btn-record, #quiz-record {
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}

@media (max-width: 700px) {
  /* ---- Mobile layout: natural page scrolling instead of the desktop fixed,
     no-scroll viewport, so the word list, controls, chart and readouts are all
     reachable. (Placed at end of file so these win over the base rules.) ---- */
  html, body { height: auto; min-height: 100dvh; }
  body { overflow-y: auto; overflow-x: hidden; }
  .tab-panel { overflow: visible; min-height: 0; }
  main { display: block; }
  section#stage { display: block; min-height: 0; }
  /* Word list becomes a slide-in drawer (toggled by 📋 Browse words) so you don't
     scroll past the entire list to reach the practice card. */
  .btn-browse {
    display: block; width: 100%; margin: 0 0 12px; padding: 12px;
    font-size: 15px; font-weight: 600; border-radius: 10px;
    background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  }
  aside#library {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 120;
    width: 86%; max-width: 340px; max-height: none;
    box-shadow: 6px 0 28px rgba(0,0,0,0.45);
    transform: translateX(-100%); transition: transform 0.25s ease;
  }
  body.lib-open { overflow: hidden; }
  body.lib-open aside#library { transform: translateX(0); }
  body.lib-open .lib-backdrop {
    display: block; position: fixed; inset: 0; z-index: 110;
    background: rgba(0, 0, 0, 0.5);
  }
  /* Bigger touch targets for fingers. */
  .word-item { padding: 12px 12px; }
  .btn, .btn-step { min-height: 44px; }
  .seg button { min-height: 40px; }
  /* Charts need a real height when the page scrolls (flex-fill collapsed them to a
     sliver → rendering artifacts). */
  .chart-wrap, .quiz-chart-wrap { height: 300px; min-height: 300px; flex: none; }
  .chart-wrap > canvas, .quiz-chart-wrap > canvas { flex: none; height: 300px !important; }
  /* Tabs wrap instead of overflowing the phone width. */
  .tabs { flex-wrap: wrap; }
  /* Trim panel side-padding + let segmented controls fill the width so the intro
     text and controls fit. */
  #quiz-stage, #stats-stage, #stage { padding-left: 14px; padding-right: 14px; }
  .quiz-sub { white-space: normal; overflow-wrap: anywhere; }
  .seg { display: flex; width: 100%; }
  /* Let flex/grid descendants shrink below their content (the default
     min-width:auto forced the quiz/stats panels wider than the viewport, which
     clipped the subtitle and stat-card labels at the screen edge). */
  #tab-quiz *, #tab-stats *, #tab-words * { min-width: 0; }
  /* Stat / results cards: let the 2-col grids shrink below content width
     (repeat(2,1fr) was blowing the grid out past the viewport). */
  #stats-top { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #quiz-results-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .onb-demo { grid-template-columns: 1fr; }
  .quiz-prompt { font-size: 42px; }
  /* Per-tone diagnostic scrolls horizontally with single-line headers. */
  .stats-section { overflow-x: auto; }
  .tone-table { table-layout: auto; min-width: 480px; font-size: 11px; }
  .tone-table th, .tone-table td { white-space: nowrap; padding: 6px 8px; word-break: normal; }
  .tone-table th:last-child, .tone-table td:last-child { white-space: normal; }
}
