/* ──────────────────────────────────────────────────────────────────────────
   editor-v2.css — the v2 editor layer (docs/design_handoff_editor_redesign).

   Loaded only by app/templates/index_v2.html, on top of editor.css /
   timeline.css / modals.css, and scoped to `body.ui-v2` so nothing here can
   reach the v1 editor. Two jobs:

     1. TOKENS. The redesign's palette (README § 12) as `--v2-*` properties,
        then a remap of the existing semantic tokens to them. The remap is the
        point: the caption rows, popovers, pickers and modals are still drawn
        by the shared JS against editor.css's `var(--surface)` / `var(--accent)`
        / … , so re-pointing those tokens repaints the whole editor from ONE
        palette instead of standing up a second one (README, "Fidelity").
     2. FRAME. Header · 72px rail · panel · stage · 132px timeline (§ 1).

   The tab bodies, stage internals and timeline tracks are still v1 markup or
   empty shells here — PRs 2–13 fill them in. Dark-only: the redesign specifies
   no light palette, so `html:not(.dark)` gets the same v2 values (the theme
   toggle in the shared header is a no-op under the v2 flag for now).
   ────────────────────────────────────────────────────────────────────────── */

  :root {
    /* ── Surfaces ── */
    --v2-page:          #08080a;   /* page background */
    --v2-panel:         #0e0e12;   /* header + panel */
    --v2-rail:          #0b0b0e;   /* tab rail */
    --v2-raised:        #17171d;
    --v2-raised-2:      #1a1a21;
    --v2-selected:      #1b1b23;   /* active rail tab / active nav link */
    --v2-popover:       #14141a;
    --v2-input:         #15151b;
    --v2-track:         #131319;   /* slider + timeline track */
    /* ── Borders ── */
    --v2-border-chrome: #1d1d24;
    --v2-border:        #23232c;
    --v2-border-input:  #26262f;
    --v2-border-btn:    #2c2c37;
    --v2-border-pop:    #2e2e3a;
    --v2-border-track:  #20202a;
    /* ── Text ── */
    --v2-text:          #ececf1;
    --v2-text-btn:      #d6d6de;
    --v2-text-2:        #9a9aa6;
    --v2-text-muted:    #7a7a86;
    --v2-text-label:    #65656f;
    --v2-text-faint:    #4f4f5a;
    /* ── Accent + semantic ── */
    --v2-accent:        #7c5cff;
    --v2-accent-link:   #8f79ff;
    --v2-accent-hover:  #b6a6ff;
    --v2-accent-tint:   rgba(124,92,255,0.14);
    --v2-fx:            #ffd60a;   /* emphasis / FX */
    --v2-positive:      #3ddc84;   /* trim-in */
    --v2-danger:        #ff4d6d;   /* trim-out */
    --v2-danger-text:   #ff7b8f;
    --v2-game:          #3a4a5c;
    --v2-game-2:        #5c7c9a;
    /* ── Radii (5 / 7 / 8 / 9 / 10 / 12 / 16) ── */
    --v2-r-1:  5px;
    --v2-r-2:  7px;
    --v2-r-3:  8px;
    --v2-r-4:  9px;
    --v2-r-5: 10px;
    --v2-r-6: 12px;
    --v2-r-7: 16px;
    /* ── Shadows ── */
    --v2-shadow-pop:   0 22px 60px rgba(0,0,0,0.65);
    --v2-shadow-strip: 0 6px 18px rgba(0,0,0,0.5);
    --v2-shadow-stage: 0 24px 70px rgba(0,0,0,0.6);
    /* ── Type. The prototype's Archivo / Space Mono are NOT adopted: they map
       to the stacks already in editor.css (body, #logOutput). Sizes, weights
       and tracking from the prototype still apply. Anton stays for the
       caption + title preview and is loaded by the template. ── */
    --v2-font-ui:   -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --v2-font-mono: "SF Mono", "Fira Code", monospace;
    /* ── Frame metrics (§ 1) ── */
    --v2-rail-w:      72px;
    --v2-toolbar-h:   48px;
    --v2-timeline-h: 132px;
  }

  /* ── Token remap ────────────────────────────────────────────────────────
     Both selectors are needed: editor.css defines the light palette on
     `html:not(.dark)`, which has the same specificity as `body.ui-v2`, and
     relying on file order alone to win that tie is the kind of thing that
     breaks the day someone reorders the <link>s. Listing it explicitly makes
     the v2 layer deterministic in either theme. --info/--info-2 and
     --accent-pale have no v2 counterpart and keep their v1 values.
     ─────────────────────────────────────────────────────────────────────── */
  body.ui-v2,
  html:not(.dark) body.ui-v2 {
    --bg:          var(--v2-page);
    --surface:     var(--v2-panel);
    --surface-2:   var(--v2-border-chrome);
    --hover:       var(--v2-raised);
    --input-bg:    var(--v2-input);
    --text:        var(--v2-text);
    --text-1:      var(--v2-text);
    --text-2:      var(--v2-text-2);
    --text-3:      var(--v2-text-btn);
    --text-muted:  var(--v2-text-muted);
    --text-quiet:  var(--v2-text-label);
    --border:      var(--v2-border-btn);
    --border-2:    var(--v2-border-pop);
    --accent:      var(--v2-accent);
    --accent-2:    var(--v2-accent-link);
    --accent-soft: var(--v2-accent-hover);
    --accent-bg:   var(--v2-accent-tint);
    --bg-2:        var(--v2-popover);
    --warning:     var(--v2-fx);
    --danger:      var(--v2-danger);
    --danger-2:    var(--v2-danger-text);
    --success:     var(--v2-positive);
    --success-2:   var(--v2-positive);
  }

  body.ui-v2 {
    font-family: var(--v2-font-ui);
    background: var(--v2-page);
    color: var(--v2-text);
  }

  /* ── Header ─────────────────────────────────────────────────────────────
     The shared <clipflow-header> stays (README § 16, item 14) — it owns the
     brand, the cross-service nav and the bell, and it's shadow-DOM, so only
     the host and our slotted `.editor-actions` children are ours to style.
     ─────────────────────────────────────────────────────────────────────── */
  body.ui-v2 clipflow-header {
    flex: none;
    background: var(--v2-panel);
    border-bottom: 1px solid var(--v2-border-chrome);
  }
  body.ui-v2 .v2-header-actions button {
    border-radius: var(--v2-r-3);
    font-family: var(--v2-font-ui);
  }
  body.ui-v2 .v2-header-actions #renderBtn:not(:disabled) {
    background: var(--v2-accent);
    border-color: var(--v2-accent);
    color: #fff;
    border-radius: var(--v2-r-4);
  }
  body.ui-v2 .v2-header-actions #saveStatus {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    letter-spacing: 0.06em;
  }

  /* ── Frame ── */
  body.ui-v2 .v2-body {
    background: var(--v2-page);
  }

  /* ── Rail — 72px, four tabs ─────────────────────────────────────────────
     The buttons keep `.tab-btn` so showTab() and the 1–4 shortcuts find them;
     these rules undo the horizontal tab-bar styling that comes with it.
     ─────────────────────────────────────────────────────────────────────── */
  body.ui-v2 .v2-rail {
    width: var(--v2-rail-w);
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 10px 0;
    background: var(--v2-rail);
    border-right: 1px solid var(--v2-border-chrome);
  }
  body.ui-v2 .v2-rail-btn {
    flex: none;
    width: 60px;
    padding: 9px 0 7px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    border: none;
    border-radius: var(--v2-r-5);
    background: transparent;
    color: var(--v2-text-muted);
    font-family: inherit;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: none;
    cursor: pointer;
    transition: background 0.12s, color 0.12s;
  }
  body.ui-v2 .v2-rail-btn:hover {
    background: var(--v2-raised);
    color: var(--v2-text);
  }
  body.ui-v2 .v2-rail-btn.active {
    background: var(--v2-selected);
    color: #fff;
    border-bottom-color: transparent;
  }
  body.ui-v2 .v2-rail-icon { flex: none; }
  body.ui-v2 .v2-rail-label { line-height: 1; }

  /* ── Panel ──────────────────────────────────────────────────────────────
     Width tracks the active tab (prototype: text 52%, script 48%, the rest
     42%). showTab() sets `display` inline on the tab panels, so :has() reads
     the active one without any new JS; a browser without :has() just keeps
     the narrow default. ui-v2.js can take this over if it ever needs to.
     ─────────────────────────────────────────────────────────────────────── */
  body.ui-v2 .panel-left {
    width: min(352px, 42%);
    flex: none;
    background: var(--v2-panel);
    border-right: 1px solid var(--v2-border-chrome);
  }
  body.ui-v2 .panel-left:has(> #tabCaptions:not([style*="none"])) { width: min(620px, 52%); }
  body.ui-v2 .panel-left:has(> #tabScript:not([style*="none"]))   { width: min(560px, 48%); }

  /* PERMANENT (load-bearing for the PR-8 cards): the cam/game cards single-
     column in v2's 352px panel — editor.css's two-column grid fits only the
     old 54% panel, and its collapse is keyed to the VIEWPORT (720px), not
     the panel width. */
  body.ui-v2 .lt-pane-grid { grid-template-columns: 1fr; }


  /* ── Preset rows (PR 2) ─────────────────────────────────────────────────
     Equal-width buttons fronting a hidden/advanced slider (README § 2):
     caption size S·M·L·XL, title duration 2.5·4·6·10s. Selected = purple
     ring + tint; no selection at all is a legal state (slider dragged off
     every preset value). Wiring lives in ui-v2.js.
     ─────────────────────────────────────────────────────────────────────── */
  body.ui-v2 .v2-preset-row {
    flex: 1;
    display: flex;
    gap: 7px;
    min-width: 0;
  }
  body.ui-v2 .v2-preset-btn {
    flex: 1;
    min-width: 0;
    padding: 8px 0;
    border: 1px solid var(--v2-border-btn);
    border-radius: var(--v2-r-4);
    background: var(--v2-input);
    color: var(--v2-text-btn);
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s, color 0.12s, box-shadow 0.12s;
  }
  body.ui-v2 .v2-preset-btn:hover {
    background: var(--v2-raised);
    color: var(--v2-text);
  }
  body.ui-v2 .v2-preset-btn.v2-active {
    border-color: var(--v2-accent);
    box-shadow: 0 0 0 1px var(--v2-accent);
    background: var(--v2-accent-tint);
    color: #fff;
  }

  /* ── Stage ── */
  body.ui-v2 .panel-right {
    flex: 1;
    min-width: 320px;
    display: flex;
    flex-direction: column;
    background: var(--v2-page);
  }
  body.ui-v2 .v2-stage-toolbar {
    height: var(--v2-toolbar-h);
    flex: none;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 18px;
    border-bottom: 1px solid var(--v2-popover);
    white-space: nowrap;
    overflow: hidden;
  }
  body.ui-v2 .v2-stage-spec {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    letter-spacing: 0.12em;
    color: var(--v2-text-label);
  }
  body.ui-v2 .v2-toolbar-sep {
    width: 1px;
    height: 18px;
    background: #1f1f27;
  }
  /* Safe-area toggle + cam/game chips land here in PR 7. */
  body.ui-v2 .v2-stage-tools { flex: 1; min-width: 0; }
  body.ui-v2 .v2-live {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: var(--v2-font-mono);
    font-size: 10px;
    letter-spacing: 0.06em;
    color: var(--v2-text-label);
  }
  body.ui-v2 .v2-live-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--v2-positive);
    animation: v2Pulse 2.4s ease-in-out infinite;
  }
  @keyframes v2Pulse { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } }

  /* ── Timeline — 132px, three tracks (shell; PR 10 fills it) ── */
  body.ui-v2 .v2-timeline {
    height: var(--v2-timeline-h);
    flex: none;
    display: flex;
    flex-direction: column;
    padding: 10px 18px 12px;
    background: var(--v2-rail);
    border-top: 1px solid var(--v2-border-chrome);
  }
  body.ui-v2 .v2-timeline-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 8px;
  }
  body.ui-v2 .v2-timeline-title {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    letter-spacing: 0.14em;
    color: var(--v2-text-label);
  }
  body.ui-v2 .v2-timeline-hint {
    margin-left: auto;
    font-family: var(--v2-font-mono);
    font-size: 10px;
    color: var(--v2-text-faint);
  }
  body.ui-v2 .v2-timeline-tracks {
    flex: 1;
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 5px;
  }
  body.ui-v2 .v2-track {
    position: relative;
    height: 22px;
    border-radius: var(--v2-r-2);
    background: var(--v2-track);
    border: 1px solid var(--v2-border-track);
  }
  body.ui-v2 .v2-track-audio { height: 34px; }
  body.ui-v2 .v2-track-label {
    position: absolute;
    left: 8px;
    top: 50%;
    transform: translateY(-50%);
    font-family: var(--v2-font-mono);
    font-size: 9px;
    letter-spacing: 0.08em;
    color: var(--v2-text-faint);
  }
  body.ui-v2 .v2-track-audio .v2-track-label { top: 3px; transform: none; }

  /* The injected sheet grab handles are mobile-only UI — as bare flex items
     they add gap dead-space to #layoutPicker/#timingPanel on desktop. */
  body.ui-v2 .v2-sheet-grab { display: none; }

  /* ── Mobile (PR 13, README § 17) ────────────────────────────────────────
     Breakpoint ≤768px, same as v1's reflow in modals.css (which stacks
     .panel-right over .panel-left — kept). The v2 additions: the rail
     becomes a FIXED BOTTOM tab bar, popovers present as bottom sheets,
     and every interactive target grows to ≥44px. The three-track timeline
     is desktop-only (§ 17) — the scrubber stands in. The "⇲ Desktop view"
     escape hatch is v1's, untouched.
     ─────────────────────────────────────────────────────────────────────── */
  @media (max-width: 768px) {
    body.ui-v2 .v2-timeline { display: none; }

    /* Rail → fixed bottom tab bar: same buttons (.tab-btn[data-tab] hooks),
       same icons, 10px labels, safe-area padding for the home indicator. */
    body.ui-v2 .v2-rail {
      position: fixed;
      left: 0; right: 0; bottom: 0;
      z-index: 300;
      width: 100%;
      flex-direction: row;
      justify-content: space-around;
      gap: 0;
      padding: 4px 4px calc(4px + env(safe-area-inset-bottom));
      border-right: none;
      border-top: 1px solid var(--v2-border-chrome);
      background: var(--v2-rail);
    }
    body.ui-v2 .v2-rail-btn { flex: 1; max-width: 110px; min-height: 48px; }
    /* The bar overlays the bottom — keep the panel's tail reachable. */
    body.ui-v2 .panel-left { padding-bottom: calc(64px + env(safe-area-inset-bottom)); }
    body.ui-v2 .v2-bulkbar { margin-bottom: 0; }

    /* Repeat the :has() selectors so the per-tab desktop widths, which are a
       specificity step above the bare `.panel-left` rule, don't survive. */
    body.ui-v2 .panel-left,
    body.ui-v2 .panel-left:has(> #tabCaptions:not([style*="none"])),
    body.ui-v2 .panel-left:has(> #tabScript:not([style*="none"])) {
      width: 100%;
      flex: 1 1 auto;
    }
    /* Give the stacked stage back its content-sized row (the desktop flex:1
       would let the caption list squeeze the preview to nothing). */
    body.ui-v2 .panel-right { flex: 0 0 auto; min-width: 0; }

    /* Shortcuts are pointless without a keyboard (§ 17) — hide on touch. */
    body.ui-v2 .v2-header-actions #helpBtn { display: none; }

    /* ── Hit targets ≥ 44px (§ 17): visual size may stay, touch box grows. ── */
    body.ui-v2 .v2-preset-btn,
    body.ui-v2 .v2-bulk-btn,
    body.ui-v2 .v2-strip-btn,
    body.ui-v2 .v2-mini-btn,
    body.ui-v2 .v2-step-btn,
    body.ui-v2 .v2-obj-eye,
    body.ui-v2 .v2-safe-toggle { min-height: 44px; min-width: 44px; }
    body.ui-v2 .v2-ws-btn { min-width: 44px; height: 44px; }
    body.ui-v2 .v2-swatch { width: 44px; height: 44px; }   /* § 17: margin doesn't count toward the touch box */
    body.ui-v2 .word-chip { min-height: 44px; }
    body.ui-v2 .v2-obj-row { min-height: 48px; }
    body.ui-v2 .v2-music-row { min-height: 48px; }

    /* ── Popovers → bottom sheets (§ 17): full width, docked, one look.
       The pickers' own JS positions them with inline left/top, so the
       overrides must be !important. Content is unchanged; a grab notch is
       drawn and ui-v2.js adds drag-to-dismiss. ── */
    body.ui-v2 #layoutPicker,
    body.ui-v2 #fxPicker,
    body.ui-v2 #sfxPicker,
    body.ui-v2 #timingPanel,
    body.ui-v2 #emojiPopover,
    body.ui-v2 .emph-dial-popover {
      position: fixed !important;
      left: 0 !important;
      right: 0 !important;
      top: auto !important;
      bottom: 0 !important;
      width: auto !important;
      max-width: none !important;
      max-height: 70vh !important;   /* _positionPicker sets an anchor-derived inline maxHeight (as small as 80px) */
      overflow-y: auto;
      border-radius: 16px 16px 0 0 !important;   /* the later § 8 chrome's 13px would win otherwise */
      padding-top: 26px;
      padding-bottom: calc(12px + env(safe-area-inset-bottom));
      z-index: 320;
      touch-action: pan-y;
    }
    body.ui-v2 #layoutPicker::before,
    body.ui-v2 #fxPicker::before,
    body.ui-v2 #sfxPicker::before,
    body.ui-v2 #timingPanel::before,
    body.ui-v2 #emojiPopover::before,
    body.ui-v2 .emph-dial-popover::before {
      content: "";
      position: absolute;
      top: 8px;
      left: 50%;
      transform: translateX(-50%);
      width: 36px;
      height: 4px;
      border-radius: 2px;
      background: var(--v2-border-pop);
    }
    /* The word strip opens on tap (pointerover fires on touch taps) — keep
       it above the sheet stack and inside the viewport. */
    body.ui-v2 .v2-word-strip { z-index: 330; }

    /* Pinch shield (round-1 Critical): without this the browser claims any
       two-finger gesture on the stage as page zoom/scroll and pointercancels
       the module's tracking before a single scale step applies. Safe — the
       app shell is overflow:hidden, no page scroll starts on the stage. */
    body.ui-v2 #videoContainer { touch-action: none; }

    /* Real grab handles (ui-v2.js injects them): pseudo-element notches
       can't opt out of the sheet's pan-y, so the drag-to-dismiss gesture
       needs an element with touch-action none. The visual notch stays the
       ::before. */
    body.ui-v2 .v2-sheet-grab {
      display: block;
      position: absolute;
      top: 0; left: 0; right: 0;
      height: 30px;
      touch-action: none;
      z-index: 1;
      cursor: grab;
    }

    /* The emphasis dial's base design is deliberately container-less (§ 8
       excludes it from the desktop chrome) — as a SHEET it needs a real
       surface and centering, and its content is tap-only (no inner scroll),
       so the whole sheet can refuse browser panning. */
    body.ui-v2 .emph-dial-popover {
      background: var(--v2-popover) !important;
      border-top: 1px solid var(--v2-border-pop) !important;
      display: flex;
      justify-content: center;
      padding: 26px 0 calc(16px + env(safe-area-inset-bottom)) !important;
      touch-action: none;
    }

    /* v1's render-log drawer is fixed-bottom at z-100 — lift it above the
       z-300 tab bar's footprint. */
    body.ui-v2 #logDrawer { bottom: calc(56px + env(safe-area-inset-bottom)); }
  }

  /* ── Overlay tab (PR 3) — object list + object panels ───────────────────
     README § 2. All rules flag-scoped; the v1 controls inside keep their
     editor.css styling except where the new chrome overrides it.
     ─────────────────────────────────────────────────────────────────────── */
  body.ui-v2 #tabOverlay { padding: 0 0 18px; }

  body.ui-v2 .v2-objlist {
    padding: 16px 18px 14px;
    border-bottom: 1px solid var(--v2-raised-2);
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  body.ui-v2 .v2-objlist-label,
  body.ui-v2 .v2-sec-label {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--v2-text-label);
    margin: 14px 0 5px;
  }
  body.ui-v2 .v2-objlist-label { margin: 0 0 5px; }

  body.ui-v2 .v2-obj-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    border-radius: var(--v2-r-5);
    border: 1px solid var(--v2-border);
    background: transparent;
    cursor: pointer;
    transition: border-color 0.12s, background 0.12s;
  }
  body.ui-v2 .v2-obj-row:hover { border-color: #33333f; }
  body.ui-v2 .v2-obj-row.v2-obj-selected {
    border-color: var(--v2-accent);
    background: var(--v2-accent-tint);
  }
  body.ui-v2 .v2-obj-row.v2-obj-dim .v2-obj-body { opacity: 0.45; }
  body.ui-v2 .v2-obj-glyph {
    width: 22px;
    height: 22px;
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    background: #22222b;
    color: #8a8a96;
    font-family: var(--v2-font-mono);
    font-size: 11px;
    font-weight: 700;
  }
  body.ui-v2 .v2-obj-selected .v2-obj-glyph { background: var(--v2-accent); color: #fff; }
  body.ui-v2 .v2-obj-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  body.ui-v2 .v2-obj-name {
    font-size: 13px;
    font-weight: 600;
    color: #c9c9d4;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  body.ui-v2 .v2-obj-selected .v2-obj-name { color: #fff; }
  body.ui-v2 .v2-obj-meta {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    color: var(--v2-text-label);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  body.ui-v2 .v2-obj-eye {
    width: 24px;
    height: 24px;
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 6px;
    background: transparent;
    cursor: pointer;
  }
  body.ui-v2 .v2-obj-eye:hover { background: #22222c; }
  body.ui-v2 .v2-eye-dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 2px solid var(--v2-accent);
    background: var(--v2-accent);
    transition: background 0.12s, border-color 0.12s;
  }
  body.ui-v2 .v2-obj-eye.v2-eye-off .v2-eye-dot { border-color: #3d3d49; background: transparent; }

  /* Auto-edit card */
  body.ui-v2 .v2-autoedit {
    margin-top: 4px;
    padding: 10px 11px;
    border-radius: var(--v2-r-5);
    background: #101015;
    border: 1px solid #1f1f27;
    display: flex;
    align-items: center;
    gap: 10px;
  }
  body.ui-v2 .v2-autoedit-body { flex: 1; min-width: 0; }
  body.ui-v2 .v2-autoedit-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 600;
    color: #c9c9d4;
  }
  body.ui-v2 .v2-autoedit-bolt { color: var(--v2-positive); }
  body.ui-v2 .v2-autoedit-sum {
    font-family: var(--v2-font-mono);
    font-size: 9.5px;
    color: var(--v2-text-label);
    margin-top: 2px;
  }
  body.ui-v2 .v2-autoedit-rerun {
    flex: none;
    padding: 7px 10px;
    border-radius: var(--v2-r-3);
    border: 1px solid var(--v2-border-btn);
    background: var(--v2-raised);
    color: var(--v2-text-btn);
    font-family: inherit;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
  }
  body.ui-v2 .v2-autoedit-rerun:hover { background: #22222b; }

  /* Object panels */
  body.ui-v2 .v2-obj-panel {
    padding: 2px 18px 8px;
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  body.ui-v2 .v2-obj-panel .pos-row { margin: 0; }

  /* Theme grid — live mini-swatches per theme */
  body.ui-v2 .v2-theme-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 7px;
  }
  body.ui-v2 .v2-theme-grid .title-theme-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 8px 4px 7px;
    border: 1px solid var(--v2-border-btn);
    border-radius: var(--v2-r-4);
    background: var(--v2-input);
    color: var(--v2-text-btn);
    font-family: inherit;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
  }
  body.ui-v2 .v2-theme-grid .title-theme-btn:hover { background: var(--v2-raised); }
  body.ui-v2 .v2-theme-grid .title-theme-btn.ttheme-active {
    border-color: var(--v2-accent);
    box-shadow: 0 0 0 1px var(--v2-accent);
    background: var(--v2-accent-tint);
    color: #fff;
  }
  body.ui-v2 .v2-theme-chip {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 26px;
    border-radius: 6px;
    background: #1b1b23;
    font-family: Anton, Impact, sans-serif;
    font-size: 11px;
    letter-spacing: 0.04em;
  }
  body.ui-v2 .v2-theme-classic { color: #ffe020; -webkit-text-stroke: 0.5px #fff; }
  body.ui-v2 .v2-theme-boxed   { color: #fff; background: #1b1b23; }
  body.ui-v2 .v2-theme-boxed::before { content: ""; }
  body.ui-v2 .v2-theme-comic   { color: #ffe020; text-shadow: 1.5px 1.5px 0 #000; }
  body.ui-v2 .v2-theme-minimal { color: #ececf1; font-weight: 400; letter-spacing: 0.12em; }

  /* Swatch rows */
  body.ui-v2 .v2-swatch-row {
    display: flex;
    align-items: center;
    gap: 7px;
    flex-wrap: wrap;
  }
  body.ui-v2 .v2-swatch {
    width: 34px;
    height: 34px;
    flex: none;
    border-radius: var(--v2-r-4);
    border: 1px solid rgba(255,255,255,0.12);
    cursor: pointer;
    padding: 0;
  }
  body.ui-v2 .v2-swatch:hover { transform: translateY(-1px); }
  body.ui-v2 .v2-swatch.v2-swatch-active {
    outline: 2px solid var(--v2-accent);
    outline-offset: 2px;
  }
  body.ui-v2 .v2-swatch-row .color-control { margin-left: auto; }

  /* Cards + switches */
  body.ui-v2 .v2-card {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 11px;
    border-radius: var(--v2-r-5);
    border: 1px solid var(--v2-border);
    background: var(--v2-input);
  }
  body.ui-v2 .v2-card-label { cursor: pointer; }
  body.ui-v2 .v2-card-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 12px;
    font-weight: 600;
    color: #c9c9d4;
  }
  body.ui-v2 .v2-card-hint {
    font-size: 10.5px;
    font-weight: 400;
    color: var(--v2-text-muted);
  }
  body.ui-v2 .v2-switch,
  body.ui-v2 input.v2-switch-chk {
    appearance: none;
    -webkit-appearance: none;
    width: 34px;
    height: 20px;
    flex: none;
    border: none;
    border-radius: 999px;
    background: #2b2b36;
    position: relative;
    cursor: pointer;
    transition: background 0.15s;
    margin: 0;
  }
  body.ui-v2 .v2-switch::after,
  body.ui-v2 input.v2-switch-chk::after {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: #fff;
    transition: transform 0.15s;
  }
  body.ui-v2 .v2-switch.v2-switch-on,
  body.ui-v2 input.v2-switch-chk:checked { background: var(--v2-accent); }
  body.ui-v2 .v2-switch.v2-switch-on::after,
  body.ui-v2 input.v2-switch-chk:checked::after { transform: translateX(14px); }

  body.ui-v2 .v2-mini-btn {
    flex: none;
    padding: 7px 12px;
    border-radius: var(--v2-r-3);
    border: 1px solid var(--v2-border-btn);
    background: var(--v2-raised);
    color: var(--v2-text-btn);
    font-family: inherit;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
  }
  body.ui-v2 .v2-mini-btn:hover { background: #22222b; color: #fff; }
  body.ui-v2 .v2-mini-danger { color: var(--v2-danger-text); border-color: #3a232b; }
  body.ui-v2 .v2-mini-danger:hover { background: rgba(255,77,109,0.12); }

  /* Style cards (Box / Karaoke) */
  body.ui-v2 .v2-style-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
  body.ui-v2 .v2-style-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
    padding: 10px 6px 8px;
    border: 1px solid var(--v2-border-btn) !important;
    border-radius: var(--v2-r-4);
    background: var(--v2-input);
    color: var(--v2-text-btn);
    font-size: 12px;
    font-weight: 600;
  }
  body.ui-v2 .v2-style-card.seg-active {
    border-color: var(--v2-accent) !important;
    box-shadow: 0 0 0 1px var(--v2-accent);
    background: var(--v2-accent-tint);
    color: #fff;
  }
  body.ui-v2 .v2-style-demo {
    font-family: Anton, Impact, sans-serif;
    font-size: 13px;
    letter-spacing: 0.05em;
    padding: 4px 9px;
    border-radius: 6px;
  }
  body.ui-v2 .v2-demo-box { background: #50ff1e; color: #08080a; }
  body.ui-v2 .v2-demo-karaoke { color: #fff; text-shadow: 0 0 1px #fff; background: #1b1b23; }

  /* Censor segmented + hints */
  body.ui-v2 .v2-censor-seg { display: flex; gap: 7px; }
  body.ui-v2 .v2-censor-seg .seg-control-btn { flex: 1; }
  body.ui-v2 .v2-hint {
    font-size: 11px;
    color: var(--v2-text-muted);
  }
  body.ui-v2 .v2-hint-note { margin-top: 8px; }

  /* SHOW EXACT VALUES disclosure */
  body.ui-v2 .v2-exact { margin-top: 8px; }
  body.ui-v2 .v2-exact summary {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    letter-spacing: 0.12em;
    color: var(--v2-text-label);
    cursor: pointer;
    user-select: none;
    padding: 4px 0;
  }
  body.ui-v2 .v2-exact summary:hover { color: var(--v2-text-2); }
  body.ui-v2 .v2-exact[open] { padding-bottom: 4px; }

  /* Music list */
  body.ui-v2 .v2-music-list { display: flex; flex-direction: column; gap: 6px; }
  body.ui-v2 .v2-music-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    border-radius: var(--v2-r-5);
    border: 1px solid var(--v2-border);
    cursor: pointer;
  }
  body.ui-v2 .v2-music-row:hover { border-color: #33333f; }
  body.ui-v2 .v2-music-row.v2-music-sel {
    border-color: var(--v2-accent);
    background: var(--v2-accent-tint);
    cursor: default;
  }
  body.ui-v2 .v2-music-eq {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    width: 26px;
    height: 16px;
    flex: none;
  }
  body.ui-v2 .v2-music-eq i {
    flex: 1;
    background: #4a4a5a;
    border-radius: 1px;
    height: 40%;
  }
  body.ui-v2 .v2-music-eq i:nth-child(2) { height: 90%; }
  body.ui-v2 .v2-music-eq i:nth-child(3) { height: 60%; }
  body.ui-v2 .v2-music-eq i:nth-child(4) { height: 75%; }
  body.ui-v2 .v2-music-sel .v2-music-eq i { background: var(--v2-accent-hover); }
  body.ui-v2 .v2-music-name {
    flex: 1;
    min-width: 0;
    font-size: 13px;
    font-weight: 600;
    color: #c9c9d4;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  body.ui-v2 .v2-music-sel .v2-music-name { color: #fff; }
  body.ui-v2 .v2-music-sum {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    color: var(--v2-text-2);
    flex: none;
  }
  body.ui-v2 .v2-music-expand {
    margin: -2px 0 4px;
    padding: 10px 11px;
    border-radius: 0 0 var(--v2-r-5) var(--v2-r-5);
    border: 1px solid var(--v2-border);
    border-top: none;
    background: #101015;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
  body.ui-v2 .v2-wave {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 34px;
    padding: 3px 4px;
    border-radius: var(--v2-r-2);
    background: var(--v2-track);
    border: 1px solid var(--v2-border-track);
    cursor: ew-resize;
    touch-action: none;
  }
  body.ui-v2 .v2-wave i { flex: 1; background: #5a5a72; border-radius: 1px; min-height: 12%; }
  body.ui-v2 .v2-wave i.v2-wave-skip { background: #33333f; }
  body.ui-v2 .v2-upload-dashed {
    margin-top: 8px;
    width: 100%;
    justify-content: center;
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 9px 0;
    border: 1px dashed var(--v2-border-btn);
    border-radius: var(--v2-r-5);
    background: transparent;
    color: var(--v2-text-2);
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
  }
  body.ui-v2 .v2-upload-dashed:hover { color: #fff; border-color: var(--v2-text-faint); }

  /* Review fixes (PR 3): _syncTitleThemeUI (fx-picker.js) re-reveals the
     legacy Motion row for the classic theme on every clip load by clearing
     its inline display — in v2 the On/Off switch card is the Motion UI, so
     the raw select row must stay hidden no matter what the shared JS writes. */
  body.ui-v2 #titleMotionRow { display: none !important; }

  /* The Volume/Start rows moved inside #v2MusicExpand, so their row layout
     lives here (v1's `.music-row .music-vol` rules in editor.css are gone). */
  body.ui-v2 .v2-music-expand .music-vol {
    display: flex;
    align-items: center;
    gap: 10px;
  }
  body.ui-v2 .v2-music-expand .music-vol .pos-label { min-width: 44px; }
  body.ui-v2 .v2-music-expand .music-vol .pos-slider { flex: 1 1 auto; }

  /* ── Text tab (PR 4) — caption row list (README § 3) ────────────────────
     Restyle of the JS-rendered rows: the markup is v1's (timeline.js /
     transcript.js render functions), with three tiny flag-gated additions
     (trim-banner note, gap SILENCE label, footer counts). Anatomy:
     | accent bar | layout chip | FX chip | times | word chips | eye |
     ─────────────────────────────────────────────────────────────────────── */
  body.ui-v2 .captions-list { padding: 10px 14px; gap: 7px; }

  body.ui-v2 .chunk-row {
    background: var(--v2-input);
    border: 1px solid var(--v2-border);
    border-left: 0;
    border-radius: var(--v2-r-5);
    padding: 7px 12px 7px 16px;
    gap: 8px;
    overflow: hidden;   /* keeps the accent bar's square ends inside the radius */
  }
  body.ui-v2 .chunk-row:hover { border-color: #33333f; }
  /* Accent bar — 3px, colored by STATE. This retargets v1's ::before, which
     modals.css uses as the per-layout "lane" strip — in v2 the layout signal
     lives on the chip diagram instead, and these higher-specificity rules
     win the cascade on every chunk row. overflow keeps the bar's square ends
     inside the 10px-radius outline (the ::after playhead sits at left:4px,
     unaffected; the ⚡ chip badge stays within the row box). */
  body.ui-v2 .chunk-row::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 3px;
    border-radius: 3px 0 0 3px;
    background: #2a2a35;
  }
  body.ui-v2 .chunk-row.row-selected { background: var(--v2-accent-tint); border-color: var(--v2-accent); }
  body.ui-v2 .chunk-row.row-selected::before { background: var(--v2-accent); }
  body.ui-v2 .chunk-row.row-playing::before  { background: var(--v2-positive); }
  body.ui-v2 .chunk-row.active { border-color: var(--v2-border-pop); background: var(--v2-raised); }
  body.ui-v2 .chunk-row.chunk-hidden { opacity: 0.42; }
  body.ui-v2 .chunk-row.chunk-hidden::before { background: var(--v2-text-faint); }

  /* Layout chip — 30×26 mini diagram drawn from the li-* classes; the text
     glyph is hidden (the title attribute keeps the a11y name). */
  body.ui-v2 .layout-indicator {
    width: 30px;
    height: 26px;
    flex: none;
    padding: 2px;
    border: 1px solid var(--v2-border-btn);
    border-radius: var(--v2-r-2);
    background: var(--v2-track);
    color: transparent;
    font-size: 0;
    position: relative;
    overflow: visible;
    cursor: pointer;
  }
  body.ui-v2 .layout-indicator::before {
    content: "";
    position: absolute;
    inset: 3px;
    border-radius: 4px;
    /* split default: cam 44 / game 56 */
    background: linear-gradient(180deg, var(--v2-accent-hover) 0 44%, var(--v2-game-2) 44% 100%);
  }
  body.ui-v2 .layout-indicator.li-zoom::before { background: linear-gradient(180deg, var(--v2-accent-hover) 0 65%, var(--v2-game-2) 65% 100%); }
  body.ui-v2 .layout-indicator.li-full::before { background: var(--v2-accent-hover); }
  body.ui-v2 .layout-indicator.li-gf::before   { background: linear-gradient(180deg, var(--v2-accent-hover) 0 35%, var(--v2-game-2) 35% 100%); }
  body.ui-v2 .layout-indicator.li-os::before   { background: linear-gradient(135deg, #f59e0b, #b45309); }
  body.ui-v2 .layout-indicator:hover { border-color: var(--v2-text-faint); }
  /* ⚡ auto-edit badge (li-auto = heuristic/smoothed/claude sources). § 3
     specifies one green badge — v1's blue li-claude variant merges into it
     deliberately, not a regression. */
  body.ui-v2 .layout-indicator.li-auto::after {
    content: "⚡";
    position: absolute;
    right: -5px;
    top: -6px;
    font-size: 9px;
    color: var(--v2-positive);
    text-shadow: 0 0 3px rgba(0,0,0,0.9);
  }

  /* FX chip — 26px, yellow when the row has an effect. */
  body.ui-v2 .fx-indicator {
    width: 26px;
    height: 26px;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--v2-border-btn);
    border-radius: var(--v2-r-2);
    background: transparent;
    color: var(--v2-text-faint);
    cursor: pointer;
  }
  body.ui-v2 .fx-indicator:hover { color: var(--v2-text-2); border-color: var(--v2-text-faint); }
  body.ui-v2 .fx-indicator.fx-active {
    color: var(--v2-fx);
    border-color: rgba(255,214,10,0.4);
    background: rgba(255,214,10,0.08);
  }
  /* The v1 alignment placeholder has no place in the v2 anatomy. */
  body.ui-v2 .chunk-row .sfx-placeholder { display: none; }

  body.ui-v2 .chunk-time {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    color: var(--v2-text-label);
    min-width: 108px;
  }
  body.ui-v2 .chunk-dur { font-size: 9px; color: var(--v2-text-faint); }

  body.ui-v2 .word-chip { border-radius: var(--v2-r-2); }
  body.ui-v2 .word-input { font-size: 14px; font-weight: 600; }

  body.ui-v2 .hide-btn { color: var(--v2-text-faint); }
  body.ui-v2 .hide-btn:hover { color: var(--v2-text); background: rgba(255,255,255,0.06); }

  /* Gap rows — dashed SILENCE dividers with the Split affordance. */
  body.ui-v2 .gap-row {
    background: transparent;
    border: 1px dashed var(--v2-border-btn);
    border-radius: var(--v2-r-2);
  }
  body.ui-v2 .gap-row:hover { border-color: var(--v2-text-faint); }
  /* v1's layout-lane ::before would poke a solid 4px strip through the
     dashed divider's rounded corners — the chip carries the layout in v2. */
  body.ui-v2 .gap-row::before { display: none; }
  /* State backgrounds: modals.css declares these with !important (to beat
     its own layout banding), so the v2 palette must too — without it the
     selected states silently render v1's opaque indigo. */
  body.ui-v2 .chunk-row.row-selected { background: var(--v2-accent-tint) !important; }
  body.ui-v2 .chunk-row.row-looping  { background: rgba(124,92,255,0.10) !important; }
  body.ui-v2 .gap-row.gap-selected     { border-color: var(--v2-accent); background: var(--v2-accent-tint) !important; }
  body.ui-v2 .gap-row.gap-selected.cut { border-color: var(--v2-accent); background: rgba(124,92,255,0.20) !important; }
  body.ui-v2 .gap-row.cut              { border-color: var(--v2-danger); background: rgba(255,77,109,0.08) !important; }
  body.ui-v2 .gap-label {
    font-family: var(--v2-font-mono);
    font-size: 9.5px;
    color: var(--v2-text-label);
  }
  body.ui-v2 .gap-kind {
    display: inline-block;
    margin-right: 8px;
    padding: 1px 6px;
    border-radius: 4px;
    background: var(--v2-raised);
    color: var(--v2-text-muted);
    letter-spacing: 0.1em;
    font-size: 8.5px;
    font-weight: 700;
  }
  body.ui-v2 .gap-row.cut .gap-kind { color: var(--v2-danger-text); background: rgba(255,77,109,0.1); }

  /* Trim banners — v2 palette + the plain-language note (README § 3). The
     colors ride the token remap (--success/--danger → v2 values); this block
     adds the mono label treatment and the note. */
  body.ui-v2 .trim-marker {
    font-family: var(--v2-font-mono);
    letter-spacing: 0.1em;
    border-radius: var(--v2-r-1);
  }
  body.ui-v2 .trim-in-marker  { background: rgba(61,220,132,0.07);
                                border-top-color: rgba(61,220,132,0.3); border-bottom-color: rgba(61,220,132,0.3); }
  body.ui-v2 .trim-out-marker { background: rgba(255,77,109,0.06);
                                border-top-color: rgba(255,77,109,0.3); border-bottom-color: rgba(255,77,109,0.3); }
  body.ui-v2 .trim-marker-note {
    margin-left: auto;
    font-family: var(--v2-font-ui);
    font-size: 10.5px;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    opacity: 0.65;
  }

  /* Footer — mono counts + Jump to current. */
  body.ui-v2 .captions-status {
    border-top: 1px solid var(--v2-border-chrome);
    background: var(--v2-panel);
  }
  body.ui-v2 #captionsStats {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    letter-spacing: 0.04em;
    color: var(--v2-text-label);
    display: flex;
    gap: 0;
  }
  body.ui-v2 #captionsStats span + span::before { content: "·"; margin: 0 7px; color: var(--v2-text-faint); }
  body.ui-v2 #captionsStats .cs-cuts { color: var(--v2-accent-link); }
  body.ui-v2 #captionsStats .cs-hidden { color: var(--v2-fx); }
  body.ui-v2 #captionsStats .cs-out { color: var(--v2-positive); }

  /* ── Bulk bar (PR 5) — docks above the footer at 2+ selected rows ─────── */
  body.ui-v2 #bulkLayoutPicker { display: none !important; }  /* v2 surface is the bulk bar */
  body.ui-v2 .v2-bulkbar {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 8px 14px;
    border-top: 1px solid var(--v2-accent);
    background: linear-gradient(180deg, rgba(124,92,255,0.10), rgba(124,92,255,0.04));
    flex-shrink: 0;
  }
  body.ui-v2 .v2-bulkbar[hidden] { display: none; }
  body.ui-v2 .v2-bulkbar-count {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    letter-spacing: 0.06em;
    color: var(--v2-accent-hover);
    margin-right: 4px;
    white-space: nowrap;
  }
  body.ui-v2 .v2-bulk-btn {
    padding: 6px 11px;
    border: 1px solid var(--v2-border-btn);
    border-radius: var(--v2-r-3);
    background: var(--v2-raised);
    color: var(--v2-text-btn);
    font-family: inherit;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
  }
  body.ui-v2 .v2-bulk-btn:hover:not(:disabled) { background: #22222b; color: #fff; }
  body.ui-v2 .v2-bulk-btn:disabled { opacity: 0.4; cursor: default; }
  body.ui-v2 .v2-bulk-clear { margin-left: auto; color: var(--v2-text-muted); }

  /* ── Per-word hover strip (PR 6) ────────────────────────────────────────
     Floating toolbar over the hovered word chip; popover surface + the
     strip shadow from § 12. The v1 in-chip buttons stay as the touch/v1
     surface — the strip is additive. ─────────────────────────────────── */
  body.ui-v2 .v2-word-strip {
    position: fixed;
    z-index: 260;
    display: flex;
    align-items: center;
    gap: 3px;
    padding: 5px 6px;
    border-radius: var(--v2-r-4);
    background: var(--v2-popover);
    border: 1px solid var(--v2-border-pop);
    box-shadow: var(--v2-shadow-strip);
  }
  body.ui-v2 .v2-word-strip[hidden] { display: none; }
  body.ui-v2 .v2-ws-btn {
    min-width: 26px;
    height: 26px;
    padding: 0 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: var(--v2-r-2);
    background: transparent;
    color: var(--v2-text-2);
    font-family: inherit;
    font-size: 12px;
    cursor: pointer;
  }
  body.ui-v2 .v2-ws-btn:hover { background: var(--v2-raised); color: #fff; }
  body.ui-v2 .v2-ws-btn.v2-ws-on {
    color: var(--v2-fx);
    background: color-mix(in srgb, var(--v2-fx) 10%, transparent);   /* visible even on <img> content */
  }
  body.ui-v2 .v2-ws-dur {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    color: var(--v2-text-btn);
    border-right: 1px solid var(--v2-border);
    border-radius: var(--v2-r-2) 0 0 var(--v2-r-2);
    padding-right: 8px;
    margin-right: 2px;
  }
  /* The ↕ line-break affordance between chips: v1's .split-btn, restyled to
     read as the deliberate break control the design draws between words. */
  body.ui-v2 .chunk-words .split-btn {
    opacity: 0;
    transition: opacity 0.12s;
  }
  body.ui-v2 .chunk-row:hover .chunk-words .split-btn { opacity: 0.55; }
  body.ui-v2 .chunk-words .split-btn:hover { opacity: 1; color: var(--v2-accent-hover); }
  body.ui-v2 .chunk-words .split-btn.active { opacity: 1; color: var(--v2-accent); }

  /* ── Stage overlay (PR 7, README § 6) ───────────────────────────────────
     Root is pointer-events:none; only boxes/strips/toggle take input. All
     geometry is inline (ui-v2.js positions from the sliders). ──────────── */
  body.ui-v2 .v2-stage-ovl {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 5;
    overflow: hidden;
  }
  body.ui-v2 .v2-safe { position: absolute; inset: 0; }
  body.ui-v2 .v2-safe-frame {
    position: absolute;
    inset: 4%;
    border: 1.5px dashed rgba(182,166,255,0.45);
    border-radius: 8px;
  }
  body.ui-v2 .v2-safe-band {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 16%;
    background: repeating-linear-gradient(135deg, rgba(182,166,255,0.10) 0 7px, transparent 7px 14px);
    border-top: 1px dashed rgba(182,166,255,0.4);
  }
  body.ui-v2 .v2-safe-label {
    position: absolute;
    right: 8px; top: 6px;
    font-family: var(--v2-font-mono);
    font-size: 9px;
    letter-spacing: 0.08em;
    color: rgba(180,168,255,0.7);
  }
  body.ui-v2 .v2-snap { position: absolute; background: var(--v2-accent); opacity: 0.8; }
  body.ui-v2 .v2-snap-v { left: 50%; top: 0; bottom: 0; width: 1px; transform: translateX(-0.5px); }
  body.ui-v2 .v2-snap-h { top: 50%; left: 0; right: 0; height: 1px; transform: translateY(-0.5px); }

  body.ui-v2 .v2-objbox {
    position: absolute;
    pointer-events: auto;
    border: 1.5px solid transparent;
    border-radius: 9px;
    cursor: move;
    touch-action: none;
  }
  body.ui-v2 .v2-objbox:hover { border-color: rgba(124,92,255,0.45); }
  body.ui-v2 .v2-objbox.v2-objbox-sel { border-color: var(--v2-accent); }
  body.ui-v2 .v2-objbox-dot {
    position: absolute;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--v2-accent);
    display: none;
  }
  body.ui-v2 .v2-objbox-sel .v2-objbox-dot { display: block; }
  body.ui-v2 .v2-dot-tl { left: -3px; top: -3px; }
  body.ui-v2 .v2-dot-tr { right: -3px; top: -3px; }
  body.ui-v2 .v2-dot-bl { left: -3px; bottom: -3px; }
  body.ui-v2 .v2-objbox-resize {
    position: absolute;
    right: -7px; bottom: -7px;
    width: 12px; height: 12px;
    border-radius: 50%;
    background: #fff;
    border: 2px solid var(--v2-accent);
    cursor: nwse-resize;
    padding: 0;
    display: none;
    touch-action: none;
  }
  body.ui-v2 .v2-objbox-sel .v2-objbox-resize { display: block; }

  /* Travel strip: a CHILD of the box (moves with the drag), flips above when
     the box nears the container bottom, clamps horizontally via margin. */
  body.ui-v2 .v2-obj-strip {
    position: absolute;
    top: calc(100% + 7px);
    left: 50%;
    transform: translateX(-50%);
    display: none;
    align-items: center;
    gap: 3px;
    padding: 4px 5px;
    border-radius: var(--v2-r-3);
    background: rgba(14,14,18,0.88);
    border: 1px solid var(--v2-border-pop);
    box-shadow: var(--v2-shadow-strip);
    white-space: nowrap;
  }
  body.ui-v2 .v2-objbox-sel .v2-obj-strip { display: flex; }
  body.ui-v2 .v2-obj-strip.v2-strip-above { top: auto; bottom: calc(100% + 7px); }
  body.ui-v2 .v2-strip-btn {
    padding: 4px 8px;
    border: none;
    border-radius: var(--v2-r-2);
    background: transparent;
    color: var(--v2-text-btn);
    font-family: inherit;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
  }
  body.ui-v2 .v2-strip-btn:hover { background: var(--v2-raised); color: #fff; }
  body.ui-v2 .v2-strip-danger:hover { color: var(--v2-danger-text); }

  body.ui-v2 .v2-fx-region {
    position: absolute;
    left: 8%; right: 8%;
    height: 22%;
    border: 1.5px dashed rgba(255,214,10,0.55);
    border-radius: 10px;
    background: repeating-linear-gradient(135deg, rgba(255,214,10,0.09) 0 7px, transparent 7px 14px);
    display: flex;
    align-items: center;
    justify-content: center;
  }
  body.ui-v2 .v2-fx-region span {
    font-family: var(--v2-font-mono);
    font-size: 11px;
    letter-spacing: 0.04em;
    color: #ffe680;
    max-width: 92%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  body.ui-v2 .v2-stage-hint {
    position: absolute;
    left: 50%; bottom: 18px;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 8px 13px;
    border-radius: 999px;
    background: rgba(14,14,18,0.86);
    border: 1px solid #2b2b36;
    backdrop-filter: blur(8px);
    white-space: nowrap;
    font-size: 12px;
    font-weight: 500;
    color: #d0d0da;
  }
  body.ui-v2 .v2-stage-hint[hidden] { display: none; }
  body.ui-v2 .v2-hint-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--v2-accent); }

  /* Toolbar bits (shell shipped in PR 1) */
  body.ui-v2 .v2-stage-tools { display: flex; align-items: center; gap: 10px; }
  body.ui-v2 .v2-safe-toggle {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 6px 10px;
    border-radius: var(--v2-r-3);
    border: 1px solid var(--v2-border-btn);
    background: transparent;
    color: var(--v2-text-2);
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
  }
  body.ui-v2 .v2-safe-toggle:hover { color: #fff; background: var(--v2-raised); }
  body.ui-v2 .v2-safe-toggle.v2-safe-on {
    color: var(--v2-accent-hover);
    border-color: var(--v2-accent);
    background: var(--v2-accent-tint);
  }
  body.ui-v2 .v2-safe-icon {
    width: 11px; height: 11px;
    border: 1.5px dashed currentColor;
    border-radius: 2px;
  }
  body.ui-v2 .v2-stage-chips {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    overflow: hidden;
    font-family: var(--v2-font-mono);
    font-size: 10px;
    letter-spacing: 0.06em;
  }
  body.ui-v2 .v2-stage-chips[hidden] { display: none; }
  body.ui-v2 .v2-chip-cam  { color: #c3b3ff; white-space: nowrap; }
  body.ui-v2 .v2-chip-game { color: #8fb6ff; white-space: nowrap; }

  /* Pane selection ring (README § 6: the selected pane gets a ring). */
  body.ui-v2 .v2-pane-ring {
    position: absolute;
    left: 2px; right: 2px;
    border: 1.5px solid var(--v2-accent);
    border-radius: 10px;
    pointer-events: none;
  }
  body.ui-v2 .v2-pane-ring[hidden] { display: none; }

  /* Ghost state: the title box while its text is stashed (Remove pressed) —
     keeps the strip's Restore button reachable. */
  body.ui-v2 .v2-objbox-ghost { border-style: dashed; border-color: var(--v2-text-faint); }

  /* ── Layout tab (PR 8, README § 4) ──────────────────────────────────────
     Mode grid: 3 columns of preset cards with 26×46 mini-frame diagrams
     (purple cam / slate game). Pane cards: header + mono readout, −/+ zoom
     row, 132px pan pad with rule-of-thirds guides. ────────────────────── */
  body.ui-v2 #tabLayout { padding: 2px 18px 18px; display: flex; flex-direction: column; gap: 6px; }
  body.ui-v2 .v2-mode-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 7px;
  }
  body.ui-v2 .v2-mode-grid .lp-mode-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    /* editor.css's .lt-preview-modes .lp-mode-btn residue (space-between +
       min-height: 56px) is latent — pin it off. */
    justify-content: flex-start;
    min-height: 0;
    gap: 6px;
    padding: 9px 4px 7px;
    border: 1px solid var(--v2-border-btn);
    border-radius: var(--v2-r-4);
    background: var(--v2-input);
    color: var(--v2-text-btn);
    font-family: inherit;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
  }
  body.ui-v2 .v2-mode-grid .lp-mode-btn:hover { background: var(--v2-raised); }
  body.ui-v2 .v2-mode-grid .lp-mode-btn.lp-active {
    border-color: var(--v2-accent);
    box-shadow: 0 0 0 1px var(--v2-accent);
    background: var(--v2-accent-tint);
    color: #fff;
  }
  body.ui-v2 .v2-mode-frame {
    width: 26px;
    height: 46px;
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 2px;
    border-radius: 5px;
    background: var(--v2-track);
    border: 1px solid var(--v2-border-track);
  }
  body.ui-v2 .v2-mode-frame i { border-radius: 2px; }
  /* editor.css's `.lt-preview-modes .lp-mode-label { font-size: 8.5px }`
     outranks inherited size — the labels are the reskin's only text. */
  body.ui-v2 .v2-mode-grid .lp-mode-label { font-size: 11px; letter-spacing: 0; }
  body.ui-v2 .v2-mf-cam  { background: var(--v2-accent-hover); }
  body.ui-v2 .v2-mf-game { background: var(--v2-game); }
  body.ui-v2 .v2-mf-os   { background: linear-gradient(135deg, #f59e0b, #b45309); }

  body.ui-v2 .v2-pane-card { cursor: pointer; }
  body.ui-v2 .v2-pane-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 6px;
  }
  body.ui-v2 .v2-pane-icon {
    width: 14px; height: 22px;
    border-radius: 3px;
    border: 1.5px solid currentColor;
    flex: none;
  }
  body.ui-v2 .v2-pane-icon-cam  { color: var(--v2-accent-hover); }
  body.ui-v2 .v2-pane-icon-game { color: var(--v2-game-2); }
  body.ui-v2 .v2-pane-title { font-size: 13px; font-weight: 600; color: #c9c9d4; flex: 1; }
  body.ui-v2 .v2-pane-readout {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    color: var(--v2-text-label);
  }
  body.ui-v2 .v2-zoom-row { display: flex; align-items: center; gap: 7px; }
  body.ui-v2 .v2-zoom-row .pos-slider { flex: 1; }
  body.ui-v2 .v2-step-btn {
    width: 24px; height: 24px;
    flex: none;
    border: 1px solid var(--v2-border-btn);
    border-radius: var(--v2-r-2);
    background: var(--v2-raised);
    color: var(--v2-text-btn);
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
  }
  body.ui-v2 .v2-step-btn:hover { color: #fff; background: #22222b; }
  body.ui-v2 .v2-pad-row { display: flex; gap: 12px; align-items: flex-start; margin-top: 8px; }
  body.ui-v2 .v2-pad-side { flex: 1; display: flex; flex-direction: column; gap: 7px; align-items: flex-start; }
  /* 132px pad with rule-of-thirds guides (v1's center-cross ::before/::after
     are overridden into thirds lines via gradients). */
  body.ui-v2 .pan-pad {
    max-width: 132px;
    border-radius: var(--v2-r-2);
    background:
      linear-gradient(to right, transparent calc(33.3% - 0.5px), rgba(255,255,255,0.07) 33.3%, transparent calc(33.3% + 0.5px),
                      transparent calc(66.6% - 0.5px), rgba(255,255,255,0.07) 66.6%, transparent calc(66.6% + 0.5px)),
      linear-gradient(to bottom, transparent calc(33.3% - 0.5px), rgba(255,255,255,0.07) 33.3%, transparent calc(33.3% + 0.5px),
                      transparent calc(66.6% - 0.5px), rgba(255,255,255,0.07) 66.6%, transparent calc(66.6% + 0.5px)),
      var(--v2-input);
    border: 1px solid var(--v2-border-input);
  }
  body.ui-v2 .pan-pad::before, body.ui-v2 .pan-pad::after { display: none; }
  body.ui-v2 .pan-pad-dot {
    width: 14px; height: 14px;
    background: var(--v2-accent);
    box-shadow: 0 0 0 5px rgba(124,92,255,0.18);
  }
  body.ui-v2 .redetect-cam-btn { width: auto; }

  /* ── Script tab (PR 9, README § 5) ──────────────────────────────────────
     Reading view: 17px/1.75 prose, 34px seeking timecode gutter, centered
     pause rules, inline legend. Confidence marking is CUT by decision —
     the low-conf styling is suppressed, not restyled. ─────────────────── */
  body.ui-v2 #scriptBody {
    font-size: 17px;
    line-height: 1.75;
    padding: 14px 18px 18px 14px;
  }
  body.ui-v2 #scriptBody p,
  body.ui-v2 #scriptBody .script-p {
    position: relative;
    padding-left: 44px;
    margin: 0 0 14px;
    border-left: none;   /* v1's 2px paragraph rail would cut through the gutter */
  }
  body.ui-v2 .script-ts {
    position: absolute;
    left: 0;
    top: 0.45em;
    width: 34px;
    font-family: var(--v2-font-mono);
    font-size: 10px;
    color: var(--v2-text-label);
    cursor: pointer;
    text-align: right;
  }
  body.ui-v2 .script-ts:hover { color: var(--v2-accent-hover); }
  body.ui-v2 .pause-marker {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 10px 0 14px 44px;
  }
  body.ui-v2 .pause-marker::before,
  body.ui-v2 .pause-marker::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--v2-raised-2);
  }
  body.ui-v2 .pause-marker-dur {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    color: var(--v2-text-faint);
    white-space: nowrap;
  }
  /* Confidence is cut at the SOURCE in v2 (renderScript never emits the
     class under the flag) — no styling suppression needed, and none may
     exist: the earlier !important form also killed search/playing-now
     highlights on low-conf words (round-1 review). */
  body.ui-v2 #scriptHelpBtn { display: none; }
  body.ui-v2 .v2-script-legend {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 7px 18px;
    border-bottom: 1px solid var(--v2-raised-2);
    font-family: var(--v2-font-mono);
    font-size: 10px;
    letter-spacing: 0.04em;
    color: var(--v2-text-label);
  }
  body.ui-v2 .v2-leg::before {
    content: "";
    display: inline-block;
    width: 7px; height: 7px;
    border-radius: 2px;
    margin-right: 5px;
    vertical-align: 0;
  }
  body.ui-v2 .v2-leg-emph::before  { background: var(--v2-fx); }
  body.ui-v2 .v2-leg-hidden        { text-decoration: line-through; }
  body.ui-v2 .v2-leg-hidden::before{ background: var(--v2-text-faint); }
  body.ui-v2 .v2-leg-play::before  { background: var(--v2-positive); }
  body.ui-v2 .v2-leg-count { margin-left: auto; color: var(--v2-text-muted); }
  body.ui-v2 #scriptToolbar { border-bottom: 1px solid var(--v2-border-chrome); }
  body.ui-v2 #scriptStatusBar {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    color: var(--v2-text-label);
    border-top: 1px solid var(--v2-border-chrome);
  }

  /* ── Popovers (PR 11, README § 8) — one system: #14141a on a #2e2e3a
     border, 13px radius, the § 12 popover shadow. The pickers' internals
     keep their v1 layout; this is the shared chrome. Scrim deferred (the
     pickers' show/hide is v1-owned; recorded for the § 16 audit). ─────── */
  /* .emph-dial-popover is deliberately NOT here: the dial's transparent
     no-container design is intentional (see modals.css — "just the circle
     itself, translucent") and § 8's rows-based emphasis popover is a
     different, unbuilt component. Recorded for the § 16 audit. */
  body.ui-v2 #layoutPicker,
  body.ui-v2 #fxPicker,
  body.ui-v2 #sfxPicker,
  body.ui-v2 #timingPanel,
  body.ui-v2 #emojiPopover {
    background: var(--v2-popover);
    border: 1px solid var(--v2-border-pop);
    border-radius: 13px;
    box-shadow: var(--v2-shadow-pop);
  }
  body.ui-v2 .v2-fp-span-row { display: flex; gap: 7px; }
  body.ui-v2 .v2-fp-span-btn {
    flex: 1;
    padding: 6px 0;
    border: 1px solid var(--v2-border-btn);
    border-radius: var(--v2-r-3);
    background: var(--v2-raised);
    color: var(--v2-text-btn);
    font-family: inherit;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
  }
  body.ui-v2 .v2-fp-span-btn:hover:not(:disabled) { background: #22222b; color: #fff; }
  body.ui-v2 .v2-fp-span-btn:disabled { opacity: 0.4; cursor: default; }

  /* ── Shortcuts modal (§ 11) — VS Code-styled: full-width search, rows
     with mono keycaps, live count. The list/filter JS is v1's. ────────── */
  body.ui-v2 #helpOverlay { background: rgba(4,4,6,0.35); backdrop-filter: blur(3px); }
  body.ui-v2 #helpPanel {
    background: var(--v2-popover);
    border: 1px solid var(--v2-border-pop);
    border-radius: 13px;
    box-shadow: var(--v2-shadow-pop);
  }
  body.ui-v2 #helpSearch {
    background: var(--v2-input);
    border: 1px solid var(--v2-border-input);
    border-radius: var(--v2-r-3);
    color: var(--v2-text);
    font-family: inherit;
    margin: 10px 10px 6px;
  }
  /* The border SHORTHAND above beats v1's :focus border-bottom-color — the
     modal is keyboard-driven, the field needs its focus state back. */
  body.ui-v2 #helpSearch:focus { border-color: var(--v2-accent); }
  body.ui-v2 .help-row {
    border-radius: var(--v2-r-2);
    color: var(--v2-text-btn);
    font-size: 12.5px;
  }
  body.ui-v2 .help-row:hover,
  body.ui-v2 .help-row.help-focus { background: var(--v2-raised); color: #fff; }
  body.ui-v2 .help-key {
    font-family: var(--v2-font-mono);
    font-size: 10.5px;
    color: var(--v2-text-2);
    background: var(--v2-track);
    border: 1px solid var(--v2-border-btn);
    border-radius: var(--v2-r-1);
    padding: 2px 7px;
  }
  body.ui-v2 #helpCount,
  body.ui-v2 #helpFooter {
    font-family: var(--v2-font-mono);
    font-size: 10px;
    color: var(--v2-text-label);
  }
