/* PJ17 live interpreter — mobile-first styles.
   Base rules target phones; @media (min-width: 700px) widens for desktop.

   2026-08-01 "功能定位纠正": trimmed the translation-card/latency/detected-
   language-badge styles (no longer used — see CLAUDE.md), added styles for
   the simplified main page (language toggle, Start/Stop buttons, the big
   transcript textarea) and the standalone settings.html advanced page.

   2026-08-01 "第二轮UI精细调整" (second round of feedback): merged the
   language toggle + Start/Stop into one compact row (.controls-row), Start/
   Stop became a single circular toggle button (.toggle-btn) plus a status
   badge (.status-badge), removed the decorative ".lang-row-label" tag and
   the old .controls/.start-stop-row/.big-btn/.start-btn/.stop-btn block
   (no longer in index.html's markup), and added styles for the
   language-mismatch notice (.notice-warn) and the audio recording download
   link (.recording-link). ".brand-i18n" was dropped from index.html (to
   maximize room for the transcript textarea) but is KEPT here because
   settings.html still uses it. The settings-panel-related classes
   (.settings/.chip/.toggle-chip/.settings-hint/.experimental-hint) are
   kept because settings.html reuses them (now for two toggles).

   2026-08-27 (third round of feedback): removed the old `.status-badge`
   pill that lived inside `.controls-row` (its text length changing on
   Start/Stop caused a real layout shift — see the removal note near where
   the rule used to be); added `.header-right`/`.header-status` for the
   new fixed-position header status indicator; `.transcript-actions` now
   wraps (three buttons instead of two); `.recording-link` reworked as a
   flex container that can hold either a "saved to folder" status line or
   download links + a Share button (`.recording-status`,
   `.recording-download-link`, `.share-btn`). */

/* 2026-08-28 (sixth round of feedback): user asked for an "office use"
   look ("pj16 办公司用，风格改一下") — replaced the warm cream/coral
   "recording app" tone with a restrained corporate palette: neutral light-
   grey background, white panels, a corporate blue accent, deep teal for the
   record control, standard red/amber for error/warn, tighter 10px radius.
   Every rule reads colors through these variables; the few literal rgba()
   tints further down (notice / chip / toggle-btn states) were re-derived
   from the new accent/danger/warn hues in the same pass. */
:root {
  --bg: #eef1f5;
  --panel: #ffffff;
  --panel-2: #f3f6fa;
  --text: #1c2733;
  --text-dim: #5f6f80;
  --accent: #1d4ed8;
  --accent-2: #0f766e;
  --danger: #d92d20;
  --warn: #b45309;
  --border: #d6dde5;
  --radius: 10px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Noto Sans SC", "Noto Sans JP", sans-serif;
  -webkit-tap-highlight-color: transparent;
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* 2026-08-28 (req241): header + tabs stay pinned to the top so the tabs
   don't scroll away on a long transcript. */
.topbar {
  padding: 12px 16px 8px;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--bg);
}

.title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.topbar h1 {
  font-size: 1.1rem;
  margin: 0;
  display: flex;
  align-items: center;
  gap: 8px;
}

/* 2026-08-27: groups the header status text + settings gear together on the
   right side of the topbar, so the status sits immediately to the LEFT of
   the ⚙️ link (per the user's explicit "状态放在设置左边" request), while
   staying inside a single-line header row that never changes height —
   the whole point of moving status text here is that it can grow/shrink
   without shifting the transcript box or anything else below it. */
.header-right {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 1 auto;
  min-width: 0;
}

/* Compact "🔴 REC · ja-JP" / empty indicator — see app.js setHeaderStatus().
   Deliberately no "Stopped" text when idle (removed per user feedback: a
   redundant label next to a button whose icon already shows ▶️/⏹️). */
.header-status {
  margin: 0;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--danger);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 38vw;
}

/* 2026-08-27: Live/Settings are now two sections on the same page (see
   assets/tabs.js) instead of index.html/settings.html being separate pages
   with a gear-icon link between them (the removed .settings-btn/.brand-i18n
   rules were for that old link + settings.html's subtitle line). */
.tab-bar {
  display: flex;
  gap: 6px;
  padding: 6px 16px 0;
}

.tab-btn {
  flex: 1 1 0;
  position: relative;
  border: 1px solid var(--border);
  border-bottom: none;
  border-radius: 10px 10px 0 0;
  background: var(--panel);
  color: var(--text-dim);
  padding: 8px 10px;
  font-size: 0.88rem;
  cursor: pointer;
  touch-action: manipulation;
}

/* 2026-08-28 (req241): the active tab was too subtle ("现在看不清"). Now it
   gets the accent color, bold, a filled dot before the label, and a thick
   accent underline bar. */
.tab-btn[aria-selected="true"] {
  background: var(--panel-2);
  color: var(--accent);
  font-weight: 700;
}

.tab-btn[aria-selected="true"]::before {
  content: "\2022";
  margin-right: 5px;
  color: var(--accent);
}

.tab-btn[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: 0;
  height: 3px;
  border-radius: 3px 3px 0 0;
  background: var(--accent);
}

/* 2026-08-28 (req368): on phones the tab bar sits at the BOTTOM of the
   screen like a normal app's bottom nav. The user found top tabs on mobile
   ugly and easy to lose track of on a long transcript ("手机上面的顶部tab
   不好看，不如底部的好看，参考pj90"). Desktop keeps tabs at the top — see
   the min-width:700px block near the end of this file. */
@media (max-width: 699px) {
  .tab-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 30;
    gap: 0;
    padding: 4px 6px calc(4px + env(safe-area-inset-bottom, 0px));
    background: var(--panel);
    border-top: 1px solid var(--border);
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.07);
  }
  .tab-btn {
    border: none;
    border-radius: 8px;
    background: transparent;
    padding: 9px 4px;
    font-size: 0.8rem;
  }
  .tab-btn[aria-selected="true"] {
    background: var(--panel-2);
  }
  .tab-btn[aria-selected="true"]::before {
    content: none;
  }
  /* the accent bar goes along the TOP edge for a bottom-anchored nav */
  .tab-btn[aria-selected="true"]::after {
    top: 0;
    bottom: auto;
    border-radius: 0 0 3px 3px;
  }
}

main {
  flex: 1;
  padding: 12px 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
}

/* 2026-08-27: #tabLive/#tabHistory/#tabSettings/#tabHelp are the four tab
   panels (see assets/tabs.js) - each needs the same flex-column/gap layout
   main used to apply directly to its children back when there was only one
   tab's worth of sections in it. */
/* 2026-08-27 REAL BUG (found via Playwright checking getComputedStyle, not
   just the .hidden DOM property — that part was always correctly true/
   false, the CSS just didn't respect it): an ID selector like `#tabSettings
   { display: flex }` outranks the browser's built-in `[hidden] { display:
   none }` UA rule (ID specificity beats attribute specificity), so setting
   .hidden = true on these panels never actually hid them — all four tab
   panels rendered stacked on top of each other regardless of which tab
   button was clicked. This rule also only listed 2 of the 4 tab panels
   (History/Help were added later and never added here), which is why they
   happened to hide correctly while Live/Settings didn't. Fixed by adding an
   explicit [hidden] override below with higher specificity. */
#tabLive,
#tabHistory,
#tabSettings,
#tabHelp {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

#tabLive[hidden],
#tabHistory[hidden],
#tabSettings[hidden],
#tabHelp[hidden] {
  display: none;
}

/* --- controls row: recognition language toggle + start/stop, one line --- */

.controls-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 4px 0 2px;
}

.lang-toggle-group {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 999px;
  overflow: hidden;
}

/* req441: ⏺️ Record audio moved from Settings into the Live controls row. */
.rec-audio-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  color: var(--text-dim);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.rec-audio-toggle input { width: 16px; height: 16px; accent-color: var(--accent); }
/* req226: "🖥️ + computer audio" is desktop-Chrome/Edge only — dim it where getDisplayMedia is unavailable. */
.rec-audio-toggle.is-disabled { opacity: 0.4; cursor: not-allowed; }
.rec-audio-toggle.is-disabled input { cursor: not-allowed; }

/* req441: "⏳ Unsaved recording" holding slot below the transcript actions. */
.unsaved-rec-slot { margin-top: 8px; }
.unsaved-rec-slot p { margin: 4px 0 8px; font-size: 0.82rem; }
.unsaved-rec-slot .transcript-actions { gap: 8px; }

.lang-toggle-btn {
  border: none;
  background: var(--panel);
  color: var(--text-dim);
  padding: 10px 14px;
  font-size: 0.9rem;
  cursor: pointer;
  touch-action: manipulation;
}

.lang-toggle-btn + .lang-toggle-btn {
  border-left: 1px solid var(--border);
}

.lang-toggle-btn.active {
  background: var(--accent);
  color: #ffffff;
  font-weight: 700;
}

/* 2026-08-28 (seventh round): primary pill toggles ▶ Start <-> ⏹ Stop;
   a separate ⏸ Pause / ▶ Resume pill sits next to it, disabled until a
   session runs. min-width on the primary button keeps the row from
   resizing as its label swaps. */
.rec-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 44px;
  padding: 0 18px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--panel);
  color: var(--text);
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  touch-action: manipulation;
  transition: transform 0.1s ease, background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.rec-btn:active {
  transform: scale(0.97);
}

.rec-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.rec-btn-primary {
  min-width: 110px;
  border-color: var(--accent-2);
  color: var(--accent-2);
}

/* Primary button while a session is running = "Stop" (red). */
.rec-btn-primary.is-recording {
  border-color: var(--danger);
  color: var(--danger);
  background: rgba(217, 45, 32, 0.10);
}

.rec-btn-pause {
  min-width: 110px;
  border-color: var(--warn);
  color: var(--warn);
}

/* Pause button showing "Resume" (session is paused). */
.rec-btn-pause.is-paused {
  background: rgba(180, 83, 9, 0.10);
}

/* Old `.status-badge` pill (lived inside .controls-row, showed "⏹ Stopped"/
   "🔴 Recognizing…") was REMOVED 2026-08-27 — its text length changing on
   Start/Stop was exactly what caused the layout shift the user complained
   about ("现在开始按之后画面变了"). Replaced by `.header-status` above
   (fixed position in the topbar, doesn't affect main content layout) — see
   app.js file header notes for the full reasoning. */

/* --- settings (shared by main-page-less panel markup + settings.html) --- */

.settings {
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
}

/* An ID/class `display:flex` outranks the UA `[hidden]{display:none}` rule
   (author beats UA regardless of specificity) — same trap the tab panels
   hit. Make `hidden` actually hide a .settings section (e.g. the collapsed
   #recordingLinkSection). */
.settings[hidden] {
  display: none;
}

.settings-standalone {
  margin-bottom: 4px;
}

/* req213: Settings/Help re-org — sections that are <details> so they collapse.
   Override the .settings flex so the disclosure toggle behaves normally. */
.settings-advanced,
.help-collapsible {
  display: block;
}
/* The .settings base sets display:flex, which (with a flex child) stops the
   native <details> collapse from hiding the body. Force it closed explicitly. */
details.settings:not([open]) > :not(summary) { display: none !important; }
.settings-advanced > summary,
.help-collapsible > summary {
  cursor: pointer;
  list-style: none;
  margin: 0;
  display: flex;
  align-items: center;
  gap: 8px;
}
.settings-advanced > summary::-webkit-details-marker,
.help-collapsible > summary::-webkit-details-marker { display: none; }
.settings-advanced > summary::after,
.help-collapsible > summary::after {
  content: "▸";
  margin-left: auto;
  color: var(--text-dim);
  transition: transform 0.15s ease;
}
.settings-advanced[open] > summary::after,
.help-collapsible[open] > summary::after { transform: rotate(90deg); }
.settings-advanced-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-top: 12px;
}
.settings-sub {
  border-top: 1px solid var(--border);
  padding-top: 12px;
}
.settings-sub:first-child { border-top: none; padding-top: 0; }
.settings-sub-title {
  font-size: 0.95rem;
  font-weight: 700;
  margin: 0 0 6px;
}
.help-collapsible[open] > summary { margin-bottom: 10px; }

/* req213: "newer version available" dot next to the Settings heading */
.update-dot {
  color: #d92d20;
  font-size: 0.7em;
  vertical-align: middle;
  line-height: 1;
}
.update-dot[hidden] { display: none; }

.settings-group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

/* Folder-picker buttons on settings.html reuse .action-btn but sit in a
   .settings-group, so give them a sane width instead of stretching full
   width like the transcript-page action buttons do. */
.settings-group .action-btn {
  flex: 0 1 auto;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 7px 12px;
  font-size: 0.85rem;
  cursor: pointer;
  user-select: none;
}

.chip input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
}

.chip:has(input:checked) {
  border-color: var(--accent);
  background: rgba(29, 78, 216, 0.10);
}

.toggle-chip {
  width: 100%;
  justify-content: flex-start;
}

/* req441: a chip shown for a feature that isn't available (e.g. multi-speaker
   mode, removed until real voiceprint separation exists). */
.chip.is-disabled {
  cursor: default;
  opacity: 0.55;
  text-decoration: line-through;
}

.settings-hint {
  margin: -4px 0 2px;
  font-size: 0.72rem;
  color: var(--text-dim);
  line-height: 1.4;
}

.settings-hint a {
  color: var(--accent);
}

.settings-hint code {
  background: rgba(0,0,0,0.06);
  padding: 1px 5px;
  border-radius: 4px;
}

/* 2026-08-28 (req368): short, one-idea-per-line lists for Help + the Install
   steps — the user found the old wall-of-text paragraphs hard to read
   ("都写一行看起来费劲"). */
.settings-steps {
  margin: 2px 0 4px;
  padding-left: 1.25em;
  font-size: 0.78rem;
  color: var(--text-dim);
  line-height: 1.5;
}

.settings-steps li {
  margin: 3px 0;
}

.settings-steps a { color: var(--accent); }

.settings-steps code {
  background: rgba(0,0,0,0.06);
  padding: 1px 5px;
  border-radius: 4px;
}

/* --- History tab + Help tab environment list (2026-08-27) --- */

.tab-section-title {
  margin: 0;
  font-size: 0.95rem;
  color: var(--text);
}

.history-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.history-item {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px 10px;
  background: var(--panel-2);
  font-size: 0.85rem;
}

.history-item-name {
  font-weight: 600;
  word-break: break-all;
}

.history-item audio {
  width: 100%;
  margin-top: 6px;
}

.history-item-text {
  margin: 6px 0 0;
  white-space: pre-wrap;
  color: var(--text-dim);
  max-height: 8em;
  overflow-y: auto;
}

.history-item-text-empty {
  font-style: italic;
  opacity: 0.8;
}

/* req19: History playback transcript is an editable box styled like the Live
   one, a bit shorter (it sits inside the detail panel). Reuses
   .transcript-box for look; `textarea.` bumps specificity so these win over
   the plain .transcript-box rule that appears later in the file. */
/* req131: was 24vh — too tall. ~5 lines, still resizable if you need more.
   `.history-detail` prefix so body.tv-mode .transcript-box can't override it. */
.history-detail textarea.history-edit-box {
  height: 8em;
  min-height: 8em;
  resize: vertical;
  margin-top: 0;
}

/* Synced transcript (History playback) — one clickable row per cue, the
   row matching the audio's current time gets .is-active. 2026-08-28. */
.synced-transcript {
  margin: 6px 0 0;
  max-height: 10em;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
}

.synced-line {
  margin: 0;
  padding: 5px 8px;
  font-size: 0.85rem;
  color: var(--text-dim);
  cursor: pointer;
  border-bottom: 1px solid var(--border);
}

.synced-line:last-child {
  border-bottom: none;
}

.synced-line:hover {
  background: var(--panel-2);
}

.synced-line.is-active {
  background: rgba(29, 78, 216, 0.12);
  color: var(--text);
  font-weight: 600;
}

/* "Pick what to download" — checkbox per file + one ⬇️ Download button.
   2026-08-28 ("下载的时候，文本，和音频希望可以有 checkbox"). */
.dl-chooser {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.dl-choice {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.8rem;
  color: var(--text-dim);
  user-select: none;
}

.dl-choice input {
  width: 15px;
  height: 15px;
  accent-color: var(--accent);
}

.dl-chooser .action-btn {
  flex: 0 1 auto;
}

.history-item-actions {
  display: flex;
  gap: 8px;
  margin-top: 6px;
  flex-wrap: wrap;
}

.history-item-actions button,
.history-item-actions a {
  flex: 0 1 auto;
}

/* Delete recording — set apart from the neutral download/share buttons. */
.action-btn.danger-btn {
  border-color: rgba(217, 45, 32, 0.4);
  color: #912018;
}

/* --- History: list + detail (2026-08-28) --- */
/* 2026-08-28 (req241): a real list, not a stack of boxes. Rows share one
   outer border + hairline dividers; the selected row gets an accent left
   bar. The per-recording folder line was dropped (all rows are from the
   one chosen folder anyway). */
#historyList {
  border: 1px solid var(--border);
  border-radius: 8px;
  gap: 0;
  /* 2026-08-28 (req276): scrollable so a long list doesn't push the detail
     panel off-screen. req323: drag the bottom edge to resize. */
  height: 34vh;
  min-height: 90px;
  max-height: 75vh;
  overflow: auto;
  resize: vertical;
}

#historyList:empty {
  border: none;
}

.history-row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  padding: 8px 10px;
  border-left: 3px solid transparent;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  cursor: pointer;
  font-size: 0.83rem;
}

#historyList > .history-row:last-child {
  border-bottom: none;
}

.history-row:hover {
  background: var(--panel-2);
}

.history-row.is-selected {
  border-left-color: var(--accent);
  background: rgba(29, 78, 216, 0.08);
}

/* req501: multi-select delete */
.history-row-check {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin: 0;
  align-self: center;
  cursor: pointer;
}

.history-row.is-checked {
  background: rgba(29, 78, 216, 0.06);
}

.history-bulk-bar {
  display: flex;
  gap: 8px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}

.history-bulk-bar .action-btn {
  flex: 0 1 auto;
}

.history-row-name {
  font-weight: 600;
  word-break: break-all;
}

.history-row-tag {
  flex: 0 0 auto;
  font-size: 0.72rem;
  color: var(--text-dim);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 1px 8px;
}

.history-row-preview {
  flex: 1 1 100%;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.history-detail {
  margin-top: 10px;
  padding: 12px;
  border: 1px solid var(--accent);
  border-radius: 10px;
  background: var(--panel);
  /* req26: picking an item must NOT grow the page — fixed-ish height, scroll
     inside. (The list above is also drag-resizable.) */
  max-height: 46vh;
  overflow-y: auto;
}

.history-detail audio {
  width: 100%;
}

.history-detail-meta {
  margin: 6px 0 0;
  font-size: 0.75rem;
  color: var(--text-dim);
  word-break: break-all;
}

/* req441: restructured detail panel — scope checkboxes + section dividers. */
.history-scope-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin: 10px 0 6px;
  font-size: 0.82rem;
}
.history-scope-title { font-weight: 600; color: var(--text); margin-right: 2px; }
.history-scope-label { color: var(--text-dim); }
/* req323: 🗑️ Clear on the Live save row — red text (matches Delete's look). */
#clearBtn.danger-btn { color: #c0392b; font-weight: 600; }
.history-scope-chk {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
  user-select: none;
}
.history-scope-chk input { width: 15px; height: 15px; accent-color: var(--accent); }
.history-scope-chk input:disabled { cursor: not-allowed; }
.history-actions-divider {
  margin: 12px 0 4px;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
  border-top: 1px solid var(--border);
  padding-top: 8px;
}

/* Collapsible help text in Settings (2026-08-28) — keeps the tab compact,
   the explanations are one click away. */
.settings-help {
  margin-top: 2px;
}

.settings-help > summary {
  cursor: pointer;
  font-size: 0.76rem;
  color: var(--accent);
  list-style: none;
}

.settings-help > summary::-webkit-details-marker { display: none; }

.settings-help[open] > summary {
  margin-bottom: 4px;
}

.experimental-hint {
  color: var(--warn);
}

/* --- notices --- */

.notice {
  border-radius: var(--radius);
  padding: 12px 14px;
  font-size: 0.85rem;
  line-height: 1.45;
}

.notice-error {
  background: rgba(217, 45, 32, 0.08);
  border: 1px solid rgba(217, 45, 32, 0.30);
  color: #912018;
}

.notice-warn {
  background: rgba(180, 83, 9, 0.10);
  border: 1px solid rgba(180, 83, 9, 0.35);
  color: #7c4a11;
}

.notice p {
  margin: 6px 0 0;
  color: var(--text-dim);
}

.notice code {
  background: rgba(0,0,0,0.06);
  padding: 1px 5px;
  border-radius: 4px;
}

/* --- transcript box --- */

.transcript-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: none; /* req10: the box inside has a fixed height now */
}

/* req10: FIXED height, not grow-with-content. A long transcript scrolls
   inside the box (it's a <textarea>, so it scrolls natively) — the page
   layout below (translation panel, buttons) never moves. */
.transcript-box {
  width: 100%;
  height: 34vh;
  flex: none;
  resize: none;
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-size: 1rem;
  line-height: 1.5;
  padding: 12px 14px;
  font-family: inherit;
  /* Native text selection (for copy / translate) must keep working — no
     user-select overrides here. See app.js header notes: Copy All was
     removed in favor of this native selection + the Translate button. */
}

/* req307 item15d: always reserve the vertical scrollbar's gutter. Without
   this the box has no scrollbar until the transcript grows past one
   screenful, then the scrollbar pops in, steals ~15px of width and reflows
   every line (and rebuilds the furigana ruby) — that reflow is the "flickers
   in one spot once the scrollbar appears / flashes twice while scrolling" the
   user reported. Reserving the gutter up front means the width never changes.
   Applies in every layout and mode (incl. the web skin and captions). */
.transcript-box,
.furigana-view {
  scrollbar-gutter: stable;
}

/* Read-only while recording (the recognizer owns it); normal editable
   textarea when stopped. 2026-08-28 (req241). */
.transcript-box[readonly] {
  background: var(--panel-2);
  cursor: default;
}

.transcript-edit-hint {
  margin: 0;
  font-size: 0.72rem;
  color: var(--text-dim);
}

/* req96: shown briefly after a fresh Start auto-clears the previous session's
   transcript, so the clear is never silent/irreversible. */
.transcript-undo-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 0.35rem 0 0;
  padding: 0.4rem 0.6rem;
  font-size: 0.78rem;
  border-radius: 8px;
  background: var(--notice-warn-bg, rgba(180, 130, 20, 0.14));
  color: var(--text, inherit);
}
.transcript-undo-bar[hidden] { display: none; }
.transcript-undo-bar button { padding: 0.2rem 0.6rem; font-size: 0.78rem; }

.transcript-box::placeholder {
  color: var(--text-dim);
}

.transcript-box:focus {
  outline: none;
  border-color: var(--accent);
}

/* req160 (item 4): hard ceiling that applies at EVERY screen width, not only
   inside a media query, and independent of the flex context above. The
   transcript / furigana box can never grow with content forever — past this
   height it scrolls inside itself. Belt-and-suspenders over the media-query
   caps (which are stricter and win where they apply). Captions immersive
   mode keeps its own full-height rules and is excluded. */
body:not(.captions-mode) .transcript-box,
body:not(.captions-mode) .furigana-view {
  max-height: 78vh;
  overflow-y: auto;
}

/* --- req303 (option B): resizable split between transcript & translation --- */
.live-split {
  --split: 0.62;
  display: flex;
  flex-direction: column;
  height: 62vh;
  min-height: 0;
}
body.tv-mode .live-split { height: 78vh; }

/* transcript pane inside the split: takes --split of the height, its
   textarea grows to fill, the hint/undo/actions stay their natural size.
   These selectors (3 classes) beat the earlier body.tv-mode / @media rules
   that set .transcript-box { height: NNvh }. */
.live-split > .transcript-section {
  flex: var(--split) 1 0;
  min-height: 64px;
  overflow: hidden;
}
.live-split > .transcript-section .transcript-box {
  flex: 1 1 auto;
  height: auto;
  min-height: 40px;
}
.live-split > .transcript-section .transcript-edit-hint,
.live-split > .transcript-section .transcript-undo-bar,
.live-split > .transcript-section .transcript-actions {
  flex: none;
}

/* req323: the drag bar between the transcript and the translation panel —
   full column width (matches the text boxes), drawn as TWO thin lines. */
.live-resizer {
  flex: none;
  height: 22px;
  display: flex;
  align-items: center;
  cursor: row-resize;
  touch-action: none;
}
.live-resizer > span {
  display: block;
  width: 100%;
  height: 7px;                 /* gap between the two lines */
  box-sizing: border-box;
  border-top: 2px solid var(--text-dim);
  border-bottom: 2px solid var(--text-dim);
}
.live-resizer:hover > span,
.live-resizer:active > span { border-color: var(--accent); }

/* translation pane inside the split: takes the rest of the height, its
   list scrolls internally. */
.live-split > .translate-panel {
  flex: calc(1 - var(--split)) 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.live-split > .translate-panel .translate-panel-head { flex: none; }
.live-split > .translate-panel .translate-list {
  flex: 1 1 auto;
  min-height: 0;
  height: auto;
  overflow-y: auto;
}

/* live translation OFF -> the translate pane shrinks to just its ON/OFF row,
   transcript takes the rest, no drag bar. */
.live-split.tx-off > .transcript-section { flex: 1 1 auto; }
.live-split.tx-off > .translate-panel { flex: none; padding: 6px 10px; }
.live-split.tx-off > .live-resizer { display: none; }
/* req83: .translate-list has `display:flex` which beats the UA [hidden] rule,
   so hiding it left an empty 13vh gap and the transcript never grew. */
.translate-list[hidden] { display: none !important; }
/* req83: when translation is off, the header is just the ON/OFF switch —
   drop the target-language / provider pickers so it really is minimal. */
.live-split.tx-off > .translate-panel .translate-target { display: none; }

@media (max-width: 699px) {
  /* req42 (items 1e / 11): on a phone the fixed-vh split made the transcript
     box "特别高" on tall screens and pushed the Live-translation ON/OFF row
     (and Save/Clear) below the fold — the user had to scroll to reach them.
     Let the split flow and the page scroll instead, same as the web skin
     already does. Desktop (≥700px) is untouched. Captions-mode keeps its own
     full-height rule (higher specificity). */
  body:not(.captions-mode) .live-split,
  body.tv-mode:not(.captions-mode) .live-split { height: auto; }
  body:not(.captions-mode) .live-split > .transcript-section { overflow: visible; flex: 0 0 auto; }
  /* req69 (item 6): the earlier `.transcript-section .transcript-box { height:auto }`
     rule turns the furigana VIEW (a <div>, not a textarea) into something that
     grows with content forever — "textbox 自动变长，没有滚动条".
     req221 (item2): min-height/max-height was still a RANGE (42–58vh), so on
     the PC skin on a phone the box grew when captions arrived — "开始的高度挺好
     的，字幕之后 textbox 变高了" (web AND pc). Fix: ONE fixed height, scrolls
     inside, layout below never shifts. */
  body:not(.captions-mode) .live-split > .transcript-section .transcript-box,
  body:not(.captions-mode) .live-split > .transcript-section .furigana-view {
    height: 46vh;
    min-height: 0;
    max-height: none;
    overflow-y: auto;
  }
  body:not(.captions-mode) .live-split.tx-off > .transcript-section .transcript-box,
  body:not(.captions-mode) .live-split.tx-off > .transcript-section .furigana-view {
    height: 56vh;
  }
  /* req[1] (/loop 155-195): while the ⋯ More panel is open it adds a stacked
     row above and pushes the 💾 Save row off-screen. Shrink the (already
     fixed-height, internally-scrolling) transcript box by ~12vh so the whole
     live view — box + translate row + Save/Clear — fits one screen. Collapsing
     More removes `.more-open` and the box returns to its normal height. */
  body:not(.captions-mode).more-open .live-split > .transcript-section .transcript-box,
  body:not(.captions-mode).more-open .live-split > .transcript-section .furigana-view {
    height: 34vh;
  }
  body:not(.captions-mode).more-open .live-split.tx-off > .transcript-section .transcript-box,
  body:not(.captions-mode).more-open .live-split.tx-off > .transcript-section .furigana-view {
    height: 44vh;
  }
  body:not(.captions-mode) .live-split > .live-resizer { display: none; }
  body:not(.captions-mode) .live-split > .translate-panel { flex: 0 0 auto; }
  body:not(.captions-mode) .live-split.tx-off > .translate-panel { padding: 4px 0 0; }
}

/* ===== req69: immersive "captions view" for phones ========================= */
/* A button that only shows on phones; opens a full-screen view with just the
   transcript (top) + translation (bottom), everything else hidden. Best in
   landscape. Desktop is untouched. */
.captions-mode-btn { display: none; }
@media (max-width: 699px) {
  .captions-mode-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex: 0 0 auto;
    height: 34px;
    padding: 0 12px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--panel-2);
    color: var(--text);
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    touch-action: manipulation;
  }
}

.captions-float-btn { display: none; }
.captions-float-col { display: none; }

body.captions-mode { overflow: hidden; }
body.captions-mode .topbar,
body.captions-mode .tab-bar,
body.captions-mode .controls-row,
body.captions-mode #moreControls,
body.captions-mode .transcript-actions,
body.captions-mode .notice,
body.captions-mode #transcriptUndoBar,
body.captions-mode #tabHistory,
body.captions-mode #tabSettings,
body.captions-mode #tabHelp { display: none !important; }

body.captions-mode main { padding: 0 !important; gap: 0 !important; max-width: none !important; }
body.captions-mode #tabLive {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  height: 100dvh; /* match the VISIBLE area, not the layout viewport (mobile URL bar) */
  z-index: 60;
  background: var(--bg);
  display: block;
}
body.captions-mode .live-split {
  height: 100vh;
  height: 100dvh;
  --split: 0.6;
}
body.captions-mode .transcript-box,
body.captions-mode .furigana-view,
body.captions-mode .translate-list { font-size: 1.15rem; line-height: 1.5; }
/* req171: float buttons now live in a left-edge column — clear the LEFT side
   of the text instead of the top. */
body.captions-mode .transcript-box,
body.captions-mode .furigana-view,
body.captions-mode .translate-list { padding-left: 62px; }
/* keep the drag bar usable so the top/bottom ratio is still adjustable */
body.captions-mode .live-resizer > span { border-color: var(--accent); }

/* req171: user asked to "just put them all on the left" — on iPhone the
   scattered top-right / bottom-right buttons kept landing behind the notch /
   off-screen in both orientations. One vertical stack pinned to the LEFT edge,
   vertically centred, is always reachable and never near a system gesture zone
   or the notch. absolute inside #tabLive so it rides the cap-force-landscape
   rotation too. */
body.captions-mode .captions-float-col {
  display: flex;
  flex-direction: column;
  gap: 10px;
  position: absolute;
  z-index: 70;
  left: calc(8px + env(safe-area-inset-left, 0px));
  top: 50%;
  transform: translateY(-50%);
}
body.captions-mode .captions-float-btn {
  display: flex;
  width: 46px;
  height: 46px;
  align-items: center;
  justify-content: center;
  border: 1.5px solid rgba(255, 255, 255, 0.9);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.66);
  color: #fff;
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
}
body.captions-mode .captions-cc-toggle.is-recording { background: rgba(217, 45, 32, 0.92); }
/* req291 item6: 💬 translation on/off, reachable from the captions view.
   Filled accent = ON, hollow (default float style) = OFF. */
body.captions-mode .captions-translate.is-on {
  background: rgba(74, 144, 217, 0.94);
  border-color: #fff;
}

/* req73: CSS fallback for browsers with no Screen Orientation lock (iOS Safari)
   — rotate the whole captions view 90° so it fills a portrait screen sideways. */
body.captions-mode.cap-force-landscape #tabLive {
  position: fixed;
  top: 0;
  left: 100vw;
  transform: rotate(90deg);
  transform-origin: 0 0;
  width: 100vh;
  height: 100vw;
}
/* req314: when the view is CSS-rotated, the split's usable height is the
   viewport WIDTH. Without this the transcript box overflows the visible strip
   and new lines / the auto-scroll target land off-screen in landscape. JS
   (syncCaptionsHeight) also pins this in px; this is the CSS-only fallback. */
body.captions-mode.cap-force-landscape .live-split {
  height: 100vw;
}
body.captions-mode .transcript-box,
body.captions-mode .furigana-view { overflow-y: auto; }

/* landscape = the intended orientation: transcript a bit taller than translation */
@media (orientation: landscape) {
  body.captions-mode .live-split { --split: 0.55; }
}
@media (orientation: portrait) {
  body.captions-mode .live-split { --split: 0.62; }
}

/* settings-tab live sample for the current display mode */
.disp-preview {
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  background: var(--panel-2);
  color: var(--text);
  padding: 10px 12px;
  line-height: 1.5;
  margin-bottom: 10px;
  overflow: auto;
  white-space: nowrap;
  max-height: 40vh; /* big presets (L2 = 90px) stay contained + scrollable */
}

.transcript-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

/* req253 A3/A5: keep Save-box + Translate + Clear on one row where possible;
   🗑️ Clear pinned to the far right. */
.transcript-actions .save-box { padding: 6px 8px; gap: 8px; }
.transcript-actions .action-btn { padding: 7px 10px; }
.transcript-actions-end { margin-left: auto; }

/* req107: the 💾 Save button lives in a small bordered box with its
   📝 Text / 🔊 Audio checkboxes. */
.save-box {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel-2);
}
.save-box-chk {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.82rem;
  cursor: pointer;
  user-select: none;
}
.save-box-chk input { width: 15px; height: 15px; accent-color: var(--accent); }
.save-box-chk input:disabled { cursor: not-allowed; opacity: 0.5; }
.save-box .action-btn { flex: 0 0 auto; }
/* req541: explains why 🔊 Audio is greyed out */
.save-audio-hint {
  flex-basis: 100%;
  font-size: 0.78rem;
  line-height: 1.4;
  color: var(--muted, #667);
  margin-top: 2px;
}
.save-audio-hint b { color: var(--text, inherit); }

/* req107 + req131: the global History action bar at the top of the tab —
   "Applies to" switch + ⬇️ Download / 📤 Share (they act on the ticked rows,
   or the open recording). */
#historyScopeGlobal {
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel-2);
}
#historyScopeGlobal .action-btn { flex: 0 0 auto; padding: 6px 12px; font-size: 0.82rem; }

/* req131: labelled, bordered blocks inside the History detail panel
   ("Transcript" and "Save a copy"). The label sits ABOVE the frame. */
.history-block { margin: 12px 0 0; }
/* req323: block labels are now INLINE (first item in the controls row). */
.history-block-inlabel {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-dim);
  letter-spacing: 0.02em;
  flex: 0 0 auto;
  align-self: center;
  margin-right: 2px;
}
.history-block-label {   /* legacy — kept in case a cached page still uses it */
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-dim);
  margin-bottom: 4px;
}
.history-block-body {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px;
  background: var(--panel);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.history-block-body .history-follow,
.history-block-body textarea.history-edit-box { margin-top: 0; }

.action-btn {
  flex: 1 1 30%;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.88rem;
  cursor: pointer;
  touch-action: manipulation;
}

.action-btn:active {
  transform: scale(0.98);
}

.action-btn.is-active {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}

/* req122: an .action-btn (esp. 💾 Save) must LOOK disabled, not just be
   inert — user reported "外观save没有变化" while recording / after a save. */
.action-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.action-btn:disabled:active { transform: none; }

/* req441: "Full-width" now actually uses the screen — only a small gutter is
   left (was capped at 1600px, which left big empty margins on wide monitors:
   "full-width 好像还是有很大边框，两边空白很多"). Toggled on <body> from Settings. */
body.tv-mode main {
  max-width: none;
  padding-left: clamp(16px, 3vw, 40px);
  padding-right: clamp(16px, 3vw, 40px);
}
body.tv-mode .transcript-box { height: 56vh; }
@media (max-width: 699px) {
  body.tv-mode .transcript-box { height: 44vh; }
}

/* req 2026-09-01: width presets between "Normal" and "Full width". */
body.tv-midwidth main { max-width: 1100px; }
/* "Custom" — a user-set max content width (px). */
body.tv-custom-width main {
  max-width: var(--custom-main-width, 1100px);
}

/* req 2026-09-01: Settings — paired controls share one row. */
.settings-row-pair {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  align-items: center;
}
.settings-row-pair > .settings-group { margin: 0; flex: 1 1 auto; }

/* req38 / req61: compact Display section — tighter vertical rhythm, Reset
   button up on the heading row, no preview box. */
.disp-head-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.disp-head-row .action-btn { flex: 0 0 auto; padding: 5px 12px; font-size: 0.82rem; }
.settings-compact .settings-row-pair { margin-bottom: 4px; }
.settings-compact .settings-field label { min-width: 3.8rem; font-size: 0.85rem; }
.settings-compact .settings-field select,
.settings-compact .settings-field input[type="number"] {
  padding: 4px 6px;
  font-size: 0.85rem;
}
.settings-compact .settings-field input[type="number"] { width: 5.5rem; }
.settings-compact input[type="number"]:disabled {
  opacity: 0.55;
  background: var(--panel-2);
  cursor: not-allowed;
}

/* "TV mode" — a big, roomy reading look, independent of the width switch
   above. Purely a visual layer: removing the body class puts everything
   straight back. 2026-09-01 (req "还是以前的好，白色背景黑色字" / "文字左对齐"):
   dropped the dark background + white text + centered alignment — this now
   only opens up the line spacing/tracking so it stays a plain white panel
   with black, left-aligned text like the rest of the app. */
body.tv-reading .transcript-box,
body.tv-reading .translate-list {
  line-height: 1.85;
  letter-spacing: 0.01em;
  text-align: left;
}

/* req122: History "follow along while it plays" view. Reuses .transcript-box
   for the frame; one line per cue, current line highlighted + auto-centred. */
/* req84 (2026-09-01): History text uses a fixed, comfortable reading size —
   NOT the Settings → Display size (that's only for the Live captions). */
.history-follow,
textarea.history-edit-box { font-size: 1rem; line-height: 1.55; }
/* req131: cap the read-along view at ~5 lines like the edit box; scroll inside.
   `.history-detail` prefix so it beats the .transcript-box height media rules. */
.history-detail .history-follow {
  white-space: pre-wrap;
  height: 8em;
  min-height: 4em;
  overflow: auto;
  resize: vertical;              /* req323: adjustable height */
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 8px;
}
.history-follow[hidden] { display: none; }
.history-follow-line {
  padding: 2px 6px;
  border-radius: 4px;
  transition: background-color 0.15s ease;
}
.history-follow-line.is-current {
  background: var(--accent);
  color: #fff;
}
/* req38: History detail — scope + Download/Share row pinned to the very top,
   above the audio player. */
.history-topbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  padding-bottom: 8px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--border);
}

/* req 2026-09-01: read-along view for recordings that have no per-line timings
   — same frame, just no highlight sync. */
.history-follow-note {
  font-size: 0.75rem;
  color: var(--text-dim);
  padding: 2px 6px 8px;
  border-bottom: 1px dashed var(--border);
  margin-bottom: 6px;
}

/* req 2026-09-01: History "Save a copy" block under the transcript —
   Audio/Text radio + editable name field + button, wraps on narrow screens. */
.history-saveas {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 4px;
}
.history-saveas-name {
  flex: 1 1 12rem;
  min-width: 8rem;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
  color: var(--text);
  font: inherit;
  font-size: 0.85rem;
}

/* req122: Settings tab — label + <select> on one row. */
.settings-field {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.settings-field label {
  font-size: 0.9rem;
  color: var(--text);
  min-width: 8.5rem;
}
.settings-field select {
  padding: 6px 8px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.9rem;
}

/* --- live translation panel (req388 item 4) --- */

.translate-panel {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-2);
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.translate-panel-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.8rem;
  flex-wrap: wrap;
}

/* req501: ON/OFF switch that lives in the panel header (replaces both the
   actions-row button and the ✖ close button). */
.translate-switch {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--panel);
  color: var(--text-dim);
  padding: 5px 10px;
  font: inherit;
  font-size: 0.78rem;
  cursor: pointer;
  touch-action: manipulation;
}

.translate-switch .translate-switch-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--text-dim);
  flex: none;
}

.translate-switch .translate-switch-state {
  font-weight: 700;
  letter-spacing: 0.03em;
}

.translate-switch.is-on {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--panel-2);
}

.translate-switch.is-on .translate-switch-dot { background: var(--accent); }

/* req213: the on/off control now sits on the Save row and should read as a
   plain button like the ones next to it (not a rounded switch pill). */
.translate-toggle-btn {
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 0.88rem;
  color: var(--text);
  background: var(--panel-2);
}
.translate-toggle-btn.is-on {
  border-color: var(--accent);
  color: var(--accent);
}
.translate-toggle-btn .translate-switch-state { font-weight: 700; opacity: 0.7; }
.transcript-actions .translate-toggle-btn { flex: 1 1 30%; }

/* req213: with the toggle moved out of the panel header, the whole translate
   panel just disappears when translation is OFF (its only remaining contents
   are the target/provider selects + the results list, all meaningless off). */
.live-split.tx-off > .translate-panel { display: none; }
/* ...and in the immersive captions view the transcript then takes the full
   height instead of leaving a dead band where the translation used to be. */
body.captions-mode .live-split.tx-off > .transcript-section { flex: 1 1 auto; }
body.captions-mode .live-split.tx-off > .live-resizer { display: none; }

.translate-target {
  margin-left: auto;
  font-size: 0.78rem;
  color: var(--text-dim);
}

.translate-target select {
  font: inherit;
  font-size: 0.78rem;
  padding: 2px 4px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
}

/* req10: fixed height, scrolls inside — same idea as the transcript box. */
.translate-list {
  height: 13vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: none;
  /* Base size for the panel. app.js (applyDisplaySettings) overrides this
     inline from the current display mode's fontScale; the rows below are
     sized in `em` so that override actually cascades to them. Previously
     the rows had fixed `rem` sizes that ignored the panel setting entirely
     (req303 follow-up: "字号不影响翻译面板，手机和PC都没变"). Matches the
     transcript box's 1rem base so the two panels read at the same size. */
  font-size: 1rem;
}

.translate-row {
  display: flex;
  flex-direction: column;
  gap: 1px;
  border-left: 2px solid var(--border);
  padding-left: 8px;
  font-size: 1em;
  line-height: 1.4;
}

.translate-row-src {
  color: var(--text-dim);
  font-size: 0.9em;
}

/* 2026-09-01 (req "翻译文字用深蓝色能和原文区别吗"): the translated line is
   deep blue so it's clearly distinct from the grey source line above it. */
.translate-row-tgt { color: #1e40af; font-weight: 500; }
.translate-row-tgt.is-error { color: var(--danger); }

/* req107: furigana (振り仮名) — hiragana readings above kanji in Japanese
   translations. Extra top spacing so the <rt> ruby text isn't clipped. */
.translate-row-tgt.has-furigana { line-height: 2.1; }
.translate-row-tgt ruby rt {
  font-size: 0.6em;
  font-weight: 400;
  color: #3b5bbf;
  user-select: none;
}

/* req217: standalone furigana view of the Japanese TRANSCRIPT — independent of
   the translation panel. Read-only <div> shown under the transcript textarea
   when the あ Furigana checkbox is on and the recognition language is Japanese. */
.furigana-view {
  white-space: pre-wrap;
  line-height: 2.2;
  cursor: default;
  background: var(--panel-2);
}
.furigana-view[hidden] { display: none; }
.furigana-view ruby rt {
  font-size: 0.6em;
  font-weight: 400;
  color: #3b5bbf;
  user-select: none;
}
.furigana-chk {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.82rem;
  color: var(--text-dim);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.furigana-chk input { width: 16px; height: 16px; accent-color: var(--accent); }
/* req343: furigana disabled for non-Japanese recognition languages */
.furigana-chk.is-disabled { opacity: 0.4; cursor: not-allowed; }
.furigana-chk.is-disabled input { cursor: not-allowed; }
.translate-switch.is-disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }

.translate-note {
  margin: 0;
  font-size: 0.68rem;
  color: var(--text-dim);
  line-height: 1.35;
}

/* Holds the result of a finished recording: either "saved to folder" text,
   or (fallback, browsers without folder support) download links for the
   audio + paired transcript, plus an optional Share button. Flex+wrap so it
   lays out reasonably whether it's one line of text or several buttons. */
.recording-link {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.recording-status {
  margin: 0;
  font-size: 0.85rem;
  color: var(--accent-2);
}

.recording-download-link {
  display: inline-block;
  padding: 8px 14px;
  border-radius: 10px;
  background: var(--panel-2);
  border: 1px solid var(--accent);
  color: var(--accent);
  text-decoration: none;
  font-size: 0.85rem;
}

.share-btn {
  flex: 0 1 auto;
}

.footer {
  padding: 14px 16px 22px;
  text-align: center;
  font-size: 0.72rem;
  color: var(--text-dim);
}

.footer a { color: var(--accent); }

/* --- wider screens --- */

@media (min-width: 700px) {
  main { padding: 20px 24px; gap: 14px; }
  .topbar { padding: 18px 24px 12px; }
  .topbar h1 { font-size: 1.3rem; }
  .transcript-box { height: 40vh; }
}

/* 2026-08-28 (req368): phones only — leave room under the fixed bottom tab
   bar. Kept here, AFTER the base `main`/`.transcript-box` rules, so the
   shorthand `padding` on `main` above doesn't reset this padding-bottom. */
@media (max-width: 699px) {
  main { padding-bottom: 80px; }
  .transcript-box { height: 30vh; }
  .translate-list { height: 12vh; }
  /* req83: the small print under the translation list adds clutter on phones. */
  .translate-note { display: none !important; }
}

/* ============================================================
   req376 P426 — Live 页一屏化（index.html PC 版）
   目标：Live tab 永远一屏、不用上下滚动找按钮；transcript 框
   随窗口高度自适应；按钮行放不下就自动换成两排。
   其它 tab（History/Settings/Help 很长）不受影响，正常滚动。
   ============================================================ */
body.tab-live { height: 100dvh; overflow: hidden; }
body.tab-live main { min-height: 0; overflow: hidden; }
body.tab-live #tabLive { flex: 1 1 auto; min-height: 0; overflow: hidden; }

/* 顶部识别语言 / 录音 / Start-Pause 行：放不下就自动换到第二排 */
body.tab-live .controls-row { flex-wrap: wrap; row-gap: 8px; padding: 2px 0; }

/* transcript ↔ translation 分栏：不再用固定 62vh，改成撑满剩余高度。
   ID(#tabLive) + 子选择器，压过 `.live-split{height:62vh}` 和
   `body.tv-mode .live-split{height:78vh}`。captions-mode 不受影响。 */
body.tab-live:not(.captions-mode) #tabLive > .live-split {
  height: auto;
  flex: 1 1 auto;
  min-height: 0;
}

/* transcript 框自适应：跟着分栏高度长/缩，最少留 3 行可见 */
body.tab-live:not(.captions-mode) #tabLive > .live-split > .transcript-section .transcript-box,
body.tab-live:not(.captions-mode) #tabLive > .live-split > .transcript-section .furigana-view {
  flex: 1 1 auto;
  height: auto;
  min-height: 3.2em;
}

/* req[1] (/loop 155-195): while ⋯ More is open, cap the transcript box shorter
   so the ⋯ More rows + 💾 Save/Clear row are guaranteed on screen even on a
   short phone (where the flex slack alone might not be enough, and the mobile
   URL-bar makes 100dvh jump). The box is still fixed-ceiling + scrolls inside;
   closing More lifts the cap and the box fills the space again. */
body.tab-live.more-open:not(.captions-mode) #tabLive > .live-split > .transcript-section .transcript-box,
body.tab-live.more-open:not(.captions-mode) #tabLive > .live-split > .transcript-section .furigana-view {
  max-height: 42vh;
}

/* Save / Translate / 🗑️Clear 行：窄了就换两排，Clear 仍靠最右 */
body.tab-live .transcript-actions { flex-wrap: wrap; row-gap: 8px; }
body.tab-live .transcript-actions .transcript-actions-end { margin-left: auto; }

/* ⋯ More 面板（index.html 也用上 web.html 的那套） */
.more-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  margin: 4px 0 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-2, var(--panel));
}
.more-controls[hidden] { display: none; }
#moreControlsBtn.is-active { background: var(--accent); color: #fff; }
