/* ══════════════════════════════════════════════════════════════
   SPARK — the shared skin
   ══════════════════════════════════════════════════════════════

   Loaded by every app in the repo, after surface.css and after that
   app's own stylesheet. It does not restyle components: it REMAPS the
   kit's tokens, so anything built out of `.rlx-*` follows without
   knowing this file exists.

   Two modes, both Spark: `data-skin="spark"` (dark) and
   `data-skin="spark-light"`. `skin.js` at the repo root resolves which,
   blocking in the <head>, before any stylesheet resolves a token.

   This file was `event/console/spark.css`. It was split when the rest of
   the product moved onto Spark: the token layer — everything here — is
   shared, and the console's own §D patches (the stage's atmosphere, the
   sidebar's rows, the agent cards) stay behind in that file, which now
   loads after this one. The section numbers are the Spark spec's and are
   kept as they were so the two halves still read as one document.

   The kit stays light-only on `data-theme`; Spark's dark/light is a
   separate axis on `data-skin`, which is why the two never fight.
   ══════════════════════════════════════════════════════════════ */

/* ==============================================================
   Spark skin for the console — dark and light.

   Re-skins the console into Spark UI without rewriting a single
   component rule. It works because the kit and the console are
   almost entirely token-driven:

     surface.css          2314 var(--rlx-*)  vs   3 hardcoded colours
     console/desktop.css   735 var(--rlx-*)  vs  ~8 hardcoded colours
     console/app.css       702 var(--rlx-*)  vs   6 hardcoded colours

   So this file remaps the tokens and patches the handful of places
   that assume one ground or the other.

   ── Two modes, one design system ──

     data-skin="spark"         dark   — "light emerging from darkness"
     data-skin="spark-light"   light  — the same system on a bright ground

   Spark Light is NOT the old MildUI light theme. It keeps Spark's
   pink/violet signature, its layout, its components and its rules
   about where colour is allowed; only the ground inverts. The top band
   stays dark in both, which is what the console always did and what
   keeps the two modes recognisably the same product.

   ── The hue ──

   Pink signature, violet AI family, purple-black grounds — the system
   `event/spark/` was built against. It spent one release as an
   azure/indigo product on blue-black grounds; that is now reverted, so
   the shipped product and its reference screen are one system again.

   The STRUCTURE never moved through either pass — every role, every
   step, every measured target below is the one it always was, and only
   the hue changes. Figures are re-measured rather than transposed,
   because a hue that looks equivalent rarely measures equivalent: the
   dark accent lands at 7.43:1 where azure gave 8.03, and light needed a
   step between pink-600 and 700 to hold AA on its own wash.

   One token flips direction with the hue. `--rlx-important` takes WHITE
   here (4.50:1) where the other five semantics take ink — violet is
   dark enough to carry it, and ink manages only 4.39 on it. Under
   indigo it was the reverse. It is the one figure worth re-checking
   first if the hue is ever moved again.

   What did NOT move: cyan (data/audience), orange (agenda), green
   (success) and the red-pink `--spark-live` (critical). Those are
   status hues, not brand. Worth knowing: against a PINK signature the
   red-pink critical sits much closer to the brand than it did against
   azure, so `--spark-live` leans on being redder and on its own
   iconography rather than on hue distance alone. The reference screen
   accepts the same trade.

   The file is in three parts:

     §A  structure   — geometry and behaviour, both modes
     §B  dark tokens
     §C  light tokens
     §D  patches     — shared where the rule is token-driven, split
                       where the two grounds genuinely disagree

   ── Why `data-skin` and not `data-theme` ──

   surface.js hard-sets `data-theme="light"` on <html> at load
   (`_apply(_readPref())`, and `_resolve()` returns 'light'
   unconditionally). Anything a page writes into that attribute is
   overwritten. `data-skin` is an attribute the kit never touches, so
   the opt-in survives — and the rest of the repo stays light-only.
   ./skin.js resolves it before first paint; see there for the toggle.

   Specificity: `:root[data-skin=...]` is (0,2,0), which beats the kit's
   light tokens on plain `:root` (0,1,0) and desktop.css's own `:root`
   overrides. Where a token is set on an ELEMENT (`.pcd-attn[data-cap]`
   sets --rlx-text-muted on itself), proximity beats specificity, so
   those are restated at the same place in §D.

   Load order: surface.css → app.css → desktop.css → THIS FILE.
   ============================================================== */


/* ══════════════════════════════════════════════════════════════
   §A · SHARED — the hues, the geometry, the behaviour
   `[data-skin^="spark"]` matches both modes.
   ══════════════════════════════════════════════════════════════ */

:root[data-skin^="spark"] {

  /* The hues are the same in both modes; which STEP each role picks is
     what changes. Spark Light does not get a different pink, it gets a
     darker one — the ground moved, not the palette.

     Under Graphite (/colors.css) there is no brand hue at all: the
     primary is graphite and inverts per theme, and the only colour in
     the interface belongs to the three AGENTS and the status set. So
     these families are not decoration any more — each one IS an agent:

       pink   → Answer    --rlc-answer-*
       cyan   → Engage    --rlc-engage-*
       violet → Protect   --rlc-protect-*

     The token NAMES are kept so nothing downstream had to move, but since
     the ReactLive brand sheet they no longer describe the hue: "pink" is
     Answer blue, "cyan" is Engage orange, "violet" is Protect purple. The
     values all come out of /colors.css. Anything that wants a
     colour should reach for the agent it means, not the hue it wants.

     The remaining three are status roles and resolve to the reserved
     status set rather than to a hue family. */
  --spark-pink-300:    var(--rlc-answer-300);
  --spark-pink-400:    var(--rlc-answer-400);
  --spark-pink-500:    var(--rlc-answer-500);
  --spark-pink-600:    var(--rlc-answer-600);
  /* 650 was a derived step: light needed a signature that clears AA as
     text on its own 10% wash, and 600 managed only 4.91 there. Answer's
     own light main is already that deep step, so 650 and 700 collapse
     onto it rather than inventing two hexes the foundations file does
     not define. Both were unreferenced outside this file. */
  --spark-pink-650:    var(--rlc-answer-600);
  --spark-pink-700:    var(--rlc-answer-600);
  --spark-violet-300:  var(--rlc-protect-300);
  --spark-violet-400:  var(--rlc-protect-400);
  --spark-violet-500:  var(--rlc-protect-500);
  --spark-violet-600:  var(--rlc-protect-600);
  --spark-cyan-300:    var(--rlc-engage-300);
  --spark-cyan-400:    var(--rlc-engage-400);
  --spark-cyan-500:    var(--rlc-engage-500);
  /* "orange" here is the WARNING status (amber), not Engage's brand
     orange — the 300/400 pair is the soft-foreground/main split the kit
     expects, which the status set already provides per theme. */
  --spark-orange-300:  var(--rlc-status-warning);
  --spark-orange-400:  var(--rlc-status-warning);
  --spark-live:        var(--rlc-status-danger);
  --spark-success:     var(--rlc-status-success);

  /* Radius, for the ported sidebar (§D2). */
  --spark-r-md:        12px;

  /* The console's top band is dark in BOTH modes. It was dark in the
     light product too — a dark band over a light stage is the shell's
     own idea, not something Spark imposed — so keeping it is what makes
     the two modes read as one product rather than two. */
  --pcd-topbar-bg:          var(--rlc-zinc-900);
  --pcd-topbar-bg-grad-top: var(--rlc-zinc-well);
  --pcd-topbar-bg-rgb:      var(--rlc-zinc-900-rgb);
  /* desktop.css's band accent, still named for the lime it once held.
     The band is chrome, so by the "graphite does the work" rule it has
     no business carrying an agent — except that everything reading this
     token is a mark or a meta icon, which is exactly what the palette
     lets colour. Engage, because it is also the link colour, so the one
     bright thing on the band is the same bright thing as everywhere
     else. On graphite-900 the 400 step measures 12.4:1. */
  --pcd-lime:               var(--rlc-engage-400);
}


/* ── The tone map (ported from `event/spark/`, its §1.4) ──────────
   Every coloured surface in Spark — icon tiles, queue markers, list
   marks — reads --tone-* from the nearest [data-tone] ancestor instead
   of restating a gradient per component. Adding a tone is one block
   here, not six rules downstream.

   --tone-a/-b are the gradient pair for a FILLED tile, --tone-ink the
   legible step for a glyph or label sitting on a dark ground, and
   --tone-glow the bloom a filled tile is allowed to cast. The dark
   values are the reference's own; light re-points -ink at the deep
   steps, because a 300 step that reads on near-black disappears on
   near-white.

   The gradient pair is now the ramp's own 500 → 600 rather than five
   hand-mixed hexes, which is what stops a tile drifting off the agent
   it is supposed to name. `pink`/`violet`/`cyan` are the three agents;
   `orange` and `indigo` are the warning and info STATUS colours, kept
   under their old attribute values so no markup had to change. */
:root[data-skin^="spark"] [data-tone="pink"] {
  --tone-a: var(--rlc-answer-500); --tone-b: var(--rlc-answer-600);
  --tone-glow: rgb(var(--rlc-answer-400-rgb) / .26);
  --tone-ink: var(--rlc-answer-300);
}
:root[data-skin^="spark"] [data-tone="violet"] {
  --tone-a: var(--rlc-protect-500); --tone-b: var(--rlc-protect-600);
  --tone-glow: rgb(var(--rlc-protect-400-rgb) / .26);
  --tone-ink: var(--rlc-protect-300);
}
:root[data-skin^="spark"] [data-tone="cyan"] {
  --tone-a: var(--rlc-engage-500); --tone-b: var(--rlc-engage-600);
  --tone-glow: rgb(var(--rlc-engage-400-rgb) / .22);
  --tone-ink: var(--rlc-engage-300);
}
:root[data-skin^="spark"] [data-tone="orange"] {
  --tone-a: var(--rlc-warning-dark); --tone-b: var(--rlc-warning-light);
  --tone-glow: rgb(var(--rlc-warning-dark-rgb) / .22);
  --tone-ink: var(--rlc-warning-dark);
}
:root[data-skin^="spark"] [data-tone="indigo"] {
  --tone-a: var(--rlc-info-dark); --tone-b: var(--rlc-info-light);
  --tone-glow: rgb(var(--rlc-info-dark-rgb) / .24);
  --tone-ink: var(--rlc-info-dark);
}
/* Light: the fills keep their gradients — a filled tile is the same
   object in both modes — but every -ink drops to a step that measures
   on a near-white ground. */
:root[data-skin="spark-light"] [data-tone="pink"]   { --tone-ink: var(--rlc-answer-600); }
:root[data-skin="spark-light"] [data-tone="violet"] { --tone-ink: var(--rlc-protect-600); }
:root[data-skin="spark-light"] [data-tone="cyan"]   { --tone-ink: var(--rlc-engage-600); }
:root[data-skin="spark-light"] [data-tone="orange"] { --tone-ink: var(--rlc-warning-light); }
:root[data-skin="spark-light"] [data-tone="indigo"] { --tone-ink: var(--rlc-info-light); }


/* ══════════════════════════════════════════════════════════════
   §B · DARK
   ══════════════════════════════════════════════════════════════ */

:root[data-skin="spark"] {

  color-scheme: dark;

  /* Never one #000 everywhere (§B of the spec). These tiers sit 4–10 RGB
     points apart, which is the only reason depth reads at all here.

     They carried a violet bias before and are neutral graphite now —
     the single change that turns the whole product graphite, since
     every ground in the kit resolves through these six. `bg-soft` and
     `sidebar` have no distinct step in the foundations file: soft takes
     the panel tier and the sidebar sits straight on the canvas, which
     is what the console's own §D2 already did by hand. */
  --spark-bg:          var(--rlc-bg-canvas);
  --spark-bg-soft:     var(--rlc-bg-panel);
  --spark-sidebar:     var(--rlc-bg-sidebar);
  --spark-s1:          var(--rlc-bg-panel);    /* panel   */
  --spark-s2:          var(--rlc-bg-control);  /* control */
  --spark-s3:          var(--rlc-bg-raised);   /* raised  */
  --spark-hover:       var(--rlc-bg-hover);

  /* The dark ink that goes ON a saturated fill. Graphite ink rather
     than the kit's neutral --rlx-eclipse, so a filled chip and its
     surroundings belong to one palette. */
  --spark-ink:         var(--rlc-ink-on-color);

  /* ── Reference palette ──
     surface.css's "MildUI Environment": nine tokens everything else
     reads through, with the instruction that nothing outside them
     should hardcode a brand hex. Remapping them is the single
     highest-leverage change in this file. */
  --rlx-ref-ground:   var(--spark-bg);
  --rlx-ref-ground-2: var(--spark-bg-soft);
  /* Charcoal filled two roles in light — body ink AND every filled
     button. Spark splits them, so ref-ink takes the TEXT role and
     --rlx-accent is set explicitly below. */
  --rlx-ref-ink:      var(--rlc-text);
  --rlx-ref-sub:      var(--rlc-text-sub);
  --rlx-ref-fill:     var(--spark-s2);
  --rlx-ref-line:     var(--rlc-border-panel);

  /* The three pastel accents become the three AGENTS — tint-1 carries
     Assist (Protect) and tint-3 carries Auto (Answer), never green for
     Auto, which implies safety rather than agency (§25). They sit a
     third of the wheel apart, so the pairing does not lean on the level
     TAG to stay separable and §57's two-channel rule has both channels
     doing real work.

     ref-info is the exception: "info" is a STATUS role, not an agent,
     and the status set is reserved — so it takes the reserved blue
     rather than borrowing Protect's lime. */
  --rlx-ref-info:     var(--rlc-status-info);
  --rlx-ref-violet:   var(--rlc-agent-protect);
  --rlx-ref-sage:     var(--rlc-agent-engage);
  --rlx-ref-lime:     var(--rlc-agent-answer);

  /* The reserved status set (§51). Under Graphite this is the ONLY
     place these hues are allowed to appear: nothing decorative may use
     them and no agent colour may stand in for one. `important` is not
     in the status set and is not a status — it is the Protect agent,
     which is what the console already colours its report queue with.
     `attention` is warning at the same step; graphite defines one
     warning per theme, not two. */
  --rlx-ref-danger:       var(--rlc-status-danger);
  --rlx-ref-warning:      var(--rlc-status-warning);
  --rlx-ref-important:    var(--rlc-agent-protect);
  --rlx-ref-notification: var(--rlc-status-info);
  --rlx-ref-success:      var(--rlc-status-success);
  --rlx-ref-attention:    var(--rlc-status-warning);

  --rlx-cool-50:  var(--spark-bg-soft);
  --rlx-cool-100: var(--spark-s2);
  --rlx-cool-200: var(--spark-s3);
  --rlx-cool-300: var(--spark-hover);

  --rlx-background:           var(--spark-bg);
  --rlx-background-secondary: var(--spark-bg-soft);
  --rlx-background-tertiary:  var(--spark-s1);
  --rlx-background-inverse:   var(--rlc-zinc-25);

  --rlx-surface:              var(--spark-s1);
  --rlx-surface-secondary:    var(--spark-s2);
  --rlx-surface-tertiary:     var(--spark-s3);

  /* Borders must never read as white (§3). The first two are the
     foundations file's own panel border and divider, opaque so a card
     edge does not shift when the card moves onto a different tier. The
     third has no counterpart there — it is the "louder than a divider"
     tier — so it stays an alpha of the surface ink. */
  --rlx-separator:            var(--rlc-border-panel);
  --rlx-separator-secondary:  var(--rlc-divider);
  --rlx-separator-tertiary:   rgb(var(--rlc-zinc-25-rgb) / .22);

  /* Never pure white in quantity (§5). */
  --rlx-foreground:           var(--rlc-text);
  --rlx-foreground-muted:     var(--rlc-text-sub);
  --rlx-foreground-segment:   var(--spark-s3);
  --rlx-foreground-overlay:   var(--spark-s1);
  --rlx-foreground-link:      var(--rlc-link);

  --rlx-field-bg:             var(--spark-s2);
  --rlx-field-bg-hover:       var(--spark-s3);
  --rlx-field-bg-focus:       var(--spark-s2);
  --rlx-field-foreground:     var(--rlc-text);
  --rlx-field-placeholder:    var(--rlc-text-muted);

  --rlx-default:              var(--spark-s2);
  --rlx-default-hover:        var(--spark-s3);
  --rlx-default-foreground:   var(--rlc-text);

  /* ── Accent ──
     The token that decides whether this re-skin is readable. MildUI's
     accent is INK, which serves as a fill and as text on a light ground
     at once. No saturated hue does both, and the kit leans on the dual
     role:

         color: var(--rlx-accent)        97 uses
         background: var(--rlx-accent)   36 uses
         rgb(var(--rlx-accent-rgb) / .x) 76 uses — washes whose LABEL
                                         is var(--rlx-accent) too

     #006FEE is a saturated hue and therefore cannot do both. It is
     assigned to the FILL role, which is what the design uses it for
     everywhere: the primary button, the active nav row's rule, the
     poll bar, the switch track, the badge, the segmented thumb. As
     type on the canvas it runs 3.36:1 — fine for a 16px icon stroke
     or a 1px rule (both are non-text, 3:1), under AA for a label.

     The label case is what `-soft-foreground` is for, and the kit
     already reserves that token as "the only one of the six that may
     be text". It takes blue-300, which is the step the design itself
     puts on a blue wash — the ON THE WALL NOW eyebrow is #66AAF9 on
     rgb(0 111 238 / .16), and that pairing is reproduced here exactly.

         #006FEE as a fill, white ink on it      4.8:1
         #006FEE as text on the canvas           3.36:1  — fills only
         #66AAF9 as text on the canvas           8.6:1
         #66AAF9 as text on its own 16% wash     7.9:1

     One consequence to know about: a bare `color: var(--rlx-accent)`
     on the canvas inherits the 3.36:1 case. The design does this once
     itself (the nav count), so it is reproduced rather than corrected;
     anywhere a new accent LABEL is added, reach for
     `--rlx-accent-soft-foreground` instead. */
  --rlx-accent:                 var(--rlc-primary);
  --rlx-accent-hover:           var(--rlc-primary-hover);
  --rlx-accent-foreground:      var(--rlc-primary-ink);
  --rlx-accent-soft:            rgb(var(--rlc-primary-rgb) / .16);
  --rlx-accent-soft-hover:      rgb(var(--rlc-primary-rgb) / .26);
  --rlx-accent-soft-foreground: var(--rlc-primary-text);

  /* ── The semantic six ──
     The kit's own dark block documents the inversion and it holds: on a
     dark ground the saturated hue IS the legible text, so it serves as
     -soft-foreground; -soft becomes a deep well of the same hue rather
     than a pale wash; the base stays a fill with ink on it.

     Ink rather than white on all six: every one of these fills is a
     bright mid-tone where white runs 1.8–3.7:1 and ink runs 5.7–11.6. */
  --rlx-danger:                 var(--rlc-status-danger);
  --rlx-danger-hover:           var(--rlc-status-danger-hover);
  --rlx-danger-foreground:      var(--rlc-ink-on-color);
  --rlx-danger-soft:            var(--rlc-status-danger-bg);
  --rlx-danger-soft-hover:      rgb(var(--rlc-status-danger-rgb) / .22);
  --rlx-danger-soft-foreground: var(--rlc-status-danger);

  --rlx-warning:                 var(--rlc-status-warning);
  --rlx-warning-hover:           var(--rlc-status-warning-hover);
  --rlx-warning-foreground:      var(--rlc-ink-on-color);
  --rlx-warning-soft:            var(--rlc-status-warning-bg);
  --rlx-warning-soft-hover:      rgb(var(--rlc-status-warning-rgb) / .22);
  --rlx-warning-soft-foreground: var(--rlc-status-warning);

  --rlx-success:                 var(--rlc-status-success);
  --rlx-success-hover:           var(--rlc-status-success-hover);
  --rlx-success-foreground:      var(--rlc-ink-on-color);
  --rlx-success-soft:            var(--rlc-status-success-bg);
  --rlx-success-soft-hover:      rgb(var(--rlc-status-success-rgb) / .22);
  --rlx-success-soft-foreground: var(--rlc-status-success);

  --rlx-notification:                 var(--rlc-status-info);
  --rlx-notification-hover:           var(--rlc-status-info-hover);
  --rlx-notification-foreground:      var(--rlc-ink-on-color);
  --rlx-notification-soft:            var(--rlc-status-info-bg);
  --rlx-notification-soft-hover:      rgb(var(--rlc-status-info-rgb) / .22);
  --rlx-notification-soft-foreground: var(--rlc-status-info);

  /* Not a status — the Protect agent, which is already what the
     console's report queue reads through this token. It takes ink like
     the other five and not white: Protect's dark step is a bright lime
     where white runs 1.32:1 and graphite ink 13.6. (It was violet, the
     one token that took white, so this is the figure worth re-checking
     first if the mapping is ever moved again.) */
  --rlx-important:                 var(--rlc-agent-protect);
  --rlx-important-hover:           var(--rlc-agent-protect-hover);
  --rlx-important-foreground:      var(--rlc-ink-on-color);
  --rlx-important-soft:            var(--rlc-agent-protect-bg);
  --rlx-important-soft-hover:      rgb(var(--rlc-agent-protect-rgb) / .26);
  --rlx-important-soft-foreground: var(--rlc-protect-300);

  /* Attention is warning at the same step: graphite reserves ONE
     warning per theme, not two, and these two roles separate by
     iconography rather than by hue. */
  --rlx-attention:                 var(--rlc-status-warning);
  --rlx-attention-hover:           var(--rlc-status-warning-hover);
  --rlx-attention-foreground:      var(--rlc-ink-on-color);
  --rlx-attention-soft:            var(--rlc-status-warning-bg);
  --rlx-attention-soft-hover:      rgb(var(--rlc-status-warning-rgb) / .22);
  --rlx-attention-soft-foreground: var(--rlc-status-warning);

  /* The -rgb pairs are literal triplets the kit uses for alpha washes,
     so each has to move by hand or the washes keep the old hues. */
  --rlx-accent-rgb:       var(--rlc-primary-rgb);
  --rlx-primary-rgb:      var(--rlc-primary-rgb);
  --rlx-secondary-rgb:    var(--rlc-zinc-300-rgb);
  /* LIGHT, not the surface colour. Used as `color: rgb(var(...))` on a
     .15 wash of ITSELF — the kit's neutral badge. Set it to the neutral
     surface and the badge paints near-black on near-black (measured
     1.03:1). In a dark theme this triplet has to be the neutral INK.
     NOTE: the kit's own dark block has the same latent bug (20 25 38). */
  --rlx-default-rgb:      var(--rlc-zinc-300-rgb);
  --rlx-success-rgb:      var(--rlc-status-success-rgb);
  --rlx-warning-rgb:      var(--rlc-status-warning-rgb);
  --rlx-danger-rgb:       var(--rlc-status-danger-rgb);
  --rlx-notification-rgb: var(--rlc-status-info-rgb);
  --rlx-important-rgb:    var(--rlc-agent-protect-rgb);
  --rlx-attention-rgb:    var(--rlc-status-warning-rgb);

  --rlx-tint-1-rgb:       var(--rlc-agent-protect-rgb);   /* Protect — Assist */
  --rlx-tint-2-rgb:       var(--rlc-agent-engage-rgb);    /* Engage           */
  --rlx-tint-3-rgb:       var(--rlc-agent-answer-rgb);    /* Answer  — Auto   */
  /* Spark keeps its own agentic colour behind AI-grouped cards: the base kit
     points --rlx-ai-wash-rgb at a neutral lavender so it never renders olive,
     and Spark maps it back onto the Auto tint so the card carries the same
     pink the autonomy control does. */
  --rlx-ai-wash-rgb:       var(--rlx-tint-3-rgb);

  --rlx-text:        var(--rlc-text);
  --rlx-text-muted:  var(--rlc-text-sub);
  --rlx-text-sub:    var(--rlc-text-muted);   /* 4.90:1 on the control tier */
  --rlx-text-strong: var(--rlc-text-strong);

  /* §42: Spark separates with light and edge more than physical shadow,
     so these stay shallow and lean on the inset hairline. */
  --rlx-shadow-sm: 0 2px 10px 0 rgb(0 0 0 / .28), inset 0 0 1px 0 rgb(255 255 255 / .10);
  --rlx-shadow-md: 0 12px 30px 0 rgb(0 0 0 / .32), inset 0 0 1px 0 rgb(255 255 255 / .10);
  --rlx-shadow-lg: 0 24px 56px 0 rgb(0 0 0 / .42), inset 0 0 1px 0 rgb(255 255 255 / .10);

  /* The design's four ink tones, in full. `faint` is the new one — the
     section eyebrow and the tab count — and the reason the rail reads
     quiet. Switch tokens ride along here because the design's OFF track
     is a real ground step with a grey thumb on it, not a dimmed white. */
  --rlx-text-faint:         var(--rlc-text-faint);
  --rlx-switch-off:         var(--rlc-zinc-700);
  --rlx-switch-thumb:       var(--rlc-zinc-400);

  --rlx-scroll-thumb:       rgb(var(--rlc-zinc-25-rgb) / .14);
  --rlx-scroll-thumb-hover: rgb(var(--rlc-zinc-25-rgb) / .28);

  --rlx-input-bg:           var(--spark-s2);
  --rlx-input-bg-hover:     var(--spark-s3);
  --rlx-input-border:       var(--rlc-border-panel);
  --rlx-input-border-hover: rgb(var(--rlc-zinc-25-rgb) / .22);
  --rlx-input-border-focus: var(--rlc-primary);

  --rlx-overlay: #000000;

  --pcd-sidebar-bg:   var(--spark-sidebar);
  --pcd-sidebar-edge: linear-gradient(180deg,
                        rgb(var(--rlc-zinc-25-rgb) / .10),
                        rgb(var(--rlc-zinc-25-rgb) / .04));

  /* Local, mode-dependent values the patches in §D read. Declaring them
     here rather than branching every rule is what keeps §D mostly
     shared between the two modes. */
  --sk-nav-hover:      rgb(var(--rlc-zinc-0-rgb) / .035);
  --sk-nav-label:      var(--rlc-text-sub);
  --sk-nav-label-on:   var(--rlc-text-strong);
  /* A graphite wash now, not a magenta one. The sidebar is chrome and
     chrome is graphite; the selected row is already carried by its icon
     tile, which keeps its group's agent colour. */
  --sk-nav-wash:       linear-gradient(90deg,
                         rgb(var(--rlc-primary-rgb) / .10),
                         rgb(var(--rlc-primary-rgb) / 0));
  --sk-tile-bg:        var(--rlc-bg-raised);
  --sk-tile-border:    rgb(var(--rlc-zinc-0-rgb) / .05);
  --sk-tile-glyph:     var(--rlc-text-sub);
  --sk-pill-soft-a:    .18;
  --sk-attn-muted:     var(--rlc-zinc-300);
  --sk-sidebar-muted:  var(--rlc-text-sub);
  --sk-accent:         var(--rlc-primary);
  --sk-accent-rgb:     var(--rlc-primary-rgb);
  /* Lifted from event/spark/ `.sp-panel`; the alphas are its, the
     colours the canvas and the raised tier. */
  --sk-panel-bg:       rgb(var(--rlc-bg-canvas-rgb) / .68);
  --sk-panel-bg-hover: rgb(var(--rlc-zinc-rule-rgb) / .82);
  --sk-panel-shadow:   0 12px 30px rgb(0 0 0 / .16);
}


/* ══════════════════════════════════════════════════════════════
   §C · LIGHT
   Same system, inverted ground. Every value here was chosen against
   a measured contrast target, not by lightening the dark one.
   ══════════════════════════════════════════════════════════════ */

:root[data-skin="spark-light"] {

  color-scheme: light;

  /* The same "never one flat colour" rule as dark, read upward — but
     the tiers no longer run monotonically from canvas to raised, and
     that is the foundations file's own arrangement rather than an
     oversight: the canvas is WHITE, a panel is the faint grey that
     separates from it, and a raised thing goes back to white and
     separates by shadow instead. There is nothing above white to step
     to, so raised has to come back down the ramp. */
  --spark-bg:          var(--rlc-bg-canvas);    /* canvas  */
  --spark-bg-soft:     var(--rlc-bg-panel);
  --spark-sidebar:     var(--rlc-bg-sidebar);
  --spark-s1:          var(--rlc-bg-panel);     /* panel   */
  --spark-s2:          var(--rlc-bg-control);   /* control */
  --spark-s3:          var(--rlc-bg-raised);    /* raised  */
  --spark-hover:       var(--rlc-bg-hover);

  /* The dark ink, for PASTEL fills — deliberately not
     --rlc-ink-on-color, which is the ink for a saturated fill and is
     white in this theme. A pastel badge needs the opposite. */
  --spark-ink:         var(--rlc-zinc-900);

  --rlx-ref-ground:   var(--spark-bg);
  --rlx-ref-ground-2: var(--spark-bg-soft);
  --rlx-ref-ink:      var(--rlc-text);
  --rlx-ref-sub:      var(--rlc-text-sub);        /* 5.94:1 on white */
  --rlx-ref-fill:     var(--spark-s2);
  --rlx-ref-line:     var(--rlc-border-panel);

  /* The three agents as PASTELS here — on a light ground the fill is
     the pale step and the legible one moves to -soft-foreground, which
     is the mirror of what dark does. Each takes its agent's BORDER
     value, the colour at ~40%: the ~10% panel fill is too faint to read
     as a badge, and the deep step is the text role. Graphite ink clears
     9:1 or better on all of them. */
  --rlx-ref-info:     var(--rlc-status-info-border);
  --rlx-ref-violet:   var(--rlc-agent-protect-border);
  --rlx-ref-sage:     var(--rlc-agent-engage-border);
  --rlx-ref-lime:     var(--rlc-agent-answer-border);

  --rlx-ref-danger:       var(--rlc-status-danger-border);
  --rlx-ref-warning:      var(--rlc-status-warning-border);
  --rlx-ref-important:    var(--rlc-agent-protect-border);
  --rlx-ref-notification: var(--rlc-status-info-border);
  --rlx-ref-success:      var(--rlc-status-success-border);
  --rlx-ref-attention:    var(--rlc-status-warning-border);

  --rlx-cool-50:  var(--spark-bg-soft);
  --rlx-cool-100: var(--spark-s2);
  --rlx-cool-200: var(--spark-s3);
  --rlx-cool-300: var(--spark-hover);

  --rlx-background:           var(--spark-bg);
  --rlx-background-secondary: var(--spark-bg-soft);
  --rlx-background-tertiary:  var(--spark-s2);
  --rlx-background-inverse:   var(--rlc-primary);

  --rlx-surface:              var(--spark-s1);
  --rlx-surface-secondary:    var(--spark-s2);
  --rlx-surface-tertiary:     var(--spark-s3);

  /* Mirror of the dark rule: borders must never read as black. */
  --rlx-separator:            var(--rlc-border-panel);
  --rlx-separator-secondary:  var(--rlc-divider);
  --rlx-separator-tertiary:   rgb(var(--rlc-zinc-900-rgb) / .24);

  --rlx-foreground:           var(--rlc-text);
  --rlx-foreground-muted:     var(--rlc-text-sub);
  --rlx-foreground-segment:   var(--rlc-bg-raised);
  --rlx-foreground-overlay:   var(--rlc-bg-raised);
  --rlx-foreground-link:      var(--rlc-link);

  --rlx-field-bg:             var(--rlc-bg-raised);
  --rlx-field-bg-hover:       var(--spark-s2);
  --rlx-field-bg-focus:       var(--rlc-bg-raised);
  --rlx-field-foreground:     var(--rlc-text);
  --rlx-field-placeholder:    var(--rlc-text-muted);

  --rlx-default:              var(--spark-s2);
  --rlx-default-hover:        var(--spark-s3);
  --rlx-default-foreground:   var(--rlc-text);

  /* ── Accent ──
     Same split as dark, mirrored. The accent stays #006FEE — it is the
     one thing in this palette that does NOT invert, which is what makes
     a light screenshot recognisable as the same product as a dark one.
     Only the step that carries type moves: blue-600 here where dark
     took blue-300, because on paper the hue has to get darker to clear
     4.5:1 rather than lighter.

         #006FEE as a fill, white ink on it     4.8:1
         #006FEE as text on white               4.4:1  — fills only
         #005BC4 as text on white               6.9:1
         #005BC4 as text on its own 10% wash    6.3:1 */
  --rlx-accent:                 var(--rlc-primary);
  --rlx-accent-hover:           var(--rlc-primary-hover);
  --rlx-accent-foreground:      var(--rlc-primary-ink);
  --rlx-accent-soft:            rgb(var(--rlc-primary-rgb) / .10);
  --rlx-accent-soft-hover:      rgb(var(--rlc-primary-rgb) / .16);
  --rlx-accent-soft-foreground: var(--rlc-primary-text);

  /* ── The semantic six ──
     Pastel fill + ink on it, and a darkened hue for the text role. Each
     -soft-foreground is the darkest step of its own hue that clears
     4.5:1 on white AND on its own wash. */
  --rlx-danger:                 var(--rlx-ref-danger);
  --rlx-danger-hover:           var(--rlc-status-danger-border);
  --rlx-danger-foreground:      var(--spark-ink);
  --rlx-danger-soft:            var(--rlc-status-danger-bg);
  --rlx-danger-soft-hover:      rgb(var(--rlc-status-danger-rgb) / .20);
  --rlx-danger-soft-foreground: var(--rlc-status-danger);

  --rlx-warning:                 var(--rlx-ref-warning);
  --rlx-warning-hover:           var(--rlc-status-warning-border);
  --rlx-warning-foreground:      var(--spark-ink);
  --rlx-warning-soft:            var(--rlc-status-warning-bg);
  --rlx-warning-soft-hover:      rgb(var(--rlc-status-warning-rgb) / .22);
  --rlx-warning-soft-foreground: var(--rlc-status-warning);

  --rlx-success:                 var(--rlx-ref-success);
  --rlx-success-hover:           var(--rlc-status-success-border);
  --rlx-success-foreground:      var(--spark-ink);
  --rlx-success-soft:            var(--rlc-status-success-bg);
  --rlx-success-soft-hover:      rgb(var(--rlc-status-success-rgb) / .26);
  --rlx-success-soft-foreground: var(--rlc-status-success);

  --rlx-notification:                 var(--rlx-ref-notification);
  --rlx-notification-hover:           var(--rlc-status-info-border);
  --rlx-notification-foreground:      var(--spark-ink);
  --rlx-notification-soft:            var(--rlc-status-info-bg);
  --rlx-notification-soft-hover:      rgb(var(--rlc-status-info-rgb) / .22);
  --rlx-notification-soft-foreground: var(--rlc-status-info);

  --rlx-important:                 var(--rlx-ref-important);
  --rlx-important-hover:           var(--rlc-agent-protect-border);
  --rlx-important-foreground:      var(--spark-ink);
  --rlx-important-soft:            var(--rlc-agent-protect-bg);
  --rlx-important-soft-hover:      rgb(var(--rlc-agent-protect-rgb) / .20);
  --rlx-important-soft-foreground: var(--rlc-agent-protect);

  --rlx-attention:                 var(--rlx-ref-attention);
  --rlx-attention-hover:           var(--rlc-status-warning-border);
  --rlx-attention-foreground:      var(--spark-ink);
  --rlx-attention-soft:            var(--rlc-status-warning-bg);
  --rlx-attention-soft-hover:      rgb(var(--rlc-status-warning-rgb) / .28);
  --rlx-attention-soft-foreground: var(--rlc-status-warning);

  --rlx-accent-rgb:       var(--rlc-primary-rgb);
  --rlx-primary-rgb:      var(--rlc-primary-rgb);
  --rlx-secondary-rgb:    var(--rlc-zinc-400-rgb);
  /* DARK here, for the same reason it is light in the other mode: it is
     used as `color: rgb(var(...))` on a .15 wash of itself. */
  --rlx-default-rgb:      var(--rlc-zinc-400-rgb);    /* 5.94:1 as a badge */
  --rlx-success-rgb:      var(--rlc-status-success-rgb);
  --rlx-warning-rgb:      var(--rlc-status-warning-rgb);
  --rlx-danger-rgb:       var(--rlc-status-danger-rgb);
  --rlx-notification-rgb: var(--rlc-status-info-rgb);
  --rlx-important-rgb:    var(--rlc-agent-protect-rgb);
  --rlx-attention-rgb:    var(--rlc-status-warning-rgb);

  /* The tints now come out of the agent set, which also settles the
     note that used to sit here: tint-3 was azure in this mode and pink
     in the other, so an Auto affordance changed family with the skin.
     Both modes read the same agent token now, so they cannot drift. */
  --rlx-tint-1-rgb:       var(--rlc-agent-protect-rgb);   /* Protect — Assist */
  --rlx-tint-2-rgb:       var(--rlc-agent-engage-rgb);    /* Engage           */
  --rlx-tint-3-rgb:       var(--rlc-agent-answer-rgb);    /* Answer  — Auto   */
  --rlx-ai-wash-rgb:       var(--rlx-tint-3-rgb);

  --rlx-text:        var(--rlc-text);
  --rlx-text-muted:  var(--rlc-text-sub);
  --rlx-text-sub:    var(--rlc-text-muted);              /* 5.94:1 on white */
  --rlx-text-strong: var(--rlc-text-strong);

  /* Light shadows carry graphite ink rather than neutral black, so a
     card's edge belongs to the same family as everything else. The
     foundations file's own raised-panel shadow is the -sm step. */
  --rlx-shadow-sm: 0 1px 3px 0 rgb(var(--rlc-zinc-900-rgb) / .14);
  --rlx-shadow-md: 0 8px 24px 0 rgb(var(--rlc-zinc-900-rgb) / .08),
                   0 2px  6px 0 rgb(var(--rlc-zinc-900-rgb) / .05);
  --rlx-shadow-lg: 0 24px 56px 0 rgb(var(--rlc-zinc-900-rgb) / .13);

  --rlx-text-faint:         var(--rlc-text-faint);
  --rlx-switch-off:         var(--rlc-zinc-300);
  --rlx-switch-thumb:       var(--rlc-zinc-0);

  --rlx-scroll-thumb:       rgb(var(--rlc-zinc-900-rgb) / .18);
  --rlx-scroll-thumb-hover: rgb(var(--rlc-zinc-900-rgb) / .32);

  --rlx-input-bg:           var(--rlc-bg-raised);
  --rlx-input-bg-hover:     var(--spark-s2);
  --rlx-input-border:       var(--rlc-border-panel);
  --rlx-input-border-hover: rgb(var(--rlc-zinc-900-rgb) / .28);
  --rlx-input-border-focus: var(--rlc-primary);

  --rlx-overlay: var(--rlc-zinc-900);

  --pcd-sidebar-bg:   transparent;
  --pcd-sidebar-edge: linear-gradient(180deg,
                        rgb(var(--rlc-zinc-900-rgb) / .10),
                        rgb(var(--rlc-zinc-900-rgb) / .04));

  --sk-nav-hover:      rgb(var(--rlc-zinc-900-rgb) / .05);
  --sk-nav-label:      var(--rlc-text-sub);
  --sk-nav-label-on:   var(--rlc-text-strong);
  --sk-nav-wash:       linear-gradient(90deg,
                         rgb(var(--rlc-primary-rgb) / .08),
                         rgb(var(--rlc-primary-rgb) / 0));
  --sk-tile-bg:        var(--rlc-bg-control);
  --sk-tile-border:    rgb(var(--rlc-zinc-900-rgb) / .08);
  --sk-tile-glyph:     var(--rlc-text-sub);
  --sk-pill-soft-a:    .14;
  --sk-attn-muted:     var(--rlc-zinc-400);
  --sk-sidebar-muted:  var(--rlc-text-sub);
  --sk-accent:         var(--rlc-primary);
  --sk-accent-rgb:     var(--rlc-primary-rgb);
  /* The same construction as the dark panel, read upward: a translucent
     surface over the atmosphere, a low-alpha border in graphite rather
     than grey-blue, and a shadow that carries the same ink. */
  --sk-panel-bg:       rgb(var(--rlc-zinc-0-rgb) / .72);
  --sk-panel-bg-hover: rgb(var(--rlc-zinc-0-rgb) / .92);
  --sk-panel-shadow:   0 8px 24px rgb(var(--rlc-zinc-900-rgb) / .06);
}

/* ══════════════════════════════════════════════════════════════
   §D · PATCHES — the shared ones

   Everything above is inherited custom properties, which the whole tree
   picks up for free. What follows is the short list that cannot be
   reached that way and is NOT specific to one app. The console's own
   patches are in event/console/spark.css.
   ══════════════════════════════════════════════════════════════ */

/* ── §D3 · Focus ring (§47) ───────────────────────────────────────
   Graphite, at the alpha the foundations file specifies: white at 60%
   on dark, ink at 40% on light. Translucent rather than solid on
   purpose — at full strength the ring reads as a fill on a near-white
   primary, and a focused control has to look focused, not pressed.

   No light override any more: --rlc-primary-ring already resolves per
   theme, so the one rule is correct in both. */
:root[data-skin^="spark"] :focus-visible {
  outline: 2px solid var(--rlc-primary-ring);
  outline-offset: 2px;
}
/* …except the bare field inside a kit box that shows focus itself. The
   textarea, the input and the composer all turn their rounded box's border
   accent on :focus-within; the ring above also landed on the <textarea> or
   <input> inside, as a square outline inset in the rounded box — two focus
   marks, misaligned, on one field (v10.09 §5). The box's border is the
   focus mark. */
:root[data-skin^="spark"] :is(.rlx-textarea-input, .rlx-input-field, .rlx-composer-input):focus-visible { outline: none; }

/* ── §D8 · The wash-and-label antipattern (the shared case) ──────
   The kit's soft pills at 35% of the accent leave the label at 3.86:1.
   Every app uses pills, so this one is here rather than in the console's
   half. Found by computing contrast against the true composited
   background, not by eye. */
/* Soft pills at 35% of the accent leave the label at 3.86:1. */
:root[data-skin^="spark"] .rlx-pill--variant-soft {
  background: rgb(var(--rlx-pill-c-rgb) / var(--sk-pill-soft-a));
}

/* Join card — the guest field would otherwise share the control step with the
   provider buttons stacked directly above it (`--spark-s2`), leaving a 13%
   hairline as the only sign it is a field at all. Dark only: drop it to the
   canvas so it reads as a recessed well against those buttons. Light needs no
   fill change — there the field is already the brighter of the two (#FFFFFF
   against #EFF3F9 controls); moving it to the canvas would land it on #F4F6FA,
   a hair off the buttons, and recreate the same problem inverted. */
:root[data-skin="spark"] .rlx-joingate-form { --rlx-input-bg: var(--spark-bg); }
