/* ============================================================================
 *  styles.css
 * ============================================================================
 *  Full-height responsive shell with a fixed header, a tab bar, and internal
 *  scrolling panes. No page-level scroll. Mobile-first layout.
 * ========================================================================== */

:root {
  --bg: #FFFFFF;
  --bg-soft: #F8F9FA;
  --panel: #FFFFFF;
  --panel-soft: #F8F9FA;
  --border: #DADCE0;
  --border-soft: #E8EAED;
  --border-hair: #F1F3F4;

  --text: #202124;
  --text-soft: #3C4043;
  --text-muted: #5F6368;
  --text-subtle: #80868B;

  --accent: #1A73E8;
  --accent-hover: #1558B7;
  --accent-weak: #E8F0FE;

  --danger: #D93025;
  --success: #1E8E3E;
  --warning: #F29900;

  --shadow-xs: 0 1px 2px rgba(60, 64, 67, 0.05);
  --shadow-sm: 0 1px 2px rgba(60, 64, 67, 0.08), 0 1px 3px rgba(60, 64, 67, 0.04);
  --shadow-md: 0 2px 6px rgba(60, 64, 67, 0.10), 0 1px 2px rgba(60, 64, 67, 0.06);
  --shadow-lg: 0 6px 20px rgba(60, 64, 67, 0.14), 0 2px 6px rgba(60, 64, 67, 0.08);

  --radius-sm: 4px;
  --radius: 6px;
  --radius-lg: 8px;

  --header-h: 56px;
  --tabs-h: 44px;
}

html, body {
  height: 100%;
  background: var(--bg-soft);
  color: var(--text);
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  margin: 0;
  overflow: hidden;
}

* { box-sizing: border-box; }

/* ──────────────────────────────────────────────────────────────────────
   Shell — header + tabs + workspace, no page scroll.
   Flex column so the workspace reliably fills remaining height on every
   browser, independent of how 100dvh is computed.
─────────────────────────────────────────────────────────────────────── */

.app-shell {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

.app-header { flex: none; height: var(--header-h); }
.tab-bar { flex: none; height: var(--tabs-h); }

/* ──────────────────────────────────────────────────────────────────────
   Header
─────────────────────────────────────────────────────────────────────── */

.app-header {
  background: var(--bg);
  border-bottom: 1px solid var(--border-soft);
  z-index: 30;
}

.header-inner {
  height: 100%;
  max-width: 1600px;
  margin: 0 auto;
  /* 26px = workspace gutter (12) + pane border (1) + pane-header pad (14)
     less the 1px hairline. Aligns the brand-mark, the first tab, and the
     pane title onto one vertical column on both edges. */
  padding: 0 26px;
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.header-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  flex: 0 1 auto;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
}

.brand-mark {
  width: 30px;
  height: 30px;
  border-radius: 7px;
  background: var(--text);
  color: #FFFFFF;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  flex: none;
  letter-spacing: -0.02em;
}

.brand-text {
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.brand-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.brand-sub {
  font-size: 11.5px;
  color: var(--text-muted);
  margin-top: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ──────────────────────────────────────────────────────────────────────
   Tab bar
─────────────────────────────────────────────────────────────────────── */

.tab-bar {
  display: flex;
  align-items: center;
  gap: 2px;
  /* Match the app-header so the chrome shares one alignment column. */
  padding: 0 26px;
  background: var(--bg);
  border-bottom: 1px solid var(--border-soft);
  overflow-x: auto;
  scrollbar-width: none;
}
.tab-bar::-webkit-scrollbar { display: none; }

.tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 100%;
  padding: 0 12px;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}

.tab:hover { color: var(--text); }

.tab[aria-selected="true"] {
  color: var(--text);
  border-bottom-color: var(--text);
}

/* Hide the Split tab on small screens — only desktop can hold both */
@media (max-width: 1023px) {
  .tab[data-tab="split"] { display: none; }
}

.tab-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  /* Inherits the tab-bar's 26px right padding — no extra inset here
     or the indicator drifts off the alignment column. */
  padding: 0;
  font-size: 11.5px;
  color: var(--text-muted);
  white-space: nowrap;
  flex: none;
}

.theme-indicator {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--text-muted);
  white-space: nowrap;
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.theme-indicator > span:last-child {
  overflow: hidden;
  text-overflow: ellipsis;
}

.theme-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--accent);
}

/* ──────────────────────────────────────────────────────────────────────
   Workspace — three panes, with three responsive regimes.
     • Phones / tablets (< 1024px): single pane, chosen by the active tab.
     • Desktops (1024–1439px):       split = editor + preview side-by-side.
     • Wide desktops (≥ 1440px):     split = settings + editor + preview.
   The "split" tab adapts to viewport width; Editor / Preview / Settings
   tabs always render a single focused pane regardless of size.
─────────────────────────────────────────────────────────────────────── */

.workspace {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  padding: 12px;
  background: var(--bg-soft);
  display: grid;
  grid-template-columns: 1fr;
  grid-auto-rows: 1fr;
  gap: 12px;
}

/* Default: show only the active pane (mobile-first, single view). */
.workspace .pane { display: none; min-height: 0; height: 100%; }
.workspace[data-view="editor"]   .pane[data-pane="editor"]   { display: flex; }
.workspace[data-view="preview"]  .pane[data-pane="preview"]  { display: flex; }
.workspace[data-view="settings"] .pane[data-pane="settings"] { display: flex; }

/* Desktop split view — editor and preview side-by-side. */
@media (min-width: 1024px) {
  .workspace[data-view="split"] {
    grid-template-columns: 1fr 1fr;
  }
  .workspace[data-view="split"] .pane[data-pane="editor"],
  .workspace[data-view="split"] .pane[data-pane="preview"] {
    display: flex;
  }
}

/* Wide desktop — settings, editor, and preview all visible at once.

   Column layout (left → right): settings · editor · preview.

   Settings is capped at 25% of the workspace width (with a 280px floor so
   it stays readable, and a 420px ceiling so it doesn't bloat on ultra-wide
   monitors). The remaining ~75% is split evenly between editor and
   preview via `minmax(0, 1fr)` — the `0` minimum lets the preview paper
   scale down without forcing the grid to overflow.

   The HTML source order is editor → preview → settings, so we use
   explicit `grid-column` placement to reorder them visually. We also pin
   every pane to `grid-row: 1` (and force the grid to a single row via
   `grid-template-rows`) — without this, sparse auto-placement processes
   editor + preview first, advances the cursor past row 1, then drops
   settings onto row 2 because it can't backtrack to fill row 1 col 1. */
@media (min-width: 1440px) {
  /*
    Settings column width is exposed as a CSS variable so the collapsed
    state can flip it to 36px (the rail width) without rewriting the
    whole grid declaration. Animating `grid-template-columns` works in
    all evergreen browsers; older browsers fall back to an instant snap
    which keeps the feature functional. See the prefers-reduced-motion
    block at the bottom of this file for the motion-safe override.
  */
  .workspace[data-view="split"] {
    --settings-col-width: clamp(240px, 18%, 320px);
    grid-template-columns:
      var(--settings-col-width)
      minmax(0, 1fr)
      minmax(0, 1fr);
    grid-template-rows: 1fr;
    transition: grid-template-columns 200ms cubic-bezier(0.4, 0, 0.2, 1);
  }
  .workspace[data-view="split"] .pane[data-pane="settings"] {
    display: flex;
    grid-column: 1;
    grid-row: 1;
  }
  .workspace[data-view="split"] .pane[data-pane="editor"]   { grid-column: 2; grid-row: 1; }
  .workspace[data-view="split"] .pane[data-pane="preview"]  { grid-column: 3; grid-row: 1; }

  /* Give the settings pane the same panel chrome as editor + preview when
     it sits in the split column, so the three panes visually align. We
     keep the standalone Settings view "borderless on workspace bg" — see
     the `.pane-settings` base rule further down. */
  .workspace[data-view="split"] .pane-settings {
    background: var(--panel);
    border-color: var(--border-soft);
    box-shadow: var(--shadow-xs);
  }
  .workspace[data-view="split"] .pane-settings .pane-header {
    display: flex;
  }

  /* Drop max-width centering and outer scroll padding when settings is a
     narrow column — we want the cards to fill the column edge-to-edge. */
  .workspace[data-view="split"] .pane-settings .settings-inner {
    max-width: none;
    padding: 0;
    gap: 0;
  }

  /* Flatten the inner cards into "sections" — drop their bg/border/radius
     and use a single hairline divider between consecutive sections. This
     reads as the standard settings-sidebar pattern (think Slack / Notion
     side panels) and removes the nested-box look that happens when white
     cards sit inside a white panel. */
  .workspace[data-view="split"] .pane-settings .card {
    background: transparent;
    border: none;
    border-radius: 0;
    padding: 14px 14px;
  }
  .workspace[data-view="split"] .pane-settings .card + .card {
    border-top: 1px solid var(--border-soft);
  }

  /* Metadata field row in the narrow column:

       ┌──────────┐ ┌─┐
       │  label   │ │×│
       └──────────┘ │ │
       ┌──────────┐ │ │
       │  value   │ │ │
       └──────────┘ └─┘

     Both inputs share column 1 so they have identical widths; the remove
     button spans both rows in column 2 and is vertically centered between
     them. Each grid item gets explicit row + column — without that, the
     sparse auto-placement cursor strands `.value-input` on row 3 (same
     gotcha as the workspace 3-pane fix). */
  .workspace[data-view="split"] .pane-settings .field-row {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto;
    align-items: stretch;
  }
  .workspace[data-view="split"] .pane-settings .field-row .label-input {
    grid-column: 1;
    grid-row: 1;
  }
  .workspace[data-view="split"] .pane-settings .field-row .value-input {
    grid-column: 1;
    grid-row: 2;
  }
  .workspace[data-view="split"] .pane-settings .field-row .remove-btn {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: center;
  }

  /* ──────────────────────────────────────────────────────────────────
     Collapse / expand the settings column.

     The collapse button lives in the settings pane-header and is shown
     only here (wide split). The floating rail lives inside #workspace
     and only takes its grid slot when the app-shell has the
     data-settings-collapsed="true" hook. Every selector below is scoped
     to BOTH .workspace[data-view="split"] AND this 1440px breakpoint —
     this is critical so the standalone Settings tab and narrower
     viewports never lose the settings pane to a stray rule.
  ─────────────────────────────────────────────────────────────────── */

  /* Reveal the collapse chevron only in this exact context. */
  .workspace[data-view="split"] .pane-settings .settings-collapse-btn {
    display: inline-flex;
  }

  /* Collapsed state: narrow grid (rail width), settings pane hidden,
     rail takes column 1. The transition declared on .workspace above
     animates the column width change. */
  #app-shell[data-settings-collapsed="true"] .workspace[data-view="split"] {
    --settings-col-width: 36px;
  }
  #app-shell[data-settings-collapsed="true"]
    .workspace[data-view="split"]
    .pane[data-pane="settings"] {
    display: none;
  }
  #app-shell[data-settings-collapsed="true"]
    .workspace[data-view="split"]
    .settings-rail {
    display: flex;
    grid-column: 1;
    grid-row: 1;
  }
}

/*
   Settings pane-header is hidden by default — only the wide split layout
   uses it (see the @media (min-width: 1440px) block above). In the
   standalone Settings tab, the cards float on the workspace background
   without a header strip; adding one there would render a stray bar over
   a transparent pane.
*/
.pane-settings > .pane-header { display: none; }

/* ────────────────────────────────────────────────────────────────────
   Settings collapse / show controls.

   Both controls are display:none by default and only revealed by the
   scoped wide-split rules in the @media (min-width: 1440px) block.
   This guarantees they never appear on tablets, mobile, or in the
   standalone Settings tab.
─────────────────────────────────────────────────────────────────── */

/* Collapse chevron — secondary action, intentionally low default weight
   so it doesn't compete with the pane-title or sub-text. Brightens to
   full opacity on hover/focus, matching the macOS title-bar pattern. */
.settings-collapse-btn {
  display: none;             /* opted-in by the scoped wide-split rule */
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  margin-left: 4px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm, 6px);
  background: transparent;
  color: var(--text-muted);
  opacity: 0.6;
  cursor: pointer;
  transition: opacity 120ms ease, background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
.settings-collapse-btn:hover {
  opacity: 1;
  background: var(--bg-soft);
  color: var(--text-soft);
}
.settings-collapse-btn:focus-visible {
  opacity: 1;
  outline: none;
  border-color: var(--accent, #2D7CDB);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent, #2D7CDB) 28%, transparent);
}
.settings-collapse-btn svg {
  width: 14px;
  height: 14px;
  display: block;
}

/* Rail — primary affordance for "settings is here, click to expand".
   Flattened on the right edge (only top-left + bottom-left rounded) so
   it reads as a panel-edge handle, not a free-floating card. The
   chevron is the dominant icon; the gear is a smaller contextual hint
   underneath at reduced opacity. Hover gives the rail a 1px nudge to
   suggest outward motion — a UX micro-affordance. */
.settings-rail {
  display: none;             /* opted-in by the scoped wide-split rule */
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  padding: 16px 0;
  width: 36px;
  min-width: 0;
  height: 100%;
  background: var(--panel);
  border: 1px solid var(--border-soft);
  /* Flatten the right edge — it reads as a left-side chrome strip,
     not a card detached from the workspace. */
  border-radius: var(--radius-lg) 0 0 var(--radius-lg);
  box-shadow: var(--shadow-xs);
  color: var(--text-muted);
  cursor: pointer;
  transform: translateX(0);
  transition:
    transform 160ms cubic-bezier(0.4, 0, 0.2, 1),
    background-color 140ms ease,
    color 140ms ease,
    border-color 140ms ease;
  -webkit-appearance: none;
  appearance: none;
  font: inherit;
}
.settings-rail:hover {
  background: var(--bg-soft);
  color: var(--accent, #2D7CDB);
  border-color: color-mix(in srgb, var(--accent, #2D7CDB) 35%, var(--border-soft));
  /* Micro-nudge: implies the rail is about to expand outward. */
  transform: translateX(1px);
}
.settings-rail:focus-visible {
  outline: none;
  border-color: var(--accent, #2D7CDB);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent, #2D7CDB) 28%, transparent);
  color: var(--accent, #2D7CDB);
}
.settings-rail:active {
  transform: translateX(0);
}
.settings-rail-icon {
  width: 18px;
  height: 18px;
  color: currentColor;
}
.settings-rail-gear {
  width: 13px;
  height: 13px;
  color: var(--text-muted);
  opacity: 0.7;
  transition: opacity 140ms ease, color 140ms ease;
}
.settings-rail:hover .settings-rail-gear,
.settings-rail:focus-visible .settings-rail-gear {
  color: currentColor;
  opacity: 1;
}

/* Pane chrome */
.pane {
  background: var(--panel);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  flex-direction: column;
  overflow: hidden;
  box-shadow: var(--shadow-xs);
  min-height: 0;
}

.pane-header {
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 14px;
  border-bottom: 1px solid var(--border-soft);
  background: var(--bg);
  flex: none;
}

.pane-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-soft);
  display: flex;
  align-items: center;
  gap: 8px;
}

.pane-title svg { color: var(--text-muted); width: 14px; height: 14px; }

.pane-sub {
  font-size: 11.5px;
  color: var(--text-muted);
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Inline numeric stat in the pane sub-bar (e.g. "299 words"). The number
   sits flush with its unit; consecutive stats are separated by .divider-v
   for an even visual rhythm. */
.pane-sub .stat-inline {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.pane-sub .stat-inline > :first-child {
  color: var(--text-soft);
  font-weight: 600;
}

/* "Auto-saved" status pill. Hidden until the editor has content so we
   never claim to have saved an empty draft. The check icon makes it read
   as a state, not a stat. */
.save-indicator {
  display: none;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
  color: var(--text-muted);
  font-weight: 500;
}

.save-indicator[data-state="saved"] {
  display: inline-flex;
}

.save-indicator-icon {
  width: 12px;
  height: 12px;
  color: var(--success, #15803d);
  flex: none;
}

/* When the indicator is hidden, drop the divider that follows it so we
   don't leave a dangling rule at the start of the sub-bar. */
.save-indicator:not([data-state="saved"]) + .divider-v {
  display: none;
}

/* Editor textarea */
.editor-area {
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;
  padding: 20px;
  border: 0;
  resize: none;
  background: var(--bg);
  color: var(--text);
  font-family: "JetBrains Mono", "SFMono-Regular", Consolas, Menlo, monospace;
  font-feature-settings: "liga" 0;
  tab-size: 2;
  font-size: 13px;
  line-height: 1.65;
  outline: none;
  overflow: auto;
}
.editor-area::placeholder { color: var(--text-subtle); }

/* Preview paper */
.preview-frame {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  background: #ECEEF1;
  padding: 24px 20px;
  display: flex;
  justify-content: center;
  align-items: flex-start;
}

.preview-paper-sizer {
  flex: none;
  position: relative;
}

.preview-paper {
  --page-pad-top: 72pt;
  --page-pad-right: 72pt;
  --page-pad-bottom: 72pt;
  --page-pad-left: 72pt;
  --paper-bg: #FFFFFF;
  background: var(--paper-bg);
  box-shadow: var(--shadow-md);
  border-radius: var(--radius);
  width: 210mm;
  min-height: 297mm;
  padding: var(--page-pad-top) var(--page-pad-right) var(--page-pad-bottom) var(--page-pad-left);
  box-sizing: border-box;
  transform-origin: top left;
  transition: background-color 160ms ease, padding 160ms ease;
}

/* Wide-content wrapping for the in-app preview. The renderer emits tables
   with inline `width:100%` (auto layout) and no `overflow-wrap`, so a long
   unbreakable string in a <td> (a 40-char class name, a path like
   `builder/domain/entity/Foo.java`, a base64 blob) widens the table beyond
   the 210mm A4 paper. Long URLs in <a>, long unbroken <h1>s, long inline
   <code>, and long cover eyebrows / subtitles have the same overflow risk.

   `overflow-wrap` is inherited — setting it on the preview container reaches
   every descendant, including cover-page <div>s that carry user-authored
   text but don't fit any common selector list. The rule has no effect on
   <pre> with inline `white-space:pre` (which disables wrapping), so the
   familiar code-block horizontal scrollbar is preserved in the live preview.

   We use `break-word`, NOT `anywhere`. Both values break unbreakable strings
   at the layout step, but `anywhere` *also* counts mid-word break points
   toward `min-content` — which makes auto-layout tables collapse every
   column to one character ("Turn"/"Started"/"Stages" rendering as a single
   letter per row). `break-word` keeps min-content at the longest natural
   word, so short headers keep their column width and only true offenders
   (long class names, paths, URLs) get split mid-character. Mirrors
   src/html-builder.ts so the preview and PDF wrap the same way. */
#md-preview {
  overflow-wrap: break-word;
  word-break: normal;
}
#md-preview table { max-width: 100%; }
#md-preview img { max-width: 100%; height: auto; }
#md-preview .mdc-mermaid-wrap {
  display: block;
  width: 100%;
  max-width: 100%;
  overflow-x: auto;
}
#md-preview .mdc-mermaid-svg {
  display: block;
  width: 100%;
  max-width: 100%;
}
#md-preview .mdc-mermaid-svg svg {
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
}
/* Table data cells need `overflow-wrap: anywhere` (NOT just `break-word`)
   because the auto-layout table algorithm sizes columns by `min-content`,
   and only `anywhere` reduces min-content past natural word boundaries.
   `break-word` alone is *ignored* by the table layout step (it only kicks
   in after a box width is established, which auto-layout never establishes
   — the box expands to fit content instead). The result was: a snake_case
   identifier like `assistant_builder` (underscores are NOT a Unicode
   line-break opportunity) became one unbreakable token whose full width
   forced the column wider than the paper, overflowing the preview.

   Critical scope: `td` only, NOT `th`. Headers keep the inherited
   `break-word` so their natural width still drives column sizing — short
   headers like "Module" or "Turn" don't collapse to a 1-character column,
   and data cells wrap at any character within the header-determined
   width. Prose/headings/lists are also unaffected because they inherit
   `break-word` from `#md-preview` (only true unbreakable tokens break,
   never natural words). */
#md-preview td { overflow-wrap: anywhere; }

/* Preview pane fullscreen toggle. Lives in the preview pane-header next
   to the document title. The "exit" icon is only revealed while the
   preview pane owns the fullscreen element (toggled by app.ts via
   data-fullscreen on the pane). */
.preview-fullscreen-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 5px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: color 120ms ease, background 120ms ease, border-color 120ms ease;
}

.preview-fullscreen-btn:hover {
  color: var(--text);
  background: var(--bg-soft);
  border-color: var(--border-soft);
}

.preview-fullscreen-btn:focus-visible {
  outline: 2px solid var(--focus, #3b82f6);
  outline-offset: 1px;
}

.preview-fullscreen-btn .preview-fullscreen-exit { display: none; }
.pane-preview[data-fullscreen="1"] .preview-fullscreen-btn .preview-fullscreen-enter { display: none; }
.pane-preview[data-fullscreen="1"] .preview-fullscreen-btn .preview-fullscreen-exit { display: block; }

/* When the preview pane is the fullscreen element, the browser drops the
   pane out of its grid context and stretches it to the full viewport.
   The default `display:none` rules from setView (other panes hidden via
   workspace data-view) don't apply because the pane is detached for
   layout — but we still want the preview to fill the screen and the
   paper to remain centered. */
.pane-preview:fullscreen,
.pane-preview:-webkit-full-screen {
  width: 100vw;
  height: 100vh;
  background: var(--bg);
  display: flex;
  flex-direction: column;
}

.pane-preview:fullscreen .preview-frame,
.pane-preview:-webkit-full-screen .preview-frame {
  flex: 1 1 auto;
  min-height: 0;
}

/* ──────────────────────────────────────────────────────────────────────
   Settings pane
─────────────────────────────────────────────────────────────────────── */

.pane-settings { background: var(--bg-soft); border-color: transparent; box-shadow: none; }

.settings-scroll {
  flex: 1 1 auto;
  overflow: auto;
  min-height: 0;
}

.settings-inner {
  max-width: 760px;
  margin: 0 auto;
  padding: 20px 20px 36px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* ──────────────────────────────────────────────────────────────────────
   Cards
─────────────────────────────────────────────────────────────────────── */

.card {
  background: var(--panel);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  padding: 18px;
}

.card-eyebrow {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.card-hint {
  font-size: 12px;
  color: var(--text-subtle);
  margin-top: 2px;
  line-height: 1.45;
}

/* ──────────────────────────────────────────────────────────────────────
   Theme chips
─────────────────────────────────────────────────────────────────────── */

.theme-chip-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 8px;
}

.theme-chip {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  background: var(--panel);
  cursor: pointer;
  text-align: left;
  transition: border-color 120ms ease, background 120ms ease, box-shadow 120ms ease;
  width: 100%;
  color: var(--text);
  position: relative;
}

.theme-chip:hover {
  border-color: var(--border);
  background: var(--bg-soft);
}

.theme-chip[data-active="1"] {
  border-color: var(--text);
  box-shadow: inset 0 0 0 1px var(--text);
}

.theme-chip .swatch {
  width: 40px;
  height: 40px;
  flex: none;
  border-radius: 5px;
  display: flex;
  align-items: baseline;
  justify-content: center;
  padding-top: 9px;
  font-size: 19px;
  font-weight: 700;
  border: 1px solid var(--border-soft);
  letter-spacing: -0.03em;
  line-height: 1;
}
.theme-chip .swatch > span + span { margin-left: 1px; }

.theme-chip .meta { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 3px; overflow: hidden; }
.theme-chip .title {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.theme-chip .desc {
  display: block;
  font-size: 11.5px;
  color: var(--text-muted);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.theme-chip .edit-theme {
  opacity: 0;
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 4px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: opacity 120ms ease, background 120ms ease, border-color 120ms ease;
}
.theme-chip:hover .edit-theme { opacity: 1; border-color: var(--border-soft); background: var(--bg); }
.theme-chip .edit-theme:hover { color: var(--text); }

.custom-badge {
  position: absolute;
  top: 6px;
  right: 8px;
  font-size: 9.5px;
  font-weight: 600;
  color: var(--text-muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--bg-soft);
  padding: 2px 5px;
  border-radius: 3px;
  border: 1px solid var(--border-hair);
}

/* ──────────────────────────────────────────────────────────────────────
   Dynamic metadata fields
─────────────────────────────────────────────────────────────────────── */

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

.field-row {
  display: grid;
  grid-template-columns: minmax(120px, 1fr) minmax(140px, 2fr) auto;
  gap: 8px;
  align-items: center;
}

.field-row .label-input,
.field-row .value-input {
  height: 34px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 13px;
  background: var(--bg);
  font-family: inherit;
  color: var(--text);
  width: 100%;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.field-row .label-input { font-weight: 600; color: var(--text-soft); }
.field-row .label-input:focus,
.field-row .value-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-weak);
}

.field-row .remove-btn {
  width: 32px;
  height: 32px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color 120ms ease, background 120ms ease, border-color 120ms ease;
}
.field-row .remove-btn:hover { color: var(--danger); border-color: var(--border-soft); background: var(--bg-soft); }

.fields-empty {
  text-align: center;
  padding: 20px;
  font-size: 12.5px;
  color: var(--text-muted);
  border: 1px dashed var(--border-soft);
  border-radius: var(--radius);
}

/* ──────────────────────────────────────────────────────────────────────
   Stats
─────────────────────────────────────────────────────────────────────── */

.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 8px;
}

.stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  background: var(--panel);
}
.stat .label {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  font-weight: 600;
}
.stat .value {
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
}

/* ──────────────────────────────────────────────────────────────────────
   Buttons (unchanged palette)
─────────────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 0 14px;
  border-radius: var(--radius);
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
  white-space: nowrap;
  font-family: inherit;
}
.btn:hover { background: var(--bg-soft); border-color: #BDC1C6; }
.btn:active { background: #F1F3F4; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-primary {
  background: var(--text);
  color: #FFFFFF;
  border-color: var(--text);
}
.btn-primary:hover { background: #000000; border-color: #000000; }

.btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--text-muted);
}
.btn-ghost:hover {
  background: var(--bg-soft);
  color: var(--text);
  border-color: transparent;
}

.btn-sm { height: 30px; padding: 0 10px; font-size: 12.5px; }

/* ──────────────────────────────────────────────────────────────────────
   Inputs
─────────────────────────────────────────────────────────────────────── */

.field-label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-soft);
  margin-bottom: 6px;
}

.field-input, .field-select {
  width: 100%;
  height: 34px;
  padding: 0 10px;
  border-radius: var(--radius);
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}

.field-input:focus, .field-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-weak);
}

.field-input::placeholder { color: var(--text-subtle); }

.field-display {
  min-height: 34px;
  padding: 7px 10px;
  border-radius: var(--radius);
  background: var(--bg-soft);
  border: 1px solid var(--border-hair);
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  display: flex;
  align-items: center;
}

/* Color field composite */
.color-field {
  display: grid;
  grid-template-columns: 40px 1fr;
  gap: 8px;
  align-items: stretch;
}
.color-field input[type="color"] {
  width: 40px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  cursor: pointer;
}

/* ──────────────────────────────────────────────────────────────────────
   Toggle switch
─────────────────────────────────────────────────────────────────────── */

.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 0;
  border-top: 1px solid var(--border-hair);
  font-size: 13px;
  color: var(--text);
}
.toggle-row:first-of-type { border-top: none; padding-top: 4px; }


input[type="checkbox"]:disabled + .toggle {
  opacity: 0.45;
  cursor: not-allowed;
}

.toggle {
  position: relative;
  width: 32px;
  height: 18px;
  flex: none;
  background: #DADCE0;
  border-radius: 999px;
  cursor: pointer;
  transition: background 160ms ease;
}
.toggle::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 14px; height: 14px;
  background: #FFFFFF;
  border-radius: 999px;
  transition: transform 160ms ease;
  box-shadow: 0 1px 2px rgba(0,0,0,0.18);
}
input[type="checkbox"]:checked + .toggle { background: var(--accent); }
input[type="checkbox"]:checked + .toggle::after { transform: translateX(14px); }

/* ──────────────────────────────────────────────────────────────────────
   Download menu
─────────────────────────────────────────────────────────────────────── */

.menu {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  min-width: 280px;
  max-height: calc(100dvh - 80px);
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 4px;
  box-shadow: var(--shadow-lg);
  z-index: 40;
}

.menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  border: none;
  background: transparent;
  cursor: pointer;
  text-align: left;
  color: var(--text);
  font-family: inherit;
  transition: background 120ms ease;
}
.menu-item:hover { background: var(--bg-soft); }

.menu-item .label {
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  line-height: 1.25;
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.menu-item .hint {
  font-size: 11.5px;
  color: var(--text-muted);
  display: block;
  margin-top: 1px;
  /* Keep each hint to a single line. Long copy ellipses cleanly rather
     than wrapping into two lines, which used to break the row rhythm. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The label/hint pair lives inside an unclassed <span> for the static
   rows and a `.menu-item-body` span for the audio row. Both need
   `min-width: 0` so the children's `text-overflow: ellipsis` actually
   activates inside the parent flex item (default min-width is auto,
   which inflates with the longest unbroken word). */
.menu-item > span,
.menu-item .menu-item-body { min-width: 0; }
.menu-item .badge {
  width: 36px;
  height: 28px;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-soft);
  border: 1px solid var(--border-soft);
  color: var(--text-soft);
  font-size: 10px;
  font-weight: 700;
  flex: none;
}

/* ──────────────────────────────────────────────────────────────────────
   Audiobook menu row — visually consistent with the other rows.
   The row is a wrapper around the main "generate" button plus a small
   side button that lets the user re-open the key popover. The side
   button is hidden until a key is saved (data-locked="false") so the
   locked state looks identical to DOCX/PDF/HTML/MD.
─────────────────────────────────────────────────────────────────────── */

.menu-item-audio-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: stretch;
}
.menu-item-audio-row .menu-item { width: 100%; }

.menu-item-audio .menu-item-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.menu-item-audio .hint-locked,
.menu-item-audio .hint-unlocked { display: none; }
.menu-item-audio-row[data-locked="true"]  .hint-locked   { display: block; color: var(--accent); }
.menu-item-audio-row[data-locked="false"] .hint-unlocked { display: block; }
.menu-item-audio:focus-visible { outline-offset: -2px; }

/* Side action button. Hidden by default — only meaningful once a key
   is saved, at which point the wrapper flips data-locked to "false". */
.menu-item-side {
  display: none;
  align-items: center;
  justify-content: center;
  width: 32px;
  margin-right: 4px;
  padding: 0;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  cursor: pointer;
  font-family: inherit;
  transition: background 120ms ease, color 120ms ease;
}
.menu-item-audio-row[data-locked="false"] .menu-item-side { display: inline-flex; }
.menu-item-side:hover { background: var(--bg-soft); color: var(--text); }
.menu-item-side:focus-visible { outline-offset: -2px; }

/* ──────────────────────────────────────────────────────────────────────
   Inworld API key popover
─────────────────────────────────────────────────────────────────────── */

.audio-popover {
  position: fixed;
  z-index: 60;
  width: min(420px, calc(100vw - 24px));
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  transform-origin: top right;
  transition: opacity 160ms ease, transform 160ms ease;
}
.audio-popover.hidden {
  opacity: 0;
  pointer-events: none;
  transform: translateY(-6px) scale(0.98);
}
.audio-popover:not(.hidden) { opacity: 1; transform: translateY(0) scale(1); }

.audio-popover-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px 10px;
  border-bottom: 1px solid var(--border-soft);
}
.audio-popover-title { font-size: 14px; font-weight: 600; color: var(--text); }
.audio-popover-sub { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; line-height: 1.5; }
.audio-popover-body { padding: 12px 16px 4px; }
.audio-key-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px;
  align-items: center;
}
.audio-popover-link {
  display: inline-block;
  margin-top: 8px;
  font-size: 11.5px;
  color: var(--accent);
  text-decoration: none;
}
.audio-popover-link:hover { text-decoration: underline; }
.audio-key-status {
  margin-top: 10px;
  font-size: 12px;
  min-height: 18px;
  line-height: 1.4;
  color: var(--text-muted);
}
.audio-key-status[data-state="ok"] { color: var(--success); }
.audio-key-status[data-state="error"] { color: var(--danger); }
.audio-key-status[data-state="checking"] { color: var(--text-muted); }
.audio-popover-footer {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px 14px;
  border-top: 1px solid var(--border-soft);
}

/* ──────────────────────────────────────────────────────────────────────
   Audio Dock — persistent generation indicator
─────────────────────────────────────────────────────────────────────── */

.audio-dock {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 49;
  width: 320px;
  max-width: calc(100vw - 32px);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  transform: translateY(8px) scale(0.98);
  opacity: 0;
  transition: transform 220ms ease, opacity 220ms ease;
  font-family: inherit;
}
.audio-dock.visible { transform: translateY(0) scale(1); opacity: 1; }
.audio-dock.hidden { display: none; }

/* Top row: icon, status text, percent, and a small chevron toggle. The
   row itself is no longer a giant button — the chevron is the only
   click target so users can select / focus the title text. */
.audio-dock .dock-head {
  display: grid;
  grid-template-columns: 28px 1fr auto auto;
  gap: 10px;
  align-items: center;
  width: 100%;
  padding: 10px 12px;
  background: transparent;
  text-align: left;
  font-family: inherit;
  color: var(--text);
  border-bottom: 1px solid var(--border-hair);
}
.audio-dock .dock-expand {
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, transform 180ms ease;
}
.audio-dock .dock-expand:hover { background: var(--bg-soft); color: var(--text); }
.audio-dock .dock-expand svg { width: 14px; height: 14px; transition: transform 180ms ease; }
/* The dock is anchored to the bottom of the viewport and grows upward.
   Default SVG points down (v); we rotate to up (^) when compact so the
   chevron always points in the direction the dock will move on click:
     compact pill -> chevron up ("click to expand up")
     expanded card -> chevron down ("click to collapse down") */
.audio-dock.compact .dock-expand svg { transform: rotate(180deg); }

.audio-dock .dock-icon {
  width: 28px;
  height: 28px;
  border-radius: 6px;
  background: var(--accent-weak);
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  position: relative;
}
.audio-dock .dock-icon::after {
  content: "";
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  animation: dock-spin 900ms linear infinite;
}
.audio-dock[data-state="done"] .dock-icon { background: rgba(30, 142, 62, 0.12); color: var(--success); }
.audio-dock[data-state="failed"] .dock-icon { background: rgba(217, 48, 37, 0.12); color: var(--danger); }
.audio-dock[data-state="cancelled"] .dock-icon { background: var(--bg-soft); color: var(--text-muted); }
.audio-dock[data-state="expired"] .dock-icon { background: var(--bg-soft); color: var(--text-muted); }
.audio-dock[data-state="done"] .dock-icon::after,
.audio-dock[data-state="failed"] .dock-icon::after,
.audio-dock[data-state="cancelled"] .dock-icon::after,
.audio-dock[data-state="expired"] .dock-icon::after {
  animation: none;
  border: none;
  width: 14px; height: 14px;
  background: currentColor;
  -webkit-mask: var(--dock-icon-mask) center / contain no-repeat;
          mask: var(--dock-icon-mask) center / contain no-repeat;
  border-radius: 0;
}
.audio-dock[data-state="done"] .dock-icon {
  --dock-icon-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
}
.audio-dock[data-state="failed"] .dock-icon {
  --dock-icon-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><line x1='12' y1='8' x2='12' y2='13'/><line x1='12' y1='16' x2='12.01' y2='16'/></svg>");
}
.audio-dock[data-state="cancelled"] .dock-icon,
.audio-dock[data-state="expired"] .dock-icon {
  --dock-icon-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><line x1='18' y1='6' x2='6' y2='18'/><line x1='6' y1='6' x2='18' y2='18'/></svg>");
}

.audio-dock .dock-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.audio-dock .dock-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.audio-dock .dock-sub {
  font-size: 11.5px;
  color: var(--text-muted);
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.audio-dock .dock-pct {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  flex: none;
}
.audio-dock[data-state="done"] .dock-pct { color: var(--success); }
.audio-dock[data-state="failed"] .dock-pct { color: var(--danger); }

/* Compact mode: while running, default to a slim pill that shows only
   icon · percent · chevron. Click the chevron to expand to the full
   card. Terminal states (done/failed/cancelled/expired) drop .compact
   automatically so the Download / Retry / Dismiss buttons are reachable. */
.audio-dock.compact { width: auto; max-width: calc(100vw - 32px); }
.audio-dock.compact .dock-head {
  /* Three explicit columns when compact: icon | percent | chevron. We
     don't rely on auto-flow with hidden grid items because the trailing
     auto column would still contribute a gap. */
  grid-template-columns: 28px auto auto;
  padding: 8px 10px;
  border-bottom: none;
}
.audio-dock.compact .dock-text,
.audio-dock.compact .dock-bar,
.audio-dock.compact .dock-actions,
.audio-dock.compact .dock-confirm { display: none; }

.audio-dock .dock-bar {
  height: 3px;
  background: var(--border-hair);
  position: relative;
  overflow: hidden;
}
.audio-dock .dock-bar-inner {
  height: 100%;
  width: 0%;
  background: var(--accent);
  transition: width 280ms ease;
}
.audio-dock[data-state="done"] .dock-bar-inner { background: var(--success); }
.audio-dock[data-state="failed"] .dock-bar-inner { background: var(--danger); }
.audio-dock[data-state="cancelled"] .dock-bar-inner { background: var(--text-muted); }
.audio-dock[data-state="expired"] .dock-bar-inner { background: var(--text-muted); }

/* Indeterminate stripe while running. We tint with a translucent accent
   so themes that override --accent (custom themes) ride along. The
   color-mix() fallback keeps the brand blue for older browsers. */
.audio-dock[data-state="running"] .dock-bar::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(26, 115, 232, 0.55) 50%,
    transparent 100%
  );
  background: linear-gradient(
    90deg,
    transparent 0%,
    color-mix(in srgb, var(--accent) 55%, transparent) 50%,
    transparent 100%
  );
  width: 30%;
  animation: dock-stripe 1.6s linear infinite;
  mix-blend-mode: screen;
}

/* The middle "details" panel was removed (Chunks/Elapsed/Billed/Cache
   hits added noise without informing the user). The chevron still
   toggles between the compact pill and the full card; the card is now
   just title + sub + bar + actions. */

.audio-dock .dock-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  background: var(--bg);
  /* Right-align the action group so the primary button (Download / Retry
     / Cancel) and the dismiss X sit together at the right end of the
     row, like a notification card footer. Avoids the double-margin-auto
     bug that left Download floating in the middle. */
  justify-content: flex-end;
}
/* Same `display: inline-flex` vs `[hidden]` collision as the detail rows
   — without this rule, `els.cancel.hidden = true` etc. would do nothing
   and we'd render all four action buttons (cancel/download/retry/dismiss)
   simultaneously regardless of state. */
.audio-dock .dock-action[hidden] { display: none; }
.audio-dock .dock-action {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 28px;
  padding: 0 8px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
  font-size: 11.5px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.audio-dock .dock-action:hover {
  background: var(--bg-soft);
  color: var(--text);
  border-color: var(--border-soft);
}
/* All buttons flow naturally; the parent uses justify-content:flex-end
   so the action group hugs the right edge regardless of which buttons
   are visible in the current state. */
.audio-dock .dock-cancel:hover {
  /* Light-red wash on hover so the destructive intent is obvious before
     the click lands. The confirmation panel still appears on click. */
  background: rgba(217, 48, 37, 0.09); /* fallback for older browsers */
  background: color-mix(in srgb, var(--danger) 9%, transparent);
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 30%, transparent);
}
.audio-dock .dock-download {
  background: var(--success);
  color: #FFFFFF;
  border-color: var(--success);
}
.audio-dock .dock-download:hover {
  background: #166F30;
  border-color: #166F30;
  color: #FFFFFF;
}
.audio-dock .dock-retry {
  border-color: var(--border-soft);
  color: var(--text);
}

.audio-dock .dock-confirm {
  display: none;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px;
  background: var(--bg-soft);
  border-top: 1px solid var(--border-hair);
}
.audio-dock .dock-confirm.visible { display: flex; }
.audio-dock .dock-confirm-body { font-size: 12px; color: var(--text-soft); line-height: 1.45; }
.audio-dock .dock-confirm-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
}
.audio-dock .dock-confirm-yes { background: var(--danger); color: #FFFFFF; border-color: var(--danger); }
.audio-dock .dock-confirm-yes:hover { background: #B7251A; border-color: #B7251A; color: #FFFFFF; }

@keyframes dock-spin { to { transform: rotate(360deg); } }
@keyframes dock-stripe {
  from { transform: translateX(-30%); }
  to { transform: translateX(330%); }
}

@media (prefers-reduced-motion: reduce) {
  .audio-dock { transition: opacity 100ms ease; transform: none; }
  .audio-dock.visible { transform: none; }
  .audio-dock .dock-bar-inner { transition: none; }
  .audio-dock .dock-icon::after { animation: none; }
  .audio-dock[data-state="running"] .dock-bar::after { animation: none; opacity: 0.6; }

  /* Settings collapse: snap instantly instead of animating the grid.
     Also disable the rail's hover-nudge transform so users sensitive
     to motion don't get unsolicited movement on hover. */
  .workspace[data-view="split"] { transition: none; }
  .settings-collapse-btn,
  .settings-rail { transition: none; }
  .settings-rail:hover { transform: none; }
}

/* Mobile: tighter top-row padding and slightly smaller text. The compact
   chevron is already 22×22, no further shrink needed. */
@media (max-width: 520px) {
  .audio-dock {
    right: 8px;
    bottom: 8px;
    width: calc(100vw - 16px);
    max-width: 360px;
  }
  .audio-dock .dock-head { padding: 8px 10px; gap: 8px; }
  .audio-dock .dock-title { font-size: 12.5px; }
  .audio-dock .dock-sub { font-size: 11px; }
}

/* ──────────────────────────────────────────────────────────────────────
   Audiobook estimate modal
─────────────────────────────────────────────────────────────────────── */

.audio-estimate-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.audio-estimate-cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  background: var(--bg-soft);
}
.audio-estimate-label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.audio-estimate-value {
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* ──────────────────────────────────────────────────────────────────────
   Modal
─────────────────────────────────────────────────────────────────────── */

.modal {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.modal.hidden { display: none; }

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(32, 33, 36, 0.45);
  backdrop-filter: blur(3px);
}

.modal-panel {
  position: relative;
  width: 100%;
  max-width: 560px;
  background: var(--panel);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-soft);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  max-height: calc(100dvh - 32px);
}

.modal-header {
  padding: 16px 18px 12px;
  border-bottom: 1px solid var(--border-soft);
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 12px;
}

.modal-title { font-size: 15px; font-weight: 600; color: var(--text); }
.modal-sub { font-size: 12px; color: var(--text-muted); margin-top: 2px; }

.modal-body { padding: 16px 18px; overflow: auto; }

.modal-note {
  margin-top: 14px;
  padding: 10px 12px;
  background: var(--bg-soft);
  border: 1px solid var(--border-hair);
  border-radius: var(--radius);
  font-size: 11.5px;
  color: var(--text-muted);
  line-height: 1.5;
}

.modal-note-list {
  list-style: disc;
  padding-left: 18px;
  margin: 14px 0 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.modal-note-list li { padding-left: 2px; }

.modal-footer {
  padding: 12px 18px;
  border-top: 1px solid var(--border-soft);
  display: flex;
  align-items: center;
  gap: 8px;
}

/* ──────────────────────────────────────────────────────────────────────
   Scrollbars, toast, drag overlay, keyboard hint
─────────────────────────────────────────────────────────────────────── */

.mdc-scroll::-webkit-scrollbar { width: 10px; height: 10px; }
.mdc-scroll::-webkit-scrollbar-track { background: transparent; }
.mdc-scroll::-webkit-scrollbar-thumb {
  background: #DADCE0;
  border-radius: 10px;
  border: 2px solid transparent;
  background-clip: content-box;
}
.mdc-scroll::-webkit-scrollbar-thumb:hover {
  background: #BDC1C6;
  background-clip: content-box;
}

#toast {
  transition: transform 220ms ease, opacity 220ms ease;
  will-change: transform, opacity;
  background: var(--text);
  color: #FFFFFF;
  border: none;
  box-shadow: var(--shadow-lg);
}
#toast[data-kind="error"] { background: var(--danger); }
#toast[data-kind="success"] { background: var(--success); }

#drop-overlay {
  background: rgba(32, 33, 36, 0.55);
  backdrop-filter: blur(4px);
}
#drop-overlay .drop-card {
  background: #FFFFFF;
  border: 2px dashed var(--border);
  border-radius: var(--radius-lg);
  padding: 36px 48px;
  text-align: center;
  box-shadow: var(--shadow-lg);
}

.kbd {
  font-family: "JetBrains Mono", Consolas, Menlo, monospace;
  font-size: 11px;
  padding: 1px 6px;
  border-radius: 3px;
  background: var(--bg-soft);
  border: 1px solid var(--border-soft);
  color: var(--text-muted);
  line-height: 1.5;
}

.divider-v { display: inline-block; width: 1px; height: 18px; background: var(--border-soft); }

details { position: relative; }
details > summary::-webkit-details-marker { display: none; }
details > summary { list-style: none; cursor: pointer; }

.help-card > summary .chev { transition: transform 180ms ease; }
.help-card[open] > summary .chev { transform: rotate(180deg); }

/* ──────────────────────────────────────────────────────────────────────
   Focus visibility
─────────────────────────────────────────────────────────────────────── */

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* ──────────────────────────────────────────────────────────────────────
   Responsive tweaks
─────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {
  :root { --header-h: 52px; --tabs-h: 42px; }
  .workspace { padding: 8px; gap: 8px; }
  /* Mobile alignment column: workspace 8 + border 1 + pane-header 14 = 23.
     We round to 22px so brand, tabs, and pane title sit on the same line
     on small screens, mirroring the desktop alignment story. */
  .header-inner { padding: 0 22px; gap: 8px; }
  .tab-bar { padding: 0 22px; }
  .header-actions { gap: 4px; }
  .settings-inner { padding: 14px 14px 28px 14px; gap: 12px; }
  .editor-area { padding: 14px; }
  .field-row { grid-template-columns: 1fr auto; grid-auto-rows: auto; }
  .field-row .value-input { grid-column: 1 / -1; }
  .theme-indicator { max-width: 120px; }

  /* Phones — the A4 paper fills the pane width and keeps its 210:297 ratio.
     The paper still sits inside the preview-frame (which scrolls), but we
     drop the shadow/rounded corners so it reads as "this is the page", not
     "this is a shrunken preview of a page". Height comes from aspect-ratio
     on .preview-paper. */
  .preview-frame {
    padding: 0;
    background: var(--paper-bg, #FFFFFF);
    display: block;
    overflow-x: hidden;
  }
  .preview-paper-sizer { width: 100% !important; height: auto !important; }
  .preview-paper {
    width: 100%;
    /* Preserve the A4 ratio as a minimum height based on the viewport
       width (workspace padding is 8px per side = 16px total). Content
       taller than this still grows the paper naturally because we use
       min-height rather than a locked aspect-ratio. */
    min-height: calc((100vw - 16px) * 1.4142);
    box-shadow: none;
    border-radius: 0;
    padding: 24pt 18pt;
    transform: none !important;
    overflow-x: hidden;
    overflow-wrap: break-word;
  }

  /* Break any renderable that could be wider than the paper. Images are
     capped. Code blocks keep their own internal horizontal scroll because
     code is unwrappable. Tables stay as tables with text wrapping inside
     cells (table-layout: fixed distributes columns and lets content wrap). */
  #md-preview img { max-width: 100%; height: auto; }
  #md-preview pre { max-width: 100%; overflow-x: auto; }
  #md-preview table { max-width: 100%; width: 100% !important; table-layout: fixed; }
  #md-preview td, #md-preview th { overflow-wrap: break-word; word-wrap: break-word; }
  #md-preview a { overflow-wrap: anywhere; }
}

/* Phones — free up header room by hiding the wordmark and the button text
   labels that still show at tablet widths. */
@media (max-width: 520px) {
  .brand-text { display: none; }
  .btn { padding: 0 10px; }
  .btn-sm { padding: 0 8px; }
  .header-actions .divider-v { display: none; }
}

/* Very narrow — collapse Copy label and download dropdown chevron-only. */
@media (max-width: 400px) {
  #btn-copy span { display: none; }
  #btn-copy { padding: 0 10px; }
  #download-menu summary span:not(.hidden):first-of-type { /* keep Download text where possible */ }
}

/* Print (for the rare user who triggers browser print) */
@media print {
  html, body { background: #FFFFFF; overflow: visible; height: auto; }
  .app-header, .tab-bar, .pane:not(.pane-preview), .pane-header, #toast, #drop-overlay, .modal { display: none !important; }
  .app-shell { display: block; height: auto; }
  .workspace { display: block; padding: 0; }
  .pane-preview { display: flex; border: none; box-shadow: none; }
  .preview-frame { padding: 0; background: #FFFFFF; display: block; overflow: visible; }
  .preview-paper-sizer { width: auto !important; height: auto !important; }
  .preview-paper { box-shadow: none; margin: 0; border-radius: 0; transform: none !important; }
}
