/*
 * ozai-palette-lab.css
 *
 * Opt-in palette-testing rig -- see app/js/ozai-palette-lab.js for
 * activation. Three independent dimensions:
 *   - Palette variant: ?palette=warm|paper|slate|white|white-indigo on
 *     /workspace only, persisted to localStorage, scoped under
 *     [data-palette="..."]. `white-indigo` is a frozen A/B twin of `white`'s
 *     original all-indigo look (see that section below) kept only so the
 *     founder can compare it against `white`'s now fully monochrome
 *     (black/grey) treatment.
 *   - Sidebar darkness: ?sidebar=subtle|medium|deep on /workspace only,
 *     persisted separately, scoped under [data-sidebar="..."] -- see the
 *     "Sidebar darkness" section near the end of this file.
 *   - Accent (CTA color shotgun): ?accent=electric|cobalt|azure|
 *     ultramarine|sky|ember|lime on /workspace only, persisted separately,
 *     scoped under [data-accent="..."] -- see the "Accent" section near the
 *     end of this file.
 *
 * Every rule below is scoped under one of those three attributes, which are
 * only ever set by explicit opt-in on the /workspace route. With no opt-in
 * this file contributes nothing -- the defaults defined in ozai.css are
 * completely untouched. Safe to delete this file + its <link> + <script>s in
 * index.html + the initPaletteLab() call in ozai-app.js to fully retire
 * the rig; nothing else depends on it.
 *
 * Each variant overrides the background/surface/shell/text tokens, plus
 * two accent-shaped tokens the founder called out directly ("move away
 * from the blueish accent/background"):
 *   - --signal: the theme-aware accent (text/links/borders/focus). Also
 *     drives --btn-solid-bg/--btn-solid-fg on solid CTA buttons (see
 *     ozai.css's default `--btn-solid-bg: var(--signal)`) -- see the
 *     ACCENT-UNIFY note below.
 *   - --accent: a second, theme-INVARIANT token with no default declaration
 *     anywhere in app/ -- relied on via its `var(--accent, #84d0e4)` CSS
 *     fallback at its remaining ~14 DECORATIVE call sites (field labels,
 *     badges/pill borders, the streaming cursor + loading dot, quick-
 *     prompt hover borders), so it stays hard cyan under every theme AND
 *     every variant unless explicitly set here. Each variant sets one
 *     accent value (not split by theme, matching how every remaining call
 *     site already uses it) picked from the same hue family as that
 *     variant's --signal. These call sites use --accent as plain text/
 *     border color against a light --shell (e.g. .v2-field-label) and
 *     inherit the same contrast profile the stock cyan already has there
 *     (~1.7:1 on white) -- a pre-existing baseline gap in the default app's
 *     light theme, not something introduced or worsened by this rig
 *     (measured ~1.9-2.4:1 for these variants, slightly better than stock).
 *
 *     2026-08-28 ACCENT-UNIFY: --accent used to ALSO drive ~7-8 solid-fill
 *     primary buttons (base .v2-btn-primary, the New Session modal's
 *     Create button, the notif rate pill, the wearable-connect CTA, the
 *     camp switch/edit-form Confirm/Save buttons) via hardcoded
 *     `color: #0a1428` (or `var(--bg)`) paired text -- which meant those
 *     buttons tracked NEITHER the app's own theme NOR the ?accent=
 *     dimension below (only --btn-solid-bg/--btn-solid-fg ever did),
 *     confirmed live as a grey "Create" button under
 *     `?palette=white&accent=electric` (--accent stayed white's #bcbcbc
 *     grey since ?accent= never touches it). Every such button is now
 *     unified onto --btn-solid-bg/--btn-solid-fg like the six buttons
 *     already on that pair (ozai.css) -- see each button's own comment in
 *     ozai-v2.css (search "ACCENT-UNIFY"). --accent itself is UNCHANGED by
 *     this pass (still theme-invariant, still only decorative call sites
 *     below) -- do not delete it.
 * --warn/--danger/--ok are intentionally left alone in every variant --
 * they cascade down from the base [data-theme] blocks in ozai.css
 * unchanged, since their warm/red/green hues were never the "blue cast"
 * complaint and re-tuning them would be the separate "more colors
 * generally" ticket, not this one.
 */

/* ---------------------------------------------------------------------- */
/* Warm -- light ground #f1eeea family, white cards pop; dark lifted to a
   warm charcoal grey (not pure black). Accent family: terracotta. */

:root[data-palette="warm"][data-theme="light"] {
    --bg: #f1eeea;
    --shell: #ffffff;
    --shell-2: #f8f5f1;
    --surface: rgba(64, 48, 32, 0.045);
    --surface-strong: rgba(64, 48, 32, 0.09);
    --line: rgba(72, 56, 40, 0.14);
    --line-strong: rgba(72, 56, 40, 0.24);
    --text: #201a14;
    --text-soft: #4a4038;
    --text-faint: #79695c;
    --signal: #b8592f;
    --chart-1: #b8592f;
    --shadow: 0 18px 40px rgba(40, 30, 20, 0.10);
}

:root[data-palette="warm"][data-theme="dark"] {
    --bg: #17140f;
    --shell: #201d19;
    --shell-2: #262220;
    --surface: rgba(255, 244, 230, 0.04);
    --surface-strong: rgba(255, 244, 230, 0.07);
    --line: rgba(210, 190, 170, 0.12);
    --line-strong: rgba(210, 190, 170, 0.18);
    --text: #f2ece4;
    --text-soft: #c2b7a8;
    --text-faint: #8f8375;
    --signal: #d68a52;
    --chart-1: #d68a52;
    --shadow: 0 28px 80px rgba(10, 8, 5, 0.30);
}

/* --accent is theme-invariant (see the file-header note), same as the
   stock #84d0e4 fallback it replaces. */
:root[data-palette="warm"] {
    --accent: #e0a273;
}

/* ---------------------------------------------------------------------- */
/* Paper -- light ground #f8f6f4 family, white cards pop; dark lifted to a
   neutral grey. Accent family: deep plum/wine. */

:root[data-palette="paper"][data-theme="light"] {
    --bg: #f8f6f4;
    --shell: #ffffff;
    --shell-2: #f4f1ed;
    --surface: rgba(40, 35, 30, 0.04);
    --surface-strong: rgba(40, 35, 30, 0.08);
    --line: rgba(50, 44, 38, 0.12);
    --line-strong: rgba(50, 44, 38, 0.20);
    --text: #14120f;
    --text-soft: #423c34;
    --text-faint: #726a5f;
    --signal: #7a3a54;
    --chart-1: #7a3a54;
    --shadow: 0 18px 40px rgba(20, 20, 20, 0.07);
}

:root[data-palette="paper"][data-theme="dark"] {
    --bg: #17181a;
    --shell: #1e2022;
    --shell-2: #24272a;
    --surface: rgba(255, 255, 255, 0.04);
    --surface-strong: rgba(255, 255, 255, 0.07);
    --line: rgba(200, 205, 210, 0.10);
    --line-strong: rgba(200, 205, 210, 0.16);
    --text: #eef0f2;
    --text-soft: #b7bcc2;
    --text-faint: #82888f;
    --signal: #c97a97;
    --chart-1: #c97a97;
    --shadow: 0 28px 80px rgba(0, 0, 0, 0.30);
}

:root[data-palette="paper"] {
    --accent: #d99bb3;
}

/* ---------------------------------------------------------------------- */
/* Slate -- designer's-choice middle path: warm-neutral light ground
   (between Warm and Paper), true neutral grey dark (the most literal read
   of "more greyish", no warm or cool bias). Accent family: muted rust-brown. */

:root[data-palette="slate"][data-theme="light"] {
    --bg: #f2efeb;
    --shell: #ffffff;
    --shell-2: #f7f4f0;
    --surface: rgba(45, 42, 38, 0.04);
    --surface-strong: rgba(45, 42, 38, 0.08);
    --line: rgba(60, 55, 48, 0.13);
    --line-strong: rgba(60, 55, 48, 0.22);
    --text: #171512;
    --text-soft: #3e3a34;
    --text-faint: #6d685f;
    --signal: #8a4a30;
    --chart-1: #8a4a30;
    --shadow: 0 18px 40px rgba(30, 26, 20, 0.09);
}

:root[data-palette="slate"][data-theme="dark"] {
    --bg: #1c1b1a;
    --shell: #232221;
    --shell-2: #2a2928;
    --surface: rgba(255, 255, 255, 0.045);
    --surface-strong: rgba(255, 255, 255, 0.08);
    --line: rgba(200, 196, 190, 0.12);
    --line-strong: rgba(200, 196, 190, 0.18);
    --text: #f0eeec;
    --text-soft: #bcb8b3;
    --text-faint: #8a8681;
    --signal: #c07850;
    --chart-1: #c07850;
    --shadow: 0 28px 80px rgba(0, 0, 0, 0.32);
}

:root[data-palette="slate"] {
    --accent: #d29a76;
}

/* ---------------------------------------------------------------------- */
/* White -- the "Claude/OpenRouter" look the founder referenced directly:
   a genuinely white content area with a subtly grey sidebar sitting a
   step back from it.

   2026-08-27 REVISION (founder feedback): the original ship of this
   variant set --signal (and --chart-1, which always echoes it) to an
   indigo #4f46e5, which replaced the app's native accent EVERYWHERE --
   not just solid action buttons, but every readiness/status dot, load/
   progress bar fill, chart series line, and the active twin-tab
   underline, all of which are DATA, not chrome. Founder reaction: "not
   just the buttons... a purple accent that replaces the bluish... for
   buttons instead of the purple will do black... other places also has
   that purple." The fix below splits by role instead of overriding one
   token everywhere:
     - Chrome (solid action buttons: send/sign-in/CTA/notif-save) -- now
       driven by the app-wide --btn-solid-bg/--btn-solid-fg token pair
       (see ozai.css), overridden to black/white a few lines down. Color
       there is decoration, not information, so black is safe.
     - Data & status (bar fills, chart lines, status dots, tab
       underlines, sliders) -- these all read --signal/--chart-1 directly
       and are NEVER repointed to --btn-solid-bg (see ozai-v2.css's
       per-selector comments) -- so --signal/--chart-1 below are reset to
       the app's own native light-theme teal (#0f5e7a), not deleted
       outright. Deleting them entirely would let --signal fall through to
       whatever the literal (unrelated) [data-theme] attribute's own block
       sets -- fine in light theme (same #0f5e7a value either way), but if
       the app's own dark/light toggle is still literally set to dark
       while ?palette=white forces this light look, that fallback would be
       the DARK theme's pale cyan #84d0e4, which measures ~1.7:1 against
       this variant's forced-white ground (verified below) -- essentially
       invisible on a bar fill or tab underline. Hardcoding the light-theme
       value here avoids that failure mode and keeps data legible
       regardless of the toggle, consistent with how --bg/--text/etc. in
       this same block already force the light look unconditionally.
     - Picker selection highlights (.v2-sel-selected, .v2-dp-selected,
       .v2-dp-today, .v2-tp-selected) -- untouched, so they stay on
       --signal (now teal) too. Neither chrome nor data; black would make
       pickers look dead.
     - --accent (a second, theme-invariant token -- see the file-header
       comment) was left un-overridden by this revision (see removed text
       above), which restored the app's native cyan/teal fallback at its
       ~20 call sites.

   2026-08-27 SECOND REVISION (same day, follow-up founder feedback):
   "in the white replace that blueish color with black colors" -- the
   native teal (#0f5e7a) kept for data/status by the revision above, and
   the un-overridden native cyan --accent fallback, are exactly the
   "blueish" the founder is still seeing. This supersedes both decisions
   from the revision above -- `white` is now fully monochrome, no teal or
   cyan survives anywhere in it:
     - --signal is now #111111, the same near-black already used for
       --btn-solid-bg. Every --signal-driven data/status site (bar fills,
       chart lines, status dots, the active twin-tab underline, focus
       rings, slider thumbs, picker selection highlights, the active-nav
       color-mix tint) follows to monochrome automatically -- none of
       those call sites are repointed individually, they all read
       var(--signal) directly.
     - --chart-1 is set to a dark neutral grey (#404040), NOT the same
       #111111 as --signal/--btn-solid-bg. --chart-1 only drives the
       first series of the multi-series team-analytics chart (.v2-ta-c0),
       alongside --chart-2..--chart-6 -- this variant doesn't override
       those, so they stay the stock light-theme values (amber-brown
       #8a5e10, purple #5b4f8a, rose #a8395a, green #3e6b3a, brown
       #8a5a30). A literal #111111 there would read closer to --line-
       strong's rendered value (rgba(15,23,42,0.48) composited on white
       ~= rgb(140,144,153), well short of #111 but the two are still both
       "near-black" in the same visual family) and would sit starkly
       darker than every sibling series, reading as an axis/ink mark
       rather than "series 1 of 6". #404040 keeps it unambiguously
       monochrome (zero saturation, unlike the other five which are all
       hued) while landing in a similar luminance neighborhood to them
       (see Contrast below) so it sits sensibly alongside its siblings
       instead of vanishing into the gridlines or overpowering the set.
     - --accent is now #bcbcbc, a neutral mid-light grey (previously left
       un-overridden, which is what let the stock cyan fallback survive
       here -- see the file-header comment on why every call site needs
       an explicit override to escape that fallback). Chosen specifically
       so the hardcoded `color: #0a1428` text at this token's ~7 solid-
       fill call sites (background: var(--accent, ...)) stays legible --
       #bcbcbc gives ~9.6:1 there, comfortably clearing the same >=7.5:1
       bar the other three variants' accents hit (a literal near-black
       --accent would put that dark text on a dark fill and fail this
       exact check -- confirmed by computing it before picking #bcbcbc).
       The plain-text/border call sites (e.g. .v2-field-label) land
       ~1.9:1 on white, in the same pre-existing sub-AA ballpark as the
       other variants (~1.9-2.4:1) and the stock cyan (~1.7:1) -- not
       something this pass introduces or worsens.
     - Picker selection highlights (.v2-sel-selected, .v2-dp-selected,
       .v2-dp-today, .v2-tp-selected) still read --signal directly, so
       they follow it to monochrome too now -- accepted per the founder's
       explicit "replace that blueish color with black" ask; there is no
       longer a "teal, not black" carve-out for them.
     - .v2-send-btn:focus-visible needed a targeted fix: the app-wide
       `.v2-shell *:focus-visible { outline: 2px solid var(--signal); }`
       rule now draws a #111111 outline flush against a #111111
       (--btn-solid-bg) button -- a black ring on a black button, i.e.
       invisible. Overridden below (this variant only) to a two-tone
       box-shadow ring instead of the plain outline: a --shell-colored
       gap directly against the button, then a --signal ring outside
       that gap -- so the ring is visible against the light composer
       background via the gap, rather than relying on contrast against
       the button itself (which is the one case where --signal and
       --btn-solid-bg are now identical).

   DELIBERATE DEVIATION from warm/paper/slate's pattern (unchanged from
   the original ship): this is ONE unconditional block, not a
   [data-theme="light"] / [data-theme="dark"] pair. "White background,
   grey sidebar" only reads as a coherent design in one direction --
   there's no sensible "dark-mode white" -- so rather than leaving
   [data-theme="dark"] either unreadable (dark text tokens surviving
   against a forced-white bg) or silently no-op (confusing: the pill would
   show "White" active while nothing visibly changed), ?palette=white
   FORCES this light treatment regardless of the app's own dark/light
   theme toggle. A single :root[data-palette="white"] selector
   (specificity 0-2-0) beats the dark-theme base block (:root, [data-theme
   ="dark"] -- each selector in that group is only 0-1-0) unconditionally,
   and ties with the light-theme base block (:root[data-theme="light"],
   also 0-2-0) -- resolved in this file's favor by source order, since
   ozai-palette-lab.css loads after ozai.css (see index.html). So every
   token below applies regardless of the literal data-theme attribute.

   Known, flagged residual: a handful of UI details elsewhere key off the
   literal [data-theme="light"] attribute directly rather than these
   custom properties (the auth topbar sun/moon icon swap, the 3D twin
   stage/card-dot colors, a few camp-block hero/rest-row rules) -- those
   won't flip to their light-tuned variants if the app's own toggle is
   still literally set to dark while ?palette=white is forced on. This is
   a narrow, purely decorative inconsistency (never a text-on-background
   readability problem, which is what forcing the block above already
   solves) and out of scope for this founder-eyes-only comparison rig to
   chase down across the whole app.

   Contrast (computed via WCAG relative luminance):
     --text      #14171a on white (--bg/--shell) ~18:1
     --text-soft #475569 on white ~7.6:1 / on --sidebar-bg ~7.0:1
     --text-faint #58697d on white ~5.6:1 / on --sidebar-bg ~5.2:1
   All comfortably clear the ~4.5:1 body-text bar (and the nav labels
   that sit on --sidebar-bg specifically, per the "just a bit greyish
   sidebar" ask, clear it too). These three are unchanged by the second
   revision below.
     --signal/--btn-solid-bg #111111 (2026-08-27 SECOND REVISION --
       superseding the #0f5e7a teal figure from the first revision above)
       measures ~18.9:1 on white (--bg/--shell) and ~17.5:1 on
       --sidebar-bg #f5f6f7 -- both far in excess of the ~3:1 UI bar,
       expected for a near-black on near-white pairing. --signal and
       --btn-solid-bg are now the same value everywhere in this variant
       (see the .v2-send-btn:focus-visible note above for the one place
       that equality needed a targeted fix), so there is only one figure
       to report for both.
     --chart-1 #404040 on white ~10.4:1 -- clearly legible as a chart
       series and distinctly darker than any of the untouched
       --chart-2..--chart-6 (~5.7-7.2:1 in this variant's forced-light
       ground, computed for comparison), which is the intended "sits
       alongside, doesn't vanish or dominate" read -- see the reasoning
       above for why this is a dark neutral grey rather than literally
       #111111.
     --accent #bcbcbc (2026-08-27 SECOND REVISION -- superseding "no
       override, native cyan fallback" from the first revision above):
       measured here at ~9.6:1 against the (then-)hardcoded #0a1428 text
       at its ~7 solid-fill call sites; those call sites no longer read
       --accent at all as of the 2026-08-28 ACCENT-UNIFY pass (see the
       file-header comment) -- they render --btn-solid-bg #111111 /
       --btn-solid-fg #ffffff instead, i.e. the ~18.9:1 figure above, an
       improvement. --accent's one surviving figure below (~1.9:1 as
       plain text/border against white at the .v2-field-label-style call
       sites) is unaffected -- in the same pre-existing sub-AA range as
       the other three variants (~1.9-2.4:1) and the stock cyan (~1.7:1),
       not something this pass introduces or worsens.
   Borders: --line (rgba(15,23,42,0.14), a plain subtle divider) measures
   ~1.3:1 on white -- below the ~3:1 UI-non-text-contrast guideline, but
   this matches every sibling variant's divider (warm/paper/slate all
   land ~1.2-1.4:1 against their own near-white shells) and is standard
   for decorative dividers across flat-white UIs generally (GitHub/Linear/
   Notion all ship dividers in this same sub-3:1 range, relying on
   spacing/shadow rather than contrast for separation) -- pushing it to a
   literal 3:1 would need a solid mid-grey border (~gray-500) that reads
   as a heavy slab, the opposite of "subtle". Flagging rather than
   silently shipping it, same posture as the "deep" sidebar-darkness note
   below. --line-strong (used for stronger emphasis borders/dividers) is
   deliberately pushed further, to rgba(15,23,42,0.48) (~2.9-3.2:1
   depending on white vs. --sidebar-bg ground) specifically so the
   stronger tier clears the bar in practice.

   --sidebar-bg is set INSIDE this same unconditional block (not derived
   from --shell via color-mix like the separate sidebar-darkness dimension
   below) -- it's a fixed light grey, distinct from the white --bg/--shell,
   because the founder's ask is for grey-sidebar-on-white-content to be
   the variant's own default, no ?sidebar= param required. Composability
   with the independent ?sidebar= dimension is preserved on purpose: this
   block's --sidebar-bg declaration is placed BEFORE the "Sidebar
   darkness" section below in this file, and both selectors are the same
   0-2-0 specificity tier (:root[data-palette="white"] vs.
   :root[data-sidebar="X"]) -- so when both are set, the LATER-in-file
   sidebar-darkness rule wins the specificity tie by source order and
   correctly overrides this variant's own sidebar value. Verified by
   reading computed styles for ?palette=white&sidebar=deep (see the
   accompanying verification notes) -- --sidebar-bg resolves to the
   "deep" color-mix, not this block's #f5f6f7. */

:root[data-palette="white"] {
    --bg: #ffffff;
    --shell: #ffffff;
    --shell-2: #f7f7f8;
    --sidebar-bg: #f5f6f7;
    --surface: rgba(15, 23, 42, 0.035);
    --surface-strong: rgba(15, 23, 42, 0.07);
    --line: rgba(15, 23, 42, 0.14);
    --line-strong: rgba(15, 23, 42, 0.48);
    --text: #14171a;
    --text-soft: #475569;
    --text-faint: #58697d;
    --signal: #111111;
    --chart-1: #404040;
    --accent: #bcbcbc;
    --btn-solid-bg: #111111;
    --btn-solid-fg: #ffffff;
    --shadow: 0 18px 40px rgba(20, 20, 24, 0.07);
}

/* --signal and --btn-solid-bg are now the same #111111 in this variant
   (see the SECOND REVISION note above) -- the app-wide
   `.v2-shell *:focus-visible { outline: 2px solid var(--signal); }` rule
   (ozai-v2.css) would draw that ring flush against a same-color button,
   i.e. invisible. Two-tone box-shadow instead of a plain outline: a
   --shell-colored gap right against the button, then the --signal ring
   outside that gap, so the ring reads against the light composer
   background rather than needing contrast against the button itself. */
:root[data-palette="white"] .v2-send-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--shell), 0 0 0 4px var(--signal);
}

/* 2026-08-27 THIRD REVISION (same day, follow-up founder feedback): the 3D
   digital-twin model's stage backdrop is a further "blueish" survivor the
   token work above never reached, because ozai-v2.css hardcodes its two
   colors directly rather than reading --bg/--shell/--surface:
     .twin-body-figure                     -- ozai-v2.css:13251-13252 (dark
       theme default) / ozai-v2.css:13265-13268 (`:root[data-theme="light"]`
       override -- the one actually in effect here, since ?palette=white
       forces the light look per this file's own DELIBERATE DEVIATION note
       above)
     .twin-body-figure .twin-3d-loading    -- ozai-v2.css:13271-13279 (dark
       default) / ozai-v2.css:13282-13284 (`:root[data-theme="light"]`
       override)
   Both light-theme overrides use a cool blue-grey pair (#e6ecf3 stage /
   #f4f7fb-to-#d9e2ec gradient) -- the literal "bluish" the founder flagged
   in the live-browser stage-background check. Per the standing instruction
   not to edit ozai-v2.css while another agent is mid-edit there, the fix
   lives here instead, as two descendant-selector overrides shaped to match
   (and beat) those rules' specificity:
     `:root[data-theme="light"] .twin-body-figure` is :root + [data-theme]
       + .twin-body-figure = three class-level selectors (0-3-0).
     `:root[data-palette="white"] .twin-body-figure` below is the same
       shape (:root + [data-palette] + .twin-body-figure = 0-3-0) -- a
       specificity tie, resolved by source order (this file loads after
       ozai-v2.css, see index.html <link> order) exactly like this file's
       own top-level :root[data-palette="white"] block already relies on
       against the base :root[data-theme="light"] block. Same reasoning
       for the `.twin-3d-loading` pair one level deeper (0-4-0 vs 0-4-0).
       This also means the override wins regardless of the LITERAL
       data-theme attribute (dark or light) -- closing, for this one
       element, the "known flagged residual" this file's own comments
       already called out above ("the 3D twin stage/card-dot colors...
       won't flip... if the toggle is still literally set to dark").
   Values: every original color desaturated to a neutral grey at the same
   HSL lightness (so the "soft lit stage" falloff -- light center fading to
   a slightly deeper edge -- is preserved, just with the hue stripped):
   #e6ecf3->#ececec, #f4f7fb->#f8f8f8, #d9e2ec->#e3e3e3. The light-theme
   box-shadow's inset highlight stays (already neutral, rgba(255,255,255,
   *)) but its drop-shadow rgba(20,40,70,0.08) -- a navy-tinted shadow --
   is neutralized to rgba(20,20,20,0.08) (same alpha/blur/offset, hue
   stripped) for the same reason; `.twin-3d-loading` never declared its own
   box-shadow so there's nothing to override there.
   The rendered Three.js figure itself is readiness-tinted (good/warn/
   danger hues from body.js, never blue) via WebGL canvas draw calls, not
   CSS -- unaffected by (and not reachable through) this file. Verifying
   the model still reads clearly against the new neutral stage requires
   an actual WebGL-rendered browser check, which this pass could not run
   (no browser/WebGL tool available in this environment) -- flagged for a
   manual /qa pass on the Readiness tab. */
:root[data-palette="white"] .twin-body-figure {
    background-color: #ececec;
    background-image: radial-gradient(ellipse at 50% 50%, #f8f8f8 0%, #e3e3e3 75%);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.6), 0 8px 24px rgba(20, 20, 20, 0.08);
}

:root[data-palette="white"] .twin-body-figure .twin-3d-loading {
    background-color: #ececec;
    background-image: radial-gradient(ellipse at 50% 50%, #f8f8f8 0%, #e3e3e3 75%);
}

/* ---------------------------------------------------------------------- */
/* White (indigo) -- frozen A/B twin of `white`'s ORIGINAL ship (2026-08-27
   revision above): the founder didn't dislike the indigo look and wants to
   compare it side by side, so this reproduces it exactly, byte-for-byte,
   under its own `?palette=white-indigo` value -- same white bg/grey
   sidebar/neutral text as `white`, but --signal/--chart-1/--accent all on
   the original indigo family, and no --btn-solid-bg/--btn-solid-fg
   override (so solid buttons fall through to the shared default, i.e.
   var(--signal) = indigo, matching how those buttons actually looked
   before this revision). See the `white` section above for contrast notes
   and rationale -- this block intentionally does NOT get the same
   revisit. */

:root[data-palette="white-indigo"] {
    --bg: #ffffff;
    --shell: #ffffff;
    --shell-2: #f7f7f8;
    --sidebar-bg: #f5f6f7;
    --surface: rgba(15, 23, 42, 0.035);
    --surface-strong: rgba(15, 23, 42, 0.07);
    --line: rgba(15, 23, 42, 0.14);
    --line-strong: rgba(15, 23, 42, 0.48);
    --text: #14171a;
    --text-soft: #475569;
    --text-faint: #58697d;
    --signal: #4f46e5;
    --chart-1: #4f46e5;
    --accent: #a5b4fc;
    --shadow: 0 18px 40px rgba(20, 20, 24, 0.07);
}

/* ---------------------------------------------------------------------- */
/* 2026-08-28: this used to re-derive the base `body` rule's decorative
   radial-gradient blobs (+ the light-theme linear-gradient fade) from the
   overridden --signal/--danger/--bg tokens, so a palette variant's blobs
   would "de-blue" themselves instead of showing the hardcoded blue-teal
   default. Per founder feedback the base rule in ozai.css no longer paints
   any blobs or fade at all -- `body { background: var(--bg) }` -- so every
   variant already inherits a flat background for free via the --bg
   override above; this per-variant re-derivation is gone, not needed. */

/* ---------------------------------------------------------------------- */
/* Sidebar darkness -- a second, independent opt-in dimension (?sidebar=
   subtle|medium|deep on /workspace only, persisted separately from the
   palette variant above). Only --sidebar-bg is touched -- no other token --
   so it composes cleanly with any palette variant (or none) and with both
   themes: each level is a color-mix() built from --shell/--bg/black, which
   re-resolves per the cascade against whatever --shell/--bg an active
   palette variant + theme combination already sets, rather than a
   hand-picked hex per variant. See app/css/ozai.css for the --sidebar-bg
   default (= --shell, i.e. today's exact behavior) and everywhere it is
   consumed (.v2-sidebar, .v2-drawer, .v2-nav-subitems, .v2-drawer-subitems).

   Contrast check (2026-08-26): "deep" keeps comfortable contrast at every
   text token in dark theme, and keeps --text-soft (used by every real
   nav-item/sub-item label) comfortably >=5.8:1 in light theme too -- but
   pushes --text-faint (the Team-dropdown chevron glyph + the "Training"
   section-title label only) down to ~2.9:1 in light theme, below the
   ~4.5:1 the stock white sidebar barely clears today. "subtle"/"medium"
   stay within a few tenths of that stock baseline in both themes.
   Flagging rather than silently dropping "deep" -- this rig is
   founder-eyes-only and off by default everywhere else; pick by eye
   knowing that trade-off. */

:root[data-sidebar="subtle"] {
    --sidebar-bg: color-mix(in srgb, var(--shell) 60%, var(--bg) 40%);
}

:root[data-sidebar="medium"] {
    --sidebar-bg: var(--bg);
}

:root[data-sidebar="deep"] {
    --sidebar-bg: color-mix(in srgb, var(--bg) 85%, black 15%);
}

/* ---------------------------------------------------------------------- */
/* Accent (CTA color shotgun) -- a THIRD independent opt-in dimension
   (?accent=electric|cobalt|azure|ultramarine|sky|ember|lime on /workspace
   only, persisted separately from the palette variant and sidebar-darkness
   dimensions above). 2026-08-27 founder feedback: "not black... an actual
   color should be some call to action or like a shouting color"; five
   blue-family candidates plus two non-blue reference points (a warm
   orange/coral and a yellow-green), contrast treated as the deciding
   constraint over taste per the brief.

   Each option overrides FOUR tokens together so the whole UI moves as one
   color: --signal (theme-aware accent -- text/links/borders/focus/active
   tab underline), --chart-1 (team-analytics chart's first series, always
   the same hue as --signal per ozai.css's own convention), and
   --btn-solid-bg/--btn-solid-fg (solid CTA button fill + its label color).

   Deliberately does NOT touch --accent (a second, separate theme-invariant
   token -- see this file's header comment). As of the 2026-08-28
   ACCENT-UNIFY pass, --accent's remaining call sites are all DECORATIVE
   (field labels, badges/pill borders, the streaming cursor + loading dot,
   quick-prompt hover borders) -- the solid-fill buttons that used to read
   --accent (camp/session action buttons, the notif-rate pill, etc.) are
   now on --btn-solid-bg/--btn-solid-fg, which IS one of the four tokens
   this section overrides, so those buttons already pick up the selected
   accent color via the paragraph above; they no longer need (or get) any
   special-casing here. Composed with a palette variant that already sets
   --accent (warm/paper/slate/white/white-indigo), that palette's own
   --accent value is unaffected and stays in effect at those decorative
   call sites; with no palette active, they keep the stock cyan fallback
   while only an accent is selected.

   Each option is written as a `[data-theme="light"], [data-theme="dark"]`
   pair with IDENTICAL declarations on both sides (not tuned per theme, on
   purpose -- one shouting CTA color evaluated the same way regardless of
   the app's own dark/light toggle) purely so the selector's specificity
   (0-3-0: :root + [data-accent] + [data-theme]) reliably beats every
   palette variant's own --signal/--chart-1 -- including warm/paper/slate's
   own theme-split blocks (also 0-3-0, resolved by this section coming
   later in the file) and white/white-indigo's single unconditional blocks
   (0-2-0, definitively lower regardless of order). This is what makes
   `?palette=white&accent=electric` -- the exact composability example the
   founder's brief calls out -- actually show the electric-blue button/
   chart line/tab underline on top of white's monochrome shell, instead of
   losing to white's own --signal override.

   Contrast (computed via WCAG relative luminance; every option below
   clears every check, no dropped/undershipped option):
     - white text (#ffffff) on the --btn-solid-bg fill: >=4.5:1 required.
     - the accent hex used as plain text/link/label on a white ground
       (the `color: var(--signal)` call sites): >=4.5:1 required -- the
       SAME contrast ratio as the line above (contrast is symmetric between
       two colors regardless of which one is foreground), so any value
       clearing the text-on-white bar automatically clears the white-text-
       on-fill bar too. None of the seven needed the "--btn-solid-fg: dark
       instead" escape hatch as a result.
     - the accent vs. the `white` variant's grey sidebar (#f5f6f7): the
       real usage there is an 18%-alpha color-mix wash behind the active
       nav item (.v2-nav-item.active, ozai-v2.css), not flat text -- so
       this is a generous proxy (the RAW hex against the sidebar bg, a
       strictly harder bar than the actual translucent wash), also
       >=4.5:1 on all seven for headroom.
     - --chart-1 lands in a similar relative-luminance band (~0.10-0.16) to
       the untouched --chart-2..--chart-6 siblings (~0.10-0.13 in light
       theme) it renders alongside in the team-analytics chart, so none of
       the seven reads as an outlier series (too dark/ink-like or too
       washed-out) the way a naive un-tuned value could.
   Four of the seven starting points needed real darkening to clear these
   (all four originally read as too pale/light and undershot 4.5:1 against
   white by a wide margin): azure #0091FF -> #006DBF, sky #00A8E8 ->
   #0076A2, ember #FF5A1F -> #BF4417, lime #8BC400 -> #537600. `lime` in
   particular is a real casualty: no value bright/saturated enough to still
   read as "yellow-green" clears 4.5:1 against white -- #537600 is the
   darkest point where it still functions as green-yellow at all, and
   reads as an olive/moss tone, not the neon "shouting" lime originally
   briefed. Flagged rather than dropped, per "contrast is the deciding
   constraint, not taste" -- shown here specifically so the founder can see
   why a true neon lime doesn't work as a running UI accent (a bright lime
   would still be fine as a one-off decorative badge/highlight, just not
   this token). `electric` was also nudged 5% darker than its own starting
   point (#0066FF -> #0061F2), purely to clear the sidebar-wash proxy check
   with real headroom (the un-nudged value cleared white-text-on-fill at
   4.83:1 but landed at only 4.47:1 there, just under the bar). `cobalt`
   and `ultramarine` needed no adjustment at all -- both starting points
   already cleared every check (and `ultramarine`, despite leaning warm-
   blue as briefed, measures HSL hue 231 degrees -- closer to pure blue
   [240] than to violet/indigo territory [260+], so it does not read as
   the rejected indigo #4f46e5 [hue 243] or named-CSS indigo #4b0082
   [hue 275]). */

:root[data-accent="electric"][data-theme="light"],
:root[data-accent="electric"][data-theme="dark"] {
    --signal: #0061f2;
    --chart-1: #0061f2;
    --btn-solid-bg: #0061f2;
    --btn-solid-fg: #ffffff;
}

:root[data-accent="cobalt"][data-theme="light"],
:root[data-accent="cobalt"][data-theme="dark"] {
    --signal: #1d4ed8;
    --chart-1: #1d4ed8;
    --btn-solid-bg: #1d4ed8;
    --btn-solid-fg: #ffffff;
}

:root[data-accent="azure"][data-theme="light"],
:root[data-accent="azure"][data-theme="dark"] {
    --signal: #006dbf;
    --chart-1: #006dbf;
    --btn-solid-bg: #006dbf;
    --btn-solid-fg: #ffffff;
}

:root[data-accent="ultramarine"][data-theme="light"],
:root[data-accent="ultramarine"][data-theme="dark"] {
    --signal: #3d5afe;
    --chart-1: #3d5afe;
    --btn-solid-bg: #3d5afe;
    --btn-solid-fg: #ffffff;
}

:root[data-accent="sky"][data-theme="light"],
:root[data-accent="sky"][data-theme="dark"] {
    --signal: #0076a2;
    --chart-1: #0076a2;
    --btn-solid-bg: #0076a2;
    --btn-solid-fg: #ffffff;
}

:root[data-accent="ember"][data-theme="light"],
:root[data-accent="ember"][data-theme="dark"] {
    --signal: #bf4417;
    --chart-1: #bf4417;
    --btn-solid-bg: #bf4417;
    --btn-solid-fg: #ffffff;
}

:root[data-accent="lime"][data-theme="light"],
:root[data-accent="lime"][data-theme="dark"] {
    --signal: #537600;
    --chart-1: #537600;
    --btn-solid-bg: #537600;
    --btn-solid-fg: #ffffff;
}

/* Same problem the `white` variant's own fix (above) addresses -- --signal
   and --btn-solid-bg are identical in every accent option here too, so the
   app-wide `.v2-shell *:focus-visible { outline: 2px solid var(--signal); }`
   rule draws an outline flush against a same-color button, i.e. invisible.
   A single attribute-presence selector (matches any accent value) covers
   all seven at once rather than repeating this per key. */
:root[data-accent] .v2-send-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--shell), 0 0 0 4px var(--signal);
}

/* ---------------------------------------------------------------------- */
/* Switcher pill -- only ever mounted (by ozai-palette-lab.js, gated to
   /workspace) when a dimension is already active, so it never appears in
   the default app or on any public route.
   Anchored top-center, well below the workspace tour/modal overlay stack
   (~1100+) so it can never win over real UI -- and clear of every
   bottom-anchored surface it collided with at the original bottom-center
   position: the mobile .v2-bottom-nav (z 190) and its safe-area padding,
   the chat .v2-composer-wrap, and the FAB.
   Known minor gap: the mobile hamburger drawer (.v2-drawer, z 210) can
   still render under the pill when open, since 500 sits above it -- an
   open drawer is deliberate/brief and wasn't one of the review's flagged
   collisions, so left as-is rather than chasing every current z-index. */

.v2-palette-lab-pill {
    position: fixed;
    left: 50%;
    top: calc(8px + env(safe-area-inset-top, 0px));
    transform: translateX(-50%);
    z-index: 500;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 6px 8px;
    border-radius: 16px;
    background: var(--shell);
    border: 1px solid var(--line-strong);
    box-shadow: var(--shadow);
    max-width: calc(100vw - 24px);
}

/* One row per opt-in dimension (palette variant, sidebar darkness) --
   each scrolls independently on narrow viewports rather than the whole
   pill, so the two rows can wrap without fighting each other. */
.v2-palette-lab-row {
    display: flex;
    align-items: center;
    gap: 6px;
    overflow-x: auto;
}

.v2-palette-lab-label {
    padding: 0 4px 0 6px;
    font-size: 0.66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-faint);
    white-space: nowrap;
}

button.v2-palette-lab-btn {
    appearance: none;
    border: 1px solid var(--line);
    background: var(--shell-2);
    color: var(--text-soft);
    font-size: 0.74rem;
    font-weight: 600;
    line-height: 1;
    padding: 7px 12px;
    border-radius: 999px;
    cursor: pointer;
    white-space: nowrap;
}

button.v2-palette-lab-btn.is-active {
    background: var(--signal);
    border-color: var(--signal);
    color: #ffffff;
}

button.v2-palette-lab-btn.v2-palette-lab-reset {
    color: var(--text-faint);
}
