/* ============================================================================
   Design tokens — attempt-4

   Extracted from docs/designs/prototypes/claude-design-attempt-4/
   00-design-system.dc.html, which spec 012 names as the source of truth. It
   supersedes attempt-3, and the change is smaller than a new generation
   suggests: the same one hue rotated through lightness, the same single accent,
   the same amber-and-red-for-real-states rule. What moved is the type pairing,
   the radii, and every value by a few points.

   This file is the ONLY place a colour, font stack or radius is defined.
   Everything downstream references a custom property; a literal colour
   anywhere else is a defect, because the prototype's contrast ratios are a
   property of these exact values and nothing re-derives them.
   StyleTests.NoStylesheetOtherThanTokens_DeclaresAColour asserts it.

   oklch throughout rather than hex, for the reason attempt-3 gave: a palette
   that is one hue at many lightnesses stays evenly spaced in a perceptual
   space and does not in sRGB. The prototype is written in hex, so each token
   carries the hex it was converted from — that is the number to compare
   against the design file, and the oklch is what ships.

   Measured against the WORST background a token can land on, which is --bg-2
   and not --bg. Panels are raised, so most text in the app sits on --bg-1 or
   --bg-2 rather than the page itself:
     --ink    13.5:1     --ink-2   8.7:1
     --ink-3   6.0:1     --green   9.6:1
     --amber   9.0:1     --red     5.3:1

   TWO DELIBERATE DEVIATIONS, both to the ink ramp, both because the prototype
   is dimmer than this app can be.

   The prototype's dimmest text is #6C776E, 4.2:1 on the page background and a
   WCAG AA failure outright. The first pass lifted it to #727D74 and called it
   4.5:1 — but that measured it against --bg, and against --bg-2 the same
   colour is 4.0:1, so the fix did not hold anywhere a panel was involved. It
   also assumed --ink-3 was "de-emphasised data only": it carries 93 of the 171
   colour declarations in this app, most of the table cells and nearly all the
   11-13px text. The dimmest colour in the ramp is the one doing the most work,
   which is the reverse of what the prototype's ratios assume.

   So --ink-3 is 67.5% (#8F9A91, 6.0:1 worst case) and --ink-2 is 78%
   (#B0BBB2, 8.7:1), which also keeps the three steps roughly evenly spaced in
   lightness — 67.5 / 78 / 91.5 — where the prototype's 57.7 / 70.4 / 91.5 was
   not. Everything below the ink ramp is the prototype's value.

   ContrastTests re-derives every one of these numbers from this file and
   fails if a token stops clearing 4.5:1 on any background defined here, so
   the block above is checked rather than asserted.
   ========================================================================= */

:root {
  /* Ground. bg-1 is a panel on bg; bg-2 is raised on bg-1. */
  --bg: oklch(16% .006 156);      /* #0B0E0C */
  --bg-1: oklch(18.9% .011 151);  /* #101511 */
  --bg-2: oklch(21.8% .013 150);  /* #161C17 */

  /* An input well, darker than the panel it sits on rather than lighter. */
  --bg-well: oklch(18.1% .009 153); /* #0F1310 */

  /* Rules. --line separates; --line-2 outlines something interactive. */
  --line: oklch(27.5% .016 153);  /* #222A24 */
  --line-2: oklch(31.8% .017 152); /* #2C352E */

  /* Text, brightest first. */
  --ink: oklch(91.5% .011 150);   /* #DEE5DF */
  --ink-2: oklch(78% .018 151);   /* #B0BBB2, lifted from the prototype's #98A39A */
  --ink-3: oklch(67.5% .019 151); /* #8F9A91, lifted from the prototype's #6C776E */

  /* The single accent. --green-ink is the only text colour legible on it, and
     it is --bg exactly: the prototype fills a button with the accent and sets
     its text to the page background. */
  --green: oklch(79% .166 155);   /* #4CD98A */
  --green-ink: oklch(16% .006 156); /* #0B0E0C */
  --green-soft: oklch(79% .166 155 / .08);
  --green-edge: oklch(79% .166 155 / .35);

  /* Reserved for real states, never decoration: amber is degraded, red is
     failed. A page with no problem on it shows neither colour. */
  --amber: oklch(79.2% .121 84);  /* #E0B458 */
  --amber-soft: oklch(79.2% .121 84 / .1);
  --red: oklch(66.6% .159 26);    /* #E5675F */
  --red-soft: oklch(66.6% .159 26 / .08);
  --red-edge: oklch(66.6% .159 26 / .35);

  /* Three that are not part of the ramp. --bg-sunk is below the page, for a
     code block or a terminal; --green-dim fills the sparkline's bars, which are
     8px wide and would read as a stripe of pure accent at full strength;
     --shadow is the only black in the file, and it is a shadow rather than a
     colour anything is painted in. */
  --bg-sunk: oklch(12% .006 156);
  --green-dim: oklch(45% .1 155);
  --shadow: oklch(0% 0 0 / .45);

  /* Two faces. Sans carries prose; mono carries every piece of data — hosts,
     ports, counts, reply codes, timestamps. The split is semantic rather than
     decorative: mono marks a value a customer might copy. */
  --sans: 'Source Sans 3', system-ui, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, 'SF Mono', monospace;

  /* Two radii, both tighter than attempt-3's 6/12. --r for controls, --r-lg
     for panels. */
  --r: 4px;
  --r-lg: 6px;
}

/* ============================================================================
   The light theme, and how the switch works.

   THE BLOCK ABOVE IS ALSO THE FALLBACK. Every colour is declared twice: once
   above as a plain oklch(), and once below as light-dark(). A browser that
   does not understand light-dark() drops the second declaration as invalid
   and keeps the first, so it gets the dark theme rather than a page with no
   colours at all. light-dark() is Baseline since May 2024; the fallback is
   there because the failure mode without it is every colour token in the app
   going invalid at once, which is not a risk worth taking to save 21 lines.

   light-dark(LIGHT, DARK) — light first. Which one it returns is decided by
   the color-scheme property, and nothing else:

     :root                      color-scheme: light dark  -> follow the OS
     :root[data-theme="light"]  color-scheme: light       -> forced light
     :root[data-theme="dark"]   color-scheme: dark        -> forced dark

   So the OS preference is the default and the attribute is an override. The
   attribute is written by the server from a cookie (Render/ThemePreference.cs)
   rather than by script, because this app has to work with JavaScript off —
   and because a script that sets the theme after first paint is the flash of
   the wrong colours that every client-side theme switcher has.

   color-scheme also does the job base.css used to do with a hard-coded
   `color-scheme: dark`: it tells the browser which way to render a native
   <select>, a scrollbar and a date picker. That declaration is gone from
   base.css; this is the one place it lives now.

   THE LIGHT VALUES ARE NOT THE PROTOTYPE'S. attempt-4's src/styles.css does
   carry a light palette, and it belongs to a different token set — hue 270/90,
   Geist, 6/10px radii — so porting it would have given the light theme a
   different design from the dark one. These are derived from the shipped dark
   palette instead: the same accent hue, the same two faces, the same radii,
   with the elevation ramp inverted so raised still means closer to the viewer
   (--bg-2 is white, --bg is a tinted off-white) and the recessed pair still
   recessed (--bg-well and --bg-sunk stay darker than the panel they sit in).

   Measured against the worst background in the light theme, which is the
   DARKEST one — --bg-sunk — because the text is dark here:
     --ink    14.1:1     --ink-2   9.5:1
     --ink-3   5.8:1     --green   5.5:1
     --amber   5.4:1     --red     5.6:1
   and --green-ink on --green is 6.6:1, for the filled button.

   ContrastTests checks both themes, so these numbers are output.
   ========================================================================= */

:root {
  color-scheme: light dark;
}

:root[data-theme="light"] {
  color-scheme: light;
}

:root[data-theme="dark"] {
  color-scheme: dark;
}

:root {
  --bg: light-dark(oklch(96.8% .005 150), oklch(16% .006 156));       /* #F2F5F3 */
  --bg-1: light-dark(oklch(98.8% .003 150), oklch(18.9% .011 151));   /* #FAFCFA */
  --bg-2: light-dark(oklch(100% 0 150), oklch(21.8% .013 150));       /* #FFFFFF */
  --bg-well: light-dark(oklch(94.5% .006 150), oklch(18.1% .009 153)); /* #EAEEEB */

  --line: light-dark(oklch(91% .006 150), oklch(27.5% .016 153));     /* #DFE2DF */
  --line-2: light-dark(oklch(85% .008 150), oklch(31.8% .017 152));   /* #CACFCB */

  --ink: light-dark(oklch(22% .014 150), oklch(91.5% .011 150));      /* #161C17 */
  --ink-2: light-dark(oklch(34% .016 150), oklch(78% .018 151));      /* #323A34 */
  --ink-3: light-dark(oklch(46% .017 150), oklch(67.5% .019 151));    /* #525B53 */

  /* The accent is darkened rather than reused. oklch(79% …) is 1.7:1 on white
     and unreadable as text, and this token is a link colour as well as a
     button fill. --green-ink inverts with it: the fill's text is --bg in the
     dark theme and near-white here. */
  --green: light-dark(oklch(45% .14 155), oklch(79% .166 155));       /* #006A2F */
  --green-ink: light-dark(oklch(99% .002 150), oklch(16% .006 156));  /* #FBFCFB */
  --green-soft: light-dark(oklch(45% .14 155 / .1), oklch(79% .166 155 / .08));
  --green-edge: light-dark(oklch(45% .14 155 / .35), oklch(79% .166 155 / .35));

  --amber: light-dark(oklch(48% .115 75), oklch(79.2% .121 84));      /* #825200 */
  --amber-soft: light-dark(oklch(48% .115 75 / .12), oklch(79.2% .121 84 / .1));
  --red: light-dark(oklch(49% .18 26), oklch(66.6% .159 26));         /* #B01E22 */
  --red-soft: light-dark(oklch(49% .18 26 / .1), oklch(66.6% .159 26 / .08));
  --red-edge: light-dark(oklch(49% .18 26 / .35), oklch(66.6% .159 26 / .35));

  /* --bg-sunk stays recessed, so it is darker than the page in both themes.
     --green-dim is the sparkline bar, lightened here for the same reason it is
     dimmed there: 8px of the full accent reads as a stripe. --shadow is much
     weaker on a light ground, where .45 black would look like soot. */
  --bg-sunk: light-dark(oklch(93% .007 150), oklch(12% .006 156));    /* #E5E9E5 */
  --green-dim: light-dark(oklch(62% .135 155), oklch(45% .1 155));
  --shadow: light-dark(oklch(0% 0 0 / .1), oklch(0% 0 0 / .45));
}
