/* ==========================================================================
   Laurels — site.css
   Resting state only. No entrances, no scroll effects, no keyframes.
   A separate motion pass owns arrival; every deck layer below exposes the
   custom properties that pass will drive.

   Every component is written against the GENERIC ground names defined by
   tokens.css (--ground --surface --raised --text-1..3 --cool --warm
   --warm-fill --hairline --elev-card --elev-row --top-gradient --cta-*).
   No component reaches for --dark-ground, --on-light-1, --cool-on-dark etc.
   directly, so a card renders correctly on whichever ground it lands on.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Local custom properties.
   Only values the token layer does not carry. Each states why.
   -------------------------------------------------------------------------- */

:root {
  /* tokens.json carries no border-width scale — hairlines are described by
     colour only. One device pixel, everywhere a hairline is drawn. */
  --hairline-w: 1px;

  /* No focus-ring token exists. 2 px is the thinnest ring that survives a
     4 px offset against both grounds at 100% zoom. */
  --focus-w: 2px;

  /* Texture frequency for the .band-rules field. This is a repeat pitch,
     not a spacing step, but it is composed from the 4 pt scale so the rule
     rhythm stays commensurate with everything else on the page. */
  --rule-pitch: var(--space-4);

  /* Height of a .row-media panel. The token layer sizes type, space and
     radius but no component boxes. 380 px was the template's figure; raised
     to 460 on 2026-08-21 because the object inside was floating in a panel
     roughly twice as wide as it, and a panel that is mostly empty reads as a
     slot waiting for artwork rather than as artwork. */
  --media-h: clamp(320px, 38vw, 460px);

  /* Shared inner width for the diagram objects inside .row-media
     (.cal, .pages) so the three rows share one optical measure. Raised with
     --media-h for the same reason: the reference's panels are filled by the
     thing they are showing, edge to edge, and ours were not. */
  --media-inner-w: min(100%, calc(var(--space-20) * 5.5));

  /* The .band-mark is architecture, not an icon — it is deliberately far
     off any icon or space step, and bleeds past the band edge. */
  --mark-size: clamp(360px, 54vw, 820px);

  /* --- The hero clip -----------------------------------------------------
     Measured off the reference at 1440x900, not chosen. The media is full
     bleed until scrollY 100, then clips to an inset rounded card and stays
     there — it never scales, translates or resizes, and it never tracks the
     scroll position. All four measured values land exactly on the 4pt scale,
     so none of them is an exception to the token rule:
        16 = --space-4    24 = --space-6      (below 1280px)
        32 = --space-8    64 = --space-16     (1280px and up)
     The radius is 2x the inset at both sizes. */
  --hero-inset: var(--space-4);
  --hero-round: var(--space-6);

  /* The one measured value the token layer genuinely cannot supply. --dur-slow
     is 420ms and tokens.json scopes it to "a sheet, a modal, a screen" —
     element scale. This is the whole page settling into its layout, and at
     420ms it reads as a snap rather than as weight. 1000ms is the figure
     measured off the reference; the curve is our own --ease-staged, which is
     already the identical cubic-bezier(.22, 1, .36, 1). */
  --hero-clip-dur: 1000ms;

  /* Hero headline size. A viewport clamp rather than a --step-*, because the
     hero is now full bleed: the line is bounded by the window, not by a
     column, and no step spans 20 -> 84px.

     The slope is set by the longer of the two lines. "Set who you want to
     become." measures 13.5em in the display face, and the hero keeps
     --space-4 of inline padding at phone widths, so it holds one line while
     13.5 x font-size stays under (100vw - 32px). 6.4vw leaves roughly 6% in
     hand at every width, which is the margin between Iowan Old Style and the
     Newsreader that stands in for it off Apple platforms. The cap is
     --step-display's own cap, so the two agree at the top; the floor is only
     reached below 313px and exists so the value is never unbounded. */
  --step-hero: clamp(1.25rem, 6.4vw, 5.25rem);

  /* Measured. --leading-tight is 1.06; the reference sets 0.95, and at hero
     scale that difference is the whole character of the setting. Nothing
     else on the page uses it. */
  --leading-hero: 0.95;

  /* --- The nav plate -----------------------------------------------------
     The plate is an oversized inert sibling sitting behind the links, not
     padding on a parent. Bleeding past them on every side is what makes it
     read as a floating plate rather than a chrome bar. The reference bleeds
     4px below 1280 and 6px above; 4px is --space-1, and 6px is composed from
     --space-3 the same way --rule-pitch is composed above. */
  --pill-bleed: var(--space-1);

  /* Measured. The token layer carries no blur scale, and this is the only
     backdrop-filter on the site. */
  --pill-blur: 13px;

  /* The vertical space the floating nav occupies: its 16px offset plus its
     own 56px plate. Reused as scroll-padding so in-page anchors do not land
     under it, and as the hero's top padding so the headline is not centred
     against a window the nav is eating the top of. Composed from the 4pt
     scale. */
  --head-h: calc(var(--space-16) + var(--space-2));

  /* Grain. Desaturated fractal noise, ~330 bytes, tiled at its natural
     140 px. The token layer has no texture primitives. */
  --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   Reset and base
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--head-h) + var(--space-6));
}

body {
  margin: 0;
  /* Guard against any transformed decoration widening the page.
     `clip` (unlike `hidden`) does not create a scroll container, so the
     sticky header keeps working. */
  overflow-x: clip;
  background-color: var(--ground);
  font-family: var(--font-body);
  font-size: var(--step-body);
  line-height: var(--leading-body);
  font-synthesis-weight: none;
}

/* --------------------------------------------------------------------------
   The page is a surface, not a ground.

   design-tokens.md §Layers, SETTLED 2026-08-16 — the section titled "the gap
   all three blind builds fell into":

     L1  Body copy never sits on the ground. A paragraph on layer 0 is a defect
     L2  Layers step by one

   and the reason it gives, verbatim: "that is why the light ground looked too
   dark in all three: mist is a shadow-catcher, not a page."

   This page was the fourth build to fall into it. It ran mist end to end with
   every paragraph directly on it, which is exactly what L1 forbids and exactly
   what the sentence above predicts it would look like.

   A phone screen has room for the full four-rung ladder. A web page has two:
   the page itself carries body content, so the page IS the surface, and a card
   on it steps up one to raised. Mist keeps the job the layer table gives it —
   the space between cards — and now appears only where there is genuinely a
   gap rather than as the paper the whole page is printed on.

   Written on body rather than into .on-light because .on-light is the shared
   contract every component is coded against, and a card that lands inside a
   dark band must still resolve the app's own ladder.
   -------------------------------------------------------------------------- */

body.on-light {
  --ground:  var(--light-surface);   /* paper — the page carries body copy */
  --surface: var(--light-raised);    /* white — a card steps up one from it */
}

/* Setting a ground context also sets the text colour, so a component never
   has to restate it. */
.on-light,
.on-dark { color: var(--text-1); }

.on-dark {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

p { margin: 0; text-wrap: pretty; }
p + p { margin-top: var(--space-4); }

ul { margin: 0; padding: 0; list-style: none; }

svg { display: block; }

a { color: inherit; }

::selection {
  background-color: var(--text-1);
  color: var(--ground);
}

/* --------------------------------------------------------------------------
   Focus. One ring, both grounds. --text-1 is paper on dark and aubergine
   on light, so the ring always opposes whatever it sits on.
   -------------------------------------------------------------------------- */

:focus-visible {
  outline: var(--focus-w) solid var(--text-1);
  outline-offset: var(--space-1);
}

/* --------------------------------------------------------------------------
   Layout
   -------------------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

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

/* Half a section gap each side, so two neighbouring sections sit exactly
   one --section-gap apart. Sections that carry their own background take
   the full gap, because that padding is then internal to a filled block. */
.section { padding-block: calc(var(--section-gap) / 2); }

/* The closing band is not in the shell. It is inset from the window by the
   same figure the hero clips to, and rounded by the same figure, so the page
   opens and closes on the identical shape: 16/24 below 1280 px and 32/64
   above. Nothing new is introduced — --hero-inset and --hero-round are the
   two values measured off the reference for the hero, and both are steps on
   the 4 pt scale. */
.close-section {
  padding-block: calc(var(--section-gap) / 2);
  padding-inline: var(--hero-inset);
}

.close-shell { width: 100%; }

/* --------------------------------------------------------------------------
   Typographic primitives
   -------------------------------------------------------------------------- */

.overline {
  margin: 0;
  font-family: var(--font-label);
  font-size: var(--step-overline);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--text-3);
}

.overline-warm { color: var(--warm); }

.lead {
  font-size: var(--step-lead);
  line-height: var(--leading-body);
  color: var(--text-2);
  max-width: calc(var(--measure) * 0.66);
}

.micro,
.meta {
  font-family: var(--font-label);
  font-size: var(--step-caption);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-overline);
  color: var(--text-3);
}

/* Every section opens the same way: one line of display serif, centred, with
   nothing beside it and a great deal of nothing above it.

   Two things changed here on 2026-08-21, both measured off the reference:

   1. One size for every section heading. The reference sets all seven of its
      section headings at the identical size and never varies one — the
      hierarchy is carried by the air around the line, not by making some
      headings smaller than others. --step-h1 rather than --step-h2 because
      --step-h2 tops out at 44 px, which reads as a subheading on a page whose
      hero sets at 84.
   2. The editorial rule above the title is gone. It was a hairline that ran
      the full 1280 px shell and it fenced every section into a box; the
      reference draws no rule anywhere on the page and lets the gap do it.
      The per-row rules inside .rows stay, because there they separate three
      numbered steps rather than announce a section.               */
.section-title {
  font-size: var(--step-h1);
  /* The lightest weight the display face carries — as the hero and the
     closing band already set it. At this size it holds. */
  font-weight: 300;
  line-height: var(--leading-tight);
  max-width: calc(var(--measure) * 0.62);
  margin-inline: auto;
  text-align: center;
}

.shell > .section-title,
.section-head { margin-bottom: var(--space-20); }

.section-head {
  display: grid;
  justify-items: center;
  gap: var(--space-5);
}

.section-lead {
  color: var(--text-2);
  font-size: var(--step-lead);
  max-width: calc(var(--measure) * 0.62);
  text-align: center;
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--button-height);
  padding-inline: var(--space-8);
  border-radius: var(--radius-full);
  background-color: var(--cta-fill);
  color: var(--cta-label);
  font-family: var(--font-body);
  font-size: var(--step-body);
  font-weight: 600;
  line-height: var(--leading-snug);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard);
}

.btn:hover {
  background-color: var(--cta-press);
  box-shadow: var(--elev-row);
}

.btn-sm {
  /* Smaller than the app's 52 pt button, but never below the tap floor. */
  min-height: var(--tap-target-min);
  padding-inline: var(--space-5);
  font-size: var(--step-small);
}

/* --------------------------------------------------------------------------
   The waitlist form

   Both instances sit on .on-dark ground — the hero and the closing band — so
   there is one set of colours here and no light variant. If a form is ever
   put on paper, that is the moment to write one, not now.

   tokens.css files --radius-md under "rows, inputs, image containers". The
   input takes --radius-full instead: it is not a standalone input, it is one
   half of an inline control pair whose other half is a pill, and a 20 px
   corner beside a 999 px one reads as a mistake. Both values are tokens.
   -------------------------------------------------------------------------- */

/* Both hosts centre their contents — .hero-copy and .close-inner are both
   text-align: center — so the form centres with them rather than sitting
   left inside a centred column. */
.waitlist {
  max-width: 34rem;
  margin-inline: auto;
}

.waitlist-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
}

.waitlist-input {
  flex: 1 1 15rem;
  min-width: 0;
  min-height: var(--button-height);
  padding-inline: var(--space-6);
  border: var(--hairline-w) solid var(--hairline);
  border-radius: var(--radius-full);
  /* Not a filled box. The ground shows through, so the field reads as an
     opening in the surface rather than a component sitting on top of it. */
  background-color: color-mix(in srgb, var(--text-1) 7%, transparent);
  color: var(--text-1);
  font-family: var(--font-body);
  font-size: var(--step-body);
  line-height: var(--leading-snug);
  transition: border-color var(--dur-fast) var(--ease-standard),
              background-color var(--dur-fast) var(--ease-standard);
}

.waitlist-input::placeholder {
  color: var(--text-3);
  opacity: 1;              /* Firefox dims placeholders again on top of ours. */
}

.waitlist-input:hover {
  border-color: color-mix(in srgb, var(--text-1) 34%, transparent);
}

/* The global :focus-visible outline already handles the ring. This only
   raises the fill so the focused field is legible against it. */
.waitlist-input:focus {
  background-color: color-mix(in srgb, var(--text-1) 12%, transparent);
  outline: none;
}

.waitlist-input:focus-visible {
  outline: var(--focus-w) solid var(--text-1);
  outline-offset: var(--space-1);
}

.waitlist .btn { flex: 0 0 auto; }

/* A form mid-flight must not accept a second submission, and must say so. */
.waitlist[data-state="sending"] .btn { opacity: 0.6; pointer-events: none; }
.waitlist[data-state="done"] .waitlist-row { display: none; }

.waitlist-note { margin-top: var(--space-4); }

/* Warm is the subject — the one thing asking for attention. A failed
   submission is exactly that, and it is the only place on this page where
   the accent carries a message rather than a mood. */
.waitlist-note[data-tone="error"] { color: var(--warm-on-dark); }
.waitlist-note[data-tone="done"]  { color: var(--text-1); }

/* Off-screen rather than display:none: a honeypot that is not rendered is a
   honeypot a headless browser can see is a trap. aria-hidden and tabindex=-1
   in the markup keep it away from anyone using the page properly. */
.waitlist-trap {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Utilities
   -------------------------------------------------------------------------- */

/* Present to a screen reader, absent to the eye. Used for the form labels,
   whose text the placeholder repeats visually — a placeholder is not a label
   and disappears the moment someone types. */
.u-hidden-visually {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------------------
   Site header — a floating plate, centred, fixed.

   It is fixed rather than sticky because the hero below it is full bleed and
   starts at y = 0; a sticky bar would push it down. It is sized to its own
   contents (width: max-content) and centred, so the plate is exactly as wide
   as the links plus its own bleed.

   The header inherits body's .on-light ground, so its text, hairline and CTA
   all come from the light palette and it is legible on the page ground once
   the reader is past the hero.
   -------------------------------------------------------------------------- */

.site-head {
  position: fixed;
  top: var(--space-4);
  left: 50%;
  translate: -50% 0;
  z-index: 50;
  width: max-content;
  max-width: calc(100% - var(--space-8));
}

.head-nav {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

/* Everything except the plate is positioned, so it paints above the plate:
   among positioned siblings at z-index auto, DOM order decides, and the plate
   is written first. */
.head-nav > * { position: relative; }

/* The plate itself. Deliberately oversized, deliberately inert. */
.head-plate {
  position: absolute;
  top: calc(var(--pill-bleed) * -1);
  left: calc(var(--pill-bleed) * -1);
  width: calc(100% + var(--pill-bleed) * 2);
  height: calc(var(--tap-target-min) + var(--pill-bleed) * 2);
  border-radius: var(--radius-md);
  /* Warm, not stone. --panel-cream is the one warm surface in the token set;
     the alpha is ours, set by contrast rather than by the reference's 40%:
     this plate crosses a photograph, and --text-2 has to clear 4.5:1 over the
     darkest thing that can pass under it. */
  background-color: color-mix(in srgb, var(--panel-cream) 75%, transparent);
  border: var(--hairline-w) solid var(--hairline);
  -webkit-backdrop-filter: blur(var(--pill-blur));
          backdrop-filter: blur(var(--pill-blur));
  pointer-events: none;
}

.lockup {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--tap-target-min);
  padding-inline: var(--space-3);
  color: var(--text-1);
  text-decoration: none;
  transition: gap var(--dur-mid) var(--ease-staged);
}

.lockup-mark { display: block; height: var(--space-6); }
.lockup-mark svg { height: 100%; width: auto; }

/* The custom Laurels lettering is not a confirmed brand asset — Chris,
   2026-08-20 — so the name is set in the settled display face instead.
   Restoring the wordmark later is a one-element swap in index.html.

   It collapses out of the plate once the reader is well past the hero, so the
   plate narrows to a mark and the links. Width, not display: display: none
   cannot be transitioned, and the mark must not jump. */
.lockup-word {
  display: inline-block;
  max-width: 4.5em;
  overflow: hidden;
  white-space: nowrap;
  font-family: var(--font-display);
  font-size: var(--step-lead);
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--tracking-tight);
  transition: max-width var(--dur-mid) var(--ease-staged),
              opacity var(--dur-fast) var(--ease-standard);
}

/* Written by site.js at scrollY 400, removed again at 360 — a 40px deadband,
   so a reader parked on the boundary cannot make it flicker. */
.site-head.is-tight .lockup-word {
  max-width: 0;
  opacity: 0;
}

.site-head.is-tight .lockup { gap: 0; }

.head-link {
  display: none;
  align-items: center;
  min-height: var(--tap-target-min);
  padding-inline: var(--space-3);
  font-size: var(--step-small);
  color: var(--text-2);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-standard);
}

.head-link:hover {
  color: var(--text-1);
  text-decoration: underline;
  text-underline-offset: var(--space-1);
}

@media (min-width: 48rem) {
  .head-link { display: inline-flex; }
}

/* --------------------------------------------------------------------------
   Bands and their decorative layer.
   .band is the rounded full-bleed container. .row-media, .cell-dark and
   .statement share its atmosphere: a lifted corner, a top sheen, grain,
   and a vignette that pulls the edges back to the ground colour.
   -------------------------------------------------------------------------- */

.band,
.row-media,
.cell-dark,
.statement {
  position: relative;
  overflow: hidden;
  background-color: var(--ground);
  background-image:
    radial-gradient(125% 105% at 14% -5%, var(--surface) 0%, transparent 62%),
    linear-gradient(to bottom, var(--top-gradient) 0%, transparent 22%);
}

.band { border-radius: var(--radius-band); }

.band-fx {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
  overflow: hidden;
  pointer-events: none;
}

/* A field of fine hairlines — a fluted facade, not a pattern. Masked so it
   emerges in the lower half and never competes with the headline. */
.band-rules {
  position: absolute;
  inset: 0;
  display: block;
  background-image: repeating-linear-gradient(
    90deg,
    var(--hairline) 0 var(--hairline-w),
    transparent var(--hairline-w) var(--rule-pitch)
  );
  opacity: 0.62;
  /* Mask stops are alpha, not colour: currentColor simply means "opaque"
     here, and keeps this file free of literal colour values. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, currentColor 58%);
          mask-image: linear-gradient(to bottom, transparent 0%, currentColor 58%);
}

/* The symbol at building scale, cropped by the band edge. This is the
   page's substitute for photography. */
.band-mark {
  position: absolute;
  top: 50%;
  right: 0;
  display: block;
  width: var(--mark-size);
  translate: 26% -46%;
  color: var(--text-1);
  opacity: 0.07;
}

.band-mark svg { width: 100%; height: auto; }

.band-mark-close {
  top: auto;
  right: auto;
  left: 50%;
  bottom: 0;
  translate: -50% 42%;
  opacity: 0.06;
}

/* Vignette on the element, grain on its pseudo, so the two carry
   independent strengths. */
.band-noise {
  position: absolute;
  inset: 0;
  display: block;
  background-image: radial-gradient(
    120% 90% at 50% 18%,
    transparent 38%,
    var(--ground) 100%
  );
}

.band-noise::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--noise);
  background-repeat: repeat;
  opacity: 0.075;
}

/* --------------------------------------------------------------------------
   1 · Hero

   Full bleed. No shell, no container, no page margin: the hero is the window.
   The rounded inset card is not where it starts — it is where it arrives, 100
   px into the scroll, and getting there is the page's signature move.
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 100svh;
  /* Top padding clears the floating nav, so the copy is centred in the space
     actually left to it. The inline padding is deliberately tight at phone
     widths: every pixel taken here comes straight off the width the headline
     has to hold its first line in. */
  padding-block: calc(var(--head-h) + var(--space-8)) var(--space-16);
  padding-inline: var(--space-4);
  /* The ground the clip reveals at scroll 100. Inherited from body.on-light,
     so the margin that appears is the page itself and not a colour invented
     for the occasion. */
  background-color: var(--ground);
}

/* The clipped layer, and the only element on this page carrying a compositor
   hint. It never scales, translates or resizes — its box is the viewport at
   every scroll position, and only the clip changes, once. */
.hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  clip-path: inset(0);
  transition: clip-path var(--hero-clip-dur) var(--ease-staged);
  will-change: clip-path;
  contain: layout paint;
}

/* Written by site.js at scrollY 100 and removed below it. A class toggle, not
   a scrub: the value is identical at 400, 1000 and 4000. */
.hero.is-collapsed .hero-media {
  clip-path: inset(var(--hero-inset) round var(--hero-round));
}

/* Written against the two tags, not against a class on them, so replacing the
   placeholder <img> with the real <video> is a one-element change. */
.hero-media > img,
.hero-media > video {
  display: block;
  width: 100%;
  height: 100%;
  /* Upper centre: the subject sits in the top third of the frame, and a 4:5
     source cropped to a landscape window should lose the bottom, not the
     head. */
  object-fit: cover;
  object-position: 50% 28%;
}

/* The drawn field, standing in the same box the media occupies. It is a
   sibling of the <img>/<video> selector above rather than a case of it, so
   the day real footage lands this block is deleted and nothing else moves.

   Two light sources on the aubergine ground: a warm one high and centred,
   where the subject of the photograph would be lit, and a cool one low and
   left for the depth the warm one cannot give on its own. Warm is the
   subject and cool is what is already earned — tokens.css, and the same
   division the rest of the page uses. Percentages are positions in the
   frame, not measurements, so they take no token. */
.hero-field {
  position: absolute;
  inset: 0;
  background-color: var(--dark-ground);
  background-image:
    radial-gradient(58% 46% at 50% 26%,
      color-mix(in srgb, var(--warm-on-dark) 38%, transparent) 0%,
      color-mix(in srgb, var(--warm-on-dark) 12%, transparent) 42%,
      transparent 74%),
    radial-gradient(64% 58% at 14% 88%,
      color-mix(in srgb, var(--cool-on-dark) 26%, transparent) 0%,
      transparent 68%),
    radial-gradient(90% 70% at 82% 74%,
      color-mix(in srgb, var(--dark-raised) 80%, transparent) 0%,
      transparent 70%),
    linear-gradient(168deg,
      var(--dark-surface) 0%,
      var(--dark-ground) 58%);
}

/* Architectural scale: the mark is wider than the window and is cropped by
   it on both sides, which is what stops it reading as a logo. It sits low
   and right so the headline — upper left in the copy block — never has to
   compete with the join between the two strokes. */
.hero-glyph {
  position: absolute;
  left: 50%;
  top: 52%;
  width: clamp(30rem, 92vw, 78rem);
  height: auto;
  transform: translate(-38%, -46%) rotate(-8deg);
  color: var(--on-dark-1);
  opacity: 0.07;
  transform-origin: 50% 50%;
}

/* Portrait windows have no room for the mark beside the headline, so it
   drops behind it and loses the rotation that would push a stroke through
   the text. */
@media (max-width: 47.9375rem) {
  .hero-glyph {
    top: 68%;
    transform: translate(-46%, -40%) rotate(0deg);
    opacity: 0.05;
  }
}

/* Same construction as .band-noise: a vignette pulling the frame edges back to
   the dark ground, grain on the pseudo so the two carry independent strengths,
   and a vertical wash that buys the headline its contrast without flattening
   the photograph. .hero-media is .on-dark, so --ground here is aubergine even
   though the section around it is on light. */
.hero-scrim {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(
      to bottom,
      color-mix(in srgb, var(--ground) 44%, transparent) 0%,
      color-mix(in srgb, var(--ground) 24%, transparent) 34%,
      color-mix(in srgb, var(--ground) 74%, transparent) 100%
    ),
    radial-gradient(120% 95% at 50% 16%, transparent 30%, var(--ground) 100%);
}

.hero-scrim::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--noise);
  background-repeat: repeat;
  opacity: 0.075;
}

.hero-inner {
  position: relative;
  z-index: 1;
}

/* Wide enough that the display serif holds the headline's first line without
   wrapping at every width between 360 and 1440. The prose inside it keeps its
   own, much narrower measure. */
.hero-copy {
  max-width: min(100%, calc(var(--measure) * 2.1));
  margin-inline: auto;
  text-align: center;
}

.hero-copy h1 {
  font-size: var(--step-hero);
  /* The lightest weight the display face carries, and at this size it holds. */
  font-weight: 300;
  line-height: var(--leading-hero);
  letter-spacing: var(--tracking-tight);
  /* The break is written into the markup and --step-hero is sized so neither
     line has to wrap. `balance` rather than `nowrap` on purpose: if a fallback
     face sets wider than expected, a third line is a graceful failure and a
     line cut off at the viewport edge is not. */
  text-wrap: balance;
}

/* Italic marks the turn in the sentence, never decoration. It appears at most
   twice on the whole page. */
.hero-copy h1 em {
  font-style: italic;
  font-weight: inherit;
}

.hero-copy .lead {
  margin-top: var(--space-6);
  margin-inline: auto;
}

.hero-action { margin-top: var(--space-8); }

.hero-copy .micro {
  display: inline-block;
  margin-top: var(--space-10);
  padding-top: var(--space-4);
  border-top: var(--hairline-w) solid var(--hairline);
}

/* The reference site has no reduced-motion handling at all. Here the clip has
   no transition and no scroll dependency: the collapsed state is simply the
   resting state, applied statically, whatever site.js does with the class.
   tokens.json motion.rules.reduce-motion — "nothing travels, nothing is
   staged" — and a 1000ms clip is both. */
@media (prefers-reduced-motion: reduce) {
  .hero-media {
    clip-path: inset(var(--hero-inset) round var(--hero-round)) !important;
    will-change: auto;
  }
}

/* Above 1280px the inset doubles and the radius doubles with it. Both figures
   are measured; both are steps on the 4pt scale. The nav plate takes its wider
   bleed at the same breakpoint, as the reference does. */
@media (min-width: 80rem) {
  :root {
    --hero-inset: var(--space-8);
    --hero-round: var(--space-16);
    --pill-bleed: calc(var(--space-3) / 2);
  }
}

/* --------------------------------------------------------------------------
   The deck — the page's signature object.

   All three cards occupy one grid cell, so they share a height and read as
   a single stack. Each layer sets five custom properties which one shared
   transform consumes. The motion pass drives these; it never has to
   rewrite the transform itself.

       --card-x        horizontal offset
       --card-y        vertical offset (negative = further up the fan)
       --card-rot      rotation
       --card-scale    uniform scale
       --card-opacity  dimming of the layers behind

   transform-origin is the bottom edge, so rotation fans rather than
   pivots about the middle.
   -------------------------------------------------------------------------- */

.deck {
  display: grid;
  /* The deck used to be the right column of the hero grid and took its width
     from it. Standing alone it needs its own measure: a quest is one short
     paragraph and must not be set across a 1280px shell. */
  width: min(100%, calc(var(--measure) * 1.05));
  margin-inline: auto;
  /* Padding gives the transformed layers room. Symmetric now — the fan goes
     up and to the right, and there is ground on both sides of it. */
  padding: var(--space-10) var(--space-6) var(--space-2);
}

.deck > .quest-card { grid-area: 1 / 1; }

.quest-card {
  --card-x: 0px;
  --card-y: 0px;
  --card-rot: 0deg;
  --card-scale: 1;
  --card-opacity: 1;

  position: relative;
  padding: clamp(var(--card-padding), 2.4vw, var(--space-8));
  border-radius: var(--radius-lg);
  background-color: var(--surface);
  background-image: linear-gradient(to bottom, var(--top-gradient) 0%, transparent 34%);
  box-shadow: var(--elev-card);
  transform-origin: 50% 100%;
  transform:
    translate(var(--card-x), var(--card-y))
    rotate(var(--card-rot))
    scale(var(--card-scale));
  opacity: var(--card-opacity);
}

.deck-front {
  --card-rot: -1.25deg;
  z-index: 3;
  box-shadow: var(--elev-float);
}

.deck-mid {
  --card-x: var(--space-2);
  --card-y: calc(var(--space-3) * -1);
  --card-rot: 1.25deg;
  --card-scale: 0.965;
  --card-opacity: 0.85;
  z-index: 2;
}

.deck-back {
  --card-x: var(--space-4);
  --card-y: calc(var(--space-6) * -1);
  --card-rot: 3.25deg;
  --card-scale: 0.93;
  --card-opacity: 0.62;
  z-index: 1;
}

.quest-body {
  margin-top: var(--space-4);
  font-family: var(--font-display);
  font-size: var(--step-lead);
  line-height: var(--leading-body);
  color: var(--text-1);
}

.quest-foot {
  margin-top: var(--space-5);
  padding-top: var(--space-3);
  border-top: var(--hairline-w) solid var(--hairline);
  font-family: var(--font-label);
  font-size: var(--step-overline);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--text-3);
}

@media (min-width: 60rem) {
  .deck { padding: var(--space-16) var(--space-12) var(--space-6); }
  .deck-front { --card-rot: -2deg; }
  .deck-mid {
    --card-x: var(--space-6);
    --card-y: calc(var(--space-6) * -1);
    --card-rot: 2.25deg;
    --card-scale: 0.95;
    --card-opacity: 0.82;
  }
  .deck-back {
    --card-x: var(--space-12);
    --card-y: calc(var(--space-12) * -1);
    --card-rot: 5.25deg;
    --card-scale: 0.9;
    --card-opacity: 0.58;
  }
}

/* --------------------------------------------------------------------------
   2 · How a week works — the feature rows
   -------------------------------------------------------------------------- */

.rows {
  display: grid;
  /* Wider than the old clamp(64px, 8vw, 80px), because the hairline that used
     to divide the rows has gone and the gap is now the only thing doing it. */
  gap: clamp(var(--space-20), 10vw, calc(var(--space-20) * 1.6));
  counter-reset: row;
}

/* No rule. Each row carried a full-shell hairline across its top until
   2026-08-21, which rhymed with the identical hairline above the section
   title. That one went when the title was centred, and this one was left
   underlining a centred heading it had nothing to do with. The numbers carry
   the sequence, and the gap above carries the separation. */
.row {
  counter-increment: row;
  display: grid;
  gap: var(--space-8);
  align-items: center;
}

.row-copy::before {
  content: counter(row, decimal-leading-zero);
  display: block;
  margin-bottom: var(--space-5);
  font-family: var(--font-label);
  font-size: var(--step-overline);
  letter-spacing: var(--tracking-overline);
  color: var(--text-3);
}

.row-copy h3 { font-size: var(--step-h3); }

.row-copy p {
  margin-top: var(--space-4);
  color: var(--text-2);
  max-width: calc(var(--measure) * 0.72);
}

@media (min-width: 60rem) {
  .row {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
    gap: var(--space-12);
  }

  /* The flip reorders the two children but not the track sizes, so until
     2026-08-21 the flipped row put its panel in the 1fr column and its copy
     in the 1.4fr one: 487 px of panel against 681 px in the rows either side
     of it. The panel is the constant. Reverse the tracks with the order. */
  .row-flip { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); }
  .row-flip .row-copy { order: 2; }
  .row-flip .row-media { order: 1; }
}

/* --- the dark media panels ------------------------------------------------ */

.row-media {
  display: grid;
  place-items: center;
  min-height: var(--media-h);
  padding: clamp(var(--space-6), 4vw, var(--space-12));
  border-radius: var(--radius-lg);
}

.row-media > *:not(.band-fx) {
  position: relative;
  z-index: 1;
}

/* Two options at comparable stretch: identical frames, identical glyph
   size and weight. Only the hue differs. */
.opt-pair {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(var(--space-4), 3vw, var(--space-10));
}

.opt {
  display: grid;
  place-items: center;
  padding: clamp(var(--space-4), 2vw, var(--space-6));
  border: var(--hairline-w) solid var(--hairline);
  border-radius: var(--radius-md);
}

.opt-glyph {
  display: block;
  width: clamp(var(--space-16), 15vw, calc(var(--space-20) * 1.6));
}

.opt-glyph svg { width: 100%; height: auto; }

.opt-cool { color: var(--cool); }
.opt-warm { color: var(--warm); }

/* --- the committed day ---------------------------------------------------- */

.cal {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--space-2);
  width: var(--media-inner-w);
}

.cal > span {
  aspect-ratio: 1;
  border-radius: var(--radius-sm);
  background-color: var(--surface);
  border: var(--hairline-w) solid var(--hairline);
}

.cal .cal-on {
  background-color: var(--warm-fill);
  border-color: var(--warm-fill);
}

/* --- the chronicle pages -------------------------------------------------- */

.pages {
  position: relative;
  width: var(--media-inner-w);
  aspect-ratio: 5 / 4;
  margin-top: var(--space-8);
}

.page {
  position: absolute;
  inset: 0;
  display: block;
  border-radius: var(--radius-md);
  background-color: var(--surface);
  border: var(--hairline-w) solid var(--hairline);
  transform-origin: 50% 100%;
}

.page-1 { transform: translate(3%, -4%) rotate(-1.5deg) scale(0.985); opacity: 0.8; }
.page-2 { transform: translate(6%, -8%) rotate(-3deg) scale(0.97); opacity: 0.62; }
.page-3 { transform: translate(9%, -12%) rotate(-4.5deg) scale(0.955); opacity: 0.46; }
.page-4 { transform: translate(12%, -16%) rotate(-6deg) scale(0.94); opacity: 0.32; }

.page-0 {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-5);
  background-color: var(--raised);
  background-image: linear-gradient(to bottom, var(--top-gradient) 0%, transparent 40%);
  box-shadow: var(--elev-card);
}

/* Ruled lines under the marks — a ledger, drawn with gradients. */
.page-0::after {
  content: "";
  position: absolute;
  left: var(--space-5);
  right: var(--space-5);
  top: calc(var(--space-5) + var(--icon-md) + var(--space-5));
  height: calc(var(--space-4) * 4);
  background-image: repeating-linear-gradient(
    to bottom,
    var(--hairline) 0 var(--hairline-w),
    transparent var(--hairline-w) var(--space-4)
  );
  -webkit-mask-image: linear-gradient(to right, currentColor 52%, transparent 88%);
          mask-image: linear-gradient(to right, currentColor 52%, transparent 88%);
}

/* Three outcomes, three shapes. Identical boxes so nothing reads as
   louder than the others; shape alone carries the distinction. */
.mk {
  flex: none;
  width: var(--icon-md);
  height: var(--icon-md);
}

.mk-fill {
  border-radius: var(--radius-full);
  background-color: var(--cool);
}

.mk-ring {
  border-radius: var(--radius-full);
  border: calc(var(--icon-xl-stroke) * 1px) solid var(--text-2);
}

.mk-dash {
  background-image: linear-gradient(var(--text-2), var(--text-2));
  background-repeat: no-repeat;
  background-position: center;
  background-size: 100% calc(var(--icon-xl-stroke) * 1px);
}

/* --------------------------------------------------------------------------
   3 · The statement
   -------------------------------------------------------------------------- */

/* Inset and rounded on the same two figures as the hero and the closing band.
   The page now carries exactly one full-width shape — a dark or photographic
   block held --hero-inset off the window and rounded by --hero-round — and it
   uses it three times: to open, to turn, and to close. It was full bleed with
   square corners until 2026-08-21, which read as a different system from the
   two bands either side of it. */
.statement {
  margin-inline: var(--hero-inset);
  border-radius: var(--hero-round);
  padding-block: var(--section-gap);
}

/* The rules run the other way here — this block is the width of the window
   rather than a card in a column, so they read as a horizon rather than a
   plinth. */
.statement .band-rules {
  opacity: 0.5;
  -webkit-mask-image: linear-gradient(to right, currentColor 0%, transparent 72%);
          mask-image: linear-gradient(to right, currentColor 0%, transparent 72%);
}

.statement-inner {
  position: relative;
  z-index: 1;
  display: grid;
  gap: var(--space-12);
}

.figure-line {
  font-size: var(--step-figure);
  font-weight: 300;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

/* The one warm mark on the page that is not an in-app object: this is the
   thing asking for attention. */
.figure-line::before {
  content: "";
  display: block;
  width: var(--space-16);
  height: calc(var(--icon-xl-stroke) * 1px);
  margin-bottom: var(--space-8);
  background-color: var(--warm);
}

.statement-note {
  color: var(--text-2);
  font-size: var(--step-lead);
  border-top: var(--hairline-w) solid var(--hairline);
  padding-top: var(--space-6);
  max-width: calc(var(--measure) * 0.62);
}

@media (min-width: 60rem) {
  .statement-inner { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .figure-line { grid-column: 1 / 11; }
  .statement-note { grid-column: 7 / 13; }
}

/* --------------------------------------------------------------------------
   4 · The domains — bento
   -------------------------------------------------------------------------- */

.bento {
  display: grid;
  gap: var(--space-6);
}

.cell {
  padding: clamp(var(--space-5), 3vw, var(--space-8));
  border-radius: var(--radius-lg);
}

/* A frame, not a card. Ten outlined words are a list, and once the page
   itself became paper a filled cell here would have made three of the four
   bento cells solid blocks with a fourth solid block behind them. The
   hairline says "these belong together" and costs nothing. */
.cell-domains {
  display: grid;
  align-content: center;
  border: var(--hairline-w) solid var(--hairline);
  border-radius: var(--radius-lg);
  min-height: calc(var(--space-20) * 3);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.chip {
  display: inline-flex;
  align-items: center;
  padding: var(--space-2) var(--space-4);
  border: var(--hairline-w) solid var(--hairline);
  border-radius: var(--radius-full);
  font-family: var(--font-label);
  font-size: var(--step-caption);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--text-1);
}

/* --- the chronicle entry -------------------------------------------------- */

.cell-entry {
  display: flex;
  flex-direction: column;
  background-color: var(--raised);
  background-image: linear-gradient(to bottom, var(--top-gradient) 0%, transparent 30%);
  box-shadow: var(--elev-card);
}

.entry-body {
  margin-top: var(--space-4);
  font-family: var(--font-display);
  font-size: var(--step-lead);
  line-height: var(--leading-body);
  color: var(--text-1);
}

.entry-foot {
  margin-top: auto;
  padding-top: var(--space-5);
  border-top: var(--hairline-w) solid var(--hairline);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
}

.entry-body { margin-bottom: var(--space-8); }

/* Cool, because this is already earned. Warm belongs to the live subject. */
.state {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-3);
  border: var(--hairline-w) solid var(--cool);
  border-radius: var(--radius-full);
  font-family: var(--font-label);
  font-size: var(--step-overline);
  letter-spacing: var(--tracking-overline);
  text-transform: uppercase;
  color: var(--cool);
}

/* --- the dark cells ------------------------------------------------------- */

.cell-dark { border-radius: var(--radius-lg); }

.cell-body {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.cell-body h3 { font-size: var(--step-h3); }

.cell-body p {
  margin-top: var(--space-4);
  color: var(--text-2);
  font-size: var(--step-small);
}

/* A trajectory, not data. Cool: it is the record of what is done. */
.spark {
  width: 100%;
  max-width: calc(var(--space-20) * 2);
  height: auto;
  /* Pushed to the foot of the cell rather than sitting one gap under the
     prose: the two dark cells share a height, and with the line floating in
     the middle the pair read as two boxes with a void under the text. */
  margin-top: auto;
  padding-top: var(--space-8);
  color: var(--cool);
}

@media (min-width: 48rem) {
  .bento { grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr); }
}

/* Section 5, "Why this shape", was cut from the markup on 2026-08-21 (see
   91cfe49 — the page had been arguing a case it had already demonstrated
   three times). Its .cols / .col / .glyph rules outlived it by one commit and
   are removed here; nothing in index.html carries any of them. */

/* --------------------------------------------------------------------------
   6 · Questions
   The markup uses <details>/<summary>, so open state is native and the
   answers stay in the DOM. Nothing here sets display on .faq-a.

   Three hairline-separated rows on a tinted full-bleed band until 2026-08-21.
   Now three cards with a gap between them, which is both what the reference
   does and what the layer table requires once the page itself is paper: a
   question is body content, body content sits on a surface, and a surface on
   a paper page is a card. The band went with it — a second light value
   behind the cards was doing nothing the cards were not already doing.
   -------------------------------------------------------------------------- */

.faq {
  display: grid;
  gap: var(--space-2);
}

.faq-item {
  background-color: var(--surface);
  border-radius: var(--radius-md);
  box-shadow: var(--elev-row);
}

.faq-item > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  min-height: var(--tap-target-min);
  padding: var(--space-5) var(--space-6);
  cursor: pointer;
  list-style: none;
}

.faq-item > summary::-webkit-details-marker { display: none; }
.faq-item > summary::marker { content: ""; }

/* Serif, per the settled visual direction — "serif titles and numerals
   against system sans" — but at --step-lead rather than --step-h3. Inside a
   card, 26 px competed with the section heading above it; the reference sets
   its questions at 17. */
.faq-q {
  font-family: var(--font-display);
  font-size: var(--step-lead);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  color: var(--text-1);
}

.faq-item > summary:hover .faq-mark { color: var(--text-1); }

/* + becomes − by rotating the upright bar flat. */
.faq-mark {
  position: relative;
  flex: none;
  width: var(--icon-md);
  height: var(--icon-md);
  color: var(--text-2);
  transition: color var(--dur-fast) var(--ease-standard);
}

.faq-mark::before,
.faq-mark::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto;
  height: calc(var(--icon-lg-stroke) * 1px);
  margin-top: calc(var(--icon-lg-stroke) * -0.5px);
  border-radius: var(--radius-full);
  background-color: currentColor;
  transition: transform var(--dur-fast) var(--ease-standard);
}

.faq-mark::after { transform: rotate(90deg); }

.faq-item[open] .faq-mark::after { transform: rotate(0deg); }

.faq-a {
  padding: 0 var(--space-8) var(--space-6) var(--space-6);
  color: var(--text-2);
  max-width: var(--measure);
}

/* --------------------------------------------------------------------------
   7 · Closing band
   -------------------------------------------------------------------------- */

.close-band {
  border-radius: var(--hero-round);
  padding: var(--space-16) var(--space-6);
  background-image:
    radial-gradient(125% 105% at 86% -5%, var(--surface) 0%, transparent 62%),
    linear-gradient(to bottom, var(--top-gradient) 0%, transparent 22%);
}

.close-inner {
  position: relative;
  z-index: 1;
  /* Wide enough that the display serif sets the headline on two lines, not
     four. `ch` here is measured in the body sans, so this is roughly 700px —
     the h2 above it runs at --step-h1, which is far wider per character. */
  max-width: calc(var(--measure) * 1.3);
  margin-inline: auto;
  text-align: center;
}

.close-inner h2 {
  font-size: var(--step-h1);
  font-weight: 300;
  line-height: var(--leading-tight);
  /* Even the two lines, rather than leaving a three-word orphan. */
  text-wrap: balance;
}

.close-inner .lead {
  margin-top: var(--space-6);
  margin-inline: auto;
  /* The headline may run wide; the prose under it must not. */
  max-width: calc(var(--measure) * 0.62);
}

.close-action { margin-top: var(--space-10); }

@media (min-width: 60rem) {
  .close-band { padding: var(--space-20) var(--space-16); }
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.site-foot {
  /* No bottom padding: the last thing in here is the signature, and it is
     supposed to be cut off by the end of the page. */
  padding-block: var(--space-20) 0;
  border-top: var(--hairline-w) solid var(--hairline);
}

.foot-grid {
  display: grid;
  gap: var(--space-12);
}

.foot-word {
  display: block;
  color: var(--text-1);
  font-family: var(--font-display);
  font-size: var(--step-h2);
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--tracking-tight);
}

.foot-line {
  margin-top: var(--space-5);
  color: var(--text-2);
  font-size: var(--step-small);
  max-width: calc(var(--measure) * 0.5);
}

.foot-col {
  display: flex;
  flex-direction: column;
}

.foot-col .overline { margin-bottom: var(--space-2); }

.foot-col a {
  display: flex;
  align-items: center;
  min-height: var(--tap-target-min);
  font-size: var(--step-small);
  color: var(--text-2);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-standard);
}

.foot-col a:hover {
  color: var(--text-1);
  text-decoration: underline;
  text-underline-offset: var(--space-1);
}

/* The page ends on its own name at architectural scale, running past both
   edges of the window and cut off by the bottom of the document — the same
   device the .band-mark uses inside the two dark bands, at the same opacity,
   so this is the mark's treatment applied to the word rather than a new one.

   Set in the display face, not the wordmark asset: the custom lettering
   renders as LAJRELS at logo size and is unconfirmed (decisions/0104).

   The crop is the point, so the word is deliberately wider than the window
   and the footer carries no bottom padding under it. Presentational, and
   hidden from the accessibility tree — the name is already the first link on
   the page and the last line of the footer. */
.foot-signature {
  margin-top: var(--space-12);
  overflow: hidden;
  line-height: 0;
}

.foot-signature span {
  display: block;
  /* Crops roughly the lower fifth of the letterforms against the page edge.
     "Laurels" has no descender, so without this the word simply sits on the
     bottom of the page rather than running off it. */
  margin-block-end: -0.11em;
  font-family: var(--font-display);
  /* Floored so a small phone still gets an architectural moment rather than a
     94 px word, and capped so a very wide window does not turn it into a
     texture. Between them it is simply 24vw. */
  font-size: clamp(7rem, 24vw, 26rem);
  font-weight: 300;
  line-height: 0.80;
  letter-spacing: var(--tracking-tight);
  text-align: center;
  white-space: nowrap;
  color: var(--text-1);
  opacity: 0.07;
  -webkit-user-select: none;
          user-select: none;
}

.foot-bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-3) var(--space-6);
  margin-top: var(--space-16);
  padding-top: var(--space-5);
  border-top: var(--hairline-w) solid var(--hairline);
  font-family: var(--font-label);
  font-size: var(--step-caption);
  letter-spacing: var(--tracking-overline);
  color: var(--text-3);
}

@media (min-width: 48rem) {
  .foot-grid {
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-10);
  }
}

/* --------------------------------------------------------------------------
   Wide viewports — a little more air where there is room for it
   -------------------------------------------------------------------------- */

@media (min-width: 80rem) {
  .close-band { padding-inline: var(--space-20); }
  .bento { gap: var(--space-8); }
}

/* --------------------------------------------------------------------------
   Preferences
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
  }
}

@media (prefers-contrast: more) {
  .on-light,
  .on-dark {
    --text-2: var(--text-1);
    --hairline: var(--text-3);
  }

  .band-rules,
  .band-mark,
  .foot-signature span { opacity: 0; }

  .band-noise::before { opacity: 0; }

  .deck-mid,
  .deck-back { --card-opacity: 1; }

  .page-1 { opacity: 0.9; }
  .page-2 { opacity: 0.8; }
  .page-3 { opacity: 0.7; }
  .page-4 { opacity: 0.6; }

  .head-link,
  .foot-col a { text-decoration: underline; }
}

/* --------------------------------------------------------------------------
   Prose pages

   /privacy and anything that follows it. The landing page is composed; these
   are read, so they get one column at the measure and nothing else. No new
   values: --measure, the type scale and the space scale all come from
   tokens.css exactly as the sections above use them.
   -------------------------------------------------------------------------- */

.prose-page {
  padding-block: calc(var(--head-h) + var(--space-16)) var(--space-16);
}

.prose {
  max-width: calc(var(--measure) * 1.05);
  margin-inline: auto;
}

.prose h1 {
  font-size: var(--step-h1);
  margin-bottom: var(--space-4);
}

.prose h2 {
  font-size: var(--step-h3);
  margin-top: var(--space-12);
  margin-bottom: var(--space-4);
}

.prose p,
.prose li {
  font-size: var(--step-body);
  line-height: var(--leading-body);
  color: var(--text-2);
}

.prose li + li { margin-top: var(--space-2); }

.prose ul {
  margin-top: var(--space-4);
  padding-left: var(--space-5);
  list-style: disc;
}

.prose a {
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: from-font;
}

/* The one place on the site that has to say a thing is missing rather than
   show it. Same posture as the app's disabled contact control — 0103. */
.prose .gap {
  margin-top: var(--space-8);
  padding: var(--space-5);
  border: var(--hairline-w) solid var(--hairline);
  border-radius: var(--radius-lg);
}

.prose .gap p { color: var(--text-1); }

.prose-updated {
  margin-top: var(--space-12);
  padding-top: var(--space-5);
  border-top: var(--hairline-w) solid var(--hairline);
}
