/* ============================================================
   base.css — reset + typography + global behavior
   Loaded immediately after tokens.css.
   ============================================================ */

/* Minimal modern reset (no preflight, just essentials) */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html, body { height: 100%; }
body { -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
img, picture, video, canvas, svg { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }
:focus-visible { outline: 2px solid var(--link); outline-offset: 3px; border-radius: 4px; }

/* Webfonts (Source Serif 4 display, Schibsted Grotesk UI, JetBrains Mono numerals) are served by
   css/fonts.css — self-hosted variable subsets, loaded BEFORE this file. Body is Georgia, a system
   serif: zero load, zero CLS.
   [P6.1] Two local()-only @font-face registrations used to sit here, meant as a courtesy to readers
   with the fonts installed. They were a liability, not a courtesy. Being declared after fonts.css,
   they won the match for their families on any machine that had them — serving a local copy in
   place of the vendored subset. That subset is not a mirror: it carries U+2192 and U+2194, which
   Google's own latin subset omits and this essay sets mid-sentence. So the fallback they invited
   was exactly the arrow fallback fonts.css was built to end. They also declared wider weight ranges
   (200 900 / 400 900) than the real faces (400 700 / 400 600), which is what made a
   `font-weight: 380` look reasonable when nothing could render it. */

html {
  font-family: var(--font-body);
  font-optical-sizing: auto;
  font-size: clamp(16.5px, 15.6px + 0.22vw, 18px);   /* fluid root: ~16.5 phone → 18 desktop (FT Georgia body) */
  line-height: var(--lh-normal);
  color: var(--ink);
  background: var(--bg);
  color-scheme: light dark;
  scroll-behavior: smooth;
  -moz-osx-font-smoothing: grayscale;
  transition: background-color var(--dur-3) var(--ease-out),
              color var(--dur-3) var(--ease-out);
}

/* Root font-size is now fluid via the clamp() above (15.5→17px); the old stepped
   @media font-size overrides were removed so the whole rem scale interpolates smoothly. */

body {
  background: transparent;   /* html supplies the surface colour; the fixed grain (below) sits between it and the content */
  color: var(--ink);
  min-height: 100dvh;
}

/* ---------- Paper grain — printed-paper texture, fixed behind content, theme-aware ---------- */
/* A single inline feTurbulence data-URI (zero assets, zero network). Very low opacity,
   pointer-events:none. Light = faint dark specks; dark = faint light specks. Static → reduced-motion safe. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='grain'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.9 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23grain)'/%3E%3C/svg%3E");
}
[data-theme="dark"] body::before {
  opacity: 0.07;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='grain'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.9 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23grain)'/%3E%3C/svg%3E");
}

/* Display headings — Source Serif 4, upright (FT's authoritative voice; the italic-Fraunces
   signature is retired). opsz via font-optical-sizing:auto so h1 reads display, h4 reads text. */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--ink-strong);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: var(--lh-tight);
  text-wrap: balance;
}
h1 { font-size: clamp(var(--fs-800), 6.5vw, var(--fs-max)); font-weight: 700; }
h2 { font-size: clamp(var(--fs-700), 4vw, var(--fs-900)); }
h3 { font-size: var(--fs-600); }
h4 { font-size: var(--fs-500); }

h2, h3, h4 { margin-block-end: var(--space-4); }

/* Body */
p {
  max-width: var(--w-prose);
  line-height: var(--lh-relaxed);
  margin-block-end: var(--space-5);
  color: var(--ink-soft);
  font-size: var(--fs-400);
  text-wrap: pretty;   /* avoids orphans/short last lines in prose */
}
p strong { color: var(--ink); font-weight: 600; }
p em { color: var(--ink); font-style: italic; }

/* Tabular numerals on every data-number run — figures (charts + their controls), the
   singleton tooltip, and the .num/output utilities. (.tnum and .tabular were listed here
   too and are gone: nothing in index.html or js/ ever carried either class.) */
.num,
figure,
output,
.tooltip { font-variant-numeric: tabular-nums; }

a {
  color: var(--link);
  text-decoration-color: var(--link-underline);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
  transition: color var(--dur-2) var(--ease-out);
}
a:hover { color: var(--link-hover); }

/* Lists */
ul, ol { padding-inline-start: 1.25em; margin-block-end: var(--space-5); color: var(--ink-soft); }
li { margin-block-end: var(--space-2); text-wrap: pretty; }

/* Inline code */
code, kbd, samp {
  font-family: var(--font-mono);
  font-size: 0.92em;
  background: var(--bg-sunken);
  padding: 1px 6px;
  border-radius: var(--radius-1);
  font-variant-numeric: tabular-nums;
}

/* Small caption */
.caption, figcaption {
  font-family: var(--font-ui);
  font-size: var(--fs-100);
  color: var(--ink-soft);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  line-height: var(--lh-snug);
}

/* Selection */
::selection { background: var(--accent); color: var(--bg-elev); }

/* Reduced motion — disable transitions */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0ms !important;
    /* [P4.4] Zeroing the DURATIONS alone leaves a delayed transition still waiting: the change
       lands instantly, but only after the delay elapses, which for a reduced-motion reader is the
       same "why is nothing happening" the block exists to remove. No uncovered victim in today's
       CSS -- this closes the gap rather than fixing a symptom. */
    transition-delay: 0ms !important;
    animation-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
}

/* [R4-motion] Theme-toggle cross-fade via the View Transitions API (ThemeManager wraps the theme
   flip in document.startViewTransition where supported). Tune the root cross-fade to the house
   duration; gated to no-preference so reduced-motion users get the instant apply ThemeManager does. */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: var(--motion-base);
  }
}

/* Skip-to-content link (a11y) */
.skip-link {
  position: absolute;
  inset-inline-start: var(--space-3);
  inset-block-start: var(--space-3);
  padding: var(--space-2) var(--space-4);
  background: var(--accent);
  color: var(--bg-elev);
  border-radius: var(--radius-2);
  z-index: var(--z-modal);
  transform: translateY(-200%);
  transition: transform var(--dur-3) var(--ease-out);
}
.skip-link:focus { transform: translateY(0); }

/* SR-only */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap; border: 0;
}
