/* Nocturne — design-system tokens and component classes. This file is the source of truth for the system's look; retune it here and see readme.md. */
/* @import of Inter from fonts.googleapis.com removed for offline use —
   see the font stack below. The app must render with no network. */

/* Archivo, the wordmark's face (design/brand.md's Wordmark section, approved
   mockup design/marks/Wordmark.dc.html) — SELF-HOSTED rather than dropped, unlike
   Inter above: Inter is the whole UI, cheap to fall back to system-ui everywhere;
   the wordmark is one small brand element where the specific letterforms are the
   point, and self-hosting keeps it working offline without adding a live
   fonts.googleapis.com dependency this app already removed once on purpose.
   web/archivo-600.woff2 is the Google Fonts "latin" subset only (weight 600, the
   one weight the wordmark uses) — 13.5KB, not the multi-weight/multi-script family. */
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/archivo-600.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --color-bg: #0d1723;
  --color-surface: #1c2633;
  --color-text: #f0f4f9;
  --color-accent: #eca84a; /* DEV-31: the accent moves off the blurple to a
     warm amber — OKLCH hue 71.7, L 0.779 (the ramp's 400 slot), C 0.135.
     This is a SEMANTIC hue, not a decorative one: the app's light-and-dark
     strip has to say "bright light" versus "dark / shades", and Nocturne's
     mono rule made both bands the same purple-grey. Measured before the
     change, on the rendered strip: 1.03:1 between the two states — with the
     "dark" band fractionally the LIGHTER of the two. Warm-for-light against
     cool-for-dark is the only split that survives greyscale.
     Nocturne's own don't-list forbids a second hue; that rule is amended in
     nocturne-design-system-guide.md rather than quietly broken here. */
  --color-accent-2: #dbae76; /* the machine-derived stand-in follows the
     accent as it always did: same hue, chroma at the same 2:3 proportion. Still
     one role — nothing in the app distinguishes accent from accent-2. */
  --color-divider: color-mix(in srgb, #f0f4f9 16%, transparent);

  /* Tonal ramps — generated in OKLCH on one shared lightness scale, so the
     same step of any role matches the others in visual value. */
  --color-neutral-100: #f2f6fb;
  --color-neutral-200: #e0e9f2;
  --color-neutral-300: #c9d6e4;
  --color-neutral-400: #aab9ca;
  --color-neutral-500: #899aad;
  --color-neutral-600: #6b7c8f;
  --color-neutral-700: #505f71;
  --color-neutral-800: #374452;
  --color-neutral-900: #222c37;

  --color-accent-100: #fef4e7;
  --color-accent-200: #fbe4c8;
  --color-accent-300: #f7cb96;
  --color-accent-400: #eca84a;
  --color-accent-500: #c9892b;
  --color-accent-600: #a36d1a;
  --color-accent-700: #7e5412;
  --color-accent-800: #5b3b0a;
  --color-accent-900: #392710;

  --color-accent-2-100: #fbf4ec;
  --color-accent-2-200: #f5e5d3;
  --color-accent-2-300: #eccfac;
  --color-accent-2-400: #dbae76;
  --color-accent-2-500: #ba905a;
  --color-accent-2-600: #967345;
  --color-accent-2-700: #745834;
  --color-accent-2-800: #533e23;
  --color-accent-2-900: #35291a;

  /* Deck section-divider ground — review round 3: saturation as presence.
     Dividers take a saturated deep indigo (hue 277, the neutral ramp's own
     family; C 0.094 — written when the accent held C 0.030, before the
     round-7 blurple raised it past the ground's) with a lighter bloom and
     a ghost tint of the same hue, while the slide grounds stay
     desaturated. Deck-scale fills only — not interface colors. */
  --color-section: #262a60;
  --color-section-glow: #353b80;
  --color-section-ghost: #4c5397;

  --font-heading: "Inter", system-ui, sans-serif;
  --font-heading-weight: 500;
  --font-body: "Inter", system-ui, sans-serif;
  /* Deliberately its own token, not folded into --font-heading: brand.md is
     explicit that "the wordmark sits outside the type scale" — every h1/h2/h3
     stays Inter, only the actual "JET LAGGARD" wordmark uses this. */
  --font-wordmark: "Archivo", system-ui, sans-serif;

  --space-1: 2.8px;
  --space-2: 5.6px;
  --space-3: 8.4px;
  --space-4: 11.2px;
  --space-6: 16.8px;
  --space-8: 22.4px;

  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 14px;

  /* Elevation — derived from the ground: soft ink-tinted shadows on a
     light theme, a hairline edge + ambient darkness on a dark one. */
  --shadow-sm: 0 0 0 1px #374452;
  --shadow-md: 0 0 0 1px #505f71, 0 6px 18px rgba(0,0,0,0.55);
  --shadow-lg: 0 0 0 1px #899aad, 0 16px 40px rgba(0,0,0,0.65);

  /* JL-B43: how much of --color-text survives the color-mix() in
     .text-muted/figcaption. A theme-agnostic 55% (fine against the dark
     ground) reads at only 3.71:1 against the light ground below — a real
     AA failure for 11-13px text, not a rounding nit. Kept as its own token
     so the light block can raise it without duplicating either rule. */
  --muted-mix: 55%;
  /* .card-meta's own mix — kept as a second token, not folded into
     --muted-mix above, so the light-block override below cannot nudge
     .card-meta's DARK-mode rendering even by a rounding step (Phase 1's own
     rule: add a light block, touch zero existing dark values). */
  --muted-mix-2: 50%;
  /* JL-B43: web/index.html's link colour and .go:active state read this
     ramp step directly rather than --color-accent (a softer tint than the
     full-strength accent, deliberately). Aliased here, unchanged in value,
     so the light block below can retint it without a raw --color-accent-300
     reference anywhere needing to change per theme itself. */
  --color-accent-soft: var(--color-accent-300);
  /* .go:active's fill mix — kept theme-aware for the same reason as the two
     mix tokens above: 38% of --color-accent over a LIGHT ground reads too
     close to --color-accent-soft's own value (measured 3.47:1 against light,
     via tests-web/theme-contrast.mjs's CDP-forced :active pass) — increasing
     the mix moves the fill TOWARD the text colour, which makes this fail
     worse, not better, so it needs a smaller (not larger) share on light. */
  --go-active-mix: 38%;
}

/* JL-B43, 2026-09-09: real light palette, added alongside (not replacing)
   the dark block above — every value here is independently WCAG-AA
   contrast-checked against ITS OWN ground (bg or surface, whichever the
   consuming rule actually paints on), not eyeballed:
     text   #12202c / bg #f5f8fb  -> 15.53:1
     text   #12202c / surface #fff -> 16.55:1
     accent #7e5412 / bg #f5f8fb  -> 6.23:1   (AA needs 4.5 for normal text)
     accent-2 #745834 / bg #f5f8fb -> 6.18:1
     muted (68% mix) / bg          -> ~5.6:1  (55%, the dark-mode figure, was 3.71:1 — fails)
   Verified with tests-web/theme-contrast.mjs (paint into a 1x1 canvas, read
   the pixel back — the same technique tests-web/strip-contrast.mjs already
   proved is the only one that survives this file's oklch/color-mix()
   values; see that file's own header for why a regex-based checker already
   failed here once).
   --color-accent and --color-accent-2 deliberately use the 700 ramp step,
   not 400: the 400 step (this file's own accent/accent-2 value) is tuned
   for text ON the DARK ground and reads at only ~2.8:1 on light — a
   straight swap of bg/text is not enough, the accent needs re-deriving per
   ground too.
   The neutral, accent and accent-2 ramps, and the deck-only section tokens,
   are NOT overridden here: every consumer pairs a fixed dark step with a
   fixed light step from the SAME ramp (e.g. .tag-accent's accent-800
   background with accent-100 text), so those pairings are already
   self-contained and theme-independent — changing them would be a redesign
   of the chip system, out of scope here. */
:root[data-theme="light"] {
  --color-bg: #f5f8fb;
  --color-surface: #ffffff;
  --color-text: #12202c;
  --color-accent: #7e5412;
  --color-accent-2: #745834;
  --color-accent-soft: var(--color-accent);
  --go-active-mix: 12%;
  --color-divider: color-mix(in srgb, #12202c 14%, transparent);
  --muted-mix: 68%;
  --muted-mix-2: 68%;

  --shadow-sm: 0 1px 2px rgba(18,32,44,0.06);
  --shadow-md: 0 1px 2px rgba(18,32,44,0.06), 0 6px 18px rgba(18,32,44,0.10);
  --shadow-lg: 0 1px 2px rgba(18,32,44,0.06), 0 16px 40px rgba(18,32,44,0.14);
}

body {
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
}
h1, h2, h3, h4 { font-family: var(--font-heading); font-weight: var(--font-heading-weight); }

.lighten{mix-blend-mode:lighten;background-color:transparent}

/* ══════════════════════════════════════════════════════════════════════════
   Components — built with the tokens above. Plain CSS
   on plain HTML: no JavaScript, no build step. Each class is documented in
   readme.md and demonstrated in foundations/ and components/.
   ══════════════════════════════════════════════════════════════════════ */

*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font-size: 15px; line-height: 1.55; font-weight: 400; }
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  line-height: 1.12; letter-spacing: -0.015em; margin: 0 0 var(--space-2);
}
/* Phase 3, 2026-09-02: h1/h2/h3 font-size deleted here — index.html's own h1/h2/h3
   rule (22.5/20.25/18px, DEV-32's 18px root) already wins the cascade (equal
   specificity, later source order), so these three lines were dead weight, not a
   competing live scale. Verified via computed style before deleting: rendered
   size was already 22.5/20.25/18px, unchanged by this edit. h4/h5/h6 are
   untouched — unused today (0 renders), but not part of the h1/h2/h3
   contradiction this correction resolves, and deleting working non-conflicting
   CSS is out of scope. See design/design-standards.md Rule 3. */
h4 { font-size: 20px; }
h5 { font-size: 16px; }
h6 { font-size: 13px; }
h6 { letter-spacing: 0.08em; text-transform: uppercase; }
p { margin: 0 0 var(--space-3); }
a { color: var(--color-accent); text-underline-offset: 3px; }
img { display: block; max-width: 100%; }
figure { margin: 0; }
figcaption {
  font-size: 11px; margin-top: var(--space-1);
  color: color-mix(in srgb, var(--color-text) var(--muted-mix), transparent);
}
.text-muted { color: color-mix(in srgb, var(--color-text) var(--muted-mix), transparent); }
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }

/* — rules — */
/* Rules fade to transparent at both ends instead of stopping cleanly — a
   Nocturne signature. The ramp is 48px an end (one deck baseline unit),
   painted from the same divider token. Freestanding rules fade; box
   outlines, in-control separators, and short accent marks stay solid. */
.hr {
  height: 1px; border: 0; margin: var(--space-4) 0;
  background: linear-gradient(to right,
    transparent, var(--color-divider) 48px,
    var(--color-divider) calc(100% - 48px), transparent);
}

/* Phase 3, 2026-09-02: this component library was never instantiated by the app —
   0 uses of .btn/.input/.radio/.seg/.table/.dialog measured, confirmed again immediately
   before deletion. The app re-implements its own equivalents inline in index.html's
   <style> block (.go/.ghost/.inp/.chipf/etc). Two component systems in one bundle was
   the defect (design/design-standards.md Rule 4); this is bytes on every first load
   for markup that never renders. .field > label, .card*, .tag*, and .nav* are NOT part
   of this deletion — all confirmed live before touching anything. See
   design/design-standards.md and _docs/plans/jetlag-design-audit-reverification.md. */

/* — forms — */
.field > label {
  display: block; font-size: 12px; margin-bottom: 5px;
  color: color-mix(in srgb, var(--color-text) 70%, transparent);
}
/* — cards — */
.card {
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-surface);
}
.card-kicker { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-accent); }
.card-title {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 17px; line-height: 1.2;
}
.card-body { margin: 0; font-size: 13px; opacity: 0.8; flex: 1; }
.card-meta {
  display: flex; align-items: center; gap: 6px; font-size: 11px;
  color: color-mix(in srgb, var(--color-text) var(--muted-mix-2), transparent);
}
.elev-sm { box-shadow: var(--shadow-sm); }
.elev-md { box-shadow: var(--shadow-md); }
.elev-lg { box-shadow: var(--shadow-lg); }

/* — tags — */
.tag {
  display: inline-flex; align-items: center; font-size: 11px;
  letter-spacing: 0.02em; padding: 3px 10px;
  border-radius: calc(var(--radius-md) * 0.75);
}
.tag-accent { background: var(--color-accent-800); color: var(--color-accent-100); }
.tag-accent-2 { background: var(--color-accent-2-800); color: var(--color-accent-2-100); }
.tag-neutral { background: var(--color-neutral-800); color: var(--color-neutral-100); }
.tag-outline { border: 1px solid var(--color-accent); color: var(--color-accent); }

/* — navigation — */
.nav {
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-bottom: none;
}
.nav-brand {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 18px; margin-right: auto;
}
.nav a { color: inherit; text-decoration: none; font-size: 14px; }
.nav a:hover, .nav a[aria-current='page'] { color: var(--color-accent); }
