/*
 * redesign.css — HiFi Riff Raff public-facing stylesheet
 * =========================================================
 *
 * AESTHETIC DIRECTION: Editorial Magazine
 * ----------------------------------------
 * Think: a music publication's artist feature page, not a tech product
 * landing. Generous whitespace, confident typography, warm palette.
 * The band takes themselves seriously enough to want bookings and press
 * coverage — the site should reflect that without feeling corporate.
 *
 * ONE clear vision executed consistently across every page:
 *   - Cream/parchment backgrounds (not sterile white, not moody dark)
 *   - Near-black charcoal text (not pure #000, not gray-on-gray)
 *   - Fraunces variable font for all display headings (expressive,
 *     slightly editorial, has WONK axis for personality)
 *   - Inter for body copy (legible, neutral, doesn't fight Fraunces)
 *   - Single warm accent: amber/terracotta — used sparingly
 *   - Lots of breathing room; elements are never cramped
 *
 * SCOPE: Public-facing pages only.
 *   Covers: MainLayout, HamburgerMenu, NewsletterSignup,
 *   Home bento, About, Releases, Playlists, Shows, Press,
 *   Privacy, Terms, Unsubscribe, Contact.
 *   Does NOT cover: /band/*, /admin/*, Identity pages, audio player.
 *   Those continue to use app.css.
 *
 * FILE STRUCTURE:
 *   1. Design tokens (custom properties)
 *   2. Base reset + global typography
 *   3. Layout chrome (header, footer, body container)
 *   4. Hamburger navigation
 *   5. Newsletter signup strip + component
 *   6. Public-page shell (hero, sections, shared utilities)
 *   7. Home page (bento grid)
 *   8. About page
 *   9. Releases page
 *  10. Playlists page
 *  11. Shows page
 *  12. Press / EPK page
 *  13. Contact form
 *  14. Privacy & Terms (prose pages)
 *  15. Unsubscribe page
 *  16. Utility + accessibility
 *  17. Responsive (mobile breakpoint ≤ 720px, mid ≤ 960px)
 */


/* =========================================================
   1. DESIGN TOKENS
   ========================================================= */

:root {
    /* --- Color palette ---
       Warm cream for backgrounds; near-black for text; amber accent.
       Only 5 named colors + their shades — one designer, one weekend. */

    --color-cream-light: #FBF8F2;   /* raised surfaces above the page — cards, inputs, modals */
    --color-cream:       #F5F0E8;   /* page background — warm, not sterile */
    --color-cream-deep:  #EDE7D9;   /* subtle inset / card backgrounds */
    --color-cream-mid:   #E0D9CC;   /* borders, dividers */
    --color-cream-dark:  #C9C0B0;   /* muted borders, placeholder fills */

    --color-charcoal:    #1C1A17;   /* primary text — near-black, warm */
    --color-charcoal-mid: #3D3A34;  /* secondary text, subheads */
    /* BL-064 / FLG-CLR-006 — nudged from #6B6660 to #615C56. The old value cleared 4.5:1 on cream
       and white but sat at exactly 4.05:1 on the tinted cream-mid / cream-deep fills where meta text
       and status badges land (mv-badge-insufficient, images-admin summary, the register required
       asterisk). The nudge lifts the worst case (on cream-mid) to 4.72:1 while every lighter-surface
       use improves too: on cream 5.83:1, on white 6.62:1. */
    --color-charcoal-muted: #615C56; /* captions, meta, labels */

    --color-accent:      #C4521A;   /* amber/terracotta — the ONE pop color (FILLS/borders/focus) */
    --color-accent-light: #E8733A;  /* hover states */
    --color-accent-dim:  rgba(196, 82, 26, 0.12); /* tinted backgrounds */

    /* Accent-as-TEXT role — split from --color-accent (BL-001 / FLG-CLR-001/002/006).
       --color-accent (#C4521A) is correct for fills/borders/focus but fails the 4.5:1
       text floor as a foreground on cream (4.05:1) and cream-deep (3.73:1). This darker
       amber keeps the brand hue while clearing AA on BOTH cream surfaces AND the accent-dim
       tint. WCAG relative-luminance math (sRGB, contrast = (L_light+0.05)/(L_dark+0.05)):
         #A6440F on #F5F0E8 (cream)      = 5.36:1   (margin +0.86)
         #A6440F on #EDE7D9 (cream-deep) = 4.93:1   (margin +0.43)
         #A6440F on accent-dim/cream     = 4.61:1   (fixes FLG-CLR-002 amber-on-tint ~1:1)
       Both surfaces clear 4.5:1 with margin ≥ 0.2. Used for links, active-nav/tab text,
       role/caption accent text. */
    --color-accent-text: #A6440F;

    --color-white:       #FFFFFF;
    --color-surface:     var(--color-cream);

    /* --- Status solids (warn / ok) — meaning-bearing pill fills, white text on top ---
       Chosen so BOTH floors hold on the cream admin surfaces: white text ≥4.5:1 AND the fill
       itself ≥3:1 as a graphic vs the surface (BL-060). Green ok was a raw #2F6B33 literal (BL-016).
         --color-warn-solid #8a5a00: white-on-fill = 5.93:1, fill-vs-cream = 5.59:1
         --color-ok-solid   #2F6B33: white-on-fill = 5.71:1, fill-vs-cream = 4.13:1 */
    --color-warn-solid:  #8a5a00;
    --color-warn-dim:    rgba(138, 90, 0, 0.10); /* tint for quiet destructive/warn hovers */
    --color-ok-solid:    #2F6B33;

    /* Inline error/destructive TEXT + solid destructive fills (contact + newsletter status,
       CMS field errors, admin viz danger buttons). Defines the token those rules ALREADY
       reference via var(--color-danger, …) — the fallbacks (crimson / #b3261e) meant the token
       was assumed-but-never-declared, and the leftover #b00020 text literals never got folded in.
       Value = the vetted alert-danger red: on cream ≈7:1 as text, white-on-fill ≈8:1 as a
       destructive button. Distinct from the tinted --alert-danger-* BOX vocabulary below.
       (Success/ok text is already covered by --color-ok-solid / --alert-success-*.) */
    --color-danger:      #991B1B;

    /* --- Alert palette (BL-075 / BL-016) — Identity alert boxes + inline danger/info text ---
       Was ~13 raw hex literals scattered across the identity rules (danger/success/info fill,
       text, border, left-rule). Moved into the palette layer so the alert vocabulary is one place.
       Text-on-fill pairs clear AA (e.g. #991B1B on #FEF2F2 = 8.9:1, #166534 on #F0FDF4 = 6.9:1).
       The info blue is retained (informational-alert convention) but centralized here. */
    --alert-danger-bg:     #FEF2F2;
    --alert-danger-text:   #991B1B;
    --alert-danger-border: #FCA5A5;
    --alert-danger-rule:   #B91C1C;
    --alert-success-bg:     #F0FDF4;
    --alert-success-text:   #166534;
    --alert-success-border: #86EFAC;
    --alert-success-rule:   #16A34A;
    --alert-info-bg:     #EFF6FF;
    --alert-info-text:   #1E40AF;
    --alert-info-border: #BFDBFE;
    --alert-info-rule:   #3B82F6;
    /* Solid-fill status pair — the notification bar's saturated green/red banners
       (white text ON a saturated status fill), distinct from the tinted alert
       BOXES above. Kept in the alert palette so the notification bar carries no raw
       literals. Contrast preserved from the prior literals (white on #15803D = 4.6:1,
       white on #B91C1C = 5.9:1); --alert-on-solid is the shared white foreground. */
    --alert-success-solid: #15803D;
    --alert-danger-solid:  #B91C1C;
    /* Status palette — extended shades (admin badges / stronger alert variants). De-literalized
       from raw hex across admin surfaces; VALUES PRESERVED EXACTLY (zero visual change). These are
       the more-saturated Tailwind -100/-600/-700/-800 shades the badges used, distinct from the
       -50/-300 Identity-alert shades above. */
    --alert-danger-bg-strong:      #FEE2E2;
    --alert-danger-border-strong:  #DC2626;
    --alert-success-bg-strong:     #D1FAE5;
    --alert-success-text-strong:   #065F46;
    --alert-success-border-strong: #059669;
    --color-warning:      #B45309;
    --color-warning-deep: #92400E;
    --alert-on-solid:      #FFFFFF;

    /* Google sign-in brand blue — the official Google "G" mark color, identifying Google auth
       (a functional brand dependency, kept per the brand-names rule; tokenized per BL-075). */
    --color-brand-google: #4285F4;

    /* Modal / dialog backdrop scrim — charcoal-tinted, semi-opaque (BL-016). */
    --scrim: rgba(28, 26, 23, 0.55);

    /* --- Semantic surface + text pairs ---
       Pairs ALWAYS travel together. Whenever you set a background-color
       you MUST set its companion text color, and vice versa. This is the
       single rule that makes contrast bugs structurally impossible:
       there's no such thing as "text on body bg" — every text element
       lives in a labeled surface with a guaranteed contrast partner.

       Surfaces:
         surface-page    = the body canvas (cream)
         surface-raised  = a tile sitting on the page (white)
         surface-deep    = a recessed surface (e.g., input field, cream-deep)
         surface-inverse = a dark tile for emphasis (charcoal)
         surface-accent  = the orange/amber accent (CTAs only)

       Each has -text-strong (primary text) and -text-muted (captions,
       meta, eyebrows). The surface/text/muted pairs meet WCAG AA 4.5:1
       for normal text and 3:1 for ≥18px bold. NOTE: the raw brand accent
       (--color-accent) is NOT AA as a text foreground on cream — use
       --color-accent-text for accent-colored text (see BL-001 above). */

    --surface-page:           var(--color-cream);
    --surface-page-text:      var(--color-charcoal);
    --surface-page-text-muted: var(--color-charcoal-muted);

    --surface-raised:         var(--color-white);
    --surface-raised-text:    var(--color-charcoal);
    --surface-raised-text-muted: var(--color-charcoal-muted);

    --surface-deep:           var(--color-cream-deep);
    --surface-deep-text:      var(--color-charcoal);
    --surface-deep-text-muted: var(--color-charcoal-muted);

    --surface-inverse:        var(--color-charcoal);
    --surface-inverse-text:   var(--color-cream);
    --surface-inverse-text-muted: rgba(245, 240, 232, 0.72);

    --surface-accent:         var(--color-accent);
    --surface-accent-text:    var(--color-white);
    --surface-accent-text-muted: rgba(255, 255, 255, 0.85);

    /* Borders for the surface family — same hue family, low contrast */
    --surface-border:         var(--color-cream-mid);
    --surface-inverse-border: rgba(245, 240, 232, 0.18);

    /* --- Chrome surface washes (BL-001 / LayoutSystems L0) ---
       Translucent surfaces the SITE CHROME sits on (sticky header, and — from L5+
       — Stage/Canvas pill + sheet backdrops). These are a translucent wash OVER the
       active page surface, so under Light they resolve to the exact legacy header
       literal (rgb(245,240,232) at .93 α — zero visual delta) and under a dark theme
       they become a translucent near-black wash (the header stops rendering cream —
       the reported bug).

       AI Note (CSS gotcha, verified in-browser): a color-mix() that references
       var(--surface-page) resolves that inner var AT THE ELEMENT WHERE THIS TOKEN IS
       DECLARED (:root), NOT at the consuming element — so defining the mixed color
       here would bake in :root's cream and IGNORE a theme's body-level --surface-page
       override (that was the whole bug in a subtler form). Therefore these tokens hold
       only the RECIPE constants (the source surface role + alpha); the CONSUMER
       composes the mix inline against its own --surface-page (see .main-layout-header)
       so the inner var resolves in the themed element's context. A theme may still
       re-point --surface-veil to an explicit color; the Light default below is the
       exact legacy value for that path too.
         --surface-veil        header/edge-chrome wash — legacy header rgba (Light default)
         --surface-veil-alpha  the wash opacity, so consumers compose one mix
         --chrome-scrim        Stage/Canvas pill + sheet backdrop (L5+ consumers)
         --chrome-scrim-alpha  its opacity
         --chrome-scrim-text   text ON that scrim — the page-surface text role */
    --surface-veil:        rgba(245, 240, 232, 0.93);
    --surface-veil-alpha:  93%;
    --chrome-scrim:        rgba(245, 240, 232, 0.88);
    --chrome-scrim-alpha:  88%;
    --chrome-scrim-text:   var(--surface-page-text);

    /* --- Typography ---
       Fraunces: display headings (weights 300–800, WONK axis for flair)
       Inter: body copy, UI labels, small text */

    --font-display: 'Fraunces', Georgia, serif;
    --font-body:    'Inter', system-ui, -apple-system, sans-serif;

    /* Type scale — tightened for density. Anchor: 1rem = 16px */
    /* --- Type scale: derived from --text-base via fixed multipliers ---
       Change ONE token (--text-base) and every step scales proportionally.
       The /admin/general page edits a site setting that overrides
       --text-base at runtime — see App.razor for the inline <style> that
       injects the override.
       Multipliers chosen to reproduce the prior visual scale (14 / 16 / 17
       / 20 / 26 / 34 / 44 px when base is 14px). */
    --text-base:  0.875rem;                         /* default = 14px */
    --text-xs:    calc(var(--text-base) * 0.800);   /* ≈ 11.2px @ base 14 */
    --text-sm:    calc(var(--text-base) * 0.914);   /* ≈ 12.8px @ base 14 */
    --text-md:    calc(var(--text-base) * 1.071);   /* ≈ 15px   @ base 14 */
    --text-lg:    calc(var(--text-base) * 1.214);   /* ≈ 17px   @ base 14 */
    --text-xl:    calc(var(--text-base) * 1.429);   /* ≈ 20px   @ base 14 */
    --text-2xl:   calc(var(--text-base) * 1.857);   /* ≈ 26px   @ base 14 */
    --text-3xl:   calc(var(--text-base) * 2.400);   /* ≈ 34px   @ base 14 */
    --text-4xl:   calc(var(--text-base) * 3.143);   /* ≈ 44px   @ base 14 */

    /* Line-height companions */
    --leading-tight:  1.15;
    --leading-snug:   1.25;
    --leading-normal: 1.5;
    --leading-relaxed: 1.6;

    /* --- Spacing scale — tightened for dense interface feel ---
       Reduced ~25-30% across the board. */
    --space-1:   0.2rem;    /* 3.2px */
    --space-2:   0.375rem;  /* 6px   */
    --space-3:   0.5rem;    /* 8px   */
    --space-4:   0.75rem;   /* 12px  */
    --space-5:   1rem;      /* 16px  */
    --space-6:   1.5rem;    /* 24px  */
    --space-7:   2rem;      /* 32px  */
    --space-8:   2.75rem;   /* 44px  */
    --space-9:   4rem;      /* 64px  */
    --space-10:  5.5rem;    /* 88px  */

    /* --- Unified page frame (U1 / Unification-Plan-v1.md §M2) ---
       ONE frame token set the .page-frame shell consumes so every public + CMS
       page (all 5 layouts + Identity) shares one geometry. Each token maps to a
       KB rule id in `Layout - Page Frame and Containers` (2026-07-02). The OLD
       names below are kept as ALIASES pointing here so nothing breaks this
       milestone (a later cleanup deletes them). Folded values == the old ones
       (1140 / 720 / clamp) → zero visual delta for correct pages.

         --frame-max-width    frame-container-centered  (folds --max-width + --content-max)
         --frame-prose-measure frame-container-centered (folds --max-width-prose)
         --frame-gutter       frame-min-inline-gutter   (nonzero floor; stepped down in media queries)
         --frame-section-gap  frame-section-rhythm      (one between-section step)
         --frame-inset        (layout override input; insets STACK on the gutter via max(), never replace) */
    --frame-max-width:     1140px;
    --frame-prose-measure: 720px;
    --frame-gutter:        clamp(var(--space-5), 5vw, var(--space-8));
    --frame-section-gap:   var(--space-8);
    --frame-inset:         0px;

    /* Legacy aliases → the frame tokens. Kept so existing consumers (.public-page,
       per-layout header/footer gutters, prose blocks) are unchanged this milestone. */
    --max-width:        var(--frame-max-width);
    --max-width-prose:  var(--frame-prose-measure);
    --page-gutter:      var(--frame-gutter);

    /* --- Borders + Radii ---
       Understated — editorial sites rarely have heavy borders. */
    --radius-sm:   4px;
    --radius-md:   8px;
    --radius-lg:   16px;
    --radius-full: 999px;

    /* Global rounding for CMS bento tiles (.cms-block). One knob rounds every tile —
       background, visualizer, and colored tiles alike. Change here to retune site-wide. */
    --cms-tile-radius: var(--radius-md);

    --border-thin:  1px solid var(--color-cream-mid);
    --border-mid:   2px solid var(--color-cream-dark);
    --border-accent: 2px solid var(--color-accent);

    /* --- Interactive-control border (BL-061 / FLG-CLR-003) ---
       Transparent-fill utility buttons (.track-button, .pager-btn) whose ONLY boundary is a
       hairline need that boundary to clear the 3:1 non-text floor so the affordance is perceivable
       — the shared --border-thin (cream-mid) sits at ~1.24:1 on cream, invisible. This darker warm
       grey is for control OUTLINES only (not decorative dividers, which stay on --border-thin).
       WCAG: #948972 vs cream = 3.04:1 · vs white = 3.45:1. */
    --color-border-control: #948972;
    --border-control: 1px solid var(--color-border-control);

    /* --- Shadows ---
       Subtle warm shadows — no cold gray box shadows. */
    --shadow-sm:  0 1px 3px rgba(28, 26, 23, 0.08);
    --shadow-md:  0 4px 12px rgba(28, 26, 23, 0.10);
    --shadow-lg:  0 8px 32px rgba(28, 26, 23, 0.14);

    /* --- Motion ---
       Short transitions for interactive feedback. */
    --ease-out:    cubic-bezier(0.0, 0.0, 0.2, 1);
    --duration-fast: 120ms;
    --duration-mid:  220ms;

    /* --- Border tokens ---
       --color-border-subtle: the low-contrast hairline used by CMS cards,
       inputs, and editor panels (18 usage sites). Was USED but never DEFINED
       (undefined-var landmine → every `border: 1px solid var(--color-border-subtle)`
       silently dropped to no border — BL-009 / FLG-CMP-BLOCKS-1-02). Points at the
       dedicated border shade so the boundaries actually render; on cream this clears
       the 3:1 non-text floor where it bounds a control. */
    --color-border-subtle: var(--color-cream-mid);

    /* --- Z-INDEX SCALE (BL-003 / FLG-SYS-002) ---
       Semantic ladder replacing 66 raw literals (0..20000). Mapped FROM the actual
       stacking order already in the file so relative order is preserved exactly:
         base(0) < raised(10) < sticky(100) < nav(1000) < overlay(5000)
         < modal(9000) < toast(9500) < max(20000)
       The previously UNDEFINED var(--z-modal) (used at 2 sites) resolves here to 9000,
       matching the live reconnect-dialog / global-modal tier. Literals that don't map
       cleanly (mid-tier player/visualizer values 50/200/500/550/600/700/1010/1200/2000/
       2100) keep their raw value with an inline note — retiering those is out of scope. */
    --z-base:    0;
    --z-raised:  10;
    --z-sticky:  100;
    --z-nav:     1000;
    --z-overlay: 5000;
    --z-modal:   9000;
    --z-toast:   9500;
    --z-max:     20000;

    /* --- Theme groundwork (BL-001/Themes-Architecture-v1) ---
       Light-identical defaults — ZERO visual delta at rest. Themes re-point these.
       Every token is already consumed by a rule below so a theme override never hits
       an undefined var. */
    --surface-page-backdrop: none;                     /* body background-image layer */
    --color-accent-alt:      var(--color-accent-light); /* second accent for two-tone themes */
    --focus-ring:            var(--color-accent);       /* focus-visible outline color */
    --link-hover:            var(--color-accent-light);  /* a:hover color (removes primitive leak) */
    --selection-bg:          var(--color-accent-dim);   /* ::selection background */
    --selection-text:        var(--color-charcoal);     /* ::selection text */
    --display-weight:        600;                        /* display-heading weight */
    --display-tracking:      normal;                     /* display-heading letter-spacing */
    --display-transform:     none;                       /* display-heading text-transform */

    /* --- Surface-LEVEL elevation roles (BL-017 / FLG-SYS-003) ---
       Named ladder documenting the tonal-tint depth model for dark-leaning themes.
       Under Light these are aliases (zero delta); a dark theme re-points them so
       "raised" reads lighter than "page" (elevation-as-lighter-tint, per KB Dark-Mode).
       Ladder low→high: page < deep < raised < raised-2.
         --surface-page   (cream)      the body canvas — lowest
         --surface-deep   (cream-deep) recessed insets/inputs
         --surface-raised (white)      a tile on the page
         --surface-raised-2            a surface stacked ABOVE a raised tile (popover on a card) */
    --surface-raised-2: var(--color-white);

    /* --- Practice game palette ---
       Games use an immersive dark theme distinct from the editorial cream palette.
       Keep these tokens together so a future light-mode game variant can swap them. */
    --game-bg:           #16161f;   /* page/stage background */
    --game-card:         #1e1e2e;   /* card / panel background */
    --game-card-alt:     #2a2050;   /* choice button fill */
    --game-card-hover:   #342a66;   /* choice button hover */
    --game-text:         #eeeeee;   /* primary text on dark bg */
    --game-text-muted:   #aaaaaa;   /* secondary / meta text */
    --game-border:       #444444;   /* default border */
    --game-accent:       #7c6fff;   /* purple accent (links, active states) */
    --game-success:      #80e0a0;   /* correct answer green */
    --game-success-bg:   #1a3a24;   /* success card fill */
    --game-success-border: #2a8040; /* success card border */
    --game-danger:       #f08080;   /* wrong answer red */
    --game-danger-bg:    #3a1a1a;   /* danger card fill */
    --game-danger-border: #803030;  /* danger card border */
    --game-gold:         #e0c840;   /* new-best / gold highlight */

    /* Lyric-game specific — light surface theme used by PracticeDashboard
       and the lyric-game setup / results screens. */
    --game-light-bg:     #f0eefb;   /* pill / metric card background */
    --game-light-border: #e3e1ee;   /* tab / card border */
    --game-light-primary: #6a5acd; /* purple primary — buttons, progress, scores */
    --game-light-success: #2e7d32; /* green — best-score, correct flags */
    --game-light-danger:  #c0392b; /* red — trouble words, miss counts */
    --game-light-success-bg: #e7f5e9;  /* success state fill */
    --game-light-danger-bg:  #fbe4e2;  /* danger state fill */
    --game-light-badge-due:  #e7f0fb;  /* "due" badge fill */
    --game-light-badge-due-text: #2f6fb0;
    /* BL-059 / FLG-CLR-005 — muted text for the LIGHT game surfaces (setup / empty / dashboard).
       The dark-theme --game-text-muted (#aaaaaa) was reused on light-bg/white here where it read
       ~2.0–2.3:1 (labels, mode buttons, empty subtext all failed the 4.5 floor). This darker warm
       grey clears AA on every light game surface. WCAG ratios (contrast=(L_hi+0.05)/(L_lo+0.05)):
         #6b6660 on #f0eefb (light-bg) = 4.96:1 · on #F5F0E8 (cream) = 5.01:1 · on #fff (white) = 5.68:1. */
    --game-light-muted:  #6b6660;
    /* BL-059 — was #9a6a00, only 4.13:1 on light-bg / 4.28:1 on its own warn-bg (below 4.5).
       Darkened to clear AA everywhere: #805700 on #f0eefb = 5.59:1 · on #fff3cf (warn-bg) = 5.78:1 · on #fff = 6.40:1. */
    --game-light-warn:   #805700;   /* amber warning text */
    --game-light-warn-bg: #fff3cf;  /* amber highlight background */
    --game-light-warn-border: #e6b800; /* amber highlight border */

    /* --- Admin control DENSITY tokens (single source of truth for every admin control) ---
       These drive font-size / control height / padding / gaps across the page builder, the
       inspector, the foundation controls, and the layer editor so the admin UI is ONE cohesive,
       space-conserving density system instead of dozens of hardcoded rem/px values. The values
       here are the DENSE profile (default). Wrapping a subtree in `.admin-shell` and setting
       `data-density="ultra"` switches it to the tighter Ultra-dense profile below — that's the
       runtime density toggle. Absolute px (not rem) on purpose: admin chrome should not ride the
       site's --text-base zoom knob. */
    --admin-text-label:   11px;     /* field labels */
    --admin-text-control: 12px;     /* input / select / button text */
    --admin-text-help:    10.5px;   /* helper + error text */
    --admin-text-section: 11px;     /* group/section headings (uppercase) */
    --admin-control-h:    24px;     /* shared input/select/button height — keeps a row aligned */
    --admin-pad-y:        4px;
    --admin-pad-x:        8px;
    --admin-gap:          6px;      /* gap between a label and its control / between fields */
    --admin-section-gap:  10px;     /* gap between grouped sections */
    --admin-radius:       var(--radius-sm);
}

/* Ultra-dense profile — opt-in via the density toggle. Only the values that get tighter. */
.admin-shell[data-density="ultra"] {
    --admin-text-label:   10.5px;
    --admin-text-control: 11px;
    --admin-text-help:    10px;
    --admin-text-section: 10.5px;
    --admin-control-h:    22px;
    --admin-pad-y:        3px;
    --admin-pad-x:        6px;
    --admin-gap:          4px;
    --admin-section-gap:  8px;
}


/* =========================================================
   1b. BENTO SPEC FOUNDATION (additive — docs/features/bento-system/)
   Spec-compliant tokens + utilities layered ALONGSIDE the tokens above.
   Nothing here is wired to a component yet — components migrate onto these
   per-phase (BentoRollout-Plan-v1.md), so this block is visually inert.
   Do NOT re-point the existing --space-1..10 / --text-* values; migrate
   call sites instead.
   ========================================================= */
:root {
    /* --- Spacing: coherent 8px scale (4px substep), role-named ---
       Distinct from the numeric --space-1..10 above (kept until migrated). */
    --space-3xs: 0.25rem;  /* 4px  */
    --space-2xs: 0.5rem;   /* 8px  */
    --space-xs:  0.75rem;  /* 12px */
    --space-s:   1rem;     /* 16px */
    --space-m:   1.5rem;   /* 24px */
    --space-l:   2rem;     /* 32px */
    --space-xl:  3rem;     /* 48px */
    --space-2xl: 4rem;     /* 64px */
    --space-3xl: 6rem;     /* 96px */

    /* --- Fluid type scale (modular ~1.25); clamp() with rem floor/ceiling ---
       Floor/ceiling in rem => zoom-safe (WCAG 1.4.4 200%); the vw term only
       drives the slope between min/max viewport (20rem..80rem). Page/shell text
       uses these steps; in-tile text uses cqi (.bento-tile-* below). */
    --step--1: clamp(0.8rem,  0.76rem + 0.20vw, 0.9rem);
    --step-0:  clamp(1rem,    0.95rem + 0.25vw, 1.125rem);  /* body */
    --step-1:  clamp(1.25rem, 1.16rem + 0.45vw, 1.5rem);
    --step-2:  clamp(1.56rem, 1.41rem + 0.75vw, 2rem);
    --step-3:  clamp(1.95rem, 1.71rem + 1.20vw, 2.66rem);
    --step-4:  clamp(2.44rem, 2.05rem + 1.95vw, 3.55rem);
    --step-5:  clamp(3.05rem, 2.43rem + 3.10vw, 4.74rem);

    /* --- Measure (readable line length) --- */
    --measure: 65ch;

    /* --- Bento layout primitives --- */
    --bento-gutter: clamp(1rem, 5vw, 2.5rem);    /* fluid page side gutter */
    --bento-gap:    clamp(0.75rem, 2vw, 1.5rem); /* fluid inter-tile gap   */
    --content-max:  75rem;                        /* ~1200px content column */
    --radius-tile:  var(--cms-tile-radius);       /* semantic alias         */
    --tile-focal:   50% 50%;                      /* default image focal     */

    /* Header logo height — admin-controlled (/admin/general → App.razor injects a :root
       override at request time). Declared here as a first-class token (default 24px) so
       consumers reference it directly; the App.razor override wins when set. The header
       rule's var(--logo-height, 24px) fallback is now belt-and-suspenders. */
    --logo-height:  24px;
}

/* Readable-measure helper — never wider than its container. */
.bento-measure { max-width: min(var(--measure), 100%); }

/* In-tile fluid text — scales to the TILE (needs an inline-size container
   ancestor). cqi = 1% of container inline size; rem floor/ceiling keep it
   zoom-safe. (Named .bento-* to avoid the existing .tile-title rule.) */
.bento-tile-title { font-size: clamp(1.1rem, 6cqi, 2.5rem);  line-height: var(--leading-tight, 1.15); }
.bento-tile-body  { font-size: clamp(0.9rem, 3.5cqi, 1.25rem); line-height: var(--leading-normal, 1.5); }

/* Full-bleed safe-area padding (notched devices). Requires viewport-fit=cover
   on the viewport meta (App.razor); env() resolves to 0 on rectangular screens. */
.bento-safe-pad-inline {
    padding-inline: max(var(--bento-gutter), env(safe-area-inset-left), env(safe-area-inset-right));
}

/* Grid size-class spans of a 12-col authoring grid, clamped so a span never
   exceeds the live column count (--bento-cols, set per breakpoint in Phase 1).
   Inert until the grid contract lands; here so components can adopt them. */
.bento-s    { grid-column: span min(3, var(--bento-cols, 12)); }
.bento-m    { grid-column: span min(4, var(--bento-cols, 12)); }
.bento-l    { grid-column: span min(6, var(--bento-cols, 12)); }
.bento-wide { grid-column: span min(8, var(--bento-cols, 12)); }
.bento-hero { grid-column: 1 / -1; }


/* =========================================================
   2. BASE RESET + GLOBAL TYPOGRAPHY
   ========================================================= */

/*
 * Minimal targeted reset — don't nuke everything because app.css
 * is still in play for admin/band areas. We scope to the public
 * layout container where possible.
 */

*,
*::before,
*::after {
    box-sizing: border-box;
}

/* Body sets the canvas.
   app.css's `.dynamic-background-*` classes paint a blurred gray
   gradient + `filter: blur(80px) contrast(80%)` on <body>. The filter
   blurs ALL child content — which is why the redesign was rendering
   "dark purple over dark grey" for release titles + every page felt
   smeared. We override the entire animated-bg machinery here:
     - background-color: solid cream (kills the gradient)
     - background-image: none (kills the radial-gradient stops)
     - filter: none (THIS is the critical one — without it the entire
                     page is rendered through an 80px Gaussian blur)
     - all !important because app.css's body rules outweigh ours
                     without it. */
body {
    background-color: var(--surface-page) !important;
    background-image: var(--surface-page-backdrop) !important;
    filter: none !important;
    color: var(--surface-page-text);
    font-family: var(--font-body);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    margin: 0;
    padding: 0;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Kill the animated blobs (::before / ::after pseudo-elements) painted
   by .dynamic-background-bright-one + -dark-one in app.css. These were
   incompatible with the editorial direction — blurry gray motion behind
   editorial type doesn't work. */
body[class*="dynamic-background"]::before,
body[class*="dynamic-background"]::after {
    content: none !important;
    display: none !important;
    animation: none !important;
}

/* SCROLLBAR + HORIZONTAL-OVERFLOW ROOT-CAUSE FIX.
   app.css's `.main-layout-body { height: calc(100dvh - 4.5rem);
   overflow-y: auto; width: 100vw }` was creating both bugs:
     1. Inner overflow-y: auto → a second vertical scrollbar inside
        the page, while <html> also scrolls. (User report: "two
        side-by-side vertical scrollbars.")
     2. width: 100vw → viewport width INCLUDES the scrollbar gutter,
        so the body becomes ~15px wider than its parent on browsers
        that reserve scrollbar space. (User report: horizontal
        scrollbar that only scrolls the scrollbar's own width.)
   Both are dispatched by letting <html> own the scrolling, and sizing
   the body to its container (not the viewport). The previous
   overflow-x: clip + scrollbar-gutter: stable hack is removed —
   defending against this overflow was unnecessary once the source
   stopped producing it. */
.main-layout-body {
    height: auto !important;
    overflow: visible !important;
    width: 100% !important;
}

/* Typographic defaults inside the public layout container.
   AI Note: every selector below uses `:where()` so it has specificity 0,0,1
   instead of 0,1,1. This is THE critical fix for the contrast-bug class
   we kept hitting: previously `.main-layout-container h1 { color: charcoal }`
   beat per-tile rules like `.home-hero-tagline-text { color: cream }`
   because (0,1,1) > (0,1,0). With :where() the specificity falls to a single
   element, so any per-component class wins automatically. */
:where(.main-layout-container) {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
}

:where(.main-layout-container) h1,
:where(.main-layout-container) h2,
:where(.main-layout-container) h3,
:where(.main-layout-container) h4 {
    font-family: var(--font-display);
    font-weight: var(--display-weight);
    letter-spacing: var(--display-tracking);
    text-transform: var(--display-transform);
    line-height: var(--leading-tight);
    /* No color: surface containers set their own; absent that, headings
       inherit body color (charcoal). This is what lets a charcoal tile
       have cream-colored headings without a specificity fight. */
    margin: 0;
}

:where(.main-layout-container) p {
    margin: 0;
}

:where(.main-layout-container) a {
    color: var(--color-accent-text);
    text-decoration: none;
    transition: color var(--duration-fast) var(--ease-out);
}

:where(.main-layout-container) a:hover {
    color: var(--link-hover);
}

/* Text selection — themeable pair, Light default = accent-dim / charcoal (zero delta). */
:where(.main-layout-container) ::selection {
    background: var(--selection-bg);
    color: var(--selection-text);
}

/* Remove list bullets inside the public layout (nav, press lists,
   etc. use their own classes) */
:where(.main-layout-container) ul,
:where(.main-layout-container) ol {
    margin: 0;
    padding: 0;
    list-style: none;
}

img {
    max-width: 100%;
    height: auto;
    display: block;
}

button {
    font-family: inherit;
    cursor: pointer;
}

/* Form-control font reset (BL-018 / FLG-TSM-001).
   Native input/select/textarea/button otherwise fall to the UA default
   ~13.333px (0.8333em), escaping the type scale on 33 pages. Inherit the
   ancestor font (public controls → body --text-base) instead.
   AI Note: zero-specificity :where() on purpose — any component rule that
   sets font-size (the --admin-* density system: .admin-input, .admin-button,
   etc.) still wins, so admin/band px sizing is untouched. Only controls with
   NO explicit font-size change (the ones that were silently dropping to UA
   default). */
:where(input, select, textarea, button) {
    font-family: inherit;
    font-size: inherit;
    line-height: inherit;
}

/* Focus ring — warm accent, not browser blue (themeable via --focus-ring) */
.main-layout-container :focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 3px;
    border-radius: var(--radius-sm);
}


/* =========================================================
   3. LAYOUT CHROME
   Header · Body · Footer
   ========================================================= */

/*
 * Main layout structure:
 *   .main-layout-container (flex column, full height)
 *     .main-layout-header  (sticky top bar — compact, 40px target height)
 *     .main-layout-body    (flex-grow, page content lives here)
 *     .main-layout-newsletter (slim strip above footer)
 *     .main-layout-footer  (copyright row)
 *
 * Header child order (left → right):
 *   [logo] [HamburgerMenu — inline nav + mobile toggle] [booking pill]
 */

/* --- Header --- */

.main-layout-header {
    position: sticky;
    top: 0;
    z-index: var(--z-sticky);
    /* relative so .site-nav-panel (position: absolute) anchors here */
    display: flex;
    align-items: center;
    gap: var(--space-4);
    /* Header height target: ~32px. Both the logo (24px) and the booking
       pill (~22px) are sized below so they fit in this band without
       padding pushing it taller. */
    padding: 2px var(--page-gutter);
    /* Semantic border + wash so all themes reach the header (was --border-thin +
       a cream rgba literal, which kept the header cream under Dark — BL-001). The
       wash is composed INLINE from --surface-page so the theme's body-level page
       color wins here (see the --surface-veil AI Note — a :root-baked mix would not
       follow the override). Light: mix(cream 93%, transparent) == the legacy value. */
    border-bottom: 1px solid var(--surface-border);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    background-color: color-mix(in srgb, var(--surface-page) var(--surface-veil-alpha), transparent);
    min-height: 0;
}

/* Logo chrome — height/padding/margin are admin-controlled via
   /admin/general, injected into :root by App.razor. Defaults set
   below are the bare-CSS fallback when no override is saved. */
.main-layout-header-logo-wrapper {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    padding: var(--logo-padding, 0);
    margin: var(--logo-margin, 0);
}

.main-layout-header-logo-link {
    display: flex;
    align-items: center;
    /* No color override — SVG carries its own color */
}

.main-layout-header-logo {
    height: var(--logo-height, 24px);
    width: auto;
    display: block;
}

/* Right-side actions group — booking pill + any future header icons */
.main-layout-header-actions {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
}

/* "Booking Inquiry" pill — minimal so it doesn't dominate header height.
   Pill is ~22px tall; with header's 2px vertical padding the total band
   is ~26-28px. */
.main-layout-header-booking {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    /* BL-029 / FLG-NAV-005 — the pill rendered ~21px tall, below the 24px target floor. */
    min-height: 24px;
    padding: 1px var(--space-3);
    background-color: var(--surface-accent);
    color: var(--surface-accent-text) !important;
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    border-radius: var(--radius-full);
    text-decoration: none;
    line-height: 1.5;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.main-layout-header-booking:hover {
    background-color: var(--color-accent-light);
    color: var(--surface-accent-text) !important;
    transform: translateY(-1px);
}

/* --- Body --- */

.main-layout-body {
    flex: 1;
    /* No padding here — each page controls its own gutter */
}

.main-layout-body main {
    min-height: 0;
}

/* --- Newsletter strip --- */

.main-layout-newsletter {
    border-top: var(--border-thin);
    background-color: var(--surface-deep);
    padding: var(--space-4) var(--page-gutter);
    display: flex;
    justify-content: center;
}

/* --- Footer --- */

.main-layout-footer {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: var(--space-5);
    padding: var(--space-4) var(--page-gutter);
    /* Footer is the page surface (was cream + --border-thin, which stayed cream
       under Dark — BL-001). Page tokens follow every theme. */
    border-top: 1px solid var(--surface-border);
    background-color: var(--surface-page);
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
}

.main-layout-footer a {
    color: var(--surface-page-text-muted);
    transition: color var(--duration-fast) var(--ease-out);
}

.main-layout-footer a:hover {
    color: var(--color-accent-text); /* BL-001: contrast-guaranteed accent-as-text */
}

/* Footer legal links render with no whitespace between them (Blazor loop). Separate each with a
   colored "|" divider — a different color than the (muted) link text so the links read as distinct. */
.main-layout-footer nav {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
}
.main-layout-footer nav a:not(:last-child)::after {
    content: "|";
    margin-inline: 0.6em;
    color: var(--color-accent);
    pointer-events: none;
}

/* Blazor error UI.
   AI Note: this div MUST default to `display: none`. Blazor's JS reveals it by
   setting an inline `style="display: block"` ONLY when a genuine unhandled error
   occurs. A previous redesign pass set `display: flex` with NO hidden default
   ("keep unobtrusive but visible"), which left the "An unhandled error has
   occurred" banner permanently shown on every page using this layout — with no
   actual error. Do NOT remove `display: none`. See docs/Landmines-v1.md. */
#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: var(--z-toast); /* BL-003: error banner above modals */
    padding: var(--space-4) var(--page-gutter);
    background: #7B1D1D;
    color: #fff;
    font-size: var(--text-sm);
    align-items: center;
    gap: var(--space-4);
}

/* When Blazor genuinely reveals the banner it sets inline `display: block`.
   Restore the flex row layout (so the dismiss button right-aligns) — !important
   is required to beat the framework-set inline style. */
#blazor-error-ui[style*="block"] {
    display: flex !important;
}

#blazor-error-ui a {
    color: #fff;
    text-decoration: underline;
}

#blazor-error-ui .dismiss {
    margin-left: auto;
    cursor: pointer;
    opacity: 0.8;
}

#blazor-error-ui .dismiss:hover {
    opacity: 1;
}


/* =========================================================
   3b. STAGE LAYOUT — CHROME COLOR ASSIGNMENTS
   The Stage layout's GEOMETRY lives in wwwroot/layouts/stage.css (inert
   until data-layout="stage" is stamped). COLOR must stay here so it flows
   through the same semantic-token discipline the rest of the chrome does —
   every declaration below consumes a semantic token (no primitive/literal),
   so all 12 themes reach the Stage chrome and the ClassicChromePurityTest
   (which scans .site-nav / .main-layout-* selectors) stays green.

   - Stage header: transparent, so --surface-page-backdrop shows through the
     full-bleed identity band.
   - Scroll cue + active-nav underline: currentColor / accent-as-text, so they
     inherit the themed text color the base rules already assign.
   - Pill + fixed sheet: the --chrome-scrim backdrop, composed INLINE from
     --surface-page (the L0 idiom — a :root-baked mix would ignore a theme's
     body-level --surface-page override; see the --chrome-scrim AI Note), with
     --chrome-scrim-text on top.
   - Backstage footer: the --surface-inverse family (the "backstage" band).
   ========================================================= */

/* Stage header reads as an open band over the page backdrop — no wash/bar fill. */
.main-layout-container[data-layout="stage"] .main-layout-header {
    background-color: transparent;
    border-bottom-color: transparent;
}

/* Scroll cue: themed text color (its borders use currentColor via the geometry
   file's border-*: <width> solid with no color). */
.main-layout-container[data-layout="stage"] .stage-cue {
    color: var(--surface-page-text-muted);
}

/* Active inline-nav underline color = the accent-as-text role the base
   .site-nav-link.active already sets for text; mirror it onto the border. */
.main-layout-container[data-layout="stage"] .site-nav-link.active {
    border-bottom-color: currentcolor;
}

/* Pill + fixed disclosure sheet: the chrome scrim backdrop (composed inline so
   the theme's page color wins) + scrim text. Same recipe as the L0 header wash
   but at the scrim alpha. */
.main-layout-container[data-layout="stage"].stage--scrolled .stage-cluster,
.main-layout-container[data-layout="stage"].stage--scrolled .site-nav-panel {
    background-color: color-mix(in srgb, var(--surface-page) var(--chrome-scrim-alpha), transparent);
    color: var(--chrome-scrim-text);
    border: 1px solid var(--surface-border);
}

/* Reduced-motion pins the pill permanently (geometry in stage.css §7); it needs
   the same scrim colors since .stage--scrolled may never be toggled. */
@media (prefers-reduced-motion: reduce) {
    .main-layout-container[data-layout="stage"] .stage-cluster,
    .main-layout-container[data-layout="stage"] .site-nav-panel {
        background-color: color-mix(in srgb, var(--surface-page) var(--chrome-scrim-alpha), transparent);
        color: var(--chrome-scrim-text);
        border: 1px solid var(--surface-border);
    }
}

/* Backstage footer: the inverse surface family (full-bleed dark band). */
.main-layout-container[data-layout="stage"] .main-layout-footer {
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    border-top-color: var(--surface-inverse-border);
}

.main-layout-container[data-layout="stage"] .main-layout-footer a {
    color: var(--surface-inverse-text);
}

.main-layout-container[data-layout="stage"] .main-layout-footer a:hover {
    color: var(--surface-inverse-text-muted);
}


/* =========================================================
   3c. OVERLAY LAYOUT — CHROME COLOR ASSIGNMENTS
   The Overlay layout's GEOMETRY lives in wwwroot/layouts/overlay.css (inert
   until data-layout="overlay" is stamped). COLOR stays here so it flows through
   the same semantic-token discipline the rest of the chrome does — every
   declaration below consumes a semantic token (no primitive/literal), so all 12
   themes reach the Overlay chrome and ClassicChromePurityTest stays green.

   - Edge header: transparent, so the page backdrop reads through the edge chrome.
   - Menu button + poster nav sit on the page surface (edge chrome) OR the inverse
     fullscreen sheet (panel). The panel = the --surface-inverse family (a full-
     bleed dark sheet), so poster text/eyebrows use --surface-inverse-text*.
   - CURRENT-PAGE cue is NON-COLOR by design: accent-as-text (--color-accent-text)
     is tuned for AA on the LIGHT page surface and is NOT guaranteed to clear AA on
     the inverse sheet per theme. So the active link is marked by index-marker fill +
     underline (geometry in overlay.css §5) rendered in the inverse TEXT color — a
     shape/weight cue, not a hue cue. Documented in LayoutSpec-Overlay-v1.md.
   ========================================================= */

/* Edge header reads as an open transparent strip over the page backdrop. */
.main-layout-container[data-layout="overlay"] .main-layout-header {
    background-color: transparent;
    border-bottom-color: transparent;
}

/* The Menu button + its bars/label sit on the page surface at the edge — themed
   page text so they read on any theme's backdrop. */
.main-layout-container[data-layout="overlay"] .site-nav-toggle-btn {
    color: var(--surface-page-text);
    border: 1px solid var(--surface-border);
    background-color: color-mix(in srgb, var(--surface-page) var(--chrome-scrim-alpha), transparent);
}

.main-layout-container[data-layout="overlay"] .site-nav-toggle-btn .site-nav-bar {
    background-color: var(--surface-page-text);
}

/* Fullscreen panel = the inverse surface family (a full-bleed dark sheet). */
.main-layout-container[data-layout="overlay"] .site-nav-panel {
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
}

/* Poster public nav: display type in the inverse text color; inherits the theme's
   display font family (poster type follows --font-display per the spec). */
.main-layout-container[data-layout="overlay"] .site-nav-panel-public .site-nav-panel-link {
    font-family: var(--font-display);
    color: var(--surface-inverse-text);
}

.main-layout-container[data-layout="overlay"] .site-nav-panel-public .site-nav-panel-link:hover {
    color: var(--surface-inverse-text);
    background-color: transparent;
}

/* Numbered eyebrow + active marker/underline: inverse text color (a non-color cue —
   fill + underline geometry lives in overlay.css §5). The active link is NOT tinted
   with the accent, because accent-as-text isn't contrast-guaranteed on the inverse. */
.main-layout-container[data-layout="overlay"] .site-nav-panel-public .site-nav-panel-link::before {
    color: var(--surface-inverse-text-muted);
}

.main-layout-container[data-layout="overlay"] .site-nav-panel-public .site-nav-panel-link.active,
.main-layout-container[data-layout="overlay"] .site-nav-panel-public .site-nav-panel-link.active::before {
    color: var(--surface-inverse-text);
    text-decoration-color: var(--surface-inverse-text);
}

/* Utility column: auth section labels/links on the inverse sheet. */
.main-layout-container[data-layout="overlay"] .site-nav-panel-section-label {
    color: var(--surface-inverse-text-muted);
}

.main-layout-container[data-layout="overlay"] .site-nav-panel-link {
    color: var(--surface-inverse-text);
}

.main-layout-container[data-layout="overlay"] .site-nav-panel-link:hover {
    color: var(--surface-inverse-text);
    background-color: var(--surface-inverse-border);
}


/* =========================================================
   3d. RAIL LAYOUT — CHROME COLOR ASSIGNMENTS
   The Rail layout's GEOMETRY lives in wwwroot/layouts/rail.css (inert until
   data-layout="rail" is stamped). COLOR stays here so it flows through the same
   semantic-token discipline the rest of the chrome does — every declaration below
   consumes a semantic token (no primitive/literal), so all 12 themes reach the Rail
   chrome and ClassicChromePurityTest stays green.

   - Rail sidecar: transparent over the page backdrop, a single --surface-border
     right-rule separating it from the content column. Rail text = the page-text family.
   - Vertical public nav: base .site-nav-link colors already follow the theme; the
     aria-current left-rule CONSUMES the existing accent-as-text token (--color-accent),
     matching the accent the base .active rule assigns to the link text.
   - The "Account" flyout panel keeps the base raised-surface family (the base
     .site-nav-panel already uses --surface-raised*), so no re-assignment is needed.
   - Social glyphs + credits: muted page text; CTA = the surface-accent pair (base
     .main-layout-header-booking already themes correctly).
   - Collapsed (≤880px) top bar: the --surface-veil wash composed INLINE from
     --surface-page (the L0 idiom — a :root-baked mix would ignore a theme's body-level
     --surface-page override), so the compact bar reads on any theme's backdrop.
   ========================================================= */

/* The sidecar reads as an open transparent column over the page backdrop, divided from
   the content by one themed right-rule (geometry — the border WIDTH/side — is in rail.css;
   only the COLOR is assigned here). */
.main-layout-container[data-layout="rail"] .main-layout-header {
    background-color: transparent;
    border-right-color: var(--surface-border);
}

/* aria-current cue: a left-rule whose COLOR is the accent, mirroring the accent-as-text
   the base .site-nav-link.active rule assigns to the label. Geometry (3px, left side) is in
   rail.css; only the color lives here. */
.main-layout-container[data-layout="rail"] .site-nav-link.active {
    border-left-color: var(--color-accent);
}

/* Social glyphs + credits sit on the transparent rail as muted page text. */
.main-layout-container[data-layout="rail"] .rail-social-link,
.main-layout-container[data-layout="rail"] .rail-credits {
    color: var(--surface-page-text-muted);
}

.main-layout-container[data-layout="rail"] .rail-social-link:hover {
    color: var(--surface-page-text);
}

/* Collapsed (≤880px) top bar: a compact sticky bar whose backdrop is the veil wash,
   composed inline from the theme's page surface (same recipe as the L0 header wash). */
@media (max-width: 880px) {
    .main-layout-container[data-layout="rail"] .main-layout-header {
        background-color: color-mix(in srgb, var(--surface-page) var(--surface-veil-alpha), transparent);
        border-right-color: transparent;
        border-bottom-color: var(--surface-border);
    }
}

/* =========================================================
   3e. CANVAS LAYOUT (EXPERIMENTAL) — CHROME COLOR ASSIGNMENTS
   The Canvas layout's GEOMETRY lives in wwwroot/layouts/canvas.css (inert
   until data-layout="canvas" is stamped). COLOR stays here so it flows
   through the same semantic-token discipline the rest of the chrome does —
   every declaration below consumes a semantic token (no primitive/literal),
   so all 12 themes reach the Canvas chrome and ClassicChromePurityTest stays
   green.

   - Pinned pill: the --chrome-scrim backdrop (composed INLINE from --surface-page
     so a theme's body-level page override wins — the L0 idiom) + --chrome-scrim-text,
     mirroring Stage's pill so the Canvas-home / Stage-interior pairing matches.
   - Nav chip label: the raised-surface family (a small floating pill on the board),
     with the accent-as-text role on hover/focus (contrast-guaranteed — BL-001). The
     stretched anchor itself is transparent (hit area only), so no color there.
   ========================================================= */

/* The permanently-pinned nav pill: the chrome scrim backdrop + scrim text, same recipe as Stage's
   pill (composed inline so the theme's page color wins). */
.main-layout-container[data-layout="canvas"] .canvas-pill,
.main-layout-container[data-layout="canvas"] .site-nav-panel {
    background-color: color-mix(in srgb, var(--surface-page) var(--chrome-scrim-alpha), transparent);
    color: var(--chrome-scrim-text);
    border: 1px solid var(--surface-border);
}

/* The Canvas header is an open band over the board — no wash/bar fill (the pill carries the scrim). */
.main-layout-container[data-layout="canvas"] .main-layout-header {
    background-color: transparent;
    border-bottom-color: transparent;
}

/* Nav-chip label: a raised-surface pill on the board; accent-as-text on hover/focus. The visible chip
   is the label span (the anchor is a transparent full-tile hit layer, so it takes no color). */
.main-layout-container[data-layout="canvas"] .canvas-nav-chip-label {
    background-color: var(--surface-raised);
    color: var(--surface-raised-text);
    box-shadow: var(--shadow-sm);
    border: 1px solid var(--surface-border);
}

.main-layout-container[data-layout="canvas"] .canvas-nav-chip:hover .canvas-nav-chip-label,
.main-layout-container[data-layout="canvas"] .canvas-nav-chip:focus-visible .canvas-nav-chip-label {
    color: var(--color-accent-text); /* BL-001: contrast-guaranteed accent-as-text */
}


/* =========================================================
   4. SITE NAVIGATION
   Inline desktop strip + mobile slide-down panel
   ========================================================= */

/*
 * HamburgerMenu.razor renders the nav in two layers:
 *
 *   1. .site-nav-inline  — horizontal row of links, visible on desktop
 *                          (> 880px), hidden on mobile
 *   2. .site-nav-toggle-btn + .site-nav-panel — the hamburger icon +
 *                          full-width slide-down panel, visible on mobile
 *                          and always-available for authenticated users
 *                          who need band/admin links on desktop
 *
 * Markup order in HamburgerMenu.razor (MUST stay fixed):
 *   input.site-nav-toggle-input   ← hidden checkbox toggle
 *   nav.site-nav-inline           ← desktop inline links
 *   label.site-nav-toggle-btn     ← the 3-bar button
 *   nav.site-nav-panel            ← the panel (sibling of checkbox)
 *
 * CSS selector bridge: :checked ~ .site-nav-panel opens the panel.
 * The label is the visual button; the input is the state holder.
 *
 * AI Note: The toggle input must remain a PREVIOUS sibling of BOTH the
 * label and the panel. Reordering breaks the :checked ~ selector without
 * producing a compile error. See HamburgerMenu.razor for the full rationale.
 */

/* --- Shared container --- */

/* The entire SiteNav is a flex row that lives in the header.
   We set flex: 1 so it stretches between logo and actions. */
.site-nav-toggle-input,
.site-nav-inline,
.site-nav-toggle-btn,
.site-nav-panel {
    /* nothing at this level — each sub-element sized below */
}

/* The SiteNav renders directly inside .main-layout-header as siblings:
   [logo-wrapper] [toggle-input (0x0)] [site-nav-inline] [toggle-btn] [actions]
   We need site-nav-inline to grow and fill the center gap. */
.site-nav-inline {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: 1;
    padding: 0 var(--space-3);
}

/* --- Desktop inline links --- */

.site-nav-link {
    display: inline-flex;
    align-items: center;
    /* Tight enough to fit in the ~32px header band; min-height holds the 24px target floor
       (BL-029 / FLG-NAV-005 — links measured ~26px, but floor it so it can't dip under). */
    min-height: 24px;
    padding: 2px var(--space-3);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    /* Muted page-surface text — resolves to charcoal-mid under Light (zero delta),
       and to the theme's muted role elsewhere (BL-001). */
    color: var(--surface-page-text-muted);
    text-decoration: none;
    border-radius: var(--radius-sm);
    letter-spacing: 0.01em;
    line-height: 1.5;
    transition: color var(--duration-fast) var(--ease-out),
                background-color var(--duration-fast) var(--ease-out);
    white-space: nowrap;
}

.site-nav-link:hover {
    /* Hover lifts text to full page-text strength on a recessed wash.
       --surface-deep = cream-deep under Light (zero delta) and themes re-point it,
       so the hover chip stays legible cross-theme. */
    color: var(--surface-page-text);
    background-color: var(--surface-deep);
}

/* Blazor NavLink adds .active when the route matches */
.site-nav-link.active {
    color: var(--color-accent-text); /* BL-001/FLG-CLR-001: contrast-guaranteed accent-as-text */
    font-weight: 600;
}

/* --- Hidden toggle checkbox --- */

.site-nav-toggle-input {
    /* Invisible state holder — activated via label */
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    pointer-events: none;
}

/* --- Hamburger toggle button --- */

.site-nav-toggle-btn {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 5px;
    width: 36px;
    height: 36px;
    padding: var(--space-2);
    flex-shrink: 0;
    cursor: pointer;
    border-radius: var(--radius-sm);
    transition: background-color var(--duration-fast) var(--ease-out);
}

.site-nav-toggle-btn:hover {
    background-color: var(--surface-deep); /* same recessed-wash family as nav-link hover */
}

/* The visible "Menu" word is hidden by default — only the Overlay layout shows it
   (overlay.css un-hides under [data-layout="overlay"]). Keeping it display:none here
   means Classic/Stage render the bare 3-bar glyph exactly as before this span landed. */
.site-nav-toggle-label {
    display: none;
}

.site-nav-bar {
    display: block;
    width: 18px;
    height: 1.5px;
    background-color: var(--surface-page-text); /* bars read as page text on the header wash */
    border-radius: 1px;
    transition: transform var(--duration-mid) var(--ease-out),
                opacity var(--duration-mid) var(--ease-out);
    transform-origin: center;
}

/* X animation when panel is open */
.site-nav-toggle-input:checked ~ .site-nav-toggle-btn .site-nav-bar:nth-child(1) {
    transform: translateY(6.5px) rotate(45deg);
}

.site-nav-toggle-input:checked ~ .site-nav-toggle-btn .site-nav-bar:nth-child(2) {
    opacity: 0;
    transform: scaleX(0);
}

.site-nav-toggle-input:checked ~ .site-nav-toggle-btn .site-nav-bar:nth-child(3) {
    transform: translateY(-6.5px) rotate(-45deg);
}

/* --- Slide-down panel --- */

/*
 * The panel is position:absolute relative to .main-layout-header (sticky).
 * It is sized to its CONTENT and right-anchored (under the booking pill
 * area). NOT full-viewport-width — that looked ridiculous on desktop.
 *
 * AI Note: max-height + overflow-y ensures the panel never clips when
 * a logged-in Administrator has 15+ items in band+admin sections.
 */
.site-nav-panel {
    display: none;           /* closed by default */
    position: absolute;
    top: 100%;
    right: 0;                /* anchor to header's right edge */
    z-index: 200;
    background-color: var(--surface-raised);
    color: var(--surface-raised-text);
    border: 1px solid var(--surface-border);
    border-top: none;
    border-radius: 0 0 var(--radius-md) var(--radius-md);
    box-shadow: var(--shadow-lg);
    /* Size to content with a sane min/max envelope. Cap is wide enough for all admin sections
       (Account/Band/Site/Admin/Store) to sit side-by-side on desktop instead of wrapping the
       last column to a new line; still clamps to the viewport on narrow screens. */
    width: max-content;
    max-width: min(calc(100vw - 2rem), 1040px);
    min-width: 200px;
    max-height: calc(100dvh - 4rem);
    overflow-y: auto;
    padding: var(--space-4) var(--space-5);
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--space-4) var(--space-6);
}

.site-nav-toggle-input:checked ~ .site-nav-panel {
    display: flex;
}

/* Public links — shown in panel on mobile, hidden on desktop
   since they're visible inline */
.site-nav-panel-public {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 130px;
}

/* Section groups for authenticated links */
.site-nav-panel-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 130px;
}

.site-nav-panel-section-label {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--surface-raised-text-muted); /* label sits on the raised panel */
    padding: var(--space-2) var(--space-3) var(--space-1);
    display: block;
}

.site-nav-panel-link {
    display: block;
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-body);
    font-size: var(--text-base);
    font-weight: 500;
    color: var(--surface-raised-text); /* link text on the raised panel */
    text-decoration: none;
    border-radius: var(--radius-sm);
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.site-nav-panel-link:hover {
    background-color: var(--surface-deep);
    color: var(--color-accent-text); /* BL-001: contrast-guaranteed accent-as-text (was raw --color-accent) */
}

.site-nav-panel-link.active {
    color: var(--color-accent-text); /* BL-001: accent-as-text role, not the fill accent */
    font-weight: 600;
}

/* Footer row inside the panel — login/logout */
.site-nav-panel-footer {
    width: 100%;
    border-top: 1px solid var(--surface-border);
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    display: flex;
    align-items: center;
}

.site-nav-panel-logout {
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-body);
    font-size: var(--text-base);
    font-weight: 500;
    color: var(--surface-raised-text-muted); /* logout on the raised panel */
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    text-align: left;
    transition: color var(--duration-fast) var(--ease-out),
                background-color var(--duration-fast) var(--ease-out);
}

.site-nav-panel-logout:hover {
    background-color: var(--surface-deep);
    color: var(--surface-raised-text);
}

/* On desktop: the panel is still available (for authenticated band/admin
   users), but the public links column inside it is redundant — already
   visible inline. Hide the public-links column at desktop widths.
   The panel itself only opens when the hamburger is clicked. */
@media (min-width: 881px) {
    .site-nav-panel-public {
        display: none;
    }

    /* On desktop, unauthenticated visitors never need the panel at all.
       We don't hide the toggle button because we can't know auth state in
       CSS — but we can hide it if there are no authenticated sections.
       The authenticated sections are wrapped in <AuthorizeView> which
       renders nothing when logged out, so the panel just shows the footer
       login link — acceptable. We can't do better without JS. */
}

/* On mobile: hide inline links, always show the toggle button */
@media (max-width: 880px) {
    .site-nav-inline {
        display: none;
    }

    .site-nav-toggle-btn {
        /* Always visible on mobile */
        display: flex;
    }
}


/* =========================================================
   5. NEWSLETTER SIGNUP COMPONENT
   ========================================================= */

/*
 * The newsletter strip sits in .main-layout-newsletter (footer-adjacent).
 * It can also be dropped on any page. The component itself is the island;
 * only the .newsletter-signup* classes are styled here.
 */

.newsletter-signup {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    max-width: 480px;
    text-align: center;
    transition: opacity var(--duration-mid) var(--ease-out);
}

/* Confirmed state: fade slightly to signal done-ness */
.newsletter-signup-ok {
    opacity: 0.75;
}

.newsletter-signup-label {
    font-family: var(--font-display);
    font-size: var(--text-base);
    font-weight: 500;
    color: var(--surface-page-text);
    letter-spacing: -0.01em;
}

.newsletter-signup-form {
    display: flex;
    gap: var(--space-2);
    width: 100%;
}

.newsletter-signup-input {
    flex: 1;
    padding: var(--space-3) var(--space-4);
    background-color: var(--surface-raised);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-base);
    color: var(--surface-raised-text);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.newsletter-signup-input::placeholder {
    color: var(--surface-page-text-muted);
}

.newsletter-signup-input:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-dim);
}

.newsletter-signup-input-invalid {
    border-color: var(--alert-danger-rule);
}

.newsletter-signup-button {
    flex-shrink: 0;
    padding: var(--space-3) var(--space-5);
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.newsletter-signup-button:hover:not(:disabled) {
    background-color: var(--color-accent);
    transform: translateY(-1px);
}

.newsletter-signup-button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Feedback messages */
.newsletter-signup-feedback {
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
}

.newsletter-signup-feedback-ok {
    color: var(--alert-success-text);
}

.newsletter-signup-feedback-alreadysubscribed,
.newsletter-signup-feedback-welcome_back {
    color: var(--surface-page-text-muted);
}

.newsletter-signup-feedback-error {
    color: var(--alert-danger-rule);
}


/* =========================================================
   6. PUBLIC-PAGE SHELL
   Page eyebrow · Section · Content · Empty · Contact card
   ========================================================= */

/*
 * PUBLIC PAGE PHILOSOPHY (post-redesign):
 *
 * Bento pages (About, Releases, Playlists, Shows):
 *   article.public-page
 *     div.page-eyebrow   ← tiny one-line label, no H1 preamble
 *     [grid/list content immediately]
 *
 * Structured pages (Press):
 *   article.public-page
 *     div.page-eyebrow
 *     [section groups with .press-section-label, no big H2 dividers]
 *
 * Prose pages (Privacy, Terms):
 *   article.public-page
 *     header.public-page-hero   ← compact hero kept for legal pages
 *     div.public-page-content
 *       section.public-page-section [repeated]
 *
 * The old pattern (large H1 hero + big H2 section-title with accent bar
 * before every bento grid) added 150-200px of chrome before first content.
 * The new pattern: tiles carry their own labels; the page eyebrow is
 * one short label line.
 */

/* --- View transitions (PP2) ---
 * @view-transition { navigation: auto } enables native page transitions
 * when Blazor Enhanced Navigation fires (uses the Navigation API in
 * Chrome/Edge 111+). Gracefully degrades to instant swap on other browsers.
 * The page-enter animation provides a fallback for non-supporting browsers
 * and acts as the ::view-transition-new animation on supporting ones.
 */
@view-transition {
    navigation: auto;
}

@keyframes page-enter {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* --- Base page container --- */

.public-page {
    max-width: var(--max-width);
    margin: 0 auto;
    padding: var(--space-5) var(--page-gutter) var(--space-8);
    width: 100%;
    animation: page-enter 0.22s var(--ease-out) both;
}

@media (prefers-reduced-motion: reduce) {
    .public-page {
        animation: none;
    }
}

/* --- Page eyebrow --- (replaces the hero on bento pages)
   A single compact line at the top: page title as a small label.
   No border, no bottom margin blowout, no lead paragraph. */

.page-eyebrow {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.page-eyebrow-title {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--surface-page-text-muted);
}

.page-eyebrow-lead {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    line-height: var(--leading-normal);
}

/* --- Prose hero (Privacy, Terms only) --- */

.public-page-hero {
    max-width: var(--max-width-prose);
    /* Tight bottom space — these are legal pages, the copy is the content */
    margin-bottom: var(--space-5);
    padding-bottom: var(--space-4);
    border-bottom: var(--border-thin);
}

.public-page-hero-title {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 700;
    line-height: var(--leading-tight);
    letter-spacing: -0.02em;
    color: var(--surface-page-text);
    margin-bottom: var(--space-2);
    font-variation-settings: 'WONK' 0;
}

.public-page-hero-lead {
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
    color: var(--surface-page-text-muted);
}

/* --- Section (prose pages — Privacy, Terms) --- */

.public-page-section {
    margin-bottom: var(--space-5);
    padding-bottom: var(--space-5);
    border-bottom: var(--border-thin);
}

.public-page-section:last-child {
    border-bottom: none;
    margin-bottom: 0;
    padding-bottom: 0;
}

/* Section heading for prose pages — plain, legible, no accent chrome */
.public-page-section-title {
    font-family: var(--font-display);
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--surface-page-text);
    margin-bottom: var(--space-3);
    line-height: var(--leading-snug);
    letter-spacing: -0.01em;
    /* No accent bar — that was the bento preamble pattern we're removing */
}

/* --- Prose content container (Privacy, Terms) --- */

.public-page-content {
    max-width: var(--max-width-prose);
}

.public-page-content p + p {
    margin-top: var(--space-4);
}

.public-page-content ul,
.public-page-content ol {
    list-style: revert;
    padding-left: var(--space-6);
    margin-top: var(--space-3);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* --- Section label used inside bento + press sections ---
   A small uppercase label above a grid or content block.
   Does NOT add a heavy border or large margin. */

.section-label {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--surface-page-text-muted);
    margin-bottom: var(--space-3);
    display: block;
}

/* --- .section-block ---
   A FULL-WIDTH slim tile used to host text that would otherwise sit
   orphaned on the body background. Same chrome family as the other
   tiles — predictable contrast guaranteed because it pulls its color
   from the surface-deep token pair.

   Use this when you need a between-section header, divider label, or
   any standalone text that's not inside a card/grid. Don't use it for
   primary section titles inside a tile (the tile chrome already does
   that job).

       <div class="section-block">
         <span class="section-label">Latest releases</span>
         <p>Optional one-line description.</p>
       </div> */
.section-block {
    background-color: var(--surface-deep);
    color: var(--surface-deep-text);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-5);
    margin: var(--space-5) 0 var(--space-4);
    display: flex;
    align-items: baseline;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.section-block .section-label {
    margin-bottom: 0;       /* tile padding handles spacing */
    color: var(--surface-deep-text-muted);
}

.section-block p {
    font-size: var(--text-sm);
    color: var(--surface-deep-text);
    line-height: var(--leading-normal);
    margin: 0;
}


/* =========================================================
   6.5 COMPOSABLE TILE CONTAINER CLASSES
   ========================================================= */

/*
 * The user-proposed "guarantee" pattern:
 *
 *   "Define CSS classes for the different bento box styles and define
 *    all the text colors along with the background colors, button colors,
 *    etc. So that you can just apply that class to the container and be
 *    guaranteed that everything will look right."
 *
 * Three named tile variants (light / deep / dark / accent) — apply ONE
 * variant class to any container and EVERY descendant element gets a
 * matching color from the same surface token pair. No more "I picked
 * a dark tile bg and forgot to recolor the .meta inside it" bugs.
 *
 * Usage:
 *   <div class="tile tile-light">       ← light cream surface
 *     <h2>Title</h2>                    ← gets surface-raised-text
 *     <p>Body copy.</p>                 ← gets surface-raised-text
 *     <a href="...">A link</a>          ← gets accent
 *     <span class="meta">Caption</span> ← gets muted token
 *   </div>
 *
 *   <div class="tile tile-dark">        ← dark charcoal surface
 *     [all descendants → cream text automatically]
 *   </div>
 *
 * Pick a variant based on emphasis: light = default tile, deep =
 * recessed/secondary, dark = high-emphasis hero block, accent = CTA.
 *
 * AI Note: descendants are matched by tag where possible (h1-h4, p, a,
 * dt, dd) so the system works without forcing every text node to carry
 * an extra class. For semantic-neutral spans + divs, use the .muted
 * helper class to opt into the muted color.
 */

/* --- Base tile chrome — apply this WITH a variant class --- */
.tile {
    padding: var(--space-4) var(--space-5);
    border-radius: var(--radius-md);
    border: 1px solid transparent;
}

/*
 * U2 — CMS semantic color system (docs/features/layouts/Unification-Plan-v1.md).
 * The tile variant classes and the CMS [data-block-surface="…"] data-attribute share
 * ONE ruleset each, so a block wearing a surface role (BlockBackgroundKind.Theme/Role →
 * BlockHost stamps data-block-surface) gets the EXACT same descendant color inheritance
 * as a .tile-* markup class. Role → tile mapping:
 *   raised → tile-light · deep → tile-deep · inverse → tile-dark · accent → tile-accent
 *   page   → the body-canvas pair (--surface-page*), added below (no legacy tile class).
 * Both the background AND the readable text pair travel together → contrast holds across
 * every theme with NO luminance math (the U2 pair-travels-together guarantee).
 */

/* ----- LIGHT TILE / raised — cream/parchment, charcoal text (DEFAULT) ----- */
.tile-light,
[data-block-surface="raised"] {
    background-color: var(--surface-raised);
    color: var(--surface-raised-text);
    border-color: var(--surface-border);
}

.tile-light :where(h1, h2, h3, h4, h5, h6),
[data-block-surface="raised"] :where(h1, h2, h3, h4, h5, h6) {
    color: var(--surface-raised-text);
}

.tile-light :where(p, li, dt, dd, span:not(.meta):not(.muted):not([class*="eyebrow"]):not([class*="label"])),
[data-block-surface="raised"] :where(p, li, dt, dd, span:not(.meta):not(.muted):not([class*="eyebrow"]):not([class*="label"])) {
    color: var(--surface-raised-text);
}

.tile-light :where(a),
[data-block-surface="raised"] :where(a) {
    color: var(--color-accent);
}

.tile-light :where(a:hover),
[data-block-surface="raised"] :where(a:hover) {
    color: var(--color-accent-light);
}

.tile-light :where(.meta, .muted, [class*="eyebrow"], [class*="label"], small, figcaption, time),
[data-block-surface="raised"] :where(.meta, .muted, [class*="eyebrow"], [class*="label"], small, figcaption, time) {
    color: var(--surface-raised-text-muted);
}

/* ----- DEEP TILE / deep — slightly recessed cream-deep, charcoal text ----- */
.tile-deep,
[data-block-surface="deep"] {
    background-color: var(--surface-deep);
    color: var(--surface-deep-text);
    border-color: var(--surface-border);
}

.tile-deep :where(h1, h2, h3, h4, h5, h6),
[data-block-surface="deep"] :where(h1, h2, h3, h4, h5, h6) {
    color: var(--surface-deep-text);
}

.tile-deep :where(p, li, dt, dd, span:not(.meta):not(.muted):not([class*="eyebrow"]):not([class*="label"])),
[data-block-surface="deep"] :where(p, li, dt, dd, span:not(.meta):not(.muted):not([class*="eyebrow"]):not([class*="label"])) {
    color: var(--surface-deep-text);
}

.tile-deep :where(a),
[data-block-surface="deep"] :where(a) {
    color: var(--color-accent);
}

.tile-deep :where(a:hover),
[data-block-surface="deep"] :where(a:hover) {
    color: var(--color-accent-light);
}

.tile-deep :where(.meta, .muted, [class*="eyebrow"], [class*="label"], small, figcaption, time),
[data-block-surface="deep"] :where(.meta, .muted, [class*="eyebrow"], [class*="label"], small, figcaption, time) {
    color: var(--surface-deep-text-muted);
}

/* ----- DARK TILE / inverse — charcoal surface, cream text ----- */
.tile-dark,
[data-block-surface="inverse"] {
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    border-color: var(--surface-inverse-border);
}

.tile-dark :where(h1, h2, h3, h4, h5, h6),
[data-block-surface="inverse"] :where(h1, h2, h3, h4, h5, h6) {
    color: var(--surface-inverse-text);
}

.tile-dark :where(p, li, dt, dd, span:not(.meta):not(.muted):not([class*="eyebrow"]):not([class*="label"])),
[data-block-surface="inverse"] :where(p, li, dt, dd, span:not(.meta):not(.muted):not([class*="eyebrow"]):not([class*="label"])) {
    color: var(--surface-inverse-text);
}

.tile-dark :where(a),
[data-block-surface="inverse"] :where(a) {
    color: var(--color-accent-light);
}

.tile-dark :where(a:hover),
[data-block-surface="inverse"] :where(a:hover) {
    color: var(--color-cream);
}

.tile-dark :where(.meta, .muted, [class*="eyebrow"], [class*="label"], small, figcaption, time),
[data-block-surface="inverse"] :where(.meta, .muted, [class*="eyebrow"], [class*="label"], small, figcaption, time) {
    color: var(--surface-inverse-text-muted);
}

/* ----- ACCENT TILE / accent — amber surface, white text (used SPARINGLY) ----- */
.tile-accent,
[data-block-surface="accent"] {
    background-color: var(--surface-accent);
    color: var(--surface-accent-text);
    border-color: transparent;
}

.tile-accent :where(h1, h2, h3, h4, h5, h6),
[data-block-surface="accent"] :where(h1, h2, h3, h4, h5, h6) {
    color: var(--surface-accent-text);
}

.tile-accent :where(p, li, dt, dd, span:not(.meta):not(.muted)),
[data-block-surface="accent"] :where(p, li, dt, dd, span:not(.meta):not(.muted)) {
    color: var(--surface-accent-text);
}

.tile-accent :where(a),
[data-block-surface="accent"] :where(a) {
    color: var(--surface-accent-text);
    text-decoration: underline;
}

.tile-accent :where(.meta, .muted),
[data-block-surface="accent"] :where(.meta, .muted) {
    color: var(--surface-accent-text-muted);
}

/* ----- PAGE surface (data-attr only; no legacy tile class) — the body canvas pair -----
   A block wearing role=page sits transparently on the page: no background/border, but its
   descendant text still resolves to the theme's page pair so nested primitives don't strand
   under Dark. (Most role=page blocks are transparent RichText/structural sections.) */
[data-block-surface="page"] {
    color: var(--surface-page-text);
}

[data-block-surface="page"] :where(h1, h2, h3, h4, h5, h6),
[data-block-surface="page"] :where(p, li, dt, dd, span:not(.meta):not(.muted):not([class*="eyebrow"]):not([class*="label"])) {
    color: var(--surface-page-text);
}

[data-block-surface="page"] :where(a) {
    color: var(--color-accent);
}

[data-block-surface="page"] :where(a:hover) {
    color: var(--color-accent-light);
}

[data-block-surface="page"] :where(.meta, .muted, [class*="eyebrow"], [class*="label"], small, figcaption, time) {
    color: var(--surface-page-text-muted);
}

/* ----- Tile-internal labels (eyebrows above titles within tiles) ----- */
/* The .tile-eyebrow class is a small uppercase chip inside any tile.
   Color is inherited from the variant's muted token via the descendant
   match above, so it adapts to light/deep/dark/accent automatically. */
.tile-eyebrow {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    display: block;
    margin-bottom: var(--space-2);
}

/* ----- Tile-internal title (the in-tile heading) ----- */
.tile-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    line-height: var(--leading-tight);
    letter-spacing: -0.01em;
    margin: 0 0 var(--space-2);
    display: block;
}

/* --- Empty state --- */

.public-page-empty {
    font-size: var(--text-md);
    color: var(--surface-page-text-muted);
    font-style: italic;
    padding: var(--space-8) 0;
    text-align: center;
}

/* --- Contact card --- */

.public-page-contact-card {
    margin-top: var(--space-4);
    padding: var(--space-4) var(--space-5);
    background-color: var(--surface-deep);
    color: var(--surface-deep-text);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    font-size: var(--text-base);
    max-width: 400px;
}

.public-page-contact-card p {
    color: var(--surface-deep-text);
    line-height: var(--leading-normal);
}

/* --- Contact form container override (Contact.razor) ---
   app.css's .contact-container sets a dark bg + dark-grey label color
   (user report: "dark grey text on a slightly darker grey background").
   Override here so the contact page reads as a light tile with charcoal
   labels — same surface family as everything else on the public site. */
.contact-container {
    background-color: var(--surface-raised) !important;
    color: var(--surface-raised-text) !important;
    border: var(--border-thin);
    border-radius: var(--radius-md);
    padding: var(--space-6) var(--space-6) !important;
    box-shadow: none !important;
    min-height: 0 !important;       /* override `calc(100vh - 4.5rem)` */
}

.contact-container :where(h1, h2, h3) {
    color: var(--surface-raised-text) !important;
}

.contact-container :where(label, .form-group label) {
    color: var(--surface-raised-text) !important;
    opacity: 1 !important;
    font-weight: 600;
    text-transform: none !important;
    letter-spacing: 0 !important;
    font-size: var(--text-sm);
    margin-bottom: var(--space-1);
}

/* Fields sit ON the raised contact card — pair them with the PAGE surface so the
   field boundary reads against the card AND typed text follows the theme (a fixed
   white field + themed text made typing invisible under dark themes). */
.contact-container :where(input, select, textarea) {
    background-color: var(--surface-page) !important;
    color: var(--surface-page-text) !important;
    border: 1px solid var(--surface-border) !important;
    border-radius: var(--radius-sm) !important;
    padding: var(--space-2) var(--space-3) !important;
    font-size: var(--text-base) !important;
}

.contact-container :where(input:focus, select:focus, textarea:focus) {
    outline: none !important;
    border-color: var(--color-accent) !important;
    box-shadow: 0 0 0 3px var(--color-accent-dim) !important;
}

.contact-container .btn-submit {
    background-color: var(--surface-accent) !important;
    color: var(--surface-accent-text) !important;
    border: none !important;
    border-radius: var(--radius-full) !important;
    padding: var(--space-3) var(--space-6) !important;
    font-family: var(--font-body);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    width: auto !important;
    align-self: flex-start;
}


/* =========================================================
   7. HOME PAGE — BENTO GRID
   .home > .home-hero > tiles
   ========================================================= */

/*
 * The Home page uses an asymmetric bento grid. Tiles of varying sizes
 * sit in a CSS grid container. Tile types:
 *   - Tagline block (spans ~2 columns, large display text)
 *   - Band photo  (portrait tile, spans a full column)
 *   - Release tile (rich: cover art + body)
 *   - Performance tile (rich: title + video embed)
 *   - Shows strip (when upcoming show exists)
 *   - Booking CTA (always present)
 *
 * WONK axis on Fraunces adds personality to the hero text.
 */

.home {
    /* Remove default public-page padding — home manages its own layout */
    padding: 0;
    max-width: none;
}

/* Bento grid container
   AI Note: grid placement is explicit on ALL tiles to prevent overlap.
   4-column × 3-row layout (2fr 1fr 1fr 1fr):
     Row 1: tagline (col 1-2) | release (col 3) | photo (col 4)
     Row 2: performance (col 1-2) | shows (col 3) | booking (col 4)
     Row 3: newsletter (cols 1-4 full-width slim strip)
   The shows tile is conditional — when absent, booking still sits at
   col 4 row 2 and performance keeps its min-height.

   AI Note: row-gap is defined on the container (gap: var(--space-3)).
   Do NOT add negative margins or top offsets on tiles — use gap exclusively
   for row spacing. Using explicit grid-template-rows: auto auto auto prevents
   implicit row creation which was the source of the "second row hovering
   over the first row" bug (auto-rows produced uneven row heights at certain
   content sizes). */
.home-hero {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr 1fr;
    /* Rows are dynamic — tiles set their own grid-row via inline styles
       from the HomeTile DB row (admin-controlled). Auto rows so the grid
       grows to fit however many rows admins use. */
    grid-auto-rows: minmax(180px, auto);
    gap: var(--space-3);
    padding: var(--space-5) var(--page-gutter) var(--space-7);
    max-width: var(--max-width);
    margin: 0 auto;
    width: 100%;
    align-items: stretch;
}

/* =========================================================
   7.5 HOME-TILE COMPONENT (data-driven)
   ========================================================= */
/* Each tile in the home bento is a .tile.tile-{variant} (chrome from
   the composable tile system) plus .home-tile + a type modifier
   (.home-tile-tagline / -photo / -release / -performance / -show /
   -newsletter / -booking / -custom).

   The wrapper carries grid-column / grid-row INLINE styles (set from
   the HomeTile DB row by the admin), so layout is data-driven, not
   per-class.

   Layout inside each tile-type is handled here. Color comes from the
   tile-{variant} composable class. */

.home-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    overflow: hidden;
}

/* Override: tagline tile is centered + has its own large type stack */
.home-tile-tagline {
    justify-content: center;
    gap: var(--space-3);
    padding: var(--space-6) var(--space-5);
}

.home-tile-tagline-text {
    font-family: var(--font-display);
    font-size: var(--text-4xl);
    font-weight: 800;
    line-height: 1.0;
    letter-spacing: -0.04em;
    margin: 0;
    font-variation-settings: 'WONK' 1, 'opsz' 144;
}

.home-tile-tagline-sub {
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    max-width: 40ch;
    margin: 0;
}

.home-tile-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-2);
}

/* Photo tile — unboxed: image bleeds to tile edges */
.home-tile-photo {
    padding: 0;
    overflow: hidden;
}

.home-tile-photo-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center top;
    display: block;
}

.home-tile-photo .scene-container {
    /* Cancel any min-height the composite component sets */
    min-height: 0;
    height: 100%;
    width: 100%;
}

/* Release tile — cover-art + body side-by-side */
.home-tile-release {
    padding: var(--space-3);
}

.home-tile-link-cover,
.home-tile-link {
    display: flex;
    gap: var(--space-3);
    text-decoration: none;
    color: inherit;
    height: 100%;
}

.home-tile-cover {
    flex-shrink: 0;
    width: 96px;
    aspect-ratio: 1 / 1;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background-color: var(--color-charcoal);
}

.home-tile-cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.home-tile-cover-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-2);
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-cream);
    text-align: center;
}

.home-tile-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
    flex: 1;
}

.home-tile-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    line-height: var(--leading-snug);
    margin: 0;
}

.home-tile-meta {
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
}

.home-tile-empty {
    font-size: var(--text-sm);
    margin: 0;
    opacity: 0.85;
}

/* Performance tile — title on top, embed dominates below */
.home-tile-performance {
    padding: var(--space-3);
}

.home-tile-video {
    margin-top: var(--space-2);
    border-radius: var(--radius-sm);
    overflow: hidden;
    aspect-ratio: 16 / 9;
}

.home-tile-video .youtube-embed {
    height: 100%;
    width: 100%;
}

/* Show tile — date block + venue side-by-side */
.home-tile-show {
    padding: var(--space-3);
}

.home-tile-show-date {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-width: 56px;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    background-color: rgba(0, 0, 0, 0.18);
    line-height: 1;
}

.home-tile-show-month {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.home-tile-show-day {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 700;
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
}

.home-tile-show-info {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    justify-content: center;
    min-width: 0;
}

/* Booking tile — single CTA-style row */
.home-tile-booking .home-tile-link {
    flex-direction: column;
    justify-content: center;
}

.home-tile-arrow {
    font-size: var(--text-lg);
    margin-top: var(--space-1);
}

/* Newsletter tile — eyebrow + title + form */
.home-tile-newsletter {
    padding: var(--space-4);
    justify-content: center;
}

.home-tile-newsletter .newsletter-signup {
    max-width: 100%;
    margin-top: var(--space-3);
}

.home-tile-newsletter .newsletter-signup-label {
    display: none;
}

/* Custom tile — markdown body styling */
.home-tile-custom {
    padding: var(--space-4);
    gap: var(--space-3);
}

.home-tile-body-prose {
    font-size: var(--text-base);
    line-height: var(--leading-relaxed);
}

.home-tile-body-prose p { margin: 0 0 var(--space-2); }
.home-tile-body-prose p:last-child { margin-bottom: 0; }
.home-tile-body-prose ul, .home-tile-body-prose ol {
    margin: 0 0 var(--space-2);
    padding-left: var(--space-5);
    list-style: revert;
}

.home-tile-media-img {
    width: 100%;
    border-radius: var(--radius-sm);
    display: block;
}

/* Immersive hero tile (PP4) — non-default; admin creates a tile with
   HomeTileType.ImmersiveHero to enable. Typically spans the full grid
   width. MediaUrl supplies the background image. */

.home-tile-immersive {
    padding: 0;
    min-height: 380px;
}

/* The background layer: full-bleed image + subtle Ken Burns drift.
   --hero-bg is set inline by the renderer when MediaUrl is present;
   falls back to a gradient derived from brand colors when absent. */
.home-tile-immersive-bg {
    position: absolute;
    inset: 0;
    background-image: var(--hero-bg,
        linear-gradient(135deg, var(--color-charcoal) 0%, #302d28 100%));
    background-size: cover;
    background-position: center 30%;
    animation: hero-ken-burns 24s ease-in-out infinite alternate;
    z-index: 0;
}

/* Dark vignette over the image so text is legible at any image brightness */
.home-tile-immersive-bg::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        to bottom,
        rgba(28, 26, 23, 0.08) 0%,
        rgba(28, 26, 23, 0.62) 65%,
        rgba(28, 26, 23, 0.82) 100%
    );
}

@keyframes hero-ken-burns {
    from { transform: scale(1.0) translate(0, 0); }
    to   { transform: scale(1.07) translate(-1%, -1%); }
}

/* Content stacks in the flex flow at z-index 1 — above the absolute bg */
.home-tile-immersive-content {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    flex: 1;
    padding: var(--space-8) var(--space-6) var(--space-6);
    color: var(--color-cream);
}

.home-tile-immersive-eyebrow {
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--color-cream);
    opacity: 0.75;
    margin: 0 0 var(--space-2);
    animation: hero-text-fade-up 0.55s var(--ease-out) 0.1s both;
}

.home-tile-immersive-headline {
    font-family: var(--font-display);
    font-size: clamp(1.75rem, 4.5vw, 3.25rem);
    font-weight: 800;
    line-height: 1.05;
    letter-spacing: -0.03em;
    color: var(--color-cream);
    margin: 0 0 var(--space-5);
    animation: hero-text-fade-up 0.55s var(--ease-out) 0.22s both;
}

.home-tile-immersive-actions {
    margin-top: 0;
    animation: hero-text-fade-up 0.55s var(--ease-out) 0.38s both;
}

@keyframes hero-text-fade-up {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .home-tile-immersive-bg { animation: none; }
    .home-tile-immersive-eyebrow,
    .home-tile-immersive-headline,
    .home-tile-immersive-actions { animation: none; }
}

/* ---- Visualizer Showcase tile: silent, timeline-driven viz hero ---- */
.home-tile-showcase {
    padding: 0;
    container-type: inline-size;   /* headline scales to the tile's own width via cqi */
    min-height: clamp(18rem, 38vw, 26rem);
    overflow: hidden;
}

/* Fills the tile wrapper; the canvas sits behind a legibility scrim + text. */
.showcase-tile {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    background: linear-gradient(135deg, var(--surface-inverse) 0%, #302d28 100%);
}

.showcase-tile-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
    z-index: 0;
}

/* Dark scrim under the text, over the canvas — keeps the overlay legible
   regardless of how bright the visualizer gets. */
.showcase-tile-scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: linear-gradient(
        to bottom,
        rgba(28, 26, 23, 0.05) 0%,
        rgba(28, 26, 23, 0.55) 62%,
        rgba(28, 26, 23, 0.82) 100%
    );
}

.showcase-tile-overlay {
    position: relative;
    z-index: 2;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    flex: 1;
    padding: var(--space-8) var(--space-6) var(--space-6);
    color: var(--surface-page-text);
}

.showcase-tile-eyebrow {
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--surface-page-text);
    opacity: 0.78;
    margin: 0 0 var(--space-2);
}

.showcase-tile-headline {
    font-family: var(--font-display);
    font-size: clamp(1.75rem, 8cqi, 3.25rem);
    font-weight: 800;
    line-height: 1.05;
    letter-spacing: -0.03em;
    color: var(--surface-page-text);
    margin: 0 0 var(--space-5);
    text-shadow: 0 2px 18px rgba(0, 0, 0, 0.45);
}

.showcase-tile-cta {
    align-self: flex-start;
}

/* Poster fallback (timeline missing / no WebGL / reduced-motion): gradient
   surface, no canvas — the overlay text still reads. */
.showcase-tile-poster {
    background: radial-gradient(120% 100% at 50% 0%, #3a3630 0%, var(--surface-inverse) 70%);
}

/* A tile that opted into the layered compositor renders full-bleed: zero
   padding, positioned so the absolute .tile-layer-host fills the whole tile. */
.home-tile-layered {
    padding: 0;
    position: relative;
    overflow: hidden;
    min-height: 15rem;   /* was 240px — rem scales with zoom */
}

/* ---- Layered tiles: an N-layer composite (canvas runs + DOM text layers) ---- */
/* The host is the positioned stacking context the compositor fills with run
   canvases and absolutely-positioned text layers, each z-indexed by stack order. */
.tile-layer-host {
    position: absolute;
    inset: 0;
    overflow: hidden;
    background: var(--color-charcoal);
    /* Query container so tile text (headline) sizes relative to THIS TILE, not the viewport — a
       small mobile tile gets small text instead of staying humongous (see .tile-layer-text--headline). */
    container-type: inline-size;
}

/* Full-bleed canvas runs only. Cell-placed canvases are sized inline by the
   compositor (grid items), so they must NOT inherit absolute positioning. */
.tile-layer-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
}

/* Prerendered poster of the base image layer (TileLayerHost). Sits above the compositor canvas
   and fades out once the tile goes live (.tile-live), so the hero photo / backdrop paints with
   the SSR HTML instead of showing the charcoal base while WASM + WebGL boot. object-fit /
   object-position are set inline per the layer's Fit + focal. pointer-events:none so it never
   intercepts clicks during the fade. */
.tile-layer-poster {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 2;
    opacity: 1;
    transition: opacity 0.45s ease;
    pointer-events: none;
}
.tile-layer-host.tile-live .tile-layer-poster { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
    .tile-layer-poster { transition-duration: 0.01ms; }
}

/* Instant-paint placeholder backing for a layered tile. Paints a dark, theme-tinted
   fill the moment the SSR HTML lands, then fades out once the tile goes live
   (.tile-live) — so the visualizer appears to fade IN over it instead of popping in
   over a charcoal box while WASM + WebGL boot. Image tiles keep their photo poster
   (above) over this; visualizer / non-image tiles get this themed color as the
   placeholder. Restored when a scrolled-away tile releases its compositor (.tile-live
   removed). Sits below the poster (same z, later DOM = poster wins) and above the
   compositor's canvas layers.
   Color: matches the header's resting background so a loading tile reads as part of the
   same surface. The header washes --surface-page at --surface-veil-alpha over a page
   that is itself --surface-page, so its effective color is just --surface-page — use
   that here (opaque, no bleed over the tile's charcoal host). --surface-page is inherited
   from body[data-theme], so it tracks the theme (cream under Light, dark under Dark).
   Overridable via --tile-placeholder-bg. */
.tile-layer-placeholder {
    position: absolute;
    inset: 0;
    z-index: 2;
    background: var(--tile-placeholder-bg, var(--surface-page));
    opacity: 1;
    transition: opacity 0.45s ease;
    pointer-events: none;
}
.tile-layer-host.tile-live .tile-layer-placeholder { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
    .tile-layer-placeholder { transition-duration: 0.01ms; }
}

/* DOM text layers. Base = TYPOGRAPHY only (color/shadow), so a grid-placed text
   layer flows in its cell. Positioning is applied by modifier classes:
   --fullbleed (fills the tile, bottom-aligned overlay) vs grid placement
   (compositor sets grid-area + self-align inline). */
.tile-layer-text {
    margin: 0;
    color: var(--color-cream);
    text-decoration: none;
    text-shadow: 0 2px 18px rgba(0, 0, 0, 0.45);
}

/* ----- Carousel layer (auto-advancing slides; fade or slide) ----- */
.tile-carousel { position: absolute; inset: 0; overflow: hidden; --car-tms: 600ms; }
.tile-carousel-track { width: 100%; height: 100%; }
.tile-carousel-slide {
    display: flex; align-items: flex-end;
    background-size: cover; background-position: center;
    color: var(--surface-page-text); text-decoration: none;
}
/* Fade: slides stacked, only the active one visible. */
.tile-carousel--fade .tile-carousel-slide {
    position: absolute; inset: 0; opacity: 0;
    transition: opacity var(--car-tms) ease;
}
.tile-carousel--fade .tile-carousel-slide.is-active { opacity: 1; }
/* Slide: a flex track translated by the active index. */
.tile-carousel--slide .tile-carousel-track {
    display: flex; transition: transform var(--car-tms) ease;
}
.tile-carousel--slide .tile-carousel-slide { flex: 0 0 100%; height: 100%; }
.tile-carousel-caption {
    padding: var(--space-3); width: 100%;
    background: linear-gradient(to top, rgba(0,0,0,0.55), transparent);
    text-shadow: 0 2px 18px rgba(0,0,0,0.45);
}
.tile-carousel-heading { margin: 0; font-size: 1.2rem; }
.tile-carousel-body { margin: var(--space-1) 0 0; font-size: 0.9rem; }
.tile-carousel-cta { display: inline-block; margin-top: var(--space-2); font-weight: 700; text-decoration: underline; }
.tile-carousel-arrow {
    position: absolute; top: 50%; transform: translateY(-50%);
    border: 0; background: rgba(0,0,0,0.35); color: var(--surface-page-text);
    width: 2rem; height: 2rem; border-radius: var(--radius-full);
    font-size: 1.2rem; line-height: 1; cursor: pointer; z-index: 2;
}
.tile-carousel-prev { left: var(--space-2); }
.tile-carousel-next { right: var(--space-2); }
.tile-carousel-dots {
    position: absolute; bottom: var(--space-2); left: 0; right: 0;
    display: flex; gap: 6px; justify-content: center; z-index: 2;
}
.tile-carousel-dot {
    width: 8px; height: 8px; padding: 0; border: 0; border-radius: var(--radius-full);
    background: rgba(255,255,255,0.45); cursor: pointer;
}
.tile-carousel-dot.is-active { background: var(--surface-page); }

.tile-layer-text--eyebrow {
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    opacity: 0.8;
}

.tile-layer-text--headline {
    font-family: var(--font-display);
    /* cqi = 1% of the TILE's inline size (the .tile-layer-host query container), so the headline
       scales with the tile — big on a wide desktop tile, small on a narrow mobile tile — instead of
       riding the viewport width (vw) and staying humongous when the tile shrinks. */
    font-size: clamp(1.1rem, 12cqi, 2.75rem);
    font-weight: 800;
    line-height: 1.05;
    letter-spacing: -0.03em;
}

.tile-layer-text--body {
    font-size: clamp(0.85rem, 4.5cqi, var(--text-md));
    line-height: 1.4;
}

/* Custom-size text — the font-size is applied inline by the compositor (Style=custom + Size). */
.tile-layer-text--custom {
    font-weight: 700;
    line-height: 1.15;
}

/* CTA = a button (works as a grid item or a full-bleed-anchored button). */
.tile-layer-text--cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: fit-content;
    padding: var(--space-3) var(--space-5);
    background: var(--color-amber, #d9933a);
    color: #fff;
    font-weight: 700;
    border-radius: var(--radius-pill, 999px);
    text-shadow: none;
    pointer-events: auto;
}

/* Full-bleed single text overlay: fill the tile, bottom-align (the legacy look). */
.tile-layer-text--fullbleed:not(.tile-layer-text--cta) {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: var(--space-6);
    pointer-events: none;
}

/* Full-bleed CTA: anchor the button at the bottom-left rather than fill. */
.tile-layer-text--fullbleed.tile-layer-text--cta {
    position: absolute;
    inset: auto auto var(--space-6) var(--space-6);
}

/* ---- Layer stack editor (preset creator + tile admin) ---- */
.layer-stack-add {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

/* Each reorderable item = a grip handle + the row. Only the grip starts a drag,
   so the row's sliders/selects work normally. */
.layer-row-wrap {
    list-style: none;
    display: flex;
    align-items: stretch;
    gap: var(--space-1);
    margin-bottom: var(--space-2);
}

.reorder-handle {
    display: flex;
    align-items: center;
    padding: 0 var(--space-1);
    cursor: grab;
    opacity: 0.5;
    user-select: none;
    font-size: var(--text-lg);
}
.reorder-handle:active { cursor: grabbing; }

.layer-row {
    flex: 1;
    border: 1px solid var(--color-border, rgba(0, 0, 0, 0.12));
    border-radius: var(--radius-md, 8px);
    background: var(--color-surface, #fff);
}

/* ----- Grid layer: compact summary row + pop-out editor modal ----- */
.layer-grid-summary {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--space-2); padding: var(--space-2) var(--space-3);
}
.grid-modal-backdrop {
    position: fixed; inset: 0; z-index: var(--z-nav);
    background: rgba(0, 0, 0, 0.5);
    display: flex; align-items: center; justify-content: center;
    padding: var(--space-4);
}
.grid-modal {
    background: var(--color-cream, #fff); color: var(--surface-page-text);
    border-radius: var(--radius-lg); width: min(720px, 100%); max-height: 90vh;
    display: flex; flex-direction: column; overflow: hidden;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
}
.grid-modal-head, .grid-modal-foot {
    display: flex; align-items: center; gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
}
.grid-modal-head { justify-content: space-between; border-bottom: var(--border-thin); }
.grid-modal-foot { justify-content: flex-end; border-top: var(--border-thin); }
.grid-modal-title { margin: 0; font-size: var(--text-md); }
.grid-modal-close { border: 0; background: transparent; font-size: var(--text-md); cursor: pointer; color: inherit; }
.grid-modal-body { padding: var(--space-4); overflow-y: auto; display: flex; flex-direction: column; gap: var(--space-4); }
.grid-modal-section { display: flex; flex-direction: column; gap: var(--space-2); }
.grid-modal-section-title {
    margin: 0; font-size: var(--admin-text-section); text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--surface-page-text-muted); border-bottom: var(--border-thin); padding-bottom: var(--space-1);
}
.grid-modal-row { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-end; }
.grid-modal-row .admin-field { margin: 0; }
.grid-modal-presets { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.grid-modal-advanced { margin-top: var(--space-1); }
.grid-modal-advanced summary { cursor: pointer; font-size: var(--admin-text-help); color: var(--color-accent); }

/* ===== Reusable admin control family (AdminControls-Spec-v1) ===== */

/* DimensionInput: number + unit */
.dim-input { display: inline-flex; gap: var(--admin-gap); align-items: center; flex-wrap: wrap; }
/* Wide enough to read a 3–4 digit value and a full unit name ("vmin"); the admin-input-narrowest
   80px cap is removed here so the value is never clipped (was the "can't see the padding values" bug). */
.dim-input-num { width: 4.5rem; max-width: none; flex: 0 0 auto; }
.dim-input-unit { width: 4.75rem; max-width: none; flex: 0 0 auto; }
/* BL-051 / FLG-CMP-ADMIN-1-02 — cascade fix. The children carry the shared .admin-input class,
   whose `width:100%` is declared LATER in the file and so wins by source order, stretching both
   the number field and the unit dropdown to full width (they stack as two separate-looking fields).
   Re-assert the compact fixed widths from inside the component scope so the pair renders inline. */
.dim-input .admin-input { width: auto; max-width: none; }
.dim-input .dim-input-num  { width: 4.5rem; }
.dim-input .dim-input-unit { width: 4.75rem; }

/* GridPlacementField — compact label|control layout for grid-cell placement (every grid-child layer). */
.grid-place {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: var(--admin-gap);
    padding: var(--admin-pad-y) 0;
}
.grid-place-label {
    font-size: var(--admin-text-label); font-weight: 700; letter-spacing: 0.05em;
    text-transform: uppercase; color: var(--surface-page-text-muted);
}
.grid-place-pair { display: inline-flex; align-items: center; gap: var(--admin-gap); flex-wrap: wrap; }
.grid-place-num { width: 3.25rem; max-width: none; }
.grid-place-x { font-size: var(--admin-text-help); color: var(--surface-page-text-muted); }

/* FocalField — click-to-set focal point + zoom for a tile layer (generalizes the members focal editor). */
.focal-field { display: flex; gap: var(--admin-gap); align-items: flex-start; flex-wrap: wrap; }
.focal-field-frame {
    position: relative; width: 160px; aspect-ratio: 4 / 3; overflow: hidden;
    border-radius: var(--admin-radius); border: var(--border-thin); cursor: crosshair;
    background: rgba(0, 0, 0, 0.06); flex-shrink: 0;
}
.focal-field-image {
    width: 100%; height: 100%; object-fit: cover;
    object-position: var(--focal-x, 50%) var(--focal-y, 50%);
    transform: scale(var(--focal-scale, 1)); transform-origin: var(--focal-x, 50%) var(--focal-y, 50%);
    user-select: none; pointer-events: none; display: block;
}
.focal-field-placeholder {
    display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;
    color: var(--surface-page-text-muted); font-size: var(--admin-text-help);
    text-transform: uppercase; letter-spacing: 0.08em;
}
.focal-field-pin {
    position: absolute; left: var(--focal-x, 50%); top: var(--focal-y, 50%);
    width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%;
    border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5); pointer-events: none;
}
.focal-field-controls { display: flex; flex-direction: column; gap: var(--admin-gap); }

/* ColorField: picker + opacity + theme swatch pulldown */
.color-field { display: inline-flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; }
.color-field-picker { width: 2.5rem; height: 2rem; padding: 0; border: var(--border-thin); border-radius: var(--radius-sm); background: none; cursor: pointer; }
.color-field-alpha { width: 6rem; }
.color-field-alpha-val { font-size: var(--admin-text-help); color: var(--surface-page-text-muted); min-width: 2.6em; }
.color-field-theme { position: relative; }
.color-field-theme-toggle { cursor: pointer; font-size: var(--admin-text-help); color: var(--color-accent); list-style: none; }
.color-field-theme[open] .color-field-swatches {
    position: absolute; z-index: 50; margin-top: var(--space-1);
    display: grid; grid-template-columns: repeat(6, 1.25rem); gap: var(--space-1);
    padding: var(--space-2); background: var(--surface-raised);
    border: var(--border-thin); border-radius: var(--radius-md); box-shadow: var(--shadow-md, 0 6px 18px rgba(0,0,0,0.18));
}
.color-field-swatch { width: 1.25rem; height: 1.25rem; padding: 0; border: 1px solid var(--surface-border); border-radius: var(--radius-sm); cursor: pointer; }
.color-field-swatch.is-active { outline: 2px solid var(--color-accent); outline-offset: 1px; }

/* U2 RoleField — semantic-surface picker. Each swatch is a LIVE chip: the [data-theme] wrapper lets
   the browser resolve --surface-<role> to the previewed theme's actual color natively. */
.role-field { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.role-field-swatch {
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    padding: var(--space-1); background: none; border: 1px solid transparent;
    border-radius: var(--radius-sm); cursor: pointer;
}
.role-field-swatch.is-active { border-color: var(--color-accent); }
.role-field-swatch:hover { border-color: var(--surface-border); }
.role-field-chip {
    display: flex; align-items: center; justify-content: center;
    width: 2.25rem; height: 1.75rem; border-radius: var(--radius-sm);
    border: 1px solid var(--surface-border, rgba(0,0,0,0.12));
    font-size: var(--admin-text-help); font-weight: 600;
}
.role-field-label { font-size: var(--admin-text-help); color: var(--surface-page-text-muted); }

/* U2 — warn line under the "Custom (not themed)" color escape hatch. */
.admin-field-warn { color: var(--color-warn-solid, #A6440F); }

/* SimpleAdvanced shell */
.simple-advanced { display: flex; flex-direction: column; gap: var(--space-2); }
.simple-advanced-adv { margin-top: var(--space-1); }
.simple-advanced-summary { cursor: pointer; font-size: var(--admin-text-help); color: var(--color-accent); }
.simple-advanced-body { margin-top: var(--space-2); display: flex; flex-direction: column; gap: var(--space-2); }

/* RepeaterField */
.repeater-field { display: flex; flex-direction: column; gap: var(--space-2); }
.repeater-row { display: flex; gap: var(--space-2); align-items: flex-start; }
.repeater-row-body { flex: 1 1 auto; }

/* PageLinkField */
.page-link-field { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; }
.page-link-field > .admin-input:last-child { flex: 1 1 12rem; }

.layer-row-head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
}

.layer-row-handle { cursor: grab; opacity: 0.5; user-select: none; }
.layer-row-kind { font-weight: 700; min-width: 4.5em; }
.layer-row-opacity { flex: 1; display: flex; }
.layer-row-opacity input { width: 100%; }

.layer-row-body {
    padding: var(--space-2) var(--space-3) var(--space-3);
    border-top: 1px solid var(--color-border, rgba(0, 0, 0, 0.08));
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.layer-pool {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11em, 1fr));
    gap: var(--space-1) var(--space-3);
    max-height: 12rem;
    overflow-y: auto;
    padding: var(--space-2);
    border: 1px solid var(--color-border, rgba(0, 0, 0, 0.1));
    border-radius: var(--radius-sm, 6px);
}

.layer-pool-item {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-sm);
}

.layer-grid-presets {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

/* A Grid layer's nested children editor — indented + ruled so the tree reads. */
.layer-row-body .layer-stack-editor {
    margin-top: var(--space-2);
    padding-left: var(--space-3);
    border-left: 2px solid var(--color-border, rgba(0, 0, 0, 0.12));
}

/* Live-preview frame for the preset creator — gives the absolutely-positioned
   .tile-layer-host a sized, positioned parent. */
.preset-preview-frame {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius-md, 8px);
    overflow: hidden;
    background: var(--color-charcoal);
}

/* Admin edit-pencil overlay — appears only when an admin views the page */
.home-tile-edit-pencil {
    position: absolute;
    top: var(--space-2);
    right: var(--space-2);
    z-index: 10;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(0, 0, 0, 0.55);
    color: #fff !important;
    border-radius: 50%;
    font-size: 14px;
    text-decoration: none !important;
    opacity: 0.7;
    transition: opacity var(--duration-fast) var(--ease-out),
                background-color var(--duration-fast) var(--ease-out);
}

.home-tile-edit-pencil:hover {
    opacity: 1;
    background-color: var(--color-accent);
}

/* Mobile collapse — every tile spans full width, in DisplayOrder */
@media (max-width: 720px) {
    .home-hero {
        grid-template-columns: 1fr;
    }
    .home-hero > .home-tile {
        grid-column: 1 / -1 !important;
        grid-row: auto !important;
    }
}

/* --- Tagline tile --- */

.home-hero-tagline {
    grid-column: 1 / 3;
    grid-row: 1 / 2;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--space-3);
    padding: var(--space-6) var(--space-5);
    background-color: var(--color-charcoal);
    color: var(--color-cream);
    border-radius: var(--radius-lg);
    /* AI Note: min-height removed — grid-template-rows: auto + align-items: stretch
       on the container handles row sizing without risk of one tile forcing
       its neighbor into the wrong row track. */
}

.home-hero-tagline-text {
    font-family: var(--font-display);
    font-size: var(--text-4xl);
    font-weight: 800;
    line-height: 1.0;
    letter-spacing: -0.04em;
    color: var(--color-cream);
    /* Max personality on the WONK axis — this is the marquee line */
    font-variation-settings: 'WONK' 1, 'opsz' 144;
}

.home-hero-tagline p {
    font-size: var(--text-base);
    color: var(--color-cream-dark);
    line-height: var(--leading-normal);
    max-width: 40ch;
}

/* CTA buttons within the tagline tile */
.home-hero-tagline-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-2);
}

.home-cta {
    display: inline-flex;
    align-items: center;
    padding: var(--space-3) var(--space-5);
    border-radius: var(--radius-full);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.home-cta-primary {
    background-color: var(--color-accent);
    color: var(--color-white);
}

.home-cta-primary:hover {
    background-color: var(--color-accent-light);
    color: var(--color-white);
    transform: translateY(-1px);
}

.home-cta-secondary {
    background-color: transparent;
    color: var(--surface-page-text);
    border: 1px solid rgba(245, 240, 232, 0.4);
}

.home-cta-secondary:hover {
    background-color: rgba(245, 240, 232, 0.1);
    color: var(--surface-page-text);
    transform: translateY(-1px);
}

/* CTA size + shape MODIFIERS — compose with .home-cta (and -primary / -secondary) so one button
   system covers small/large and pill/rectangle instead of bespoke per-use classes. Declared after
   .home-cta so they win for the properties they set.
     .home-cta--sm / --lg : tighter / roomier
     .home-cta--rect      : rounded rectangle instead of the full pill (less "bulbous")
     .home-cta--fluid     : size scales with the tile width (cqi) — good inside visualizer tiles */
.home-cta--sm   { padding: var(--space-1) var(--space-3); font-size: var(--text-xs); }
.home-cta--lg   { padding: var(--space-4) var(--space-6); font-size: var(--text-base); }
.home-cta--rect { border-radius: var(--radius-md); }
.home-cta--fluid { padding: clamp(0.4rem, 1.6cqi, 0.8rem) clamp(0.9rem, 3.5cqi, 1.6rem); font-size: clamp(0.78rem, 2.4cqi, 0.95rem); }

/* --- Band photo tile --- */

.home-hero-photo {
    grid-column: 4 / 5;
    grid-row: 1 / 2;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background-color: var(--color-cream-deep);
    /* AI Note: min-height removed — grid stretch handles height uniformity. */
    /* GroupPhotoComposite renders an image that fills this tile */
}

.home-hero-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* --- Generic bento tile base --- */

.home-hero-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: var(--space-2);
    padding: var(--space-4);
    background-color: var(--color-cream-deep);
    border: var(--border-thin);
    border-radius: var(--radius-lg);
    overflow: hidden;
    text-decoration: none;
    color: var(--color-charcoal);
    transition: transform var(--duration-mid) var(--ease-out),
                box-shadow var(--duration-mid) var(--ease-out),
                border-color var(--duration-mid) var(--ease-out);
}

/* Clickable tiles get a hover lift */
a.home-hero-tile:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--surface-border);
}

/* Shared tile content */
.home-hero-tile-eyebrow {
    display: block;
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-accent);
}

.home-hero-tile-title {
    display: block;
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-charcoal);
    line-height: var(--leading-snug);
    font-variation-settings: 'WONK' 0;
}

.home-hero-tile-meta {
    display: block;
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
    margin-top: var(--space-1);
}

.home-hero-tile-arrow {
    display: block;
    font-size: var(--text-lg);
    color: var(--color-accent);
    margin-top: var(--space-1);
    transition: transform var(--duration-fast) var(--ease-out);
}

a.home-hero-tile:hover .home-hero-tile-arrow {
    transform: translateX(4px);
}

/* --- Release tile (rich variant) --- */

.home-hero-tile-release {
    grid-column: 3 / 4;
    grid-row: 1 / 2;
}

/* Rich tiles have a horizontal cover+body split */
.home-hero-tile-rich {
    flex-direction: column;
    justify-content: flex-start;
    gap: 0;
    padding: 0;
}

.home-hero-tile-cover {
    width: 100%;
    aspect-ratio: 1 / 1;
    overflow: hidden;
    background-color: var(--surface-deep);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    flex-shrink: 0;
}

.home-hero-tile-cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform var(--duration-mid) var(--ease-out);
}

a.home-hero-tile:hover .home-hero-tile-cover img {
    transform: scale(1.03);
}

.home-hero-tile-cover-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--color-charcoal);
    color: var(--color-cream);
    font-family: var(--font-display);
    font-size: var(--text-md);
    font-weight: 600;
    padding: var(--space-4);
    text-align: center;
}

.home-hero-tile-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-4);
    flex: 1;
}

/* --- Performance tile (rich variant) --- */

.home-hero-tile-performance {
    grid-column: 1 / 3;
    grid-row: 2 / 3;
    min-height: 200px;
}

.home-hero-tile-performance.home-hero-tile-rich {
    flex-direction: column;
}

.home-hero-tile-video {
    flex: 1;
    min-height: 160px;
    overflow: hidden;
    border-radius: 0 0 var(--radius-md) var(--radius-md);
}

/* YouTubeEmbed fills available space */
.home-hero-tile-video iframe,
.home-hero-tile-video > * {
    width: 100%;
    height: 100%;
    border: none;
}

/* --- Shows strip tile --- */

.home-hero-tile-shows {
    grid-column: 3 / 4;
    grid-row: 2 / 3;
    flex-direction: row;
    align-items: center;
    gap: var(--space-3);
    justify-content: flex-start;
    background-color: var(--color-accent-dim);
    border-color: rgba(196, 82, 26, 0.25);
}

/* Date block — month+day display */
.home-hero-tile-shows-date {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 56px;
    padding: var(--space-2);
    background-color: var(--color-accent);
    color: var(--color-white);
    border-radius: var(--radius-md);
    text-align: center;
    line-height: 1;
}

.home-hero-tile-shows-month {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.home-hero-tile-shows-day {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 800;
    line-height: 1.1;
    font-variation-settings: 'WONK' 0;
}

.home-hero-tile-shows-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    flex: 1;
    min-width: 0;
}

/* --- Booking CTA tile --- */

.home-hero-tile-booking {
    grid-column: 4 / 5;
    grid-row: 2 / 3;
    background-color: var(--color-charcoal);
    border-color: transparent;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start;
    gap: var(--space-3);
    /* When .home-hero-tile-shows is absent the grid auto-places booking
       into col 4 row 2 regardless — explicit assignment keeps it stable. */
}

.home-hero-tile-booking .home-hero-tile-eyebrow {
    color: var(--color-cream-dark);
}

.home-hero-tile-booking .home-hero-tile-title {
    color: var(--color-cream);
    font-size: var(--text-xl);
    font-weight: 700;
    font-variation-settings: 'WONK' 1;
}

.home-hero-tile-booking .home-hero-tile-arrow {
    color: var(--color-accent-light);
}

a.home-hero-tile-booking:hover {
    background-color: #2A2824;
    border-color: transparent;
}

/* --- Newsletter tile (row 3, full-width slim strip) --- */

.home-hero-tile-newsletter {
    grid-column: 1 / -1;
    grid-row: 3 / 4;
    background-color: var(--surface-deep);
    color: var(--surface-deep-text);
    border-color: var(--surface-border);
    display: flex;
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-4) var(--space-6);
    padding: var(--space-4) var(--space-5);
}

.home-hero-tile-newsletter .home-hero-tile-eyebrow {
    color: var(--surface-deep-text-muted);
    flex-shrink: 0;
}

.home-hero-tile-newsletter .home-hero-tile-title {
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--surface-deep-text);
    margin-right: auto;          /* push the signup form to the right */
    flex: 0 1 auto;
}

.home-hero-tile-newsletter .newsletter-signup {
    /* Stretch to fill remaining row space, but cap at a reasonable width */
    max-width: 460px;
    flex: 1 1 320px;
    text-align: left;
}

/* The form inside the home tile doesn't need the label — the tile's
   own title provides context. */
.home-hero-tile-newsletter .newsletter-signup-label {
    display: none;
}

/* --- Empty tile state --- */

.home-hero-tile-empty {
    opacity: 0.6;
    pointer-events: none;
}

.home-hero-tile-empty .home-hero-tile-eyebrow {
    color: var(--color-charcoal-muted);
}

.home-hero-tile-empty .home-hero-tile-title {
    color: var(--color-charcoal-muted);
    font-style: italic;
    font-size: var(--text-base);
    font-weight: 400;
}


/* =========================================================
   8. ABOUT PAGE
   ========================================================= */

/*
 * Classes: .about-members, .about-members-grid, .about-member-card,
 *          .about-member-photo, .about-member-info, .about-member-name,
 *          .about-member-role, .about-member-bio,
 *          .about-story, .about-performances, .about-performances-grid,
 *          .about-performance-card, .about-performance-title,
 *          .about-performance-meta, .about-cta, .about-cta-button,
 *          .about-cta-primary, .about-cta-secondary
 */

/* Generic section spacer for about sections — compact gap between
   the section-label and the grid below, and between sections */
.about-section,
.about-members-section {
    margin-bottom: var(--space-6);
}

.about-section:last-child,
.about-members-section:last-child {
    margin-bottom: 0;
}

/* Member grid — responsive cards */
.about-members-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr));
    gap: var(--space-4);
}

/* Band-members CMS block: center the cards so a partial last row (e.g. a lone 5th member) sits centered
   instead of stranded at the left. Flex (not grid) so an incomplete final row centers; cards keep a card
   width on wide screens (cap so a lone card doesn't balloon full-width) and go full-width on phones. */
.cms-data-block .about-members-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
}
.cms-data-block .about-members-grid > .about-member-card {
    flex: 1 1 200px;
    max-width: 260px;
}
@media (max-width: 640px) {
    .cms-data-block .about-members-grid > .about-member-card { max-width: 100%; }
}

.about-member-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    background-color: var(--surface-deep); /* themed surface (was --color-cream-deep primitive → light island under Dark) */
    color: var(--surface-deep-text);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    transition: box-shadow var(--duration-mid) var(--ease-out);
}

.about-member-card:hover {
    box-shadow: var(--shadow-md);
}

/* Photo frame — owns the aspect ratio AND `overflow: hidden` so any
   transform: scale on the inner <img> is clipped to the photo region.
   Without this wrapper, the card's overflow:hidden only clips at the
   card boundary, which sits BELOW the info text — letting a zoomed
   image visually obscure the name/instrument/bio. Mirrors the
   .admin-focal-frame on /admin/members. */
.about-member-photo-frame {
    width: 100%;
    aspect-ratio: 3 / 4;
    overflow: hidden;
    /* The member portraits are transparent SVG cutouts, so THIS backdrop shows behind them. --surface-border
       (a divider token, ~#75628F) read too dark. --about-member-photo-bg is a single knob: lightens the
       theme border toward white by default; override it (per theme or inline) for any backdrop color. */
    background-color: var(--about-member-photo-bg, color-mix(in srgb, var(--surface-border) 55%, #ffffff 45%));
    /* Positioning + paint containment context for the portrait: the focal-zoom transform on the
       inner <img> is scoped to this box, so the scaled image never contributes width past the
       frame (U1/M2 element-overflow fix — FLG-TSM-005; the frame is the img's containing block). */
    position: relative;
    contain: paint;
}

/* Member portrait. Focal point + zoom come from inline CSS custom
   properties (--focal-x, --focal-y, --focal-scale) set per-member in
   About.razor, edited via /admin/members. The wrapper owns the shape;
   the img fills the frame absolutely and applies object-position + a
   focal-zoom transform CLIPPED to the frame (contain:paint above). */
.about-member-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    max-width: 100%;   /* never lay out wider than the frame (U1/M2) */
    object-fit: cover;
    object-position: var(--focal-x, 50%) var(--focal-y, 50%);
    transform: scale(var(--focal-scale, 1));
    transform-origin: var(--focal-x, 50%) var(--focal-y, 50%);
    display: block;
}

.about-member-info {
    padding: var(--space-3) var(--space-4) var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.about-member-name {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--surface-deep-text); /* themed (was --color-charcoal primitive) */
    font-variation-settings: 'WONK' 0;
}

.about-member-role {
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    /* accent eyebrow on the deep card. --color-accent-text is page-tuned; on the deep surface
       under Dark it dropped to ~2.2:1. --surface-deep-text-muted pairs with the card by
       construction (contrast guaranteed every theme). */
    color: var(--surface-deep-text-muted);
}

.about-member-bio {
    font-size: var(--text-sm);
    line-height: var(--leading-relaxed);
    color: var(--surface-deep-text);
    margin-top: var(--space-2);
}

/* Performances grid — YouTube embed cards */
.about-performances-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-5);
}

.about-performance-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    background-color: var(--surface-deep);
    color: var(--surface-deep-text);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    transition: box-shadow var(--duration-mid) var(--ease-out);
}

.about-performance-card:hover {
    box-shadow: var(--shadow-md);
}

/* YouTubeEmbed inside performance card fills the top portion */
.about-performance-card > *:first-child {
    width: 100%;
    aspect-ratio: 16 / 9;
    overflow: hidden;
}

.about-performance-title {
    font-family: var(--font-display);
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--surface-deep-text);
    padding: 0 var(--space-4);
}

.about-performance-meta {
    font-size: var(--text-xs);
    color: var(--surface-deep-text-muted);
    padding: 0 var(--space-4) var(--space-4);
}

/* Videos page — YouTube embed grid (moved from About.razor; class names updated) */
.videos-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
    gap: var(--space-6);
}

/* R3: raised pair replaces the cream-light island (card froze Light under
   dark themes — owner-visible on /videos under Prince). */
.videos-card {
    display: flex;
    flex-direction: column;
    background: var(--surface-raised);
    border-radius: var(--radius-md);
    overflow: hidden;
    border: 1px solid var(--surface-border);
    transition: box-shadow 0.15s ease;
}

.videos-card:hover {
    box-shadow: var(--shadow-md);
}

.videos-card > *:first-child {
    width: 100%;
    aspect-ratio: 16 / 9;
    display: block;
}

.videos-card-title {
    font-family: var(--font-display);
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--surface-raised-text);
    padding: var(--space-3) var(--space-4) var(--space-1);
}

.videos-card-meta {
    font-size: var(--text-xs);
    color: var(--surface-raised-text-muted);
    padding: 0 var(--space-4) var(--space-4);
}

/* About CTA section — pair of buttons */
.about-cta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    padding-top: var(--space-2);
    border-bottom: none !important;
    border-top: var(--border-thin);
}

.about-cta-button {
    display: inline-flex;
    align-items: center;
    padding: var(--space-3) var(--space-6);
    border-radius: var(--radius-full);
    font-family: var(--font-body);
    font-size: var(--text-base);
    font-weight: 600;
    text-decoration: none;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.about-cta-primary {
    background-color: var(--color-accent);
    color: var(--color-white);
}

.about-cta-primary:hover {
    background-color: var(--color-accent-light);
    color: var(--color-white);
    transform: translateY(-1px);
}

.about-cta-secondary {
    background-color: transparent;
    color: var(--surface-page-text);
    border: var(--border-mid);
}

.about-cta-secondary:hover {
    background-color: var(--surface-deep);
    color: var(--surface-deep-text);
    transform: translateY(-1px);
}

/* Story section — body paragraphs */
.about-story p + p {
    margin-top: var(--space-4);
}

.about-story p {
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    color: var(--surface-page-text-muted);
    max-width: 72ch;
}


/* =========================================================
   9. RELEASES PAGE
   ========================================================= */

/*
 * Classes: .releases-grid, .release-card, .release-cover,
 *          .release-cover-placeholder, .release-cover-placeholder-title,
 *          .release-cover-placeholder-tag, .release-info, .release-title,
 *          .release-meta, .release-meta-sep, .release-description,
 *          .release-actions, .release-action-play, .release-external-link
 *
 * TrackList component has its own internal styles — we just provide the
 * card frame it sits inside.
 */

.releases-grid {
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
}

/* Each release is a horizontal card: cover art | info.
   The card now carries .tile.tile-light from markup, so background +
   text colors are guaranteed via the tile-light descendant rules.
   No more between-card border — gap on .releases-grid does that work. */
.release-card {
    display: grid;
    grid-template-columns: clamp(7.5rem, 28%, 12.5rem) 1fr;   /* fluid cover (was fixed 200px) */
    gap: var(--space-5);
    align-items: start;
}
.release-card > * { min-width: 0; }   /* grid-child overflow guard for the 1fr info column */

/* Cover art square */
.release-cover {
    position: relative;
    width: 100%;
    aspect-ratio: 1 / 1;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background-color: var(--surface-deep);
    flex-shrink: 0;
    box-shadow: var(--shadow-md);
}

.release-cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* DSP link icons in the release actions row (next to "Play release"). Small brand-tinted chips linking
   out to each streaming service in a new tab. */
.release-dsp-links {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.release-dsp-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.94);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.22);
    transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.release-dsp-link:hover,
.release-dsp-link:focus-visible {
    transform: scale(1.1);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

.dsp-icon { display: inline-flex; color: #333; }
.dsp-icon svg { width: 1.2rem; height: 1.2rem; display: block; }

/* Keep "Play release" high-contrast regardless of the CMS block's luminance-based text color that
   otherwise cascades onto it. The button fills with the INVERSE surface, so its text must use the
   inverse surface's paired text token — not --surface-page-text, which tracks the page and rendered
   light-on-light (white-on-white) under a dark theme. */
.release-actions .release-action-play { background-color: var(--surface-inverse); }
.release-actions .release-action-play,
.release-actions .release-action-play span,
.release-actions .release-action-play .dsp-icon,
.release-actions .release-action-play svg { color: var(--surface-inverse-text); fill: currentColor; }

/* Brand tints (the glyph uses currentColor). */
.dsp-icon-spotify       { color: #1DB954; }
.dsp-icon-apple-music,
.dsp-icon-apple         { color: #FA243C; }
.dsp-icon-youtube-music,
.dsp-icon-youtube       { color: #FF0000; }
.dsp-icon-tidal         { color: #000000; }
.dsp-icon-bandcamp      { color: #629AA9; }
.dsp-icon-soundcloud    { color: #FF5500; }
.dsp-icon-amazon-music,
.dsp-icon-amazon        { color: #00A8E1; }
.dsp-icon-deezer        { color: #A238FF; }

/* DSP icon preview in the Releases admin's link editor. */
.admin-dsp-preview { display: inline-flex; align-items: center; flex-shrink: 0; }
.admin-dsp-preview .dsp-icon svg { width: 1.3rem; height: 1.3rem; }

/* Searchable song combobox (Releases admin) — a normal-looking dropdown that filters as you type. */
.admin-combobox { position: relative; }
.admin-combobox-input { width: 100%; padding-right: 1.8rem; }
.admin-combobox-caret {
    position: absolute; right: 0.6rem; top: 50%; transform: translateY(-50%);
    pointer-events: none; color: var(--color-charcoal, #333); opacity: 0.55; font-size: 0.8rem;
}
.admin-combobox-list {
    position: absolute; left: 0; right: 0; top: calc(100% + 2px); z-index: 30;
    margin: 0; padding: 0.25rem; list-style: none;
    max-height: 16rem; overflow-y: auto;
    background: var(--color-cream-light, #fff);
    border: var(--border-thin, 1px solid #ccc);
    border-radius: var(--radius-sm, 6px);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}
.admin-combobox-item {
    display: flex; align-items: baseline; overflow: hidden;
    padding: 0.4rem 0.6rem; border-radius: 4px; cursor: pointer;
    color: var(--color-charcoal, #222); font-size: var(--admin-text-control, 0.9rem);
}
.admin-combobox-item:hover { background: var(--color-cream-mid, #ece6da); }
.admin-combobox-item.is-sel { background: var(--color-cream-mid, #ece6da); }
/* Keyboard-active option (arrow-key navigation) — distinct from hover/selected. */
.admin-combobox-item.is-active { background: var(--color-accent-dim); box-shadow: inset 0 0 0 2px var(--color-accent); }
.admin-combobox-item.is-sel .admin-combobox-label { font-weight: 600; }
.admin-combobox-label { flex: 0 0 auto; white-space: nowrap; }
.admin-combobox-sep { flex: 0 0 auto; opacity: 0.45; margin: 0 0.1rem; }
/* Version notes: italic, and truncated with an ellipsis when the row runs out of width. */
.admin-combobox-note {
    flex: 0 1 auto; min-width: 0;
    font-style: italic; opacity: 0.7;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.admin-combobox-none { font-style: italic; opacity: 0.75; }
.admin-combobox-empty { padding: 0.4rem 0.6rem; opacity: 0.6; font-style: italic; }

/* Placeholder when no cover art is uploaded */
.release-cover-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    padding: var(--space-5);
    text-align: center;
}

.release-cover-placeholder-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    font-variation-settings: 'WONK' 0;
}

.release-cover-placeholder-tag {
    font-size: var(--text-xs);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-accent-light);
}

/* Release info column */
.release-info {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding-top: var(--space-2);
}

/* U2: the release card is a .tile.tile-light (a RAISED surface). Its internal text used
   PRIMITIVE --color-charcoal* tokens that DON'T flip under Dark → charcoal-on-transparent
   ~1.05:1 on the dark canvas. Re-pointed to the semantic raised-surface pair so the card's
   text follows its surface on every theme. (docs/features/layouts/Unification-Sweep-v1.md §a.) */
.release-title {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--surface-raised-text);
    line-height: var(--leading-tight);
    letter-spacing: -0.02em;
    font-variation-settings: 'WONK' 0;
}

.release-meta {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    font-size: var(--text-sm);
    color: var(--surface-raised-text-muted);
}

.release-meta-sep {
    /* U2: the muted meta separator follows the card's raised surface (was --color-charcoal-muted,
       which stranded on the dark canvas). The raised muted token clears AA on every theme. */
    color: var(--surface-raised-text-muted);
}

.release-description {
    font-size: var(--text-base);
    line-height: var(--leading-relaxed);
    color: var(--surface-raised-text);
    max-width: 60ch;
    margin-top: var(--space-2);
}

/* "Coming soon" pre-release teaser badge */
.release-badge {
    align-self: flex-start;
    display: inline-block;
    padding: 2px 10px;
    margin-bottom: var(--space-1);
    border-radius: 999px;
    background-color: var(--color-accent);
    color: var(--color-white);
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

/* Credits line (publisher / featuring) under a release's meta + description */
.release-credits {
    font-size: var(--text-sm);
    color: var(--surface-raised-text-muted);   /* U2: follow the card's raised surface (was --color-charcoal-muted). */
    margin-top: var(--space-2);
}

/* Action buttons row */
.release-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-2);
}

.release-action-play {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    border: none;
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.release-action-play:hover {
    background-color: var(--color-accent);
    transform: translateY(-1px);
}

.release-external-link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    background-color: transparent;
    color: var(--surface-page-text-muted);
    font-size: var(--text-sm);
    font-weight: 600;
    border: var(--border-thin);
    border-radius: var(--radius-full);
    text-decoration: none;
    transition: border-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.release-external-link:hover {
    border-color: var(--color-accent);
    color: var(--color-accent-text);
    transform: translateY(-1px);
}

/* Store cross-sell CTA (PP5) — shown only when /store is public and
   release.SuppressStoreCrossSell is false. Styled as a tertiary link
   so it doesn't compete with the play / streaming-service buttons. */
.release-store-cta {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
    padding: var(--space-2) var(--space-4);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-accent);
    border: 1px solid var(--color-accent);
    border-radius: var(--radius-full);
    text-decoration: none;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.release-store-cta:hover {
    background-color: var(--surface-accent);
    color: var(--surface-accent-text);
    transform: translateY(-1px);
}

/* Card → detail links. The cover + title on the list page link to
   /releases/{slug}; keep them visually identical to the static versions
   (no default underline/blue) so the card still reads as a unit. */
.release-cover-link {
    display: block;
    line-height: 0;
    width: 100%;
    height: 100%;
}

.release-title-link {
    color: inherit;
    text-decoration: none;
    transition: color var(--duration-fast) var(--ease-out);
}

.release-title-link:hover {
    color: var(--color-accent-text);
}

/* ---- Release detail page (/releases/{slug}) ---- */
.release-detail-back {
    font-size: var(--text-sm);
    margin-bottom: var(--space-4);
}

.release-detail-back a {
    color: var(--surface-page-text-muted);
    text-decoration: none;
}

.release-detail-back a:hover {
    color: var(--color-accent-text);
}

/* Cover | info, like a release-card but with a larger cover. */
.release-detail-layout {
    display: grid;
    grid-template-columns: clamp(10rem, 35%, 20rem) minmax(0, 1fr);   /* fluid cover (was fixed 320px) + info overflow guard */
    gap: var(--space-7);
    align-items: start;
}

.release-detail-cover {
    width: 100%;
    aspect-ratio: 1 / 1;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background-color: var(--surface-deep);
    box-shadow: var(--shadow-lg);
}

.release-detail-cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.release-detail-info {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.release-detail-title {
    font-family: var(--font-display);
    font-size: var(--text-3xl);
    font-weight: 700;
    color: var(--surface-page-text);
    line-height: var(--leading-tight);
    letter-spacing: -0.02em;
    font-variation-settings: 'WONK' 0;
}

.release-detail-description {
    margin-top: var(--space-6);
    max-width: 65ch;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    font-size: var(--text-base);
    line-height: var(--leading-relaxed);
    color: var(--surface-page-text-muted);
}

.release-detail-missing {
    text-align: center;
    padding: var(--space-9) 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-4);
    color: var(--surface-page-text-muted);
}

/* Stack cover above info on narrow viewports. */
@media (max-width: 720px) {
    .release-detail-layout {
        grid-template-columns: 1fr;
        gap: var(--space-5);
    }

    .release-detail-cover {
        max-width: 320px;
    }
}


/* =========================================================
   10. PLAYLISTS PAGE
   ========================================================= */

/*
 * Classes: .playlists-grid, .playlist-card, .playlist-card-header,
 *          .playlist-card-titles, .playlist-title, .playlist-meta,
 *          .playlist-meta-sep, .playlist-card-actions, .playlist-action,
 *          .playlist-action-play, .playlist-action-queue,
 *          .playlist-notes, .playlist-tracklist, .playlist-tracklist-row,
 *          .playlist-tracklist-row-unplayable, .playlist-tracklist-num,
 *          .playlist-tracklist-titles, .playlist-tracklist-name,
 *          .playlist-tracklist-artist, .playlist-tracklist-play
 */

.playlists-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 360px), 1fr));
    gap: var(--space-6);
}

.playlist-card {
    display: flex;
    flex-direction: column;
    background-color: var(--surface-deep);
    border: var(--border-thin);
    border-radius: var(--radius-lg);
    overflow: hidden;
    transition: box-shadow var(--duration-mid) var(--ease-out);
}

.playlist-card:hover {
    box-shadow: var(--shadow-md);
}

/* Card header: titles on left, actions on right */
.playlist-card-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-4) var(--space-2);
}

.playlist-card-titles {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.playlist-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--surface-page-text);
    line-height: var(--leading-snug);
    font-variation-settings: 'WONK' 0;
}

.playlist-meta {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
}

.playlist-meta-sep {
    /* Contrast fix: same as release-meta-sep — cream-dark on cream-deep
       gave 1.46:1. charcoal-muted gives 4.61:1. */
    color: var(--surface-page-text-muted);
}

/* Play / Queue action buttons */
.playlist-card-actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
}

.playlist-action {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: none;
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.playlist-action-play {
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
}

.playlist-action-play:hover {
    background-color: var(--color-accent);
    transform: translateY(-1px);
}

.playlist-action-queue {
    background-color: transparent;
    color: var(--surface-page-text-muted);
    border: var(--border-thin);
}

.playlist-action-queue:hover {
    border-color: var(--surface-page-text);
    color: var(--surface-page-text);
    transform: translateY(-1px);
}

/* Optional notes paragraph */
.playlist-notes {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    line-height: var(--leading-relaxed);
    padding: 0 var(--space-5) var(--space-3);
    font-style: italic;
}

/* Tracklist — ordered list of songs */
.playlist-tracklist {
    display: flex;
    flex-direction: column;
    border-top: var(--border-thin);
    margin-top: var(--space-2);
    list-style: none;
    padding: 0;
}

.playlist-tracklist-row {
    display: grid;
    grid-template-columns: 28px 1fr 28px;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    border-bottom: 1px solid rgba(0, 0, 0, 0.04);
    transition: background-color var(--duration-fast) var(--ease-out);
}

.playlist-tracklist-row:last-child {
    border-bottom: none;
}

.playlist-tracklist-row:hover {
    background-color: color-mix(in srgb, currentColor 8%, transparent);
}

.playlist-tracklist-row-unplayable {
    opacity: 0.5;
}

.playlist-tracklist-num {
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.playlist-tracklist-titles {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.playlist-tracklist-name {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--surface-page-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.playlist-tracklist-artist {
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Per-row play button */
.playlist-tracklist-play {
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: transparent;
    border: none;
    border-radius: 50%;
    color: var(--surface-page-text-muted);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.playlist-tracklist-play:hover {
    background-color: var(--surface-accent);
    color: var(--surface-accent-text);
}


/* =========================================================
   11. SHOWS PAGE
   ========================================================= */

/*
 * Classes: .shows-list, .show-card, .show-card-date,
 *          .show-card-date-month, .show-card-date-day, .show-card-date-year,
 *          .show-card-info, .show-card-title, .show-card-venue,
 *          .show-card-city, .show-card-time, .show-card-notes,
 *          .show-card-ticket
 *
 * Design intent: a calendar-list hybrid. Big date badge on the left,
 * venue info in the center, ticket CTA on the right.
 */

.shows-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.show-card {
    display: grid;
    grid-template-columns: 64px minmax(0, 1fr) auto;   /* minmax(0,..) lets the info column shrink (overflow guard) */
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    background-color: var(--surface-deep);
    border: var(--border-thin);
    border-radius: var(--radius-lg);
    transition: box-shadow var(--duration-mid) var(--ease-out),
                border-color var(--duration-mid) var(--ease-out);
}

.show-card:hover {
    box-shadow: var(--shadow-sm);
    border-color: var(--surface-border);
}

/* Date badge — tight calendar block */
.show-card-date {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    background-color: var(--color-accent);
    color: var(--color-white);
    border-radius: var(--radius-md);
    text-align: center;
    flex-shrink: 0;
    line-height: 1;
    gap: 2px;
}

.show-card-date-month {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.show-card-date-day {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 800;
    line-height: 1;
    font-variation-settings: 'WONK' 0;
}

.show-card-date-year {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    /* Contrast fix: opacity 0.8 reduced white-on-accent to ~3.50:1 (FAIL for
       11px text). Full white gives 4.60:1 — just passes WCAG AA. */
    color: var(--color-white);
}

/* Venue info column */
.show-card-info {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.show-card-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--surface-page-text);
    line-height: var(--leading-snug);
    font-variation-settings: 'WONK' 0;
}

.show-card-venue {
    font-size: var(--text-base);
    color: var(--surface-page-text-muted);
}

.show-card-city {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
}

.show-card-time {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    font-style: italic;
}

.show-card-notes {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    margin-top: var(--space-1);
}

/* Ticket CTA */
.show-card-ticket {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    padding: var(--space-2) var(--space-4);
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.02em;
    border-radius: var(--radius-full);
    text-decoration: none;
    white-space: nowrap;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.show-card-ticket:hover {
    background-color: var(--color-accent);
    color: var(--color-white);
    transform: translateY(-1px);
}

/* Actions column: ticket + add-to-calendar + directions, stacked on the right
   of the card. Secondary actions are outline pills so the ticket CTA stays
   dominant. */
.show-card-actions {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    align-items: stretch;
}

.show-card-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-1) var(--space-3);
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--surface-page-text-muted);
    border: var(--border-thin);
    border-radius: var(--radius-full);
    text-decoration: none;
    white-space: nowrap;
    transition: border-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.show-card-action:hover {
    border-color: var(--color-accent);
    color: var(--color-accent);
}

/* Past-shows archive — a lightweight disclosure below the upcoming list. */
.shows-archive {
    margin-top: var(--space-7);
}

.shows-archive-toggle {
    background: none;
    border: none;
    cursor: pointer;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--surface-page-text-muted);
    padding: var(--space-2) 0;
}

.shows-archive-toggle:hover {
    color: var(--color-accent);
}

.shows-archive-list {
    list-style: none;
    margin: var(--space-3) 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.shows-archive-row {
    display: flex;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-top: var(--border-thin);
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
}

.shows-archive-date {
    flex-shrink: 0;
    width: 8.5rem;
    color: var(--surface-page-text-muted);
    font-variant-numeric: tabular-nums;
}

.shows-archive-where {
    font-weight: 600;
    color: var(--surface-page-text);
}

/* Show countdown badge (shows within 7 days) */
.show-card-countdown {
    display: inline-block;
    margin-top: var(--space-2);
    padding: 2px 6px;
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    background-color: var(--color-amber, #d97706);
    color: var(--color-white);
    border-radius: var(--radius-sm);
}

.show-card-countdown--tonight {
    background-color: var(--color-accent);
    animation: countdown-pulse 1.5s ease-in-out infinite;
}

@keyframes countdown-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.7; }
}

@media (prefers-reduced-motion: reduce) {
    .show-card-countdown--tonight {
        animation: none;
    }
}


/* =========================================================
   12. PRESS / EPK PAGE
   ========================================================= */

/*
 * Classes: .press-page (modifier on .public-page), .press-section,
 *          .press-facts, .press-facts-list, .press-facts-row,
 *          .press-bio-short, .press-bio-long, .press-section-lead,
 *          .press-photos-grid, .press-photo, .press-photo-link,
 *          .press-releases-list, .press-releases-row, .press-releases-cover,
 *          .press-releases-info, .press-releases-title, .press-releases-meta,
 *          .press-shows-list, .press-tech, .press-quotes, .press-empty
 *
 * An EPK is a reference document; layout prioritizes scannability.
 */

/* press-section: each section is its own .tile.tile-light now, so no
   between-section horizontal-rule borders here — gap between tiles
   does the work. Just space them out vertically. */
.press-section {
    margin-bottom: var(--space-4);
}

.press-section:last-child {
    margin-bottom: 0;
}

/* .press-section-title is retired in favor of .tile-eyebrow. The class
   is left styled minimally in case any stale markup references it. */
.press-section-title {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    margin-bottom: var(--space-3);
    display: block;
    /* Color inherited from parent tile via the tile-* descendant rules */
}

.press-section-lead {
    font-size: var(--text-sm);
    line-height: var(--leading-relaxed);
    margin-bottom: var(--space-4);
    /* Color inherited from parent tile's muted token */
}

.press-section-lead a {
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* At-a-glance fact box — definition list */
.press-facts-list {
    display: flex;
    flex-direction: column;
    gap: 0;
    border: var(--border-thin);
    border-radius: var(--radius-md);
    overflow: hidden;
    max-width: 480px;
}

.press-facts-row {
    display: grid;
    grid-template-columns: 120px 1fr;
    align-items: baseline;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-5);
    border-bottom: var(--border-thin);
    background-color: var(--surface-deep);
}

.press-facts-row:last-child {
    border-bottom: none;
}

.press-facts-row dt {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--surface-page-text-muted);
}

.press-facts-row dd {
    font-size: var(--text-base);
    color: var(--surface-page-text);
}

/* Bio text */
.press-bio-short {
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    color: var(--surface-page-text-muted);
    max-width: 72ch;
    font-style: italic;
    border-left: 3px solid var(--color-accent);
    padding-left: var(--space-4);
    margin-left: 0;
}

.press-bio-long {
    font-size: var(--text-base);
    line-height: var(--leading-relaxed);
    color: var(--surface-page-text-muted);
    max-width: 72ch;
}

/* Markdown output within press-bio-long / press-tech / press-quotes */
.press-bio-long p,
.press-tech p,
.press-quotes p {
    margin-bottom: var(--space-4);
}

.press-bio-long blockquote,
.press-tech blockquote,
.press-quotes blockquote {
    border-left: 3px solid var(--color-accent);
    padding-left: var(--space-5);
    margin: var(--space-5) 0;
    color: var(--surface-page-text-muted);
    font-style: italic;
}

.press-bio-long ul,
.press-tech ul,
.press-quotes ul {
    list-style: disc;
    padding-left: var(--space-6);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

/* Press photos grid */
.press-photos-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr));
    gap: var(--space-4);
}

.press-photo {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.press-photo-link {
    display: block;
    /* No fixed aspect-ratio — images render at their natural proportions.
       overflow: hidden kept to clip the hover-scale animation so the image
       doesn't bleed into adjacent grid cells. */
    overflow: hidden;
    border-radius: var(--radius-md);
    border: var(--border-thin);
    transition: box-shadow var(--duration-mid) var(--ease-out);
}

.press-photo-link:hover {
    box-shadow: var(--shadow-md);
}

.press-photo-link img {
    width: 100%;
    height: auto;   /* natural aspect ratio */
    display: block; /* removes inline baseline gap */
    transition: transform var(--duration-mid) var(--ease-out);
}

.press-photo-link:hover img {
    transform: scale(1.03);
}

.press-photo figcaption {
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
    text-align: center;
}

/* Downloadable press-kit assets (logo pack, one-sheet, photo bundle) */
.press-downloads {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    max-width: 560px;
}

.press-download {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background-color: var(--surface-deep);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: var(--surface-deep-text);
    transition: border-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.press-download:hover {
    border-color: var(--color-accent);
    transform: translateY(-1px);
}

.press-download-label {
    font-weight: 600;
    flex: 1 1 auto;
    min-width: 0;   /* let long file names shrink/wrap instead of overflowing the row */
}

.press-download-meta {
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
    font-variant-numeric: tabular-nums;
}

.press-download-arrow {
    color: var(--color-accent);
    font-weight: 700;
}

/* Releases list (compact — links to /releases for full detail) */
.press-releases-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    max-width: 560px;
}

.press-releases-row {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    background-color: var(--surface-deep);
    border: var(--border-thin);
    border-radius: var(--radius-md);
}

.press-releases-cover {
    width: 48px;
    height: 48px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
}

.press-releases-info {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.press-releases-title {
    font-weight: 600;
    font-size: var(--text-base);
    color: var(--surface-page-text);
    text-decoration: none;
}

.press-releases-title:hover {
    color: var(--color-accent-text);
}

.press-releases-meta {
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
}

/* Upcoming shows (condensed list) */
.press-shows-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    font-size: var(--text-base);
    color: var(--surface-page-text-muted);
    max-width: 560px;
}

.press-shows-list li {
    padding: var(--space-2) 0;
    border-bottom: var(--border-thin);
}

.press-shows-list li:last-child {
    border-bottom: none;
}

/* Tech specs + quotes — markdown output regions */
.press-tech,
.press-quotes {
    font-size: var(--text-base);
    line-height: var(--leading-relaxed);
    color: var(--surface-page-text-muted);
    max-width: 72ch;
}

/* Empty states */
.press-empty {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    font-style: italic;
    padding: var(--space-5) 0;
}


/* =========================================================
   13. CONTACT FORM
   ========================================================= */

/*
 * Classes (ContactForm.razor): .contact-container (on .public-page),
 *   .compact-row, .form-group, .message-group, .message-box,
 *   .captcha-group, .captcha-row, .captcha-img, .captcha-input,
 *   .btn-submit, .validation-message
 *
 * The contact page wraps ContactForm in .contact-container. The form
 * itself is a server-side Blazor EditForm.
 */

.contact-container {
    /* Narrow the page for a form — 720px feels intimate */
    max-width: 720px;
}

/* Blazor EditForm renders a <form> — target it within the container */
.contact-container form {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    margin-top: var(--space-6);
}

/* Two-column row for paired fields (Name+Email, Phone+Reason) */
.compact-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-5);
}

/* Individual form group */
.form-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* R2: shared form rules are consumed on THEMED surfaces (Identity auth pages,
   contact) — color-bearing props are semantic tokens, never primitives. The old
   charcoal-mid labels were unreadable on dark themes (owner report: Prince login). */
.form-group label {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.03em;
    color: var(--surface-page-text-muted);
    text-transform: uppercase;
}

/* All form inputs — text, email, select, number. Fields are small raised surfaces:
   the raised pair keeps typed text readable under every theme (a fixed white field
   with themed text made typing invisible under dark themes). */
.form-group input,
.form-group select,
.contact-container input[type="text"],
.contact-container input[type="email"],
.contact-container select {
    width: 100%;
    padding: var(--space-3) var(--space-4);
    background-color: var(--surface-raised);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-base);
    color: var(--surface-raised-text);
    appearance: none;
    -webkit-appearance: none;
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.form-group input:focus,
.form-group select:focus,
.contact-container input[type="text"]:focus,
.contact-container input[type="email"]:focus,
.contact-container select:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-dim);
}

/* Message textarea */
.message-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.message-group label {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.03em;
    color: var(--surface-page-text-muted);
    text-transform: uppercase;
}

.message-box {
    width: 100%;
    min-height: 160px;
    padding: var(--space-3) var(--space-4);
    background-color: var(--color-white);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-base);
    color: var(--color-charcoal);
    line-height: var(--leading-relaxed);
    resize: vertical;
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.message-box:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-dim);
}

/* Captcha section */
.captcha-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.captcha-row {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.captcha-img {
    border-radius: var(--radius-sm);
    border: var(--border-thin);
    background-color: var(--surface-raised);
    display: block;
}

.captcha-input {
    width: 100px;
    padding: var(--space-3) var(--space-4);
    background-color: var(--surface-raised);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-base);
    color: var(--surface-raised-text);
    text-align: center;
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.captcha-input:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-dim);
}

/* Validation messages (Blazor DataAnnotationsValidator) */
.validation-message {
    font-size: var(--text-sm);
    color: var(--alert-danger-rule);
}

.contact-container .validation-message {
    font-size: var(--text-xs);
    margin-top: var(--space-1);
}

/* Submit button */
.btn-submit {
    align-self: flex-start;
    padding: var(--space-3) var(--space-7);
    background-color: var(--color-charcoal);
    color: var(--color-cream);
    font-family: var(--font-body);
    font-size: var(--text-base);
    font-weight: 600;
    letter-spacing: 0.04em;
    border: none;
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.btn-submit:hover:not(:disabled) {
    background-color: var(--color-accent);
    transform: translateY(-1px);
}

.btn-submit:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}


/* =========================================================
   14. PRIVACY & TERMS (PROSE PAGES)
   ========================================================= */

/*
 * Both Privacy and Terms use: .public-page > .public-page-hero
 *   then .public-page-content > .public-page-section (repeated)
 *   and .public-page-contact-card at the end.
 *
 * The shared rules in sections 6 + 13 cover most of it.
 * Additional typographic polish for prose paragraphs:
 */

.public-page-content .public-page-section p {
    font-size: var(--text-base);
    line-height: var(--leading-relaxed);
    color: var(--surface-page-text-muted);
}

.public-page-content .public-page-section p + p {
    margin-top: var(--space-4);
}

.public-page-content .public-page-section strong {
    font-weight: 700;
    color: var(--surface-page-text);
}

.public-page-content .public-page-section a {
    color: var(--color-accent);
    text-decoration: underline;
    text-decoration-color: rgba(196, 82, 26, 0.35);
    text-underline-offset: 3px;
}

.public-page-content .public-page-section a:hover {
    text-decoration-color: var(--color-accent);
}


/* =========================================================
   15. UNSUBSCRIBE PAGE
   ========================================================= */

/*
 * Classes: .unsubscribe-working, .unsubscribe-working-dot
 * Rest is .public-page-content + .newsletter-signup-feedback-error
 */

/* Loading affordance */
.unsubscribe-working {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-size: var(--text-md);
    color: var(--surface-page-text-muted);
    font-style: italic;
    padding: var(--space-6) 0;
}

/* Animated dot — CSS pulse, falls back to invisible under
   prefers-reduced-motion (the text is self-explanatory alone) */
.unsubscribe-working-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    background-color: var(--color-accent);
    border-radius: 50%;
    flex-shrink: 0;
    animation: dot-pulse 1.2s ease-in-out infinite;
}

@keyframes dot-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50%       { opacity: 0.4; transform: scale(0.75); }
}

@media (prefers-reduced-motion: reduce) {
    .unsubscribe-working-dot {
        animation: none;
        opacity: 0.5;
    }
}

/* Confirmation paragraphs in the unsubscribe done state */
.public-page-content p {
    font-size: var(--text-base);
    line-height: var(--leading-relaxed);
    color: var(--surface-page-text-muted);
    margin-bottom: var(--space-4);
}

.public-page-content p:last-child {
    margin-bottom: 0;
}


/* =========================================================
   16. UTILITY + ACCESSIBILITY
   ========================================================= */

/* Visually hidden — accessible but not painted */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Skip-to-main link (WCAG 2.4.1 Bypass Blocks). First focusable in <body>;
   off-screen until it receives keyboard focus, then pinned top-left. */
.skip-link {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 20000;
    transform: translateY(-120%);
    padding: 0.5rem 1rem;
    /* Accent surface pair (was raw accent + #fff — BL-001). */
    background: var(--surface-accent);
    color: var(--surface-accent-text);
    text-decoration: none;
    border-radius: 0 0 var(--radius-sm, 4px) 0;
    transition: transform 0.15s ease;
}

.skip-link:focus,
.skip-link:focus-visible {
    transform: translateY(0);
    outline: 2px solid var(--surface-accent-text);
    outline-offset: -4px;
}


/* =========================================================
   17. RESPONSIVE — MOBILE (≤ 720px) + MID (≤ 960px)
   ========================================================= */

/*
 * Mobile-first refinements. The base styles above assume a desktop
 * viewport; these overrides adapt for smaller screens.
 */

/* =========================================================
   17. RESPONSIVE — MID (≤ 960px) + MOBILE (≤ 880px) + SMALL (≤ 480px)
   ========================================================= */

/* --- Mid breakpoint (960px) --- */
@media (max-width: 960px) {

    /* Home bento: collapse to 2 columns
       Row 1: tagline (full width)
       Row 2: photo | release
       Row 3: performance (full width)
       Row 4: shows | booking
       Row 5: newsletter (full width) */
    .home-hero {
        grid-template-columns: 1fr 1fr;
        grid-template-rows: auto auto auto auto auto;
        gap: var(--space-3);
    }

    .home-hero-tagline {
        grid-column: 1 / 3;
        grid-row: 1 / 2;
    }

    .home-hero-photo {
        grid-column: 1 / 2;
        grid-row: 2 / 3;
    }

    .home-hero-tile-release {
        grid-column: 2 / 3;
        grid-row: 2 / 3;
    }

    .home-hero-tile-performance {
        grid-column: 1 / 3;
        grid-row: 3 / 4;
    }

    .home-hero-tile-shows {
        grid-column: 1 / 2;
        grid-row: 4 / 5;
        flex-direction: column;
        align-items: flex-start;
    }

    .home-hero-tile-booking {
        grid-column: 2 / 3;
        grid-row: 4 / 5;
    }

    .home-hero-tile-newsletter {
        grid-column: 1 / 3;
        grid-row: 5 / 6;
    }

    /* Release cards: same 2-column on mid */
    .release-card {
        grid-template-columns: 180px 1fr;
        gap: var(--space-5);
    }

    /* Show cards: drop the actions to their own row */
    .show-card {
        grid-template-columns: 72px 1fr;
        grid-template-rows: auto auto;
    }

    .show-card-actions {
        grid-column: 2;
        grid-row: 2;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        justify-self: start;
        margin-top: var(--space-2);
    }
}

/* --- Mobile breakpoint (880px) — inline nav collapses, hamburger appears --- */
@media (max-width: 880px) {

    /* Reduce gutter (set the frame token; --page-gutter aliases it) */
    :root {
        --frame-gutter: var(--space-5);
    }

    /* Keep the booking pill READABLE on narrow screens — it has no icon, so the old font-size:0
       left a blank orange rectangle. Just tighten padding; the (short) label stays visible. */
    .main-layout-header-booking {
        padding: var(--space-1) var(--space-3);
    }
}

/* --- Small mobile (≤ 640px) --- */
@media (max-width: 640px) {

    :root {
        --frame-gutter: var(--space-4);
    }

    /* Home bento: single column — all tiles auto-flow, grid-row: auto on each */
    .home-hero {
        grid-template-columns: 1fr;
        grid-template-rows: none; /* let single-column flow naturally */
        gap: var(--space-3);
        padding: var(--space-4) var(--space-4) var(--space-6);
    }

    .home-hero-tagline {
        grid-column: 1;
        grid-row: auto;
        min-height: 200px;
    }

    .home-hero-tagline-text {
        /* Fluid so an author-set tagline of any length can't overflow the single column at
           narrow widths (KB no-horizontal-scroll floor @320). Ramps ~26px→34px as width grows;
           the tight -0.04em tracking + a long unbroken word (e.g. the band name) at a fixed
           --text-3xl was the overflow risk. break-word is the last-resort backstop. */
        font-size: clamp(var(--text-2xl), 7vw, var(--text-3xl));
        overflow-wrap: break-word;
    }

    .home-hero-photo {
        grid-column: 1;
        grid-row: auto;
        min-height: 240px;
    }

    .home-hero-tile-release,
    .home-hero-tile-performance,
    .home-hero-tile-shows,
    .home-hero-tile-booking,
    .home-hero-tile-newsletter {
        grid-column: 1;
        grid-row: auto;
    }

    /* Newsletter on small screens: stack title + form vertically */
    .home-hero-tile-newsletter {
        flex-direction: column;
        align-items: flex-start;
    }

    .public-page {
        padding: var(--space-4) var(--page-gutter) var(--space-6);
    }

    /* Release card: stack vertically */
    .release-card {
        grid-template-columns: 1fr;
    }

    .release-cover {
        max-width: 220px;
        margin: 0 auto;
    }

    /* Contact form: single column */
    .compact-row {
        grid-template-columns: 1fr;
        gap: var(--space-4);
    }

    /* Shows card: tighter */
    .show-card {
        grid-template-columns: 60px 1fr;
        gap: var(--space-3);
        padding: var(--space-4);
    }

    .show-card-date {
        width: 52px;
        height: 52px;
    }

    .show-card-date-day {
        font-size: var(--text-xl);
    }

    .show-card-actions {
        grid-column: 1 / 3;
        grid-row: 2;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        justify-self: start;
        margin-top: var(--space-2);
    }

    /* Playlist grid: single column */
    .playlists-grid {
        grid-template-columns: 1fr;
    }

    /* About member grid: two columns on mobile */
    .about-members-grid {
        grid-template-columns: 1fr 1fr;
        gap: var(--space-3);
    }

    /* About performances / Videos page: single column */
    .about-performances-grid,
    .videos-grid {
        grid-template-columns: 1fr;
    }

    /* Press photos: 2 columns */
    .press-photos-grid {
        grid-template-columns: 1fr 1fr;
    }

    /* Booking pill: hide entirely on small mobile — it's in the nav panel */
    .main-layout-header-actions {
        display: none;
    }

    /* Footer: stack vertically */
    .main-layout-footer {
        flex-direction: column;
        gap: var(--space-3);
        text-align: center;
    }

    /* Newsletter form: stack */
    .newsletter-signup-form {
        flex-direction: column;
    }

    .newsletter-signup-button {
        width: 100%;
        justify-content: center;
    }
}

/* Very small screens (≤ 400px) */
@media (max-width: 400px) {
    .about-members-grid {
        grid-template-columns: 1fr;
    }

    .press-photos-grid {
        grid-template-columns: 1fr;
    }

    .home-hero-tile-shows {
        flex-direction: column;
        align-items: flex-start;
    }
}


/* =========================================================
   18. FONT FACE DECLARATIONS
   (Must be in the stylesheet; @font-face isn't inherited
    from app.css because app.css.old is no longer loaded)
   ========================================================= */

/*
 * Fraunces — variable font with weight 100-900, opsz (optical size) axis,
 * and the WONK axis for personality. Used exclusively for display headings.
 * WONK 1 = maximum quirk on key headline text; WONK 0 = clean editorial.
 */
@font-face {
    font-family: 'Fraunces';
    src: url('/fonts/Fraunces.ttf') format('truetype-variations'),
         url('/fonts/Fraunces.ttf') format('truetype');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

/*
 * Inter — body copy, UI labels, navigation. Weight 400-700 from the variable
 * source. Neutral companion to Fraunces.
 */
@font-face {
    font-family: 'Inter';
    src: url('/fonts/Inter.ttf') format('truetype');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}


/* =========================================================
   19. LOADING SPLASH
   ========================================================= */

/*
 * Full-viewport overlay visible during WASM download.
 * JS in App.razor adds .splash-overlay-hiding on `blazor:webstarted`
 * to fade out. Background matches the cream page bg so there's no
 * color flash when the overlay lifts.
 *
 * AI Note: do NOT use a CSS timer/keyframe for hide — it fires regardless
 * of WASM readiness and exposes the un-interactive page on slow connections.
 */
.splash-overlay {
    position: fixed;
    top: 0;
    left: 0;
    /* 100% not 100vw — avoids the scrollbar-width horizontal overflow */
    width: 100%;
    height: 100dvh;
    background-color: var(--color-cream);
    z-index: var(--z-max);
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 0.35s ease-out, visibility 0s linear 0.35s;
}

.splash-overlay-hiding {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}

.splash-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-7);
}

.splash-logo {
    width: min(50vw, 300px);
    height: auto;
    animation: splash-pulse 2s ease-in-out infinite;
}

.splash-spinner {
    width: 36px;
    height: 36px;
    border: 3px solid var(--color-cream-mid);
    border-top-color: var(--color-accent);
    border-radius: 50%;
    animation: splash-spin 0.9s linear infinite;
}

@keyframes splash-spin {
    to { transform: rotate(360deg); }
}

@keyframes splash-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50%       { opacity: 0.8; transform: scale(0.97); }
}

@media (prefers-reduced-motion: reduce) {
    .splash-logo      { animation: none; }
    .splash-spinner   { animation: none; border-top-color: var(--color-accent); }
}


/* =========================================================
   20. GLOBAL AUDIO PLAYER
   Fixed bottom bar — z-index 500 (Sticky App UI tier)
   ========================================================= */

/*
 * Classes: .player-bar, .player-scrubber, .player-scrubber-input,
 *          .player-scrubber-progress, .player-hud, .player-info-wrap,
 *          .player-info, .player-artwork, .player-artwork-placeholder,
 *          .player-track-name, .player-track-meta, .player-time,
 *          .player-on-deck, .player-controls, .player-right,
 *          .player-queue-count, .player-button, .player-button-primary,
 *          .player-button-active, .player-button-disabled,
 *          .player-hidden-audio
 *          Queue popup: .player-queue-popup, .player-queue-popup-expanded,
 *            .player-queue-header, .player-queue-header-title,
 *            .player-queue-header-count, .player-queue-header-spacer,
 *            .player-queue-clear, .player-queue-list,
 *            .player-queue-item, .player-queue-item-dragover,
 *            .player-queue-track-number, .player-queue-track-title,
 *            .player-queue-track-version, .player-queue-empty,
 *            .player-queue-jump, .player-queue-artwork,
 *            .player-queue-artwork-placeholder, .player-queue-remove
 *          Volume popup: .player-volume-popup, .player-volume-container,
 *            .player-volume-track, .player-volume-fill,
 *            .player-volume-handle, .player-volume-label
 *
 * AI Note: The player inherits the dark surface from the inverse token
 * family so it contrasts against the cream page background without any
 * !important overrides. It is NOT wrapped in .main-layout-container,
 * so it needs its own explicit color declarations.
 */

/* --- Main bar --- */

/* Player chrome is UI, not copy — don't let pointer drags select the track
   name / time / queue labels. */
/* AI Note (owner decision, 2026-07-03): the player is a FIXED DARK CINEMA SURFACE
   in every theme — the original dark bar with the FFT visualizer behind it — the
   same doctrine as the fullscreen viz overlay and the video letterbox. It is
   deliberately EXEMPT from the semantic-token rule: do NOT re-point it to
   --surface-inverse (an R1 attempt did; under Prince the inverse surface is
   LIGHT and the owner rejected the cream bar). --player-ink stays the single
   ink variable every glyph/label/color-mix derives from — a fixed light cream
   here, re-paired only by the artwork-tint override below. */
.player-bar,
.player-queue-popup,
.player-volume-popup {
    user-select: none;
    -webkit-user-select: none;
    --player-ink: var(--color-cream);
    color: var(--player-ink);
}

.player-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 500;
    /* Fixed dark bar (the FFT canvas paints over it); the dynamic
       --player-artwork-color tint still wins when set, and JS pairs it with
       --player-artwork-text (a luminance-paired ink) so the pair travels
       together, mirroring the CMS role rule. */
    --player-ink: var(--player-artwork-text, var(--color-cream));
    background-color: var(--player-artwork-color, var(--color-charcoal));
    transition: background-color 0.6s ease;
    color: var(--player-ink);
    border-top: 1px solid rgba(245, 240, 232, 0.18);
    box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.40);
    display: flex;
    flex-direction: column;
}

/* Rail layout — cosmetic player-bar inset (docs/features/layouts/LayoutSpec-Rail-v1.md).
   Under Rail the sticky sidecar occupies the left --rail-w column, so above the collapse
   width the bottom player-bar is inset by that width to align with the content column
   instead of sliding under the rail. This is body-scope COSMETICS (the engine's cosmetic
   tier, mirrored from the container attr one frame later on enhanced-nav — one-frame lag
   accepted; docs Landmines). --rail-w is re-declared on this scope so the offset matches
   the rail width without depending on the container-scoped structural token. */
@media (min-width: 881px) {
    body[data-layout="rail"] {
        --rail-w: clamp(224px, 15vw, 272px);
    }

    body[data-layout="rail"] .player-bar {
        left: var(--rail-w);
    }
}

/* Scrubber sits above the HUD — a thin progress stripe */
.player-scrubber {
    position: relative;
    width: 100%;
    height: 4px;
    background-color: color-mix(in srgb, var(--player-ink) 12%, transparent);
    cursor: pointer;
}

/* Buffered ("loaded") stripe — a dim band showing how far the browser has
   downloaded ahead of the playhead. Rendered via --buffered-pct (inline style)
   and sits BELOW the bright fill (::before paints before ::after). */
.player-scrubber::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: var(--buffered-pct, 0%);
    background-color: color-mix(in srgb, var(--player-ink) 28%, transparent);
    pointer-events: none;
    transition: width 300ms linear;
}

/* Fill rendered via CSS custom property --scrubber-pct (inline style).
   When artwork color extraction produces a light variant, use it so the
   scrubber matches the tinted bar. Falls back to the standard accent color. */
.player-scrubber::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: var(--scrubber-pct, 0%);
    background-color: var(--player-artwork-color-light, var(--color-accent));
    pointer-events: none;
    transition: width 200ms linear;
}

/* The actual <input type=range> is layered on top for mouse interaction */
.player-scrubber-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
    margin: 0;
    padding: 0;
    /* Enlarge hit area without changing visual footprint */
    touch-action: none;
}

.player-scrubber-progress {
    /* Handled by ::after pseudo-element — this div is intentionally empty */
    display: none;
}

/* HUD: left info | center controls | right extras */
.player-hud {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-5);
    min-height: 56px;
}

/* --- Track info (left) --- */

.player-info-wrap {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-width: 0;
}

.player-artwork {
    width: 40px;
    height: 40px;
    border-radius: var(--radius-sm);
    object-fit: cover;
    flex-shrink: 0;
    background-color: color-mix(in srgb, var(--player-ink) 8%, transparent);
}

.player-artwork-placeholder {
    width: 40px;
    height: 40px;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
    background-color: color-mix(in srgb, var(--player-ink) 8%, transparent);
    /* Music-note placeholder via CSS */
    display: flex;
    align-items: center;
    justify-content: center;
}

.player-artwork-placeholder::after {
    content: '♪';
    font-size: var(--text-lg);
    color: color-mix(in srgb, var(--player-ink) 35%, transparent);
}

.player-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.player-track-name {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--player-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.player-track-meta {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-xs);
    color: color-mix(in srgb, var(--player-ink) 60%, transparent);
}

.player-time {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.player-on-deck {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 20ch;
}

/* --- Playback controls (center) --- */

.player-controls {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* --- Right controls --- */

.player-right {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    justify-content: flex-end;
}

.player-queue-count {
    font-size: var(--text-xs);
    color: color-mix(in srgb, var(--player-ink) 50%, transparent);
    white-space: nowrap;
}

/* --- Player buttons ---
   One icon-button system. Base = .player-button (36px); size modifiers
   .player-button-primary (42px play/pause) and .player-button-sm (32px, e.g.
   queue remove); state modifiers -active / -disabled. Every clickable icon in
   the player rides this, so hover / focus / disabled behave identically. */
.player-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    background: none;
    border: none;
    border-radius: var(--radius-md);
    color: color-mix(in srgb, var(--player-ink) 72%, transparent);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
    flex-shrink: 0;
}

.player-button:hover {
    background-color: color-mix(in srgb, var(--player-ink) 10%, transparent);
    color: var(--player-ink);
}

/* Keyboard focus — the player previously had NO focus affordance. */
.player-button:focus-visible {
    outline: 2px solid var(--color-accent-light);
    outline-offset: 2px;
    color: var(--player-ink);
}

/* Compact variant (queue remove). */
.player-button-sm {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-sm);
}

/* Primary play/pause button — larger, filled, accent on hover. */
.player-button-primary {
    width: 42px;
    height: 42px;
    background-color: color-mix(in srgb, var(--player-ink) 10%, transparent);
    color: var(--player-ink);
}

.player-button-primary:hover {
    background-color: var(--color-accent);
    color: var(--color-white);
    transform: scale(1.04);
}

.player-button-primary:active {
    transform: scale(0.97);
}

/* Active state (loop on, queue open, volume open) */
.player-button-active {
    color: var(--color-accent-light);
    background-color: color-mix(in srgb, var(--color-accent) 15%, transparent);
}

.player-button-active:hover {
    background-color: color-mix(in srgb, var(--color-accent) 25%, transparent);
    color: var(--color-accent-light);
}

/* Disabled state */
.player-button-disabled {
    opacity: 0.3;
    cursor: not-allowed;
    pointer-events: none;
}

/* Respect reduced-motion: drop the play-button scale. */
@media (prefers-reduced-motion: reduce) {
    .player-button-primary:hover,
    .player-button-primary:active {
        transform: none;
    }
}

/* Hidden audio element — never rendered, just used for JS interop */
.player-hidden-audio {
    display: none;
}

/* --- Queue popup --- */

.player-queue-popup {
    position: fixed;
    bottom: calc(56px + 4px + var(--space-3));  /* above the player bar */
    right: var(--space-5);
    z-index: 550;
    width: 360px;
    max-height: 420px;
    overflow-y: auto;
    background-color: var(--color-charcoal);
    border: 1px solid color-mix(in srgb, var(--player-ink) 15%, transparent);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-2) 0;
}

/* Wider/taller variant toggled by the expand chevron in the header (MP-P7). */
.player-queue-popup-expanded {
    width: 460px;
    max-height: min(72vh, 680px);
}

/* Queue header: "Up next" + count, then a spacer pushing Clear + expand right. */
.player-queue-header {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4);
    border-bottom: 1px solid color-mix(in srgb, var(--player-ink) 10%, transparent);
    position: sticky;
    top: 0;
    background-color: var(--color-charcoal);
    z-index: 1;
}

.player-queue-header-title {
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--player-ink) 70%, transparent);
}

.player-queue-header-count {
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
    color: color-mix(in srgb, var(--player-ink) 45%, transparent);
}

.player-queue-header-spacer {
    flex: 1;
}

/* Text button (not an icon) — give it horizontal padding and small type. */
.player-queue-clear {
    width: auto;
    padding: 0 var(--space-2);
    font-size: var(--text-xs);
    font-weight: 600;
    color: color-mix(in srgb, var(--player-ink) 55%, transparent);
}

.player-queue-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

.player-queue-item {
    display: flex;
    align-items: center;
    gap: 0;
    padding: 0;
    border-bottom: 1px solid color-mix(in srgb, var(--player-ink) 6%, transparent);
    transition: background-color var(--duration-fast) var(--ease-out);
    cursor: grab;
}

.player-queue-item:last-child {
    border-bottom: none;
}

.player-queue-item:hover {
    background-color: color-mix(in srgb, var(--player-ink) 6%, transparent);
}

.player-queue-item-dragover {
    background-color: color-mix(in srgb, var(--color-accent) 15%, transparent);
    border-color: color-mix(in srgb, var(--color-accent) 35%, transparent);
}

/* The clickable portion of the queue row */
.player-queue-jump {
    flex: 1;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: none;
    border: none;
    color: var(--player-ink);
    text-align: left;
    cursor: pointer;
    min-width: 0;
    font-family: var(--font-body);
}

/* Keyboard focus for the row-select button (sits inside the row). */
.player-queue-jump:focus-visible {
    outline: 2px solid var(--color-accent-light);
    outline-offset: -2px;
    border-radius: var(--radius-sm);
}

.player-queue-track-number {
    font-size: var(--text-xs);
    color: color-mix(in srgb, var(--player-ink) 40%, transparent);
    min-width: 20px;
    text-align: right;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}

.player-queue-artwork {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-sm);
    object-fit: cover;
    flex-shrink: 0;
}

.player-queue-artwork-placeholder {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
    background-color: color-mix(in srgb, var(--player-ink) 8%, transparent);
}

.player-queue-track-title {
    flex: 1;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--player-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.player-queue-track-version {
    font-size: var(--text-xs);
    color: color-mix(in srgb, var(--player-ink) 40%, transparent);
    white-space: nowrap;
    flex-shrink: 0;
    margin-left: var(--space-2);
}

/* Remove button — now rides on .player-button .player-button-sm (consistent
   hover/focus/sizing with every other icon button). This rule only nudges it to
   the row's right edge and keeps it a touch dimmer at rest (per-row destructive
   action); hover/focus from .player-button brings it up. */
.player-queue-remove {
    margin-right: var(--space-2);
    color: color-mix(in srgb, var(--player-ink) 45%, transparent);
}

.player-queue-empty {
    padding: var(--space-5) var(--space-5);
    font-size: var(--text-sm);
    color: color-mix(in srgb, var(--player-ink) 45%, transparent);
    text-align: center;
    font-style: italic;
}

/* --- Volume popup --- */

.player-volume-popup {
    position: fixed;
    bottom: calc(56px + 4px + var(--space-3));
    right: calc(var(--space-5) + 80px);
    z-index: 550;
    background-color: var(--color-charcoal);
    border: 1px solid color-mix(in srgb, var(--player-ink) 15%, transparent);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-5);
}

.player-volume-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
}

/* Vertical track — click/drag to set volume */
.player-volume-track {
    width: 6px;
    height: 120px;
    background-color: color-mix(in srgb, var(--player-ink) 15%, transparent);
    border-radius: var(--radius-full);
    position: relative;
    cursor: pointer;
}

.player-volume-fill {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    /* Height driven by --volume-fill-pct inline style on the track */
    height: var(--volume-fill-pct, 100%);
    background-color: var(--color-accent);
    border-radius: var(--radius-full);
    pointer-events: none;
}

.player-volume-handle {
    position: absolute;
    left: 50%;
    /* Positioned at current volume level */
    bottom: calc(var(--volume-fill-pct, 100%) - 8px);
    transform: translateX(-50%);
    width: 14px;
    height: 14px;
    background-color: var(--player-ink);
    border-radius: 50%;
    pointer-events: none;
    box-shadow: 0 1px 4px rgba(0,0,0,0.4);
}

.player-volume-label {
    font-size: var(--text-xs);
    color: color-mix(in srgb, var(--player-ink) 60%, transparent);
    font-variant-numeric: tabular-nums;
    text-align: center;
}

/* Speed toggle + A-B loop (hidden; available for future prototyping)
   Remove style="display: none" from the buttons in GlobalPlayer.razor to enable. */
.player-speed-toggle,
.player-ab-toggle {
    min-width: 40px;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
    font-size: var(--text-xs);
    font-weight: 600;
}

.player-speed-label,
.player-ab-label {
    font-size: var(--text-xs);
    font-weight: 700;
}

/* Audio visualizer canvas (P3)
   Positioned absolutely inside .player-bar, behind all HUD content.
   Frequency bars rise from the bottom, reacting to the playing audio.
   JS writes pixel data; Blazor does no rendering of this element. */
.player-waveform-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 1;          /* above bar background, below HUD content */
}

/* HUD and scrubber sit above the visualizer canvas */
.player-hud {
    position: relative;
    z-index: 2;
}

.player-scrubber {
    z-index: 2;
}

/* Responsive: hide queue/volume popups on very narrow screens */
@media (max-width: 480px) {
    .player-hud {
        grid-template-columns: 1fr auto auto;
        padding: var(--space-2) var(--space-4);
    }

    /* Narrow screens keep only the fullscreen action in the right cluster —
       queue count, queue, volume, and close are dropped to fit. */
    .player-right > * {
        display: none;
    }

    .player-right > .player-mobile-show {
        display: inline-flex;
    }

    /* Fullscreen takes priority over the artwork thumbnail here: drop the
       thumbnail so the button has room without squeezing the track title. */
    .player-artwork,
    .player-artwork-placeholder {
        display: none;
    }

    .player-queue-popup,
    .player-volume-popup {
        right: var(--space-3);
        left: var(--space-3);
        width: auto;
    }

    .player-track-meta .player-on-deck {
        display: none;
    }
}


/* =========================================================
   20b. FULLSCREEN AUDIO VISUALIZER OVERLAY (P1a)
   Fixed full-viewport — z-index 600 (above player bar at 500)
   ========================================================= */

/*
 * Classes: .player-viz-overlay, .player-viz-canvas, .player-viz-bg-art,
 *          .player-viz-info, .player-viz-artwork, .player-viz-track,
 *          .player-viz-title, .player-viz-artist,
 *          .player-viz-controls, .player-viz-play-btn,
 *          .player-viz-close-btn
 *
 * JS drives the canvas (frequency bars + oscilloscope via Web Audio AnalyserNode).
 * Album art shown as a very subtle blurred atmosphere behind the bars.
 * Click the dark background to dismiss; Escape key also closes.
 *
 * AI Note (R1): the cream literals in THIS section are intentional and exempt from
 * the semantic-token rule — the overlay is a FIXED near-black cinema surface
 * (rgb(8,7,6)) in every theme, so a fixed light ink is the correct pair (same
 * doctrine as .btn-google's fixed white face). Do not re-point these to
 * --surface-* tokens; a light theme would turn the ink dark on near-black.
 */

.player-viz-overlay {
    position: fixed;
    inset: 0;
    z-index: 600;
    /* Very dark warm near-black — lets the colorful bars read clearly */
    background-color: rgb(8, 7, 6);
    animation: viz-overlay-in 0.22s ease;
    /* Pointer on background area hints that clicking dismisses the overlay */
    cursor: pointer;
}

/* When promoted to the native fullscreen element, fill the screen explicitly.
   (Browsers can letterbox a :fullscreen element to its intrinsic size otherwise.) */
.player-viz-overlay:fullscreen {
    width: 100%;
    height: 100%;
}

@keyframes viz-overlay-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .player-viz-overlay { animation: none; }
}

/* Full-viewport canvas — JS draws bars and oscilloscope */
.player-viz-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    display: block;
}

/* Album art blurred atmospheric background */
.player-viz-bg-art {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0.07;
    pointer-events: none;
    filter: blur(28px);
    transform: scale(1.12); /* overshoot to hide blur-edge artifacts */
    z-index: 0;
}

/* Track info strip — bottom-left, above canvas */
.player-viz-info {
    position: absolute;
    bottom: 76px;
    left: var(--page-gutter, 2rem);
    display: flex;
    align-items: center;
    gap: 0.875rem;
    z-index: 1;
    cursor: default;
}

.player-viz-artwork {
    width: 60px;
    height: 60px;
    object-fit: cover;
    border-radius: 4px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.70);
    flex-shrink: 0;
}

.player-viz-track {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.player-viz-title {
    font-size: var(--text-base, 1rem);
    font-weight: 600;
    color: var(--color-cream);
    text-shadow: 0 1px 10px rgba(0, 0, 0, 0.85);
    max-width: 280px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.player-viz-artist {
    font-size: var(--text-sm, 0.875rem);
    color: rgba(245, 240, 232, 0.60);
}

/* Playback controls — bottom-center, lifted above the waveform seek bar */
.player-viz-controls {
    position: absolute;
    bottom: 56px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: var(--space-4, 1rem);
    z-index: 1;
    cursor: default;
}

/* Primary play/pause in the viz is slightly larger than the bar version */
.player-viz-play-btn {
    width: 52px !important;
    height: 52px !important;
    border-radius: 50% !important;
}

/* Close button — top-right corner */
.player-viz-close-btn {
    position: absolute;
    top: var(--space-4, 1rem);
    right: var(--space-4, 1rem);
    z-index: 1;
    border-radius: 50% !important;
    cursor: pointer;
    background-color: rgba(245, 240, 232, 0.10) !important;
}

/* Waveform seek bar — full-width strip pinned to the very bottom of the fullscreen viz. Played portion
   sweeps into the hollow full-track outline; click/drag anywhere seeks. */
.player-viz-waveform {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 40px;
    z-index: 3;
    cursor: pointer;
    touch-action: none;   /* let a pointer drag seek instead of scrolling */
    /* Dark scrim behind the semi-opaque waveform so the seek bar stays legible over a very light viz
       scene — the "some other method of contrast" for background-vs-waveform. The canvas draws on top. */
    background: linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.12));
}

/* Pulsing glow on the mini-player's fullscreen button to invite (re)opening the visualizer. */
.player-viz-pulse {
    border-radius: 50%;
    animation: player-viz-pulse 2s ease-in-out infinite alternate;
}
@keyframes player-viz-pulse {
    from { box-shadow: 0 0 3px 1px rgba(245, 240, 232, 0.25); }
    to   { box-shadow: 0 0 14px 5px rgba(245, 240, 232, 0.70); }
}
@media (prefers-reduced-motion: reduce) {
    .player-viz-pulse { animation: none; }
}

.player-viz-close-btn:hover {
    background-color: rgba(245, 240, 232, 0.20) !important;
}

/* Scene name label — fades in when the scene changes, top-center */
.player-viz-scene-label {
    position: absolute;
    top: var(--space-8, 2rem);
    left: 50%;
    transform: translateX(-50%);
    z-index: 2;
    font-size: var(--text-sm, 0.875rem);
    color: rgba(245, 240, 232, 0.65);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    font-weight: 500;
    pointer-events: none;
    white-space: nowrap;
    opacity: 0;
}

.player-viz-scene-label.viz-label-visible {
    animation: viz-label-show 3.2s ease forwards;
}

@keyframes viz-label-show {
    0%   { opacity: 0;    }
    12%  { opacity: 0.65; }
    72%  { opacity: 0.65; }
    100% { opacity: 0;    }
}

@media (max-width: 480px) {
    .player-viz-info {
        bottom: 84px;
        left: var(--space-4, 1rem);
    }
    .player-viz-title {
        max-width: 180px;
    }
}


/* =========================================================
   21. NOTIFICATION BAR
   Fixed top — z-index 2100 (System Overlays tier)
   ========================================================= */

/*
 * Classes: .notification-bar, .notification-content, .notification-icon,
 *          .notification-message, .bar-success, .bar-error, .bar-info,
 *          .animate-slide-down
 */

.notification-bar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 2100;
    display: flex;
    align-items: stretch;
    justify-content: center;
    padding: 0 var(--page-gutter);
    /* Bar is slim by design — it's an alert, not a dialog */
    min-height: 44px;
}

.notification-content {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-5);
    border-radius: 0 0 var(--radius-md) var(--radius-md);
    max-width: 600px;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    box-shadow: var(--shadow-md);
}

.notification-icon {
    flex-shrink: 0;
    display: flex;
    align-items: center;
}

.notification-message {
    /* Allow message to wrap on very long strings */
    line-height: var(--leading-normal);
}

/* Status color variants */
.bar-success .notification-content {
    background-color: var(--alert-success-solid);
    color: var(--alert-on-solid);
}

.bar-error .notification-content {
    background-color: var(--alert-danger-solid);
    color: var(--alert-on-solid);
}

.bar-info .notification-content {
    /* Neutral info banner = the inverse tile; themes re-point it (was charcoal/cream
       primitives, which stayed cream-on-charcoal under Dark — BL-001). */
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
}

/* Slide-down entry animation */
@keyframes slide-down {
    from {
        opacity: 0;
        transform: translateY(-100%);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.animate-slide-down {
    animation: slide-down 220ms var(--ease-out) forwards;
}

@media (prefers-reduced-motion: reduce) {
    .animate-slide-down {
        animation: none;
    }
}


/* =========================================================
   22. APP MODALS
   Backdrop + dialog — z-index 1000-1010 (App Modals tier)
   ========================================================= */

/*
 * Two modal systems used in the codebase:
 *   A. .app-modal-backdrop + .app-modal-dialog  (SongPortal, PlaylistPortal)
 *   B. .am-backdrop + .am-dialog  (Dashboard conversation modal)
 *
 * Both use the same visual language — semi-transparent dark backdrop,
 * raised white dialog with charcoal text.
 */

/* --- System A: app-modal --- */

.app-modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--z-nav);
    background-color: rgba(28, 26, 23, 0.65);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}

.app-modal-dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 1010;
    background-color: var(--color-cream);
    color: var(--color-charcoal);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    width: min(90vw, 800px);
    max-height: 90dvh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
}

/* --- System B: am-* (dashboard activity / conversation modal) --- */

.am-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--z-nav);
    background-color: rgba(28, 26, 23, 0.65);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}

.am-dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 1010;
    background-color: var(--surface-page);
    color: var(--surface-page-text);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    width: min(90vw, 640px);
    max-height: 85dvh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.am-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-4) var(--space-5);
    border-bottom: var(--border-thin);
    flex-shrink: 0;
}

.am-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--surface-page-text);
    margin: 0;
}

.am-btn-close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--surface-page-text-muted);
    font-size: var(--text-xl);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.am-btn-close:hover {
    background-color: var(--surface-deep);
    color: var(--surface-deep-text);
}

.am-body {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-5);
}

.am-body.conversation-mode {
    padding: var(--space-4);
}

/* GlobalModalContainer — same z-index tier */
.modal-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--z-nav);
    background-color: rgba(28, 26, 23, 0.65);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    display: flex;
    align-items: center;
    justify-content: center;
}

.modal-box {
    background-color: var(--color-cream);
    color: var(--color-charcoal);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    width: min(90vw, 560px);
    max-height: 85dvh;
    overflow-y: auto;
    padding: var(--space-6);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}


/* =========================================================
   23. BAND PORTAL — SHARED CONTAINER + COMMON CONTROLS
   /band/* pages — authenticated BandMember routes
   ========================================================= */

/*
 * The band portal uses the legacy .admin-container pattern (predates the
 * new admin vocabulary). It inherits the cream page background via body.
 * The container just frames the content with max-width + padding.
 *
 * Classes: .admin-container, .dashboard-mode, .animate-entry,
 *          .filter-bar, .search-input, .btn-primary, .btn-tab,
 *          .btn-icon-action, .btn-header-action, .btn-header-chat,
 *          .tabs-row, .edit-section, .card-header, .card-header-actions,
 *          .user-card
 */

/* --- Page frame --- */

.admin-container {
    max-width: 1100px;
    margin: 0 auto;
    padding: var(--space-6) var(--page-gutter);
    width: 100%;
}

.admin-container.dashboard-mode {
    max-width: 1300px;
}

/* Fade-in on page entry — plays once */
.animate-entry {
    animation: animate-entry-fade 0.5s var(--ease-out) forwards;
}

/* AI Note: [Constraint] opacity-ONLY — do NOT add `transform` here. With `animation-fill-mode: forwards`
   the element keeps its final `transform` value, and ANY non-`none` transform (even translateY(0)) makes
   this element the containing block for every `position: fixed` descendant. That mis-positioned the "…"
   ContextMenu and the dashboard modals relative to #dashboard-home instead of the viewport. See
   Landmines-v1.md "A `transform` on an entry-animated ancestor breaks position:fixed". */
@keyframes animate-entry-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* --- Section header row (h2 + optional actions) --- */

.admin-container h2 {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--surface-page-text);
    margin-bottom: var(--space-5);
    font-variation-settings: 'WONK' 0;
}

/* --- Filter/search bar --- */

.filter-bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-5);
    align-items: center;
}

.search-input {
    flex: 1;
    min-width: 180px;
    padding: var(--space-3) var(--space-4);
    background-color: var(--color-white);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-base);
    color: var(--color-charcoal);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.search-input:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-dim);
}

/* Primary action button (was dark themed) */
/* R2: the inverse pair replaces charcoal/cream — under dark themes the old
   primitives rendered a dark-on-dark button (owner report: Prince login). */
.btn-primary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-5);
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.02em;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    text-decoration: none;
    width: auto;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.btn-primary:hover:not(.disabled) {
    background-color: var(--surface-accent);
    color: var(--surface-accent-text);
    transform: translateY(-1px);
}

.btn-primary.disabled,
.btn-primary:disabled {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
    transform: none;
    background-color: color-mix(in srgb, var(--surface-inverse) 70%, transparent);
}

/* Small play/queue buttons inline in the attribute table */
.btn-playlist-play {
    padding: var(--space-2) var(--space-3);
    min-width: 36px;
}

/* Songs-list row actions: Original play/queue + Stem-mix play/queue.
   .song-actions gives the small gap between Play and Queue; .song-actions-stems
   sets the stem pair apart; .btn-stem prefixes a small "S" tag. */
.song-actions {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.song-actions-stems {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: var(--space-4);
}

.btn-stem {
    display: inline-flex;
    align-items: center;
    gap: 2px;
}

.btn-stem-tag {
    font-weight: 700;
    font-size: 0.78em;
    line-height: 1;
}

/* --- Song/Playlist modal card chrome --- */

.user-card {
    background-color: var(--surface-page);
    color: var(--surface-page-text);
    border-radius: var(--radius-lg);
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    width: 100%;
}

.card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding-bottom: var(--space-4);
    border-bottom: var(--border-thin);
}

.card-header h3 {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--color-charcoal);
    margin: 0;
    font-variation-settings: 'WONK' 0;
}

.card-header-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-shrink: 0;
}

.btn-icon-action {
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    border-radius: var(--radius-md);
    color: var(--color-charcoal-muted);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
    padding: 0;
    /* BL-029 / FLG-CMP-DASH-1-04 — `width:auto` collapsed the packed dashboard-row icon buttons to
       ~16px wide (below the 24px target floor); floor the width so the hit target holds. Height was
       already 36px. */
    min-width: 24px;
    padding-inline: var(--space-1);
}

.btn-icon-action:hover {
    background-color: var(--color-cream-deep);
    color: var(--color-charcoal);
}

.btn-icon-action:focus-visible {
    outline: 2px solid var(--focus-ring);   /* BL-029: was missing a focus indicator */
    outline-offset: 2px;
}

.btn-header-action {
    color: var(--color-charcoal-muted);
}

.btn-header-chat {
    color: var(--color-charcoal-muted);
}

.btn-header-chat.active {
    color: var(--color-accent);
    background-color: var(--color-accent-dim);
}

/* --- Tabs row --- */

.tabs-row {
    display: flex;
    gap: 0;
    border-bottom: var(--border-thin);
    margin-bottom: var(--space-4);
}

.btn-tab {
    padding: var(--space-3) var(--space-5);
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;   /* overlap the parent border-bottom */
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-charcoal-muted);
    cursor: pointer;
    transition: color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
    width: auto;
}

.btn-tab:hover {
    color: var(--color-charcoal);
}

.btn-tab.active {
    color: var(--color-accent);
    border-bottom-color: var(--color-accent);
    font-weight: 600;
}

.btn-tab.disabled {
    opacity: 0.4;
    cursor: not-allowed;
    pointer-events: none;
}

/* --- Edit section container --- */

.edit-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}


/* =========================================================
   24. DASHBOARD GRID
   ========================================================= */

/*
 * Classes: .dashboard-grid, .dashboard-card, .dashboard-header-row,
 *          .dashboard-title, .dashboard-controls, .dashboard-select,
 *          .activity-feed-container, .activity-row, .activity-icon,
 *          .activity-header, .actor-name, .activity-details-inline,
 *          .activity-date, .activity-empty
 */

.dashboard-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
    gap: var(--space-5);
    align-items: start;
}

/* Admin-positioned bento variant: a fixed 4-column grid so each DashboardTile's
   grid-column / grid-row start+end are meaningful. Collapses to a single
   stacked column on narrow screens (positions ignored there). */
.dashboard-grid-positioned {
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: minmax(min-content, auto);
}

.dashboard-tile-slot {
    min-width: 0;          /* allow grid children to shrink instead of overflow */
    display: flex;
}

.dashboard-tile-slot > * {
    flex: 1 1 auto;
    min-width: 0;
}

/* Fixed full-width tabbed section (Playlists / Songs) below the grid. */
.dashboard-tabs-section {
    margin-top: var(--space-5);
}

.dashboard-tabs-row {
    display: flex;
    gap: var(--space-2);
    border-bottom: var(--border-thin);
    margin-bottom: var(--space-4);
}

.dashboard-tab {
    appearance: none;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    padding: var(--space-3) var(--space-4);
    font-family: var(--font-display);
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--color-charcoal);
    opacity: 0.7;
    cursor: pointer;
    transition: color var(--duration-fast) var(--ease-out),
                opacity var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}

.dashboard-tab:hover {
    opacity: 1;
    color: var(--color-accent);
}

.dashboard-tab.active {
    opacity: 1;
    color: var(--color-accent);
    border-bottom-color: var(--color-accent);
}

.dashboard-tab:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
    border-radius: var(--radius-sm, 4px);
}

@media (max-width: 900px) {
    .dashboard-grid-positioned {
        grid-template-columns: 1fr;
    }
    /* Ignore admin grid coords on narrow screens — stack in DisplayOrder. */
    .dashboard-grid-positioned .dashboard-tile-slot {
        grid-column: 1 / -1 !important;
        grid-row: auto !important;
    }
}

.dashboard-card {
    background-color: var(--color-white);
    border: var(--border-thin);
    border-radius: var(--radius-lg);
    padding: var(--space-4) var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    box-shadow: var(--shadow-sm);
}

.dashboard-header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}

.dashboard-title {
    font-family: var(--font-display);
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--color-charcoal);
    letter-spacing: -0.01em;
    font-variation-settings: 'WONK' 0;
}

.dashboard-controls {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.dashboard-select {
    padding: var(--space-1) var(--space-3);
    background-color: var(--color-cream-deep);
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: var(--text-xs);
    color: var(--color-charcoal-mid);
    cursor: pointer;
    transition: border-color var(--duration-fast) var(--ease-out);
    width: auto;
}

.dashboard-select:focus {
    outline: none;
    border-color: var(--color-accent);
}

/* Activity feed */
.activity-feed-container {
    display: flex;
    flex-direction: column;
    gap: 0;
}

.activity-row {
    display: grid;
    grid-template-columns: 32px 1fr;
    gap: var(--space-3);
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--color-cream-mid);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.activity-row:last-child {
    border-bottom: none;
}

.activity-row:hover {
    background-color: var(--color-cream-deep);
    border-radius: var(--radius-sm);
    margin: 0 calc(-1 * var(--space-2));
    padding: var(--space-3) var(--space-2);
}

.activity-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background-color: var(--color-cream-deep);
    color: var(--color-charcoal-muted);
    flex-shrink: 0;
    font-size: var(--text-sm);
}

.activity-header {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.actor-name {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-charcoal);
}

.activity-details-inline {
    font-size: var(--text-sm);
    color: var(--color-charcoal-mid);
    line-height: var(--leading-snug);
}

.activity-date {
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
    white-space: nowrap;
    margin-left: auto;
    flex-shrink: 0;
}

.activity-empty {
    font-size: var(--text-sm);
    color: var(--color-charcoal-muted);
    font-style: italic;
    padding: var(--space-4) 0;
    text-align: center;
}

/* ---- Recent Activity rows (D5): compact two-line layout, shared by the inline
   tile and the "Show N" modal via the ActivityRow component. ---- */
.af-row {
    display: grid;
    grid-template-columns: 24px 1fr;
    gap: var(--space-2) var(--space-3);
    align-items: start;
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--color-cream-mid);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.af-row:last-child {
    border-bottom: none;
}

.af-row:hover {
    background-color: var(--color-cream-deep);
    border-radius: var(--radius-sm);
    margin: 0 calc(-1 * var(--space-2));
    padding-left: var(--space-2);
    padding-right: var(--space-2);
}

.af-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background-color: var(--color-cream-deep);
    color: var(--color-charcoal-mid);
    flex-shrink: 0;
    margin-top: 1px;
}

.af-main {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.af-line {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--space-3);
}

.af-summary {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--text-sm);
    line-height: var(--leading-snug);
    color: var(--color-charcoal-mid);
}

.af-actor {
    font-weight: 600;
    color: var(--color-charcoal);
}

.af-date {
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
    white-space: nowrap;
    flex-shrink: 0;
}

.af-preview {
    font-size: var(--text-xs);
    color: var(--color-charcoal-mid);
    line-height: var(--leading-snug);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* "Show N" activity modal: scroll the list within the viewport; the pager below
   stays visible. */
.am-body.activity-mode {
    max-height: 60vh;
    overflow-y: auto;
}

.dashboard-activity-modal-footer {
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-cream-mid);
}

/* /admin/dashboard-tiles — layout preview (placeholder boxes at tile coords). */
.dashboard-tiles-preview {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-2);
    grid-auto-rows: 44px;
    margin-top: var(--space-2);
}

.dashboard-tiles-preview-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: var(--space-1);
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--color-charcoal);
    background-color: var(--color-cream-deep);
    border: var(--border-thin);
    border-radius: var(--radius-sm, 4px);
}

.dashboard-tiles-preview-cell.is-selected {
    background-color: var(--color-accent-light);
    border-color: var(--color-accent);
}

/* To-Do tile: its lists collapse and expand one at a time, so a per-section
   pager is awkward UX. Cap the content height and scroll instead, so the tile
   never overflows the bento cell. (Replies / Songs / Playlists use PagedTileBody
   pagers; Recent Activity has its own pager + modal.) */
.todo-list-panel-content {
    max-height: 420px;
    overflow-y: auto;
}

/* Dashboard tile titles are now <h2> (BL-007 heading outline). Reset UA heading
   block-margins so the flex header row keeps the prior <div> baseline. */
h2.dashboard-title {
    margin: 0;
}

/* Activity rows are now real <button>s (BL-007 keyboard activation). Reset UA button
   chrome so the button renders identically to the former clickable <div> grid row. */
button.af-row {
    width: 100%;
    background: none;
    border: none;
    border-bottom: 1px solid var(--color-cream-mid);
    text-align: left;
    font: inherit;
    color: inherit;
    appearance: none;
}


/* =========================================================
   25. ADMIN PAGES (NEW VOCABULARY)
   /admin/* — admin-page + admin-* class family
   ========================================================= */

/*
 * Classes: .admin-page, .admin-header, .admin-title, .admin-lead,
 *          .admin-layout, .admin-list, .admin-list-new, .admin-list-item,
 *          .admin-list-item-selected, .admin-list-filter, .admin-empty,
 *          .admin-detail, .admin-detail-title, .admin-field,
 *          .admin-field-label, .admin-input, .admin-input-invalid,
 *          .admin-input-narrow, .admin-field-error, .admin-textarea,
 *          .admin-fieldset, .admin-required, .admin-checkbox,
 *          .admin-file-input, .admin-upload-status, .admin-preview,
 *          .admin-preview-cover, .admin-child-row, .admin-child-detail,
 *          .admin-message, .admin-message-ok, .admin-message-error,
 *          .admin-actions, .admin-button, .admin-button-primary,
 *          .admin-button-danger, .admin-button-confirm, .admin-button-small
 *
 * Master-detail layout: .admin-layout splits into .admin-list (narrow
 * scrollable list) and .admin-detail (wide edit panel).
 */

/* --- Page frame --- */

.admin-page {
    max-width: 1200px;
    margin: 0 auto;
    padding: var(--space-5) var(--page-gutter) var(--space-8);
    width: 100%;
}

.admin-header {
    margin-bottom: var(--space-5);
    padding-bottom: var(--space-4);
    border-bottom: var(--border-thin);
}

.admin-title {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 700;
    color: var(--surface-page-text);
    line-height: var(--leading-tight);
    letter-spacing: -0.02em;
    font-variation-settings: 'WONK' 0;
}

.admin-lead {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    margin-top: var(--space-2);
    line-height: var(--leading-normal);
}

/* --- Master-detail split --- */

.admin-layout {
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: var(--space-5);
    align-items: start;
}

/* --- List panel (left) --- */

.admin-list {
    display: flex;
    flex-direction: column;
    gap: 0;
    background-color: var(--surface-raised);
    border: var(--border-thin);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.admin-list-filter {
    padding: var(--space-3) var(--space-4);
    border-bottom: var(--border-thin);
    background-color: var(--surface-deep);
}

.admin-list-filter input {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    background-color: var(--surface-raised);
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--surface-raised-text);
}

.admin-list-filter input:focus {
    outline: none;
    border-color: var(--color-accent);
}

/* "New" button row at the top of the list */
.admin-list-new {
    padding: var(--space-3) var(--space-4);
    border-bottom: var(--border-thin);
}

.admin-list-new button,
.admin-list-new .admin-button {
    width: 100%;
    justify-content: center;
}

/* Stack of "+ New <type>" buttons (e.g. shared-components admin). */
.admin-list-new-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-bottom: var(--border-thin);
}
.admin-list-new-group .admin-list-new {
    padding: var(--space-2) var(--space-3);
    border-bottom: none;
}

.admin-list-item {
    padding: var(--space-3) var(--space-4);
    font-family: var(--font-body);
    color: var(--surface-page-text-muted);
    border-bottom: 1px solid var(--surface-border);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
    /* Stack title over meta so neither wraps awkwardly in the narrow sidebar (was side-by-side). */
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    width: 100%;
    min-width: 0;
    text-align: left;
}

/* Primary = the release title: the row's single focal point. */
.admin-list-item > strong {
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--surface-page-text);
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Secondary = the meta line: visibly subordinate (smaller, lighter, muted). */
.admin-list-item > small {
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--surface-page-text-muted);
}

.admin-list-item:last-child {
    border-bottom: none;
}

.admin-list-item:hover {
    background-color: var(--surface-deep);
}

/* Selected: the item as a whole is marked (tint + left bar), but only the TITLE takes the accent —
   the meta stays subordinate so the internal hierarchy isn't flattened. */
.admin-list-item-selected {
    background-color: var(--color-accent-dim);
    border-left: 3px solid var(--color-accent);
}

.admin-list-item-selected > strong {
    color: var(--color-accent);
}

.admin-list-item-selected:hover {
    background-color: var(--color-accent-dim);
}

/* Reorderable list row: the selectable item grows, move up/down buttons sit at
   the right edge (Phase 8 WS-3 dashboard-tiles editor). */
.admin-list-row {
    display: flex;
    align-items: center;
}

.admin-list-row .admin-list-item {
    flex: 1;
    min-width: 0;
}

.admin-list-reorder {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 0 var(--space-2);
    flex-shrink: 0;
    border-bottom: 1px solid var(--surface-border);
    align-self: stretch;
    justify-content: center;
}

.admin-list-row:last-child .admin-list-reorder {
    border-bottom: none;
}

.admin-button-icon {
    width: 30px;
    height: 22px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.admin-empty {
    padding: var(--space-6);
    text-align: center;
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    font-style: italic;
}

/* --- Detail panel (right) --- */

.admin-detail {
    background-color: var(--surface-raised);
    border: var(--border-thin);
    border-radius: var(--radius-lg);
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

.admin-detail-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--surface-page-text);
    padding-bottom: var(--space-4);
    border-bottom: var(--border-thin);
    font-variation-settings: 'WONK' 0;
}

/* --- Form fields --- */

.admin-field {
    display: flex;
    flex-direction: column;
    gap: var(--admin-gap);
}

.admin-field-label {
    font-family: var(--font-body);
    font-size: var(--admin-text-label);
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--surface-page-text-muted);
}

.admin-required {
    color: var(--color-accent);
    margin-left: 2px;
}

.admin-input {
    width: 100%;
    min-height: var(--admin-control-h);
    padding: var(--admin-pad-y) var(--admin-pad-x);
    background-color: var(--surface-deep);
    border: var(--border-thin);
    border-radius: var(--admin-radius);
    font-family: var(--font-body);
    font-size: var(--admin-text-control);
    line-height: 1.2;
    color: var(--surface-deep-text);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.admin-input:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-dim);
    background-color: var(--surface-raised);
}

.admin-input-invalid {
    border-color: var(--alert-danger-rule);
}

.admin-input-narrow {
    max-width: 200px;
}

.admin-field-error {
    font-size: var(--admin-text-help);
    color: var(--alert-danger-rule);
}

.admin-textarea {
    width: 100%;
    min-height: 96px;
    padding: var(--admin-pad-y) var(--admin-pad-x);
    background-color: var(--surface-deep);
    border: var(--border-thin);
    border-radius: var(--admin-radius);
    font-family: var(--font-body);
    font-size: var(--admin-text-control);
    color: var(--surface-deep-text);
    line-height: var(--leading-normal);
    resize: vertical;
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.admin-textarea:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-dim);
    background-color: var(--surface-raised);
}

.admin-fieldset {
    border: var(--border-thin);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* Checkbox row */
.admin-checkbox {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    cursor: pointer;
}

.admin-checkbox input[type="checkbox"] {
    width: 16px;
    height: 16px;
    border-radius: var(--radius-sm);
    border: var(--border-thin);
    accent-color: var(--color-accent);
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
    /* Restore sensible defaults that get overridden by the broad input rule */
    background: initial;
    appearance: auto;
    -webkit-appearance: auto;
}

/* AI Note (dead-selector history): this was `.admin-checkbox label` — a
   DESCENDANT label that never exists. The markup is
   `<label class="admin-checkbox"><input/> Option text</label>`, so the
   option text is a bare text node ON the labeled element, not in a nested
   <label>. The old selector matched nothing and the authored 12px
   (--admin-text-control) intent silently never applied. Corrected to
   `label.admin-checkbox` so the element itself is sized. */
label.admin-checkbox {
    font-size: var(--admin-text-control);
    font-weight: 500;
    color: var(--surface-page-text-muted);
    cursor: pointer;
    text-transform: none;
    letter-spacing: 0;
    opacity: 1;
}

/* One responsive-crop breakpoint row in the image layer editor (Workstream D): a max-width field +
   a focal picker + remove, grouped and set off from the base focal above. */
.viz-responsive-focal {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-2);
    margin-bottom: var(--space-2);
    border: 1px solid var(--surface-border);
    border-radius: var(--admin-radius, 4px);
}

/* Small inline chip for status callouts inside admin help text
   (e.g. "hidden from public" next to a toggle). */
.admin-pill {
    display: inline-block;
    padding: 1px var(--admin-pad-x);
    margin-left: var(--space-2);
    border-radius: 999px;
    font-size: var(--admin-text-help);
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    vertical-align: middle;
    line-height: 1.6;
}

.admin-pill-warn {
    /* BL-060 / FLG-CLR-004 — was white on light-amber #d4a657 = 2.24:1 text AND the fill itself
       cleared only ~2.11:1 vs the admin surface (a meaning-bearing graphic needs 3:1). Darkened to
       a saturated amber that clears BOTH floors: white-on-#8a5a00 = 5.93:1, fill-vs-cream = 5.59:1. */
    background-color: var(--color-warn-solid);
    color: var(--color-white);
}

.admin-pill-ok {
    background-color: var(--color-ok-solid);
    color: var(--color-white);
}

/* ====================================================================
   PublicPageGate — hidden-page UI + admin preview banner.
   Used by toggleable public pages when admin has set them hidden in
   /admin/general. Non-admins see the .public-page-gate-hidden surface
   (functions as a 404). Admins see a banner above the real content so
   they can preview before flipping the toggle on.
   ==================================================================== */
.public-page-gate-hidden {
    max-width: 640px;
    margin: var(--space-7) auto;
    padding: var(--space-6) var(--space-5);
    text-align: center;
}

.public-page-gate-hidden-title {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 700;
    color: var(--surface-page-text);
    margin: 0 0 var(--space-3);
}

.public-page-gate-hidden-lead {
    font-size: var(--text-base);
    color: var(--surface-page-text-muted);
    margin: 0 0 var(--space-5);
}

.public-page-gate-hidden-link {
    margin: 0;
    font-size: var(--text-base);
}

.public-page-gate-hidden-link a {
    color: var(--color-accent-text); /* text-safe accent (5.36:1); --color-accent fails 4.5 as text */
    text-decoration: underline;
}

/* R5: dark ink on the fixed amber notice (white was 2.24:1 — the one recurring
   contrast finding across every sweep). The banner is a fixed admin-notice
   surface, so a fixed dark ink is the correct pair. */
.public-page-gate-admin-banner {
    margin: 0 0 var(--space-4);
    padding: var(--space-3) var(--space-4);
    background-color: var(--color-amber, #d4a657);
    color: #2B2008;
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 500;
}

.public-page-gate-admin-banner strong {
    margin-right: var(--space-2);
}

.public-page-gate-admin-banner a {
    color: #2B2008;
    text-decoration: underline;
    margin-left: var(--space-2);
}

/* Admin press-photo CRUD list — used in the "Press photos" section
   of /admin/general. Each row: thumbnail + caption/order fields stack
   + delete button. */
.press-photos-admin-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.press-photos-admin-row {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
    padding: var(--space-3);
    background-color: var(--surface-deep);
    border: var(--border-thin);
    border-radius: var(--radius-md);
}

.press-photos-admin-thumb {
    width: 96px;
    height: 96px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    background-color: var(--surface-deep);
    flex-shrink: 0;
}

.press-photos-admin-fields {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
}

.press-photos-admin-fields .admin-field {
    margin: 0;
}

/* Press-kit asset rows reuse .press-photos-admin-row but show a filename +
   size instead of an image thumbnail. */
.press-asset-admin-fileinfo {
    width: 200px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    word-break: break-word;
}

/* Per-section "hidden from public" badge on the Press page (and any
   other page that gates content at the section level). Rendered only
   for admins; sits in the section's top-right corner. Subtler than the
   page-level admin banner — section gating is a maintenance affordance,
   not a frequent state worth shouting about. */
.press-section-hidden-badge {
    display: inline-block;
    float: right;
    padding: 1px 8px;
    border-radius: 999px;
    background-color: var(--color-amber, #d4a657);
    color: white;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    line-height: 1.6;
    margin-left: var(--space-2);
}

/* File inputs */
.admin-file-input {
    font-family: var(--font-body);
    font-size: var(--admin-text-help);
    color: var(--surface-page-text-muted);
    cursor: pointer;
    width: auto;
    padding: 0;
    background: none;
    border: none;
}

.admin-upload-status {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    font-style: italic;
}

/* Preview images */
.admin-preview {
    margin-top: var(--space-2);
}

.admin-preview-cover {
    width: 120px;
    height: 120px;
    border-radius: var(--radius-md);
    object-fit: cover;
    border: var(--border-thin);
}

/* ====================================================================
   Focal-point + zoom editor (used on /admin/members member photos).
   Click anywhere in the frame to set the focal point; the slider scales
   the image around that point. The frame mirrors the public site's
   3:4 portrait aspect so admins see ≈ what visitors will see.

   AI Note: the frame dimensions (240 × 320) are duplicated in the
   page's @code FocalFrameWidth / FocalFrameHeight constants — when
   editing here, update those too, or click→percent math drifts.
   ==================================================================== */
.admin-focal-block {
    display: flex;
    gap: var(--space-4);
    align-items: flex-start;
    margin-top: var(--space-2);
    flex-wrap: wrap;
}

.admin-focal-frame {
    position: relative;
    width: 240px;
    aspect-ratio: 3 / 4;     /* 240 × 320, matches FocalFrameHeight constant */
    overflow: hidden;
    border-radius: var(--radius-md);
    border: var(--border-thin);
    cursor: crosshair;
    background-color: rgba(0, 0, 0, 0.05);
    user-select: none;
    flex-shrink: 0;
}

.admin-focal-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: var(--focal-x) var(--focal-y);
    transform: scale(var(--focal-scale));
    transform-origin: var(--focal-x) var(--focal-y);
    transition: transform 0.12s ease-out;
    pointer-events: none;   /* clicks pass through to .admin-focal-frame */
    user-select: none;
}

.admin-focal-pin {
    position: absolute;
    left: var(--focal-x);
    top:  var(--focal-y);
    width: 14px;
    height: 14px;
    margin-left: -7px;
    margin-top:  -7px;
    border: 2px solid white;
    border-radius: 50%;
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.55), 0 0 6px rgba(0, 0, 0, 0.4);
    pointer-events: none;
}

.admin-focal-controls {
    flex: 1 1 220px;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.admin-focal-readout {
    font-size: var(--text-sm);
    color: var(--surface-raised-text-muted);
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.admin-focal-readout code {
    background-color: rgba(0, 0, 0, 0.05);
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 0.92em;
}

/* Range slider styling — relies on browser default thumb but adds enough
   chrome that the track is visible against the form background. */
.admin-range {
    -webkit-appearance: auto;   /* defeat the admin-input padding/border */
    appearance: auto;
    padding: 0;
    border: none;
    background: transparent;
    width: 100%;
}

/* =========================================================
   Admin → Visualizer — fullscreen-viz config + live preview
   ========================================================= */
.viz-admin-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
    gap: var(--space-5);
    align-items: start;
}

.viz-admin-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    min-width: 0;
}

.viz-admin-preview {
    position: sticky;
    top: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.viz-admin-preview-frame {
    aspect-ratio: 16 / 10;
    width: 100%;
    border-radius: var(--radius-md);
    overflow: hidden;
    background-color: rgb(8, 7, 6);   /* same near-black as the live overlay */
    border: var(--border-thin);
}

.viz-admin-preview-canvas {
    display: block;
    width: 100%;
    height: 100%;
}

.viz-scene-actions { margin: 0; }

.viz-scene-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
    gap: var(--space-2);
}

.viz-scene-chip {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--admin-pad-y) var(--admin-pad-x);
    border: var(--border-thin);
    border-radius: var(--admin-radius);
    background-color: var(--color-cream-deep);
    font-size: var(--admin-text-control);
    color: var(--color-charcoal);
    cursor: pointer;
    user-select: none;
}

.viz-scene-chip input[type="checkbox"] {
    accent-color: var(--color-accent);
    flex-shrink: 0;
    cursor: pointer;
    background: initial;
    appearance: auto;
    -webkit-appearance: auto;
}

.viz-scene-chip-on {
    border-color: var(--color-accent);
    background-color: var(--color-accent-dim);
}

/* Advanced collapsible — match the fieldset, summary reads like a legend */
.viz-admin-advanced > summary {
    font-weight: 700;
    cursor: pointer;
    letter-spacing: 0.04em;
}

@media (max-width: 860px) {
    .viz-admin-layout { grid-template-columns: 1fr; }
    .viz-admin-preview {
        position: static;
        order: -1;   /* preview on top on narrow screens */
    }
}

/* Child row / nested detail within detail panel */
/* DSP-link repeater rows (track- + release-level): shared grid tracks so icon | platform | url |
   remove line up down the list (was per-row flex, which misaligned when platform/URL lengths varied). */
.admin-child-row {
    display: grid;
    grid-template-columns: auto 10rem minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) 0;
    border-bottom: var(--border-thin);
}

.admin-child-row:last-child {
    border-bottom: none;
}

.admin-child-detail {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
    flex: 1;
}

/* -------------------------------------------------------------------------
 * Release track composite rows (Part D — KB Rich List Item)
 * A scannable card per track: drag handle + ▲▼ reorder, derived position,
 * primary title, duration (m:ss), an at-a-glance audio-source status chip,
 * and an expand-to-detail disclosure for the grouped "more fields".
 * ------------------------------------------------------------------------- */

.admin-field-hint {
    margin: 0 0 var(--space-2);
    font-size: var(--admin-text-help);
    color: var(--surface-page-text-muted);
}

.release-track-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.release-track {
    border: var(--border-thin);
    border-radius: var(--admin-radius);
    /* Raised-surface tone so the cream-deep .admin-input fills read as editable insets (affordance),
       instead of camouflaging into a same-colored card. */
    background: var(--surface-raised);
}

.release-track.is-dragging {
    opacity: 0.5;
}

/* Keyboard-reorder selection: the row whose handle is focused/selected, so the user sees which track the
   arrow keys will move. An accent left-bar + tint (not color alone) marks it. */
.release-track.is-selected {
    box-shadow: inset 3px 0 0 0 var(--color-accent);
    background: var(--color-accent-dim);
}

/* Fixed-track grid (not per-row flex) so every row's cells land on the SAME columns — LENGTH, status,
   and the actions align vertically down the list (scannable-grid). Only the title flexes (1fr); the
   side columns are fixed, so all rows resolve identical tracks. */
.release-track-head {
    display: grid;
    grid-template-columns: 2rem 1.5rem minmax(0, 1fr) 5rem 12rem auto;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
}

@media (max-width: 720px) {
    .release-track-head {
        display: flex;
        flex-wrap: wrap;
    }
}

/* Reorder: a single grab handle — mouse drag AND keyboard (focus it, then ↑/↓). */
.release-track-reorder {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
}

.release-track-handle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 24px;
    min-height: 24px;
    padding: 0;
    border: none;
    background: none;
    color: var(--color-charcoal-mid);
    border-radius: var(--radius-sm);
    cursor: grab;
}

.release-track-handle:active {
    cursor: grabbing;
}

.release-track-handle:hover {
    color: var(--color-accent);
}

.release-track-handle:focus-visible {
    outline: none;
    color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-dim);
}

.release-track-num {
    flex: 0 0 auto;
    min-width: 1.4em;
    text-align: right;
    font-variant-numeric: tabular-nums;
    /* Subordinate to the title (was 600/charcoal-mid, competing as a second focal point). */
    font-weight: 500;
    color: var(--surface-page-text-muted);
}

/* Primary field — fills the flexible 1fr track */
.release-track-title {
    min-width: 0;
}

.release-track-duration {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.release-track-mini-label {
    font-size: var(--admin-text-help);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--surface-page-text-muted);
}

.release-track-duration-input {
    width: 4.5rem;
    text-align: center;
}

/* At-a-glance status chip — icon + label (never color-alone), AND the button that opens the audio-source
   editor. Sits in a fixed 12rem grid track and ellipses within it, so the length column before it and the
   actions after it stay aligned across rows. */
.release-track-status {
    justify-self: start;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    max-width: 100%;
    padding: 2px var(--space-2);
    border: var(--border-thin);
    border-radius: var(--radius-pill, 999px);
    font-family: inherit;
    font-size: var(--admin-text-help);
    font-weight: 500;   /* signal, not a competing headline — lighter than the title */
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    cursor: pointer;   /* it's a button — signify it's actionable */
    transition: filter var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.release-track-status:hover {
    filter: brightness(0.96);
}

.release-track-status:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--color-accent-dim);
}

.release-track-status-label {
    overflow: hidden;
    text-overflow: ellipsis;
}

.release-track-status-icon {
    flex: 0 0 auto;
}

/* Playable (own upload or linked mix) → positive; no audio → attention */
.release-track-status-ok,
.release-track-status-linked {
    background: #ECFDF5;
    /* mid-green border clears the 3:1 non-text floor on the cream card (#6EE7B7 was ~1.4:1). */
    border-color: var(--alert-success-border-strong);
    color: var(--alert-success-text-strong);
}

.release-track-status-warn {
    background: #FEF3C7;
    /* mid-amber border clears 3:1 (#FCD34D was ~1.4:1). */
    border-color: var(--color-warning);
    color: var(--color-warning-deep);
}

.release-track-actions {
    justify-self: end;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.release-track-expand {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    min-height: var(--admin-control-h);
    padding: var(--admin-pad-y) var(--space-2);
    font-family: var(--font-body);
    font-size: var(--admin-text-help);
    font-weight: 600;
    border: var(--border-thin);
    border-radius: var(--admin-radius);
    background: var(--surface-page);
    color: var(--surface-page-text-muted);
    cursor: pointer;
}

.release-track-expand:hover {
    border-color: var(--color-accent);
    color: var(--color-accent);
}

/* Detail disclosure — a real two aligned columns (not ragged auto-fit): both columns share a top edge
   and a consistent field rhythm, so the panel reads as an aligned label/value grid. */
.release-track-detail {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: start;
    gap: var(--space-4) var(--space-6);
    padding: var(--space-4);
    border-top: var(--border-thin);
}

@media (max-width: 640px) {
    .release-track-detail {
        grid-template-columns: 1fr;
    }
}

.release-track-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
}

/* Inside the raised track card the inputs need a visible boundary — a white fill + border reads as an
   editable field rather than blending into the panel (affordance/signifier). */
.release-track-detail .admin-input,
.release-track-head .admin-input {
    background-color: var(--surface-raised);
}

.release-track-group-title {
    margin: 0 0 var(--space-1);
    font-size: var(--admin-text-help);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-accent);
}

@media (max-width: 640px) {
    .release-track-head {
        flex-wrap: wrap;
    }
    .release-track-actions {
        margin-left: 0;
    }
}

/* Status messages */
.admin-message {
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 500;
    border: var(--border-thin);
}

.admin-message-ok {
    background-color: var(--alert-success-bg-strong);
    color: var(--alert-success-text-strong);
    /* mid-green / mid-red borders clear the 3:1 non-text floor (were the same weak pastels as the chips). */
    border-color: var(--alert-success-border-strong);
}

.admin-message-error {
    background-color: var(--alert-danger-bg-strong);
    color: var(--color-danger);
    border-color: var(--alert-danger-border-strong);
}

/* --- Action buttons --- */

.admin-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    padding-top: var(--space-4);
    border-top: var(--border-thin);
    align-items: center;
}

.admin-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: var(--admin-control-h);
    padding: var(--admin-pad-y) var(--admin-pad-x);
    font-family: var(--font-body);
    font-size: var(--admin-text-control);
    font-weight: 600;
    line-height: 1.2;
    border: var(--border-thin);
    border-radius: var(--admin-radius);
    cursor: pointer;
    background-color: var(--surface-deep);
    color: var(--surface-deep-text-muted);
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
    width: auto;
}

.admin-button:hover {
    background-color: var(--surface-deep);
    color: var(--surface-deep-text);
}

.admin-button-primary {
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    border-color: transparent;
}

.admin-button-primary:hover {
    background-color: var(--color-accent);
    color: var(--color-white);
    border-color: transparent;
}

.admin-button-danger {
    background-color: transparent;
    color: var(--alert-danger-rule);
    /* #DC2626 clears the 3:1 non-text-contrast floor on the page background; #FCA5A5 was ~2.8:1. */
    border-color: var(--alert-danger-border-strong);
}

/* Reserved status-message region (Releases editor) — always present + a stable live region, so a save/
   error message appearing or clearing doesn't shift the action buttons and AT announces it. */
.admin-message-region {
    min-height: 2.75rem;
}

.admin-button-danger:hover {
    background-color: var(--alert-danger-bg-strong);
    border-color: var(--alert-danger-rule);
}

.admin-button-confirm {
    background-color: var(--alert-danger-solid);
    color: #fff;
    border-color: transparent;
}

.admin-button-confirm:hover {
    background-color: var(--color-danger);
    border-color: transparent;
}

.admin-button-small {
    /* BL-028 / FLG-CMP-ADMIN-3-02 — was min-height:0 + 2px pad → rendered ~19px, below the
       24px WCAG 2.5.8 target floor. Hold the admin control-height floor (ACC-008 accepts admin
       px sizing but the target floor is universal). Font stays label-sized for density. */
    min-height: 24px;
    padding: 2px var(--admin-pad-x);
    font-size: var(--admin-text-label);
}

/* Responsive: collapse admin layout to single column */
@media (max-width: 880px) {
    .admin-layout {
        grid-template-columns: 1fr;
    }

    .admin-list {
        max-height: 280px;
        overflow-y: auto;
    }
}


/* =========================================================
   26. IDENTITY PAGES (Login, Register, Manage, etc.)
   ========================================================= */

/*
 * The Identity pages are mostly ASP.NET Identity-scaffolded Razor pages.
 * They use: .identity-page-container, .manage-container, .manage-sidebar,
 *   .manage-nav-link, .manage-content-area, .manage-sectioned-container,
 *   .manage-header, .login-links-row, .login-text-row, .form-check,
 *   .passkey-list, .passkey-item, .passkey-name, .recovery-code-grid,
 *   .recovery-code, .alert-box, .alert-danger, .alert-success, .alert-info,
 *   .text-danger, .text-error, .text-info, .step-header, .step-instruction,
 *   .qr-box, .two-factor-auth-button-group, .register-confirmation-message-container
 *
 * M5 (U3): these pages joined the theme + layout systems. Every color-bearing
 * prop is a SEMANTIC surface token (--surface-page/-raised/-deep + their -text/
 * -text-muted pairs, --surface-border, and --color-accent-text for accent-as-text)
 * — NEVER a charcoal, cream, or accent primitive, which was why Identity
 * was excluded (it froze to Light and clashed under Dark/Marquee). The auth form
 * reads as a width-capped column centered on the page frame; Manage is a two-pane
 * card. Forms just need clarity — no editorial display treatment.
 *
 * AI Note: [Constraint] never write the literal sequence star-slash inside a CSS
 * comment (e.g. shorthand like "charcoal*" followed by "/cream*") — it TERMINATES
 * the comment early and the parser then swallows the NEXT rule as an invalid
 * selector prelude. That exact bug shipped in M5: this comment originally
 * contained that shorthand, which silently killed the .identity-page-container
 * rule below (login rendered flush-left with no frame while the rule sat
 * healthy-looking in the file).
 */

/* --- Page containers --- */

/* Auth pages (Login/Register/Forgot/…) — a centered auth card (KB auth-message-
   page-stack). Width-capped to the prose measure so the local + social sections
   stack into one readable column rather than sprawling to the full page width; the
   natural-height column sits on the surface-page canvas so it follows the active
   theme. Uses the M2 frame tokens (prose measure + nonzero gutter) — never a raw
   max-width — so it stays consistent with every other framed surface. */
.identity-page-container {
    display: flex;
    background-color: transparent;
    justify-content: center;
    padding: var(--space-6) var(--frame-gutter);
    margin: 0 auto;
    gap: var(--space-7);
    width: 100%;
    max-width: var(--frame-prose-measure);
    flex-wrap: wrap;
    align-items: flex-start;
}

/* Manage account layout — sidebar nav + content, framed as a two-pane card. */
.manage-container {
    padding: var(--space-5) var(--frame-gutter);
    margin: 0 auto;
    display: grid;
    grid-template-columns: 220px 1fr;
    gap: var(--space-7);
    width: 100%;
    max-width: var(--frame-max-width);
    align-items: start;
}

.manage-sidebar {
    padding-right: var(--space-4);
}

.manage-header {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--surface-page-text);
    margin-bottom: var(--space-4);
    font-variation-settings: 'WONK' 0;
}

.manage-nav-link {
    display: block;
    padding: var(--space-3) var(--space-4);
    text-decoration: none;
    color: var(--surface-page-text-muted);
    border-left: 3px solid transparent;
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}

.manage-nav-link:hover {
    background-color: var(--surface-deep);
    color: var(--surface-deep-text);
}

/* Active nav row: the recessed surface-deep tile carries the accent left-rule +
   accent-as-text label. --color-accent-text is the contrast-guaranteed accent for
   TEXT (the raw --color-accent on --color-accent-dim was amber-on-amber-tint 1.32
   — the M5 sweep miss). surface-deep-text label stays legible on the tint. */
.manage-nav-link.active {
    border-left-color: var(--color-accent);
    color: var(--color-accent-text);
    font-weight: 600;
    background-color: var(--surface-deep);
}

.manage-sectioned-container {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.manage-content-area {
    padding: 0;
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

.manage-content-area > .form-group,
.manage-content-area > div {
    width: 100%;
}

/* The .manage-content-area gap only spaces its DIRECT children; the label/input groups and buttons live
   INSIDE the <form>, which had no spacing (owner: "no margin between successive groups or buttons"). Make
   the Identity manage forms flex-column with a gap; buttons keep their natural width. */
.manage-content-area form {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}
.manage-content-area form > button,
.manage-content-area form button[type="submit"],
.manage-content-area form .btn-primary,
.manage-content-area form .btn-delete {
    align-self: flex-start;
}

/* --- Form check (checkbox row for identity forms) --- */

.form-check {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-3) 0;
}

.form-check input[type="checkbox"],
.form-check input[type="radio"] {
    width: auto;
    padding: 0;
    border: initial;
    background: initial;
    appearance: auto;
    -webkit-appearance: auto;
    accent-color: var(--color-accent);
    cursor: pointer;
}

.form-check label {
    margin-bottom: 0;
    cursor: pointer;
    font-size: var(--text-sm);
    text-transform: none;
    letter-spacing: 0;
    opacity: 1;
    color: var(--surface-page-text-muted);
}

/* --- Login links row --- */

.login-links-row {
    display: flex;
    gap: var(--space-5);
    align-items: center;
    justify-content: center;
    margin-top: var(--space-5);
    font-size: var(--text-sm);
}

.login-text-row {
    text-align: center;
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    white-space: nowrap;
}

/* Accent LINK text → --color-accent-text (the contrast-guaranteed accent for text;
   raw --color-accent is 4.05 on the page canvas — the M5 "Forgot Password?" miss). */
.login-links-row a,
.login-text-row a {
    color: var(--color-accent-text);
    text-decoration: none;
    font-weight: 600;
    transition: color var(--duration-fast) var(--ease-out);
}

.login-text-row a {
    margin-left: var(--space-2);
}

.login-links-row a:hover,
.login-text-row a:hover {
    color: var(--color-accent);
    text-decoration: underline;
}

/* --- Alert boxes --- */

.alert-box {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4);
    border: 1px solid transparent;
    border-left: 4px solid;
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    max-width: 480px;
    width: 100%;
}

.alert-box-heading {
    font-weight: 700;
    margin-bottom: var(--space-1);
}

.alert-danger {
    background-color: var(--alert-danger-bg);
    color: var(--alert-danger-text);
    border-color: var(--alert-danger-border);
    border-left-color: var(--alert-danger-rule);
}

.alert-success {
    background-color: var(--alert-success-bg);
    color: var(--alert-success-text);
    border-color: var(--alert-success-border);
    border-left-color: var(--alert-success-rule);
}

.alert-info {
    background-color: var(--alert-info-bg);
    color: var(--alert-info-text);
    border-color: var(--alert-info-border);
    border-left-color: var(--alert-info-rule);
}

.text-danger,
.text-error {
    color: var(--alert-danger-rule);
    font-size: var(--text-sm);
}

.text-info {
    color: var(--surface-page-text-muted);
    font-size: var(--text-sm);
}

/* --- Passkey list --- */

.passkey-list {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.passkey-item {
    width: 100%;
    display: grid;
    grid-template-columns: 1fr auto;
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md);
    background: var(--surface-deep);
    color: var(--surface-deep-text);
    gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    align-items: center;
}

.passkey-item button {
    padding: var(--space-2) var(--space-3);
    width: auto;
}

.passkey-name {
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--surface-deep-text);
}

/* --- Recovery codes grid --- */

.recovery-code-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    justify-items: center;
    background: var(--surface-deep);
    border: 1px dashed var(--surface-border);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    gap: var(--space-4);
    padding: var(--space-4);
    max-width: 420px;
}

.recovery-code {
    font-size: var(--text-base);
    color: var(--surface-deep-text);
    font-weight: 600;
}

/* --- Email confirmed --- */

.email-confirmed-group {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

/* --- Registration confirmation --- */

.register-confirmation-message-container {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-3);
}

/* --- 2FA / TOTP steps --- */

.step-header {
    font-family: var(--font-display);
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--surface-page-text);
    border-bottom: 1px solid var(--surface-border);
    padding-bottom: var(--space-3);
    margin-bottom: var(--space-3);
    font-variation-settings: 'WONK' 0;
}

.step-instruction {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    line-height: var(--leading-relaxed);
    margin-bottom: var(--space-4);
}

.qr-box {
    background-color: var(--surface-raised);   /* BL-016: was #fff (QR needs a true-white quiet zone) */
    padding: 16px;
    width: 176px;
    height: 176px;
    border-radius: var(--radius-sm);
    display: flex;
    justify-content: center;
    align-items: center;
    border: var(--border-thin);
}

.two-factor-auth-button-group {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
}

/* --- Section separator --- */

.section-separator {
    border: none;
    border-top: 1px solid var(--surface-border);
    margin: var(--space-6) 0;
    width: 100%;
}

/* --- kbd element --- */

kbd {
    background-color: var(--surface-deep);
    padding: 2px var(--space-2);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    color: var(--surface-deep-text);
    border: 1px solid var(--surface-border);
    font-size: var(--text-xs);
}

/* Responsive: identity pages stack on mobile */
@media (max-width: 640px) {
    .manage-container {
        grid-template-columns: 1fr;
        padding: var(--space-4) var(--space-4);
    }

    .manage-sidebar {
        padding-right: 0;
        padding-bottom: var(--space-4);
        border-bottom: 1px solid var(--surface-border);
    }
}


/* =========================================================
   27. INLINE EDIT DIALOG (Admin only)
   Native <dialog> element — z-index 2000 (System Overlays tier)
   ========================================================= */

/*
 * Classes: .inline-edit-dialog, .inline-edit-form, .inline-edit-title,
 *          .inline-edit-toolbar, .inline-edit-toolbar-btn,
 *          .inline-edit-toolbar-btn-italic, .inline-edit-toolbar-btn-code,
 *          .inline-edit-toolbar-spacer, .inline-edit-toolbar-hint,
 *          .inline-edit-textarea, .inline-edit-hint, .inline-edit-error,
 *          .inline-edit-actions, .inline-edit-btn, .inline-edit-btn-cancel,
 *          .inline-edit-btn-save
 *
 * Invoked by clicking an editable-content field (admin role).
 * Uses native <dialog> so Esc-to-close and focus-trap come for free.
 */

/* Native <dialog> element reset — browser adds a border by default */
.inline-edit-dialog[open] {
    display: flex;
    flex-direction: column;
}

.inline-edit-dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 2000;
    background-color: var(--surface-raised);
    color: var(--surface-raised-text);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    width: min(90vw, 600px);
    max-height: 85dvh;
    overflow: hidden;
    padding: 0;
    margin: 0;
}

/* ::backdrop is the native dialog backdrop */
.inline-edit-dialog::backdrop {
    background-color: var(--scrim);   /* BL-016: was rgba(28,26,23,0.55) */
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}

.inline-edit-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-5);
    overflow-y: auto;
    flex: 1;
}

.inline-edit-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--surface-page-text);
    margin: 0 0 var(--space-2);
    font-variation-settings: 'WONK' 0;
}

/* Markdown toolbar — shown only for Markdown content types */
.inline-edit-toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex-wrap: wrap;
    padding: var(--space-2) 0;
    border-bottom: var(--border-thin);
}

.inline-edit-toolbar[hidden] {
    display: none;
}

.inline-edit-toolbar-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-1) var(--space-3);
    background: none;
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
    width: auto;
}

.inline-edit-toolbar-btn:hover {
    background-color: var(--surface-deep);
    color: var(--surface-deep-text);
}

.inline-edit-toolbar-btn-italic {
    font-style: italic;
}

.inline-edit-toolbar-btn-code {
    font-size: var(--text-xs);
}

.inline-edit-toolbar-spacer {
    flex: 1;
}

.inline-edit-toolbar-hint {
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
}

/* Textarea */
.inline-edit-textarea {
    width: 100%;
    min-height: 140px;
    padding: var(--space-3) var(--space-4);
    background-color: var(--surface-deep);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-base);
    color: var(--surface-deep-text);
    line-height: var(--leading-relaxed);
    resize: vertical;
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.inline-edit-textarea:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-dim);
    background-color: var(--surface-raised);
}

.inline-edit-hint {
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
    margin-top: calc(-1 * var(--space-2));
}

.inline-edit-error {
    font-size: var(--text-sm);
    color: var(--alert-danger-rule);          /* BL-016/BL-075: was #B91C1C */
    padding: var(--space-3) var(--space-4);
    background-color: var(--alert-danger-bg);  /* was #FEE2E2 */
    border-radius: var(--radius-sm);
    border: 1px solid var(--alert-danger-border); /* was #FCA5A5 */
}

.inline-edit-error[hidden] {
    display: none;
}

/* Action buttons row */
.inline-edit-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-3);
    padding-top: var(--space-3);
    border-top: var(--border-thin);
}

.inline-edit-btn {
    display: inline-flex;
    align-items: center;
    padding: var(--space-3) var(--space-5);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out);
    width: auto;
}

.inline-edit-btn-cancel {
    background-color: transparent;
    color: var(--surface-page-text-muted);
    border: var(--border-thin);
}

.inline-edit-btn-cancel:hover {
    background-color: var(--surface-deep);
    color: var(--surface-deep-text);
}

.inline-edit-btn-save {
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    border: none;
}

.inline-edit-btn-save:hover {
    background-color: var(--color-accent);
    color: var(--color-white);
}


/* =========================================================
   28. LEGACY / COMPATIBILITY UTILITIES
   Classes from app.css.old that are still in use
   ========================================================= */

/*
 * These classes are still referenced in active components.
 * They get the editorial skin treatment (cream/charcoal) rather
 * than the old dark theme, but the class names are preserved
 * for compatibility.
 */

/* .disabled utility — used in several band portal components */
.disabled {
    opacity: 0.45 !important;
    pointer-events: none !important;
    cursor: not-allowed !important;
}

/* .hidden utility */
.hidden {
    display: none !important;
}

/* Utility classes */
.u-flex          { display: flex; }
.u-flex-col      { display: flex; flex-direction: column; }
.u-flex-row      { display: flex; flex-direction: row; }
.u-flex-wrap     { flex-wrap: wrap; }
.u-justify-center  { justify-content: center; }
.u-justify-between { justify-content: space-between; }
.u-justify-end     { justify-content: flex-end; }
.u-align-center    { align-items: center; }
.u-align-start     { align-items: flex-start; }
.u-align-end       { align-items: flex-end; }
.u-text-center     { text-align: center; }
.u-text-right      { text-align: right; }
.u-text-muted      { opacity: 0.65; }

.u-mb-sm  { margin-bottom: 0.25rem; }
.u-mb-md  { margin-bottom: 0.5rem; }
.u-mb-lg  { margin-bottom: 1rem; }
.u-mb-xl  { margin-bottom: 1.5rem; }
.u-mt-sm  { margin-top: 0.25rem; }
.u-mt-md  { margin-top: 0.5rem; }
.u-mt-lg  { margin-top: 1rem; }
.u-mt-xl  { margin-top: 1.5rem; }
.u-ml-sm  { margin-left: 0.25rem; }
.u-ml-md  { margin-left: 0.5rem; }
.u-ml-lg  { margin-left: 1rem; }
.u-mr-sm  { margin-right: 0.25rem; }
.u-mr-md  { margin-right: 0.5rem; }
.u-mr-lg  { margin-right: 1rem; }
.u-gap-sm { gap: 0.25rem; }
.u-gap-md { gap: 0.5rem; }
.u-gap-lg { gap: 1rem; }
.u-w-full { width: 100%; }
.u-h-full { height: 100%; }
.u-hidden        { display: none !important; }
.u-inline-block  { display: inline-block; }
.u-truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.u-row {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: flex-start;
}

/* Legacy button shape for band portal — reuses btn-primary above */
.btn-delete {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-5);
    background-color: var(--color-warning);
    color: #fff;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    width: auto;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.btn-delete:hover {
    background-color: var(--color-warning-deep);
}

.btn-delete-confirm {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-5);
    background-color: var(--alert-danger-solid);
    color: #fff;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    width: auto;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.btn-delete-confirm:hover {
    background-color: var(--color-danger);
}

/* Empty layout bar (popout pages: LyricView, SongHistoryView, etc.) */
.empty-layout-bar {
    padding: var(--space-3) var(--page-gutter);
    background-color: var(--color-cream);
    border-bottom: var(--border-thin);
    display: flex;
    align-items: center;
}

.empty-layout-home {
    display: inline-flex;
    align-items: center;
    line-height: 0;
}

.empty-layout-home img {
    height: 24px;
    width: auto;
}

/* Spacer utilities */
.spacer-y {
    margin-top: var(--space-5);
}

/* Print: hide chrome, show content */
@media print {
    .main-layout-header,
    .main-layout-footer,
    .main-layout-newsletter,
    .player-bar,
    .notification-bar,
    .site-nav-toggle-btn,
    .main-layout-header-booking,
    .splash-overlay {
        display: none !important;
    }

    .main-layout-body {
        overflow: visible !important;
    }

    body {
        background-color: #fff !important;
        color: #000 !important;
    }
}

/* Reduced motion: disable all animations */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ==========================================================================
   SECTION 29 — CONVERSATION + COMMENT CONTROLS
   Controls: Conversation.razor, CommentControl.razor
   Used inside the band portal song/playlist detail modals (.am-body.conversation-mode).
   ========================================================================== */

/* Outer container — fills the .am-body area */
.conversation-container {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

/* Scrollable message list */
.conversation-list {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: var(--space-3) var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* Sticky footer: reply banner + textarea + send */
.conversation-footer {
    flex: 0 0 auto;
    border-top: var(--border-thin);
    padding: var(--space-3) var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    background-color: var(--surface-card);
}

/* "Replying to X" banner */
.replying-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    background-color: var(--color-cream);
    border-left: 3px solid var(--color-amber);
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

/* Textarea for composing a message */
.conversation-input {
    width: 100%;
    min-height: 72px;
    padding: var(--space-2);
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    font: var(--text-sm)/1.5 var(--font-body);
    color: var(--text-primary);
    background-color: var(--surface-page);
    resize: vertical;
}

.conversation-input:focus {
    outline: none;
    border-color: var(--color-amber);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-amber) 20%, transparent);
}

/* Send button row */
.conversation-actions {
    display: flex;
    justify-content: flex-end;
}

/* Individual comment bubble */
.comment-bubble {
    background-color: var(--surface-card);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* "Replying to …" context bar inside a bubble */
.reply-context-bar {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    background-color: var(--color-cream);
    border-left: 3px solid var(--color-charcoal);
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
    color: var(--text-secondary);
    cursor: pointer;
    margin-bottom: var(--space-1);
}

.reply-line-indicator {
    width: 2px;
    align-self: stretch;
    background-color: var(--text-muted);
    border-radius: 1px;
    flex-shrink: 0;
}

.reply-content {
    flex: 1;
}

.reply-author {
    font-weight: 600;
    color: var(--text-primary);
}

.reply-icon {
    margin-right: var(--space-1);
}

.reply-preview {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.reply-full-text {
    white-space: pre-wrap;
}

/* Comment meta row */
.comment-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}

.comment-info {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
}

.comment-author {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-primary);
}

.comment-date {
    font-size: var(--text-xs);
    color: var(--text-muted);
}

/* Comment body text */
.comment-text {
    font-size: var(--text-sm);
    color: var(--text-primary);
    white-space: pre-wrap;
    line-height: 1.5;
}

/* Tiny icon button (reply arrow, dismiss) */
.btn-icon-small {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border: none;
    background: transparent;
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    font-size: 13px;
    cursor: pointer;
    flex-shrink: 0;
    transition: background-color var(--transition-fast), color var(--transition-fast);
}

.btn-icon-small:hover {
    background-color: var(--color-cream);
    color: var(--text-primary);
}

/* ==========================================================================
   SECTION 30 — USER MANAGEMENT ADMIN PAGE
   Admin/UserManagement.razor — legacy vocabulary that predates .admin-page
   ========================================================================== */

/* Responsive data table */
.user-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}

.user-table th {
    text-align: left;
    padding: var(--space-2) var(--space-3);
    border-bottom: 2px solid var(--border-color);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    white-space: nowrap;
}

.user-table td {
    padding: var(--space-2) var(--space-3);
    border-bottom: var(--border-thin);
    color: var(--text-primary);
    vertical-align: middle;
}

.user-table tr:hover td {
    background-color: var(--surface-page);
}

/* Clickable ID pill that opens the user edit card */
.id-link {
    color: var(--color-amber);
    cursor: pointer;
    font-weight: 500;
    text-decoration: underline;
    text-decoration-color: transparent;
    transition: text-decoration-color var(--transition-fast);
}

.id-link:hover {
    text-decoration-color: var(--color-amber);
}

/* Modal backdrop — used in UserManagement for the edit card overlay */
/* AI Note: .app-modal-backdrop (SongPortal/PlaylistPortal) is in Section 22.
   .modal-backdrop here is UserManagement.razor's own pattern; same behavior. */
.modal-backdrop {
    position: fixed;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.45);
    z-index: var(--z-modal);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
}

/* 2-column grid for paired form fields */
.grid-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
    align-items: start;
}

/* Contact grid: input + checkbox toggle inline */
.grid-contact {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--space-3);
    align-items: end;
    margin-bottom: var(--space-2);
}

/* Inline checkbox + label toggle */
.toggle-box {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--text-primary);
    cursor: pointer;
    user-select: none;
    padding: var(--space-2) var(--space-2);
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    background-color: var(--surface-card);
    white-space: nowrap;
}

.toggle-box:hover {
    background-color: var(--color-cream);
}

.toggle-box input[type="checkbox"] {
    accent-color: var(--color-amber);
    width: 15px;
    height: 15px;
    cursor: pointer;
}

/* Role checkboxes grid */
.roles-grid-compact {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-1);
}

.role-item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-sm);
    cursor: pointer;
    user-select: none;
}

.role-item input[type="checkbox"] {
    accent-color: var(--color-amber);
}

/* Section title inside edit-section */
.edit-section-title {
    display: block;
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    font-weight: 600;
    margin-bottom: var(--space-2);
}

/* Save/Cancel button row at the bottom of an edit card */
.action-buttons {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: var(--border-thin);
}

/* Secondary button — cancel/close actions */
.btn-secondary {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    background-color: transparent;
    color: var(--text-secondary);
    font-size: var(--text-sm);
    font-weight: 500;
    cursor: pointer;
    text-decoration: none;
    transition: background-color var(--transition-fast), border-color var(--transition-fast);
}

.btn-secondary:hover {
    background-color: var(--color-cream);
    border-color: var(--color-charcoal);
    color: var(--text-primary);
}

/* BL-052 / FLG-PG-ADMIN-SERVER-1-04 — the legacy .btn-secondary (server-rendered Storefront /
   UserManagement admin pages: Edit / View / Delete / Cancel) had NO focus indicator, so keyboard
   focus was invisible. Add the standard accent focus ring. (The broader migration of these pages
   off the legacy .admin-container/.form-group vocabulary is a separate .razor effort.) */
.btn-secondary:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Small button variant (compact height) */
.btn-small {
    padding: var(--space-1) var(--space-2);
    font-size: var(--text-xs);
    line-height: 1.4;
}

/* ==========================================================================
   SECTION 31 — ACTIVITY DETAIL MODAL EXTENSIONS
   DashboardComponents/ActivityDetailModal.razor
   Extends the base .am-* vocabulary (backdrop/dialog/header/body) in Section 22
   with the content-specific sub-components.
   ========================================================================== */

/* Title + subtitle group in the modal header */
.am-title-group {
    flex: 1;
    min-width: 0;
}

.am-subtitle {
    font-size: var(--text-xs);
    color: var(--text-muted);
    margin-top: 2px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Content box — wraps either a comment view, diff view, or kv view */
.am-content-box {
    padding: var(--space-3) var(--space-4);
    background-color: var(--surface-page);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-3);
}

/* --- Comment view --- */
.am-comment-display {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
}

.am-comment-icon {
    flex-shrink: 0;
    color: var(--text-muted);
    margin-top: 2px;
}

.am-comment-text {
    font-style: italic;
    color: var(--text-primary);
    margin-top: var(--space-1);
    line-height: 1.5;
}

/* --- Diff view --- */
.am-diff-grid {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.am-diff-row {
    display: grid;
    grid-template-columns: 120px 1fr auto 1fr;
    gap: var(--space-2);
    align-items: baseline;
    font-size: var(--text-sm);
}

.am-diff-label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    font-weight: 600;
}

.am-diff-old {
    color: var(--alert-danger-rule);
    text-decoration: line-through;
    overflow-wrap: anywhere;
}

.am-diff-new {
    color: var(--alert-success-solid);
    overflow-wrap: anywhere;
}

.am-diff-arrow {
    color: var(--text-muted);
    flex-shrink: 0;
}

/* --- Key-value list view --- */
.am-kv-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.am-kv-item {
    display: grid;
    grid-template-columns: 120px 1fr;
    gap: var(--space-2);
    font-size: var(--text-sm);
}

.am-kv-item label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    font-weight: 600;
}

/* Long-field notes block */
.am-notes-block {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: var(--border-thin);
}

.am-notes-label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    font-weight: 600;
    display: block;
    margin-bottom: var(--space-1);
}

.am-notes-text {
    font-size: var(--text-sm);
    color: var(--text-primary);
    white-space: pre-wrap;
    line-height: 1.5;
}

/* Quick reply section */
.am-reply-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.am-reply-section > label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    font-weight: 600;
}

/* Textarea inside the modal */
.am-input {
    width: 100%;
    padding: var(--space-2);
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    font: var(--text-sm)/1.5 var(--font-body);
    color: var(--text-primary);
    background-color: var(--surface-page);
    resize: vertical;
}

.am-input:focus {
    outline: none;
    border-color: var(--color-amber);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-amber) 20%, transparent);
}

/* Action row: Open Full Page + Post Comment */
.am-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-1);
}

.am-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    font-weight: 500;
    cursor: pointer;
    border: var(--border-thin);
    transition: background-color var(--transition-fast), color var(--transition-fast);
    text-decoration: none;
}

.am-btn-primary {
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    border-color: var(--color-charcoal);
}

.am-btn-primary:hover:not(:disabled) {
    background-color: var(--color-amber);
    border-color: var(--color-amber);
    color: var(--surface-page-text);
}

.am-btn-secondary {
    background-color: transparent;
    color: var(--text-secondary);
    border-color: var(--border-color);
}

.am-btn-secondary:hover {
    background-color: var(--surface-page);
    color: var(--text-primary);
}

.am-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* ==========================================================================
   SECTION 32 — DASHBOARD SUMMARY CARD INTERNALS
   DashboardSongSummary.razor, DashboardPlaylistSummary.razor,
   DashboardToDoSummary.razor, DashboardActivityFeed.razor,
   DashboardReplyList.razor
   ========================================================================== */

/* Scrollable content area inside a dashboard card */
.dashboard-content {
    overflow-y: auto;
    flex: 1 1 auto;
}

/* Full dashboard lists (songs/playlists show ALL rows, no pager) scroll within the tile so it doesn't grow
   unbounded; the sortable grid header sits above this wrapper and stays put while the rows scroll. */
.dashboard-list-scroll {
    max-height: 60vh;
    overflow-y: auto;
}

/* ===========================================================================
   Fan Favorites widget (DashboardSongPopularity) — public-play popularity.
   Composite rows on a SHARED grid (scannable): rank · identity · metric bar · trend.
   Song name is the one primary focal point per row; metrics + region strip are
   subordinate (smaller, --text-muted); the momentum callout is the single hero.
   =========================================================================== */
.pop-period-tabs { display: inline-flex; gap: 2px; }
.pop-period-tab {
    border: var(--border-thin) solid var(--color-border);
    background: transparent;
    color: var(--text-muted);
    font-size: 0.78rem;
    line-height: 1;
    padding: var(--space-1) var(--space-2);
    cursor: pointer;
}
.pop-period-tab:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.pop-period-tab:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.pop-period-tab + .pop-period-tab { border-left: none; }
.pop-period-tab.active {
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: #fff;
}

.pop-empty { color: var(--text-muted); padding: var(--space-3); text-align: center; }

/* The single emphasized element (emphasis budget). */
.pop-momentum {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    border-left: 3px solid var(--color-accent);
    background: color-mix(in srgb, var(--color-accent) 12%, var(--color-surface));
}
.pop-momentum-arrow { color: var(--color-accent); font-weight: 700; }
.pop-momentum-text { font-size: 0.9rem; }

.pop-list { display: flex; flex-direction: column; }
.pop-row {
    display: grid;
    grid-template-columns: 1.4rem minmax(0, 9rem) 1fr auto;
    align-items: center;
    column-gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: var(--border-thin) solid var(--color-border);
}
.pop-row:last-child { border-bottom: none; }
.pop-rank { color: var(--text-muted); font-variant-numeric: tabular-nums; text-align: right; }
.pop-id { min-width: 0; }
.pop-song {
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.pop-artist { font-size: 0.78rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.pop-bar-col { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.pop-bar-track { height: 6px; border-radius: 3px; background: var(--color-border); overflow: hidden; }
.pop-bar-fill { height: 100%; border-radius: 3px; background: var(--color-accent); }
.pop-metrics { font-size: 0.76rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.pop-sep { margin: 0 0.35em; opacity: 0.5; }
.pop-repeat { color: var(--color-accent); }

.pop-trend { font-size: 0.8rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pop-trend-up { color: var(--color-success, #2e7d32); font-weight: 600; }
.pop-trend-down { color: var(--color-danger); font-weight: 600; }

.pop-regions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
    padding-top: var(--space-2);
    border-top: var(--border-thin) solid var(--color-border);
    font-size: 0.78rem;
    color: var(--text-muted);
}
.pop-regions-label { text-transform: uppercase; letter-spacing: 0.04em; font-size: 0.68rem; }
.pop-region-chip {
    padding: 2px var(--space-2);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    border: var(--border-thin) solid var(--color-border);
}
.pop-region-count { font-weight: 600; color: var(--color-accent); }

/* Band dashboard rows (songs + playlists) — a CSS grid: a stacked name/sub label block on the left, then
   action buttons (play · queue · "…") as columns, vertically centered next to the two-line label. */
.band-row {
    display: grid;
    align-items: center;
    column-gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border-bottom: var(--border-thin);
}
.band-row:last-child { border-bottom: none; }
.band-row--song { grid-template-columns: 1fr auto auto auto; }   /* name/artist | play | queue | … */
.band-row--playlist { grid-template-columns: 1fr auto auto auto auto; }   /* name | status | play | … | expand */
.band-row-status { justify-self: start; }

/* Expanded playlist drawer: its song rows are nested + slightly recessed. */
.band-drawer {
    padding-left: var(--space-4);
    background: var(--surface-deep, var(--color-cream-deep));
    border-bottom: var(--border-thin);
}
.band-row--nested { padding-left: var(--space-3); }
.band-row-labels { min-width: 0; display: flex; flex-direction: column; }
.band-row-name {
    font-weight: 600;
    color: var(--color-charcoal);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.band-row-sub {
    font-size: var(--text-sm);
    color: var(--color-charcoal-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.band-row-btn { flex: 0 0 auto; }

/* ContextMenu links styled like its buttons (the "…" menu mixes <a> nav items and <button> actions). */
a.viz-ctxmenu-item { text-decoration: none; display: block; }

/* Mobile: keep the stacked label + buttons on one row but tighten the gap. */
@media (max-width: 640px) {
    .band-row { column-gap: var(--space-1); padding: var(--space-2); }
}

/* --- Songs / Playlists LIST pages — mobile refactor (W-M) --- */
@media (max-width: 640px) {
    /* M3 — Songs page hides Genre / Key / BPM / Feel columns. */
    #view-songs-list th[data-col="Genre"], #view-songs-list td[data-label="Genre"],
    #view-songs-list th[data-col="Key"],   #view-songs-list td[data-label="Key"],
    #view-songs-list th[data-col="BPM"],    #view-songs-list td[data-label="BPM"],
    #view-songs-list th[data-col="Feel"],   #view-songs-list td[data-label="Feel"] { display: none; }

    /* M2 — Playlists page hides Updated / Last Editor columns. */
    #view-playlists th[data-col="Updated"],      #view-playlists td[data-label="Updated"],
    #view-playlists th[data-col="Last Editor"],  #view-playlists td[data-label="Last Editor"] { display: none; }

    /* M1 — collapse row actions to just the play button; the rest live in the long-press menu. */
    #view-songs-list .song-actions > :not(:first-child),
    #view-playlists .playlist-actions > :not(:first-child) { display: none; }
    /* Compact play button on mobile. */
    #view-songs-list .song-actions .btn-playlist-play,
    #view-playlists .playlist-actions .btn-playlist-play { padding: 4px 8px; min-width: 0; }
}

/* Sticky header row for sortable column headers */
.dashboard-grid-header {
    display: grid;
    padding: var(--space-1) var(--space-3);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    font-weight: 600;
    border-bottom: var(--border-thin);
    position: sticky;
    top: 0;
    background-color: var(--surface-card);
    z-index: 1;
}

.header-sortable {
    cursor: pointer;
    user-select: none;
    transition: color var(--transition-fast);
}

.header-sortable:hover {
    color: var(--text-primary);
}

/* Grid column templates */
/* Song grid: Name | Artist | Status | Actions */
.grid-cols-song {
    grid-template-columns: 2fr 1fr 80px 100px;
    gap: var(--space-2);
}

/* Playlist grid: Name | Songs | Status | Actions */
.grid-cols-playlist {
    grid-template-columns: 2fr 60px 80px 100px;
    gap: var(--space-2);
}

/* A data row in the summary grid */
.dashboard-row {
    display: grid;
    padding: var(--space-2) var(--space-3);
    align-items: center;
    border-bottom: var(--border-thin);
    font-size: var(--text-sm);
    transition: background-color var(--transition-fast);
}

.dashboard-row:last-child {
    border-bottom: none;
}

.dashboard-row:hover {
    background-color: var(--color-cream);
}

/* Clickable row variant — shows pointer cursor */
.clickable-row {
    cursor: pointer;
}

/* Actions cell — icon buttons aligned right */
.action-cell {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-1);
}

/* Expansion panel below a row */
.dashboard-expand-panel {
    padding: var(--space-3) var(--space-4);
    background-color: var(--color-cream);
    border-bottom: var(--border-thin);
    animation: animate-entry-fade 0.15s ease-out;
}

/* Compact details line inside expand panel */
.expand-details-compact {
    display: flex;
    gap: var(--space-3);
    font-size: var(--text-xs);
    color: var(--text-muted);
    margin-bottom: var(--space-2);
}

.expand-details-separator {
    padding-left: var(--space-3);
    border-left: var(--border-thin);
}

/* Track list inside an expand panel */
.expand-track-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.expand-track-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    background-color: var(--surface-card);
}

.expand-track-info {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: 1;
    min-width: 0;
}

.expand-track-actions {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex-shrink: 0;
}

/* Track metadata inside expand row */
.track-meta {
    font-size: var(--text-xs);
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.track-title {
    font-weight: 500;
    color: var(--text-primary);
}

/* "(feat. Name)" after the title — lighter so it reads as a credit, not part of the title. */
.track-feat {
    font-weight: 400;
    color: var(--text-muted);
}

.track-artist {
    font-size: var(--text-xs);
    color: var(--text-muted);
}

.track-seq-num {
    font-size: var(--text-xs);
    color: var(--text-muted);
    width: 20px;
    text-align: right;
    flex-shrink: 0;
}

/* Status badge — shows song or playlist status */
.status-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 12px;
    font-size: 11px;
    font-weight: 600;
    background-color: var(--color-cream);
    color: var(--text-secondary);
    border: var(--border-thin);
    white-space: nowrap;
}

/* Type badge — shows audio track type (Original, Cover, Vocals, etc.) */
.type-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 7px;
    border-radius: 10px;
    font-size: 11px;
    font-weight: 600;
    background-color: color-mix(in srgb, var(--color-amber) 12%, transparent);
    color: var(--color-charcoal);
    border: 1px solid color-mix(in srgb, var(--color-amber) 30%, transparent);
    white-space: nowrap;
    flex-shrink: 0;
}

/* Small "view-only" content area (items tab) */
.content-viewer {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* Dashboard card header CTA buttons */
.dashboard-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    /* BL-029 / FLG-CMP-DASH-2-03 — the "+ New" button rendered ~21px tall, below the 24px floor. */
    min-height: 24px;
    font-size: var(--text-xs);
    font-weight: 600;
    border-radius: var(--radius-sm);
    border: none;
    cursor: pointer;
    transition: background-color var(--transition-fast);
}

.dashboard-btn:focus-visible {
    outline: 2px solid var(--focus-ring);   /* BL-029: was missing a focus indicator */
    outline-offset: 2px;
}

.dashboard-btn-new {
    background-color: var(--color-charcoal);
    color: var(--color-cream);
}

.dashboard-btn-new:hover {
    background-color: var(--color-amber);
    color: var(--color-charcoal);
}

/* ==========================================================================
   SECTION 33 — TODO LIST COMPONENTS
   DashboardToDoSummary.razor, ToDoListDetailModal.razor
   ========================================================================== */

/* Panel content area (todo variant of dashboard-content) */
.todo-list-panel-content {
    display: flex;
    flex-direction: column;
    gap: 0;
    overflow-y: auto;
}

/* Section header: "My Private Lists" / "Band Public Lists" */
.todo-section-header {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 700;
    color: var(--text-muted);
    padding: var(--space-2) var(--space-3);
    background-color: var(--color-cream);
    border-top: var(--border-thin);
    border-bottom: var(--border-thin);
    margin-top: var(--space-1);
}

.todo-section-header:first-child {
    margin-top: 0;
    border-top: none;
}

/* Wrapper around a single list row + its expansion panel */
.todo-list-wrapper {
    border-bottom: var(--border-thin);
}

.todo-list-wrapper:last-child {
    border-bottom: none;
}

/* List title row (inherits .dashboard-row.clickable-row) */
.todo-list-title-row {
    grid-template-columns: 1fr auto auto;
    gap: var(--space-2);
    align-items: center;
}

/* Chevron area */
.todo-list-title-row-chevrons {
    display: flex;
    align-items: center;
    color: var(--text-muted);
}

/* Truncated list name */
.todo-list-name {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--text-primary);
}

/* Expansion header: edit button + show-completed toggle */
.todo-expansion-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

.todo-expansion-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-xs);
    color: var(--text-secondary);
    cursor: pointer;
    user-select: none;
}

.todo-checkbox {
    accent-color: var(--color-amber);
    cursor: pointer;
}

.todo-list-edit-button {
    /* inherits .btn-icon-action — no extra styles needed */
}

/* Empty states */
.todo-empty-state {
    padding: var(--space-4) var(--space-3);
    text-align: center;
    font-size: var(--text-sm);
    color: var(--text-muted);
}

/* Scroll area for the items tab */
.todo-list-scroll-area {
    max-height: 320px;
    overflow-y: auto;
}

/* Toolbar row above the item list */
.todo-toolbar {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
    padding-bottom: var(--space-2);
}

/* Description textarea in the detail modal */
.todo-list-new-item-description {
    width: 100%;
    resize: vertical;
    min-height: 60px;
}

/* Muted helper text */
.todo-text-muted {
    font-size: var(--text-sm);
    color: var(--text-muted);
    padding: var(--space-2) var(--space-3);
}

/* Single-line truncation helper */
.todo-text-truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Disclosure rows are now real <button>s (BL-007 keyboard/aria-expanded). Reset the
   UA button chrome so the button renders identically to the former <div> grid row. */
button.dashboard-row {
    width: 100%;
    margin: 0;
    background: none;
    border: none;
    border-bottom: var(--border-thin);
    text-align: left;
    font: inherit;
    color: inherit;
    appearance: none;
}

/* ==========================================================================
   SECTION 34 — INLINE EDIT TARGET (EditableContent.razor admin mode)
   The span wrapping editable text in admin mode — shows a pencil cursor
   and a subtle underline to signal editability.
   ========================================================================== */

.inline-edit-target {
    cursor: pointer;
    text-decoration-line: underline;
    text-decoration-style: dotted;
    text-decoration-color: color-mix(in srgb, var(--color-amber) 50%, transparent);
    text-underline-offset: 3px;
    transition: text-decoration-color var(--transition-fast);
}

.inline-edit-target:hover {
    text-decoration-color: var(--color-amber);
}

/* Empty slot placeholder — shows "click to edit" hint */
.inline-edit-target:empty::before {
    content: attr(data-label);
    color: var(--text-muted);
    font-style: italic;
    font-size: var(--text-xs);
    text-decoration: none;
    display: inline-block;
}

/* ==========================================================================
   SECTION 35 — ACTIVITY FEED (DashboardActivityFeed.razor)
   ========================================================================== */

/* Activity feed container */
.activity-feed-container {
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    flex: 1;
}

/* Individual activity row */
.activity-item {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-bottom: var(--border-thin);
    cursor: pointer;
    transition: background-color var(--transition-fast);
}

.activity-item:last-child {
    border-bottom: none;
}

.activity-item:hover {
    background-color: var(--color-cream);
}

/* Icon badge */
.activity-icon {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background-color: color-mix(in srgb, var(--color-amber) 15%, transparent);
    color: var(--color-charcoal);
    font-size: 14px;
    margin-top: 1px;
}

/* Text content area */
.activity-header {
    display: flex;
    align-items: baseline;
    gap: var(--space-1);
    flex-wrap: wrap;
}

.actor-name {
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--text-primary);
}

.af-target-entity {
    font-size: var(--text-xs);
    color: var(--color-amber);
    font-weight: 500;
}

.activity-details-inline {
    font-size: var(--text-sm);
    color: var(--text-primary);
}

.activity-date {
    font-size: var(--text-xs);
    color: var(--text-muted);
    margin-top: 2px;
}

.activity-row {
    flex: 1;
    min-width: 0;
}

.activity-empty {
    padding: var(--space-4) var(--space-3);
    text-align: center;
    font-size: var(--text-sm);
    color: var(--text-muted);
}

/* Responsive: stack grid-2 on narrow screens */
@media (max-width: 640px) {
    .grid-2 {
        grid-template-columns: 1fr;
    }

    .grid-contact {
        grid-template-columns: 1fr;
    }

    .am-diff-row {
        grid-template-columns: 80px 1fr;
    }

    .am-diff-arrow,
    .am-diff-new {
        grid-column: 2;
    }

    .grid-cols-song,
    .grid-cols-playlist {
        grid-template-columns: 1fr auto;
    }

    .dashboard-grid-header .header-sortable:nth-child(n+3),
    .dashboard-row > div:nth-child(n+3):not(.action-cell) {
        display: none;
    }
}


/* ==========================================================================
   SECTION 36 — COVERAGE AUDIT GAP FILL
   All classes that were used in markup but had no rule in this file.
   Organized by the tier inventory from the audit.
   ========================================================================== */


/* --------------------------------------------------------------------------
   36-A. PUBLIC SURFACE GAPS
   -------------------------------------------------------------------------- */

/* Home hero tagline subtitle (p below the big display text) */
.home-hero-tagline-sub {
    font-size: var(--text-md);
    color: rgba(245, 240, 232, 0.80);
    line-height: var(--leading-relaxed);
    max-width: 44ch;
    /* No separate margin — the gap on .home-hero-tagline flex parent handles it */
}

/* Play-release button overlaid on the Home release tile.
   Floated inside .home-hero-tile-body so it doesn't push copy around. */
.home-hero-tile-play {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    background-color: var(--color-accent);
    color: var(--color-white);
    border: none;
    border-radius: 50%;
    cursor: pointer;
    flex-shrink: 0;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
    /* Sits in the tile-body flex column — margin-top: auto pushes it to the bottom */
    margin-top: auto;
    align-self: flex-start;
}

.home-hero-tile-play:hover {
    background-color: var(--color-accent-light);
    transform: scale(1.08);
}

/* Press page root — modifier on .public-page */
.press-page {
    /* No extra override needed beyond .public-page; preserves space for
       any future press-specific padding tweaks without breaking the base. */
}

/* Press facts container — wraps the at-a-glance definition list */
.press-facts {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* GroupPhotoComposite — .person-image, .person-name-caption */
.person-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top center;
    display: block;
}

.person-name-caption {
    position: absolute;
    bottom: var(--space-3);
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    /* Semi-transparent backdrop so the logo reads on any photo */
    background-color: rgba(28, 26, 23, 0.45);
    border-radius: var(--radius-sm);
    padding: var(--space-1) var(--space-3);
    pointer-events: none;
}

.person-name-caption img {
    height: 20px;
    width: auto;
    filter: brightness(0) invert(1);
    opacity: 0.90;
}

/* YouTubeEmbed component classes */

/* Outer wrapper — reserves 16:9 space even before the iframe loads */
.youtube-embed {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    background-color: var(--color-charcoal);
    border-radius: var(--radius-md);
    overflow: hidden;
}

/* Stage — fills the embed area for both the facade and the placeholder */
.youtube-embed-stage {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
}

/* Facade — clickable thumbnail + play icon */
.youtube-embed-facade {
    cursor: pointer;
}

/* Thumbnail image fills the stage */
.youtube-embed-thumb {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* The big triangle play icon over the thumbnail */
.youtube-embed-play-icon {
    position: relative;
    z-index: 1;
    font-size: 3rem;
    color: var(--color-white);
    background-color: rgba(196, 82, 26, 0.85);
    width: 64px;
    height: 64px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.youtube-embed-facade:hover .youtube-embed-play-icon {
    background-color: var(--color-accent);
    transform: scale(1.10);
}

/* Actual iframe fills the stage after click */
.youtube-embed-iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: none;
    display: block;
}

/* Placeholder tile when VideoId is empty */
.youtube-embed-placeholder .youtube-embed-stage {
    background-color: var(--color-charcoal);
    cursor: default;
}

.youtube-embed-placeholder-text {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: rgba(245, 240, 232, 0.50);
    font-style: italic;
}

/* TrackList component — public-facing ordered track list */

.track-list {
    display: flex;
    flex-direction: column;
    gap: 0;
    list-style: none;
    padding: 0;
    margin: var(--space-4) 0 0;
    border-top: var(--border-thin);
}

.track-row {
    display: grid;
    grid-template-columns: 28px 1fr auto auto;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-2);
    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
    transition: background-color var(--duration-fast) var(--ease-out);
}

.track-row:last-child {
    border-bottom: none;
}

/* R5: a currentColor veil themes on every surface (was a frozen cream — the
   owner's "releases hover is cream under Prince"). */
.track-row:hover {
    background-color: color-mix(in srgb, currentColor 8%, transparent);
}

/* U2: tracklist rows sit inside the release card's raised surface — the muted number/duration
   used --color-charcoal-muted (stranded on the dark canvas ~2.51:1). Re-pointed to the raised
   muted token so they follow the card's surface across themes. */
.track-number {
    font-size: var(--text-xs);
    color: var(--surface-raised-text-muted);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

/* .track-title already styled in section 32 (.track-title) — no duplicate */

.track-duration {
    font-size: var(--text-xs);
    color: var(--surface-raised-text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    min-width: 3.25rem;
    text-align: right;
}

/* Reserved 3-cell grid (Play · Queue · "…") so every row's actions align — controls that don't apply
   are disabled-in-place, not omitted (no content-width jitter). */
.track-actions {
    display: grid;
    grid-template-columns: repeat(3, 28px);
    align-items: center;
    gap: var(--space-2);
}

.track-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    background: none;
    border: var(--border-control);   /* BL-061: 3:1-perceivable outline (was --border-thin ~1.24:1) */
    border-radius: 50%;
    color: var(--surface-raised-text-muted);   /* U2: follow the card's raised surface (was --color-charcoal-muted). */
    cursor: pointer;
    padding: 0;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}

.track-button:hover {
    background-color: var(--color-accent);
    color: var(--color-white);
    border-color: var(--color-accent);
}

/* Disabled (e.g. Play/Queue on a track with no audio) — present for alignment, unmistakably inert. */
.track-button:disabled,
.track-button:disabled:hover {
    opacity: 0.4;
    cursor: default;
    background: none;
    color: var(--surface-raised-text-muted);   /* U2: follow the card's raised surface. */
    border-color: var(--surface-border);
}

.track-button-play {
    /* Same as .track-button — no extra override needed */
}

.track-button-queue {
    /* Same as .track-button — no extra override needed */
}

/* Mobile: give track titles far more width so short names don't wrap. The number column sizes to the digit
   itself (min-content) — killing the dead space that made the # look like it had a big left margin — and the
   gaps / padding / actions / duration all tighten. Placed AFTER the base .track-* rules so it wins the cascade. */
@media (max-width: 640px) {
    .track-row {
        grid-template-columns: min-content 1fr auto auto;
        gap: var(--space-2);
        padding-inline: var(--space-1);
    }
    .track-duration { min-width: 0; }
    .track-actions { gap: 4px; }
    .track-button { width: 26px; height: 26px; }
}

.track-external {
    font-size: var(--text-xs);
    color: var(--color-accent);
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    padding: var(--space-1) var(--space-2);
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    border-color: var(--color-accent);
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.track-external:hover {
    background-color: var(--color-accent);
    color: var(--color-white);
}

/* Per-track DSP links — one brand glyph per service (mirrors the release-level .release-dsp-link). */
.track-dsp-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.94);
    /* BL-077 / FLG-CMP-CONTROLS-1-06 — light brand glyphs (e.g. Spotify green ~2.59:1 on cream)
       can't be lifted without recoloring the mark, so instead the mark's white pill gets a
       perceivable boundary: a 3:1 control-outline ring so the affordance shape clears the non-text
       floor even when the glyph inside is a low-contrast brand color. */
    border: var(--border-control);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
    transition: transform var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.track-dsp-link:hover,
.track-dsp-link:focus-visible {
    transform: scale(1.1);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.28);
}

.track-dsp-link .dsp-icon svg {
    width: 1.05rem;
    height: 1.05rem;
}

/* "…" details button — a different color from the play controls (cream-deep fill, charcoal glyph).
   Active/hover uses the ACCENT fill with a white glyph (clears non-text contrast) — the previous
   charcoal-on-charcoal open state was unreadable. State is also carried by aria-expanded + the popover,
   so it isn't signalled by color alone. */
.track-button-more {
    /* U2: was primitive cream/charcoal — under Dark the CMS block's luminance color leaked cream
       onto the glyph (~1.03:1). Semantic deep-surface pair keeps the "…" glyph legible on any theme. */
    background: var(--surface-deep);
    border-color: var(--surface-border);
    color: var(--surface-deep-text-muted);
    font-size: var(--text-lg);   /* BL-077 / FLG-TSM-003: was a hardcoded 1.05rem off-scale literal (~16.8px) */
    line-height: 1;
    letter-spacing: 0.05em;
}

.track-button-more:hover,
.track-button-more.is-open {
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: var(--color-white);
}

/* Non-modal track-details popover (credits / notes / streaming links). Light backdrop that
   light-dismisses; the card is a raised surface. role=dialog WITHOUT aria-modal (page stays live). */
.track-pop-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    background: rgba(0, 0, 0, 0.18);
}

.track-pop {
    width: min(28rem, 100%);
    max-height: 80vh;
    overflow-y: auto;
    background: var(--surface-raised);
    border: var(--border-thin);
    border-radius: var(--radius-lg, 12px);
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.28);
    padding: var(--space-4);
    outline: none;
}

.track-pop-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

.track-pop-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--text-primary);
}

.track-pop-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: none;
    background: none;
    font-size: 1.4rem;
    line-height: 1;
    color: var(--surface-page-text-muted);
    cursor: pointer;
    border-radius: 50%;
}

.track-pop-close:hover { color: var(--color-accent); }
.track-pop-close:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-accent-dim); }

.track-pop-block { margin-bottom: var(--space-3); }
.track-pop-block:last-child { margin-bottom: 0; }

.track-pop-label {
    display: block;
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 700;
    color: var(--surface-page-text-muted);
    margin-bottom: 2px;
}

.track-pop-text {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    white-space: pre-wrap;
}

.track-pop-dsp {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* track-version-notes — description text inside the audio-row dropdown
   (band portal / SongPortal audio tab) */
.track-version-notes {
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
    font-style: italic;
    cursor: pointer;
    max-width: 160px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.track-version-notes:hover {
    color: var(--color-charcoal);
}

/* DropdownView — wrapper + floating popup */
.dropdown-wrapper {
    position: relative;
    display: inline-block;
}

.popup-container {
    position: fixed;        /* JS positions via positionPopup() */
    z-index: 600;
    background-color: var(--color-white);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    padding: var(--space-3) var(--space-4);
    min-width: 220px;
    max-width: 360px;
}

/* .dismiss — used in Blazor error UI (already styled under #blazor-error-ui .dismiss)
   and as a standalone utility in a few other places */
.dismiss {
    cursor: pointer;
    background: none;
    border: none;
    color: inherit;
    opacity: 0.75;
    padding: 0 var(--space-2);
    font-size: var(--text-base);
    transition: opacity var(--duration-fast) var(--ease-out);
}

.dismiss:hover {
    opacity: 1;
}

/* .reload — "Reload" link/button in error state panels */
.reload {
    display: inline-flex;
    align-items: center;
    padding: var(--space-2) var(--space-4);
    background-color: var(--color-accent);
    color: var(--color-white);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    border: none;
    border-radius: var(--radius-full);
    cursor: pointer;
    text-decoration: none;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.reload:hover {
    background-color: var(--color-accent-light);
    color: var(--color-white);
}


/* --------------------------------------------------------------------------
   36-B. BAND PORTAL GAPS
   -------------------------------------------------------------------------- */

/* Dashboard input — text inputs on dashboard cards */
.dashboard-input {
    padding: var(--space-2) var(--space-3);
    background-color: var(--color-white);
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--color-charcoal);
    transition: border-color var(--duration-fast) var(--ease-out);
}

.dashboard-input:focus {
    outline: none;
    border-color: var(--color-accent);
}

/* dashboard-mode is already on .admin-container.dashboard-mode (Section 23) */

/* Pager footer (PagerControl.razor) */
.dashboard-pager-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-top: var(--border-thin);
    margin-top: var(--space-2);
    background-color: var(--surface-page);
}

.pager-buttons {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.pager-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    background: none;
    border: var(--border-control);   /* BL-061: 3:1-perceivable outline (was --border-thin ~1.24:1) */
    border-radius: var(--radius-sm);
    color: var(--color-charcoal-muted);
    cursor: pointer;
    padding: 0;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.pager-btn:hover:not(:disabled) {
    background-color: var(--color-cream-deep);
    color: var(--color-charcoal);
}

.pager-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

.pager-info {
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
    font-variant-numeric: tabular-nums;
}

/* Discussion list / panel / footer (SongPortal discussion tab) */
.discussion-panel {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    min-height: 200px;
}

.discussion-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    flex: 1;
    overflow-y: auto;
    padding: var(--space-2) 0;
}

.discussion-footer {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding-top: var(--space-3);
    border-top: var(--border-thin);
}

/* .conversation-mode already styled in Section 22 (.am-body.conversation-mode) */

/* Replying-to banner (SongPortal discussion + Conversation component) */
.replying-to-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background-color: var(--color-cream-deep);
    border-left: 3px solid var(--color-accent);
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
}

/* Song editor classes */
.song-detail-notes {
    width: 100%;
    min-height: 80px;
    padding: var(--space-2) var(--space-3);
    background-color: var(--color-cream-deep);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--color-charcoal);
    resize: vertical;
}

.song-detail-notes:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-dim);
}

/* SortableSongList grid */
.song-sortable-list {
    display: flex;
    flex-direction: column;
    gap: 0;
    border: var(--border-thin);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.song-grid-header {
    background-color: var(--color-cream-deep);
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-charcoal-muted);
}

.song-grid-row {
    display: grid;
    /* 7 cols: handle | seq | title | artist | key | bpm | actions */
    grid-template-columns: 28px 32px 2fr 1fr 60px 60px 60px;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border-bottom: var(--border-thin);
    font-size: var(--text-sm);
    color: var(--color-charcoal);
    transition: background-color var(--duration-fast) var(--ease-out);
}

.song-grid-row:last-child {
    border-bottom: none;
}

.song-draggable-row {
    cursor: grab;
}

.song-draggable-row:hover {
    background-color: var(--color-cream);
}

.song-draggable-row.is-dragging {
    opacity: 0.55;
    background-color: var(--color-accent-dim);
}

.drag-handle-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-charcoal-muted);
    cursor: grab;
    flex-shrink: 0;
}

.song-seq-text {
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.song-title-text {
    font-weight: 600;
    color: var(--color-charcoal);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.song-artist-text {
    color: var(--color-charcoal-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.song-meta-text {
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
}

.song-actions-cell {
    display: flex;
    align-items: center;
    justify-content: flex-end;
}

.song-col-header-action {
    text-align: right;
}

/* PlaylistLyricsView / SongHistoryView — print/lyric popout classes */
.playlist-lyrics-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) var(--page-gutter);
    border-bottom: var(--border-thin);
    background-color: var(--surface-page);
    print-color-adjust: exact;
}

.playlist-title-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.playlist-main-title {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--surface-page-text);
    font-variation-settings: 'WONK' 0;
}

/* .playlist-detail-notes — notes on a playlist detail (PlaylistPortal) */
.playlist-detail-notes {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    font-style: italic;
    line-height: var(--leading-relaxed);
}

/* .playlist-songs — the songs section in the playlist detail modal */
.playlist-songs {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* Print / lyric page styles */
.lyrics-view-container {
    background-color: #fff;
    color: #000;
    max-width: 820px;
    margin: 0 auto;
    padding: var(--space-5) var(--page-gutter);
    font-family: var(--font-body);
    font-size: 13px;
    line-height: 1.5;
}

.lyrics-body {
    padding: var(--space-3) 0 var(--space-6);
}

.lyrics-body pre {
    font-family: var(--font-body);
    font-size: 12px;
    white-space: pre-wrap;
    word-break: break-word;
    line-height: 1.6;
}

.lyrics-display {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--color-charcoal);
    white-space: pre-wrap;
    word-break: break-word;
    line-height: var(--leading-relaxed);
    padding: var(--space-3) 0;
}

.lyric-page-break {
    break-inside: avoid;
    page-break-inside: avoid;
    margin-bottom: var(--space-6);
}

.song-header-inline {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: var(--border-thin);
}

/* .song-title already styled elsewhere; used in lyric view context */
.song-title {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--color-charcoal);
    font-variation-settings: 'WONK' 0;
}

.song-meta-inline {
    display: flex;
    gap: var(--space-4);
    flex-wrap: wrap;
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
}

/* --- Chord chart (ChordChartView / PlaylistChordChartView via ChordSheet) ---
   Sheet-music density: bold, glanceable chord symbols; sections never split across a page break.
   Reuses .lyrics-view-container / .playlist-lyrics-header / .btn-print from the lyrics print styles. */
.chord-body {
    padding: var(--space-3) 0 var(--space-6);
}

.chord-sheet {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

.chord-section {
    break-inside: avoid;
    page-break-inside: avoid;
}

.chord-section-head {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
    padding-bottom: var(--space-1);
    border-bottom: var(--border-thin);
}

.chord-section-label {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-charcoal);
}

.chord-section-tag,
.chord-section-hint {
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
    font-style: italic;
}

.chord-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-5);
    align-items: baseline;
}

/* Large, bold chord symbols — readable at arm's length on a music stand. */
.chord-symbol {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.2;
    color: var(--color-charcoal);
    min-width: 2.5ch;
}

.chord-row-empty {
    color: var(--color-charcoal-muted);
    font-size: 1.25rem;
}

@media print {
    .chord-symbol { color: #000; }
    .chord-section { break-inside: avoid; page-break-inside: avoid; }
}

/* Interactive chart controls (transpose stepper + Nashville toggle + print) — hidden in print,
   so the printed chart shows the chosen rendering without the on-screen buttons. */
.chart-controls {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.transpose-stepper {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    background-color: var(--color-cream);
}

.transpose-stepper.is-disabled {
    opacity: 0.45;
}

.ts-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border: none;
    border-radius: var(--radius-sm);
    background-color: var(--color-cream-deep);
    color: var(--color-charcoal);
    font-size: var(--text-md);
    font-weight: 700;
    cursor: pointer;
}

.ts-btn:disabled {
    cursor: default;
}

.ts-btn:not(:disabled):hover {
    background-color: var(--color-accent);
    color: var(--color-white);
}

.ts-label {
    min-width: 3ch;
    text-align: center;
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--color-charcoal);
}

.btn-mode {
    padding: var(--space-2) var(--space-3);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    background-color: var(--color-cream);
    color: var(--color-charcoal-mid);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
}

.btn-mode.is-active {
    background-color: var(--color-charcoal);
    color: var(--color-cream);
}

/* Segmented chord-display selector (Letters / Nashville / Roman) — buttons read as one control. */
.mode-group {
    display: inline-flex;
    gap: var(--space-1);
}

@media print {
    .chart-controls { display: none !important; }
}

/* --- Lyric-with-chords idiom (ChordProSheet) ---
   Interim view: each section's chord row (from its "> chords:" attribute) above its lyric lines.
   NOT syllable-anchored — see PrintableTabsCharts-v1.md M2 tech-debt note. */
.chordpro-sheet {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

.chordpro-section {
    break-inside: avoid;
    page-break-inside: avoid;
}

.chordpro-heading {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-charcoal);
    margin-bottom: var(--space-2);
    padding-bottom: var(--space-1);
    border-bottom: var(--border-thin);
}

.chordpro-chord-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    align-items: baseline;
    margin-bottom: var(--space-2);
}

/* Bold, glanceable chords sitting above the lyric block (the ONE pop color marks them as chords). */
.chordpro-chord {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1.2;
    color: var(--color-accent);
    min-width: 2ch;
}

.chordpro-lines {
    display: flex;
    flex-direction: column;
}

.chordpro-line {
    font-family: var(--font-body);
    font-size: var(--text-md);
    line-height: var(--leading-relaxed);
    color: var(--color-charcoal);
}

.chordpro-gap {
    height: var(--space-3);
}

.chordpro-instrumental {
    font-size: var(--text-sm);
    font-style: italic;
    color: var(--color-charcoal-muted);
}

@media print {
    .chordpro-chord { color: #000; }
    .chordpro-line { color: #000; }
    .chordpro-section { break-inside: avoid; page-break-inside: avoid; }
}

/* --- Chord-diagram boxes (ChordDiagram.razor) ---
   Own SVG, standard style. Ink follows the charcoal token; finger numbers contrast on the filled
   dots; prints black-on-white. Geometry is in the component; this is color/type only. */
.chord-diagram {
    color: var(--color-charcoal);
    display: inline-block;
    vertical-align: top;
}

.chord-diagram .cd-ink {
    stroke: currentColor;
}

.chord-diagram .cd-open {
    fill: none;
    stroke: currentColor;
    stroke-width: 1.4;
}

.chord-diagram .cd-mute {
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
}

.chord-diagram .cd-dot,
.chord-diagram .cd-barre {
    fill: currentColor;
}

.chord-diagram .cd-name {
    fill: currentColor;
    font-family: var(--font-display);
    font-weight: 700;
}

.chord-diagram .cd-pos {
    fill: currentColor;
    font-weight: 600;
}

.chord-diagram .cd-finger {
    fill: var(--color-cream);
    font-weight: 700;
    font-size: 9px;                 /* fit inside the dot (was inheriting the page size) */
    dominant-baseline: central;     /* vertically center the number in the circle */
}

.chord-diagram .cd-label {
    fill: var(--color-charcoal-muted);
}

@media print {
    .chord-diagram { color: #000; }
    .chord-diagram .cd-finger { fill: #fff; }
    .chord-diagram .cd-label { fill: #000; }
}

/* Chord legend — a row of diagrams for the song's distinct chords (ChordLegend.razor). */
.chord-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    align-items: flex-start;
    padding: var(--space-3) 0 var(--space-5);
    margin-bottom: var(--space-4);
    border-bottom: var(--border-thin);
}

.chord-legend-noshape {
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--color-charcoal-muted);
    padding: var(--space-3) var(--space-2);
}

@media print {
    .chord-legend { border-color: #000; break-inside: avoid; }
}

/* Legend chord is a button — click opens its inversions. */
.chord-legend-btn {
    appearance: none;
    background: none;
    border: none;
    margin: 0;
    padding: var(--space-1);
    line-height: 0;
    cursor: pointer;
    border-radius: var(--radius-md);
}

.chord-legend-btn:hover {
    background-color: var(--color-cream-deep);
}

.chord-legend-btn:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

@media print {
    .chord-legend-btn:hover { background: none; }
}

/* --- Inversions popover (ChordInversionsPopover.razor) — screen-only --- */
.chord-pop-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--z-nav);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    background-color: rgba(0, 0, 0, 0.45);
}

.chord-pop {
    background-color: var(--color-cream);
    color: var(--color-charcoal);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-5);
    max-width: min(92vw, 760px);
    max-height: 85vh;
    overflow-y: auto;
}

.chord-pop-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: var(--border-thin);
}

.chord-pop-title {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--color-charcoal);
}

.chord-pop-close {
    appearance: none;
    border: none;
    background: none;
    padding: var(--space-1) var(--space-2);
    font-size: var(--text-xl);
    line-height: 1;
    cursor: pointer;
    color: var(--color-charcoal-muted);
}

.chord-pop-close:hover {
    color: var(--color-accent);
}

.chord-pop-group {
    margin-top: var(--space-4);
}

.chord-pop-group-label {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-charcoal-muted);
    margin-bottom: var(--space-2);
}

.chord-pop-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.chord-pop-none {
    font-size: var(--text-sm);
    font-style: italic;
    color: var(--color-charcoal-muted);
}

.chord-pop-footer {
    margin-top: var(--space-5);
    padding-top: var(--space-3);
    border-top: var(--border-thin);
}

.chord-pop-explore {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-accent);
    text-decoration: none;
}

.chord-pop-explore:hover {
    text-decoration: underline;
}

@media print {
    .chord-pop-backdrop { display: none !important; }
}

/* --- Chord Explorer page (ChordExplorer.razor) --- */
.explorer {
    max-width: 1100px;
    margin: 0 auto;
    padding: var(--space-5) var(--page-gutter);
}

.explorer-title {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--color-charcoal);
}

.explorer-sub {
    color: var(--color-charcoal-muted);
    margin-bottom: var(--space-4);
}

.explorer-controls {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4);
    margin-bottom: var(--space-5);
    background-color: var(--color-cream-deep);
    border-radius: var(--radius-lg);
}

.explorer-group {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
}

.explorer-label {
    min-width: 4.5rem;
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-charcoal-muted);
}

.explorer-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
}

.chip {
    appearance: none;
    border: var(--border-thin);
    border-radius: var(--radius-md);
    background-color: var(--color-cream);
    color: var(--color-charcoal-mid);
    padding: var(--space-1) var(--space-3);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
}

.chip:hover {
    border-color: var(--color-accent);
}

.chip.is-active {
    background-color: var(--color-charcoal);
    color: var(--color-cream);
    border-color: var(--color-charcoal);
}

.explorer-span {
    font-size: var(--text-sm);
    color: var(--color-charcoal-mid);
}

.explorer-result {
    margin-top: var(--space-5);
}

.explorer-result-label {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-charcoal);
    margin-bottom: var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: var(--border-thin);
}

.explorer-count {
    margin-left: var(--space-2);
    color: var(--color-charcoal-muted);
    font-weight: 600;
}

.explorer-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.explorer-empty {
    color: var(--color-charcoal-muted);
    font-style: italic;
}

/* --- Voicings appendix (ChordVoicingsAppendix.razor) — per-chord inversions; prints on its own page --- */
.voicings-appendix {
    margin-top: var(--space-6);
    padding-top: var(--space-4);
    border-top: var(--border-thin);
}

.voicings-appendix-title {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-charcoal);
    margin-bottom: var(--space-4);
}

.voicings-chord {
    margin-bottom: var(--space-5);
    break-inside: avoid;
    page-break-inside: avoid;
}

.voicings-chord-name {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--color-charcoal);
    margin-bottom: var(--space-2);
}

.voicings-chord-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5);
}

.voicings-inv {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-1);
}

.voicings-inv-label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-charcoal-muted);
}

@media print {
    .voicings-appendix { break-before: page; }
    .voicings-chord { break-inside: avoid; page-break-inside: avoid; }
}

/* --- Print tablature (TabStaff.razor) — own "ts-" classes, decoupled from the editor's TabView --- */
.ts-staff {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    color: var(--color-charcoal);
}

.ts-phrase {
    break-inside: avoid;
    page-break-inside: avoid;
}

.ts-phrase-label {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-charcoal);
    margin-bottom: var(--space-2);
}

.ts-system {
    display: grid;
    row-gap: 0;
    column-gap: 0;
    align-items: stretch;
    margin-bottom: var(--space-4);
    font-family: var(--font-mono, ui-monospace, "Cascadia Mono", Consolas, monospace);
}

.ts-strlabel {
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
}

/* Each cell carries the string line through its vertical middle, so the lines run continuously
   across the row; the fret number sits in a paper-colored box that masks the line behind it. */
.ts-cell {
    box-sizing: border-box;
    position: relative;
    min-height: 1.6em;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-sm);
    background-image: linear-gradient(to bottom,
        transparent calc(50% - 0.6px), var(--color-charcoal-mid) calc(50% - 0.6px),
        var(--color-charcoal-mid) calc(50% + 0.6px), transparent calc(50% + 0.6px));
}

.ts-bar-start { border-left: 1.5px solid var(--color-charcoal); }
.ts-bar-end { border-right: 1.5px solid var(--color-charcoal); }

.ts-fret {
    position: relative;
    padding: 0 0.2em;
    font-weight: 700;
    color: var(--color-charcoal);
    background-color: var(--color-cream);
}

.ts-tech {
    font-size: var(--text-xs);
    color: var(--color-accent);
}

@media print {
    .ts-staff { color: #000; }
    .ts-cell {
        background-image: linear-gradient(to bottom,
            transparent calc(50% - 0.6px), #000 calc(50% - 0.6px),
            #000 calc(50% + 0.6px), transparent calc(50% + 0.6px));
    }
    .ts-bar-start { border-left-color: #000; }
    .ts-bar-end { border-right-color: #000; }
    .ts-fret { background-color: #fff; color: #000; }
}

/* Per-song tab sheet (TabSheet.razor) — one part (bass, guitar, …) per instrument line. */
.tab-sheet {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.tab-part {
    break-inside: avoid;
}

.tab-part-head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: 2px solid var(--color-charcoal);
}

.tab-part-role {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--color-charcoal);
}

.tab-part-summary {
    font-size: var(--text-sm);
    font-style: italic;
    color: var(--color-charcoal-muted);
}

.tab-part-approach {
    font-size: var(--text-sm);
    color: var(--color-charcoal-mid);
    line-height: var(--leading-relaxed);
    margin-top: var(--space-3);
}

/* Setlist chord charts (PlaylistChordChartView) — each song titled; one song per page in print. */
.chord-setlist-song {
    margin-bottom: var(--space-6);
}

.chord-song-header {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: 2px solid var(--color-charcoal);
}

.chord-song-index {
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--color-charcoal-muted);
}

.chord-song-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--color-charcoal);
}

.chord-song-artist,
.chord-song-key {
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
}

@media print {
    .chord-setlist-song { break-before: page; }
    .chord-setlist-song:first-child { break-before: auto; }
}

/* SongHistoryView print table */
.history-print-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
}

.history-print-table th {
    text-align: left;
    padding: var(--space-2) var(--space-3);
    border-bottom: 2px solid var(--color-charcoal);
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-charcoal-muted);
}

.history-print-meta td {
    padding: var(--space-2) var(--space-3);
    border-bottom: var(--border-thin);
    vertical-align: top;
    font-size: 12px;
    color: var(--color-charcoal);
}

.history-print-lyrics-cell {
    padding: 0 !important;
    border-bottom: 2px solid var(--color-charcoal-mid) !important;
}

.history-print-lyrics-box {
    padding: var(--space-3) var(--space-5);
    background-color: var(--color-cream);
}

.history-print-lyrics-text {
    font-family: var(--font-body);
    font-size: 11px;
    white-space: pre-wrap;
    word-break: break-word;
    line-height: 1.55;
    color: var(--color-charcoal);
    margin: 0;
}

/* version-header — in the Lyrics tab of SongPortal */
.version-header {
    padding-bottom: var(--space-3);
    border-bottom: var(--border-thin);
    margin-bottom: var(--space-4);
    font-size: var(--text-sm);
    color: var(--color-charcoal-mid);
}

/* Attachment UI (SongPortal / Links tab) */
.add-attachment-panel {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-4);
    background-color: var(--color-cream-deep);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-5);
}

.add-song-bar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3);
    background-color: var(--color-cream-deep);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    flex-wrap: wrap;
}

/* Playlist editor: shuffle + duplicate-detection toolbar above the sortable
   song list (Phase 8 WS-1). */
.playlist-tools {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin: var(--space-3) 0;
}

/* Buttons that pair an icon with a text label — keeps the AppIcon and span on
   one baseline-aligned row. */
.btn-icon-text {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.playlist-dup-warning {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-warning);
    margin-left: auto; /* push the duplicate notice + action to the right */
}

.attachment-mode-toggle {
    display: flex;
    gap: var(--space-5);
    align-items: center;
    flex-wrap: wrap;
}

.attachment-mode-toggle label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--color-charcoal-mid);
    cursor: pointer;
}

.attachment-grid {
    display: flex;
    flex-direction: column;
    gap: 0;
    border: var(--border-thin);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.attachment-row {
    display: grid;
    grid-template-columns: 32px auto 1fr auto;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-bottom: var(--border-thin);
    background-color: var(--color-white);
    transition: background-color var(--duration-fast) var(--ease-out);
}

.attachment-row:last-child {
    border-bottom: none;
}

.attachment-row:hover {
    background-color: var(--color-cream);
}

.attachment-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-charcoal-muted);
    flex-shrink: 0;
}

.attachment-meta {
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

.attachment-type-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px var(--space-2);
    background-color: var(--color-cream-deep);
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--color-charcoal-muted);
    white-space: nowrap;
}

.attachment-desc-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.attachment-desc-text {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-charcoal);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.attachment-link {
    font-size: var(--text-xs);
    color: var(--color-accent);
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.attachment-link:hover {
    color: var(--color-accent-light);
    text-decoration: underline;
}

.attachment-actions {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex-shrink: 0;
}

/* Audio tab (SongPortal) */
.audio-tab {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.audio-grid {
    display: flex;
    flex-direction: column;
    gap: 0;
    border: var(--border-thin);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.audio-row {
    display: grid;
    /* Type | Ver | Actions | Notes */
    grid-template-columns: 100px 80px 1fr 1fr;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-bottom: var(--border-thin);
    font-size: var(--text-sm);
    color: var(--color-charcoal);
    background-color: var(--color-white);
}

.audio-row:first-child {
    background-color: var(--color-cream-deep);
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-charcoal-muted);
}

.audio-row:last-child {
    border-bottom: none;
}

/* .header-cell — column header within the audio-row header */
.header-cell {
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-charcoal-muted);
}

/* File upload components */
.upload-wrapper {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.upload-file-label {
    display: inline-flex;
    align-items: center;
    padding: var(--space-2) var(--space-4);
    background-color: var(--color-cream-deep);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--color-charcoal-mid);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}

.upload-file-label:hover {
    background-color: var(--color-cream-mid);
    border-color: var(--color-charcoal-muted);
}

/* Progress bar — generic Bootstrap-like pattern */
.progress {
    width: 100%;
    height: 8px;
    background-color: var(--color-cream-mid);
    border-radius: var(--radius-full);
    overflow: hidden;
}

.progress-bar {
    height: 100%;
    background-color: var(--color-accent);
    border-radius: var(--radius-full);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-xs);
    color: transparent;  /* text is invisible inside 8px bar; still in DOM for aria */
    transition: width 150ms linear;
}

.upload-progress-track {
    width: 100%;
    height: 6px;
    background-color: var(--color-cream-mid);
    border-radius: var(--radius-full);
    overflow: hidden;
    margin: var(--space-2) 0;
}

.upload-progress-fill {
    height: 100%;
    background-color: var(--color-accent);
    border-radius: var(--radius-full);
    transition: width 150ms linear;
}

/* song-version-option — <option> elements in the audio track version select */
.song-version-option {
    /* <option> styling is limited by browsers; just ensure readable text */
    color: var(--color-charcoal);
    background-color: var(--color-white);
}

/* ToDoItem display */
.todo-input {
    flex: 1;
    padding: var(--space-2) var(--space-3);
    background-color: var(--color-white);
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--color-charcoal);
    transition: border-color var(--duration-fast) var(--ease-out);
}

.todo-input:focus {
    outline: none;
    border-color: var(--color-accent);
}

.todo-item-display {
    /* Modifier on .todo-item-row for the read-only display variant */
    cursor: default;
}

.todo-item-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-bottom: var(--border-thin);
    transition: background-color var(--duration-fast) var(--ease-out);
}

.todo-item-row:last-child {
    border-bottom: none;
}

.todo-item-row:hover {
    background-color: var(--color-cream);
}

.todo-item-row.completed {
    opacity: 0.55;
}

.todo-text-display {
    font-size: var(--text-sm);
    color: var(--color-charcoal);
    flex: 1;
    line-height: var(--leading-normal);
}

/* Drag-reorder list container (band portal drag interactions) */
.drag-handle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    color: var(--color-charcoal-muted);
    cursor: grab;
    flex-shrink: 0;
}

.reorder-list-container {
    display: flex;
    flex-direction: column;
    gap: 0;
    border: var(--border-thin);
    border-radius: var(--radius-md);
    overflow: hidden;
}

/* Sortable table headers */
.sortable-th {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
    transition: color var(--duration-fast) var(--ease-out);
}

.sortable-th:hover {
    color: var(--color-charcoal);
}

.sort-indicator-inactive {
    opacity: 0.35;
    margin-left: var(--space-1);
    font-size: var(--text-xs);
}

/* Band portal action buttons */
.delete-btn {
    /* Alias for .btn-delete — same pattern */
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-2) var(--space-3);
    background-color: transparent;
    color: var(--alert-danger-rule);
    border: 1px solid var(--alert-danger-border);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.delete-btn:hover {
    background-color: var(--alert-danger-bg-strong);
    border-color: var(--alert-danger-rule);
}

.btn-add-song {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    background-color: var(--color-charcoal);
    color: var(--color-cream);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.btn-add-song:hover {
    background-color: var(--color-accent);
}

.btn-queue {
    /* inline queue button in the audio row */
    /* Shares .btn-secondary visual but smaller padding */
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    background-color: transparent;
    color: var(--color-charcoal-mid);
    border: var(--border-thin);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 600;
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.btn-queue:hover {
    background-color: var(--color-cream-deep);
    color: var(--color-charcoal);
}

.btn-print {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    background-color: var(--color-charcoal);
    color: var(--color-cream);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    text-decoration: none;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.btn-print:hover {
    background-color: var(--color-accent);
    color: var(--color-white);
}

.btn-modal {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    background-color: var(--color-cream-deep);
    color: var(--color-charcoal-mid);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.btn-modal:hover {
    background-color: var(--color-cream-mid);
    color: var(--color-charcoal);
}

.btn-small-delete {
    /* Compact delete used in SortableSongList rows */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-1) var(--space-2);
    background-color: transparent;
    color: var(--alert-danger-rule);
    border: 1px solid var(--alert-danger-border);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    cursor: pointer;
    line-height: 1;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.btn-small-delete:hover {
    background-color: var(--alert-danger-bg-strong);
    border-color: var(--alert-danger-rule);
}

.btn-close-small {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    background: none;
    border: none;
    border-radius: 50%;
    color: var(--color-charcoal-muted);
    font-size: var(--text-md);
    cursor: pointer;
    padding: 0;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.btn-close-small:hover {
    background-color: var(--color-cream-deep);
    color: var(--color-charcoal);
}

/* Accent link-style button (e.g. "Log In With Passkey"). --color-accent-text is the
   contrast-safe accent for text (raw --color-accent is 4.05 on the page — the M5
   passkey-button sweep miss). */
.btn-link-action {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background: none;
    border: none;
    color: var(--color-accent-text);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
    transition: color var(--duration-fast) var(--ease-out);
}

.btn-link-action:hover {
    color: var(--color-accent);
}

.btn-external {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    background-color: transparent;
    color: var(--color-charcoal-mid);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: border-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.btn-external:hover {
    border-color: var(--color-accent);
    color: var(--color-accent);
}

.btn-group {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}


/* --------------------------------------------------------------------------
   36-C. ADMIN GAPS
   -------------------------------------------------------------------------- */

/* admin-table — generic data table used in Newsletter + Subscribers admin */
.admin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}

.admin-table th {
    text-align: left;
    padding: var(--space-2) var(--space-3);
    border-bottom: 2px solid var(--surface-border);
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--surface-deep-text-muted);
    white-space: nowrap;
    background-color: var(--surface-deep);
}

.admin-table td {
    padding: var(--space-2) var(--space-3);
    border-bottom: var(--border-thin);
    color: var(--surface-page-text);
    vertical-align: middle;
}

.admin-table tbody tr:hover td {
    background-color: var(--surface-page);
}

/* Buttons grouped inside a table cell (e.g. the contact-inbox row actions). */
.admin-cell-actions {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
}

/* Free-text cell that preserves the visitor's line breaks and stays readable. */
.admin-cell-message {
    max-width: 32rem;
    white-space: pre-wrap;
}

/* Rows the admin has marked handled read as de-emphasized. */
.admin-table tbody tr.is-handled td {
    opacity: 0.55;
}

/* admin-page-toolbar — filter bar above admin tables */
.admin-page-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    padding: var(--space-3) var(--space-4);
    background-color: var(--surface-deep);
    border: var(--border-thin);
    border-radius: var(--radius-md);
}

.admin-page-toolbar-count {
    margin-left: auto;
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* admin-input-narrowest — very narrow text field (e.g. year/code inputs) */
.admin-input-narrowest {
    max-width: 80px;
}

/* Newsletter admin compose page */
.newsletter-admin {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-6);
    align-items: start;
}

.newsletter-admin-section-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--surface-page-text);
    margin-bottom: var(--space-4);
    font-variation-settings: 'WONK' 0;
}

.newsletter-admin-compose {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.newsletter-admin-body {
    min-height: 200px;
    font-family: var(--font-body);
    font-size: var(--text-sm);
}

.newsletter-admin-blast-fieldset {
    border-color: var(--color-accent);
}

.newsletter-admin-confirm {
    font-size: var(--text-sm);
    color: var(--surface-page-text);
    line-height: var(--leading-normal);
    margin-bottom: var(--space-3);
}

.newsletter-admin-dev-banner {
    padding: var(--space-3) var(--space-4);
    background-color: #FEF3C7;
    color: var(--color-warning-deep);
    border: 1px solid #FCD34D;
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
}

.newsletter-admin-history {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

@media (max-width: 880px) {
    .newsletter-admin {
        grid-template-columns: 1fr;
    }
}

/* Images-admin library — grid of all site images with usage annotations */
.images-admin-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin-bottom: var(--space-4); }
.images-admin-upload { cursor: pointer; }
.images-admin-upload input { display: none; }
.images-admin-summary { font-size: var(--text-sm); color: var(--surface-page-text-muted); margin-bottom: var(--space-3); }
.images-admin-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--space-4); }
.images-admin-card {
    display: flex; flex-direction: column;
    border: 1px solid var(--surface-border); border-radius: var(--radius-md);
    overflow: hidden; background: var(--surface-raised);
}
.images-admin-card.is-unused { border-color: var(--alert-danger-border); }
.images-admin-thumb { width: 100%; aspect-ratio: 1 / 1; object-fit: contain; background: var(--surface-deep); }
.images-admin-meta { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-2) var(--space-3); }
.images-admin-name { font-weight: 600; font-size: var(--text-sm); word-break: break-all; color: var(--surface-page-text); }
.images-admin-dims { font-size: 0.72rem; color: var(--surface-page-text-muted); display: flex; flex-wrap: wrap; gap: var(--space-1); align-items: center; }
.images-admin-folder { padding: 0 var(--space-1); border-radius: var(--radius-sm); background: var(--surface-deep); color: var(--surface-deep-text-muted); }
.images-admin-badge { align-self: flex-start; font-size: 0.66rem; font-weight: 700; padding: 1px var(--space-2); border-radius: var(--radius-sm); }
.images-admin-badge-unused { background: var(--alert-danger-bg-strong); color: var(--color-danger); }
.images-admin-uses { font-size: 0.72rem; color: var(--surface-page-text-muted); }
.images-admin-uses summary { cursor: pointer; color: var(--color-accent); font-weight: 600; }
.images-admin-uses ul { margin: var(--space-1) 0 0; padding-left: var(--space-3); display: flex; flex-direction: column; gap: 2px; }
.images-admin-use-kind { font-weight: 700; color: var(--surface-page-text); }
.images-admin-use-where { color: var(--surface-page-text-muted); }
.images-admin-copy { align-self: flex-start; margin-top: var(--space-1); }

/* FFT-timeline library admin */
.audio-fft-url { font-size: 0.72rem; color: var(--color-charcoal-muted); word-break: break-all; }
.audio-fft-actions { display: flex; gap: var(--space-1); white-space: nowrap; }

/* Email-test admin — SMTP diagnostics surface */
.email-test {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    max-width: 640px;
}

.email-test-actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.email-test-section-title {
    font-size: var(--text-lg);
    margin-bottom: var(--space-3);
}

.email-test-detail {
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
    white-space: pre-wrap;
    word-break: break-word;
}

.email-test-detail.is-ok {
    background-color: #DCFCE7;
    color: var(--alert-success-text);
    border: 1px solid var(--alert-success-border);
}

.email-test-detail.is-error {
    background-color: var(--alert-danger-bg-strong);
    color: var(--color-danger);
    border: 1px solid var(--alert-danger-border);
}

.email-test-config {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-1) var(--space-4);
    margin-top: var(--space-3);
    font-size: var(--text-sm);
}

.email-test-config dt {
    font-weight: 600;
    color: var(--color-charcoal-muted);
}

.email-test-config dd {
    margin: 0;
    color: var(--color-charcoal);
    word-break: break-word;
}


/* --------------------------------------------------------------------------
   36-D. IDENTITY GAPS
   -------------------------------------------------------------------------- */

/* login-local — the email/password form section */
.login-local {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    width: 100%;
    max-width: 380px;
}

/* login-external / social-login — the "Log In with Google" section */
.login-external,
.social-login {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    width: 100%;
    max-width: 380px;
}

/* .btn-google — Google sign-in button.
   AI Note (M5): this button KEEPS a fixed white surface + dark ink on purpose — it
   is a BRAND-standard "Sign in with Google" button (white bg, dark label), not a
   themeable site surface. --color-charcoal (a primitive dark ink) is CORRECT here
   because the surface is a fixed white; theming the text to --surface-*-text would
   make it cream/invisible on white under Dark. Border/hover use --surface-border /
   --surface-deep so the chrome AROUND the fixed white face still follows the theme. */
.btn-google {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-3) var(--space-5);
    background-color: var(--color-white);
    color: var(--color-charcoal);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
    justify-content: center;
    transition: background-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
    box-shadow: var(--shadow-sm);
}

.btn-google:hover {
    background-color: var(--surface-deep);
    box-shadow: var(--shadow-md);
}

/* Google "G" icon chip — the Google-brand mark: a white "G" on the Google-blue
   circular chip, sitting on the button's white face. This is Google's OWN brand
   pairing (white-on-Google-blue), an exact-brand element we do NOT recolor.
   AI Note (M5): the white "G" on --color-brand-google measures 3.56:1 — below the
   4.5 text floor — but it is the mandated Google-mark rendering (identifying
   material we don't own; recoloring it would misrepresent the brand). Documented as
   a brand exception in the contrast sweep's known-accepted list (see
   ContrastOverflowSweepTests.KnownAcceptedContrast). Do NOT "fix" by darkening. */
.google-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background-color: var(--color-brand-google);   /* BL-075: was raw #4285F4 */
    color: var(--color-white);
    font-family: var(--font-body);
    font-size: 12px;
    font-weight: 700;
    flex-shrink: 0;
}

/* btn-passkey-action — passkey action buttons (rename/delete on passkey items) */
.btn-passkey-action {
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-xs);
}

/* hr-replacement-separator — horizontal divider between login sections */
.hr-replacement-separator {
    width: 100%;
    height: 1px;
    background-color: var(--surface-border);
    margin: var(--space-4) 0;
}

/* passkey-section — section wrapping passkey sign-in in Login page */
.passkey-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    align-items: flex-start;
}

/* Manage layout classes */

/* manage-content — the main content column in ManageLayout */
.manage-content {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    min-width: 0;
}

/* manage-nav — alias target for the nav panel in manage layout */
.manage-nav {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* manage-form-wrapper — wraps forms on manage pages */
.manage-form-wrapper {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    max-width: 480px;
    width: 100%;
}

/* recovery-grid-item — individual code cell in the 2FA recovery grid */
.recovery-grid-item {
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--surface-deep-text);
    font-family: var(--font-body);
    text-align: center;
    letter-spacing: 0.08em;
}

/* step-form — multi-step form wrapper (e.g. EnableAuthenticator) */
.step-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    max-width: 480px;
}

/* sectioned-container — a form divided into labeled sections */
.sectioned-container {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

/* panel-padding — adds interior padding to a panel/card */
.panel-padding {
    padding: var(--space-4);
}

/* gap-bottom — simple bottom spacer utility */
.gap-bottom {
    margin-bottom: var(--space-4);
}


/* --------------------------------------------------------------------------
   36-E. BLAZOR RECONNECT MODAL
   -------------------------------------------------------------------------- */

/*
 * Blazor's ReconnectModal renders a <dialog> element. The dialog is styled
 * by the framework's own JS visibility management: it adds CSS classes to
 * the <body> tag (components-reconnect-show, etc.) but the modal's *child
 * content* uses the classes below. We style it as a centered overlay tile
 * in the editorial cream/charcoal palette.
 *
 * AI Note: the <dialog> element gets its position from the framework JS
 * (not from this CSS). We only need to style the container content and
 * the conditional-visibility text/button elements.
 */

#components-reconnect-modal {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: var(--z-modal);
    /* Raised tile on the page — themes reach the reconnect modal too (BL-001). */
    background-color: var(--surface-raised);
    color: var(--surface-raised-text);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-6);
    max-width: min(90vw, 400px);
    width: 100%;
}

#components-reconnect-modal::backdrop {
    background-color: color-mix(in srgb, var(--surface-inverse) 55%, transparent);
    backdrop-filter: blur(2px);
}

.components-reconnect-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-4);
    text-align: center;
}

/* Animated "rejoining" spinner — two bouncing dots */
.components-rejoining-animation {
    display: flex;
    gap: var(--space-3);
    align-items: center;
    justify-content: center;
}

.components-rejoining-animation div {
    width: 10px;
    height: 10px;
    background-color: var(--color-accent);
    border-radius: 50%;
    animation: reconnect-bounce 1.2s ease-in-out infinite;
}

.components-rejoining-animation div:nth-child(2) {
    animation-delay: 0.3s;
}

@keyframes reconnect-bounce {
    0%, 80%, 100% { transform: scale(0.75); opacity: 0.5; }
    40%            { transform: scale(1.0);  opacity: 1.0; }
}

/* All the conditional-visibility paragraphs — hidden by default */
.components-reconnect-container p {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--surface-raised-text-muted); /* text on the raised modal */
    line-height: var(--leading-normal);
    margin: 0;
}

.components-reconnect-container button {
    display: inline-flex;
    align-items: center;
    padding: var(--space-3) var(--space-6);
    /* Inverse pill on the raised modal; accent fill on hover (was charcoal/cream
       primitives — BL-001). */
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    border: none;
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out);
}

.components-reconnect-container button:hover {
    background-color: var(--surface-accent);
    color: var(--surface-accent-text);
}

/* Visibility classes toggled by Blazor's reconnect JS
   The framework uses these class names to show/hide specific messages. */
.components-reconnect-first-attempt-visible,
.components-reconnect-repeated-attempt-visible,
.components-reconnect-failed-visible,
.components-pause-visible,
.components-resume-failed-visible {
    /* These start hidden; the framework removes/adds visibility states.
       We provide base display so they render correctly when visible. */
    display: block;
}

/* Re-use reduced-motion preference */
@media (prefers-reduced-motion: reduce) {
    .components-rejoining-animation div {
        animation: none;
        opacity: 0.7;
    }
}


/* --------------------------------------------------------------------------
   36-F. ALERTS / UTILITY GAPS
   -------------------------------------------------------------------------- */

/* alert-warning — amber-tinted warning alert (used in audio-tab guard) */
.alert-warning {
    display: flex;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background-color: #FEF3C7;
    color: var(--color-warning-deep);
    border: 1px solid #FCD34D;
    border-left: 4px solid #D97706;
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
}

/* alert-link — link inside an alert */
.alert-link {
    color: inherit;
    font-weight: 700;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.alert-link:hover {
    opacity: 0.8;
}

/* alert-text-block — body paragraph within an alert */
.alert-text-block {
    font-size: var(--text-sm);
    line-height: var(--leading-relaxed);
}

/* empty-state — inline empty-state message within a panel */
.empty-state {
    padding: var(--space-5) var(--space-4);
    text-align: center;
    font-size: var(--text-sm);
    color: var(--color-charcoal-muted);
    font-style: italic;
}

/* empty-layout — body-level background for popout/print pages
   (EmptyLayout.razor — no header/nav chrome) */
.empty-layout {
    background-color: #fff;
    color: #000;
    min-height: 100dvh;
}


/* --------------------------------------------------------------------------
   36-G. HELPER CLASSES
   -------------------------------------------------------------------------- */

/* text-secondary — muted secondary text (used in several band portal spots) */
.text-secondary {
    color: var(--color-charcoal-muted);
    font-size: var(--text-sm);
}

/* global-background — override for body background when needed outside layouts */
.global-background {
    background-color: var(--surface-page);
    min-height: 100dvh;
}

/* table-responsive — horizontal-scroll wrapper for tables on narrow screens */
.table-responsive {
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* edit-mode-container — wraps lyrics / version editor inputs */
.edit-mode-container {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* about-members / about-performances — section containers on About page */
.about-members {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.about-performances {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* Band content-view title is now a real <h1> (page-title landmark, BL-005).
   Reset UA heading block-margins so the promoted heading matches the prior
   <div class="playlist-main-title"> layout exactly. */
h1.playlist-main-title {
    margin: 0;
}


/* =========================================================
   37. HOME TILES ADMIN — /admin/home-tiles
   ========================================================= */
/* Three-pane layout: tile list (left), edit form (center), live preview
   (right). Preview re-renders the home grid with in-memory edits so the
   admin sees changes immediately. */

.home-tiles-admin-layout {
    display: grid;
    grid-template-columns: 240px 1fr 380px;
    gap: var(--space-4);
    align-items: start;
}

.home-tiles-admin-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    background-color: var(--surface-raised);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    max-height: 80vh;
    overflow-y: auto;
}

.home-tiles-admin-form {
    background-color: var(--surface-raised);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.home-tiles-admin-preview {
    background-color: var(--surface-deep);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    position: sticky;
    top: calc(var(--header-height, 48px) + var(--space-3));
    max-height: calc(100vh - 80px);
    overflow-y: auto;
}

.home-tiles-admin-preview .tile-eyebrow {
    color: var(--surface-deep-text-muted);
    margin-bottom: var(--space-2);
}

/* Scale the preview down so the full 4-column home grid fits in the
   right pane. transform: scale shrinks; transform-origin top-left keeps
   the grid pinned to the upper-left of the preview frame. */
.home-tiles-admin-preview-frame {
    transform: scale(0.4);
    transform-origin: top left;
    width: 250%;            /* compensate for the 0.4 scale → 1/0.4 */
    pointer-events: none;   /* clicks on preview tiles do nothing */
}

.home-tiles-admin-preview-frame .home-hero {
    padding: var(--space-2);
}

/* Inline 4-input row for grid coordinates */
.home-tiles-admin-grid-row {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-2);
}

.home-tiles-admin-grid-row .admin-field {
    margin: 0;
}

.admin-field-help {
    font-size: var(--text-xs);
    color: var(--surface-raised-text-muted);
    margin-top: 2px;
}

/* Two-column settings form used by /admin/general. Labels right-aligned
   in column 1, inputs + help text in column 2. Stacks on narrow viewports. */
.admin-form-grid {
    display: grid;
    grid-template-columns: 200px 1fr;
    gap: var(--space-3) var(--space-5);
    align-items: start;
    margin-bottom: var(--space-5);
}

.admin-form-grid-label {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    text-align: right;
    padding-top: 0.55rem;   /* aligns label baseline with input text */
    color: inherit;
}

.admin-form-grid-input {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.admin-form-grid-input code {
    background-color: rgba(0, 0, 0, 0.05);
    padding: 1px 4px;
    border-radius: 3px;
    font-size: 0.92em;
}

/* Section header that spans both columns inside .admin-form-grid.
   Used to break a long settings form into labeled groups. Contains
   an eyebrow line + optional help text. The top border + spacing
   visually separates it from the row above. */
.admin-form-grid-section {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding-top: var(--space-4);
    margin-top: var(--space-2);
    border-top: 1px solid var(--surface-raised-border);
}

.admin-form-grid-section:first-child {
    padding-top: 0;
    margin-top: 0;
    border-top: none;
}

.admin-form-grid-section .tile-eyebrow {
    /* eyebrow already styled globally; tighten margins for in-form use */
    margin: 0;
}

/* Inline row that pairs two narrow inputs with a separator between them
   (e.g. width × height, min × max). Lives inside .admin-form-grid-input. */
.admin-form-grid-pair {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.admin-form-grid-pair-sep {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--surface-raised-text-muted);
    user-select: none;
    line-height: 1;
}

@media (max-width: 720px) {
    .admin-form-grid {
        grid-template-columns: 1fr;
    }

    .admin-form-grid-label {
        text-align: left;
        padding-top: 0;
    }
}

/* Responsive: stack on narrower viewports */
@media (max-width: 1280px) {
    .home-tiles-admin-layout {
        grid-template-columns: 200px 1fr;
    }
    .home-tiles-admin-preview {
        grid-column: 1 / -1;
        position: static;
        max-height: none;
    }
    .home-tiles-admin-preview-frame {
        transform: scale(0.55);
        width: 182%;
    }
}

@media (max-width: 880px) {
    .home-tiles-admin-layout {
        grid-template-columns: 1fr;
    }
    .home-tiles-admin-list {
        max-height: none;
    }
}

/* ==========================================================================
   SECTION 37 — IMAGE PICKER MODAL
   ImagePickerModal.razor — admin image browser (HomeTilesAdmin Media section).
   Classes: .img-picker-backdrop, .img-picker-dialog, .img-picker-header,
            .img-picker-title, .img-picker-close, .img-picker-body,
            .img-picker-empty, .img-picker-group-label, .img-picker-row,
            .img-picker-row-active, .img-picker-thumb, .img-picker-meta,
            .img-picker-filename, .img-picker-dims, .img-picker-path,
            .img-picker-footer
   ========================================================================== */

/* Semi-transparent full-viewport backdrop. Clicking it closes the modal. */
.img-picker-backdrop {
    position: fixed;
    inset: 0;
    background-color: rgba(28, 26, 23, 0.55);
    backdrop-filter: blur(2px);
    z-index: var(--z-modal);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
}

/* The dialog panel itself. Fixed width, scrollable body, capped height. */
.img-picker-dialog {
    background-color: var(--surface-page);
    color: var(--surface-page-text);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    width: min(680px, 100%);
    max-height: 82vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Title bar: heading on the left, × button on the right. */
.img-picker-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-4) var(--space-5);
    border-bottom: var(--border-thin);
    flex-shrink: 0;
}

.img-picker-title {
    font-size: var(--text-md);
    font-weight: 600;
    margin: 0;
    color: var(--surface-page-text);
}

.img-picker-close {
    background: none;
    border: none;
    font-size: var(--text-lg);
    line-height: 1;
    color: var(--surface-page-text-muted);
    cursor: pointer;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    transition: color var(--duration-fast) var(--ease-out),
                background-color var(--duration-fast) var(--ease-out);
}

.img-picker-close:hover {
    color: var(--surface-page-text);
    background-color: var(--surface-deep);
}

/* Scrollable image list. */
.img-picker-body {
    overflow-y: auto;
    flex: 1 1 auto;
    padding: var(--space-2) var(--space-4);
}

.img-picker-empty {
    color: var(--surface-page-text-muted);
    font-size: var(--text-sm);
    padding: var(--space-6) 0;
    text-align: center;
}

/* Sub-folder section divider label. */
.img-picker-group-label {
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--surface-page-text-muted);
    padding: var(--space-3) 0 var(--space-2);
    border-bottom: var(--border-thin);
    margin-bottom: var(--space-1);
}

/* Clickable image row: thumbnail on left, text metadata on right. */
.img-picker-row {
    display: flex;
    gap: var(--space-3);
    align-items: center;
    width: 100%;
    padding: var(--space-2);
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    cursor: pointer;
    text-align: left;
    transition: background-color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
    margin-bottom: var(--space-1);
}

.img-picker-row:hover {
    background-color: var(--surface-deep);
}

/* Highlight applied immediately on click, cleared when modal closes. */
.img-picker-row-active {
    background-color: color-mix(in srgb, var(--color-amber) 12%, transparent);
    border-color: color-mix(in srgb, var(--color-amber) 40%, transparent);
}

/* Square thumbnail with centered cover crop. */
.img-picker-thumb {
    width: 64px;
    height: 64px;
    object-fit: cover;
    object-position: center;
    border-radius: var(--radius-sm);
    border: var(--border-thin);
    flex-shrink: 0;
    /* Subtle placeholder while loading="lazy" images arrive. */
    background-color: var(--surface-deep);
}

/* Three-line stacked text block: filename, size+dimensions, path. */
.img-picker-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1;
}

.img-picker-filename {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--surface-page-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.img-picker-dims {
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
}

.img-picker-path {
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
    font-family: var(--font-mono, ui-monospace, monospace);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Footer bar with Cancel button. */
.img-picker-footer {
    padding: var(--space-3) var(--space-5);
    border-top: var(--border-thin);
    display: flex;
    justify-content: flex-end;
    flex-shrink: 0;
}

/* Narrow viewport: modal takes full width with reduced padding. */
@media (max-width: 720px) {
    .img-picker-backdrop {
        padding: var(--space-2);
    }

    .img-picker-header,
    .img-picker-footer {
        padding-left: var(--space-3);
        padding-right: var(--space-3);
    }

    .img-picker-body {
        padding-left: var(--space-3);
        padding-right: var(--space-3);
    }
}

/* ==========================================================================
   SECTION 38 — STEM MIX PANEL (SongPortal audio tab, BandMember)
   "Play a mix" selector: Original / Cover / Stem Mix (+ per-stem checkboxes).
   ========================================================================== */
.stem-mix-panel {
    margin-top: var(--space-5);
    padding: var(--space-4);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    background-color: var(--color-cream-mid);
}

.stem-mix-panel h4 {
    margin: 0 0 var(--space-1);
    font-size: var(--text-sm);
    font-weight: 600;
}

.stem-mix-hint {
    margin: 0 0 var(--space-3);
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
}

.stem-mix-controls {
    display: flex;
    gap: var(--space-2);
    align-items: center;
    flex-wrap: wrap;
}

.stem-mix-source {
    max-width: 240px;
}

/* Stem checkboxes — wrap into a tidy row of pill-ish labels. */
.stem-mix-stems {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: var(--border-thin);
}

.stem-mix-stem {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    cursor: pointer;
}

.stem-mix-stem input[type="checkbox"] {
    accent-color: var(--color-amber);
    width: 15px;
    height: 15px;
    cursor: pointer;
}

/* Pitch shift panel (PitchShift-v1.md) — extends .stem-mix-panel. */
.pitch-shift-field {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
}

.pitch-shift-field input[type="number"] {
    width: 4.5rem;
}

.pitch-shift-actions {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: var(--border-thin);
}

.pitch-tuning-row {
    margin-bottom: var(--space-3);
    padding-bottom: var(--space-3);
    border-bottom: var(--border-thin);
}

.pitch-tuning-result {
    font-size: var(--text-sm);
    color: var(--color-charcoal-muted);
}

.pitch-stem-status {
    display: block;
    margin-top: var(--space-2);
}

/* ==========================================================================
   SECTION 39 — BATCH DOWNLOADER (BandDownloader.razor)
   Song multi-select + a scrollable list + progress.
   ========================================================================== */
.downloader-songs {
    margin-top: var(--space-5);
}

.downloader-songs-header {
    padding-bottom: var(--space-2);
    border-bottom: var(--border-thin);
    margin-bottom: var(--space-2);
    font-weight: 600;
}

.downloader-song-list {
    display: flex;
    flex-direction: column;
    max-height: 360px;
    overflow-y: auto;
    border: var(--border-thin);
    border-radius: var(--radius-md);
}

.downloader-song-head,
.downloader-song-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) minmax(60px, 0.7fr) 3rem 3.4rem 3.4rem;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
}

/* Column header row — sticky so labels stay visible while scrolling. */
.downloader-song-head {
    position: sticky;
    top: 0;
    background-color: var(--color-cream);
    border-bottom: var(--border-thin);
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-charcoal-muted);
    z-index: 1;
}

.downloader-song-row {
    cursor: pointer;
    border-bottom: var(--border-thin);
}

.downloader-song-row:last-child {
    border-bottom: none;
}

.downloader-song-row:hover {
    background-color: var(--surface-deep);
}

.downloader-song-row input[type="checkbox"] {
    accent-color: var(--color-amber);
    width: 15px;
    height: 15px;
    cursor: pointer;
}

.downloader-song-name {
    font-weight: 500;
    color: var(--color-charcoal);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.downloader-song-artist {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Original / Cover / Stems availability indicators. */
.downloader-flag,
.downloader-flag-head {
    text-align: center;
}

.downloader-flag.on {
    color: var(--color-amber);
    font-weight: 700;
}

.downloader-flag.off {
    color: var(--color-charcoal-muted);
    opacity: 0.45;
}

.downloader-progress {
    margin-top: var(--space-4);
}

/* ===== MIDI key check — MV5 read-only review surface (.mv-) ===== */
.mv-summary {
    color: var(--color-charcoal-muted);
    font-size: var(--text-sm);
    margin-bottom: var(--space-4);
}

.mv-summary strong { color: var(--color-accent); }

.mv-link { color: var(--color-accent); }

.mv-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.mv-row {
    background-color: var(--surface-raised);
    color: var(--surface-raised-text);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md, 8px);
    padding: var(--space-3) var(--space-4);
}

/* The most actionable verdict gets the one pop color as a left rule. */
.mv-row:has(.mv-badge-likelywrong) { border-left: 3px solid var(--color-accent); }

.mv-row-head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
}

.mv-song {
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--color-charcoal);
}

.mv-keys { font-size: var(--text-sm); color: var(--color-charcoal-mid); }
.mv-key-stored { font-weight: 600; }
.mv-arrow { color: var(--color-charcoal-muted); margin: 0 0.15em; }
.mv-key-proposed { font-weight: 600; color: var(--color-accent); }
.mv-transpose { color: var(--color-charcoal-muted); }

.mv-explain {
    margin: var(--space-2) 0 0;
    font-size: var(--text-sm);
    color: var(--color-charcoal-mid);
}

.mv-meta {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin-top: var(--space-2);
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
}

/* Status badges — palette-respecting: the accent is loudest (likely wrong), neutrals for the rest. */
.mv-badge {
    display: inline-block;
    padding: 0.1em 0.6em;
    border-radius: var(--radius-pill, 999px);
    font-size: var(--text-xs);
    font-weight: 600;
    white-space: nowrap;
}

.mv-badge-likelywrong { background-color: var(--color-accent); color: var(--color-white); }
.mv-badge-suspect { background-color: var(--color-accent-dim); color: var(--color-accent-text); } /* BL-001/FLG-CLR-002: amber-on-tint */
.mv-badge-possibletransposition { background-color: var(--color-cream-deep); color: var(--color-charcoal-mid); border: 1px solid var(--color-cream-mid); }
.mv-badge-confirmed { background-color: var(--color-cream-deep); color: var(--color-charcoal-muted); }
.mv-badge-insufficient { background-color: var(--color-cream-mid); color: var(--color-charcoal-muted); }

.mv-sources { margin-top: var(--space-2); }

.mv-sources > summary {
    cursor: pointer;
    font-size: var(--text-xs);
    color: var(--color-charcoal-muted);
}

.mv-source-list {
    list-style: none;
    margin: var(--space-2) 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    font-size: var(--text-xs);
}

.mv-source {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-2);
    color: var(--color-charcoal-mid);
}

.mv-source-status { font-weight: 600; color: var(--color-charcoal-muted); }
.mv-source-used { color: var(--color-accent); }
.mv-source-label { color: var(--color-charcoal-mid); }
.mv-source-key { color: var(--color-charcoal); }
.mv-source-note { color: var(--color-charcoal-muted); font-style: italic; }
.mv-source-url { color: var(--color-accent); }

/* MX-E6: "adopt the MIDI version" expander inside an instrument-line editor. */
.ile-midi { margin-top: var(--space-3); }

.ile-midi > summary {
    cursor: pointer;
    user-select: none;
    font-size: var(--text-sm);
    color: var(--color-accent);
}


/* =========================================================
   37. PRACTICE GAMES — LYRIC GAMES
   (ClozeGame, SequencerGame, NextLineGame,
    FadingScaffoldGame, WrongWordGame)
   ========================================================= */

/* ---------- Shared lyric-game setup-screen pattern (BL-010 / BL-053 / BL-059) ----------
   ClozeGame, SequencerGame, NextLineGame, FadingScaffoldGame, WrongWordGame all ship the same
   setup markup (-setup-wrap / -back / -blurb / -setup / -field / -select-wide / -check / -chip /
   -chip-row / -start / -error), but only the two -setup-wrap selectors were ever styled — nl/ww/fs
   fell back to bare UA chrome (edge-to-edge, default-blue underlined back-link) and cloze's
   difficulty chips / trouble checkbox sat below the 24px target floor. This one block styles all
   five on a single class set so the back-link, label weight, select size, chip size and row gaps
   are uniform (matches the sibling cg/wc/nc/ps chord-game group below). */
.cloze-setup-wrap,
.seq-setup-wrap,
.nl-setup-wrap,
.ww-setup-wrap,
.fs-setup-wrap {
    max-width: 480px;
    margin: 0 auto;
    padding: 1.5rem 1rem;
}

.cloze-back, .seq-back, .nl-back, .ww-back, .fs-back {
    display: inline-block;
    margin-bottom: 1rem;
    font-size: 0.9rem;
    /* Was UA default-blue underlined on nl/ww/fs — the games palette link color, retuned in
       BL-059 to clear 4.5:1 on the game-bg surface. */
    color: var(--game-light-primary);
    text-decoration: none;
}
.cloze-back:hover, .seq-back:hover, .nl-back:hover, .ww-back:hover, .fs-back:hover { text-decoration: underline; }

.cloze-blurb, .seq-blurb, .nl-blurb, .ww-blurb, .fs-blurb {
    /* Setup screens render on EmptyLayout's light page, so muted text uses the light-surface
       muted token (BL-059) — the dark --game-text-muted would fail 4.5:1 here. */
    color: var(--game-light-muted);
    margin: 0 0 1rem;
    font-size: 0.9rem;
}

.cloze-setup, .seq-setup, .nl-setup, .ww-setup, .fs-setup {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.cloze-field, .seq-field, .nl-field, .ww-field, .fs-field {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-size: 0.85rem;
    color: var(--game-light-muted);
}
.cloze-field > span, .seq-field > span, .nl-field > span, .ww-field > span, .fs-field > span {
    font-weight: 600;
    color: var(--game-text);
}

.cloze-select-wide, .seq-select-wide, .nl-select-wide, .ww-select-wide, .fs-select-wide {
    width: 100%;
    min-height: 24px;   /* BL-028: hold the 24px target floor for the native select */
}

/* Difficulty / option chip-row (cloze difficulty, nl option-count, etc.). */
.cloze-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}
.cloze-chip {
    /* BL-028 / FLG-PG-GAMES-1-02 — was ~22px, below the 24px target floor.
       Setup renders on the light page, so the chip is dark-text-on-light with the light-surface
       primary as its selected fill (all pairings clear AA — see BL-059). */
    min-height: 24px;
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0.7rem;
    border-radius: 999px;
    border: 1px solid var(--game-light-border);
    background: var(--game-light-bg);
    color: var(--color-charcoal);   /* charcoal on #f0eefb = 13.6:1 */
    font-size: 0.85rem;
    cursor: pointer;
}
.cloze-chip:hover { border-color: var(--game-light-primary); }
.cloze-chip.is-active {
    border-color: var(--game-light-primary);
    background: var(--game-light-primary);
    color: var(--color-white);   /* white on #6a5acd = 4.68:1 */
}

/* Trouble-spots checkbox row — the raw 13×13px checkbox was below the 24px floor;
   size the whole label as the hit target and enlarge the box. */
.cloze-check {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 24px;
    font-size: 0.85rem;
    color: var(--color-charcoal);
    cursor: pointer;
}
.cloze-check input[type="checkbox"] {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    cursor: pointer;
}

.cloze-start, .seq-start, .nl-start, .ww-start, .fs-start { align-self: flex-start; }
.cloze-error, .seq-error, .nl-error, .ww-error, .fs-error { color: var(--game-danger); font-size: 0.85rem; }

/* ---------- ClozeGame ---------- */
/* Fullscreen drill: fixed topbar, scrolling lyrics zone, fixed bottom option bar. */

.cloze-back {
    display: inline-block;
    margin-bottom: 1rem;
    font-size: 0.9rem;
    color: var(--game-light-primary);
    text-decoration: none;
}
.cloze-back:hover { text-decoration: underline; }

/* Viewport-filling stage split at 48 / 52 vh */
.cloze-topbar {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 3.2rem;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0 1rem;
    background: var(--game-card);
    border-bottom: 1px solid var(--game-border);
    z-index: var(--z-sticky);
}
.cloze-timer {
    font-variant-numeric: tabular-nums;
    font-size: 1.4rem;
    font-weight: 800;
    color: var(--game-light-primary);
}
.cloze-progress  { font-size: 0.9rem; color: var(--game-text-muted); }
.cloze-misses    { font-size: 0.9rem; color: var(--game-light-danger); }
.cloze-cancel {
    margin-left: auto;
    border: none;
    background: transparent;
    font-size: 1.2rem;
    color: var(--game-text-muted);
    cursor: pointer;
    padding: 0.3rem 0.5rem;
}
.cloze-cancel:hover { color: var(--game-text); }

.cloze-lyrics-scroll {
    position: fixed;
    top: 3.2rem;
    left: 0; right: 0;
    /* End the scroll area exactly at the option/result bar's top (bar is height:52vh, bottom:0).
       Previously height:48vh overshot the bar by the 3.2rem top offset, so the last lines scrolled
       under the bar. bottom:52vh tracks the bar height directly. */
    bottom: 52vh;
    overflow-y: auto;
    padding: 1rem;
}
.cloze-lyrics-content { max-width: 680px; margin: 0 auto; }
.cloze-zip { font-size: 0.65rem; color: var(--game-text-muted); letter-spacing: 0.04em; text-transform: uppercase; margin-bottom: 0.5rem; }

.cloze-section    { margin-bottom: 1.2rem; }
.cloze-section-head { /* handled by global section heading styles */ }
.cloze-line       { line-height: 1.8; margin-bottom: 0.15rem; }
.cloze-word       { margin-right: 0.3em; }
.cloze-tok        {
    display: inline-block;
    padding: 0 0.2em;
    border-radius: 3px;
    transition: background var(--duration-fast);
}
/* Glide highlight — emphasizes the active blank's lyrics context */
.cloze-tok.is-glide {
    background: color-mix(in srgb, var(--game-light-primary) 18%, transparent);
}

/* Fixed option bar at the bottom (results are a separate light screen — see .cloze-results) */
.cloze-optionbar {
    position: fixed;
    bottom: 0; left: 0; right: 0;
    height: 52vh;
    overflow-y: auto;
    padding: 1rem;
    background: var(--game-bg);
    border-top: 1px solid var(--game-border);
}
.cloze-optiongrid {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    justify-content: center;
    max-width: 600px;
    margin: 0 auto;
}
.cloze-option {
    padding: 0.6rem 1.1rem;
    border-radius: 8px;
    border: 1px solid var(--game-border);
    background: var(--game-card);
    color: var(--game-text);
    font-size: 1rem;
    cursor: pointer;
    transition: border-color var(--duration-fast), background var(--duration-fast);
}
.cloze-option:hover:not(:disabled) { border-color: var(--game-accent); }
.cloze-option.is-wrong {
    border-color: var(--game-danger-border);
    background: var(--game-danger-bg);
    color: var(--game-danger);
    cursor: not-allowed;
    animation: cloze-shake 0.25s;
}
@keyframes cloze-shake {
    0%, 100% { transform: translateX(0); }
    25%       { transform: translateX(-5px); }
    75%       { transform: translateX(5px); }
}

/* Results + trouble list (shared shape across all lyric games) */
.cloze-result-score  { font-size: 2rem; font-weight: 800; color: var(--game-light-primary); }
.cloze-result-time   { font-size: 2rem; font-weight: 800; color: var(--game-light-primary); display: inline-flex; align-items: baseline; gap: 0.5rem; justify-content: center; }
.cloze-newbest       { font-size: 1rem; font-weight: 700; color: var(--game-light-success); }
.cloze-recent-pill   { display: inline-flex; align-items: center; padding: 0.1rem 0.5rem; border-radius: var(--radius-full); border: 1px solid var(--game-border); color: var(--game-text-muted); font-size: 0.72rem; font-variant-numeric: tabular-nums; }
.cloze-result-sub    { font-size: 1rem; color: var(--game-text-muted); font-variant-numeric: tabular-nums; }
.cloze-result-best   { font-size: 0.95rem; color: var(--game-text-muted); font-variant-numeric: tabular-nums; }
.cloze-result-best.is-new { color: var(--game-light-success); font-weight: 700; }
.cloze-result-actions { display: flex; gap: 0.6rem; margin-top: 0.8rem; }
.cloze-trouble-list  { width: 100%; max-width: 440px; text-align: left; margin-top: 0.5rem; }
.cloze-trouble-list h4 { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--game-light-danger); margin: 0 0 0.3rem; }
.cloze-trouble-line  { font-size: 0.9rem; padding: 0.18rem 0; border-bottom: 1px dotted var(--game-border); }
.cloze-trouble-more  { font-size: 0.8rem; color: var(--game-text-muted); margin-top: 0.25rem; }

/* Recent-miss counter chips in the topbar */
.cloze-recent       { display: inline-flex; gap: 0.3rem; }
.cloze-recent-chip  {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.4rem; height: 1.4rem;
    padding: 0 0.2rem;
    border-radius: var(--radius-full);
    font-size: 0.72rem;
    font-weight: 700;
    background: var(--game-danger-border);
    color: var(--game-text);
}


/* ---------- SequencerGame ---------- */
/* flex-column 100vh stage (not fixed-position like Cloze). */

.seq-topbar {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.8rem 1rem;
    border-bottom: 1px solid var(--game-border);
    background: var(--game-card);
}
.seq-sofar   { padding: 0.8rem 1rem; font-size: 0.9rem; color: var(--game-text-muted); }
.seq-chips   { display: flex; flex-wrap: wrap; gap: 0.5rem; padding: 0.5rem 1rem 0.8rem; }
.seq-chip {
    padding: 0.4rem 0.8rem;
    border-radius: 8px;
    border: 1px solid var(--game-border);
    background: var(--game-card);
    color: var(--game-text);
    font-size: 0.95rem;
    cursor: pointer;
    transition: border-color var(--duration-fast);
}
.seq-chip:hover { border-color: var(--game-accent); }
.seq-chip.is-correct { border-color: var(--game-success-border); background: var(--game-success-bg); color: var(--game-success); cursor: default; }
.seq-chip.is-wrong   { border-color: var(--game-danger-border);  background: var(--game-danger-bg);  color: var(--game-danger);  cursor: default; animation: seq-shake 0.25s; }
@keyframes seq-shake {
    0%, 100% { transform: translateX(0); }
    25%       { transform: translateX(-4px); }
    75%       { transform: translateX(4px); }
}

.seq-tray {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 1rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    align-content: flex-start;
}
.seq-card {
    padding: 0.55rem 0.9rem;
    border-radius: 8px;
    border: 1px solid var(--game-border);
    background: var(--game-card);
    color: var(--game-text);
    font-size: 0.95rem;
    cursor: pointer;
    transition: border-color var(--duration-fast), background var(--duration-fast);
}
.seq-card:hover  { border-color: var(--game-accent); }
.seq-card.is-used { opacity: 0.35; cursor: default; }

.seq-results { padding: 1.5rem 1rem; text-align: center; }
.seq-result-score { font-size: 2rem; font-weight: 800; color: var(--game-light-primary); }
.seq-result-sub   { font-size: 1rem; color: var(--game-text-muted); }
.seq-result-best  { font-size: 0.9rem; color: var(--game-text-muted); }
.seq-result-best.is-new { color: var(--game-light-success); font-weight: 700; }
.seq-result-actions { display: flex; gap: 0.6rem; justify-content: center; margin-top: 0.8rem; }
.seq-trouble-list { width: 100%; max-width: 440px; text-align: left; margin: 0.5rem auto 0; }
.seq-trouble-list h4 { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--game-light-danger); margin: 0 0 0.3rem; }
.seq-trouble-line { font-size: 0.9rem; padding: 0.18rem 0; border-bottom: 1px dotted var(--game-border); }
.seq-trouble-more { font-size: 0.8rem; color: var(--game-text-muted); margin-top: 0.25rem; }


/* ---------- NextLineGame ---------- */
/* Fixed-position stage: top 48 vh = cue, bottom 52 vh = options. */

.nl-topbar {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 3.2rem;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0 1rem;
    background: var(--game-card);
    border-bottom: 1px solid var(--game-border);
    z-index: var(--z-sticky);
}

.nl-cue {
    position: fixed;
    top: 3.2rem; left: 0; right: 0;
    height: calc(48vh - 3.2rem);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    text-align: center;
}
.nl-cue-label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--game-text-muted); margin-bottom: 0.5rem; }
.nl-cue-line  { font-size: 1.4rem; font-weight: 600; line-height: 1.4; max-width: 640px; }

.nl-reveal {
    position: fixed;
    top: 3.2rem; left: 0; right: 0;
    height: calc(48vh - 3.2rem);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    text-align: center;
    background: var(--game-light-success-bg);
}

.nl-answerbar {
    position: fixed;
    bottom: 0; left: 0; right: 0;
    height: 52vh;
    overflow-y: auto;
    padding: 1rem;
    background: var(--game-bg);
    border-top: 1px solid var(--game-border);
}
.nl-optiongrid {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    max-width: 600px;
    margin: 0 auto;
}
.nl-option {
    padding: 0.7rem 1rem;
    border-radius: 10px;
    border: 1px solid var(--game-border);
    background: var(--game-card);
    color: var(--game-text);
    font-size: 1rem;
    text-align: left;
    cursor: pointer;
    transition: border-color var(--duration-fast), background var(--duration-fast);
}
.nl-option:hover:not(:disabled) { border-color: var(--game-accent); }
.nl-option.is-correct { border-color: var(--game-success-border); background: var(--game-success-bg); color: var(--game-success); cursor: default; }
.nl-option.is-wrong   { border-color: var(--game-danger-border);  background: var(--game-danger-bg);  color: var(--game-danger);  cursor: not-allowed; animation: nl-shake 0.25s; }
.nl-type { font-size: 0.78rem; color: var(--game-text-muted); margin-top: 0.3rem; }

@keyframes nl-shake {
    0%, 100% { transform: translateX(0); }
    25%       { transform: translateX(-5px); }
    75%       { transform: translateX(5px); }
}
@keyframes nl-slide-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

/* Standalone results screen — shared shape across lyric games (light, centered, scrollable). */
.nl-results,
.cloze-results {
    height: 100vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 1.5rem 1rem;
    text-align: center;
}
.cloze-result-stats { display: flex; flex-direction: column; align-items: center; gap: 0.45rem; }
.nl-result-score { font-size: 2rem; font-weight: 800; color: var(--game-light-primary); }
.nl-result-sub   { font-size: 1rem; color: var(--game-text-muted); font-variant-numeric: tabular-nums; }
.nl-result-best  { font-size: 0.9rem; color: var(--game-text-muted); font-variant-numeric: tabular-nums; }
.nl-result-best.is-new { color: var(--game-light-success); font-weight: 700; }
.nl-result-actions { display: flex; gap: 0.6rem; margin-top: 0.8rem; }
.nl-trouble-list { width: 100%; max-width: 440px; text-align: left; margin-top: 0.5rem; }
.nl-trouble-list h4 { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--game-light-danger); margin: 0 0 0.3rem; }
.nl-trouble-line { font-size: 0.9rem; padding: 0.18rem 0; border-bottom: 1px dotted var(--game-border); }
.nl-trouble-more { font-size: 0.8rem; color: var(--game-text-muted); margin-top: 0.25rem; }


/* ---------- FadingScaffoldGame ---------- */
/* Full-height flex-column; progressive blanking of lyrics. */

.fs-stage  { display: flex; flex-direction: column; min-height: 100vh; }
.fs-topbar {
    flex: 0 0 3.2rem;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0 1rem;
    background: var(--game-card);
    border-bottom: 1px solid var(--game-border);
}
.fs-body    { flex: 1 1 auto; overflow-y: auto; padding: 1rem; }
.fs-section { margin-bottom: 1.4rem; }

/* Each scaffold rung: full/blank/partial variants */
.fs-rung-full   { opacity: 1; }
.fs-rung-hint   { opacity: 0.65; }
.fs-rung-blank  { opacity: 0.35; }

.fs-line     { line-height: 1.8; margin-bottom: 0.1rem; }
.fs-scaffold { display: inline; }
.fs-word     { display: inline; }
.fs-full     { display: inline; }
.fs-blank-bar {
    display: inline-block;
    width: 5em;
    height: 0.15em;
    background: var(--game-text-muted);
    border-radius: 2px;
    vertical-align: middle;
    margin: 0 0.15em;
}
.fs-prompt {
    padding: 0.8rem 1rem;
    border-top: 1px solid var(--game-border);
    text-align: center;
    font-size: 1.2rem;
    font-weight: 600;
}
.fs-reveal { color: var(--game-light-success); }

/* Rate buttons after each section */
.fs-rate    { display: flex; gap: 0.5rem; flex-wrap: wrap; justify-content: center; margin-top: 0.5rem; }
.fs-ratebtn {
    padding: 0.4rem 0.9rem;
    border-radius: 8px;
    border: 1px solid var(--game-border);
    background: var(--game-card);
    color: var(--game-text);
    cursor: pointer;
    transition: border-color var(--duration-fast);
}
.fs-ratebtn:hover { border-color: var(--game-accent); }
.fs-ratebtn.is-good { border-color: var(--game-success-border); background: var(--game-success-bg); color: var(--game-success); }
.fs-ratebtn.is-bad  { border-color: var(--game-danger-border);  background: var(--game-danger-bg);  color: var(--game-danger);  }

@keyframes fs-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes fs-pop {
    0%   { transform: scale(1); }
    50%  { transform: scale(1.06); }
    100% { transform: scale(1); }
}

.fs-results { padding: 1.5rem 1rem; text-align: center; }
.fs-result-score { font-size: 2rem; font-weight: 800; color: var(--game-light-primary); }
.fs-result-sub   { font-size: 1rem; color: var(--game-text-muted); }
.fs-result-best  { font-size: 0.9rem; color: var(--game-text-muted); }
.fs-result-best.is-new { color: var(--game-light-success); font-weight: 700; }
.fs-result-actions { display: flex; gap: 0.6rem; justify-content: center; margin-top: 0.8rem; }
.fs-trouble-list { width: 100%; max-width: 440px; text-align: left; margin: 0.5rem auto 0; }
.fs-trouble-list h4 { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--game-light-danger); margin: 0 0 0.3rem; }
.fs-trouble-line { font-size: 0.9rem; padding: 0.18rem 0; border-bottom: 1px dotted var(--game-border); }
.fs-trouble-more { font-size: 0.8rem; color: var(--game-text-muted); margin-top: 0.25rem; }


/* ---------- WrongWordGame ---------- */
/* Full-height flex-column; walk through the song word-by-word. */

.ww-stage  { display: flex; flex-direction: column; min-height: 100vh; }
.ww-topbar {
    flex: 0 0 3.2rem;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0 1rem;
    background: var(--game-card);
    border-bottom: 1px solid var(--game-border);
}
.ww-scroll { flex: 1 1 auto; overflow-y: auto; padding: 1rem; }

.ww-section-head {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--game-text-muted);
    margin: 1rem 0 0.3rem;
}
.ww-row {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.4rem 0;
    border-radius: 6px;
    transition: background var(--duration-fast), opacity var(--duration-fast);
}
.ww-row.is-done     { opacity: 0.4; }
.ww-row.is-active   { background: color-mix(in srgb, var(--game-light-primary) 8%, transparent); padding-left: 0.5rem; }
.ww-row.is-upcoming { opacity: 0.55; }
.ww-word {
    padding: 0 0.18em;
    border-radius: 3px;
    transition: background var(--duration-fast), color var(--duration-fast);
}
.ww-word.is-current  { background: color-mix(in srgb, var(--game-light-primary) 20%, transparent); }
.ww-word.is-correct  { background: var(--game-light-success-bg); color: var(--game-light-success); }
.ww-word.is-wrong    { background: var(--game-light-danger-bg);  color: var(--game-light-danger); animation: ww-shake 0.25s; }

.ww-foot       { flex: 0 0 auto; padding: 0.8rem 1rem; border-top: 1px solid var(--game-border); background: var(--game-bg); }
.ww-hint       { font-size: 0.88rem; color: var(--game-text-muted); margin-bottom: 0.5rem; }
.ww-correction { font-size: 0.88rem; color: var(--game-light-success); margin-top: 0.3rem; }

@keyframes ww-row-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}
@keyframes ww-shake {
    0%, 100% { transform: translateX(0); }
    25%       { transform: translateX(-4px); }
    75%       { transform: translateX(4px); }
}
@keyframes ww-pop {
    0%   { transform: scale(1); }
    50%  { transform: scale(1.08); }
    100% { transform: scale(1); }
}

.ww-results { padding: 1.5rem 1rem; text-align: center; }
.ww-result-score { font-size: 2rem; font-weight: 800; color: var(--game-light-primary); }
.ww-result-sub   { font-size: 1rem; color: var(--game-text-muted); }
.ww-result-best  { font-size: 0.9rem; color: var(--game-text-muted); }
.ww-result-best.is-new { color: var(--game-light-success); font-weight: 700; }
.ww-result-actions { display: flex; gap: 0.6rem; justify-content: center; margin-top: 0.8rem; }
.ww-trouble-list { width: 100%; max-width: 440px; text-align: left; margin: 0.5rem auto 0; }
.ww-trouble-list h4 { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--game-light-danger); margin: 0 0 0.3rem; }
.ww-trouble-line { font-size: 0.9rem; padding: 0.18rem 0; border-bottom: 1px dotted var(--game-border); }
.ww-trouble-more { font-size: 0.8rem; color: var(--game-text-muted); margin-top: 0.25rem; }

@media (prefers-reduced-motion: reduce) {
    .cloze-option.is-wrong,
    .seq-chip.is-wrong,
    .nl-option.is-wrong,
    .ww-word.is-wrong { animation: none; }
    .nl-option.is-wrong,
    .cloze-option.is-wrong { transform: none; }
}


/* =========================================================
   38. PRACTICE GAMES — CHORD GAMES, WHICH-VERSION & DASHBOARD
   (ChordClozeGame, WrongChordGame, NextChordGame,
    ProgressionSequencerGame, WhichVersionGame,
    PracticeDashboard, NoteLineGame)
   ========================================================= */

/* ---------- Shared chord-game setup pattern ---------- */
/* All chord games share this centered max-width setup card. */
.cg-setup-wrap,
.wc-setup-wrap,
.nc-setup-wrap,
.ps-setup-wrap {
    max-width: 560px;
    margin: 0 auto;
    padding: var(--space-6);
}
.cg-back, .wc-back, .nc-back, .ps-back {
    font-size: 0.85rem;
    color: var(--game-accent);
    text-decoration: none;
}
.cg-back:hover, .wc-back:hover, .nc-back:hover, .ps-back:hover { text-decoration: underline; }

.cg-blurb, .wc-blurb, .nc-blurb, .ps-blurb {
    color: var(--game-text-muted);
    margin: 0 0 var(--space-5);
}
.cg-setup, .wc-setup, .nc-setup, .ps-setup {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}
.cg-field, .wc-field, .nc-field, .ps-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-size: 0.85rem;
    color: var(--game-text-muted);
}
.cg-select-wide, .wc-select-wide, .nc-select-wide, .ps-select-wide { width: 100%; }
.cg-start, .wc-start, .nc-start, .ps-start { align-self: flex-start; }
.cg-note,  .wc-note,  .nc-note,  .ps-note  { color: var(--game-text-muted); font-size: 0.85rem; }
.cg-error, .wc-error, .nc-error, .ps-error  { color: var(--game-danger); }

/* ---------- Shared chord-game stage topbar + key-line ---------- */
.cg-topbar, .wc-topbar, .nc-topbar, .ps-topbar {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    font-variant-numeric: tabular-nums;
    margin-bottom: var(--space-4);
}
.cg-timer, .wc-timer, .nc-timer, .ps-timer { font-size: 1.1rem; font-weight: 700; }
.cg-progress, .cg-accuracy,
.wc-progress, .wc-accuracy,
.nc-progress, .nc-accuracy,
.ps-count { color: var(--game-text-muted); }
.cg-cancel, .wc-cancel, .nc-cancel, .ps-cancel {
    margin-left: auto;
    background: none;
    border: none;
    color: var(--game-text-muted);
    font-size: 1.1rem;
    cursor: pointer;
}
.cg-cancel:hover, .wc-cancel:hover, .nc-cancel:hover, .ps-cancel:hover { color: var(--game-text); }
.cg-keyline, .wc-keyline, .nc-keyline, .ps-keyline {
    color: var(--game-text-muted);
    font-size: 0.9rem;
    margin-bottom: var(--space-4);
}
.cg-keyline strong, .wc-keyline strong, .nc-keyline strong, .ps-keyline strong { color: var(--game-text); }

/* ---------- Shared chord-section layout ---------- */
.cg-sections, .wc-sections { display: flex; flex-direction: column; gap: var(--space-5); }
.cg-section-head, .wc-section-head {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--game-text-muted);
    margin-bottom: 6px;
}
.cg-progression, .wc-progression {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: flex-start;
}

/* ---------- ChordClozeGame (cg-*) ---------- */
.cg-stage { max-width: 820px; margin: 0 auto; padding: var(--space-5); }

.cg-chip {
    display: inline-flex;
    align-items: center;
    min-width: 3.2rem;
    justify-content: center;
    padding: 0.5rem 0.7rem;
    border-radius: 8px;
    font-weight: 700;
    font-size: 1.15rem;
    border: 2px solid var(--game-border);
    background: var(--game-card);
}
.cg-chip-given   { color: var(--game-text); }
.cg-chip-correct { border-color: var(--game-success-border); background: var(--game-success-bg); color: var(--game-success); }

.cg-blank {
    display: inline-grid;
    grid-template-columns: 1fr 1fr;
    gap: 4px;
    padding: 4px;
    border-radius: 8px;
    border: 2px dashed var(--game-accent);
}
.cg-choice {
    border: 1px solid var(--game-border);
    border-radius: 6px;
    background: var(--game-card-alt);
    color: var(--game-text);
    font-weight: 700;
    font-size: 1rem;
    padding: 0.35rem 0.6rem;
    cursor: pointer;
    transition: border-color var(--duration-fast), background var(--duration-fast);
}
.cg-choice:hover:not(:disabled) { border-color: var(--game-accent); background: var(--game-card-hover); }
.cg-choice:focus-visible         { outline: 2px solid var(--game-accent); outline-offset: 1px; }
.cg-choice.is-wrong              { border-color: var(--game-danger-border); background: var(--game-danger-bg); color: var(--game-danger); cursor: not-allowed; }

.cg-foot { margin-top: var(--space-6); }

.cg-results      { max-width: 480px; margin: 0 auto; padding: var(--space-6); text-align: center; }
.cg-result-score { font-size: 2rem; font-weight: 800; }
.cg-result-sub   { color: var(--game-text-muted); margin: var(--space-2) 0 var(--space-4); }
.cg-result-best  { color: var(--game-text-muted); margin-bottom: var(--space-4); }
.cg-result-best.is-new { color: var(--game-gold); font-weight: 700; }
.cg-result-actions { display: flex; gap: var(--space-3); justify-content: center; }


/* ---------- WrongChordGame (wc-*) ---------- */
.wc-stage { max-width: 820px; margin: 0 auto; padding: var(--space-5); }

.wc-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-width: 3.2rem;
    justify-content: center;
    padding: 0.5rem 0.7rem;
    border-radius: 8px;
    font-weight: 700;
    font-size: 1.15rem;
    cursor: pointer;
    border: 2px solid var(--game-border);
    background: var(--game-card);
    color: var(--game-text);
    transition: border-color var(--duration-fast), background var(--duration-fast);
}
.wc-chip:hover:not(:disabled) { border-color: var(--game-accent); }
.wc-chip:focus-visible         { outline: 2px solid var(--game-accent); outline-offset: 2px; }
.wc-chip:disabled              { cursor: default; }
.wc-chip-found   { border-color: var(--game-success-border); background: var(--game-success-bg); color: var(--game-success); }
.wc-chip-tapped  { border-color: var(--game-danger-border);  background: var(--game-danger-bg);  color: var(--game-danger); }
.wc-mark         { font-size: 0.8rem; }
.wc-reveal       { font-size: 0.85rem; color: var(--game-text-muted); margin-top: 6px; }
.wc-lure         { color: var(--game-danger); }
.wc-reveal strong { color: var(--game-success); }
.wc-foot         { margin-top: var(--space-6); }

.wc-results      { max-width: 480px; margin: 0 auto; padding: var(--space-6); text-align: center; }
.wc-result-score { font-size: 2rem; font-weight: 800; }
.wc-result-sub   { color: var(--game-text-muted); margin: var(--space-2) 0 var(--space-4); }
.wc-result-best  { color: var(--game-text-muted); margin-bottom: var(--space-4); }
.wc-result-best.is-new { color: var(--game-gold); font-weight: 700; }
.wc-result-actions { display: flex; gap: var(--space-3); justify-content: center; }


/* ---------- NextChordGame (nc-*) ---------- */
.nc-stage { max-width: 820px; margin: 0 auto; padding: var(--space-5); }

.nc-trail {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    padding: var(--space-4);
    border-radius: 8px;
    background: var(--game-card);
    margin-bottom: var(--space-4);
    min-height: 3.5rem;
}
.nc-section {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--game-text-muted);
    border-left: 2px solid var(--game-border);
    padding-left: 6px;
    margin-left: 4px;
}
.nc-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.8rem;
    padding: 0.4rem 0.6rem;
    border-radius: 8px;
    font-weight: 700;
    font-size: 1.1rem;
    border: 2px solid var(--game-border);
    background: var(--game-bg);
    color: var(--game-text);
}
.nc-chip-current { border-color: var(--game-accent); }
.nc-chip-unknown { color: var(--game-text-muted); border-style: dashed; }
.nc-arrow        { color: var(--game-text-muted); font-size: 1.2rem; }

.nc-prompt  { font-weight: 600; margin-bottom: var(--space-3); }
.nc-options { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.nc-choice {
    min-width: 3.5rem;
    padding: 0.6rem 1rem;
    border-radius: 8px;
    border: 2px solid var(--game-border);
    background: var(--game-card-alt);
    color: var(--game-text);
    font-weight: 700;
    font-size: 1.1rem;
    cursor: pointer;
    transition: border-color var(--duration-fast), background var(--duration-fast);
}
.nc-choice:hover:not(:disabled) { border-color: var(--game-accent); background: var(--game-card-hover); }
.nc-choice:focus-visible         { outline: 2px solid var(--game-accent); outline-offset: 2px; }
.nc-choice.is-wrong              { border-color: var(--game-danger-border); background: var(--game-danger-bg); color: var(--game-danger); cursor: not-allowed; }

.nc-results      { max-width: 480px; margin: 0 auto; padding: var(--space-6); text-align: center; }
.nc-result-score { font-size: 2rem; font-weight: 800; }
.nc-result-sub   { color: var(--game-text-muted); margin: var(--space-2) 0 var(--space-4); }
.nc-result-best  { color: var(--game-text-muted); margin-bottom: var(--space-4); }
.nc-result-best.is-new { color: var(--game-gold); font-weight: 700; }
.nc-result-actions { display: flex; gap: var(--space-3); justify-content: center; }


/* ---------- ProgressionSequencerGame (ps-*) ---------- */
.ps-stage   { max-width: 640px; margin: 0 auto; padding: var(--space-5); }
.ps-keyline { color: var(--game-text-muted); font-size: 0.9rem; margin-bottom: var(--space-4); }
.ps-keyline strong { color: var(--game-text); }

.ps-banner {
    padding: var(--space-3) var(--space-4);
    border-radius: 8px;
    margin-bottom: var(--space-4);
    font-weight: 600;
    background: var(--game-card);
    border: 1px solid var(--game-border);
}
.ps-banner.is-perfect { background: #1a3a24; border-color: #2a5a34; color: var(--game-success); }
.ps-best-new { color: var(--game-gold); }

.ps-list {
    list-style: none;
    margin: 0 0 var(--space-5);
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.ps-card {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: 8px;
    border: 2px solid var(--game-border);
    background: var(--game-card);
}
.ps-card.is-ok  { border-color: var(--game-success-border); background: var(--game-success-bg); }
.ps-card.is-bad { border-color: var(--game-danger-border);  background: var(--game-danger-bg); }

.ps-pos {
    flex-shrink: 0;
    width: 1.8rem; height: 1.8rem;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--game-bg);
    color: var(--game-text-muted);
    font-weight: 700;
    font-size: 0.9rem;
}
.ps-body   { flex: 1; min-width: 0; }
.ps-label  { font-weight: 600; margin-bottom: 4px; }
.ps-chords { display: flex; flex-wrap: wrap; gap: 4px; }
.ps-chord {
    font-size: 0.85rem;
    font-weight: 700;
    padding: 1px 6px;
    border-radius: 4px;
    background: var(--game-bg);
    color: var(--game-text);
    border: 1px solid var(--game-border);
}
.ps-should { font-size: 0.8rem; color: var(--game-danger); margin-top: 4px; }
.ps-moves  { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; }
.ps-move {
    width: 2rem; height: 1.7rem;
    border-radius: 6px;
    cursor: pointer;
    line-height: 1;
    font-size: 1rem;
    border: 1px solid var(--game-border);
    background: var(--game-bg);
    color: var(--game-text);
}
.ps-move:hover:not(:disabled)    { border-color: var(--game-accent); }
.ps-move:disabled                 { opacity: 0.35; cursor: not-allowed; }
.ps-move:focus-visible            { outline: 2px solid var(--game-accent); outline-offset: 1px; }
.ps-foot { display: flex; gap: var(--space-3); }


/* ---------- WhichVersionGame (wv-*) ---------- */
/* Variant-discrimination drill: light surface theme with timeline + option cards. */

.wv-setup-wrap  { max-width: 480px; margin: 0 auto; padding: 1.5rem 1rem; }
.wv-back        { display: inline-block; margin-bottom: 1rem; font-size: 0.9rem; color: var(--game-light-primary); text-decoration: none; }
.wv-back:hover  { color: var(--game-light-primary); text-decoration: underline; }
.wv-blurb       { color: var(--game-light-muted); font-size: 0.95rem; margin-bottom: 1.2rem; } /* BL-059: light-surface muted */
.wv-setup       { display: flex; flex-direction: column; gap: 1.2rem; }
.wv-field       { display: flex; flex-direction: column; gap: 0.45rem; }
.wv-field > span { font-size: 0.85rem; font-weight: 600; color: var(--game-light-muted); } /* BL-059 */
.wv-select-wide { padding: 0.6rem 0.7rem; border: 1px solid var(--game-light-border); border-radius: 8px; background: var(--color-white); font-size: 1rem; }
.wv-start       { font-size: 1.1rem; padding: 0.8rem 1.4rem; }
.wv-error       { color: var(--game-light-danger); }

.wv-howto {
    margin: 0 0 1.3rem;
    padding-left: 1.2rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-width: 46ch;
    color: var(--game-light-muted);   /* BL-059: light-surface muted */
    font-size: 0.9rem;
    line-height: 1.45;
}
.wv-howto-q, .wv-cap-q, .wv-ask-q {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.2rem; height: 1.2rem;
    border-radius: var(--radius-full);
    background: var(--game-light-primary);
    color: var(--color-white);
    font-weight: 800;
    font-size: 0.78rem;
    vertical-align: middle;
}
.wv-howto-hl {
    color: var(--game-light-warn);
    background: var(--game-light-warn-bg);
    border-radius: 4px;
    padding: 0 0.2rem;
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-underline-offset: 2px;
    font-weight: 600;
}

.wv-stage { display: flex; flex-direction: column; height: 100vh; }

.wv-topbar {
    flex: 0 0 3.4rem;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0 1rem;
    border-bottom: 1px solid var(--game-light-border);
    background: var(--color-white);
}
.wv-actionbar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.8rem;
    flex-wrap: wrap;
    padding: 0.7rem 1rem;
    border-bottom: 1px solid var(--game-light-border);
    background: var(--color-white);
}
.wv-timer        { font-variant-numeric: tabular-nums; font-size: 1.7rem; font-weight: 800; color: var(--game-light-primary); }
.wv-progress     { font-size: 0.95rem; color: var(--game-text-muted); }
.wv-accuracy     { font-size: 0.95rem; color: #444; }
.wv-cancel       { margin-left: auto; border: none; background: transparent; font-size: 1.3rem; color: var(--game-text-muted); cursor: pointer; padding: 0.3rem 0.5rem; }
.wv-cancel:hover { color: var(--color-charcoal); }
.wv-check-hint   { font-size: 0.85rem; color: var(--game-text-muted); }
.wv-result-inline { font-size: 1rem; color: var(--game-text-muted); }
.wv-result-inline strong { color: var(--game-light-primary); font-size: 1.15rem; }
.wv-action-spacer { flex: 1 1 auto; }

.wv-timeline-caption {
    flex: 0 0 auto;
    margin: 0;
    padding: 0.5rem 1rem 0;
    text-align: center;
    color: var(--game-text-muted);
    font-size: 0.82rem;
}
.wv-timeline {
    flex: 0 0 auto;
    max-height: 24vh;
    overflow-y: auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    padding: 0.8rem 1rem;
    border-bottom: 1px solid var(--game-light-border);
}
.wv-tl-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.6rem;
    border-radius: var(--radius-full);
    font-size: 0.82rem;
    font-weight: 600;
    white-space: nowrap;
    background: #f3f3f6;
    color: var(--game-text-muted);
    border: 1px solid transparent;
}
.wv-tl-pill .wv-tl-label { line-height: 1.1; }
.wv-tl-pill.is-variant { background: var(--color-white); border: 1px dashed var(--game-light-border); color: var(--color-charcoal); }
.wv-tl-pill.is-active  { border: 2px solid var(--game-light-primary); color: var(--game-light-primary); background: color-mix(in srgb, var(--game-light-primary) 10%, #fff); animation: wv-pulse 1.3s ease-in-out infinite; }
.wv-tl-pill.is-filled  { background: var(--game-light-success-bg); border: 1px solid var(--game-light-success); color: var(--game-light-success); animation: none; }
.wv-tl-badge { display: inline-flex; align-items: center; justify-content: center; min-width: 1.25rem; height: 1.25rem; padding: 0 0.2rem; border-radius: var(--radius-full); font-size: 0.78rem; font-weight: 800; }
.wv-tl-badge.is-q     { background: var(--game-light-primary); color: var(--color-white); }
.wv-tl-badge.is-q-dim { background: rgba(0,0,0,0.1); color: var(--game-text-muted); }
.wv-tl-badge.is-placed { background: var(--game-light-success); color: var(--color-white); }
@keyframes wv-pulse {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--game-light-primary) 45%, transparent); }
    50%       { box-shadow: 0 0 0 5px color-mix(in srgb, var(--game-light-primary) 0%, transparent); }
}

.wv-struct {
    flex: 0 0 auto;
    max-height: 32vh;
    overflow-y: auto;
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    justify-content: center;
    gap: 0.5rem;
    padding: 1rem;
    border-bottom: 1px solid var(--game-light-border);
}
.wv-ctx {
    display: inline-flex;
    align-items: center;
    padding: 0.45rem 0.7rem;
    border-radius: 8px;
    background: #f3f3f6;
    color: var(--game-text-muted);
    font-size: 0.82rem;
    font-weight: 600;
    white-space: nowrap;
}
.wv-slot {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 0.2rem;
    min-width: 6rem;
    padding: 0.5rem 0.7rem;
    border-radius: 10px;
    background: var(--color-white);
    border: 2px dashed var(--game-light-border);
    cursor: pointer;
    transition: border-color var(--duration-fast), background var(--duration-fast), box-shadow var(--duration-fast);
}
.wv-slot-label  { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--game-text-muted); font-weight: 700; }
.wv-slot-empty  { font-size: 1.3rem; font-weight: 800; color: var(--game-light-primary); line-height: 1; }
.wv-slot-tag    { font-size: 0.95rem; font-weight: 800; color: var(--color-charcoal); }
.wv-slot-fix    { font-size: 0.72rem; color: var(--game-light-danger); }
.wv-slot.is-filled    { border-style: solid; border-color: var(--game-light-primary); }
.wv-slot.is-droppable { box-shadow: 0 0 0 2px color-mix(in srgb, var(--game-light-primary) 40%, transparent); }
.wv-slot.is-correct   { border-style: solid; background: var(--game-light-success-bg); border-color: var(--game-light-success); cursor: default; }
.wv-slot.is-correct .wv-slot-tag { color: var(--game-light-success); }
.wv-slot.is-wrong     { border-style: solid; background: var(--game-light-danger-bg); border-color: var(--game-light-danger); cursor: default; }
.wv-slot.is-wrong .wv-slot-tag   { color: var(--game-light-danger); }

.wv-instruction { flex: 0 0 auto; text-align: center; padding: 0.6rem 1rem 0; color: var(--game-text-muted); font-size: 0.9rem; }
.wv-selhint     { display: block; margin-top: 0.2rem; color: var(--game-light-primary); font-size: 0.85rem; }

.wv-vtray {
    flex: 1 1 auto;
    overflow-y: auto;
    display: flex;
    flex-wrap: wrap;
    gap: 0.7rem;
    align-content: flex-start;
    justify-content: center;
    padding: 1rem;
    width: 100%;
    max-width: 760px;
    margin: 0 auto;
}
.wv-vcard {
    flex: 0 1 240px;
    align-self: flex-start;
    padding: 0.8rem 1rem;
    border-radius: 14px;
    border: 1px solid var(--game-light-border);
    background: var(--color-white);
    color: var(--color-charcoal);
    cursor: grab;
    user-select: none;
    transition: border-color var(--duration-fast), box-shadow var(--duration-fast);
}
.wv-vcard:hover   { border-color: var(--game-light-primary); }
.wv-vcard:active  { cursor: grabbing; }
.wv-vcard.is-selected { border-color: var(--game-light-primary); box-shadow: 0 0 0 2px color-mix(in srgb, var(--game-light-primary) 35%, transparent); }
.wv-vcard-head    { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 800; color: var(--game-light-primary); margin-bottom: 0.3rem; }
.wv-vcard-lyrics  { font-size: 1rem; line-height: 1.45; }

.wv-ask {
    flex: 0 0 auto;
    padding: 0.9rem 1rem 0.6rem;
    text-align: center;
    animation: wv-slide-in 0.2s ease-out;
}
@keyframes wv-slide-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.wv-ask-text { font-size: 1.25rem; font-weight: 700; line-height: 1.3; }
.wv-ask-sub  { font-size: 0.9rem; color: var(--game-text-muted); margin-top: 0.2rem; }
.wv-ask-legend { margin: 0.3rem 0 0; color: var(--game-text-muted); font-size: 0.82rem; }

.wv-linemap {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    width: 100%;
    max-width: 320px;
    margin: 0.6rem auto 0.2rem;
}
.wv-linemap-row  { display: flex; align-items: center; gap: 0.5rem; }
.wv-linemap-arrow { flex: 0 0 1rem; text-align: right; color: var(--game-light-warn); font-weight: 800; font-size: 1rem; }
.wv-linemap-bar  { flex: 1 1 auto; height: 0.55rem; border-radius: var(--radius-full); background: #e7e6ef; }
.wv-linemap-row.is-target .wv-linemap-bar { background: var(--game-light-warn-bg); box-shadow: inset 0 0 0 2px var(--game-light-warn-border); }

.wv-options {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.8rem;
    width: 100%;
    max-width: 600px;
    margin: 0 auto;
}
.wv-card {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    width: 100%;
    text-align: left;
    padding: 0.9rem 1rem;
    border: 1px solid var(--game-light-border);
    border-radius: 14px;
    background: var(--color-white);
    color: var(--color-charcoal);
    font-size: 1.05rem;
    line-height: 1.5;
    cursor: pointer;
    transition: border-color var(--duration-fast), background var(--duration-fast);
}
.wv-card:hover { border-color: var(--game-light-primary); }
.wv-card-head  { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; color: var(--game-text-muted); display: flex; align-items: center; gap: 0.4rem; margin-bottom: 0.2rem; }
.wv-card-mark  { font-size: 1rem; }
.wv-card-line  { display: block; }
.wv-tok.is-variant {
    color: var(--game-light-warn);
    background: var(--game-light-warn-bg);
    border-radius: 4px;
    padding: 0 0.15rem;
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-underline-offset: 2px;
    font-weight: 600;
}
.wv-card.is-correct { background: var(--game-light-success-bg); border-color: var(--game-light-success); }
.wv-card.is-correct .wv-card-head { color: var(--game-light-success); }
.wv-card.is-wrong   { background: var(--game-light-danger-bg); border-color: var(--game-light-danger); cursor: default; animation: wv-shake 0.25s; }
.wv-card.is-wrong .wv-card-head   { color: var(--game-light-danger); }
@keyframes wv-shake {
    0%, 100% { transform: translateX(0); }
    25%       { transform: translateX(-5px); }
    75%       { transform: translateX(5px); }
}

.wv-checkbar      { flex: 0 0 auto; display: flex; align-items: center; gap: 0.8rem; justify-content: center; padding: 0.8rem 1rem 1.1rem; border-top: 1px solid var(--game-light-border); }
.wv-checkbar-hint { font-size: 0.85rem; color: var(--game-text-muted); }
.wv-banner {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.35rem;
    padding: 1rem;
    border-top: 1px solid var(--game-light-border);
    background: color-mix(in srgb, var(--game-light-primary) 5%, var(--color-white));
}

.wv-check.is-ready { animation: wv-check-pulse 1.4s ease-in-out infinite; }
@keyframes wv-check-pulse {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--game-light-primary) 55%, transparent); }
    50%       { box-shadow: 0 0 0 7px color-mix(in srgb, var(--game-light-primary) 0%, transparent); }
}

.wv-results {
    height: 100vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 1.5rem 1rem;
    text-align: center;
}
.wv-result-score { font-size: 2rem; font-weight: 800; color: var(--game-light-primary); }
.wv-result-sub   { font-variant-numeric: tabular-nums; font-size: 1rem; color: var(--game-text-muted); }
.wv-result-best  { font-size: 0.95rem; color: var(--game-text-muted); font-variant-numeric: tabular-nums; }
.wv-result-best.is-new { color: var(--game-light-success); font-weight: 700; }
.wv-trouble-list { width: 100%; max-width: 440px; text-align: left; margin-top: 0.5rem; }
.wv-trouble-list h4 { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--game-light-danger); margin: 0 0 0.3rem; }
.wv-trouble-line { font-size: 0.9rem; padding: 0.18rem 0; border-bottom: 1px dotted var(--game-light-border); }
.wv-trouble-more { font-size: 0.8rem; color: var(--game-text-muted); margin-top: 0.25rem; }
.wv-result-actions { display: flex; gap: 0.6rem; margin-top: 0.8rem; }

@media (max-width: 600px) {
    .wv-ask-text  { font-size: 1.1rem; }
    .wv-card      { font-size: 1rem; }
    .wv-tl-pill   { font-size: 0.78rem; }
    .wv-vcard     { flex-basis: 100%; }
    .wv-slot      { min-width: 5rem; }
}
@media (prefers-reduced-motion: reduce) {
    .wv-ask                   { animation: none; }
    .wv-card.is-wrong         { animation: none; }
    .wv-tl-pill.is-active     { animation: none; box-shadow: 0 0 0 2px var(--game-light-primary); }
    .wv-check.is-ready        { animation: none; box-shadow: 0 0 0 3px var(--game-light-primary); }
}


/* ---------- PracticeDashboard (practice-*) ---------- */

.practice-page {
    max-width: 720px;
    margin: 0 auto;
    padding: 1rem;
}
.practice-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.2rem;
}
.practice-head h1  { font-size: 1.6rem; margin: 0; }
.practice-play     { white-space: nowrap; text-decoration: none; }

.practice-mode {
    display: inline-flex;
    gap: 4px;
    padding: 3px;
    border-radius: var(--radius-full);
    background: var(--game-light-bg);
    border: 1px solid var(--game-light-border);
}
.practice-mode-btn {
    border: none;
    background: none;
    color: var(--game-light-muted);   /* BL-059: was --game-text-muted (2.03:1 on light-bg) */
    font-weight: 600;
    font-size: 0.9rem;
    padding: 0.35rem 0.95rem;
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: color var(--duration-fast), background var(--duration-fast);
}
.practice-mode-btn:hover            { color: var(--color-charcoal); }
.practice-mode-btn.is-active        { background: var(--game-light-primary); color: var(--color-white); }
.practice-mode-btn:focus-visible    { outline: 2px solid var(--game-light-primary); outline-offset: 2px; }

.practice-games {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.7rem;
    margin-bottom: 1.6rem;
}
.practice-game-btn {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    padding: 0.9rem 1rem;
    border-radius: 12px;
    text-decoration: none;
    color: var(--color-white);
    background: var(--game-light-primary);
    transition: filter var(--duration-fast);
}
.practice-game-btn:hover       { filter: brightness(1.07); }
.practice-game-btn-name        { font-weight: 700; font-size: 1.1rem; }
.practice-game-btn-desc        { font-size: 0.8rem; opacity: 0.9; }

@media (max-width: 520px) { .practice-games { grid-template-columns: 1fr; } }

.practice-error { color: var(--game-light-danger); }
.practice-empty {
    padding: 1.5rem;
    border: 1px dashed var(--game-light-border);
    border-radius: 12px;
    text-align: center;
}
.practice-empty-sub { font-size: 0.9rem; color: var(--game-light-muted); margin-top: 0.4rem; } /* BL-059 */

.practice-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    margin-bottom: 1.2rem;
    border-bottom: 1px solid var(--game-light-border);
}
.practice-tab {
    border: none;
    background: transparent;
    cursor: pointer;
    padding: 0.5rem 0.85rem;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--game-light-muted);   /* BL-059 */
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    border-radius: 8px 8px 0 0;
    transition: color var(--duration-fast), background var(--duration-fast);
}
.practice-tab:hover     { color: var(--color-charcoal); background: var(--game-light-bg); }
.practice-tab.is-active { color: var(--game-light-primary); border-bottom-color: var(--game-light-primary); }

.practice-tab-wrap {
    display: inline-flex;
    align-items: center;
    margin-bottom: -1px;
    border-bottom: 2px solid transparent;
    border-radius: 8px 8px 0 0;
}
.practice-tab-wrap.is-active                    { border-bottom-color: var(--game-light-primary); }
.practice-tab-wrap.is-active .practice-tab-pinned { color: var(--game-light-primary); }
.practice-tab-pinned { border-bottom: none; margin-bottom: 0; padding-right: 0.25rem; }
.practice-tab-x {
    border: none;
    background: transparent;
    cursor: pointer;
    color: var(--game-light-muted);   /* BL-059/BL-016: was raw #aaa (2.03:1 on light) */
    font-size: 0.72rem;
    line-height: 1;
    padding: 0.25rem 0.45rem 0.25rem 0.1rem;
    border-radius: 6px;
}
.practice-tab-x:hover { color: var(--game-light-danger); background: var(--game-light-bg); }
.practice-tab-add     { display: inline-flex; align-items: center; }
.practice-tab-addbtn  { color: var(--game-light-primary); }
.practice-tab-picker {
    padding: 0.4rem 0.5rem;
    margin-bottom: 0.3rem;
    border: 1px solid var(--game-light-border);
    border-radius: 8px;
    background: var(--color-white);
    font-size: 0.9rem;
}

.practice-metrics {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0.7rem;
    margin-bottom: 1.6rem;
}
.practice-metric {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.2rem;
    padding: 0.9rem 0.5rem;
    border-radius: 12px;
    background: var(--game-light-bg);
    border: 1px solid var(--game-light-border);
}
.practice-metric-value {
    font-size: 1.7rem;
    font-weight: 800;
    line-height: 1;
    color: var(--game-light-primary);
}
.practice-metric-label {
    font-size: 0.78rem;
    color: var(--game-light-muted);   /* BL-059 */
    text-align: center;
}
.practice-metric.is-trouble .practice-metric-value { color: var(--game-light-danger); }

.practice-subhead {
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--game-light-muted);   /* BL-059 */
    margin: 0 0 0.6rem;
}
.practice-songs    { display: flex; flex-direction: column; gap: 0.6rem; }
.practice-song {
    display: block;
    padding: 0.8rem 1rem;
    border: 1px solid var(--game-light-border);
    border-radius: 12px;
    text-decoration: none;
    color: inherit;
    transition: border-color var(--duration-fast), box-shadow var(--duration-fast);
}
.practice-song:hover { border-color: var(--game-light-primary); box-shadow: 0 2px 10px rgba(106, 90, 205, 0.12); }
.practice-song-top  { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem; }
.practice-song-name { font-weight: 700; font-size: 1.05rem; }
.practice-song-pct  { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--game-light-primary); }

.practice-bar { height: 7px; border-radius: var(--radius-full); background: var(--game-light-border); margin: 0.45rem 0; overflow: hidden; }
.practice-bar-fill { height: 100%; border-radius: var(--radius-full); background: var(--game-light-primary); }

.practice-song-badges { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.practice-badge { font-size: 0.75rem; padding: 0.1rem 0.5rem; border-radius: var(--radius-full); font-weight: 600; }
.practice-badge.due     { background: var(--game-light-badge-due);  color: var(--game-light-badge-due-text); }
.practice-badge.trouble { background: var(--game-light-danger-bg);  color: var(--game-light-danger); }
.practice-badge.muted   { background: var(--game-light-bg); color: var(--game-light-muted); font-weight: 500; } /* BL-059 */

@media (max-width: 520px) { .practice-metrics { grid-template-columns: repeat(2, 1fr); } }


/* ---------- NoteLineGame (inline <style> extracted) ---------- */
/* Note-reading drill: note grid + multiple-choice answer buttons. */

.cg-game-wrap {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    padding: 16px;
    max-width: 720px;
    margin: 0 auto;
}
.cg-phrase-label {
    font-size: 1rem;
    font-weight: 600;
    color: var(--game-text-muted);
    margin: 12px 0 4px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.cg-note-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 12px 0;
}
.cg-note-cell {
    min-width: 44px;
    padding: 6px 8px;
    text-align: center;
    border-radius: 6px;
    border: 1px solid var(--game-border);
    font-family: ui-monospace, 'Cascadia Code', 'Consolas', monospace;
    font-size: 0.85rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    background: var(--game-card);
    transition: background var(--duration-fast), border-color var(--duration-fast);
}
.cg-note-cell--rest  { opacity: 0.4; border-style: dashed; }
.cg-note-cell--blank { border-color: var(--game-accent); border-width: 2px; font-size: 0.95rem; min-width: 50px; }
.cg-note-cell--active {
    border-color: var(--game-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--game-accent) 35%, transparent);
    animation: nl-pulse 1.2s ease-in-out infinite;
}
@keyframes nl-pulse {
    0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--game-accent) 35%, transparent); }
    50%       { box-shadow: 0 0 0 6px color-mix(in srgb, var(--game-accent) 15%, transparent); }
}
.cg-note-cell--correct {
    border-color: var(--game-success);
    background: color-mix(in srgb, var(--game-success) 15%, var(--game-card));
    animation: none;
}
.cg-note-cell--wrong {
    border-color: var(--game-danger);
    background: color-mix(in srgb, var(--game-danger) 20%, var(--game-card));
    animation: nl-shake 0.4s ease-in-out;
}
@keyframes nl-shake {
    0%, 100% { transform: translateX(0); }
    20%       { transform: translateX(-4px); }
    60%       { transform: translateX(4px); }
}
.cg-syllable {
    font-size: 0.7rem;
    color: var(--game-text-muted);
    font-family: var(--font-body);
}
.cg-choices-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    max-width: 360px;
    margin: 16px auto;
}
.cg-choice-btn {
    min-height: 48px;
    border: 1px solid var(--game-border);
    border-radius: 8px;
    background: var(--game-card);
    color: var(--game-text);
    font-family: ui-monospace, 'Cascadia Code', 'Consolas', monospace;
    font-size: 1rem;
    cursor: pointer;
    transition: background var(--duration-fast), border-color var(--duration-fast);
}
.cg-choice-btn:hover:not(:disabled) { background: var(--game-card-alt); border-color: var(--game-accent); }
.cg-choice-btn--wrong {
    border-color: var(--game-danger);
    background: color-mix(in srgb, var(--game-danger) 20%, var(--game-card));
    opacity: 0.5;
    cursor: not-allowed;
}
.cg-result-list {
    margin: 16px 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.cg-result-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 12px;
    border-radius: 6px;
    border: 1px solid var(--game-border);
    font-size: 0.9rem;
}
.cg-result-row.is-clean  { border-color: var(--game-success); background: color-mix(in srgb, var(--game-success) 10%, transparent); }
.cg-result-row.is-missed { border-color: var(--game-danger);  background: color-mix(in srgb, var(--game-danger)  10%, transparent); }
/* AI Note: .cg-foot is also used by ChordClozeGame; both need margin-top + text-align, which this rule covers. */
.cg-foot { margin-top: 24px; text-align: center; }

@media (prefers-reduced-motion: reduce) {
    .cg-note-cell--active,
    .cg-note-cell--wrong { animation: none; }
    .wv-check.is-ready   { animation: none; }
}


/* =========================================================
   39. STORE PAGES
   (Store, StoreProduct, StoreCart)
   ========================================================= */

/* ---------- Store — product grid ---------- */

.store-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr));
    gap: var(--space-5);
    margin-top: var(--space-5);
}

.store-card {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--surface-raised);
    color: var(--surface-raised-text);
    transition: box-shadow var(--duration-fast), transform var(--duration-fast);
    text-decoration: none;
    color: inherit;
}
.store-card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
}

.store-card-media {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    display: block;
    background: var(--surface-deep);
}

.store-card-noimage {
    width: 100%;
    aspect-ratio: 1 / 1;
    background: var(--surface-deep);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--surface-deep-text-muted);
    font-size: var(--text-sm);
}

.store-card-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-4);
    flex: 1 1 auto;
}

.store-card-price {
    font-weight: 700;
    color: var(--color-accent-text);
    margin-top: auto;
}


/* ---------- StoreProduct — detail page ---------- */

.store-detail-crumbs {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    margin-bottom: var(--space-4);
}

.store-detail {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);   /* overflow guard on both columns */
    gap: var(--space-7);
    align-items: flex-start;
    margin-top: var(--space-5);
}
@media (max-width: 720px) {
    .store-detail { grid-template-columns: 1fr; }
}

.store-detail-main {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.store-detail-noimage {
    width: 100%;
    aspect-ratio: 1 / 1;
    background: var(--surface-deep);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--surface-deep-text-muted);
    font-size: var(--text-sm);
    border-radius: var(--radius-md);
}

.store-detail-thumbs {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin-top: var(--space-2);
}

.store-detail-thumb {
    width: 60px;
    height: 60px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    border: 2px solid var(--surface-border);
    cursor: pointer;
    transition: border-color var(--duration-fast);
}
.store-detail-thumb.is-selected { border-color: var(--color-accent); }

.store-detail-sku {
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
}

.store-detail-added {
    color: var(--color-accent-text);
    font-weight: 700;
}


/* ---------- StoreCart — cart line items ---------- */

.cart-item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
}

.cart-thumb {
    width: 44px;
    height: 44px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    background: var(--surface-deep);
    flex: 0 0 auto;
}

/* ---------- StoreCheckout — test-mode hint ---------- */

.store-test-hint {
    background: var(--surface-deep);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-sm);
    color: var(--surface-deep-text-muted);
    margin-bottom: var(--space-4);
}

/* ---------- StorefrontCheckoutReturn — order confirmation ---------- */

.checkout-return {
    max-width: 600px;
    margin-top: var(--space-6);
}

.checkout-return-meta {
    background: var(--surface-raised);
    color: var(--surface-raised-text);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md);
    padding: var(--space-4) var(--space-5);
    margin-bottom: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.checkout-return-status-pending {
    display: inline-block;
    background: var(--surface-deep);
    color: var(--surface-deep-text-muted);
    font-size: var(--text-sm);
    font-weight: 600;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-full);
}

.checkout-return-status-paid {
    display: inline-block;
    background: var(--alert-success-bg-strong);
    color: var(--alert-success-text-strong);
    font-size: var(--text-sm);
    font-weight: 600;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-full);
}

.checkout-return-refresh {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    margin-bottom: var(--space-4);
}

.checkout-return-address {
    margin-top: var(--space-5);
}

.checkout-return-address-block {
    font-size: var(--text-sm);
    color: var(--surface-page-text-muted);
    line-height: 1.7;
    margin-top: var(--space-2);
}


/* =========================================================
   40. LAYOUT — RECONNECT MODAL  (REMOVED — was dead, cascade-winning)
   ========================================================= */

/*
 * BL-008 / FLG-CMP-MISC-2-01: this section previously re-declared
 * #components-reconnect-modal with `display: none`, un-hidden only by
 * `.components-reconnect-show/-failed/-rejected` classes. But the live
 * ReconnectModal.razor is a native <dialog> opened via showModal()/close()
 * (see ReconnectModal.razor.js) — nothing ever adds those state classes,
 * and its child markup uses <div> dots + a .components-reconnect-container,
 * NOT the .components-reconnect-dialog/-title/-body/span markup this block
 * targeted. Being later in source order, its `display: none` cascade-BEAT
 * the live section 36-E, so a real circuit drop showed the user NOTHING.
 * The whole block (plus its dead --reconnect-blue* tokens) is deleted;
 * the live styling lives at section 36-E (search "36-E. BLAZOR RECONNECT MODAL").
 */


/* =========================================================
   41. ADMIN TOOLS
   (StorefrontCatalog, LyricSheet, LyricMigration,
    SongArrangementsAdmin, TabView, ChordChartEditor,
    InstrumentLineEditor, GrandStaffView, MelodyView,
    TabEditor)
   ========================================================= */

/* ---------- StorefrontCatalog — image manager grid ---------- */

.storefront-image-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 140px), 1fr));
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.storefront-image-card {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--surface-raised);
}

.storefront-image-thumb {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    display: block;
    background: var(--surface-deep);
}

.storefront-image-badge {
    position: relative;
}
.storefront-image-badge::after {
    content: attr(data-label);
    position: absolute;
    top: var(--space-1);
    left: var(--space-1);
    background: rgba(0, 0, 0, 0.65);
    color: var(--color-white);
    font-size: var(--text-xs);
    padding: 1px var(--space-2);
    border-radius: var(--radius-sm);
}

.storefront-image-actions {
    display: flex;
    gap: var(--space-2);
    padding: var(--space-2);
    justify-content: flex-end;
}

.storefront-image-alt {
    font-size: var(--text-xs);
    color: var(--surface-page-text-muted);
    padding: 0 var(--space-2) var(--space-2);
    word-break: break-all;
}


/* ---------- LyricSheet — structured lyric display + print ---------- */

.lyric-sheet-section  { margin-bottom: 1.25rem; }

.lyric-sheet-heading {
    font-weight: 700;
    font-size: 0.9rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-accent);
    margin: 0 0 0.2rem;
}

.lyric-sheet-notes {
    display: flex;
    flex-wrap: wrap;
    gap: 0.2rem 1rem;
    margin: 0 0 0.4rem;
}
.lyric-sheet-note {
    font-size: 0.78rem;
    font-style: italic;
    color: var(--color-charcoal-mid);
}

.lyric-sheet-line {
    font-family: var(--font-body);
    line-height: 1.55;
    white-space: pre-wrap;
    word-break: break-word;
}

.lyric-sheet-gap { height: 0.6rem; }

.lyric-sheet-instrumental {
    font-style: italic;
    color: var(--color-charcoal-muted);
}

@media print {
    .lyric-sheet-heading { color: #000; break-after: avoid; }
    .lyric-sheet-note    { color: #333; }
}


/* ---------- LyricMigration — side-by-side diff + lint ---------- */

.lyric-migration-status { margin-left: 0.75rem; font-size: 0.9rem; }

.lyric-migration-lint {
    margin: 0.25rem 0 0.5rem;
    padding-left: 1.1rem;
    color: #9a5b00;
    font-size: 0.85rem;
}

.lyric-migration-diff {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
    margin: 0.5rem 0;
}
.lyric-migration-diff h4 { margin: 0 0 0.25rem; font-size: 0.85rem; }
.lyric-migration-diff pre {
    white-space: pre-wrap;
    word-break: break-word;
    font-size: 0.8rem;
    line-height: 1.45;
    background: var(--color-cream-deep);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-md);
    padding: 0.5rem 0.6rem;
    max-height: 340px;
    overflow: auto;
}
@media (max-width: 720px) { .lyric-migration-diff { grid-template-columns: 1fr; } }


/* ---------- SongArrangementsAdmin (arr-*) ---------- */

.admin-page-wide { max-width: none; }

.arr-search   { margin-bottom: var(--space-3); }
.arr-progress { margin: var(--space-2) 0 var(--space-3); font-size: var(--text-xs); color: var(--color-charcoal-muted); }

.arr-queue {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    max-height: 58vh;
    overflow-y: auto;
    padding-right: var(--space-2);
}

.arr-tag {
    display: inline-block;
    margin-left: var(--space-2);
    padding: 0 var(--space-2);
    font-size: var(--text-xs);
    border-radius: var(--radius-full);
    background: var(--color-accent-dim);
    color: var(--color-accent);
}

.arr-badges { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }
.arr-badge {
    padding: 1px var(--space-3);
    font-size: var(--text-xs);
    line-height: 1.6;
    border-radius: var(--radius-full);
    background: var(--color-cream-deep);
    color: var(--color-charcoal-mid);
    border: 1px solid var(--color-cream-mid);
    white-space: nowrap;
}
.arr-badge-empty { background: transparent; color: var(--color-charcoal-muted); border-style: dashed; }
.arr-badge-state-needsreview { background: #FBEED9; color: #8A5A12; border-color: #E9D3A8; }
.arr-badge-state-approved    { background: #E2F0E0; color: #2F6B33; border-color: #BFE0BD; }
.arr-badge-state-draft       { background: var(--color-cream-deep); color: var(--color-charcoal-muted); }
.arr-badge-conf-low          { color: #9A3B2A; }
.arr-badge-conf-medium       { color: #8A5A12; }
.arr-badge-conf-high         { color: #2F6B33; }

.arr-quick-approve {
    display: inline-block;
    margin-top: var(--space-2);
    padding: 1px var(--space-3);
    font-size: var(--text-xs);
    border-radius: var(--radius-full);
    border: 1px solid #BFE0BD;
    background: #E2F0E0;
    color: #2F6B33;
    cursor: pointer;
}
.arr-quick-approve:hover { background: #CFE7CC; }

.arr-detail-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.arr-field-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    align-items: flex-end;
}
.arr-field-row > .admin-field { flex: 1 1 8rem; margin-bottom: 0; }
.arr-hint { font-weight: 400; font-size: var(--text-xs); color: var(--color-charcoal-muted); }

.arr-chart-block { margin: var(--space-4) 0 var(--space-5); }
.arr-chart-head {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

.arr-preview {
    margin: var(--space-5) 0;
    padding: var(--space-4);
    background: var(--color-cream-deep);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-md);
}
.arr-preview-head {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}
.arr-preview-title {
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--color-charcoal);
}
.arr-transpose { display: flex; align-items: center; gap: var(--space-2); }
.arr-tpose-btn {
    width: 1.6rem; height: 1.6rem;
    border-radius: var(--radius-full);
    border: 1px solid var(--surface-border);
    background: var(--color-white);
    color: var(--color-charcoal);
    font-size: var(--text-md);
    line-height: 1;
    cursor: pointer;
}
.arr-tpose-btn:hover    { border-color: var(--color-accent); color: var(--color-accent); }
.arr-tpose-readout      { font-size: var(--text-xs); color: var(--color-charcoal-mid); min-width: 9rem; text-align: center; }
.arr-tpose-note         { color: var(--color-accent); }
.arr-tpose-reset        { font-size: var(--text-xs); background: none; border: none; color: var(--color-accent); cursor: pointer; text-decoration: underline; }

.arr-preview-body  { display: flex; flex-direction: column; gap: var(--space-3); }
.arr-prev-section  { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); }
.arr-prev-heading  { flex: 0 0 7rem; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-charcoal-muted); }
.arr-chip {
    display: inline-block;
    padding: 1px var(--space-3);
    font-family: ui-monospace, 'Cascadia Code', 'Consolas', monospace;
    font-size: var(--text-sm);
    border-radius: var(--radius-sm);
    background: var(--color-white);
    color: var(--color-charcoal);
    border: 1px solid var(--color-cream-mid);
}
.arr-prev-scale { font-size: var(--text-sm); font-style: italic; color: var(--color-charcoal-muted); }

.arr-instruments .admin-field { margin-bottom: var(--space-3); }
.arr-provenance { margin: var(--space-4) 0; font-size: var(--text-sm); color: var(--color-charcoal-mid); }
.arr-provenance summary { cursor: pointer; color: var(--color-charcoal-muted); }
.arr-rejected { margin: var(--space-3) 0 0; padding-left: var(--space-5); color: var(--color-charcoal-muted); }
.arr-rejected li { margin-bottom: var(--space-2); }

.admin-button-approve { background: #2F6B33; color: var(--color-white); border-color: #2F6B33; }
.admin-button-approve:hover { background: #265628; }


/* ---------- Stem-import compare panel (stem-*) ---------- */

.stem-compare {
    margin: var(--space-4) 0 var(--space-5);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md);
    background: var(--color-cream-deep);
}
.stem-compare-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    cursor: pointer;
}
.stem-compare-title {
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--color-charcoal);
}
.stem-compare-body {
    padding: 0 var(--space-4) var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.stem-compare-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.stem-compare-table th,
.stem-compare-table td {
    text-align: left;
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--color-cream-mid);
    vertical-align: middle;
}
.stem-compare-table thead th {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-charcoal-muted);
    font-weight: 600;
}
.stem-compare-table th[scope="row"] { font-weight: 600; color: var(--color-charcoal-mid); }
.stem-cmp-db       { color: var(--color-charcoal-muted); }
.stem-cmp-reported { color: var(--color-charcoal); font-weight: 500; }
.stem-cmp-mismatch {
    color: var(--color-warning-deep);
    background: var(--color-warn-dim);
    border-radius: var(--radius-sm);
}
.stem-cmp-action { text-align: right; white-space: nowrap; }
.stem-accept-btn {
    padding: 1px var(--space-3);
    font-size: var(--text-xs);
    border-radius: var(--radius-full);
    border: 1px solid var(--color-accent);
    background: var(--color-accent-dim);
    color: var(--color-accent-text);
    cursor: pointer;
}
.stem-accept-btn:hover:not([disabled]) { background: var(--color-accent); color: var(--color-white); }
.stem-accept-btn[disabled] { opacity: 0.5; cursor: default; }

.stem-compare-msg { margin: 0; font-size: var(--text-sm); }

.stem-track-block { display: flex; flex-direction: column; gap: var(--space-2); }
.stem-track-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.stem-track {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}
.stem-track-name { font-size: var(--text-sm); color: var(--color-charcoal); }
.stem-track-audio { height: 2rem; max-width: 100%; }

.stem-raw > summary { cursor: pointer; font-size: var(--text-sm); color: var(--color-charcoal-muted); }
.stem-raw-pre {
    margin: var(--space-3) 0 0;
    padding: var(--space-3);
    max-height: 22rem;
    overflow: auto;
    font-family: ui-monospace, 'Cascadia Code', 'Consolas', monospace;
    font-size: var(--text-xs);
    line-height: 1.5;
    background: var(--surface-raised);
    color: var(--color-charcoal-mid);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
    white-space: pre;
}

/* Stem-import upload utility (/admin/stem-import) */
.stem-upload { display: flex; flex-direction: column; gap: var(--space-3); max-width: 40rem; }
.stem-opts { display: flex; flex-direction: column; gap: var(--space-2); }
.stem-opt {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--color-charcoal-mid);
    cursor: pointer;
}

.stem-progress { margin-top: var(--space-5); display: flex; flex-direction: column; gap: var(--space-2); max-width: 40rem; }
.stem-progress-bar { height: 0.5rem; border-radius: var(--radius-full); background: var(--color-cream-mid); overflow: hidden; }
.stem-progress-fill { height: 100%; width: var(--pct, 0%); background: var(--color-accent); }
@media (prefers-reduced-motion: no-preference) { .stem-progress-fill { transition: width 0.2s ease; } }
.stem-progress-line { margin: 0; font-size: var(--text-sm); color: var(--color-charcoal-mid); }

.stem-report { margin-top: var(--space-5); display: flex; flex-direction: column; gap: var(--space-4); }
.stem-report-summary { margin: 0; font-size: var(--text-sm); font-weight: 600; color: var(--color-charcoal-mid); }
.stem-report-item {
    padding: var(--space-4);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md);
    background: var(--color-cream-deep);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.stem-report-head { display: flex; align-items: center; gap: var(--space-3); }
.stem-report-file { font-family: var(--font-display); font-size: var(--text-md); color: var(--color-charcoal); }
.stem-report-msg { margin: 0; font-size: var(--text-sm); color: var(--color-charcoal-mid); }

.stem-suggest { display: flex; flex-direction: column; gap: var(--space-2); }
.stem-suggest-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.stem-suggest-item { display: flex; align-items: baseline; gap: var(--space-3); }
.stem-suggest-song { font-size: var(--text-sm); color: var(--color-charcoal); }

.stem-report-warnings { margin: 0; padding-left: var(--space-5); font-size: var(--text-sm); color: var(--color-charcoal-muted); }
.stem-report-warnings li { margin-bottom: var(--space-2); }


/* ---------- TabView (tab-*) ---------- */

.tab-empty  { font-size: var(--text-sm); font-style: italic; color: var(--color-charcoal-muted); }
.tab-phrase { margin-bottom: var(--space-4); }
.tab-plabel {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-charcoal-muted);
    margin-bottom: var(--space-1);
}
.tab-grid {
    display: grid;
    align-items: stretch;
    font-family: ui-monospace, 'Cascadia Code', 'Consolas', monospace;
    font-size: var(--text-sm);
    background: var(--color-white);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
    overflow-x: auto;
}
.tab-open {
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    color: var(--color-charcoal-muted);
    background: var(--color-cream-deep);
    border-right: 1px solid var(--color-cream-mid);
    padding: 0 var(--space-1);
}
.tab-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-cream-dark);
    padding: 1px 2px;
    min-height: 1.5em;
}
.tab-cell-on { color: var(--color-charcoal); font-weight: 600; }
.tab-tech    { font-size: var(--text-xs); color: var(--color-accent); }


/* ---------- ChordChartEditor (cce-*) ---------- */

.cce { display: flex; flex-direction: column; gap: var(--space-4); }
.cce-error { margin: 0 0 var(--space-2); }
.cce-empty {
    padding: var(--space-4);
    border: 1px dashed var(--surface-border);
    border-radius: var(--radius-md);
    color: var(--color-charcoal-muted);
    text-align: center;
}
.cce-sections { display: flex; flex-direction: column; gap: var(--space-3); }
.cce-section {
    padding: var(--space-3) var(--space-4);
    background: var(--color-cream-deep);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-md);
    transition: opacity var(--duration-fast), border-color var(--duration-fast), background var(--duration-fast);
}
.cce-section-dragging  { opacity: 0.5; }
.cce-section-droptarget { border-color: var(--color-accent); background: var(--color-cream-mid); }

.cce-drag {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--color-charcoal-muted);
    cursor: grab;
    padding: 0 2px;
}
.cce-drag:hover  { color: var(--color-accent); }
.cce-drag:active { cursor: grabbing; }

.cce-section-head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}
.cce-heading {
    flex: 1 1 auto;
    min-width: 6rem;
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--color-charcoal);
    background: var(--color-white);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
    padding: 2px var(--space-2);
}
.cce-heading:focus { outline: none; border-color: var(--color-accent); }
.cce-type {
    flex: 0 0 auto;
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-charcoal-muted);
    padding: 1px var(--space-2);
    border-radius: var(--radius-full);
    background: var(--color-cream-mid);
}
.cce-section-tools { flex: 0 0 auto; display: inline-flex; gap: 2px; }
.cce-tool {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem; height: 1.5rem;
    border-radius: var(--radius-sm);
    border: 1px solid var(--surface-border);
    background: var(--color-white);
    color: var(--color-charcoal-mid);
    font-size: var(--text-sm);
    line-height: 1;
    cursor: pointer;
}
.cce-tool:hover:not(:disabled)        { border-color: var(--color-accent); color: var(--color-accent); }
.cce-tool:disabled                     { opacity: 0.35; cursor: default; }
.cce-tool-danger:hover:not(:disabled)  { border-color: #9A3B2A; color: #9A3B2A; }

.cce-chords { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; }
.cce-ins {
    border: none;
    background: none;
    cursor: pointer;
    color: var(--color-charcoal-muted);
    font-size: var(--text-sm);
    line-height: 1;
    padding: 0 1px;
    opacity: 0.35;
    transition: opacity var(--duration-fast), color var(--duration-fast);
}
.cce-ins:hover { opacity: 1; color: var(--color-accent); }

.cce-chip {
    display: inline-flex;
    align-items: center;
    gap: 1px;
    padding: 1px 2px 1px var(--space-2);
    background: var(--color-white);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
}
.cce-chip:focus-within { border-color: var(--color-accent); }
.cce-chip-unknown { border-style: dashed; border-color: var(--surface-border); background: var(--color-cream-deep); }

.cce-chip-input {
    border: none;
    background: transparent;
    outline: none;
    font-family: ui-monospace, 'Cascadia Code', 'Consolas', monospace;
    font-size: var(--text-sm);
    color: var(--color-charcoal);
    padding: 1px 0;
}
.cce-chip-x {
    border: none;
    background: none;
    cursor: pointer;
    color: var(--color-charcoal-muted);
    font-size: var(--text-sm);
    line-height: 1;
    padding: 0 2px;
    border-radius: var(--radius-sm);
}
.cce-chip-x:hover { color: #9A3B2A; }

.cce-addchord {
    margin-left: var(--space-2);
    border: 1px dashed var(--surface-border);
    background: transparent;
    color: var(--color-charcoal-mid);
    font-size: var(--text-xs);
    border-radius: var(--radius-sm);
    padding: 2px var(--space-2);
    cursor: pointer;
}
.cce-addchord:hover { border-color: var(--color-accent); color: var(--color-accent); }

.cce-scale { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-3); }
.cce-scale-label { flex: 0 0 auto; font-size: var(--text-xs); color: var(--color-charcoal-muted); }
.cce-scale-input {
    flex: 1 1 auto;
    font-size: var(--text-sm);
    color: var(--color-charcoal);
    background: var(--color-white);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
    padding: 2px var(--space-2);
}
.cce-scale-input:focus { outline: none; border-color: var(--color-accent); }

.cce-sounds {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
    padding-top: var(--space-2);
    border-top: 1px dashed var(--color-cream-mid);
}
.cce-sounds-label { font-size: var(--text-xs); font-style: italic; color: var(--color-charcoal-muted); }
.cce-sounds-chip {
    font-family: ui-monospace, 'Cascadia Code', 'Consolas', monospace;
    font-size: var(--text-sm);
    color: var(--color-charcoal-mid);
    padding: 0 var(--space-2);
    border-radius: var(--radius-sm);
    background: var(--color-cream-mid);
}

.cce-addbar       { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.cce-addbar-label { font-size: var(--text-sm); color: var(--color-charcoal-mid); }
.cce-add-select {
    font-size: var(--text-sm);
    color: var(--color-charcoal);
    background: var(--color-white);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
    padding: 2px var(--space-2);
}

.cce-raw          { font-size: var(--text-sm); }
.cce-raw summary  { cursor: pointer; color: var(--color-charcoal-muted); font-size: var(--text-xs); }
.cce-raw-hint     { margin: var(--space-2) 0; font-size: var(--text-xs); color: var(--color-charcoal-muted); }
.cce-raw-box {
    font-family: ui-monospace, 'Cascadia Code', 'Consolas', monospace;
    font-size: var(--text-sm);
    line-height: var(--leading-snug);
}


/* ---------- InstrumentLineEditor (ile-*) ---------- */

.ile {
    margin-bottom: var(--space-5);
    padding-bottom: var(--space-4);
    border-bottom: 1px solid var(--color-cream-mid);
}
.ile:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
.ile-head { font-family: var(--font-display); font-size: var(--text-md); color: var(--color-charcoal); margin-bottom: var(--space-2); }
.ile-hint { font-weight: 400; font-size: var(--text-xs); color: var(--color-charcoal-muted); }
.ile-notes {
    font-family: ui-monospace, 'Cascadia Code', 'Consolas', monospace;
    font-size: var(--text-sm);
    line-height: var(--leading-snug);
}
.ile-preview { margin-top: var(--space-2); }

.ile-viewtoggle { display: inline-flex; gap: 2px; margin-bottom: var(--space-2); }
.ile-vbtn {
    border: 1px solid var(--surface-border);
    background: var(--color-white);
    color: var(--color-charcoal-muted);
    font-size: var(--text-xs);
    padding: 2px var(--space-2);
    cursor: pointer;
}
.ile-vbtn:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.ile-vbtn:last-child  { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.ile-vbtn-on          { background: var(--color-accent); color: var(--color-white); border-color: var(--color-accent); }

.ile-preview-label { display: block; font-size: var(--text-xs); color: var(--color-charcoal-muted); margin-bottom: var(--space-2); }

.ile-advanced { margin-top: var(--space-3); }
.ile-advanced > summary { cursor: pointer; user-select: none; font-size: var(--text-sm); color: var(--color-charcoal-muted); }

.ile-paste { margin-top: var(--space-3); }
.ile-paste > summary { cursor: pointer; user-select: none; font-size: var(--text-sm); color: var(--color-charcoal-muted); }
.ile-paste-hint { margin: var(--space-2) 0; font-size: var(--text-xs); color: var(--color-charcoal-muted); }
.ile-paste-box {
    /* AI Note: white-space: pre is required — tab columns must stay aligned; do not change to pre-wrap. */
    white-space: pre;
    overflow-x: auto;
    font-family: ui-monospace, 'Cascadia Code', 'Consolas', monospace;
    font-size: var(--text-sm);
    line-height: var(--leading-snug);
}
.ile-paste-actions { display: flex; align-items: center; gap: var(--space-3); margin-top: var(--space-2); }
.ile-paste-status  { font-size: var(--text-xs); color: var(--color-charcoal-muted); }


/* ---------- GrandStaffView (gs-*) ---------- */

.gs { display: flex; flex-direction: column; gap: var(--space-3); overflow-x: auto; }
.gs-empty { font-size: var(--text-sm); color: var(--color-charcoal-muted); }
.gs-label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-charcoal-muted);
    margin-bottom: 2px;
}
/* SVG canvas + overlaid glyph spans share the same origin box. */
.gs-canvas { position: relative; }
.gs-svg {
    display: block;
    background: var(--color-white);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
}

/* SVG element classes — stroke/fill properties target the inline SVG elements. */
.gs-line        { stroke: var(--color-charcoal-mid); stroke-width: 1; }
.gs-ledger      { stroke: var(--color-charcoal-mid); stroke-width: 1; }
.gs-barline     { stroke: var(--color-charcoal); stroke-width: 1.4; }
.gs-barline-thin { stroke: var(--color-cream-dark); stroke-width: 1; }
.gs-head        { fill: var(--color-white); stroke: var(--color-charcoal); stroke-width: 1.3; }
.gs-head-filled { fill: var(--color-charcoal); }
.gs-stem        { stroke: var(--color-charcoal); stroke-width: 1.3; }
.gs-flag        { stroke: var(--color-charcoal); stroke-width: 1.6; }

/* HTML overlaid glyph spans positioned in SVG pixel coordinates. */
.gs-glyph { position: absolute; line-height: 1; pointer-events: none; color: var(--color-charcoal); }
.gs-clef       { font-family: 'Segoe UI Symbol', 'Cambria Math', 'Bravura', serif; font-size: 34px; }
.gs-clef-bass  { font-size: 28px; }
.gs-acc        { font-family: 'Segoe UI Symbol', Arial, sans-serif; font-size: 15px; }
.gs-rest       { font-family: 'Segoe UI Symbol', 'Cambria Math', serif; font-size: 22px; }


/* ---------- MelodyView (roll-*) ---------- */
/* Vocal-melody piano roll. Row height 15px must match MelodyView.RowH. */

.roll-empty  { font-size: var(--text-sm); font-style: italic; color: var(--color-charcoal-muted); }
.roll-phrase { margin-bottom: var(--space-4); }
.roll-line   { margin-bottom: var(--space-3); }
.roll-line:last-child { margin-bottom: 0; }
.roll-plabel {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-charcoal-muted);
    margin-bottom: var(--space-1);
}
.roll-body {
    display: flex;
    background: var(--color-white);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.roll-keys { flex: 0 0 auto; border-right: 1px solid var(--color-cream-mid); }
.roll-key {
    height: 15px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding: 0 4px;
    font-size: 0.6rem;
    line-height: 1;
    color: var(--color-charcoal-muted);
    white-space: nowrap;
}
.roll-key-black { background: var(--color-cream-deep); }
.roll-scroll { flex: 1 1 auto; overflow-x: auto; }
.roll-area   { position: relative; min-width: 100%; }
.roll-bar    { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--color-cream-mid); }
.roll-note {
    position: absolute;
    background: var(--color-accent);
    border-radius: 2px;
    color: var(--color-white);
    font-size: 0.6rem;
    line-height: 1;
    overflow: hidden;
    display: flex;
    align-items: center;
}
.roll-syll { padding: 0 3px; white-space: nowrap; }


/* ---------- TabEditor (te-*) ---------- */

.te { display: flex; flex-direction: column; gap: var(--space-3); }
.te-empty {
    padding: var(--space-3);
    border: 1px dashed var(--surface-border);
    border-radius: var(--radius-sm);
    color: var(--color-charcoal-muted);
    font-size: var(--text-sm);
}
.te-phrase {
    padding: var(--space-3);
    background: var(--color-cream-deep);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-md);
}
.te-phrase-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}
.te-phrase-label {
    flex: 1 1 8rem;
    min-width: 6rem;
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--color-charcoal);
    background: var(--color-white);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
    padding: 2px var(--space-2);
}
.te-phrase-label:focus { outline: none; border-color: var(--color-accent); }

.te-ctl-l { display: inline-flex; align-items: center; gap: 4px; font-size: var(--text-xs); color: var(--color-charcoal-muted); }
.te-ctl-n {
    width: 3.2rem;
    font-size: var(--text-sm);
    background: var(--color-white);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
    padding: 2px var(--space-2);
}
.te-ctl {
    font-size: var(--text-sm);
    background: var(--color-white);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
    padding: 2px var(--space-2);
}
.te-phrase-del {
    margin-left: auto;
    width: 1.6rem; height: 1.6rem;
    border-radius: var(--radius-sm);
    border: 1px solid var(--surface-border);
    background: var(--color-white);
    color: var(--color-charcoal-muted);
    cursor: pointer;
    line-height: 1;
}
.te-phrase-del:hover { border-color: #9A3B2A; color: #9A3B2A; }

.te-grid {
    display: grid;
    gap: 2px;
    max-width: 100%;
    overflow-x: auto;
    padding-bottom: var(--space-2);
    margin-bottom: var(--space-2);
    font-family: ui-monospace, 'Cascadia Code', 'Consolas', monospace;
}
.te-beat { text-align: center; font-size: var(--text-xs); color: var(--color-charcoal-muted); line-height: 1.4; }
.te-strlabel {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding-right: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-charcoal-mid);
}
.te-cellwrap { position: relative; display: flex; }
.te-cell {
    width: 100%;
    min-width: 0;
    text-align: center;
    font: inherit;
    font-size: var(--text-sm);
    color: var(--color-charcoal);
    background: var(--color-white);
    border: 1px solid var(--color-cream-mid);
    border-radius: var(--radius-sm);
    padding: 2px 0;
    -moz-appearance: textfield;
}
.te-cell:focus  { outline: none; border-color: var(--color-accent); background: #FFFDF6; }
.te-cellwrap.te-sel .te-cell { border-color: var(--color-accent); box-shadow: 0 0 0 1px var(--color-accent); }

/* Bar-start columns get a heavier left edge to read measures at a glance. */
.te-barstart              { border-left: 2px solid var(--color-cream-dark); margin-left: 1px; }
.te-cellwrap.te-barstart  { padding-left: 1px; }

.te-tech {
    position: absolute;
    top: -2px; right: -1px;
    font-size: 0.6rem;
    line-height: 1;
    color: var(--color-accent);
    pointer-events: none;
}

.te-mods        { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: var(--space-3); }
.te-mods-label  { font-size: var(--text-xs); color: var(--color-charcoal-muted); margin-right: var(--space-2); }
.te-mod {
    min-width: 1.8rem;
    padding: 2px var(--space-2);
    font-size: var(--text-sm);
    border: 1px solid var(--surface-border);
    background: var(--color-white);
    color: var(--color-charcoal-mid);
    border-radius: var(--radius-sm);
    cursor: pointer;
}
.te-mod:hover:not(:disabled) { border-color: var(--color-accent); color: var(--color-accent); }
.te-mod:disabled              { opacity: 0.4; cursor: default; }
.te-mod-on                    { background: var(--color-accent); color: var(--color-white); border-color: var(--color-accent); }
.te-mods-hint { font-size: var(--text-xs); font-style: italic; color: var(--color-charcoal-muted); }

.te-addphrase {
    align-self: flex-start;
    padding: 2px var(--space-3);
    font-size: var(--text-xs);
    border: 1px dashed var(--surface-border);
    background: transparent;
    color: var(--color-charcoal-mid);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

/* ==========================================================================
   PRESS KIT DOWNLOAD BUTTON
   Press.razor — "Download Press Kit (PDF)" CTA above the press sections.
   Charcoal/cream matches the newsletter-signup-button pattern used
   elsewhere on public pages.
   ========================================================================== */

.press-download-bar {
    display: flex;
    justify-content: flex-end;
    margin-bottom: var(--space-5);
}

.press-download-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-5);
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.press-download-btn:hover {
    background-color: var(--color-accent);
    transform: translateY(-1px);
}

/* ==========================================================================
   PRESS KIT PRINT / PDF EXPORT
   Applied when the visitor uses the "Download Press Kit (PDF)" button
   (which triggers window.print()) or Ctrl+P on the press page.

   Hidden sections are not in the DOM at all (ShouldRender() guards with
   @if in Press.razor), so they naturally do not appear in print — no
   extra CSS needed for that case.
   ========================================================================== */

@media print {
    /* Hide site chrome and the download button itself */
    .site-header,
    .site-footer,
    .hamburger-menu,
    .global-player,
    .press-download-bar,
    .press-download-btn,
    .admin-edit-overlay,
    .press-section-hidden-badge { display: none !important; }

    /* Reset backgrounds and text colors for print */
    body,
    .public-page,
    .press-page,
    .press-section,
    .tile,
    .tile-light {
        background: white !important;
        color: #1a1a1a !important;
        box-shadow: none !important;
    }

    /* Press sections as clean, self-contained blocks */
    .press-section {
        page-break-inside: avoid;
        border: 1px solid #ddd !important;
        margin-bottom: 16pt;
        padding: 12pt;
    }

    /* Photos grid: 3 per row in print (overrides the responsive auto-fill) */
    .press-photos-grid {
        grid-template-columns: repeat(3, 1fr) !important;
        gap: 8pt;
    }

    .press-photos-grid figure { page-break-inside: avoid; }

    /* Page header: band name + EPK label injected via CSS */
    .press-page::before {
        content: "HiFi Riff Raff \2014  Electronic Press Kit";
        display: block;
        font-size: 18pt;
        font-weight: bold;
        border-bottom: 2pt solid #1a1a1a;
        padding-bottom: 8pt;
        margin-bottom: 16pt;
    }

    /* Show full URLs after links so the printed copy is useful offline */
    a[href^="http"]::after {
        content: " (" attr(href) ")";
        font-size: 8pt;
        color: #666;
    }
    a[href^="mailto"]::after {
        content: " (" attr(href) ")";
        font-size: 8pt;
        color: #666;
    }

    /* Prevent links from breaking mid-line across a page boundary */
    a { page-break-inside: avoid; }

    /* Standard 1-inch margins for a clean printed page */
    @page { margin: 1in; }
}
.te-addphrase:hover { border-color: var(--color-accent); color: var(--color-accent); }

/* ==========================================================================
   SCROLL REVEAL — entrance animations
   Elements with class "scroll-reveal" fade + slide up when they enter the
   viewport. The JS module (wwwroot/js/scroll-reveal.js) drives the observer;
   it adds "scroll-reveal--visible" on intersection. One-time per element.
   ========================================================================== */

.scroll-reveal {
    opacity: 0;
    transform: translateY(20px);
    transition: opacity 0.45s ease, transform 0.45s ease;
}

.scroll-reveal--visible {
    opacity: 1;
    transform: translateY(0);
}

/* Respect prefers-reduced-motion: disable transition entirely; keep opacity
   at 1 so content is always visible even if JS has not run yet. */
@media (prefers-reduced-motion: reduce) {
    .scroll-reveal,
    .scroll-reveal--visible {
        transition: none;
        opacity: 1;
        transform: none;
    }
}

/* Canvas: the focal block is the always-first-screen anchor. Its content must never sit at
   scroll-reveal's opacity:0 waiting for the IntersectionObserver, or the first viewport reads
   empty (the Videos-under-Canvas case — the gallery is now focal via CanvasDerivation, so its
   cards must show immediately). The observer still runs; this only removes the pre-reveal hidden
   state for the anchor. Satellites below the fold keep their reveal-on-scroll. */
.cms-page-canvas [data-canvas-role="focal"] .scroll-reveal {
    opacity: 1;
    transform: none;
}

/* ==========================================================================
   PAGE LOADING SKELETON — shown while gRPC data is being fetched on WASM
   navigation (the pre-render handoff window).

   Pattern: each public page wraps its data-dependent content in an @if
   (_isLoading) / @else block. The skeleton uses pulsing placeholder bars
   that match the page card-grid or list layout so the page never looks
   blank or frozen.
   ========================================================================== */

/* Shared wrapper: same flow as .public-page */
.page-loading {
    display: flex;
    flex-direction: column;
    gap: var(--space-7);
    width: 100%;
}

/* Pulse animation for all skeleton bars */
@keyframes page-skeleton-pulse {
    0%, 100% { opacity: 1; }
    50%       { opacity: 0.45; }
}

/* Generic skeleton bar */
.page-loading-bar {
    background: var(--surface-deep);
    border-radius: 6px;
    animation: page-skeleton-pulse 1.6s ease-in-out infinite;
}

/* Grid of skeleton cards — mirrors .videos-grid / .releases-grid /
   .playlists-grid / .about-members-grid responsive breakpoints */
.page-loading-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
    gap: var(--space-7);
}

/* Individual skeleton card */
.page-loading-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    background: var(--surface-deep);
    border-radius: 12px;
    padding: var(--space-5);
    animation: page-skeleton-pulse 1.6s ease-in-out infinite;
}

/* Aspect-ratio placeholder for video / image thumbnails (16:9) */
.page-loading-thumb {
    width: 100%;
    aspect-ratio: 16 / 9;
    background: color-mix(in srgb, var(--surface-page-text-muted) 15%, transparent);
    border-radius: 8px;
}

/* Square thumbnail variant for release cover art */
.page-loading-thumb-square {
    width: 100%;
    aspect-ratio: 1 / 1;
    background: color-mix(in srgb, var(--surface-page-text-muted) 15%, transparent);
    border-radius: 8px;
}

/* Text line bars of varying widths */
.page-loading-line {
    height: 14px;
    background: color-mix(in srgb, var(--surface-page-text-muted) 20%, transparent);
    border-radius: 4px;
}
.page-loading-line-title  { height: 18px; width: 70%; }
.page-loading-line-meta   { height: 12px; width: 45%; }
.page-loading-line-body   { height: 12px; width: 90%; }
.page-loading-line-body2  { height: 12px; width: 75%; }

/* List skeleton — mirrors .shows-list */
.page-loading-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

/* Each row in the list skeleton */
.page-loading-list-row {
    display: flex;
    gap: var(--space-5);
    align-items: flex-start;
    background: var(--surface-deep);
    border-radius: 10px;
    padding: var(--space-5);
    animation: page-skeleton-pulse 1.6s ease-in-out infinite;
}

.page-loading-list-date {
    width: 48px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    align-items: center;
}

.page-loading-list-date .page-loading-line {
    width: 100%;
}

.page-loading-list-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* Stagger the pulse on sibling skeleton items so they pulse in waves */
.page-loading-card:nth-child(2),
.page-loading-list-row:nth-child(2) { animation-delay: 0.2s; }
.page-loading-card:nth-child(3),
.page-loading-list-row:nth-child(3) { animation-delay: 0.4s; }
.page-loading-card:nth-child(4),
.page-loading-list-row:nth-child(4) { animation-delay: 0.2s; }
.page-loading-card:nth-child(5),
.page-loading-list-row:nth-child(5) { animation-delay: 0.4s; }
.page-loading-card:nth-child(6),
.page-loading-list-row:nth-child(6) { animation-delay: 0.6s; }

/* =============================================================
   SOCIAL PROOF — About page section (PP7)
   Default-off: the .about-social-proof element only renders when
   visible items exist. See About.razor for the guard logic.
   ============================================================= */

.about-social-proof {
    margin: 2.5rem 0;
    padding: 0;
}

/* Section label — same pattern as other about-page section headings. */
.about-social-proof .section-label {
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--surface-page-text-muted, #6b7280);
    margin-bottom: 1.2rem;
}

/* Responsive grid: single column on narrow viewports, auto-fill
   ~280 px columns on wider screens — adapts naturally to 1, 2, or 3
   items without explicit breakpoints. */
.social-proof-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
    gap: 1rem;
}

/* ---- Quote tile ---- */
.social-proof-quote {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding: 1.2rem 1.4rem;
    margin: 0;
    text-decoration: none;
    color: inherit;
    transition: box-shadow var(--duration-fast);
}

.social-proof-quote:is(a):hover {
    box-shadow: 0 4px 18px rgba(0, 0, 0, 0.12);
}

/* ---- Milestone tile ---- */
.social-proof-milestone {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.5rem;
    padding: 1.2rem 1.4rem;
    text-align: center;
}

/* ---- Shared typography ---- */
.social-proof-text {
    font-size: 1rem;
    line-height: 1.55;
    margin: 0;
}

.social-proof-attribution {
    font-size: 0.85rem;
    font-style: normal;
    color: var(--surface-page-text-muted, #6b7280);
    margin: 0;
}

/* ---- Badge tile ---- */
.social-proof-badge-link {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.8rem;
    text-decoration: none;
}

.social-proof-badge-img {
    max-width: 100%;
    max-height: 120px;
    object-fit: contain;
}

/* ---- Mobile: single column ---- */
@media (max-width: 540px) {
    .social-proof-grid {
        grid-template-columns: 1fr;
    }
}

/* ============================================================
   Mini-CMS page builder (docs/features/MiniCMS-v1.md)
   Full-width three-zone editor: Structure / Canvas / Inspector
   + a collapsible Output Console. Uses the full area under the
   app header (intentionally not constrained to the site layout).
   ============================================================ */
.cms-builder {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    width: 100%;
    min-height: calc(100dvh - 7rem);
    padding: var(--space-3);
    box-sizing: border-box;
}
.cms-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background: var(--surface-raised);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
}
.cms-toolbar-spacer { flex: 1 1 var(--space-4); }
.cms-device-switch { display: inline-flex; gap: var(--space-1); }
.cms-device-switch .is-active { background: var(--color-accent); color: var(--color-white); }

.cms-stage {
    display: flex;
    gap: var(--space-2);
    flex: 1 1 auto;
    min-height: 24rem;
    align-items: stretch;
}
.cms-panel {
    flex: 0 0 auto;
    overflow: auto;
    padding: var(--space-3);
    background: var(--surface-raised);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
}
.cms-structure { width: 16rem; }
.cms-inspector { width: 22rem; }
.cms-panel-title { font-size: 1rem; margin: 0 0 var(--space-2); }
.cms-structure-head { display: flex; align-items: center; justify-content: space-between; margin: var(--space-3) 0 var(--space-1); }

.cms-tree-row { display: flex; align-items: center; gap: var(--space-1); }
.cms-tree-item {
    flex: 1 1 auto;
    text-align: left;
    padding: var(--space-1) var(--space-2);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    cursor: pointer;
    color: var(--surface-page-text);
}
.cms-tree-item:hover { background: var(--surface-deep); }
.cms-tree-item.is-selected { background: var(--color-accent-light); border-color: var(--color-accent); }
.cms-delete-page { margin-top: var(--space-4); width: 100%; }

/* Reuse / shared-component affordances (full-reuse model). */
.cms-insert-shared { margin-top: var(--space-2); width: 100%; }
.cms-shared-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    margin: var(--space-3) 0 var(--space-1);
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    background: var(--color-accent-light);
    border: 1px solid var(--color-accent);
}

.cms-canvas {
    flex: 1 1 auto;
    overflow: auto;
    background: var(--surface-deep);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    display: flex;
    justify-content: center;
}
.cms-canvas-frame {
    width: 100%;
    transition: max-width 0.2s ease;
    container-type: inline-size;   /* device-frame width drives the @container reflow below */
    /* R6 WYSIWYG: the frame paints the PAGE surface. With the selected theme's vars
       stamped inline (hfrr-theme-vars.js) this is that theme's real page color, so
       blocks sit on the same canvas a visitor sees — not the workbench backdrop. */
    background: var(--surface-page);
    color: var(--surface-page-text);
}
.cms-device-desktop { max-width: 1280px; }
.cms-device-tablet { max-width: 768px; }
.cms-device-mobile { max-width: 390px; }

/* ── PageBuilder theme+layout preview (U5 / Unification-Plan-v1.md §M4) ───────────────────────
   The Preview view swaps the editing canvas for an iframe at the page's real public URL under the
   admin ?theme=/?layout= override. Reuses the device-frame width classes above (cms-device-*), so
   the desktop/tablet/mobile switch drives the preview too. */
.cms-preview-hint { margin-bottom: var(--space-2); text-align: center; }
.cms-preview-shell {
    /* A tall viewport for the framed page; the device-frame class caps the width. */
    height: min(72vh, 900px);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--surface-raised);
}
.cms-preview-frame {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}
/* Preview theme/layout selects sit inline in the toolbar. */
.cms-preview-select { display: inline-flex; align-items: center; }

/* ── Unified page frame (U1 / Unification-Plan-v1.md §M2) ─────────────────────────────────────
   ONE shell rule the renderer applies; blocks never re-decide geometry. Centered max-width column
   with a nonzero inline gutter, at the renderer level (KB: frame-container-centered +
   frame-min-inline-gutter + frame-consistent-across-pages). `max(gutter, inset)` is the KB
   "insets STACK on the gutter, never replace" rule — a layout raises --frame-inset to add chrome
   inset without losing the gutter floor, and it never double-pads. */
.page-frame {
    max-width: var(--frame-max-width);
    margin-inline: auto;
    padding-inline: max(var(--frame-gutter), var(--frame-inset));
    /* R4 (KB frame-section-rhythm): content never butts the chrome — the frame
       owns the vertical breathing room between header/footer and the page column.
       --frame-block-gap is overridable per surface; the fullbleed-first exemption
       below keeps intentional hero bleeds touching the header. */
    padding-block: var(--frame-block-gap, var(--space-6)) var(--space-7);
    box-sizing: border-box;
}
/* Prose variant: the narrow measure for text-first pages (folds --max-width-prose). */
.page-frame--prose { max-width: var(--frame-prose-measure); }

/* A page whose FIRST block is an intentional full-bleed/hero keeps touching the
   header: pull it back up by the frame's top gap. (The sr-only page h1 precedes
   the first block inside .cms-page, hence the adjacent-sibling anchor.) */
.cms-page > .sr-only + .cms-block-fullbleed {
    margin-top: calc(-1 * var(--frame-block-gap, var(--space-6)));
}

/* Public page wrapper is the framed column AND the bento's query container: .page-frame supplies
   the centered max-width + gutter, container-type stays on the SAME element so 100cqw == the framed
   column (the full-bleed technique below bleeds to the column edges, not the viewport). */
.cms-page-container {
    container-type: inline-size;
}

/* Grid tracks + cell placement come from CSS custom props (set inline by PageGrid.ToCss /
   BlockHost / the builder), so the container queries below can collapse the bento on mobile. */
.cms-page {
    display: grid;
    grid-template-columns: var(--cms-cols, repeat(4, minmax(0, 1fr)));
    grid-template-rows: var(--cms-rows, none);
    /* Fluid inter-tile gap — grows gently on wide screens, stays tight (current 8px) on small.
       Spec: fluid gap; kept near the existing density rather than jumping to roomy. */
    gap: clamp(var(--space-3), 1.2vw, var(--space-5));
    /* Content gutter comes from the .page-frame shell on .cms-page-container (single-gutter
       invariant, U1/M2) — NOT here. --cms-pad is now an OPTIONAL author extra (default 0), stacked
       INSIDE the frame gutter, never the frame's gutter source. */
    padding: var(--cms-pad, 0);
}
/* An authored --cms-pad (set inline from the page's grid config, e.g. 0 5rem) is a fine extra gutter on a
   wide page but crushes content on phones (5rem each side of a 375px screen leaves ~190px). Cap the
   HORIZONTAL padding on small screens so the content nearly fills the width; the authored vertical stays. */
@media (max-width: 640px) {
    .cms-page { padding-inline: var(--space-4); }
}
.cms-block {
    grid-column: var(--cms-col, auto);
    grid-row: var(--cms-row, auto);
    /* Overflow guard: grid/flex children default to min-width:auto, so wide content (long words,
       media, pre) can force the whole grid to overflow horizontally. min-width:0 lets a tile shrink
       to its track instead — the key anti-blowout fix for 320px reflow. */
    min-width: 0;
    /* Global tile rounding (one knob: --cms-tile-radius). overflow:hidden so background
       images, colored surfaces, and the WebGL visualizer all clip to the rounded corner. */
    border-radius: var(--cms-tile-radius);
    overflow: hidden;
}
/* Full-bleed banner: a Full-page block breaks out of the page's centered frame to span the full
   width of the FRAMED COLUMN, edge to edge (no rounding). Spans all grid columns via --cms-col.
   ONE generalized technique (U1/M2): keyed to the query CONTAINER (.cms-page-container is
   container-type:inline-size), so 100cqw == the framed column width under EVERY layout — the bleed
   reaches the column edges without escaping to the viewport (KB: frame-fullbleed-keeps-inner). This
   replaced the old 100vw/calc(50%-50vw) that overflowed under any inset (Rail/Canvas); the per-rail
   rail.css §8 override that pioneered this is now redundant and removed. */
.cms-block-fullbleed {
    width: 100cqw;
    max-width: 100cqw;
    margin-inline: calc(50% - 50cqw);
    border-radius: 0;
}

.cms-canvas-cell {
    position: relative;
    min-height: 8rem;
    grid-column: var(--cms-col, auto);
    grid-row: var(--cms-row, auto);
    border-radius: var(--radius-md);
    outline: 1px dashed var(--color-border-subtle);
    outline-offset: -1px;
    cursor: pointer;
    overflow: hidden;
    /* Flex so the block content stretches to fill the cell's full height — matching the public
       page, where the block IS the grid item. Without this the block sat at natural height,
       top-pinned, in a cell stretched to the grid row's min-height. */
    display: flex;
}

/* Bento reflow: 4 cols → 2 cols (tablet) → 1 col full-width (mobile). Keyed to the query
   container (device frame in the builder, viewport on the public page). */
@container (max-width: 760px) {
    .cms-page { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: none; }
    /* Blocks carry explicit 4-col --cms-col/--cms-row (e.g. "3 / 5"); in a 2-col grid those land in
       non-existent tracks and sit side-by-side/overflow. Reset to auto-flow so they reflow into 2
       columns in order instead of staying pinned to their desktop position. */
    .cms-block, .cms-canvas-cell { grid-column: auto !important; grid-row: auto !important; }
    /* Wide desktop tiles (banners/features spanning >=2 cols, tagged by BlockHost) span BOTH tablet
       columns instead of shrinking to a half-width cell that clips their content. */
    .cms-block-tablet-wide { grid-column: 1 / -1 !important; }
    /* Same collapse risk at the 2-col tablet breakpoint — floor scene/visualizer tile height. */
    .cms-block:has(> .cms-block-bg) { min-height: clamp(12rem, 35vw, 18rem); }
}
@container (max-width: 460px) {
    /* Phones: one column. The side gutter comes from the .page-frame shell (single-gutter invariant,
       U1/M2) — NOT a padding-inline here, which would double-pad against the frame gutter. */
    .cms-page { grid-template-columns: 1fr; grid-template-rows: none; }
    .cms-block, .cms-canvas-cell { grid-column: 1 / -1 !important; grid-row: auto !important; }
    /* Visualizer/scene tiles position their content (canvas + text layers) ABSOLUTELY, so with auto
       rows on mobile they collapse to nothing — squashing the band and clipping the in-tile button.
       Floor their height so the layered content stays visible. (A true fit-to-tallest-layer needs a
       compositor change; this is the robust CSS mitigation.) */
    .cms-block:has(> .cms-block-bg) { min-height: clamp(14rem, 60vw, 20rem); }
}
.cms-canvas-cell.is-selected { outline: 2px solid var(--color-accent); }
.cms-canvas-cell .tile-layer-host { width: 100%; height: 100%; min-height: 8rem; }
.cms-canvas-empty {
    grid-column: 1 / -1;
    display: flex; align-items: center; justify-content: center;
    min-height: 12rem; color: var(--surface-page-text-muted);
    text-align: center;
}

.cms-console {
    flex: 0 0 auto;
    background: var(--surface-inverse);
    color: var(--surface-inverse-text);
    border-radius: var(--radius-md);
    overflow: hidden;
}
.cms-console-head { padding: var(--space-1) var(--space-3); background: var(--surface-inverse); font-size: 0.85rem; }
.cms-console-body { padding: var(--space-2) var(--space-3); max-height: 12rem; overflow: auto; }
.cms-console-body .admin-field-help { color: var(--color-cream-mid); }

@media (max-width: 900px) {
    .cms-stage { flex-direction: column; }
    .cms-structure, .cms-inspector { width: 100%; }
}

/* Mini-CMS: admin edit-pencil overlay on public blocks + deep-link flash */
.cms-block { position: relative; }
.cms-block-edit {
    position: absolute;
    top: var(--space-1);
    right: var(--space-1);
    z-index: 5;
    width: 1.75rem; height: 1.75rem;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--color-charcoal);
    color: var(--color-cream);
    border-radius: var(--radius-full);
    text-decoration: none;
    opacity: 0; transition: opacity 0.15s ease;
}
.cms-block:hover .cms-block-edit { opacity: 0.92; }
.cms-block-error, .cms-block-unknown {
    padding: var(--space-2);
    font-size: 0.85rem;
    color: var(--surface-deep-text-muted);
    background: var(--surface-deep);
    border: 1px dashed var(--color-border-subtle);
    border-radius: var(--radius-sm);
}
@keyframes cmsCellFlash {
    0%, 100% { box-shadow: 0 0 0 0 rgba(0,0,0,0); }
    30% { box-shadow: 0 0 0 4px var(--color-accent); }
}
.cms-cell-flash { animation: cmsCellFlash 1.2s ease; }

/* Mini-CMS builder: tile being dragged for rearrange */
.cms-canvas-cell.is-dragging { opacity: 0.5; }
.cms-canvas-cell[draggable="true"] { cursor: grab; }

/* Mini-CMS builder: publish status + version history */
.cms-status { display: flex; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-1); }
.cms-status-badge {
    padding: 0.1rem var(--space-2);
    border-radius: var(--radius-full);
    background: var(--surface-deep);
    color: var(--surface-deep-text);
    font-size: 0.8rem;
}
.cms-status-badge.is-published { background: var(--color-accent); color: var(--color-white); }
/* Amber-ish "draft has edits not yet live" pill. */
.cms-status-badge-dirty { background: #B8860B; color: var(--color-white); }
.cms-status-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }
/* Bounded + scrollable so a long history never stretches the inspector column. */
.cms-versions { list-style: none; margin: var(--space-1) 0 0; padding: 0; max-height: 14rem; overflow-y: auto; }
.cms-version-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--admin-gap); padding: var(--space-1) 0;
    border-bottom: 1px solid var(--color-border-subtle);
    font-size: var(--admin-text-control);
}
.cms-version-actions { display: inline-flex; gap: var(--space-1); flex-shrink: 0; }

/* Mini-CMS: contact-form block + Output Console log entries */
/* R3: field-stack rhythm — space-2 read as a cramped 6px between groups (owner
   report); space-4 gives each label+field group breathing room. */
.cms-contact-form { display: flex; flex-direction: column; gap: var(--space-4); padding: var(--space-3); }
.cms-cf-field { display: flex; flex-direction: column; gap: var(--space-1); }
.cms-cf-field > span { font-size: 0.85rem; color: var(--surface-raised-text-muted); } /* contact form is a raised surface; primitive charcoal-mid was invisible under Dark */
/* R3: fields sit ON the raised contact card — the page pair keeps the field
   boundary visible against the card AND typed text themed (was a cream-light
   island with default-black text under every theme). */
.cms-cf-field input, .cms-cf-field textarea {
    padding: var(--space-2); min-height: 2.75rem; border: 1px solid var(--surface-border); border-radius: var(--radius-sm);
    font: inherit; background: var(--surface-page); color: var(--surface-page-text);
}
/* BL-012 / FLG-CMP-BLOCKS-1-01: explicit focus ring on the public contact form
   (guarantees a visible focus delta on the primary public form). */
.cms-cf-field input:focus-visible, .cms-cf-field textarea:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
    border-color: var(--color-accent);
}
.cms-cf-status.is-ok { color: var(--color-accent); }
.cms-cf-status.is-error { color: var(--color-danger); }
/* Honeypot: kept in the DOM for bots to fill, removed from view + a11y tree for
   real users (off-screen, no pointer/tab reach). aria-hidden + tabindex=-1 are
   also set on the input itself. Not display:none — some bots skip hidden fields. */
.cms-cf-hp {
    position: absolute; left: -9999px; width: 1px; height: 1px;
    overflow: hidden; opacity: 0; pointer-events: none;
}
.cms-log { padding: var(--space-1) 0; border-bottom: 1px solid var(--color-charcoal-mid); }
.cms-log-meta { font-size: 0.72rem; opacity: 0.65; }
.cms-log-msg { font-size: 0.85rem; }
.cms-log.is-error .cms-log-msg { color: var(--color-amber); }
.cms-log-detail {
    white-space: pre-wrap; font-size: 0.72rem; margin: var(--space-1) 0 0;
    max-height: 8rem; overflow: auto;
    background: rgba(0, 0, 0, 0.25); padding: var(--space-1) var(--space-2); border-radius: var(--radius-sm);
}

/* Mini-CMS: rich-text block content */
.cms-richtext { padding: var(--space-3); overflow-wrap: break-word; }
.cms-richtext > :first-child { margin-top: 0; }
.cms-richtext img { max-width: 100%; height: auto; }   /* responsive images in prose */

/* BL-041 / FLG-TSM-004 — cap the readable measure. The block tile itself stays full-bleed (don't
   cap the bento grid), but author prose ran ~158 CPL on privacy/terms/press at full viewport width
   (~2x the WCAG 1.4.8 ~80-char cap). We cap the INNER text-bearing children at --measure (65ch) so
   line length stays readable while media/tables can still use the full tile width. */
.cms-richtext > p,
.cms-richtext > ul,
.cms-richtext > ol,
.cms-richtext > blockquote,
.cms-richtext > h2,
.cms-richtext > h3,
.cms-richtext > h4,
.cms-richtext > h5,
.cms-richtext > h6 {
    max-width: var(--measure);
}

/* BL-042 / FLG-TSM-002 — author-prose headings had NO font-size, so they fell to the UA defaults
   (h2 24px / h3 18.72px), bypassing the live display type scale. Put them on the --text-* steps
   (the live scale; the near-dead --step-* scale is intentionally not used here per ACC-007). */
.cms-richtext h2 { font-size: var(--text-2xl); margin-top: var(--space-4); }
.cms-richtext h3 { font-size: var(--text-xl);  margin-top: var(--space-4); }
.cms-richtext h4 { font-size: var(--text-lg);  margin-top: var(--space-3); }
.cms-richtext h5 { font-size: var(--text-md);  margin-top: var(--space-3); }
.cms-richtext h6 { font-size: var(--text-sm);  margin-top: var(--space-3); }

/* BL-016 residue — pin prose links to the AA accent-text role (5.36:1 on cream) so a richtext
   link never inherits the accent-light hover hue (#E8733A ~3.78:1) as its resting color. */
/* U2: richtext links follow the block's surface accent, not the darker --color-accent-text
   (which stranded to ~1.56:1 on the grunge canvas backdrop). --color-accent is the surface
   link color the [data-block-surface] :where(a) rules also emit, kept here to win specificity. */
.cms-richtext a { color: var(--color-accent-text); } /* text-safe accent (5.36:1 cream); --color-accent is fills only */
.cms-richtext a:hover { color: var(--link-hover); }

/* Data-backed display blocks (Releases / Shows / Playlists / Featured release).
   Self-contained block styling — consistent across the three embedding contexts. */
.cms-data-block { padding: var(--space-3); }
.cms-data-heading { margin: 0 0 var(--space-3); font-size: var(--step-1); }
.cms-data-empty { color: var(--color-charcoal-soft, inherit); opacity: 0.75; padding: var(--space-2) 0; }
.cms-data-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr));
    gap: var(--space-3);
}
.cms-data-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-3);
    border: var(--border-thin);
    border-radius: var(--radius-md);
    background: var(--color-cream-mid, transparent);
}
.cms-data-cover { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: var(--radius-sm); margin-bottom: var(--space-1); }
.cms-data-card-title { margin: 0; font-size: 1.05rem; }
.cms-data-card-meta { margin: 0; font-size: 0.85rem; opacity: 0.8; }
.cms-data-card-notes { margin: var(--space-1) 0 0; font-size: 0.85rem; }
.cms-data-tracklist { margin: var(--space-2) 0 0; padding-left: 1.2em; font-size: 0.85rem; }
.cms-data-eyebrow, .cms-data-show-tickets { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; }

/* Upcoming-shows list */
.cms-data-shows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.cms-data-show { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); border: var(--border-thin); border-radius: var(--radius-md); }
.cms-data-show-date { display: flex; flex-direction: column; align-items: center; min-width: 3rem; }
.cms-data-show-month { font-size: 0.75rem; text-transform: uppercase; opacity: 0.8; }
.cms-data-show-day { font-size: 1.4rem; font-weight: 700; line-height: 1; }
.cms-data-show-info { flex: 1 1 auto; }
.cms-data-show-tickets { margin-left: auto; padding: var(--space-1) var(--space-3); border: var(--border-thin); border-radius: var(--radius-sm); text-decoration: none; white-space: nowrap; }

/* Featured release */
.cms-data-featured { display: flex; gap: var(--space-4); flex-wrap: wrap; padding: var(--space-3); }
.cms-data-featured-cover { width: 220px; max-width: 100%; aspect-ratio: 1; object-fit: cover; object-position: var(--tile-focal); border-radius: var(--radius-tile); }
.cms-data-featured-body { flex: 1 1 260px; min-width: 0; }
.cms-data-featured-desc { margin: var(--space-2) 0 0; }
.cms-data-meta { display: block; font-size: 0.85rem; opacity: 0.8; margin-top: var(--space-1); }

/* Featured video (single performance) — the video sits above its title in a tile. */
.cms-data-featured .cms-data-video { flex: 1 1 100%; }
.cms-data-video { aspect-ratio: 16 / 9; border-radius: var(--radius-md); overflow: hidden; }
.cms-data-video iframe, .cms-data-video > * { width: 100%; height: 100%; border: 0; }

/* Featured show — the date-badge card links to /shows; empty state keeps the eyebrow. */
a.cms-data-show { text-decoration: none; color: inherit; }
.cms-data-show-empty { padding: var(--space-2) var(--space-3); }

/* Press quotes */
.cms-data-quotes { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: var(--space-3); }
.cms-data-quote { margin: 0; padding: var(--space-3); border-left: 3px solid var(--color-accent); background: var(--color-cream-mid, transparent); }
.cms-data-quote blockquote { margin: 0; font-style: italic; }
.cms-data-quote figcaption { margin-top: var(--space-2); font-size: 0.85rem; opacity: 0.8; }

/* Newsletter signup */
.cms-newsletter-form { display: flex; gap: var(--space-2); flex-wrap: wrap; align-items: center; }
/* R3: the email field pairs with the page surface (was an unstyled default —
   white with black text under every theme). */
.cms-newsletter-email { flex: 1 1 220px; min-width: 0; min-height: 2.75rem; padding: var(--space-2) var(--space-3); border: 1px solid var(--surface-border); border-radius: var(--radius-sm); background: var(--surface-page); color: var(--surface-page-text); }
/* R3: inverse pair replaces charcoal/cream (a dark-on-dark button under dark themes). */
.cms-newsletter-button {
    flex-shrink: 0;
    min-height: 2.75rem;   /* tap target */
    padding: var(--space-2) var(--space-5);
    background-color: var(--surface-inverse);
    color: var(--surface-inverse-text);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background-color var(--duration-fast), color var(--duration-fast), transform var(--duration-fast);
}
.cms-newsletter-button:hover:not(:disabled) { background-color: var(--surface-accent); color: var(--surface-accent-text); transform: translateY(-1px); }
.cms-newsletter-button:disabled { opacity: 0.5; cursor: not-allowed; }
.cms-newsletter-done { font-weight: 600; }
.cms-newsletter-error { color: var(--color-danger); font-size: 0.85rem; margin-top: var(--space-1); }

/* Mini-CMS: ultra-dense inspector (Visual Studio properties-grid style).
   Scoped to .cms-props so the nested LayerStackEditor keeps its own layout. */
/* Inspector density is now the shared admin token system (no per-rule hardcoded sizes). These rules
   keep only the inspector LAYOUT — the 2-column label|control grid + per-row dividers. Font sizes,
   control heights, and padding come from --admin-* (which the Dense/Ultra toggle drives). */
.cms-inspector .cms-panel-title { font-size: var(--admin-text-section); margin: 0 0 var(--space-1); }
.cms-props { display: flex; flex-direction: column; }
.cms-props > .admin-field {
    display: grid;
    grid-template-columns: minmax(5.5rem, 42%) 1fr;
    align-items: center;
    gap: 0 var(--admin-gap);
    margin: 0;
    padding: var(--admin-pad-y) 0;
    border-bottom: 1px solid var(--color-border-subtle);
}
.cms-props > .admin-field > .admin-field-label {
    color: var(--surface-page-text-muted);
    margin: 0;
    line-height: 1.15;
}
/* Wide controls (markdown, status block, page-grid) span both columns. */
.cms-props > .admin-field > textarea.admin-input { grid-column: 1 / -1; }
.cms-props > .admin-checkbox {
    display: flex; align-items: center; gap: var(--admin-gap);
    padding: var(--admin-pad-y) 0; margin: 0;
    border-bottom: 1px solid var(--color-border-subtle);
}
.cms-props .admin-field-help { grid-column: 1 / -1; margin: 1px 0 0; }
.cms-props .cms-hardcoded-note { padding: var(--space-1); background: var(--surface-deep); border-radius: var(--radius-sm); }
.cms-props .cms-status { display: flex; align-items: center; gap: var(--admin-gap); margin: 0; }
/* Field editor: full-row group headers, advanced fold, inline validation errors. */
.cms-props .cms-group-head { grid-column: 1 / -1; margin-top: var(--admin-section-gap); padding-top: var(--space-1); border-top: 1px solid var(--color-border-subtle); font-size: var(--admin-text-section); font-weight: 600; }
.cms-props .cms-advanced-toggle { grid-column: 1 / -1; justify-self: start; margin: 2px 0; padding: 1px var(--admin-pad-x); background: none; border: 0; color: var(--surface-page-text-muted); font-size: var(--admin-text-help); cursor: pointer; }
.cms-props .cms-advanced-toggle:hover { color: var(--surface-page-text); }
.cms-props .cms-field-error { grid-column: 1 / -1; font-size: var(--admin-text-help); margin: 1px 0 0; color: var(--color-danger); }
/* Reusable image field (upload + browse + preview). */
.image-field { display: flex; flex-direction: column; gap: var(--admin-gap); }
.image-field-preview { max-width: 100%; max-height: 110px; border-radius: var(--admin-radius); object-fit: cover; }
.image-field-empty { font-size: var(--admin-text-help); color: var(--surface-page-text-muted); padding: var(--space-1); border: 1px dashed var(--color-border-subtle); border-radius: var(--admin-radius); text-align: center; }
.image-field-actions { display: flex; flex-wrap: wrap; gap: var(--admin-gap); align-items: center; }
.image-field-actions .admin-file-input { max-width: 11rem; }
/* Downloadable-file field (CMS Downloads block) — the non-image counterpart of .image-field. */
.file-field { display: flex; flex-direction: column; gap: var(--admin-gap); }
.file-field-current { font-size: var(--admin-text-help); color: var(--color-accent); word-break: break-all; }
.file-field-empty { font-size: var(--admin-text-help); color: var(--surface-page-text-muted); padding: var(--space-1); border: 1px dashed var(--color-border-subtle); border-radius: var(--admin-radius); text-align: center; }
.file-field-actions { display: flex; flex-wrap: wrap; gap: var(--admin-gap); align-items: center; }
.file-field-actions .admin-file-input { max-width: 11rem; }

/* Mini-CMS builder: canvas renders blocks with the real renderer; disable their pointer
   events so clicks select/drag the tile (and preview forms don't fire). */
.cms-canvas-cell-content { pointer-events: none; width: 100%; height: 100%; display: flex; }
.cms-canvas-cell-content .cms-block { min-height: 4rem; flex: 1; width: 100%; }

/* Mini-CMS builder: don't let a double-click select text in a canvas tile (it can leave an
   unreadable highlight); the tile is a selection target, not selectable content. */
.cms-canvas-cell { user-select: none; }

/* CMS block: the tile-layer substrate is a z-0 background (contained to the block); the
   block's foreground content (text/form/data) sits above it at z-1. Fixes content blocks
   going black when they carry a layer stack (the absolute, charcoal .tile-layer-host used to
   paint over the foreground). */
.cms-block-bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; border-radius: inherit; }
.cms-block > :not(.cms-block-bg):not(.cms-block-edit) { position: relative; z-index: 1; }
.cms-block { min-height: 3rem; }
/* The charcoal .tile-layer-host base is for home tiles. In the CMS the substrate must be
   transparent so a block's own layers (or the page) show through — never a dark box behind
   foreground text. (Belt-and-suspenders with HasStack: an empty stack no longer mounts a host.) */
.cms-block-bg .tile-layer-host { background: transparent; }

/* Builder-canvas stand-in for a Visualizer block — a static placeholder instead of a live WebGL
   compositor per block (heavy/fragile in the canvas). The real animation renders on the page. */
.cms-visualizer-placeholder {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: var(--space-1); min-height: 8rem; width: 100%; padding: var(--space-3);
    border: 1px dashed var(--surface-border); border-radius: inherit; text-align: center;
    color: var(--surface-page-text-muted);
    background: repeating-linear-gradient(45deg,
        var(--surface-deep), var(--surface-deep) 10px,
        var(--surface-deep) 10px, var(--surface-deep) 20px);
}
.cms-visualizer-placeholder-label { font-weight: 600; font-size: 0.85rem; }
.cms-visualizer-placeholder-meta { font-size: 0.72rem; }
/* Visualizer-preset block: the composer preset rendered as a tile (canvas + interactive overlay). */
.cms-viz-preset { position: relative; width: 100%; height: 100%; min-height: 12rem; border-radius: inherit; overflow: hidden; }
.cms-viz-preset-canvas { display: block; width: 100%; height: 100%; }

/* ==========================================================================
   STRUCTURAL / LAYOUT BLOCKS (Phase 3): accordion, tabs, hero, CTA group,
   columns, spacer, embed, gallery, map, countdown.
   ========================================================================== */

.cms-block-heading {
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--surface-page-text);
    margin: 0 0 var(--space-3);
}

/* ----- Accordion / FAQ ----- */
.cms-accordion { padding: var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); }
.cms-accordion-item {
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
    overflow: hidden;
}
.cms-accordion-summary {
    cursor: pointer; list-style: none;
    min-height: 2.75rem;   /* comfortable tap target (WCAG 2.5.5) */
    padding: var(--space-3) var(--space-4);
    font-weight: 600; color: var(--surface-page-text);
    display: flex; align-items: center; justify-content: space-between;
}
.cms-accordion-summary::-webkit-details-marker { display: none; }
.cms-accordion-summary::after { content: "+"; color: var(--color-accent); font-weight: 700; }
.cms-accordion-item[open] .cms-accordion-summary::after { content: "\2212"; }
.cms-accordion-body { padding: 0 var(--space-4) var(--space-3); color: var(--surface-page-text-muted); }
.cms-accordion-body > :first-child { margin-top: 0; }

/* ----- Tabs (pure-CSS radio tabs; labels row via flex order, panels below) ----- */
.cms-tabs { display: flex; flex-wrap: wrap; padding: var(--space-3); gap: 0; }
/* .cms-tab-radio rules removed — TabsBlock is now real ARIA tabs (BL-045); state via .is-active. */
.cms-tab-label {
    order: 1; cursor: pointer;
    padding: var(--space-2) var(--space-4);
    border-bottom: 2px solid transparent;
    color: var(--surface-page-text-muted); font-weight: 600;
}
.cms-tab-panel {
    order: 2; width: 100%; display: none;
    padding: var(--space-4) var(--space-1) var(--space-2);
    color: var(--surface-page-text-muted);
}
.cms-tab-panel > :first-child { margin-top: 0; }

/* ----- Hero / Banner ----- */
.cms-hero {
    position: relative; overflow: hidden;
    container-type: inline-size;   /* heading/subheading scale to the hero's own width via cqi */
    border-radius: var(--radius-tile);
    min-height: clamp(16rem, 30vw, 24rem); display: flex;
    padding: var(--space-6) var(--space-5);
    background: var(--surface-inverse);
}
.cms-hero-bg {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; object-position: var(--tile-focal); z-index: 0; opacity: 0.55;
}
.cms-hero-inner {
    position: relative; z-index: 1; max-width: 42rem;
    display: flex; flex-direction: column; gap: var(--space-3); align-self: center;
}
.cms-hero-center { justify-content: center; text-align: center; }
.cms-hero-center .cms-hero-inner { margin: 0 auto; align-items: center; }
.cms-hero-left { justify-content: flex-start; text-align: left; }
.cms-hero-eyebrow { text-transform: uppercase; letter-spacing: 0.08em; font-size: clamp(0.75rem, 2cqi, 0.95rem); color: var(--color-accent-light); font-weight: 700; }
.cms-hero-heading { font-size: clamp(1.6rem, 7cqi, 3.5rem); line-height: 1.1; color: var(--color-white); margin: 0; }
.cms-hero-subheading { font-size: clamp(1rem, 3cqi, 1.4rem); color: var(--surface-page-text); margin: 0; }
.cms-hero-cta { align-self: flex-start; }
.cms-hero-center .cms-hero-cta { align-self: center; }

/* ----- CTA / button group ----- */
.cms-cta-group { padding: var(--space-3); }
.cms-cta-row { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.cms-cta-btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 2.75rem;   /* ~44px comfortable tap target (WCAG 2.5.5 enhanced) */
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-md); font-weight: 600; text-decoration: none;
    transition: transform 0.12s ease, background-color 0.12s ease;
}
.cms-cta-btn:hover { transform: translateY(-1px); }
.cms-cta-primary { background: var(--color-accent); color: var(--color-white); border: 1px solid var(--color-accent); }
.cms-cta-primary:hover { background: var(--color-accent-light); }
.cms-cta-secondary { background: transparent; color: var(--color-accent); border: 1px solid var(--color-accent); }
.cms-cta-secondary:hover { background: var(--surface-deep); }

/* ----- Columns / Section ----- */
.cms-columns { padding: var(--space-3); }
.cms-columns-grid {
    display: grid;
    grid-template-columns: repeat(var(--cms-columns, 2), minmax(0, 1fr));   /* minmax(0,..) = column overflow guard */
    gap: var(--space-4);
}
.cms-column-heading { font-size: var(--step-1); margin: 0 0 var(--space-2); color: var(--surface-page-text); }
.cms-column-body { color: var(--surface-page-text-muted); }
.cms-column-body > :first-child { margin-top: 0; }
@media (max-width: 700px) {
    .cms-columns-grid { grid-template-columns: 1fr; }
}

/* ----- Spacer / Divider ----- */
.cms-spacer { width: 100%; }
.cms-spacer-sm { height: var(--space-3); }
.cms-spacer-md { height: var(--space-5); }
.cms-spacer-lg { height: var(--space-7, 3rem); }
.cms-spacer-xl { height: 5rem; }
.cms-spacer-rule {
    border: 0; border-top: 1px solid var(--surface-border);
    margin: 0; position: relative; top: 50%;
}

/* ----- Embed / HTML ----- */
.cms-embed { padding: var(--space-3); }
.cms-embed-frame { position: relative; width: 100%; aspect-ratio: 16 / 9; border-radius: var(--radius-md); overflow: hidden; }
.cms-embed-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* ----- Gallery / Lightbox ----- */
.cms-gallery { padding: var(--space-3); }
.cms-gallery-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 160px), 1fr)); gap: var(--space-3); }
.cms-gallery-item {
    display: block; margin: 0; border-radius: var(--radius-md); overflow: hidden;
    background: var(--surface-deep); text-decoration: none; color: inherit;
}
.cms-gallery-item img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: var(--tile-focal); aspect-ratio: 1 / 1; transition: transform 0.2s ease; }
.cms-gallery-grid.is-downloadable .cms-gallery-item { cursor: pointer; }
.cms-gallery-grid.is-downloadable .cms-gallery-item:hover img { transform: scale(1.05); }
.cms-gallery-caption { display: block; padding: var(--space-1) var(--space-2); font-size: var(--text-sm); color: var(--surface-page-text-muted); }

/* ----- Map ----- */
.cms-map { padding: var(--space-3); }
.cms-map-frame { width: 100%; border-radius: var(--radius-md); overflow: hidden; }
.cms-map-frame iframe { width: 100%; border: 0; display: block; }
.cms-map-short iframe { height: 220px; }
.cms-map-medium iframe { height: 360px; }
.cms-map-tall iframe { height: 520px; }

/* ----- Media player (inline, drives the singleton AudioPlayerService) ----- */
.cms-media-player { padding: var(--space-4) var(--space-3); display: flex; flex-direction: column; gap: var(--space-3); }
.cms-media-player-now { display: flex; align-items: center; gap: var(--space-3); }
.cms-media-player-art { width: 3.5rem; height: 3.5rem; border-radius: var(--radius-md); object-fit: cover; object-position: var(--tile-focal); }
.cms-media-player-info { display: flex; flex-direction: column; min-width: 0; }
.cms-media-player-title { font-weight: 700; color: var(--surface-page-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cms-media-player-artist { font-size: var(--text-sm); color: var(--surface-page-text-muted); }
.cms-media-player-progress { height: 4px; border-radius: 2px; background: var(--surface-deep); overflow: hidden; }
.cms-media-player-progress-fill { height: 100%; background: var(--color-accent); transition: width 0.25s linear; }
.cms-media-player-controls { display: flex; align-items: center; gap: var(--space-2); }
.cms-media-player-btn {
    border: 1px solid var(--surface-border); background: var(--surface-raised);
    border-radius: 50%; width: 2.25rem; height: 2.25rem; cursor: pointer;
    font-size: 1rem; color: var(--surface-raised-text); display: inline-flex; align-items: center; justify-content: center;
}
.cms-media-player-btn:disabled { opacity: 0.4; cursor: default; }
.cms-media-player-play { background: var(--color-accent); color: var(--color-white); border-color: var(--color-accent); width: 2.75rem; height: 2.75rem; }
.cms-media-player-fs { margin-left: auto; }
.cms-media-player-empty { color: var(--surface-page-text-muted); font-size: var(--text-sm); }

/* ----- Countdown ----- */
.cms-countdown { padding: var(--space-4) var(--space-3); text-align: center; }
.cms-countdown-units { display: inline-flex; flex-wrap: wrap; justify-content: center; gap: var(--space-4); }
.cms-countdown-cell { display: flex; flex-direction: column; min-width: 3.5rem; }
.cms-countdown-value { font-size: clamp(1.75rem, 5vw, 2.25rem); font-weight: 700; line-height: 1; color: var(--color-accent); font-variant-numeric: tabular-nums; }
.cms-countdown-unit { font-size: var(--text-sm); text-transform: uppercase; letter-spacing: 0.06em; color: var(--surface-page-text-muted); margin-top: var(--space-1); }
.cms-countdown-done { font-size: var(--text-lg); font-weight: 700; color: var(--color-accent); }

/* Mini-CMS pop-out markdown editor modal */
.cms-md-popout { margin: var(--space-1) 0 var(--space-2); }
.cms-md-overlay {
    position: fixed; inset: 0; z-index: var(--z-nav);
    background: rgba(0, 0, 0, 0.55);
    display: flex; align-items: center; justify-content: center;
    padding: var(--space-4);
}
.cms-md-modal {
    background: var(--surface-raised);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    width: min(1100px, 95vw); height: min(82vh, 820px);
    display: flex; flex-direction: column; overflow: hidden;
}
.cms-md-head { display: flex; align-items: center; justify-content: space-between; padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-border-subtle); font-weight: 600; }
.cms-md-toolbar { display: flex; gap: var(--space-1); flex-wrap: wrap; padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-border-subtle); }
.cms-md-body { flex: 1 1 auto; display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); padding: var(--space-3); overflow: hidden; }
.cms-md-textarea { width: 100%; height: 100%; resize: none; font-family: ui-monospace, monospace; font-size: 0.9rem; line-height: 1.5; padding: var(--space-2); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm); }
.cms-md-preview { overflow: auto; padding: var(--space-2) var(--space-3); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm); background: var(--surface-page); }
.cms-md-foot { display: flex; justify-content: flex-end; gap: var(--space-2); padding: var(--space-2) var(--space-3); border-top: 1px solid var(--color-border-subtle); }
@media (max-width: 760px) { .cms-md-body { grid-template-columns: 1fr; } }

/* =========================================================
   Visualizer Composer (timeline editor) — Composer M4
   ========================================================= */
.viz-presets-layout { display: grid; grid-template-columns: minmax(0, 16rem) minmax(0, 1fr); gap: var(--space-4); align-items: start; }
.viz-composer { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.viz-composer-top { display: flex; align-items: center; gap: var(--space-2); }
.viz-composer-name { max-width: 22rem; font-weight: 700; }
.viz-spacer { flex: 1; }

/* NOTE: the docked preview frame is styled below (search ".viz-preview-frame { flex"). The old
   aspect-ratio:16/9 + max-height:40vh rule that used to live here locked the preview to a fixed
   wide box — removed so the frame fills the dock and adopts the available aspect. */

.viz-transport { display: flex; align-items: center; gap: var(--space-3); }
.viz-scrub { flex: 1; }
.viz-time { font-variant-numeric: tabular-nums; font-size: var(--admin-text-control); color: var(--color-charcoal-muted); white-space: nowrap; }
.viz-dur { display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--admin-text-label); color: var(--color-charcoal-muted); }
.viz-dur-input { width: 4.5rem; }

.viz-addlayer { margin: 0; }

.viz-lanes { display: flex; flex-direction: column; gap: var(--space-2); overflow-x: auto; padding-bottom: var(--space-2); }
.viz-lane { border: var(--border-thin); border-radius: var(--admin-radius); background: var(--color-cream-deep); }
.viz-lane-off { opacity: 0.55; }
.viz-lane-head { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2); border-bottom: var(--border-thin); }
.viz-lane-kind { font-weight: 700; font-size: var(--admin-text-label); text-transform: uppercase; letter-spacing: .05em; color: var(--color-charcoal-muted); min-width: 5rem; }
.viz-lane-label { max-width: 10rem; }
.viz-lane-mode, .viz-lane-blend { width: auto; min-width: 6rem; }

.viz-pool { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-2); }
.viz-chip { display: inline-flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: var(--radius-sm); background: var(--color-accent-dim); border: var(--border-thin); font-size: var(--admin-text-control); }
.viz-chip button { all: unset; cursor: pointer; color: var(--color-accent); font-weight: 700; }
/* A chip that is itself a toggle button (dynamic-blend subset picker, Workstream B). */
button.viz-chip { cursor: pointer; color: var(--color-accent); font-weight: 700; }
.viz-chip.viz-chip-on { background: var(--color-accent); color: var(--color-white); border-color: var(--color-accent); }
.viz-pool-dwell { display: inline-flex; align-items: center; gap: 4px; font-size: var(--admin-text-label); color: var(--color-charcoal-muted); }
.viz-mini { width: 5rem; }

.viz-track { position: relative; height: 44px; margin: var(--space-2); background: repeating-linear-gradient(90deg, rgba(0,0,0,0.05) 0, rgba(0,0,0,0.05) 1px, transparent 1px, transparent 40px); border-radius: var(--radius-sm); }
.viz-clip { position: absolute; top: 4px; height: 36px; box-sizing: border-box; background: var(--color-accent); color: var(--color-white); border-radius: var(--radius-sm); padding: 2px 6px; overflow: hidden; cursor: grab; user-select: none; font-size: var(--admin-text-control); display: flex; align-items: center; }
.viz-clip-sel { outline: 2px solid var(--color-charcoal); }
.viz-clip-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: none; }
.viz-clip-resize { position: absolute; right: 0; top: 0; width: 8px; height: 100%; cursor: ew-resize; background: rgba(255,255,255,0.25); }
/* Left resize grip (R11 #3) — both clip edges are draggable. */
.viz-clip-resize-l { right: auto; left: 0; }
.viz-addclip { position: absolute; top: 6px; }

/* Transition handle at a clip cut (R6 E3): a diamond at the boundary; filled = a transition exists. */
.viz-cut { position: absolute; top: 7px; width: 16px; height: 30px; transform: translateX(-50%); display: flex; align-items: center; justify-content: center; padding: 0; border: none; background: transparent; color: var(--color-charcoal); opacity: 0.4; cursor: pointer; z-index: 4; font-size: 12px; line-height: 1; }
.viz-cut:hover { opacity: 0.9; }
.viz-cut-on { opacity: 0.95; color: var(--color-accent); }
.viz-cut-sel { outline: 2px solid var(--color-charcoal); border-radius: var(--radius-sm); opacity: 1; }

/* Loop-seam crossfade affordance on a looping timeline lane. The seam marks where the last
   clip wraps back to the first; the fade span visualizes the crossfade window (stronger toward
   the seam); the handle drags to set LoopCrossfadeSeconds (drag left to lengthen). Companion to
   the .viz-cut transition handles. */
.viz-loop-seam { position: absolute; top: 2px; height: 40px; width: 2px; transform: translateX(-1px); background: var(--color-accent); opacity: 0.7; pointer-events: none; z-index: 3; }
.viz-loop-fade { position: absolute; top: 4px; height: 36px; border-radius: var(--radius-sm); pointer-events: none; z-index: 3; opacity: 0.35; background: linear-gradient(to right, rgba(0,0,0,0) 0%, var(--color-accent) 100%); }
.viz-loop-fade-handle { position: absolute; top: 7px; width: 12px; height: 30px; transform: translateX(-50%); border-radius: var(--radius-sm); background: var(--color-accent); opacity: 0.55; cursor: ew-resize; z-index: 5; touch-action: none; }
.viz-loop-fade-handle:hover { opacity: 0.95; }

.viz-inspector { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-3); padding: var(--space-2); border: var(--border-thin); border-radius: var(--admin-radius); }
.viz-inspector label { display: inline-flex; align-items: center; gap: 4px; font-size: var(--admin-text-label); }

/* Scene picker modal */
.viz-picker-backdrop { position: fixed; inset: 0; z-index: 700; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; }
.viz-picker { width: min(820px, 92vw); max-height: 86vh; display: flex; flex-direction: column; background: var(--color-cream); border-radius: var(--radius-lg); overflow: hidden; }
.viz-picker-head { display: flex; align-items: center; justify-content: space-between; padding: var(--space-3); border-bottom: var(--border-thin); }
.viz-picker-body { overflow-y: auto; padding: var(--space-3); display: flex; flex-direction: column; gap: var(--space-3); }
.viz-picker-group-title { margin: 0 0 var(--space-2); font-size: var(--admin-text-label); text-transform: uppercase; letter-spacing: .05em; color: var(--color-charcoal-muted); }
.viz-picker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); gap: var(--space-2); }
.viz-picker-item { padding: var(--admin-pad-y) var(--admin-pad-x); border: var(--border-thin); border-radius: var(--admin-radius); background: var(--color-cream-deep); cursor: pointer; font-size: var(--admin-text-control); text-align: left; }
.viz-picker-item:hover { border-color: var(--color-accent); }
.viz-picker-slide { display: flex; flex-direction: column; gap: 4px; }
.viz-picker-slide img { width: 100%; aspect-ratio: 16/9; object-fit: cover; border-radius: var(--radius-sm); }

@media (max-width: 900px) { .viz-presets-layout { grid-template-columns: 1fr; } }

/* Composer time ruler (M5) */
.viz-ruler { position: relative; height: 22px; border-bottom: var(--border-thin); margin-bottom: var(--space-1); cursor: pointer; min-width: 600px; }
.viz-ruler-tick { position: absolute; top: 2px; font-size: 10px; color: var(--color-charcoal-muted); transform: translateX(-2px); pointer-events: none; }
.viz-ruler-beat { position: absolute; bottom: 0; width: 1px; height: 8px; background: var(--color-accent); opacity: 0.6; pointer-events: none; }
.viz-ruler-playhead { position: absolute; top: 0; width: 2px; height: 100%; background: var(--color-charcoal); pointer-events: none; }

/* Composer LRC import (M6) */
.viz-lrc { display: flex; flex-direction: column; gap: var(--space-2); }
.viz-lrc-text { width: 100%; font-family: var(--font-mono, monospace); resize: vertical; }
.viz-emb-row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.viz-emb-badge { font-size: 0.72rem; font-weight: 600; padding: 0.1em 0.5em; border-radius: var(--radius-pill);
    background: var(--color-surface); color: var(--color-charcoal-muted); border: 1px solid var(--color-border-subtle); }
.viz-emb-badge-ok { background: var(--alert-success-bg-strong); color: var(--alert-success-text-strong);
    border-color: var(--alert-success-border-strong); }
/* Lyric-import conversion dialog */
.viz-lyric-dialog { max-width: 640px; }
.viz-ld-row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-1); }
.viz-ld-check { display: inline-flex; align-items: center; gap: var(--space-1); font-size: 0.85rem; }
.viz-ld-preview { display: flex; align-items: baseline; gap: var(--space-2); flex-wrap: wrap; }
.viz-ld-preview-list { flex-basis: 100%; margin: var(--space-1) 0 0; padding-left: var(--space-3); font-size: 0.82rem;
    max-height: 9rem; overflow-y: auto; }
.viz-ld-preview-t { display: inline-block; min-width: 3.2em; color: var(--color-charcoal-muted); font-variant-numeric: tabular-nums; }

/* Composer zoom/pan + bottom ruler + playhead line (W1) */
.viz-lanes { position: relative; }
.viz-lanes-playhead { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--color-charcoal); z-index: 6; pointer-events: none; }
.viz-lanes > .viz-ruler { order: 999; border-bottom: none; border-top: var(--border-thin); margin: var(--space-1) 0 0; }

/* Per-layer opacity slider in the lane head (W5) */
.viz-lane-opacity { display: inline-flex; align-items: center; gap: var(--space-1); }
.viz-lane-opacity input[type="range"] { width: 64px; }
.viz-mini-label { font-size: var(--admin-text-help); color: var(--color-charcoal); opacity: 0.7; min-width: 2.6em; text-align: right; }

/* ============================================================================
   Visualizer Composer — Premiere-style docked layout (R3)
   Full-bleed editor: left=presets, center=preview, right=properties, all above
   a full-width bottom timeline. Panels resize via .viz-splitter (viz-dock.js)
   and collapse via Blazor state.
   ============================================================================ */
.viz-editor {
    --viz-row-h: 2.5rem;
    --viz-gutter: 13rem;
    display: flex; flex-direction: column;
    height: calc(100dvh - 3rem); min-height: 26rem;   /* header only — the footer is hidden in the editor */
}
.viz-top { display: flex; flex: 1 1 auto; min-height: 8rem; overflow: hidden; }

/* The editor is a full-bleed tool; the site footer wastes its scarce vertical space. Hide it only on the
   editor page (scoped via :has) and let the editor reclaim the height. */
:where(.main-layout-container):has(.viz-editor) .main-layout-footer { display: none; }

/* Presets panel: compact toolbar header + filter + slim selectable list. */
.viz-preset-bar { gap: 3px; }
.viz-preset-actions { display: flex; align-items: center; gap: 3px; flex: 1 1 auto; min-width: 0; }
.viz-tool-btn { display: inline-flex; align-items: center; justify-content: center; height: var(--admin-control-h); padding: 0 6px; border: var(--border-thin); border-radius: var(--admin-radius); background: var(--color-white); color: var(--color-charcoal); cursor: pointer; font-size: var(--admin-text-control); line-height: 1; white-space: nowrap; }
.viz-tool-btn:hover:not(:disabled) { background: var(--color-cream); }
.viz-tool-btn:disabled { opacity: 0.4; cursor: default; }
.viz-tool-btn-primary:not(:disabled) { background: var(--color-accent); color: var(--color-white); border-color: var(--color-accent); }
.viz-tool-btn-danger.is-confirm { background: var(--color-danger); color: var(--color-white); border-color: var(--color-danger); }
.viz-preset-filter { width: 100%; margin-bottom: var(--space-1); }
.viz-preset-list { display: flex; flex-direction: column; gap: 1px; }
.viz-preset-item { display: block; width: 100%; text-align: left; padding: 3px 6px; border: none; border-radius: var(--admin-radius); background: none; color: var(--color-charcoal); cursor: pointer; font-size: var(--admin-text-control); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.viz-preset-item:hover { background: var(--color-cream); }
.viz-preset-item.is-sel { background: var(--color-accent-light); font-weight: 600; }

.viz-dock {
    display: flex; flex-direction: column; min-width: 0; min-height: 0;
    background: var(--color-cream-light); border: var(--border-thin);
    border-radius: var(--radius-md); overflow: hidden;
}
.viz-dock-presets  { flex: 0 0 auto; width: 14rem; }
.viz-dock-preview  { flex: 1 1 auto; }
.viz-dock-props    { flex: 0 0 auto; width: 22rem; }
.viz-dock-timeline { flex: 0 0 auto; height: 17rem; }

.viz-dock-head {
    display: flex; align-items: center; gap: var(--space-1);
    padding: var(--space-1) var(--space-2); border-bottom: var(--border-thin);
    font-size: var(--admin-text-control); font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; flex: 0 0 auto;
}
.viz-dock-head .viz-spacer { flex: 1 1 auto; }
.viz-dock-body { flex: 1 1 auto; overflow: auto; padding: var(--space-2); min-height: 0; }
.viz-dock-collapse { background: none; border: none; cursor: pointer; padding: 0 var(--space-1); font-size: var(--admin-text-control); color: var(--color-charcoal); }

.viz-splitter { flex: 0 0 auto; }
.viz-splitter-v { width: 6px; cursor: col-resize; }
.viz-splitter-h { height: 6px; cursor: row-resize; }
.viz-splitter:hover { background: var(--color-accent); opacity: 0.5; }

.viz-dock-collapsed.viz-dock-presets,
.viz-dock-collapsed.viz-dock-props { width: 2.1rem !important; }
.viz-dock-collapsed.viz-dock-timeline { height: 2.1rem !important; }
.viz-dock-collapsed .viz-dock-body, .viz-dock-collapsed .viz-tl { display: none; }
/* Only the SIDE panels collapse to a vertical strip; the timeline collapses to a short, full-width bar,
   so its head must stay horizontal (else the label crops + the expand button is pushed offscreen). */
.viz-dock-collapsed.viz-dock-presets .viz-dock-head,
.viz-dock-collapsed.viz-dock-props .viz-dock-head { writing-mode: vertical-rl; border-bottom: none; }
.viz-dock-collapsed.viz-dock-presets .viz-preset-actions { display: none; }

/* properties panel — two-column label/control grid */
.viz-prop-grid { display: grid; grid-template-columns: minmax(4.5rem, auto) 1fr; gap: var(--admin-gap) var(--admin-gap); align-items: center; }
.viz-prop-label { font-size: var(--admin-text-label); color: var(--color-charcoal); opacity: 0.85; }
.viz-prop-control { display: flex; align-items: center; gap: var(--space-1); min-width: 0; }
.viz-prop-control .admin-input, .viz-prop-control select { width: 100%; min-width: 0; }
.viz-prop-control .viz-mini { width: 5rem; flex: 0 0 auto; }
.viz-prop-section { grid-column: 1 / -1; margin: var(--admin-section-gap) 0 var(--space-1); font-weight: 600; font-size: var(--admin-text-section); text-transform: uppercase; letter-spacing: 0.03em; opacity: 0.7; border-bottom: var(--border-thin); padding-bottom: 2px; }
.viz-prop-empty { color: var(--color-charcoal); opacity: 0.6; font-size: var(--admin-text-help); padding: var(--space-2); }
.viz-prop-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); grid-column: 1 / -1; }
.viz-prop-current { margin-right: 6px; overflow: hidden; text-overflow: ellipsis; font-size: var(--admin-text-control); color: var(--color-charcoal); }
.viz-prop-control.is-disabled { opacity: 0.5; }
.viz-prop-control select:disabled { cursor: not-allowed; }

/* preview dock interior */
.viz-dock-preview .viz-dock-body { display: flex; flex-direction: column; gap: var(--space-2); }
/* The canvas fills the frame absolutely so it always grows to the available space (sidesteps the flexbox
   percentage-height gotcha where height:100% on a flex child can collapse). */
.viz-preview-frame { flex: 1 1 auto; min-height: 6rem; position: relative; background: #000; border-radius: var(--radius-sm); overflow: hidden; }
.viz-preview-frame .viz-admin-preview-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* timeline dock: tool rail + fixed header gutter + horizontally-scrolling track area */
.viz-tl { display: flex; flex: 1 1 auto; min-height: 0; }

/* Tool rail (R6 B1): Select / Edit / + add, left of the gutter. */
.viz-tool-rail { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 4px 3px; border-right: var(--border-thin); position: relative; background: var(--color-cream-light); }
.viz-tool { width: 26px; height: 26px; display: flex; align-items: center; justify-content: center; padding: 0; border: var(--border-thin); border-radius: var(--radius-sm); background: var(--color-white); color: var(--color-charcoal); cursor: pointer; font-size: 14px; line-height: 1; }
.viz-tool:hover { background: var(--color-cream); }
.viz-tool.is-on { background: var(--color-accent); color: var(--color-white); border-color: var(--color-accent); }
.viz-tool-addmenu { position: absolute; left: 30px; top: 56px; z-index: 20; display: flex; flex-direction: column; background: var(--color-white); border: var(--border-thin); border-radius: var(--radius-sm); box-shadow: var(--shadow-md, 0 2px 8px rgba(0,0,0,0.18)); }
.viz-tool-addmenu button { padding: 4px 12px; border: none; background: none; text-align: left; cursor: pointer; font-size: var(--admin-text-control); white-space: nowrap; }
.viz-tool-addmenu button:hover { background: var(--color-accent-light); }

/* Marquee selection box (R6 B2). */
.viz-marquee { position: absolute; background: rgba(47,125,209,0.16); border: 1px solid var(--color-accent); border-radius: 2px; pointer-events: none; z-index: 6; }

/* Context menu (R6 C1). */
.viz-ctxmenu-backdrop { position: fixed; inset: 0; z-index: 999; }
.viz-ctxmenu { position: fixed; z-index: var(--z-nav); min-width: 11rem; max-width: calc(100vw - 16px); overflow-y: auto; display: flex; flex-direction: column; padding: 4px 0; background: var(--color-white); border: var(--border-thin); border-radius: var(--radius-sm); box-shadow: var(--shadow-md, 0 4px 14px rgba(0,0,0,0.22)); }
.viz-ctxmenu-item { padding: 5px 14px; border: none; background: none; text-align: left; cursor: pointer; font-size: var(--admin-text-control); color: var(--color-charcoal); white-space: nowrap; }
.viz-ctxmenu-item:hover { background: var(--color-accent-light); }
.viz-ctxmenu-item:disabled { opacity: 0.4; cursor: default; background: none; }
.viz-ctxmenu-item-danger { color: var(--color-danger); }
.viz-ctxmenu-sep { height: 1px; margin: 4px 0; background: var(--color-cream); }
.viz-ctxmenu-head { padding: 4px 14px 2px; font-size: var(--admin-text-help); font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; opacity: 0.6; white-space: nowrap; max-width: 16rem; overflow: hidden; text-overflow: ellipsis; }
.viz-ctxmenu-note { padding: 4px 14px; font-size: var(--admin-text-help); opacity: 0.7; white-space: nowrap; }

.viz-tl-gutter { flex: 0 0 auto; width: var(--viz-gutter); overflow: hidden; border-right: var(--border-thin); }
.viz-tl-scroll { flex: 1 1 auto; overflow: auto; position: relative; }
.viz-tl-tracks { position: relative; }
.viz-tl-playhead { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--color-charcoal); z-index: 5; pointer-events: none; }
/* Lyric-import region band: the marquee's persisted time span. Behind clips, non-interactive. */
.viz-sel-range { position: absolute; top: 0; bottom: 0; background: rgba(47,125,209,0.10);
    border-left: 1px solid var(--color-accent); border-right: 1px solid var(--color-accent); z-index: 1; pointer-events: none; }
/* Draggable playhead grip: a semi-opaque upward triangle in the ruler band (R9 B). */
.viz-playhead-handle { position: absolute; bottom: 0; width: 12px; height: 10px; margin-left: -6px; z-index: 8; cursor: ew-resize; }
.viz-playhead-handle::after { content: ""; position: absolute; left: 0; bottom: 0; width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 10px solid var(--color-charcoal); opacity: 0.55; }
.viz-playhead-handle:hover::after { opacity: 0.9; }
/* Sticky-snap guide shown while dragging an edge onto a snap target (R6 D). */
.viz-snap-guide { position: absolute; top: 0; bottom: 0; width: 0; border-left: 1px dashed var(--color-accent); opacity: 0.85; z-index: 6; pointer-events: none; }

/* Out-marker: the ⟧ handle that bounds how long random/looped layers cycle. Drag to set; thin grab zone. */
.viz-out-marker { position: absolute; top: 0; bottom: 0; width: 12px; margin-left: -6px; z-index: 7; cursor: ew-resize; }
.viz-out-marker::after { content: ""; position: absolute; left: 6px; top: 0; bottom: 0; border-left: 2px solid var(--color-charcoal); opacity: 0.5; }
.viz-out-marker::before { content: "\27E7"; position: absolute; top: -2px; left: 1px; font-size: 12px; line-height: 1; color: var(--color-charcoal); opacity: 0.7; }
.viz-out-marker:hover::after, .viz-out-marker:hover::before { opacity: 1; }
.viz-out-marker.is-explicit::after { border-color: var(--color-accent); opacity: 0.95; }
.viz-out-marker.is-explicit::before { color: var(--color-accent); opacity: 1; }

/* Audio reference layer (R7 P2): the song block in its lane + decoded waveform; the song picker list. */
.viz-audio-block { position: absolute; top: 3px; bottom: 3px; background: rgba(192,71,107,0.16); border: 1px solid #c0476b; border-radius: var(--radius-sm); overflow: hidden; cursor: grab; }
.viz-audio-wave { position: absolute; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none; }
.viz-audio-label { position: absolute; left: 4px; top: 2px; font-size: var(--admin-text-help); color: var(--color-charcoal); background: rgba(245,240,232,0.65); padding: 0 3px; border-radius: 2px; pointer-events: none; white-space: nowrap; }
.viz-song-list { display: flex; flex-direction: column; gap: 1px; max-height: 50vh; overflow: auto; margin-top: var(--space-1); }
.viz-song-item { display: block; width: 100%; text-align: left; padding: 4px 8px; border: none; border-radius: var(--admin-radius); background: none; color: var(--color-charcoal); cursor: pointer; font-size: var(--admin-text-control); }
.viz-song-item:hover:not(:disabled) { background: var(--color-accent-light); }
.viz-song-item:disabled { opacity: 0.45; cursor: default; }

/* Interactive layer (R8 P3): a clickable DOM overlay over the viz canvas; elements placed by ratio. */
.viz-ix-overlay { position: absolute; inset: 0; pointer-events: none; z-index: 3; }
.viz-ix-el { position: absolute; pointer-events: auto; cursor: pointer; display: flex; align-items: center; justify-content: center; box-sizing: border-box; overflow: hidden; }
.viz-ix-img { width: 100%; height: 100%; object-fit: contain; display: block; }
.viz-ix-text { white-space: nowrap; text-shadow: 0 1px 3px rgba(0,0,0,0.55); }
/* A Text element styled as a CTA button fills its placement box so Width%/Height% size it (R11 #1/#8). */
.viz-ix-btn { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; box-sizing: border-box; white-space: nowrap; }
.viz-ix-el.is-edit { outline: 1px dashed rgba(255,255,255,0.45); }
.viz-ix-el.is-edit.viz-ix-hotspot { background: rgba(47,125,209,0.18); outline: 1px dashed var(--color-accent); }
.viz-ix-el.is-sel { outline: 2px solid var(--color-accent); }
/* Interactive item blocks in the timeline + sub-lane indent. */
.viz-ix-block { position: absolute; top: 4px; height: 32px; box-sizing: border-box; background: rgba(154,90,208,0.30); border: 1px solid #8a5cd0; border-radius: var(--radius-sm); color: var(--color-white); font-size: var(--admin-text-help); padding: 2px 6px; overflow: hidden; cursor: grab; white-space: nowrap; display: flex; align-items: center; }
.viz-ix-block.is-sel { outline: 2px solid var(--color-charcoal); }
.viz-ix-block-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.viz-ix-mark { position: absolute; top: 8px; height: 16px; background: #8a5cd0; opacity: 0.7; border-radius: 2px; }
.viz-tl-sublane { background: rgba(138,92,208,0.06); }
/* Interactive child gutter heads read as children of the master: indented, left accent bar, muted. */
.viz-tl-ghead-sub { margin-left: 0.9rem; padding-left: var(--space-2); border-left: 3px solid #8a5cd0; background: rgba(138,92,208,0.07); }
.viz-tl-ghead-sub .viz-tl-ghead-name { opacity: 0.8; }
.viz-tl-row { height: var(--viz-row-h); border-bottom: var(--border-thin); position: relative; box-sizing: border-box; }
.viz-tl-row.is-off { opacity: 0.5; }
.viz-tl-rowsummary { position: absolute; inset: 0; display: flex; align-items: center; gap: var(--space-2); padding: 0 var(--space-2); font-size: var(--admin-text-help); color: var(--color-charcoal); opacity: 0.75; }
.viz-tl-ghead {
    height: var(--viz-row-h); box-sizing: border-box; display: flex; align-items: center; gap: var(--space-1);
    padding: 0 var(--space-1); border-bottom: var(--border-thin); cursor: pointer; font-size: var(--admin-text-label);
}
.viz-tl-ghead.is-sel { background: var(--color-accent-light); }
.viz-tl-ghead.is-off { opacity: 0.5; }
.viz-tl-kind { font-weight: 600; flex: 0 0 auto; }
.viz-tl-ghead-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.viz-tl-ghead-btn { background: none; border: none; cursor: pointer; padding: 0 2px; font-size: var(--admin-text-control); color: var(--color-charcoal); }
/* The Interactive collapse toggle reads as a dot at the button's default size — give it a real triangle. */
.viz-tl-collapse { font-size: 0.8rem; line-height: 1; color: var(--color-accent); }
/* Layer reorder grip (R9 A). The Interactive master's is disabled — it must stay on top. */
.viz-tl-drag-handle { flex: 0 0 auto; cursor: grab; user-select: none; padding: 0 2px; opacity: 0.55; font-size: var(--admin-text-control); color: var(--color-charcoal); }
.viz-tl-drag-handle:hover { opacity: 0.85; }
.viz-tl-drag-handle.is-disabled { cursor: not-allowed; opacity: 0.3; }
/* Always-present (NOT drag-gated — see the razor note) slim drop zones: drop a layer here to jump it to
   the extreme top/bottom. Subtle by default, accented on hover so they read as targets. */
.viz-tl-dropzone { height: 0.85rem; display: flex; align-items: center; justify-content: center; font-size: var(--admin-text-help); line-height: 1; color: var(--color-charcoal); opacity: 0.35; border: 1px dashed var(--color-border); border-radius: var(--radius-sm); margin: 1px 4px; }
.viz-tl-dropzone:hover { opacity: 1; color: var(--color-accent); border-color: var(--color-accent); background: var(--color-accent-light); }
/* Invisible twin in the tracks column — reserves the same height as the gutter drop zones so the layer
   rows line up vertically with their gutter titles (no visual, no interaction). */
.viz-tl-dz-ghost { visibility: hidden; }
/* Interactive element list in the master layer's Properties (R9 A). */
.viz-ix-list { display: flex; flex-direction: column; gap: 2px; }
.viz-ix-listitem { text-align: left; background: none; border: var(--border-thin); border-radius: var(--radius-sm); padding: 3px 6px; cursor: pointer; font-size: var(--admin-text-control); color: var(--color-charcoal); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.viz-ix-listitem:hover { background: var(--color-accent-light); }
.viz-ix-listitem.is-sel { background: var(--color-accent-light); outline: 1px solid var(--color-accent); }
.viz-tl-foot { height: 1.4rem; }

/* Layer-type glyph in the timeline gutter (R4 M3) */
.viz-kind-icon { flex: 0 0 auto; display: block; }

/* Ghosted loop-repeat clips (R4 M5) — non-interactive previews of where a looping layer repeats */
.viz-clip-ghost { pointer-events: none; opacity: 0.3; border-style: dashed; }

/* Draw-to-place region + affordances (R4 M6b) */
.viz-tl-row { cursor: crosshair; }
.viz-draw-box { position: absolute; top: 2px; bottom: 2px; background: rgba(47, 125, 209, 0.22); border: 1px dashed var(--color-accent); border-radius: 3px; pointer-events: none; z-index: 3; }
/* Crop-tool drag selection (R11 #5). */
.viz-crop-box { position: absolute; top: 2px; bottom: 2px; background: rgba(192, 71, 107, 0.25); border: 1px solid #c0476b; border-radius: 3px; pointer-events: none; z-index: 4; }

/* Tool cursors — viz-timeline-drag.js mirrors the active tool onto the lane (incl. momentary hold-C crop),
   so the cursor signals crop/select even over clips, where Edit would otherwise show its grab/resize cursor. */
.viz-tl-scroll.viz-tool-crop,
.viz-tl-scroll.viz-tool-crop .viz-tl-row,
.viz-tl-scroll.viz-tool-crop .viz-clip,
.viz-tl-scroll.viz-tool-crop .viz-ix-block,
.viz-tl-scroll.viz-tool-crop .viz-clip-resize { cursor: crosshair; }
.viz-tl-scroll.viz-tool-select,
.viz-tl-scroll.viz-tool-select .viz-tl-row { cursor: cell; }
.viz-tl-scroll.viz-tool-select .viz-clip,
.viz-tl-scroll.viz-tool-select .viz-ix-block,
.viz-tl-scroll.viz-tool-select .viz-clip-resize { cursor: pointer; }

/* 3x3 text-anchor picker (R5 M4) */
.anchor-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; width: 4.4rem; aspect-ratio: 4 / 3; }
.anchor-cell { border: var(--border-thin); background: var(--surface-raised); cursor: pointer; padding: 0; display: flex; align-items: center; justify-content: center; }
.anchor-cell span { width: 5px; height: 5px; border-radius: 50%; background: var(--surface-inverse); opacity: 0.3; }
.anchor-cell.is-sel { background: var(--color-accent-light); border-color: var(--color-accent); }
.anchor-cell.is-sel span { opacity: 1; background: var(--color-accent); }

/* Composer chrome is not text-selectable (avoids drag-selecting labels); inputs + messages stay selectable (R6 A1) */
.viz-editor { user-select: none; -webkit-user-select: none; }
.viz-editor input, .viz-editor textarea, .viz-editor select, .viz-editor [contenteditable="true"] { user-select: text; -webkit-user-select: text; }
.viz-editor .admin-message { user-select: text; -webkit-user-select: text; }

/* Timeline help affordance (R6 A2) — gestures live in the tooltip, not a row */
.viz-help-dot { display: inline-flex; align-items: center; justify-content: center; width: 1.1rem; height: 1.1rem; padding: 0; border-radius: 50%; border: var(--border-thin); background: var(--color-white); font-size: var(--admin-text-help); color: var(--color-charcoal); cursor: pointer; opacity: 0.6; }
.viz-help-dot:hover { opacity: 1; }

/* Help modal (R6) — ONE grid for the whole reference so columns stay uniform; section titles span both. */
.viz-help-grid { display: grid; grid-template-columns: max-content 1fr; gap: 5px 16px; margin: 0; align-items: baseline; }
.viz-help-h { grid-column: 1 / -1; margin: 10px 0 2px; font-size: var(--admin-text-section); font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; opacity: 0.65; }
.viz-help-grid > .viz-help-h:first-child { margin-top: 0; }
.viz-help-k { white-space: nowrap; font-weight: 600; color: var(--color-charcoal); font-size: var(--admin-text-control); }
.viz-help-d { color: var(--color-charcoal); font-size: var(--admin-text-control); }
.viz-help-grid kbd { display: inline-block; min-width: 1.1em; padding: 1px 6px; border: var(--border-thin); border-bottom-width: 2px; border-radius: 4px; background: var(--color-cream-light); font: 600 0.85em ui-monospace, "Cascadia Mono", monospace; color: var(--color-charcoal); }

/* Re-pick affordances (R6) — change an existing scene clip / pool item. */
.viz-chip-edit { background: none; border: none; padding: 0; margin: 0; font: inherit; color: var(--color-accent); cursor: pointer; text-decoration: underline dotted; }

/* Preview-dock title = the preset name (click → preset properties) (R6 A4) */
.viz-composer-title { font-weight: 600; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 60%; }
.viz-composer-title:hover { text-decoration: underline; }


/* =========================================================
   PHASE-G2 SUPPORT RULES — classes introduced by the Tier-2/3
   markup remediation (audit backlog); grouped here, token-only.
   ========================================================= */

/* Nav toggle is now a real <button> (BL-019) — neutralize UA chrome. */
button.site-nav-toggle-btn { border: 0; background: transparent; font: inherit; padding: 0; }

/* Identity/auth page headings + local/social divider (BL-022/023). */
.identity-page-heading { flex-basis: 100%; width: 100%; text-align: center;
  font-family: var(--font-display); font-size: var(--text-xl); font-weight: 700;
  color: var(--surface-page-text); margin: 0 0 var(--space-4); }
.login-or-divider { flex-basis: 100%; display: flex; align-items: center; gap: var(--space-3);
  color: var(--surface-page-text-muted); font-size: var(--text-sm); max-width: 380px; }
.login-or-divider::before, .login-or-divider::after { content: ""; flex: 1; height: 1px;
  background: var(--surface-border); }
.manage-page-heading { font-family: var(--font-display); font-size: var(--text-lg);
  font-weight: 700; color: var(--surface-page-text); margin: 0 0 var(--space-3); }
.form-group-wide-label > label { text-transform: none; letter-spacing: 0; }

/* Quiet destructive action (BL-073) — visible but subordinate to the primary. */
.btn-delete-quiet { display: inline-flex; align-items: center; justify-content: center;
  gap: var(--space-2); padding: var(--space-3) var(--space-5); background: transparent;
  color: var(--color-warn-solid); border: 1px solid var(--color-warn-solid);
  border-radius: var(--radius-md); font: 600 var(--text-sm)/1 var(--font-body);
  cursor: pointer; width: auto; }
.btn-delete-quiet:hover { background: var(--color-warn-dim); }

button.id-link { border: 0; background: none; padding: 0; font: inherit; }
.user-card { max-width: 560px; }
/* The song-details modal holds a wide audio table + "Play a mix" panel, so its card should fill the
   dialog (min(90vw,800px)) instead of the 560px form-comfortable cap that leaves a right gutter. */
.user-card--fill { max-width: none; }
.edit-section-title { margin-top: var(--space-4); } /* eyebrow spacing (BL-026) */
.admin-field-narrow { max-width: 28rem; }
.recovery-code-actions { display: flex; align-items: center; gap: var(--space-3); margin-top: var(--space-4); }
.recovery-code-copied { font-size: var(--text-sm); color: var(--surface-page-text-muted); }
.newsletter-admin-body { font-size: var(--admin-text-control); }
.error-page { padding: var(--space-6) var(--page-gutter); }
.error-request-id { color: var(--color-charcoal-muted); font-size: var(--text-sm); }

/* Toast host is a permanent live region (BL-014/046). */
.notification-host { display: contents; }
.notification-prefix { font-weight: 700; margin-right: var(--space-1); }
.notification-dismiss { flex-shrink: 0; display: inline-flex; align-items: center;
  justify-content: center; min-width: 24px; min-height: 24px; margin-left: var(--space-2);
  padding: 0; border: none; background: transparent; color: inherit; cursor: pointer;
  border-radius: var(--radius-sm); }
.notification-dismiss:hover { background: color-mix(in srgb, currentColor 18%, transparent); }
.notification-dismiss:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* About member photo can never exceed its track (BL-015 / reflow-320). The max-width:100% + the
   frame's position:relative + contain:paint now live on the primary .about-member-photo rule
   (U1/M2 element-overflow fix); nothing extra needed here. */

/* Public contact-form primary + select (BL-043) — public vocabulary, not admin. */
/* U2: the accent surface PAIR travels together — under Dark, --surface-accent-text flips to
   charcoal, so the button clears AA (was primitive amber + white = 2.69:1 on the dark theme). */
.cms-cf-submit { align-self: start; padding: var(--space-3) var(--space-5); min-height: 44px;
  background: var(--surface-accent); color: var(--surface-accent-text); border: none;
  border-radius: var(--radius-md); font: inherit; font-weight: 600; cursor: pointer; }
.cms-cf-submit:hover:not(:disabled) { filter: brightness(0.92); }
.cms-cf-submit:disabled { opacity: .6; cursor: default; }
.cms-cf-field select { font: inherit; min-height: 44px; padding: var(--space-2) var(--space-3);
  border: 1px solid var(--surface-border); border-radius: var(--radius-md);
  background: var(--surface-page); color: var(--surface-page-text); }

/* Shows countdown chip: white text needs the deep warn fill (BL-044; 5.93:1). */
.show-card-countdown { background-color: var(--color-warn-solid); color: var(--color-white); }

/* TabsBlock ARIA tabs (BL-045): state-driven visibility + focus ring. */
.cms-tab-panel { display: none; }
.cms-tab-panel.is-active { display: block; }
.cms-tab-label.is-active { color: var(--color-accent-text); border-bottom-color: var(--color-accent); }
.cms-tab-label:focus-visible, .cms-tab-panel:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* Band content-header reflow (BL-020). */
.playlist-lyrics-header { flex-wrap: wrap; }
@media (max-width: 640px) {
  .playlist-lyrics-header { flex-direction: column; align-items: flex-start; }
  .playlist-lyrics-header .chart-controls { flex-wrap: wrap; }
  /* Downloader: identity columns stay readable at narrow (BL-062). */
  .band-downloader-song-grid { grid-template-columns: 1fr; }
}

/* Notation meaning-bearing microtext up to the scale floor (BL-068). */
.roll-syll, .te-tech, .te-beat, .te-strlabel { font-size: var(--text-xs); }

/* AttributeTable keyboard sort/open (BL-027/066): button-in-th keeps the plain-th look. */
.sortable-th-btn { all: unset; display: block; width: 100%; box-sizing: border-box;
  cursor: pointer; font: inherit; color: inherit; white-space: nowrap; }
.sortable-th-btn:focus-visible, .row-open-cell:focus-visible {
  outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.row-open-cell { cursor: pointer; }

/* =========================================================
   42. ADMIN WORKBENCH (R6 — Decisions-v1.md 2026-07-03)
   The admin TOOLING palette. Admin routes carry no body[data-theme]
   (expressive themes never touch the tools); tooling CSS consumes the
   same --surface-* vocabulary, which resolves to the :root Light
   defaults = the light workbench. This block is the operator's DARK
   workbench: a fixed NEUTRAL re-point of the surface tokens, stamped
   as body[data-workbench="dark"] on admin routes only (never public
   pages — the public theme system owns those). The PageBuilder editing
   canvas is exempt either way: it receives the live theme's variables
   INLINE (hfrr-theme-vars.js), which override anything inherited here.
   ========================================================= */
body[data-workbench="dark"] {
    --surface-page:            #17181B;
    --surface-page-text:       #E8E8EA;
    --surface-page-text-muted: #A7A8AD;

    --surface-raised:          #212226;
    --surface-raised-text:     #E8E8EA;
    --surface-raised-text-muted: #A7A8AD;

    --surface-deep:            #101114;
    --surface-deep-text:       #DDDDE0;
    --surface-deep-text-muted: #9C9DA3;

    --surface-inverse:         #E9E9EB;
    --surface-inverse-text:    #1B1C1F;
    --surface-inverse-text-muted: rgba(27, 28, 31, 0.72);

    /* Accent stays the brand family; the tuned text variant flips dark for AA. */
    --surface-accent-text:     #FFFFFF;
    --color-accent-text:       #FF9D66;

    --surface-border:          #3A3B41;
    --surface-inverse-border:  rgba(27, 28, 31, 0.25);

    --surface-veil:            rgba(23, 24, 27, 0.93);
    --chrome-scrim:            rgba(23, 24, 27, 0.88);

    --color-border-subtle:     #33343A;
    --focus-ring:              #7AB8FF;
}

/* ============================================================================
   E4 — Boot splash (App.razor). Static overlay shown only during a slow cold
   WASM boot: it starts invisible, is revealed past a ~500ms threshold by the
   inline hook, then faded out and removed on Blazor.start(). Matches the dark
   theme-color so it reads as the app, not a flash of unstyled content.
   ========================================================================== */
.app-splash {
    position: fixed;
    inset: 0;
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #1a1a1a;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.35s ease;
}
.app-splash--visible {
    opacity: 1;
    pointer-events: auto;
}
.app-splash--hidden {
    opacity: 0 !important;
    pointer-events: none;
}
.app-splash-logo {
    width: min(240px, 50vw);
    height: auto;
    animation: app-splash-pulse 1.4s ease-in-out infinite;
}
@keyframes app-splash-pulse {
    0%, 100% { opacity: 0.55; }
    50%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .app-splash-logo { animation: none; }
    .app-splash { transition: none; }
}

/* =============================================================================
 * /listen/{slug} — public share landing (Listen.razor + ListenLayout).
 * A single giant play button over the release's full-resolution cover art, and
 * nothing else, so a link recipient can't be confused about how to play. The
 * click starts playback and the persistent GlobalPlayer auto-opens its
 * fullscreen visualizer (z-600), which then covers this stage.
 *
 * AI Note (R1 doctrine): the fixed light-on-dark literals here are intentional
 * and exempt from the semantic-token rule — same as .player-viz-overlay. This
 * is a FIXED near-black cinema surface behind cover art in every theme, so a
 * fixed white ink is the correct pair. Do NOT re-point these to --surface-*.
 * ============================================================================= */
.listen-stage {
    position: fixed;
    inset: 0;
    z-index: 400;                    /* below the fullscreen viz overlay (z-600) and player-bar (z-500) */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-6);
    background-color: rgb(8, 7, 6);
    background-image: var(--listen-cover);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    text-align: center;
    padding: var(--space-6);
}
.listen-stage--nocover { background-image: none; }

/* Upper-left home logo — the only navigation on the chrome-free stage (ListenLayout). Sits above the
   stage (z-400) and below the fullscreen viz overlay (z-600), so it's tappable on the landing but the
   visualizer covers it during playback. The mark's own white strokes read on the dark scrim; the shadow
   keeps it legible over lighter cover art without recoloring the brand. */
.listen-home {
    position: fixed;
    top: var(--space-4);
    left: var(--space-4);
    z-index: 450;
    display: inline-flex;
    align-items: center;
    border-radius: var(--radius-sm);
    transition: transform 0.15s ease;
}
.listen-home img {
    height: 2.5rem;
    width: auto;
    display: block;
    filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.55));
}
.listen-home:hover { transform: scale(1.04); }
.listen-home:focus-visible { outline: 3px solid #fff; outline-offset: 4px; }
@media (prefers-reduced-motion: reduce) {
    .listen-home { transition: none; }
}

/* Radial scrim: darkens the edges + center just enough for the white button and
   caption to read over any cover art, without hiding the artwork. */
.listen-scrim {
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse at center, rgba(8, 7, 6, 0.30), rgba(8, 7, 6, 0.78));
    pointer-events: none;
}

.listen-play-btn {
    position: relative;
    z-index: 1;
    width: min(44vmin, 260px);
    height: min(44vmin, 260px);
    border: 2px solid rgba(255, 255, 255, 0.55);
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.14);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    color: #fff;
    display: grid;
    place-items: center;
    cursor: pointer;
    box-shadow: 0 12px 44px rgba(0, 0, 0, 0.5);
    transition: transform 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}
.listen-play-btn:hover:not(:disabled) {
    transform: scale(1.06);
    background: rgba(255, 255, 255, 0.24);
    border-color: rgba(255, 255, 255, 0.85);
}
.listen-play-btn:active:not(:disabled) { transform: scale(0.98); }
.listen-play-btn:focus-visible { outline: 3px solid #fff; outline-offset: 4px; }
.listen-play-btn:disabled { opacity: 0.5; cursor: default; }
/* Optical-center the play triangle inside the circle (a triangle's visual mass sits left). */
.listen-play-icon { display: grid; place-items: center; margin-left: 0.35rem; }

.listen-caption { position: relative; z-index: 1; color: #fff; }
.listen-title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(1.5rem, 4.5vw, 2.6rem);
    line-height: 1.1;
    text-shadow: 0 2px 14px rgba(0, 0, 0, 0.65);
}
.listen-sub {
    margin-top: 0.25rem;
    opacity: 0.9;
    text-shadow: 0 2px 14px rgba(0, 0, 0, 0.65);
}
/* Upcoming-release street date (future-dated releases only). */
.listen-releasedate {
    margin-top: var(--space-2);
    font-weight: 600;
    color: #fff;
    text-shadow: 0 2px 14px rgba(0, 0, 0, 0.65);
}
/* DSP out-links row — reuses .release-dsp-links / .release-dsp-link chips; just adds spacing. */
.listen-dsp { margin-top: var(--space-3); }

.listen-missing {
    position: relative;
    z-index: 1;
    color: #fff;
    max-width: 32rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-4);
}
.listen-missing h1 { font-family: var(--font-display); }

/* Loading spinner (white ring) while the release resolves. */
.listen-spinner {
    position: relative;
    z-index: 1;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    border: 3px solid rgba(255, 255, 255, 0.25);
    border-top-color: #fff;
    animation: listen-spin 0.8s linear infinite;
}
@keyframes listen-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    .listen-spinner { animation: none; }
    .listen-play-btn { transition: none; }
}

/* =============================================================================
 * Fan-Favorites reach map + List/Map view toggle (DashboardSongPopularity /
 * PlayReachMap). US choropleth shaded by public play count.
 * AI Note: the map's stroke/fill hexes are fixed data-viz colour (sequential-
 * ramp legibility), the StyleConventions data-viz exception — not themed tokens.
 * ============================================================================= */
.pop-view-toggle { display: inline-flex; gap: 2px; margin-left: auto; }
.pop-view-btn {
    padding: 2px 10px;
    font-size: var(--admin-text-control, 0.85rem);
    border: var(--border-thin);
    background: var(--color-white, #fff);
    color: var(--color-charcoal, #2b2b2b);
    cursor: pointer;
    border-radius: var(--radius-sm, 6px);
}
.pop-view-btn.active {
    background: var(--color-accent, #2f7dd1);
    color: #fff;
    border-color: var(--color-accent, #2f7dd1);
}

.reach-map { display: flex; flex-direction: column; gap: var(--space-2, 0.5rem); }
.reach-map-svg { width: 100%; height: auto; max-height: 340px; display: block; }
.reach-state { stroke: #fff; stroke-width: 0.6; transition: opacity 0.1s ease; }
.reach-state.has-plays { cursor: default; }
.reach-state.has-plays:hover { opacity: 0.82; }
.reach-legend {
    display: flex; align-items: center; gap: var(--space-2, 0.5rem);
    font-size: var(--admin-text-help, 0.75rem); color: var(--color-charcoal, #2b2b2b); opacity: 0.8;
}
.reach-legend-bar { flex: 0 0 120px; height: 8px; border-radius: 4px; background: linear-gradient(90deg, #cfe3f7, #1f5fa8); }
.reach-other { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.reach-other-label { font-size: var(--admin-text-help, 0.75rem); text-transform: uppercase; letter-spacing: 0.03em; opacity: 0.6; }
.reach-chip {
    display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px;
    border-radius: 999px; background: var(--color-cream, #f2efe9); font-size: var(--admin-text-help, 0.78rem);
}
.reach-chip-n { font-weight: 700; }
.reach-chip-unknown { background: transparent; border: 1px dashed rgba(0, 0, 0, 0.28); opacity: 0.85; }
.reach-empty { padding: var(--space-3, 0.75rem); text-align: center; font-size: var(--admin-text-help, 0.8rem); opacity: 0.7; }
