  /* ── New Clip modal ── */
  #newClipModal {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.65);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 500;
  }
  #newClipModal.open { display: flex; }
  #newClipBox {
    background: var(--bg);
    border: 1px solid var(--surface-2);
    border-radius: 8px;
    width: 560px;
    max-width: calc(100vw - 40px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: 0 24px 60px rgba(0,0,0,0.6);
  }
  #newClipHeader {
    display: flex;
    align-items: center;
    padding: 13px 18px;
    border-bottom: 1px solid var(--surface-2);
    gap: 10px;
    background: var(--surface);
  }
  #newClipHeader h2 {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    flex: 1;
    letter-spacing: 0.01em;
  }
  #newClipClose {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 16px;
    cursor: pointer;
    padding: 0 4px;
    line-height: 1;
    transition: color 0.12s;
  }
  #newClipClose:hover { color: var(--text); }
  #newClipBody {
    padding: 18px;
    display: flex;
    flex-direction: column;
    gap: 13px;
  }
  .nc-row {
    display: flex;
    flex-direction: column;
    gap: 5px;
  }
  .nc-label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
  }
  .nc-input {
    background: #252525;
    color: var(--text);
    border: 1px solid #333;
    border-radius: 6px;
    padding: 7px 10px;
    font-size: 13px;
    font-family: inherit;
    width: 100%;
  }
  .nc-input:focus { outline: 2px solid var(--info); border-color: transparent; }
  select.nc-input { cursor: pointer; }
  #newClipLog {
    margin: 0 18px 0;
    background: #0d0d0d;
    border: 1px solid #222;
    border-radius: 6px;
    height: 130px;
    overflow-y: auto;
    padding: 8px 10px;
    font-family: "SF Mono", "Fira Code", monospace;
    font-size: 11px;
    line-height: 1.6;
    color: var(--text-2);
    display: none;
  }
  #newClipLog.visible { display: block; }
  #newClipLog::-webkit-scrollbar { width: 4px; }
  #newClipLog::-webkit-scrollbar-thumb { background: var(--input-bg); border-radius: 2px; }
  #newClipLog .log-done  { color: var(--success-2); }
  #newClipLog .log-error { color: var(--danger-2); }
  #newClipLog .log-sep   { color: var(--text-muted); margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--input-bg); }
  #newClipFooter {
    padding: 14px 18px;
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    border-top: 1px solid var(--input-bg);
  }
  #ingestBtn {
    background: var(--accent);
    color: #fff;
    border: none;
    border-radius: 6px;
    padding: 8px 20px;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.15s;
    white-space: nowrap;
  }
  #ingestBtn:hover    { background: #4338ca; }
  #ingestBtn:active   { background: #3730a3; }
  #ingestBtn:disabled { background: #374151; color: var(--text-muted); cursor: not-allowed; }
  #newClipCancelBtn {
    background: none;
    border: 1px solid #3a3a3a;
    color: var(--text-2);
    border-radius: 6px;
    padding: 8px 16px;
    font-size: 13px;
    cursor: pointer;
  }
  #newClipCancelBtn:hover { border-color: #555; color: var(--text); }
  /* ── Clip picker (searchable list) ── */
  #ncSearch {
    background: #252525;
    color: var(--text);
    border: 1px solid #333;
    border-radius: 6px 6px 0 0;
    padding: 8px 10px 8px 32px;
    font-size: 13px;
    font-family: inherit;
    width: 100%;
    box-sizing: border-box;
    border-bottom: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='5.5' cy='5.5' r='4'/%3E%3Cline x1='9' y1='9' x2='13' y2='13'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 10px center;
  }
  #ncSearch:focus { outline: 2px solid var(--info); border-color: transparent; border-bottom: none; z-index: 1; position: relative; }
  #ncSearch::placeholder { color: var(--border-2); }
  #ncList {
    background: #1a1a1a;
    border: 1px solid #333;
    border-radius: 0 0 6px 6px;
    max-height: 260px;
    overflow-y: auto;
  }
  #ncList::-webkit-scrollbar { width: 4px; }
  #ncList::-webkit-scrollbar-thumb { background: var(--input-bg); border-radius: 2px; }
  .ncl-folder-header {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px 4px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--border-2);
    cursor: pointer;
    user-select: none;
    position: sticky;
    top: 0;
    background: #1a1a1a;
    z-index: 1;
  }
  .ncl-folder-header:hover { color: var(--text-muted); }
  .ncl-folder-header .ncl-caret { font-size: 8px; transition: transform 0.15s; }
  .ncl-folder.collapsed .ncl-caret { transform: rotate(-90deg); }
  .ncl-folder.collapsed .ncl-folder-body { display: none; }
  .ncl-item {
    padding: 7px 14px;
    font-size: 13px;
    color: #c9cdd4;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    border-left: 2px solid transparent;
  }
  .ncl-item:hover { background: #252525; color: var(--text); }
  .ncl-item.ncl-selected {
    background: #1e1b38;
    border-left-color: var(--accent);
    color: var(--text);
  }
  .ncl-empty {
    padding: 20px 14px;
    font-size: 12px;
    color: var(--border-2);
    text-align: center;
  }
  /* ── Stage badges in clip dropdown ── */
  .stage-badge {
    display: inline-block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    border-radius: 4px;
    padding: 1px 5px;
    vertical-align: middle;
    margin-left: 4px;
  }
  .stage-ingest   { background: #374151; color: var(--text-2); }
  .stage-composed { background: #312e81; color: var(--accent-2); }
  .stage-rendered { background: #14532d; color: var(--success-2); }

  /* ── Compose panel ── */
  #composePanel {
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 28px 20px;
    background: linear-gradient(to bottom, rgba(67,56,202,0.06) 0%, transparent 100%);
    border-top: 1px solid rgba(255,255,255,0.06);
    flex-shrink: 0;
  }
  #composePanel p {
    font-size: 12px;
    color: #4b5568;
    text-align: center;
    max-width: 220px;
    line-height: 1.6;
  }
  button#newClipBtn {
    background: var(--surface);
    color: var(--text-3);
    border: 1px solid var(--surface-2);
    border-radius: 6px;
    padding: 7px 14px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
    white-space: nowrap;
    display: inline-flex; align-items: center; gap: 6px;
    line-height: 1;
  }
  button#newClipBtn:hover  { background: var(--hover); border-color: var(--border); color: var(--text-3); }
  button#newClipBtn:active { background: var(--surface); }
  button#newClipBtn svg { display: block; }

  button#composeBtn {
    background: rgba(99,102,241,0.12);
    color: var(--accent-soft);
    border: 1px solid rgba(99,102,241,0.40);
    border-radius: 6px;
    padding: 8px 18px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
    white-space: nowrap;
    display: inline-flex; align-items: center; gap: 7px;
    line-height: 1;
  }
  button#composeBtn:hover    { background: rgba(99,102,241,0.20); border-color: rgba(99,102,241,0.60); color: var(--accent-pale); }
  button#composeBtn:active   { background: rgba(99,102,241,0.28); }
  button#composeBtn:disabled { background: var(--surface-2); color: var(--text-muted); border-color: transparent; cursor: not-allowed; }
  button#composeBtn svg { display: block; }

  button#reTranscribeBtn {
    background: rgba(99,102,241,0.12); color: var(--accent-soft);
    border: 1px solid rgba(99,102,241,0.40); border-radius: 6px;
    padding: 7px 14px; font-size: 12px; font-weight: 600; cursor: pointer;
    font-family: inherit; transition: background 0.12s, border-color 0.12s, color 0.12s;
    white-space: nowrap;
    display: inline-flex; align-items: center; gap: 6px; line-height: 1;
  }
  button#reTranscribeBtn:hover    { background: rgba(99,102,241,0.20); border-color: rgba(99,102,241,0.60); color: var(--accent-pale); }
  button#reTranscribeBtn:active   { background: rgba(99,102,241,0.28); }
  button#reTranscribeBtn:disabled { background: var(--surface-2); color: var(--text-muted); border-color: transparent; cursor: not-allowed; }
  button#reTranscribeBtn svg { display: block; }

  /* ── Emphasis toggle ── */
  .word-chip {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    flex: 0 0 auto;                /* never grow or shrink */
  }
  .emph-btn {
    background: none;
    border: none;
    cursor: pointer;
    padding: 2px;
    border-radius: 3px;
    opacity: 0.3;
    transition: opacity 0.12s, color 0.12s;
    line-height: 0;
    color: var(--text-2);
    flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .emph-btn:hover { opacity: 0.75; }
  .emph-btn.active { opacity: 1; color: var(--warning); }
  .emph-btn.active-celebratory { opacity: 1; color: #ec4899; }
  /* Emphasis picker — popover with the arsenal of emphasis types */
  .emph-picker {
    position: absolute;
    background: var(--bg-2);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.4);
    padding: 4px;
    z-index: 1000;
    display: none;
    flex-direction: column;
    gap: 2px;
    min-width: 220px;
  }
  .emph-picker.show { display: flex; }
  .emph-picker-opt {
    background: transparent;
    border: none;
    border-radius: 6px;
    padding: 8px 10px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 10px;
    text-align: left;
    color: var(--text-1);
    font-size: 13px;
  }
  .emph-picker-opt:hover { background: var(--bg-3); }
  .emph-picker-opt.active { background: var(--accent-bg); color: var(--accent); }
  .emph-picker-icon { width: 18px; height: 18px; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; }
  .emph-picker-label { font-weight: 600; line-height: 1.2; }
  .emph-picker-hint { font-size: 11px; color: var(--text-3); margin-top: 2px; line-height: 1.2; }

  /* Emphasis dial picker — a floating frosted-glass radial menu. Each
     non-null entry in EMPHASIS_PICKER_OPTIONS becomes a wedge; null/Off
     is the center hub. The dial extends automatically as new emphasis
     types are added. No rectangular container — just the circle itself,
     translucent, with a backdrop blur so the captions stay visible under
     it. */
  .emph-dial-popover {
    position: absolute;
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 0;
    z-index: 1000;
    display: none;
  }
  .emph-dial-popover.show { display: block; }
  .emph-dial {
    position: relative;
    width: 132px;
    height: 132px;
    /* Soft outer glow so the dial reads as a discrete object even
       against busy backgrounds, without imposing a hard rectangle. */
    filter: drop-shadow(0 6px 18px rgba(0,0,0,0.45));
  }
  /* Frosted-glass background disk. The actual blur lives here (CSS
     backdrop-filter requires an HTML element with its own background,
     not an SVG path). The SVG wedges sit on top, mostly transparent,
     contributing the dividing lines and the active-state tint. The
     disk is clip-shaped to a donut via mask so the center hub stays
     visually distinct. */
  .emph-dial::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: rgba(20, 20, 24, 0.42);
    backdrop-filter: blur(12px) saturate(140%);
    -webkit-backdrop-filter: blur(12px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.10);
    /* Hollow center via radial mask so the page shows through the
       hub area too, matching the dial's donut visual. */
    -webkit-mask: radial-gradient(circle at 50% 50%, transparent 0 24px, #000 24px);
            mask: radial-gradient(circle at 50% 50%, transparent 0 24px, #000 24px);
    pointer-events: none;
  }
  .edial-svg {
    display: block;
    width: 100%;
    height: 100%;
    overflow: visible;
    position: relative;
    z-index: 1;
  }
  .edial-wedge {
    fill: transparent;
    stroke: rgba(255, 255, 255, 0.18);
    stroke-width: 1.2;
    transition: fill 0.12s, stroke 0.12s;
    cursor: pointer;
  }
  .edial-wedge:hover { fill: rgba(255, 255, 255, 0.06); }
  .edial-wedge.edial-active {
    fill: rgba(251, 191, 36, 0.22);
    stroke: var(--warning);
  }
  .edial-wedge.edial-active-celebratory {
    fill: rgba(236, 72, 153, 0.22);
    stroke: #ec4899;
  }
  .edial-btn {
    position: absolute;
    width: 30px; height: 30px;
    border: none;
    background: transparent;
    color: rgba(255, 255, 255, 0.92);
    border-radius: 50%;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transform: translate(-50%, -50%);
    padding: 0;
    transition: color 0.12s, transform 0.12s;
    pointer-events: auto;
    filter: drop-shadow(0 1px 2px rgba(0,0,0,0.6));
    z-index: 2;
  }
  .edial-btn:hover { transform: translate(-50%, -50%) scale(1.18); }
  .edial-btn svg { width: 22px; height: 22px; }
  .edial-btn.edial-active { color: var(--warning); }
  .edial-btn.edial-active-celebratory { color: #ec4899; }
  .edial-center {
    position: absolute;
    width: 40px; height: 40px;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background: rgba(20, 20, 24, 0.55);
    border: 1px solid rgba(255, 255, 255, 0.14);
    cursor: pointer;
    color: rgba(255, 255, 255, 0.55);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    backdrop-filter: blur(14px) saturate(140%);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    transition: color 0.12s, border-color 0.12s, background 0.12s, transform 0.12s;
    z-index: 3;
  }
  .edial-center:hover {
    color: rgba(255, 255, 255, 0.95);
    transform: translate(-50%, -50%) scale(1.08);
  }
  .edial-center svg { width: 18px; height: 18px; }
  .edial-center.edial-active {
    color: rgba(255, 255, 255, 0.92);
    border-color: rgba(255, 255, 255, 0.30);
  }
  .edial-label {
    text-align: center;
    font-size: 10.5px;
    color: rgba(255, 255, 255, 0.75);
    margin-top: 4px;
    min-height: 14px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-shadow: 0 1px 3px rgba(0,0,0,0.7);
    pointer-events: none;
  }
  .emoji-btn {
    background: none; border: none; cursor: pointer;
    font-size: 12px; padding: 0 1px; line-height: 1; flex-shrink: 0;
    visibility: hidden; opacity: 0.5; transition: opacity 0.12s;
  }
  .word-chip:hover .emoji-btn,
  .emoji-btn.has-emoji,
  .emoji-btn.has-custom { visibility: visible; }
  .emoji-btn.has-custom  { opacity: 1; }
  .emoji-btn.has-emoji   { opacity: 0.55; }
  .sfx-btn {
    background: none; border: none; cursor: pointer;
    padding: 2px; line-height: 0; flex-shrink: 0;
    color: var(--text-2);
    visibility: hidden; opacity: 0.55; transition: opacity 0.12s;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .word-chip:hover .sfx-btn,
  .gap-row:hover .gap-sfx-btn,
  .sfx-btn.sfx-active { visibility: visible; }
  .sfx-btn:hover { opacity: 1; }
  .sfx-btn.sfx-active { opacity: 1; color: #38bdf8; }
  /* Invisible alignment slot used by chunk-row to mirror gap-row's SFX
     button position. Matches .sfx-btn metrics so the time column lines up. */
  .sfx-placeholder {
    padding: 2px; line-height: 0; flex-shrink: 0;
    visibility: hidden; pointer-events: none;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .split-word-btn {
    background: none; border: none; cursor: pointer;
    padding: 2px; line-height: 0; flex-shrink: 0;
    visibility: hidden; opacity: 0.55; transition: opacity 0.12s, color 0.12s;
    color: var(--text-2);
    display: inline-flex; align-items: center; justify-content: center;
  }
  .word-chip:hover .split-word-btn { visibility: visible; }
  .split-word-btn:hover { opacity: 1; color: var(--info-2); }

  /* ── Compact word rows ────────────────────────────────────────────────
     Per-word config buttons collapse OUT OF THE LAYOUT (display:none, not
     just visibility:hidden) until you hover or keyboard-focus the word — so
     rows read as plain text, reclaim their width, and you don't mis-fire a
     config while navigating between lines. A word that already HAS a config
     keeps that one badge visible as an at-a-glance overview. Pairs with the
     single-click-to-seek / double-click-to-edit behavior in timeline.js. */
  .word-chip .emph-btn,
  .word-chip .emoji-btn,
  .word-chip .sfx-btn,
  .word-chip .split-word-btn { display: none; }

  .word-chip:hover .emph-btn,
  .word-chip:hover .emoji-btn,
  .word-chip:hover .sfx-btn,
  .word-chip:hover .split-word-btn,
  .word-chip:focus-within .emph-btn,
  .word-chip:focus-within .emoji-btn,
  .word-chip:focus-within .sfx-btn,
  .word-chip:focus-within .split-word-btn { display: inline-flex; }

  /* Applied configs stay visible even when not hovering (the overview). */
  .word-chip .emph-btn.active,
  .word-chip .emoji-btn.has-custom,
  .word-chip .emoji-btn.has-emoji,
  .word-chip .sfx-btn.sfx-active { display: inline-flex; }
  #sfxPicker {
    position: fixed; background: var(--bg); border: 1px solid var(--surface-2);
    border-radius: 6px; padding: 5px 0; display: none;
    flex-direction: column; z-index: 270;
    box-shadow: 0 8px 24px rgba(0,0,0,0.55); min-width: 200px;
    overflow: hidden;
  }
  #sfxPicker.show { display: flex; }
  #sfxList { overflow-y: auto; flex: 1; min-height: 0; }
  #sfxVolumeRow {
    border-top: 1px solid var(--surface-2); padding: 7px 12px 5px;
    display: none; align-items: center; gap: 6px; font-size: 11px;
    flex-shrink: 0;
  }
  #sfxVolumeRow.show { display: flex; }
  /* Emoji popover */
  #emojiPopover {
    position: fixed; z-index: 9000;
    background: #1c1c1c; border: 1px solid #3a3a3a; border-radius: 8px;
    padding: 10px; width: 228px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.55);
    display: none;
  }
  #emojiPopover.open { display: block; }
  #emojiPopoverInput {
    width: 100%; box-sizing: border-box;
    background: #111; border: 1px solid #333; border-radius: 5px;
    color: #e0e0e0; font-size: 22px; padding: 5px 8px;
    text-align: center; outline: none;
    font-family: system-ui, sans-serif;
  }
  #emojiPopoverInput:focus { border-color: var(--accent); }
  #emojiPopoverHint {
    font-size: 10px; color: #555; text-align: center; margin-top: 5px;
  }
  .emoji-quick-row {
    display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px;
  }
  .emoji-quick-btn {
    background: var(--input-bg); border: 1px solid #3a3a3a; border-radius: 4px;
    font-size: 15px; padding: 3px 4px; cursor: pointer; line-height: 1;
  }
  .emoji-quick-btn:hover { background: #353550; border-color: #5a5a9a; }
  .emoji-action-row { display: flex; gap: 6px; margin-top: 8px; }
  .emoji-action-btn {
    flex: 1; background: #252525; border: 1px solid #3a3a3a; border-radius: 4px;
    color: #888; font-size: 10px; padding: 5px 4px; cursor: pointer;
  }
  .emoji-action-btn:hover { background: #303030; color: #ccc; }
  .emoji-action-btn.ea-none { color: var(--danger-2); }
  .emoji-action-btn.ea-none:hover { background: #2d1a1a; }
  .word-chip.word-emphasized .word-input {
    border-color: var(--warning);
    box-shadow: 0 0 0 2px rgba(251,191,36,0.18);
  }
  .split-btn {
    background: none;
    border: none;
    cursor: pointer;
    padding: 2px;
    line-height: 0;
    color: var(--border-2);
    opacity: 0.24;
    transition: opacity 0.1s, color 0.1s;
    flex-shrink: 0;
    align-self: center;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .split-btn:hover { opacity: 1; color: var(--info-2); }
  .split-btn.active { opacity: 1; color: var(--info); }

  /* ── Per-line layout indicator ── */
  .layout-indicator {
    width: 24px; height: 24px;
    border-radius: 4px;
    border: 1px solid var(--surface-2);
    background: none;
    cursor: pointer;
    font-size: 11px;
    line-height: 1;
    padding: 0;
    flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    color: var(--border-2);
    transition: border-color 0.12s, background 0.12s, color 0.12s;
  }
  .layout-indicator:hover { border-color: var(--border); color: var(--text); }
  .layout-indicator.li-zoom { border-color: #7c3aed; color: #a78bfa; background: rgba(124,58,237,0.14); }
  .layout-indicator.li-full { border-color: #be185d; color: #f472b6; background: rgba(190,24,93,0.14); }
  .layout-indicator.li-gf   { border-color: #0d9488; color: #5eead4; background: rgba(13,148,136,0.14); }
  .layout-indicator.li-os   { border-color: var(--warning); color: var(--warning); background: rgba(217,119,6,0.14); }
  /* Auto-layout source badge: small lightning ⚡ in the corner when the layout
     was picked by the heuristic (not the user). Fades when the user has
     manually overridden the chunk so they can see what's their choice. */
  .layout-indicator.li-auto::after {
    content: '⚡';
    position: absolute;
    top: -3px; right: -4px;
    font-size: 8px;
    color: var(--warning);
    text-shadow: 0 0 2px #000, 0 0 2px #000;
    pointer-events: none;
  }
  .layout-indicator.li-claude::after { color: var(--info-2); }  /* Claude-refined = blue */
  .layout-indicator { position: relative; }
  /* ── Layout track: continuous left-edge bar that color-codes the per-line
        camera layout. Reading down the left edge tells you the layout
        structure of the whole clip at a glance. ── */
  .chunk-row::before, .gap-row::before {
    content: "";
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 4px;
    background: transparent;
    transition: background 0.12s;
    pointer-events: none;
  }
  .chunk-row.layout-zoom,        .gap-row.layout-zoom        { --lane: #8b5cf6; --lane-wash: rgba(139,92,246,0.07); }
  .chunk-row.layout-fullscreen,  .gap-row.layout-fullscreen  { --lane: #ec4899; --lane-wash: rgba(236,72,153,0.07); }
  .chunk-row.layout-game-full,   .gap-row.layout-game-full   { --lane: #14b8a6; --lane-wash: rgba(20,184,166,0.07); }
  .chunk-row.layout-one-shot,    .gap-row.layout-one-shot    { --lane: var(--warning); --lane-wash: rgba(245,158,11,0.07); }
  .chunk-row.layout-zoom::before,       .gap-row.layout-zoom::before,
  .chunk-row.layout-fullscreen::before, .gap-row.layout-fullscreen::before,
  .chunk-row.layout-game-full::before,  .gap-row.layout-game-full::before,
  .chunk-row.layout-one-shot::before,   .gap-row.layout-one-shot::before { background: var(--lane); }
  /* Banding: rows with a non-default layout get a faint background wash in the
     same color so consecutive same-layout rows visually group together. */
  .chunk-row.layout-zoom,
  .chunk-row.layout-fullscreen,
  .chunk-row.layout-game-full,
  .chunk-row.layout-one-shot { background-color: color-mix(in srgb, var(--lane) 7%, var(--bg)); }
  .gap-row.layout-zoom,
  .gap-row.layout-fullscreen,
  .gap-row.layout-game-full,
  .gap-row.layout-one-shot { background-color: color-mix(in srgb, var(--lane) 7%, var(--surface)); }
  /* Eliminate vertical margin between consecutive rows sharing the same layout
     so the left-edge track reads as one continuous bar. */
  .chunk-row + .chunk-row,
  .chunk-row + .gap-row,
  .gap-row   + .chunk-row,
  .gap-row   + .gap-row { margin-top: 1px; }
  /* State backgrounds win over layout banding (must come after layout rules). */
  .chunk-row.row-selected,
  .gap-row.gap-selected     { background-color: #1e1a38 !important; border-color: var(--accent); }
  .gap-row.gap-selected.cut { background-color: rgba(168,85,247,0.14) !important; border-color: #a855f7; }
  .chunk-row.row-looping    { background-color: rgba(99,102,241,0.10) !important; }
  .gap-row.cut              { background-color: rgba(185,28,28,0.10) !important; border-color: var(--danger); }

  /* ── Inline layout picker ── */
  #layoutPicker {
    position: fixed;
    background: var(--bg);
    border: 1px solid var(--surface-2);
    border-radius: 6px;
    padding: 8px;
    display: none;
    flex-direction: column;
    gap: 7px;
    z-index: 300;
    box-shadow: 0 8px 24px rgba(0,0,0,0.55);
    min-width: 188px;
  }
  #layoutPicker.show { display: flex; }
  .lp-modes { display: flex; gap: 4px; }
  .lp-mode-btn {
    flex: 1;
    background: var(--surface);
    border: 1px solid var(--surface-2);
    border-radius: 5px;
    color: var(--text-2);
    cursor: pointer;
    font-size: 9px;
    font-weight: 600;
    padding: 6px 3px;
    text-align: center;
    transition: border-color 0.12s, background 0.12s, color 0.12s;
    font-family: inherit;
    letter-spacing: 0.04em;
    display: flex; flex-direction: column; align-items: center; gap: 3px;
  }
  .lp-mode-btn:hover { border-color: var(--border); color: var(--text); }
  .lp-mode-btn.lp-active       { border-color: rgba(99,102,241,0.55); background: rgba(99,102,241,0.14); color: var(--accent-soft); }
  .lp-mode-btn.lp-active.lp-zm { border-color: #7c3aed; background: rgba(124,58,237,0.2); color: #a78bfa; }
  .lp-mode-btn.lp-active.lp-fs { border-color: #be185d; background: rgba(190,24,93,0.2); color: #f472b6; }
  .lp-mode-btn.lp-active.lp-gf { border-color: #0d9488; background: rgba(13,148,136,0.2); color: #5eead4; }
  .lp-mode-btn.lp-active.lp-os { border-color: var(--warning); background: rgba(217,119,6,0.2);  color: var(--warning); }
  .lp-mode-icon  { font-size: 14px; line-height: 1; }
  .lp-mode-label { font-size: 8px; letter-spacing: 0.06em; }
  .lp-zoom-row {
    display: none;
    align-items: center; gap: 6px; padding: 1px 0;
  }
  .lp-zoom-row.lp-visible { display: flex; }
  .lp-zoom-label  { font-size: 10px; color: var(--text-muted); font-weight: 700; min-width: 28px; }
  .lp-zoom-slider { flex: 1; accent-color: #7c3aed; cursor: pointer; height: 4px; }
  .lp-zoom-value  { font-size: 10px; color: var(--text-2); min-width: 28px; text-align: right; font-variant-numeric: tabular-nums; }

  /* ── Bulk layout picker ── */
  #bulkLayoutPicker {
    display: none; gap: 5px;
    align-items: center;
  }
  #bulkLayoutPicker.show { display: flex; }
  #bulkLayoutPicker .blp-label {
    font-size: 10px; font-weight: 600; color: var(--text-muted);
    letter-spacing: 0.04em;
    margin-right: 3px; white-space: nowrap;
  }
  .blp-btn {
    background: var(--surface); border: 1px solid var(--surface-2); border-radius: 5px;
    color: var(--text-2); cursor: pointer; font-size: 10px; font-weight: 600;
    padding: 4px 9px; transition: border-color 0.12s, color 0.12s, background 0.12s;
    font-family: inherit; white-space: nowrap;
  }
  .blp-btn:hover { border-color: rgba(99,102,241,0.55); color: var(--accent-soft); background: rgba(99,102,241,0.08); }

  /* ── FX indicators & picker ── */
  .fx-indicator {
    background: none;
    border: 1px solid var(--surface-2);
    border-radius: 4px;
    color: var(--border-2);
    cursor: pointer;
    padding: 4px;
    line-height: 0;
    transition: border-color 0.12s, color 0.12s, background 0.12s;
    flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .fx-indicator:hover   { border-color: var(--border); color: var(--text-2); }
  .fx-indicator.fx-active { border-color: rgba(245,158,11,0.55); color: var(--warning); background: rgba(245,158,11,0.10); }

  #fxPicker {
    position: fixed;
    background: var(--bg);
    border: 1px solid var(--surface-2);
    border-radius: 6px;
    padding: 5px 0;
    display: none;
    flex-direction: column;
    z-index: 260;
    box-shadow: 0 8px 24px rgba(0,0,0,0.55);
    min-width: 200px;
    overflow: hidden;
  }
  #fxPicker.show { display: flex; }
  .fp-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 6px 12px; border-bottom: 1px solid var(--surface-2);
    flex-shrink: 0;
  }
  .fp-title { font-size: 10px; font-weight: 600; color: var(--text-muted); letter-spacing: 0.04em; }
  .fp-clear {
    font-size: 10px; color: var(--text-muted); background: none; border: none;
    cursor: pointer; padding: 2px 5px; border-radius: 4px;
    transition: color 0.12s; font-family: inherit;
  }
  .fp-clear:hover { color: var(--danger); }
  #fpList { overflow-y: auto; flex: 1; min-height: 0; }
  .fp-item {
    display: flex; align-items: center; gap: 7px;
    padding: 6px 12px; cursor: pointer;
    font-size: 12px; color: var(--text-2);
    transition: background 0.1s, color 0.1s;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .fp-item:hover  { background: var(--hover); color: var(--text); }
  .fp-item.fp-selected { color: var(--warning); }
  .fp-item-icon { font-size: 13px; flex-shrink: 0; }
  #fpSettings {
    border-top: 1px solid var(--surface-2);
    padding: 8px 12px 6px;
    display: none;
    flex-direction: column;
    gap: 6px;
    flex-shrink: 0;
  }
  #fpSettings.show { display: flex; }
  .fp-settings-row {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 11px;
  }
  .fp-settings-label {
    color: var(--text-muted);
    width: 56px;
    flex-shrink: 0;
  }
  .fp-settings-input {
    background: var(--surface);
    border: 1px solid var(--surface-2);
    border-radius: 4px;
    color: var(--text);
    font-size: 11px;
    width: 46px;
    padding: 2px 5px;
    font-family: inherit;
    text-align: right;
  }
  .fp-settings-input:focus { outline: none; border-color: var(--accent); }
  .fp-settings-unit { color: var(--text-muted); }
  .fp-settings-reset {
    background: none;
    border: 1px solid var(--surface-2);
    border-radius: 4px;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 11px;
    padding: 1px 5px;
    font-family: inherit;
    transition: color 0.12s, border-color 0.12s;
  }
  .fp-settings-reset:hover { color: var(--text); border-color: var(--border); }
  .fp-fade-last { color: var(--text-muted); }
  .fp-settings-check { cursor: pointer; accent-color: var(--accent); }
  .fp-fade-input-wrap { display: contents; }
  .fp-fade-input-wrap.hidden { display: none; }

  /* ── Word timing panel ── */
  #timingPanel {
    position: fixed; background: var(--bg); border: 1px solid var(--surface-2);
    border-radius: 6px; padding: 6px 8px; display: none;
    flex-direction: column; gap: 4px; z-index: 260;
    box-shadow: 0 8px 24px rgba(0,0,0,0.55); pointer-events: auto;
  }
  #timingPanel.show { display: flex; }
  .tp-row  { display: flex; align-items: center; gap: 4px; }
  .tp-label { color: var(--text-muted); font-size: 10px; width: 26px; font-weight: 600; }
  .tp-val  { color: var(--text-3); font-family: ui-monospace, monospace; font-size: 11px; width: 52px; text-align: center;
             background: var(--surface); border: 1px solid var(--surface-2); border-radius: 3px; padding: 2px 4px; outline: none;
             font-variant-numeric: tabular-nums; transition: border-color 0.12s, background 0.12s; }
  .tp-val:hover { border-color: var(--border); }
  .tp-val:focus { border-color: var(--accent); color: #fff; background: var(--bg); }
  .tp-val.tp-val-error { border-color: var(--danger); background: #2d1010; animation: tp-shake 0.25s; }
  @keyframes tp-shake {
    0%,100%{transform:translateX(0)} 25%{transform:translateX(-3px)} 75%{transform:translateX(3px)}
  }
  .tp-btn  {
    background: var(--surface); border: 1px solid var(--surface-2); border-radius: 3px;
    color: var(--text-2); cursor: pointer; font-size: 10px; line-height: 1;
    padding: 3px 6px; font-family: inherit;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
  }
  .tp-btn:hover { background: var(--hover); color: var(--text-3); border-color: var(--border); }
  .tp-meta { display: flex; justify-content: space-between; align-items: center;
             padding-top: 3px; border-top: 1px solid var(--input-bg); margin-top: 2px; }
  .tp-meta span { color: var(--border-2); font-size: 9px; font-family: monospace; }
  #tpDurVal { color: var(--accent); }

  .gap-row {
    display: flex;
    align-items: center;
    gap: 10px;                          /* match chunk-row */
    padding: 6px 12px 6px 22px;         /* match chunk-row spacing + layout track room */
    min-height: 44px;
    box-sizing: border-box;
    background: var(--surface);
    border: 1px solid var(--bg);
    border-left: 0;
    border-radius: 6px;
    font-size: 11px;
    color: var(--text-muted);
    cursor: pointer;
    user-select: none;
    position: relative;
    flex-shrink: 0;                     /* same fix as chunk-row — column-flex parent
                                           would otherwise squish gap rows */
  }
  .gap-split-marker {
    position: absolute; top: 0; bottom: 0; width: 2px;
    background: rgba(250, 204, 21, 0.45);
    cursor: ew-resize; z-index: 1;
    transform: translateX(-50%);
    opacity: 0; transition: opacity 0.15s, background 0.1s;
    pointer-events: all;
  }
  .gap-split-marker::before {
    content: ''; position: absolute;
    top: 0; bottom: 0; left: -6px; right: -6px;
  }
  .gap-row:hover .gap-split-marker,
  .gap-row.gap-selected .gap-split-marker,
  .gap-split-marker.dragging { opacity: 1; }
  .gap-split-marker:hover,
  .gap-split-marker.dragging { background: var(--warning); }
  .gap-row button { cursor: pointer; }
  .gap-row.cut {
    border-color: var(--danger);
    background: rgba(185,28,28,0.07);
    color: var(--danger-2);
  }
  .gap-row.gap-selected {
    border-color: var(--accent);
    background: rgba(99,102,241,0.1);
    color: var(--accent-2);
  }
  .gap-row.gap-selected.cut {
    border-color: #a855f7;
    background: rgba(168,85,247,0.12);
    color: #d8b4fe;
  }
  .gap-row.gap-looping { outline: 1px solid rgba(99,102,241,0.45); }
  .gap-label {
    flex: 1;
    font-size: 10px;
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
    letter-spacing: 0.01em;
  }
  .gap-hide-btn, .gap-split-btn {
    background: none;
    border: 1px solid #374151;
    color: var(--text-muted);
    cursor: pointer;
    width: 24px; height: 24px;
    border-radius: 4px;
    line-height: 0;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    transition: border-color 0.12s, color 0.12s, background 0.12s;
  }
  .gap-hide-btn:hover, .gap-split-btn:hover { border-color: var(--text-muted); color: var(--text); background: rgba(255,255,255,0.04); }
  .gap-hide-btn.cut { border-color: var(--danger); color: var(--danger); background: rgba(239,68,68,0.1); }
  .gap-cut-badge {
    display: none; align-items: center; gap: 4px;
    font-size: 9px; font-weight: 700; letter-spacing: 0.05em;
    color: var(--danger-2); background: rgba(185,28,28,0.22); border-radius: 3px;
    padding: 2px 6px; flex-shrink: 0;
  }
  .gap-row.cut .gap-cut-badge { display: inline-flex; }

  /* ── Trim markers in captions list ── */
  .trim-marker {
    display: flex; align-items: center; gap: 10px;
    padding: 5px 10px 5px 14px;
    font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
    user-select: none; flex-shrink: 0; position: relative;
  }
  .trim-in-marker  { color: var(--success); background: rgba(34,197,94,0.07);
                     border-top: 1px solid rgba(34,197,94,0.3); border-bottom: 1px solid rgba(34,197,94,0.3); }
  .trim-out-marker { color: var(--danger); background: rgba(239,68,68,0.07);
                     border-top: 1px solid rgba(239,68,68,0.3); border-bottom: 1px solid rgba(239,68,68,0.3); }
  .trim-marker::before {
    content: ''; position: absolute; left: 0; top: 0; bottom: 0;
    width: 3px; border-radius: 0 2px 2px 0;
  }
  .trim-in-marker::before  { background: var(--success); }
  .trim-out-marker::before { background: var(--danger); }
  .trim-marker-time { opacity: 0.6; font-weight: 400; }
  .row-trimmed-out { opacity: 0.28; }

  /* ── Script tab ───────────────────────────────────────────────────────────
     Repalleted to the neutral grey shared by Captions/Overlay/Layout.
     Top: toolbar (actions + help + search). Middle: backend selector.
     Body: scrollable transcript. Bottom: status bar. */
  #scriptToolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--surface-2);
    flex-shrink: 0;
    background: var(--bg);
  }
  .script-toolbar-btn {
    background: var(--surface);
    color: var(--text-2);
    border: 1px solid var(--surface-2);
    border-radius: 5px;
    padding: 5px 10px;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
    white-space: nowrap;
    display: inline-flex; align-items: center; gap: 6px;
    line-height: 1;
  }
  .script-toolbar-btn:hover { background: var(--hover); color: var(--text-3); border-color: var(--border); }
  .script-toolbar-btn.script-btn-primary {
    background: rgba(99,102,241,0.12); color: var(--accent-soft);
    border-color: rgba(99,102,241,0.40);
  }
  .script-toolbar-btn.script-btn-primary:hover {
    background: rgba(99,102,241,0.20); border-color: rgba(99,102,241,0.60); color: var(--accent-pale);
  }
  .script-toolbar-btn:disabled { opacity: 0.4; cursor: not-allowed; }
  .script-toolbar-btn svg { display: block; }

  /* In-page search (Cmd+F style) — slides into the toolbar when toggled. */
  .script-search {
    display: none; align-items: center; gap: 6px;
    background: var(--surface);
    border: 1px solid var(--surface-2);
    border-radius: 5px;
    padding: 3px 8px;
    flex: 1;
    max-width: 280px;
  }
  .script-search.show { display: inline-flex; }
  .script-search:focus-within { border-color: var(--accent); }
  .script-search svg { color: var(--text-muted); flex-shrink: 0; }
  .script-search input {
    flex: 1;
    background: transparent; border: none; outline: none;
    color: var(--text-3); font-family: inherit; font-size: 12px;
    padding: 2px 0; min-width: 60px;
  }
  .script-search input::placeholder { color: var(--text-quiet); }
  .script-search-count {
    font-size: 10px; color: var(--text-muted);
    font-variant-numeric: tabular-nums; letter-spacing: 0.02em;
    white-space: nowrap;
  }
  .script-search-close {
    background: none; border: none; color: var(--text-muted); cursor: pointer;
    padding: 2px; line-height: 0; border-radius: 3px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .script-search-close:hover { color: var(--text-3); background: rgba(255,255,255,0.05); }

  /* Help button — a (?) icon at top-right that reveals the legend tooltip. */
  .script-help-btn {
    margin-left: auto;
    background: none; border: 1px solid var(--surface-2); color: var(--text-muted);
    width: 22px; height: 22px; border-radius: 50%;
    cursor: pointer; font-family: inherit; font-size: 11px; font-weight: 700;
    display: inline-flex; align-items: center; justify-content: center;
    transition: color 0.12s, border-color 0.12s, background 0.12s;
    position: relative;
  }
  .script-help-btn:hover, .script-help-btn.show { color: var(--text-3); border-color: var(--border); background: var(--hover); }
  .script-help-popover {
    display: none;
    position: absolute; right: 0; top: calc(100% + 6px);
    background: var(--bg); border: 1px solid var(--surface-2); border-radius: 6px;
    padding: 10px 12px; font-size: 11px; font-weight: 500;
    color: var(--text-2); line-height: 1.6; white-space: nowrap;
    box-shadow: 0 8px 24px rgba(0,0,0,0.5); z-index: 50;
    text-align: left;
  }
  .script-help-btn.show .script-help-popover { display: block; }
  .script-help-popover b { color: var(--text-3); font-weight: 600; }
  .script-help-key { color: var(--warning); font-weight: 600; }
  .script-help-strike { color: var(--text-quiet); text-decoration: line-through; font-weight: 600; }

  /* Backend bar — segmented control replaces the old pill radios. */
  #scriptBackendBar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px;
    border-bottom: 1px solid var(--surface-2);
    flex-shrink: 0;
    background: var(--surface);
  }
  .sbb-label {
    font-size: 10px;
    color: var(--text-muted);
    white-space: nowrap;
    font-weight: 600;
    flex-shrink: 0;
    display: inline-flex; align-items: center; gap: 6px;
  }
  .sbb-label svg { color: var(--text-muted); }

  /* Body — the transcript reading surface. */
  #scriptBody {
    flex: 1;
    overflow-y: auto;
    padding: 14px 18px 18px;
    line-height: 1.95;
    font-size: 15px;
    font-weight: 500;
    color: #cbd5e1;
    background: var(--surface);
  }
  #scriptBody p {
    margin: 0 0 0.7em;
    padding-left: 10px;
    border-left: 2px solid var(--surface-2);
    transition: border-color 0.15s;
  }
  #scriptBody p:hover { border-left-color: var(--border-2); }
  #scriptBody::-webkit-scrollbar { width: 6px; }
  #scriptBody::-webkit-scrollbar-thumb { background: var(--surface-2); border-radius: 3px; }
  #scriptBody::-webkit-scrollbar-thumb:hover { background: var(--border); }

  .script-word {
    cursor: pointer;
    border-radius: 3px;
    padding: 0 1px;
    transition: background 0.1s, color 0.1s;
  }
  .script-word:hover { background: rgba(99,102,241,0.22); color: var(--text-3); }
  .script-word.script-hidden  { color: var(--border-2); text-decoration: line-through; }
  .script-word.script-emph    { color: var(--warning); }
  .script-word.script-playing {
    background: rgba(80,255,30,0.20);
    color: #b8ffb8;
    border-radius: 3px;
  }
  /* Low-confidence ASR words get a subtle wavy red underline, like spell-check.
     Lets the reviewer scan for "probably wrong" words at a glance. */
  .script-word.script-low-conf {
    text-decoration: underline wavy rgba(239,68,68,0.55);
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
  }
  /* Search-match highlight — yellow background, dimmed non-matches. */
  #scriptBody.script-searching .script-word { opacity: 0.35; }
  #scriptBody.script-searching .script-word.script-match {
    opacity: 1; background: rgba(250,204,21,0.30); color: #fef3c7;
  }
  #scriptBody.script-searching .script-word.script-match-current {
    background: rgba(250,204,21,0.55); color: #fffbeb;
    box-shadow: 0 0 0 1px rgba(250,204,21,0.7);
  }

  .script-break { display: block; height: 0.4em; }
  /* Inline pause marker between paragraphs — exposes the speech rhythm
     that's currently invisible (paragraphs just break at long pauses). */
  .pause-marker {
    display: flex; align-items: center; gap: 8px;
    margin: 6px 0 10px;
    font-size: 9.5px; color: var(--text-quiet);
    font-variant-numeric: tabular-nums; font-feature-settings: "tnum";
    letter-spacing: 0.04em;
    user-select: none;
  }
  .pause-marker::before, .pause-marker::after {
    content: ""; flex: 1; height: 1px;
    background: linear-gradient(to right, transparent, var(--surface-2), transparent);
  }
  .pause-marker-dur { white-space: nowrap; }

  /* Status footer — metadata lives at the bottom, not floating in the toolbar. */
  #scriptStatusBar {
    display: flex; align-items: center; gap: 14px;
    padding: 7px 14px; flex-shrink: 0;
    border-top: 1px solid var(--surface-2);
    background: var(--surface);
    font-size: 10px; color: var(--text-quiet);
    font-variant-numeric: tabular-nums; font-feature-settings: "tnum";
    letter-spacing: 0.02em;
  }
  #scriptStatusBar .ssb-sep { color: var(--surface-2); }
  #scriptStatusBar .ssb-strong { color: var(--text-2); font-weight: 500; }

  /* Empty state — friendlier than plain text. */
  .script-empty-state {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 10px; padding: 50px 20px;
    color: var(--text-quiet); text-align: center;
  }
  .script-empty-state svg { color: var(--border); }
  .script-empty-state-title { font-size: 13px; font-weight: 600; color: var(--text-muted); }
  .script-empty-state-hint  { font-size: 11px; color: var(--border-2); line-height: 1.5; max-width: 280px; }

  @keyframes _spin { from { transform: rotate(0); } to { transform: rotate(360deg); } }
  .spin-anim { animation: _spin 1.1s linear infinite; transform-origin: 50% 50%; }

  /* ─────────────────────────────────────────────────────────────────
     MOBILE / TOUCH OVERRIDES — chunk 1 of the mobile UI plan
     The query `(hover: none) and (pointer: coarse)` matches phones
     and touch-only tablets but NOT mouse / trackpad desktops or
     hybrid tablets in keyboard mode. Desktop UI is byte-identical
     at all viewport widths because this entire block is gated by
     the touch capability of the input device, not the screen size.
     ───────────────────────────────────────────────────────────── */
  @media (hover: none) and (pointer: coarse) {
    /* ── Force visibility of hover-revealed controls ─────────────
       On desktop these chip controls are hidden until the user hovers
       the parent row; touch has no hover so the controls were
       effectively unreachable. Show them at the same opacity the
       hover state used. */
    .emoji-btn,
    .sfx-btn,
    .split-word-btn,
    .gap-sfx-btn {
      visibility: visible;
      opacity: 0.7;
    }
    .gap-split-marker {
      opacity: 0.7;
    }
    .color-control:hover .color-control-reset,
    .color-control-reset {
      opacity: 0.7;
    }
    .trim-handle {
      opacity: 1;
      width: 8px;
      height: 26px;
    }
    /* Trim handles are intentionally narrow (8px) so they don't visually
       clutter the scrubber. On touch, the visible handle is hard to grab,
       so widen the invisible ::before hit zone to a comfortable 28×44 box
       around each handle without changing the painted glyph. */
    .trim-handle::before { inset: -10px -16px; }
    /* Render-log drawer close (×) — 23×23 default is below iOS HIG; pad
       it out to 36×36 to make it easy to dismiss the drawer. */
    button#logDrawerClose { padding: 9px; min-width: 36px; min-height: 36px; }

    /* New-clip modal close (✕) — 20×16 default (padding: 0 4px) is well below
       the HIG floor and is the primary way to dismiss a full-screen modal on
       touch, so give it the full 44×44 target. */
    button#newClipClose { padding: 10px; min-width: 44px; min-height: 44px; }

    /* ── Touch targets ≥44×44 per iOS HIG / Android Material ──────
       Apply min-width/min-height to the row-control icons. Visible
       width still drives layout via flex; the min sizes only kick
       in when something tries to render smaller. The chunk-row left
       controls keep their pixel positions because they were already
       ≥24px wide — this only enlarges the truly tiny ones. */
    .hide-btn,
    .emph-btn,
    .emoji-btn,
    .sfx-btn,
    .split-word-btn,
    .split-btn,
    .gap-hide-btn,
    .gap-split-btn,
    .gap-sfx-btn,
    .layout-indicator,
    .fx-indicator,
    .tab-btn,
    .lp-mode-btn,
    .blp-btn,
    .title-theme-btn,
    .seg-control-btn,
    button#newClipBtn,
    button#composeBtn,
    button#renderBtn,
    button#helpBtn {
      min-width: 44px;
      min-height: 44px;
    }

    /* SVG icons inside the touch-sized buttons should grow a bit so
       the button doesn't feel mostly empty padding. */
    .hide-btn svg, .emph-btn svg, .sfx-btn svg, .split-word-btn svg,
    .gap-hide-btn svg, .gap-split-btn svg, .gap-sfx-btn svg,
    .split-btn svg {
      width: 16px;
      height: 16px;
    }

    /* Active-state cue replaces :hover feedback that touch devices
       don't show. Quick depress effect on tap so the user knows the
       tap registered. */
    .hide-btn:active, .emph-btn:active, .emoji-btn:active,
    .sfx-btn:active, .split-word-btn:active, .split-btn:active,
    .gap-hide-btn:active, .gap-split-btn:active, .gap-sfx-btn:active,
    .layout-indicator:active, .fx-indicator:active,
    .tab-btn:active, .lp-mode-btn:active, .blp-btn:active {
      transform: scale(0.94);
      transition: transform 0.05s;
    }

    /* Chunk-row / gap-row controls override the 44×44 default — a row
       carries 6–10 of these icons, and 44×44 each (264–440 px just for
       row buttons) blows out the 393-px iPhone viewport. 32×32 is still
       above the accessibility floor for in-row controls; users target
       the row body for coarse seeks and the icons for refinement. */
    .chunk-row .hide-btn,
    .chunk-row .emph-btn,
    .chunk-row .emoji-btn,
    .chunk-row .sfx-btn,
    .chunk-row .split-word-btn,
    .chunk-row .split-btn,
    .chunk-row .layout-indicator,
    .chunk-row .fx-indicator,
    .gap-row   .gap-hide-btn,
    .gap-row   .gap-split-btn,
    .gap-row   .gap-sfx-btn,
    .gap-row   .layout-indicator,
    .gap-row   .fx-indicator {
      min-width: 32px;
      min-height: 32px;
    }

    /* Chunk-row two-row layout on mobile: the desktop one-line flex squeezes
       chunk-words down to ~54 px on a 393-px iPhone (left side eats up
       indicators + time + hide-btn). Word chips then overflow and wrap
       inside their tiny box → 122-px-tall rows that look broken. Solution:
       flex-wrap the row so .chunk-words gets a full second line below. */
    .chunk-row {
      flex-wrap: wrap;
      row-gap: 4px;
      padding-top: 6px;
      padding-bottom: 6px;
    }
    .chunk-row .chunk-time {
      min-width: 0;
      flex: 1 1 auto;
    }
    .chunk-row .chunk-words {
      flex: 0 0 100%;
      order: 10;                  /* drop to its own row */
      padding-left: 0;
    }
    /* hide-btn lives at the end of the row in DOM order. With wrap +
       order:10 on .chunk-words, hide-btn would land on the words row.
       Override its order so it stays on the top row beside the time. */
    .chunk-row > .hide-btn {
      order: 1;
    }

    /* Apply the same wrap pattern to .gap-row, even though gaps don't
       have a chunk-words element — keeps the time / cut-buttons readable
       without flex squishing them to nothing. */
    .gap-row {
      flex-wrap: wrap;
      row-gap: 2px;
    }

    /* Playing-row highlight: the 1px green inset shadow is subtle enough
       that on a phone you can blow past the active line without noticing
       it scrolled past. Bump it to a 2px green left bar + brighter tint. */
    .chunk-row.row-playing,
    .gap-row.gap-playing {
      box-shadow: inset 3px 0 0 0 #50ff1e, inset 0 0 0 1px rgba(80,255,30,0.35);
      background: rgba(80,255,30,0.06);
    }

    /* Scrubber bar: stack the slider above time/speed/loop on mobile so the
       slider gets the full viewport width to scrub. Default flex-row layout
       squeezes scrubber-wrap to ~136 px on a 393 px iPhone (time text + speed
       dropdown + loop button eat the rest), making precise scrubbing hard. */
    .scrubber-bar.show {
      flex-wrap: wrap;
      gap: 6px;
      padding: 6px 8px;
    }
    .scrubber-bar .scrubber-wrap {
      flex: 0 0 100%;
      width: 100%;
    }
    .scrubber-bar .scrubber-time {
      flex: 1 1 auto;
    }
    .scrubber-bar .scrubber-controls {
      flex: 0 0 auto;
    }

    /* ── Resizable preview/tools divider ──────────────────────────────────
       A horizontal grab-pill between panel-right (video, order 1) and
       panel-left (tools, order 3). JS drag handler updates panel-right's
       inline max-height/height; localStorage persists the chosen size.
       Visual: 22 px-tall bar with a 40×4 grey pill that turns indigo on
       press. touch-action:none so the OS doesn't try to scroll-pan during
       a vertical drag. */
    #paneDivider {
      order: 2;
      flex: 0 0 auto;
      height: 22px;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      background: var(--surface);
      border-top:    1px solid var(--input-bg);
      border-bottom: 1px solid var(--input-bg);
      cursor: ns-resize;
      touch-action: none;
      -webkit-user-select: none;
      user-select: none;
      z-index: 2;
    }
    #paneDivider::before {
      content: '';
      width: 44px;
      height: 4px;
      border-radius: 2px;
      background: #4a4a55;
      transition: background 0.12s, transform 0.08s;
    }
    #paneDivider.dragging::before,
    #paneDivider:active::before {
      background: var(--accent);
      transform: scaleX(1.2);
    }
    /* When dragging, JS sets inline max-height/height on .panel-right and
       removes the original 55vh cap. Make .panel-right resizable by giving
       it flex-shrink:0 so its inline height wins the column-flex layout. */
    .panel-right { flex-shrink: 0; }
  }
  /* Desktop default: divider hidden — only visible inside the mobile media
     query above where its display:flex applies. */
  #paneDivider { display: none; }
  @media (max-width: 768px) {
    #paneDivider { display: flex; }
  }

  /* ─────────────────────────────────────────────────────────────────
     MOBILE / PHONE LAYOUT REFLOW — chunk 2 of the mobile UI plan
     Width-based query (NOT capability-based — chunk 1 used hover/pointer
     for that). Triggers on phone viewports and narrow browser windows
     alike; desktop CSS at ≥768px is byte-identical because every rule
     below lives inside this @media block.
     ───────────────────────────────────────────────────────────── */
  @media (max-width: 768px) {
    /* iOS Safari zooms the viewport when focusing any input whose computed
       font-size is below 16px. Bump all text-like inputs/selects/textareas
       to 16px on phones so tapping a caption word doesn't zoom the page. */
    input[type="text"],
    input[type="search"],
    input[type="number"],
    input[type="email"],
    input:not([type]),
    select,
    textarea {
      font-size: 16px;
    }
    /* Specific ID selectors win specificity over the generic rule above;
       repeat them here so the iOS-zoom guard actually applies. */
    select#speedSelect { font-size: 16px; width: 56px; padding: 4px; }
    /* Loop button: bigger tap target on touch devices (Apple HIG recommends
       44pt minimum; 36px height + comfortable padding keeps it scrubber-sized
       without dominating the row). */
    button.loop-btn { padding: 8px 10px; min-height: 36px; }
    /* Jump-to-current button: 20px tall by default. Pad to 44 on touch
       so the bottom stats row stays tappable. The row itself grows a
       few px but the chunk list above scrolls anyway. */
    #jumpToCurrentBtn { padding: 8px 12px; min-height: 44px; font-size: 12px; }
    /* Transcribe modal clip list rows — 33px default, hard to tap on touch. */
    .ncl-item { min-height: 44px; display: flex; align-items: center; }
    /* Transcribe modal footer buttons — 35px default, both bumped to 44 on touch. */
    #ingestBtn, #newClipCancelBtn { min-height: 44px; }
    /* FX/SFX picker controls — header clear (~14px), settings reset (~13px),
       list items (~30px). All under HIG on touch. */
    .fp-clear, .fp-settings-reset { min-height: 44px; min-width: 44px; display: inline-flex; align-items: center; justify-content: center; }
    .fp-item { min-height: 44px; }
    /* Color reset (↺) for title-card + caption color — ~17×17 default. */
    .color-control-reset { min-height: 44px; min-width: 44px; }
    /* Click-to-edit number pills next to position sliders — ~14px default. */
    .pos-value { min-height: 44px; display: inline-flex; align-items: center; padding: 4px 8px; }
    /* Color-picker input — 22×22 default opens the native iOS picker on tap. */
    .color-control input[type=color] { width: 44px; height: 44px; }
    /* ── Body: stack panels vertically (preview on top) ──────────── */
    .body {
      flex-direction: column;
    }
    /* Preview pinned to top. 55vh gives the 9:16 portrait video real
       breathing room (was 45vh → 132px of wasted side-whitespace per
       edge on iPhone). Captions list still gets 45vh below. */
    .panel-right {
      width: 100%;
      flex: 0 0 auto;
      max-height: 55vh;
      order: 1;
      border-bottom: 1px solid var(--input-bg);
    }
    .panel-left {
      width: 100%;
      border-right: none;
      flex: 1 1 auto;
      min-height: 0;
      order: 3;
    }
    /* Trim preview chrome so the video can claim every available px. */
    .video-wrapper {
      padding: 6px 6px 3px;
      gap: 4px;
    }
    /* The desktop .video-container max-height is calc(100vh - 150px),
       which lets the 9:16 portrait container outgrow .panel-right's
       55vh on mobile — capping at 100% lets panel-right be the real
       boss, eliminating wasted whitespace flanking the video. */
    .video-container {
      max-height: 100%;
      box-shadow: 0 0 0 1.5px rgba(255,255,255,0.06),
                  0 8px 24px rgba(0,0,0,0.5);
    }

    /* ── Header: hide decorative title, compress search, icon-only btns ─ */
    header {
      padding: env(safe-area-inset-top) 8px 0;
      padding-left:  max(8px, env(safe-area-inset-left));
      padding-right: max(8px, env(safe-area-inset-right));
      gap: 4px;
      min-height: 48px;
      /* Mobile safety net: if action buttons plus search would still overflow
         (saveStatus has a long message, or browser zoom is on), let the
         header itself scroll horizontally instead of pushing Render
         off-screen with no way to reach it. */
      overflow-x: auto;
      overflow-y: hidden;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;
    }
    header::-webkit-scrollbar { display: none; }
    header h1 { display: none; }
    /* Status text shrinks (and truncates) rather than pushing buttons off. */
    .save-status {
      min-width: 0;
      max-width: 90px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    /* Keyboard-shortcut hint button — no keyboard on touch devices */
    #helpBtn { display: none; }
    /* Action buttons: hide text labels, keep SVG icons. font-size:0 hides
       the text node; SVGs have explicit width/height attrs so they're
       unaffected. Selector specificity must match existing `button#id`
       rules (1,0,1) to win the cascade. */
    button#newClipBtn,
    button#composeBtn,
    button#renderBtn {
      font-size: 0;
      padding: 0 10px;
      min-width: 44px;
      flex-shrink: 0;
    }

    /* Force the header-action slot to lay out horizontally. Without this,
       the slot's parent (.actions in clipflow-header's shadow DOM) is only
       ~75 px wide on a 393-px iPhone, so two 44-px buttons + the 4-px gap
       wrap to a second row. The 88-px stacked content then renders centered
       in the 57-px header — pushing the first button 16 px above the
       viewport (clipped) and the second below the header into the editor
       area. flex-wrap:nowrap pins both buttons on one line; the smaller
       in-slot button override below brings their width down enough to
       fit. The Transcribe + Render pair stays usable on touch instead of
       both being unreachable. */
    .editor-actions {
      display: flex;
      flex-direction: row;
      flex-wrap: nowrap;
      align-items: center;
      gap: 4px;
      min-width: 0;
    }
    /* Shrink the two visible buttons just enough to fit the cramped slot.
       36×36 sits below the 44×44 HIG floor but stays well above the
       practical hit-target threshold (~30 px) — and crucially is a
       reachable button instead of a clipped one. The selector specificity
       (0,2,1) beats the generic `button#X` rule (0,1,1) at line 1397, so
       this override wins the cascade regardless of source order. */
    .editor-actions button#newClipBtn,
    .editor-actions button#composeBtn,
    .editor-actions button#renderBtn {
      min-width: 36px;
      min-height: 36px;
      padding: 0 6px;
    }

    /* ── Tab bar: horizontal scroll as a safety net ──────────────── */
    .tab-bar {
      overflow-x: auto;
      overflow-y: hidden;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;       /* Firefox */
    }
    .tab-bar::-webkit-scrollbar { display: none; }
    .tab-btn {
      flex: 1 0 auto;
      min-width: 80px;
      white-space: nowrap;
    }

    /* ── Bottom-sheet pickers (chunk 3) ──────────────────────────────
       Each floating popover (#layoutPicker, #fxPicker, #sfxPicker,
       #emojiPopover, #timingPanel) gets pinned to the viewport bottom
       on mobile, full-width with rounded top corners + a drag-handle
       pill for affordance. JS sets inline top/left at click coords;
       !important overrides those so the sheet always anchors bottom.
       Close-on-outside-click handlers already in place still apply. */
    #layoutPicker,
    #fxPicker,
    #sfxPicker,
    #emojiPopover,
    #timingPanel {
      left:      0    !important;
      right:     0    !important;
      top:       auto !important;
      bottom:    0    !important;
      width:     100% !important;
      max-width: none !important;
      min-width: 0    !important;
      border-radius: 14px 14px 0 0;
      border-bottom: none;
      padding-bottom: max(16px, env(safe-area-inset-bottom));
      max-height: 70vh;
      overflow-y: auto;
    }
    /* Drag-handle pill at the top of each sheet — purely visual
       affordance that this is a bottom sheet. */
    #layoutPicker::before,
    #fxPicker::before,
    #sfxPicker::before,
    #emojiPopover::before,
    #timingPanel::before {
      content: '';
      display: block;
      width: 36px;
      height: 4px;
      border-radius: 2px;
      background: var(--border);
      margin: 6px auto 12px;
      flex-shrink: 0;
    }

    /* Touch-friendly sheet content ─────────────────────────────────── */
    .fp-item {
      padding: 12px 16px;
      font-size: 14px;
    }
    .lp-mode-btn {
      font-size: 11px;
      padding: 10px 6px;
    }
    /* Larger timing-panel inputs for finger-tap precision */
    .tp-val {
      width: 64px;
      height: 32px;
      font-size: 14px;
    }
    .tp-btn {
      font-size: 12px;
      padding: 8px 12px;
    }
    /* Emoji popover content scales up on mobile */
    #emojiPopoverInput { font-size: 24px; padding: 10px 12px; }
    .emoji-quick-btn { font-size: 20px; padding: 6px 8px; }
    .emoji-action-btn { font-size: 12px; padding: 10px 6px; }
    /* Desktop-only keyboard-shortcut hints: no physical keyboard on phones,
       these read as gibberish. Hide them on touch viewports. */
    #emojiPopoverHint,
    .tp-hint {
      display: none;
    }

    /* ── Font legibility bumps (chunk 4) ──────────────────────────────
       Anything below 12px is hard to read on a phone. Bump the worst
       offenders (tab labels, status bars, timing-panel labels) to a
       reasonable minimum without restructuring the layout. */
    .tab-btn               { font-size: 13px; }
    .tp-label              { font-size: 11px; }
    .tp-meta span          { font-size: 10px; }
    .captions-status       { font-size: 12px; }
    /* bulkLayoutPicker lives in the captionsStatus row beside the stats
       counter. Default desktop sizing overflows the 500px row on phones —
       hide the redundant "Layout →" label and shrink the mode buttons so
       the row never exceeds the viewport. */
    #bulkLayoutPicker .blp-label { display: none; }
    #bulkLayoutPicker .blp-btn   {
      font-size: 10px;
      padding: 4px 6px;
    }
    /* Also let the captionsStatus row wrap rather than overflow if the
       inputs ever still don't fit (e.g. a future layout adds buttons). */
    #captionsStatus {
      flex-wrap: wrap;
      row-gap: 4px;
    }
    .fp-title              { font-size: 11px; }
    .fp-clear              { font-size: 12px; }
    .fp-settings-row       { font-size: 12px; }
    .fp-settings-input     { font-size: 13px; }
    .scrubber-time         { font-size: 12px; }

    /* ── Desktop-view escape hatch ────────────────────────────────────
       Floating pill that swaps viewport meta to a fixed 1280px width,
       defeating the mobile @media rules so power users can drive the
       full desktop UI on a phone. Anchored to top-LEFT below the header
       — the right side has the LIVE PREVIEW / RENDERED badges inside
       the video container, which this would overlap if positioned right. */
    #desktopViewToggle {
      position: fixed;
      top: 56px;
      left: 6px;
      z-index: 9999;
      /* Apple HIG: 44pt minimum touch target. inline-flex keeps text vertically centered. */
      min-height: 44px;
      display: inline-flex;
      align-items: center;
      background: rgba(20,20,26,0.85);
      border: 1px solid rgba(58,58,68,0.6);
      border-radius: 14px;
      color: var(--text-3);
      font: 600 10px/1 ui-sans-serif, system-ui, sans-serif;
      padding: 6px 12px;
      cursor: pointer;
      box-shadow: 0 4px 12px rgba(0,0,0,0.35);
      backdrop-filter: blur(6px);
      -webkit-backdrop-filter: blur(6px);
    }
    #desktopViewToggle:active { transform: scale(0.94); }
  }

  /* ──────────────────────────────────────────────────────────────
     ≤480px: hide saveStatus on iPhone-SE / mini-class screens so the
     three action buttons (Transcribe + Compose + Render) always fit
     without a horizontal scroll. Flat top-level @media so it doesn't
     depend on CSS Nesting (iOS < 16.5). */
  @media (max-width: 480px) {
    .save-status { display: none !important; }
  }

  /* Desktop-view toggle is hidden by default (desktop). Mobile @media
     above sets position:fixed for it; this rule keeps it off-screen
     until that media query kicks in. */
  #desktopViewToggle { display: none; }
  @media (max-width: 768px) {
    #desktopViewToggle { display: inline-flex; }
  }
  /* When the user forces desktop view on a phone, hide the floating
     escape-hatch button — they can re-toggle via a long-press on the
     header H1 (see JS). The CSS class is added by the toggle handler. */
  body.force-desktop-view #desktopViewToggle { display: none; }
