/* ==========================================================================
   whitepage base layer — invisible scaffolding only
   --------------------------------------------------------------------------
   Vendored token + layout primitives shared by every generated site. This
   file is structural ONLY: spacing scale, type scale, container width, a
   small set of layout utilities, a reset, and vertical rhythm.

   It deliberately defines NO colors and NO concrete font families — those are
   the renderer's per-run job (palette = DS-2, type pairing = DS-6). Keeping
   this file colorless/typeface-less means it never fights the palette lint
   and never imposes a recognizable framework "look" (DS-8).

   Rules for the renderer:
     1. Copy this file VERBATIM into the site (e.g. assets/base.css) and link
        it FIRST, before the run's theme stylesheet.
     2. Build the run's aesthetics ON TOP of these tokens (set colors, pick
        the font pairing, map them onto --font-sans / --font-serif).
     3. NEVER edit this file. Override via your own cascade, not by mutation.
   ========================================================================== */

/* --- Tokens ------------------------------------------------------------- */
:root {
  /* 4px-based spacing scale — use these everywhere instead of ad-hoc px */
  --space-3xs: 0.25rem;  /*  4px */
  --space-2xs: 0.5rem;   /*  8px */
  --space-xs:  0.75rem;  /* 12px */
  --space-sm:  1rem;     /* 16px */
  --space-md:  1.5rem;   /* 24px */
  --space-lg:  2rem;     /* 32px */
  --space-xl:  3rem;     /* 48px */
  --space-2xl: 4rem;     /* 64px */
  --space-3xl: 6rem;     /* 96px */
  --space-4xl: 8rem;     /* 128px */

  /* Modular type scale (~1.25 minor third), fluid where it helps reading */
  --text-xs:   0.8rem;
  --text-sm:   0.9rem;
  --text-base: clamp(1.0625rem, 1rem + 0.3vw, 1.125rem); /* ~17–18px body */
  --text-lg:   1.25rem;
  --text-xl:   1.563rem;
  --text-2xl:  1.953rem;
  --text-3xl:  clamp(2.25rem, 1.8rem + 2vw, 2.441rem);
  --text-4xl:  clamp(2.75rem, 2rem + 3.5vw, 3.815rem);

  /* Line-heights */
  --leading-tight:   1.15;
  --leading-snug:    1.3;
  --leading-normal:  1.65;  /* generous, for body reading */

  /* Reading measure / page container widths */
  --measure: 68ch;          /* article body — a proper read, not full column */
  --container: 72rem;       /* outer page max-width (homepage/lists) */
  --container-narrow: 42rem;

  /* Radii + border width tokens (color is set by the theme) */
  --radius-sm: 0.25rem;
  --radius-md: 0.5rem;
  --radius-lg: 1rem;
  --border-width: 1px;

  /* Font role variables — the THEME assigns real faces to these.
     Left empty here on purpose so this file ships no typeface. */
  --font-sans: ;
  --font-serif: ;
}

/* --- Reset / normalize -------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  -moz-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  min-height: 100vh;
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
}

input,
button,
textarea,
select {
  font: inherit;
}

button {
  cursor: pointer;
  background: none;
  border: none;
}

a {
  color: inherit;
  text-decoration-thickness: 0.06em;
  text-underline-offset: 0.15em;
}

ul[role="list"],
ol[role="list"] {
  list-style: none;
  padding: 0;
}

p,
h1, h2, h3, h4, h5, h6 {
  overflow-wrap: break-word;
}

/* --- Vertical rhythm ---------------------------------------------------- */
h1, h2, h3, h4, h5, h6 {
  line-height: var(--leading-tight);
  font-weight: 600;
}

h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); }
h4 { font-size: var(--text-xl); }
h5 { font-size: var(--text-lg); }

/* Flow spacing: consistent gaps between stacked content without per-element
   margins. Apply `.flow` (or .prose) to a container of block content. */
.flow > * + *,
.prose > * + * {
  margin-block-start: var(--space-md);
}

.prose > * + :is(h2, h3, h4) {
  margin-block-start: var(--space-xl);
}

.prose :is(h2, h3, h4) + * {
  margin-block-start: var(--space-sm);
}

.prose {
  max-width: var(--measure);
  line-height: var(--leading-normal);
}

/* --- Card / list kicker (cluster label) --------------------------------- */
/* Small eyebrow label that surfaces each article's content cluster above its
   title (richness, DS-13). STRUCTURAL ONLY — no color, no typeface: theme.css
   paints it (typically with the secondary accent) and the inherited --font-sans
   gives it a face. Sits in the normal flow; the layout libs space the card. */
.article-card__kicker,
.article-list__kicker {
  display: block;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: var(--leading-snug);
  margin-block-end: var(--space-2xs);
}

/* --- Layout primitives -------------------------------------------------- */
/* Centered page container with a responsive inline gutter. */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--space-md);
}

.container--narrow {
  max-width: var(--container-narrow);
}

@media (min-width: 768px) {
  .container {
    padding-inline: var(--space-xl);
  }
}

/* Vertical stack with a configurable gap (default md). */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--stack-gap, var(--space-md));
}

/* Horizontal cluster that wraps gracefully (nav, tag rows, button rows). */
.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cluster-gap, var(--space-sm));
}

/* Auto-fit responsive grid — cards reflow with no media queries needed.
   Tune the minimum column width per use with --grid-min. */
.grid {
  display: grid;
  gap: var(--grid-gap, var(--space-lg));
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(var(--grid-min, 18rem), 100%), 1fr)
  );
}

/* Push a footer to the bottom; main fills remaining height. */
.page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.page > main {
  flex: 1 0 auto;
}

/* Vertical section padding token for major page bands. */
.section {
  padding-block: var(--section-pad, var(--space-2xl));
}

/* Visually hidden but accessible (skip links, labels). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- Theme toggle (DS-12) ----------------------------------------------- */
/* Colorless STARTER primitives for the deterministically-injected light/dark
   toggle. The button inherits color via currentColor; the theme paints around it.
   Sun/moon icons are both injected; CSS shows the one for the theme you'd
   switch TO (moon in light, sun in dark). Keyed on the <html data-theme>.

   These are defaults, not a straitjacket: theme.css MAY restyle the toggle's
   SHAPE within the palette (border-radius → pill, border ↔ borderless, size, an
   optional text label) so it doesn't read as the same square on every site
   (DS-12). What stays deterministic is the MARKUP + JS (render-shell injects
   them); theme.css only paints + reshapes via the cascade, never re-authors. */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;          /* 44px — reachable tap target at 320px (DS-7) */
  height: 2.75rem;
  padding: 0;
  border-radius: var(--radius-md);
  color: inherit;
  transition: opacity 0.2s ease;
}

.theme-toggle:hover { opacity: 0.7; }

.theme-toggle:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.theme-toggle__icon {
  width: 1.25rem;
  height: 1.25rem;
}

[data-theme="light"] .theme-toggle .icon-sun  { display: none; }
[data-theme="dark"]  .theme-toggle .icon-moon { display: none; }

/* --- Nav controls + burger menu (DS-14) --------------------------------- */
/* The burger + theme toggle are grouped in an injected .nav-controls cluster.
   On mobile the nav-links collapse behind the burger so the header stays
   compact; at >=768px the links show inline and the burger hides. All gated by
   the `js` class (added synchronously before paint) so no-JS users keep a
   plain, fully-navigable stacked header — progressive enhancement.

   Layout libs load AFTER base.css, so these overrides carry extra specificity
   (`html.js .site-nav …`) to win the cascade regardless of source order. */
.nav-controls {
  display: inline-flex;
  align-items: center;
  align-self: center;   /* center the icon cluster on the cross axis regardless of the
                           lib's .site-nav alignment (beats swiss's align-items:baseline
                           and editorial's column masthead) — keeps it level with the brand */
  gap: var(--space-2xs);
}

.nav-toggle {
  display: none;            /* shown only on mobile when JS is active */
  align-items: center;
  justify-content: center;
  width: 2.75rem;           /* 44px tap target (DS-7) */
  height: 2.75rem;
  padding: 0;
  border-radius: var(--radius-md);
  color: inherit;
  transition: opacity 0.2s ease;
}

.nav-toggle:hover { opacity: 0.7; }
.nav-toggle:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.nav-toggle__icon { width: 1.5rem; height: 1.5rem; }

/* Icon swap: hamburger when closed, X when open. */
.site-nav[data-nav-open="true"]  .nav-toggle .icon-menu  { display: none; }
.site-nav:not([data-nav-open="true"]) .nav-toggle .icon-close { display: none; }

@media (max-width: 767px) {
  /* Compact single-row bar across EVERY layout lib: brand left, controls right.
     This intentionally OVERRIDES any lib that stacks the nav (e.g. editorial's
     centered column masthead) so the mobile header is always one tidy row plus a
     drop-down panel — never a tall stacked column that eats the first screen. */
  html.js .site-nav {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    column-gap: var(--space-sm);
    row-gap: var(--space-2xs);
    padding-block: var(--space-sm);   /* keep the bar short — don't eat the first screen */
    text-align: start;
  }
  /* Pin brand + controls to the top row so the burger NEVER moves when the menu
     opens; the links always drop BELOW (order-based, DOM stays a11y-sane). */
  html.js .site-nav .nav-brand    { order: 0; }
  html.js .site-nav .nav-controls { order: 1; }
  html.js .site-nav .nav-links    { order: 2; }

  /* DS-16 — the 320px one-row law. Brand + theme toggle + burger MUST share a
     single row down to the 320px floor. The two 44px controls never shrink
     (flex 0 0 auto); the wordmark scales down with the viewport and, as a
     last-resort guarantee, truncates with an ellipsis — so the controls can
     never be pushed onto a second line. The full brand name still shows in the
     hero <h1> below, so nav truncation is cosmetic, never a loss of info. */
  html.js .site-nav .nav-brand {
    /* flex-basis 0 is the crux: with flex-wrap on, the browser decides line breaks
       from each item's BASE size. A nowrap wordmark's auto basis is its full width
       (wider than 320px), so it would claim the whole first line and wrap the
       controls below it. flex-basis 0 makes the brand contribute nothing to line
       packing — the controls stay on row 1 and the brand grows into the leftover
       space (ellipsizing only if even that is too narrow). min-width:0 is REQUIRED
       so the nowrap text can shrink below its content size. */
    font-size: clamp(0.7rem, 0.5rem + 0.9vw, var(--text-base));
    line-height: var(--leading-tight);
    min-width: 0;
    flex: 1 1 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  html.js .site-nav .nav-controls { flex: 0 0 auto; }
  /* Burger at the far-right edge (most reachable); theme toggle to its left. */
  html.js .site-nav .nav-controls .theme-toggle { order: 0; }
  html.js .site-nav .nav-controls .nav-toggle   { order: 1; }

  html.js .site-nav .nav-toggle { display: inline-flex; }
  /* Links collapse by default; expand to a full-width column when opened. */
  html.js .site-nav .nav-links { display: none; }
  html.js .site-nav[data-nav-open="true"] .nav-links {
    display: flex;
    flex-direction: column;
    align-items: stretch;     /* beat a theme's align-items:center → clean left-aligned stack */
    text-align: start;
    flex-basis: 100%;
    width: 100%;
    gap: var(--space-3xs);
    margin-block-start: var(--space-2xs);
    padding-block-start: var(--space-xs);
    border-block-start: var(--border-width) solid var(--color-border, currentColor);
  }
  /* Comfortable full-width tap targets in the dropdown (DS-7). */
  html.js .site-nav[data-nav-open="true"] .nav-links a {
    display: block;
    width: 100%;
    padding-block: var(--space-2xs);
  }
}

/* --- Tablet/desktop: the one-row law holds above mobile too (DS-16) ------ */
@media (min-width: 768px) {
  /* Some layout libs cap the nav narrow (container-narrow ~672px). A large
     wordmark + the nav links + the injected theme toggle can overflow that width
     and, because the libs allow flex-wrap, drop the controls onto their OWN second
     line. Forbid the wrap and let the brand + links shrink (brand ellipsizes only
     in the extreme) so the toggle/controls always stay on the nav line. */
  html.js .site-nav { flex-wrap: nowrap; }
  html.js .site-nav .nav-brand {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  html.js .site-nav .nav-links { min-width: 0; }
  html.js .site-nav .nav-controls { flex: 0 0 auto; }
}

/* --- Motion safety ------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
