/* Metabyl Labs — the two palettes.

   Everything the engine paints reads one of these variables, because
   labs/theme.js sets every token to var(--x). A theme is therefore one
   attribute on <html>, not a rebuild.

   Both palettes are contrast-audited and both are deliberately COMPRESSED. The
   complaint that started this was "the black background made it harder to
   focus", and the measurement showed the range was wrong at BOTH ends: primary
   text at 15.81:1 (glare) over secondary text at 5.96:1 (below AAA) and link
   underlines at 3.38:1 (below AA). Widening the gap is what tires a reader, so
   neither palette reaches for maximum contrast. */

:root {
  /* LIGHT — the default. Ground is a cool off-white on the brand slate's hue. */
  --ink: #F7F9FA;        /* the ground */
  --panel: #FFFFFF;
  --panel2: #E9EEF1;
  --well: #F1F5F7;       /* the recessed band in the module rail — see note below */
  --line: #D3DCE0;
  --bone: #26353F;       /* 11.95:1 — primary text */
  --muted: #44545D;      /*  7.44:1 — AAA, carries most prose */
  --dim: #5D6C74;        /*  4.65:1 on panel2, the strictest surface */

  --brand: #2E7475;      /*  4.64:1 on panel2, the strictest surface */
  --slate: #4F5C63;

  --ldl: #CA2531;        /* 5.21:1 */
  --hdl: #1C7767;        /* 4.63:1 on panel2 */
  --tg:  #925F16;        /* 4.64:1 on panel2 */
  --lpa: #7A3BCB;        /* 6.00:1 */
  --ok:  #1D784F;        /* 4.66:1 on panel2 */
  --bad: #CA2531;

  --on-accent: #FFFFFF;  /*  5.06:1 on the light teal; black would be 3.77:1 */
  --bar-bg: rgba(255, 255, 255, .92);

  --lift: rgba(0, 0, 0, .045);    /* a row lifted off its surface; white-on-white before */

  --hdl-soft: rgba(29, 124, 107, .40);
  --tg-soft:  rgba(150, 98, 23, .33);
  --lpa-soft: rgba(122, 59, 203, .33);

  color-scheme: light;
}

[data-theme="dark"] {
  /* DARK — the ramp from s107, on the brand slate's hue (201°). */
  --ink: #151B1E;
  --panel: #1D2428;
  --panel2: #242C30;
  --well: #0F1721;       /* unchanged: the literal the rail used to hardcode */
  --line: #3A454B;
  --bone: #D7DEE2;       /* 12.78:1 */
  --muted: #9CACB4;      /*  7.43:1 — AAA */
  --dim: #82969F;        /*  4.61:1 on panel2, the strictest surface */

  --brand: #60C0C1;      /*  8.12:1 — the mark's teal, unmodified */
  --slate: #4F5C63;

  --ldl: #E56F77;        /* 4.65:1 on panel2 */
  --hdl: #2DBFA5;        /* 7.54:1 */
  --tg:  #E2A03F;        /* 7.73:1 */
  --lpa: #A980DD;        /* 4.61:1 on panel2 */
  --ok:  #3FCF8E;        /* 8.72:1 */
  --bad: #E0555F;

  --on-accent: #08101A;  /*  8.28:1 on the dark teal */
  --bar-bg: rgba(29, 36, 40, .92);

  --lift: rgba(255, 255, 255, .03);   /* unchanged: the literal the table hardcoded */

  --hdl-soft: rgba(45, 191, 165, .40);
  --tg-soft:  rgba(226, 160, 63, .33);
  --lpa-soft: rgba(155, 107, 216, .33);

  color-scheme: dark;
}

/* A mechanism diagram is a FIGURE PLATE, not chrome. Its node colours are
   literal hexes tuned against a dark canvas across twenty-odd maps, and the
   renderer parses them as hex to derive translucent fills — so the diagram
   surface declares itself dark and its variables resolve to the dark palette
   whatever the app is set to. */
[data-figure="dark"] {
  --ink: #151B1E; --panel: #1D2428; --panel2: #242C30; --well: #0F1721; --line: #3A454B;
  --lift: rgba(255, 255, 255, .03);
  --bone: #D7DEE2; --muted: #9CACB4; --dim: #82969F;
  --brand: #60C0C1;
  --ldl: #E56F77; --hdl: #2DBFA5; --tg: #E2A03F; --lpa: #A980DD;
  --ok: #3FCF8E; --bad: #E56F77;
  --hdl-soft: rgba(45, 191, 165, .40);
  --tg-soft:  rgba(226, 160, 63, .33);
  --lpa-soft: rgba(155, 107, 216, .33);
  --on-accent: #08101A;
  --bar-bg: rgba(29, 36, 40, .92);

  color-scheme: dark;
}

/* A MODULE'S IDENTITY COLOUR, RESOLVED WHERE --dom IS ACTUALLY IN SCOPE.

   This used to be one line — `--dom-text: var(--dom-lt, var(--bone))` on :root
   — and it silently painted --bone for every module in both themes. A custom
   property containing var() is substituted on the element that DECLARES it, so
   the substitution happened at :root with --dom-lt unset, and the resolved bone
   is what inherited down. An element setting --dom on itself arrived after the
   only substitution that was ever going to occur.

   Matching on the marker property the engine's domText()/domFill() spread write
   into the style attribute puts the declaration on the element itself, where
   --dom and --dom-lt resolve. The selectors are deliberately low specificity
   (0,1,0) and the helpers no longer write colour or background inline, so a
   call site that wants a themed token instead simply sets one and wins.

   --dom-lt / --domf-lt are the walked-down values for the light ground;
   --dom / --domf are the originals, which is what the dark theme wants. */
[style*="--dom-lt"]  { color: var(--dom-lt, var(--bone)); }
[style*="--domf-lt"] { background: var(--domf-lt, var(--panel2)); }

[data-theme="dark"] [style*="--dom-lt"]  { color: var(--dom, var(--bone)); }
[data-theme="dark"] [style*="--domf-lt"] { background: var(--domf, var(--panel2)); }

[data-figure="dark"] [style*="--dom-lt"]  { color: var(--dom, var(--bone)); }
[data-figure="dark"] [style*="--domf-lt"] { background: var(--domf, var(--panel2)); }

/* --well IS A FOURTH SURFACE, AND IT IS DELIBERATELY NOT A STRICTER ONE.

   The rail's module bands sit in a recess: below the panel in dark, below it in
   light too, with the SELECTED band on panel2 either way. That recess was a
   literal — `background: "#0F1721"` in the engine — and a literal does not move
   when the theme does, so in the light palette it stayed near-black under text
   tokens that had gone dark. Measured in the drawer where a reader met it:
   bone 1.43:1, muted 2.29:1, dim 3.32:1, and every module's identity colour
   between 3.03:1 and 3.61:1. The menu was legible in one theme and not the
   other, which is the whole defect in one sentence.

   The value it takes in light is the constrained part. Adding a surface means
   re-auditing every text token against it, and the way to make that audit
   cheap is to keep the new surface INSIDE the range already cleared: #F1F5F7
   sits between --ink and --panel2, so every token reads BETTER on it than on
   panel2 — dim 4.96:1 against 4.65:1, and the worst module colour 4.55:1
   against 4.27:1. panel2 therefore remains the strictest surface in both
   themes and the table below still holds, which it would not if the recess had
   been taken any darker. In dark the value is the old literal exactly, so
   nothing that shipped there changes by a pixel. */

/* AND WHY panel2 IS THE SURFACE THEY ARE ALL TUNED AGAINST.

   Tuning --dim against the panel fixed thirty-five elements and left two, which
   is how this became a table rather than a chase: every text token measured
   against every surface it can land on. There are three — ink, panel, panel2 —
   and panel2 is the strictest in BOTH themes. Seven tokens cleared AA on the
   ground and failed on panel2, three of them in the dark theme, which means
   they shipped that way in s107.

   A palette is not audited until every colour has been checked on every
   surface it can appear on. Checking one surface is how six rounds of this cut
   each found the same class of defect somewhere new. */

/* WHY --dim IS TUNED AGAINST THE PANEL AND NOT THE GROUND.

   It was set to clear AA against --ink and did: 4.56:1. But almost every label
   it paints — YOUR PROGRESS, DECK, GATES PASSED, UNREAD — sits on a PANEL, and
   a panel is lighter than the ground in dark mode and darker than it in light.
   Measured where the text actually is, --dim was 4.13:1 in dark and 4.26:1 in
   light: below AA on thirty-five elements of the Lab home alone, and it had
   been below AA there before this cut too, by more.

   The ground is not the surface. Tuning a text colour against the page
   background and then painting it on a card is how a palette passes its own
   audit and fails the reader. */

html, body { background: var(--ink); }
