/* ============================================================================
 * Player v2 — Stage identity, REV 2 (Tranche S2 rev-2 wave: Task 1 + Task 2)
 * ----------------------------------------------------------------------------
 * Dave's checkpoint-1 verdicts (binding): ONE typographic voice (platform stack,
 * no webfonts) · ONE accent (the EchoVQ brand violet) · FLAT + full-bleed (no
 * boxes-in-boxes, no risers) · DARK every practice surface · SVG icons only,
 * no emoji glyphs anywhere.
 *
 * Every rule is scoped under `.v2-stage` (the wrapper on player_v2.html) so it
 * supersedes the v1-copied styles (songsplit.css) INSIDE the v2 shell only —
 * except the `--ss-*` :root overrides in §0, which are deliberately global-on-
 * this-page (see the note there). Loaded LAST (after songsplit.css +
 * shell-skeleton.css) so scoped selectors win on specificity AND source order.
 *
 * SCOPE (this wave): tokens · full-bleed · type scale · focus · header console ·
 * zone nav · sub-nav chips · transport row · stem lanes · dark canvas wells ·
 * record region + tally-lamp signature + ON AIR · take block · practice panel.
 * Song Sheets paper, My Progress harmonize, and the Mix popover are Task 3.
 * ==========================================================================*/

/* ============================================================================
 * 0. DARK-CANVAS INJECTION — redefine the platform `--ss-*` theme variables.
 *
 * WHY :root (not .v2-stage): songsplit-player-style canvas paint reads these via
 * getComputedStyle(document.documentElement) (bootstrap.js rebuildThemeColors +
 * getStemColors). Custom props scoped to `.v2-stage` would NOT reach documentElement,
 * so the canvases would bake in the light platform palette. Defining them on :root
 * DOES reach documentElement.
 *
 * WHY safe: stage.css is referenced ONLY by templates/songsplit/player_v2.html
 * (verified: `grep -rn stage.css templates static` → 1 hit). So this :root block
 * never loads on any other page. It also loads in <head>, so the vars exist before
 * bootstrap.js runs at end-of-body → rebuildThemeColors reads the dark values on the
 * first (and only init-time) call. No JS, no module edits — choice (a).
 *
 * NB piano-roll-renderer.js (window.createPianoRoll, the exercise Piano Roll tab)
 * paints from HARDCODED light colors ('white', '#8c49f0', '#333' …) — it reads NO
 * CSS vars. Per rev-2 rule 5 it is LEFT LIGHT this tranche and flagged as a
 * follow-up. Everything below is CSS-var-driven and themes dark.
 * ==========================================================================*/
:root {
  /* Accent → brand violet (was blue #6ea0ff): progress fill, sliders, master vol */
  --ss-accent:        #8B5CF6;
  --ss-accent-hover:  #A78BFA;
  --ss-accent-glow:   rgba(139, 92, 246, 0.25);

  /* Practice text (vocal-match reveal + demo cards read these) */
  --ss-text:          #EFEDF6;
  --ss-text-muted:    #8E8AA3;
  --ss-surface:       #1B1823;
  --ss-surface-hover: #232130;
  --ss-border:        rgba(255, 255, 255, 0.06);

  /* App background — THE var .ss-view-panel paints (`background: var(--ss-bg)`).
     WAVE 4 root-cause fix: this is the ONE theme var §0 previously missed, so the
     authenticated `[data-theme="light"]` block (songsplit.css:121 `--ss-bg:#f5f5f7`)
     WON on the v2 page → #view-waveform / #view-roll / #view-export rendered as WHITE
     picture-frames around the waveform + note-roll groups (empirically confirmed:
     headless dump with data-theme="light" → #view-waveform bg rgb(245,245,247), 335k px).
     Redefining it here (same (0,1,0) as [data-theme=light], stage.css loads last → wins)
     darks every practice/export panel. Sheets paper is unaffected — W2 paints its
     view-panel `var(--paper)` at (0,3,0). Set to --stage so panels merge with the room;
     the waveform WELL stays deeper via --ss-canvas-bg. */
  --ss-bg:            #131118;
  /* Overlay surface (tooltips / dropdown menus) — also flips near-white under light
     theme (rgba(245,245,247,0.92)); pin dark so no overlay reads light on the stage. */
  --ss-surface-overlay: rgba(27, 24, 35, 0.92);

  /* Waveform / pitch canvases — deep violet well */
  --ss-canvas-bg:     #0F0D14;
  --ss-playhead:      rgba(239, 237, 246, 0.85);
  --ss-toast-bg:      #1B1823;
  --ss-toast-text:    #EFEDF6;

  /* rebuildThemeColors also reads these two (sliderTrack / toastBorder).
     MUST be pinned here: authenticated users get platform_base.html which forces
     data-theme="light" on <html> (platform_base.html:19), and songsplit.css's
     [data-theme="light"] block flips them to BLACK alphas — invisible on the dark
     stage. Same specificity (0,1,0) as this :root, but stage.css loads last → wins. */
  --ss-white-alpha-06: rgba(255, 255, 255, 0.08);
  --ss-white-alpha-08: rgba(255, 255, 255, 0.12);

  /* Stems = violet lightness steps off the two brand anchors (#8B5CF6 / #7C3AED).
     Vocals brightest; the rest step down darker so the singer reads first. */
  --ss-stem-vocals:   #8B5CF6;   /* the voice — brightest */
  --ss-stem-other:    #584A99;   /* mid step */
  --ss-stem-guitar:   #584A99;
  --ss-stem-piano:    #584A99;
  --ss-stem-drums:    #453C77;   /* dark step */
  --ss-stem-bass:     #453C77;
  --ss-stem-backing:  #453C77;
  --ss-stem-recording:#E5493B;   /* the lamp — record only */

  /* Note-roll pitch lanes / gridlines — violet-tinted, dark */
  --ss-pitch-lane-natural:    rgba(255, 255, 255, 0.02);
  --ss-pitch-lane-sharp:      rgba(0, 0, 0, 0.28);
  --ss-pitch-gridline-octave: rgba(139, 92, 246, 0.22);
  --ss-pitch-gridline:        rgba(255, 255, 255, 0.05);
  --ss-piano-label:           #8B5CF6;   /* keyboard octave labels → violet */
}

/* ---- 1. Design tokens (pinned — verbatim from plan §"THE DESIGN SYSTEM — REV 2") ---- */
.v2-stage {
  --stage:      #131118;  /* the room — near-black, warm violet undertone */
  --stage-2:    #1B1823;  /* subtle region differentiation (record region, popovers) */
  --hairline:   #232130;  /* row separators — the ONLY border color */
  --accent:     #8B5CF6;  /* THE brand violet, light step — play, active nav, progress */
  --accent-deep:#7C3AED;  /* brand primary — pressed states, gradients with --accent */
  --lamp:       #E5493B;  /* record ONLY (warm red; glow rgba(229,73,59,.35)) */
  --paper:      #FAF7F0;  --paper-edge: #E7E1D3;  --ink: #26232C;   /* Song Sheets */
  --voice-hi:   #EFEDF6;  --voice-lo: #8E8AA3;    /* text on stage */
  --chip:       #232130;  --chip-text: #B9B3D6;   /* control chips */

  /* derived helpers (no new colours — alphas of the pinned set) */
  --accent-60:  rgba(139, 92, 246, 0.60);   /* focus ring */
  --accent-glow:rgba(139, 92, 246, 0.45);   /* active-zone underglow */
  --lamp-glow:  rgba(229, 73, 59, 0.35);    /* record halo */

  /* ≤768 fixed bottom-bar height budget (visible bar + safe area). Single source of
   * truth for the four offsets that must clear it (main/footer padding, mix sheet +
   * toast `bottom`). Change the bar height here, everything below follows. */
  --v2-bar-h: 64px;

  /* ONE voice: the platform system stack. Hierarchy by weight/size/colour only. */
  --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}

/* ---- 2. The room ---- */
.v2-stage {
  background: var(--stage);
  color: var(--voice-hi);
  font-family: var(--font-body);
  font-size: 13.5px;              /* body */
  line-height: 1.5;
}

/* ---- 2b. FULL-BLEED — the player fills the platform content column edge-to-edge.
 * The platform wrapper (.ss-container) applies a Tailwind gutter (p-2 / md:p-4 /
 * lg:p-6 = 8 / 16 / 24px) and .ss-player-page adds its own card constraint
 * (max-width 1200 + margin auto + padding). We break the gutter with matched
 * negative margins and drop the card. The sidebar (lg:ml-64) and the topbar
 * reservation (pt-14 / mt-10, ~56px) are NOT touched — pulling only the small
 * gutter leaves the header comfortably below the topbar. No !important: the
 * `.ss-container .ss-player-page.v2-stage` (0,3,0) selector out-specifies the
 * platform `.ss-container .ss-player-page` (0,2,0) rule. ---- */
.ss-container .ss-player-page.v2-stage,
.ss-player-page.v2-stage {
  max-width: none;
  width: auto;
  margin: -8px -8px -8px;
  padding: 0;
  background: var(--stage);
  min-height: 100vh;
}
@media (min-width: 768px) {
  .ss-container .ss-player-page.v2-stage,
  .ss-player-page.v2-stage { margin: -16px -16px -16px; }
}
@media (min-width: 1024px) {
  .ss-container .ss-player-page.v2-stage,
  .ss-player-page.v2-stage { margin: -24px -24px -24px; }
}

/* Micro-label utility (10.5px uppercase +0.05em) */
.v2-stage .ss-detail-label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--voice-lo);
}

/* ---- 3. Focus — always-visible 2px --accent ring at 60% ---- */
.v2-stage :focus-visible {
  outline: 2px solid var(--accent-60);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ============================================================================
 * 4. HEADER — console strip: part of the room (--stage), a single hairline below.
 * ==========================================================================*/
.v2-stage .v2-header {
  background: var(--stage);
  border-bottom: 1px solid var(--hairline);
  padding: 26px 24px 18px;   /* W5: top padding ≥24px — more air above the console */
  gap: 16px;
}
/* ON AIR tally edge — 2px --lamp along the top of the console while recording */
.v2-stage.v2-recording .v2-header {
  box-shadow: inset 0 2px 0 0 var(--lamp);
}

/* The v1 header block sits inside .v2-header — strip its surface + border so the
 * whole strip reads as one continuous console, not a card-in-a-card. */
.v2-stage .ss-player-header {
  background: transparent;
  border-bottom: none;
  padding: 0;
  flex: 1;
  min-width: 0;
}

/* Thumbnail */
.v2-stage .ss-player-art {
  width: 52px;
  height: 52px;
  border-radius: 8px;
  border: 1px solid var(--hairline);
}
.v2-stage .ss-player-art-placeholder {
  background: var(--stage-2);
  color: var(--voice-lo);
}

/* Title — 21/700, one voice (W5: Dave's checkpoint-2 bump from 17 → 21) */
.v2-stage .ss-player-title {
  font-weight: 700;
  font-size: 21px;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--voice-hi);
  margin-bottom: 3px;
}

/* Subtitle (duration · date · expiry) — quiet meta, 11/--voice-lo */
.v2-stage .ss-player-subtitle,
.v2-stage .ss-player-date,
.v2-stage .ss-player-expiry,
.v2-stage .ss-player-duration,
.v2-stage .ss-meta-sep,
.v2-stage .ss-cover-count {
  color: var(--voice-lo);
  font-size: 11px;
}
.v2-stage .ss-cover-count strong { color: var(--voice-hi); }

/* Meta chips (separation · quality · key · range) — small control chips */
.v2-stage .ss-player-header-right {
  gap: 8px;
  align-items: stretch;
  flex-wrap: wrap;
}
.v2-stage .ss-player-detail {
  gap: 2px;
  padding: 5px 11px;
  background: var(--chip);
  border: none;
  border-radius: 8px;
}
.v2-stage .ss-detail-value {
  font-size: 12px;
  font-weight: 600;
  color: var(--voice-hi);
}
.v2-stage .ss-quality-badge.ss-quality-hq { color: var(--accent); }

/* Right action cluster: Mix ▾ / record / ⋯ + the REC tally */
.v2-stage .v2-header-actions { gap: 10px; align-items: center; }

/* Ghost console buttons (Mix, overflow) — chips, no heavy borders */
.v2-stage .v2-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--voice-hi);
  background: var(--chip);
  border: none;
  border-radius: 8px;
  padding: 9px 14px;
  min-height: 40px;
  transition: background 120ms ease-out;
}
.v2-stage .v2-btn:hover { background: var(--stage-2); }
.v2-stage .v2-btn svg { display: block; }

/* Record proxy — the tally lamp. 44px circle, --lamp, breathing idle glow, SVG
 * mic (no glyph). ON AIR (root .v2-recording) → brighter halo. Full tally spec. */
.v2-stage .v2-btn--record {
  width: 44px;
  height: 44px;
  min-height: 44px;
  padding: 0;
  border-radius: 50%;
  background: var(--lamp);
  border: 2px solid rgba(229, 73, 59, 0.85);
  box-shadow: 0 0 12px var(--lamp-glow);
  color: #fff;
  flex-shrink: 0;
  animation: v2-tally-breathe 2.6s ease-in-out infinite;
}
.v2-stage .v2-btn--record:hover {
  background: var(--lamp);
  border-color: var(--lamp);
}
.v2-stage .v2-btn--record svg { margin: 0 auto; }
@keyframes v2-tally-breathe {
  0%, 100% { transform: scale(1);    box-shadow: 0 0 12px rgba(229, 73, 59, 0.24); }
  50%      { transform: scale(1.03); box-shadow: 0 0 16px rgba(229, 73, 59, 0.34); }
}
/* ON AIR — solid, brighter halo, no breathing (it's steady while live) */
.v2-stage.v2-recording .v2-btn--record {
  animation: none;
  box-shadow: 0 0 18px rgba(229, 73, 59, 0.55);
  border-color: var(--lamp);
}

/* REC tally chip — mono-feel dot + label, revealed only while ON AIR. The dot is
 * a CSS element (no ● glyph, no emoji). */
.v2-stage .v2-rec-tally {
  display: none;
  align-items: center;
  gap: 6px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--lamp);
}
.v2-stage.v2-recording .v2-rec-tally { display: inline-flex; }
.v2-stage .v2-rec-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--lamp);
  box-shadow: 0 0 8px var(--lamp-glow);
  animation: v2-rec-blink 1.1s ease-in-out infinite;
}
@keyframes v2-rec-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* ============================================================================
 * 5. ZONE NAV — flat backlit labels with an --accent underglow on the active one.
 * ==========================================================================*/
.v2-stage .v2-zones {
  background: var(--stage);
  border-bottom: 1px solid var(--hairline);
  gap: 4px;
  padding: 0 24px;
}
.v2-stage .v2-zone-btn {
  position: relative;
  font-weight: 600;
  font-size: 14px;
  color: var(--voice-lo);
  background: transparent;
  border: none;
  padding: 13px 14px 15px;
  transition: color 150ms ease-out;
}
.v2-stage .v2-zone-btn:hover { color: var(--voice-hi); }
.v2-stage .v2-zone-btn[aria-selected="true"] { color: var(--voice-hi); }
.v2-stage .v2-zone-btn::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
  box-shadow: 0 0 8px 1px var(--accent-glow);
  opacity: 0;
  transition: opacity 150ms ease-out;
}
.v2-stage .v2-zone-btn[aria-selected="true"]::after { opacity: 1; }

/* Main column padding — the zones' content breathes inside the full-bleed room */
.v2-stage .v2-main { padding: 20px 24px 40px; }

/* ============================================================================
 * 6. SUB-NAV CHIPS — practice melody toggle + sheet tabs (sheets become paper
 * file-dividers in Task 3; kept as chips here for coherence).
 * ==========================================================================*/
.v2-stage .v2-subnav { gap: 6px; margin-bottom: 16px; }
.v2-stage .v2-subnav-btn,
.v2-stage .v2-subnav .ss-view-tab {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--voice-lo);
  background: var(--chip);
  border: none;
  border-radius: 8px;
  padding: 7px 14px;
  min-height: 34px;
  transition: background 120ms ease-out, color 120ms ease-out;
}
.v2-stage .v2-subnav-btn:hover,
.v2-stage .v2-subnav .ss-view-tab:hover {
  background: var(--stage-2);
  color: var(--voice-hi);
}
.v2-stage .v2-subnav-btn.v2-subnav-btn-active,
.v2-stage .v2-subnav .ss-view-tab.ss-view-tab-active {
  background: var(--stage-2);
  color: var(--accent);
}

/* ============================================================================
 * 7. TRANSPORT ROW — a flat control row on the stage, a hairline below.
 * No box: it's part of the room, not a riser.
 * ==========================================================================*/
.v2-stage .ss-transport-bar {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--hairline);
  border-radius: 0;
  padding: 10px 0 16px;
  margin-bottom: 18px;
  gap: 14px;
}
/* Transport control buttons → chips */
.v2-stage .ss-toolbar-btn,
.v2-stage .ss-reset-btn,
.v2-stage .ss-transpose-select {
  background: var(--chip);
  border: none;
  color: var(--voice-hi);
  border-radius: 8px;
  transition: background 120ms ease-out, color 120ms ease-out;
}
.v2-stage .ss-toolbar-btn:hover,
.v2-stage .ss-reset-btn:hover { background: var(--stage-2); color: var(--voice-hi); }
.v2-stage .ss-toolbar-btn.ss-loop-active { color: var(--accent); background: var(--stage-2); }
.v2-stage .ss-reset-btn { font-size: 12px; font-weight: 600; }
.v2-stage .ss-transpose-select { padding: 8px 10px; font-size: 12.5px; }

/* Play button — the primary transport affordance, brand violet */
.v2-stage .ss-play-btn {
  background: var(--accent);
  color: #fff;
  border: none;
}
.v2-stage .ss-play-btn:hover { background: var(--accent-deep); }
.v2-stage .ss-play-btn svg { fill: #fff; }

/* Time readout — quiet meta */
.v2-stage .ss-toolbar-time { color: var(--voice-hi); font-size: 13px; }
.v2-stage .ss-toolbar-time .ss-time-sep,
.v2-stage #total-time { color: var(--voice-lo); }

/* Progress bar — --accent fill, loop region in --accent 30% */
.v2-stage .ss-progress-bar { background: var(--hairline); }
.v2-stage .ss-progress-fill { background: var(--accent); }
.v2-stage .ss-progress-handle { background: var(--voice-hi); border-color: var(--accent); }
.v2-stage .ss-loop-region { background: rgba(139, 92, 246, 0.30); }
.v2-stage .ss-loop-start,
.v2-stage .ss-loop-end { background: var(--accent); }

/* Practice-mode panel — flat, hairline-topped region */
.v2-stage .ss-practice-panel {
  background: var(--stage-2);
  border: none;
  border-radius: 10px;
  margin-bottom: 16px;
}
.v2-stage .ss-practice-label,
.v2-stage .ss-practice-value,
.v2-stage .ss-practice-status { color: var(--voice-lo); }
.v2-stage .ss-practice-value { color: var(--voice-hi); }
.v2-stage .ss-practice-select { background: var(--chip); border: none; color: var(--voice-hi); border-radius: 8px; }

/* ============================================================================
 * 8. STEM LANES + WAVEFORM WELL — channel-strip rows, dark well, no outer box.
 * ==========================================================================*/
.v2-stage .ss-stems-layout,
.v2-stage .ss-waveform-scroll,
.v2-stage .ss-stems-container { background: transparent; border: none; }

/* Sidebar channel strips — rows separated by hairlines, no boxes */
.v2-stage .ss-stems-sidebar { background: transparent; }
.v2-stage .ss-stem-sidebar-block {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--hairline);
}
.v2-stage .ss-stem-name { color: var(--voice-hi); font-size: 12.5px; font-weight: 600; }
.v2-stage .ss-stem-pan-label { color: var(--voice-lo); font-size: 10.5px; }

/* Mute / solo → console toggle chips */
.v2-stage .ss-mute-btn,
.v2-stage .ss-solo-btn {
  background: var(--chip);
  border: none;
  color: var(--voice-lo);
  border-radius: 6px;
  font-size: 11px;
  font-weight: 700;
  transition: background 120ms ease-out, color 120ms ease-out;
}
.v2-stage .ss-mute-btn:hover,
.v2-stage .ss-solo-btn:hover { background: var(--stage-2); color: var(--voice-hi); }
/* Active mute = quiet emphasis, NOT --lamp (--lamp is record affordances only) */
.v2-stage .ss-mute-btn.active { background: var(--stage-2); color: var(--voice-hi); }
.v2-stage .ss-solo-btn.active { background: var(--stage-2); color: var(--accent); }

/* Pan knob */
.v2-stage .ss-pan-knob { background: var(--chip); border: 1px solid var(--hairline); }

/* Waveform well — the deepest surface: --stage-2 tinted, canvas paints on it */
.v2-stage .ss-stem-lane { background: transparent; border-bottom: 1px solid var(--hairline); }
.v2-stage .ss-stem-canvas { background: transparent; }

/* Waveform zoom chip cluster */
.v2-stage .ss-waveform-zoom { background: var(--chip); border: none; border-radius: 8px; }
.v2-stage .ss-waveform-zoom-btn { color: var(--voice-lo); background: transparent; border: none; }
.v2-stage .ss-waveform-zoom-btn:hover { color: var(--voice-hi); }
.v2-stage .ss-waveform-zoom-label { color: var(--voice-hi); font-size: 11px; }

/* Locked-stem upsell rows — quiet, still a row */
.v2-stage .ss-stem-lane-locked { opacity: 0.75; }
.v2-stage .ss-locked-stem-name { color: var(--voice-lo); }
.v2-stage .ss-stem-unlock-overlay { color: var(--voice-lo); }

/* Inline 3-line lyrics under the waveform */
.v2-stage .ss-inline-lyrics { background: transparent; }
.v2-stage .ss-inline-lyrics-prev,
.v2-stage .ss-inline-lyrics-next { color: var(--voice-lo); }
.v2-stage .ss-inline-lyrics-current { color: var(--voice-hi); }

/* Note-roll pitch view chrome (canvases themselves paint from --ss-* in §0) */
.v2-stage .ss-pitch-mode-toggle,
.v2-stage .ss-pitch-zoom { background: var(--chip); border: none; border-radius: 8px; }
.v2-stage .ss-pitch-mode-btn { color: var(--voice-lo); background: transparent; border: none; }
.v2-stage .ss-pitch-mode-btn.active { color: var(--accent); }
.v2-stage .ss-pitch-zoom-btn { color: var(--voice-lo); }
.v2-stage .ss-pitch-loading p { color: var(--voice-lo); }

/* ============================================================================
 * 9. RECORD STUDIO — a REGION of the stage (top hairline + --stage-2 tint), not a
 * box. The header record proxy is the tally lamp; this body is the full studio.
 * ==========================================================================*/
.v2-stage .ss-record-studio-wrap { margin-top: 18px; }
.v2-stage .ss-record-studio {
  background: var(--stage-2);
  border: none;
  border-top: 1px solid var(--hairline);
  border-radius: 12px;
}
.v2-stage .ss-record-studio-title {
  color: var(--voice-hi);
  font-size: 12.5px;
  font-weight: 700;
}
.v2-stage .ss-record-studio-note,
.v2-stage .ss-record-hero-label { color: var(--voice-lo); font-size: 11px; }

/* Record mode toggle (Audio | Video) → chips */
.v2-stage .ss-record-mode-toggle { background: var(--chip); border: none; border-radius: 8px; }
.v2-stage .ss-record-mode-btn { color: var(--voice-lo); background: transparent; border: none; }
.v2-stage .ss-record-mode-btn.active { color: var(--voice-hi); background: var(--stage-2); }
.v2-stage .ss-record-studio-tip { color: var(--voice-lo); }
.v2-stage .ss-record-tip-dismiss { color: var(--voice-lo); background: transparent; border: none; }

/* Record hero button — the studio-body lamp: --lamp circle, breathing idle */
.v2-stage .ss-record-hero-btn {
  background: var(--lamp);
  border: 2px solid rgba(229, 73, 59, 0.85);
  box-shadow: 0 0 12px var(--lamp-glow);
  color: #fff;
  animation: v2-tally-breathe 2.6s ease-in-out infinite;
}
.v2-stage .ss-record-hero-icon svg { stroke: #fff; }
.v2-stage .ss-record-hero-countdown { color: #fff; }
/* While ON AIR, the hero button is steady + bright and the timer shows --lamp */
.v2-stage.v2-recording .ss-record-hero-btn {
  animation: none;
  box-shadow: 0 0 18px rgba(229, 73, 59, 0.55);
}
.v2-stage .ss-record-hero-timer { color: var(--lamp); font-size: 12px; font-weight: 600; }
.v2-stage .ss-recording-dot { background: var(--lamp); }

/* ============================================================================
 * 10. TAKE BLOCK — recorded-take rows + the take-navigator chips (injected by the
 * recorder as .ss-recording-lane / .ss-recording-sidebar / .ss-take-nav).
 * ==========================================================================*/
.v2-stage .ss-recording-sidebar {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--hairline);
}
.v2-stage .ss-recording-lane { background: transparent; border-bottom: 1px solid var(--hairline); }
.v2-stage .ss-take-nav { gap: 6px; }
.v2-stage .ss-take-btn {
  background: var(--chip);
  border: none;
  color: var(--voice-lo);
  border-radius: 6px;
  font-size: 11px;
  font-weight: 600;
  transition: background 120ms ease-out, color 120ms ease-out;
}
.v2-stage .ss-take-btn:hover { background: var(--stage-2); color: var(--voice-hi); }
.v2-stage .ss-take-btn.active { background: var(--stage-2); color: var(--accent); }

/* ============================================================================
 * 11. MY PROGRESS + SONG SHEETS shells — recolored to rev-2 tokens. Full paper
 * inversion + vocal-match harmonize + Mix popover are Task 3; here we just keep
 * the containers dark + flat so nothing reads as a light card on the stage.
 * ==========================================================================*/
.v2-stage #view-vocalmatch,
.v2-stage #view-results {
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 8px 0;
}
.v2-stage .ss-vm-ring-track { stroke: var(--hairline); }

/* ============================================================================
 * 12. ZONE CROSSFADE — 150ms ease-out fade-in on the incoming zone.
 * ==========================================================================*/
@keyframes v2-zone-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.v2-stage .v2-main[data-active-zone="practice"] .v2-zone[data-zone="practice"],
.v2-stage .v2-main[data-active-zone="sheets"]   .v2-zone[data-zone="sheets"],
.v2-stage .v2-main[data-active-zone="progress"] .v2-zone[data-zone="progress"] {
  animation: v2-zone-fade 150ms ease-out;
}

/* ---- 13. Reduced motion: kill decorative transitions/animations ---- */
@media (prefers-reduced-motion: reduce) {
  .v2-stage .v2-main[data-active-zone] .v2-zone { animation: none; }
  .v2-stage .v2-btn--record,
  .v2-stage .ss-record-hero-btn,
  .v2-stage .v2-bar-record,
  .v2-stage .v2-rec-dot { animation: none; }
  .v2-stage .v2-zone-btn,
  .v2-stage .v2-zone-btn::after,
  .v2-stage .v2-btn,
  .v2-stage .ss-toolbar-btn,
  .v2-stage .ss-mute-btn,
  .v2-stage .ss-solo-btn,
  .v2-stage .ss-take-btn,
  .v2-stage .v2-subnav-btn,
  .v2-stage .v2-subnav .ss-view-tab { transition: none; }
}

/* ============================================================================
 * ============================  WAVE 3  ======================================
 * S2 wave 3 — Dave's checkpoint-2: kill the last light surfaces, make Song Sheets
 * the real paper, remove the platform grey gutters, dark the platform top-bar.
 * Appended LAST so ties with §6/§8/§11 resolve here (source order). Each block
 * carries a root-cause note. rev-2 tokens only.
 * ==========================================================================*/

/* ----------------------------------------------------------------------------
 * W1 — remaining light surfaces in the Practice zone.
 * --------------------------------------------------------------------------*/

/* Per-stem canvas tints. ROOT CAUSE: songsplit.css paints the waveform canvas a
 * light lavender/blue tint via `.ss-stem-lane[data-stem-type="vocals"] .ss-stem-canvas`
 * (specificity 0,2,1). §8's `.v2-stage .ss-stem-canvas { transparent }` is only
 * (0,2,0) → the v1 tint WON. Out-specify it (0,3,0). The canvas paints its own dark
 * well (--ss-canvas-bg) over transparent, so the stage reads through the gaps. */
.v2-stage .ss-stem-lane .ss-stem-canvas,
.v2-stage .ss-tempo-lane .ss-stem-canvas { background: transparent; }

/* Tempo / BPM lane strip. ROOT CAUSE: `.ss-tempo-lane` + `.ss-tempo-sidebar-block`
 * carry `background: rgba(110,160,255,0.04)` (a blue wash) that §8 never covered.
 * Make them stage rows separated by a hairline, like the stem lanes. */
.v2-stage .ss-tempo-lane,
.v2-stage .ss-tempo-sidebar-block {
  background: transparent;
  border-bottom: 1px solid var(--hairline);
}

/* Zoom chips (waveform + pitch). ROOT CAUSE: v1 base `background: var(--ss-surface-overlay)`
 * plus the platform `[data-theme="light"]` block (0,2,0) tie §8's rule; pin them dark
 * from wave 3 (later source order) so the light-theme value can't win. */
.v2-stage .ss-waveform-zoom,
.v2-stage .ss-pitch-zoom {
  background: var(--chip);
  border: none;
  border-radius: 8px;
}
.v2-stage .ss-waveform-zoom-label,
.v2-stage .ss-pitch-zoom-label { color: var(--voice-hi); }

/* Practice inline-lyrics (the 3-line strip under the waveform). ROOT CAUSE: the panel
 * bg AND its ::before/::after fade edges read `var(--ss-surface-alt, …)`, which is NOT
 * redefined in §0 → it falls back to the platform light-theme value → the big pale panel
 * + light gradient edges Dave sees. Dark treatment: --stage-2 body, dark-matched fade
 * edges, voice-lo idle lines, voice-hi active line. */
.v2-stage .ss-inline-lyrics { background: var(--stage-2); }
.v2-stage .ss-inline-lyrics::before { background: linear-gradient(to bottom, var(--stage-2), transparent); }
.v2-stage .ss-inline-lyrics::after  { background: linear-gradient(to top, var(--stage-2), transparent); }
.v2-stage .ss-inline-lyrics-prev,
.v2-stage .ss-inline-lyrics-next { color: var(--voice-lo); }
.v2-stage .ss-inline-lyrics-current { color: var(--voice-hi); }

/* ----------------------------------------------------------------------------
 * W2 — Song Sheets = the real paper. It was INVERTED (dark content box in white
 * chrome). ROOT CAUSE of the dark content box: §0's global `:root { --ss-surface:#1B1823 }`
 * (needed for the dark practice canvases/cards) also reaches the Sheets DOM, and
 * `.ss-lyrics-display { background: var(--ss-surface) }` + `color: var(--ss-text)`
 * (also darkened to #EFEDF6 in §0) render the lyrics dark-on-dark. FIX: re-scope the
 * `--ss-*` legibility tokens back to paper/ink INSIDE the sheets zone only (custom
 * props inherit, so this recolors chords/chart/leadsheet too — they were light-native),
 * then dress each view panel as one floating paper sheet. Practice inline-lyrics stays
 * dark (scoped separately above) — practice-vs-sheets treatments are kept apart. */
.v2-stage .v2-zone[data-zone="sheets"] {
  --ss-text:        #26232C;              /* ink */
  --ss-text-muted:  rgba(38, 35, 44, 0.55);
  --ss-surface:     #FAF7F0;              /* paper */
  --ss-surface-alt: #FAF7F0;
  --ss-border:      #E7E1D3;              /* paper-edge */
  --ss-accent:      #7C3AED;              /* brand deep — readable on paper */
  --ss-accent-glow: rgba(124, 58, 237, 0.20);
}

/* The paper panel: the visible view panel becomes one centered sheet with the single
 * deliberate floating shadow (rev-2 rule 3). */
.v2-stage .v2-zone[data-zone="sheets"] .ss-view-panel {
  max-width: 880px;
  margin: 0 auto;
  background: var(--paper);
  color: var(--ink);
  border-radius: 0 10px 10px 10px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
  padding: 26px 30px;
}

/* Sub-tabs → file-divider tabs attached to the paper top. The strip behind them is the
 * dark stage (transparent), NOT a white bar. Active tab is paper (connects to the sheet). */
.v2-stage #view-tabs.v2-subnav {
  max-width: 880px;
  margin: 0 auto;
  padding: 0 2px;
  gap: 4px;
  background: transparent;
}
.v2-stage .v2-zone[data-zone="sheets"] .ss-view-tab {
  background: transparent;
  color: var(--voice-lo);
  border-radius: 8px 8px 0 0;
  padding: 8px 16px;
}
.v2-stage .v2-zone[data-zone="sheets"] .ss-view-tab:hover { background: rgba(250, 247, 240, 0.12); color: var(--voice-hi); }
.v2-stage .v2-zone[data-zone="sheets"] .ss-view-tab.ss-view-tab-active {
  background: var(--paper);
  color: var(--ink);
}

/* Lyrics content ON the paper (light bg, ink text) — undo the dark-well styling. */
.v2-stage .v2-zone[data-zone="sheets"] .ss-lyrics-display {
  background: transparent;
  border: none;
}
.v2-stage .v2-zone[data-zone="sheets"] .ss-lyrics-ready { color: var(--ink); opacity: 0.55; }
.v2-stage .v2-zone[data-zone="sheets"] .ss-lyric-line[data-position="0"] {
  color: var(--ink);
  text-shadow: none;
}
.v2-stage .v2-zone[data-zone="sheets"] .ss-lyric-line[data-position="-1"],
.v2-stage .v2-zone[data-zone="sheets"] .ss-lyric-line[data-position="1"],
.v2-stage .v2-zone[data-zone="sheets"] .ss-lyric-line[data-position="-2"],
.v2-stage .v2-zone[data-zone="sheets"] .ss-lyric-line[data-position="2"] { color: rgba(38, 35, 44, 0.5); }
.v2-stage .v2-zone[data-zone="sheets"] .ss-word.ss-sung { color: var(--accent-deep); }
.v2-stage .v2-zone[data-zone="sheets"] .ss-word.ss-current {
  color: #fff;
  background: var(--accent);              /* highlight word = --accent */
  text-shadow: none;
}

/* Copy / Print / Fullscreen (+ chart follow / chord settings) = inked ghost buttons. */
.v2-stage .v2-zone[data-zone="sheets"] .ss-chord-shift-btn,
.v2-stage .v2-zone[data-zone="sheets"] .ss-chart-follow-btn,
.v2-stage .v2-zone[data-zone="sheets"] .ss-chord-settings-btn {
  background: transparent;
  border: 1px solid var(--paper-edge);
  color: var(--ink);
}
.v2-stage .v2-zone[data-zone="sheets"] .ss-chord-shift-btn:hover,
.v2-stage .v2-zone[data-zone="sheets"] .ss-chart-follow-btn:hover,
.v2-stage .v2-zone[data-zone="sheets"] .ss-chord-settings-btn:hover { background: rgba(38, 35, 44, 0.06); }
.v2-stage .v2-zone[data-zone="sheets"] .ss-chart-follow-btn.active { background: var(--accent-deep); border-color: var(--accent-deep); color: #fff; }

/* "Auto-transcribed …" caption = muted ink. */
.v2-stage .v2-zone[data-zone="sheets"] .ss-lyrics-disclaimer { color: rgba(38, 35, 44, 0.55); }

/* ----------------------------------------------------------------------------
 * W4 — grey gutters (~15px) left/right of the dark room on the authenticated path.
 * ROOT CAUSE: platform_base.html nests content TWICE: `.ss-container` (Tailwind
 * p-2/md:p-4/lg:p-6 gutter) → `div.p-2.md:p-4` (a SECOND gutter) → .ss-player-page.
 * §2b's negative-margin full-bleed only cancels ONE layer, so the inner div's
 * 8/16/16px survived as the grey (bg-gray-100) gutter. Zero the inner wrapper's
 * padding; combined with §2b's margins the sheet then reaches the .ss-container edge.
 * :has() → graceful degradation: without it the inner gutter simply remains (today's
 * state), never a break. Standalone path has no `.ss-container` (content sits straight
 * in `.ss-main`, whose 24px padding §2b already cancels) → unaffected. No !important. */
.ss-container > div:has(> .ss-player-page.v2-stage) { padding: 0; }

/* ----------------------------------------------------------------------------
 * W6 — dark platform top-bar, THIS PAGE ONLY. The platform navbar
 * (templates/components/navbar.html) is `bg-white … fixed top-0 … shadow-sm` and
 * looks broken floating above the dark room. Scope a dark variant only when the page
 * contains the v2 stage, from stage.css (which loads on the v2 page ONLY). The bar is
 * OUTSIDE `.v2-stage`, so we reach it via body:has(). NOTE: rev-2 tokens are defined
 * on `.v2-stage`, which is NOT an ancestor of the top-bar, so the custom props don't
 * resolve here — the literal rev-2 hexes are used instead (same colours: --stage-2
 * #1B1823, --hairline #232130, --voice-lo #8E8AA3). Graceful degradation: browsers
 * without :has() leave the bar white (current state) — no breakage. NO platform CSS
 * files touched. Specificity (0,6,1) beats Tailwind `.bg-white` (0,1,0) → no !important. */
body:has(.ss-player-page.v2-stage) .fixed.top-0.left-0.right-0.shadow-sm {
  background: #1B1823;
  box-shadow: inset 0 -1px 0 0 #232130;
}
body:has(.ss-player-page.v2-stage) .fixed.top-0.left-0.right-0.shadow-sm i { color: #8E8AA3; }
body:has(.ss-player-page.v2-stage) .fixed.top-0.left-0.right-0.shadow-sm i:hover { color: #EFEDF6; }

/* ============================================================================
 * ============================  WAVE 4  ======================================
 * S2 wave 4 — EMPIRICAL dark sweep. Method: headless Chrome loaded the live
 * ?v2=1 page with data-theme="light" FORCED on <html> (replicating the
 * authenticated platform_base.html cascade — the missing step that let two prior
 * "reason-about-the-cascade" waves miss these), then dumped computed
 * background-color for every visible practice-zone element, filtered to non-dark.
 * The T1 white frame is fixed at source above (--ss-bg in §0). Everything below
 * closes the remaining empirical findings + P1 (progress harmonize) + Mix popover
 * styling (P2 markup in template, wiring in bootstrap). rev-2 tokens only.
 * ==========================================================================*/

/* ----------------------------------------------------------------------------
 * T2 — per-stem waveform canvas washes. ROOT CAUSE: wave 3's W1 transparent rule
 * `.v2-stage .ss-stem-lane .ss-stem-canvas` is (0,3,0), but songsplit.css paints the
 * non-vocal lanes via `.ss-stem-lane:not([data-stem-type="vocals"]):not(.ss-recording-lane)
 * .ss-stem-canvas` which is (0,4,0) — TWO :not() args each add a class-weight — so the
 * blue wash rgba(91,155,245,0.05) WON on the drums/bass/other/tempo lanes (confirmed:
 * tempo-lane-canvas computed bg still rgba(91,155,245,0.05) in the dump). Match (0,4,0)
 * with .ss-stems-container as an extra ancestor; stage.css loads last → the tie resolves
 * here → every stem + tempo lane canvas paints on transparent (its JS well --ss-canvas-bg
 * #0F0D14 shows through). Covers vocals (0,3,0), recording (0,2,0), tempo (0,2,0) too. */
.v2-stage .ss-stems-container .ss-stem-lane .ss-stem-canvas { background: transparent; }

/* ----------------------------------------------------------------------------
 * T4 — record studio reads as a rounded BOX. Rev-2 rule 4: it is a REGION of the stage
 * (top hairline + at most --stage-2 tint), never a box. Wave 2/§9 gave it radius 12 →
 * drop the radius so it's a flush region, keep the --stage-2 tint + single top hairline. */
.v2-stage .ss-record-studio { border-radius: 0; }

/* ----------------------------------------------------------------------------
 * T6 — the trailing "Report" link (+ its popover) read light. Link → --voice-lo (quiet),
 * hover --voice-hi; the popover is a real elevated surface → --stage-2 (rev-2 rule 3). */
.v2-stage .ss-report-link { color: var(--voice-lo); }
.v2-stage .ss-report-link:hover { color: var(--voice-hi); }
.v2-stage .ss-report-popover {
  background: var(--stage-2);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
  color: var(--voice-hi);
}
.v2-stage .ss-report-popover-title { color: var(--voice-hi); }
.v2-stage .ss-report-option { color: var(--voice-lo); }
.v2-stage .ss-report-details {
  background: var(--chip);
  border: 1px solid var(--hairline);
  color: var(--voice-hi);
}

/* ----------------------------------------------------------------------------
 * P1 — My Progress dark harmonize (rev-2 rule 6). The vocal-match reveal inline styles
 * live in player_v2.html AFTER the stage.css <link>, so `.v2-stage` (higher specificity)
 * is required to override them — source order alone would lose. Overrides ONLY:
 *  · metric card bg + border → --stage-2 / --hairline (was faint purple wash)
 *  · "New best!" badge → --accent family (rev-2 bans a new green for success/positive)
 *  · ring track → --hairline (also done in §11; kept here for locality)
 * Card/verdict TEXT already harmonizes via §0 (cards read --ss-text/--ss-text-muted →
 * voice-hi/lo). The reveal's violet score accents (#a855f7) stay — they're --accent
 * family, allowed by rev-2. No vocal-match.js / no inline-style edits. */
.v2-stage .ss-vm-metric-card {
  background: var(--stage-2);
  border: 1px solid var(--hairline);
}
.v2-stage .ss-vm-newbest {
  color: var(--accent);
  background: rgba(139, 92, 246, 0.10);
  border: 1px solid rgba(139, 92, 246, 0.28);
}
.v2-stage .ss-vm-ring-track { stroke: var(--hairline); }

/* ----------------------------------------------------------------------------
 * P2 — the REAL Mix popover shell (wiring + teleport in bootstrap.js). Anchored
 * --stage-2 panel (radius 12 + the one permitted shadow), styled as a channel strip.
 * The live `#stems-sidebar` channel rows are TELEPORTED in on open (existing markup +
 * wiring, no module edit) and returned on close — see bootstrap. */
.v2-stage .v2-mix-popover-wrap { position: relative; }
.v2-stage .v2-mix-popover {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  /* z-ladder: the v1 base .ss-transport-bar is `position:sticky; z-index:90` (songsplit.css),
   * which forms its own stacking context in the root — at z 60 the open popover painted UNDER
   * the transport row (loop/stats/key/reset). Raise ABOVE the transport (90) yet BELOW the
   * ≤768 bottom bar (200) / mix sheet (250) / toast (400) / modals (1000+). */
  z-index: 120;
  width: 300px;
  max-width: calc(100vw - 32px);
  max-height: 70vh;
  overflow-y: auto;
  background: var(--stage-2);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
  padding: 8px;
}
.v2-stage .v2-mix-popover[hidden] { display: none; }
.v2-stage .v2-mix-popover-title {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--voice-lo);
  padding: 4px 8px 8px;
}
.v2-stage .v2-mix-popover-empty { color: var(--voice-lo); font-size: 12.5px; padding: 8px; }
/* Channel-strip rows inside the popover: hairline separators, no boxed cells. The
 * teleported sidebar blocks inherit the §8 stem-lane treatment (transparent + hairline). */
.v2-stage .v2-mix-popover .ss-stems-sidebar { background: transparent; width: 100%; }
.v2-stage .v2-mix-popover .ss-stem-sidebar-block,
.v2-stage .v2-mix-popover .ss-tempo-sidebar-block { border-bottom: 1px solid var(--hairline); }
.v2-stage .v2-mix-popover .ss-stem-sidebar-block:last-child,
.v2-stage .v2-mix-popover .ss-tempo-sidebar-block:last-child { border-bottom: none; }

/* ============================================================================
 * ============================  WAVE 5  ======================================
 * S2 wave 5 — the T4 polish wave: responsive header stacking, Pitch Trace promotion,
 * accessibility + responsive sweep. Additive/surgical — must NOT regress the approved
 * look at wide widths. rev-2 tokens only. Appended LAST (source order tie-breaks here).
 * ==========================================================================*/

/* ----------------------------------------------------------------------------
 * H1 — Pitch Trace promoted to a practice sub-toggle SIBLING (bootstrap owns the
 * new button + wiring). The old inner Note Roll ↔ Pitch Trace mode toggle inside
 * #view-roll is now REDUNDANT in v2 — hide it (scoped; v1's copy is untouched).
 * Not !important: `.v2-stage .ss-pitch-mode-toggle` (0,2,0) beats the v1 base
 * `.ss-pitch-mode-toggle` display rule (0,1,0). The #pitch-mode-roll/-trace buttons
 * still exist in the DOM (switchPitchMode toggles their .active state harmlessly);
 * only their container is removed from view. --------------------------------*/
.v2-stage .ss-pitch-mode-toggle { display: none; }

/* ----------------------------------------------------------------------------
 * H2 — PAPER focus ring. §3's global stage ring is `--accent-60` (violet @60%
 * alpha) — fine on the dark stage, but over the paper Song Sheets it blends toward
 * the paper and reads faint (non-text contrast borderline). Re-color the ring to
 * solid `--accent-deep` (#7C3AED) inside the sheets zone: ~5.3:1 against paper
 * #FAF7F0 (WCAG 1.4.11 non-text ≥3:1 ✓). Keeps §3's 2px width + 2px offset. ----*/
.v2-stage .v2-zone[data-zone="sheets"] :focus-visible {
  outline-color: var(--accent-deep);
}

/* ----------------------------------------------------------------------------
 * H3 — RESPONSIVE HEADER STACKING. Breakpoint 1280px (chosen from the header width
 * math: on the authenticated path the sidebar reserves 256px at ≥1024px, so a 1280
 * viewport leaves ~1024px of content — right at the edge where thumbnail + title +
 * 4 meta chips (~430px) + the Mix/record/⋯ cluster (~190px) stop co-fitting and the
 * title truncates). Below it the header reflows to two rows:
 *   row 1 = thumbnail + FULL title (wrapping, no ellipsis) + the right-cluster controls
 *           (Mix / record / ⋯ stay top-right)
 *   row 2 = the meta chips, left-aligned, wrapping.
 *
 * MECHANISM (no markup surgery): the meta chips (.ss-player-header-right) are nested
 * one level deeper than the action cluster (.v2-header-actions is a sibling of
 * .ss-player-header, the chips live INSIDE it), so plain flex on .v2-header can't put
 * the chips on their own row below both. `display: contents` on .ss-player-header
 * dissolves its box and promotes .ss-player-header-left + .ss-player-header-right to be
 * direct flex children of .v2-header (already display:flex + flex-wrap:wrap). Then order
 * + a 100% basis on the chips row lays out exactly as specified. display:contents is
 * a plain presentational div here (no role/semantics lost) — well-supported; without it
 * the header simply keeps the wide single-row layout (graceful, never a break). --------*/
@media (max-width: 1280px) {
  .v2-stage .ss-player-header { display: contents; }

  /* Row 1 left: thumbnail + title block grows to push the actions to the right edge. */
  .v2-stage .ss-player-header-left { order: 0; flex: 1 1 auto; min-width: 0; }
  /* Row 1 right: the Mix / record / ⋯ cluster stays top-right. */
  .v2-stage .v2-header-actions { order: 1; flex: 0 0 auto; }
  /* Row 2: meta chips break to their own full-width line, left-aligned, wrapping. */
  .v2-stage .ss-player-header-right {
    order: 2;
    flex-basis: 100%;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 8px;
  }

  /* FULL title — allow wrapping, drop the v1 ellipsis (base .ss-player-title is
     nowrap + overflow:hidden + text-overflow:ellipsis; (0,2,0) beats v1 (0,1,0)). */
  .v2-stage .ss-player-title {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }
}

/* ----------------------------------------------------------------------------
 * H4 — modal surface under FORCED-light theme. Found by the wave-5 light-theme dump
 * (data-theme="light" on <html>, the authenticated cascade): the upsell modal read
 * WHITE. ROOT CAUSE: songsplit.css `[data-theme="light"] .ss-modal { background:
 * rgba(255,255,255,.95) }` (0,2,0) — a literal white, so §0's dark `--ss-surface`
 * can't reach it. CRUCIAL: #upsell-modal is rendered as a SIBLING AFTER
 * .ss-player-page — it is OUTSIDE `.v2-stage` (verified: modal.closest('.v2-stage')
 * === null at runtime), so a `.v2-stage .ss-modal` scope never matches. Reach it the
 * same way W6 reaches the (also-outside) top-bar: `body:has(.ss-player-page.v2-stage)`
 * — active only on the v2 page. rev-2 tokens are defined on `.v2-stage`, NOT an
 * ancestor of the teleported modal, so LITERAL hexes are used (same colours: --stage-2
 * #1B1823, --hairline #232130). Specificity (0,3,1) [body + :has(.ss-player-page.v2-stage)
 * + .ss-modal] beats `[data-theme="light"] .ss-modal` (0,2,0) → wins regardless of order,
 * no !important. Graceful degradation: no :has() → modal stays white (current state),
 * never a break. Modal TEXT already stays light (§0 pins --ss-text/-muted on :root, a
 * documentElement var that reaches the modal even outside .v2-stage). Before: 1 non-dark
 * el in modal; after: 0. --------------------------------------------------------------*/
body:has(.ss-player-page.v2-stage) .ss-modal-overlay { background: rgba(0, 0, 0, 0.55); }
body:has(.ss-player-page.v2-stage) .ss-modal {
  background: #1B1823;
  border: 1px solid #232130;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
}

/* ============================================================================
 * ============================  S3 — WAVE 1  ================================
 * §14 MOBILE IA (≤768px). Mobile is a LAYOUT MODE of the same page, not a fork:
 * the bottom zone bar (additive markup, hidden ≥769px) takes over zone switching;
 * the tally-lamp record relocates to its raised center; the top zone nav + header
 * record proxy hide; the header compacts. Desktop ≥769px is untouched (the bar is
 * display:none there, and every mobile rule lives inside the max-width query below).
 * The bar's height budget feeds the content bottom padding so nothing hides behind it.
 * ==========================================================================*/

/* Bar is desktop-hidden by default — never paints ≥769px. */
.v2-stage .v2-bottom-bar { display: none; }

@media (max-width: 768px) {
  /* -- The bottom bar: fixed, --stage-2 region, top hairline, safe-area inset. 4 equal
     slots; overflow visible so the raised record circle can poke above the top edge. -- */
  .v2-stage .v2-bottom-bar {
    display: flex;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 200;                       /* above zone content; the toast, Mix sheet + modals each layer ABOVE it (see their ≤768 rules below) */
    align-items: center;
    justify-content: space-around;
    gap: 2px;
    padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
    background: var(--stage-2);
    border-top: 1px solid var(--hairline);
    overflow: visible;
  }

  /* Zone slots — icon over 10.5px label, quiet by default, ≥44px touch target. */
  .v2-stage .v2-bar-btn {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-width: 0;
    min-height: 44px;
    padding: 4px 2px;
    background: transparent;
    border: none;
    color: var(--voice-lo);
    transition: color 150ms ease-out;
  }
  .v2-stage .v2-bar-ic { display: block; }
  .v2-stage .v2-bar-label {
    font-size: 10.5px;
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
  }
  /* Active zone: --voice-hi label, --accent icon (matches the top nav's active language). */
  .v2-stage .v2-bar-btn-active { color: var(--voice-hi); }
  .v2-stage .v2-bar-btn-active .v2-bar-ic { color: var(--accent); }

  /* -- The raised center record: the tally lamp relocated. SAME visual rules as
     .v2-btn--record — 56px --lamp circle, breathing idle glow, lifted above the bar
     (camera-app pattern). ON AIR (root .v2-recording) → solid + brighter halo, steady. -- */
  .v2-stage .v2-bar-record {
    flex: 0 0 auto;
    width: 56px;
    height: 56px;
    padding: 0;
    margin-top: -20px;                  /* lift the circle above the bar's top edge */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--lamp);
    border: 3px solid var(--stage-2);   /* seat it in the bar (not a --lamp border — that's the halo's job) */
    box-shadow: 0 0 14px var(--lamp-glow);
    color: #fff;
    animation: v2-tally-breathe 2.6s ease-in-out infinite;
  }
  .v2-stage .v2-bar-record svg { display: block; }
  .v2-stage.v2-recording .v2-bar-record {
    animation: none;
    box-shadow: 0 0 20px rgba(229, 73, 59, 0.6);
  }

  /* -- Top zone nav yields to the bar; header record proxy hides (bar owns record). -- */
  .v2-stage .v2-zones { display: none; }
  .v2-stage .v2-btn--record { display: none; }   /* header proxy — the bar lamp replaces it ≤768 */

  /* -- Header compaction: full wrapping title already lands (the ≤1280 block); here the
     meta chips collapse to ONE horizontally scrollable row (no wrap, no scrollbar chrome),
     Mix ▾ + ⋯ stay top-right. -- */
  .v2-stage .v2-header { padding: 16px 16px 12px; gap: 12px; }
  .v2-stage .ss-player-header-right {
    display: flex;                      /* v1 base is display:block here — force the row */
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;              /* Firefox — hide the chrome */
  }
  .v2-stage .ss-player-header-right::-webkit-scrollbar { display: none; }  /* WebKit */
  /* Each chip shrinks to its content so the row scrolls instead of stacking. */
  .v2-stage .ss-player-detail { flex: 0 0 auto; width: auto; }
  .v2-stage .v2-header-actions { gap: 8px; }

  /* -- Transport compaction + content bottom padding in ONE declaration (no split
     shorthand+override): tighter side gutters (12px) as the slim top strip, and the
     bottom = bar height budget (~64px, covers the visible bar + safe area) so the last
     zone content never hides behind the fixed bar. -- */
  .v2-stage .v2-main { padding: 14px 12px calc(var(--v2-bar-h) + env(safe-area-inset-bottom)); }
  /* The footer/legal overflow surface clears the bar the same way. */
  .v2-stage .ss-player-footer-legal { padding-bottom: calc(var(--v2-bar-h) + env(safe-area-inset-bottom)); }

  /* -- ZONE-CONTENT SWEEP (Task 2) --------------------------------------------------- */

  /* Stem lanes compact: the base ≤768 rules already stack sidebar-over-canvas + row the
     controls; here we tighten to the pinned spec — M/S 32px console chips, name truncates
     at ~72px, the volume slider flexes to fill, canvas keeps the full stacked width. */
  .v2-stage .ss-mute-btn,
  .v2-stage .ss-solo-btn { min-width: 32px; }              /* console density (touch note: sub-44, see report) */
  .v2-stage .ss-stem-name { max-width: 72px; }             /* truncate long names (base already ellipsises) */
  .v2-stage .ss-stem-bottom .ss-stem-volume { flex: 1 1 auto; min-width: 0; }

  /* Practice sub-nav + sheet tabs → one horizontally scrollable chip row (no wrap, no
     scrollbar chrome). Chips shrink-to-content so the row scrolls instead of stacking.
     (#view-tabs.ss-view-tabs already scrolls via its base rule; this covers the practice
     melody sub-nav too and gives the chips a 44px touch height on mobile.) */
  .v2-stage .v2-subnav {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .v2-stage .v2-subnav::-webkit-scrollbar { display: none; }
  .v2-stage .v2-subnav-btn,
  .v2-stage .v2-subnav .ss-view-tab { flex: 0 0 auto; min-height: 44px; }

  /* Song Sheets paper: full-width within the 12px main gutters (max-width:880 + margin
     auto already collapses to viewport width on mobile); trim the desktop 26/30 padding
     to a comfortable phone reading inset. Tabs stay intact (attached to the paper top). */
  .v2-stage .v2-zone[data-zone="sheets"] .ss-view-panel { padding: 20px 16px; }

  /* My Progress reveal: the ring (200px) + metric cards (max-width:360px) already fit a
     390px column inside the 12px gutters; trim the reveal side padding so nothing crowds. */
  .v2-stage #view-vocalmatch .ss-vm-reveal { padding-left: 8px; padding-right: 8px; }

  /* -- MIX POPOVER → BOTTOM SHEET (≤768px only) -------------------------------------
     CSS alone docks it: overriding the desktop absolute-in-wrap positioning to `fixed`
     detaches it from .v2-mix-popover-wrap and pins it to the viewport, full-width, docked
     ABOVE the bottom bar (bottom = bar height + safe area), ~60vh with internal scroll.
     No bootstrap mobile-position branch needed — the same toggle / outside-click / Escape
     wiring is untouched (moving position doesn't change .contains()). z-order: above the
     bar (200), below modals (1000+). No transformed ancestor traps the fixed box. -- */
  .v2-stage .v2-mix-popover {
    position: fixed;
    left: 0;
    right: 0;
    top: auto;
    bottom: calc(var(--v2-bar-h) + env(safe-area-inset-bottom));
    width: auto;
    max-width: none;
    max-height: 60vh;
    overflow-y: auto;
    border-radius: 14px 14px 0 0;
    z-index: 250;                       /* above the bar (200), below modals (overlay 1000+) */
  }

  /* -- TOAST above the bar (T1 carry #1): the shared .ss-toast (base z-index 200, bottom
     24px) tied with the bar and lost on DOM order → recorder mic/status toasts hid behind
     it. Scoped to the v2 page (#ss-toast lives INSIDE .ss-player-page.v2-stage): lift it
     above the bar AND reposition above it (bar height + safe area + 12px gap). Only bottom
     + z-index change — the base translateX/translateY reveal transition is preserved. -- */
  .v2-stage .ss-toast {
    bottom: calc(var(--v2-bar-h) + env(safe-area-inset-bottom) + 12px);
    z-index: 400;                       /* above bar (200) + Mix sheet (250), below modals (1000+) */
  }

  /* Modals fit with 12px side gutters. The upsell/export modals teleport OUTSIDE .v2-stage
     (reached via body:has, per §H4), so cap the modal width to the viewport minus 24px. */
  body:has(.ss-player-page.v2-stage) .ss-modal { max-width: calc(100vw - 24px); }
}

/* ============================================================================
 * =====================  REUSED MIXER ACCENTS (P2-T2 Task 6)  ================
 * Task 6 RETIRED the post-record wizard on v2 (step indicator → Preview & Polish
 * mix panel → Share panel are never built once `onTakeSaved` is injected), so the
 * old S3-T3 dark-skin for `.ss-mix-panel` / `.ss-share-panel--player` / `.ss-step-*`
 * is GONE — that DOM no longer renders on the stage (confirmed: recorder.js only
 * reaches those builders on the v1 gate; stage.css is v2-only).
 *
 * What REMAINS: the Basic / Full mixer (`createMixerSection` / `buildBasicMix`) is
 * REUSED — surfaced on demand from the score card's "Polish the mix" (mixer sheet)
 * and the Hear-it-back Voice↔Music balance slider. Its base geometry comes from
 * songsplit.css (v1 BLUE #5b9bf5); these rules re-accent it to the brand violet so
 * it belongs on the dark stage. Kept verbatim from the removed skin block.
 * ==========================================================================*/
.v2-stage .ss-mixer-tab.active {
  background: rgba(139, 92, 246, 0.15);
  color: var(--accent);
}
.v2-stage .ss-basic-mix-labels { color: var(--accent); }
.v2-stage .ss-basic-mix-slider::-webkit-slider-thumb {
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
}
.v2-stage .ss-basic-mix-slider::-moz-range-thumb {
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
}
.v2-stage .ss-mixer-fader::-webkit-slider-thumb:hover { background: var(--accent); }
.v2-stage .ss-mixer-fader::-moz-range-thumb:hover { background: var(--accent); }

/* ============================================================================
 * 15. THE SAVING STRIP (P2-T2) — the slim post-record surface take-flow paints
 *     into the DEDICATED #v2-postrecord node (a sibling of #recording-placeholder-wrap,
 *     so it NEVER clobbers the live #record-studio) the instant a recording stops.
 *     It shows "✓ Take N saved" with a Listening → Matching → Scoring shimmer while
 *     T1 scores the take, resolving into a basic "Take N · 82" line. Later tranche
 *     tasks replace it with the full inline card. All colours are pinned tokens.
 * ==========================================================================*/
/* Post-record mount (CHECKPOINT 1): now sits DIRECTLY below the transport bar and ABOVE the
 * .v2-zone tab content, persistent across zones. Empty = zero-height (no margin) so it never
 * disturbs layout; once take-flow paints, it spaces itself off the transport and the zone below. */
.v2-stage .v2-postrecord:not(:empty) { margin: 12px 0; }
.v2-stage .v2-saving-strip {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 14px;
  padding: 12px 16px;
  background: var(--stage-2);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  color: var(--voice-hi);
  font-size: 13.5px;
}
.v2-stage .v2-saving-check { color: var(--accent); flex: 0 0 auto; }
.v2-stage .v2-saving-label { font-weight: 600; }
.v2-stage .v2-saving-sub { color: var(--voice-lo); font-size: 12px; }

/* Spinner (pre-confirm "Saving…") — a thin --accent arc. */
.v2-stage .v2-saving-spinner {
  width: 15px; height: 15px; flex: 0 0 auto;
  border: 2px solid var(--hairline);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: v2-saving-spin 0.7s linear infinite;
}
@keyframes v2-saving-spin { to { transform: rotate(360deg); } }

/* Stage shimmer — the active stage carries an --accent sweep; done stages fade. */
.v2-stage .v2-saving-stages {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--voice-lo);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
}
.v2-stage .v2-saving-arrow { color: var(--hairline); }
.v2-stage .v2-saving-stage { color: var(--voice-lo); transition: color 0.15s ease; }
.v2-stage .v2-saving-stage.is-done { color: var(--voice-lo); opacity: 0.55; }
.v2-stage .v2-saving-stage.is-active {
  color: var(--accent);
  background: linear-gradient(90deg, var(--accent) 25%, var(--voice-hi) 50%, var(--accent) 75%);
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: v2-saving-shimmer 1.2s linear infinite;
}
@keyframes v2-saving-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* Actions — flat chips; "Hear it back" is the accent action. */
.v2-stage .v2-saving-actions { display: inline-flex; gap: 8px; margin-left: auto; }
.v2-stage .v2-saving-hear,
.v2-stage .v2-saving-discard {
  padding: 6px 12px;
  border-radius: 8px;
  border: 1px solid var(--hairline);
  background: var(--chip);
  color: var(--chip-text);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.v2-stage .v2-saving-hear { color: var(--accent); }
.v2-stage .v2-saving-hear:hover { background: var(--stage-2); color: var(--voice-hi); }
.v2-stage .v2-saving-discard:hover { background: var(--stage-2); color: var(--voice-hi); }

/* Reduced motion — no spin, no shimmer; the active stage is a static --accent label. */
@media (prefers-reduced-motion: reduce) {
  .v2-stage .v2-saving-spinner { animation: none; }
  .v2-stage .v2-saving-stage.is-active { animation: none; -webkit-text-fill-color: var(--accent); }
}
.v2-stage .v2-saving-strip--reduced .v2-saving-spinner { animation: none; }
.v2-stage .v2-saving-strip--reduced .v2-saving-stage.is-active {
  animation: none; -webkit-text-fill-color: var(--accent);
}

/* ============================================================================
 * 16. THE INLINE SCORE CARD (P2-T2) — "earn the spotlight" (DAVE CHECKPOINT 1)
 *     When scoring lands, take-flow replaces the saving strip with this: a VIOLET
 *     count-up ring (the score is the hero, the ring is its frame — NOT a red/amber/
 *     green traffic light; that stays on the My Progress reveal), one self-referential
 *     coach sentence, three neutral metric chips, and actions. Withheld/failed
 *     show the fixed reason, never a 0. All colours are pinned REV 2 tokens.
 * ==========================================================================*/
.v2-stage .v2-score-card {
  box-sizing: border-box;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 24px 20px 20px;
  background: var(--stage-2);
  border: 1px solid var(--hairline);
  border-radius: 12px;                       /* card radius */
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); /* the ONE card shadow */
  text-align: center;
}
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-score-card { animation: v2-score-in 0.28s ease-out both; }
}
@keyframes v2-score-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* Ring — the signature. SVG track is a quiet hairline; the fill stroke + colour are
 * driven inline by take-flow (ringColor). Hero number sits dead-centre over it. */
.v2-stage .v2-score-ring {
  position: relative;
  width: 176px;
  height: 176px;
}
.v2-stage .v2-score-ring-svg {
  width: 176px;
  height: 176px;
  display: block;
}
.v2-stage .v2-score-ring-track { stroke: var(--hairline); }
.v2-stage .v2-score-hero {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  pointer-events: none;
}
.v2-stage .v2-score-num {
  font-size: 58px;
  font-weight: 700;
  line-height: 1;
  color: var(--voice-hi);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.v2-stage .v2-score-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--voice-lo);
}

/* Coach line — one honest sentence, the verdict in words. */
.v2-stage .v2-score-coach {
  margin: 0;
  max-width: 30ch;
  font-size: 14.5px;
  line-height: 1.45;
  color: var(--voice-hi);
}

/* Metric chips are TABS (P2-T3 Task 5) — Match Score · Pitch · Timing · Note. Selecting one drives
 * the hero headline + the progress graph. Still CHECKPOINT 1 neutral: label + value (+ an earned
 * ▲gain over the singer's own start line), never a "weakest" highlight. */
.v2-stage .v2-score-chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}
.v2-stage .v2-metric-chip {
  position: relative;                        /* anchors the Task 6 PB ember dot */
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 6px 10px;
  border-radius: 6px;                        /* chip radius */
  border: 1px solid var(--hairline);
  background: var(--chip);
  font-size: 12px;
  font-family: inherit;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
.v2-stage .v2-metric-chip:hover { border-color: var(--accent); }
.v2-stage .v2-metric-chip[aria-selected="true"] {
  border-color: var(--accent);
  background: var(--accent-soft, rgba(139, 92, 246, 0.12));
  box-shadow: inset 0 0 0 1px var(--accent);
}
.v2-stage .v2-metric-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.v2-stage .v2-metric-chip-label {
  color: var(--chip-text);
  font-weight: 600;
}
.v2-stage .v2-metric-chip-val {
  color: var(--voice-hi);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.v2-stage .v2-metric-chip-delta {
  color: var(--accent);
  font-weight: 700;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

/* ── THE EMBER (P2-T3 Task 6) — the per-metric personal-best discovery dot ────────────────────
 * A small breathing dot in THAT metric's own colour, pinned to the chip's top-right corner. It
 * says "you've a best waiting here" without a word. Colour rides the inline --ember custom prop
 * (METRIC_COLORS[metric].bright, set by take-flow). Clicking the chip rests it (dot removed) and,
 * if the latest is still that metric's PB, lifts the hero haze below. Reduced motion → a static
 * solid dot (still information, just no pulse). */
.v2-stage .v2-ember {
  position: absolute;
  top: -3px;
  right: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ember, #A78BFA);
  box-shadow: 0 0 7px 1px var(--ember, #A78BFA);
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-ember { animation: v2-ember-breathe 2.4s ease-in-out infinite; }
}
@keyframes v2-ember-breathe {
  0%, 100% { opacity: 0.55; transform: scale(1); }
  50%      { opacity: 1;    transform: scale(1.3); }
}

/* PB haze — behind the hero when a sub-metric at its personal best is selected. A single soft
 * halo in the metric colour (--pb-glow, an rgba set by take-flow); the takeover's one-disciplined-
 * bloom recipe, scaled down to the card. Reduced motion → static halo, no bloom-in. */
.v2-stage .v2-score-hero--pb {
  border-radius: 50%;
  box-shadow: 0 0 40px 8px var(--pb-glow, rgba(139, 92, 246, 0.55));
}
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-score-hero--pb { animation: v2-pb-haze-in 0.5s ease-out both; }
}
@keyframes v2-pb-haze-in {
  from { box-shadow: 0 0 0 0 var(--pb-glow, rgba(139, 92, 246, 0.55)); }
  to   { box-shadow: 0 0 40px 8px var(--pb-glow, rgba(139, 92, 246, 0.55)); }
}

/* Actions — Go again is the live accent action; Share / Polish are visibly disabled
 * until Task 6 relocates them (never wired to the legacy share/mix surface here). */
.v2-stage .v2-score-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin-top: 2px;
}
.v2-stage .v2-score-btn {
  padding: 9px 16px;
  border-radius: 8px;
  border: 1px solid var(--hairline);
  background: var(--chip);
  color: var(--chip-text);
  font-size: 13px;
  font-weight: 600;
  font-family: var(--font-body);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.v2-stage .v2-score-btn:hover { background: var(--stage-2); color: var(--voice-hi); }
.v2-stage .v2-score-btn--go {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.v2-stage .v2-score-btn--go:hover { background: var(--accent-deep); border-color: var(--accent-deep); color: #fff; }
.v2-stage .v2-score-btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}
.v2-stage .v2-score-btn[disabled]:hover { background: var(--chip); color: var(--chip-text); }

/* ── Hear it back (P2-T2 Task 6): MIXED voice+backing playback + the ONE Voice↔Music
 *    balance slider (reveals only when playback is a real mix). SVG play/pause, never emoji. */
.v2-stage .v2-score-playback {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 100%;
}
.v2-stage .v2-score-hear {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 18px;
  border-radius: 999px;                        /* the playback pill — distinct from square action chips */
  border: 1px solid var(--accent);
  background: transparent;
  color: var(--accent);
  font-size: 13px;
  font-weight: 600;
  font-family: var(--font-body);
  cursor: pointer;
  transition: background 0.14s ease-out, color 0.14s ease-out;
}
.v2-stage .v2-score-hear:hover { background: rgba(139, 92, 246, 0.12); }
.v2-stage .v2-score-hear[aria-pressed="true"] {
  background: var(--accent);
  color: #fff;
}
.v2-stage .v2-score-hear-ico { display: inline-flex; }
/* The balance slot hosts the recorder's Basic Mix (Voice↔Music) — one slider, full card width. */
.v2-stage .v2-score-balance {
  width: 100%;
  max-width: 320px;
}
.v2-stage .v2-score-balance[hidden] { display: none; }
.v2-stage .v2-score-balance .ss-basic-mix { margin: 0; }

/* Withheld / failed — honest, neutral, non-alarming. Icon is --voice-lo (NOT --lamp). */
.v2-stage .v2-score-card--withheld {
  align-items: stretch;
  text-align: left;
  gap: 14px;
  padding: 18px 18px 16px;
}
.v2-stage .v2-score-withheld-top {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.v2-stage .v2-score-withheld-icon {
  flex: 0 0 auto;
  color: var(--voice-lo);
  margin-top: 1px;
}
.v2-stage .v2-score-withheld-copy { min-width: 0; }
.v2-stage .v2-score-withheld-title {
  margin: 0 0 3px;
  font-size: 14px;
  font-weight: 600;
  color: var(--voice-hi);
}
.v2-stage .v2-score-withheld-msg {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--voice-lo);
}
.v2-stage .v2-score-withheld-note {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--voice-lo);
  opacity: 0.85;
}
.v2-stage .v2-score-card--withheld .v2-score-actions { justify-content: flex-start; }

/* Narrow stage — shrink the ring + hero so the card breathes on a phone. */
@media (max-width: 768px) {
  .v2-stage .v2-score-ring,
  .v2-stage .v2-score-ring-svg { width: 150px; height: 150px; }
  .v2-stage .v2-score-num { font-size: 50px; }
  .v2-stage .v2-score-card { padding: 20px 16px 16px; }
}

/* ============================================================================
 * 17. THE PERSONAL-BEST TAKEOVER (P2-T2 Task 3) — "earn the spotlight" (CHECKPOINT 2)
 *     The ONLY state that takes over the screen. When a take beats the singer's
 *     PREVIOUS best, take-flow overlays this full-bleed spotlight above the inline
 *     card: the room dims to --stage, a single warm violet light rises behind an
 *     ENLARGED count-up ring (the same violet ring, never a traffic light), the delta
 *     over their previous best, and actions. Restraint is the point — every other take
 *     stays the calm inline card. Reduced motion: it still appears, but static. No red
 *     (--lamp is record-only), no confetti — one disciplined violet bloom.
 * ==========================================================================*/
.v2-stage .v2-takeover {
  position: fixed;
  inset: 0;
  z-index: 900;                                /* above zone content, bar (200), mix sheet (250), toast (400); below global modals (1000+) */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  /* the room dims — near-opaque --stage so the card beneath reads only as a glow */
  background: rgba(19, 17, 24, 0.94);          /* --stage @ 94% */
  -webkit-tap-highlight-color: transparent;
}
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-takeover { animation: v2-takeover-fade 0.3s ease-out both; }
}
@keyframes v2-takeover-fade { from { opacity: 0; } to { opacity: 1; } }

/* The spotlight — one warm violet light pooled behind the ring. It blooms in once, then
 * rests. This is the signature: the room goes quiet and a single light rises. */
.v2-stage .v2-takeover-glow {
  position: absolute;
  top: 42%;
  left: 50%;
  width: min(560px, 92vw);
  height: min(560px, 92vw);
  transform: translate(-50%, -50%);
  pointer-events: none;
  background: radial-gradient(circle at center,
    rgba(139, 92, 246, 0.34) 0%,
    rgba(124, 58, 237, 0.16) 34%,
    rgba(139, 92, 246, 0) 68%);
}
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-takeover-glow { animation: v2-takeover-bloom 0.7s ease-out both; }
}
@keyframes v2-takeover-bloom {
  from { opacity: 0; transform: translate(-50%, -50%) scale(0.7); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

.v2-stage .v2-takeover-inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  text-align: center;
  max-width: 420px;
  width: 100%;
}
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-takeover-inner { animation: v2-takeover-rise 0.5s 0.06s ease-out both; }
}
@keyframes v2-takeover-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* Done — a quiet ghost affordance, top-right of the spotlight. Keyboard-reachable. */
.v2-stage .v2-takeover-close {
  position: absolute;
  top: -8px;
  right: 0;
  padding: 6px 10px;
  border: none;
  background: transparent;
  color: var(--voice-lo);
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: color 0.15s ease;
}
.v2-stage .v2-takeover-close:hover { color: var(--voice-hi); }

/* Badge — small, uppercase, the brand violet. The word that earns the spotlight. */
.v2-stage .v2-takeover-badge {
  display: inline-flex;
  align-items: center;
  padding: 5px 14px;
  border-radius: 999px;
  background: rgba(139, 92, 246, 0.16);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
}

/* Ring — the enlarged twin of the inline card's ring (same fill/colour, driven by take-flow). */
.v2-stage .v2-takeover-ring.v2-score-ring {
  width: 232px;
  height: 232px;
}
.v2-stage .v2-takeover-ring .v2-score-ring-svg {
  width: 232px;
  height: 232px;
}
.v2-stage .v2-takeover-ring .v2-score-num { font-size: 76px; }

/* Delta — the self-referential verdict: how far past their own best they went. */
.v2-stage .v2-takeover-delta {
  margin: 0;
  font-size: 19px;
  font-weight: 700;
  color: var(--voice-hi);
  letter-spacing: -0.01em;
}
.v2-stage .v2-takeover-prev {
  margin: -8px 0 0;
  font-size: 13px;
  color: var(--voice-lo);
}

.v2-stage .v2-takeover-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin-top: 6px;
}

/* Reduced motion — the takeover still APPEARS (it's information) but nothing moves: no fade,
 * no bloom, no rise, no ring count-up (take-flow pre-fills the ring). The glow is a static state. */
@media (prefers-reduced-motion: reduce) {
  .v2-stage .v2-takeover,
  .v2-stage .v2-takeover-glow,
  .v2-stage .v2-takeover-inner { animation: none; }
}
.v2-stage .v2-takeover--static,
.v2-stage .v2-takeover--static .v2-takeover-glow,
.v2-stage .v2-takeover--static .v2-takeover-inner { animation: none; }

/* Narrow stage — the spotlight clears the fixed bottom bar (it's fixed inset:0, above z-200)
 * and the ring shrinks so the delta + actions fit a phone column. */
@media (max-width: 768px) {
  .v2-stage .v2-takeover { padding: 20px 16px; }
  .v2-stage .v2-takeover-ring.v2-score-ring,
  .v2-stage .v2-takeover-ring .v2-score-ring-svg { width: 196px; height: 196px; }
  .v2-stage .v2-takeover-ring .v2-score-num { font-size: 62px; }
  .v2-stage .v2-takeover-delta { font-size: 17px; }
}

/* ============================================================================
 * 18. THE SESSION TAKE STRIP (P2-T2 Task 4) — the persistent "where am I across
 *     my takes" surface. take-flow paints it into #v2-take-strip, which sits
 *     DIRECTLY below the transport and ABOVE #v2-postrecord (a sibling, so the
 *     transient card never wipes the strip). Chips read chronological L→R (the
 *     trajectory), reusing the .ss-take-btn chip language (--chip · radius 6 ·
 *     120ms ease-out). SVG glyphs only. A session trend arrow closes the row.
 *     Placement note: strip = persistent nav; the card below is its detail panel.
 * ==========================================================================*/
.v2-stage .v2-take-strip-wrap:not(:empty) { margin: 12px 0; }
/* The strip is a row: [‹ older] [ the take window ] [newer ›] [session trend]. The chip window is
 * a CAROUSEL — desktop shows ~5 takes (most-recent by default) and pages with the chevrons; ≤768
 * the track becomes a horizontal scroll-row (swipe IS the carousel) and the chevrons hide. */
.v2-stage .v2-take-strip {
  display: flex;
  align-items: stretch;
  gap: 6px;
  min-width: 0;
}
/* The viewport clips the sliding track to a stable ~5-chip window (its px width is measured + set by
 * take-flow so it hugs 5 chips and never resizes mid-slide). max-width:100% guarantees it can never
 * push the page into a horizontal scroll. On ≤768 it turns transparent and the track scrolls natively. */
.v2-stage .v2-take-viewport {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
}
/* The track holds EVERY chip; desktop paging TRANSLATES it (the glide), so the eye reads how many takes
 * there are as they slide past. ~300ms standard-ease is a carousel slide, not a micro-transition. */
.v2-stage .v2-take-track {
  display: flex;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: 6px;
  min-width: 0;
  transform: translateX(0);
  transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
  will-change: transform;
}

/* Carousel chevrons — quiet chip-language buttons (radius 8, --chip), desktop only. Disabled = dim. */
.v2-stage .v2-take-nav {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 28px;
  align-self: stretch;
  background: var(--chip);
  border: 1px solid var(--hairline);
  border-radius: 8px;                           /* button radius */
  color: var(--voice-lo);
  cursor: pointer;
  transition: color 120ms ease-out, background 120ms ease-out;
}
.v2-stage .v2-take-nav:hover { color: var(--voice-hi); background: var(--stage-2); }
.v2-stage .v2-take-nav[disabled] { opacity: 0.32; cursor: default; }
.v2-stage .v2-take-nav[disabled]:hover { color: var(--voice-lo); background: var(--chip); }
.v2-stage .v2-take-nav svg { display: block; }

/* The chip — one take: the control row on top, a readable date underneath (dates disambiguate
 * legacy takes that all read "Take 1"). Reuses the flat --chip resting look, radius 6. */
.v2-stage .v2-take-chip {
  display: inline-flex;
  flex-direction: column;
  align-items: stretch;
  flex: 0 0 auto;
  gap: 1px;
  padding: 3px 5px 4px;
  background: var(--chip);
  border: 1px solid transparent;
  border-radius: 6px;                           /* chip radius */
  color: var(--voice-lo);
  transition: background 120ms ease-out, border-color 120ms ease-out;
}
.v2-stage .v2-take-chip:hover { background: var(--stage-2); }
.v2-stage .v2-take-chip-main { display: inline-flex; align-items: center; gap: 2px; }

/* Date line — quiet meta, centred under the controls. "3 Jul '26". */
.v2-stage .v2-take-chip-date {
  color: var(--voice-lo);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-align: center;
  white-space: nowrap;
  padding: 0 2px;
  min-height: 12px;                             /* reserve the row even when a date is missing */
}

/* Chip sub-buttons — bare, inherit the chip's colour; each does exactly one job. */
.v2-stage .v2-take-chip-play,
.v2-stage .v2-take-chip-body,
.v2-stage .v2-take-chip-exclude {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 5px;
  background: transparent;
  border: none;
  border-radius: 5px;
  color: inherit;
  font-family: var(--font-body);
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  transition: color 120ms ease-out, background 120ms ease-out;
}
.v2-stage .v2-take-chip-play { color: var(--accent); padding: 4px 4px; }
.v2-stage .v2-take-chip-play:hover { color: var(--ss-accent-hover); }
.v2-stage .v2-take-chip-play svg { display: block; }
.v2-stage .v2-take-chip-body:hover { color: var(--voice-hi); }
.v2-stage .v2-take-chip-label { white-space: nowrap; }
.v2-stage .v2-take-chip-score {
  color: var(--voice-hi);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.v2-stage .v2-take-chip-score--none { color: var(--voice-lo); }
.v2-stage .v2-take-chip-score--pending { display: inline-flex; align-items: center; }
.v2-stage .v2-take-chip-star { display: inline-flex; color: var(--accent); }
.v2-stage .v2-take-chip-star svg { display: block; }

/* Exclude affordance — quiet by default, the whole chip's state cue when active. A hover/focus
 * tooltip ("Hide from your progress") makes the ⊘ discoverable (Dave Checkpoint-3 #5). */
.v2-stage .v2-take-chip-exclude { position: relative; color: var(--voice-lo); opacity: 0.6; padding: 4px; }
.v2-stage .v2-take-chip-exclude:hover { color: var(--voice-hi); opacity: 1; }
.v2-stage .v2-take-chip-exclude svg { display: block; }
.v2-stage .v2-take-chip-exclude::after {
  content: attr(data-tip);
  position: absolute;
  top: calc(100% + 7px);                        /* below the chip — clears the transport above the strip */
  left: 50%;
  transform: translateX(-50%) translateY(-3px);
  padding: 5px 9px;
  background: var(--stage-2);
  border: 1px solid var(--hairline);
  border-radius: 6px;
  color: var(--voice-hi);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  z-index: 20;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
  transition: opacity 120ms ease-out, transform 120ms ease-out;
}
.v2-stage .v2-take-chip-exclude:hover::after,
.v2-stage .v2-take-chip-exclude:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Current take — the "you are here" endpoint of the trajectory: a thin accent frame. */
.v2-stage .v2-take-chip--current { border-color: var(--accent); }
.v2-stage .v2-take-chip--current .v2-take-chip-label { color: var(--voice-hi); }

/* Best take — the ★ carries it (already --accent); nothing else shouts. */
.v2-stage .v2-take-chip--best .v2-take-chip-score { color: var(--voice-hi); }

/* Unscored (withheld / failed / pending) — dim, the body isn't a link. */
.v2-stage .v2-take-chip--unscored { opacity: 0.72; }
.v2-stage .v2-take-chip-body[disabled] { cursor: default; }
.v2-stage .v2-take-chip-body[disabled]:hover { color: inherit; }

/* Excluded — dimmed out of the trajectory; its exclude glyph stays lit to show it's toggled off. */
.v2-stage .v2-take-chip--excluded { opacity: 0.45; }
.v2-stage .v2-take-chip--excluded .v2-take-chip-exclude { opacity: 1; color: var(--voice-hi); }

/* Pending spinner — a tiny --accent arc (reuses the saving-strip spin keyframe). */
.v2-stage .v2-take-chip-spin {
  width: 11px; height: 11px;
  border: 2px solid var(--hairline);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: v2-saving-spin 0.7s linear infinite;
}

/* Session trend arrow — quiet --voice-lo, brightens to --accent only when improving. */
.v2-stage .v2-take-trend {
  display: inline-flex;
  align-items: center;
  margin-left: 4px;
  padding: 4px;
  color: var(--voice-lo);
}
.v2-stage .v2-take-trend--up { color: var(--accent); }
.v2-stage .v2-take-trend svg { display: block; }

/* Card layout (P2-T3 Task 5) — the score ring and the progress graph share ONE flex row, equal
 * weight (Dave's "gold" vision: the journey graph sits RIGHT of the ring). Below 480 it stacks. */
.v2-stage .v2-score-main {
  display: flex;
  gap: 20px;
  align-items: center;
}
.v2-stage .v2-score-graph {
  flex: 1;
  min-width: 0;                 /* let it shrink inside the flex row (no horizontal overflow) */
  position: relative;           /* the graph's tooltip positions against this */
}
@media (max-width: 700px) {
  .v2-stage .v2-score-main { gap: 12px; }
  .v2-stage .v2-score-ring,
  .v2-stage .v2-score-ring svg { width: 128px; height: 128px; }
}
@media (max-width: 480px) {
  .v2-stage .v2-score-main { flex-direction: column; }
  .v2-stage .v2-score-graph { width: 100%; }
}

/* Coach line — one honest sentence, centered under the ring/graph row. */
.v2-stage .v2-score-coach-row {
  display: flex;
  justify-content: center;
  max-width: 100%;              /* never exceed the card → no horizontal page scroll on narrow phones */
}
.v2-stage .v2-score-coach { min-width: 0; margin: 0; }

/* Reduced motion — no spin, no chip transitions. */
@media (prefers-reduced-motion: reduce) {
  .v2-stage .v2-take-chip,
  .v2-stage .v2-take-chip-play,
  .v2-stage .v2-take-chip-body,
  .v2-stage .v2-take-chip-exclude,
  .v2-stage .v2-take-chip-exclude::after,
  .v2-stage .v2-take-nav { transition: none; }
  /* No carousel glide — paging snaps to the new page instantly (still the correct chips). */
  .v2-stage .v2-take-track { transition: none; }
  .v2-stage .v2-take-chip-spin { animation: none; }
  .v2-stage .v2-metric-chip { transition: none; }
}

/* Mobile ≤768: the chevrons hide and the TRACK becomes a single horizontal scroll-row (no wrap,
 * hidden scrollbar chrome, 44px touch chips) — swipe IS the carousel. The session trend stays
 * pinned at the strip's end (outside the scroller). It's in normal flow (NOT position:fixed), so it
 * never collides with the fixed bottom bar (z-200) or the mix sheet (z-250); .v2-main clears the bar. */
@media (max-width: 768px) {
  .v2-stage .v2-take-nav { display: none; }
  /* Viewport turns transparent: it stops clipping and lets the track own the horizontal scroll. Any
   * inline width/transform take-flow set on desktop is cleared in JS on the narrow re-render. */
  .v2-stage .v2-take-viewport {
    flex: 1 1 auto;
    min-width: 0;
    max-width: none;
    width: auto;
    overflow: visible;
  }
  .v2-stage .v2-take-track {
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    transform: none;
    transition: none;
  }
  .v2-stage .v2-take-track::-webkit-scrollbar { display: none; }
  .v2-stage .v2-take-chip { flex: 0 0 auto; min-height: 44px; }
  .v2-stage .v2-take-trend { flex: 0 0 auto; align-self: center; }
}

/* ============================================================================
 * 19. DISCARD / EXCLUDE — the honest, distinct affordances (P2-T2 Task 5).
 *   · Exclude (post-dispatch, REVERSIBLE) → a light UNDO TOAST, never a scary modal.
 *   · Discard (pre-dispatch, REAL deletion) → a REV 2 CONFIRM MODAL, never confirm().
 *   Honest-copy law: Discard says DELETE, Exclude says HIDE/KEPT — never blur them.
 *   No red anywhere (--lamp is record-only); the copy carries the consequence.
 * ==========================================================================*/

/* -- The exclude undo toast: a small, non-blocking pill pinned bottom-centre, ABOVE the fixed
 *    mobile bottom bar (200) + mix sheet (250). Sits below the confirm modal (1000+). -- */
.v2-stage .v2-undo-toast {
  position: fixed;
  left: 50%;
  bottom: 88px;                                 /* clears the ≤768 fixed bottom bar */
  transform: translateX(-50%);
  z-index: 500;
  display: inline-flex;
  align-items: center;
  gap: 14px;
  max-width: calc(100vw - 32px);
  padding: 10px 10px 10px 16px;
  background: var(--stage-2);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  color: var(--voice-hi);
  font-size: 13px;
  font-weight: 600;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
}
.v2-stage .v2-undo-toast-msg { min-width: 0; }
.v2-stage .v2-undo-toast-btn {
  flex: 0 0 auto;
  padding: 6px 14px;
  background: transparent;
  border: 1px solid var(--accent);
  border-radius: 8px;
  color: var(--accent);
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
  transition: background 120ms ease-out, color 120ms ease-out;
}
.v2-stage .v2-undo-toast-btn:hover { background: var(--accent); color: #fff; }
@media (min-width: 769px) { .v2-stage .v2-undo-toast { bottom: 24px; } }
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-undo-toast { animation: v2-undo-rise 140ms ease-out both; }
}
@keyframes v2-undo-rise {
  from { opacity: 0; transform: translateX(-50%) translateY(8px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

/* -- The confirm modal: a centred REV 2 card over a dimmed room. Escape / tap-out / Keep cancel. -- */
.v2-stage .v2-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;                                /* above everything, incl. the takeover (900) */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(19, 17, 24, 0.82);           /* --stage @ 82% — the room dims */
  -webkit-tap-highlight-color: transparent;
}
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-modal { animation: v2-takeover-fade 0.18s ease-out both; }
}
.v2-stage .v2-modal-card {
  width: 100%;
  max-width: 380px;
  padding: 22px 22px 18px;
  background: var(--stage-2);
  border: 1px solid var(--hairline);
  border-radius: 12px;                          /* card radius */
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.55);
  text-align: left;
}
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-modal-card { animation: v2-takeover-rise 0.22s 0.02s ease-out both; }
}
.v2-stage .v2-modal-title {
  margin: 0 0 8px;
  color: var(--voice-hi);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.v2-stage .v2-modal-body {
  margin: 0 0 20px;
  color: var(--voice-lo);
  font-size: 13.5px;
  line-height: 1.5;
}
.v2-stage .v2-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  flex-wrap: wrap;
}
.v2-stage .v2-modal-btn {
  padding: 9px 18px;
  border-radius: 8px;                           /* button radius */
  border: 1px solid var(--hairline);
  background: var(--chip);
  color: var(--voice-hi);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  transition: background 120ms ease-out, color 120ms ease-out, border-color 120ms ease-out;
}
.v2-stage .v2-modal-btn:hover { background: var(--stage); }
/* Primary = the emphasised SAFE default (Keep) / the recommended action (Hide). Filled violet. */
.v2-stage .v2-modal-btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.v2-stage .v2-modal-btn--primary:hover { background: var(--accent-deep); border-color: var(--accent-deep); }
/* Ghost = the quieter consequential action (Discard). Not red — the copy carries the warning. */
.v2-stage .v2-modal-btn--ghost { background: transparent; color: var(--voice-lo); }
.v2-stage .v2-modal-btn--ghost:hover { background: var(--stage); color: var(--voice-hi); }

/* ============================================================================
 * 20. THE SHARE / POLISH SHEETS (P2-T2 Task 6) — the two on-demand affordances
 *     the retired wizard's mandatory Share + Preview&Polish steps became. Both
 *     reuse the takeover/modal dismissal grammar (tap-out · Esc · Done · focus
 *     restore) and mount on the stage root. Bottom-anchored on a phone (thumb
 *     reach), centred on desktop. One violet accent; SVG glyphs only.
 * ==========================================================================*/
.v2-stage .v2-sheet {
  position: fixed;
  inset: 0;
  z-index: 1050;                                 /* above the takeover (900); peer of the modal (1000) */
  display: flex;
  align-items: flex-end;                         /* bottom sheet on a phone */
  justify-content: center;
  background: rgba(19, 17, 24, 0.82);            /* --stage @ 82% — the room dims */
  -webkit-tap-highlight-color: transparent;
}
@media (min-width: 769px) { .v2-stage .v2-sheet { align-items: center; padding: 24px; } }
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-sheet { animation: v2-takeover-fade 0.16s ease-out both; }
}
.v2-stage .v2-sheet-card {
  box-sizing: border-box;
  width: 100%;
  max-width: 440px;
  max-height: 88vh;
  overflow-y: auto;
  padding: 18px 18px 22px;
  background: var(--stage-2);
  border: 1px solid var(--hairline);
  border-radius: 16px 16px 0 0;                  /* rounded top — bottom sheet */
  box-shadow: 0 -12px 48px rgba(0, 0, 0, 0.55);
  padding-bottom: calc(22px + env(safe-area-inset-bottom, 0px));
}
@media (min-width: 769px) {
  .v2-stage .v2-sheet-card {
    border-radius: 14px;                          /* fully rounded when centred */
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.55);
    padding-bottom: 22px;
  }
}
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-sheet-card { animation: v2-takeover-rise 0.2s 0.02s ease-out both; }
}
.v2-stage .v2-sheet--static,
.v2-stage .v2-sheet--static .v2-sheet-card { animation: none; }
.v2-stage .v2-sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}
.v2-stage .v2-sheet-title {
  margin: 0;
  color: var(--voice-hi);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.v2-stage .v2-sheet-close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid var(--hairline);
  background: var(--chip);
  color: var(--voice-lo);
  cursor: pointer;
  transition: background 0.14s ease-out, color 0.14s ease-out;
}
.v2-stage .v2-sheet-close:hover { background: var(--stage); color: var(--voice-hi); }
.v2-stage .v2-sheet-body { display: flex; flex-direction: column; gap: 14px; }

/* Copy-link — the emphasised share action (filled violet), full width. */
.v2-stage .v2-share-copy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 12px 16px;
  border-radius: 10px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  font-size: 13.5px;
  font-weight: 600;
  font-family: var(--font-body);
  cursor: pointer;
  transition: background 0.14s ease-out;
}
.v2-stage .v2-share-copy:hover { background: var(--accent-deep); border-color: var(--accent-deep); }
.v2-stage .v2-share-copy--done { background: var(--accent-deep); border-color: var(--accent-deep); }

/* Social row — quiet chip buttons; the platform mark reads, not the button. */
.v2-stage .v2-share-social { display: flex; gap: 10px; }
.v2-stage .v2-share-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 10px;
  border: 1px solid var(--hairline);
  background: var(--chip);
  color: var(--voice-hi);
  cursor: pointer;
  transition: background 0.14s ease-out, border-color 0.14s ease-out;
}
.v2-stage .v2-share-icon:hover { background: var(--stage); border-color: var(--accent); }

/* Score-card image — the "Create a score card" ghost button + the revealed image + its actions. */
.v2-stage .v2-share-card-btn {
  width: 100%;
  padding: 11px 16px;
  border-radius: 10px;
  border: 1px solid var(--hairline);
  background: var(--chip);
  color: var(--voice-hi);
  font-size: 13px;
  font-weight: 600;
  font-family: var(--font-body);
  cursor: pointer;
  transition: background 0.14s ease-out, border-color 0.14s ease-out;
}
.v2-stage .v2-share-card-btn:hover { background: var(--stage); border-color: var(--accent); }
.v2-stage .v2-share-card-btn:disabled { opacity: 0.5; cursor: default; }
.v2-stage .v2-share-card-slot:empty { display: none; }
/* Publish-then-reveal states (share makes a take public; school students are blocked server-side). */
.v2-stage .v2-share-preparing {
  margin: 0;
  padding: 18px 4px;
  text-align: center;
  color: var(--voice-lo);
  font-size: 13px;
  font-family: var(--font-body);
}
.v2-stage .v2-share-note {
  margin: 2px 0 0;
  text-align: center;
  color: var(--voice-lo);
  font-size: 11px;
  font-family: var(--font-body);
}
.v2-stage .v2-share-blocked {
  padding: 8px 4px 4px;
  text-align: center;
}
.v2-stage .v2-share-blocked-title {
  margin: 0 0 6px;
  color: var(--voice-hi);
  font-size: 14px;
  font-weight: 600;
  font-family: var(--font-body);
}
.v2-stage .v2-share-blocked-body {
  margin: 0 0 12px;
  color: var(--voice-lo);
  font-size: 12.5px;
  line-height: 1.5;
  font-family: var(--font-body);
}
.v2-stage .v2-share-retry {
  display: inline-block;
  width: auto;
  padding: 8px 18px;
}
.v2-stage .v2-share-card-img {
  width: 100%;
  max-width: 100%;
  height: auto;
  display: block;
  border-radius: 10px;
  border: 1px solid var(--hairline);
}
.v2-stage .v2-share-card-actions { display: flex; gap: 10px; margin-top: 12px; }
.v2-stage .v2-sheet-btn {
  flex: 1 1 auto;
  text-align: center;
  padding: 10px 14px;
  border-radius: 9px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  font-family: var(--font-body);
  text-decoration: none;
  cursor: pointer;
  transition: background 0.14s ease-out;
}
.v2-stage .v2-sheet-btn:hover { background: var(--accent-deep); border-color: var(--accent-deep); }
.v2-stage .v2-sheet-btn--ghost {
  background: transparent;
  border-color: var(--hairline);
  color: var(--voice-hi);
}
.v2-stage .v2-sheet-btn--ghost:hover { background: var(--stage); border-color: var(--accent); }

/* Polish the mix — the recorder's Basic/Full mixer, hosted in the sheet body. Its own
 * geometry is songsplit.css; the violet re-accents live in §14's reused-mixer block. */
.v2-stage .v2-mix-host { width: 100%; }
.v2-stage .v2-mix-host .ss-mixer-section { margin: 0; }

/* ── T3: the shared progress graph (.v2-pg-*) ───────────────────────────────────────────────
 * SSProgressGraph paints a hand-rolled inline SVG (viewBox card 260×130 / hero 300×160); CSS
 * only scales it and styles the line. Per-metric stroke colours are set inline on the elements
 * (from METRIC_COLORS in progress-graph.js) — the ALLOWLIST lives in JS, never here. Task 4 adds
 * the tooltip / hover furniture; this block is the static line + dot presentation only. */
.v2-stage .v2-pg { display: block; width: 100%; height: auto; }
.v2-stage .v2-pg--card { max-width: 300px; }
.v2-stage .v2-pg--hero { max-width: 420px; }
.v2-stage .v2-pg-line {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.v2-stage .v2-pg-dots circle { stroke: none; }

/* ── Take-nav Task 2: selected-point highlight ───────────────────────────────────────────────
 * A selected take dims the journey (line + dots to .5) so the highlight — a --voice-hi core inside
 * a metric-colour halo (halo tint set inline) — reads as the focus. Static (no transition), so it
 * is identical under reduced motion. `.v2-pg--take` is toggled by the JS selection guard. */
.v2-stage .v2-pg--take .v2-pg-line,
.v2-stage .v2-pg--take .v2-pg-dots { opacity: .5; }
.v2-stage .v2-pg-selected-core { fill: var(--voice-hi); stroke: none; }

/* ── T3 Task 4: progressive furniture, hit targets + tooltip ─────────────────────────────────
 * Furniture (goal/start reference marks) is invisible at rest and breathes in on the `.v2-pg--lean`
 * class the JS toggles from hover / focus / a ~1.2s post-metric-switch force. The 9px goal/start
 * labels are the ONLY text on the chart. Hit circles are transparent, tabbable; one reused tooltip
 * node is positioned in pixel space inside the (relative) mount. */
.v2-stage .v2-pg-furniture { opacity: 0; transition: opacity .25s ease; pointer-events: none; }
.v2-stage .v2-pg--lean .v2-pg-furniture { opacity: 1; }
.v2-stage .v2-pg-goal-line  { stroke-width: 1.5; stroke-dasharray: 4 4; fill: none; }
.v2-stage .v2-pg-start-line { stroke: var(--hairline); stroke-width: 1.5; fill: none; }
.v2-stage .v2-pg-start-ring { stroke-width: 1.5; fill: none; opacity: .8; }
.v2-stage .v2-pg-flabel {
  font-size: 9px;
  font-family: inherit;
  fill: var(--voice-lo);
  letter-spacing: .04em;
}

.v2-stage .v2-pg-hit { fill: transparent; cursor: pointer; outline: none; }
.v2-stage .v2-pg-hit:focus-visible {
  stroke: var(--voice-hi);
  stroke-width: 1.5;
  fill: rgba(255, 255, 255, 0.04);
}

.v2-stage .v2-pg-tip {
  position: absolute;
  z-index: 6;
  transform: translate(-50%, calc(-100% - 9px));
  display: none;
  align-items: center;
  gap: 7px;
  padding: 5px 7px 5px 9px;
  border-radius: 9px;
  background: var(--stage-2);
  border: 1px solid var(--hairline);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
  color: var(--voice-hi);
  font-size: 11px;
  line-height: 1;
  white-space: nowrap;
  pointer-events: auto;
}
.v2-stage .v2-pg-tip--on { display: inline-flex; }
.v2-stage .v2-pg-tip-score { font-variant-numeric: tabular-nums; }
.v2-stage .v2-pg-tip-play {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--ss-accent);
  color: #fff;
  cursor: pointer;
  transition: background .15s ease;
}
.v2-stage .v2-pg-tip-play:hover { background: var(--ss-accent-hover); }
.v2-stage .v2-pg-tip-play:focus-visible { outline: 2px solid var(--voice-hi); outline-offset: 2px; }

/* Reduced motion: furniture appears instantly (no fade), morph is already JS-guarded, PB halo static. */
@media (prefers-reduced-motion: reduce) {
  .v2-stage .v2-pg-furniture { transition: none; }
  .v2-stage .v2-pg-tip-play  { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
 * MY PROGRESS ZONE (P2-T3 Task 7) — the journey surface (.v2-pz-*)
 * The zone hero reuses the card's ring/hero/chips/coach primitives (.v2-score-*) at a larger size,
 * then adds a BEST suffix, a stats strip, the anon gate, and two empty states. Scoped under
 * .v2-stage so the shared .v2-pg-* graph styles apply to the hero graph too.
 * ══════════════════════════════════════════════════════════════════════════════════════════════ */
.v2-stage .v2-pz {
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 8px 0 16px;
}
.v2-stage .v2-pz-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

/* Ring + journey graph share ONE row, equal weight (the hero graph is wider than the card's). */
.v2-stage .v2-pz-main {
  display: flex;
  gap: 28px;
  align-items: center;
  width: 100%;
  max-width: 720px;
}
.v2-stage .v2-pz-ring,
.v2-stage .v2-pz-ring .v2-score-ring-svg {
  width: 208px;
  height: 208px;
  flex: 0 0 auto;
}
.v2-stage .v2-pz-graph {
  flex: 1;
  min-width: 0;
  position: relative;
}
/* Hero ring's headline reads bigger than the card's. */
.v2-stage .v2-pz-ring .v2-score-num { font-size: 66px; }
.v2-stage .v2-pz-best-suffix {
  margin-top: 3px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--voice-lo);
}

/* Coach line under the hero row (+ the take-mode "back to journey" pill stacked above it). */
.v2-stage .v2-pz-coach-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  max-width: 100%;
}

/* Take-nav: "← Back to your journey" pill — a quiet chip, only shown while a take is pinned. */
.v2-stage .v2-pz-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--chip);
  color: var(--chip-text);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: color 120ms ease, background 120ms ease, border-color 120ms ease;
}
.v2-stage .v2-pz-back:hover {
  color: var(--voice-hi);
  background: var(--stage-2);
  border-color: var(--accent-60);
}
.v2-stage .v2-pz-back:focus-visible {
  outline: 2px solid var(--accent-60);
  outline-offset: 2px;
}
.v2-stage .v2-pz-back[hidden] { display: none; }

/* The hero ring becomes clickable in take-mode (a second way back to the journey). */
.v2-stage .v2-pz-ring--clickable { cursor: pointer; }
.v2-stage .v2-pz-coach {
  min-width: 0;
  margin: 0;
  text-align: center;
  max-width: 42ch;
}

/* PB glow in the My Progress zone — the payoff. When the pinned take IS the viewed metric's personal
 * best, the hero ring lifts a soft haze in the metric colour (--pb-glow, set by progress-zone.js at
 * alpha 0.55). Mirrors the card's .v2-score-hero--pb recipe exactly; reuses its v2-pb-haze-in bloom.
 * Reduced motion → the halo is static (no bloom-in). Journey / non-PB takes carry no glow. */
.v2-stage .v2-pz-hero--pb {
  border-radius: 50%;
  box-shadow: 0 0 40px 8px var(--pb-glow, rgba(139, 92, 246, 0.55));
}
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-pz-hero--pb { animation: v2-pb-haze-in 0.5s ease-out both; }
}

/* The celebration caption under the hero — the self-referential PB line ("Your truest pitch yet"),
 * coloured to the metric (inline, set by progress-zone.js). Only shown while the PB glow is lit. */
.v2-stage .v2-pz-pb-line {
  margin: 0;
  text-align: center;
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
}
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-pz-pb-line { animation: v2-pz-pb-line-in 0.4s ease-out both; }
}
@keyframes v2-pz-pb-line-in {
  from { opacity: 0; transform: translateY(3px); }
  to   { opacity: 1; transform: translateY(0); }
}
.v2-stage .v2-pz-pb-line[hidden] { display: none; }
.v2-stage .v2-pz-chips { margin-top: 2px; }

/* Stats strip — a quiet row of number · label tiles (takes · days · best · gain). */
.v2-stage .v2-pz-stats {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 28px;
  padding-top: 4px;
}
.v2-stage .v2-pz-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}
.v2-stage .v2-pz-stat-val {
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
  color: var(--voice-hi);
  font-variant-numeric: tabular-nums;
}
.v2-stage .v2-pz-stat-lbl {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--voice-lo);
}

/* ── The anon account gate ─────────────────────────────────────────────────────────────────────
 * Shown when the viewer isn't signed in: their session takes are here, but nothing is saved yet. */
.v2-stage .v2-pz-gate {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
  padding: 40px 24px 32px;
  border: 1px solid var(--hairline);
  border-radius: 14px;
  background: var(--chip);
}
.v2-stage .v2-pz-gate-heading {
  margin: 0;
  font-size: 19px;
  font-weight: 700;
  line-height: 1.35;
  color: var(--voice-hi);
  max-width: 34ch;
}
.v2-stage .v2-pz-gate-sub {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--voice-lo);
  max-width: 40ch;
}
.v2-stage .v2-pz-gate-cta {
  margin-top: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 11px 22px;
  border-radius: 999px;
  background: var(--ss-accent, #8B5CF6);
  color: #fff;
  font-size: 14.5px;
  font-weight: 700;
  text-decoration: none;
  transition: background .15s ease;
}
.v2-stage .v2-pz-gate-cta:hover { background: var(--ss-accent-hover, #7C3AED); }
.v2-stage .v2-pz-gate-cta:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── Empty states (ghost journey + no-scores) ──────────────────────────────────────────────────*/
.v2-stage .v2-pz-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
  padding: 40px 24px;
}
.v2-stage .v2-pz-empty-heading {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  color: var(--voice-hi);
}
.v2-stage .v2-pz-empty-sub {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--voice-lo);
  max-width: 34ch;
}
.v2-stage .v2-pz-ghost-svg {
  width: 100%;
  max-width: 300px;
  height: 96px;
  margin-bottom: 4px;
}
.v2-stage .v2-pz-ghost-line {
  stroke: var(--accent, #8B5CF6);
  opacity: 0.35;
  stroke-dasharray: 5 5;
}

/* Hero graph max width bump vs the card. */
.v2-stage .v2-pz-graph .v2-pg--hero { max-width: none; }

@media (max-width: 700px) {
  .v2-stage .v2-pz-ring,
  .v2-stage .v2-pz-ring .v2-score-ring-svg { width: 168px; height: 168px; }
  .v2-stage .v2-pz-ring .v2-score-num { font-size: 52px; }
  .v2-stage .v2-pz-main { gap: 16px; }
}
@media (max-width: 520px) {
  .v2-stage .v2-pz-main { flex-direction: column; }
  .v2-stage .v2-pz-graph { width: 100%; }
}

/* ── CP2 fix: the progress zone SUBSUMES the resolved card (Dave Checkpoint 2) ────────────────
 * With a resolved score card up, entering My Progress showed TWO ring+graph displays — the
 * persistent #v2-postrecord card (T2 design: above all zones) AND the new zone hero. The zone
 * owns the journey, so the RESOLVED card (scored AND withheld/failed — both render root
 * .v2-score-card) hides while the progress zone is active. PURE CSS visibility: take-flow state
 * is untouched and the card reappears intact on switching back to practice/sheets. The
 * saving/scoring strips (.v2-saving-strip) and the take strip (#v2-take-strip) stay visible in
 * EVERY zone — recording from the bottom bar must keep giving feedback. Keyed on the SAME
 * data-active-zone attribute switchZone already stamps on .v2-main (bootstrap.js) — the one
 * zone-visibility choke point, so this can never drift from the zone switch. */
.v2-stage .v2-main[data-active-zone="progress"] #v2-postrecord .v2-score-card { display: none; }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
 * TAKE HISTORY + THEN-VS-NOW (P2-T3 Task 8) — the journey's evidence, under the hero (.v2-pz-*)
 * Day-grouped rows (▶ · Take N · mini score bar · score · ★ · Share · ⊘), the "hear the climb"
 * pill, collapsed older days, and the voice-only tag every historical (dry) playback carries.
 * ══════════════════════════════════════════════════════════════════════════════════════════════ */
.v2-stage .v2-pz-history-inner {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-top: 4px;
}

/* MH-11: the single Voice↔Music balance mixer — shown only while a MIXED historical take plays.
 * Reuses the global .ss-basic-mix* markup (base songsplit.css + the .v2-stage accent overrides above)
 * so it reads as the SAME mixer as the post-record card. This wrapper just gives it a quiet panel and
 * the show/hide affordance. Placed at the top of the history block, near the now-playing rows. */
.v2-stage .v2-pz-mix {
  padding: 10px 14px;
  border: 1px solid var(--accent);
  border-radius: 12px;
  background: rgba(139, 92, 246, 0.08);
}
.v2-stage .v2-pz-mix[hidden] { display: none; }
.v2-stage .v2-pz-mix .ss-basic-mix { padding: 0; }
@media (prefers-reduced-motion: no-preference) {
  .v2-stage .v2-pz-mix:not([hidden]) { animation: v2-pz-mix-in .18s ease both; }
  @keyframes v2-pz-mix-in { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }
}

/* The two jump buttons — "Your first take" / "Your best take" — SELECT + PLAY their target take. */
.v2-stage .v2-pz-jumps {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.v2-stage .v2-pz-jump {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1 1 200px;
  min-width: 0;
  padding: 10px 14px;
  border: 1px solid var(--accent);
  border-radius: 12px;
  background: rgba(139, 92, 246, 0.10);
  color: var(--voice-hi);
  cursor: pointer;
  text-align: left;
  transition: background .15s ease, border-color .15s ease;
}
.v2-stage .v2-pz-jump:hover { background: rgba(139, 92, 246, 0.18); }
.v2-stage .v2-pz-jump--playing { background: var(--accent); border-color: var(--accent); color: #fff; }
.v2-stage .v2-pz-jump-ico {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: var(--stage-2);
  color: var(--accent);
}
.v2-stage .v2-pz-jump--playing .v2-pz-jump-ico { background: rgba(255, 255, 255, 0.18); color: #fff; }
.v2-stage .v2-pz-jump-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.v2-stage .v2-pz-jump-label { font-size: 13.5px; font-weight: 700; }
.v2-stage .v2-pz-jump-meta {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--voice-lo);
  font-variant-numeric: tabular-nums;
}
.v2-stage .v2-pz-jump--playing .v2-pz-jump-meta { color: rgba(255, 255, 255, 0.85); }
.v2-stage .v2-pz-jump .v2-pz-voiceonly { margin-left: auto; }
.v2-stage .v2-pz-jump--playing .v2-pz-voiceonly { color: #fff; background: rgba(255, 255, 255, 0.18); }

/* Section + day headings — quiet meta, never shouting over the rows. */
.v2-stage .v2-pz-history-title {
  margin: 6px 0 0;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--voice-lo);
}
.v2-stage .v2-pz-day { display: flex; flex-direction: column; gap: 6px; }
.v2-stage .v2-pz-day-head {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--voice-lo);
  padding-top: 4px;
}

/* Collapsed older day → a single tappable summary row ("3 Jul '26 · 4 takes · best 79 · Show"). */
.v2-stage .v2-pz-day--collapsed {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 11px 14px;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: var(--chip);
  color: var(--voice-hi);
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  text-align: left;
  transition: background .15s ease;
}
.v2-stage .v2-pz-day--collapsed:hover { background: var(--stage-2); }
.v2-stage .v2-pz-day-expand {
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--accent);
}

.v2-stage .v2-pz-rows { display: flex; flex-direction: column; gap: 6px; }

/* One take row. */
.v2-stage .v2-pz-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: var(--chip);
}
.v2-stage .v2-pz-row--playing {
  border-color: var(--accent);
  background: rgba(139, 92, 246, 0.12);
}
.v2-stage .v2-pz-row--excluded,
.v2-stage .v2-pz-row--failed { opacity: 0.55; }
/* A plotted (scored, non-excluded) row is tappable to pin the hero to that take. */
.v2-stage .v2-pz-row--selectable { cursor: pointer; }
.v2-stage .v2-pz-row--selectable:hover { border-color: var(--accent); }

.v2-stage .v2-pz-row-play {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 999px;
  background: var(--stage-2);
  color: var(--voice-hi);
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.v2-stage .v2-pz-row-play:hover { background: var(--accent); color: #fff; }
.v2-stage .v2-pz-row-play:disabled { opacity: 0.4; cursor: default; }
.v2-stage .v2-pz-row--playing .v2-pz-row-play { background: var(--accent); color: #fff; }

/* Buffering spinner (Task 8): a mixed historical play loads async (signed-url fetch ± key shift), so
   the tapped control shows a small ring while onLoading(true). Row spinner sits on .v2-pz-row-play;
   jump spinner sits on the jump button itself. REV 2 accent token; static under reduced-motion. */
.v2-stage .v2-pz-row--loading .v2-pz-row-play::after,
.v2-stage .v2-pz-jump--loading::after {
  content: "";
  width: 12px;
  height: 12px;
  margin-left: 6px;
  border: 2px solid var(--ss-accent, #8B5CF6);
  border-top-color: transparent;
  border-radius: 50%;
  display: inline-block;
  animation: v2-pz-spin .7s linear infinite;
}
@keyframes v2-pz-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .v2-stage .v2-pz-row--loading .v2-pz-row-play::after,
  .v2-stage .v2-pz-jump--loading::after { animation: none; }
}

.v2-stage .v2-pz-row-take {
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 700;
  color: var(--voice-hi);
  min-width: 4.2em;
}

/* Mini score bar — violet fill, width = score%. */
.v2-stage .v2-pz-bar {
  flex: 1 1 auto;
  min-width: 40px;
  height: 6px;
  border-radius: 999px;
  background: var(--hairline);
  overflow: hidden;
}
.v2-stage .v2-pz-bar-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), var(--accent-deep));
}
.v2-stage .v2-pz-row-score {
  flex: 0 0 auto;
  font-size: 14px;
  font-weight: 700;
  color: var(--voice-hi);
  font-variant-numeric: tabular-nums;
  min-width: 2em;
  text-align: right;
}
.v2-stage .v2-pz-row-star { flex: 0 0 auto; color: var(--accent); font-size: 13px; }

/* Reason (failed) / note (excluded / pending) fill the bar's place with quiet copy. */
.v2-stage .v2-pz-row-reason {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12.5px;
  color: var(--voice-lo);
}
.v2-stage .v2-pz-row-note {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--voice-lo);
}

/* The voice-only tag — shown (hidden attr removed) only while that surface's dry audio plays. */
.v2-stage .v2-pz-voiceonly {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--voice-lo);
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--stage-2);
}
.v2-stage .v2-pz-row-actions { flex: 0 0 auto; display: flex; align-items: center; gap: 6px; margin-left: auto; }
.v2-stage .v2-pz-row-share,
.v2-stage .v2-pz-row-unhide,
.v2-stage .v2-pz-row-hide {
  border: 1px solid var(--hairline);
  border-radius: 8px;
  background: transparent;
  color: var(--voice-lo);
  font-size: 12px;
  font-weight: 600;
  padding: 5px 10px;
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.v2-stage .v2-pz-row-share:hover,
.v2-stage .v2-pz-row-unhide:hover { color: var(--voice-hi); border-color: var(--accent); }
.v2-stage .v2-pz-row-hide { padding: 5px 9px; font-size: 14px; line-height: 1; }
.v2-stage .v2-pz-row-hide:hover { color: var(--voice-hi); border-color: var(--voice-lo); }

/* The retryable fetch-error state (Task 8 fold 4) — quiet, never the ghost. */
.v2-stage .v2-pz-empty--error .v2-pz-retry {
  margin-top: 4px;
  padding: 9px 20px;
  border: 1px solid var(--accent);
  border-radius: 999px;
  background: transparent;
  color: var(--voice-hi);
  font-size: 13.5px;
  font-weight: 700;
  cursor: pointer;
  transition: background .15s ease;
}
.v2-stage .v2-pz-empty--error .v2-pz-retry:hover { background: rgba(139, 92, 246, 0.15); }

@media (max-width: 520px) {
  .v2-stage .v2-pz-row { flex-wrap: wrap; gap: 8px; }
  .v2-stage .v2-pz-bar { order: 5; flex-basis: 100%; }
  .v2-stage .v2-pz-jumps { flex-direction: column; }
  .v2-stage .v2-pz-jump-label { font-size: 13px; }
}

/* ============ PRACTICE ROOM — takeover chrome (Task 3) ============ */
body.ss-room-body { background:#131118; color:#EDEAF4; margin:0; }
body.ss-room-body .ss-main.ss-room { max-width:1180px; margin:0 auto; padding:0 28px 80px; }
.ss-room-utility { display:flex; justify-content:space-between; align-items:flex-start;
  max-width:1180px; margin:0 auto 20px; padding:14px 28px 4px; }
/* The content card (.ss-player-page.v2-stage) has a -24px TOP margin that bleeds it up
   under the header, eating the utility bar's margin. Neutralise ONLY the top bleed in the
   room (keep the horizontal bleed) so the card floats clearly below the header chrome. */
.ss-room .ss-player-page.v2-stage { margin-top:0; }
.ss-room-exit { display:inline-flex; align-items:center; gap:9px; color:#8B8698;
  font-size:13px; text-decoration:none; }
.ss-room-exit:hover { color:#EDEAF4; }
.ss-room-exit-glyph { width:26px; height:26px; border-radius:7px; background:#1D1926;
  border:1px solid #322C40; display:flex; align-items:center; justify-content:center; color:#A78BFA; }
.ss-room-utility-right { display:flex; align-items:center; gap:14px; }
.ss-room-avatar { width:30px; height:30px; border-radius:50%; overflow:hidden; display:inline-flex;
  align-items:center; justify-content:center; background:linear-gradient(135deg,#8B5CF6,#EC4899);
  color:#fff; font-size:12px; text-decoration:none; }
.ss-room-avatar img { width:100%; height:100%; object-fit:cover; }
.ss-room-bell { color:#8B8698; text-decoration:none; display:inline-flex; align-items:center; }
.ss-room-bell:hover { color:#EDEAF4; }
.ss-room-bell svg, .ss-room-glyph svg, .ss-room-exit-glyph svg { display:block; }
.ss-room-signin { color:#A78BFA; text-decoration:none; font-size:13px; }
@media (max-width:768px){ .ss-room-utility, body.ss-room-body .ss-main.ss-room { padding-left:16px; padding-right:16px; } }

/* ============ PRACTICE ROOM — D1 identity header ============ */
.ss-room-identity { display:flex; flex-direction:column; gap:9px; }
.ss-room-wordmark { display:inline-flex; align-items:center; gap:8px; font-size:13px; font-weight:600; letter-spacing:.2px; color:#EDEAF4; }
.ss-room-glyph { width:24px; height:24px; border-radius:7px; background:linear-gradient(135deg,#8B5CF6,#7C3AED);
  display:flex; align-items:center; justify-content:center; color:#fff; }
.ss-room-utility-right { align-items:center; }

/* ============ PRACTICE ROOM — desktop setlist rail (Fix C) ============ */
.ss-setlist-rail { position:fixed; left:0; top:64px; bottom:0; width:46px; z-index:60;
  display:flex; flex-direction:column; align-items:center; gap:9px; padding:16px 0 16px;
  background:linear-gradient(180deg,#1a1524,#141019); border:none; border-right:1px solid #2A2634;
  cursor:pointer; }
.ss-setlist-rail:hover { background:linear-gradient(180deg,#1e1830,#161120); }
.ss-rail-num { font-size:12px; font-weight:700; color:#C4B5FD; text-align:center; line-height:1.1; }
.ss-rail-den { display:block; font-size:8px; color:#6E6880; }
.ss-rail-dots { display:flex; flex-direction:column; gap:4px; margin-top:2px; }
.ss-rail-dot { width:5px; height:5px; border-radius:50%; background:#3A3350; }
.ss-rail-dot.is-done { background:#5E4B8C; }
.ss-rail-dot.is-current { background:#A78BFA; box-shadow:0 0 0 2px rgba(167,139,250,.22); }
.ss-rail-label { writing-mode:vertical-rl; transform:rotate(180deg); margin-top:6px;
  font-size:8.5px; letter-spacing:2px; text-transform:uppercase; color:#6E6880; }
.ss-rail-handle { margin-top:auto; color:#8B8698; font-size:13px; }
/* room content clears the rail on desktop */
body.ss-room--railed .ss-main.ss-room { padding-left:74px; }
body.ss-room--railed .ss-room-utility { padding-left:74px; }
/* MUST re-assert the mobile reset AFTER the 74px rules — the existing @media at line 3024
   is EARLIER in source order, so at equal specificity the 74px rules would win ≤768px and
   shove the whole mobile room right with an empty gutter (spec §7 requires the offset removed). */
@media (max-width:768px){
  body.ss-room--railed .ss-main.ss-room,
  body.ss-room--railed .ss-room-utility { padding-left:16px; }
}
@media (max-width:768px){ .ss-setlist-rail { display:none; } }

/* ============ PRACTICE ROOM — mobile progress chip (Fix C) ============ */
/* Desktop: calm text line (today's look) — dots + caret hidden. */
.v2-plan-chip .v2-plan-chip-dots,
.v2-plan-chip .v2-plan-chip-caret { display:none; }
.v2-plan-chip { display:inline-flex; align-items:center; gap:8px; }
@media (max-width:768px){
  .v2-plan-chip { background:#1C1826; border:1px solid #332C44; border-radius:999px;
    padding:5px 11px; text-transform:none; letter-spacing:0; color:#C9C4D6; margin-bottom:2px; }
  .v2-plan-chip .v2-plan-chip-text { font-size:11px; }
  .v2-plan-chip .v2-plan-chip-dots { display:inline-flex; gap:3px; }
  .v2-chip-dot { width:5px; height:5px; border-radius:50%; background:#3A3350; }
  .v2-chip-dot.is-done { background:#5E4B8C; }
  .v2-chip-dot.is-current { background:#A78BFA; }
  .v2-plan-chip .v2-plan-chip-caret { display:inline; color:#8B8698; font-size:9px; }
}

/* ============ PRACTICE ROOM — hero ============ */
.v2-hero { padding:26px 0 20px; }
.v2-hero-plan { background:none; border:none; cursor:pointer; padding:0 0 8px;
  font-size:11.5px; letter-spacing:1.5px; text-transform:uppercase; color:#5E5970; }
.v2-hero-plan:hover { color:#A78BFA; }
.v2-hero-title { font-size:26px; font-weight:700; letter-spacing:-.3px; margin:0 0 10px; color:#EDEAF4; }
.v2-hero-meta { display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
.v2-hero-metaline { font-size:12.5px; color:#8B8698; } .v2-dot { color:#4A4458; }
.v2-hero-info-wrap { position:relative; }
.v2-hero-info { width:18px; height:18px; border-radius:50%; border:1px solid #4A4458;
  background:none; color:#8B8698; font-size:11px; font-style:italic; cursor:pointer; line-height:1; }
.v2-hero-info:hover { color:#EDEAF4; border-color:#8B8698; }
.v2-room-info-pop { position:absolute; top:26px; left:0; z-index:120; min-width:200px;
  background:#181420; border:1px solid #322C40; border-radius:12px; padding:12px 14px;
  box-shadow:0 14px 40px rgba(0,0,0,.5); }
.v2-info-row { display:flex; justify-content:space-between; gap:20px; font-size:12px; padding:4px 0; color:#8B8698; }
.v2-info-row b { color:#EDEAF4; font-weight:600; }
.v2-hero-next { margin-left:auto; display:inline-flex; align-items:center; gap:6px; text-decoration:none;
  background:#221C33; border:1px solid #4C3D73; border-radius:999px; padding:6px 14px; font-size:12.5px; color:#C9C4D6; }
.v2-hero-next b { color:#C4B5FD; }
@media (max-width:768px){ .v2-hero{ padding:18px 0 14px; } .v2-hero-title{ font-size:20px; } .v2-hero-next{ margin-left:0; } }

/* ============ PRACTICE ROOM — plan drawer ============ */
.v2-drawer { position:fixed; top:0; left:0; bottom:0; width:min(340px,86vw); z-index:200;
  background:#181420; border-right:1px solid #322C40; box-shadow:8px 0 30px rgba(0,0,0,.45);
  padding:18px 16px; overflow-y:auto; transform:translateX(-8px); opacity:0; transition:transform .18s ease,opacity .18s ease; }
.v2-drawer.is-open { transform:none; opacity:1; }
.v2-drawer-head { display:flex; justify-content:space-between; align-items:center; margin-bottom:14px; }
.v2-drawer-head b { font-size:14px; color:#EDEAF4; }
.v2-drawer-close { background:none; border:none; color:#8B8698; font-size:20px; cursor:pointer; line-height:1; }
.v2-drawer-list { list-style:none; margin:0; padding:0; }
.v2-drawer-link { display:flex; align-items:center; gap:12px; padding:10px 12px; border-radius:9px;
  text-decoration:none; color:#C9C4D6; font-size:13px; }
a.v2-drawer-link:hover { background:#211C2E; }
.v2-drawer-item.is-current .v2-drawer-link { background:#251E38; border:1px solid #4C3D73; color:#EDEAF4; }
.v2-drawer-n { width:20px; text-align:center; color:#5E5970; font-size:11.5px; }
.v2-drawer-item.is-current .v2-drawer-n { color:#A78BFA; }
.v2-drawer-t { flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.v2-drawer-ex { color:#5E5970; font-size:11px; }
.v2-drawer-item.is-exercise .v2-drawer-t { color:#8B8698; }
.v2-drawer-s { font-size:11.5px; color:#8B8698; white-space:nowrap; }
@media (max-width:768px){ /* bottom sheet */
  .v2-drawer { top:auto; right:0; bottom:0; left:0; width:auto; max-height:70vh; border-right:none;
    border-top:1px solid #322C40; border-radius:16px 16px 0 0; transform:translateY(10px); box-shadow:0 -8px 30px rgba(0,0,0,.5); }
  .v2-drawer.is-open { transform:none; }
}

/* ============ PRACTICE ROOM — mobile practice surface (Task 7) ============ */
@media (max-width:768px){
  /* one waveform: hide non-primary STEM lanes only. Tempo (metronome) and recording lanes also
     carry .ss-stem-lane but must NOT be hidden — the in-progress recording waveform especially. */
  .ss-room .ss-stem-lane:not(.ss-mobile-primary):not(.ss-tempo-lane):not(.ss-recording-lane) { display:none; }
  .ss-room .ss-stem-lane.ss-mobile-primary { width:100%; }
  .ss-room .ss-stem-lane.ss-mobile-primary .ss-stem-sidebar-block { display:none; } /* per-stem M/S/vol live in the Mix sheet */
  .ss-room #waveform-scroll { overflow:hidden; }
}

/* ============ PRACTICE ROOM — guide-vocal row (mobile) ============ */
.v2-guide-row { display:none; }
@media (max-width:768px){
  .ss-room .v2-guide-row { display:flex; align-items:center; gap:10px; margin:12px 0;
    background:#1A1622; border:1px solid #322C40; border-radius:11px; padding:9px 11px; }
  .v2-guide-toggle { display:flex; align-items:center; gap:7px; background:none; border:none; cursor:pointer;
    font-size:11px; font-weight:600; color:#C4B5FD; white-space:nowrap; }
  .v2-guide-label { display:inline-flex; align-items:center; gap:5px; }
  .v2-guide-label svg { display:block; }
  .v2-guide-knob { width:26px; height:16px; border-radius:999px; background:#8B5CF6; position:relative; transition:background .15s; }
  .v2-guide-knob::after { content:''; position:absolute; right:2px; top:2px; width:12px; height:12px; border-radius:50%; background:#fff; transition:right .15s,left .15s; }
  .v2-guide-toggle.is-muted { color:#5E5970; }
  .v2-guide-toggle.is-muted .v2-guide-knob { background:#2A2634; }
  .v2-guide-toggle.is-muted .v2-guide-knob::after { right:auto; left:2px; background:#5E5970; }
  .v2-guide-slider { flex:1; accent-color:#8B5CF6; }
}

/* ============ PRACTICE ROOM — post-take next banner ============ */
.v2-card-nextbanner { display:flex; align-items:center; justify-content:space-between; gap:12px;
  margin-top:10px; padding:10px 13px; border-radius:11px; text-decoration:none; font-size:12px;
  background:#221C33; border:1px solid #4C3D73; color:#C9C4D6; }
.v2-card-nextbanner b { color:#C4B5FD; }
.v2-card-nextbanner.is-end { justify-content:center; color:#C4B5FD; }

/* ============ PRACTICE ROOM — lit continuous surface (Fix A) ============ */
/* Ambient top-down stage glow + edge vignette so the centred column melts into the room. */
body.ss-room-body { position:relative; }
body.ss-room-body::before { content:''; position:fixed; inset:0; z-index:0; pointer-events:none;
  background:
    radial-gradient(90% 55% at 50% -8%, rgba(139,92,246,.10) 0%, rgba(139,92,246,0) 60%),
    radial-gradient(120% 90% at 50% 120%, rgba(0,0,0,.55) 0%, rgba(0,0,0,0) 55%); }
body.ss-room-body::after { content:''; position:fixed; inset:0; z-index:0; pointer-events:none;
  box-shadow:inset 0 0 220px 40px rgba(0,0,0,.55); }
/* Betty I1: `background` takes ONLY <image> layers (gradients). Never add a `box-shadow`
   value (`inset …`) into this list — one invalid layer invalidates the WHOLE declaration and
   silently drops both gradients (the brace-balance check won't catch it). The vignette is the
   ::after box-shadow above; keep the two concerns on separate pseudo-elements. */
/* keep all real content above the ambient layers. The utility bar MUST out-stack the main
   content: .ss-player-page.v2-stage has a negative top margin (-24px) that bleeds up over the
   utility bar, and at equal z-index the later-in-DOM opaque main would paint over the header
   (hiding Practice Room / Exit room). Utility sits above main; still well below rail(60)/drawer(200). */
body.ss-room-body .ss-main.ss-room { position:relative; z-index:1; }
.ss-room-utility { position:relative; z-index:5; }

/* de-box: lanes become hairline-separated rows, not cards */
.ss-room .ss-stem-lane { border-bottom-color:rgba(255,255,255,.05); }
/* view tabs (Lyrics/Chords/Chart/Lead Sheet) lose their chip box — active = violet ink.
   Keep a hairline under the active tab so it stays discoverable without the box. */
.ss-room .v2-subnav .ss-view-tab { background:transparent; }
.ss-room .v2-subnav .ss-view-tab:hover { background:rgba(255,255,255,.04); }
.ss-room .v2-subnav .ss-view-tab.ss-view-tab-active { background:transparent; color:#C4B5FD;
  box-shadow:inset 0 -2px 0 rgba(167,139,250,.55); }
/* tempo / BPM block de-boxes */
.ss-room .ss-tempo-lane, .ss-room .ss-tempo-sidebar-block { background:transparent; border-color:transparent; }

/* waveform sits on a wider lit strip that signals "the performance surface" */
.ss-room .ss-stems-container { position:relative; }
.ss-room .ss-stems-container::before { content:''; position:absolute; z-index:0; inset:0 -24px;
  border-radius:16px; pointer-events:none;
  background:linear-gradient(180deg, rgba(139,92,246,.05) 0%, rgba(139,92,246,.015) 40%, rgba(0,0,0,0) 100%); }
.ss-room .ss-stems-container > * { position:relative; z-index:1; }
@media (max-width:768px){ .ss-room .ss-stems-container::before { inset:0 -8px; } }

/* record studio flows out of the mix — no card, a soft radial pool under the button */
.ss-room .ss-record-studio { background:transparent; border:none; box-shadow:none; position:relative; }
.ss-room .ss-record-studio::before { content:''; position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width:340px; height:220px; max-width:90%; z-index:0; pointer-events:none;
  background:radial-gradient(closest-side, rgba(139,92,246,.12), rgba(139,92,246,0) 72%); }
.ss-room .ss-record-studio > * { position:relative; z-index:1; }

/* vertical rhythm: pull the footer legal up into a settled quiet row */
.ss-room .ss-record-studio-wrap { margin-top:14px; }
.ss-room .ss-player-footer-legal { margin-top:22px; padding-top:14px; padding-left:0; padding-right:0; border-top:1px solid rgba(255,255,255,.05);
  text-align:center; }
.ss-room .ss-report-link { color:#5E5970; font-size:11.5px; }
.ss-room .ss-report-link:hover { color:#8B8698; }
