/* zachevan.com v2 tokens. Every custom property the site uses is declared in this file, so a
   stylesheet or page that references an undeclared property fails design_lint. Colour literals
   live here and nowhere else. Sources: SITE-PLAN.md section 8 and MENU-DESIGN-LOCK.md section 1.
   [DAWN: 2026-09-03, v2 token file; review-by 2026-12-03] */

:root {
  color-scheme: light;

  /* Palette. Signal Meadow, 24 tokens, values from redesign/r7-palette.md section 4.1.
     [OWNER: Zachary Evans, 2026-08-31, "signal meadow is beautiful, keep the dark panel"] */
  --ground-paper: #F7F7F1;
  --ground-surface: #FFFFFF;
  --ground-mist: #EAECE4;
  --text-strong: #0F1F33;
  --text-body: #2C394A;
  --text-muted: #4F5966;
  --action-blue: #1F64D6;
  --action-blue-hover: #084FBA;
  --field-blue-soft: #D7E6FD;
  --field-grass-soft: #D2E7B1;
  --mark-grass: #5D7721;
  --mark-gold: #B77E00;
  --text-gold: #865900;
  --signal-watermelon: #D63375;
  --semantic-good: #2F7442;
  --semantic-warning: #865900;
  --semantic-critical: #801341;
  --ground-dark: #091628;
  --ground-dark-raised: #17273C;
  --text-inverse: #F6F6EE;
  --text-inverse-muted: #ACB9C7;
  --link-inverse: #87BAFD;
  --mark-grass-inverse: #BDD594;
  --mark-gold-inverse: #EDBB64;
  --signal-watermelon-inverse: #F284AA;

  /* Derived values. The shadows derive from ground-dark per MENU-DESIGN-LOCK.md section 2. The
     inverse line uses the muted inverse token directly so meaningful table boundaries clear 3:1.
     [DAWN: 2026-09-04, meaningful inverse boundary contrast; review-by 2026-12-04] */
  --shadow-panel: 0 18px 48px rgb(9 22 40 / 14%), 0 3px 12px rgb(9 22 40 / 8%);
  --shadow-sheet: 0 18px 36px rgb(9 22 40 / 12%);
  --line-inverse: var(--text-inverse-muted);
  --swatch: transparent;

  /* Size primitives. */
  --px-1: 1px; --px-2: 2px; --px-4: 4px; --px-6: 6px; --px-8: 8px; --px-10: 10px;
  --px-12: 12px; --px-13: 13px; --px-14: 14px; --px-16: 16px; --px-17: 17px;
  --px-18: 18px; --px-19: 19px; --px-20: 20px; --px-22: 22px; --px-24: 24px;
  --px-26: 26px; --px-28: 28px; --px-32: 32px; --px-34: 34px; --px-40: 40px;
  --px-44: 44px; --px-48: 48px; --px-52: 52px; --px-56: 56px; --px-64: 64px;
  --px-72: 72px; --px-76: 76px; --px-84: 84px;

  /* Faces. Three self-hosted variable faces from the Google Fonts library with metric fallbacks.
     [LAW: SITE-PLAN.md section 8.2] */
  --font-display: "Archivo", "Archivo Fallback", "Helvetica Neue", Arial, sans-serif;
  --font-prose: "Source Serif 4", "Source Serif 4 Fallback", Georgia, "Times New Roman", serif;
  --font-mono: "IBM Plex Mono", "IBM Plex Mono Fallback", ui-monospace, "SFMono-Regular", monospace;

  /* The launch taste revision keeps the faces and body roles but lowers H2 so H1 is the only
     page-scale heading. [LAW: FABLE-TASTE-READ.md, H1 versus H2 scale] */
  --type-h1: 700 clamp(36px, 5.2vw, 72px)/1.06 var(--font-display);
  --type-h2: 700 clamp(30px, 3.3vw, 40px)/1.12 var(--font-display);
  --type-h3: 700 var(--px-24)/28.8px var(--font-display);
  --type-lede: 400 var(--px-22)/31.9px var(--font-prose);
  --type-body: 400 var(--px-18)/28.98px var(--font-prose);
  --type-label: 600 var(--px-13)/var(--px-19) var(--font-prose);
  --type-button: 600 var(--px-17)/var(--px-24) var(--font-display);
  --type-numeral-label: 500 var(--px-13)/var(--px-19) var(--font-mono);
  --tracking-h1: -0.02em;
  --tracking-h2: -0.02em;

  /* Component type roles added beside the scale. The link role is the accepted header type the
     menu lock keeps; the menu roles are the lock's rows, section summaries and group labels; the
     rest name one component each. [LAW: MENU-DESIGN-LOCK.md sections 2 to 4]
     [DAWN: 2026-09-03, component type roles; review-by 2026-12-03] */
  --type-link: 600 var(--px-17)/var(--px-26) var(--font-prose);
  --type-menu-row: 600 var(--px-16)/var(--px-22) var(--font-display);
  --type-menu-section: 600 var(--px-17)/var(--px-24) var(--font-display);
  --type-menu-group: 600 var(--px-12)/var(--px-16) var(--font-prose);
  --tracking-group: 0.08em;
  --type-name: 600 var(--px-20)/var(--px-26) var(--font-display);
  /* Complete price strings include words, spaces and plus signs. Keep them in one display face.
     IBM Plex Mono remains the numeral-only face for tool figures. */
  --type-price: 600 clamp(var(--px-16), 4.7vw, var(--px-24))/1.2 var(--font-display);
  --type-figure: 500 var(--px-32)/var(--px-34) var(--font-mono);
  --type-note: 400 var(--px-16)/25.76px var(--font-prose);
  --type-field-label: 600 var(--px-17)/var(--px-26) var(--font-prose);
  --type-footer-heading: 700 var(--px-24)/26.88px var(--font-display);

  /* Spacing scale 4, 8, 12, 16, 24, 32, 48, 72 and the named gaps. */
  --space-4: var(--px-4); --space-8: var(--px-8); --space-12: var(--px-12); --space-16: var(--px-16);
  --space-24: var(--px-24); --space-32: var(--px-32); --space-48: var(--px-48); --space-72: var(--px-72);
  --gap-para: var(--space-16);
  --gap-heading: var(--space-24);
  --gap-group: var(--space-32);
  --gap-subordinate: var(--space-48);
  --gap-action: var(--space-48);
  --pad-section: var(--px-64);
  --pad-hero-top: var(--px-72);
  --pad-hero-bottom: var(--px-64);
  --pad-close: var(--px-64);

  /* Frame and measure. Chrome may use the wide frame; reading pages use the centred 704px frame. */
  --content-max: 1312px;
  --reading-max: 704px;
  --page-margin: clamp(var(--px-48), calc((100vw - var(--content-max)) / 2), var(--px-64));
  --measure-prose: 676px;
  --measure-note: 600px;
  --measure-h1: 820px;
  --measure-heading: 720px;
  --measure-supporting-heading: 568px;
  --measure-lede: 660px;
  --measure-rail: 640px;
  --header-height: var(--px-64);
  --target-min: var(--px-44);

  /* Lines, rings, shapes. */
  --border-hairline: var(--px-1);
  --border-emphasis: var(--px-2);
  --focus-ring: var(--px-2);
  --focus-offset: var(--px-2);
  --radius-mark: var(--px-4);
  --radius-container: var(--px-8);

  /* Menu component aliases. Computed values are the test contract. [LAW: MENU-DESIGN-LOCK.md section 1] */
  --menu-panel-width: 336px;
  --menu-panel-pad: 12px;
  --menu-panel-radius: 8px;
  --menu-row-height: 44px;
  --menu-mobile-row-height: 48px;
  --menu-mobile-section-height: 52px;
  --menu-mark-size: 12px;
  --menu-mark-box: 16px;
  --menu-panel-shift: 0px;
  --menu-motion-open: 220ms;
  --menu-motion-close: 160ms;
  --menu-motion-state: 160ms;
  --menu-motion-intent-open: 120ms;
  --menu-motion-intent-close: 240ms;
  --menu-motion-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --menu-motion-offset: 8px;
  --menu-motion-stagger: 0ms;

  /* State transitions outside the menu use the menu's state duration and easing. Motion is the
     menu only; nothing else moves. [LAW: SITE-PLAN.md section 8.5] */
  --motion-state: var(--menu-motion-state);
}

@media (max-width: 1100px) {
  :root {
    --content-max: 1024px;
    --page-margin: var(--px-48);
  }
}

@media (max-width: 760px) {
  :root {
    --content-max: 100%;
    --page-margin: 20px;
    --header-height: 85px;
    --pad-section: var(--px-48);
    --pad-hero-top: var(--px-52);
    --pad-hero-bottom: 48px;
    --pad-close: var(--px-56);
    --gap-heading: var(--px-20);
    --gap-group: var(--px-28);
    --gap-subordinate: var(--px-40);
    --gap-action: var(--px-40);
    --measure-prose: 637px;
    --type-lede: 400 var(--px-19)/27.55px var(--font-prose);
    --type-body: 400 var(--px-17)/27.88px var(--font-prose);
  }
}

@media (max-width: 376px) {
  :root {
    --header-height: calc(var(--target-min) + var(--target-min) + var(--space-16));
  }
}

/* Reduced motion. Open, close, state, stagger and offset compute to zero. The two hover-intent
   delays remain because they prevent accidental pointer activation and are not visual motion.
   [LAW: MENU-DESIGN-LOCK.md section 5] */
@media (prefers-reduced-motion: reduce) {
  :root {
    --menu-motion-open: 0ms;
    --menu-motion-close: 0ms;
    --menu-motion-state: 0ms;
    --menu-motion-stagger: 0ms;
    --menu-motion-offset: 0px;
    --motion-state: 0ms;
  }
}

/* Dark preference. The site ships one measured light theme. Under a dark system preference the
   page keeps the paper ground and the ink text, because the palette's contrast pairs are measured
   on paper and the dark tokens are reserved for the bounded price panel and the footer. The
   redefinitions below restate the light-ground pairs so no user-agent dark default reaches a
   surface. The rejected alternative is a full dark theme, which needs a second measured contrast
   pass and puts the dark panel on a dark ground. [DAWN: 2026-09-03, one measured theme with the
   dark tokens reserved for the panel; review-by 2026-12-03] */
@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: light;
    --ground-paper: #F7F7F1;
    --ground-surface: #FFFFFF;
    --ground-mist: #EAECE4;
    --text-strong: #0F1F33;
    --text-body: #2C394A;
    --text-muted: #4F5966;
    --field-blue-soft: #D7E6FD;
  }
}
