/* ===========================================================================
   Deckr — dark, high contrast, thumb-first.
   Latin text is sized for glanceability; Chinese is always noticeably larger
   because small hanzi are unreadable on a phone.
   =========================================================================== */

:root {
  --bg:        #0e1116;
  --surface:   #171d26;
  --surface-2: #212a36;
  --line:      #2c3644;
  --text:      #f2f5f8;
  --muted:     #9aa7b8;
  --accent:    #4cc9a7;
  --accent-dk: #123a30;
  --bad:       #ff6b6b;
  --bad-dk:    #3d1b1e;

  --pad: 16px;
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);

  color-scheme: dark;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior: none;
}

/* Kill the iOS tap flash and text selection — this is an app, not a document. */
button, label.btn, .seg {
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
}

/* Chinese wants a font stack that actually has traditional glyphs. */
.zh {
  font-family: "PingFang HK", "PingFang TC", "Hiragino Sans CNS",
               "Noto Sans HK", "Microsoft JhengHei", system-ui, sans-serif;
}

/* ---------------------------------------------------------------- screens */

.screen {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  padding: calc(var(--safe-t) + 12px) var(--pad) calc(var(--safe-b) + 24px);
}
.screen[hidden] { display: none; }

.home-head { margin: 8px 0 20px; }
.home-head h1 {
  margin: 0;
  font-size: 34px;
  font-weight: 700;
  letter-spacing: -0.02em;
}
/* A screen you came into rather than one you start on: the way out sits
   beside the title, where a thumb reaches before it reaches the bottom. */
.head-with-back { display: flex; align-items: flex-start; gap: 12px; }
.back-arrow { font-size: 22px; line-height: 1; margin-top: 2px; }

.home-head .sub {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 16px;
}

.section-title {
  margin: 28px 0 10px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}

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

.stats {
  display: flex;
  gap: 10px;
  margin-bottom: 14px;
}
.stats[hidden] { display: none; }
.stat {
  flex: 1;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 12px 8px;
  text-align: center;
}
.stat-num {
  display: block;
  font-size: 26px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.stat-num.good { color: var(--accent); }
.stat-num.bad  { color: var(--bad); }

/* Mastery-level tallies: green = levels 1–3, red = level 4, grey = level 5. */
.stat-num.lvl-known  { color: var(--accent); }
.stat-num.lvl-weak   { color: var(--bad); }
.stat-num.lvl-unseen { color: var(--muted); }
.stat-label {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}

/* ---------------------------------------------------------------- buttons */

.btn {
  display: block;
  width: 100%;
  border: 1px solid transparent;
  border-radius: 14px;
  font: inherit;
  font-weight: 600;
  text-align: center;
  padding: 16px;
  cursor: pointer;
  background: var(--surface-2);
  color: var(--text);
}
.btn:active { transform: scale(0.985); filter: brightness(1.15); }
.btn:disabled { opacity: 0.4; }
/* Dimmed like :disabled but still clickable — used for Quiz/List with no
   deck selected, so a tap can prompt the user to pick one. */
.btn.looks-disabled { opacity: 0.4; }
.btn[hidden] { display: none; }

.btn-big { min-height: 60px; font-size: 19px; }

.btn-primary   { background: var(--accent); color: #06231b; }
.btn-secondary { background: var(--surface-2); border-color: var(--line); }
.btn-ghost     { background: transparent; border-color: var(--line); color: var(--text); padding: 14px; }
.btn-danger-ghost {
  background: transparent;
  border-color: var(--bad-dk);
  color: var(--bad);
  margin-top: 10px;
  padding: 14px;
}

.btn-note {
  display: block;
  margin-top: 3px;
  font-size: 13px;
  font-weight: 500;
  opacity: 0.7;
}

/* Recommended carries its due count as a pill under the label, where the
   explanatory note used to sit. */
.btn-with-count {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
}
.btn-count {
  padding: 2px 11px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.18);
  font-size: 14px;
  font-weight: 700;
  white-space: nowrap;
}
.btn-count[hidden] { display: none; }

/* The row does the spacing. A button that carries its own margin (a ghost
   danger button does) would otherwise sit lower and shorter than its pair. */
.tool-row { display: flex; gap: 10px; margin-top: 14px; }
.tool-row .btn { flex: 1; margin: 0; }
label.btn { line-height: normal; }

/* A column of full-width buttons, spaced by the gap alone — same reason, and
   the same for the two action stacks that already existed (.edit-actions puts
   a danger button under Save/Cancel, .summary-actions can too). */
.btn-stack { display: flex; flex-direction: column; gap: 10px; }
.btn-stack > .btn, .btn-stack > .tool-row,
.edit-actions > .btn, .summary-actions > .btn { margin: 0; }
/* ...and, when it sits under a list, clear of it. */
.stack-foot { margin-top: 16px; }

/* A list that pushes the buttons under it down to the bottom of the screen. */
.list-grow { flex: 1 1 auto; }

.footnote {
  margin: 16px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}

.btn-spaced { margin-bottom: 10px; }

/* The version stamp at the foot of Settings. Quiet enough to ignore, there
   when you go looking for it. */
.version-line {
  margin: 22px 0 0;
  text-align: center;
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
  opacity: 0.75;
}

/* --------------------------------------------------- reminder banner */

.banner {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
  padding: 13px 14px;
  border-radius: 14px;
  background: var(--surface);
  border: 1px solid var(--line);
}
.banner[hidden] { display: none; }
.banner-text { flex: 1; font-size: 15px; color: var(--muted); }

/* Outstanding session: warm up the whole banner so it reads at a glance. */
.banner.banner-due {
  background: #2a2113;
  border-color: #5c4a1e;
}
.banner.banner-due .banner-text { color: #ffd98a; font-weight: 600; }

.banner-action {
  flex: 0 0 auto;
  min-height: 40px;
  padding: 0 18px;
  border: 0;
  border-radius: 11px;
  background: var(--accent);
  color: #06231b;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.banner-action[hidden] { display: none; }

.notice {
  margin: 0 0 14px;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--bad-dk);
  border: 1px solid #5c2a2e;
  color: #ffc9c9;
  font-size: 14px;
}

/* Prompt shown when Quiz/List is tapped with no decks selected. */
.hint {
  margin: 0 0 10px;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--accent-dk);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: 14px;
}
.hint[hidden] { display: none; }

/* ================================================================= the path

   A ladder rather than a wandering trail: the rail sits under the middle of
   every square, so it stays straight at any width and the titles all start
   at the same place. Squares fill from the bottom with the share of their
   deck that has stuck.
   ------------------------------------------------------------------------ */

/* Three across the top of the home screen, above everything they change.
   The notes are the first thing to go when the screen is narrow — the words
   Path, Decks and Show carry it on their own. */
.mode-toggle { margin-bottom: 14px; gap: 8px; }
.mode-toggle .seg-opt { padding: 11px 6px; font-size: 16px; }
.mode-toggle .seg-opt-note { font-size: 11px; }
.mode-toggle .seg-opt[hidden] { display: none; }

@media (max-width: 359px) {
  .mode-toggle .seg-opt-note { display: none; }
}

.path-block[hidden], .deck-block[hidden] { display: none; }

.path { list-style: none; margin: 0; padding: 0; }

.path-step { position: relative; padding-bottom: 20px; }
.path-step:last-child { padding-bottom: 0; }

/* The rail down to the next square: 4px wide, centred under a 54px node. */
.path-step::after {
  content: '';
  position: absolute;
  left: 25px;
  top: 54px;
  width: 4px;
  height: 20px;
  border-radius: 2px;
  background: var(--line);
}
.path-step:last-child::after { display: none; }
/* Lit as far as you have got: the rail below a deck you have passed. */
.path-step.passed::after { background: var(--accent); }

.path-row {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  cursor: pointer;
}

.path-node {
  position: relative;
  flex: 0 0 auto;
  width: 54px;
  height: 54px;
  padding: 0;
  border: 2px solid var(--line);
  border-radius: 16px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  overflow: hidden;
  cursor: pointer;
}
.path-node:active { transform: scale(0.96); }

/* How much of the deck is learned, painted from the bottom up. */
.path-fill {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--accent-dk);
  transition: height 0.3s ease;
}

.path-mark {
  position: relative;          /* over the fill */
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  font-size: 20px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* The deck you are on, ringed so the eye lands on it first. */
.path-node.current {
  border-color: var(--accent);
  box-shadow: 0 0 0 4px rgba(76, 201, 167, 0.16);
}

/* Past the line: solid green, the number in the dark ink the primary
   buttons use. */
.path-step.passed .path-node { border-color: var(--accent); }
.path-step.passed .path-fill { background: var(--accent); }
.path-step.passed .path-mark { color: #06231b; }

/* Shut: flat, dashed, and out of the way of the ones that are not. */
.path-step.locked .path-node {
  border-style: dashed;
  background: transparent;
  opacity: 0.55;
}
.path-step.locked .path-mark { font-size: 17px; }
.path-step.locked .path-title { color: var(--muted); font-weight: 600; }
.path-step.locked .path-row { cursor: default; }

.path-meta {
  flex: 1;
  min-width: 0;
  padding-top: 6px;
}
.path-title {
  display: block;
  font-size: 17px;
  font-weight: 600;
}
.path-sub {
  display: block;
  margin-top: 2px;
  font-size: 13px;
  color: var(--muted);
}

.path-done {
  display: inline-block;
  margin-top: 6px;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--accent-dk);
  color: var(--accent);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

/* -------------------------------------------------------------- deck list */

/* Looks like a search field and behaves like a button: tapping it opens the
   List screen with the real box focused, rather than typing here and having
   the screen change under the keyboard. */
.search-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  margin-bottom: 12px;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  color: var(--muted);
  font: inherit;
  font-size: 16px;
  text-align: left;
  cursor: pointer;
}
.search-bar:active { border-color: var(--accent); }
.search-glyph {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
}

.deck-list { list-style: none; margin: 0; padding: 0 0 12px; }

.deck-item {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 14px;
  margin-bottom: 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.deck-item[aria-checked="true"] {
  border-color: var(--accent);
  background: #14251f;
}

/* The chevron that says a row opens something. */
.deck-chev {
  flex: 0 0 auto;
  margin-left: 2px;
  color: var(--muted);
  font-size: 22px;
  line-height: 1;
}

/* Quizzing the deck you are reading. It rides in the sticky header, so it
   stays under the thumb however far down the list you are. */
.btn-quiz-deck {
  flex: 0 0 auto;
  min-height: 40px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: var(--accent);
  color: #06231b;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.btn-quiz-deck:active { filter: brightness(1.12); transform: scale(0.97); }
.btn-quiz-deck[hidden] { display: none; }

/* A deck row that opens something rather than toggling. */
.deck-open { cursor: pointer; }

.deck-name { flex: 1; font-weight: 600; }
.deck-mine {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--accent-dk);
  color: var(--accent);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  vertical-align: middle;
}
.deck-meta { font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* The colour-coded level counts down the right side of every deck row.
   Green = learned (1–3), red = only-wrong (4), grey = never seen (5). */
.deck-levels {
  flex: 0 0 auto;
  display: inline-flex;
  gap: 9px;
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.deck-levels .lvl-known  { color: var(--accent); }
.deck-levels .lvl-weak   { color: var(--bad); }
.deck-levels .lvl-unseen { color: var(--muted); }

/* ------------------------------------------------------------------- quiz */

/* The quiz screen is height-bounded, not just min-height: that is what lets
   .back-scroll scroll internally while the answer bar stays pinned. */
#screen-quiz {
  height: 100vh;
  height: 100dvh;
  max-height: 100dvh;
  padding-bottom: 0;
  overflow: hidden;
}

.quiz-top {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 0 0 auto;
  padding-bottom: 8px;
}
.btn-icon {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font-size: 17px;
  cursor: pointer;
}
.progress-track {
  flex: 1;
  height: 6px;
  border-radius: 3px;
  background: var(--surface-2);
  overflow: hidden;
}
.progress-bar {
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width 0.2s ease;
}
.quiz-count {
  flex: 0 0 auto;
  font-size: 14px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.card-face { flex: 1 1 auto; display: flex; min-height: 0; }
.card-face[hidden] { display: none; }

/* --- front --- */
.card-front {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 24px 8px calc(var(--safe-b) + 24px);
  cursor: pointer;
}
.kind-tag {
  font-size: 12px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 20px;
}
.front-text {
  font-size: clamp(28px, 8.5vw, 36px);
  font-weight: 600;
  line-height: 1.25;
  max-width: 18ch;
}
/* Chinese on the front (sign cards) gets much bigger. */
.front-text.zh {
  font-size: clamp(52px, 17vw, 76px);
  line-height: 1.15;
  font-weight: 500;
  letter-spacing: 0.03em;
}
.tap-hint {
  margin-top: 36px;
  font-size: 14px;
  color: var(--muted);
}

/* Being dragged down to be dismissed. Screens sit one after another in
   normal flow, so the one on its way out is lifted onto the viewport for the
   length of the gesture — that is what lets the home screen show through
   underneath it. See swipe to close in app.js. */
.screen-lifting {
  position: fixed;
  inset: 0;
  z-index: 30;
  background: var(--bg);
  border-radius: 22px 22px 0 0;
  box-shadow: 0 -14px 34px rgba(0, 0, 0, 0.5);
}

/* Tracks the finger with no transition at all; the class is added only for
   the spring back or the slide out. */
.card-settling { transition: transform 0.22s ease-out; }

/* The same, for a screen being pushed off sideways (see Settings). */
.screen-sliding { transition: transform 0.2s ease-out; }

/* Home is showing through underneath and must not scroll behind the card. */
body.card-lifting { overflow: hidden; }

/* --- back --- */
.card-back { flex-direction: column; }

.back-scroll {
  flex: 1 1 auto;
  min-height: 0;               /* without this a flex item refuses to shrink */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 16px;
}

.back-prompt {
  display: block;
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  padding: 4px 0 14px;
  margin-bottom: 22px;
  color: var(--muted);
  font: inherit;
  text-align: center;
  cursor: pointer;
}
#back-prompt-text {
  display: block;
  font-size: 20px;
  font-weight: 600;
  color: var(--text);
}
#back-prompt-text.zh { font-size: 30px; font-weight: 500; }
.back-prompt-hint {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.65;
}

/* THE SEGMENT ROW.
   A flex-wrap container of inline-block columns. Each column is one segment
   and wraps as a whole unit — a segment never splits across two lines. */
.segments {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: 10px 8px;
  margin-bottom: 22px;
}
.seg {
  display: inline-block;          /* the column is one indivisible box */
  vertical-align: top;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 10px 10px 8px;
  min-width: 62px;
  max-width: 46vw;
  font: inherit;
  color: var(--text);
  cursor: pointer;
}
.seg:disabled { opacity: 1; }        /* no voice just means it cannot be tapped */
.seg:active { background: var(--accent-dk); border-color: var(--accent); }
.seg.speaking { background: var(--accent-dk); border-color: var(--accent); }

.seg-zh {
  display: block;
  font-size: clamp(27px, 8.5vw, 36px);
  line-height: 1.2;
  font-weight: 500;
  white-space: nowrap;            /* keep a segment's hanzi on one line */
}
.seg-jp {
  display: block;
  margin-top: 4px;
  font-size: 15px;
  color: var(--accent);
  font-weight: 600;
  letter-spacing: 0.01em;
}
.seg-en {
  display: block;
  margin-top: 3px;
  font-size: 12.5px;
  line-height: 1.25;
  color: var(--muted);
}

.back-english {
  margin: 0 0 20px;
  text-align: center;
  font-size: 16px;
  color: var(--muted);
}

.btn-speak {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 62px;
  font-size: 19px;
  background: var(--surface-2);
  border: 1px solid var(--line);
}
.btn-speak .speak-glyph { font-size: 23px; }

/* Deliberately low-key and well away from the answer buttons — hiding a card
   is rare and must never be a misfire. */
.btn-hide-card {
  display: block;
  margin: 26px auto 8px;
  padding: 12px 18px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 12px;
  color: var(--muted);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}
.btn-hide-card:active { color: var(--bad); border-color: #5c2a2e; }

/* THE ANSWER BAR.
   Pinned to the bottom, above the home indicator, with a wide gutter between
   the two buttons so a thumb cannot catch the wrong one. */
.answer-bar {
  flex: 0 0 auto;
  display: flex;
  gap: 20px;
  padding: 12px 0 calc(var(--safe-b) + 12px);
  background: linear-gradient(to top, var(--bg) 72%, transparent);
}
.answer-bar .btn {
  flex: 1;
  min-height: 68px;
  font-size: 19px;
  border-radius: 18px;
}
.btn-got    { background: var(--accent); color: #06231b; }
.btn-missed { background: var(--bad-dk); color: #ffb3b3; border-color: #5c2a2e; }

/* ---------------------------------------------------------------- summary */

.missed-list { list-style: none; margin: 0; padding: 0; flex: 1 1 auto; }
.missed-list:empty::after {
  content: "Nothing missed. 叻仔!";
  display: block;
  padding: 20px 0;
  color: var(--muted);
}
.missed-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  margin-bottom: 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.missed-body { flex: 1; min-width: 0; }
.missed-zh { display: block; font-size: 26px; line-height: 1.25; }
.missed-jp { display: block; font-size: 14px; color: var(--accent); font-weight: 600; }
.missed-en { display: block; font-size: 14px; color: var(--muted); }
.missed-speak { flex: 0 0 auto; font-size: 22px; opacity: 0.8; }

.summary-actions { margin-top: 22px; display: flex; flex-direction: column; gap: 10px; }

/* --------------------------------------------------------- list (browse) */

/* Header and filter stay put while a few hundred cards scroll past them. The
   negative margins cancel the screen's own padding so the sticky band reaches
   the edges — otherwise cards would scroll visibly up its sides. */
.browse-top {
  position: sticky;
  top: 0;
  z-index: 2;
  flex: 0 0 auto;
  margin: calc(-1 * (var(--safe-t) + 12px)) calc(-1 * var(--pad)) 14px;
  padding: calc(var(--safe-t) + 12px) var(--pad) 10px;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
}
.browse-bar { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 12px; }
.browse-heading { flex: 1; min-width: 0; }
.browse-bar .btn-icon { margin-top: 4px; font-size: 22px; line-height: 1; }
.browse-heading h1 { margin: 0; font-size: 28px; font-weight: 700; letter-spacing: -0.02em; }
.browse-heading .sub { margin: 2px 0 0; font-size: 13px; color: var(--muted); }

.browse-filter {
  display: block;
  width: 100%;
  padding: 13px 14px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 17px;              /* never below 16px, or iOS zooms on focus */
  -webkit-appearance: none;
  appearance: none;
}
.browse-filter:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Sort toggle. It rides in the sticky band with the filter, so it is kept
   short — the band eats scrolling space on a phone as it is. */
.browse-sort { display: flex; gap: 8px; margin-top: 8px; }
.sort-opt {
  flex: 1;
  padding: 8px 10px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.sort-opt[aria-checked="true"] {
  border-color: var(--accent);
  background: #14251f;
  color: var(--text);
}

.browse-list { list-style: none; margin: 0; padding: 0 0 24px; flex: 1 1 auto; }
.browse-list:empty::after {
  content: "Nothing matches that.";
  display: block;
  padding: 24px 0;
  color: var(--muted);
}

/* Deck separator — only shown when more than one deck is ticked. */
.browse-deck {
  margin: 18px 0 8px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}
.browse-deck:first-child { margin-top: 0; }

/* Sorted by skill, the heading names a mastery level rather than a deck —
   colour it the same way the home screen colours its three tallies. */
.browse-deck.lvl-known  { color: var(--accent); }
.browse-deck.lvl-weak   { color: var(--bad); }
.browse-deck.lvl-unseen { color: var(--muted); }

/* A search that found nothing, saying so. */
.browse-none {
  padding: 18px 4px;
  color: var(--muted);
  font-size: 15px;
}

.browse-item {
  padding: 12px 14px 10px;
  margin-bottom: 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
}

.browse-head { display: flex; align-items: baseline; gap: 12px; }
.browse-en { flex: 1; min-width: 0; font-size: 17px; font-weight: 600; }

.browse-speak {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: transparent;
  font-size: 18px;
  cursor: pointer;
}
.browse-speak:active { background: var(--accent-dk); border-color: var(--accent); }
.browse-speak:disabled { opacity: 0.35; }

/* The whole romanisation on one line, then the syllable-by-syllable breakdown. */
.browse-jp {
  margin-top: 2px;
  font-size: 15px;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: 0.01em;
}

.browse-segs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}
.browse-seg {
  display: inline-block;
  text-align: left;
  padding: 6px 9px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
.browse-seg:disabled { opacity: 1; }   /* no voice just means it cannot be tapped */
.browse-seg:active,
.browse-seg.speaking { background: var(--accent-dk); border-color: var(--accent); }

.browse-seg-top { display: block; }
.browse-seg-jp { font-size: 14px; font-weight: 600; color: var(--accent); }
.browse-seg-zh { margin-left: 6px; font-size: 19px; line-height: 1.1; }
.browse-seg-en {
  display: block;
  margin-top: 1px;
  font-size: 12.5px;
  line-height: 1.25;
  color: var(--muted);
}

/* Per-card actions — deliberately low-key, like the quiz's hide button. */
.browse-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}
.browse-action {
  padding: 8px 14px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.browse-action:active { background: var(--surface-2); color: var(--text); }
.browse-hide:active { color: var(--bad); border-color: #5c2a2e; }

/* ---------------------------------------------------------- hidden cards */

.hidden-list { list-style: none; margin: 0 0 20px; padding: 0; flex: 1 1 auto; }

.hidden-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  margin-bottom: 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
}
.hidden-body { flex: 1; min-width: 0; }
.hidden-zh { display: block; font-size: 26px; line-height: 1.25; }
.hidden-en { display: block; font-size: 13px; color: var(--muted); }

.btn-restore {
  flex: 0 0 auto;
  width: auto;
  padding: 12px 16px;
  font-size: 15px;
}

/* -------------------------------------------------------- progress graph */

.range-row { display: flex; gap: 8px; margin: 4px 0 14px; }

.range-btn {
  flex: 1;
  padding: 9px 0;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}
.range-btn.is-on {
  background: var(--surface-2);
  border-color: var(--accent);
  color: var(--text);
}

.chart-card {
  padding: 12px 10px 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
}

.chart { display: block; width: 100%; height: auto; }

.chart-grid { stroke: var(--line); stroke-width: 1; }
.chart-axis { fill: var(--muted); font-size: 9px; }

.chart-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart-known { stroke: var(--accent); }
.chart-weak  { stroke: var(--bad); stroke-width: 1.5; opacity: 0.8; }

.chart-area { fill: var(--accent); opacity: 0.12; stroke: none; }
.chart-dot  { fill: var(--accent); }

.chart-legend {
  display: flex;
  gap: 16px;
  margin-top: 10px;
  padding-left: 4px;
  font-size: 13px;
  color: var(--muted);
}
.legend-item { display: flex; align-items: center; gap: 6px; }
.legend-swatch { width: 12px; height: 3px; border-radius: 2px; }
.legend-known { background: var(--accent); }
.legend-weak  { background: var(--bad); }

.chart-empty { margin: 10px 4px 2px; font-size: 14px; color: var(--muted); }

/* ------------------------------------------------------------- my cards */

.mycards-list { list-style: none; margin: 18px 0; padding: 0; flex: 1 1 auto; }

.mycard-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  margin-bottom: 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.mycard-body { flex: 1; min-width: 0; }
.mycard-zh { display: block; font-size: 26px; line-height: 1.25; }
.mycard-meta { display: block; font-size: 13px; color: var(--muted); }
.mycard-hidden {
  flex: 0 0 auto;
  padding: 4px 9px;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.mycard-silent {
  flex: 0 0 auto;
  padding: 4px 9px;
  border-radius: 999px;
  background: var(--bad-dk);
  color: #ffb3b3;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ------------------------------------------------------------ settings */

/* Title on the left, gear on the right, both on the home header's baseline. */
/* The name, with the tour a tap away beside it. */
.title-row { display: flex; align-items: center; gap: 9px; }

.btn-info {
  position: relative;
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}
/* A 24px circle is the right size to look at and the wrong size to hit. */
.btn-info::after { content: ''; position: absolute; inset: -11px; }
.btn-info:active { color: var(--accent); border-color: var(--accent); }

.home-head-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}
.btn-gear { font-size: 20px; line-height: 1; margin-top: 4px; }

/* ------------------------------------------------------------ language */

/* The language pill sits next to the gear and names the language you are in,
   so which one you are studying is readable from the home screen without
   opening anything. */
.head-tools {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}
.btn-lang {
  flex: 0 0 auto;
  height: 40px;
  margin-top: 4px;
  padding: 0 14px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}

/* Rows on the language screen carry a second line of their own progress, so
   they are taller than a deck row and stack rather than sit on one line. */
.lang-item { align-items: center; }
.lang-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.lang-sub { font-size: 13px; color: var(--muted); }
.lang-current {
  flex: 0 0 auto;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--accent-dk);
  color: var(--accent);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}
.setting-row:last-child { border-bottom: 0; }

.setting-text { min-width: 0; }          /* let the label wrap, not the input */
.setting-label { display: block; font-size: 17px; }
.setting-sub {
  display: block;
  margin-top: 2px;
  font-size: 13px;
  color: var(--muted);
}

/* A setting picked off a list needs the room a number does not. */
.setting-select { min-width: 10.5em; }

.setting-input {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.setting-number {
  width: 78px;
  padding: 10px 12px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 17px;          /* never below 16px, or iOS zooms on focus */
  text-align: right;
  -moz-appearance: textfield;
}
.setting-number::-webkit-outer-spin-button,
.setting-number::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.setting-number:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.setting-unit { font-size: 13px; color: var(--muted); }

/* --------------------------------------------------------- card editor */

.field { display: block; margin-bottom: 16px; }
.field-label {
  display: block;
  margin-bottom: 6px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.field input {
  width: 100%;
  padding: 14px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 17px;          /* never below 16px, or iOS zooms on focus */
}
.field input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.field input.input-zh { font-size: 26px; letter-spacing: 0.04em; }

.field-select {
  width: 100%;
  padding: 14px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 17px;
  -webkit-appearance: none;
  appearance: none;
}
.field-select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.field-hint { margin: 0 0 8px; font-size: 13px; color: var(--muted); }

/* Syllable chips — tap to cycle through homophones. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 18px;
  min-height: 4px;
}
.chip {
  display: inline-block;
  text-align: center;
  padding: 8px 10px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
.chip-choice { border-color: var(--accent); }
.chip-unknown { border-color: #5c2a2e; background: var(--bad-dk); }
.chip-zh { display: block; font-size: 28px; line-height: 1.15; }
.chip-unknown .chip-zh { color: #ffb3b3; }
.chip-jp { display: block; margin-top: 2px; font-size: 12px; color: var(--accent); font-weight: 600; }
.chip-more { display: block; margin-top: 1px; font-size: 10px; color: var(--muted); }

.seg-toggle { display: flex; gap: 10px; }
.seg-opt {
  flex: 1;
  padding: 13px 10px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.seg-opt[aria-checked="true"] { border-color: var(--accent); background: #14251f; }
.seg-opt-note {
  display: block;
  margin-top: 3px;
  font-size: 11px;
  font-weight: 500;
  color: var(--muted);
}

.edit-preview {
  min-height: 60px;
  margin: 8px 0 14px;
  padding: 12px 8px;
  border-radius: 14px;
  background: var(--surface);
  border: 1px dashed var(--line);
}
.seg-missing { color: var(--muted); opacity: 0.6; }

.edit-actions { margin-top: 22px; display: flex; flex-direction: column; gap: 10px; }

.silent-note {
  margin: 18px 0 0;
  text-align: center;
  font-size: 13px;
  color: var(--muted);
}

.back-deck {
  margin: 20px 0 0;
  text-align: center;
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--muted);
  opacity: 0.75;
}

.card-tools { display: flex; gap: 10px; justify-content: center; }
.card-tools .btn-hide-card { margin-left: 0; margin-right: 0; }

/* ---------------------------------------------------------------- share */

/* The share node in the home header, drawn rather than set in a glyph: no
   font ships a share mark that looks the same on Android and iOS. */
/* The pill and the gear both drop 4px to sit on the title's baseline; the
   share button has to make the same drop or it rides above its neighbours. */
.btn-share {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 4px;
}
.btn-share svg {
  display: block;
  width: 19px;
  height: 19px;
}
.btn-share circle { fill: currentColor; }
.btn-share path { fill: none; stroke: currentColor; stroke-width: 1.7; }

/* A sheet, not a screen — it slides over Home and gives it straight back. */
.sheet {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.sheet[hidden] { display: none; }

.sheet-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
}

.sheet-panel {
  position: relative;
  width: 100%;
  max-width: 520px;
  max-height: 88vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 8px var(--pad) calc(var(--pad) + var(--safe-b));
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: 22px 22px 0 0;
  background: var(--surface);
  animation: sheet-rise 0.18s ease-out;
}
@keyframes sheet-rise {
  from { transform: translateY(16px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

/* The grab handle every sheet on a phone has, so it reads as dismissable. */
.sheet-grip {
  width: 38px;
  height: 4px;
  margin: 0 auto 12px;
  border-radius: 2px;
  background: var(--line);
}

.sheet-title { margin: 0; font-size: 20px; }
.sheet-sub {
  margin: 4px 0 0;
  font-size: 14px;
  color: var(--muted);
  word-break: break-all;
}
.sheet-note {
  margin: 12px 0 0;
  text-align: center;
  font-size: 13px;
  color: var(--muted);
}
.sheet-note-live { color: var(--accent); }
.sheet-note[hidden] { display: none; }
.sheet-close { margin-top: 14px; width: 100%; }

/* Two by two: four targets a thumb can hit without looking. */
.share-options {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 16px;
}
.share-options[hidden] { display: none; }

.share-opt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  padding: 16px 8px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}
.share-opt:active { transform: scale(0.985); filter: brightness(1.15); }

.share-tile {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 14px;
}
.share-tile svg { width: 26px; height: 26px; }
.glyph-fill { fill: currentColor; }
.glyph-stroke {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
}

/* Brand colours, so the two apps are recognised before the label is read. */
.tile-whatsapp { background: #25d366; color: #ffffff; }
.tile-snapchat { background: #fffc00; color: #12140a; }
.tile-plain    { background: var(--surface); border: 1px solid var(--line); color: var(--text); }

/* A QR code is only scannable on white, whatever the app around it looks
   like — so the frame is a white card rather than a dark one. */
.share-qr[hidden] { display: none; }
.qr-frame {
  width: min(260px, 62vw);
  margin: 18px auto 0;
  padding: 8px;
  border-radius: 14px;
  background: #ffffff;
}
.qr-frame svg { display: block; width: 100%; height: auto; }
.share-qr .btn { margin-top: 14px; width: 100%; }

/* The country list in its sheet: name on the left, how it is written on the
   right, so the answer teaches something on the way past. */
.country-list { margin-top: 16px; max-height: 52vh; overflow-y: auto; }
.country-list .deck-item { margin-bottom: 8px; }
.country-zh { margin-left: auto; font-size: 20px; color: var(--muted); }

/* With a sheet up, the page behind it must not scroll under the thumb. */
body.sheet-open { overflow: hidden; }

/* ============================================================== welcome tour

   A full-screen overlay, not a screen: it has to sit over Home while the
   decks are still loading. The panel is a column — top bar, one scrolling
   slide, fixed nav — so the two buttons stay under the thumb however long
   the slide is.
   ------------------------------------------------------------------------ */

.welcome {
  position: fixed;
  inset: 0;
  z-index: 60;              /* over the share sheet, which is 50 */
  background: var(--bg);
  display: flex;
  justify-content: center;
}
.welcome[hidden] { display: none; }

.welcome-panel {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 520px;
  height: 100%;
  padding: calc(var(--safe-t) + 12px) var(--pad) calc(var(--safe-b) + 16px);
}

.welcome-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
}

.welcome-dots { display: flex; gap: 7px; }
.welcome-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--line);
  cursor: pointer;
}
.welcome-dot.on { background: var(--accent); }
/* Wider than it looks: a 8px dot is not a tap target. */
.welcome-dot::after {
  content: '';
  position: absolute;
  inset: -11px;
}
.welcome-dot { position: relative; }

.welcome-skip {
  padding: 6px 2px;
  border: 0;
  background: none;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
}
.welcome-skip:active { color: var(--text); }

/* The only part that scrolls. */
.welcome-body {
  flex: 1 1 auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 8px;
}

.wslide { animation: wslide-in 0.18s ease-out; }
/* A page follows the finger with no transition; this is added only to ease
   it back when the swipe was too short to turn it. */
.wslide-settling { transition: transform 0.18s ease-out; }
.wslide[hidden] { display: none; }
@keyframes wslide-in {
  from { transform: translateX(12px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

.welcome-h {
  margin: 10px 0 0;
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.welcome-lead {
  margin: 8px 0 0;
  font-size: 17px;
  color: var(--muted);
}
.welcome-body-text { margin: 18px 0 0; font-size: 16px; }
.welcome-note {
  margin: 16px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}

.welcome-nav {
  display: flex;
  gap: 10px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}
.welcome-nav .btn { flex: 1; margin: 0; min-height: 54px; }
.welcome-nav .btn[hidden] { display: none; }

/* ---- slide 1: a card, so the thing being explained is on screen first */

.welcome-demo { display: flex; justify-content: center; margin: 22px 0 4px; }
.demo-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: min(240px, 74%);
  padding: 20px 16px;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--surface);
  /* A hint of the cards stacked behind it. */
  box-shadow: 0 0 0 1px var(--bg), 0 -6px 0 -1px var(--surface-2),
              0 -6px 0 0 var(--line), 0 10px 24px rgba(0, 0, 0, 0.35);
}
.demo-tag {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}
.demo-en { font-size: 17px; color: var(--muted); }
.demo-zh { font-size: 40px; line-height: 1.15; }
.demo-jp { font-size: 17px; font-weight: 600; color: var(--accent); }

/* ---- slide 2: one syllable pulled apart */

.jp-anatomy {
  margin: 22px 0 0;
  padding: 18px 16px 14px;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--surface);
  text-align: center;
}
.jp-word {
  font-size: 46px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.1;
}
.jp-sound { color: var(--text); }
.jp-tone  { color: var(--accent); }

/* The word again, taken apart a line at a time — spelled out rather than
   pointed at with ticks, which never line up on every font and width. */
.jp-parts {
  margin: 14px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  text-align: left;
}
.jp-part {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-top: 6px;
}
.jp-part dt {
  flex: 0 0 auto;
  min-width: 52px;
  text-align: right;
  font-size: 19px;
  font-weight: 700;
}
.jp-part dd {
  margin: 0;
  font-size: 15px;
  color: var(--muted);
}

.jp-pairs {
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}
.jp-pairs li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-top: 8px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
  font-size: 17px;
}
.jp-pairs .zh { font-size: 28px; line-height: 1; }
.jp-pairs b { color: var(--accent); }
.jp-gloss { margin-left: auto; color: var(--muted); font-size: 15px; }

/* ---- slide 3: the tone chart */

.tone-chart {
  margin: 20px 0 0;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--surface);
  overflow: hidden;
}

.tone-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 14px;
  border: 0;
  border-top: 1px solid var(--line);
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.tone-row:first-child { border-top: 0; }
.tone-row:active,
.tone-row.speaking { background: var(--accent-dk); }
/* No voice on the device: still a chart, just not a button. */
.tone-row:disabled { opacity: 1; cursor: default; }

.tone-num {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--accent);
  font-size: 14px;
  font-weight: 700;
}
.tone-plot { flex: 0 0 auto; width: 58px; height: 40px; display: block; }
.tone-grid { stroke: var(--line); stroke-width: 1; }
.tone-line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 3;
  stroke-linecap: round;
}

.tone-word { flex: 0 0 auto; display: flex; align-items: baseline; gap: 7px; }
.tone-zh { font-size: 24px; line-height: 1; }
.tone-jp { font-size: 15px; font-weight: 600; color: var(--accent); }

.tone-text { margin-left: auto; text-align: right; line-height: 1.25; }
.tone-name { display: block; font-size: 14px; font-weight: 600; }
.tone-en   { display: block; font-size: 13px; color: var(--muted); }

/* ---- slide 4: the numbered walk-through */

.welcome-steps {
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
  counter-reset: wstep;
}
.welcome-steps li {
  position: relative;
  margin-top: 14px;
  padding-left: 42px;
  font-size: 16px;
  line-height: 1.45;
  color: var(--muted);
}
.welcome-steps li b { color: var(--text); font-weight: 600; }
.welcome-steps li::before {
  counter-increment: wstep;
  content: counter(wstep);
  position: absolute;
  left: 0;
  top: 0;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--accent);
  font-size: 14px;
  font-weight: 700;
}

/* The two answer buttons, quoted inline at the size of a word. */
.pill {
  display: inline-block;
  padding: 1px 9px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 700;
  white-space: nowrap;
}
.pill-good { background: var(--accent); color: #06231b; }
.pill-bad  { background: var(--bad-dk); color: #ffb3b3; }

/* ---- slide 5: installing */

.welcome-installed {
  margin: 16px 0 0;
  padding: 12px 14px;
  border: 1px solid var(--accent-dk);
  border-radius: 14px;
  background: var(--accent-dk);
  color: var(--accent);
  font-size: 15px;
  font-weight: 600;
}
.welcome-installed[hidden] { display: none; }

.install-steps { margin-top: 18px; }

.install-card {
  margin-top: 10px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--surface);
}
/* The platform this phone actually is, called out from the other one. */
.install-card.likely { border-color: var(--accent); }

.install-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
.install-card.likely .install-head { color: var(--accent); }
.install-you {
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--accent-dk);
  font-size: 11px;
  letter-spacing: 0.05em;
}

.install-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 10px 0 0;
  font-size: 16px;
  line-height: 1.5;
}
.install-line .step-key {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--surface-2);
  font-size: 15px;
  font-weight: 600;
}
.install-line .step-key svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.install-arrow { color: var(--muted); }

/* With the tour up, the home screen behind it must not scroll. */
body.welcome-open { overflow: hidden; }

/* ============================================================ show someone

   A list to pick from, and then the phrase alone on the glass. The card is
   sized to the viewport and then turned inside it, so the same markup reads
   upright or sideways without the layout knowing which.
   ------------------------------------------------------------------------ */

.show-block[hidden] { display: none; }

/* The search box, which borrows the List screen's field wholesale — same
   height, same radius, same 17px that keeps iOS from zooming the page on
   focus. It reads English only, so it stays above everything: the tiles
   while you are browsing, the rows once you are not. */
.show-filter { margin-bottom: 12px; }

/* Two to a row and nothing below the fold: in a shop you know what sort of
   thing you are trying to say long before you know which sentence. */
.show-cats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.show-cats[hidden] { display: none; }

.show-cat {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 104px;
  padding: 16px 12px;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
.show-cat:active { border-color: var(--accent); background: #14251f; }

/* The name is the whole tile, so it is sized like a heading rather than a
   label — and it gives way on a narrow phone before it wraps badly. */
.show-cat-name {
  font-size: clamp(19px, 5.6vw, 24px);
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  letter-spacing: -0.01em;
}

/* The way back out of a category, with the category named beside it. */
.show-open {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}
.show-open[hidden] { display: none; }
.show-open .btn-icon { font-size: 22px; line-height: 1; }
.show-open-title { font-size: 20px; font-weight: 700; letter-spacing: -0.01em; }

.show-list { list-style: none; margin: 0; padding: 0; }
.show-list[hidden] { display: none; }

.show-row {
  display: flex;
  align-items: baseline;
  gap: 14px;
  width: 100%;
  margin-bottom: 8px;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.show-row:active { border-color: var(--accent); background: #14251f; }

.show-row-en { flex: 1; min-width: 0; font-size: 16px; font-weight: 600; }
/* Which tile a search result came out of — the other half of what you were
   looking for, and small enough not to compete with the phrase. */
.show-row-cat {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  font-weight: 500;
  color: var(--muted);
}
/* The characters are the point of the row, so they are not the small print. */
.show-row-zh { flex: 0 1 auto; font-size: 21px; line-height: 1.3; color: var(--muted); }

/* ---------------------------------------------------------- the card */

.show-card {
  position: fixed;
  inset: 0;
  z-index: 55;
  background: var(--bg);
  overflow: hidden;           /* the stage sticks out of the box when turned */
}
.show-card[hidden] { display: none; }

.show-stage {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100vw;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 28px;
  text-align: center;
  /* transform is set in JS: translate(-50%, -50%) rotate(…) */
}
/* Turned a quarter: the box swaps its sides so the phrase is laid out for
   the shape it is actually being read in. */
.show-stage.sideways {
  width: 100vh;
  width: 100dvh;
  height: 100vw;
}

.show-zh {
  margin: 0;
  font-weight: 500;
  line-height: 1.18;
  letter-spacing: 0.02em;
}
/* Four sizes rather than one that fits nothing: 幾多錢 deserves the whole
   screen, a full sentence has to come down to fit on it. */
.size-huge  .show-zh { font-size: clamp(64px, 22vmin, 190px); }
.size-big   .show-zh { font-size: clamp(48px, 15vmin, 130px); }
.size-mid   .show-zh { font-size: clamp(36px, 11vmin, 96px); }
.size-small .show-zh { font-size: clamp(28px,  8vmin, 68px); }

.show-jp {
  margin: 0;
  font-size: clamp(14px, 3.4vmin, 26px);
  font-weight: 600;
  color: var(--accent);
}
.show-en {
  margin: 0;
  font-size: clamp(13px, 2.8vmin, 20px);
  color: var(--muted);
}

/* The controls stay with the phone rather than with the phrase: whichever
   way the words are turned, these are where your thumb left them. */
.show-tools {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 10px var(--pad) calc(var(--safe-b) + 10px);
  background: linear-gradient(to top, var(--bg) 65%, transparent);
}

.show-tool {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}
.show-tool:active { color: var(--accent); border-color: var(--accent); }
.show-tool[hidden] { display: none; }

.show-pick, .show-money {
  height: 44px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 16px;            /* never below 16px, or iOS zooms on focus */
  -webkit-appearance: none;
  appearance: none;
}
.show-pick[hidden], .show-money[hidden] { display: none; }

.show-money {
  display: flex;
  align-items: center;
  gap: 4px;
  color: var(--muted);
}
.show-money input {
  width: 5ch;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 16px;
  font-weight: 600;
  -webkit-appearance: none;
  appearance: none;
}
.show-money input::-webkit-outer-spin-button,
.show-money input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

body.show-open { overflow: hidden; }

/* --------------------------------------------------------- accessibility */

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  .btn:active { transform: none; }
  .path-node:active { transform: none; }
  .show-row:active { background: var(--surface); }
  .show-cat:active { background: var(--surface); }
  .path-fill { transition: none; }
  .sheet-panel { animation: none; }
  .share-opt:active { transform: none; }
  .wslide { animation: none; }
}

/* ===========================================================================
   SAY IT — the pronunciation check.

   Lives on the back of a card, under Play. Everything here is hidden unless
   a scorer is configured, so on a normal offline install none of it is ever
   seen.
   =========================================================================== */

.btn-say {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin-top: 10px;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--line);
}

.pron-panel {
  margin-top: 12px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
}

.pron-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.pron-title {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Held, not tapped — so it must not also be selectable, draggable, or a
   long-press that summons iOS's callout menu over the top of it. */
.pron-mic {
  width: 100%;
  padding: 18px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: 17px;
  font-weight: 600;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.pron-mic.live {
  background: var(--accent-dk);
  border-color: var(--accent);
  color: var(--accent);
  animation: pron-pulse 1.1s ease-in-out infinite;
}

@keyframes pron-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}

@media (prefers-reduced-motion: reduce) {
  .pron-mic.live { animation: none; }
}

.pron-status {
  margin: 10px 0 0;
  font-size: 14px;
  color: var(--muted);
  text-align: center;
}
.pron-status.good { color: var(--accent); }
.pron-status.bad  { color: var(--bad); }

.pron-results { margin-top: 6px; }

/* One row per syllable: what it was, how the three parts went, and the
   tone drawn out. */
.pron-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-top: 1px solid var(--line);
}

.pron-syl {
  flex: 0 0 62px;
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.pron-pills {
  flex: 1 1 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.pron-pill {
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 12px;
  white-space: nowrap;
  border: 1px solid transparent;
}
.pron-pill.ok   { background: var(--accent-dk); color: var(--accent); }
.pron-pill.bad  { background: var(--bad-dk);    color: var(--bad); }

/* Right, but by way of a Hong Kong shift rather than the book — outlined
   instead of filled, so it reads as "accepted" and not as "perfect". */
.pron-pill.okish {
  background: transparent;
  color: var(--accent);
  border-color: var(--accent-dk);
}

.pron-plot {
  flex: 0 0 96px;
  height: 44px;
  overflow: visible;
}

.pron-grid   { stroke: var(--line); stroke-width: 1; }
.pron-target { fill: none; stroke: var(--muted); stroke-width: 1.5;
               stroke-dasharray: 3 3; stroke-linecap: round; }
.pron-heard  { fill: none; stroke: var(--accent); stroke-width: 2;
               stroke-linecap: round; stroke-linejoin: round; }
.pron-heard.bad { stroke: var(--bad); }

.pron-legend {
  margin: 10px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
}

/* Not judged at all — the scorer has no aligner for this half yet. Neither a
   pass nor a fail, and it must not be mistaken for either. */
.pron-pill.unknown {
  background: transparent;
  color: var(--muted);
  border-color: var(--line);
  border-style: dashed;
}

/* ---------------------------------------------- tone recognition, settings */

/* Subordinate to .section-title: same shape, smaller, and not shouting, so
   the two subsections read as parts of Pronunciation rather than as two more
   top-level settings groups. */
.subsection-title {
  margin: 22px 0 8px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--text);
}

.tone-box {
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
}

.tone-state {
  margin: 0 0 10px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}

/* The prompt during calibration: what to say, large enough to read at arm's
   length, since you are about to be holding the phone and speaking at it. */
.tone-step {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0 0 10px;
  text-align: center;
}

.tone-step-n {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.tone-step-say {
  font-size: 30px;
  font-weight: 500;
  letter-spacing: 0.04em;
}

.tone-step-hint {
  font-size: 13px;
  color: var(--muted);
}

/* ---- what it heard */

.tone-try-out:empty { display: none; }

.tone-heard {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 10px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

.tone-heard-n {
  flex: 0 0 auto;
  min-width: 46px;
  padding: 6px 10px;
  border-radius: 12px;
  background: var(--accent-dk);
  color: var(--accent);
  font-size: 20px;
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.tone-heard-txt {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.tone-heard-name { font-size: 15px; font-weight: 600; }
.tone-heard-eg   { font-size: 13px; color: var(--muted); }

/* The runner-up is the useful half when a verdict looks wrong: it says which
   way the call was close, which is nearly always the merging pair. */
.tone-heard-alt  { font-size: 12px; color: var(--muted); opacity: 0.8; }

/* ---- the six si */

.tone-ref {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
}

.tone-ref-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 9px 12px;
  background: var(--surface);
}
.tone-ref-row + .tone-ref-row { border-top: 1px solid var(--line); }

.tone-ref-zh { flex: 0 0 28px; font-size: 20px; }
.tone-ref-jp {
  flex: 0 0 34px;
  font-size: 14px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.tone-ref-en { flex: 1 1 auto; font-size: 13px; color: var(--muted); }

/* The level from the microphone test. Not a live meter — it shows the peak
   of what was just recorded, which is the number that answers whether
   anything was actually heard. */
.mic-meter {
  height: 6px;
  margin-top: 10px;
  border-radius: 999px;
  background: var(--surface-2);
  overflow: hidden;
}

.mic-meter-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--accent);
  transition: width 140ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .mic-meter-fill { transition: none; }
}
