:root {
  --bg: #faf7f2;
  --surface: #ffffff;
  --text: #26221f;
  --text-muted: #6f6a64;
  --primary: #ff5a5f;
  --primary-dark: #e14448;
  --accent: #3d5af1;
  --accent-soft: #e8ecff;
  --success: #2fb380;
  --success-soft: #e3f8ef;
  --warn: #ffb020;
  --border: #eee3d8;
  --shadow: 0 8px 24px rgba(38, 34, 31, 0.08);
  --radius: 18px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #17151a;
    --surface: #221f26;
    --text: #f2eee9;
    --text-muted: #a79f97;
    --primary: #ff6b70;
    --primary-dark: #ff8388;
    --accent: #7c8dff;
    --accent-soft: #2a2c47;
    --success: #43cf9a;
    --success-soft: #17332a;
    --warn: #ffc247;
    --border: #322e35;
    --shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  }
}

* {
  box-sizing: border-box;
}

/* Global safety net: a normal-priority author rule that sets `display` on an
   element (e.g. `display: flex` for a flex container) always beats the
   browser's default `[hidden] { display: none }`, regardless of specificity
   — so any such element silently ignores the `hidden` attribute unless
   something re-asserts `display: none` for it. Hit this exact bug three
   times independently this session (a mic waveform, a language dropdown, a
   review-due panel) before promoting the fix to one global rule instead of
   re-adding it per element. `!important` is deliberate and the only case in
   this file: it must outrank every element's own `display`, and `hidden` is
   already the strongest possible visibility signal in the markup, so nothing
   should ever need to override it. */
[hidden] {
  display: none !important;
}

/* Windows' emoji font has no country flags, so the language flags in
   languages.js (🇯🇵 🇮🇱) render as bare letters ("JP", "IL") there. This font
   covers only the regional-indicator range, so listing it first swaps in
   real flags without touching any other text. */
@font-face {
  font-family: 'Twemoji Country Flags';
  unicode-range: U+1F1E6-1F1FF, U+1F3F4, U+E0062-E0063, U+E0065, U+E0067, U+E006C, U+E006E, U+E0073-E0074, U+E0077, U+E007F;
  src: url('https://cdn.jsdelivr.net/npm/country-flag-emoji-polyfill@0.1/dist/TwemojiCountryFlags.woff2') format('woff2');
  font-display: swap;
}

/* Flags sit inside <button>s, which don't inherit the body font. */
.flag {
  font-family: 'Twemoji Country Flags', 'Apple Color Emoji', 'Segoe UI Emoji', sans-serif;
}

body {
  margin: 0;
  font-family: 'Twemoji Country Flags',-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
}

#app {
  max-width: 560px;
  margin: 0 auto;
  padding: 24px 20px 60px;
  min-height: 100vh;
}

/* ---------- Header ---------- */
.app-header {
  position: relative;
  text-align: center;
  margin-bottom: 28px;
}

.app-header h1 {
  font-size: 2.2rem;
  margin: 0;
  color: var(--primary);
  letter-spacing: -0.02em;
}

.tagline {
  margin: 6px 0 0;
  color: var(--text-muted);
  font-size: 0.95rem;
}

/* ---------- Language selector ---------- */
/* Pinned to the header's top-left corner rather than flowing inline, so it
   sits clear of the centered title/tagline regardless of their width. */
.lang-select {
  position: absolute;
  top: 0;
  left: 0;
}

.account-select {
  position: absolute;
  top: 0;
  right: 0;
}

.account-select-btn {
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow);
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--accent);
  cursor: pointer;
  transition: transform 0.1s ease;
}

.account-select-btn:active {
  transform: scale(0.95);
}

.account-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 20;
  min-width: 200px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow);
  text-align: left;
}

.account-email {
  font-size: 0.85rem;
  color: var(--text-muted);
  padding: 4px 6px;
  word-break: break-all;
}

.account-signout-btn {
  padding: 8px 12px;
  border: none;
  border-radius: 10px;
  background: var(--primary);
  color: white;
  font-size: 0.9rem;
  font-weight: 500;
  cursor: pointer;
}

.lang-select-btn {
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow);
  font-size: 1.5rem;
  cursor: pointer;
  transition: transform 0.1s ease;
}

.lang-select-btn:active {
  transform: scale(0.95);
}

.lang-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 20;
  min-width: 200px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow);
  text-align: left;
}

.lang-option {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: none;
  border-radius: 10px;
  background: none;
  color: var(--text);
  font-size: 0.95rem;
  text-align: left;
  cursor: pointer;
}

.lang-option:hover:not([disabled]) {
  background: var(--bg);
}

.lang-option.active {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

.lang-option-add {
  margin-top: 2px;
  border-top: 1px solid var(--border);
  border-radius: 0 0 8px 8px;
  padding-top: 12px;
}

.lang-option[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

/* ---------- Panels ---------- */
.panel {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 18px 18px 20px;
  margin-bottom: 18px;
  box-shadow: var(--shadow);
}

/* Distinct accent-colored treatment so "words due today" reads as the
   priority action, distinct from browsing categories below it. Hidden by
   default in the markup and only unhidden once there's actually something
   due — see updateReviewPanel() in ui.js. */
.review-panel {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--accent-soft);
  border: 1px solid var(--accent);
}

.review-info {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.review-count {
  font-size: 1.8rem;
  font-weight: 700;
  color: var(--accent);
}

.review-label {
  color: var(--text);
  font-size: 0.9rem;
}

.panel-title {
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  margin: 0 0 12px;
}

/* Segmented control for switching how the word pool is browsed: fixed-size
   lesson chunks vs. cross-level thematic categories (see wordbanks.js). */
.browse-mode-toggle {
  display: flex;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 4px;
  margin-bottom: 14px;
}

.mode-btn {
  flex: 1;
  border: none;
  background: none;
  color: var(--text-muted);
  font-size: 0.85rem;
  font-weight: 600;
  padding: 8px;
  border-radius: 9px;
  cursor: pointer;
}

.mode-btn.active {
  background: var(--surface);
  color: var(--accent);
  box-shadow: var(--shadow);
}

.study-view-toggle {
  display: flex;
  justify-content: center;
  gap: 4px;
  margin: 0 0 14px;
}

.study-view-btn {
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 600;
  padding: 5px 14px;
  border-radius: 999px;
  cursor: pointer;
}

.study-view-btn.active {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: var(--accent);
}

.hint {
  color: var(--text-muted);
  font-size: 0.85rem;
  margin: 8px 0 0;
}

.romaji-hint {
  text-align: center;
  margin: 14px 0 0;
}

/* ---------- Category cards ---------- */
.category-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.chapter-group {
  border-bottom: 1px solid var(--border);
}

.chapter-group[open] {
  padding-bottom: 10px;
}

.chapter-title {
  padding: 12px 0;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 10px;
  list-style: none;
}

.chapter-title:hover {
  color: var(--accent);
}

.chapter-arrow {
  display: inline-block;
  transition: transform 0.2s ease;
  color: var(--text-muted);
  font-size: 0.9rem;
}

.chapter-group[open] .chapter-arrow {
  transform: rotate(0deg);
}

.chapter-group:not([open]) .chapter-arrow {
  transform: rotate(-90deg);
}

.chapter-content {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 10px;
}

.category-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 14px;
}

.category-card.custom {
  border-style: dashed;
}

.category-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.tools-section {
  margin-top: 20px;
}

.tools-heading {
  font-size: 0.85rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  margin: 0 0 10px;
}

.bulk-add-row {
  margin-top: 0;
}

.listen-along-row {
  margin-top: 10px;
}

.photo-scan-row {
  margin-top: 10px;
}

.inbox-email-row {
  margin-top: 10px;
  flex-wrap: wrap;
}

.inbox-email-row .category-info {
  flex: 1 1 100%;
}

.inbox-email-row .category-actions {
  flex-wrap: wrap;
  flex-shrink: 1;
}

.inbox-email-address {
  margin-top: 8px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.95em;
  word-break: break-all;
  user-select: all;
}

.inbox-email-line {
  margin-top: 8px;
  line-height: 26px;
}

.inbox-email-line .inbox-email-address {
  margin: 0;
  word-break: normal;
  overflow-wrap: anywhere;
}

.inbox-email-copyable {
  cursor: pointer;
  border-radius: 4px;
  /* Fills the 26px line box so a tap between wrapped lines still lands. */
  padding: 4px 0;
}

.inbox-email-copyable:hover,
.inbox-email-copyable:focus-visible {
  color: var(--accent);
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}

.inbox-email-domain,
.inbox-inline-icons {
  white-space: nowrap;
}

.inbox-inline-icons {
  margin-left: 4px;
}

.inbox-inline-icon {
  display: inline-flex;
  vertical-align: middle;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.inbox-inline-icon:hover,
.inbox-inline-icon:focus-visible {
  color: var(--accent);
  background: var(--accent-soft);
}

.inbox-inline-icon svg {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
}

.inbox-qr[hidden] { display: none; }

.inbox-qr {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 12px;
}

.inbox-qr-code {
  flex-shrink: 0;
  width: 132px;
  height: 132px;
  border-radius: 10px;
  overflow: hidden;
}

.inbox-qr-code svg {
  display: block;
  width: 100%;
  height: 100%;
}

.pending-scan-banner {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.engine-select {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 8px;
}

.engine-option {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  color: var(--text-muted);
  cursor: pointer;
}

.add-single-word-form {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.add-single-word-form input {
  flex: 1;
  min-width: 120px;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 1rem;
  background: var(--bg);
  color: var(--text);
}

.category-icon {
  font-size: 1.6rem;
  width: 40px;
  text-align: center;
}

.category-info {
  flex: 1;
  min-width: 0;
}

.category-label {
  font-weight: 600;
}

.category-meta {
  font-size: 0.8rem;
  color: var(--text-muted);
}

/* ---------- Buttons ---------- */
.btn {
  border: none;
  border-radius: 12px;
  padding: 10px 16px;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.05s ease, opacity 0.15s ease;
}

.btn:active {
  transform: scale(0.97);
}

a.btn {
  display: inline-block;
  text-decoration: none;
  text-align: center;
}

.btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn-primary {
  background: var(--primary);
  color: white;
}

.btn-primary:hover {
  background: var(--primary-dark);
}

.btn-secondary {
  background: var(--accent-soft);
  color: var(--accent);
}

.btn-start {
  background: var(--primary);
  color: white;
  flex-shrink: 0;
}

/* Sits to the left of the (primary, pink) Review button on a category
   already seen once — smaller and text-only so Review still reads as the
   main action, Quiz as the quick secondary one. */
.btn-quiz {
  background: none;
  color: var(--accent);
  font-size: 0.8rem;
  padding: 6px 10px;
  flex-shrink: 0;
}

.btn-wide {
  width: 100%;
}

.btn-icon {
  background: transparent;
  border: none;
  font-size: 1.3rem;
  cursor: pointer;
  color: var(--text);
  padding: 4px 8px;
}

/* ---------- Add word dialog ---------- */
dialog {
  border: none;
  border-radius: var(--radius);
  padding: 0;
  background: var(--surface);
  color: var(--text);
  max-width: 420px;
  width: 90vw;
}

dialog::backdrop {
  background: rgba(0, 0, 0, 0.4);
}

.add-word-form {
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.add-word-form h2 {
  margin: 0;
}

.add-word-form label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.add-word-form input {
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-size: 1rem;
}

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 6px;
}

.custom-word-list {
  border-top: 1px solid var(--border);
  margin-top: 12px;
  padding-top: 12px;
  max-height: 160px;
  overflow-y: auto;
}

.custom-word-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 0;
  font-size: 0.9rem;
}

/* ---------- Drill screen ---------- */
.drill-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}

.progress-bar {
  flex: 1;
  height: 10px;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: var(--success);
  transition: width 0.3s ease;
}

.progress-badge {
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--success);
  font-weight: 700;
  font-size: 0.95rem;
  flex-shrink: 0;
}

/* Learn Mode's badge is a plain position count ("3/25"), not a correct-answer
   tally, so it doesn't get the success-green treatment above. */
.progress-badge.neutral {
  color: var(--text-muted);
}

.check-icon {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--success);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
}

.drill-meta {
  color: var(--text-muted);
  font-size: 0.85rem;
  margin-bottom: 4px;
}

.drill-instruction {
  font-size: 1.4rem;
  margin: 0 0 56px;
}

/* A peeking stack of cards behind the active one, echoing a physical deck. */
/* 50% of the drill screen's width — was full-width (see drill-card's own
   comment below) before the user asked for a visibly smaller card. Sized on
   the container rather than .drill-card itself so the peeking stack behind
   it (also positioned relative to .card-stack) shrinks along with it instead
   of poking out past a now-smaller front card. */
.card-stack {
  position: relative;
  width: 50%;
  margin: 0 auto 10px;
}

/* Evenly-spaced, equal-width layers that fade progressively — each one
   reads as farther back purely through offset + fade, matching a real
   receding stack rather than layers that shrink or drift sideways. Insets,
   height and offsets below are half their original values, scaled down
   along with .card-stack so the peeking effect stays proportional at the
   smaller size instead of looking oversized against it. */
.stack-layer {
  position: absolute;
  top: 0;
  left: 5px;
  right: 5px;
  height: 28px;
  border-radius: 14px 14px 0 0;
  background: var(--surface);
  border: 1px solid var(--border);
}

/* Up to 7 layers can be rendered (plus the front .drill-card itself, for 8
   total) — see renderDrill()'s stackLayerCount, which sizes this to the
   actual number of cards left in the queue, capped at 8. */
.stack-layer.layer-1 {
  transform: translateY(-6px);
  z-index: 7;
  opacity: 0.65;
}

.stack-layer.layer-2 {
  transform: translateY(-11px);
  z-index: 6;
  opacity: 0.5;
}

.stack-layer.layer-3 {
  transform: translateY(-17px);
  z-index: 5;
  opacity: 0.38;
}

.stack-layer.layer-4 {
  transform: translateY(-22px);
  z-index: 4;
  opacity: 0.29;
}

.stack-layer.layer-5 {
  transform: translateY(-28px);
  z-index: 3;
  opacity: 0.22;
}

.stack-layer.layer-6 {
  transform: translateY(-33px);
  z-index: 2;
  opacity: 0.16;
}

.stack-layer.layer-7 {
  transform: translateY(-39px);
  z-index: 1;
  opacity: 0.1;
}

/* Pressing ♻️ reveals the translation in place (is-revealed), then once
   speech finishes the whole card fades out (is-leaving) before being
   replaced by the next card underneath. Stays a perfect square (aspect-ratio
   1/1) at whatever width .card-stack gives it — see that rule for why the
   card itself has no width of its own. */
.drill-card {
  position: relative;
  z-index: 10;
  background: var(--surface);
  border: 2px solid transparent;
  border-radius: 16px;
  box-shadow: var(--shadow);
  padding: 14px;
  text-align: center;
  aspect-ratio: 1 / 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  transition: opacity 0.3s ease, border-color 0.2s ease;
  margin-inline: 5px;
}

.drill-card.is-correct {
  border-color: var(--success);
}

/* The correct-celebration flip (see handleAttempt in ui.js) shows the same
   kanji/kana reveal as the ♻️ button and Learn Mode, just tinted green
   instead of accent-blue so a correct answer still reads as distinct from
   a "here's the answer, you got it wrong" reveal. Covers both the two-line
   kanji+kana case and the single-line .drill-word fallback for words with
   no kanji. */
.drill-card.is-correct .drill-word,
.drill-card.is-correct .drill-primary,
.drill-card.is-correct .drill-secondary {
  color: var(--success);
}

.drill-card.is-revealed .drill-word {
  color: var(--accent);
}

.drill-card.is-leaving {
  opacity: 0;
}

.drill-word {
  font-size: 1.4rem;
  font-weight: 700;
}

/* Shown instead of .drill-word, only once a card is revealed and the word
   has a kanji form (see the `kanji` field in wordbanks.js) — kanji on top
   and larger, since that's the form a learner mainly needs to recognize;
   the kana reading sits underneath, smaller, as the pronunciation aid.
   Kanji uses `--text` rather than a literal white: `--text` IS white-ish
   (#f2eee9) in the app's dark theme, but flips to near-black in light theme
   (`prefers-color-scheme: light` or the OS light mode) — a hardcoded white
   would go invisible against that theme's white card surface. .drill-secondary
   keeps the accent color from .is-revealed below, unaffected by this. */
.drill-primary {
  font-size: 2.3rem;
  font-weight: 700;
  color: var(--text);
  line-height: 1.15;
}

.drill-secondary {
  font-size: 1rem;
  font-weight: 600;
  color: var(--accent);
}

/* Kanji words: the kanji sits dead-center on the card and the kana reading
   hangs directly above it, taken out of flow so it doesn't push the kanji
   down off-center. */
.drill-reading {
  position: relative;
}

.drill-reading .drill-secondary {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  margin-bottom: 2px;
}

.drill-feedback-slot {
  min-height: 1.4em;
  text-align: center;
  margin: 14px 0;
}

.feedback {
  font-size: 0.95rem;
}

.feedback.wrong {
  color: var(--primary-dark);
}

.feedback.notice {
  color: var(--text-muted);
}

/* On-screen state readout, only present with ?debug in the URL. */
#debug-panel {
  position: fixed;
  left: 8px;
  right: 8px;
  bottom: 8px;
  z-index: 99;
  margin: 0;
  padding: 10px;
  background: rgba(0, 0, 0, 0.88);
  color: #43cf9a;
  font-family: ui-monospace, Menlo, monospace;
  font-size: 10px;
  line-height: 1.45;
  white-space: pre-wrap;
  border-radius: 10px;
  pointer-events: none;
}

/* The one element the UI updates while listening — a single line of text.
   Never re-rendered mid-listen; see setVoiceStatus in ui.js. */
.voice-status {
  text-align: center;
  min-height: 1.4em;
  margin-bottom: 10px;
  color: var(--accent);
  font-size: 1.05rem;
}

.script-suggestion {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-bottom: 10px;
  color: var(--text-muted);
  font-size: 0.9rem;
}

.script-chip {
  border: 1px solid var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 1.3rem;
  font-weight: 700;
  padding: 4px 14px;
  border-radius: 999px;
  cursor: pointer;
  transition: transform 0.1s ease;
}

.script-chip:active {
  transform: scale(0.94);
}

.controls-row {
  display: flex;
  align-items: stretch;
  gap: 12px;
}

.mic-btn {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: var(--primary);
  color: white;
  font-size: 1.8rem;
  padding: 16px;
  border-radius: 20px;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(255, 90, 95, 0.35);
  transition: transform 0.1s ease, background 0.15s ease;
}

.mic-btn:active {
  transform: scale(0.96);
}

/* Listening turns the button itself into a live waveform — both the idle
   mic glyph and the bars are always in the DOM; only visibility toggles via
   the `.listening` class, so starting a listen never has to touch innerHTML
   (recognition runs in its own iframe now — see voice.js — so mutating the
   PARENT page's classes here can't disturb it the way DOM churn once could). */
.mic-btn.listening {
  background: var(--accent);
  box-shadow: 0 6px 18px rgba(61, 90, 241, 0.35);
  animation: mic-pulse 1.4s ease-in-out infinite;
}

.mic-idle-icon {
  display: block;
}

.mic-btn.listening .mic-idle-icon {
  display: none;
}

.mic-waveform {
  display: none;
  align-items: center;
  justify-content: center;
  gap: 4px;
  height: 28px;
}

.mic-btn.listening .mic-waveform {
  display: flex;
}

.mic-waveform .bar {
  width: 4px;
  height: 100%;
  border-radius: 999px;
  background: white;
  transform: scaleY(0.22);
  animation: wave-idle 1.1s ease-in-out infinite;
}

/* Staggered delays and slightly different durations per bar are what make
   this read as a lively waveform instead of a row of bars pulsing in unison. */
.mic-waveform .bar:nth-child(1) { animation-delay: 0s; animation-duration: 1.1s; }
.mic-waveform .bar:nth-child(2) { animation-delay: 0.12s; animation-duration: 0.95s; }
.mic-waveform .bar:nth-child(3) { animation-delay: 0.24s; animation-duration: 1.2s; }
.mic-waveform .bar:nth-child(4) { animation-delay: 0.06s; animation-duration: 1s; }
.mic-waveform .bar:nth-child(5) { animation-delay: 0.3s; animation-duration: 0.85s; }
.mic-waveform .bar:nth-child(6) { animation-delay: 0.18s; animation-duration: 1.15s; }
.mic-waveform .bar:nth-child(7) { animation-delay: 0.36s; animation-duration: 1.05s; }

/* Real signal, zero extra mic consumers: `sound-active` is toggled by the
   recognizer's own soundstart/soundend events (relayed from the recognition
   iframe), not a second getUserMedia stream. A second stream was tried for a
   waveform earlier and was a prime suspect for breaking recognition on iOS —
   see the iOS speech gotcha notes. This reuses a signal already proven safe. */
.mic-waveform.sound-active .bar {
  animation-name: wave-active;
}

@keyframes wave-idle {
  0%, 100% { transform: scaleY(0.22); }
  50% { transform: scaleY(0.5); }
}

@keyframes wave-active {
  0%, 100% { transform: scaleY(0.3); }
  50% { transform: scaleY(1); }
}

@keyframes mic-pulse {
  0%, 100% { box-shadow: 0 6px 18px rgba(61, 90, 241, 0.35); }
  50% { box-shadow: 0 6px 26px rgba(61, 90, 241, 0.55); }
}

.mic-btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

.type-form {
  flex: 1;
  min-width: 0; /* lets the form shrink so ♻️ stays on screen on phones */
  display: flex;
  gap: 8px;
}

.type-form input {
  flex: 1;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 1rem;
  min-width: 0;
}

.next-btn {
  flex-shrink: 0;
  width: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 20px;
  background: var(--accent-soft);
  color: var(--accent);
  cursor: pointer;
  transition: transform 0.1s ease;
}

/* An inline SVG rather than the ♻️ emoji: emoji glyphs carry their own fixed
   colors and ignore the button's `color`, so the icon looked inconsistent
   across platforms instead of matching the app's accent blue like the
   reference UI's icon does. `stroke="currentColor"` ties it to `.next-btn`'s
   color, so it re-themes for free in light/dark mode. */
.next-btn svg {
  width: 26px;
  height: 26px;
}

.next-btn:active {
  transform: scale(0.94);
}

.next-btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Voice / Type switcher, replacing what used to be a single "Can't speak
   now?" link (this once also included a self-graded "Review" input mode,
   removed since the home screen's own Review button — a full flip-through
   revisit, see startLearnMode — covers that need without duplicating it
   here under a confusingly similar name). */
.input-mode-toggle {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin: 18px auto 0;
}

.mode-icon-btn {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 6px 10px;
  border-radius: 10px;
  cursor: pointer;
}

.mode-icon-btn.active {
  color: var(--accent);
  background: var(--accent-soft);
}

.mode-icon-btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Learn Mode: full-width single button, same footprint either flipped
   ("Show answer") or not ("Next →") — see renderLearn() in ui.js. */
.learn-btn {
  flex: 1;
}

/* Repeat-pronunciation button, shown next to "Next →" once a Learn Mode
   card is flipped — same fixed-width icon-button treatment as the drill
   screen's ♻️ .next-btn, so the two screens' controls-row feel consistent. */
.replay-btn {
  flex-shrink: 0;
  width: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 20px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 1.4rem;
  cursor: pointer;
  transition: transform 0.1s ease;
}

.replay-btn:active {
  transform: scale(0.94);
}

/* ---------- Admin mode (internal testing only, see ui.js) ---------- */
.admin-badge {
  position: fixed;
  bottom: 14px;
  right: 14px;
  z-index: 1000;
  background: var(--warn);
  color: #26221f;
  border: none;
  border-radius: 999px;
  padding: 6px 12px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  box-shadow: var(--shadow);
  cursor: pointer;
}

.btn-admin-auto {
  display: block;
  width: 100%;
  margin-top: 12px;
  padding: 10px;
  border: 1px dashed var(--warn);
  border-radius: 12px;
  background: none;
  color: var(--warn);
  font-size: 0.8rem;
  font-weight: 700;
  cursor: pointer;
}

.btn-admin-auto[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

/* ---------- Complete screen ---------- */
.complete-screen {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 40px 26px;
  text-align: center;
}

.complete-emoji {
  font-size: 3rem;
}

.complete-sub {
  color: var(--text-muted);
  margin-top: -6px;
}

.stats-row {
  display: flex;
  justify-content: center;
  gap: 28px;
  margin: 24px 0;
}

.stat-value {
  font-size: 1.6rem;
  font-weight: 700;
  color: var(--accent);
}

.stat-label {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.complete-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Bulk add words */
.bulk-add-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.form-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.form-group label {
  font-weight: 500;
  color: var(--text);
  font-size: 0.9rem;
}

.form-group input {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 1rem;
  background: var(--surface);
  color: var(--text);
}

.form-group input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-soft);
}

.form-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.bulk-words-list {
  padding: 12px;
  background: var(--accent-soft);
  border-radius: 10px;
  text-align: center;
}

.bulk-count {
  margin: 0;
  color: var(--accent);
  font-size: 0.9rem;
  font-weight: 500;
}

.bulk-queued-chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  margin-top: 8px;
}

.bulk-queued-chip {
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-size: 0.85rem;
}

.bulk-review-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.bulk-review-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: 60vh;
  overflow-y: auto;
}

.bulk-review-card {
  display: grid;
  grid-template-columns: 1fr 40px;
  gap: 10px;
  align-items: start;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px;
}

.bulk-review-word {
  display: grid;
  /* The Japanese side ("漢字 (かな)") is usually the longer one. */
  grid-template-columns: minmax(0, 1fr) 20px minmax(0, 1.6fr);
  /* Full card width — the buttons sit on their own row below. */
  grid-column: 1 / -1;
  gap: 8px;
  align-items: center;
}

.bulk-review-en {
  font-size: 0.9rem;
  color: var(--text-muted);
  word-break: break-word;
}

.bulk-review-arrow {
  text-align: center;
  color: var(--text-muted);
  font-size: 0.8rem;
}

.bulk-target-edit,
.bulk-context-edit {
  width: 100%;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.95rem;
  background: var(--surface);
  color: var(--text);
}

.bulk-target-edit {
  display: block;
  resize: none;
  overflow: hidden;
  font-family: inherit;
  line-height: 1.4;
  word-break: break-word;
}

.bulk-target-edit:focus,
.bulk-context-edit:focus {
  outline: none;
  border-color: var(--accent);
}

.bulk-review-context {
  grid-column: 1 / -1;
}

.bulk-context-edit {
  width: 100%;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.85rem;
  background: var(--surface);
  color: var(--text-muted);
}

.bulk-context-edit:focus {
  outline: none;
  border-color: var(--accent);
  color: var(--text);
}

.bulk-delete-btn {
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  font-size: 1.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s ease;
}

.bulk-delete-btn:hover {
  border-color: var(--primary);
  color: var(--primary);
  background: rgba(255, 90, 95, 0.1);
}

.bulk-ignore-btn {
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  font-size: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s ease;
  margin-left: 6px;
}

.bulk-ignore-btn:hover {
  border-color: var(--warn);
  background: rgba(255, 176, 32, 0.1);
}


.bulk-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.loading-spinner {
  width: 40px;
  height: 40px;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* ---------- Listening Practice (see renderListening in ui.js) ---------- */
.listening-mystery {
  font-size: 4rem;
  font-weight: 800;
  color: var(--accent);
  line-height: 1;
}

.listening-en {
  font-size: 1.5rem;
  line-height: 1.2;
  overflow-wrap: anywhere;
  text-wrap: balance;
  color: var(--text-muted, var(--text));
  opacity: 0.8;
}

/* ---------- Phone widths ---------- */
/* Category rows carry up to four buttons (View My Words / Listen / Quiz /
   Review), which can't share one line with the title on a phone — the
   buttons drop to their own row under the title instead of running off
   the right edge. */
@media (max-width: 600px) {
  .category-card {
    flex-wrap: wrap;
  }

  .category-info {
    flex: 1 1 0;
    min-width: 0;
  }

  .category-actions {
    flex: 1 1 100%;
    flex-wrap: wrap;
    justify-content: flex-end;
    flex-shrink: 1;
  }
}

/* ---------- Example sentence ----------
   Opened by the "💬 Example" card tool under a revealed card — see
   toggleExampleSentence in ui.js. Furigana comes from <ruby>/<rt>. */
.card-tool-btn.active {
  background: var(--accent);
  color: var(--surface);
}

.example-sentence {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 4px 5px 8px;
  padding: 12px 14px;
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow);
  text-align: left;
}

.example-item {
  display: flex;
  align-items: center;
  gap: 12px;
}

.example-item + .example-item {
  border-top: 1px solid var(--border);
  padding-top: 12px;
}

.example-play {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border: none;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 1.1rem;
  cursor: pointer;
}

.example-text {
  min-width: 0;
}

.example-target {
  font-size: 1.15rem;
  line-height: 2;
  color: var(--text);
  overflow-wrap: anywhere;
}

.example-target rt {
  font-size: 0.55em;
  color: var(--accent);
}

.example-roman {
  font-size: 0.85rem;
  font-style: italic;
  color: var(--accent);
  line-height: 1.4;
}

.example-en {
  font-size: 0.9rem;
  color: var(--text-muted);
  margin-top: 2px;
}

/* ---------- Library & Playlists ----------
   A music-player-style view over every custom word (see renderLibrary /
   renderPlaylist in ui.js): tracks with a ▶ play button, and playlists. */
.library-row,
.playlist-home-row {
  margin-top: 10px;
}

.btn-small {
  padding: 6px 12px;
  font-size: 0.8rem;
}

.library-top {
  display: flex;
  margin-bottom: 12px;
}

.library-tabs {
  margin-bottom: 12px;
}

.library-search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
}

.library-search:focus-within {
  border-color: var(--accent);
}

.library-search-icon {
  font-size: 0.85rem;
  opacity: 0.7;
}

.library-search input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  color: var(--text);
  font-size: 1rem; /* 16px+ stops iOS zooming in on focus */
  padding: 10px 0;
  outline: none;
}

.library-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 10px 2px;
  font-size: 0.8rem;
  color: var(--text-muted);
}

.library-sort select {
  margin-left: 4px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  padding: 4px 6px;
  font-size: 0.8rem;
}

.track-list {
  display: flex;
  flex-direction: column;
  margin-top: 6px;
}

.track-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 4px;
  border-bottom: 1px solid var(--border);
}

.track-row:last-of-type {
  border-bottom: none;
}

.track-play {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.8rem;
  cursor: pointer;
}

.track-play:active {
  transform: scale(0.94);
}

.track-info {
  flex: 1;
  min-width: 0;
}

.track-title {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}

.track-sub {
  font-size: 0.85rem;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

.track-action {
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--surface);
  color: var(--accent);
  font-size: 1rem;
  cursor: pointer;
}

.track-action.added {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--surface);
}

.track-action.remove {
  color: var(--text-muted);
  font-size: 0.85rem;
}

.playlist-menu {
  margin: 0 0 8px 48px;
  padding: 10px 12px;
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow);
  text-align: left;
}

.playlist-menu-label {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  margin-bottom: 8px;
}

.playlist-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.playlist-chips:empty {
  display: none;
}

.playlist-chip {
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-size: 0.85rem;
  padding: 6px 12px;
  border-radius: 999px;
  cursor: pointer;
}

.playlist-chip.added {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}

.new-playlist-form {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}

.new-playlist-form.compact {
  margin: 10px 0 0;
}

.new-playlist-form input {
  flex: 1;
  min-width: 0;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg);
  color: var(--text);
  font-size: 1rem;
}

.new-playlist-form input:focus {
  outline: none;
  border-color: var(--accent);
}

.playlist-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.playlist-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  color: var(--text);
  text-align: left;
  cursor: pointer;
}

.playlist-art,
.playlist-hero-art {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: linear-gradient(135deg, var(--primary), var(--accent));
  font-size: 1.3rem;
}

.playlist-item-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.playlist-item-name {
  font-weight: 600;
  overflow-wrap: anywhere;
}

.playlist-item-meta {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.playlist-item-arrow {
  font-size: 1.4rem;
  color: var(--text-muted);
}

.library-adding-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
  padding: 10px 12px;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--text);
  font-size: 0.9rem;
}

.playlist-hero {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 16px;
  text-align: left;
}

.playlist-hero-art {
  width: 88px;
  height: 88px;
  border-radius: 16px;
  font-size: 2.4rem;
  box-shadow: var(--shadow);
}

.playlist-hero-info {
  flex: 1;
  min-width: 0;
}

.playlist-hero-name {
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--text);
  overflow-wrap: anywhere;
}

.playlist-hero-meta {
  font-size: 0.85rem;
  color: var(--text-muted);
  margin-top: 2px;
}

.playlist-study-row,
.playlist-edit-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.playlist-study-row .btn {
  flex: 1 1 0;
}

.playlist-delete.confirming {
  background: var(--primary);
  color: white;
}

/* Per-word study marks (library): hidden until hover; the active non-neutral
   mark always shows, and touch screens show all three. */
.mark-group { display: flex; gap: 2px; flex-shrink: 0; }
.mark-btn {
  width: 28px; height: 28px; border: none; border-radius: 50%;
  background: transparent; color: var(--text-muted); font-size: 0.75rem;
  cursor: pointer; opacity: 0; transition: opacity 0.15s;
}
.track-row:hover .mark-btn,
.mark-btn:focus-visible { opacity: 0.7; }
.mark-btn.active.mark-more, .mark-btn.active.mark-less { opacity: 1; }
.mark-btn.active.mark-more { color: #c2410c; background: rgba(234, 88, 12, 0.14); }
.mark-btn.active.mark-less { color: #15803d; background: rgba(34, 197, 94, 0.16); }
.mark-btn.active.mark-neutral { opacity: 0.7; }
.mark-btn:hover { opacity: 1 !important; }
.mark-group:not(.marked) .mark-btn.active.mark-neutral { opacity: 0; }
.track-row:hover .mark-group:not(.marked) .mark-btn.active.mark-neutral { opacity: 0.7; }
@media (hover: none) { .mark-btn { opacity: 0.55; } .mark-group:not(.marked) .mark-btn.active.mark-neutral { opacity: 0.55; } }

/* Home review buttons (Quick Review / Custom Review). */
.review-panel { gap: 10px; }
.review-panel .btn { flex: 1; white-space: nowrap; }

/* My Words: Quick Review is the main button; Custom Review is a quiet link. */
.mywords-actions { flex-wrap: wrap; }
.mywords-actions #quick-review-btn { flex: 1 1 100%; }
.custom-review-btn { background: none; border: none; box-shadow: none; color: var(--text-muted); font-size: 0.8rem; text-decoration: underline; padding: 6px 10px; }

.quick-row { display: flex; gap: 8px; width: 100%; }
.quick-row #quick-review-btn { flex: 1; }
.quick-settings-btn { padding: 0 14px; }
.mywords-actions .quick-row { flex: 1 1 100%; }
.daily-row { display: flex; gap: 8px; width: 100%; }
.mywords-actions .daily-row { flex: 1 1 100%; }
.daily-tile { flex: 1; min-width: 0; padding: 9px 10px; font-size: 0.88rem; white-space: nowrap; }
.daily-tile:hover, .daily-tile:active { transform: none; box-shadow: none; }
.quick-setting-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; }

/* ---------- Backup & Restore window ---------- */
.backup-overlay { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; padding: 16px; background: rgba(0, 0, 0, 0.45); }
.backup-card { width: 100%; max-width: 420px; max-height: 90vh; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; padding: 20px; background: var(--surface); border: 1px solid var(--border); border-radius: 16px; box-shadow: var(--shadow); text-align: left; }
.backup-card h2 { margin: 0; font-size: 1.2rem; }
.backup-card h3 { margin: 6px 0 0; font-size: 0.95rem; }
.backup-card p { margin: 0; font-size: 0.92rem; }
.backup-note { color: var(--text-muted); font-size: 0.85rem !important; word-break: break-word; }
.backup-msg { color: #b3261e; }
.backup-btn { display: block; box-sizing: border-box; padding: 11px 14px; border: none; border-radius: 10px; background: var(--primary); color: #fff; font-size: 0.95rem; font-weight: 500; text-align: center; text-decoration: none; cursor: pointer; }
.backup-danger { background: #b3261e; }
.backup-list { display: flex; flex-direction: column; gap: 6px; }
.backup-item, .backup-close { padding: 9px 12px; border: 1px solid var(--border); border-radius: 10px; background: transparent; color: inherit; font-size: 0.9rem; cursor: pointer; text-align: left; }
.backup-close { text-align: center; }

.us-data-btn { display: block; width: 100%; margin: 8px 0 6px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px; background: var(--bg); color: inherit; font-size: 0.95rem; cursor: pointer; }

/* Daily Words Story (messaging-app look) */
.story-word { font: inherit; color: inherit; background: rgba(0,0,0,.12); border: 0; border-bottom: 2px solid #6366f1; border-radius: 4px; padding: 0 3px; cursor: pointer; }
.story-word.active { background: rgba(99,102,241,.4); }
.story-word-tools { margin-top: 10px; }
.chat-app { display: flex; flex-direction: column; gap: 10px; max-width: 640px; margin: 0 auto; }
.chat-top { display: flex; align-items: center; gap: 12px; padding: 10px 14px; border-radius: 14px; background: var(--card-bg, rgba(127,127,127,.12)); }
.chat-avatars { display: flex; }
.chat-avatar { width: 40px; height: 40px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 22px; background: #e0e7ff; flex: none; }
.chat-avatars .chat-avatar + .chat-avatar { margin-left: -12px; box-shadow: -2px 0 0 var(--bg, #fff); }
.chat-avatar.small { width: 32px; height: 32px; font-size: 18px; align-self: flex-end; }
.chat-top-name { font-weight: 700; }
.chat-top-sub { font-size: .8rem; opacity: .7; }
.chat-messages { display: flex; flex-direction: column; gap: 12px; min-height: 240px; max-height: 60vh; overflow-y: auto; padding: 8px 2px; }
.chat-row { display: flex; gap: 8px; align-items: flex-end; max-width: 88%; align-self: flex-start; }
.chat-row.right { flex-direction: row-reverse; align-self: flex-end; }
.chat-col { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.chat-row.right .chat-col { align-items: flex-end; }
.chat-name { font-size: .72rem; opacity: .65; padding: 0 6px; }
.chat-bubble { padding: 9px 14px; border-radius: 18px 18px 18px 4px; background: rgba(127,127,127,.2); font-size: 1.1rem; line-height: 1.6; }
.chat-row.right .chat-bubble { border-radius: 18px 18px 4px 18px; background: #3b82f6; color: #fff; }
.chat-row.right .story-word { background: rgba(255,255,255,.25); border-bottom-color: #fff; }
.chat-en { font-size: .85rem; opacity: .75; padding: 0 6px; }
.chat-tools { display: flex; gap: 4px; padding: 0 4px; }
.chat-tool { border: 0; background: transparent; font-size: .8rem; opacity: .6; cursor: pointer; padding: 2px 6px; color: inherit; }
.chat-typing .dot { display: inline-block; width: 7px; height: 7px; margin: 0 2px; border-radius: 50%; background: currentColor; opacity: .5; animation: chatdot 1s infinite; }
.chat-typing .dot:nth-child(2) { animation-delay: .2s; }
.chat-typing .dot:nth-child(3) { animation-delay: .4s; }
@keyframes chatdot { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-4px); } }
.chat-bar { display: flex; gap: 8px; position: sticky; bottom: 8px; }
.chat-next { flex: 1; font-size: 1.1rem; padding: 14px; }
.chat-key { font-size: .7rem; opacity: .7; border: 1px solid currentColor; border-radius: 4px; padding: 0 5px; margin-left: 6px; }
@media (hover: none) { .chat-key { display: none; } }
.chat-end { padding: 8px 0; }

/* Story word popup: a small speech bubble above the tapped word */
.word-pop { position: fixed; z-index: 1000; width: max-content; max-width: min(300px, calc(100vw - 16px)); background: #1f2133; color: #fff; border-radius: 16px; padding: 8px 10px; box-shadow: 0 6px 24px rgba(0,0,0,.35); border: 1px solid rgba(255,255,255,.12); }
.word-pop-main { display: flex; align-items: center; gap: 10px; }
.word-pop-word { font-weight: 700; font-size: 1.05rem; }
.word-pop-read { font-weight: 400; font-size: .8rem; opacity: .7; }
.word-pop-en { font-size: .85rem; opacity: .85; }
.word-pop-icons { display: flex; gap: 4px; margin-left: 4px; }
.word-pop-btn { width: 36px; height: 36px; border-radius: 50%; border: 0; background: rgba(255,255,255,.12); color: inherit; font-size: 1.05rem; cursor: pointer; }
.word-pop-btn.active { background: #6366f1; }
.word-pop-menu { margin-top: 8px; width: 260px; max-width: 100%; }
.word-pop-menu .playlist-menu { margin: 0; }
.word-pop-tail { position: absolute; bottom: -7px; width: 14px; height: 14px; background: #1f2133; border-right: 1px solid rgba(255,255,255,.12); border-bottom: 1px solid rgba(255,255,255,.12); transform: translateX(-50%) rotate(45deg); }
.word-pop.below .word-pop-tail { bottom: auto; top: -7px; transform: translateX(-50%) rotate(225deg); }
