/* Stanzai dev styles 16 — FREEFORM NOIR theme (2026-06-11). New surface file appended per styles/README.md
   rule: genuinely new surfaces get a new numbered file at the end so existing cascade positions never shift.

   Scope: every rule is gated on body.ff-noir — a presentation-only class that fires whenever the
   session screen (s-session) is the active surface. Both modes wear it: Guided and Freeform share
   the surface and components, and the founder approved the same look for both (2026-06-12).

   Architecture note: component rules use `:where(body.ff-noir)` so they carry the SAME specificity as
   the base class rules in files 03/09/11 (and win only by load order). Lifecycle / state rules like
   .v9-concept.is-selected, .v9-chip.glow, .v9-sp.is-rec keep their higher specificity and continue to
   win over this theme — states stay alive, only the base coat changes. The stage background and the
   composer use full-specificity selectors on purpose (they must beat ID + light-mode rules).

   Plain static CSS — no prompts, no schemas, no model-facing content (CLAUDE.md client-side rule). */

/* ── 0 · NOIR PALETTE — warm parchment text over deep green-teal black ── */
body.ff-noir {
  --ffn-ink: #04090b;                       /* deepest stage black, green-teal cast */
  --ffn-cream: #e7dfc6;                     /* body prose */
  --ffn-cream-hi: #f4ecd4;                  /* emphasis / strong */
  --ffn-glass: rgba(2, 12, 14, 0.90);      /* card glass base — reference-sampled cool teal-black (#030d0f), near-opaque */
  --ffn-glass-deep: rgba(1, 6, 8, 0.94);   /* lower edge of card glass gradient */
  --ffn-hairline-gold: rgba(var(--gold-rgb), 0.26);
  --ffn-hairline-teal: rgba(var(--teal-rgb), 0.24);
  --ffn-grain:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.38 0 0 0 0 0.58 0 0 0 0 0.64 0 0 0 0.04 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  /* Warm the global text roles a touch while the noir stage is up */
  --t1: #ece3cb;
  --t2: #b9b09a;
}

/* ── 1 · THE STAGE — founder gradient recipe + smoke plate on screen blend ──
   #s-session is a fixed viewport-sized scroll container, so background layers
   here stay pinned while the thread scrolls — exactly the mockup behavior.
   Full specificity: must beat `body.session-active #s-session { background: var(--dt-well) }`
   (10-library) and `body.light-mode .v9-chat-bg` (11-consolidated).
   Base locked to the #040A0C–#061112 family. The smoke plate rides IN the
   background stack via background-blend-mode:screen (reliable on iOS Safari —
   the earlier fixed ::before + mix-blend-mode approach rendered in Chromium
   but WebKit dropped it entirely). The plate's intensity (~26%) and color trim
   (brightness 0.78 · saturate 0.75 · hue -8deg) are BAKED into the webp;
   regenerate via sharp `.modulate({ brightness: 0.20, saturation: 0.75, hue: -8 })`
   from the source art to retune. */
body.ff-noir #s-session.v9-chat-bg {
  background-color: var(--stz-obsidian);
  background-image:
    radial-gradient(circle at 34% 10%, rgba(19, 42, 45, 0.30), transparent 34%),
    radial-gradient(circle at 76% 82%, rgba(143, 95, 42, 0.05), transparent 32%),
    url('/img/stanzai-smoke-mobile.webp'),
    linear-gradient(180deg, var(--stz-petrol) 0%, var(--stz-void) 48%, var(--stz-void) 100%);
  background-size: auto, auto, cover, auto;
  background-position: center, center, center top, center;
  background-repeat: no-repeat;
  background-blend-mode: normal, normal, screen, normal;
}

/* Film grain — one fixed, click-through pass over the whole frame so prose,
   cards, and chrome all sit under the same emulsion. Static (not animated)
   on purpose: battery + vestibular safety. */
body.ff-noir::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 2147483000;
  pointer-events: none;
  background: var(--ffn-grain);
  opacity: 0.45;
}

/* ── 2 · CHROME — nav, context bar, DNA bar melt into the stage ── */
:where(body.ff-noir) .v9-nav {
  background: linear-gradient(180deg, rgba(4, 9, 11, 0.88), rgba(4, 9, 11, 0.55) 70%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
:where(body.ff-noir) .v9-nav-title {
  font-style: italic;
  font-size: 19px;
  letter-spacing: 0.01em;
  color: var(--ffn-cream);
}
:where(body.ff-noir) .v9-nav-btn { color: rgba(var(--ivory-rgb), 0.62); }

:where(body.ff-noir) .v9-ctx-bar {
  background: transparent;
  border-bottom: 1px solid rgba(var(--gold-rgb), 0.10);
}
:where(body.ff-noir) .v9-dna-bar {
  background: transparent;
  border-bottom: 1px solid rgba(var(--gold-rgb), 0.08);
}
:where(body.ff-noir) .v9-dna-chip {
  background: rgba(7, 10, 11, 0.55);
  border-color: rgba(var(--gold-rgb), 0.20);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

/* ── 3 · THE CONVERSATION — serif prose, mono labels, teal-glass user bubble ── */
:where(body.ff-noir) .v9-ai {
  font-family: 'Cormorant Garamond', 'EB Garamond', Georgia, serif;
  font-size: 19px;            /* x-height parity with the old Outfit 17px — reads the same size */
  font-weight: 400;
  line-height: 1.62;
  color: var(--ffn-cream);
  letter-spacing: 0.005em;
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.35);
}
:where(body.ff-noir) .v9-ai-bubble strong {
  color: var(--ffn-cream-hi);
  font-weight: 600;
}
:where(body.ff-noir) .v9-ai-label {
  color: rgba(216, 182, 118, 0.60);
  letter-spacing: 0.22em;
}

:where(body.ff-noir) .v9-user {
  font-family: 'Cormorant Garamond', 'EB Garamond', Georgia, serif;
  font-size: 18px;
  line-height: 1.55;
  color: var(--ffn-cream);
  /* Dark-center glass per reference close-up: faint sheen at the top rim,
     near-black through the middle */
  background: linear-gradient(180deg, rgba(26, 33, 35, 0.62) 0%, rgba(6, 10, 12, 0.82) 38%, rgba(4, 8, 9, 0.86) 68%, rgba(12, 18, 20, 0.70) 100%);
  border: 1px solid rgba(var(--ivory-rgb), 0.16);
  border-top-color: rgba(236, 231, 218, 0.32); /* rim light */
  border-radius: 18px 18px 6px 18px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.09),
    inset 0 10px 20px -12px rgba(236, 231, 218, 0.07),
    inset 0 -18px 28px -18px rgba(0, 0, 0, 0.65),
    0 10px 26px -10px rgba(0, 0, 0, 0.60);
}

/* ── 4 · SUGGESTION CHIPS — frosted pills; .glow (gold) state stays in charge ── */
:where(body.ff-noir) .v9-chip {
  background: linear-gradient(180deg, rgba(24, 31, 33, 0.55) 0%, rgba(6, 10, 12, 0.78) 45%, rgba(10, 16, 18, 0.62) 100%);
  border-color: rgba(var(--ivory-rgb), 0.13);
  color: rgba(var(--ivory-rgb), 0.78);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-radius: 999px;
  box-shadow:
    inset 0 -14px 20px -14px rgba(0, 0, 0, 0.60),
    0 6px 18px -8px rgba(0, 0, 0, 0.55);
}
/* The gold primary chip ("Show me directions" etc.) reads in the final-lyrics
   Save/Create CTA's editorial register — Cormorant italic gold, NOT a mono
   uppercase label. Founder 2026-06-17 (mobile + desktop). Fires for both modes
   on the session screen; the desktop studio layers its gold-pill treatment on
   top (24-desktop-studio.css). Regular chips stay Outfit. */
:where(body.ff-noir) .v9-chip.glow {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 17px;
  letter-spacing: 0.005em;
  text-transform: none;
}
:where(body.ff-noir) .v9-prompt-card {
  background: var(--ffn-glass);
  border-color: rgba(var(--ivory-rgb), 0.12);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* ── 5 · ARTIFACT GLASS — the shared raised-card recipe ──
   Same card DOM, same type sizes; only the material changes. Interior matched
   to the reference card's sampled #030d0f–#051315 cool teal-black, near-opaque
   so the smoke plate's warm regions cannot tint it. Lift comes from a deep
   doubled black shadow + top hairline light — NOT a gold glow (the reference
   card's under-edge samples #0a1013, still cool). The global emulsion overlay
   supplies card texture; no per-card grain layer (cream noise was warming the
   panes). */
:where(body.ff-noir) .v9-concept,
:where(body.ff-noir) .v9-struct,
:where(body.ff-noir) .v9-sp,
:where(body.ff-noir) .v9-status,
:where(body.ff-noir) .v9-collapsed,
:where(body.ff-noir) .v9-lyrics,
:where(body.ff-noir) .v9-concept-rail,
:where(body.ff-noir) .v9-sp-rec-rail {
  /* edge-light pass (reference IMG_2748): a soft bloom enters from the top
     edge and dies within ~60px (sampled #0d1112 -> #04080b). Depth from
     light falloff, not lighter surfaces — interiors stay manuscript-dark. */
  background:
    linear-gradient(180deg, rgba(236, 231, 218, 0.060) 0%, rgba(236, 231, 218, 0.018) 8%, transparent 17%),
    linear-gradient(180deg, var(--ffn-glass), var(--ffn-glass-deep));
  border: 1px solid var(--ffn-hairline-gold);
  border-top-color: rgba(236, 224, 196, 0.40); /* pale-gold rim catching the light */
  border-radius: 16px;
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  box-shadow:
    inset 0 1px 0 rgba(244, 236, 212, 0.10),
    inset 0 14px 28px -14px rgba(236, 231, 218, 0.05),
    0 6px 16px rgba(0, 0, 0, 0.45),
    0 28px 56px -16px rgba(0, 0, 0, 0.80);
}
:where(body.ff-noir) .v9-struct { border-color: var(--ffn-hairline-teal); }

/* Card prose joins the serif voice — same size register as the old Outfit 16px */
:where(body.ff-noir) .v9-concept-body,
:where(body.ff-noir) .v9-struct-body {
  font-family: 'Cormorant Garamond', 'EB Garamond', Georgia, serif;
  font-size: 17.5px;
  line-height: 1.55;
  color: var(--ffn-cream);
}
:where(body.ff-noir) .v9-status { border-color: rgba(var(--sage-rgb), 0.20); }

/* Re-assert the selected/recommended states ON TOP of the glass coat so the
   lifecycle accents read against the new material (same accent language,
   glassier base). */
body.ff-noir .v9-concept.is-selected {
  background: linear-gradient(180deg, rgba(11, 12, 15, 0.93), rgba(5, 6, 8, 0.96));
  border-color: rgba(var(--gold-rgb), 0.55);
}
body.ff-noir .v9-struct.rec {
  background: linear-gradient(180deg, rgba(5, 16, 17, 0.93), rgba(3, 9, 10, 0.96));
  border-color: rgba(var(--teal-rgb), 0.30);
}

/* Final-lyrics manuscript card — keep its gold gradient frame (::before) and
   layout; swap the opaque ink slab for raised smoked glass. */
:where(body.ff-noir) .v9-final-lyrics {
  background:
    linear-gradient(180deg, rgba(236, 231, 218, 0.055) 0%, rgba(236, 231, 218, 0.016) 9%, transparent 18%),
    linear-gradient(180deg, rgba(4, 14, 16, 0.94), rgba(2, 7, 9, 0.97));
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  box-shadow:
    inset 0 1px 0 rgba(244, 236, 212, 0.09),
    inset 0 16px 32px -16px rgba(236, 231, 218, 0.05),
    0 8px 20px rgba(0, 0, 0, 0.50),
    0 34px 64px -20px rgba(0, 0, 0, 0.82);
}
:where(body.ff-noir) .v9-final-lyrics .fl-title {
  color: var(--ffn-cream-hi);
  text-shadow: 0 0 26px rgba(232, 200, 136, 0.13);
}
:where(body.ff-noir) .v9-final-lyrics .fl-lyric-line {
  color: var(--ffn-cream);
  text-shadow: 0 0 16px rgba(232, 210, 160, 0.11);
}

/* ── 6 · COMPOSER — input bar floats as glass over the stage ──
   Full specificity: must beat .v9-input-area{background:var(--bg)} (09) and
   body.light-mode .v9-input-area (11). */
body.ff-noir .v9-input-area {
  background: linear-gradient(180deg, rgba(4, 9, 11, 0) 0%, rgba(4, 9, 11, 0.66) 34%, rgba(3, 7, 9, 0.90) 100%);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
body.ff-noir .v9-input {
  font-family: 'Cormorant Garamond', 'EB Garamond', Georgia, serif;
  font-size: 18px;
  background: linear-gradient(180deg, rgba(22, 29, 31, 0.58) 0%, rgba(5, 9, 11, 0.84) 40%, rgba(4, 8, 9, 0.86) 70%, rgba(11, 17, 19, 0.68) 100%);
  border-color: rgba(var(--ivory-rgb), 0.15);
  border-top-color: rgba(var(--ivory-rgb), 0.22);
  color: var(--ffn-cream);
  box-shadow:
    inset 0 1px 0 rgba(244, 236, 212, 0.05),
    inset 0 -16px 24px -16px rgba(0, 0, 0, 0.65),
    0 8px 22px -10px rgba(0, 0, 0, 0.55);
}
body.ff-noir .v9-input::placeholder { color: rgba(var(--ivory-rgb), 0.36); }
body.ff-noir .v9-input:focus {
  border-color: rgba(var(--teal-rgb), 0.38);
  background: linear-gradient(180deg, rgba(24, 33, 35, 0.60) 0%, rgba(6, 11, 13, 0.85) 40%, rgba(5, 9, 11, 0.87) 70%, rgba(12, 19, 21, 0.70) 100%);
}

/* ── 7 · SHEETS & OVERLAYS — DNA sheet and rescue card join the glass family ── */
:where(body.ff-noir) .v9-dna-sheet-panel,
:where(body.ff-noir) .v9-p1-rescue-card {
  background: linear-gradient(180deg, rgba(4, 13, 15, 0.96), rgba(2, 7, 9, 0.98));
  border: 1px solid var(--ffn-hairline-gold);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

/* Collapsed phase summaries strip melts into the stage */
:where(body.ff-noir) #v9CollapsedStrip { background: transparent; }

/* ── 8 · DESKTOP — keep the stage when the session sits between rails ──
   Wide screens get their own landscape smoke plate (the portrait plate
   cover-stretched badly past ~1024px). Same bake recipe as mobile. */
@media (min-width: 1024px) {
  body.ff-noir #s-session.v9-chat-bg,
  body.ff-noir.session-active #s-session.v9-chat-bg {
    background-color: var(--stz-obsidian);
    background-image:
      radial-gradient(circle at 34% 10%, rgba(19, 42, 45, 0.30), transparent 34%),
      radial-gradient(circle at 76% 82%, rgba(143, 95, 42, 0.05), transparent 32%),
      url('/img/stanzai-smoke-desktop.webp'),
      linear-gradient(180deg, var(--stz-petrol) 0%, var(--stz-void) 48%, var(--stz-void) 100%);
    background-size: auto, auto, cover, auto;
    background-position: center, center, center top, center;
    background-repeat: no-repeat;
    background-blend-mode: normal, normal, screen, normal;
  }
}

/* ── 9 · ACCESSIBILITY — honor reduced transparency: trade glass for solid ink ── */
@media (prefers-reduced-transparency: reduce) {
  :where(body.ff-noir) .v9-concept,
  :where(body.ff-noir) .v9-struct,
  :where(body.ff-noir) .v9-sp,
  :where(body.ff-noir) .v9-status,
  :where(body.ff-noir) .v9-collapsed,
  :where(body.ff-noir) .v9-lyrics,
  :where(body.ff-noir) .v9-final-lyrics,
  :where(body.ff-noir) .v9-user,
  :where(body.ff-noir) .v9-dna-sheet-panel {
    background: #0a161a;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  body.ff-noir::after { opacity: 0.25; }
}

/* ── 10 · GOLD FILAMENT PRIMARY — "Start with sound" / "Use in current song" ──
   Adapted from a Uiverse.io gradient-border pattern (vinodjangid07), recolored
   to stanzai gold and refit to the noir glass family. The element's background
   is a wide gold gradient that reads as a luminous border; an inset ::before
   carries the near-black fill (element gets its own stacking context via
   z-index:0, so the negative-z pseudo sits above the gradient but under the
   label text — the original baked its label into the pseudo's content, which
   can't carry our dynamic labels). Label wears the mono letterpress voice.
   Hover sweep is desktop-only (hover:hover) so iOS never sticks mid-sweep. */
body.ff-noir .v9-concept-lock[data-route="freeform-style-start-song"],
body.ff-noir .v9-concept-lock[data-route="freeform-style-use"],
body.ff-noir .v9-concept-lock[data-route="freeform-use"] {
  position: relative;
  z-index: 0;
  border: none;
  border-radius: 12px;
  padding: 15px 20px;
  background: linear-gradient(to right, #62491a, #ddb86e, #62491a, #62491a, #ddb86e, #62491a);
  background-size: 250% 100%;
  background-position: left;
  color: #d6bf85;
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 11px;
  /* !important: the renderer puts font-weight:600 in the element's inline style;
     DM Mono only ships 300/400, so 600 synthesizes a chunky faux-bold on iOS. */
  font-weight: 400 !important;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  overflow: hidden;
  transition: background-position 1s ease, transform 0.15s ease;
}
body.ff-noir .v9-concept-lock[data-route="freeform-style-start-song"]::before,
body.ff-noir .v9-concept-lock[data-route="freeform-style-use"]::before,
body.ff-noir .v9-concept-lock[data-route="freeform-use"]::before {
  content: "";
  position: absolute;
  inset: 1.5px;
  z-index: -1;
  border-radius: 10.5px;
  background: linear-gradient(180deg, rgba(4, 12, 14, 0.97), rgba(2, 7, 9, 0.99));
}
@media (hover: hover) {
  body.ff-noir .v9-concept-lock[data-route="freeform-style-start-song"]:hover,
  body.ff-noir .v9-concept-lock[data-route="freeform-style-use"]:hover,
  body.ff-noir .v9-concept-lock[data-route="freeform-use"]:hover {
    background-position: right;
    border-color: transparent;
  }
}
body.ff-noir .v9-concept-lock[data-route="freeform-style-start-song"]:active,
body.ff-noir .v9-concept-lock[data-route="freeform-style-use"]:active,
body.ff-noir .v9-concept-lock[data-route="freeform-use"]:active {
  transform: scale(0.97);
  background-position: right;
}

/* ── 11 · QUIET HANDS — no gold-and-clear flash when fingers brush cards ──
   Base hover/selected rules replace the opaque glass with translucent gold
   washes; on touch, scroll-taps trigger them and cards "go gold and clear."
   Under noir, every interactive state KEEPS the dark glass interior — gold
   speaks only through the frame (border + faint halo), like the reference
   card. Full-specificity selectors on purpose: they must beat the base
   .v9-sp.is-selected / :hover rules. */
body.ff-noir .v9-sp[data-runtime-card="1"]:hover:not(.is-pending):not(.is-streaming),
body.ff-noir .v9-sp[data-static-card="1"]:hover:not(.is-pending):not(.is-streaming),
body.ff-noir .v9-concept:hover,
body.ff-noir .v9-concept.is-selectable:hover {
  background: linear-gradient(180deg, var(--ffn-glass), var(--ffn-glass-deep));
}
@media (hover: hover) {
  /* Real pointers still get a whisper of acknowledgment — frame only */
  body.ff-noir .v9-sp[data-runtime-card="1"]:hover:not(.is-pending):not(.is-streaming),
  body.ff-noir .v9-sp[data-static-card="1"]:hover:not(.is-pending):not(.is-streaming),
  body.ff-noir .v9-concept.is-selectable:hover {
    border-color: rgba(var(--gold-rgb), 0.40);
  }
}

/* Selected sound — dark interior, gold frame, soft halo (no wash) */
body.ff-noir .v9-sp.is-selected,
body.ff-noir .v9-sp.is-selected:hover {
  background: linear-gradient(180deg, var(--ffn-glass), var(--ffn-glass-deep));
  border-color: rgba(var(--gold-rgb), 0.50);
  box-shadow:
    inset 0 1px 0 rgba(236, 200, 120, 0.10),
    0 6px 16px rgba(0, 0, 0, 0.45),
    0 28px 56px -16px rgba(0, 0, 0, 0.80),
    0 0 20px rgba(var(--gold-rgb), 0.07);
}

/* Recommended (Stanzai Pick) — the one card that wears golden accents:
   brighter top edge, fuller gold hairline, faint outer halo. Interior stays
   the same dark glass as its siblings. */
body.ff-noir .v9-sp.is-rec {
  background: linear-gradient(180deg, var(--ffn-glass), var(--ffn-glass-deep));
  border-color: rgba(var(--gold-rgb), 0.42);
  border-top-color: rgba(236, 200, 120, 0.55);
  box-shadow:
    inset 0 1px 0 rgba(236, 200, 120, 0.12),
    0 6px 16px rgba(0, 0, 0, 0.45),
    0 28px 56px -16px rgba(0, 0, 0, 0.80),
    0 0 26px rgba(var(--gold-rgb), 0.08);
}

/* ── 12 · LYRICS INGEST CAPTURE CARD (PR #469) joins the glass family ──
   The Manuscript capture card shipped on main using the neutral grey surface
   tokens (--s1/--s2); on the noir stage that reads flat and off-family. Shell
   takes the shared glass; the inner manuscript page goes SOLID dark (not
   translucent) so its sticky bottom fade can match seamlessly. Buttons keep
   their Session-2 design. */
:where(body.ff-noir) .v9-ing-card {
  background: linear-gradient(180deg, var(--ffn-glass), var(--ffn-glass-deep));
  border: 1px solid var(--ffn-hairline-gold);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  box-shadow:
    inset 0 1px 0 rgba(244, 236, 212, 0.06),
    0 6px 16px rgba(0, 0, 0, 0.45),
    0 28px 56px -16px rgba(0, 0, 0, 0.80);
}
:where(body.ff-noir) .v9-ing-page {
  background: #0a1416;
  border-color: rgba(var(--ivory-rgb), 0.10);
}
@media (max-width: 1023px) {
  :where(body.ff-noir) .v9-ing-page::after {
    background: linear-gradient(to bottom, rgba(10, 20, 22, 0), #0a1416);
  }
}

/* ── 13 · GUIDED PICKERS — option cards, mood grid, genre/sound chips ──
   (Theme widened to Guided 2026-06-12: the ff-noir class now fires for ANY
   session-screen visit, both modes.) Guided's phase pickers ship on the grey
   surface tokens; under noir they take a light ink wash — translucent tint
   only, deliberately NO backdrop-filter: these render in dense grids and
   dozens of blurred chips would jank scrolling on older phones. Selection
   states (.sel) keep their higher specificity and their gold. */
:where(body.ff-noir) .optcard,
:where(body.ff-noir) .gchip,
:where(body.ff-noir) .stchip,
:where(body.ff-noir) .moodpill {
  background: rgba(6, 14, 16, 0.55);
  border-color: rgba(var(--ivory-rgb), 0.10);
}
:where(body.ff-noir) .v9-phase-card {
  background: rgba(4, 11, 13, 0.40);
  border-top-color: rgba(var(--gold-rgb), 0.12);
  border-bottom-color: rgba(var(--gold-rgb), 0.12);
}

/* ── 14 · "READING THE ROOM" LIGHT SWEEP — rail thinking rows ──
   Founder spec (lightsweepspec.md): a soft band of warm off-white light
   passes across dim italic text while Stanzai is thinking. Applied to the
   second row of both recommendation rails, gated on the rails' existing
   .is-thinking state class — the sweep runs only while scanning and the
   resolved reason text returns to its normal style automatically when the
   runtime drops .is-thinking. No gold: the sweep is off-white only.
   Animation math per spec: 300% bg, band at 40-60%, 100%→0% so the band
   fully enters and exits each 3.2s linear cycle. will-change +
   translateZ(0) required — iOS Safari skips repaints on animated
   background-position over clipped text without compositor promotion. */
body.ff-noir .v9-concept-rail.is-thinking .v9-concept-rail-msg,
body.ff-noir .v9-sp-rec-rail.is-thinking .v9-sp-rec-rail-reason {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  font-family: 'Cormorant Garamond', 'EB Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(16px, 4vw, 20px);
  letter-spacing: 0.01em;
  background-image: linear-gradient(
    100deg,
    rgba(236, 231, 218, 0.38) 0%,
    rgba(236, 231, 218, 0.38) 40%,
    rgba(236, 231, 218, 0.92) 50%,
    rgba(236, 231, 218, 0.38) 60%,
    rgba(236, 231, 218, 0.38) 100%
  );
  background-size: 300% 100%;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: ffnSweep 3.2s linear infinite;
  will-change: background-position;
  transform: translateZ(0);
}
@keyframes ffnSweep {
  from { background-position: 100% 0; }
  to   { background-position: 0% 0; }
}
@media (prefers-reduced-motion: reduce) {
  body.ff-noir .v9-concept-rail.is-thinking .v9-concept-rail-msg,
  body.ff-noir .v9-sp-rec-rail.is-thinking .v9-sp-rec-rail-reason {
    animation: none;
    -webkit-text-fill-color: rgba(236, 231, 218, 0.38);
  }
}

/* ── 15 · SECTION DRAFT PRESENTATION — the framed [VERSE 1] card ──
   Replaces the bare left-rule float (renderer now emits .v9-secd classes
   instead of inline styles; icon prefixes removed per founder — no emoji).
   The frame is the reference card: glass pane, edge light, mono header row
   with a line count, hairline rule, serif lyrics with the text halo. */
:where(body.ff-noir) .v9-secd {
  margin: 16px 0;
  padding: 18px 18px 20px;
  border-radius: 16px;
  background:
    linear-gradient(180deg, rgba(236, 231, 218, 0.060) 0%, rgba(236, 231, 218, 0.018) 8%, transparent 17%),
    linear-gradient(180deg, var(--ffn-glass), var(--ffn-glass-deep));
  border: 1px solid var(--ffn-hairline-gold);
  border-top-color: rgba(236, 224, 196, 0.40);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  box-shadow:
    inset 0 1px 0 rgba(244, 236, 212, 0.10),
    inset 0 14px 28px -14px rgba(236, 231, 218, 0.05),
    0 6px 16px rgba(0, 0, 0, 0.45),
    0 28px 56px -16px rgba(0, 0, 0, 0.80);
}
:where(body.ff-noir) .v9-secd-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 14px 0 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid rgba(var(--gold-rgb), 0.14);
}
:where(body.ff-noir) .v9-secd-head:first-child { margin-top: 0; }
:where(body.ff-noir) .v9-secd-label {
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: rgba(216, 182, 118, 0.85);
}
:where(body.ff-noir) .v9-secd-label::before { content: "[ "; opacity: 0.5; }
:where(body.ff-noir) .v9-secd-label::after  { content: " ]"; opacity: 0.5; }
:where(body.ff-noir) .v9-secd-count {
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.22em;
  color: rgba(var(--ivory-rgb), 0.40);
  white-space: nowrap;
}
:where(body.ff-noir) .v9-secd-text {
  font-family: 'Cormorant Garamond', 'EB Garamond', Georgia, serif;
  font-size: 19px;
  line-height: 1.75;
  color: var(--ffn-cream);
  text-shadow: 0 0 16px rgba(232, 210, 160, 0.11);
  margin: 0;
}

/* Craft notes — Stanzai's margin commentary. Upright serif at reading size
   (the old 14px italic wall read tiny and gray); a mono eyebrow names it. */
:where(body.ff-noir) .v9-secd-note {
  margin: 16px 0 8px;
  padding: 14px 16px;
  border-left: 2px solid rgba(var(--gold-rgb), 0.28);
  border-radius: 0 10px 10px 0;
  background: rgba(2, 10, 12, 0.45);
  font-family: 'Cormorant Garamond', 'EB Garamond', Georgia, serif;
  font-style: normal;
  font-size: 17px;
  line-height: 1.62;
  color: rgba(var(--ivory-rgb), 0.72);
}
:where(body.ff-noir) .v9-secd-note p { margin: 0 0 10px; }
:where(body.ff-noir) .v9-secd-note p:last-child { margin-bottom: 0; }
:where(body.ff-noir) .v9-secd-note em { color: rgba(244, 236, 212, 0.85); }
:where(body.ff-noir) .v9-secd-note-eyebrow {
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 9px;
  letter-spacing: 0.30em;
  text-transform: uppercase;
  color: rgba(216, 182, 118, 0.55);
  margin-bottom: 8px;
}

/* Save = the USE THIS letterpress; Revise/Copy stay quiet mono pills */
body.ff-noir .v9-act.v9-secd-save {
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: #d6bf85;
  padding: 12px 22px;
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(24, 31, 33, 0.55) 0%, rgba(6, 10, 12, 0.78) 45%, rgba(10, 16, 18, 0.62) 100%);
  border: 1px solid rgba(var(--gold-rgb), 0.45);
  box-shadow: 0 0 14px rgba(var(--gold-rgb), 0.08), inset 0 -12px 18px -12px rgba(0, 0, 0, 0.55);
}
body.ff-noir .v9-act.v9-secd-quiet {
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(var(--ivory-rgb), 0.55);
  padding: 12px 18px;
  border-radius: 999px;
  background: rgba(4, 10, 12, 0.50);
  border: 1px solid rgba(var(--ivory-rgb), 0.12);
}

/* Sound-prompt secondary pills (Save to Vault / Show me more) — OUTLINE: no fill, just a hairline.
   Bare .v9-act otherwise inherits var(--s2); these two live in .sp-secd-row, so the outline is
   scoped there without disturbing any other .v9-act. Keeps the base shape + Outfit label. */
body.ff-noir .v9-sp .sp-secd-row .v9-act {
  background: transparent;
  border-color: rgba(var(--ivory-rgb), 0.18);
  color: rgba(var(--ivory-rgb), 0.62);
}
body.ff-noir .v9-sp .sp-secd-row .v9-act:hover {
  background: rgba(var(--ivory-rgb), 0.05);
  border-color: rgba(var(--ivory-rgb), 0.30);
  color: rgba(var(--ivory-rgb), 0.82);
}

/* ── 16 · COMPOSER DNA AFFORDANCE — anchored, not floating ──
   The chip moved from its own orphan row above the strip into the composer
   row itself (leading adornment, same pattern as the dev screenshot button).
   Height matches the send circle so the row reads as one instrument. */
body.ff-noir .v9-dna-aff { padding: 0; flex-shrink: 0; align-self: flex-end; }
body.ff-noir .v9-dna-aff button {
  height: 46px;
  padding: 0 14px;
  border-radius: 999px;
  background: rgba(4, 10, 12, 0.55);
  border-color: rgba(var(--gold-rgb), 0.32);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
}

/* ── 17 · SOUND CARD COPY BADGE — the cryptic glyph becomes a readable
   letterpress badge; the vault heart is gone (Save to Vault carries it). */
body.ff-noir .v9-sp-util-btn[data-util="copy"] {
  width: auto;
  height: auto;
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid rgba(var(--ivory-rgb), 0.16);
  background: rgba(4, 10, 12, 0.50);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 9px;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: rgba(var(--ivory-rgb), 0.60);
}
body.ff-noir .v9-sp-util-btn[data-util="vault"] { display: none; }
