/**
 * universal.css — base + brand + top bar + modals + JOY COIN + Header + Auth.
 *
 * EXTRACTION STATUS: partially populated (b.851).
 *
 * b.851 first slice: JOY COIN, HEADER, LIQUID BUTTONS, Account button,
 * Auth modal, Profile modal — extracted from index.html top inline <style>
 * (was lines 2627-4091 in the b.850 build). 1466 lines / 33KB byte-identical.
 *
 * TODO (future extractions): bal-card dropdown, Brand meta + MODE PILL,
 * TAB redesign, MY COINS pill, MY ACCOUNT pill, MENU pill, Theme video
 * background, MODAL primitives, Toast primitives, Theme overrides
 * (DAY-MODE, LSD/TRIPPY/DIFFUSED/BLACK themes), ANIMATED ORBS, UNIVERSAL
 * LIQUID-GLASS SWEEPER, SYSTEM-WIDE LIQUID GLASS, LIQUID GLASS PRIMITIVES.
 */

/* ════════════════════════════════════════════════════════════════════
   b.869 — GLOBAL [hidden] RESPECT GUARD.
   The HTML5 [hidden] attribute is supposed to hide elements (UA
   stylesheet: [hidden] { display: none }). But any class rule like
   `.director-default-bar { display: flex }` beats it on specificity,
   leaking the element into the page when it shouldn't be visible.

   This rule restores the contract: if an element has [hidden], it
   is hidden — period — unless something explicitly overrides with
   `display: <whatever> !important`. Surface CSS files that NEED to
   override [hidden] (e.g. the chat input row visible during chat
   even when other things hide) do so via !important; everything else
   respects the attribute as authors intended.

   This fixes the class of bugs where defer-loaded JS doesn't get to
   set hidden=true before first paint, leaving the element visible.
   Replaces the per-surface guard added in b.868 (which is now
   redundant but kept for documentation; safe to remove later).
   ════════════════════════════════════════════════════════════════════ */
[hidden] {
  display: none !important;
}

/* ════════════════════════════════════════════════════════════════════
   b.901 — REDUCED MOTION + tab-hidden animation pause.
   - prefers-reduced-motion: kill orb drift, video autoplay, scene-card
     entrance bounces, etc. Respects OS accessibility setting AND saves
     CPU for users who don't want animation.
   - body.soj-tab-hidden: set by visibilitychange handler in
     src/universal-boot.js when the tab is backgrounded. Pauses all
     CSS animations + video playback so we don't burn battery on
     invisible frames.
   ════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  /* Orbs become static blobs; theme video stays on first frame */
  .orb { animation: none !important; }
  #storyGardenVideo,
  #bgVideo { animation: none !important; }
}

body.soj-tab-hidden .orb,
body.soj-tab-hidden .bg-playback span {
  animation-play-state: paused !important;
}

/* ════════════════════════════════════════════════════════════════════
   b.889 — CONTENT-VISIBILITY for long-list items.
   Tells the browser to skip layout + paint for off-screen instances of
   these classes, dramatically improving rendering perf when a list has
   many items (long chat threads, big galleries, story scenes, etc.).

   contain-intrinsic-size gives a placeholder height so the scrollbar
   stays correct + scroll position doesn't jump as items hydrate.
   Values are best-guess averages; an off-by-2x guess just means slightly
   wrong scrollbar, not a layout break.

   Supported: Chrome 85+, Edge 85+, Safari 18+. Older browsers silently
   ignore — graceful degradation, no @supports gate needed.
   ════════════════════════════════════════════════════════════════════ */
.msg,
.scene-card,
.gallery-item,
.gallery-tile,
.asset-row,
.ld-turn,
.ms-track,
.dm-cast-card,
.mhc-card,
.vc-project,
.ce-history-item {
  content-visibility: auto;
}

/* Per-class intrinsic-size hints (avoid scrollbar jumps as content
   hydrates). Numbers come from observed natural heights of each item. */
.msg                { contain-intrinsic-size: 1px 200px; }
.scene-card         { contain-intrinsic-size: 1px 400px; }
.gallery-item,
.gallery-tile       { contain-intrinsic-size: 300px 300px; }
.asset-row          { contain-intrinsic-size: 1px 80px; }
.ld-turn            { contain-intrinsic-size: 1px 150px; }
.ms-track           { contain-intrinsic-size: 1px 100px; }
.dm-cast-card       { contain-intrinsic-size: 1px 120px; }
.mhc-card           { contain-intrinsic-size: 1px 280px; }
.vc-project         { contain-intrinsic-size: 1px 140px; }
.ce-history-item    { contain-intrinsic-size: 1px 60px; }


/* ════════════════════════════════════════════════════════════════════
   TOP UNIVERSAL FOUNDATION (THEME SYSTEM, DAY-MODE, ORBS, SWEEPER).
   Extracted in b.860. 720 lines from index.html top inline <style>
   (was the very top of the mega-block, lines 102-1438 originally).
   Includes:
   - THEME SYSTEM (replaces day/night, 107 lines)
   - DAY-MODE READABILITY PASS (192 lines)
   - ANIMATED COLORED ORBS (the "liquid" behind the glass, 205 lines)
   - UNIVERSAL LIQUID-GLASS SWEEPER rev 2 (214 lines)
   These are the foundation of the design system — must load first.
   ════════════════════════════════════════════════════════════════════ */

    /* ============================================================
   2026-05-07 — THEME SYSTEM (replaces day/night)
   :root holds the universal liquid-glass tokens. Each theme
   block (data-theme="garden-of-life" / "hanley-sky") layers
   only the things that DIFFER (background video, accent hues,
   bloom palette). All text is white in every theme; all
   surfaces are translucent liquid glass; switches use the
   animated emerald gradient defined further down.
   ============================================================ */
    :root {
      /* Base canvas — only visible if the theme video fails to load. */
      --bg-deep: #050a06;

      /* Universal text — always white, every theme. */
      --text: #ffffff;
      --text-muted: rgba(255, 255, 255, .72);
      --text-faint: rgba(255, 255, 255, .55);

      /* Liquid-glass tier tokens. Used by every panel/button/chip
     in every theme. Hover/active states brighten the glass. */
      --lg-fill: rgba(255, 255, 255, .06);
      --lg-fill-hover: rgba(255, 255, 255, .10);
      --lg-fill-active: rgba(255, 255, 255, .16);
      --lg-stroke: rgba(255, 255, 255, .22);
      --lg-stroke-hi: rgba(255, 255, 255, .45);
      --lg-blur: blur(22px) saturate(1.30) brightness(1.04);
      --lg-blur-light: blur(14px) saturate(1.20);
      --lg-shadow:
        0 1px 0 rgba(255, 255, 255, .55) inset,
        0 -1px 0 rgba(255, 255, 255, .18) inset,
        0 0 0 1px rgba(255, 255, 255, .10) inset,
        0 24px 60px -22px rgba(0, 0, 0, .65);

      /* Legacy variable names kept so anything still pointing at
     them doesn't break. They alias to the new lg-* tokens. */
      --glass-bg: var(--lg-fill);
      --glass-bg-strong: var(--lg-fill-hover);
      --glass-bg-active: var(--lg-fill-active);
      --glass-bg-cta: rgba(255, 255, 255, .32);
      --glass-border: var(--lg-stroke);
      --glass-border-strong: var(--lg-stroke-hi);
      --glass-blur: var(--lg-blur-light);
      --glass-blur-strong: var(--lg-blur);
      --glass-shadow: var(--lg-shadow);

      /* Animated-green switch palette — used by .toggle-grp .on */
      --switch-1: #1aa86a;
      --switch-2: #2fd084;
      --switch-3: #6fe6a8;
      --switch-4: #0f7a48;

      /* Default theme = Garden. The theme blocks below override these. */
      --orb-1: #2c5a36;
      --orb-2: #1f4a2c;
      --orb-3: #3a8b5d;
      --orb-4: #4fa564;
      --orb-5: #27ae60;
      --orb-6: #6fc99a;

      --coin-gold: #fca600;
      --danger: #ff5060;

      --r-sm: 8px;
      --r-md: 14px;
      --r-lg: 22px;
      --r-xl: 28px;
      --ease: cubic-bezier(.2, .7, .2, 1);
      --ease-out: cubic-bezier(.16, 1, .3, 1);

      --font-display: "Plus Jakarta Sans", ui-sans-serif, system-ui, "Helvetica Neue", sans-serif;
      --font-ui: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
      --font-body: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
    }

    /* THEME 1 — GARDEN OF LIFE
   Botanical liquid garden, dense growing plants, warm dewy palette. */
    html[data-theme="garden-of-life"] {
      --bg-deep: #050a06;
      --orb-1: #2c5a36;
      --orb-2: #1f4a2c;
      --orb-3: #3a8b5d;
      --orb-4: #4fa564;
      --orb-5: #27ae60;
      --orb-6: #6fc99a;
      /* Tinted scrim between the bg video and the UI — keeps text legible. */
      --bg-scrim-top: rgba(0, 0, 0, .30);
      --bg-scrim-btm: rgba(0, 8, 4, .55);
      --bg-vignette: radial-gradient(ellipse at 50% 50%, transparent 30%, rgba(0, 0, 0, .40) 95%);
      --video-tone: saturate(1.10) brightness(.78) contrast(1.06);
    }

    /* THEME 2 — HANLEY SKY
   Deep cosmos, millions of stars, Milky Way in slow rotation. */
    html[data-theme="hanley-sky"] {
      --bg-deep: #02030a;
      --orb-1: #1a2452;
      --orb-2: #2a1d4f;
      --orb-3: #3b3475;
      --orb-4: #5a4ca8;
      --orb-5: #7b5fc4;
      --orb-6: #a890e8;
      --bg-scrim-top: rgba(0, 0, 0, .25);
      --bg-scrim-btm: rgba(2, 3, 12, .55);
      --bg-vignette: radial-gradient(ellipse at 50% 50%, transparent 35%, rgba(0, 0, 0, .55) 95%);
      --video-tone: saturate(1.15) brightness(.82) contrast(1.10);
    }

    /* ============================================================
   2026-05-07 — DAY-MODE READABILITY PASS
   The original day-mode rules used rgba(10,39,85, .40-.62) for
   labels, placeholders, captions, and counts. Against bright
   glass panels these read as washed-out grey — invisible on the
   "Direct this scene" composer in particular. This block forces
   every label/placeholder/caption to near-black so all text in
   day mode reads as the user expects.
   ============================================================ */
    html[data-theme="day"] ::placeholder {
      color: rgba(0, 0, 0, .55) !important;
      opacity: 1
    }

    html[data-theme="day"] ::-webkit-input-placeholder {
      color: rgba(0, 0, 0, .55) !important;
      opacity: 1
    }

    html[data-theme="day"] :-ms-input-placeholder {
      color: rgba(0, 0, 0, .55) !important
    }

    /* Director Modal scene composer */
    html[data-theme="day"] .director-modal-v2 .dm-roster-label,
    html[data-theme="day"] .director-modal-v2 .dm-param-label,
    html[data-theme="day"] .director-modal-v2 .dm-roster-count,
    html[data-theme="day"] .director-modal-v2 .dm-param-value,
    html[data-theme="day"] .director-modal-v2 .dm-context-input,
    html[data-theme="day"] .director-modal-v2 .dm-topbar-text h2,
    html[data-theme="day"] .director-modal-v2 .dm-topbar-text p,
    html[data-theme="day"] .director-modal .dm-topbar-text p,
    html[data-theme="day"] .director-modal .dm-tagline,
    html[data-theme="day"] .director-modal .dm-section-name,
    html[data-theme="day"] .director-modal .dm-section-sub,
    html[data-theme="day"] .director-modal .dm-label,
    html[data-theme="day"] .director-modal .dm-label-sub,
    html[data-theme="day"] .director-modal .dm-tab-name,
    html[data-theme="day"] .director-modal .dm-tab-num,
    html[data-theme="day"] .director-modal .dm-tab-sub,
    html[data-theme="day"] .director-modal .dm-tile-name,
    html[data-theme="day"] .director-modal .dm-tile-sub,
    html[data-theme="day"] .director-modal .dm-block-head h3,
    html[data-theme="day"] .director-modal .dm-block-head p,
    html[data-theme="day"] .director-modal .dm-prompt-toggle,
    html[data-theme="day"] .director-modal .dm-prompt-count,
    html[data-theme="day"] .director-modal .dm-prompt-hint,
    html[data-theme="day"] .director-modal .dm-section-caret,
    html[data-theme="day"] .director-modal .dm-cast-name,
    html[data-theme="day"] .director-modal .dm-cast-action,
    html[data-theme="day"] .dm-popover-shell h3,
    html[data-theme="day"] .dm-popover-tagline,
    html[data-theme="day"] .dm-tile-name,
    html[data-theme="day"] .dm-tile-sub,
    html[data-theme="day"] .director-bottom-btn .dbb-sub,
    html[data-theme="day"] .dm-manual-toggle .dm-mt-label,
    html[data-theme="day"] .manual-return-btn,
    html[data-theme="day"] .director-default-bar .ddb-pill,
    html[data-theme="day"] .director-default-bar .ddb-on,
    html[data-theme="day"] .director-default-bar .ddb-cta,
    html[data-theme="day"] .director-default-bar .ddb-arrow {
      color: #000 !important;
    }

    /* Slightly softer still readable for true secondary text */
    html[data-theme="day"] .director-modal .dm-tab-sub,
    html[data-theme="day"] .director-modal .dm-tile-sub,
    html[data-theme="day"] .director-modal .dm-prompt-count,
    html[data-theme="day"] .director-modal .dm-prompt-hint,
    html[data-theme="day"] .director-modal-v2 .dm-roster-count,
    html[data-theme="day"] .director-modal .dm-section-caret,
    html[data-theme="day"] .dm-popover-tagline {
      color: rgba(0, 0, 0, .62) !important;
    }

    /* Cinema modal + cast modal */
    html[data-theme="day"] .cast-modal .cm-textarea,
    html[data-theme="day"] .cast-modal .cm-label,
    html[data-theme="day"] .cast-modal .cm-cost-note,
    html[data-theme="day"] .cinema-modal .cm-h,
    html[data-theme="day"] .cinema-modal .cm-tile-name,
    html[data-theme="day"] .cinema-modal .cm-section-h {
      color: #000 !important;
    }

    /* Generic catch-all for any element with explicitly set text-muted */
    html[data-theme="day"] .text-muted {
      color: #0a0a0a !important
    }

    html[data-theme="day"] .text-faint {
      color: #1a1a1a !important
    }

    *,
    *::before,
    *::after {
      box-sizing: border-box
    }

    html,
    body {
      height: 100%
    }

    html {
      scroll-behavior: smooth;
      -webkit-text-size-adjust: 100%
    }

    body {
      margin: 0;
      font-family: var(--font-ui);
      background: var(--bg-deep);
      color: var(--text);
      font-weight: 600;
      line-height: 1.5;
      -webkit-font-smoothing: antialiased;
      text-rendering: optimizeLegibility;
      display: flex;
      flex-direction: column;
      overflow: hidden;
      transition: background-color .4s var(--ease), color .4s var(--ease);
    }

    img,
    svg,
    video {
      display: block;
      max-width: 100%
    }

    button {
      font: inherit;
      color: inherit;
      background: none;
      border: none;
      cursor: pointer;
      letter-spacing: inherit;
      outline: none
    }

    input,
    textarea {
      font: inherit;
      color: inherit;
      background: none;
      border: none;
      outline: none
    }

    /* b.539 — Suppress the macOS / Chromium system accent focus ring
   on EVERY interactive element. On macOS Sonoma+ the default focus
   ring inherits the user's System Settings accent colour — when
   that's set to green, every clicked button picks up a green halo.
   Same logic for blue / pink / etc. We replace the system ring
   with a subtle white :focus-visible ring (keyboard-only) so
   accessibility is preserved without colour-bleed. Mouse clicks
   show no ring at all. */
    button:focus,
    button:active,
    [role="button"]:focus,
    [role="button"]:active,
    a:focus,
    [tabindex]:focus {
      outline: none !important;
    }

    button:focus-visible,
    [role="button"]:focus-visible,
    a:focus-visible,
    [tabindex]:focus-visible {
      outline: 2px solid rgba(255, 255, 255, .45) !important;
      outline-offset: 2px !important;
    }

    em,
    i {
      font-style: normal !important
    }

    /* no italics anywhere */
    ::selection {
      background: rgba(255, 255, 255, .22);
      color: #fff
    }

    html[data-theme="day"] ::selection {
      background: rgba(0, 0, 0, .12);
      color: #000
    }

    /* ============================================================
   ANIMATED COLORED ORBS — the "liquid" behind the glass
   ============================================================ */
    .bg-stage {
      position: fixed;
      inset: 0;
      z-index: 0;
      pointer-events: none;
      overflow: hidden;
      background: var(--bg-deep);
    }

    /* b.902 — ORBS REMOVED. The .orb / .story-orb / @keyframes drift1..8
       block (~194 lines) lived here. Themes layer their own full-viewport
       background video/imagery, so the orbs were redundant CPU+GPU work for
       a layer nobody saw. .bg-stage above is KEPT because backdrop-filter
       on modals composes against it as a stable target. */

    /* ================================================================
   2026-05-07 — UNIVERSAL LIQUID-GLASS SWEEPER (rev 2)
   ONLY individual interactive elements + cards become glass. Their
   parent containers (.header, .tabs, .h-right, .bal-card,
   .input-shell, .auth-shell, .controls, .modes-screen) stay
   completely transparent so each child reads as a separate floating
   pill against the moving theme video. Nothing is grouped into a
   bar. Every chip, button, input, and modal panel is its own piece.
   ================================================================ */
    [data-theme] .glass-pill,
    [data-theme] .theme-toggle,
    [data-theme] .account-btn,
    [data-theme] .balance-pill,
    [data-theme] .balance-add,
    [data-theme] .bal-add,
    [data-theme] .build-tag,
    [data-theme] .tab,
    [data-theme] .mode-pill,
    [data-theme] .mode-pill-top,
    [data-theme] .topup-btn,
    [data-theme] .input-row,
    [data-theme] .toggle-grp button,
    [data-theme] .ref-btn,
    [data-theme] .boost-btn,
    [data-theme] .action-pill,
    [data-theme] .video-tip,
    [data-theme] .quality-tip,
    [data-theme] .modal,
    [data-theme] .modal-shell,
    [data-theme] .auth-btn,
    [data-theme] .auth-input,
    [data-theme] .pack-card,
    [data-theme] .topup-card,
    [data-theme] .tile,
    [data-theme] .lib-empty,
    [data-theme] .saved-story-row,
    [data-theme] .profile-head,
    [data-theme] .profile-actions button,
    [data-theme] .signout-top,
    [data-theme] .asset-chip,
    [data-theme] .pp-cell,
    [data-theme] .field input,
    [data-theme] .field textarea,
    [data-theme] .input,
    [data-theme] textarea,
    [data-theme] input[type="text"],
    [data-theme] input[type="email"],
    [data-theme] input[type="password"],
    [data-theme] input[type="number"],
    [data-theme] input[type="search"],
    [data-theme] input[type="url"],
    [data-theme] .sc-action-btn,
    [data-theme] .sc-cancel,
    [data-theme] .ddb-cta,
    [data-theme] .my-stories-btn,
    [data-theme] .story-stitch-btn,
    [data-theme] .story-title-input,
    [data-theme] .modes-screen .ms-tile {
      background: var(--lg-fill) !important;
      border: 1.5px solid var(--lg-stroke) !important;
      -webkit-backdrop-filter: var(--lg-blur) !important;
      backdrop-filter: var(--lg-blur) !important;
      box-shadow: var(--lg-shadow) !important;
      color: #ffffff !important;
      border-radius: 999px !important;
      /* default to pill — cards override */
    }

    /* Cards / panels (not pills) keep their natural radius. */
    [data-theme] .pack-card,
    [data-theme] .topup-card,
    [data-theme] .tile,
    [data-theme] .lib-empty,
    [data-theme] .saved-story-row,
    [data-theme] .pp-cell,
    [data-theme] .modal,
    [data-theme] .modal-shell,
    [data-theme] .video-tip,
    [data-theme] .quality-tip,
    [data-theme] .modes-screen .ms-tile,
    [data-theme] textarea {
      border-radius: 22px !important;
    }

    /* 2026-05-07 — UNIVERSAL "no sharp edges" rule. Every interactive
   surface across the app gets a soft rounded corner. Larger radii
   declared elsewhere still win because of cascade order. */
    [data-theme] button,
    [data-theme] input,
    [data-theme] select,
    [data-theme] textarea,
    [data-theme] .scene-card,
    [data-theme] .scene-card .sc-frame,
    [data-theme] .director-modal .dm-shell,
    [data-theme] .director-modal-v2 .dm-shell-v2,
    [data-theme] .cinema-modal .cm-shell,
    [data-theme] .cast-modal .cm-shell,
    [data-theme] .stitch-modal .sm-shell,
    [data-theme] .story-chip-pop,
    [data-theme] .story-cost-popover,
    [data-theme] .dm-popover-shell,
    [data-theme] .director-default-bar,
    [data-theme] .director-summary-chip,
    [data-theme] .auth-shell,
    [data-theme] .field {
      border-radius: 16px;
    }

    [data-theme] .modal img,
    [data-theme] .modal video,
    [data-theme] .scene-card img,
    [data-theme] .scene-card video,
    [data-theme] .pack-card img,
    [data-theme] .tile img,
    [data-theme] .tile video,
    [data-theme] .sc-frame img,
    [data-theme] .sc-frame video {
      border-radius: 14px;
    }

    /* 2026-05-07 — NO CONTAINERS. Every wrapping element across the
   app is fully transparent. Each individual button / chip / input
   floats on its own glass. Nothing groups, nothing boxes anything.
   .bal-card is included in this — Joy Coins and Buy Coins are now
   two separate floating pills with normal gap between them. */
    [data-theme] .header,
    [data-theme] .tabs,
    [data-theme] .h-right,
    [data-theme] .bal-card,
    [data-theme] .input-bar,
    [data-theme] .input-shell,
    [data-theme] .input-row,
    [data-theme] .auth-shell,
    [data-theme] .controls,
    /* 2026-05-12 b.349 — .modes-screen removed from wrapper-transparency
   sweep. It WAS a fullscreen takeover wrapper (children carried the
   frost). Since b.348 it IS the popover itself, so it needs to keep
   its own background + border + backdrop-filter. Was the reason the
   redesign rendered fully transparent over wallpapers. */
    [data-theme] .gallery,
    [data-theme] .modes-head,
    [data-theme] .story-head,
    [data-theme] .director-default-bar,
    [data-theme] .director-summary,
    [data-theme] .profile-actions,
    [data-theme] .pack-list,
    [data-theme] .topup-list,
    [data-theme] .lib-list,
    [data-theme] main,
    [data-theme] section,
    [data-theme] footer {
      background: transparent !important;
      border: 0 !important;
      box-shadow: none !important;
      backdrop-filter: none !important;
      -webkit-backdrop-filter: none !important;
      overflow: visible !important;
    }

    /* Tabs — each tab becomes its own pill, gap between them. */
    [data-theme] .tabs {
      gap: 10px !important;
      height: auto !important;
      width: auto !important
    }

    [data-theme] .tab {
      height: 44px !important;
      padding: 0 18px !important;
      flex: 0 0 auto !important;
    }

    /* Header / right cluster gap so individual pills breathe */
    [data-theme] .header {
      gap: 14px !important
    }

    [data-theme] .h-right {
      gap: 12px !important
    }

    /* 2026-05-08 v38 — Joy Coins balance + Buy coins are now ONE connected
   unit. The shell is .bal-card itself; inside, .bal-amount sits flush
   on the left, a thin vertical divider line, then .bal-add on the
   right. Each child loses its own glass treatment so the seam is
   invisible — the user sees a single pill where the right end is
   clearly a button. */
    [data-theme] .bal-card {
      gap: 0 !important;
      padding: 0 !important;
      height: 44px !important;
      display: inline-flex !important;
      align-items: stretch !important;
      background: var(--lg-fill) !important;
      border: 1.5px solid var(--lg-stroke) !important;
      -webkit-backdrop-filter: var(--lg-blur) !important;
      backdrop-filter: var(--lg-blur) !important;
      box-shadow: var(--lg-shadow) !important;
      border-radius: 999px !important;
      overflow: hidden !important;
      white-space: nowrap !important;
      color: #fff !important;
      /* b.232 — bal-card is no longer pushed down with margin. Instead,
     when expanded (body:not(.coins-collapsed)) it gets pinned to
     the top of the viewport in the same band as the MY COINS pill
     it replaces (rule below). */
      margin-top: 0 !important;
    }

    /* b.232 — When MY COINS is hovered, the pill hides and the
   bal-card appears at the pill's same location (top of viewport),
   not in the header flow underneath. This avoids any vertical
   overlap with the MY ACCOUNT pill while keeping the swap
   visually anchored to the spot the user clicked. */

    /* ============================================================
   JOY COIN — glass disc with fluid colorful energy moving inside
   ============================================================ */
    .joy-coin {
      position: relative;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 1.25em;
      height: 1.25em;
      flex: none;
      vertical-align: middle;
      filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .18)) drop-shadow(0 0 10px rgba(255, 255, 255, .16));
    }

    .joy-coin svg {
      width: 100%;
      height: 100%;
      display: block;
      overflow: visible
    }

    .joy-coin .coin-spiral {
      mix-blend-mode: screen;
      filter: saturate(140%)
    }

    html[data-theme="day"] .joy-coin .coin-spiral {
      mix-blend-mode: multiply;
      opacity: .92
    }

    .joy-coin .r {
      transform-origin: 16px 16px;
      will-change: transform
    }

    .joy-coin .r1 {
      animation: cr 1.6s linear infinite
    }

    .joy-coin .r2 {
      animation: cr 2.0s linear infinite reverse
    }

    .joy-coin .r3 {
      animation: cr 1.4s linear infinite
    }

    .joy-coin .r4 {
      animation: cr 1.8s linear infinite reverse
    }

    .joy-coin .r5 {
      transform-origin: 16px 16px;
      animation: cr-pulse 2s ease-in-out infinite
    }

    @keyframes cr {
      to {
        transform: rotate(360deg)
      }
    }

    @keyframes cr-pulse {

      0%,
      100% {
        transform: scale(1);
        opacity: 1
      }

      50% {
        transform: scale(1.5);
        opacity: .7
      }
    }

    .joy-coin .hi {
      animation: cr-hi 3s ease-in-out infinite
    }

    @keyframes cr-hi {

      0%,
      100% {
        opacity: .5
      }

      50% {
        opacity: .25
      }
    }

    /* ratio icons */
    .ratio-ico {
      display: inline-block;
      border: 1.5px solid currentColor;
      border-radius: 2px;
      flex: none;
      opacity: .9
    }

    .ratio-ico.r-9-16 {
      width: 9px;
      height: 14px
    }

    .ratio-ico.r-16-9 {
      width: 14px;
      height: 9px
    }

    /* b.306 — additional aspect-ratio icons. Sized to mirror the visual
   intent of each ratio at roughly the same area as 9:16 / 16:9. */
    .ratio-ico.r-1-1 {
      width: 11px;
      height: 11px
    }

    .ratio-ico.r-4-5 {
      width: 11px;
      height: 14px
    }

    /* ============================================================
   HEADER
   ============================================================ */
    .header {
      position: relative;
      z-index: 10;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 14px;
      padding: 33px 22px 12px;
      /* no background — each child floats */
      contain: layout;
    }

    [data-theme] .header,
    html .header {
      padding-top: 33px !important;
    }

    .brand {
      display: flex;
      align-items: center;
      gap: 14px;
      white-space: nowrap
    }

    /* b.268 — Brand wordmark doubles as a "return home" button (routes
   to the Chat tab). Soft hover state telegraphs clickability without
   competing with the actual header pills. */
    .brand[role="button"] {
      transition: opacity .2s ease, transform .2s ease
    }

    .brand[role="button"]:hover {
      opacity: .82
    }

    .brand[role="button"]:active {
      transform: translateY(1px)
    }

    .brand[role="button"]:focus-visible {
      outline: 2px solid rgba(255, 255, 255, .55);
      outline-offset: 6px;
      border-radius: 6px
    }

    .brand .joy-coin {
      width: 42px;
      height: 42px
    }

    .build-tag {
      display: inline-flex;
      align-items: center;
      padding: 3px 8px;
      border-radius: 999px;
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 10px;
      letter-spacing: .10em;
      color: var(--text-muted);
      background: rgba(255, 255, 255, .04);
      border: 1px solid var(--glass-border);
      text-transform: lowercase;
      line-height: 1;
      user-select: all;
    }

    .brand-name {
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 20px;
      letter-spacing: .005em;
      line-height: 1.05;
      color: var(--text);
      text-transform: none;
      display: inline-flex;
      flex-direction: column;
      /* 2026-05-15 b.713 — nudge wordmark up 15px per K. Using
         transform so it doesn't disturb document flow / BETA pill. */
      transform: translateY(-15px);
    }

    .brand-name em {
      font-family: var(--font-display);
      font-weight: 800;
      font-style: normal;
      font-size: 13px;
      letter-spacing: .18em;
      text-transform: uppercase;
      color: var(--text-muted);
      margin-top: 3px;
    }

    /* glass pill — shared base */
    .glass-pill {
      display: inline-flex;
      align-items: center;
      border: 1px solid var(--glass-border);
      background: var(--glass-bg);
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      border-radius: 12px;
      box-shadow: var(--glass-shadow);
      transition: background .25s var(--ease), border-color .25s, transform .25s var(--ease);
    }

    .glass-pill:hover {
      background: var(--glass-bg-strong);
      border-color: var(--glass-border-strong)
    }

    /* ============================================================
   LIQUID BUTTONS — moving colors behind the glass
   any element with .liquid gets a slow rotating colored haze
   ============================================================ */
    .liquid {
      position: relative;
      overflow: hidden;
      isolation: isolate
    }

    .liquid::before {
      content: "";
      position: absolute;
      width: 240%;
      height: 240%;
      left: -70%;
      top: -70%;
      background: conic-gradient(from 45deg,
          var(--orb-1), var(--orb-2), var(--orb-3),
          var(--orb-4), var(--orb-5), var(--orb-6),
          var(--orb-1));
      filter: blur(28px);
      opacity: .55;
      mix-blend-mode: screen;
      animation: liquidSpin 14s linear infinite;
      z-index: -2;
      pointer-events: none;
    }

    html[data-theme="day"] .liquid::before {
      mix-blend-mode: multiply;
      opacity: .32;
      filter: blur(32px);
    }

    .liquid:hover::before {
      animation-duration: 8s
    }

    @keyframes liquidSpin {
      to {
        transform: rotate(360deg)
      }
    }

    /* tabs */
    .tabs {
      display: flex;
      align-items: center;
      border: 1px solid var(--glass-border);
      background: transparent;
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      border-radius: 14px;
      overflow: hidden;
      height: 44px;
      width: min(560px, 58vw);
      /* b.598 — 4 tabs, was 440px */
      /* b.234 — VIEWPORT-anchored centring. b.233 used position:absolute
     relative to .header, but .header has `contain: layout` which
     collapsed the positioning context and pushed the tabs to the
     right side. Switching to position:fixed anchors directly to the
     viewport — 50% of viewport width is genuinely dead-centre on
     the screen no matter what the header contains. */
      position: fixed;
      left: 50%;
      top: 24px;
      transform: translateX(-50%);
      z-index: 20;
    }

    .tab {
      position: relative;
      flex: 1;
      /* equal width */
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 12px;
      letter-spacing: .02em;
      text-transform: uppercase;
      line-height: 1;
      padding: 0 16px;
      height: 100%;
      border-radius: 0;
      color: var(--text-muted);
      white-space: nowrap;
      transition: color .25s;
    }

    /* no internal separator between tabs (same approach as toggles) */
    .tab.active {
      color: var(--text);
      font-weight: 800;
      backdrop-filter: blur(20px) saturate(220%) brightness(1.08);
      -webkit-backdrop-filter: blur(20px) saturate(220%) brightness(1.08);
    }

    html[data-theme="day"] .tab.active {
      color: #000;
      backdrop-filter: blur(20px) saturate(180%) brightness(.96);
      -webkit-backdrop-filter: blur(20px) saturate(180%) brightness(.96);
    }

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

    .tab.locked {
      opacity: .55
    }

    @keyframes dotPulse {

      0%,
      100% {
        transform: scale(1);
        opacity: 1
      }

      50% {
        transform: scale(.5);
        opacity: .55
      }
    }

    /* header right pills */
    /* b.434 — min-height pins the .h-right cluster at the bal-card's
   original 44px tall regardless of which children are visible. When
   bal-card is hoisted out to body root (b.430) and the coins pill is
   hidden (b.432), .h-right was collapsing to ~32px (the next-tallest
   children — buttons). That made the header shorter than the .main
   height calc(100vh - 64px) reserved, so the entire chat surface
   (tabs + textarea + input row) slid upward by ~12px. Pinning .h-right
   at 44px restores the header to its original height and the chat to
   its original position. */
    .h-right {
      display: flex;
      align-items: flex-end;
      gap: 10px;
      min-height: 44px
    }

    /* unified balance + top-up card */
    .bal-card {
      display: inline-flex;
      align-items: center;
      height: 44px;
      border: 1px solid var(--glass-border);
      border-radius: 14px;
      background: transparent;
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      overflow: hidden;
    }

    .bal-amount {
      display: inline-flex;
      align-items: center;
      gap: 9px;
      padding: 0 16px;
      height: 100%;
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 13px;
      letter-spacing: 0;
      color: var(--text);
      line-height: 1;
    }

    .bal-amount .joy-coin {
      width: 1.85em;
      height: 1.85em;
      margin-right: 2px
    }

    .bal-amount .num {
      min-width: 1ch;
      display: inline-block
    }

    /* b.559 — fractional coin display: "23·42p" reads as 23 coins and
   42 paise (1/100 of a coin). The paise pip is small, lower-weight,
   slightly muted so the integer reads as primary and the fraction
   as a quiet secondary. Inspired by the "₹23·42" rupee/paise format
   most Indian users recognise immediately. */
    .bal-amount .num .coin-paise,
    .coin-paise {
      font-size: .55em;
      font-weight: 600;
      opacity: .65;
      margin-left: 1px;
      letter-spacing: .02em;
      vertical-align: .05em;
    }

    .bal-add {
      padding: 0 18px;
      height: 100%;
      border: none;
      border-left: 1px solid var(--glass-border);
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 12px;
      letter-spacing: .02em;
      color: var(--text);
      line-height: 1;
      white-space: nowrap;
      transition: transform .25s var(--ease);
    }

    .bal-add:hover {
      transform: translateY(-1px)
    }

    .icon-btn {
      width: 44px;
      height: 44px;
      border-radius: 12px;
      display: inline-grid;
      place-items: center;
      background: transparent;
      border: 1px solid var(--glass-border);
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      color: var(--text);
      font-size: 16px;
      transition: background .25s, border-color .25s;
    }

    .icon-btn:hover {
      background: var(--glass-bg-strong);
      border-color: var(--glass-border-strong)
    }

    .theme-toggle {
      height: 44px;
      padding: 0 16px 0 12px;
      gap: 9px;
      border: 1px solid var(--glass-border);
      border-radius: 12px;
      background: transparent;
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 12px;
      letter-spacing: .02em;
      text-transform: uppercase;
      color: var(--text);
      line-height: 1;
    }

    /* ===== Account button ===== */
    .account-btn {
      height: 44px;
      padding: 0 16px;
      display: inline-flex;
      align-items: center;
      gap: 10px;
      border: 1px solid var(--glass-border);
      border-radius: 12px;
      background: transparent;
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 12px;
      letter-spacing: .02em;
      color: var(--text);
      line-height: 1;
      white-space: nowrap;
      transition: transform .25s var(--ease), background .25s, border-color .25s;
    }

    .account-btn:hover {
      transform: translateY(-1px);
      border-color: var(--glass-border-strong)
    }

    .account-btn .ava {
      display: none;
      width: 26px;
      height: 26px;
      border-radius: 8px;
      background: linear-gradient(135deg, var(--orb-1), var(--orb-5));
      color: #fff;
      align-items: center;
      justify-content: center;
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 13px;
      letter-spacing: 0;
    }

    .account-btn.signed .ava {
      display: inline-flex
    }

    .account-btn.signed .lbl-create {
      display: none
    }

    .account-btn.signed .lbl-name {
      display: inline
    }

    .account-btn .lbl-name {
      display: none
    }

    /* Balance card: hide the actual coin readout until the user is signed in.
   "+ Buy coins" stays visible (signed-out users can still click it; the
   buy flow then prompts sign-in). */
    .bal-card {
      display: inline-flex;
      align-items: center;
      gap: 10px
    }

    .bal-card.signed-out .bal-amount {
      display: none
    }

    /* ===== Auth modal ===== */
    .auth-screen {
      display: flex;
      flex-direction: column;
      align-items: center;
      text-align: center;
      padding: 6px 4px 4px;
    }

    .auth-hero {
      width: 64px;
      height: 64px;
      border-radius: 18px;
      display: grid;
      place-items: center;
      background: linear-gradient(135deg, var(--orb-1), var(--orb-3), var(--orb-5));
      margin-bottom: 14px;
      box-shadow: 0 12px 36px -10px rgba(0, 0, 0, .45);
    }

    .auth-hero .joy-coin {
      width: 38px;
      height: 38px
    }

    .auth-title {
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 22px;
      letter-spacing: -.005em;
      color: var(--text);
      margin: 0 0 8px;
      line-height: 1.15;
    }

    .auth-sub {
      font-family: var(--font-display);
      font-weight: 600;
      font-size: 14px;
      line-height: 1.5;
      color: var(--text-muted);
      margin: 0 0 22px;
      max-width: 380px;
    }

    .auth-sub strong {
      color: var(--text);
      font-weight: 800
    }

    .auth-bullets {
      display: flex;
      flex-direction: column;
      gap: 8px;
      margin: 0 0 22px;
      align-self: stretch;
    }

    .auth-bullet {
      display: flex;
      align-items: flex-end;
      gap: 10px;
      padding: 10px 14px;
      border-radius: 10px;
      background: rgba(255, 255, 255, .05);
      border: 1px solid var(--glass-border);
      font-family: var(--font-display);
      font-weight: 600;
      font-size: 13px;
      color: var(--text);
      text-align: left;
      line-height: 1.35;
    }

    html[data-theme="day"] .auth-bullet {
      background: rgba(0, 0, 0, .03)
    }

    .auth-bullet .ico {
      font-size: 16px;
      flex: none;
      line-height: 1
    }

    .auth-block {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 10px;
      align-self: stretch;
      padding: 0;
    }

    #gsiBtnHost {
      display: flex;
      justify-content: center;
      align-self: stretch;
      /* Google button is a child iframe; we just give it room */
      min-height: 44px;
    }

    .auth-btn {
      width: 100%;
      max-width: 360px;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 12px;
      height: 48px;
      padding: 0 18px;
      border-radius: 24px;
      border: 1px solid var(--glass-border-strong);
      background: rgba(255, 255, 255, .10);
      backdrop-filter: blur(14px) saturate(160%);
      -webkit-backdrop-filter: blur(14px) saturate(160%);
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 14px;
      letter-spacing: .005em;
      color: var(--text);
      line-height: 1;
      transition: transform .2s var(--ease), background .2s, border-color .2s;
    }

    html[data-theme="day"] .auth-btn {
      background: rgba(0, 0, 0, .04)
    }

    .auth-btn:hover {
      transform: translateY(-1px);
      background: rgba(255, 255, 255, .18);
      border-color: var(--glass-border-strong)
    }

    html[data-theme="day"] .auth-btn:hover {
      background: rgba(0, 0, 0, .07)
    }

    .auth-btn svg {
      width: 18px;
      height: 18px;
      flex: none
    }

    .auth-fine {
      font-family: var(--font-display);
      font-weight: 600;
      font-size: 11.5px;
      letter-spacing: .01em;
      color: var(--text-muted);
      text-align: center;
      margin: 18px 0 0;
      line-height: 1.5;
      max-width: 380px;
    }

    /* "Use a different Google account" — only meaningful when GIS rendered
   a personalized button (the user has an active Google session). Hidden
   by default; JS adds .is-visible after detecting a personalized button. */
    .auth-switch-link {
      display: none;
      align-self: center;
      background: transparent;
      border: none;
      cursor: pointer;
      margin-top: 6px;
      padding: 6px 10px;
      border-radius: 6px;
      font-family: var(--font-display);
      font-weight: 600;
      font-size: 12.5px;
      letter-spacing: .005em;
      color: var(--text-muted);
      text-decoration: underline;
      text-underline-offset: 3px;
      transition: color .2s, background .2s;
    }

    .auth-switch-link.is-visible {
      display: inline-flex
    }

    .auth-switch-link:hover {
      color: var(--text);
      background: rgba(255, 255, 255, .06)
    }

    html[data-theme="day"] .auth-switch-link:hover {
      background: rgba(0, 0, 0, .04)
    }

    .auth-notice {
      align-self: stretch;
      padding: 10px 14px;
      margin: 0 0 16px;
      border-radius: 10px;
      background: rgba(255, 200, 80, .08);
      border: 1px solid rgba(255, 200, 80, .22);
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 12.5px;
      color: var(--text);
      text-align: left;
    }

    /* ===== Profile modal ===== */
    .profile-head {
      display: flex;
      align-items: center;
      gap: 14px;
      margin-bottom: 18px;
      padding-bottom: 18px;
      border-bottom: 1px solid var(--glass-border)
    }

    .profile-head .ava-lg {
      width: 54px;
      height: 54px;
      border-radius: 14px;
      flex: none;
      background: linear-gradient(135deg, var(--orb-1), var(--orb-5));
      color: #fff;
      display: grid;
      place-items: center;
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 24px;
    }

    .profile-head .info {
      display: flex;
      flex-direction: column;
      gap: 4px;
      min-width: 0;
      flex: 1
    }

    .profile-head .info .nm {
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 18px;
      color: var(--text);
      line-height: 1.1
    }

    .profile-head .info .em {
      font-family: var(--font-display);
      font-weight: 600;
      font-size: 12.5px;
      color: var(--text-muted);
      letter-spacing: .01em;
      line-height: 1.2;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap
    }

    .profile-balance {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 12px;
      padding: 16px 18px;
      border-radius: 14px;
      border: 1px solid var(--glass-border);
      background: transparent;
      backdrop-filter: var(--glass-blur);
      margin-bottom: 18px;
    }

    .profile-balance .lbl {
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 11px;
      letter-spacing: .10em;
      color: var(--text-muted);
      text-transform: uppercase
    }

    .profile-balance .v {
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 24px;
      color: var(--text);
      display: inline-flex;
      align-items: center;
      gap: 10px;
      line-height: 1
    }

    .profile-balance .v .joy-coin {
      width: 1.7em;
      height: 1.7em
    }

    .profile-balance .balance-buy {
      margin-left: auto;
      height: 38px;
      padding: 0 16px;
      border-radius: 12px;
      background: linear-gradient(135deg, rgba(252, 166, 0, .30), rgba(252, 166, 0, .14));
      border: 1px solid rgba(252, 166, 0, .55);
      color: #fff;
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 12px;
      letter-spacing: .04em;
      text-transform: uppercase;
      cursor: pointer;
      line-height: 1;
      transition: transform .2s, background .25s, border-color .25s;
    }

    .profile-balance .balance-buy:hover {
      transform: translateY(-1px);
      background: linear-gradient(135deg, rgba(252, 166, 0, .42), rgba(252, 166, 0, .18));
      border-color: rgba(252, 166, 0, .8);
    }

    html[data-theme="day"] .profile-balance .balance-buy {
      color: #1a1305
    }

    .history-title {
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 11px;
      letter-spacing: .14em;
      color: var(--text-muted);
      text-transform: uppercase;
      margin: 0 0 10px;
      padding: 0 2px
    }

    .history-list {
      display: flex;
      flex-direction: column;
      gap: 6px;
      max-height: 280px;
      overflow-y: auto
    }

    .history-list::-webkit-scrollbar {
      width: 6px
    }

    .history-list::-webkit-scrollbar-thumb {
      background: var(--glass-border);
      border-radius: 3px
    }

    .h-row {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 10px 12px;
      border-radius: 10px;
      border: 1px solid var(--glass-border);
      background: transparent;
      backdrop-filter: blur(12px);
    }

    .h-row .h-thumb {
      width: 34px;
      height: 34px;
      border-radius: 8px;
      flex: none;
      overflow: hidden;
      position: relative
    }

    .h-row .h-thumb .art {
      position: absolute;
      inset: 0
    }

    .h-row .h-meta {
      flex: 1;
      min-width: 0;
      display: flex;
      flex-direction: column;
      gap: 3px
    }

    .h-row .h-prompt {
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 13px;
      color: var(--text);
      line-height: 1.2;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap
    }

    .h-row .h-sub {
      font-family: var(--font-display);
      font-weight: 600;
      font-size: 10px;
      letter-spacing: .10em;
      color: var(--text-muted);
      text-transform: uppercase;
      line-height: 1
    }

    .h-row .h-cost {
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 11px;
      letter-spacing: .04em;
      color: var(--text);
      display: inline-flex;
      align-items: center;
      gap: 5px;
      flex: none
    }

    .h-row .h-cost .joy-coin {
      width: 1.1em;
      height: 1.1em
    }

    /* New thumbnail grid for the profile history — shows actual generated
   media so the user sees their library, not a text list. */
    .h-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
      gap: 10px;
      max-height: 480px;
      overflow-y: auto;
      padding: 2px;
    }

    .h-grid::-webkit-scrollbar {
      width: 6px
    }

    .h-grid::-webkit-scrollbar-thumb {
      background: var(--glass-border);
      border-radius: 3px
    }

    .h-card {
      display: flex;
      flex-direction: column;
      border-radius: 12px;
      overflow: hidden;
      border: 1px solid var(--glass-border);
      background: var(--glass-bg);
      cursor: pointer;
      text-align: left;
      font: inherit;
      color: inherit;
      padding: 0;
      /* native button reset */
      text-decoration: none;
      color: inherit;
      transition: transform .2s, border-color .2s, box-shadow .2s;
    }

    .h-card:hover {
      transform: translateY(-2px);
      border-color: var(--glass-border-strong);
      box-shadow: 0 8px 30px -12px rgba(0, 0, 0, .5)
    }

    .h-card .h-media {
      width: 100%;
      aspect-ratio: 1/1;
      object-fit: cover;
      display: block;
      background: #0c0a18;
    }

    .h-card .h-placeholder {
      background: linear-gradient(135deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, .02));
    }

    .h-card video.h-media {
      aspect-ratio: 9/16
    }

    .h-card-info {
      padding: 8px 10px 10px;
      display: flex;
      flex-direction: column;
      gap: 6px;
    }

    .h-card-prompt {
      font-family: var(--font-display);
      font-weight: 600;
      font-size: 12px;
      color: var(--text);
      line-height: 1.35;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      overflow: hidden;
    }

    .h-card-row {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 6px
    }

    .h-card-meta {
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 9.5px;
      letter-spacing: .08em;
      color: var(--text-muted);
      text-transform: uppercase;
      line-height: 1;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      flex: 1;
    }

    .h-card-cost {
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 11px;
      color: var(--text);
      display: inline-flex;
      align-items: center;
      gap: 4px;
      flex: none;
      line-height: 1;
    }

    .h-card-cost .joy-coin {
      width: 1em;
      height: 1em
    }

    /* Studio tabs inside the account modal — top-level switcher between
   Visual Studio (active), Music, Vibe Code, Chat. Locked tabs show a
   "Soon" pill and stay visually muted. */
    .studio-tabs {
      display: flex;
      gap: 6px;
      flex-wrap: wrap;
      margin: 0 0 14px;
      padding: 6px;
      border-radius: 14px;
      background: var(--glass-bg);
      border: 1px solid var(--glass-border);
    }

    .studio-tab {
      flex: 1 1 auto;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 6px;
      padding: 8px 12px;
      border-radius: 10px;
      background: transparent;
      border: 1px solid transparent;
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 12px;
      letter-spacing: .04em;
      color: var(--text-muted);
      cursor: pointer;
      line-height: 1;
      transition: background .2s, color .2s, border-color .2s;
    }

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

    .studio-tab.on {
      background: var(--glass-bg-active);
      border-color: var(--glass-border-strong);
      color: var(--text);
    }

    .studio-tab.locked {
      opacity: .7;
      cursor: default
    }

    .studio-tab .st-soon {
      font-size: 9px;
      letter-spacing: .12em;
      padding: 3px 6px;
      border-radius: 999px;
      background: rgba(252, 166, 0, .14);
      color: #fca600;
      text-transform: uppercase;
      line-height: 1;
    }

    .studio-pane {
      display: none;
      margin-bottom: 12px
    }

    .studio-pane.on {
      display: block
    }

    /* Visual Studio sub-tabs — Photos / Videos */
    .vs-subtabs {
      display: inline-flex;
      gap: 4px;
      padding: 4px;
      border-radius: 999px;
      background: var(--glass-bg);
      border: 1px solid var(--glass-border);
      margin: 0 0 12px;
    }

    .vs-subtab {
      padding: 6px 14px;
      border-radius: 999px;
      background: transparent;
      border: none;
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 11px;
      letter-spacing: .06em;
      color: var(--text-muted);
      cursor: pointer;
      line-height: 1;
      transition: background .2s, color .2s;
    }

    .vs-subtab.on {
      background: var(--glass-bg-active);
      color: var(--text)
    }

    .vs-subtab:hover {
      color: var(--text)
    }

    .vs-pane {
      display: none
    }

    .vs-pane.on {
      display: block
    }

    /* Coming-soon panel for locked studios */
    .vs-coming {
      text-align: center;
      padding: 48px 24px;
      border: 1px dashed var(--glass-border-strong);
      border-radius: 16px;
      background: linear-gradient(135deg, rgba(252, 166, 0, .04), rgba(112, 72, 236, .04));
    }

    .vs-coming-ico {
      font-size: 32px;
      color: #fca600;
      margin-bottom: 12px
    }

    .vs-coming-h {
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 15px;
      letter-spacing: .04em;
      color: var(--text);
      margin-bottom: 8px;
    }

    .vs-coming-p {
      font-family: var(--font-body);
      font-weight: 600;
      font-size: 13.5px;
      color: var(--text-muted);
      line-height: 1.5;
      max-width: 380px;
      margin: 0 auto;
    }

    /* Sign-out button at top of profile — small, neutral, always visible */
    .profile-head {
      position: relative
    }

    .profile-head .signout-top {
      align-self: center;
      margin-left: auto;
      flex: none;
      padding: 7px 12px;
      border-radius: 8px;
      background: transparent;
      border: 1px solid var(--glass-border);
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 11px;
      letter-spacing: .06em;
      text-transform: uppercase;
      color: var(--text-muted);
      cursor: pointer;
      line-height: 1;
      transition: background .2s, color .2s, border-color .2s;
    }

    .profile-head .signout-top:hover {
      background: rgba(255, 80, 80, .10);
      border-color: rgba(255, 80, 80, .4);
      color: #ff8a8a;
    }

    html[data-theme="day"] .profile-head .signout-top:hover {
      background: rgba(220, 38, 38, .08);
      border-color: rgba(220, 38, 38, .35);
      color: #dc2626;
    }

    .profile-actions {
      display: flex;
      gap: 10px;
      margin-top: 18px;
      padding-top: 18px;
      border-top: 1px solid var(--glass-border)
    }

    .profile-actions button {
      flex: 1;
      padding: 12px 14px;
      border-radius: 12px;
      border: 1px solid var(--glass-border-strong);
      background: transparent;
      backdrop-filter: var(--glass-blur);
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 11.5px;
      letter-spacing: .04em;
      text-transform: uppercase;
      color: var(--text);
      line-height: 1;
    }

    .profile-actions button:hover {
      background: rgba(255, 255, 255, .06)
    }

    html[data-theme="day"] .profile-actions button:hover {
      background: rgba(0, 0, 0, .04)
    }

    .theme-toggle .ico {
      display: inline-grid;
      place-items: center;
      width: 24px;
      height: 24px;
      border-radius: 50%;
      background: rgba(255, 255, 255, .10);
      font-size: 12px;
      transition: transform .5s var(--ease-out);
    }

    .theme-toggle:hover .ico {
      transform: rotate(180deg)
    }

    @media (max-width:1180px) {
      .brand-name {
        font-size: 18px
      }

      .brand-name em {
        font-size: 11px;
        letter-spacing: .16em
      }

      .tab {
        padding: 0 12px;
        font-size: 11px;
        letter-spacing: .02em
      }

      .bal-amount,
      .bal-add,
      .theme-toggle {
        font-size: 11px
      }

      .tabs {
        width: min(480px, 50vw)
      }
    }

    @media (max-width:980px) {
      .header {
        flex-wrap: wrap;
        gap: 8px;
        padding: 12px 14px
      }

      .tabs {
        order: 3;
        width: 100%
      }

      .theme-toggle .lbl {
        display: none
      }

      .theme-toggle {
        padding: 0 10px
      }

      .bal-amount {
        padding: 0 12px;
        font-size: 11px
      }

      .bal-add {
        padding: 0 12px;
        font-size: 11px
      }

      .account-btn .lbl-create {
        font-size: 11px
      }

      .account-btn {
        padding: 0 12px
      }
    }

    @media (max-width:560px) {
      .account-btn .lbl-create {
        display: none
      }

      .account-btn::after {
        content: "+";
        font-size: 18px;
        font-weight: 800
      }

      .account-btn.signed::after {
        display: none
      }
    }

    @media (max-width:560px) {
      .brand .joy-coin {
        width: 30px;
        height: 30px
      }

      .brand-name {
        font-size: 14px
      }

      .brand-name em {
        font-size: 9px
      }

      .header {
        padding: 10px 12px;
        gap: 6px
      }

      .h-right {
        gap: 6px
      }

      .bal-card {
        height: 40px
      }

      .bal-amount {
        padding: 0 10px
      }

      .bal-add {
        padding: 0 10px
      }

      .icon-btn {
        width: 40px;
        height: 40px
      }

      .theme-toggle {
        height: 40px;
        padding: 0 10px
      }

      .tabs {
        height: 40px
      }
    }


/* ════════════════════════════════════════════════════════════════════
   BAL-CARD COMPACT VERTICAL DROPDOWN (b.428).
   Extracted in b.852. 1133 lines moved from index.html top inline <style>
   (was lines 1439-2570 in b.851). The wallet balance card dropdown that
   appears when MY COINS pill is clicked in the top bar. Universal — used
   across all surfaces. Also includes related .btn-create + .bc-cost rules
   for the Create button cost-strip styling.
   ════════════════════════════════════════════════════════════════════ */

    /* ============================================================
   2026-05-12 b.428 — Compact vertical bal-card dropdown.
   Was a wide horizontal pill (44px tall, ~280px wide) that felt
   visually divorced from the small MY COINS tab pill above it.
   Redesigned as a compact card hanging UNDER the pill — same
   148px width as the pill, vertically stacked:
     • Joy Coin icon (slightly larger, gentle bob animation)
     • Featured balance number (big, bold, hero element)
     • "JOY COINS" label (small, uppercase, muted)
     • Thin glass divider
     • Animated "+ BUY COINS" CTA stretched across the full width
   A soft amber-tinted radial glow sits behind the number so the
   card has its own subtle ambient light source independent of the
   page bg, matching the "Joy Coin" brand colour. Slide-in
   animation makes the dropdown feel like a natural extension of
   the pill rather than a separate floating panel. */
    body:not(.coins-collapsed) .bal-card:not(.signed-out) {
      position: fixed !important;
      /* 2026-05-12 b.432 — Card now REPLACES the MY COINS pill in place
     instead of opening below it. Same right anchor + same width as
     the pill (148px) so there's no dead space at the top — the card
     is the pill, expanded. The pill's tucked-tab is hidden via the
     rule below so they don't collide.
     2026-05-12 b.433 — top bumped 0 → 4 to leave a hint of breathing
     room between the viewport edge and the card.
     2026-05-12 b.436 — z-index pushed to 9999 so the dropdown is
     the absolute master layer — every modal, every popover, every
     overlay paints BEHIND it. Nothing can land on top. */
      top: 4px !important;
      right: 236px !important;
      left: auto !important;
      z-index: 9999 !important;
      width: 148px !important;
      min-width: 148px !important;
      height: auto !important;
      display: flex !important;
      flex-direction: column !important;
      align-items: stretch !important;
      padding: 0 !important;
      gap: 0 !important;
      /* 2026-05-12 b.430 — Real liquid-glass recipe per user spec. No
     opaque dark base layer — colour comes from the blurred bg, not
     from a tint stacked on top. Heavy blur + saturate so the page
     bg's hues come through, layered insets give the glass its
     top/bottom edge lighting, and a soft drop carries the card
     visually away from the page behind it. */
      background: rgba(255, 255, 255, .08) !important;
      border: 1px solid rgba(255, 255, 255, .22) !important;
      -webkit-backdrop-filter: blur(40px) saturate(1.8) brightness(1.05) !important;
      backdrop-filter: blur(40px) saturate(1.8) brightness(1.05) !important;
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .30) inset,
        0 -1px 0 rgba(0, 0, 0, .12) inset,
        0 24px 60px -12px rgba(0, 0, 0, .55) !important;
      border-radius: 16px !important;
      overflow: hidden !important;
      isolation: isolate !important;
      animation: balCardDrop .28s cubic-bezier(.2, .8, .2, 1);
    }

    @keyframes balCardDrop {
      from {
        opacity: 0;
        transform: translateY(-8px) scale(.96);
      }

      to {
        opacity: 1;
        transform: none;
      }
    }

    /* 2026-05-12 b.432 — Inner content tightened to fit the new 148px
   card width. Coin icon a touch smaller, number stays the hero
   element at 20px (was 22), label trimmed to 9px with tighter
   tracking. Still: number + "Joy Coins" baseline-aligned on the
   same line via .bal-row. Padding pulled in for a more compact
   feel that matches the pill geometry. */
    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-amount {
      position: relative !important;
      display: flex !important;
      flex-direction: column !important;
      align-items: center !important;
      justify-content: center !important;
      gap: 6px !important;
      padding: 14px 10px 12px !important;
      background: transparent !important;
      border: 0 !important;
      border-radius: 0 !important;
      height: auto !important;
      line-height: 1 !important;
      white-space: normal !important;
    }

    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-amount::before {
      content: none !important;
    }

    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-amount .joy-coin {
      width: 28px !important;
      height: 28px !important;
      margin: 0 !important;
      animation: balCoinFloat 4.2s ease-in-out infinite;
      filter: drop-shadow(0 4px 10px rgba(0, 0, 0, .30));
    }

    @keyframes balCoinFloat {

      0%,
      100% {
        transform: translateY(0) rotate(-2deg);
      }

      50% {
        transform: translateY(-2px) rotate(2deg);
      }
    }

    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-amount .bal-row {
      display: inline-flex !important;
      align-items: baseline !important;
      gap: 6px !important;
      white-space: nowrap !important;
      line-height: 1 !important;
    }

    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-amount .bal-row .num {
      font-family: var(--font-display) !important;
      font-size: 20px !important;
      font-weight: 800 !important;
      letter-spacing: -0.02em !important;
      line-height: 1 !important;
      text-transform: none !important;
      color: #fff !important;
      display: inline-block !important;
      margin: 0 !important;
      min-width: 0 !important;
      text-shadow: 0 1px 8px rgba(255, 255, 255, .10);
    }

    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-amount .bal-row .bal-label {
      font-family: var(--font-display) !important;
      font-size: 9px !important;
      font-weight: 800 !important;
      letter-spacing: .14em !important;
      text-transform: uppercase !important;
      color: rgba(255, 255, 255, .72) !important;
      line-height: 1 !important;
      display: inline-block !important;
    }

    /* 2026-05-12 b.432 — Hide the MY COINS tucked pill while the
   bal-card is visible. The card now sits at top:0 in the pill's
   space and visually takes its place — leaving the pill visible
   on top would create the dead-space artefact the user flagged. */
    body:not(.coins-collapsed) .coins-menu-pill {
      display: none !important;
    }

    /* Bottom CTA — Buy coins stretched across the full card width.
   2026-05-12 b.439 — MAXIMALLY AGGRESSIVE green-strip. The previous
   pass missed two leakage points:
     1. Base `[data-theme] .bal-add` at line ~14773 sets `border:1px
        solid rgba(255,255,255,.20)` — a full four-sided border with
        20% white. Over a green Garden bg the 80%-transparent border
        renders as green. Old override only zeroed border-left, so
        right + bottom + top still showed green.
     2. The orb shimmer `::before` was nulled via `content:none` but
        the base rule's `content:'' !important` lives at higher
        specificity than I thought when factoring the entire chain.
        Belt + braces: content:none + display:none + visibility:
        hidden + opacity:0.
   New rules zero EVERY border and pseudo-painted layer, then re-add
   ONE divider on the top edge using a slightly heavier white so the
   line stays white-tinted instead of picking up Garden green via
   backdrop-filter saturation. */
    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-add {
      width: 100% !important;
      height: 36px !important;
      /* Zero ALL borders first, then re-add only the top divider.
     2026-05-12 b.443 — Divider opacity bumped 28% → 70% white. At
     28% the 72%-transparent border was letting the card's saturated
     green bg show through (backdrop-filter: saturate(1.8) over the
     Garden theme bg), so the line read green on hover. 70% white is
     opaque enough that no green can bleed through — it stays white
     regardless of bg. outline:0 added so no browser focus ring can
     paint a coloured stroke either. */
      border: 0 !important;
      border-top: 1px solid rgba(255, 255, 255, .70) !important;
      border-radius: 0 !important;
      outline: 0 !important;
      padding: 0 14px !important;
      font-family: var(--font-display) !important;
      font-size: 10.5px !important;
      letter-spacing: .12em !important;
      text-transform: uppercase !important;
      font-weight: 800 !important;
      display: inline-flex !important;
      align-items: center !important;
      justify-content: center !important;
      background: transparent !important;
      background-image: none !important;
      -webkit-backdrop-filter: none !important;
      backdrop-filter: none !important;
      box-shadow: none !important;
      color: #fff !important;
      text-shadow: 0 1px 2px rgba(0, 0, 0, .35) !important;
    }

    /* Kill the animated orb-coloured gradient pseudo — every which way.
   The base rule generates this with `content:''` !important; layering
   five kill switches (content:none, display:none, visibility:hidden,
   background:none, opacity:0) leaves no path for it to paint. */
    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-add::before,
    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-add::after {
      content: none !important;
      display: none !important;
      visibility: hidden !important;
      background: none !important;
      background-image: none !important;
      animation: none !important;
      opacity: 0 !important;
    }

    /* Hover: a soft white wash only — no colour, no transform, no
   bleed-through. border-color matches the base state's .70 so the
   divider stays consistently white on hover (was bumping back to
   28% via the older value, which let the green bg leak through). */
    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-add:hover {
      background: rgba(255, 255, 255, .06) !important;
      background-image: none !important;
      transform: none !important;
      box-shadow: none !important;
      border-color: rgba(255, 255, 255, .70) !important;
      outline: 0 !important;
    }

    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-add:hover::before,
    body:not(.coins-collapsed) .bal-card:not(.signed-out) .bal-add:hover::after {
      content: none !important;
      display: none !important;
      visibility: hidden !important;
      opacity: 0 !important;
      animation: none !important;
    }

    /* Mode pill — never wraps; one line. */
    [data-theme] .mode-pill,
    [data-theme] .mode-pill-top {
      white-space: nowrap !important;
      height: 44px !important;
      padding: 0 18px !important;
      display: inline-flex !important;
      align-items: center !important;
    }

    [data-theme] .mode-pill .mp-name,
    [data-theme] .mode-pill-top .mp-name {
      white-space: nowrap !important
    }

    /* 2026-05-08 v38 — children sit flush inside the unified .bal-card.
   No individual glass, no individual borders — they share the shell. */
    [data-theme] .bal-card .bal-amount {
      display: inline-flex !important;
      align-items: center !important;
      gap: 8px !important;
      padding: 0 14px 0 12px !important;
      height: 100% !important;
      background: transparent !important;
      border: 0 !important;
      -webkit-backdrop-filter: none !important;
      backdrop-filter: none !important;
      box-shadow: none !important;
      border-radius: 0 !important;
      white-space: nowrap !important;
      color: #fff !important;
      font-weight: 500 !important;
    }

    /* 2026-05-10 b.208 — Buy coins is now liquid glass with a slow,
   theme-driven colour shimmer behind it. The previous flat
   white-tint fill always read as solid; this version uses a
   transparent shell + animated gradient pseudo that pulls from the
   active theme's orb palette (--orb-1 / --orb-3 / --orb-5), so the
   button feels alive and matches whatever background is in play. */
    [data-theme] .bal-card .bal-add {
      position: relative !important;
      isolation: isolate !important;
      /* contain ::before stacking */
      height: 100% !important;
      background: transparent !important;
      border: 0 !important;
      border-left: 1px solid var(--lg-stroke, rgba(255, 255, 255, .20)) !important;
      -webkit-backdrop-filter: var(--lg-blur, blur(18px) saturate(1.4)) !important;
      backdrop-filter: var(--lg-blur, blur(18px) saturate(1.4)) !important;
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .16) inset,
        0 -1px 0 rgba(0, 0, 0, .12) inset !important;
      border-radius: 0 !important;
      padding: 0 16px !important;
      white-space: nowrap !important;
      color: #fff !important;
      font-weight: 500 !important;
      cursor: pointer !important;
      overflow: hidden !important;
      text-shadow: 0 1px 2px rgba(0, 0, 0, .35);
      transition: transform .15s ease, box-shadow .15s ease !important;
    }

    /* Animated theme-coloured shimmer. Pulls from the orb palette so the
   button takes on the same hues that drift behind the rest of the
   UI; falls back to amber → pink → violet for old themes that don't
   define orb vars. */
    [data-theme] .bal-card .bal-add::before {
      content: '' !important;
      position: absolute !important;
      inset: 0 !important;
      z-index: -1 !important;
      background: linear-gradient(135deg,
          color-mix(in srgb, var(--orb-1, #fca600) 38%, transparent),
          color-mix(in srgb, var(--orb-3, #ff8fb8) 28%, transparent),
          color-mix(in srgb, var(--orb-5, #c08fff) 38%, transparent),
          color-mix(in srgb, var(--orb-1, #fca600) 38%, transparent));
      background-size: 300% 300%;
      animation: balAddShimmer 9s ease-in-out infinite;
      opacity: .85;
      pointer-events: none;
    }

    @keyframes balAddShimmer {
      0% {
        background-position: 0% 50%;
      }

      50% {
        background-position: 100% 50%;
      }

      100% {
        background-position: 0% 50%;
      }
    }

    [data-theme] .bal-card .bal-add:hover {
      transform: translateY(-1px) !important;
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .22) inset,
        0 -1px 0 rgba(0, 0, 0, .14) inset,
        0 6px 18px -6px rgba(0, 0, 0, .40) !important;
    }

    [data-theme] .bal-card .bal-add:hover::before {
      opacity: 1 !important;
      animation-duration: 4.5s !important;
      /* speed up on hover */
    }

    [data-theme] .bal-card.signed-out {
      /* Signed-out — Buy coins is a standalone pill. The shell still
     gets the glass treatment from .bal-card; the inner button
     loses the divider line so the shimmer fills the whole pill. */
      background: var(--lg-fill) !important;
      border: 1.5px solid var(--lg-stroke) !important;
    }

    [data-theme] .bal-card.signed-out .bal-add {
      border-left: 0 !important;
    }

    /* Story-head no bottom-border — was rendering as a horizontal line. */
    [data-theme] .story-head {
      border-bottom: 0 !important;
      padding-bottom: 0 !important;
      display: flex !important;
      align-items: center !important;
      gap: 14px !important;
      flex-wrap: nowrap !important;
    }

    /* Story title input lives at the left, format/engine in the middle,
   My library pinned to the right. */
    [data-theme] .story-head .story-title-input {
      margin-right: auto !important
    }

    /* 2026-05-07 — Story mode cleanup
   Strip every residual container outline behind the scene strip and
   hide the standard-mode Describe + Create row (story has the
   Director default bar instead). */
    [data-theme] body.in-story-mode .story-board,
    [data-theme] body.in-story-mode .story-scroll,
    [data-theme] body.in-story-mode .story-board.active,
    body.in-story-mode .story-board,
    body.in-story-mode .story-scroll,
    body.in-story-mode .story-board.active {
      background: transparent !important;
      border: 0 !important;
      box-shadow: none !important;
      -webkit-backdrop-filter: none !important;
      backdrop-filter: none !important;
    }

    /* 2026-05-09 v83 — Director on/off bar swap WITHOUT layout shift.
   Was: `display:none` on .input-shell when director-default-on is set,
   so flipping director off made the input-shell suddenly appear and
   push the centred scene card upward. The user flagged this as the
   card "jumping" on Director Mode toggle.
   Now: stack the director-default-bar and input-shell in the same
   grid cell. Both reserve the same height; only one is visible at
   a time via visibility-hidden on the inactive surface. The .input-bar
   total height = max(director-pill, input-shell) regardless of which
   mode is active, so the card above it stays rock-stable. */
    body.in-story-mode .input-bar {
      display: grid !important;
      grid-template-areas: 'stack' !important;
      /* 2026-05-09 v90 — grid-template-columns: 1fr is REQUIRED here.
     Without it, grid-template-areas alone creates a 1-column grid
     where the column defaults to `auto` (content size), which made
     .input-shell collapse to the width of its narrowest content
     instead of filling the full bar. The user kept seeing the
     textbox / pill row rendering at ~600px even on a 1900px viewport
     because of this. 1fr forces the column to fill the parent's
     width, .input-shell's max-width:1100px + margin-inline:auto
     then re-centres it inside that full-width column — exactly the
     same look as the home screen's standard-mode bar. */
      grid-template-columns: 1fr !important;
      align-items: end !important;
    }

    /* 2026-05-09 v89 — Extend the stack to ALL siblings of .input-shell
   inside .input-bar. Without this, .manual-return-btn and
   .director-summary auto-place into NEW grid rows when un-hidden,
   adding 30+ px to the bar — which is the residual director-on /
   director-off vertical jump the user was still seeing after v83.
   Now everything stacks in the same cell, all anchored to the bottom
   via align-items: end on the bar. align-self overrides peel the
   summary chips up and the manual-return label down so they don't
   visually collide with the input-shell. */
    body.in-story-mode .input-bar>.director-default-bar,
    body.in-story-mode .input-bar>.input-shell,
    body.in-story-mode .input-bar>.manual-return-btn,
    body.in-story-mode .input-bar>.director-summary,
    body.in-story-mode .input-bar>.video-tip {
      grid-area: stack !important;
    }

    /* 2026-05-09 v91 — Force the input-shell to stretch to the FULL column
   width. .input-shell has `margin-inline: auto` in its base CSS, and
   per CSS Grid spec, a grid item with ANY auto margin is treated as
   "do not stretch" — so the shell was sizing to its min-content width
   (~600-700px) instead of filling the 1fr column. THIS is the actual
   reason the user kept seeing a narrow centred bar instead of the
   wide expansive bar the home screen has. width:100% + justify-self:
   stretch override the auto-margin opt-out; max-width:1100px in the
   base CSS still caps the visible glass at the same width as the home
   screen, and margin-inline:auto re-centres it within the full-width
   cell. */
    body.in-story-mode .input-bar>.input-shell {
      width: 100% !important;
      justify-self: stretch !important;
      align-self: end !important;
    }

    body.in-story-mode .input-bar>.director-default-bar {
      width: 100% !important;
      justify-self: stretch !important;
      align-self: end !important;
    }

    body.in-story-mode .input-bar>.director-summary {
      align-self: start !important;
      /* chips ride above the shell */
      justify-self: stretch !important;
      pointer-events: auto;
    }

    body.in-story-mode .input-bar>.manual-return-btn {
      align-self: end !important;
      justify-self: center !important;
      /* small label centred under bar */
    }

    body.in-story-mode.director-default-on .input-shell,
    body.in-story-mode.director-default-on .input-row,
    body.in-story-mode.director-default-on .input-shell .controls {
      visibility: hidden !important;
      pointer-events: none !important;
    }

    /* 2026-05-09 v88 — PIN the scene card without inflating the bar.
   v87 set min-height:140px on .input-bar, which pushed the bar
   taller than its natural ~108px and shifted the centred scene card
   UP from where it had been sitting. The user wanted the card
   pinned where it ALREADY was — stable, but NOT moved.
   Correct fix: stabilise only the things that VARY between phases,
   at their NATURAL sizes. Don't add over-reservation:
     • .controls — keeps its 44px height even when empty (otherwise
       the strip collapses to 0 in image-set/done phase, shrinking
       the shell and shifting the card down).
     • .input-row — kept in layout via visibility:hidden (handled by
       JS in setStoryToolbarPhase), so its 64px reservation persists
       through phases that hide the textbox.
   With both rows reserved at their natural sizes, .input-shell's
   outer height stays constant at ~108px, the v83 grid-stack keeps
   .input-bar locked at that value, story-board's flex:1 absorbs the
   same remainder every time, and the card stays pinned. */
    body.in-story-mode .input-shell .controls {
      min-height: 32px;
      /* tighter than the 44px default */
      margin-bottom: -27px;
      /* pull input-row up in flex flow  */
      transform: translateY(10px) translateX(5px) !important;
      /* visual nudge: 10px down, 5px right — bypasses layout */
    }

    /* 2026-05-08 — Story mode: bottom bar (input + director default) is
   COMPLETELY hidden until the user picks Add first frame OR
   Generate first frame on the scene card. body.story-action-chosen
   is toggled by setStoryToolbarPhase based on phase. */
    /* 2026-05-09 v78 — Hide-the-bottom-bar-pre-action.
   Was: `display:none` which removed the bar from layout entirely. The
   problem: the centered scene card lived in the space ABOVE the bar.
   When the user picked Generate (and the bar reappeared) the available
   vertical space shrank and the card jumped up — exactly the "card
   moving from its original place" bug the user flagged.
   Now: keep the bar in layout but hide it visually. Same height
   reserved either way → card position is rock-stable across the
   empty → image-prompt transition. */
    body.in-story-mode:not(.story-action-chosen) .input-bar,
    body.in-story-mode:not(.story-action-chosen) .input-shell,
    body.in-story-mode:not(.story-action-chosen) .input-row,
    body.in-story-mode:not(.story-action-chosen) .director-default-bar,
    body.in-story-mode:not(.story-action-chosen) .director-summary {
      visibility: hidden !important;
      pointer-events: none !important;
    }

    /* Director default bar (the pulsating pill that floats at the
   bottom of story mode) keeps its own glass treatment from earlier. */

    /* 2026-05-07 — when Director console is OPEN, hide EVERY UI surface
   on the page (header, story board, input bar, gallery, chat,
   director summary, default bar) so only the moving theme video sits
   behind the modal. The console glass refracts a clean canvas. */
    /* 2026-05-08 v18 — added :not(.cast-modal):not(.cinema-modal):not(.modal-back)
   to the director-open hide list. Without it, modals that portal to
   <body> (Create Character / Create Space, sign-in, packs) inherit
   visibility:hidden and silently disappear behind the director
   console even though their z-index is higher than .director-modal.
   That was the root cause of the "Create character opens behind
   everything" report. */
    body.director-open>*:not(.bg-stage):not(.director-modal):not(.cast-modal):not(.cinema-modal):not(.stitch-modal):not(.modal-back):not(.story-cost-popover):not(.modes-screen):not(script):not(style),
    body.director-open .header,
    body.director-open .story-board,
    body.director-open .story-board.active,
    body.director-open .story-head,
    body.director-open .director-default-bar,
    body.director-open .director-summary,
    body.director-open .input-bar,
    body.director-open .chat,
    body.director-open .gallery,
    body.director-open main,
    body.director-open footer {
      visibility: hidden !important;
      pointer-events: none !important;
    }

    body.director-open .director-modal,
    body.director-open .cast-modal,
    body.director-open .cinema-modal,
    body.director-open .stitch-modal {
      visibility: visible !important;
      pointer-events: auto !important;
    }

    /* 2026-05-08 v22 — modal-back ONLY participates when its `.show`
   class is set (matches the base behaviour). The previous v18 rule
   forced visibility:visible + pointer-events:auto on every
   .modal-back when director was open, which made the empty 1470x835
   backdrop sit on top of the entire director console and eat every
   click. That was the "console jammed" report — now fixed. */
    body.director-open .modal-back.show {
      visibility: visible !important;
      pointer-events: auto !important;
      z-index: 112 !important;
    }

    /* Cast modal stacks above the director console when both are visible. */
    body.director-open .cast-modal {
      z-index: 110 !important
    }

    /* 2026-05-07 — Strip residual amber tint from every director surface.
   Replace any remaining amber (--story-accent / 184,115,51 / 232,176,74)
   with neutral white-glass stroke + theme-tinted glow. */
    [data-theme] .director-modal-v2 .dm-roster-card,
    [data-theme] .director-modal-v2 .dm-param-card,
    [data-theme] .director-modal-v2 .dm-context-card,
    [data-theme] .director-modal-v2 .dm-tile,
    [data-theme] .director-modal .dm-shell,
    [data-theme] .director-modal-v2 .dm-shell-v2,
    [data-theme] .director-modal .dm-prompt-text,
    [data-theme] .director-modal .dm-co-input,
    [data-theme] .director-modal-v2 .dm-co-director-v2 .dm-co-input {
      border-color: var(--lg-stroke) !important;
    }

    [data-theme] .director-modal-v2 .dm-roster-card.has-cast,
    [data-theme] .director-modal-v2 .dm-roster-card.has-space,
    [data-theme] .director-modal-v2 .dm-param-card.has-value {
      border-color: var(--lg-stroke-hi) !important;
      background:
        radial-gradient(120% 100% at 30% 0%, var(--active-tint), transparent 70%),
        var(--lg-fill) !important;
      box-shadow:
        var(--lg-shadow),
        0 0 22px var(--active-glow) !important;
    }

    /* Intensify the glass pane density inside the director — currently
   reads weak. Bumping the fill opacity + saturate so each pane has
   real presence against the moving theme video. */
    [data-theme] .director-modal-v2 .dm-roster-card,
    [data-theme] .director-modal-v2 .dm-param-card,
    [data-theme] .director-modal-v2 .dm-context-card,
    [data-theme] .director-modal-v2 .dm-tile,
    [data-theme] .director-modal-v2 .dm-prompt-shell-v2,
    [data-theme] .director-modal .dm-prompt-shell {
      background: rgba(255, 255, 255, .10) !important;
      -webkit-backdrop-filter: blur(28px) saturate(1.45) brightness(1.04) !important;
      backdrop-filter: blur(28px) saturate(1.45) brightness(1.04) !important;
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .55) inset,
        0 -1px 0 rgba(255, 255, 255, .18) inset,
        0 0 0 1px rgba(255, 255, 255, .12) inset,
        0 24px 60px -22px rgba(0, 0, 0, .65) !important;
    }

    [data-theme] .director-modal-v2 .dm-roster-card.has-cast,
    [data-theme] .director-modal-v2 .dm-roster-card.has-space,
    [data-theme] .director-modal-v2 .dm-param-card.has-value {
      background:
        radial-gradient(120% 100% at 30% 0%, var(--active-tint), transparent 70%),
        rgba(255, 255, 255, .12) !important;
    }

    /* Scene Context — own row, FULL width. Movement + Pacing share the
   row above; Scene Context spans both columns underneath. */
    [data-theme] .director-modal-v2 .dm-deck-row-context {
      display: grid !important;
      grid-template-columns: 1fr 1fr !important;
      gap: 16px !important;
    }

    [data-theme] .director-modal-v2 .dm-context-card {
      grid-column: 1 / -1 !important;
      width: 100% !important;
    }

    @media (max-width:760px) {
      [data-theme] .director-modal-v2 .dm-deck-row-context {
        grid-template-columns: 1fr !important;
      }
    }

    /* 2026-05-07 — Prompt preview accordion fix.
   When opened, the textarea was expanding and overflowing the modal,
   clipping the Camera row above and pushing the footer off-screen.
   Cap the textarea height + make the modal shell scroll when its
   content exceeds the viewport. */
    [data-theme] .director-modal {
      overflow-y: auto !important;
    }

    [data-theme] .director-modal .dm-shell,
    [data-theme] .director-modal-v2 .dm-shell-v2 {
      margin: 24px auto !important;
      max-height: none !important;
      overflow: visible !important;
    }

    [data-theme] .director-modal .dm-prompt-shell,
    [data-theme] .director-modal-v2 .dm-prompt-shell-v2 {
      position: relative !important;
      /* stay in normal flow */
      flex-shrink: 0 !important;
    }

    [data-theme] .director-modal-v2 .dm-prompt-shell-v2[open] .dm-prompt-text,
    [data-theme] .director-modal .dm-prompt-shell[open] .dm-prompt-text,
    [data-theme] .director-modal .dm-prompt-text {
      max-height: 200px !important;
      min-height: 100px !important;
      resize: vertical !important;
      overflow-y: auto !important;
    }

    [data-theme] .director-modal-v2 .dm-prompt-shell-v2 .dm-prompt-body,
    [data-theme] .director-modal .dm-prompt-shell .dm-prompt-body {
      max-height: 280px !important;
      overflow: hidden !important;
    }

    /* 9:16 / 16:9 dim toggle — kill the legacy solid amber active fill;
   match the universal liquid-glass active state. */
    [data-theme] .toggle-grp[data-grp="dim"] button.on,
    [data-theme] .toggle-grp[data-grp="dim"] button[aria-pressed="true"] {
      background:
        radial-gradient(120% 100% at 30% 0%, var(--active-tint), transparent 70%),
        var(--lg-fill) !important;
      border: 1.5px solid var(--lg-stroke-hi) !important;
      color: #fff !important;
      -webkit-backdrop-filter: var(--lg-blur) !important;
      backdrop-filter: var(--lg-blur) !important;
    }

    /* 2026-05-07 — SILENT / SOUND single-button toggle.
   Hide the inactive option so only one button is visible at a time.
   Click handler in JS (singleSoundToggle) flips state.sound between
   'on' and 'off' and syncSoundToggle() swaps which button has .on. */
    [data-theme] .toggle-grp[data-grp="sound"] button:not(.on) {
      display: none !important;
    }

    /* 2026-05-08 v37 — apply the same single-button pattern to QUALITY
   (SD↔HD) and DIM (9:16↔16:9). Both <button>s stay in the DOM (so
   wireToggle's existing handler logic doesn't break), but only the
   active one is visible. The user clicks the visible button to flip
   to the other state — the IIFEs below wire that flip.
   v39 — DURATION cycles 5s → 10s → 15s → 5s on the same single button. */
    [data-theme] .toggle-grp[data-grp="quality"] button:not(.on),
    [data-theme] .toggle-grp[data-grp="dim"] button:not(.on),
    [data-theme] .toggle-grp[data-grp="duration"] button:not(.on) {
      display: none !important;
    }

    /* 2026-05-08 v48 — @-tag autocomplete dropdown for story prompt.
   Floats above the prompt textarea; lists cast + spaces + areas.
   Same liquid-glass treatment as dm-popover for visual consistency. */
    .soj-tag-drop {
      position: fixed;
      z-index: 220;
      max-height: 240px;
      overflow-y: auto;
      border-radius: 14px;
      background: var(--lg-fill, rgba(255, 255, 255, .06));
      border: 1.5px solid var(--lg-stroke, rgba(255, 255, 255, .22));
      -webkit-backdrop-filter: var(--lg-blur, blur(22px) saturate(1.3) brightness(1.04));
      backdrop-filter: var(--lg-blur, blur(22px) saturate(1.3) brightness(1.04));
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .45) inset,
        0 -1px 0 rgba(255, 255, 255, .18) inset,
        0 24px 60px -22px rgba(0, 0, 0, .55);
      padding: 6px;
    }

    .soj-tag-drop[hidden] {
      display: none !important;
    }

    .soj-tag-row {
      display: grid;
      grid-template-columns: 22px 1fr auto;
      align-items: center;
      gap: 10px;
      width: 100%;
      padding: 9px 10px;
      background: transparent;
      border: 0;
      border-radius: 10px;
      color: #fff;
      font-family: inherit;
      font-size: 13px;
      text-align: left;
      cursor: pointer;
    }

    .soj-tag-row:hover {
      background: rgba(255, 255, 255, .08);
    }

    .soj-tag-ico {
      font-size: 16px;
      line-height: 1;
    }

    .soj-tag-lbl {
      font-weight: 500;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .soj-tag-sub {
      font-size: 11px;
      color: rgba(255, 255, 255, .55);
    }

    .soj-tag-empty {
      padding: 14px 12px;
      font-size: 12px;
      color: rgba(255, 255, 255, .65);
      text-align: center;
      font-style: italic;
    }

    /* 2026-05-12 b.348 — Mode tiles are now compact glass menu rows, not
   photo cards. The earlier theme-accent border/arrow rules belong to
   the retired full-screen picker; the new base block handles all the
   tile look. Kept as no-op placeholders so older selectors still
   resolve without surprises elsewhere. */
    [data-theme] .mode-tile {
      /* base block in earlier CSS handles the new look */
    }

    [data-theme] .mode-tile:hover {
      /* base block handles the hover */
    }

    [data-theme] .mode-tile .mt-arrow {
      display: none !important;
    }

    [data-theme] .mode-tile:hover .mt-arrow {
      display: none !important;
    }

    /* 2026-05-07 — Story layout:
     • Story-head (Enter story name + Format + Engine + My library)
       sits at the TOP, full-width, title pinned left, library pinned
       right (justify-content: space-between handles the gap).
     • Scene strip occupies the remaining space and vertically centres
       the cards, anchored to the LEFT.
     • Story-board absorbs all available height via flex:1. */
    [data-theme] .story-board.active {
      flex: 1 1 auto !important;
      display: flex !important;
      flex-direction: column !important;
      justify-content: flex-start !important;
      min-height: 0 !important;
    }

    [data-theme] .story-head {
      flex: 0 0 auto !important;
      display: flex !important;
      align-items: center !important;
      justify-content: space-between !important;
      /* title left, library right */
      gap: 14px !important;
      /* 2026-05-09 v63 — Match the header padding (18px 22px 12px) exactly
     so the story-title input lines up with the "Shades of Joy" wordmark
     on the left edge, and the My library button lines up with the theme
     button on the right edge. The previous clamp(20px,4vw,64px) pushed
     both inwards on wide viewports, breaking the visual grid. */
      padding: 6px 22px 0 !important;
      margin: 0 !important;
    }

    /* Story-board itself has zero top padding so the head sits flush
   against the header bar above. */
    [data-theme] .story-board.active {
      padding-top: 0 !important
    }

    [data-theme] .story-head .story-title-input {
      margin-right: auto !important
    }

    [data-theme] .story-head .my-stories-btn {
      margin-left: auto !important
    }

    /* Scene strip — fill remaining vertical space, cards vertically
   centred inside. b.785 — REVERTED the b.727/b.730 full-bleed change:
   pinning cards to flex-start with first-child margin made a single
   scene card look hard-pinned to the left edge on wide viewports
   (originally it sat centred). Restored to centred layout with the
   original padding-inline budget, exactly matching pre-b.727
   behaviour. When the strip overflows, the container still scrolls
   normally (overflow-x:auto on the base rule); cards just visually
   centre when they fit. */
    [data-theme] .story-board.active .story-scroll {
      flex: 1 1 auto !important;
      display: flex !important;
      align-items: center !important;
      justify-content: flex-start !important;
      padding: 0 !important;
      scroll-padding-inline: 22px !important;
      margin: 0 !important;
      min-height: 0 !important;
    }

    [data-theme] .story-scroll .scene-card {
      margin: 0 !important
    }

    /* b.806 — RE-APPLIED b.727/b.730 left-aligned scroll. b.805 reverted
       to center-justified at the user's request after a screenshot showed
       the card pinned left, but the user clarified that LEFT-aligned IS
       the original correct position they want — center looked wrong.
       Restoring flex-start + edge margins so the first card sits flush-
       left with a 22px breathing margin, and the last card has the same
       margin on the right so the scroll surface feels balanced. */
    [data-theme] .story-scroll > .scene-card:first-child {
      margin-left: 22px !important
    }

    [data-theme] .story-scroll > .scene-card:last-child {
      margin-right: 22px !important
    }

    /* b.814 — NUDGE CARD DOWN 30PX. The b.811 margin-block: auto attempt
       resolved to 0 because the scroll container is sized to the card's
       intrinsic height (no leftover space for auto margins to distribute).
       User wants a literal 30px downward offset, so using a fixed margin-top
       which doesn't depend on container height computation. */
    [data-theme] .story-scroll > .scene-card {
      margin-top: 30px !important;
    }

    /* 2026-05-07 — Hide scene strip until the user picks a format.
   2026-05-08 v2 — Bumped specificity. The previous rule
   `body.in-story-mode:not(.format-chosen) .story-scroll` was (0,0,3,1)
   and lost to `[data-theme] .story-board.active .story-scroll` (0,0,4,0)
   which forces display:flex !important. Adding [data-theme] +
   .story-board.active climbs to (0,0,6,1) and wins. We also explicitly
   hide .scene-card so even if some renderer slips a card OUTSIDE
   .story-scroll (defensive belt-and-braces), it stays hidden too. */
    [data-theme] body.in-story-mode:not(.format-chosen) .story-board.active .story-scroll,
    [data-theme] body.in-story-mode:not(.format-chosen) .story-board.active .scene-card,
    [data-theme] body.in-story-mode:not(.format-chosen) .story-scroll,
    [data-theme] body.in-story-mode:not(.format-chosen) .scene-card {
      display: none !important;
    }

    /* 2026-05-08 — Format hint moved out of the scene canvas and anchored
   directly UNDER the story-head row (Format · Engine · My library), so
   it lives in the same visual cluster the user just looked at. Show
   only AFTER the user has typed a name AND before they pick a format.
   Right-aligned to sit directly beneath the My library / Engine /
   Format chips on the right edge. */
    body.in-story-mode.story-has-name:not(.format-chosen) .story-board.active .story-head {
      position: relative;
    }

    body.in-story-mode.story-has-name:not(.format-chosen) .story-board.active .story-head::after {
      content: "Choose a format above to start your first scene";
      position: absolute;
      top: calc(100% + 6px);
      right: clamp(20px, 4vw, 64px);
      font-family: var(--font-display);
      font-size: 12px;
      letter-spacing: .06em;
      color: rgba(255, 255, 255, .72);
      text-shadow: 0 1px 2px rgba(0, 0, 0, .45);
      pointer-events: none;
      white-space: nowrap;
    }

    /* 2026-05-07 — Director manual-toggle switch — strip the amber fill
   and the rectangular bordered look. Match the theme accent. */
    [data-theme] .dm-manual-toggle .dm-mt-track {
      background: rgba(255, 255, 255, .10) !important;
      border: 1.5px solid rgba(255, 255, 255, .22) !important;
      width: 38px !important;
      height: 22px !important;
    }

    [data-theme] .dm-manual-toggle .dm-mt-knob {
      width: 16px !important;
      height: 16px !important;
      top: 2px !important;
      left: 2px !important;
      background: #fff !important;
    }

    [data-theme] .dm-manual-toggle input:checked+.dm-mt-track {
      background:
        radial-gradient(120% 100% at 30% 0%, var(--active-tint), transparent 70%),
        var(--lg-fill) !important;
      border-color: var(--lg-stroke-hi) !important;
      box-shadow:
        0 0 18px var(--active-glow),
        0 1px 0 rgba(255, 255, 255, .45) inset !important;
    }

    [data-theme] .dm-manual-toggle input:checked+.dm-mt-track .dm-mt-knob {
      left: 18px !important;
    }

    /* 2026-05-07 — Connected pill anatomy fix.
   The .input-row is ONE continuous glass surface. The Create button
   inside is a transparent flex child with NO own border, NO shadow,
   NO inner highlight — otherwise the inner highlight reads as a thin
   line at the top of the button (the "slight overlap on the upper
   side" the user saw).
   2026-05-11 b.252 — DESIGN-SYSTEM PASS. The "transparent embedded"
   approach is obsolete. User wants the VS CREATE button to be a
   standalone pill matching Chat's ↑ | ∞ FREE pill verbatim. Now
   the override APPLIES the chat send-btn recipe instead of stripping
   chrome. Recipe = pill radius 999, 1.5px .45 white border, .10
   white-wash bg, 22px blur with brightness, no box-shadow. The
   .bc-main / .bc-cost two-segment structure is preserved with a
   .22 border-left divider on bc-cost and a faint .05 bg on it,
   identical to chat's .ce-send-main / .ce-send-cost. */
    [data-theme] .btn-create,
    [data-theme] .input-row .btn-create {
      /* b.558 — Pill → rounded rectangle. Was 999px full-pill; now
     16px gives a soft-cornered rectangle that still reads as a
     glass button but doesn't dome the ends. Matches the visual
     language of the input-row / popovers / tile cards better. */
      border-radius: 16px !important;
      border: 1.5px solid rgba(255, 255, 255, .45) !important;
      background: rgba(255, 255, 255, .10) !important;
      -webkit-backdrop-filter: blur(22px) saturate(1.30) brightness(1.04) !important;
      backdrop-filter: blur(22px) saturate(1.30) brightness(1.04) !important;
      box-shadow: none !important;
      overflow: hidden !important;
      height: 48px !important;
    }

    [data-theme] .btn-create .bc-main {
      border: 0 !important;
      background: transparent !important;
      box-shadow: none !important;
    }

    [data-theme] .btn-create .bc-cost {
      border: 0 !important;
      border-left: 1px solid rgba(255, 255, 255, .22) !important;
      background: rgba(255, 255, 255, .05) !important;
      box-shadow: none !important;
      border-radius: 0 !important;
    }

    /* 2026-05-08 v8 — More compact horizontally, bigger type + coin.
   The Create section was eating too much width with `padding:0 14px`
   on the label and `padding:0 18px 0 6px` on the cost segment. Tighten
   the padding so the whole pill cluster is compact, and scale up the
   CREATE text, the cost number, and the joy-coin so they read as the
   primary action — not a quiet trailing chip. */
    /* 2026-05-11 b.262 — normalize VS create-button typography to match
   chat's send-button exactly. Was: 16px/800/.06em with 2em coin.
   Now: 13px/800/.02em with 1.7em coin — identical to chat's
   .ce-send-main / .ce-send-cost spec. */
    [data-theme] .btn-create .bc-main {
      padding: 0 18px !important;
      font-size: 13px !important;
      font-weight: 800 !important;
      letter-spacing: .02em !important;
      gap: 6px !important;
    }

    [data-theme] .btn-create .bc-cost {
      padding: 0 14px !important;
      font-size: 13px !important;
      font-weight: 800 !important;
      letter-spacing: .02em !important;
      gap: 6px !important;
    }

    [data-theme] .btn-create .bc-cost .joy-coin {
      width: 1.7em !important;
      height: 1.7em !important;
    }

    /* 2026-05-08 v4 — Kill the .liquid conic-gradient haze that was
   rendering INSIDE .btn-create. The blurred conic was the source of
   the "rectangle sitting on top of the pill" look — it was creating a
   visible coloured wash bounded by straight horizontal edges (top &
   bottom of the button) that didn't follow the parent pill's curve.
   The button is now a truly transparent flex child of .input-row. */
    [data-theme] .btn-create.liquid::before,
    [data-theme] .btn-create.liquid::after,
    [data-theme] .input-row .btn-create::before,
    [data-theme] .input-row .btn-create::after {
      display: none !important;
      content: none !important;
    }

    /* Kill any inner highlight inset shadow on the button or its
   children. Belt-and-braces: this catches the legacy
   `box-shadow: 0 8px 22px -10px rgba(0,0,0,.28)` from line 4282 and
   any other inset glints. */
    [data-theme] .input-row .btn-create,
    [data-theme] .input-row .btn-create *,
    [data-theme] .btn-create,
    [data-theme] .btn-create * {
      box-shadow: none !important;
      filter: none !important;
      mix-blend-mode: normal !important;
      isolation: auto !important;
      text-shadow: none !important;
    }

    /* 2026-05-11 b.252 — these "re-state the seamless rules" blocks
   were part of the old "transparent embed" design. With the design-
   system pass making the VS CREATE button a standalone pill matching
   chat's send-btn, we explicitly re-affirm the pill recipe here so
   it wins against any earlier .liquid / hover / cost-segment
   overrides. Hover deepens the bg + brightens the rim — same
   transition as .ce-send-btn:hover. */
    [data-theme] .input-row .btn-create,
    [data-theme] .btn-create.liquid {
      /* b.558 — second declaration of the same recipe. Same rounded-
     rectangle treatment as the block above; both must change in
     lockstep because either selector can win depending on whether
     the button carries the .liquid class. */
      border-radius: 16px !important;
      border: 1.5px solid rgba(255, 255, 255, .45) !important;
      background: rgba(255, 255, 255, .10) !important;
      -webkit-backdrop-filter: blur(22px) saturate(1.30) brightness(1.04) !important;
      backdrop-filter: blur(22px) saturate(1.30) brightness(1.04) !important;
      height: 48px !important;
      align-self: center !important;
      margin: 0 !important;
    }

    [data-theme] .input-row .btn-create:hover {
      background: rgba(255, 255, 255, .16) !important;
      border-color: rgba(255, 255, 255, .55) !important;
      transform: translateY(-1px) !important;
    }

    /* Cost segment keeps the .22 left divider + .05 wash that matches
   chat's .ce-send-cost. NOT stripped any more. */
    [data-theme] .btn-create .bc-cost {
      background: rgba(255, 255, 255, .05) !important;
      border-left: 1px solid rgba(255, 255, 255, .22) !important;
    }


/* ════════════════════════════════════════════════════════════════════
   STUDIOS — mode picker, asset chips, setup modals.
   Extracted in b.855. 915 lines moved from index.html top inline
   <style>. Cross-studio shared chrome (mode-picker pills, asset chips
   for image/video/audio uploads, setup-modals primitives).
   ════════════════════════════════════════════════════════════════════ */

    /* ============================================================
   STUDIOS — mode picker, asset chips, setup modals
   ============================================================ */
    /* Mode picker — opens as a fullscreen overlay with the rest of the page
   blurred behind. Cards lay out as a horizontal sequence (no grid box),
   each card a 3:4-ish portrait tile with a subtle gradient surface and
   the icon + name + tagline stacked top-to-bottom. */
    /* 2026-05-12 b.348 — Modes picker redesigned from full-screen takeover
   into a compact liquid-glass popover that floats above the Mode pill.
   No icons / no photos: just a vertical stack of title + tagline cards
   that match the .engine-popover language (low-alpha base, heavy
   backdrop blur, soft sheen along the top edge). Switching mode now
   feels like a quick menu pick rather than a context switch.
   2026-05-12 b.359 — SPECIFICITY FIX. .modes-screen markup is a
   <section> element. The wrapper-transparency sweep at line 875–877
   (`[data-theme] section { backdrop-filter: none !important; ... }`)
   was silently nuking backdrop-filter / background / border because
   it has higher specificity (0,0,1,1) than a bare `.modes-screen`
   (0,0,1,0) — and with both `!important` the higher-specificity rule
   wins. THAT is why the popover kept rendering totally transparent
   over wallpapers. Fix: chain to `html[data-theme] section.modes-screen`
   (0,0,2,3) so this rule wins the cascade. */
    html[data-theme] section.modes-screen,
    .modes-screen {
      position: fixed;
      z-index: 90;
      width: min(280px, calc(100vw - 24px));
      max-height: min(440px, calc(100vh - 80px));
      padding: 8px;
      border-radius: 20px;
      /* 2026-05-12 b.356 — Canonical liquid-glass recipe via the studio
     tokens (matches .ms-lang-pop / persona-picker shell). The b.349
     dark rgba(8,14,28,.55) base layer is stripped — that was the
     surface the user flagged as wrong. The shell is now pure glass
     and the corner glow is delivered by a ::before pseudo. */
      background: var(--lg-fill) !important;
      background-image: none !important;
      border: 1px solid var(--lg-stroke-hi) !important;
      backdrop-filter: var(--lg-blur) !important;
      -webkit-backdrop-filter: var(--lg-blur) !important;
      box-shadow: var(--lg-shadow), 0 24px 60px rgba(0, 0, 0, .4) !important;
      overflow-y: auto;
      overflow-x: hidden;
      display: flex;
      flex-direction: column;
      gap: 6px;
      isolation: isolate;
      opacity: 0;
      transform: translateY(6px) scale(.98);
      transition: opacity .18s ease, transform .18s ease;
      pointer-events: none;
    }

    /* 2026-05-12 b.360 — Critical fix. b.359 bumped the base selector to
   `html[data-theme] section.modes-screen` (specificity 0,0,2,3) to
   beat the wrapper-transparency sweep. But the .open/.hidden state
   rules stayed at `.modes-screen.open` (0,0,2,0) — LOWER — so the
   base `pointer-events:none` kept winning even when the popover got
   `.open`. The popover rendered but was non-clickable: the pill
   click opened it visually, and tile clicks never reached their
   listeners. Bumping the state rules to the same chained selector
   restores pointer-events:auto when open. */
    html[data-theme] section.modes-screen.open,
    .modes-screen.open {
      opacity: 1;
      transform: translateY(0) scale(1);
      pointer-events: auto;
    }

    html[data-theme] section.modes-screen.hidden,
    html[data-theme] section.modes-screen[hidden],
    .modes-screen.hidden,
    .modes-screen[hidden] {
      display: none
    }

    /* 2026-05-12 b.356 — Luminous top-left corner glow. Same recipe the
   .ms-lang-pop / persona-picker uses to break the flatness of the
   pure-glass shell. */
    .modes-screen::before {
      content: '';
      position: absolute;
      inset: 0;
      border-radius: inherit;
      background: radial-gradient(80% 80% at 0% 0%, rgba(255, 255, 255, .18), transparent 60%);
      pointer-events: none;
      z-index: 0;
    }

    /* Direct children sit above the corner glow. */
    .modes-screen>* {
      position: relative;
      z-index: 2;
    }

    /* Tiny section header. Stays out of the way; main job is to add a bit
   of vertical rhythm at the top of the menu. */
    .modes-head {
      padding: 8px 12px 6px;
      border-bottom: 1px solid rgba(255, 255, 255, .08);
      margin-bottom: 2px;
    }

    html[data-theme="day"] .modes-head {
      border-bottom-color: rgba(0, 0, 0, .06);
    }

    .modes-head h2 {
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 10.5px;
      letter-spacing: .18em;
      text-transform: uppercase;
      color: var(--text-muted);
      margin: 0;
      line-height: 1;
    }

    .modes-head h2 em {
      font-style: normal;
      color: var(--text-muted);
      font-weight: 800
    }

    .modes-head .modes-sub {
      display: none
    }

    /* Close button retired — click-outside / Escape handle dismissal. */
    .modes-close {
      display: none
    }

    /* Vertical stack of mode rows. */
    .modes-grid {
      display: flex;
      flex-direction: column;
      gap: 4px;
      padding: 2px 4px 4px;
    }

    /* Mode row — one per mode, full width of the popover. Pure glass: no
   per-mode background image, no gradient — just a translucent tile
   that lights up on hover. */
    .mode-tile {
      position: relative;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 3px;
      width: 100%;
      padding: 11px 14px;
      border-radius: 12px;
      background: rgba(255, 255, 255, .04);
      border: 1px solid rgba(255, 255, 255, .10);
      color: var(--text);
      text-align: left;
      cursor: pointer;
      transition: background .15s ease, border-color .15s ease, transform .15s ease;
    }

    .mode-tile:hover {
      background: rgba(255, 255, 255, .10);
      border-color: rgba(255, 255, 255, .22);
      transform: translateY(-1px);
    }

    .mode-tile.active {
      background: rgba(255, 255, 255, .14);
      border-color: rgba(255, 255, 255, .30);
      box-shadow: inset 0 1px 0 rgba(255, 255, 255, .12);
    }

    html[data-theme="day"] .mode-tile {
      background: rgba(0, 0, 0, .03);
      border-color: rgba(0, 0, 0, .08);
    }

    html[data-theme="day"] .mode-tile:hover {
      background: rgba(0, 0, 0, .07);
      border-color: rgba(0, 0, 0, .14);
    }

    html[data-theme="day"] .mode-tile.active {
      background: rgba(0, 0, 0, .09);
      border-color: rgba(0, 0, 0, .18);
    }

    /* Drop icon + arrow from old card. Hidden in case markup is left in
   place anywhere — guarantees no leak. */
    .mode-tile .mt-ico,
    .mode-tile .mt-arrow {
      display: none !important
    }

    .mode-tile .mt-text {
      display: flex;
      flex-direction: column;
      gap: 2px;
      background: transparent;
      border: 0;
      padding: 0;
      margin: 0;
      box-shadow: none;
      backdrop-filter: none;
      -webkit-backdrop-filter: none;
    }

    .mode-tile .mt-name {
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 12.5px;
      letter-spacing: .02em;
      color: var(--text);
      margin: 0;
    }

    .mode-tile .mt-desc {
      font-family: var(--font-body);
      font-weight: 500;
      font-size: 10.5px;
      line-height: 1.35;
      color: var(--text-muted);
      margin: 0;
    }

    /* Mode pill — clean glass pill with a slow electric-blue shimmer that
   travels ALONG the border (no halo, no shadow, no glow extending out).
   Achieved with two stacked backgrounds: a solid pill body via
   padding-box, plus a slowly-shifting blue gradient masked to just the
   1.5px border ring via a pseudo-element. */
    .mode-pill {
      position: relative;
      display: inline-flex;
      align-items: center;
      gap: 8px;
      padding: 7px 14px;
      background: var(--glass-bg);
      border: 1.5px solid rgba(232, 176, 74, .30);
      border-radius: 999px;
      font-family: var(--font-display);
      font-size: 12px;
      letter-spacing: .04em;
      color: var(--text);
      cursor: pointer;
      isolation: isolate;
      transition: transform .2s ease;
    }

    .mode-pill:hover {
      transform: translateY(-1px)
    }

    .mode-pill::before {
      content: '';
      position: absolute;
      inset: -1.5px;
      border-radius: inherit;
      padding: 1.5px;
      background: linear-gradient(110deg,
          transparent 0%,
          transparent 35%,
          #e8b04a 50%,
          transparent 65%,
          transparent 100%);
      background-size: 300% 100%;
      -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
      mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
      -webkit-mask-composite: xor;
      mask-composite: exclude;
      animation: pill-shimmer 3.2s linear infinite;
      pointer-events: none;
    }

    .mode-pill .mp-name {
      font-weight: 500
    }

    @keyframes pill-shimmer {
      0% {
        background-position: 300% 0%;
      }

      100% {
        background-position: -100% 0%;
      }
    }

    /* Top-position variant — sits in the header tabs as a soft pill with
   a richer accent so it reads as the active sub-selector under Visual
   Studio. */
    .mode-pill.mode-pill-top {
      padding: 6px 14px 6px 8px;
      font-size: 11.5px;
      letter-spacing: .04em;
      margin-left: 14px;
      background: linear-gradient(135deg, rgba(232, 176, 74, .22), rgba(112, 72, 236, .18));
      border: 1.5px solid rgba(232, 176, 74, .55);
      color: #fff;
      display: inline-flex;
      align-items: center;
      gap: 8px;
      box-shadow: 0 4px 18px -8px rgba(232, 176, 74, .55);
    }

    .mode-pill.mode-pill-top:hover {
      background: linear-gradient(135deg, rgba(232, 176, 74, .32), rgba(112, 72, 236, .26));
      border-color: rgba(232, 176, 74, .85);
      /* Pause the bounce on hover so cursor users can read the pill calmly. */
      animation-play-state: paused;
    }

    /* Constant gentle bounce — slow + perpetual so the pill always
   draws the eye without feeling frantic. 2.4s cycle ≈ a relaxed
   "breathing" rhythm. */
    .mode-pill.mode-pill-top {
      animation: modePillBounce 2.4s ease-in-out infinite;
    }

    @keyframes modePillBounce {

      0%,
      100% {
        transform: translateY(0);
      }

      50% {
        transform: translateY(-4px);
      }
    }

    .mode-pill.mode-pill-top::after {
      content: '⇅';
      font-size: 11px;
      color: rgba(255, 255, 255, .75);
      margin-left: 2px;
    }

    .mode-pill.mode-pill-top .mp-name {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      font-weight: 600;
    }

    .mode-pill.mode-pill-top .mp-name::before {
      content: '';
      width: 7px;
      height: 7px;
      border-radius: 50%;
      background: #e8b04a;
      box-shadow: 0 0 8px rgba(232, 176, 74, .85);
    }

    /* Hide the legacy bottom-bar mode pill — it's been promoted to the top */
    .input-shell .mode-pill:not(.mode-pill-top) {
      display: none !important
    }

    /* Asset chip (Persona / Pet) injected just above the textarea */
    .asset-bar {
      display: flex;
      align-items: flex-end;
      gap: 10px;
      flex-wrap: wrap;
      margin: 0 0 10px;
      padding: 0 4px;
    }

    .asset-chip {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      padding: 5px 10px 5px 5px;
      background: var(--glass-bg);
      border: 1px solid var(--glass-border);
      border-radius: 999px;
      cursor: pointer;
      font-size: 12px;
      color: var(--text);
      font-family: var(--font-body);
      font-weight: 500;
      transition: border-color .2s ease;
      max-width: 100%;
    }

    .asset-chip:hover {
      border-color: rgba(252, 166, 0, .50)
    }

    .asset-chip .ac-thumb {
      width: 24px;
      height: 24px;
      border-radius: 50%;
      background-color: rgba(255, 255, 255, .08);
      background-size: cover;
      background-position: center;
      border: 1px solid rgba(255, 255, 255, .1);
      flex-shrink: 0;
    }

    .asset-chip .ac-thumb.empty {
      display: grid;
      place-items: center;
      font-size: 14px;
      color: #fca600;
      background: rgba(252, 166, 0, .10);
      border-color: rgba(252, 166, 0, .30)
    }

    .asset-chip .ac-name {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      max-width: 140px
    }

    .asset-chip.active {
      border-color: rgba(252, 166, 0, .55);
      background: rgba(252, 166, 0, .08)
    }

    .asset-chip-add {
      font-style: italic;
      color: var(--text-muted)
    }

    /* Asset setup modal (Persona/Pet/Product) — uses the existing modal shell */
    .studio-setup {
      padding: 4px 0 0
    }

    .studio-setup .ss-step {
      margin-bottom: 18px
    }

    .studio-setup .ss-label {
      display: block;
      font-family: var(--font-display);
      font-size: 12px;
      letter-spacing: .06em;
      color: var(--text-muted);
      text-transform: uppercase;
      margin-bottom: 8px
    }

    .studio-setup .ss-input {
      width: 100%;
      padding: 11px 14px;
      border-radius: 12px;
      background: var(--glass-bg);
      border: 1px solid var(--glass-border);
      color: var(--text);
      font-size: 15px;
      font-family: var(--font-body);
      outline: none;
      transition: border-color .2s ease;
    }

    .studio-setup .ss-input:focus {
      border-color: rgba(252, 166, 0, .6)
    }

    .studio-setup select.ss-input {
      appearance: none;
      -webkit-appearance: none;
      background-image: linear-gradient(45deg, transparent 50%, #fca600 50%), linear-gradient(135deg, #fca600 50%, transparent 50%);
      background-position: calc(100% - 18px) calc(50% - 2px), calc(100% - 13px) calc(50% - 2px);
      background-size: 5px 5px, 5px 5px;
      background-repeat: no-repeat;
      padding-right: 36px
    }

    .studio-setup .ss-photos {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
      gap: 10px;
      margin-top: 6px;
    }

    .studio-setup .ss-photo {
      position: relative;
      aspect-ratio: 1/1;
      border-radius: 12px;
      overflow: hidden;
      background: rgba(255, 255, 255, .04);
      border: 1px dashed rgba(255, 255, 255, .18);
      display: grid;
      place-items: center;
      cursor: pointer;
      transition: border-color .2s ease, background .2s ease;
      font-size: 11px;
      color: var(--text-muted);
      text-align: center;
      line-height: 1.2;
      padding: 6px;
    }

    .studio-setup .ss-photo.filled {
      border-style: solid;
      border-color: rgba(252, 166, 0, .30);
      background-color: rgba(255, 255, 255, .06)
    }

    .studio-setup .ss-photo.filled:hover {
      border-color: rgba(252, 166, 0, .55)
    }

    .studio-setup .ss-photo img {
      width: 100%;
      height: 100%;
      object-fit: cover
    }

    .studio-setup .ss-photo .pp-x {
      position: absolute;
      top: 4px;
      right: 4px;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background: rgba(0, 0, 0, .65);
      color: #fff;
      border: none;
      cursor: pointer;
      display: grid;
      place-items: center;
      font-size: 13px;
      line-height: 1;
    }

    .studio-setup .ss-photo .pp-hint {
      font-style: italic;
      opacity: .85
    }

    .studio-setup .ss-photo .pp-add-icon {
      font-size: 22px;
      color: #fca600;
      margin-bottom: 2px
    }

    .studio-setup .ss-help {
      font-size: 12px;
      color: var(--text-muted);
      margin: 8px 0 0;
      line-height: 1.5
    }

    .studio-setup .ss-actions {
      display: flex;
      justify-content: flex-end;
      gap: 10px;
      margin-top: 18px
    }

    .studio-setup .btn-primary {
      background: linear-gradient(180deg, #fca600, #e69200);
      color: #1a0e00;
      border: none;
      padding: 11px 22px;
      border-radius: 12px;
      font-family: var(--font-display);
      font-size: 13px;
      letter-spacing: .06em;
      cursor: pointer;
      font-weight: 600;
    }

    .studio-setup .btn-primary:disabled {
      opacity: .45;
      cursor: not-allowed
    }

    .studio-setup .btn-secondary {
      background: var(--glass-bg);
      color: var(--text);
      border: 1px solid var(--glass-border);
      padding: 11px 18px;
      border-radius: 12px;
      font-family: var(--font-display);
      font-size: 13px;
      letter-spacing: .06em;
      cursor: pointer;
    }

    /* Pet Studio: angle checklist gives users an actual visual brief */
    .pet-checklist {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
      gap: 8px;
      margin: 8px 0 0
    }

    .pet-checklist .pc-item {
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 12px;
      color: var(--text-muted);
      line-height: 1.3
    }

    .pet-checklist .pc-item.done {
      color: var(--text)
    }

    .pet-checklist .pc-item .dot {
      width: 7px;
      height: 7px;
      border-radius: 50%;
      background: rgba(255, 255, 255, .18);
      flex-shrink: 0
    }

    .pet-checklist .pc-item.done .dot {
      background: #fca600
    }

    /* Asset list (existing personas/pets/products to pick from) */
    .asset-list {
      display: flex;
      flex-direction: column;
      gap: 8px;
      margin: 0 0 18px
    }

    .asset-row {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 10px;
      background: rgba(255, 255, 255, .04);
      border: 1px solid var(--glass-border);
      border-radius: 14px;
      cursor: pointer;
      transition: border-color .2s ease;
    }

    .asset-row:hover {
      border-color: rgba(252, 166, 0, .5)
    }

    .asset-row.active {
      border-color: rgba(252, 166, 0, .7);
      background: rgba(252, 166, 0, .08)
    }

    .asset-row .ar-thumb {
      width: 48px;
      height: 48px;
      border-radius: 12px;
      background-color: rgba(255, 255, 255, .05);
      background-size: cover;
      background-position: center;
      flex-shrink: 0
    }

    .asset-row .ar-meta {
      flex: 1;
      min-width: 0
    }

    .asset-row .ar-name {
      font-size: 14px;
      color: var(--text);
      font-weight: 500;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis
    }

    .asset-row .ar-sub {
      font-size: 11px;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: .05em;
      margin-top: 2px
    }

    .asset-row .ar-del {
      width: 30px;
      height: 30px;
      border-radius: 9px;
      border: 1px solid var(--glass-border);
      background: transparent;
      color: var(--text-muted);
      cursor: pointer;
      display: grid;
      place-items: center;
      font-size: 14px;
    }

    .asset-row .ar-del:hover {
      color: #ff6b6b;
      border-color: rgba(255, 107, 107, .4)
    }

    /* Product Studio shoot grid — shows the full shoot pack as it generates */
    .shoot-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
      gap: 14px;
      margin: 18px 0;
    }

    .shoot-card {
      position: relative;
      background: var(--glass-bg);
      border: 1px solid var(--glass-border);
      border-radius: 14px;
      overflow: hidden;
    }

    .shoot-card .sc-media {
      position: relative;
      aspect-ratio: 1/1;
      background: rgba(0, 0, 0, .35);
      overflow: hidden
    }

    .shoot-card .sc-media img,
    .shoot-card .sc-media video {
      width: 100%;
      height: 100%;
      object-fit: cover;
      display: block
    }

    .shoot-card .sc-loader {
      position: absolute;
      inset: 0;
      display: grid;
      place-items: center;
      background: linear-gradient(135deg, #0a0610, #1a0820);
      color: #fca600;
      font-family: var(--font-display);
      font-size: 11px;
      letter-spacing: .08em;
    }

    .shoot-card .sc-loader::before {
      content: '';
      width: 18px;
      height: 18px;
      border: 2px solid rgba(252, 166, 0, .2);
      border-top-color: #fca600;
      border-radius: 50%;
      animation: cr 1s linear infinite;
      margin-right: 10px;
    }

    .shoot-card .sc-meta {
      padding: 10px 12px
    }

    .shoot-card .sc-title {
      font-size: 12px;
      color: var(--text);
      font-weight: 600;
      font-family: var(--font-display);
      letter-spacing: .04em
    }

    .shoot-card .sc-ratio {
      font-size: 10px;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: .06em;
      margin-top: 2px
    }

    .shoot-card .sc-fail {
      position: absolute;
      inset: 0;
      display: flex;
      align-items: center;
      justify-content: center;
      background: rgba(40, 8, 8, .85);
      color: #ff9b9b;
      font-size: 11px;
      text-align: center;
      padding: 14px;
      line-height: 1.4;
    }

    .shoot-card .sc-kind {
      position: absolute;
      top: 8px;
      left: 8px;
      padding: 3px 8px;
      border-radius: 999px;
      background: rgba(0, 0, 0, .55);
      color: #fff;
      font-size: 10px;
      text-transform: uppercase;
      letter-spacing: .08em;
      backdrop-filter: blur(6px);
    }

    .studio-actions-row {
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 12px;
      flex-wrap: wrap;
      margin-top: 14px
    }

    .studio-actions-row .sa-info {
      font-size: 12px;
      color: var(--text-muted)
    }

    /* Story Mode scene timeline */
    .story-stage {
      padding: 18px 0
    }

    .story-strip {
      display: flex;
      gap: 10px;
      overflow-x: auto;
      padding: 6px 4px 14px;
      -webkit-overflow-scrolling: touch
    }

    .story-strip .ss-cell {
      flex: 0 0 auto;
      width: 120px;
      background: var(--glass-bg);
      border: 1px solid var(--glass-border);
      border-radius: 12px;
      overflow: hidden;
      cursor: pointer;
    }

    .story-strip .ss-cell.active {
      border-color: rgba(252, 166, 0, .7)
    }

    .story-strip .ss-cell .sc-img {
      width: 100%;
      aspect-ratio: 1/1;
      background-color: rgba(0, 0, 0, .3);
      background-size: cover;
      background-position: center
    }

    .story-strip .ss-cell .sc-num {
      padding: 6px 10px;
      font-size: 11px;
      color: var(--text-muted);
      font-family: var(--font-display);
      letter-spacing: .06em;
      text-transform: uppercase
    }

    .story-strip .ss-cell.add {
      display: grid;
      place-items: center;
      color: #fca600;
      font-size: 24px;
      border-style: dashed;
      border-color: rgba(252, 166, 0, .3);
      height: 160px
    }

    /* Mobile tweaks for the studios stack */
    @media (max-width: 720px) {
      .modes-screen {
        width: min(260px, calc(100vw - 16px));
      }

      .mode-tile {
        padding: 10px 12px;
      }

      .mode-tile .mt-name {
        font-size: 12.5px;
      }

      .mode-tile .mt-desc {
        font-size: 10.5px;
        line-height: 1.35;
      }

      .studio-setup .ss-photos {
        grid-template-columns: repeat(3, 1fr)
      }

      .pet-checklist {
        grid-template-columns: 1fr 1fr
      }

      .shoot-grid {
        grid-template-columns: 1fr 1fr
      }

      .story-strip .ss-cell {
        width: 96px
      }
    }

    @media (max-width: 420px) {
      .modes-screen {
        width: min(240px, calc(100vw - 16px));
      }

      .shoot-grid {
        grid-template-columns: 1fr
      }
    }


/* ════════════════════════════════════════════════════════════════════
   MODAL PRIMITIVES.
   Extracted in b.859. 556 lines from index.html top inline <style>.
   Universal modal shell, scrim, header, footer rules.
   ════════════════════════════════════════════════════════════════════ */

    /* ============================================================
   MODAL
   ============================================================ */
    .modal-back {
      position: fixed;
      inset: 0;
      z-index: 50;
      background: rgba(0, 0, 0, .45);
      backdrop-filter: blur(10px);
      -webkit-backdrop-filter: blur(10px);
      opacity: 0;
      pointer-events: none;
      transition: opacity .3s;
    }

    html[data-theme="day"] .modal-back {
      background: rgba(255, 255, 255, .55)
    }

    .modal-back.show {
      opacity: 1;
      pointer-events: auto
    }

    .modal {
      position: fixed;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -46%) scale(.97);
      z-index: 60;
      width: min(720px, calc(100vw - 28px));
      max-height: calc(100vh - 48px);
      /* b.287 — canonical liquid-glass recipe. Radial corner gradients
     give the shell a refractive feel against the moving theme video,
     the white base tint reads as frosted glass, and the multi-layer
     box-shadow adds depth (inset rim light + outer drop). This is
     the same recipe used by the Voice Mode shell and the chat
     engine consoles — keeps every popup on the same design language. */
      background:
        radial-gradient(60% 60% at 0% 0%, rgba(255, 210, 170, .20) 0%, transparent 70%),
        radial-gradient(60% 60% at 100% 0%, rgba(180, 200, 255, .18) 0%, transparent 70%),
        radial-gradient(80% 80% at 50% 100%, rgba(220, 185, 240, .16) 0%, transparent 70%),
        rgba(255, 255, 255, .10);
      border: 1.5px solid rgba(255, 255, 255, .45);
      -webkit-backdrop-filter: blur(28px) saturate(1.5) brightness(1.05);
      backdrop-filter: blur(28px) saturate(1.5) brightness(1.05);
      border-radius: 22px;
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .55) inset,
        0 -1px 0 rgba(255, 255, 255, .20) inset,
        0 0 0 1px rgba(255, 255, 255, .12) inset,
        0 30px 90px -16px rgba(0, 0, 0, .60);
      opacity: 0;
      pointer-events: none;
      transition: opacity .35s var(--ease), transform .45s var(--ease-out);
      display: flex;
      flex-direction: column;
      overflow: hidden;
    }

    .modal.show {
      opacity: 1;
      transform: translate(-50%, -50%) scale(1);
      pointer-events: auto
    }

    .modal-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 14px;
      padding: 18px 22px;
      border-bottom: 1px solid var(--glass-border);
    }

    .modal-head h3 {
      margin: 0;
      font-family: var(--font-display);
      font-size: 13px;
      letter-spacing: .16em;
      text-transform: uppercase;
      color: var(--text);
      display: inline-flex;
      align-items: center;
      gap: 11px;
      line-height: 1;
    }

    .modal-close {
      width: 42px;
      height: 42px;
      border-radius: 12px;
      display: grid;
      place-items: center;
      background: transparent;
      border: 1px solid var(--glass-border);
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      color: var(--text);
      transition: background .25s;
    }

    .modal-close:hover {
      background: var(--glass-bg-strong)
    }

    .modal-body {
      padding: 24px 22px;
      overflow: auto
    }

    /* settings */
    .field {
      display: flex;
      flex-direction: column;
      gap: 7px;
      margin-bottom: 18px
    }

    .field label {
      font-family: var(--font-display);
      font-size: 11px;
      letter-spacing: .14em;
      color: var(--text-muted);
      text-transform: uppercase;
      line-height: 1;
      display: inline-flex;
      align-items: center;
      gap: 8px;
    }

    .field label .note {
      color: var(--text-muted);
      text-transform: none;
      letter-spacing: 0;
      font-size: 13px;
      font-style: normal;
      font-family: var(--font-body);
      font-weight: 500
    }

    .field .input-wrap {
      display: flex;
      align-items: center;
      gap: 8px;
      border: 1px solid var(--glass-border);
      background: var(--glass-bg);
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      border-radius: 12px;
      padding: 5px 5px 5px 14px;
    }

    .field .input-wrap input {
      flex: 1;
      padding: 10px 0;
      font-size: 14px;
      font-family: var(--font-ui);
      font-weight: 600;
      color: var(--text)
    }

    .field .input-wrap input::placeholder {
      color: var(--text-muted)
    }

    .field .input-wrap button {
      padding: 9px 12px;
      border-radius: 8px;
      font-family: var(--font-display);
      font-size: 10px;
      letter-spacing: .10em;
      text-transform: uppercase;
      background: var(--glass-bg-active);
      color: var(--text);
      line-height: 1;
    }

    .field .help {
      font-size: 13px;
      color: var(--text-muted);
      font-style: normal;
      font-family: var(--font-body);
      font-weight: 500
    }

    .pricing-table {
      border: 1px solid var(--glass-border);
      border-radius: 14px;
      overflow: hidden;
      background: var(--glass-bg);
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      margin-top: 8px;
    }

    .pricing-table .row {
      display: grid;
      grid-template-columns: 1fr auto auto;
      gap: 14px;
      padding: 13px 16px;
      border-bottom: 1px solid var(--glass-border);
      font-family: var(--font-display);
      font-size: 12px;
      letter-spacing: .06em;
      align-items: center;
      text-transform: uppercase;
      line-height: 1;
    }

    .pricing-table .row:last-child {
      border-bottom: none
    }

    .pricing-table .row .name {
      color: var(--text)
    }

    .pricing-table .row .coin-amt {
      color: var(--text);
      display: inline-flex;
      align-items: center;
      gap: 7px
    }

    .pricing-table .row .inr {
      color: var(--text-muted)
    }

    /* coin shop */
    .shop-balance {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 12px;
      padding: 16px 20px;
      border-radius: 14px;
      background: var(--glass-bg);
      border: 1px solid var(--glass-border);
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      margin-bottom: 18px;
    }

    .shop-balance .lbl {
      font-family: var(--font-display);
      font-size: 11px;
      letter-spacing: .14em;
      color: var(--text-muted);
      text-transform: uppercase;
      line-height: 1
    }

    .shop-balance .v {
      font-family: var(--font-display);
      font-size: 22px;
      color: var(--text);
      display: inline-flex;
      align-items: center;
      gap: 9px;
      line-height: 1
    }

    .packs {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      gap: 12px
    }

    .pack {
      position: relative;
      border: 1px solid var(--glass-border);
      border-radius: 18px;
      padding: 20px;
      background: var(--glass-bg);
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      display: flex;
      flex-direction: column;
      gap: 11px;
      transition: border-color .2s, transform .25s, background .2s;
    }

    .pack:hover {
      transform: translateY(-2px);
      background: var(--glass-bg-strong);
      border-color: var(--glass-border-strong)
    }

    .pack.featured {
      border-color: var(--glass-border-strong);
      background: var(--glass-bg-strong)
    }

    .pack .ribbon {
      position: absolute;
      top: -1px;
      right: 18px;
      background: var(--glass-bg-cta);
      color: var(--text);
      border: 1px solid var(--glass-border-strong);
      font-family: var(--font-display);
      font-size: 9px;
      letter-spacing: .14em;
      padding: 6px 11px;
      border-radius: 0 0 8px 8px;
      text-transform: uppercase;
      line-height: 1;
    }

    html[data-theme="day"] .pack .ribbon {
      color: #fff
    }

    .pack .name {
      font-family: var(--font-display);
      font-size: 12px;
      letter-spacing: .14em;
      color: var(--text-muted);
      text-transform: uppercase;
      line-height: 1
    }

    .pack .coins {
      font-family: var(--font-display);
      font-size: 30px;
      line-height: 1;
      color: var(--text);
      display: inline-flex;
      align-items: center;
      gap: 9px
    }

    .pack .price {
      font-family: var(--font-display);
      font-size: 18px;
      color: var(--text);
      line-height: 1
    }

    .pack .price .usd {
      color: var(--text-muted);
      font-size: 12px;
      margin-left: 7px
    }

    .pack .makes {
      font-family: var(--font-body);
      font-style: normal;
      font-size: 13.5px;
      color: var(--text-muted);
      min-height: 38px;
      line-height: 1.45;
      font-weight: 500
    }

    .pack .buy {
      margin-top: auto;
      padding: 13px 14px;
      border-radius: 12px;
      background: var(--glass-bg);
      color: var(--text);
      border: 1px solid var(--glass-border-strong);
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      font-family: var(--font-display);
      font-size: 11px;
      letter-spacing: .10em;
      text-transform: uppercase;
      line-height: 1;
    }

    .pack:not(.featured) .buy {
      background: var(--glass-bg);
      border-color: var(--glass-border)
    }

    .shop-foot {
      margin-top: 16px;
      font-family: var(--font-display);
      font-size: 11px;
      letter-spacing: .14em;
      color: var(--text-muted);
      text-align: center;
      text-transform: uppercase;
      line-height: 1.4;
    }

    @media (max-width:560px) {
      .packs {
        grid-template-columns: 1fr
      }
    }

    /* locked engine modal */
    .locked-modal {
      text-align: center;
      padding: 14px 8px
    }

    .locked-modal h2 {
      font-family: var(--font-display);
      font-size: 38px;
      letter-spacing: .02em;
      line-height: 1;
      margin: 0 0 12px;
      color: var(--text);
      text-transform: uppercase;
    }

    .locked-modal h2 em {
      font-style: normal;
      color: var(--text);
      opacity: .75
    }

    .locked-modal p {
      font-family: var(--font-body);
      font-style: normal;
      color: var(--text-muted);
      font-size: 16px;
      max-width: 42ch;
      margin: 0 auto 18px;
      line-height: 1.55;
      font-weight: 500
    }

    .locked-modal .when {
      display: inline-flex;
      padding: 8px 14px;
      border-radius: 12px;
      border: 1px solid var(--glass-border-strong);
      background: var(--glass-bg);
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      font-family: var(--font-display);
      font-size: 11px;
      letter-spacing: .14em;
      color: var(--text);
      text-transform: uppercase;
      line-height: 1;
    }

    /* tooltip */
    .tip {
      position: absolute;
      top: calc(100% + 10px);
      left: 50%;
      transform: translateX(-50%);
      background: var(--glass-bg-strong);
      color: var(--text);
      border: 1px solid var(--glass-border-strong);
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      padding: 8px 12px;
      border-radius: 8px;
      font-family: var(--font-display);
      font-size: 10px;
      letter-spacing: .10em;
      text-transform: uppercase;
      white-space: nowrap;
      line-height: 1;
      opacity: 0;
      pointer-events: none;
      transition: opacity .2s;
      z-index: 20;
    }

    .tab.locked:hover .tip {
      opacity: 1
    }

    /* tile lightbox */
    .tile-light {
      position: fixed;
      inset: 0;
      z-index: 80;
      background: rgba(0, 0, 0, .5);
      backdrop-filter: blur(14px);
      -webkit-backdrop-filter: blur(14px);
      display: grid;
      place-items: center;
      opacity: 0;
      pointer-events: none;
      transition: opacity .3s;
      padding: 24px;
    }

    html[data-theme="day"] .tile-light {
      background: rgba(255, 255, 255, .65)
    }

    .tile-light.show {
      opacity: 1;
      pointer-events: auto
    }

    .tile-light .frame {
      width: min(640px, 100%);
      max-height: calc(100vh - 80px);
      border-radius: 22px;
      overflow: hidden;
      border: 1px solid var(--glass-border-strong);
      background: var(--glass-bg-strong);
      backdrop-filter: var(--glass-blur-strong);
      -webkit-backdrop-filter: var(--glass-blur-strong);
      box-shadow: 0 30px 90px -16px rgba(0, 0, 0, .7);
    }

    .tile-light .art-wrap {
      position: relative;
      width: 100%;
      aspect-ratio: 1/1;
      overflow: hidden
    }

    .tile-light .meta {
      padding: 18px 22px
    }

    .tile-light .meta .pr {
      font-family: var(--font-body);
      font-style: normal;
      font-size: 15px;
      color: var(--text);
      font-weight: 500;
      margin: 0 0 6px;
      line-height: 1.5
    }

    .tile-light .meta .ln {
      font-family: var(--font-display);
      font-size: 11px;
      letter-spacing: .12em;
      color: var(--text-muted);
      text-transform: uppercase;
      line-height: 1
    }

    .tile-light .x {
      position: absolute;
      top: 24px;
      right: 24px;
      width: 44px;
      height: 44px;
      border-radius: 12px;
      background: var(--glass-bg-strong);
      border: 1px solid var(--glass-border-strong);
      backdrop-filter: var(--glass-blur);
      -webkit-backdrop-filter: var(--glass-blur);
      display: grid;
      place-items: center;
      color: var(--text);
    }


/* ════════════════════════════════════════════════════════════════════
   SYSTEM-WIDE LIQUID GLASS + LIQUID GLASS PRIMITIVES (b.506).
   Extracted in b.859. 432 lines from index.html top inline <style>.
   Core liquid-glass design primitives — single source of truth used by
   every surface.
   ════════════════════════════════════════════════════════════════════ */

    /* ============================================================
   SYSTEM-WIDE LIQUID GLASS — NO SOLID COLORS
   Every "selected / on / active / hover-emphasis" state across
   the parent app (Visual Studio, header, mode pills, toggles,
   composer, modals, gallery) collapses to white-light glass.
   Brand amber (#fca600) is preserved ONLY in the joy-coin SVG
   asset since that IS our currency identity. Everything else
   reads as frosted glass with a soft white halo when active.
   ============================================================ */
    [data-theme] .toggle-grp button.on,
    [data-theme] .toggle-grp[data-grp="dim"] button.on,
    [data-theme] .toggle-grp[data-grp="duration"] button.on,
    [data-theme] .toggle-grp[data-grp="sound"] button.on,
    [data-theme] .toggle-grp[data-grp="mode"] button.on,
    [data-theme] .toggle-grp[data-grp="quality"] button.on,
    [data-theme] .opt.active,
    [data-theme] .opt.on,
    [data-theme] .dm-tile.active,
    [data-theme] .story-board.active,
    [data-theme] .story-chip-pop .opt.active,
    [data-theme] [aria-selected="true"]:not(.tab),
    [data-theme] [aria-checked="true"],
    [data-theme] .story-chip.on,
    [data-theme] .story-chip.active,
    [data-theme] .mode-tile.active,
    [data-theme] .ratio-row .opt.on,
    [data-theme] .quality-row .opt.on {
      background: rgba(255, 255, 255, .10) !important;
      background-image: none !important;
      border-color: rgba(255, 255, 255, .35) !important;
      color: #fff !important;
      box-shadow:
        0 0 0 1px rgba(255, 255, 255, .16) inset,
        0 0 18px rgba(255, 255, 255, .20) !important;
    }

    /* Tabs in the top nav — active tab gets a white underline glow,
   not a theme tint. Locked tabs stay dimmed. */
    [data-theme] .tab.active,
    [data-theme] .tab[aria-selected="true"] {
      color: #fff !important;
    }

    [data-theme] .tab.active::after,
    [data-theme] .tab[aria-selected="true"]::after {
      background: rgba(255, 255, 255, .85) !important;
      box-shadow: 0 0 12px rgba(255, 255, 255, .55) !important;
    }

    /* Mode pill (top-of-header) — pure glass */
    [data-theme] .mode-pill,
    [data-theme] .mode-pill-top {
      background: rgba(255, 255, 255, .05) !important;
      border: 1px solid rgba(255, 255, 255, .18) !important;
      color: #fff !important;
    }

    [data-theme] .mode-pill:hover,
    [data-theme] .mode-pill-top:hover {
      background: rgba(255, 255, 255, .10) !important;
      border-color: rgba(255, 255, 255, .36) !important;
      box-shadow: 0 0 16px rgba(255, 255, 255, .18) !important;
    }

    /* ── Restore amber accent to mode pills that need it ─────────────────
   The glass-normalisation block above strips amber from all .mode-pill
   elements. Undo that for the two pills that must keep their glow:
   • .mode-pill-top  — the header tabs pill (bouncing amber badge)
   • #mksModePill   — the Marketing Studio controls pill               */
    [data-theme] .mode-pill.mode-pill-top {
      background: linear-gradient(135deg, rgba(232, 176, 74, .22), rgba(112, 72, 236, .18)) !important;
      border: 1.5px solid rgba(232, 176, 74, .55) !important;
      box-shadow: 0 4px 18px -8px rgba(232, 176, 74, .55) !important;
    }

    [data-theme] .mode-pill.mode-pill-top:hover {
      background: linear-gradient(135deg, rgba(232, 176, 74, .32), rgba(112, 72, 236, .26)) !important;
      border-color: rgba(232, 176, 74, .85) !important;
      box-shadow: 0 0 16px rgba(232, 176, 74, .30) !important;
    }

    /* #mksModePill now uses mode-pill-top class — no ID overrides needed */

    /* Buy-coins button — glass instead of amber fill */
    [data-theme] .bal-add {
      background: rgba(255, 255, 255, .06) !important;
      border: 1px solid rgba(255, 255, 255, .20) !important;
      color: #fff !important;
    }

    [data-theme] .bal-add:hover {
      background: rgba(255, 255, 255, .10) !important;
      border-color: rgba(255, 255, 255, .40) !important;
      box-shadow: 0 0 18px rgba(255, 255, 255, .24) !important;
    }

    /* Account + Theme pills — glass */
    [data-theme] .account-btn,
    [data-theme] .theme-toggle,
    [data-theme] .glass-pill {
      background: rgba(255, 255, 255, .04) !important;
      border: 1px solid rgba(255, 255, 255, .16) !important;
    }

    /* Composer / input bar / send button — pure glass */
    [data-theme] .input-bar,
    [data-theme] .composer {
      background: rgba(255, 255, 255, .04) !important;
      border: 1px solid rgba(255, 255, 255, .14) !important;
    }

    [data-theme] .send-btn,
    [data-theme] .create-btn,
    [data-theme] .liquid:not(.bal-add):not(.balance-buy) {
      background: rgba(255, 255, 255, .06) !important;
      background-image: none !important;
      border: 1px solid rgba(255, 255, 255, .24) !important;
      color: #fff !important;
    }

    [data-theme] .send-btn:hover:not(:disabled),
    [data-theme] .create-btn:hover:not(:disabled) {
      background: rgba(255, 255, 255, .10) !important;
      border-color: rgba(255, 255, 255, .45) !important;
      box-shadow: 0 0 22px rgba(255, 255, 255, .30) !important;
    }

    /* Action pills — glass */
    [data-theme] .action-pill,
    [data-theme] .action-pill.is-primary {
      background: rgba(255, 255, 255, .05) !important;
      background-image: none !important;
      border: 1px solid rgba(255, 255, 255, .20) !important;
      color: #fff !important;
    }

    [data-theme] .action-pill:hover {
      background: rgba(255, 255, 255, .10) !important;
      border-color: rgba(255, 255, 255, .40) !important;
      box-shadow: 0 0 16px rgba(255, 255, 255, .20) !important;
    }

    /* Reference button — glass. b.539 — halo removed. The previous
   `box-shadow: 0 0 14px rgba(255,255,255,.22)` produced a soft
   white glow that the Garden orbs behind it tinted green through
   the bar's translucency. Dropping the outer shadow keeps only a
   solid border-edge tone change between idle and has-refs — no
   colour-bleed-through, no green halo. */
    [data-theme] .ref-btn {
      background: rgba(255, 255, 255, .05) !important;
      border: 1px solid rgba(255, 255, 255, .18) !important;
      box-shadow: none !important;
    }

    [data-theme] .ref-btn.has-refs {
      background: rgba(255, 255, 255, .10) !important;
      border-color: rgba(255, 255, 255, .40) !important;
      box-shadow: none !important;
    }

    [data-theme] .ref-btn:focus,
    [data-theme] .ref-btn:focus-visible,
    [data-theme] .ref-btn:active {
      outline: none !important;
      /* No outer glow on focus / press — the existing hover state
     supplies enough visual feedback. Prevents any system focus
     ring (macOS Sonoma+ uses the user's system accent colour,
     which the user's setup paints green) from showing through. */
      box-shadow: none !important;
    }

    /* Modes screen tiles — glass */
    [data-theme] .mode-tile {
      background: rgba(255, 255, 255, .04) !important;
      border: 1px solid rgba(255, 255, 255, .14) !important;
    }

    [data-theme] .mode-tile:hover,
    [data-theme] .mode-tile.active {
      background: rgba(255, 255, 255, .10) !important;
      border-color: rgba(255, 255, 255, .36) !important;
      box-shadow: 0 0 22px rgba(255, 255, 255, .20) !important;
    }

    /* Modal shells — pure glass, no solid bg */
    [data-theme] .modal-shell,
    [data-theme] .modal-card,
    [data-theme] .lightbox-shell,
    [data-theme] .signin-card,
    [data-theme] .shop-card {
      background: rgba(255, 255, 255, .04) !important;
      border: 1px solid rgba(255, 255, 255, .14) !important;
      -webkit-backdrop-filter: blur(28px) saturate(1.3) !important;
      backdrop-filter: blur(28px) saturate(1.3) !important;
    }

    /* Director Mode tiles + chips */
    [data-theme] .dm-tile,
    [data-theme] .director-modal-v2 .dm-tile,
    [data-theme] .story-chip {
      background: rgba(255, 255, 255, .04) !important;
      border: 1px solid rgba(255, 255, 255, .14) !important;
      background-image: none !important;
    }

    [data-theme] .dm-tile:hover,
    [data-theme] .story-chip:hover {
      background: rgba(255, 255, 255, .08) !important;
      border-color: rgba(255, 255, 255, .30) !important;
    }

    /* Gallery item hover — white halo not theme-tint */
    [data-theme] .gallery-item:hover,
    [data-theme] .gallery-tile:hover {
      border-color: rgba(255, 255, 255, .40) !important;
      box-shadow: 0 0 22px rgba(255, 255, 255, .22) !important;
    }


    /* SYSTEM-WIDE MODAL BACKDROP RULE — never blur the page backdrop
   when a modal opens. The bg-stage (video + orbs) flows uniformly
   from top to bottom. Each modal's SHELL carries its own liquid-
   glass treatment. This eliminates the visible seam between the
   header and the content area. */
    [data-theme] .modal-back,
    [data-theme] .lightbox-back,
    [data-theme] .signin-back,
    [data-theme] .shop-back,
    [data-theme] .modal-overlay,
    [data-theme] .toast-overlay,
    [data-theme] .ref-popup-back {
      background: transparent !important;
      background-image: none !important;
      -webkit-backdrop-filter: none !important;
      backdrop-filter: none !important;
    }


    /* Parent-side per-theme --lg-fill so glass surfaces read milky on
   dark themes and subtle on bright themes. */
    html[data-theme="hanley-sky"] {
      --lg-fill: rgba(255, 255, 255, .14);
      --lg-fill-hover: rgba(255, 255, 255, .18);
      --lg-stroke: rgba(255, 255, 255, .30);
      --lg-stroke-hi: rgba(255, 255, 255, .55);
    }

    html[data-theme="garden-of-life"] {
      --lg-fill: rgba(255, 255, 255, .06);
      --lg-fill-hover: rgba(255, 255, 255, .10);
      --lg-stroke: rgba(255, 255, 255, .22);
      --lg-stroke-hi: rgba(255, 255, 255, .45);
    }


    /* CANONICAL LIQUID GLASS — parent-side. Same intrinsic-frost recipe
   for the public listen page card, any modal shells, and popups. */
    [data-theme] .listen-card,
    [data-theme] .modal-shell,
    [data-theme] .modal-card,
    [data-theme] .lightbox-shell,
    [data-theme] .signin-card,
    [data-theme] .shop-card {
      background:
        radial-gradient(60% 60% at 0% 0%, rgba(255, 210, 170, .22) 0%, transparent 70%),
        radial-gradient(60% 60% at 100% 0%, rgba(180, 200, 255, .20) 0%, transparent 70%),
        radial-gradient(80% 80% at 50% 100%, rgba(220, 185, 240, .16) 0%, transparent 70%),
        rgba(255, 255, 255, .12) !important;
      border: 1px solid rgba(255, 255, 255, .45) !important;
      -webkit-backdrop-filter: blur(24px) saturate(1.4) brightness(1.05) !important;
      backdrop-filter: blur(24px) saturate(1.4) brightness(1.05) !important;
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .55) inset,
        0 -1px 0 rgba(255, 255, 255, .20) inset,
        0 0 0 1px rgba(255, 255, 255, .12) inset,
        0 24px 60px -12px rgba(0, 0, 0, .55),
        0 0 50px rgba(255, 255, 255, .08) !important;
    }


    /* CRITICAL — force parent shells visible too. */
    [data-theme] .listen-card,
    [data-theme] .modal-shell,
    [data-theme] .modal-card,
    [data-theme] .lightbox-shell,
    [data-theme] .signin-card,
    [data-theme] .shop-card {
      opacity: 1 !important;
    }


    /* Parent shells — same stronger recipe */
    [data-theme] .listen-card,
    [data-theme] .modal-shell,
    [data-theme] .modal-card,
    [data-theme] .lightbox-shell,
    [data-theme] .signin-card,
    [data-theme] .shop-card {
      background:
        radial-gradient(60% 60% at 0% 0%, rgba(255, 210, 170, .40) 0%, transparent 70%),
        radial-gradient(60% 60% at 100% 0%, rgba(180, 200, 255, .36) 0%, transparent 70%),
        radial-gradient(80% 80% at 50% 100%, rgba(220, 185, 240, .32) 0%, transparent 70%),
        rgba(255, 255, 255, .22) !important;
      border: 1px solid rgba(255, 255, 255, .55) !important;
      opacity: 1 !important;
    }

    /* ============================================================
   ===== CHAT ENGINE — MERGED FROM /chat-prototype/ ===========
   All .ce- prefixed; safe to coexist with Visual Studio styles.
   Activated only when the Chat tab is clicked.
   ============================================================ */

    /* ════════════════════════════════════════════════════════════
   LIQUID GLASS PRIMITIVES — SINGLE SOURCE OF TRUTH (b.506)
   ────────────────────────────────────────────────────────────
   The chat consoles fight a wall of global `[data-theme]` rules
   that apply `!important` styling to every textarea / input
   on the page (border-radius:22px, color:#fff, etc.). Per-class
   CSS LOSES the cascade because !important always wins,
   regardless of specificity.

   These primitive classes carry every property forced with
   !important so they win the cascade against the globals.
   Drop one of these classes onto any chat-console glass surface
   and it gets a consistent, guaranteed-to-render look.

   • .lg-glass-input  — full canonical liquid-glass surface
                        (use on bare textareas or on wrapper divs
                        that should look like glass containers)

   • .lg-glass-bare   — invisible reset for inner textareas that
                        live inside a wrapper that already has
                        .lg-glass-input. Zeros out background,
                        border, radius, shadow, outline, padding
                        so only the wrapper's glass is visible.
   ════════════════════════════════════════════════════════════ */
    .lg-glass-input,
    textarea.lg-glass-input,
    input.lg-glass-input,
    div.lg-glass-input {
      background: rgba(255, 255, 255, .03) !important;
      background-color: rgba(255, 255, 255, .03) !important;
      background-image: none !important;
      border: 1px solid rgba(255, 255, 255, .18) !important;
      -webkit-backdrop-filter: blur(40px) saturate(1.7) !important;
      backdrop-filter: blur(40px) saturate(1.7) !important;
      border-radius: 14px !important;
      box-shadow:
        0 28px 64px -18px rgba(0, 0, 0, .55),
        inset 0 1px 0 rgba(255, 255, 255, .16),
        inset 0 -1px 0 rgba(0, 0, 0, .10) !important;
      padding: 16px 20px !important;
      /* b.509 — width / max-width are deliberately NOT !important. The
     hoist JS sets `el.style.width = r.width + 'px'` inline for
     hoisted elements (topic textbox, Argue composer). External CSS
     with !important would WIN over inline style without !important,
     forcing hoisted elements to 100vw and pushing them outside the
     modal. Leaving these as non-!important lets the JS-set inline
     width win; non-hoisted elements still get 100% of parent. */
      width: 100%;
      max-width: 100%;
      box-sizing: border-box !important;
      color: var(--text) !important;
      outline: 0 !important;
      margin: 0 !important;
    }

    textarea.lg-glass-input,
    input.lg-glass-input {
      resize: vertical;
      font-family: var(--font-body);
      font-size: 14.5px;
      line-height: 1.45;
    }

    .lg-glass-input::placeholder,
    textarea.lg-glass-input::placeholder,
    input.lg-glass-input::placeholder {
      color: rgba(255, 255, 255, .42) !important;
      font-style: italic;
    }

    .lg-glass-input:focus,
    textarea.lg-glass-input:focus,
    input.lg-glass-input:focus {
      border-color: rgba(255, 255, 255, .45) !important;
      box-shadow:
        0 28px 64px -18px rgba(0, 0, 0, .55),
        inset 0 1px 0 rgba(255, 255, 255, .16),
        inset 0 -1px 0 rgba(0, 0, 0, .10),
        0 0 0 3px rgba(255, 255, 255, .08) !important;
    }

    /* Inner textareas living inside a .lg-glass-input wrapper.
   Everything that could paint a visible boundary is zeroed out so
   only the parent wrapper's glass surface is visible. */
    .lg-glass-bare,
    textarea.lg-glass-bare,
    input.lg-glass-bare {
      background: transparent !important;
      background-color: transparent !important;
      background-image: none !important;
      border: 0 !important;
      border-radius: 0 !important;
      outline: 0 !important;
      box-shadow: none !important;
      padding: 0 !important;
      margin: 0 !important;
      width: 100% !important;
      max-width: 100% !important;
      box-sizing: border-box !important;
      color: var(--text) !important;
      font-family: var(--font-body);
      font-size: 14.5px;
      line-height: 1.45;
      resize: vertical;
    }

    .lg-glass-bare::placeholder,
    textarea.lg-glass-bare::placeholder,
    input.lg-glass-bare::placeholder {
      color: rgba(255, 255, 255, .42) !important;
      font-style: italic;
    }

    /* SLIDER + CHAT VOICE-MODE/DM/COACH block (4066 lines) → styles/chat.css in b.846. */
    /* LIVE DEBATE / COACH / DM / VOICE-CALL / SHARE block (4714 lines)
       → styles/chat.css in b.845. */
    /* ARGUE CONSOLE + SETUP COMPOSER + MOBILE chat surface optimisation
       (2214 lines) → styles/chat.css in b.849. */


/* ════════════════════════════════════════════════════════════════════
   HEADER PILLS CLUSTER.
   Extracted in b.861. 1359 lines from index.html top inline <style>.
   Includes:
   - HEADER OVERHAUL (b.160)
   - MY PROJECTS pill (Vibe Code, b.700) -- but should ideally be in vibe-code.css
   - BRAND META + MODE PILL RELOCATION (b.162)
   - TAB REDESIGN + MENU AUTO-COLLAPSE (b.164)
   - MY COINS pill (b.213) -- twin of .tabs-menu-pill
   - MY ACCOUNT pill (b.220) -- permanent button
   ════════════════════════════════════════════════════════════════════ */

    /* ============================================================
   2026-05-10 b.160 — HEADER OVERHAUL.
   - VIBE CODE tab removed from HTML.
   - Theme toggle becomes a single circular pill with only the icon
     visible. Hovering reveals a floating caption ("Garden of Life"
     or "Hanley Night Sky") below the circle.
   - Coin balance + "+ Buy coins" hidden until the user is signed in
     (default body has .bal-card.signed-out; renderAccount() removes
     the class on sign-in).
   - Mode pill scoped to Visual Studio only — hidden when the active
     tab is chat / music. CSS uses body[data-active-tab=…].
   - Header uses flex with gap so the layout reflows naturally as
     elements appear / disappear (no dead empty slots).
   ============================================================ */

    /* Header layout — flex with even gap so removing/adding any element
   reflows the row without empty gaps. */
    [data-theme] .header {
      display: flex !important;
      align-items: center !important;
      gap: 14px !important;
    }

    /* The .h-right cluster also flexes with gap — no fixed widths. */
    [data-theme] .h-right {
      display: flex !important;
      align-items: center !important;
      gap: 10px !important;
    }

    /* COIN BALANCE GATE — hide the entire .bal-card (amount + Buy coins)
   until signed in. Old rule only hid .bal-amount; the Buy button was
   still showing for guests, which let anybody act as if they had an
   account. Hide the whole card. */
    .bal-card.signed-out {
      display: none !important;
    }

    .bal-card.signed-out .bal-amount,
    .bal-card.signed-out .bal-add {
      display: none !important;
    }

    /* MODE PILL — only visible when on the Visual Studio tab. The pill
   sits between .tabs and .h-right; when hidden, flex gap collapses
   the empty slot so the row stays balanced. */
    .mode-pill-top {
      display: inline-flex;
    }

    body[data-active-tab="chat"] .mode-pill-top,
    body[data-active-tab="music"] .mode-pill-top,
    body[data-active-tab="vibe"] .mode-pill-top {
      display: none !important;
    }



    /* ── Meta row right group: usage pill + My Projects (b.706) ── */
    .vc-input-meta {
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 0 4px;
      font-family: var(--font-ui);
      font-size: 11.5px;
      color: var(--text-faint);
      flex-wrap: wrap;
    }

    .vc-meta-right {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      margin-left: auto;
    }

    /* b.760 — Balance pill CSS removed (the pill itself was retired
       from the meta row; coin spend signalling lives in the Estimate
       Console now). Old rules were the only place rgba(184, 115, 51)
       still leaked into the Vibe Code UI — that's now gone too. */

    /* b.753 — .vc-build-est / .vc-build-coin CSS removed; coin SVG +
       per-build estimate no longer ship inside the BUILD pill. */

    /* ═══════════════════════════════════════════════════════════════
   MY PROJECTS — Vibe Code  (b.700)
   ═══════════════════════════════════════════════════════════════ */

    .vc-proj-bar {
      display: flex;
      align-items: center;
      padding: 0 4px 6px;
    }

    .vc-myproj-btn {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      background: rgba(255, 255, 255, .04);
      border: 1px solid rgba(255, 255, 255, .14);
      -webkit-backdrop-filter: blur(24px) saturate(1.5);
      backdrop-filter: blur(24px) saturate(1.5);
      border-radius: 20px;
      padding: 6px 14px;
      color: rgba(255, 255, 255, .75);
      font-family: inherit;
      font-size: 12px;
      letter-spacing: .04em;
      cursor: pointer;
      transition: background .18s, border-color .18s, color .18s;
      box-shadow: 0 2px 12px rgba(0, 0, 0, .25), inset 0 1px 0 rgba(255, 255, 255, .10);
    }

    .vc-myproj-btn:hover {
      background: rgba(255, 255, 255, .08);
      border-color: rgba(255, 255, 255, .28);
      color: #fff;
    }

    .vc-myproj-btn svg {
      opacity: .7;
      flex-shrink: 0;
    }

    .vc-myproj-btn .vc-mp-count {
      background: rgba(255, 255, 255, .12);
      border-radius: 10px;
      padding: 1px 6px;
      font-size: 10px;
      color: rgba(255, 255, 255, .6);
    }

    /* Slide-up projects panel — b.750 liquid-glass pass.
       Was opaque rgba(12,12,14,.93), so the heavy backdrop-filter
       never had anything to filter — read as a flat black slab.
       Now: milky white tint with a top-down sheen, canonical 40px
       blur + 1.8 saturate + slight brightness lift, luminous top
       edge, layered insets for top highlight / bottom darken /
       drop. The orbs and Optical bg now bloom through. */
    .vc-projects-panel {
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
      z-index: 9990;
      display: flex;
      flex-direction: column;
      background:
        linear-gradient(180deg,
          rgba(255, 255, 255, .12) 0%,
          rgba(255, 255, 255, .06) 38%,
          rgba(255, 255, 255, .04) 100%);
      -webkit-backdrop-filter: blur(40px) saturate(1.8) brightness(1.05);
      backdrop-filter: blur(40px) saturate(1.8) brightness(1.05);
      border-top: 1px solid rgba(255, 255, 255, .22);
      border-radius: 24px 24px 0 0;
      max-height: 60vh;
      transform: translateY(100%);
      transition: transform .3s cubic-bezier(.22, 1, .36, 1);
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .32) inset,
        0 -1px 0 rgba(0, 0, 0, .14) inset,
        0 -16px 64px rgba(0, 0, 0, .55);
      isolation: isolate;
    }

    .vc-projects-panel.open {
      transform: translateY(0);
    }

    .vc-pp-hd {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 18px 22px 12px;
      flex-shrink: 0;
      border-bottom: 1px solid rgba(255, 255, 255, .07);
    }

    .vc-pp-title {
      font-size: 13px;
      font-weight: 600;
      letter-spacing: .08em;
      color: rgba(255, 255, 255, .85);
      text-transform: uppercase;
    }

    /* b.750 — close puck pulled into liquid-glass language so it
       reads against the now-translucent panel. Local blur + sheen
       inset gives it presence without going opaque. */
    .vc-pp-close {
      background: rgba(255, 255, 255, .08);
      border: 1px solid rgba(255, 255, 255, .22);
      -webkit-backdrop-filter: blur(20px) saturate(1.5);
      backdrop-filter: blur(20px) saturate(1.5);
      border-radius: 50%;
      width: 28px;
      height: 28px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      color: rgba(255, 255, 255, .65);
      font-size: 14px;
      line-height: 1;
      transition: background .15s, color .15s, border-color .15s, transform .15s;
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .22) inset,
        0 4px 12px rgba(0, 0, 0, .25);
    }

    .vc-pp-close:hover {
      background: rgba(255, 255, 255, .16);
      border-color: rgba(255, 255, 255, .34);
      color: #fff;
      transform: scale(1.04);
    }

    .vc-pp-list {
      overflow-y: auto;
      padding: 12px 16px 28px;
      display: flex;
      flex-direction: column;
      gap: 8px;
      flex: 1;
    }

    .vc-pp-empty {
      text-align: center;
      color: rgba(255, 255, 255, .3);
      font-size: 13px;
      padding: 40px 0;
      line-height: 1.7;
    }

    .vc-proj-card {
      display: flex;
      align-items: flex-start;
      gap: 12px;
      background: rgba(255, 255, 255, .03);
      border: 1px solid rgba(255, 255, 255, .09);
      border-radius: 14px;
      padding: 12px 14px;
      cursor: pointer;
      transition: background .15s, border-color .15s;
      position: relative;
    }

    .vc-proj-card:hover {
      background: rgba(255, 255, 255, .06);
      border-color: rgba(255, 255, 255, .18);
    }

    .vc-proj-icon {
      width: 36px;
      height: 36px;
      border-radius: 10px;
      background: rgba(255, 255, 255, .06);
      border: 1px solid rgba(255, 255, 255, .10);
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 14px;
      flex-shrink: 0;
      color: rgba(255, 255, 255, .5);
    }

    .vc-proj-info {
      flex: 1;
      min-width: 0;
    }

    .vc-proj-name {
      font-size: 13px;
      font-weight: 500;
      color: rgba(255, 255, 255, .88);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      margin-bottom: 4px;
    }

    .vc-proj-meta {
      display: flex;
      align-items: center;
      gap: 6px;
      flex-wrap: wrap;
    }

    .vc-proj-badge {
      font-size: 10px;
      letter-spacing: .04em;
      color: rgba(255, 255, 255, .45);
      background: rgba(255, 255, 255, .06);
      border-radius: 8px;
      padding: 1px 7px;
      text-transform: uppercase;
    }

    .vc-proj-badge.solo {
      color: #7dd3fc;
      background: rgba(125, 211, 252, .10);
    }

    .vc-proj-badge.cowork {
      color: #a78bfa;
      background: rgba(167, 139, 250, .10);
    }

    .vc-proj-badge.complete {
      color: #86efac;
      background: rgba(134, 239, 172, .10);
    }

    .vc-proj-badge.draft {
      color: rgba(255, 255, 255, .35);
      background: rgba(255, 255, 255, .04);
    }

    .vc-proj-date {
      font-size: 10px;
      color: rgba(255, 255, 255, .3);
      margin-left: auto;
      white-space: nowrap;
      flex-shrink: 0;
    }

    .vc-proj-coins {
      font-size: 10px;
      color: rgba(255, 200, 80, .6);
    }

    .vc-proj-del {
      background: none;
      border: none;
      cursor: pointer;
      color: rgba(255, 255, 255, .2);
      font-size: 14px;
      padding: 2px 4px;
      border-radius: 6px;
      transition: color .15s, background .15s;
      flex-shrink: 0;
      align-self: center;
    }

    .vc-proj-del:hover {
      color: #f87171;
      background: rgba(248, 113, 113, .08);
    }

    .vc-pp-backdrop {
      position: fixed;
      inset: 0;
      z-index: 9989;
      background: rgba(0, 0, 0, 0);
      pointer-events: none;
      transition: background .3s;
    }

    .vc-pp-backdrop.open {
      background: rgba(0, 0, 0, .45);
      pointer-events: all;
    }

    /* ─── VIBE CODE ENGINE — visibility (b.588) ─────────────────
   When vibe tab is active, hide all Visual Studio surfaces
   (same list as chat-engine-active) and reveal #vibeCodeEngine.
   body[data-active-tab="vibe"] is set by setActiveTab() and by
   showVibeCode() which stamps it on <body>.
   ──────────────────────────────────────────────────────────── */
    body:not([data-active-tab="vibe"]) #vibeCodeEngine {
      display: none !important;
    }

    body[data-active-tab="vibe"] #vibeCodeEngine {
      display: flex !important;
    }

    body[data-active-tab="vibe"] .gallery,
    body[data-active-tab="vibe"] .composer,
    body[data-active-tab="vibe"] .composer-host,
    body[data-active-tab="vibe"] .modes-screen,
    body[data-active-tab="vibe"] .input-bar,
    body[data-active-tab="vibe"] .video-tip,
    body[data-active-tab="vibe"] .cinema-bar,
    body[data-active-tab="vibe"] .chat-actions,
    body[data-active-tab="vibe"] .director-bottom-btn,
    body[data-active-tab="vibe"] .director-summary,
    body[data-active-tab="vibe"] .director-default-bar,
    body[data-active-tab="vibe"] .manual-return-btn,
    body[data-active-tab="vibe"] #inputBar,
    body[data-active-tab="vibe"] footer.input-bar,
    body[data-active-tab="vibe"] .music-studio-host,
    body[data-active-tab="vibe"] .story-board,
    body[data-active-tab="vibe"] .controls,
    body[data-active-tab="vibe"] #chatEngine,
    body[data-active-tab="vibe"] .music-studio-inline-host {
      display: none !important;
    }

    /* b.681 — Specificity fix: [data-theme] .story-board.active (120) beats
   body[data-active-tab="vibe"] .story-board (111). Bump the Vibe selector
   to include [data-theme] so it wins at 220 and the scene card stops
   bleeding into Vibe Code mode. Same fix applied to Music Studio tab. */
    [data-theme] body[data-active-tab="vibe"] .story-board,
    [data-theme] body[data-active-tab="vibe"] .story-board.active,
    [data-theme] body[data-active-tab="music"] .story-board,
    [data-theme] body[data-active-tab="music"] .story-board.active {
      display: none !important;
    }

    /* THEME TOGGLE — single circle, icon only. Hover/focus reveals the
   full theme name in a caption pinned beneath the button. */
    .theme-toggle-circle {
      width: 40px !important;
      height: 40px !important;
      padding: 0 !important;
      border-radius: 50% !important;
      display: inline-flex !important;
      align-items: center !important;
      justify-content: center !important;
      /* b.227 — reverted to in-flow position. The theme circle lives
     in the header row below the MY COINS + MY ACCOUNT pills, as
     it was before b.226.
     2026-05-11 b.245 — nudged up by 15px via transform so it sits
     visually higher in the header without disturbing the flow of
     surrounding elements (margin/top would collapse adjacent
     siblings or shift the row). */
      position: relative !important;
      transform: translateY(-15px) !important;
      background: rgba(255, 255, 255, .06) !important;
      border: 1px solid rgba(255, 255, 255, .18) !important;
      -webkit-backdrop-filter: blur(20px) saturate(1.4) !important;
      backdrop-filter: blur(20px) saturate(1.4) !important;
      cursor: pointer !important;
      transition: all .2s ease !important;
    }

    .theme-toggle-circle:hover {
      background: rgba(255, 255, 255, .12) !important;
      border-color: rgba(255, 255, 255, .40) !important;
    }

    .theme-toggle-circle .ico {
      font-size: 18px !important;
      line-height: 1 !important;
      /* 2026-05-11 b.246 — always rotating. Continuous slow spin to
     telegraph this is the theme switcher and to add motion to the
     header. 8s/turn feels deliberate without being distracting.
     On hover we speed up to ~3s/turn so the user gets a clear
     "I'm hovering and this thing reacts" signal. */
      animation: themeSpin 8s linear infinite !important;
      transform-origin: 50% 50% !important;
      will-change: transform !important;
    }

    .theme-toggle-circle:hover .ico {
      animation-duration: 3s !important;
    }

    @keyframes themeSpin {
      from {
        transform: rotate(0deg);
      }

      to {
        transform: rotate(360deg);
      }
    }

    /* Floating caption — sits below the circle, only visible on hover.
   2026-05-10 b.196 — All current theme names ("My Garden", "Her Garden",
   "Dune", "Hanley", "Black", "Pop", "LSD") are short enough to sit
   centred under the button without clipping the viewport edge. So we
   centre the tip and rely on the natural narrow width of these
   labels. If a longer name is ever added, the `max-width` clamp keeps
   the tip from running off the screen — it'll wrap in place rather
   than overflow. */
    .theme-toggle-circle .theme-tip {
      position: absolute !important;
      top: calc(100% + 6px) !important;
      left: 50% !important;
      right: auto !important;
      transform: translateX(-50%) translateY(-4px) !important;
      white-space: nowrap !important;
      /* Clamp width to whatever's available between the tooltip's centre
     and either viewport edge (button is in top-right, so the right
     side is the tighter constraint). Doubled because the tooltip is
     centred on the button. */
      max-width: calc((100vw - 24px)) !important;
      padding: 6px 10px !important;
      border-radius: 999px !important;
      background: rgba(8, 8, 12, .78) !important;
      border: 1px solid rgba(255, 255, 255, .18) !important;
      -webkit-backdrop-filter: blur(20px) saturate(1.4) !important;
      backdrop-filter: blur(20px) saturate(1.4) !important;
      color: #fff !important;
      font-family: var(--font-display) !important;
      font-size: 11px !important;
      font-weight: 700 !important;
      letter-spacing: .06em !important;
      opacity: 0 !important;
      pointer-events: none !important;
      transition: opacity .2s ease, transform .2s ease !important;
      z-index: 50 !important;
    }

    .theme-toggle-circle:hover .theme-tip,
    .theme-toggle-circle:focus-visible .theme-tip {
      opacity: 1 !important;
      transform: translateX(-50%) translateY(0) !important;
    }

    /* ============================================================
   2026-05-10 b.162 — BRAND META + MODE PILL RELOCATION
   - Brand block adds a small two-line "BETA / VERSION 1" tag.
   - Mode pill moves from the header into the visual studio's
     .controls row (right edge, above the Create button) via JS.
   ============================================================ */

    /* Brand: BETA + build number sit inline beside AI STUDIO. Single
   row, no stacked lines. Build number auto-updates on every release. */
    .brand {
      display: inline-flex !important;
      align-items: center !important;
      gap: 10px !important;
    }

    .brand-beta {
      display: inline-flex !important;
      align-items: baseline !important;
      gap: 5px !important;
      padding: 0 0 0 8px !important;
      border-left: 1px solid rgba(255, 255, 255, .16) !important;
      font-family: var(--font-display) !important;
      text-transform: uppercase !important;
      letter-spacing: .14em !important;
    }

    .brand-beta-label {
      font-size: 9.5px !important;
      font-weight: 800 !important;
      color: rgba(255, 255, 255, .85) !important;
    }

    .brand-beta-num {
      font-size: 9.5px !important;
      font-weight: 700 !important;
      color: rgba(255, 255, 255, .55) !important;
      letter-spacing: .10em !important;
    }

    /* ============================================================
   2026-05-10 b.164 — TAB REDESIGN + MENU AUTO-COLLAPSE.
   Tabs (Chat / Visual / Music) are now individual 3D-feeling pills
   instead of a flat segmented strip. Each pill has a soft frosted
   surface, a subtle inner highlight, and a hover lift. The active
   one floats on top with a brighter border and inset glow.
   After 10s of no interaction, the whole tabs cluster animates
   INTO a single "MENU" pill in the center of the header. Hover or
   click MENU to expand the tabs back. Re-collapses on idle.
   ============================================================ */

    /* Reset the legacy flat-strip container — tabs no longer share one
   capsule. Each tab is its own pill, separated by gap. */
    [data-theme] .tabs {
      border: 0 !important;
      background: transparent !important;
      -webkit-backdrop-filter: none !important;
      backdrop-filter: none !important;
      border-radius: 0 !important;
      overflow: visible !important;
      height: auto !important;
      width: auto !important;
      display: inline-flex !important;
      align-items: center !important;
      gap: 8px !important;
      /* b.235 — Was `position: relative !important` here, which won
     specificity over the base `.tabs` rule's position:fixed and
     left the tabs anchored back in the header flex flow on the
     right. Override with fixed + viewport centring so the row is
     genuinely centred on the screen no matter which surface is
     active. */
      position: fixed !important;
      left: 50% !important;
      top: 24px !important;
      transform: translateX(-50%) !important;
      z-index: 20 !important;
    }

    /* Each tab pill — 3D-feeling: soft glass surface, inner top-light
   highlight, soft drop shadow that grows on hover (lift). */
    [data-theme] .tabs .tab {
      flex: none !important;
      height: 40px !important;
      padding: 0 18px !important;
      border-radius: 999px !important;
      background: linear-gradient(180deg,
          rgba(255, 255, 255, .10) 0%,
          rgba(255, 255, 255, .04) 50%,
          rgba(255, 255, 255, .02) 100%) !important;
      border: 1px solid rgba(255, 255, 255, .16) !important;
      -webkit-backdrop-filter: blur(28px) saturate(1.4) !important;
      backdrop-filter: blur(28px) saturate(1.4) !important;
      color: rgba(255, 255, 255, .78) !important;
      font-weight: 800 !important;
      font-size: 12px !important;
      letter-spacing: .06em !important;
      text-transform: uppercase !important;
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .18) inset,
        0 -1px 0 rgba(0, 0, 0, .20) inset,
        0 6px 18px -8px rgba(0, 0, 0, .50) !important;
      transition: transform .24s cubic-bezier(.2, .8, .2, 1),
        box-shadow .24s cubic-bezier(.2, .8, .2, 1),
        background .2s, color .2s, border-color .2s !important;
      cursor: pointer !important;
      white-space: nowrap !important;
    }

    [data-theme] .tabs .tab:hover {
      color: #ffffff !important;
      border-color: rgba(255, 255, 255, .32) !important;
      transform: translateY(-2px) !important;
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .30) inset,
        0 -1px 0 rgba(0, 0, 0, .22) inset,
        0 12px 28px -10px rgba(0, 0, 0, .60),
        0 0 24px rgba(255, 255, 255, .08) !important;
    }

    [data-theme] .tabs .tab.active {
      color: #ffffff !important;
      border-color: rgba(255, 255, 255, .55) !important;
      background: linear-gradient(180deg,
          rgba(255, 255, 255, .18) 0%,
          rgba(255, 255, 255, .08) 50%,
          rgba(255, 255, 255, .04) 100%) !important;
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .40) inset,
        0 0 0 1px rgba(255, 255, 255, .10) inset,
        0 0 22px rgba(255, 255, 255, .14),
        0 8px 22px -8px rgba(0, 0, 0, .55) !important;
    }

    [data-theme] .tabs .tab:active {
      transform: translateY(0) !important;
      box-shadow:
        0 1px 0 rgba(255, 255, 255, .18) inset,
        0 -1px 0 rgba(0, 0, 0, .22) inset,
        0 4px 10px -6px rgba(0, 0, 0, .55) !important;
    }

    /* MENU PILL — the collapsed state. The pill is intentionally TALLER
   than its visible region: ~140px total, but offset by `top: -85px`
   so most of the body lives ABOVE the viewport edge. Only the
   bottom ~55px shows on screen, with heavy bottom curves. The
   "MENU" label is anchored to the bottom of the box (flex-end +
   padding-bottom) so it reads inside the visible portion. */
    .tabs-menu-pill {
      display: none;
      align-items: flex-end;
      justify-content: center;
      position: fixed;
      top: -58px;
      /* visible portion ~24px */
      left: 50%;
      /* 2026-05-11 b.236 — optical centering. The blinking dot lives at
     left:10px with no counterweight on the right, so the pill's
     geometric center reads slightly left-of-center to the eye.
     Push the pill -16px to the right of true center so the
     perceived center lands on viewport center. */
      transform: translateX(calc(-50% - 16px));
      height: 82px;
      /* 20% more compact (was 100) */
      min-width: 128px;
      /* 20% narrower (was 160) */
      padding: 0 22px 6px;
      /* padding-bottom now centers
                                           MENU vertically in the
                                           visible 24px slice. */
      border-radius: 0 0 18px 18px;
      background: linear-gradient(180deg,
          rgba(255, 255, 255, .18) 0%,
          rgba(255, 255, 255, .08) 55%,
          rgba(255, 255, 255, .04) 100%);
      border: 1px solid rgba(255, 255, 255, .32);
      border-top: 0;
      -webkit-backdrop-filter: blur(28px) saturate(1.4);
      backdrop-filter: blur(28px) saturate(1.4);
      color: #ffffff;
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 11px;
      letter-spacing: .14em;
      text-transform: uppercase;
      line-height: 1;
      box-shadow:
        0 -1px 0 rgba(255, 255, 255, .22) inset,
        0 1px 0 rgba(0, 0, 0, .18) inset,
        0 6px 14px -6px rgba(0, 0, 0, .55);
      cursor: pointer;
      transition: top .24s cubic-bezier(.2, .8, .2, 1),
        transform .24s cubic-bezier(.2, .8, .2, 1),
        box-shadow .24s cubic-bezier(.2, .8, .2, 1),
        background .2s;
      z-index: 90;
    }

    /* Blinking dot — at the LEFT extreme of the pill, vertically
   centered with MENU text inside the visible 24px slice.
   Pill height 82, top -58 → pill bottom is 24px below viewport
   top. Visible center of the pill = y=12 in viewport. Dot
   `bottom: 9` puts dot bottom at viewport y=15, center at y=12. */
    .tabs-menu-pill::before {
      content: '';
      position: absolute;
      left: 10px;
      bottom: 9px;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: rgba(255, 255, 255, .85);
      box-shadow: 0 0 6px rgba(255, 255, 255, .6);
      animation: menuDot 2.4s ease-in-out infinite;
    }

    @keyframes menuDot {

      0%,
      100% {
        opacity: 1;
        transform: scale(1);
      }

      50% {
        opacity: .45;
        transform: scale(.7);
      }
    }

    .tabs-menu-pill:hover {
      /* On hover, slide DOWN by reducing the negative top offset.
     Most of the body still hides above the viewport, but the
     visible portion grows by 4px — feels like the tab is being
     "pulled out" when the cursor approaches. */
      top: -54px;
      /* was -58: slides 4px down */
      border-color: rgba(255, 255, 255, .55);
      background: linear-gradient(180deg,
          rgba(255, 255, 255, .26) 0%,
          rgba(255, 255, 255, .12) 55%,
          rgba(255, 255, 255, .06) 100%);
      box-shadow:
        0 -1px 0 rgba(255, 255, 255, .32) inset,
        0 1px 0 rgba(0, 0, 0, .18) inset,
        0 14px 32px -10px rgba(0, 0, 0, .60),
        0 0 28px rgba(255, 255, 255, .12);
    }

    /* COLLAPSED STATE — body class set by JS after 10s idle. Tabs
   shrink to zero width with a smooth scale, MENU pill fades in
   in their place. */
    /* Tabs cluster collapse — width + opacity, no transform. Avoids any
   collision with parent transforms and is GPU-friendly. */
    body.tabs-collapsed .tabs {
      opacity: 0 !important;
      pointer-events: none !important;
      width: 0 !important;
      max-width: 0 !important;
      margin-right: -8px !important;
      /* swallow the flex gap */
      transition: opacity .28s ease, width .28s ease, margin .28s ease !important;
      overflow: hidden !important;
      will-change: opacity, width;
    }

    body.tabs-collapsed .tabs-menu-pill {
      display: inline-flex;
      animation: menuPillIn .35s cubic-bezier(.2, .8, .2, 1) both;
    }

    body:not(.tabs-collapsed) .tabs {
      opacity: 1;
      transition: opacity .22s ease, width .22s ease, margin .22s ease !important;
    }

    body:not(.tabs-collapsed) .tabs-menu-pill {
      display: none;
    }

    /* IMPORTANT: keyframes preserve the centering translateX(-50%) that
   the base .tabs-menu-pill rule sets. Without it, the animation's
   `transform: scale(...)` would REPLACE the entire transform property,
   removing the centering — the pill would briefly appear with its
   left edge at viewport center (looking like it's on the right) before
   the animation ended and the base translateX(-50%) re-applied. That's
   what was causing the "weird right hand side" jitter. */
    @keyframes menuPillIn {

      /* 2026-05-11 b.236 — keyframes carry the same -16px optical offset
     as the base rule so the entrance animation lands the pill in its
     optically-centered resting position, not 16px to the left of it. */
      from {
        opacity: 0;
        transform: translateX(calc(-50% - 16px)) scale(.88) translateY(-6px);
      }

      to {
        opacity: 1;
        transform: translateX(calc(-50% - 16px)) scale(1) translateY(0);
      }
    }

    /* ============================================================
   2026-05-11 b.213 — MY COINS pill. Twin of .tabs-menu-pill,
   anchored to the top-RIGHT of the viewport instead of the centre
   (so it sits visually above where the .bal-card would have been
   in the header). Identical shape, dot, hover, and animation —
   only the horizontal anchor differs. Body class:
   .coins-collapsed (separate from .tabs-collapsed so the two pills
   collapse independently on their own idle timers).
   ============================================================ */
    .coins-menu-pill {
      display: none;
      align-items: flex-end;
      justify-content: center;
      position: fixed;
      top: -58px;
      /* visible portion ~24px */
      right: 64px;
      /* b.214 — shifted 40px left so
                                            the pill sits directly above
                                            where the .bal-card console
                                            appears on hover, not against
                                            the viewport edge. */
      left: auto;
      /* not centred */
      transform: translateY(0);
      height: 82px;
      min-width: 148px;
      /* slightly wider so "MY COINS" fits */
      padding: 0 22px 6px;
      text-align: center;
      /* b.218 — backup centring */
      border-radius: 0 0 18px 18px;
      background: linear-gradient(180deg,
          rgba(255, 255, 255, .18) 0%,
          rgba(255, 255, 255, .08) 55%,
          rgba(255, 255, 255, .04) 100%);
      border: 1px solid rgba(255, 255, 255, .32);
      border-top: 0;
      -webkit-backdrop-filter: blur(28px) saturate(1.4);
      backdrop-filter: blur(28px) saturate(1.4);
      color: #ffffff;
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 11px;
      letter-spacing: .14em;
      text-transform: uppercase;
      line-height: 1;
      box-shadow:
        0 -1px 0 rgba(255, 255, 255, .22) inset,
        0 1px 0 rgba(0, 0, 0, .18) inset,
        0 6px 14px -6px rgba(0, 0, 0, .55);
      cursor: pointer;
      transition: top .24s cubic-bezier(.2, .8, .2, 1),
        transform .24s cubic-bezier(.2, .8, .2, 1),
        box-shadow .24s cubic-bezier(.2, .8, .2, 1),
        background .2s;
      z-index: 90;
    }

    /* b.218 — Label sits inside the pill as a centred block so the
   text is centred against the FULL pill width, independent of the
   absolutely-positioned dot on the left. */
    .coins-menu-pill .cmp-label {
      display: block;
      width: 100%;
      text-align: center;
    }

    /* ============================================================
   2026-05-11 b.220 — MY ACCOUNT pill. Now a PERMANENT button at
   the top-right (no auto-collapse, no hover-to-expand). Same
   shape as the MENU + MY COINS pills so the three read as a
   coordinated set, but this one is always visible. Underlying
   .account-btn is hidden (display:none) — this pill is the only
   user-facing control. Label flips between "Sign in" /
   "My account" based on auth state.
   ============================================================ */

    /* 2026-05-12 b.414 — MY LIBRARY moved from a floating top-right pill
   into the .controls row, sitting immediately to the left of the
   Mode pill. JS relocates the element on first load (see
   relocateLibraryPill IIFE near the Mode-pill relocator); CSS class
   .library-pill-in-controls strips the fixed positioning and
   matches the Mode pill's height + glass treatment so the two read
   as siblings. The base .library-menu-pill rules below are kept as
   fallback styling in case relocation fails. */
    [data-theme] .controls .library-pill-in-controls {
      position: static !important;
      top: auto !important;
      right: auto !important;
      left: auto !important;
      height: auto !important;
      /* Match Mode pill: small inline glass pill, same padding + radius. */
      display: inline-flex !important;
      align-items: center !important;
      padding: 7px 26px 7px 22px !important;
      background: rgba(8, 8, 12, 0.20) !important;
      border: 1px solid rgba(255, 255, 255, 0.18) !important;
      border-radius: 999px !important;
      -webkit-backdrop-filter: blur(28px) saturate(1.4) !important;
      backdrop-filter: blur(28px) saturate(1.4) !important;
      color: rgba(255, 255, 255, 0.92) !important;
      font-family: var(--font-display) !important;
      font-weight: 700 !important;
      font-size: 11px !important;
      letter-spacing: .08em !important;
      text-transform: uppercase !important;
      min-height: 0 !important;
      box-shadow: 0 1px 0 rgba(255, 255, 255, .08) inset !important;
      transform: none !important;
      cursor: pointer !important;
      /* Order: sit immediately to the LEFT of the Mode pill which has
     margin-left:auto. Using order:1 + margin-left:auto puts library
     at the right group but BEFORE the mode pill, since mode pill
     has order:auto (0) and stays last via DOM order. We append the
     library pill BEFORE the mode pill in DOM, so natural order
     handles it; just give it margin-left:auto so the whole right
     cluster (library + mode) is right-aligned together. */
      margin-left: auto !important;
    }

    [data-theme] .controls .library-pill-in-controls+.mode-pill-in-controls {
      margin-left: 8px !important;
      /* gap between library + mode, instead of pushing mode to the right alone */
    }

    [data-theme] .controls .library-pill-in-controls:hover {
      background: rgba(8, 8, 12, 0.35) !important;
      border-color: rgba(255, 255, 255, 0.40) !important;
    }

    [data-theme] .controls .library-pill-in-controls::before {
      /* Keep the blinking dot but anchor it to the inline pill height. */
      content: '';
      position: absolute;
      left: 10px;
      top: 50%;
      transform: translateY(-50%);
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: rgba(255, 255, 255, .92);
      box-shadow: 0 0 6px rgba(255, 255, 255, .65);
      animation: menuDot 2.4s ease-in-out infinite;
      z-index: 2;
    }

    [data-theme] .controls .library-pill-in-controls {
      position: relative !important;
    }

    /* When inline, hide on chat/music + small screens via the .controls
   ancestor's tab data attribute. */
    body[data-active-tab="chat"] .controls .library-pill-in-controls,
    body[data-active-tab="music"] .controls .library-pill-in-controls {
      display: none !important;
    }

    /* 2026-05-12 b.422 — Swapped Coins and Library positions per user
   request. New cluster order, left to right:
     • Library  → right:392  (LEFTMOST)
     • Coins    → right:236  (middle)
     • Account  → right:80   (rightmost, anchor)
   Same geometry recipe as MY ACCOUNT for all three so the pills read
   as identical siblings. */
    .library-menu-pill {
      display: inline-flex;
      align-items: flex-end;
      justify-content: center;
      position: fixed;
      top: -58px;
      right: 392px;
      left: auto;
      transform: translateY(0);
      height: 82px;
      min-width: 148px;
      padding: 0 22px 6px;
      text-align: center;
      border-radius: 0 0 18px 18px;
      background: linear-gradient(180deg,
          rgba(255, 255, 255, .18) 0%,
          rgba(255, 255, 255, .08) 55%,
          rgba(255, 255, 255, .04) 100%);
      border: 1px solid rgba(255, 255, 255, .32);
      border-top: 0;
      -webkit-backdrop-filter: blur(28px) saturate(1.4);
      backdrop-filter: blur(28px) saturate(1.4);
      color: #ffffff;
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 11px;
      letter-spacing: .14em;
      text-transform: uppercase;
      line-height: 1;
      box-shadow:
        0 -1px 0 rgba(255, 255, 255, .22) inset,
        0 1px 0 rgba(0, 0, 0, .18) inset,
        0 6px 14px -6px rgba(0, 0, 0, .55);
      cursor: pointer;
      transition: top .24s cubic-bezier(.2, .8, .2, 1),
        box-shadow .24s cubic-bezier(.2, .8, .2, 1),
        background .2s;
      z-index: 90;
    }

    .library-menu-pill::before {
      content: '';
      position: absolute;
      left: 10px;
      bottom: 9px;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: rgba(255, 255, 255, .85);
      box-shadow: 0 0 6px rgba(255, 255, 255, .6);
      animation: menuDot 2.4s ease-in-out infinite;
    }

    .library-menu-pill .lmp-label {
      display: block;
      width: 100%;
      text-align: center;
    }

    /* 2026-05-12 b.424 — Centre the LABEL on each of the three header
   pills against the FULL pill width — not just the inside-of-padding
   width. Previous rule (display:block; width:100%; text-align:center)
   made the label 100% of the content area, which is parent_width −
   44px (22px padding each side). The text read slightly right of
   true centre because the dot occupies the left padding zone
   visually. Switching the label to position:absolute spanning the
   FULL pill width centers the text against the whole pill, while
   the dot stays exactly where it was (absolute at left:10px /
   bottom:9px). Applied to all three pills (Coins / Library /
   Account) identically so they read as a cohesive set. */
    .coins-menu-pill .cmp-label,
    .library-menu-pill .lmp-label,
    .account-menu-pill .amp-label {
      position: absolute !important;
      left: 0 !important;
      right: 0 !important;
      bottom: 9px !important;
      /* aligns the text's baseline with the dot */
      width: auto !important;
      text-align: center !important;
      pointer-events: none;
    }

    .library-menu-pill:hover {
      top: -50px;
      background: linear-gradient(180deg,
          rgba(255, 255, 255, .26) 0%,
          rgba(255, 255, 255, .12) 55%,
          rgba(255, 255, 255, .06) 100%);
    }

    /* 2026-05-12 b.422 — Coins now sits in the MIDDLE slot (was left in
   b.419). Library took the leftmost; Coins moves to right:236 to
   sit between Library and Account. */
    .coins-menu-pill {
      right: 236px !important;
    }

    /* 2026-05-12 b.411 — Library pill is now available across EVERY
   sub-mode of Visual Studio (Standard, Story, Product, Pet Studio).
   Earlier rule hid it inside Story Mode because Story had its own
   in-header My library button; user wants ONE consistent affordance
   that works everywhere, so the top-right pill stays visible across
   all sub-modes. Still hidden on Chat / Music tabs (where there's no
   gallery to browse). */
    body[data-active-tab="chat"] .library-menu-pill,
    body[data-active-tab="music"] .library-menu-pill {
      display: none !important;
    }

    @media (max-width: 720px) {
      .library-menu-pill {
        display: none !important;
      }
    }

    /* b.922 — .music-menu-pill removed. Music Studio Expose button
       beside the input bar replaces it. See styles/music-studio.css
       for the new Expose button + full-screen gallery overlay. */

    .account-menu-pill {
      display: inline-flex;
      /* always visible */
      align-items: flex-end;
      justify-content: center;
      position: fixed;
      top: -58px;
      right: 80px;
      /* b.230 — reverted to b.228
                                            value. The b.229 240px push
                                            caused layout regressions
                                            the user wanted undone. */
      left: auto;
      transform: translateY(0);
      height: 82px;
      min-width: 148px;
      padding: 0 22px 6px;
      text-align: center;
      border-radius: 0 0 18px 18px;
      background: linear-gradient(180deg,
          rgba(255, 255, 255, .18) 0%,
          rgba(255, 255, 255, .08) 55%,
          rgba(255, 255, 255, .04) 100%);
      border: 1px solid rgba(255, 255, 255, .32);
      border-top: 0;
      -webkit-backdrop-filter: blur(28px) saturate(1.4);
      backdrop-filter: blur(28px) saturate(1.4);
      color: #ffffff;
      font-family: var(--font-display);
      font-weight: 800;
      font-size: 11px;
      letter-spacing: .14em;
      text-transform: uppercase;
      line-height: 1;
      box-shadow:
        0 -1px 0 rgba(255, 255, 255, .22) inset,
        0 1px 0 rgba(0, 0, 0, .18) inset,
        0 6px 14px -6px rgba(0, 0, 0, .55);
      cursor: pointer;
      transition: top .24s cubic-bezier(.2, .8, .2, 1),
        box-shadow .24s cubic-bezier(.2, .8, .2, 1),
        background .2s;
      z-index: 90;
    }

    .account-menu-pill::before {
      content: '';
      position: absolute;
      left: 10px;
      bottom: 9px;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: rgba(255, 255, 255, .85);
      box-shadow: 0 0 6px rgba(255, 255, 255, .6);
      animation: menuDot 2.4s ease-in-out infinite;
    }

    /* 2026-05-11 b.247 — mirror the .cmp-label centering on the account
   pill so the SIGN IN / MY ACCOUNT label is centred against the
   full pill width, independent of the absolutely-positioned dot.
   Without this, the label was a content-width span centred only
   via its parent's flex justify-content — fine in isolation, but
   the coins pill had width:100% text-align:center on its label and
   the account pill didn't, so the two pills used different
   centring strategies and the labels read at very slightly
   different positions. This makes them identical. */
    .account-menu-pill .amp-label {
      display: block;
      width: 100%;
      text-align: center;
    }

    .account-menu-pill:hover {
      top: -54px;
      border-color: rgba(255, 255, 255, .55);
      background: linear-gradient(180deg,
          rgba(255, 255, 255, .26) 0%,
          rgba(255, 255, 255, .12) 55%,
          rgba(255, 255, 255, .06) 100%);
      box-shadow:
        0 -1px 0 rgba(255, 255, 255, .32) inset,
        0 1px 0 rgba(0, 0, 0, .18) inset,
        0 14px 32px -10px rgba(0, 0, 0, .60),
        0 0 28px rgba(255, 255, 255, .12);
    }

    .account-menu-pill .amp-label {
      display: block;
      width: 100%;
      text-align: center;
    }

    /* Blinking dot — same spec as .tabs-menu-pill::before. */
    .coins-menu-pill::before {
      content: '';
      position: absolute;
      left: 10px;
      bottom: 9px;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: rgba(255, 255, 255, .85);
      box-shadow: 0 0 6px rgba(255, 255, 255, .6);
      animation: menuDot 2.4s ease-in-out infinite;
    }

    .coins-menu-pill:hover {
      top: -54px;
      border-color: rgba(255, 255, 255, .55);
      background: linear-gradient(180deg,
          rgba(255, 255, 255, .26) 0%,
          rgba(255, 255, 255, .12) 55%,
          rgba(255, 255, 255, .06) 100%);
      box-shadow:
        0 -1px 0 rgba(255, 255, 255, .32) inset,
        0 1px 0 rgba(0, 0, 0, .18) inset,
        0 14px 32px -10px rgba(0, 0, 0, .60),
        0 0 28px rgba(255, 255, 255, .12);
    }

    /* Collapsed state — bal-card shrinks to zero, coins-menu-pill drops in. */
    body.coins-collapsed .bal-card {
      opacity: 0 !important;
      pointer-events: none !important;
      width: 0 !important;
      max-width: 0 !important;
      margin-right: -8px !important;
      transition: opacity .28s ease, width .28s ease, margin .28s ease !important;
      overflow: hidden !important;
      will-change: opacity, width;
    }

    body.coins-collapsed .coins-menu-pill {
      display: inline-flex;
      animation: coinsPillIn .35s cubic-bezier(.2, .8, .2, 1) both;
    }

    body:not(.coins-collapsed) .bal-card {
      opacity: 1;
      transition: opacity .22s ease, width .22s ease, margin .22s ease !important;
    }

    body:not(.coins-collapsed) .coins-menu-pill {
      display: none;
    }

    /* Keyframe — note this one has NO translateX(-50%) because the pill
   is right-anchored, not centre-anchored. Otherwise identical to
   menuPillIn. */
    @keyframes coinsPillIn {
      from {
        opacity: 0;
        transform: scale(.88) translateY(-6px);
      }

      to {
        opacity: 1;
        transform: scale(1) translateY(0);
      }
    }


/* ════════════════════════════════════════════════════════════════════
   FOUR BACKGROUND THEMES (b.168).
   Extracted in b.862. 548 lines from index.html top inline <style>.
   Includes:
   - FOUR BACKGROUND THEMES intro (b.168, rebuilt with motion)
   - THEME 4 — LSD (static PNG fullscreen)
   - THEME 3 — TRIPPY (optical illusion, b.192 endless flow)
   - THEME 5 — DIFFUSED (HomePod top-color, warm autumn flow)
   - THEME 6 — BLACK (pure #000, b.191)
   ════════════════════════════════════════════════════════════════════ */

    /* ============================================================
   2026-05-10 b.168 — FOUR BACKGROUND THEMES (rebuilt with motion).
   All four are CSS-only (no video). Trippy 1 / 2 / Diffused run
   like videos: continuous, visible motion at all times. Each has a
   completely distinct palette. Multiple layered animated pseudos
   give the appearance of a high-bitrate motion graphic.
   No bright whites — text + liquid glass read cleanly on top.
   ============================================================ */

    /* Hide the legacy 6 orbs for the procedural + image themes. */
    html[data-theme="trippy-1"] .orb,
    html[data-theme="diffused"] .orb,
    html[data-theme="black"] .orb,
    html[data-theme="lsd"] .orb {
      display: none !important;
    }

    /* Make sure the bg-stage hosts our pseudo layers properly. */
    html[data-theme="trippy-1"] .bg-stage,
    html[data-theme="diffused"] .bg-stage,
    html[data-theme="lsd"] .bg-stage {
      position: fixed !important;
      inset: 0 !important;
      overflow: hidden !important;
    }

    /* ============================================================
   THEME 4 — LSD · static PNG fullscreen
   The PNG is already an optical illusion (concentric rainbow rings).
   2026-05-10 b.188 — Bottomless theme deleted entirely.
   ============================================================ */

    /* LSD — STATIC fullscreen PNG. No rotation, no hue cycle. The
   image-rendering hints tell the browser to favour quality when
   scaling up (so the concentric rings stay crisp on 4K screens). */
    html[data-theme="lsd"] .bg-stage {
      background: #0a0010 !important;
      overflow: hidden !important;
    }

    html[data-theme="lsd"] .bg-stage::before {
      content: '' !important;
      position: absolute !important;
      inset: 0 !important;
      /* exact viewport */
      background-image: url('Thems/L%3FD.png') !important;
      background-size: cover !important;
      background-position: center center !important;
      background-repeat: no-repeat !important;
      image-rendering: auto !important;
      image-rendering: -webkit-optimize-contrast !important;
      image-rendering: high-quality !important;
      filter: saturate(1.3) contrast(1.1) !important;
      animation: none !important;
      /* STATIC */
      pointer-events: none !important;
      z-index: 1 !important;
      opacity: 1 !important;
    }

    html[data-theme="lsd"] .bg-stage::after {
      display: none !important;
    }

    /* ============================================================
   THEME 3 — TRIPPY · OPTICAL ILLUSION (b.192 — endless flow)
   Two counter-rotating ring layers, both visible at full opacity
   at all times, sharing the same colour palette. The previous
   build crossfaded between two DIFFERENT palettes (magenta+cyan
   vs gold+violet) over a scale 0 → 2.4 cycle — at the fade
   boundary the user could see a visible "square" / blink as the
   palette swapped and one layer popped in from near-zero scale.
   Fix: identical palette on both layers, no opacity fading, no
   scale-from-zero pop. Just continuous rotation + a subtle scale
   breath (1 ↔ 1.06) that loops back to its starting value, so
   nothing ever snaps. The vortex feel comes from the counter-
   rotation moiré between the two ring layers.
   ============================================================ */
    html[data-theme="trippy-1"] .bg-stage {
      background:
        radial-gradient(ellipse 100% 100% at 50% 50%,
          #0a001a 0%,
          #03000d 60%,
          #000005 100%) !important;
      transform: translateZ(0) !important;
      backface-visibility: hidden !important;
    }

    /* Shared 4-colour ring palette for BOTH layers. Magenta + cyan
   give the strongest retinal moiré; gold + violet add chromatic
   richness without ever creating a dominant-colour swap when one
   layer fades against the other (because they don't fade — both
   layers stay at 1.0 opacity throughout). */
    html[data-theme="trippy-1"] .bg-stage::before,
    html[data-theme="trippy-1"] .bg-stage::after {
      content: '' !important;
      display: block !important;
      position: absolute !important;
      top: 50% !important;
      left: 50% !important;
      /* b.193 — 250vmax so a rotated square's edge can NEVER expose
     a viewport corner. (At rotation R, the closest point of the
     rotated square's edge to the centre is half the side length;
     a 250vmax square's edge is always 125vmax from centre, far
     beyond any 16:9 viewport corner which sits at ~57vmax max.) */
      width: 250vmax !important;
      height: 250vmax !important;
      margin: -125vmax 0 0 -125vmax !important;
      /* perfect centering */
      inset: auto !important;
      background-image: none !important;
      background:
        repeating-radial-gradient(circle at 50% 50%,
          rgba(255, 30, 200, .55) 0,
          rgba(255, 30, 200, .55) 28px,
          rgba(30, 230, 220, .55) 28px,
          rgba(30, 230, 220, .55) 56px,
          rgba(255, 200, 30, .50) 56px,
          rgba(255, 200, 30, .50) 84px,
          rgba(140, 30, 255, .55) 84px,
          rgba(140, 30, 255, .55) 112px) !important;
      background-size: auto !important;
      mix-blend-mode: screen !important;
      filter: contrast(1.20) saturate(1.20) !important;
      pointer-events: none !important;
      opacity: 1 !important;
      transform-origin: 50% 50% !important;
      will-change: transform !important;
      backface-visibility: hidden !important;
    }

    /* LAYER 1 — one-way outward scale + clockwise rotation. Combined
   into ONE keyframe because CSS honours only one transform per
   element per frame. The scale path is `1.00 → 1.10 → 1.38 → 1.85
   → 2.50` over 0%/25%/50%/75%/100% — this is a t² ease-in baked
   into keyframe positions, so with `linear` animation timing the
   visible scale ramp accelerates over the cycle (slow start, fast
   end). Rotation progresses linearly (0° → 360°) so the spin
   feels steady underneath the speeding-up zoom. */
    html[data-theme="trippy-1"] .bg-stage::before {
      z-index: 1 !important;
      animation: t1Forward 16s linear infinite !important;
    }

    /* LAYER 2 — same scale curve, counter-rotating, offset by HALF a
   cycle (-8s). When layer 1 snaps from scale 2.5 back to 1.0,
   layer 2 is at scale ~1.38 (mid-cycle) carrying the dominant
   visible pattern, so the snap is hidden. Same palette across
   both layers means no colour change at the seam. */
    html[data-theme="trippy-1"] .bg-stage::after {
      z-index: 2 !important;
      animation: t1ForwardReverse 16s linear infinite -8s !important;
    }

    /* One-way scale + rotation. Scale curve is t² ease-in expressed
   as keyframe positions: at t=25% we're only 6% of the way scale-
   wise; at t=75% we're 56% — most of the visible expansion
   happens in the second half of the cycle, which is the
   "speed keeps growing" feel. */
    @keyframes t1Forward {
      0% {
        transform: scale(1.00) rotate(0deg);
      }

      25% {
        transform: scale(1.10) rotate(90deg);
      }

      50% {
        transform: scale(1.38) rotate(180deg);
      }

      75% {
        transform: scale(1.85) rotate(270deg);
      }

      100% {
        transform: scale(2.50) rotate(360deg);
      }
    }

    @keyframes t1ForwardReverse {
      0% {
        transform: scale(1.00) rotate(0deg);
      }

      25% {
        transform: scale(1.10) rotate(-90deg);
      }

      50% {
        transform: scale(1.38) rotate(-180deg);
      }

      75% {
        transform: scale(1.85) rotate(-270deg);
      }

      100% {
        transform: scale(2.50) rotate(-360deg);
      }
    }

    /* ============================================================
   THEME 5 — DIFFUSED · HomePod top-color (warm autumn flow)
   Amber / salmon / lavender / dusty plum / soft peach. Five
   amorphous color blobs each with their own drift + scale loop
   running at different rates → constant organic morph.
   ============================================================ */
    /* 2026-05-10 — base color was near-black (#0d0710). Per user
   "no black" — replaced with a deep wine/plum that lives inside
   the Diffused palette (rgb(180,90,160) lavender → darken to
   rgb(40,18,32)). Keeps the warm desert mood without ever going
   to true black. */
    html[data-theme="diffused"] .bg-stage {
      background: rgb(48, 22, 38) !important;
    }

    /* Diffused ::before — DESERT palette unchanged. Each blob now has
   its own animation track with a different rate, so they NEVER
   sync. Also adds size-morph (the blobs scale up and down
   independently). Result: organic, never-repeats-the-same-twice. */
    html[data-theme="diffused"] .bg-stage::before {
      content: '' !important;
      position: absolute !important;
      inset: -15% !important;
      background-image: none !important;
      background:
        radial-gradient(ellipse 60% 50% at 30% 30%, rgba(220, 130, 80, .60) 0%, transparent 65%),
        radial-gradient(ellipse 50% 60% at 75% 60%, rgba(180, 90, 160, .55) 0%, transparent 65%),
        radial-gradient(ellipse 45% 45% at 70% 25%, rgba(240, 180, 100, .45) 0%, transparent 65%),
        radial-gradient(ellipse 55% 55% at 20% 75%, rgba(140, 80, 180, .55) 0%, transparent 70%),
        radial-gradient(ellipse 60% 50% at 50% 90%, rgba(220, 90, 100, .50) 0%, transparent 70%) !important;
      /* Each blob has a DIFFERENT background-size so they morph at
     different rates when their position cycles. */
      background-size: 240% 220%, 200% 280%, 260% 180%, 180% 260%, 220% 240% !important;
      mix-blend-mode: screen !important;
      filter: blur(8px) saturate(1.25) !important;
      /* 4 different animations on the same element, each with its own
     period, easing, and direction → result never repeats inside
     a 5-minute window. Drift1 is the largest, slow; Drift1b is a
     faster secondary; Drift1c is a long-period scale wobble; Hue1
     keeps the colors slowly migrating. */
      animation:
        dDrift1 31s ease-in-out infinite alternate,
        dDrift1b 19s linear infinite,
        dDrift1c 43s ease-in-out infinite alternate,
        dHue1 67s linear infinite !important;
      pointer-events: none !important;
      z-index: 1 !important;
      opacity: 1 !important;
      transform-origin: 50% 50% !important;
    }

    /* Diffused ::after — second layer, completely different motion
   profile so the two layers fight each other organically. */
    html[data-theme="diffused"] .bg-stage::after {
      content: '' !important;
      display: block !important;
      position: absolute !important;
      inset: -15% !important;
      background-image: none !important;
      background:
        radial-gradient(ellipse 70% 60% at 50% 40%, rgba(255, 160, 120, .45) 0%, transparent 65%),
        radial-gradient(ellipse 50% 80% at 80% 70%, rgba(120, 100, 200, .45) 0%, transparent 65%),
        radial-gradient(ellipse 60% 50% at 15% 50%, rgba(200, 100, 140, .50) 0%, transparent 70%),
        radial-gradient(ellipse 40% 70% at 90% 20%, rgba(180, 140, 90, .42) 0%, transparent 70%),
        radial-gradient(ellipse 80% 40% at 30% 85%, rgba(160, 90, 130, .45) 0%, transparent 70%) !important;
      background-size: 280% 200%, 220% 280%, 320% 200%, 200% 240%, 260% 220% !important;
      mix-blend-mode: screen !important;
      filter: blur(12px) saturate(1.3) !important;
      animation:
        dDrift2 37s ease-in-out infinite alternate,
        dDrift2b 23s linear infinite reverse,
        dDrift2c 51s ease-in-out infinite alternate,
        dHue2 83s linear infinite reverse !important;
      pointer-events: none !important;
      z-index: 2 !important;
      opacity: 1 !important;
      transform-origin: 50% 50% !important;
    }

    /* — DRIFT1: slow large-amplitude position drift (5 blobs) — */
    @keyframes dDrift1 {
      0% {
        background-position: 0% 0%, 100% 0%, 0% 100%, 100% 100%, 50% 50%;
      }

      25% {
        background-position: 40% 60%, 60% 40%, 100% 20%, 0% 80%, 20% 20%;
      }

      50% {
        background-position: 100% 40%, 0% 60%, 100% 0%, 0% 40%, 80% 80%;
      }

      75% {
        background-position: 60% 100%, 40% 80%, 60% 60%, 80% 20%, 10% 60%;
      }

      100% {
        background-position: 0% 60%, 100% 20%, 0% 80%, 100% 60%, 100% 50%;
      }
    }

    /* — DRIFT1B: rotation cycle (continuous, not synced with drift) — */
    @keyframes dDrift1b {
      from {
        transform: rotate(0deg);
      }

      to {
        transform: rotate(360deg);
      }
    }

    /* — DRIFT1C: scale wobble (long period, very subtle) — */
    @keyframes dDrift1c {

      0%,
      100% {
        filter: blur(8px) saturate(1.20);
      }

      50% {
        filter: blur(14px) saturate(1.45);
      }
    }

    /* — HUE1: slow color migration — */
    @keyframes dHue1 {
      from {
        /* base colors */
      }

      to {
        /* same as start; we cycle hue via element filter elsewhere */
      }
    }

    /* — DRIFT2: second layer, completely different positions — */
    @keyframes dDrift2 {
      0% {
        background-position: 100% 100%, 0% 0%, 100% 50%, 0% 100%, 50% 0%;
      }

      20% {
        background-position: 60% 40%, 40% 100%, 80% 0%, 60% 20%, 10% 80%;
      }

      40% {
        background-position: 0% 20%, 60% 100%, 0% 40%, 100% 60%, 90% 30%;
      }

      60% {
        background-position: 80% 60%, 20% 20%, 40% 100%, 60% 100%, 20% 60%;
      }

      80% {
        background-position: 20% 100%, 80% 40%, 60% 20%, 40% 60%, 70% 90%;
      }

      100% {
        background-position: 40% 60%, 80% 20%, 60% 100%, 20% 40%, 50% 20%;
      }
    }

    @keyframes dDrift2b {
      from {
        transform: rotate(0deg) scale(1);
      }

      50% {
        transform: rotate(120deg) scale(1.08);
      }

      to {
        transform: rotate(360deg) scale(1);
      }
    }

    @keyframes dDrift2c {

      0%,
      100% {
        filter: blur(12px) saturate(1.30);
      }

      33% {
        filter: blur(18px) saturate(1.50);
      }

      66% {
        filter: blur(10px) saturate(1.20);
      }
    }

    @keyframes dHue2 {
      from {}

      to {}
    }

    /* ============================================================
   THEME 6 — BLACK · pure #000 (b.191 per user request)
   Absolute black across the whole stage. No gradient, no scrim,
   no pseudo-element layers. Body fallback also gets locked to
   black so any small chrome pixels around the stage match.
   ============================================================ */
    html[data-theme="black"] {
      background: #000 !important;
    }

    html[data-theme="black"] body {
      background: #000 !important;
    }

    html[data-theme="black"] .bg-stage {
      background: #000 !important;
    }

    html[data-theme="black"] .bg-stage::before,
    html[data-theme="black"] .bg-stage::after {
      display: none !important;
    }

    /* Kill any tinted scrim / vignette overlays the base stage uses. */
    html[data-theme="black"] .bg-scrim,
    html[data-theme="black"] .bg-vignette {
      display: none !important;
    }

    /* MODE PILL relocated into .controls. Pin it to the right edge of
   the controls row (above the input bar's Create button) using
   margin-left:auto. The .controls row uses gap:8px so the other
   pills hug the LEFT edge, and the mode pill snaps to the right. */
    [data-theme] .controls .mode-pill-in-controls {
      margin-left: auto !important;
      /* Match the .toggle-grp button pill recipe so it reads as the
     same family. */
      background: rgba(8, 8, 12, 0.20) !important;
      border: 1px solid rgba(255, 255, 255, 0.18) !important;
      border-radius: 999px !important;
      -webkit-backdrop-filter: blur(28px) saturate(1.4) !important;
      backdrop-filter: blur(28px) saturate(1.4) !important;
      color: rgba(255, 255, 255, 0.92) !important;
      font-weight: 700 !important;
      font-size: 11px !important;
      letter-spacing: .08em !important;
      text-transform: uppercase !important;
      padding: 7px 13px !important;
      height: auto !important;
      min-height: 0 !important;
      box-shadow: 0 1px 0 rgba(255, 255, 255, .08) inset !important;
    }

    [data-theme] .controls .mode-pill-in-controls:hover {
      background: rgba(8, 8, 12, 0.35) !important;
      border-color: rgba(255, 255, 255, 0.40) !important;
    }

    /* 2026-05-12 b.363 — Tuck-away state. When the user is in any mode
   other than Standard, the pill slides to the right of its row so
   only the amber blinking light + a small sliver remains on screen.
   Hover / focus / active brings it back smoothly. The constant
   bounce animation is paused while tucked so the static translateX
   actually applies (CSS animations always override static transforms,
   so we have to neutralise it on this state). */
    [data-theme] .controls .mode-pill-in-controls.tucked {
      /* 2026-05-12 b.366 — Slide distance is now dynamic. JS measures the
     pill's bounding rect at tuck time and sets --tuck-x so the visible
     sliver lands at exactly 22px regardless of viewport width. The
     fixed `calc(100% - 22px)` from b.365 worked on mobile but on
     desktops with larger .input-bar padding it still left a couple
     of letters peeking past the right edge. Fallback below covers
     the brief window before JS runs. */
      transform: translateX(var(--tuck-x, calc(100% - 6px))) !important;
      transition:
        transform .35s cubic-bezier(.4, 0, .2, 1),
        background .15s, border-color .15s !important;
      animation: none !important;
      /* Cursor still reads as interactive — the sliver is the tap target. */
      cursor: pointer !important;
    }

    /* 2026-05-12 b.367 — Expand-on-hover replaced with a JS-managed
   `.hold-open` class. The pill expands on mouseenter / touchstart /
   focus and stays expanded for 2s after the user moves away. Pure
   CSS :hover collapsed the pill the instant the pointer left, which
   made quick hover-in/out feel like a stutter — the 2s hold dampens
   that. .hold-open just overrides the tucked transform back to 0
   while it's on. */
    [data-theme] .controls .mode-pill-in-controls.tucked.hold-open,
    [data-theme] .controls .mode-pill-in-controls.tucked:active {
      transform: translateX(0) !important;
    }

    /* MKS mode pill tuck — mirrors .mode-pill-in-controls.tucked exactly */
    [data-theme] #mksModePill.tucked {
      transform: translateX(var(--tuck-x, calc(100% - 6px))) !important;
      transition:
        transform .35s cubic-bezier(.4, 0, .2, 1),
        background .15s, border-color .15s !important;
      animation: none !important;
      cursor: pointer !important;
    }

    [data-theme] #mksModePill.tucked.hold-open,
    [data-theme] #mksModePill.tucked:active {
      transform: translateX(0) !important;
    }

    /* Make sure the row that holds the pill doesn't clip the tucked
   portion via overflow. Without this, the right-tucked half can be
   clipped invisibly by .controls / .input-bar and the user can't
   even hover the visible sliver to expand it. */
    [data-theme] .controls:has(.mode-pill-in-controls.tucked),
    [data-theme] .input-bar:has(.mode-pill-in-controls.tucked) {
      overflow: visible !important;
    }

    /* When the mode pill lives inside .controls, the global CSS rule
   that hides it on chat / music tabs no longer applies to its new
   parent — but it still does because the pill ID is the same and
   we keep the [body[data-active-tab=…] .mode-pill-top] selector
   active. Reinforce here. */
    body[data-active-tab="chat"] .controls .mode-pill-in-controls,
    body[data-active-tab="music"] .controls .mode-pill-in-controls {
      display: none !important;
    }

    /* 2026-05-12 b.313 — PERSISTENT MODE PILL (revised).
   The pill keeps its original home: right edge of .controls, above
   the Create button. Story Mode + Director hide .input-shell (and
   .controls) via visibility:hidden. Crucially, visibility:visible on
   a descendant ALWAYS overrides inherited hidden (unlike display:none
   which collapses the box). So we just bump visibility back to visible
   on the pill itself, in every place where its ancestor would hide it.
   No repositioning needed — the pill stays in its in-row layout slot. */
    body.in-story-mode .input-shell .controls #modePillTop,
    body.in-story-mode.director-default-on .input-shell #modePillTop,
    body.in-story-mode.director-default-on .input-shell .controls #modePillTop,
    .input-shell.edit-mode .controls #modePillTop,
    .input-shell.post-image .controls #modePillTop {
      visibility: visible !important;
      pointer-events: auto !important;
      display: inline-flex !important;
    }


/* ════════════════════════════════════════════════════════════════════
   MAIN — re-homed from chat.css final-sweep in b.870.
   This was originally extracted to chat.css in b.864 as part of the
   "FINAL MEGA-BLOCK SWEEP" cleanup, but architecturally it belongs
   here in universal.css (it owns the .main app container layout used
   by every surface, not just chat). 122 lines moved over.
   ════════════════════════════════════════════════════════════════════ */

    /* ============================================================
   MAIN
   ============================================================ */
    .main {
      flex: 1;
      overflow: hidden;
      display: flex;
      flex-direction: column;
      position: relative;
      z-index: 5
    }

    /* Music Studio host — fills .main, transparent so the parent's
   bg-stage orbs show through. Iframe fills the host completely
   with no border. Hidden by default — setActiveTab() flips it on. */
    .music-studio-host {
      position: absolute;
      inset: 0;
      display: none;
      z-index: 6;
      background: transparent;
    }

    .music-studio-host[data-open="true"] {
      display: block;
    }

    .music-studio-host iframe {
      width: 100%;
      height: 100%;
      border: 0;
      background: transparent;
      display: block;
      color-scheme: dark;
    }

    /* When the Music Studio is active, hide the Visual Studio chrome
   underneath. The .main host stays in the flow so layout doesn't
   reflow on tab switch. */
    /* When Music Studio is active, hide EVERY Visual-Studio surface so
   only the music studio iframe renders. Covers the gallery, the chat
   thread, the input-bar footer (with Reference / mode pills / textarea
   / send), the modes screen, the cinema bar, and the action pills. */
    body.music-studio-active .chat,
    body.music-studio-active .composer,
    body.music-studio-active .composer-host,
    body.music-studio-active .gallery,
    body.music-studio-active .modes-screen,
    body.music-studio-active .input-bar,
    body.music-studio-active .video-tip,
    body.music-studio-active .cinema-bar,
    body.music-studio-active .chat-actions,
    body.music-studio-active .director-bottom-btn,
    body.music-studio-active #inputBar,
    body.music-studio-active footer.input-bar {
      display: none !important;
    }

    /* Chat Engine host — visibility is gated by the [hidden] attribute
   that setActiveTab() toggles via show/hideChatEngine(). The prototype's
   own .ce-stage rule (later in this stylesheet) supplies the layout
   (flex column, max-width 1080px, gap 18px, padding-top 18px). We only
   add the absolute-positioning host behaviour when the chat engine is
   the active surface, so it overlays the .main flow without disturbing
   the visual studio layout when it's not active. */
    body.chat-engine-active #chatEngine.ce-stage {
      position: absolute;
      inset: 0;
      z-index: 6;
      background: transparent;
      /* The prototype's max-width:1080px is preserved via auto-margins on
     the inner content; the host itself spans the .main viewport so the
     mode selector + input bar can centre against the full width. */
      max-width: none;
      margin: 0;
      padding: 18px 22px 8px !important;
      /* b.713: bottom 8px (was 10px) — bring input bar 2px closer to viewport bottom. !important + override block below to bypass any future global rules. */
      overflow: auto;
    }

    /* b.713 — Belt-and-suspenders override for the chat-engine bottom gap.
   Maximum-specificity selector (html + body.class + #id.class) with
   !important to guarantee nothing else can push the input bar back up.
   Scope: chat section ONLY. */
    html body.chat-engine-active #chatEngine.ce-stage {
      padding-bottom: 8px !important;
    }

    /* b.714 — Tighten the gap above .ce-input-row from 18px → 8px.
   Important context: the chat-engine HTML has an extra </div> after the
   .ce-vm-strip block, which causes the browser to parse .ce-input-row
   as a DIRECT CHILD of .ce-stage (not nested inside .ce-inputbar). So
   the space above the input bar is governed by .ce-stage's `gap:18px`,
   not .ce-inputbar's `gap:5px`.
   We can't lower .ce-stage gap globally — that would also tighten the
   space between the thread and the buttons row. Instead, we pull
   .ce-input-row up with margin-top:-10px so flex `gap:18px - 10px = 8px`
   visual gap above the input bar. Preserves the 18px gap above the
   buttons row.
   Scope: chat-engine only. */
    /* b.791 — These b.714 negative-margin rules were UNCONDITIONAL and
       applied to BOTH mobile AND desktop, pulling the input row UP by
       10px into the meta row's vertical space on desktop. On wide
       viewports the visual merge made tools+pills+send look like a
       single compressed row with textarea wrapped to a separate line
       below. Now gated to @media (max-width: 1024px) so desktop's
       canonical 18px .ce-stage gap is preserved between meta + input. */
/* ─────────────────────────────────────────────────────────────────
       CHAT MOBILE RULES — DELETED in b.843.
       Chat is desktop-only now (>=1025px). Mobile (<=1024px) is owned
       entirely by styles/mobile-landing.css which takes over the full
       viewport via the #mobileLanding overlay.
       18 chat-mobile @media (max-width: 1024px) blocks removed here.
       ───────────────────────────────────────────────────────────────── */
        /* DESKTOP — explicit zero margin so nothing inherits the mobile pull. */
    @media (min-width: 1025px){
      html body.chat-engine-active #chatEngine.ce-stage>.ce-input-row {
        margin-top: 0 !important;
      }
    }
