/* ============================================================
   Base — @font-face, reset, element defaults, focus
   ============================================================ */

/* ---- Self-hosted faces. No request leaves this origin. ---- */
@font-face {
  font-family: "Italiana";
  src: url("../fonts/italiana-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Great Vibes";
  src: url("../fonts/great-vibes-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Source Serif 4";
  src: url("../fonts/source-serif-4-600.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("../fonts/hanken-grotesk-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("../fonts/hanken-grotesk-500.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("../fonts/hanken-grotesk-600.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("../fonts/hanken-grotesk-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  interpolate-size: allow-keywords;   /* lets the FAQ answer's height ease to auto */
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;   /* anchor targets clear the sticky nav */
}

/* Anchor targets. scroll-padding-top above clears the bar, but it aligns the
   section's box top, and every section carries --section-y of padding before its
   first line — so the heading landed a whole section's padding below the bar.
   The negative margin aims the scroll past that padding instead, and because it
   is expressed in the same token it stays right at every width. */
main > section[id] {
  scroll-margin-top: calc(var(--space-m) - var(--section-y));
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

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

/* ---- Headings: display face, tight, never Meadow ---- */
h1, h2, h3 {
  font-weight: 400;
  line-height: var(--leading-tight);
  text-wrap: balance;
  color: var(--ink);
}
/* The stroke is inherited, so it reaches the spans inside a heading too. The
   lockup's own words set their stroke explicitly and so are unaffected, which is
   what keeps the mark matching its exported files. */
h1,
h2 {
  font-family: var(--font-display);
  -webkit-text-stroke: var(--display-weight) currentColor;
  paint-order: stroke fill;
}
h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: var(--step-1);
  line-height: var(--leading-snug);
}

p { text-wrap: pretty; max-width: var(--measure); }

/* Great Vibes accent inside display type. Meadow itself stays on the lockup only (a
   logotype, exempt from contrast): on cream it is 2.73:1 and fails even the 3:1 floor
   for large text, so content script takes the deeper meadow. Dark grounds rebind it to
   light green in components.css. */
.script {
  font-family: var(--font-script);
  font-style: normal;
  color: var(--meadow-deep);
  line-height: 1;
}

/* ---- Eyebrow / label ---- */
.eyebrow {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: var(--step--1);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: var(--space-m);
  max-width: none;
  text-wrap: balance;
}

/* ---- Links ---- */
a { color: var(--accent); text-underline-offset: 0.18em; }
a:hover { text-decoration-thickness: 2px; }

/* Author display rules must never resurrect an element the markup has hidden. */
[hidden] { display: none !important; }

/* ---- Focus: visible everywhere, always ---- */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--radius-s);
}

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

/* Available to assistive tech, invisible on screen — used where an icon is the
   only visible content but the control still needs a name. */
.u-visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---- Scroll reveal ----
   Two guards, both deliberate:
   .js  — with JavaScript off nothing is ever hidden, so the page cannot end up
          blank waiting for an observer that will never run.
   no-preference — under reduced motion the initial hidden state is never applied
          at all. Hiding first and disabling the transition would leave the
          content permanently invisible, which is the usual bug here. */
@media (prefers-reduced-motion: no-preference) {
  .js [data-reveal] {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity var(--dur-slow) var(--ease-out),
                transform var(--dur-slow) var(--ease-out);
  }
  .js [data-reveal].is-in {
    opacity: 1;
    transform: none;
  }
}
