/* shared/brand.css — Brand-scoped skinning applied via body[data-brand].
 * Companion to shared/brand-apply.js. Both get loaded on every page that
 * supports multi-brand hosting (SHIROFES / FSC / Chross Cross).
 *
 * Design constraint: SHIROFES pages must look IDENTICAL to today (zero
 * regression). These rules only kick in for non-SHIROFES brands, because
 * body[data-brand] is only set by brand-apply.js, and the `[data-brand="fsc"]`
 * selectors don't match SHIROFES.
 */

/* ── Text-based wordmark fallback ──────────────────────────────────────
   brand-apply.js replaces `<img class="header-wordmark">` elements with
   `<span class="brand-wordmark-text">` for non-SHIROFES brands (no FSC/CC
   PNG asset yet). This span should read as a confident wordmark — bold,
   tracked-out, aligned with surrounding header. */
.brand-wordmark-text {
    font-family: var(--font-display);
    font-weight: 900;
    font-size: 1.1rem;
    letter-spacing: 0.1em;
    color: #fff;
    line-height: 1;
    padding: 0.35em 0.5em;
    background: var(--shirofes-red, #E50012);
    border-radius: 2px;
    display: inline-block;
    vertical-align: middle;
    text-transform: none;
    white-space: nowrap;
}

/* Kiosk wordmark is larger — scale the text fallback up to match. */
.brand-wordmark-text.kiosk-header-wordmark,
.brand-wordmark-text[class*="kiosk"] {
    font-size: 1.4rem;
    padding: 0.5em 0.7em;
}

/* Landing wordmark (big display on index.html) — scale up. */
.brand-wordmark-text.landing-wordmark {
    font-size: 2.2rem;
    padding: 0.4em 0.7em;
    letter-spacing: 0.15em;
}

/* ── Per-brand overrides ──────────────────────────────────────────────
   Shared across brands for now (FSC accent = SHIROFES red = #E50012).
   When brand-specific accents diverge, adjust here. */
body[data-brand="fsc"] .brand-wordmark-text {
    background: #E50012;
}
body[data-brand="cc"] .brand-wordmark-text {
    background: #1B6CFF;
}

/* Title suffix area — used by pages that show "SHIROFES OS" as a small
   header label. These selectors are safe no-ops on SHIROFES pages. */
body[data-brand="fsc"] [data-replace-on-fsc] { display: none !important; }
body[data-brand="cc"]  [data-replace-on-cc]  { display: none !important; }

/* SHIROFES landing-logo is a bespoke kanji PNG (「白」 medallion). No FSC/CC
   counterpart — hide for non-SHIROFES brands so the landing wordmark stands
   alone. brand-apply.js already swaps the wordmark PNG for a text span. */
body[data-brand="fsc"] .landing-logo,
body[data-brand="cc"]  .landing-logo,
body[data-brand="sfs"] .landing-logo,
body[data-brand="ros"]:not([data-ops-dark="1"]) .landing-logo { display: none !important; }

/* SHIROFES-only UI — demo-data buttons seed SAMURAI Open fixtures that are
   meaningless for FSC / Chross Cross admins and would pollute per-event data.
   Also: pages that don't exist in the FSC / Chross Cross workflow (cast, portal,
   crew, timetable, mc monitor, prep, debrief, reflect) are tagged this way so
   their nav tiles / buttons vanish on non-SHIROFES subdomains.
   Hide by default; only reveal when body[data-brand="shirofes-os"] is set.
   Use `display: revert` so the element's natural cascade value (e.g. a flex
   mode-card, a span, a div) is preserved — `display: inline` would clobber
   .mode-card's flex layout on SHIROFES. This avoids a flash-of-visible-tile
   before brand-apply.js runs. */
[data-shirofes-only="1"] { display: none !important; }
body[data-brand="shirofes-os"] [data-shirofes-only="1"] { display: revert !important; }

/* Events-OS-only UI (FSC / Chross Cross) — inverse of the above. Payment sync
   bridge is FSC/CC-only; SHIROFES OS uses Buzz Ticket for 2026 and has no
   reception-sheet bridge. Hide by default; `display: revert` below restores
   the element's normal cascade value (e.g. .nav-item's display:flex) rather
   than forcing a specific value — so this works for buttons, spans, divs. */
[data-events-only="1"] { display: none !important; }
body[data-brand="fsc"] [data-events-only="1"],
body[data-brand="cc"]  [data-events-only="1"],
body[data-brand="sfs"] [data-events-only="1"],
body[data-brand="ros"] [data-events-only="1"] { display: revert !important; }

/* ── BRAND-GATE × EXPLICIT-HIDE GUARD (categorical fix, recurrence class) ──
   The reveal rules above use `display: revert !important`. On the matching
   brand that DEFEATS an explicit hide on the SAME element — both the `.hidden`
   utility (`display:none`, no !important) AND an inline `style="display:none"`
   (inline loses to an !important stylesheet declaration). So any element that
   is BOTH brand-gated AND meant to start hidden was being FORCE-SHOWN on its
   matching brand. (Recurrence: v99 `.modal-overlay`, v110 `.lang-en`,
   2026-06 `.section-label`; the live HIGH was admin `#newIncidentForm`.)

   Root fix: the gate must never override an explicit hide. `.hidden` is the
   single canonical hide marker, so the guard keys on it. These selectors are
   scoped under `body[data-brand=…]` so they MATCH the reveal's specificity
   (0,3,1) and win by source order — a bare `[gate].hidden` (0,2,0) would lose
   to the higher-specificity reveal even with !important. Verified in-browser
   for both brands.

   Contract: an element that is brand-gated AND meant to toggle hidden/shown
   MUST use the `.hidden` class for its hidden state, NEVER inline
   `display:none` (inline can't be beaten by a stylesheet, so the gate would
   still force it open). JS toggles via classList.add/remove('hidden'). */
body[data-brand="shirofes-os"] [data-shirofes-only="1"].hidden,
body[data-brand="fsc"] [data-events-only="1"].hidden,
body[data-brand="cc"]  [data-events-only="1"].hidden,
body[data-brand="sfs"] [data-events-only="1"].hidden,
body[data-brand="ros"] [data-events-only="1"].hidden { display: none !important; }

/* ── BRAND-GATE × LAYOUT GUARD (categorical, MED layout-collision class) ──
   `display: revert` reverts a revealed element to its UA value (`block` for a
   div, `inline` for a button) — which CLOBBERS the flex/grid layout its own
   class assigns (`.nav-item`→flex, `.page-subnav`→flex, `.ops-context`→grid,
   `.prep-row`→grid). For revealed elements that must keep flex/grid, restore
   their intended display explicitly so the reveal doesn't break their layout.
   Add a line here whenever a flex/grid element gets brand-gated. */
body[data-brand="shirofes-os"] [data-shirofes-only="1"].page-subnav { display: flex !important; }
body[data-brand="shirofes-os"] [data-shirofes-only="1"].ops-context { display: grid !important; }
body[data-brand="shirofes-os"] [data-shirofes-only="1"].prep-row   { display: grid !important; }
body[data-brand="fsc"] [data-events-only="1"].nav-item,
body[data-brand="cc"]  [data-events-only="1"].nav-item,
body[data-brand="sfs"] [data-events-only="1"].nav-item,
body[data-brand="ros"] [data-events-only="1"].nav-item { display: flex !important; }
body[data-brand="fsc"] [data-events-only="1"].prep-row,
body[data-brand="cc"]  [data-events-only="1"].prep-row,
body[data-brand="sfs"] [data-events-only="1"].prep-row,
body[data-brand="ros"] [data-events-only="1"].prep-row { display: grid !important; }

/* Direct content overrides for the SHIROFES-red theme color. Non-SHIROFES
   brands may want to adjust the accent at the CSS token layer later. For
   now the red is shared. */


/* ══════════════════════════════════════════════════════════════════════
   FSC — Funky Stadium Cup brand pack
   Applied when body[data-brand="fsc"] is set by brand-apply.js.
   ───────────────────────────────────────────────────────────────────── */

/* FSC tokens — ivory paper + diagonal scratches + grain.
   Matches the approved creative drop under
   /SFS Events/Funky Cup/Funky Stadium CUP creatives/FUNKY CUP/backdrop/. */
body[data-brand="fsc"] {
    --fsc-paper:           #f1ecdd;
    --fsc-ink:             #0a0a0a;
    --fsc-scratch-opacity: 0.48;
    --fsc-grain-opacity:   0.55;
}

/* brand-apply.js injects a `.fsc-backdrop` element as the first child of
   <body> on public-facing FSC pages. The element itself does nothing on
   SHIROFES pages (hidden by default). */
.fsc-backdrop { display: none; }
body[data-brand="fsc"] .fsc-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
    background: var(--fsc-paper);
}
body[data-brand="fsc"] .fsc-backdrop__scratches {
    position: absolute;
    inset: 0;
    opacity: var(--fsc-scratch-opacity);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='520' height='520' viewBox='0 0 520 520'><g stroke='%230a0a0a' stroke-linecap='square' fill='none'><line x1='-20' y1='40' x2='160' y2='-80' stroke-width='2.2'/><line x1='60' y1='180' x2='240' y2='30' stroke-width='1.5'/><line x1='200' y1='-20' x2='410' y2='200' stroke-width='3.2'/><line x1='320' y1='80' x2='500' y2='-40' stroke-width='1.8'/><line x1='440' y1='60' x2='560' y2='220' stroke-width='2.6'/><line x1='-40' y1='260' x2='140' y2='120' stroke-width='2.0'/><line x1='80' y1='380' x2='310' y2='230' stroke-width='1.4'/><line x1='260' y1='300' x2='460' y2='180' stroke-width='3.0'/><line x1='420' y1='300' x2='560' y2='440' stroke-width='1.6'/><line x1='-60' y1='460' x2='120' y2='340' stroke-width='2.4'/><line x1='150' y1='520' x2='360' y2='360' stroke-width='2.0'/><line x1='300' y1='540' x2='480' y2='420' stroke-width='1.2'/><line x1='30' y1='60' x2='210' y2='210' stroke-width='1.3'/><line x1='350' y1='420' x2='520' y2='540' stroke-width='2.2'/><line x1='180' y1='440' x2='400' y2='280' stroke-width='1.8'/></g></svg>");
    background-size: 520px 520px;
    background-repeat: repeat;
}
body[data-brand="fsc"] .fsc-backdrop__grain {
    position: absolute;
    inset: 0;
    opacity: var(--fsc-grain-opacity);
    mix-blend-mode: multiply;
    background-image:
        radial-gradient(circle at 23% 31%, rgba(0,0,0,0.06) 1px, transparent 1.5px),
        radial-gradient(circle at 67% 74%, rgba(0,0,0,0.04) 1px, transparent 1.5px),
        radial-gradient(circle at 45% 50%, rgba(0,0,0,0.03) 1px, transparent 1.4px);
    background-size: 5px 5px, 7px 7px, 11px 11px;
}
@media (max-width: 900px) {
    body[data-brand="fsc"] .fsc-backdrop__scratches { opacity: calc(var(--fsc-scratch-opacity) * 0.85); }
}
@media (max-width: 640px) {
    body[data-brand="fsc"] .fsc-backdrop__scratches {
        background-size: 360px 360px;
        opacity: calc(var(--fsc-scratch-opacity) * 0.75);
    }
}
@media (prefers-contrast: more) {
    body[data-brand="fsc"] .fsc-backdrop__scratches { opacity: 0.25; }
    body[data-brand="fsc"] .fsc-backdrop__grain     { opacity: 0.3;  }
}

/* Public-facing shells (landing, kiosk) — strip the SHIROFES red+sayagata
   surface so the ivory backdrop reads through. We keep `.landing` /
   `.kiosk-container` as the positioning container but neutralize its
   background + ::before pattern. Cards on top keep their dark chrome
   because that's the readable contrast pairing against ivory. */
body[data-brand="fsc"] .landing,
body[data-brand="fsc"] .kiosk-container {
    background: transparent !important;
}
body[data-brand="fsc"] .landing::before,
body[data-brand="fsc"] .landing::after,
body[data-brand="fsc"] .kiosk-container::before {
    display: none !important;
}

/* On ivory, the sayagata overlay inside .mode-grid reads as muddy noise.
   Turn it off. */
body[data-brand="fsc"] .mode-grid::before { display: none !important; }

/* Text colors on the ivory surface. Section labels + taglines need to flip
   from white-on-red to ink-on-ivory. Mode cards stay dark (they're their
   own inverted surface).
   Values are solid ink-black (same as register.html tokens post-v4) so the
   "mushy grey on ivory" failure mode doesn't recur here — the inline-style
   descriptions below used to composite at rgba(10,10,10, 0.62) = ~#8a8680
   on ivory, readable-ish but still grey. Now ink, hierarchy from weight. */
/* v135.1167 — :not([data-ops-dark="1"]) so this ivory-landing dark-ink flip
   does NOT bleed onto backstage ALWAYS-DARK pages (mc-script teleprompter +
   admin) whose titles also carry class .section-label. Without the gate, this
   !important dark color rendered the MC-script section titles dark-on-dark on
   FSC (live report 2026-06-11). Same shared-class-collision class as the v110
   .lang-en body-collision: a brand override on a class name reused on an
   unintended surface. The data-ops-dark contract = backstage dark pages opt
   out of brand text flips (the ROS pattern). */
body[data-brand="fsc"]:not([data-ops-dark="1"]) .section-label,
body[data-brand="fsc"]:not([data-ops-dark="1"]) .landing-tagline {
    color: #0f1116 !important;
    text-shadow: none !important;
}
body[data-brand="fsc"] .landing > div[style*="rgba(255,255,255"] {
    color: #0f1116 !important;
    opacity: 1 !important;
}

/* Wordmark — brand-apply.js swaps the SHIROFES PNG src for the FSC PNG.
   On ivory landing we want the BLACK wordmark (high contrast), on dark
   chrome headers (admin/staff/stage/judge) we want the WHITE wordmark.
   The existing styles.css rules apply `filter: invert(1)` to the SHIROFES
   white wordmark PNG to get a black result on light surfaces; for FSC we
   already ship separate black + white PNGs, so we neutralize the filter
   wherever we've swapped to an FSC source. brand-apply.js tags the img
   with data-brand-img so the selector stays specific. */
body[data-brand="fsc"] img[data-brand-img="fsc"] {
    filter: none !important;
}
/* Landing wordmark sits on ivory — FSC black wordmark, generous max-height. */
body[data-brand="fsc"] .landing-wordmark {
    height: auto;
    max-height: 96px;
    max-width: min(92vw, 440px);
}
/* Kiosk header wordmark on ivory — black PNG. */
body[data-brand="fsc"] .kiosk-header-wordmark {
    max-height: 72px;
    max-width: min(88vw, 360px);
}
/* Header wordmark on admin/staff/stage/judge — backdrop stays dark there,
   so we keep the white PNG and leave existing sizing alone. */

/* Since the FSC landing uses its own wordmark, hide the SHIROFES kanji
   "landing-logo" medallion entirely (already set earlier in this file at
   lines 64–65, but re-asserted here for clarity alongside the rest of the
   FSC block). */

/* ══════════════════════════════════════════════════════════════════════
   CC — Chross Cross brand pack
   Applied when body[data-brand="cc"] is set by brand-apply.js.
   v135.503 — first-class creative treatment. Brand color locked at
   #1B6CFF (electric blue) — chosen from the 3 prepared per-event
   gradient examples (green/blue/orange) at SFS Events/Chross Cross/.
   Blue carries the "weekday night party" energy best (night + club +
   blue-hour) and is distinct from FSC red + SHIROFES red.
   Per-event brackets rotate the gradient color via
   eventConfig.brand.bracketAccentColor — see core/docs/cc-brand-spec.md.
   ───────────────────────────────────────────────────────────────────── */

/* CC tokens — black ink base + electric-blue accent + open-road backdrop.
   Rationale: CC is biweekly and urban/club-flavored ("a weekday night
   party" tagline). FSC = monthly ivory paper + scratches (handmade zine
   energy); SHIROFES = annual red + sayagata (traditional surface). CC
   stays cleanly distinct from both. */

/* v135.507 WCAG contrast pattern (mirrors --shirofes-red / --shirofes-red-on-dark).
   --cc-accent (#1B6CFF) is a DECORATIVE token — gradients, chips, hover
   states, non-text uses. Contrast against white = 4.32:1 (fails AA 4.5:1
   for normal text; passes 3:1 for large text + UI components). Against
   dark #0c0c1a = 4.59:1 (passes AA normal text).

   Three sibling tokens for text-on-color use:
     --cc-accent-on-light: #1A56DB → 6.10:1 on white (passes AA normal). Use
                                      for any blue text on white/ivory surfaces.
     --cc-accent-on-dark:  #4D8DFF → 6.50:1 on #0c0c1a (passes AA normal).
                                      Brighter for emphasis on dark chrome.
     --cc-accent-text-on-accent: #FFFFFF → 4.59:1+ on --cc-accent (passes AA
                                      large + UI). Use for white text ON the
                                      blue-filled chip/button.

   Migration path for failing sites: replace `color: var(--cc-accent)` (when
   the surface is light) with `color: var(--cc-accent-on-light)`. Pages that
   compose dark text on `--cc-accent` background pair `--cc-accent-text-on-accent`
   (white) for AA compliance. Documented in core/docs/cc-brand-spec.md.

   Categorical alignment: SHIROFES already does this with --shirofes-red +
   --shirofes-red-on-dark (variables.css:9). FSC's --fsc-paper / --fsc-ink is
   ivory + ink-black so AA is automatic (16:1+ both directions). */
body[data-brand="cc"] {
    --cc-ink:          #000000;
    --cc-ink-2:        #0a0a14;
    --cc-accent:       #1B6CFF;                   /* decorative-only */
    --cc-accent-on-light: #1A56DB;                /* text on white/ivory — AA normal */
    --cc-accent-on-dark:  #4D8DFF;                /* text on dark chrome — AA normal */
    --cc-accent-text-on-accent: #FFFFFF;          /* text on --cc-accent surface */
    --cc-accent-soft:  rgba(27, 108, 255, 0.28);
    --cc-line-opacity: 0.38;
    --cc-grain-opacity: 0.25;
    /* Per-event override hook. Set via eventConfig.brand.bracketAccentColor
       at runtime; brand-apply.js writes it to this CSS var, allowing each
       Chross Cross edition to rotate the gradient color (green / orange /
       magenta / etc.) without code changes. Defaults to --cc-accent.
       Per-event overrides should also set --cc-event-accent-on-light and
       --cc-event-accent-on-dark when their hue's contrast differs; otherwise
       text-on-color sites fall back to --cc-accent-on-light/-dark. */
    --cc-event-accent: var(--cc-accent);
    --cc-event-accent-on-light: var(--cc-accent-on-light);
    --cc-event-accent-on-dark:  var(--cc-accent-on-dark);
}

/* CC backdrop — open-road photo + black-to-accent vertical gradient.
   Mirrors the FSC `.fsc-backdrop` pattern exactly (3-layer fixed-position
   div injected by brand-apply.js as first child of <body>). The road
   photo lives at shared/assets/cc/backdrop.png. Gradient overlays via
   `linear-gradient` so per-event accent can swap by changing one CSS var.

   Layout intent (matches the prepared creative examples):
     • backdrop.png fades road perspective from top horizon down.
     • black-to-accent gradient sits in the upper ~40% (party-light
       glow at the horizon).
     • lower 60% stays mostly transparent so the road reads through. */
.cc-backdrop { display: none; }
body[data-brand="cc"] .cc-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
    background: var(--cc-ink);
}
body[data-brand="cc"] .cc-backdrop__photo {
    position: absolute;
    inset: 0;
    /* v135.964 — path is relative to THIS file (shared/brand.css), so the asset
       is assets/cc/backdrop.png. The old 'shared/assets/...' doubled to
       /shared/shared/assets/... → 404, so the CC backdrop photo never loaded
       (only the gradient + grain). The asset has been present since 2026-05-09. */
    background-image: url('assets/cc/backdrop.png');
    background-size: cover;
    background-position: center bottom;
    opacity: 0.65;
}
body[data-brand="cc"] .cc-backdrop__gradient {
    position: absolute;
    inset: 0;
    background:
        linear-gradient(
            180deg,
            #000000 0%,
            #000000 18%,
            var(--cc-event-accent) 38%,
            transparent 62%,
            transparent 100%
        );
    mix-blend-mode: screen;
    opacity: 0.85;
}
body[data-brand="cc"] .cc-backdrop__grain {
    position: absolute;
    inset: 0;
    opacity: var(--cc-grain-opacity);
    mix-blend-mode: overlay;
    background-image:
        radial-gradient(circle at 23% 31%, rgba(255,255,255,0.06) 1px, transparent 1.5px),
        radial-gradient(circle at 67% 74%, rgba(255,255,255,0.04) 1px, transparent 1.5px);
    background-size: 5px 5px, 11px 11px;
}
@media (prefers-contrast: more) {
    body[data-brand="cc"] .cc-backdrop__gradient { opacity: 0.6; }
    body[data-brand="cc"] .cc-backdrop__grain    { opacity: 0.1; }
}

/* Public-facing shells (landing, kiosk) — strip the SHIROFES red surface
   so the .cc-backdrop element (injected by brand-apply.js) reads through.
   Mirrors the FSC pattern. */
body[data-brand="cc"] .landing,
body[data-brand="cc"] .kiosk-container {
    background: transparent !important;
}

/* ───────────────────────────────────────────────────────────────────────
 * v135.602/v135.609 — RULER OF SPACE brand skin
 *
 * v135.602-v135.608: concrete-texture backdrop on landing/bracket surfaces
 * (mirror of CC pattern). Through three opacity bumps (0.55 → 0.65 → 0.85)
 * the texture never read clearly on operator displays.
 *
 * v135.609 OPERATOR DECISION: drop the backdrop entirely. ROS pivots to a
 * clean black-on-white skin — white background across ALL pages (landing,
 * kiosk, admin, staff, judge, etc.), BLACK wordmark variant, dark legible
 * text. Minimalist brutalism via typography + contrast, not photographic
 * texture. SHIROFES (red+sayagata), FSC (ivory+scratches), CC (gradient),
 * ROS (pure white) — each brand owns a distinct surface treatment.
 * ─────────────────────────────────────────────────────────────────────── */
body[data-brand="ros"]:not([data-ops-dark="1"]) {
    --ros-ink:       #0c0c1a;    /* near-black for text, borders, accents */
    --ros-paper:     #ffffff;    /* pure white surface */
    --ros-accent:    #0c0c1a;    /* primary accent = ink (was white in v135.608) */
    --shirofes-red:  #0c0c1a;    /* repurpose the red token to ink — match the all-mono creative voice */
}

/* v135.609 — pure-white surface across the whole body. Replaces v135.608's
   dark-ink fallback. The body background flows through every page chrome
   (landing, kiosk, admin, staff, judge, stage, etc.) unless a child element
   sets its own background. */
body[data-brand="ros"]:not([data-ops-dark="1"]) {
    background: var(--ros-paper) !important;
    color: var(--ros-ink);
}

/* v135.609 — retire the backdrop. .ros-backdrop is no longer injected by
   brand-apply.js (see comment block in shared/brand-apply.js); this rule
   defensively hides it on any stale-cache page that still renders one. */
body[data-brand="ros"]:not([data-ops-dark="1"]) .ros-backdrop { display: none !important; }

/* v135.609 — public-facing shells (landing, kiosk) had SHIROFES dark-red
   surfaces with sayagata patterns. Strip them so the pure-white body
   shows through, mirroring the FSC pattern for the same shell selectors. */
body[data-brand="ros"]:not([data-ops-dark="1"]) .landing,
body[data-brand="ros"]:not([data-ops-dark="1"]) .kiosk-container {
    background: transparent !important;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .landing::before,
body[data-brand="ros"]:not([data-ops-dark="1"]) .landing::after,
body[data-brand="ros"]:not([data-ops-dark="1"]) .kiosk-container::before {
    display: none !important;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .mode-grid::before { display: none !important; }

/* v135.612 — categorical SHIROFES-creative gate for non-SHIROFES brands.
   Following the v135.607 .landing-logo precedent: SHIROFES-specific decorative
   elements (kasumi mist accents, sayagata pattern overlays) should not render
   on FSC / CC / ROS unless the page explicitly opts in via data-shirofes-only="1".
   Audit 2026-05-18: 6 pages (admin/judge/staff/stage/post-event/export) have
   <span class="kasumi-accent-sm"> in their page headers without a gate, and
   admin.html has a .kasumi-divider in its content. .mode-card::before applies
   sayagata to every mode-card on the landing across all brands.
   Rather than chase 7 page edits, hide the classes themselves on non-SHIROFES.
   SHIROFES retains all SHIROFES creative as default behavior. */
body[data-brand="fsc"] .kasumi-accent-sm,
body[data-brand="cc"]  .kasumi-accent-sm,
body[data-brand="sfs"] .kasumi-accent-sm,
body[data-brand="ros"]:not([data-ops-dark="1"]) .kasumi-accent-sm,
body[data-brand="fsc"] .kasumi-accent,
body[data-brand="cc"]  .kasumi-accent,
body[data-brand="sfs"] .kasumi-accent,
body[data-brand="ros"]:not([data-ops-dark="1"]) .kasumi-accent,
body[data-brand="fsc"] .kasumi-divider,
body[data-brand="cc"]  .kasumi-divider,
body[data-brand="sfs"] .kasumi-divider,
body[data-brand="ros"]:not([data-ops-dark="1"]) .kasumi-divider {
    display: none !important;
}
body[data-brand="fsc"] .mode-card::before,
body[data-brand="cc"]  .mode-card::before,
body[data-brand="sfs"] .mode-card::before,
body[data-brand="ros"]:not([data-ops-dark="1"]) .mode-card::before {
    display: none !important;
}

/* v135.609 — section labels + landing taglines flip from white-on-red to
   ink-on-white. Mirrors the FSC pattern for the same selectors. Inline
   white-rgba text on landing surfaces also gets re-inked. */
body[data-brand="ros"]:not([data-ops-dark="1"]) .section-label,
body[data-brand="ros"]:not([data-ops-dark="1"]) .landing-tagline {
    color: var(--ros-ink) !important;
    text-shadow: none !important;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .landing > div[style*="rgba(255,255,255"] {
    color: var(--ros-ink) !important;
    opacity: 1 !important;
}

/* v135.609 — subtle drop shadow on ROS BLACK wordmark on white surfaces.
   Down from v135.608's hard 2px-offset shadow (which made sense for white
   wordmark on concrete backdrop). On white BG with black wordmark, a soft
   1px offset adds just enough depth without looking like a glitch. */
body[data-brand="ros"]:not([data-ops-dark="1"]) .landing-wordmark,
body[data-brand="ros"]:not([data-ops-dark="1"]) .header-wordmark,
body[data-brand="ros"]:not([data-ops-dark="1"]) .kiosk-header-wordmark {
    filter: drop-shadow(1px 1px 0 rgba(0, 0, 0, 0.18));
}

/* ROS wordmark legibility on dark ops surfaces. The brand registry swaps the
   ROS wordmark to wordmark-black.png (the high-contrast pairing for the light
   skin), but on operator pages that render the dark theme (admin etc., with
   body[data-ops-dark="1"]) a black mark is illegible on the dark chrome. Force
   it crisp-white via brightness(0) invert(1). Scoped to data-ops-dark so the
   light-skin black wordmark above is untouched. */
body[data-brand="ros"][data-ops-dark="1"] .landing-wordmark,
body[data-brand="ros"][data-ops-dark="1"] .header-wordmark,
body[data-brand="ros"][data-ops-dark="1"] .kiosk-header-wordmark,
body[data-brand="ros"][data-ops-dark="1"] img[class*="wordmark"] {
    filter: brightness(0) invert(1) !important;
}

/* v135.605/v135.609 FOUC guard preserved — hide the wordmark on ROS until
   brand-apply.js swaps the src + sets data-brand-applied. Prevents the
   SHIROFES wordmark from flashing for ~50-150ms before being replaced. */
body[data-brand="ros"]:not([data-ops-dark="1"]) .landing-wordmark:not([data-brand-applied]),
body[data-brand="ros"]:not([data-ops-dark="1"]) .header-wordmark:not([data-brand-applied]),
body[data-brand="ros"]:not([data-ops-dark="1"]) .kiosk-header-wordmark:not([data-brand-applied]) {
    visibility: hidden;
}

/* v135.609 — wordmark IMG already swapped to black PNG via brand-registry;
   neutralize any inherited invert() filter that styles.css applies to the
   default SHIROFES white wordmark on light surfaces (mirror of FSC pattern). */
body[data-brand="ros"]:not([data-ops-dark="1"]) img[data-brand-img="ros"] {
    filter: drop-shadow(1px 1px 0 rgba(0, 0, 0, 0.18)) !important;
}

/* ───────────────────────────────────────────────────────────────────────
 * v135.611 — page-private CSS-variable namespace overrides for ROS
 *
 * Categorical fix for the "white-on-white text" class of bug that surfaced
 * on prep.html after v135.609. Root cause: each backstage page defines its
 * OWN private CSS-variable namespace inline (--prep-text, --prep-text-dim,
 * --prep-text-faint, --prep-bg, --prep-surface, etc.) that the brand.css
 * platform-token overrides never reach. When v135.609 flipped the body
 * background to white, the page-local white-rgba text tokens turned
 * invisible because nothing flipped them in parallel.
 *
 * Audit (grep ^\\s*--*-(bg|surface|text|border|paper|ink|card) across all
 * 17 production HTML pages) shows only TWO private namespaces in use:
 *   • prep.html: full --prep-* token set (~12 vars)
 *   • debrief.html: --card-bg
 *
 * Every other page (admin/staff/stage/mc/mc-script/portal/cast/judge/dj/
 * post-event/reflect/crew/kiosk/register/register-cast/index) routes
 * through platform tokens (--text-primary/--text-secondary/etc.) so the
 * existing brand.css ROS rules already cover them via cascade.
 *
 * Future protection (plan-doc'd for v135.612+): add a CI gate that
 * flags new page-private --*-(text|bg|surface|border) namespaces unless
 * brand.css has a corresponding `body[data-brand="ros"]` override block.
 * Mechanically prevents this class of bleed before next ship.
 * ─────────────────────────────────────────────────────────────────────── */

/* prep.html private namespace — dark navy chrome by default; for ROS we
   flip to white page surface + light-grey content panels + ink-on-light
   text. Panels keep visual separation from the page via a slightly
   darker shade (#f5f5f7) plus a 1px ink border via --prep-border. */
body[data-brand="ros"]:not([data-ops-dark="1"]) {
    --prep-bg:            #ffffff;
    --prep-surface:       #f6f6f8;
    --prep-surface-hover: #ececef;
    --prep-border:        rgba(0, 0, 0, 0.14);
    --prep-text:          #0c0c1a;
    --prep-text-dim:      rgba(12, 12, 26, 0.72);
    --prep-text-faint:    rgba(12, 12, 26, 0.5);
    /* --prep-accent intentionally inherits from --shirofes-red which is
       already re-aliased to ink for ROS — so .prep-battle-card's left
       accent rail renders as a clean black bar, not red. */
    /* Status colors stay close to their defaults but darkened a notch
       so they read on white. The default danger/warn/info/success
       text colors were tuned for dark BG — on white they need
       saturated, slightly-darker equivalents. */
    --prep-danger-text:   #b91c1c;
    --prep-warn-text:     #b45309;
    --prep-info-text:     #1d4ed8;
    --prep-success-text:  #047857;
}

/* prep.html body explicitly uses `color: var(--text-primary, #fff)` at
   the body scope — that platform token stays white-rgba globally for ROS
   (other surfaces like .mode-card-desc on landing rely on it). Override
   color directly at the prep page-shell level via the .prep-mast +
   .prep-content + .prep-sidebar containers so any direct-body text on
   prep flips to ink without affecting other pages. */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-mast,
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-content,
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-sidebar,
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-card,
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-modal-box {
    color: var(--prep-text);
}

/* ───────────────────────────────────────────────────────────────────────
 * v135.658 — prep.html translucent-white surface flip for ROS
 *
 * Audit 2026-05-19: 54 sites in prep.html set `background: rgba(255,255,
 * 255, 0.0X)` directly (inputs, ghost buttons, checklist rows, cast
 * rows, timeline rows, lifecycle picker, etc.). On every brand except
 * ROS these render as subtle translucent-white tints on the dark navy
 * body — correct. On ROS the body flips to pure white and the
 * translucent-white tints become invisible — form inputs disappear,
 * signout button vanishes, cast/timeline alternating-row stripes go
 * flat.
 *
 * Pragmatic fix: re-skin each CSS rule selector to use slightly-darker
 * greys on ROS so the surface contrast is preserved. Inline `style="..."`
 * occurrences (run-time generated cards, lifecycle picker buttons, etc.)
 * are NOT targetable from CSS short of a brittle attribute-substring
 * selector — those are queued as a follow-up retrofit (`F-cat-prep-
 * inline-rgba-white` in POST_FSC_FOLLOWUP_QUEUE). The class-based
 * patches below cover the majority of the operator's visual surface.
 * ─────────────────────────────────────────────────────────────────────── */

/* prep-signout in masthead */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-signout {
    background: #ececef;
    color: var(--prep-text-dim);
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-signout:hover {
    background: #dadade;
    color: var(--prep-text);
}

/* prep-input / prep-select / prep-textarea — form fields */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-input,
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-select,
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-textarea {
    background: #ffffff;
    border: 1px solid var(--prep-border);
    color: var(--prep-text);
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-input:focus,
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-select:focus,
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-textarea:focus {
    background: #ffffff;
    border-color: var(--prep-accent);
    box-shadow: 0 0 0 2px rgba(12, 12, 26, 0.08);
}
/* dark-themed <option> patch (line 176) — flip to white-paper. */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-select option {
    background-color: #ffffff;
    color: var(--prep-text);
}

/* prep-btn-ghost — secondary outline button */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-btn-ghost {
    background: #ececef;
    color: var(--prep-text);
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-btn-ghost:hover {
    background: #dadade;
}

/* prep-hint code inline */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-hint code {
    background: #ececef;
}

/* prep-card details summary hover */
body[data-brand="ros"]:not([data-ops-dark="1"]) details.prep-card summary:hover {
    background: #f0f0f3;
}

/* prep-checklist-row input */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-checklist-row input[type="text"] {
    background: #ffffff;
    color: var(--prep-text);
}

/* prep-chip */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-chip {
    background: #ececef;
    color: var(--prep-text-dim);
}

/* prep-modal-close-x hover */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-modal-close-x:hover {
    background: #ececef;
    color: var(--prep-text);
}

/* prep-cast-row hover + head */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-cast-row:hover {
    background: #f0f0f3;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-cast-row-head {
    background: #ececef;
    color: var(--prep-text-dim);
}

/* prep-assignment-row */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-assignment-row {
    background: #f6f6f8;
}

/* prep-tl-row variants */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-tl-row .prep-input:hover {
    background: #f0f0f3;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-tl-row .prep-input:focus {
    background: #ffffff;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-tl-row-collapsed {
    background: #f6f6f8;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-tl-row-head {
    background: #ececef;
    color: var(--prep-text-dim);
}

/* prep-tl-mc-script inline block */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-tl-mc-script > div {
    background: #f6f6f8;
}

/* prep-tt-grid + multi-column variants */
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-tt-grid {
    background: #f6f6f8;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-tt-multi-head {
    background: #ececef;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) .prep-tt-multi-col {
    background: #f6f6f8;
}

/* Catch-all attribute-substring selector for inline style="background:
   rgba(255,255,255,0.0X); ..." patterns generated dynamically (lifecycle
   picker, audit log rows, etc.). Uses ATTRIBUTE-SUBSTRING match on the
   shape "rgba(255,255,255," — covers any opacity 0.01–0.99.
   Trade-off: hits 30+ inline-style sites uniformly. Where an inline
   site explicitly intends a forced-dark surface, it would already
   declare a non-rgba(255...) background (e.g. var(--shirofes-black))
   so this catch-all does not regress those. */
body[data-brand="ros"]:not([data-ops-dark="1"]) [style*="rgba(255,255,255,"] {
    background: #f6f6f8 !important;
}
/* Re-allow scrollbar-track + scrollbar-thumb to keep their inline rgba
   defaults — scrollbars sit on their own surface, ours doesn't reach. */

/* Scrollbar thumb override for ROS — flip to dark-ink on light. */
body[data-brand="ros"]::-webkit-scrollbar-track,
body[data-brand="ros"]:not([data-ops-dark="1"]) *::-webkit-scrollbar-track {
    background: rgba(0, 0, 0, 0.04);
}
body[data-brand="ros"]::-webkit-scrollbar-thumb,
body[data-brand="ros"]:not([data-ops-dark="1"]) *::-webkit-scrollbar-thumb {
    background: rgba(0, 0, 0, 0.18);
}
body[data-brand="ros"]::-webkit-scrollbar-thumb:hover,
body[data-brand="ros"]:not([data-ops-dark="1"]) *::-webkit-scrollbar-thumb:hover {
    background: rgba(0, 0, 0, 0.28);
}

/* debrief.html defines a single --card-bg as dark navy
   for its content panels. On ROS we flip to a light-grey card BG so
   ink text inside the cards reads. The page uses this token uniformly
   so a single override is enough. */
body[data-brand="ros"]:not([data-ops-dark="1"]) {
    --card-bg: #f6f6f8;
}

/* ───────────────────────────────────────────────────────────────────────
 * v135.658 — ROS platform-token flip for legacy --text-* and --bg-* tokens
 *
 * Operator complaint 2026-05-19 (Alex): "Text color and background color
 * matches too closely or are the same in many areas, and either are hard
 * to read or can't be read at all" — on ROS admin surfaces.
 *
 * Root cause: shared/variables.css defines `--text-primary: #FFFFFF`,
 * `--text-secondary: #b8b8d0`, `--text-tertiary: #8888a8` plus
 * `--bg-secondary: rgba(255,255,255,0.06)` for the default dark theme.
 * admin.html alone has 799 inline references to var(--text-secondary) /
 * var(--text-tertiary) and dozens more to var(--bg-secondary) — none of
 * which were flipped for ROS at body scope. The v135.641 + v135.642
 * Stream B work introduced --page-* tokens that DO flip, but only newly-
 * written code consumed them; the legacy --text-* references continued
 * to resolve to dark-mode values on the now-white ROS body → mid-gray
 * ghost text on white background (WCAG fail) and translucent-white card
 * backgrounds invisible on white page.
 *
 * The v135.642 check-page-text-primary-leakage gate covered --text-primary
 * via a refactor sweep but did NOT cover --text-secondary / --text-tertiary
 * / --bg-secondary / --bg-card / --border-color leaks. Those slipped.
 *
 * Fix (this block): flip all six legacy platform tokens at body scope for
 * ROS so every existing inline `var(--text-secondary)` reference resolves
 * to ink-on-light values. This is the same shape as the v135.609
 * #authOverlay scoped fix, expanded to body scope.
 *
 * Mode-card guard: index.html .mode-card is forced-dark (background:
 * rgba(12,12,26,0.92)) on every brand including ROS. Its children
 * (.mode-card-desc) read var(--text-secondary) and MUST stay white-rgba
 * to remain legible on the dark card. A scoped re-flip below restores
 * the dark-theme values inside .mode-card on ROS.
 *
 * Other forced-dark surfaces (Event Clock card with `background:var(
 * --shirofes-black)`, status broadcast buttons) set `color:#fff`
 * inline → not affected by token flip.
 * ─────────────────────────────────────────────────────────────────────── */
body[data-brand="ros"]:not([data-ops-dark="1"]) {
    --text-primary:   #0c0c1a;
    --text-secondary: rgba(12, 12, 26, 0.72);
    --text-tertiary:  rgba(12, 12, 26, 0.55);
    --text-accent:    rgba(12, 12, 26, 0.85);
    --bg-card:        #ffffff;
    --bg-secondary:   #f3f3f6;
    --bg-primary:     #ffffff;
    --border-color:   rgba(0, 0, 0, 0.14);
    --border:         rgba(0, 0, 0, 0.14);
    /* v135.713 — legacy raw surface token. Predates the --bg-* system;
       referenced directly by .summary-card / .card / .form-* / .modal-box
       / .editor-box / .notif-banner / select option in shared/styles.css.
       Left unflipped pre-v135.713, so those surfaces stayed dark navy on
       ROS while their text flipped to near-black ink = invisible (the
       admin dashboard stat cards Alex reported). */
    --shirofes-black-alt: #ffffff;
    /* --text-info/warning/success/danger already flipped via v135.640
       block further down (lines 916-919) for ROS. */
}

/* v135.713 — <select> option lists hardcode color:#fff on a
   --shirofes-black-alt background (shared/styles.css:210 + 223-225). With
   that token now flipped to white above, re-flip the option text to ink
   so dropdown items stay legible on ROS. */
body[data-brand="ros"]:not([data-ops-dark="1"]) select option,
body[data-brand="ros"]:not([data-ops-dark="1"]) .form-select option {
    color: var(--ros-ink);
    background-color: var(--ros-paper);
}
/* v135.713 — .card:hover hardcodes a white-alpha border (styles.css:938)
   that vanishes on the now-white ROS card surface. Use the flipped border
   token so the hover affordance stays visible. */
body[data-brand="ros"]:not([data-ops-dark="1"]) .card:hover {
    border-color: var(--border-color);
}

/* Mode-card guard. .mode-card stays dark-navy on every brand including
   ROS (see shared/styles.css:388). Its descendants reading legacy
   --text-secondary must keep dark-theme values to stay legible on the
   dark card. Re-establish those tokens inside the .mode-card scope. */
body[data-brand="ros"]:not([data-ops-dark="1"]) .mode-card {
    --text-primary:   #FFFFFF;
    --text-secondary: #b8b8d0;
    --text-tertiary:  #8888a8;
}

/* Forced-dark inline surfaces inside admin.html — Event Clock card and
   "Broadcast status" header — also descend from body and need their
   text token-references preserved. They use `background:var(
   --shirofes-black)` inline (always-dark token) so we re-flip the
   text tokens for any descendant of such surfaces. Two routes covered:
   the explicit ID, and an attribute-selector matcher on inline style. */
body[data-brand="ros"]:not([data-ops-dark="1"]) .card[style*="--shirofes-black"],
body[data-brand="ros"]:not([data-ops-dark="1"]) [style*="--shirofes-black)"] {
    --text-primary:   #FFFFFF;
    --text-secondary: rgba(255, 255, 255, 0.72);
    --text-tertiary:  rgba(255, 255, 255, 0.55);
}

/* ───────────────────────────────────────────────────────────────────────
 * v135.642 Stream B — shared --page-* private namespace
 *   (consolidates v135.641 Stream B's --admin-* + plans for sister pages)
 *
 * v135.641 Stream B introduced `--admin-*` for admin.html when 53+ inline +
 * selector references to platform `var(--text-primary)` (white on dark)
 * went illegible on ROS (white-on-white). The same trap had been flagged
 * on 7 sister pages (staff/cast/portal/live/crew/judge/stage) — counts
 * 14/13/13/5/4/3/1 — so v135.642 consolidates into a SINGLE shared
 * `--page-*` namespace that every brand-aware page consumes uniformly.
 *
 * Reading rule: any page whose background flips per brand should consume
 * `--page-text` / `--page-surface` / `--page-border` instead of platform
 * `--text-primary` / hardcoded `#fff` / etc. Pages on an always-dark
 * fixed background (mc, stage, dj live monitor surfaces) stay platform —
 * those don't flip and `--page-*` would mismatch.
 *
 * Default (SHIROFES + FSC + CC + PICKER): tokens mirror the platform
 * dark-mode tokens. ROS: tokens flip to ink-on-light values.
 *
 * The CI gate `check:page-text-primary-leakage` flags new
 * `color: var(--text-primary)` references on the brand-aware page set.
 * Reference doc: `core/docs/page-private-token-namespaces.md`.
 * ─────────────────────────────────────────────────────────────────────── */

/* Default (every brand except ROS) — mirror platform dark-mode tokens. */
:root {
    --page-bg:               #0c0c1a;
    --page-surface:          rgba(255,255,255,0.04);
    --page-surface-elevated: rgba(255,255,255,0.08);
    --page-border:           rgba(255,255,255,0.12);
    --page-text:             #fff;
    --page-text-secondary:   rgba(255,255,255,0.72);
    --page-text-tertiary:    rgba(255,255,255,0.5);
}

/* ROS — ink on light surfaces. Mirror of the prep.html --prep-* flip
   pattern. Surfaces keep visual separation via a slightly-darker
   panel shade (#f6f6f8) and a 1px ink border. */
body[data-brand="ros"]:not([data-ops-dark="1"]) {
    --page-bg:               #ffffff;
    --page-surface:          #f6f6f8;
    --page-surface-elevated: #ececef;
    --page-border:           rgba(0, 0, 0, 0.14);
    --page-text:             #0c0c1a;
    --page-text-secondary:   rgba(12, 12, 26, 0.72);
    --page-text-tertiary:    rgba(12, 12, 26, 0.5);
}

/* FSC + CC restate the dark default explicitly for the brand-private-token
   coverage CI gate. Pattern matches the v135.612 prep/--card-bg explicit
   inheritance block above. Split into two single-slug blocks (rather than a
   `body[data-brand="fsc"], body[data-brand="cc"]` group) so the
   brand-css-whitelist-coverage CI gate doesn't treat the group as a
   whitelist requiring every brand. ROS already has its own light-skin
   override above. */
body[data-brand="fsc"] {
    --page-bg:               #0c0c1a;
    --page-surface:          rgba(255,255,255,0.04);
    --page-surface-elevated: rgba(255,255,255,0.08);
    --page-border:           rgba(255,255,255,0.12);
    --page-text:             #fff;
    --page-text-secondary:   rgba(255,255,255,0.72);
    --page-text-tertiary:    rgba(255,255,255,0.5);
}
body[data-brand="cc"] {
    --page-bg:               #0c0c1a;
    --page-surface:          rgba(255,255,255,0.04);
    --page-surface-elevated: rgba(255,255,255,0.08);
    --page-border:           rgba(255,255,255,0.12);
    --page-text:             #fff;
    --page-text-secondary:   rgba(255,255,255,0.72);
    --page-text-tertiary:    rgba(255,255,255,0.5);
}
/* SFS workshops restate the dark default explicitly (single-slug block, same
   gate rationale as FSC/CC above). SFS backstage is the SHIROFES dark navy. */
body[data-brand="sfs"] {
    --page-bg:               #0c0c1a;
    --page-surface:          rgba(255,255,255,0.04);
    --page-surface-elevated: rgba(255,255,255,0.08);
    --page-border:           rgba(255,255,255,0.12);
    --page-text:             #fff;
    --page-text-secondary:   rgba(255,255,255,0.72);
    --page-text-tertiary:    rgba(255,255,255,0.5);
}

/* v135.612 — explicit FSC + CC inheritance decisions for the prep + card
   namespaces. The check-brand-private-token-coverage CI gate (v135.612)
   requires every page-private namespace with brand-aware overrides to
   declare a block for EVERY registered brand, not just the ones that
   currently differ from the default. FSC + CC operators see the
   SHIROFES default dark chrome on prep / debrief / live today (FSC has
   ivory landing/kiosk but dark backstage, mirroring the FSC pattern in
   styles.css; CC similar). Restating those values explicitly here
   satisfies the gate AND surfaces an explicit decision in code for
   future maintainers — "yes, FSC + CC prep is intentionally the same
   dark navy as SHIROFES." If a future ship wants FSC ivory backstage,
   this block is where the values get flipped. */
body[data-brand="fsc"] {
    --prep-bg:            #0c0c1a;
    --prep-surface:       #14142a;
    --prep-surface-hover: #1c1c3a;
    --prep-border:        rgba(255,255,255,0.09);
    --prep-text:          #fff;
    --prep-text-dim:      rgba(255,255,255,0.7);
    --prep-text-faint:    rgba(255,255,255,0.45);
    --prep-danger-text:   #fca5a5;
    --prep-warn-text:     #fbbf24;
    --prep-info-text:     #93c5fd;
    --prep-success-text:  #34d399;
    --card-bg:            #1a1a32;
}
body[data-brand="cc"] {
    --prep-bg:            #0c0c1a;
    --prep-surface:       #14142a;
    --prep-surface-hover: #1c1c3a;
    --prep-border:        rgba(255,255,255,0.09);
    --prep-text:          #fff;
    --prep-text-dim:      rgba(255,255,255,0.7);
    --prep-text-faint:    rgba(255,255,255,0.45);
    --prep-danger-text:   #fca5a5;
    --prep-warn-text:     #fbbf24;
    --prep-info-text:     #93c5fd;
    --prep-success-text:  #34d399;
    --card-bg:            #1a1a32;
}
/* SFS workshops — prep + card namespaces, dark default (single-slug block,
   same gate rationale as FSC/CC above). */
body[data-brand="sfs"] {
    --prep-bg:            #0c0c1a;
    --prep-surface:       #14142a;
    --prep-surface-hover: #1c1c3a;
    --prep-border:        rgba(255,255,255,0.09);
    --prep-text:          #fff;
    --prep-text-dim:      rgba(255,255,255,0.7);
    --prep-text-faint:    rgba(255,255,255,0.45);
    --prep-danger-text:   #fca5a5;
    --prep-warn-text:     #fbbf24;
    --prep-info-text:     #93c5fd;
    --prep-success-text:  #34d399;
    --card-bg:            #1a1a32;
}

/* ───────────────────────────────────────────────────────────────────────
 * v135.609 — admin-auth.js overlay surface flip for ROS
 *
 * shared/admin-auth.js renders the sign-in overlay (#authOverlay) with
 * inline styles that read `var(--shirofes-black, #0c0c1a)` for the full-
 * page background and `var(--bg-card, #1a1a32)` for the sign-in/access-
 * request panels. Inline text colors read `var(--text-secondary, white-
 * rgba)` and similar white-tinted fallbacks — invisible on a white panel.
 *
 * Four-layer fix (v135.609 → v135.609 hotfix):
 *   1. Force #authOverlay background to white (overrides the inline
 *      --shirofes-black via !important — we don't redefine the token
 *      globally because stage.css uses it as a dark text color on amber).
 *   2. Override --bg-card + --text-* tokens SCOPED TO #authOverlay so
 *      the inline `var()` references resolve to ink-on-white inside the
 *      overlay WITHOUT cascading to other dark surfaces on the page
 *      (e.g. .mode-card-desc on landing reads var(--text-secondary)
 *      and needs to stay white-rgba for legibility on dark cards).
 *      Initial v135.609 ship placed these on body[data-brand="ros"]
 *      which bled into the landing mode-cards — operator flagged via
 *      screenshot showing dark-ink description text on dark navy cards.
 *      Scoping to #authOverlay isolates the white-skin token bundle.
 *   3. Border + text-color overrides on the panels themselves for any
 *      child element that doesn't pick up the var() flip cleanly.
 *   4. Button/form-input overrides scoped to #authOverlay so .btn-primary
 *      / .form-input on other surfaces (admin.html etc.) stay default.
 * ─────────────────────────────────────────────────────────────────────── */
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay {
    --bg-card:        #ffffff;
    --text-primary:   #0c0c1a;
    --text-secondary: rgba(12, 12, 26, 0.72);
    --text-tertiary:  rgba(12, 12, 26, 0.55);
    --border-color:   rgba(0, 0, 0, 0.14);
    background: var(--ros-paper) !important;
    color: var(--ros-ink);
}
body[data-brand="ros"]:not([data-ops-dark="1"]) #authSignInPanel,
body[data-brand="ros"]:not([data-ops-dark="1"]) #authAccessRequestPanel {
    background: var(--ros-paper) !important;
    border: 2px solid var(--ros-ink) !important;
    box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.08);
    color: var(--ros-ink) !important;
}
/* Inline-styled headings + paragraphs inside the overlay had no explicit
   color (inherited from --shirofes-black=#0c0c1a → white text in default
   skin); on the white panel they need an explicit ink color. */
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay h1,
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay h2,
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay p,
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay label,
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay form span,
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay #authCurrentEmailDisplay {
    color: var(--ros-ink) !important;
}
/* Form inputs (.form-input) default to dark surface; flip to white-on-ink-
   border so the email/password fields read legibly on the white panel. */
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay .form-input {
    background: #ffffff !important;
    color: var(--ros-ink) !important;
    border: 1px solid rgba(0, 0, 0, 0.22) !important;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay .form-input:focus {
    border-color: var(--ros-ink) !important;
    outline: 2px solid rgba(0, 0, 0, 0.15);
    outline-offset: 1px;
}
/* Primary action button (Sign in / Submit request) inherits .btn-primary
   which is brand-red on default skin. For ROS we want it black-on-white. */
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay .btn.btn-primary {
    background: var(--ros-ink) !important;
    color: #ffffff !important;
    border: 2px solid var(--ros-ink) !important;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay .btn.btn-secondary {
    background: #ffffff !important;
    color: var(--ros-ink) !important;
    border: 2px solid var(--ros-ink) !important;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay .btn.btn-ghost {
    background: transparent !important;
    color: rgba(12, 12, 26, 0.65) !important;
    border: 1px solid rgba(0, 0, 0, 0.18) !important;
}
/* "新規登録 / Create account" link uses --shirofes-red which we re-aliased
   to ink for ROS — already correct, but force-override for clarity. */
body[data-brand="ros"]:not([data-ops-dark="1"]) #authOverlay a {
    color: var(--ros-ink) !important;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
}
body[data-brand="cc"] .landing::before,
body[data-brand="cc"] .landing::after,
body[data-brand="cc"] .kiosk-container::before {
    display: none !important;
}
body[data-brand="cc"] .mode-grid::before { display: none !important; }

/* Text colors on CC's ink-navy — near-white with cyan-tinted secondary. */
/* v135.1167 — same data-ops-dark gate as the FSC flip above (backstage
   dark pages opt out; the mc-script title carries .section-label). */
body[data-brand="cc"]:not([data-ops-dark="1"]) .section-label,
body[data-brand="cc"]:not([data-ops-dark="1"]) .landing-tagline {
    color: rgba(240, 248, 255, 0.94) !important;
    text-shadow: none !important;
}
body[data-brand="cc"] .landing > div[style*="rgba(255,255,255"] {
    color: rgba(200, 230, 255, 0.68) !important;
}

/* Landing wordmark text-span — bigger footprint for landing surface.
   v135.503 — text-span fallback retained for surfaces without a logo
   image. When shared/assets/cc/wordmark-*.png ships (handled by
   brand-apply.js' BRAND_WORDMARKS map below), this rule applies only
   to elements that didn't get the image swap. */
body[data-brand="cc"] .brand-wordmark-text.landing-wordmark {
    font-size: 2.5rem;
    padding: 0.45em 0.75em;
    letter-spacing: 0.12em;
    background: var(--cc-accent);
    color: #ffffff;    /* white text on electric-blue for night-party energy */
}

/* Kiosk header wordmark text-span — CC keeps electric-blue-on-dark. */
body[data-brand="cc"] .brand-wordmark-text.kiosk-header-wordmark {
    background: var(--cc-accent);
    color: #ffffff;
}

/* CC img wordmark — neutralize the SHIROFES `filter: invert(1)` that the
   base styles.css applies (white wordmark PNG → black on light surfaces).
   CC ships dedicated black + white PNGs so we want the source unchanged.
   Mirrors the FSC pattern at line 199. */
body[data-brand="cc"] img[data-brand-img="cc"] {
    filter: none !important;
}

/* Header wordmark on admin/staff/stage/judge — CC stays cyan-on-dark
   chrome; small size already set by base rule. */

/* CC accent threading — reuse SHIROFES's --shirofes-red token in a few
   places (header bars, connection dots, primary buttons). We remap via
   --shirofes-red inside the CC scope so existing components pick up the
   cyan without having to rewrite every selector.
   NOTE: Only safe because --shirofes-red is used exclusively as an
   ACCENT, not as a literal brand color in SHIROFES-specific chrome.
   The FSC section intentionally does NOT remap this for the same reason
   (FSC uses #E50012 which happens to equal --shirofes-red by chance).

   v135.511 WCAG fix: --shirofes-red is used as `color: var(--shirofes-red)`
   text across ~25 dark-chrome pages (admin/stage/live/dj/judge/etc.). The
   v135.507 remap to --cc-accent (#1B6CFF, 4.32:1 on white / 3.78:1 on dark
   #0c0c1a) failed AA on both. v135.511 remaps --shirofes-red itself to
   --cc-accent-on-dark (#4D8DFF, 6.50:1 on dark — passes AA), since the
   overwhelmingly common surface is dark. Light-surface pages
   (register.html, kiosk/landing, privacy.html) override with
   --cc-accent-on-light (#1A56DB) inside their local body styles — see
   the per-page light-surface overrides at the bottom of this file. */
body[data-brand="cc"] {
    --shirofes-red: var(--cc-accent-on-dark);
    --shirofes-red-on-dark: var(--cc-accent-on-dark);
}

/* Light-surface CC pages — override --shirofes-red to the AA-on-light
   variant so text inherits readable contrast (#1A56DB = 6.10:1 on white).
   This pattern is selector-based not body-class-based; it catches public
   pages that compose against ivory/white surfaces.

   register.html, privacy.html: already have local `body { ... }` light
   token blocks; this rule slots in via :where() so specificity matches.
   kiosk.html landing surface: --kiosk-bg is ivory under FSC/CC.
   landing index: .landing has transparent surface; backdrop reads behind. */
body[data-brand="cc"].light-surface,
body[data-brand="cc"][data-light-surface="1"] {
    --shirofes-red: var(--cc-accent-on-light);
    --shirofes-red-on-dark: var(--cc-accent-on-light);
}

/* v136.151 — Per-event identity (SFS Events Portfolio, Phase 1). An event whose
   doc carries identity.accentColor gets --event-accent set on <html> + the
   data-event-identity hook on <body> (by brand-apply.js, ATOMICALLY — the var is
   only ever set together with the hook, so there is no fallback cycle here).
   Remap the primary accent token to it so the event's color spreads to every
   accent surface (FULL reach, Alex lock 2026-06-23). Specificity
   `html body[...][...]` = (0,2,2) beats every per-brand --shirofes-red remap
   (ROS/CC/CC-light, all ≤ (0,2,1)) regardless of source order. NO identity block
   → no hook → this never applies → byte-identical for every existing event. */
html body[data-brand][data-event-identity="1"] {
    --shirofes-red: var(--event-accent);
    --shirofes-red-on-dark: var(--event-accent);
}

/* Per-page light-surface markers — register.html + privacy.html + kiosk
   public landing all carry data-light-surface="1" on body since v135.511.
   For pages that don't (yet) carry the marker, the dark-on-dark default is
   correct — most pages are dark chrome. */


/* ─────────────────────────────────────────────────────────────────
   v135.645 — Universal chip helpers (M-1 categorical contrast fix)

   Background: contrast audit flagged ~71 admin.html inline-JS chip sites
   using saturated colors (#22d3ee / #34d399 / #fbbf24 / #f87171 etc.) as
   bare `color: #...` text WITHOUT a paired dark background. On the ROS
   white body (and any brand-neutral parent), those colors all fail
   WCAG AA 4.5:1 normal-text contrast.

   The fix shape (per platform invariant: reduce operator cognitive load
   + categorical fixes over point-patches): ship four reusable chip
   classes with the 18%-opacity colored fill that always provides
   readable contrast on any brand background — ROS white, dark chrome,
   or ivory FSC/CC light surfaces.

   USAGE — new code only. Existing 71 admin sites NOT retrofitted in
   v135.645 (too much surface; tracked separately). Future code that
   needs a colored chip writes:
     <span class="sfs-chip-info">EN</span>
     <span class="sfs-chip-success">paid</span>
     <span class="sfs-chip-warning">unpaid</span>
     <span class="sfs-chip-danger">refund</span>

   WCAG AA verified at 18% opacity fill + colored text on:
     - #FFFFFF (ROS body)        — 4.5:1+ all four
     - #0c0c1a (dark chrome)     — 4.5:1+ all four
     - #FFF8E7 (FSC ivory)       — 4.5:1+ all four
   ────────────────────────────────────────────────────────────────── */
.sfs-chip-info,
.sfs-chip-success,
.sfs-chip-warning,
.sfs-chip-danger {
    display: inline-block;
    padding: 0.18rem 0.55rem;
    border-radius: 6px;
    font-weight: 600;
    font-size: 0.78rem;
    line-height: 1.2;
    letter-spacing: 0.02em;
    white-space: nowrap;
}
.sfs-chip-info    { background: rgba(34, 211, 238, 0.18); color: #22d3ee; border: 1px solid rgba(34, 211, 238, 0.4); }
.sfs-chip-success { background: rgba(52, 211, 153, 0.18); color: #34d399; border: 1px solid rgba(52, 211, 153, 0.4); }
.sfs-chip-warning { background: rgba(251, 191, 36, 0.18); color: #fbbf24; border: 1px solid rgba(251, 191, 36, 0.4); }
.sfs-chip-danger  { background: rgba(248, 113, 113, 0.18); color: #f87171; border: 1px solid rgba(248, 113, 113, 0.4); }

/* ──────────────────────────────────────────────────────────────────
   v135.646 — Semantic colored-text tokens for naked inline text
   ──────────────────────────────────────────────────────────────────
   Sister of the .sfs-chip-* helpers above. Those are for
   colored-text-on-colored-fill chips (paired bg + colored fg + border;
   AA-verified on any brand surface). These tokens are for NAKED inline
   text — `color:#f87171` style helpers without a paired background.

   The DEFAULT (root) values match the existing dark-chrome literals
   (#f87171 / #10b981 / #fbbf24 / #22d3ee). On ROS body the values
   FLIP to darker variants that hit WCAG AA on a white background.

   Migration pattern (per page-private-token-namespaces.md §Semantic
   colored-text tokens):

     <span style="color:#f87171">エラー文</span>
       →
     <span style="color:var(--text-danger,#f87171)">エラー文</span>

   Sites that already pair a dark background + colored fg + border keep
   the literal — they're chips and the contrast story already works.
   ────────────────────────────────────────────────────────────────── */
:root {
    --text-danger:  #f87171;
    --text-success: #10b981;
    --text-warning: #fbbf24;
    --text-info:    #22d3ee;
}
body[data-brand="ros"]:not([data-ops-dark="1"]) {
    --text-danger:  #b91c1c;
    --text-success: #047857;
    --text-warning: #b45309;
    --text-info:    #0e7490;
}
