/* KIX "Ink" palette. Light and dark are both first-class and invert cleanly.
   The accent is constant across themes.

   MEASURED contrast, WCAG 2.2 relative-luminance formula (audited 12 Sep 2026).
   Full board: guidelines/color-contrast.html
     ink #0A0A0A on paper #FAFAF8 ............. 18.94:1  AAA
     paper on ink #0A0A0A ..................... 18.94:1  AAA
     ink-60 #5A5A58 on paper ..................  6.62:1  AA
     muted #A3A3A0 on ink .....................  7.83:1  AA
     ink-40 #8C8C88 on paper ..................  3.23:1  FAIL for text - disabled only
     accent #FF4D00 on paper ..................  3.18:1  AA LARGE only (>=24px display)
     accent on ink ............................  5.95:1  AA any size (still never body copy)
     INK ON ACCENT (button label) .............  5.95:1  AA   <- the required pairing
     white #FFFFFF on accent ..................  3.33:1  FAIL - forbidden for labels
     paper #FAFAF8 on accent ..................  3.18:1  FAIL - forbidden for labels
     ink on accent-press #E04300 ..............  4.69:1  AA
     error #C21A00 on paper ...................  5.84:1  AA
     error-dark #FF6A45 on ink ................  6.98:1  AA
   Accent-filled controls therefore ship an INK label, never white. --kx-on-accent enforces it.
*/
/* Light values are on :root AND on an explicit [data-kx-theme="light"] scope, so a nested
   subtree can be re-scoped in EITHER direction. Without the attribute selector here,
   data-kx-theme="light" on a descendant is a no-op and an inverted band inside the dark
   theme keeps resolving dark tokens — invisible against its own page.
   Specificity is equal across all three scope blocks, so source order decides: the dark
   block below wins on <html data-kx-theme="dark">, while a nested light scope wins locally. */
:root, [data-kx-theme="light"] {
  /* base ramp */
  --kx-ink: #0A0A0A;
  --kx-ink-90: #171716;
  --kx-ink-80: #262625;
  --kx-ink-60: #5A5A58;
  --kx-ink-40: #8C8C88;
  --kx-ink-20: #C9C8C2;
  --kx-ink-10: #E2E1DC;
  --kx-ink-05: #EFEEE9;
  --kx-paper: #FAFAF8;
  --kx-white: #FFFFFF;

  /* ===================================================================
     THE ONE ACCENT — and the two pairings that are FORBIDDEN with it.
     Measured, WCAG 2.2 relative luminance. Do not reintroduce either:
       white #FFFFFF on #FF4D00 .... 3.33:1  FAIL (needs 4.5:1)
       paper #FAFAF8 on #FF4D00 .... 3.18:1  FAIL (needs 4.5:1)
     The only legal label on an accent fill is ink:
       ink   #0A0A0A on #FF4D00 .... 5.95:1  AA at any size
       ink   #0A0A0A on #E04300 .... 4.69:1  AA at any size (hover)
     --kx-on-accent resolves to ink in BOTH themes so the rule holds on a
     theme swap. Never hard-code a label colour on an accent ground; never
     redefine --kx-on-accent to a light value.
     =================================================================== */
  --kx-accent: #FF4D00;
  --kx-accent-press: #E04300;
  --kx-accent-wash: rgba(255, 77, 0, 0.12);

  /* semantic states - monochrome by default, accent carries urgency */
  --kx-error: #C21A00;
  --kx-error-dark: #FF6A45;
  --kx-success: #0A0A0A;
  --kx-warning: #FF4D00;

  /* ---- LIGHT THEME (default): paper ground / ink type ---- */
  --kx-bg: var(--kx-paper);
  --kx-bg-raised: var(--kx-white);
  --kx-bg-sunken: var(--kx-ink-05);
  --kx-bg-invert: var(--kx-ink);
  --kx-text: var(--kx-ink);
  --kx-text-muted: var(--kx-ink-60);
  --kx-text-faint: var(--kx-ink-40);
  --kx-text-invert: var(--kx-paper);
  --kx-text-invert-muted: #A3A3A0; /* muted type ON an inverted (ink) ground — 7.83:1 */
  --kx-text-accent: var(--kx-accent);
  --kx-on-accent: var(--kx-ink);
  --kx-rule: var(--kx-ink);
  --kx-rule-soft: var(--kx-ink-10);
  --kx-rule-mid: var(--kx-ink-20);
  --kx-field-bg: var(--kx-white);
  --kx-field-disabled-bg: var(--kx-ink-05);
  --kx-danger: var(--kx-error);
  --kx-focus: var(--kx-accent);
  --kx-overlay: rgba(10, 10, 10, 0.72);
  --kx-selection-bg: var(--kx-accent);
  --kx-selection-fg: var(--kx-ink);

  /* Composites — see the note in tokens/lines.css. Redeclared in every scope below that
     changes --kx-rule* or --kx-text, because var() inside a custom property is substituted
     where it is DECLARED and then inherits as a literal string. */
  --kx-border: var(--kx-hairline) solid var(--kx-rule);
  --kx-border-soft: var(--kx-hairline) solid var(--kx-rule-soft);
  --kx-border-mid: var(--kx-hairline) solid var(--kx-rule-mid);
  --kx-offset-block: 6px 6px 0 0 var(--kx-text);
}

[data-kx-theme="dark"] {
  --kx-bg: var(--kx-ink);
  --kx-bg-raised: var(--kx-ink-90);
  --kx-bg-sunken: #050505;
  --kx-bg-invert: var(--kx-paper);
  --kx-text: var(--kx-paper);
  --kx-text-muted: #A3A3A0;
  --kx-text-faint: var(--kx-ink-40);
  --kx-text-invert: var(--kx-ink);
  --kx-text-invert-muted: var(--kx-ink-60); /* muted type ON an inverted (paper) ground — 6.62:1 */
  --kx-text-accent: var(--kx-accent);
  --kx-on-accent: var(--kx-ink);
  --kx-rule: var(--kx-paper);
  --kx-rule-soft: var(--kx-ink-80);
  --kx-rule-mid: #3A3A38;
  --kx-field-bg: var(--kx-ink);
  --kx-field-disabled-bg: var(--kx-ink-90);
  --kx-danger: var(--kx-error-dark);
  --kx-focus: var(--kx-accent);
  --kx-overlay: rgba(10, 10, 10, 0.86);
  --kx-selection-bg: var(--kx-accent);
  --kx-selection-fg: var(--kx-ink);

  /* Composites are redeclared in EVERY scope that changes --kx-rule* or --kx-text. See the
     note in tokens/lines.css: a custom property containing var() is substituted where it is
     DECLARED, then inherits as a literal, so a single :root copy freezes the light values. */
  --kx-border: var(--kx-hairline) solid var(--kx-rule);
  --kx-border-soft: var(--kx-hairline) solid var(--kx-rule-soft);
  --kx-border-mid: var(--kx-hairline) solid var(--kx-rule-mid);
  --kx-offset-block: 6px 6px 0 0 var(--kx-text);
}

/* ---- INVERTED GROUND SCOPE ----
   Any subtree painted on --kx-bg-invert re-points its type and rule tokens to the invert
   steps, exactly as a nested [data-kx-theme] scope does. This is a THEME scope, not a
   component style: `color` alone only reaches text that does not name a colour of its own,
   so muted metadata, faint text and hairlines inside an inverted box keep resolving the
   outer ground's values and vanish against it. Measured before this scope existed, on a
   hovered interactive card: title and affordance at 1.00:1 in BOTH themes (ink on ink,
   paper on paper — literally invisible) and tags at 2.86:1 light / 2.42:1 dark.

   It lives here rather than inside a component rule so the values are registered tokens and
   the scope is reusable by anything with an inverted ground — cards, bands, toasts. Apply it
   as an attribute; never redeclare these six properties in a component selector.

   The accent is deliberately NOT re-pointed. On the ink ground it measures 5.95:1, but
   --kx-bg-invert is PAPER in the dark theme, where the accent is 3.18:1 — the pairing this
   file's own header names as forbidden. Inverted grounds use the muted invert step for
   emphasis instead, at 7.83:1 light / 6.62:1 dark. */
/* The hover selector is part of THIS scope, not a component rule, so the invert is pure CSS
   and works for hand-written markup against the shipped styles.css — guidelines/*.html and
   templates/marketing-page are static, and a JS-only re-scope would desync the ground from
   its tokens there and reinstate the exact contrast failure described above. */
[data-kx-ground="invert"],
[data-interactive="true"]:hover {
  --kx-text: var(--kx-text-invert);
  --kx-text-muted: var(--kx-text-invert-muted);
  --kx-text-faint: var(--kx-text-invert-muted);
  --kx-rule: var(--kx-text-invert);
  --kx-rule-mid: var(--kx-text-invert-muted);
  --kx-rule-soft: var(--kx-text-invert-muted);
  --kx-border: var(--kx-hairline) solid var(--kx-text-invert);
  --kx-border-soft: var(--kx-hairline) solid var(--kx-text-invert-muted);
  --kx-border-mid: var(--kx-hairline) solid var(--kx-text-invert-muted);
}
