/* ==========================================================================
   itkab.com design tokens
   Direction: diagnostic readout. Graphite ground, hairline grid,
   status colours that carry meaning instead of decorating.

   Two themes. Dark is the screen of the instrument, light is the printout:
   warm paper, graphite ink, the same three status hues as pigment rather
   than light. Light is not an inversion, and it is not white.

   THE RULE: every colour lives here, with a value for both themes. Never a
   literal hex in a component file. See the note at the bottom of this file.
   ========================================================================== */

/* --- Typefaces. Self-hosted latin subsets, no third-party requests. ------ */

@font-face {
  font-family: "Bricolage Grotesque";
  src: url("../fonts/bricolage-grotesque-var-latin.woff2") format("woff2");
  font-weight: 200 800;
  font-stretch: 75% 100%;
  font-display: swap;
}

@font-face {
  font-family: "Newsreader";
  src: url("../fonts/newsreader-var-latin.woff2") format("woff2");
  font-weight: 200 800;
  font-display: swap;
}

@font-face {
  font-family: "Azeret Mono";
  src: url("../fonts/azeret-mono-var-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}

/* ==========================================================================
   Colour. The values in :root are the dark theme AND the fallback for any
   browser without light-dark(), which lands on dark rather than on nothing.
   The @supports block below layers the real two-theme values on top.
   ========================================================================== */

:root {
  color-scheme: dark;

  /* --- Surface ---------------------------------------------------------- */
  --graphite: #14171b;
  --graphite-deep: #101317;
  --panel: #1c2027;
  --panel-high: #242932;
  --hairline: #2b313b;
  --hairline-soft: #21262e;

  /* --- Ink -------------------------------------------------------------- */
  --bone: #e4e1da;
  --steel: #8b93a0;
  --steel-dim: #818997;

  /* --- Status. These encode state, they are not a palette. -------------- */
  --oxide: #dd6450;        /* failure */
  --oxide-deep: #b33a2b;
  --hazard: #e4b23c;       /* warning, pending, primary accent */
  --hazard-deep: #b8871f;
  --verdigris: #4c9d81;    /* resolved, fixed */
  --verdigris-deep: #2e6e5b;

  --oxide-wash: rgba(221, 100, 80, 0.12);
  --hazard-wash: rgba(228, 178, 60, 0.12);
  --verdigris-wash: rgba(76, 157, 129, 0.12);

  /* Text sitting ON a hazard fill. Dark theme wants dark text on the yellow;
     the light theme's darkened hazard needs light text. Without this token
     one of the two always fails contrast. */
  --on-hazard: #101317;
  --hazard-lift: #f0c25a;  /* hazard fill, hover */

  /* --- Chrome and atmosphere -------------------------------------------- */
  --masthead-bg: rgba(20, 23, 27, 0.72);
  --link-underline: rgba(228, 178, 60, 0.4);
  --zebra: rgba(255, 255, 255, 0.012);
  --bloom-1: rgba(228, 178, 60, 0.10);
  --bloom-2: rgba(76, 157, 129, 0.055);
  --grid-line: rgba(139, 147, 160, 0.09);
  --grain-blend: overlay;
  --grain-opacity: 0.2;

  /* The hero log field. Atmosphere, not content: it sits behind the headline
     and is masked away at every edge. --logfield-ink is the ordinary Info
     line, --logfield-dim the timestamp and component columns. */
  --logfield-ink: rgba(139, 147, 160, 0.50);
  --logfield-dim: rgba(139, 147, 160, 0.32);
  --logfield-sweep: rgba(228, 178, 60, 0.05);

  /* --- Depth. Tinted, never a flat drop shadow. ------------------------- */
  --lift-1: 0 1px 0 rgba(228, 225, 218, 0.03) inset,
            0 2px 8px rgba(8, 10, 13, 0.45);
  --lift-2: 0 1px 0 rgba(228, 225, 218, 0.04) inset,
            0 12px 32px -12px rgba(8, 10, 13, 0.85),
            0 2px 6px rgba(8, 10, 13, 0.4);
}

/* --- The two-theme values. -----------------------------------------------
   light-dark() resolves against the used value of color-scheme, so setting
   color-scheme on :root is what actually drives the switch. That means the
   OS preference works with no JavaScript at all, and data-theme only has to
   override color-scheme rather than restate every colour.

   Every value below is measured, not eyeballed. scratchpad/audit-contrast.mjs
   parses this file and checks all 22 real foreground/background pairings in
   both themes against WCAG AA. Every one passes. If you change a colour here,
   re-run it; the tight ones are the status colours sitting on their own wash,
   which clear 4.5 by less than a tenth.

   In light mode steel (5.07) and steel-dim (4.57) sit closer together than
   they do in dark, because AA forces both down. The muted / very-muted
   hierarchy is carried by size and weight there instead of by colour.
   -------------------------------------------------------------------- */

@supports (color: light-dark(#000, #fff)) {
  :root {
    color-scheme: light dark;

    --graphite: light-dark(#eeebe4, #14171b);
    --graphite-deep: light-dark(#e4e0d7, #101317);
    --panel: light-dark(#f7f5f0, #1c2027);
    --panel-high: light-dark(#fdfcfa, #242932);
    --hairline: light-dark(#d3cec3, #2b313b);
    --hairline-soft: light-dark(#e2ddd3, #21262e);

    --bone: light-dark(#191c21, #e4e1da);
    --steel: light-dark(#5c6371, #8b93a0);
    --steel-dim: light-dark(#636a78, #818997);

    --oxide: light-dark(#b33a2b, #dd6450);
    --oxide-deep: light-dark(#8f2c20, #b33a2b);
    --hazard: light-dark(#7f5c0e, #e4b23c);
    --hazard-deep: light-dark(#6b4e0c, #b8871f);
    --verdigris: light-dark(#2e6e5b, #4c9d81);
    --verdigris-deep: light-dark(#235445, #2e6e5b);

    --oxide-wash: light-dark(rgba(179, 58, 43, 0.06), rgba(221, 100, 80, 0.10));
    --hazard-wash: light-dark(rgba(127, 92, 14, 0.06), rgba(228, 178, 60, 0.12));
    --verdigris-wash: light-dark(rgba(46, 110, 91, 0.06), rgba(76, 157, 129, 0.12));

    --on-hazard: light-dark(#fdfcfa, #101317);
    --hazard-lift: light-dark(#6b4e0c, #f0c25a);

    --masthead-bg: light-dark(rgba(238, 235, 228, 0.78), rgba(20, 23, 27, 0.72));
    --link-underline: light-dark(rgba(127, 92, 14, 0.4), rgba(228, 178, 60, 0.4));
    --zebra: light-dark(rgba(60, 52, 40, 0.022), rgba(255, 255, 255, 0.012));

    /* Atmosphere is a design change, not a value swap. On paper the blooms
       drop to a faint wash and the grid hairlines darken instead of
       lightening, so the texture reads as tooth rather than glow. */
    --bloom-1: light-dark(rgba(197, 148, 42, 0.10), rgba(228, 178, 60, 0.10));
    --bloom-2: light-dark(rgba(46, 110, 91, 0.05), rgba(76, 157, 129, 0.055));
    --grid-line: light-dark(rgba(90, 80, 64, 0.07), rgba(139, 147, 160, 0.09));

    /* On paper the log field is a warm grey and has to be weaker still: dark
       text on a light ground reads far louder than light text on graphite at
       the same alpha. */
    --logfield-ink: light-dark(rgba(74, 66, 54, 0.38), rgba(139, 147, 160, 0.50));
    --logfield-dim: light-dark(rgba(74, 66, 54, 0.22), rgba(139, 147, 160, 0.32));
    --logfield-sweep: light-dark(rgba(127, 92, 14, 0.045), rgba(228, 178, 60, 0.05));

    /* Near-black shadows on paper read as dirt. Light uses soft warm grey. */
    --lift-1: 0 1px 0 light-dark(rgba(255, 255, 255, 0.7), rgba(228, 225, 218, 0.03)) inset,
              0 2px 8px light-dark(rgba(60, 52, 40, 0.10), rgba(8, 10, 13, 0.45));
    --lift-2: 0 1px 0 light-dark(rgba(255, 255, 255, 0.8), rgba(228, 225, 218, 0.04)) inset,
              0 12px 32px -12px light-dark(rgba(60, 52, 40, 0.22), rgba(8, 10, 13, 0.85)),
              0 2px 6px light-dark(rgba(60, 52, 40, 0.10), rgba(8, 10, 13, 0.4));
  }

  /* An explicit choice wins over the OS. This is the whole override. */
  :root[data-theme="light"] { color-scheme: light; }
  :root[data-theme="dark"] { color-scheme: dark; }
}

/* The grain layer is the only part that is not expressible as a colour,
   so it switches by selector. Overlay glows on graphite; on paper it has to
   be multiply, and much weaker, or the page looks dusty. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --grain-blend: multiply;
    --grain-opacity: 0.055;
  }
}
:root[data-theme="light"] {
  --grain-blend: multiply;
  --grain-opacity: 0.055;
}

:root {
  /* --- Type ------------------------------------------------------------- */
  --display: "Bricolage Grotesque", "Trebuchet MS", sans-serif;
  --body: "Newsreader", Georgia, "Times New Roman", serif;
  --mono: "Azeret Mono", "Cascadia Mono", Consolas, monospace;

  /* --- The type scale ---------------------------------------------------

     Every font-size on the site resolves to one of these. That rule is not a
     preference, it is enforced: type-check.mjs fails if a component stylesheet
     writes a literal size. Before it existed there were 45 hand-typed sizes,
     0.8125rem appeared thirteen separate times, .code-cell duplicated the exact
     value of --t-sm, and --t-xl was declared and referenced nowhere.

     Two rungs look like duplicates and are not:

       --t-dense is for tabular log output, where density is the point. Folding
       it up into --t-xs would cost lines on screen for nothing.

       --t-num is for display numerics only, and is the one place the light
       weight below is used. It is deliberately three times its own label.
     -------------------------------------------------------------------------- */

  --t-label: 0.6875rem;   /* mono uppercase labels */
  --t-dense: 0.75rem;     /* log rows, context blocks */
  --t-xs: 0.8125rem;      /* buttons, controls, meta links */
  --t-sm: 0.9375rem;      /* secondary prose */
  --t-body: 1.0625rem;
  --t-lead: 1.1875rem;    /* hero-sub, doc-sub */
  --t-h3: 1.3125rem;      /* card titles, prose h3 */
  --t-h2: clamp(1.5rem, 2.8vw, 2.125rem);
  --t-h1: clamp(1.75rem, 4.6vw, 3.25rem);
  --t-num: clamp(1.9rem, 4.4vw, 2.5rem);

  /* The hero minimum is 2.9rem, not 2.05rem, and that only works because the
     hardcoded <br> and the 18ch cap are lifted below 600px so the headline
     wraps naturally. Raising the minimum on its own overflows a 390px screen:
     "leaves your machine." is a 20 character run. See global.css. */
  --t-hero: clamp(2.9rem, 8.5vw, 5.5rem);

  /* The site declares three variable fonts spanning 100-900 and, before this,
     never used a weight below 400: 100 and 200 appeared only inside @font-face.
     This is the light end, and it is a token so it can be dialled in one place.
     It is 300 rather than 200 because .stat b is coloured text on a dark panel,
     where thin strokes thin out optically in a way WCAG does not measure. */
  --w-display: 300;

  /* --- Spacing. One scale, used everywhere. ----------------------------- */
  --s1: 0.25rem;
  --s2: 0.5rem;
  --s3: 0.75rem;
  --s4: 1rem;
  --s5: 1.5rem;
  --s6: 2rem;
  --s7: 3rem;
  --s8: 4.5rem;
  --s9: 7rem;

  --measure: 68ch;
  --shell: 76rem;

  --radius: 3px;
  --radius-lg: 5px;

  --ease: cubic-bezier(0.16, 0.84, 0.44, 1);
}
