/* =============================================================
   BASE — reset + element defaults. Tokens only, no raw values.
   ============================================================= */

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

html {
  scroll-behavior: smooth;
  background: var(--surface);
  /* nothing is placed past the viewport edge any more; the clip stays so
     that nothing can ever create a scrollable overflow by accident */
  overflow-x: clip;
  /* both spellings: the prefixed one is what Safari and Chrome read, the
     unprefixed one is the standard property and is what an engine that has
     dropped the prefix reads. A prefix-only declaration is a portability gap
     by definition, and the value is the same either way. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100%;
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-body);
  font-weight: var(--weight-body);
  color: var(--ink);
  /* deliberately transparent: <html> owns the page colour (it is
     propagated to the canvas, painted first), so the fixed .wall
     at z-index -2 sits on top of it. A background here would
     paint over the wall and the texture would vanish. */
  background: transparent;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* clip, not hidden: `overflow-x: hidden` makes <body> a scroll container,
     and position: sticky inside one never engages. The stage pins on it. */
  overflow-x: clip;
}


/* ---------- the wall ----------
   A fixed, full-viewport layer instead of a background on <body>:
   `background-attachment: fixed` stutters on iOS, this doesn't, and it
   keeps the texture still while the page moves over it — which is what
   makes it read as a surface rather than a pattern.

   The texture is a greyscale sweep MULTIPLIED over --surface, not an
   opaque image laid on top of it, so --surface owns the colour and the
   file owns only the modulation, so a ground change is one token and never
   a second asset kept in sync by hand.                                 */

.wall {
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background-color: var(--surface);
  background-image: var(--texture);
  background-size: cover;
  background-position: center;
  background-blend-mode: multiply;
}

/* A film of the surface colour over the wall scales the modulation down by
   `1 - --texture-strength`. It exists because the ground was briefly cream on
   2026-09-06 and the white-cut asset read as dirt there; on white the token
   is 1 and this paints nothing. Measure the render before moving it
   (02-standards/pass-bands.md). */
.wall::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--surface);
  opacity: calc(1 - var(--texture-strength, 1));
}


/* ---------- the veil ----------
   The wall's other half, and the reason these five component selectors are
   in base.css rather than beside their components: this is the GROUND, and
   the sections are only the ruler the ramp is measured against. Read the
   four stops together in tokens.css or the ramp means nothing.

   A background, not a pseudo-element, and deliberately so. `.wall` is
   `position: fixed`, so anything painted on it stays in the same corner of
   the screen at every scroll position — a mask on the wall was tried and
   rejected for exactly that (02-standards/pass-bands.md). A section's own
   background scrolls with the words it sits behind, which is the whole
   point, and it needs no z-index, no isolation and no extra element.

   Each rule runs from its own stop to the next section's, so the numbers
   chain and no seam has to be hidden. The closer paints deep green over all
   of it and takes no veil; the ramp resumes underneath it at the foot.

   `--veil-hero` is 0%, and `color-mix(… 0%, transparent)` resolves to
   transparent BLACK, not transparent white. It is still correct, because
   gradients interpolate in PREMULTIPLIED alpha and a zero-alpha stop
   contributes no colour — measured 2026-09-20: the hero's top row is
   identical to a no-veil control to 0.000 of a luminance level. Write a
   non-zero stop here and it is a real colour, so keep it --surface.       */

.hero          { background-image: linear-gradient(to bottom, color-mix(in srgb, var(--surface) var(--veil-hero),  transparent), color-mix(in srgb, var(--surface) var(--veil-stage), transparent)); }
.stage         { background-image: linear-gradient(to bottom, color-mix(in srgb, var(--surface) var(--veil-stage), transparent), color-mix(in srgb, var(--surface) var(--veil-read),  transparent)); }
.idea          { background-image: linear-gradient(to bottom, color-mix(in srgb, var(--surface) var(--veil-read),  transparent), color-mix(in srgb, var(--surface) var(--veil-page),  transparent)); }

/* Flat, at the level the ramp settles to. `.welcome` is the WHOLE body of the
   confirmation page and it is here rather than left on the bare wall because
   `.foot` sits under it: a veiled foot against an unveiled page draws a
   horizontal edge across the screen exactly where the texture stops. */
.offer-section,
.welcome,
.foot          { background-color: color-mix(in srgb, var(--surface) var(--veil-page), transparent); }


/* ---------- headings ---------- */

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-variation-settings: var(--wonk-display);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  color: var(--heading);
  max-width: var(--measure-heading);
  text-wrap: balance;
}

h1 { font-size: var(--step-5); }
h2 { font-size: var(--step-4); }
h3 {
  font-size: var(--step-2);
  line-height: var(--lh-tight);
  letter-spacing: -0.008em;
}

/* the serif's italic is a real one and it is the page's second voice —
   a second sentence, or two words of a headline, in a brand tone */
em, .it {
  font-style: italic;
  font-variation-settings: var(--wonk-display);
}

/* eyebrow / label — small, tracked, uppercase, always */
h4, .label {
  margin: 0;
  font-size: var(--step--2);
  font-family: var(--font-body);
  font-weight: var(--weight-semi);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--ink-muted);
  max-width: none;
}


/* ---------- text ---------- */

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

.lead {
  font-size: var(--step-1);
  line-height: 1.5;
  max-width: var(--measure-lead);
  color: var(--ink);
}

a {
  color: var(--teal-ink);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  transition: color var(--dur-fast) var(--ease-out);
}
a:hover { color: var(--green); }

strong, b { font-weight: var(--weight-semi); }

small {
  font-size: var(--step--1);
  line-height: 1.5;
  color: var(--ink-muted);
  display: block;
}

ul, ol { margin: 0; padding-left: var(--space-m); }

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

hr { border: 0; border-top: 1px solid var(--line); margin: 0; }


/* ---------- forms ---------- */

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


/* ---------- focus ----------
   Visible focus is a requirement, not a preference.           */

:focus-visible {
  outline: 2px solid var(--teal-ink);
  outline-offset: 3px;
  border-radius: var(--radius-s);
}

.on-invert :focus-visible { outline-color: var(--gold); }

/* The confirmation page's states are focused programmatically so the change is
   announced (js/site.js swap()). They are copy blocks, not controls. */
[data-state]:focus,
[data-state]:focus-visible { outline: none; }

::selection { background: var(--gold); color: var(--green-deep); }


/* ---------- inverted (deep green) regions ---------- */

.on-invert {
  color: var(--ink-invert);
  --heading: var(--heading-invert);
  --ink: var(--ink-invert);
  --ink-muted: var(--ink-invert);   /* no muted grade on dark — see tokens.css */
  --line: var(--line-invert);
}
.on-invert a { color: var(--teal); }
.on-invert a:hover { color: var(--gold); }


/* ---------- reduced motion ----------
   Everything still arrives; it just arrives already there.    */

@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;
    scroll-behavior: auto !important;
  }
}
