/* ==========================================================================
   The Planet of Yourself: one stylesheet for every page.

   Every page is a trip from the centre of the planet up to the surface, and
   the colour is the sky over one night: Core (night, the words are the only
   light) -> Mantle (nila, the deep blue before dawn) -> Crust (morning, where
   people can see you). "My eyes were open, but I saw the words. Everything
   around it, pitch black." A section says which layer it belongs to with
   .layer-core, .layer-mantle or .layer-crust, and everything inside it picks
   up the right text, accent, rule and button colours from that.

   The colours below are the whole palette. Don't add others.
   ========================================================================== */

:root {
  /* Core: the night */
  --night:        #070A1C;  /* page background at the top: blue-black, never pure black */
  --night-2:      #0F1433;
  --pitch-black:  #020308;  /* the author page's pitch black: darker than the night, never pure black */  /* panels on the night (menus, the signup gate) */
  --sky:          #A9BEFF;  /* the accent on dark: links, buttons, the core's heat */
  --white-hot:    #F4F7FF;  /* only at the centre of the core graphic */

  /* Mantle: nila, the blue hour */
  --nila:         #16207A;  /* the mantle's ground, and the accent on light */
  --nila-lit:     #3040C8;  /* the mantle as a rock band (planet, strata, folio) */

  /* Crust: morning */
  --morning:      #E9ECF4;  /* the light background at the surface */
  --ink:          #0A0E24;  /* text on light */

  /* Rules and borders */
  --rule-dark:    #262C55;  /* on the night */
  --rule-nila:    #3A46A6;  /* on nila */
  --rule-light:   #C2C7D8;  /* on morning */

  /* Text on dark */
  --text-on-dark: #F0F0EC;
  --muted-on-dark:#A7ACC8;

  --font-display: 'Archivo', 'Arial Narrow', Arial, sans-serif;
  --font-read: 'Literata', Georgia, 'Times New Roman', serif;

  --step-0: clamp(1.125rem, 1.06rem + 0.28vw, 1.25rem);   /* body, 18 to 20px */
  --step-read: clamp(1.125rem, 1rem + 0.6vw, 1.25rem);    /* long-form, 20px on desktop */
  --space-section: clamp(64px, 8.5vw, 128px);
  --gutter: clamp(16px, 4vw, 48px);
  --col-gap: clamp(16px, 2.2vw, 32px);
  --max: 1360px;
  --measure: 65ch;
  --radius: 2px;
}

/* ---------- Layers ---------------------------------------------------- */

.layer-core,
.layer-mantle {
  --fg: var(--text-on-dark);
  --muted: var(--muted-on-dark);
  --accent: var(--sky);
  --rule: var(--rule-dark);
  --line: var(--muted-on-dark);
  --btn-bg: var(--sky);
  --btn-fg: var(--night);
  --btn-hover: var(--text-on-dark);
  --focus: var(--sky);
  color: var(--fg);
}

.layer-core { --bg: var(--night); --panel: var(--night-2); background-color: var(--night); }
.layer-mantle { --bg: var(--nila); --panel: var(--night); --rule: var(--rule-nila); background-color: var(--nila); }

/* Sky fails contrast on morning, so at the surface the accent is nila itself. */
.layer-crust {
  --bg: var(--morning);
  --panel: var(--morning);
  --fg: var(--ink);
  --muted: var(--ink);
  --accent: var(--nila);
  --rule: var(--rule-light);
  --line: var(--ink);
  --btn-bg: var(--nila);
  --btn-fg: var(--morning);
  --btn-hover: var(--ink);
  --focus: var(--nila);
  color: var(--fg);
  background-color: var(--morning);
}

/* Temperature: words run on the core's heat scale. What external worth gave me runs cold:
   cold rock (--muted) sunk a quarter into the ground, 5.3:1 on night. Where worth is built runs
   hot, in the accent, once a screen at most. Everything else is the plain type colour. */
.cold { color: var(--muted); color: color-mix(in srgb, var(--muted) 75%, var(--bg)); }
.built { color: var(--accent); }

/* The only gradients on the site: the sky changing as you rise through the night.
   They hold no text, because halfway between night and morning no text colour
   reaches 4.5:1. */
.rise { height: clamp(200px, 42vh, 460px); }
.rise--short { height: clamp(96px, 16vh, 180px); }
.rise--core-mantle { background: linear-gradient(to bottom, var(--night), var(--nila)); }
.rise--mantle-crust { background: linear-gradient(to bottom, var(--nila), var(--morning)); }
.rise--core-crust { background: linear-gradient(to bottom, var(--night), var(--morning)); }
/* A mantle section straight after the core starts as night and turns to nila as you go down. */
.layer-mantle.from-core { background: linear-gradient(to bottom, var(--night), var(--nila) 360px); }

/* ---------- Base ------------------------------------------------------ */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--morning);
}

/* Loading. Each page's head marks it scripted (html.js) and booting before the first paint, and
   site.js lifts js-booting once the fonts are in and the held pieces have drawn their first frame.
   Until then those pieces are kept out of sight, so a refresh shows the page's ground and header,
   then the piece as it really starts, and never the unscripted layout for a moment first. */
html.js-booting [data-piece] { visibility: hidden; }
/* A held act's stage is the screen from the first paint, as the scroll engine will make it
   (scrollcraft.css .sc-stage), so what follows a held opening can't show under it before the
   engine has mounted. A piece that becomes a still loses data-sc-act, and this with it. Off
   while site.js measures whether each piece's words fit the screen (js-measuring), so a grid
   that fills its stage is measured by its words. */
html.js:not(.js-measuring) [data-sc-act="pin"] > [data-sc-stage] {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: clip;
}

/* The first pass (site.js, the pacer): the first time down after the page loads, the page is held
   in each piece until it has played. While held the hand can't scroll it (the script moves it, at
   the hand's pace, up to the piece's own); the scrollbar's room is kept so nothing shifts. */
html.first-pass-held {
  overflow: hidden;
  scrollbar-gutter: stable;
  scroll-behavior: auto;
  overscroll-behavior: none;
  touch-action: none;
}

body {
  margin: 0;
  font-family: var(--font-read);
  font-size: var(--step-0);
  line-height: 1.6;
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: var(--ink);
  background: var(--morning);
  overflow-x: clip;
}

body.page-core { background: var(--night); }
body.page-mantle { background: var(--nila); }

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

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 0.95;
  letter-spacing: 0;
  text-wrap: balance;
}

/* As written (2026-10-01). No type on this site is set in capitals: the user asked whether the
   all-capital type was the last AI tell, and it was a default, not a choice (it set every heading,
   button, label and set-piece word, with small labels spaced out wide). Words are set as written:
   sentences and labels in sentence case, names in their own case, capitals only where the story had
   them (the email's ERROR, .wrong-error). Large type tracks -0.012em, like the hero; small labels
   0.01em, a pixel larger than they were, since lowercase stands at its x-height. */
h1 {
  font-size: clamp(2.75rem, 8vw, 6.5rem);
  font-weight: 900;
  letter-spacing: -0.012em;
}

h2 {
  font-size: clamp(2.25rem, 5.4vw, 4.5rem);
  letter-spacing: -0.012em;
}

h3 {
  font-size: clamp(1.375rem, 1.1rem + 1vw, 1.875rem);
  font-weight: 700;
  font-stretch: 87.5%;
  line-height: 1.1;
}

p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

a { color: inherit; }

strong { font-weight: 600; }

::selection { background: var(--sky); color: var(--night); }

:focus-visible {
  outline: 2px solid var(--focus, var(--sky));
  outline-offset: 3px;
}

.visually-hidden,
.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: 8px;
  left: var(--gutter);
  z-index: 2000;
  padding: 12px 18px;
  background: var(--sky);
  color: var(--night);
  font-family: var(--font-display);
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  font-size: 0.9375rem;
  text-decoration: none;
  transform: translateY(-160%);
}
.skip-link:focus { transform: none; }
/* Where "Back to top" puts the keyboard: the page's start, not a control, so no ring. */
main[tabindex="-1"]:focus { outline: none; }

/* Back to top (site.js, section 8; 2026-10-06). Shown only once the reader is well down a long
   page and turns back up by hand; at the lower right, in words, the size of a small label but a
   full 44px to tap. A panel on the night, or the morning with an ink edge on crust pages, so it
   stands clear of whatever passes under it. It comes and goes quickly (UI motion: 200ms,
   ease-out, never from nothing). */
.to-top {
  position: fixed;
  right: max(16px, env(safe-area-inset-right));
  bottom: max(16px, env(safe-area-inset-bottom));
  z-index: 40;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 16px 0 14px;
  font-family: var(--font-display);
  font-weight: 700;
  font-stretch: 87.5%;
  font-size: 0.9375rem;
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--text-on-dark);
  background: var(--night-2);
  border: 1px solid var(--rule-dark);
  border-radius: var(--radius);
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translate3d(0, 8px, 0);
  transition: opacity 0.2s cubic-bezier(0.23, 1, 0.32, 1), transform 0.2s cubic-bezier(0.23, 1, 0.32, 1), visibility 0s linear 0.2s;
}
.to-top.is-shown {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}
.to-top svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: square; }
.to-top--crust { color: var(--ink); background: var(--morning); border-color: var(--ink); }
.to-top:focus-visible { outline: 2px solid var(--sky); outline-offset: 3px; }
.to-top--crust:focus-visible { outline-color: var(--nila); }
.to-top.is-shown:active { transform: translateY(1px); }
@media (hover: hover) and (pointer: fine) {
  .to-top:hover { border-color: var(--sky); }
  .to-top--crust:hover { color: var(--nila); border-color: var(--nila); }
}
@media (prefers-reduced-motion: reduce) {
  .to-top { transform: none; transition: none; }
}
@media print { .to-top { display: none; } }

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

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

.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap);
}

@media (min-width: 900px) {
  .span-main { grid-column: 2 / 9; }
  .span-read { grid-column: 2 / 10; }
  .span-wide { grid-column: 2 / 12; }
  .span-full { grid-column: 1 / -1; }
  .span-side { grid-column: 10 / 13; }
  .span-aside { grid-column: 2 / 5; }
  .span-rest { grid-column: 6 / 13; }
}

@media (max-width: 899px) {
  .grid { grid-template-columns: minmax(0, 1fr); }
}

.section { padding-block: var(--space-section); }
.section--tight { padding-block: clamp(56px, 7vw, 104px); }

.measure { max-width: var(--measure); }

/* ---------- Type helpers ---------------------------------------------- */

.label {
  display: block;
  margin: 0 0 16px;
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: 700;
  font-stretch: 87.5%;
  line-height: 1.3;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}

.label--quiet { color: var(--muted); font-weight: 600; }

.lead {
  font-size: clamp(1.1875rem, 1.05rem + 0.5vw, 1.4375rem);
  line-height: 1.5;
  max-width: 36em;
}

/* Smaller display size for headings that sit in a narrow column. */
.h2-compact { font-size: clamp(2rem, 1.3rem + 2.6vw, 3.5rem); }

.section-head { margin-bottom: clamp(40px, 5vw, 72px); }
.section-head h2 + p { margin-top: 24px; }
.section-head .label + h2 { margin-top: 0; }

/* The book is still being written: a cursor waits after the Mantle and Crust. */
.cursor {
  display: inline-block;
  margin-left: 0.3em;
  color: var(--accent);
  font-weight: 400;
  animation: cursor-blink 1.1s steps(1) infinite;
}
@keyframes cursor-blink { 50% { opacity: 0; } }

/* ---------- Links and buttons ---------------------------------------- */

/* Links inside running text are always underlined, so they never rely on colour. */
.prose a,
.inline-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  transition: text-decoration-thickness 0.2s ease;
}
.prose a:hover,
.inline-link:hover { text-decoration-thickness: 2px; text-decoration-color: currentColor; }

/* Standalone links and rows: an underline draws in from the left. */
.draw {
  position: relative;
  display: inline-block;
}
.draw::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.12em;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.2s ease-out;
}
a:hover .draw::after,
a:focus-visible .draw::after,
a.draw:hover::after,
a.draw:focus-visible::after,
summary:hover .draw::after,
.row:hover .draw::after,
.row:focus-within .draw::after {
  transform: scaleX(1);
}

.btn,
.formkit-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  min-height: 52px;
  padding: 0.95em 1.5em;
  border: 0;
  border-radius: var(--radius);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 700;
  font-stretch: 87.5%;
  line-height: 1;
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.btn:hover,
.formkit-submit:hover { background: var(--btn-hover); color: var(--btn-fg); }
.layer-crust .btn:hover,
.layer-crust .formkit-submit:hover { color: var(--morning); }

.link-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  min-height: 44px;
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  color: var(--fg);
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.4em;
  transition: text-decoration-color 0.2s ease;
}
.link-cta:hover { text-decoration-color: currentColor; }

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 32px;
  margin-top: clamp(32px, 4vw, 48px);
}

/* ---------- Header and navigation ------------------------------------- */

.site-header { position: relative; z-index: 50; }
/* Every page but the homepage (2026-10-05): the header comes back when the reader scrolls up,
   and goes again when they scroll down (site.js, section 7). It's sticky, so it never leaves a
   gap or moves the page; hidden, it slides up out of sight. Once the page has moved, a rule
   marks its edge. */
html.js .site-header[data-reveal] {
  position: sticky;
  top: 0;
  transition: transform 0.28s ease;
}
html.js .site-header[data-reveal].is-stuck { box-shadow: inset 0 -1px 0 var(--rule); }
html.js .site-header[data-reveal].is-hidden { transform: translateY(-100%); }
@media (prefers-reduced-motion: reduce) {
  html.js .site-header[data-reveal] { transition: none; }
}

.header-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 24px;
  min-height: 80px;
  padding-block: 12px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  color: var(--fg);
  text-decoration: none;
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 800;
  font-stretch: 75%;
  letter-spacing: 0.01em;
  line-height: 1;
}
.brand img { width: 40px; height: 40px; flex: none; }
/* The mark (2026-10-01): the cursor standing on the planet's rim. The tile is 1.56em, so its
   cursor is the site's own cursor at the name's size (0.78em, like .edge-cursor), and its foot
   (64% down the tile) stands on the name's baseline. */
.brand:has(> .brand-mark) { align-items: baseline; }
.brand .brand-mark { width: 1.56em; height: 1.56em; position: relative; top: 0.5616em; }
/* The name, one span per letter, each holding its place, so nothing shifts and no letter is
   ever cut. In the header it is simply there (the typing as the page opened was removed
   2026-10-06); only the footer lockup types it, under the reader's scroll. */
.brand-typed svg.brand-mark { display: inline-block; overflow: visible; }
.brand-type .bt-ch { display: inline-block; }
/* The narrowest phones: the wordmark and Menu stay on one line. */
@media (max-width: 379px) {
  .header-bar { column-gap: 12px; }
  .brand { gap: 10px; }
}

.nav-list {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav-trigger,
.nav-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 14px;
  border: 0;
  background: none;
  color: var(--fg);
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
}

.nav-trigger::after {
  content: "";
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
}
.nav-group.is-open .nav-trigger::after { transform: rotate(225deg); margin-top: 3px; }

.nav-link[aria-current="page"] .draw::after,
.nav-build a[aria-current="page"] .draw::after { transform: scaleX(1); }

.nav-group { position: relative; }

.nav-menu {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 60;
  min-width: 320px;
  margin: 0;
  padding: 8px 0;
  list-style: none;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.nav-group.is-open .nav-menu { display: block; }

.nav-menu a {
  display: block;
  padding: 12px 20px;
  color: var(--fg);
  text-decoration: none;
}

/* The menus have no box: the words themselves, large, in the display face. They open and close
   at once, with no animation. */
.nav-build {
  min-width: 0;
  padding: 10px 14px 24px;
  background: none;
  border: 0;
  border-radius: 0;
}
.nav-build::before {
  content: "";
  position: absolute;
  inset: -28px -80px -64px -48px;
  z-index: -1;
  background: radial-gradient(closest-side, var(--bg) 60%, transparent);
  pointer-events: none;
}
.nav-build a { display: block; padding: 4px 0; white-space: nowrap; }
.nb-word {
  font-family: var(--font-display);
  font-size: clamp(2rem, 1.3rem + 1.5vw, 2.875rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 1;
  letter-spacing: -0.012em;
}
.nb-word.draw::after { height: 2px; bottom: -0.04em; }
.nb-out { margin-left: 0.2em; font-size: 1.25rem; vertical-align: top; }

.menu-toggle {
  display: none;
  min-height: 44px;
  padding: 0 4px;
  border: 0;
  background: none;
  color: var(--fg);
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.4em;
  cursor: pointer;
}

@media (min-width: 821px) and (hover: hover) and (pointer: fine) {
  html:not(.js) .nav-group:hover .nav-menu { display: block; }
}

@media (max-width: 820px) {
  .menu-toggle { display: inline-flex; align-items: center; }
  .site-nav { display: none; flex-basis: 100%; }
  .site-nav.is-open { display: block; }
  .nav-list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 8px 0 20px;
    border-top: 1px solid var(--rule);
  }
  .nav-trigger,
  .nav-link { width: 100%; justify-content: space-between; padding: 0; min-height: 52px; font-size: 1rem; }
  .nav-menu {
    position: static;
    min-width: 0;
    padding: 0 0 12px;
    border: 0;
    background: none;
  }
  .nav-menu a { padding: 10px 0 10px 16px; border-left: 1px solid var(--rule); }
  .nav-build { padding: 2px 0 16px; }
  .nav-build::before { display: none; }
  .nav-build a { padding: 6px 0; border-left: 0; }
  .nb-word { font-size: 2rem; }
}

/* ---------- The folio (homepage) --------------------------------------- */
/* Chapter, layer and how far into the book, plus the reader's own strata: one band is laid down as each
   chapter is passed, and the Crust band is laid during the break. The bands are links
   to their chapters. Core sits at the bottom of the column; you read upward. */

.depth-gauge {
  --g-bg: var(--night);
  --g-fg: var(--text-on-dark);
  --g-muted: var(--muted-on-dark);
  --g-accent: var(--sky);
  --g-line: var(--rule-dark);
  --dg-pos: 1;
  position: fixed;
  z-index: 40;
  top: 50%;
  right: 20px;
  width: 104px;
  padding: 12px 12px 14px;
  transform: translateY(-50%);
  background: var(--g-bg);
  color: var(--g-fg);
  border: 1px solid var(--g-line);
  border-radius: var(--radius);
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  /* It changes as the page scrolls (the count, the marker, the bands): on a layer of its own,
     and laid out on its own, so none of that ever repaints or re-lays the page under it. */
  will-change: transform;
  contain: layout style;
}
.depth-gauge[data-tone="light"] {
  --g-bg: var(--morning);
  --g-fg: var(--ink);
  --g-muted: var(--ink);
  --g-accent: var(--nila);
  --g-line: var(--rule-light);
}

.dg-chapter,
.dg-unit,
.dg-band a {
  font-size: 0.8125rem;
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
}
.dg-chapter { display: flex; gap: 6px; color: var(--g-accent); white-space: nowrap; }
.dg-num { font-family: var(--font-read); font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--g-fg); }
.dg-num:empty { display: none; }
/* How far into the book: words into the draft, counting as you read. At the end of what's
   written, the cursor waits after the count. */
.dg-readout { margin-top: 6px; white-space: nowrap; }
.dg-count { font-size: 1.375rem; font-weight: 800; font-stretch: 75%; line-height: 1; }
.dg-readout .cursor { display: none; margin-left: 1px; font-size: 1.125rem; line-height: 1; color: var(--g-accent); }
.dg-readout.is-end .cursor { display: inline; }
.dg-unit { display: block; margin-top: 4px; color: var(--g-muted); }

.dg-column { position: relative; margin-top: 14px; }
.dg-strata { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; }

.dg-band--core { --band: var(--sky); --band-ink: var(--night); }
.dg-band--mantle { --band: var(--nila-lit); --band-ink: var(--text-on-dark); }
.dg-band--crust { --band: var(--morning); --band-ink: var(--ink); }

.dg-band a {
  position: relative;
  display: flex;
  align-items: flex-end;
  height: max(44px, 9vh);
  margin-top: -1px;
  padding: 6px 8px;
  border: 1px solid var(--g-line);
  color: var(--g-muted);
  font-size: 0.75rem;
  text-decoration: none;
  overflow: hidden;
  transition: color 0.2s ease-out, border-color 0.15s ease-out;
}
.dg-band:first-child a { margin-top: 0; }
.dg-name { position: relative; }
/* The rock itself. Laid from the bottom up, the way rock is laid down. */
.dg-fill {
  position: absolute;
  inset: 0;
  background: var(--band);
  will-change: transform;
  transform: scaleY(var(--lay, 0));
  transform-origin: 50% 100%;
  transition: transform 0.5s cubic-bezier(0.23, 1, 0.32, 1);
}
.dg-band.is-laid { --lay: 1; }
.dg-band.is-inked a { color: var(--band-ink); }
/* The Crust band is laid under the reader's hand, so it follows the scroll directly. */
.dg-band--crust .dg-fill { transition: none; }
.dg-band a:focus-visible { outline: 2px solid var(--g-accent); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .dg-band a:hover { border-color: var(--g-fg); }
}

/* At the break the column cracks first, then the crack runs out across the page. */
.dg-band--crust a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 7px;
  margin-top: -4px;
  background: var(--g-fg);
  clip-path: polygon(0 45%, 12% 15%, 25% 60%, 38% 20%, 52% 70%, 66% 25%, 80% 65%, 92% 30%, 100% 50%,
                     100% 80%, 92% 60%, 80% 95%, 66% 55%, 52% 100%, 38% 50%, 25% 90%, 12% 45%, 0 75%);
  transform: scaleX(0);
  transform-origin: 100% 50%;
  transition: transform 0.35s cubic-bezier(0.23, 1, 0.32, 1);
}
.depth-gauge.is-cracked .dg-band--crust a::after { transform: scaleX(1); }

.dg-marker {
  position: absolute;
  z-index: 1;
  left: -6px;
  top: 0;
  bottom: 0;
  width: 11px;
  pointer-events: none;
  /* A strip as tall as the column, slid down by how far through it the reading is (its own
     height is the column's, so 100% is the whole column). Moved, never laid out again. */
  transform: translate3d(0, calc(var(--dg-pos, 1) * 100%), 0);
  will-change: transform;
}
/* The mark itself, at the top of the strip. */
.dg-marker::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -1px;
  height: 3px;
  background: var(--g-accent);
}

/* On a phone the folio is a strip along the top: chapter, the three bands side by side
   (Core on the left, rising to the Crust on the right), and the depth. */
@media (max-width: 899px) {
  body.has-gauge { padding-top: 40px; }
  .chapter { scroll-margin-top: 40px; }
  .depth-gauge {
    top: 0;
    left: 0;
    right: 0;
    width: auto;
    height: 40px;
    padding: 0 var(--gutter);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    transform: none;
    border: 0;
    border-bottom: 1px solid var(--g-line);
    border-radius: 0;
  }
  .dg-head { display: contents; }
  .dg-chapter { order: 1; min-width: 5.5em; }
  .dg-column { order: 2; position: static; margin: 0; }
  .dg-readout { order: 3; display: flex; align-items: baseline; justify-content: flex-end; gap: 5px; margin: 0; min-width: 4.5em; }
  .dg-count { font-size: 1.125rem; }
  .dg-unit { margin: 0; }
  .dg-unit-tail { display: none; }
  .dg-strata { flex-direction: row-reverse; gap: 2px; }
  .dg-band a {
    width: 40px;
    height: 40px;
    margin: 0;
    padding: 0;
    border: 0;
  }
  .dg-band a::before {
    content: "";
    position: absolute;
    inset: 15px 0;
    border: 1px solid var(--g-line);
  }
  .dg-fill { inset: 15px 0; transform: scaleX(var(--lay, 0)); transform-origin: 0 50%; }
  .dg-name {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .dg-band a:focus-visible { outline-offset: -2px; }
  .dg-band--crust a::after { transform-origin: 0 50%; }
  .dg-marker {
    top: auto;
    left: 0;
    right: 0;
    bottom: -1px;
    width: auto;
    height: 2px;
    margin: 0;
    background: var(--g-accent);
    transform-origin: left center;
    transform: scaleX(calc(1 - var(--dg-pos, 1)));
  }
  .dg-marker::before { display: none; }
}

@media (min-width: 900px) {
  body.has-gauge .wrap { padding-right: max(var(--gutter), 150px); }
}

@media (prefers-reduced-motion: reduce) {
  .dg-fill,
  .dg-band--crust a::after { transition: none; }
}

/* ---------- Hero and the molten core ---------------------------------- */

.hero {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  min-height: min(88svh, 960px);
  padding-block: clamp(40px, 6vw, 96px) clamp(72px, 10vw, 144px);
}
.hero .wrap { position: relative; z-index: 1; }

.hero h1 .line { display: block; }

.year-line {
  margin-top: clamp(16px, 1.6vw, 24px);
  max-width: 34em;
  color: var(--muted);
}

.core {
  position: absolute;
  z-index: 0;
  top: 50%;
  right: 0;
  width: clamp(520px, 64vw, 1040px);
  aspect-ratio: 1;
  border-radius: 50%;
  transform: translate(50%, -50%);
  background: radial-gradient(closest-side,
    var(--white-hot) 0%,
    var(--sky) 40%,
    rgba(169, 190, 255, 0.32) 72%,
    rgba(169, 190, 255, 0) 100%);
  pointer-events: none;
}
.core::after {
  content: "";
  position: absolute;
  inset: 20%;
  border-radius: 50%;
  background: radial-gradient(closest-side, var(--white-hot), rgba(244, 247, 255, 0));
  opacity: 0.2;
  animation: core-heat 9s ease-in-out infinite alternate;
}
@keyframes core-heat {
  from { opacity: 0.1; }
  to { opacity: 0.75; }
}

/* As a still, the title page's signup sits straight under the line about Dear 15, in the
   heading's column and as wide as its longer line; held, it is centred (below). */
.title-page .signup {
  margin-top: clamp(28px, 2.6vw, 40px);
  max-width: var(--hero-col, 44rem);
}
/* Both Dear 15 forms on the homepage (the title page and the sign-off) are taller than the
   site's other forms, and the button is the only filled one on its screen. The field is filled
   with its own ground, so the title page's fragments don't show through it. */
.form-big .formkit-fields { gap: 10px; }
.form-big .formkit-field { flex-basis: 260px; }
.form-big .formkit-input {
  min-height: 64px;
  padding-inline: 20px;
  background: var(--bg);
  font-size: 1.1875rem;
}
.form-big .formkit-submit {
  min-height: 64px;
  padding-inline: 1.75em;
  font-size: 1.0625rem;
}
.hero-note {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0 24px;
  margin: 4px 0 0;
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: 600;
  font-stretch: 87.5%;
  line-height: 1.3;
  letter-spacing: 0.01em;
  color: var(--muted);
}
.hero-more {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-weight: 700;
  color: var(--fg);
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.4em;
  transition: text-decoration-color 0.2s ease;
}
.hero-more:hover { text-decoration-color: currentColor; }
@media (max-width: 899px) {
  .form-big .formkit-input,
  .form-big .formkit-submit { min-height: 56px; }
}
@media (max-width: 559px) {
  .form-big .formkit-submit { flex: 1 1 100%; }
}

/* On a phone the core rises from the bottom-right corner, below the text. */
@media (max-width: 899px) {
  .hero { display: block; min-height: 0; padding-bottom: min(62vw, 380px); }
  .core {
    top: auto;
    right: max(-46vw, -270px);
    bottom: max(-46vw, -270px);
    width: min(112vw, 660px);
    transform: none;
  }
}

/* Homepage title page: the title gets the full width and the signup stays on the first
   screen. Fragments of rock hang across the dark and the hot rim of the core shows along the
   bottom edge (site.js draws both, on a canvas fixed to the screen, and pulls them into the
   core in chapter I). */
@media (min-width: 900px) {
  .title-page .span-main { grid-column: 2 / 12; }
}

/* The heading is a sentence I would say out loud, so it is set in sentence case rather than the
   capitals of the chapter plates: Archivo pressed narrow and heavy, tight at this size. It breaks
   after "and" so the number starts the second line. --hero-col is the width of that second line,
   and the signup matches it. */
.title-page {
  --hero-type: clamp(2.5rem, 0.95rem + 5vw, 5.75rem);
  --hero-col: calc(var(--hero-type) * 10.33);
}
.title-page h1 {
  font-size: var(--hero-type);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 0.98;
  letter-spacing: -0.012em;
  text-transform: none;
}
.title-page h1 .hl { display: block; }
.words-total { font-variant-numeric: lining-nums tabular-nums; }

/* A year back. As a still: the heading, then the letter under it, left-aligned. "Dear fifteen,"
   is set exactly like the heading so the word that travels into it fits its place. Held
   (html.js, not .is-static): the heading and the letter share one place on the screen, the
   letter centred; site.js moves "sixteen" to the middle, rolls two of its letters back a year,
   carries it into "Dear fifteen," and raises the rest of the letter under it. */
.year-letter { margin-top: clamp(40px, 5vw, 72px); }
.year-dear {
  font-size: var(--hero-type);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 0.98;
  letter-spacing: -0.012em;
  text-transform: none;
}
.year-word { display: inline-block; white-space: nowrap; }
.year-glyphs { display: inline-block; }
/* A letter that changes is a roll of two: the old one in its place, the new one waiting unseen
   above it. site.js rolls them with the scroll (the old one drops a little and fades, the new one
   comes down into its place as it fades in) and slides what follows each roll (.yr-after) to close
   up to the new letter's width. All of it by transform and opacity, with nothing clipped, so the
   heading is never laid out or repainted while it turns and no frame shows half a letter. */
.year-roll {
  position: relative;
  display: inline-block;
}
.year-roll .yr-in { visibility: hidden; }
.year-roll .yr-old,
.year-roll .yr-new {
  position: absolute;
  left: 0;
  top: 0;
}
.year-roll .yr-new { opacity: 0; }
.yr-after { display: inline-block; }
@media (min-width: 900px) {
  .year-letter { grid-column: 2 / 12; }
}
html.js .year:not(.is-static) { display: block; overflow: visible; min-height: 0; padding: 0; }
.year-stage { display: flex; align-items: center; }
.year-stage > .wrap { width: 100%; }
html.js .year:not(.is-static) .hero-lead,
html.js .year:not(.is-static) .year-letter { grid-row: 1; align-self: center; }
/* On a phone the grid has one column: place the heading in it too, or it is pushed into a
   second, implicit one. */
@media (max-width: 899px) {
  html.js .year:not(.is-static) .hero-lead { grid-column: 1 / -1; }
}
html.js .year:not(.is-static) .year-letter {
  grid-column: 1 / -1;
  margin: 0;
  text-align: center;
}
html.js .year:not(.is-static) .year-line { margin-inline: auto; max-width: 30em; text-wrap: balance; }
html.js .year:not(.is-static) .year-letter .signup { margin-inline: auto; max-width: 44rem; text-align: left; }
html.js .year:not(.is-static) .year-letter .hero-note { max-width: 44rem; margin-inline: auto; }
html.js .year:not(.is-static) .year-slot { visibility: hidden; }
html.js .year:not(.is-static) :is(.year-dear, .year-line, .year-letter .signup, .year-letter .hero-note) { opacity: 0; }
/* The word travels over everything else on the stage. Everything that moves keeps its own layer
   for the whole hold, so nothing has to be repainted as a move starts or ends. */
html.js .year:not(.is-static) .year-word { position: relative; z-index: 2; will-change: transform; }
html.js .year:not(.is-static) :is(.year-roll > .yr-old, .year-roll > .yr-new) { will-change: transform, opacity; }
html.js .year:not(.is-static) .yr-after { will-change: transform; }
html.js .year:not(.is-static) .year-rest { will-change: opacity; }
html.js .year:not(.is-static) :is(.year-dear, .year-line, .year-letter .signup, .year-letter .hero-note) { will-change: opacity, transform; }

/* canvas.field, not .field: the contact form's field wrappers share the class name. */
canvas.field {
  position: fixed;
  z-index: 0;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
/* As a still (reduced motion) the fragments and rim belong to the title page, not the screen. */
canvas.field.is-still { position: absolute; }
html.js .edge-heat { display: none; }
.edge-heat {
  position: fixed;
  z-index: 0;
  left: 0;
  right: 0;
  bottom: 0;
  height: 0;
  pointer-events: none;
}
.core--edge {
  top: auto;
  right: auto;
  left: 50%;
  bottom: 0;
  transform: translate(-50%, 82%);
}
.core--full {
  position: relative;
  top: auto;
  right: auto;
  bottom: auto;
  width: 100%;
  transform: none;
}
@media (max-width: 899px) {
  .title-page { padding-bottom: clamp(104px, 30vw, 180px); }
  .core--edge {
    right: auto;
    bottom: 0;
    left: 50%;
    width: min(120vw, 680px);
    transform: translate(-50%, 80%);
  }
  .core--full { right: auto; bottom: auto; width: 100%; }
}

/* ---------- Meet Sparsh / editorial story ----------------------------- */

.story {
  font-size: clamp(1.25rem, 1.1rem + 0.45vw, 1.5rem);
  line-height: 1.55;
}
.story p { max-width: 34em; }

/* Big enough to stand on its own: no bar beside it. The opening quote mark hangs in the
   margin so the words line up with the story. */
.pull {
  margin: 1.1em 0 1.2em;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 1.1rem + 2.2vw, 3rem);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 1.02;
  max-width: 18em;
}
.pull p { max-width: none; margin: 0; text-indent: -0.32em; }
.pull blockquote { margin: 0; }
.pull figcaption,
.pull cite {
  display: block;
  margin-top: 16px;
  font-family: var(--font-display);
  font-style: normal;
  font-size: 0.875rem;
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  line-height: 1.3;
  color: var(--muted);
}

.story .closing { color: var(--fg); font-weight: 500; }

.portrait { margin: 0; }
.portrait img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% 26%;
}

.story-grid { align-items: start; }
.story-grid .story { margin-top: clamp(28px, 3vw, 44px); }

/* The portrait on the left, the story on the right (2026-10-11, the user: "move the author picture
   to the left and format the sections well"). On a wide screen it stays beside the story as it's
   read, so the column under it is never left empty; the tallies sit in the column between. On a
   phone it's small, beside the heading, so the story starts on the first screen; there the photo
   is still in its frame (site.js takes the drift off), because a small frame would crop the face. */
@media (min-width: 900px) {
  .story-grid .portrait {
    grid-column: 2 / 5;
    grid-row: 1 / span 2;
    margin-top: 8px;
    position: sticky;
    top: clamp(96px, 14vh, 160px);
  }
  .story-grid .story-head { grid-column: 6 / 13; }
  .story-grid .story { grid-column: 6 / 13; }
}

@media (max-width: 899px) {
  .story-grid { grid-template-columns: minmax(96px, 34%) minmax(0, 1fr); column-gap: 20px; }
  .story-grid .portrait { grid-column: 1; grid-row: 1; margin: 0; }
  .story-grid .story-head { grid-column: 2; grid-row: 1; align-self: end; }
  .story-grid .story { grid-column: 1 / -1; grid-row: 2; }
  .story-grid .portrait-frame img { top: 0; height: 100%; }
}

/* ---------- The Three Layers: what the email didn't show (homepage) --- */
/* One story of mine, from the outside in. Above the surface, the one line anyone saw. Under
   it, each layer is set the way it behaves: the crust is a few thin lines hanging just under
   the surface, the mantle is a sentence whose lines slide against each other, and the core is
   the heaviest type on the page, heated from its centre (site.js section 3). No boxes, keys or
   labels: the layers are told apart by how they are set. */

.dig { padding-block: clamp(8px, 2vw, 32px) var(--space-section); }

.dig-before { margin: 0 0 14px; max-width: 34em; color: var(--muted); text-wrap: balance; }

/* The surface: one line across the whole page, drawn from the left as it comes up the screen. */
.dig-surface {
  height: 1px;
  margin-top: 0;
  background: var(--morning);
  transform: scaleX(var(--surface, 1));
  transform-origin: 0 50%;
}

/* Each layer's idea, its name run in at the start, in the quiet voice under the big line. */
.dig-note { max-width: 34em; font-size: 1rem; line-height: 1.6; color: var(--muted); }
.dig-note h3,
.dig-note p { display: inline; }
.dig-note h3 {
  margin-right: 0.3em;
  font-size: 1.0625rem;
  font-weight: 800;
  line-height: inherit;
  letter-spacing: 0.01em;
  color: var(--fg);
}

/* Crust: thin, hanging just under the surface. */
.dig-crust .dig-note { margin-top: 18px; }
.dig-under {
  margin: clamp(80px, 11vw, 160px) 0 0;
  max-width: 22em;
  font-size: clamp(1.375rem, 1.05rem + 1.4vw, 2.125rem);
  font-style: italic;
  line-height: 1.3;
  color: var(--fg);
}

/* Mantle: never still. site.js splits the sentence into its lines and slides them against
   each other as you scroll; they are level as they cross the middle of the screen. */
.dig-mantle { margin-top: clamp(64px, 9vw, 128px); overflow-x: clip; }
.dig-drift {
  margin: 0;
  font-size: clamp(2rem, 1rem + 4vw, 4.75rem);
  line-height: 1.1;
  color: var(--fg);
}
.dig-line { display: block; white-space: nowrap; transform: translate3d(var(--dx, 0px), 0, 0); }
/* Moved every frame, so each line is a layer of its own and is never drawn again as it slides. */
html.can-dig .dig-line { will-change: transform; }
.dig-mantle .dig-note { margin-top: clamp(28px, 3.5vw, 48px); }

/* Core: the heaviest type on the page, in the middle. site.js keeps it dark until it arrives,
   then heats it from the centre word outward, and it stays lit. Without script it is lit. */
.dig-core { margin-top: clamp(96px, 13vw, 192px); text-align: center; }
.dig-core .dig-before { margin: 0 auto 18px; }
.dig-heat {
  margin: 0 auto;
  max-width: 12em;
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 1rem + 5.6vw, 6.25rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.9;
  letter-spacing: -0.012em;
  text-wrap: balance;
  color: var(--white-hot);
}
.dig-core .dig-note { margin: clamp(32px, 4vw, 56px) auto 0; text-align: left; }

@media (min-width: 900px) {
  .dig-crust .dig-under,
  .dig-mantle .dig-drift,
  .dig-core > * { grid-column: 2 / 12; }
  .dig-crust .dig-note { grid-column: 8 / -1; grid-row: 1; }
  .dig-crust .dig-under { grid-row: 2; }
  .dig-mantle .dig-note { grid-column: 7 / 12; }
}

/* ---------- Table of contents (practices) ----------------------------- */

.toc-group + .toc-group { margin-top: clamp(48px, 6vw, 80px); }

.toc-layer {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 16px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--rule);
  font-size: clamp(1.625rem, 1.2rem + 1.6vw, 2.5rem);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 1;
  letter-spacing: -0.012em;
}
.toc-layer .label { margin: 0; font-size: inherit; font-weight: inherit; font-stretch: inherit; letter-spacing: inherit; }

.status {
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  color: var(--muted);
  white-space: nowrap;
}

.toc-list { margin: 0; padding: 0; list-style: none; }

.toc-row {
  display: grid;
  grid-template-columns: clamp(3rem, 7vw, 6rem) minmax(0, 1fr);
  gap: 0 clamp(16px, 3vw, 40px);
  align-items: start;
  padding-block: clamp(20px, 2.4vw, 30px);
  border-bottom: 1px solid var(--rule);
  color: inherit;
  text-decoration: none;
}

.toc-num {
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 1.6rem + 3vw, 4.5rem);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 0.8;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  transition: color 0.2s ease;
}
a.toc-row:hover .toc-num,
a.toc-row:focus-visible .toc-num { color: var(--accent); }

.toc-title {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1rem + 0.9vw, 1.75rem);
  font-weight: 700;
  font-stretch: 87.5%;
  line-height: 1.1;
}
.toc-lesson {
  display: block;
  margin-top: 8px;
  color: var(--muted);
  max-width: 44em;
}

/* Practices page: the same contents, with room for each practice to say more. */
.layer-sub { margin: 16px 0 0; max-width: 40em; color: var(--muted); }
.practice { scroll-margin-top: 24px; }
.practice .toc-title { font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2.25rem); font-stretch: 75%; font-weight: 800; }
.practice .toc-lesson { color: var(--fg); font-size: clamp(1.1875rem, 1.05rem + 0.5vw, 1.4375rem); line-height: 1.45; }
.practice-more { margin-top: 12px; color: var(--muted); max-width: 40em; }
.practice .link-cta { margin-top: 8px; }
.practice:target .toc-num { color: var(--accent); }

/* ---------- Journal index (articles) ---------------------------------- */

.index { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rule); }

.index-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(9rem, 12rem) minmax(0, 1fr);
  gap: 10px clamp(20px, 3vw, 48px);
  align-items: baseline;
  padding-block: clamp(24px, 3vw, 36px);
  border-bottom: 1px solid var(--rule);
}

.index-meta { display: flex; flex-direction: column; gap: 6px; }
.index-meta .label { margin: 0; }

.index-title {
  text-transform: none;
  font-size: clamp(1.375rem, 1.1rem + 1vw, 2rem);
  font-weight: 700;
  font-stretch: 87.5%;
  line-height: 1.1;
}
.index-title a { color: inherit; text-decoration: none; }
/* The whole row is one link target. */
.index-title a::before { content: ""; position: absolute; inset: 0; }

.index-text { margin: 10px 0 0; max-width: 44em; }
.index-foot { margin-top: 10px; }

@media (max-width: 760px) {
  .index-row { grid-template-columns: minmax(0, 1fr); }
  .index-meta { flex-direction: row; flex-wrap: wrap; gap: 4px 16px; }
}

/* ---------- Three ways in ---------------------------------------------- */

.ways-lead {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 24px 48px;
  padding-top: 28px;
  border-top: 4px solid var(--fg);
}
.ways-lead h3 {
  font-size: clamp(2.25rem, 1.4rem + 3.6vw, 4.75rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.92;
  letter-spacing: -0.012em;
}
.ways-lead p { margin-top: 20px; max-width: 34em; font-size: clamp(1.1875rem, 1.05rem + 0.5vw, 1.4375rem); line-height: 1.5; }

.ways-rest {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 40px var(--col-gap);
  margin-top: clamp(48px, 6vw, 80px);
}
.ways-item { padding-top: 20px; border-top: 1px solid var(--line); }
.ways-item h3 { margin-bottom: 12px; }
.ways-item p { max-width: 30em; }
.ways-item .link-cta { margin-top: 12px; }

@media (max-width: 760px) {
  .ways-lead { grid-template-columns: minmax(0, 1fr); }
  .ways-rest { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- FAQ -------------------------------------------------------- */

.faq-grid { align-items: start; }
@media (min-width: 900px) {
  .faq-head { grid-column: 2 / 6; position: sticky; top: 56px; }
  .faq-list { grid-column: 7 / 13; }
}

.faq-item { border-top: 1px solid var(--rule); }
.faq-item:last-child { border-bottom: 1px solid var(--rule); }

.faq-item summary {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  padding: 22px 0;
  font-family: var(--font-display);
  font-size: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
  font-weight: 700;
  font-stretch: 87.5%;
  line-height: 1.25;
  cursor: pointer;
  list-style: none;
}
.faq-item summary::-webkit-details-marker { display: none; }

.faq-icon { position: relative; flex: none; width: 14px; height: 14px; margin-top: 0.3em; }
.faq-icon::before,
.faq-icon::after {
  content: "";
  position: absolute;
  top: 6px;
  left: 0;
  width: 14px;
  height: 2px;
  background: var(--accent);
}
.faq-icon::after { transform: rotate(90deg); transition: transform 0.2s ease; }
.faq-item[open] .faq-icon::after { transform: rotate(0deg); }

.faq-answer { padding: 0 38px 28px 0; max-width: 62ch; }

@media (max-width: 899px) {
  .faq-head { margin-bottom: 40px; }
}

/* ---------- Kit (Dear 15) forms --------------------------------------- */

.formkit-form { margin: 0; }
.formkit-fields { display: flex; flex-wrap: wrap; gap: 12px; }
.formkit-field { flex: 1 1 240px; min-width: 0; }

.formkit-input,
.field input,
.field select,
.field textarea {
  width: 100%;
  min-height: 52px;
  padding: 13px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: transparent;
  color: var(--fg);
  font-family: var(--font-read);
  font-size: 1.0625rem;
  line-height: 1.4;
}
.formkit-input::placeholder,
.field input::placeholder,
.field textarea::placeholder { color: var(--muted); opacity: 1; }
.layer-crust .formkit-input::placeholder,
.layer-crust .field input::placeholder,
.layer-crust .field textarea::placeholder { opacity: 0.72; }

.formkit-input:focus-visible,
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

.formkit-submit { flex: none; }
.formkit-spinner { display: none; }
.formkit-submit[data-active] .formkit-spinner { display: inline-flex; gap: 4px; }
.formkit-submit[data-active] .formkit-spinner div {
  width: 6px;
  height: 6px;
  background: currentColor;
  animation: ck-pulse 1.2s infinite ease-in-out both;
}
.formkit-submit[data-active] .formkit-spinner div:nth-child(2) { animation-delay: 0.15s; }
.formkit-submit[data-active] .formkit-spinner div:nth-child(3) { animation-delay: 0.3s; }
@keyframes ck-pulse { 0%, 80%, 100% { opacity: 0.2; } 40% { opacity: 1; } }

.formkit-guarantee p {
  margin: 12px 0 0;
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: 600;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  color: var(--muted);
}

.formkit-alert {
  margin: 0 0 12px;
  padding: 0;
  list-style: none;
  font-size: 1rem;
  color: var(--accent);
}
.formkit-alert:empty { display: none; }
.formkit-alert-success { color: var(--fg); }
.formkit-powered-by-convertkit-container,
.formkit-powered-by-convertkit { display: none !important; }

/* Closing letter band. Shown to everyone, subscribers too. */
.dear15-band .formkit-form { margin-top: 32px; max-width: 620px; }

/* ---------- Reading pages (free chapter, articles) -------------------- */

.reading { padding-block: clamp(32px, 5vw, 72px) clamp(72px, 9vw, 128px); }

.reading-head { margin-bottom: clamp(48px, 6vw, 88px); }
.reading-head h1 { font-size: clamp(2.5rem, 1.4rem + 4.6vw, 5.5rem); }
.reading-head .lead { margin-top: 28px; color: var(--muted); }
.reading-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 20px;
  margin-top: 24px;
}
.reading-meta .label { margin: 0; }

.back-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-bottom: 28px;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  color: var(--fg);
  text-decoration: none;
}

@media (min-width: 900px) {
  .reading-head { grid-column: 2 / 11; }
  .reading-body { grid-column: 2 / 10; }
}

.reading-body {
  max-width: var(--measure);
  font-size: var(--step-read);
  line-height: 1.7;
}
.reading-body > * { margin-top: 0; margin-bottom: 0; }
.reading-body > * + * { margin-top: 1.1em; }
.reading-body > * + h2 { margin-top: 2.4em; }
.reading-body > * + h3 { margin-top: 2em; }
.reading-body h2 { font-size: clamp(1.625rem, 1.2rem + 1.6vw, 2.375rem); line-height: 1; }
.reading-body h3 { font-size: clamp(1.25rem, 1.05rem + 0.8vw, 1.625rem); }
.reading-body h4 { font-size: 1.1875rem; font-weight: 700; font-stretch: 87.5%; line-height: 1.2; }
.reading-body h2 + *,
.reading-body h3 + *,
.reading-body h4 + * { margin-top: 0.7em; }

.reading-body ul,
.reading-body ol { padding-left: 1.3em; }
.reading-body li + li { margin-top: 0.5em; }
.reading-body li::marker { color: var(--accent); font-family: var(--font-display); font-weight: 700; }

.quote {
  margin: 1.8em 0;
  padding: 0.1em 0 0.1em 22px;
  border-left: 1px solid var(--rule);
  font-style: italic;
  font-size: 1.15em;
  line-height: 1.55;
}
.quote cite {
  display: block;
  margin-top: 12px;
  font-family: var(--font-display);
  font-style: normal;
  font-size: 0.875rem;
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  color: var(--muted);
}

/* A part of the writing set a step in under the heading it belongs to, the way a book sets a
   subsection: no box (2026-10-06; a 3px rule over a heading, a paragraph and a 1px rule,
   repeated three times under "The Three Qualities That Matter", read as a stack of cards). */
.note {
  margin: 1.9em 0;
  padding-left: clamp(16px, 2.6vw, 36px);
}
.note + .note { margin-top: 2.1em; }
.note > * + * { margin-top: 0.5em; }
.note h3,
.note h4 { font-size: 1.25rem; }
/* Closer to its own words than to what's above it. */
.reading-body .note h3 + *,
.reading-body .note h4 + * { margin-top: 0.25em; }
.reading-body h2 + .note { margin-top: 1.1em; }

.epigraph {
  margin: 0 0 2em;
  font-family: var(--font-display);
  font-size: clamp(1.625rem, 1.1rem + 2vw, 2.75rem);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 1.04;
}

.steps { margin: 1.6em 0; padding: 0; list-style: none; counter-reset: step; }
.steps > li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  gap: 0 16px;
  padding: 18px 0;
  border-top: 1px solid var(--rule);
}
.steps > li:last-child { border-bottom: 1px solid var(--rule); }
.steps > li::before {
  content: counter(step);
  font-family: var(--font-display);
  font-size: 2rem;
  font-weight: 800;
  font-stretch: 75%;
  line-height: 1;
  color: var(--accent);
}
.steps > li > * { grid-column: 2; }
.steps .step-title {
  margin: 0 0 4px;
  font-family: var(--font-display);
  font-size: 1.1875rem;
  font-weight: 700;
  font-stretch: 87.5%;
  line-height: 1.2;
}

.closing-quote {
  margin: 2.6em 0 0;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.25rem);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 1.05;
}

/* Where reading picks up once the free chapter's gate lifts. (The articles' blurred preview was
   removed on 2026-10-01: the articles are open to everyone.) */
.gate-resume:focus { outline: none; }

/* ---------- Signup gate ------------------------------------------------ */

.chapter-gate { display: none; }

html.chapter-locked,
html.chapter-locked body { overflow: hidden; }

html.chapter-locked .chapter-gate {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 900;
  align-items: center;
  justify-content: center;
  padding: 24px 16px;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: rgba(7, 10, 28, 0.95);
  animation: gate-in 0.35s ease both;
}
.chapter-gate.is-leaving { animation: gate-out 0.45s ease both; }

.gate-card {
  --fg: var(--text-on-dark);
  --muted: var(--muted-on-dark);
  --accent: var(--sky);
  --rule: var(--rule-dark);
  --line: var(--muted-on-dark);
  --btn-bg: var(--sky);
  --btn-fg: var(--night);
  --btn-hover: var(--text-on-dark);
  --focus: var(--sky);
  width: 100%;
  max-width: 560px;
  margin: auto;
  padding: clamp(28px, 5vw, 44px);
  background: var(--night-2);
  color: var(--fg);
  border: 1px solid var(--rule-dark);
  border-top: 4px solid var(--sky);
  border-radius: var(--radius);
}

.gate-quote {
  margin: 0 0 24px;
  padding: 0 0 24px;
  border-bottom: 1px solid var(--rule);
  font-style: italic;
  font-size: 1.1875rem;
  line-height: 1.5;
  color: var(--muted);
}
.gate-title {
  margin-bottom: 14px;
  font-size: clamp(2rem, 1.4rem + 2.4vw, 2.75rem);
  letter-spacing: -0.012em;
}
.gate-desc { font-size: 1.0625rem; line-height: 1.6; color: var(--muted); margin-bottom: 24px; }

.gate-signup .formkit-fields { flex-direction: column; }
.gate-signup .formkit-field { flex: none; }
.gate-signup .formkit-submit { width: 100%; }
.gate-signup .formkit-alert-success { display: none; }

.gate-exit {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-top: 16px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  font-family: var(--font-read);
  font-size: 1rem;
  text-decoration: underline;
  text-decoration-color: var(--rule);
  text-underline-offset: 0.2em;
  cursor: pointer;
}
.gate-exit:hover { color: var(--fg); text-decoration-color: currentColor; }

.gate-waiting,
.gate-success { display: none; }
.gate-card.is-waiting .gate-form-area,
.gate-card.is-unlocked .gate-form-area,
.gate-card.is-unlocked .gate-waiting { display: none; }
.gate-card.is-waiting .gate-waiting,
.gate-card.is-unlocked .gate-success { display: block; }

.gate-success-title {
  margin: 0 0 10px;
  font-family: var(--font-display);
  font-size: 2rem;
  font-weight: 800;
  font-stretch: 75%;
  line-height: 1;
  letter-spacing: -0.012em;
}
.gate-success-text { color: var(--muted); margin: 0 0 6px; }
.gate-success-text strong { color: var(--fg); font-weight: 600; word-break: break-all; }
.gate-waiting-hint { margin: 14px 0 0; font-size: 1rem; color: var(--muted); }

@keyframes gate-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes gate-out { from { opacity: 1; } to { opacity: 0; } }

/* ---------- Contact ---------------------------------------------------- */
/* One column that reads top to bottom: the question that started the book, then the form, with
   the other story told beside the two moments of sending a message (the writing, then the
   waiting), in the margin on a wide screen and just before each moment on a phone. Labels are
   plain sentences; nothing is marked required, only what's optional. */

.contact { padding: clamp(32px, 5vw, 72px) 0 var(--space-section); }
.ct-open,
.ct-body { grid-column: 1 / -1; }
.ct-before,
.ct-after {
  max-width: 34em;
  font-size: clamp(1.1875rem, 1.05rem + 0.5vw, 1.4375rem);
  line-height: 1.5;
  text-wrap: pretty;
}
.ct-before { margin: clamp(28px, 3.4vw, 48px) 0 0; }
.ct-q {
  margin: clamp(10px, 1.2vw, 16px) 0 clamp(14px, 1.6vw, 22px);
  font-size: clamp(1.875rem, 1.2rem + 2.4vw, 3.25rem);
  font-style: italic;
  line-height: 1.15;
  text-wrap: balance;
}
.ct-after { margin: 0; }
.ct-body { margin-top: clamp(56px, 7vw, 104px); padding-top: clamp(28px, 3vw, 40px); border-top: 1px solid var(--rule); }

.ct-form[hidden] { display: none; }
.ct-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "topic" "who" "write" "msg" "wait" "send";
}
.ct-topic { grid-area: topic; }
.ct-who { grid-area: who; }
.ct-aside--write { grid-area: write; }
.ct-message { grid-area: msg; }
.ct-aside--wait { grid-area: wait; }
.ct-send { grid-area: send; }

.ct-topic { margin: 0 0 clamp(32px, 4vw, 48px); padding: 0; border: 0; min-width: 0; }
.ct-topic legend,
.field label {
  display: block;
  margin-bottom: 10px;
  padding: 0;
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 700;
  font-stretch: 87.5%;
  line-height: 1.3;
}
.ct-choice {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 48px;
  font-size: clamp(1.125rem, 1.05rem + 0.3vw, 1.3125rem);
  line-height: 1.3;
  cursor: pointer;
}
.ct-choice + .ct-choice { border-top: 1px solid var(--rule); }
.ct-choice input {
  flex: none;
  width: 20px;
  height: 20px;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.ct-choice:has(input:checked) { font-weight: 500; }
.ct-choice input:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
.ct-topic .field-error { margin-top: 4px; }

.ct-who { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 20px; }
.field { margin-bottom: 28px; }
.field textarea { min-height: 220px; resize: vertical; }
.ct-message .field-hint { margin: -2px 0 12px; max-width: 34em; }
.field-hint a { color: inherit; text-decoration-color: var(--accent); text-underline-offset: 0.2em; }

.ct-aside {
  margin: 0 0 18px;
  max-width: 30em;
  font-size: 1.125rem;
  font-style: italic;
  line-height: 1.5;
  text-wrap: pretty;
}
.ct-send { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 28px; }
.ct-direct { margin: 0; font-size: 1rem; }
.ct-direct a { overflow-wrap: anywhere; }
.ct-send .form-error { flex-basis: 100%; }

.field [aria-invalid="true"] { border-color: var(--accent); border-width: 2px; }
.field-hint,
.field-error { display: block; margin-top: 8px; font-size: 0.9375rem; line-height: 1.4; }
.field-error { color: var(--accent); font-weight: 600; }
.field-error[hidden],
.field-hint[hidden] { display: none; }
.form-error {
  margin-top: 4px;
  padding: 14px 16px;
  border: 1px solid var(--accent);
  color: var(--fg);
}
.form-error:empty { display: none; }

.ct-sent[hidden] { display: none; }
.ct-sent h2:focus { outline: none; }
.ct-sent-msg {
  margin: clamp(24px, 3vw, 36px) 0 0;
  padding: 0 0 0 clamp(16px, 2vw, 24px);
  max-width: 36em;
  border-left: 1px solid var(--rule);
  font-size: clamp(1.125rem, 1.05rem + 0.3vw, 1.3125rem);
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.ct-sent-when { margin: clamp(20px, 2.4vw, 28px) 0 0; font-size: clamp(1.1875rem, 1.05rem + 0.5vw, 1.4375rem); }
.ct-sent-when span { font-weight: 500; overflow-wrap: anywhere; }

@media (min-width: 900px) {
  .ct-open { grid-column: 2 / 10; }
  .ct-body { grid-column: 2 / 12; }
  /* The story in the margin, level with the moment it belongs to. */
  .ct-form {
    grid-template-columns: minmax(0, 7fr) minmax(0, 3fr);
    column-gap: clamp(40px, 5vw, 88px);
    grid-template-areas: "topic ." "who ." "msg write" "send wait";
  }
  .ct-aside { margin: 0; padding-top: 34px; align-self: start; }
  .ct-aside--wait { padding-top: 0; }
  .ct-send { align-self: start; }
  .ct-sent { max-width: 70%; }
}
@media (max-width: 560px) {
  .ct-who { grid-template-columns: minmax(0, 1fr); }
}

.ticks { margin: 16px 0 8px; padding-left: 1.2em; list-style: square; }
.ticks li + li { margin-top: 4px; }
.ticks li::marker { color: var(--accent); }

/* ---------- Definition rows (contact routes, author facts) ------------- */

.facts { margin: 0; padding: 0; border-top: 1px solid var(--rule); }
.facts > div {
  display: grid;
  grid-template-columns: minmax(6.5rem, 9rem) minmax(0, 1fr);
  gap: 4px 24px;
  padding: 14px 0;
  border-bottom: 1px solid var(--rule);
}
.facts dt {
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  color: var(--accent);
  padding-top: 0.2em;
}
.facts dd { margin: 0; font-size: 1.0625rem; }
.facts a { overflow-wrap: anywhere; }

@media (max-width: 480px) {
  .facts > div { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- Rows: timeline, three As, packages ------------------------ */

.rows { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
.rows > li,
.rows > .row-item {
  display: grid;
  grid-template-columns: minmax(8rem, 13rem) minmax(0, 1fr);
  gap: 8px clamp(20px, 3vw, 48px);
  padding-block: clamp(20px, 2.4vw, 32px);
  border-bottom: 1px solid var(--rule);
}
.rows .row-key {
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  color: var(--accent);
  padding-top: 0.3em;
}
.rows--big > li { grid-template-columns: minmax(0, 17rem) minmax(0, 1fr); }
.rows .row-key--big {
  font-size: clamp(1.75rem, 1.2rem + 1.6vw, 2.625rem);
  font-weight: 800;
  font-stretch: 75%;
  letter-spacing: -0.012em;
  line-height: 0.95;
  padding-top: 0;
  color: var(--fg);
}
.rows h3 { margin-bottom: 8px; }
.rows p { max-width: 44em; }
.rows .row-now .row-key { color: var(--fg); }

@media (max-width: 640px) {
  .rows > li,
  .rows > .row-item { grid-template-columns: minmax(0, 1fr); }
}

/* Moments in the timeline (author page, 2026-10-17; `.moment`, used for the practices page's
   elephant too). Three rows of "How I got here" are held while
   their moment is drawn beside their words (site.js section 5, drawn.moment). Held, the row's stage
   is the whole screen, wider than the row: site.js sets where the row starts (--bleed-l), how wide
   the screen is (--bleed-w) and how wide the row is (--row-w), so the words stay over the right of
   the row and the drawing has the rest. As a still (reduced motion, no script, a screen too short)
   it is the plain row, laid out like the others. */
.rows > li.row-moment { display: block; padding: 0; }
.row-moment .moment-words {
  display: grid;
  grid-template-columns: minmax(8rem, 13rem) minmax(0, 1fr);
  gap: 8px clamp(20px, 3vw, 48px);
  padding-block: clamp(20px, 2.4vw, 32px);
}
.moment-art { display: none; }
html.js .moment:not(.is-static) > .moment-stage {
  width: var(--bleed-w, 100vw);
  margin-left: calc(-1 * var(--bleed-l, 0px));
  display: flex;
  align-items: center;
}
html.js .moment:not(.is-static) .moment-art { display: block; position: absolute; inset: 0; width: 100%; height: 100%; }
html.js .moment:not(.is-static) .moment-words {
  position: relative;
  z-index: 1;
  grid-template-columns: minmax(0, 1fr);
  gap: 4px;
  margin-left: calc(var(--bleed-l, 0px) + var(--row-w, 60vw) * 0.64);
  width: calc(var(--row-w, 60vw) * 0.36);
  padding-block: 0;
}
html.js .moment:not(.is-static) .mb[data-at] { opacity: 0; }
@media (max-width: 899px) {
  html.js .moment:not(.is-static) > .moment-stage { align-items: flex-end; }
  html.js .moment:not(.is-static) .moment-words {
    margin-left: var(--bleed-l, 16px);
    width: var(--row-w, calc(100vw - 32px));
    padding-bottom: 6vh;
    padding-bottom: 6svh;
  }
}
@media (max-width: 640px) {
  .row-moment .moment-words { grid-template-columns: minmax(0, 1fr); }
}
/* In a story (the practices page's elephant, 2026-10-17): held, its words stay at the right edge of
   where the paragraph was, a little narrower, and the drawing has the page to their left
   (data-art-left). As a still, the paragraph. */
.prose-moment { margin-block: 1em; }
.prose-moment .moment-words { display: block; padding: 0; }
.prose-moment .moment-words p { margin: 0; }
/* Its own width is the paragraph's, so the full-screen stage inside it never widens the story
   around it (Search for the Truth is set to the right at its own width). */
html.js .prose-moment:not(.is-static) { width: 34em; max-width: 100%; }
html.js .prose-moment:not(.is-static) .moment-words {
  --held-w: min(var(--row-w, 34em), 24em);
  margin-left: calc(var(--bleed-l, 0px) + var(--row-w, 34em) - var(--held-w));
  width: var(--held-w);
}
@media (max-width: 899px) {
  html.js .prose-moment:not(.is-static) .moment-words { --held-w: var(--row-w, 100%); }
}

/* Tales at the top of four articles (2026-10-17). The story's own paragraphs, with its moment
   drawn beside them (site.js section 5, `tale`): the drawing waits on the right, held in place
   while the paragraphs go past it, and moves as each one reaches the reading line. The tale
   reaches out to the right edge of the screen (--tale-out); its paragraphs keep the article's
   column on the left. On a phone the drawing is a band across the top that the paragraphs go
   under. Not held: the page scrolls as it always does. As a still it's the plain paragraphs. */
.tale-figure { display: none; }
.tale-steps > * { margin: 0; }
.tale-steps > * + * { margin-top: 1.1em; }
html.can-tale .tale:not(.is-static) {
  position: relative;
  z-index: 41;
  display: grid;
  grid-template-columns: minmax(0, 30em) minmax(0, 1fr);
  column-gap: clamp(32px, 4vw, 72px);
  margin-right: calc(-1 * var(--tale-out, 0px));
}
html.can-tale .tale:not(.is-static) .tale-steps { grid-column: 1; grid-row: 1; padding-block: 32vh 10vh; }
html.can-tale .tale:not(.is-static) .tale-figure {
  display: block;
  grid-column: 2;
  grid-row: 1;
  align-self: start;
  position: sticky;
  top: 18vh;
  height: 64vh;
}
.tale-art { display: block; width: 100%; height: 100%; }
/* The click's silence: pitch black over everything but the tale. */
.tale-dark { position: fixed; inset: 0; z-index: 40; background: var(--pitch-black); opacity: 0; pointer-events: none; }
@media (max-width: 899px) {
  html.can-tale .tale:not(.is-static) { display: block; margin-right: 0; }
  html.can-tale .tale:not(.is-static) .tale-figure {
    top: 0;
    height: 44vh;
    height: 44svh;
    z-index: 1;
    width: var(--tale-vw, 100vw);
    margin-left: calc(-1 * var(--tale-l, 16px));
    background: var(--morning);
  }
  html.can-tale .tale:not(.is-static) .tale-steps { padding-block: 26vh 10vh; }
}

.worth-line {
  margin: clamp(48px, 6vw, 80px) 0 20px;
  font-family: var(--font-display);
  font-size: clamp(2rem, 1.2rem + 3.4vw, 4.25rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.95;
  letter-spacing: -0.012em;
  max-width: 14em;
}

/* ---------- Footer: the surface ---------------------------------------- */
/* Three bands (2026-10-05): the links, spread edge to edge; the name, large and centred, with
   the tagline under it; then the small print under a rule. The links' outer columns line up
   with the small print's ends, and the name sits on the centre line between them. */

.site-footer {
  padding-block: clamp(64px, 8vw, 112px) 28px;
  border-top: 2px solid var(--ink);
}

.footer-top {
  display: grid;
  grid-template-columns: repeat(3, auto);
  justify-content: space-between;
  gap: 40px var(--col-gap);
}

.footer-col h2 {
  margin-bottom: 14px;
  font-size: 0.875rem;
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  text-transform: none;
  line-height: 1.3;
  color: var(--accent);
}
.footer-col ul { margin: 0; padding: 0; list-style: none; }
.footer-col ul + h2 { margin-top: 28px; }
.footer-col li + li { margin-top: 4px; }
.footer-col a {
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  color: var(--fg);
  text-decoration: none;
  font-size: 1.0625rem;
  overflow-wrap: anywhere;
}

/* The name, large and centred, with the tagline tucked under it: it starts where the name
   starts and sits beside the tile's drop, so the three read as one lockup. --lk is the name's
   size. The last stretch of the page types the name out under the reader's hand (site.js,
   section 6): a letter for each step scrolled, back off the same way going up. The cursor
   blinks while it waits, at the start and once the name is written. */
.footer-lockup {
  --lk: clamp(1.5rem, 6.6vw, 6.25rem);
  display: grid;
  justify-content: center;
  margin-top: clamp(64px, 8vw, 112px);
}
.footer-lockup .brand {
  gap: 0.6em;
  min-height: 0;
  font-size: var(--lk);
  font-weight: 900;
  letter-spacing: -0.012em;
  white-space: nowrap;
}
.footer-tagline {
  /* Its baseline on the tile's foot: the tile ends 0.38 of the name's size below the name's line box. */
  margin: calc(var(--lk) * 0.38 - 1em) 0 0;
  padding-left: calc(var(--lk) * 2.16);
  font-size: clamp(1rem, 1.5vw, 1.375rem);
  line-height: 1.35;
  text-wrap: balance;
  color: var(--fg);
}
/* The name is typed through a window (site.js section 6): the window clips the whole name, drawn
   once, and opens a letter at a time; the window and the name are each a layer, moved by
   transforms, so a letter typed draws nothing again. The window has a little room past the
   name's box (padding, given back by margins so nothing moves) for the letters' overhang. */
html.can-type .footer-lockup .brand-type {
  overflow: clip;
  padding: 0.3em 0.2em 0.3em 0;
  margin: -0.3em -0.2em -0.3em 0;
  will-change: transform;
}
html.can-type .footer-lockup .bt-ink { display: inline-block; will-change: transform; }
/* Until the window is set, the name waits out of sight, like the held pieces. */
html.js-booting .footer-lockup .brand-type { visibility: hidden; }
.footer-lockup .bm-cursor.is-blinking { animation: edge-blink 1.1s steps(1, end) infinite; }
@media (prefers-reduced-motion: reduce) {
  .footer-lockup .bm-cursor.is-blinking { animation: none; }
}

.footer-base {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 32px;
  margin-top: clamp(64px, 8vw, 112px);
  padding-top: 20px;
  border-top: 1px solid var(--rule);
}
.footer-legal { display: flex; flex-wrap: wrap; gap: 4px 24px; margin: 0; padding: 0; list-style: none; }
.footer-legal a { display: inline-flex; min-height: 36px; align-items: center; color: var(--fg); text-decoration: none; }
.footer-base small,
.footer-legal a {
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: 600;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
}

/* Narrower: Explore and On Medium side by side, Contact and Find us across the width under them
   (the address needs the room). On a phone the name grows to fill the width, and the tagline,
   too long to tuck beside the small tile, is centred under the whole lockup. */
@media (max-width: 760px) {
  .footer-top { grid-template-columns: repeat(2, minmax(0, 1fr)); justify-content: stretch; }
  .footer-col:last-child { grid-column: 1 / -1; }
}
@media (max-width: 600px) {
  .footer-lockup { --lk: 7.8vw; }
  .footer-tagline { margin-top: 16px; padding-left: 0; text-align: center; }
}

/* ---------- Homepage chapters (scrollcraft) --------------------------- */
/* The homepage reads like the printed book: a title page, then three chapters with their
   own title plates and grounds, hard cuts between them, and one held moment where the crust
   breaks open. The scroll engine (scrollcraft.js/.css, never edited) drives the attributes
   marked data-sc-*; site.js drives the folio and the break. */

:root {
  --sc-canvas: var(--night);
  --sc-surface: var(--night-2);
  --sc-ink: var(--text-on-dark);
  --sc-ink-soft: var(--muted-on-dark);
  --sc-accent: var(--sky);
  --sc-accent-ink: var(--night);
  --sc-font-display: var(--font-display);
  --sc-font-text: var(--font-read);
  --sc-track-normal: 0;
  --sc-r-sm: var(--radius);
}

/* If the engine never loads, nothing it would have revealed stays hidden. Without scripts the
   title page shows a plain heat at its bottom edge in place of the fragments. */
html:not(.sc-ready) [data-sc-in],
html:not(.sc-ready) [data-sc-stagger] > *,
html:not(.sc-ready) [data-sc-cue] { opacity: 1; transform: none; }
/* ...and the title page's heat stays with the title page instead of following the screen. */
html:not(.sc-ready) .edge-heat { position: absolute; }

/* Chapter title plates: a numeral at page scale, the layer, and its depth. */
.chapter-open { padding-top: var(--space-section); align-items: end; }
.intertitle { grid-column: 2 / 8; margin: 0; }
/* Book numerals: Literata's serifs make "I" read as a chapter number, not a bar. */
.it-num {
  display: block;
  font-family: var(--font-read);
  font-size: clamp(6.5rem, 3rem + 13vw, 15rem);
  font-weight: 500;
  line-height: 0.8;
  color: var(--fg);
}
.it-name,
.it-sub {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-stretch: 87.5%;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
}
.it-name { margin-top: clamp(20px, 2.4vw, 32px); font-size: clamp(1.0625rem, 0.95rem + 0.5vw, 1.375rem); color: var(--accent); }
.it-sub { margin-top: 6px; font-size: 0.875rem; color: var(--muted); }
/* The first section after a title plate doesn't need a full section's air above it. */
.chapter-first { padding-top: clamp(48px, 6vw, 88px); }

/* Chapter I: the plate on the left. .chapter-core is only a box: the stretch of the screen the
   fist is clenched in, driven across and held in (site.js draws it there). */
.chapter-open--core { align-items: center; }
.chapter-open--core .intertitle { grid-column: 2 / 5; grid-row: 1; }
.chapter-core { grid-column: 5 / 12; grid-row: 1; aspect-ratio: 5 / 2; }
html:not(.can-build) .chapter-core,
.core-build.is-static .chapter-core { display: none; }
/* Held, it runs from beside the plate to just short of the folio (the grid stops short of the
   right edge). */
@media (min-width: 900px) {
  .core-build:not(.is-static) .chapter-open--core { position: static; }
  .core-build:not(.is-static) .chapter-core { position: absolute; left: 33%; right: 17%; top: 50%; height: 30vh; aspect-ratio: auto; translate: 0 -50%; }
}
.chapter .story-grid { padding-block: clamp(48px, 6vw, 88px) var(--space-section); }

/* The portrait is a window: the photo moves a little inside its frame as you pass. */
.portrait-frame { position: relative; aspect-ratio: 4 / 5; overflow: hidden; }
.portrait-frame img {
  position: absolute;
  left: 0;
  top: -44px;
  width: 100%;
  max-width: none;
  height: calc(100% + 88px);
  aspect-ratio: auto;
  object-fit: cover;
  object-position: 50% 26%;
}
/* It moves on every frame it's on screen, so it's a layer of its own and the photo is never drawn
   again as it moves (2026-10-06). */
html.js .portrait-frame img[data-sc-parallax] { will-change: transform; }
.portrait figcaption { margin: 12px 0 0; }

/* The break. Two slabs of dark rock split along a fracture that site.js draws from the
   folio's strata; the granite behind them is the surface. */
.break { position: relative; background: var(--nila); }
.break-stage { background: var(--nila); }
.break-light,
.break-slab,
.break-crack { position: absolute; inset: 0; }
.break-light { background: var(--morning); opacity: 0; }
.break-slab { background: var(--nila); will-change: transform; }
.break-crack { width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.break-crack path { fill: none; stroke: var(--morning); stroke-linejoin: miter; stroke-linecap: butt; }
/* Reduced motion: no hold. The break is a still of the rock already split open. */
.break.is-static { height: 70vh; height: 70svh; }
.break.is-static .break-stage { position: relative; height: 100%; overflow: hidden; }

/* Chapter III rises straight out of the break, so it starts close to the top. Its numeral
   surfaces once as the chapter opens, at its own pace. */
.chapter-open--after-break { padding-top: clamp(24px, 3vw, 40px); }
.it-surface { grid-column: 2 / 8; padding-block: 0.12em; }
/* It surfaces through a window: the plate is a window that rises into place while the numeral
   inside it is moved the other way by as much, so the numeral stays put and is uncovered from the
   bottom up. Both are transforms, played by the compositor, so nothing is drawn again as it goes
   (an animated clip-path was redrawn every frame; 2026-10-06). The padding moves inside, so the
   window and the numeral are the same height and cancel exactly. */
html.can-surface .it-surface { padding-block: 0; overflow: hidden; transform: translate3d(0, 100%, 0); }
html.can-surface .it-surface .intertitle { padding-block: 0.12em; transform: translate3d(0, -100%, 0); }
html.can-surface .it-surface.is-up,
html.can-surface .it-surface.is-up .intertitle { transform: none; transition: transform 0.6s cubic-bezier(0.23, 1, 0.32, 1); }
/* Once it has surfaced, the window is opened altogether, so nothing of the numeral is ever cut. */
html.can-surface .it-surface.is-up.is-surfaced { overflow: visible; }
.it-surface .intertitle { grid-column: auto; }

/* The sign-off: the page ends by opening a letter. "Dear 15," is set like the title page's
   heading (sentence case, Archivo pressed narrow), so the page starts and ends in one voice,
   and the line and the form under it are the title page's too. Shown to everyone. */
.signoff { position: relative; padding-block: clamp(96px, 12vw, 176px) clamp(96px, 11vw, 160px); }
.letter-head {
  font-size: clamp(3.25rem, 1.2rem + 6.4vw, 7.5rem);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 0.95;
  letter-spacing: -0.012em;
  text-transform: none;
}
.letter-line { margin-top: clamp(20px, 2vw, 32px); max-width: 34em; }
/* The edge of the draft: the next practice's heading, and the cursor waiting after it. */
.edge-cursor {
  display: inline-block;
  width: 0.09em;
  height: 0.78em;
  margin-left: 0.12em;
  vertical-align: -0.02em;
  background: currentColor;
  animation: edge-blink 1.1s steps(1, end) infinite;
}
@keyframes edge-blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .edge-cursor { animation: none; } }
.signoff .formkit-form { margin-top: clamp(28px, 2.6vw, 40px); max-width: 44rem; }

@media (max-width: 899px) {
  /* One column on a phone: the desktop column spans would otherwise invent extra columns. */
  .intertitle,
  .chapter-open--core .intertitle,
  .chapter-core,
  .it-surface { grid-column: 1 / -1; }
  .chapter-core { grid-row: auto; width: 100%; aspect-ratio: 8 / 5; margin-top: 24px; }
}

/* Smaller moments. Each belongs to the words beside it, and each stays smaller than the break. */

/* "My heart dropped.": the line falls a few pixels and lands, once. */
html.can-drop .heart-drop { transform: translateY(-12px); }
html.can-drop .heart-drop.is-dropped { animation: heart-drop 0.53s forwards; }
@keyframes heart-drop {
  0% { transform: translateY(-12px); animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
  58% { transform: translateY(3px); animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); }
  100% { transform: translateY(0); }
}

/* Night after night: pencil tallies in the margin, drawn as the paragraph is read. */
.nights { position: relative; }
.tally {
  display: block;
  overflow: visible;
  fill: none;
  stroke: var(--muted);
  stroke-width: 1.5;
  stroke-linecap: round;
}
@media (min-width: 900px) {
  .tally { position: absolute; top: 0.45em; right: calc(100% + var(--col-gap)); width: 62px; height: 86px; }
}
@media (max-width: 899px) {
  .tally { width: 214px; max-width: 100%; height: 22px; margin: 0 0 1.2em; }
}

/* The practices: each number lights as the reading line passes it, and stays lit. */
#ch-mantle .toc-row.is-lit .toc-num { color: var(--accent); }
@media (prefers-reduced-motion: no-preference) {
  #ch-mantle .toc-row .toc-num { transition: color 0.4s ease-out; }
}

/* The Three As (chapter I). Each A is the moment in my story where I fell into it, moving the
   way that moment went (site.js section 5). No colour carries the story, only place, size and
   time. As stills (no script, reduced motion, a screen too short to hold them) each is plain type
   in its final state. */
.three-as { padding-block: 0 var(--space-section); }
.as-head .lead { margin-top: 24px; }
.as-letters > span { display: inline-block; } /* the author page's Three As */
.as-word {
  margin: 0;
  font-size: clamp(2.25rem, 1.2rem + 3.6vw, 4.5rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.9;
  letter-spacing: -0.012em;
}
.as-rule {
  margin: clamp(14px, 1.6vw, 22px) 0 0;
  max-width: 30em;
  font-size: clamp(1.125rem, 1rem + 0.45vw, 1.3125rem);
  line-height: 1.5;
  text-wrap: pretty;
}
.as-close {
  margin: 0;
  padding-top: clamp(72px, 12vh, 144px);
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.25rem);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 1.05;
  letter-spacing: -0.012em;
}

/* Approval: what the $50 bought. My side of the page is on the left, theirs on the right (on a
   phone, theirs is underneath). Held, the lunch starts on my side and site.js carries each thing
   across to its place on theirs; the slice under the garlic bread is what stays. The copies on
   their side are the places the lunch lands, and are what shows as a still. */
.given-stage { display: flex; align-items: center; }
.given-stage > .wrap { width: 100%; }
.given-body {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  grid-template-areas: "word word" "rule rule" "mine theirs" "felt nice";
  column-gap: clamp(24px, 6vw, 120px);
  align-items: start;
}
.given-body > .as-word { grid-area: word; }
.given-rule { grid-area: rule; }
.given-mine,
.given-theirs { display: grid; margin-top: clamp(28px, 5vh, 64px); }
.given-mine { grid-area: mine; }
.given-theirs { grid-area: theirs; }
.given-item {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 0.8rem + 3.3vw, 4rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.95;
  letter-spacing: -0.012em;
  white-space: nowrap;
}
.given-mine > * { grid-column: 1; }
.given-mine > .given-slice,
.given-mine > .given-item--bread { grid-row: 1; }
.given-mine > :nth-child(3) { grid-row: 2; }
.given-mine > :nth-child(4) { grid-row: 3; }
.given-slice {
  align-self: center;
  justify-self: start;
  font-family: var(--font-read);
  font-style: italic;
  font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  line-height: 1;
}
.given-nice { grid-area: nice; margin: clamp(24px, 4vh, 48px) 0 0; }
.given-said {
  display: block;
  font-family: var(--font-read);
  font-style: italic;
  font-size: clamp(1.5rem, 1rem + 1.8vw, 2.5rem);
  line-height: 1.15;
}
.given-who { display: block; margin-top: 10px; font-size: 0.9375rem; color: var(--muted); }
.given-felt {
  grid-area: felt;
  margin: clamp(24px, 4vh, 48px) 0 0;
  font-family: var(--font-read);
  font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  line-height: 1.2;
}
html:not(.js) .given-mine .given-item,
.given.is-static .given-mine .given-item { display: none; }
.given.is-static .given-stage { display: block; padding-block: clamp(48px, 8vw, 112px); }
html.js .given:not(.is-static) .given-theirs .given-item { visibility: hidden; }
html.js .given:not(.is-static) :is(.given-slice, .given-nice, .given-felt) { opacity: 0; }
/* What moves while it's held is a layer of its own, so the stage around it isn't drawn again on
   every frame it moves (2026-10-06; the same for the other held pieces below). */
html.js .given:not(.is-static) :is(.given-mine .given-item, .given-slice, .given-nice, .given-felt) { will-change: transform, opacity; }
@media (max-width: 899px) {
  .given-body {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "word" "rule" "mine" "theirs" "nice" "felt";
  }
  .given-mine,
  .given-theirs { margin-top: 24px; }
  .given-theirs { justify-items: end; }
  .given-nice { text-align: right; }
  .given-felt { margin-top: 16px; }
}

/* The Three As keep to the page's columns, clear of the folio on the right. */
@media (min-width: 900px) {
  .given-body { grid-column: 2 / 11; }
  .rich-body { grid-column: 2 / 11; }
}

/* Attention: buried beneath. The morning after the $50, "with guilt buried beneath me", set in
   quiet type; Kingston's question lands on it letter by letter, and the guilt under each letter is
   gone. Then it is asked less, a few words fewer each lunch, and the guilt shows again under every
   word that goes, until only the guilt and "It never lasted." are left. Held, the guilt and the
   question share one place on the page, the guilt set on the question's lines so the letters land
   on it (site.js section 5). As a still it all reads in order, the question under the guilt. */
.rich-stage { display: flex; align-items: center; }
.rich-stage > .wrap { width: 100%; }
.rich.is-static .rich-stage { display: block; padding-block: clamp(96px, 16vh, 200px); }
.rich-body { --ask: clamp(3rem, 0.6rem + 8.6vw, 9.5rem); }
.rich-under {
  margin: clamp(40px, 7vh, 88px) 0 0;
  max-width: 30em;
  font-family: var(--font-read);
  font-size: clamp(1.25rem, 1rem + 0.9vw, 1.75rem);
  line-height: 1.45;
  color: var(--muted);
  text-wrap: pretty;
}
.rich-when {
  margin: clamp(28px, 5vh, 56px) 0 0;
  font-size: clamp(1.125rem, 1rem + 0.45vw, 1.3125rem);
  color: var(--muted);
}
.rich-ask {
  margin: 0.15em 0 0;
  max-width: 9em;
  font-family: var(--font-display);
  font-size: var(--ask);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.88;
  letter-spacing: -0.012em;
  text-wrap: balance;
}
.rich-given { margin: clamp(16px, 2vw, 28px) 0 0; font-size: clamp(1.125rem, 1rem + 0.45vw, 1.3125rem); }
.rich-end {
  margin: clamp(32px, 6vh, 72px) 0 0;
  font-family: var(--font-read);
  font-size: clamp(1.5rem, 1rem + 1.8vw, 2.5rem);
  line-height: 1.2;
}
.rich-ask .rq-w { white-space: nowrap; }
html.js .rich:not(.is-static) .rich-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "head" "when" "zone" "after";
}
html.js .rich:not(.is-static) .rich-head { grid-area: head; }
html.js .rich:not(.is-static) .rich-when { grid-area: when; }
html.js .rich:not(.is-static) :is(.rich-under, .rich-ask) { grid-area: zone; align-self: start; }
html.js .rich:not(.is-static) :is(.rich-given, .rich-end) { grid-area: after; align-self: start; }
/* The guilt on the question's lines, each line of it only as long as the line of the question
   over it: site.js sets its size and places each word. */
html.js .rich:not(.is-static) .rich-under {
  position: relative;
  margin: calc(var(--ask) * 0.15) 0 0;
  max-width: none;
  line-height: 1.2;
}
html.js .rich:not(.is-static) .rich-under .ru-w { position: absolute; left: 0; top: 0; white-space: nowrap; will-change: transform, opacity; }
html.js .rich:not(.is-static) .rich-ask { position: relative; z-index: 1; }
html.js .rich:not(.is-static) .rich-ask .rq-l { display: inline-block; transform-origin: 50% 55%; will-change: transform, opacity; }
html.js .rich:not(.is-static) :is(.rich-when, .rich-ask .rq-l, .rich-given > span, .rich-end) { opacity: 0; }
@media (max-width: 899px) {
  .rich-body { --ask: clamp(4.5rem, 0.72rem + 18.6vw, 7.2rem); }
}

/* Achievement: the role climbs. Held, site.js lifts it up the screen, and each time it nears the
   top a line drops in from above it and knocks it back down, until it is under two of them. As a
   still the three lines are stacked, the role at the bottom. */
.above-stage { display: flex; }
.above-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap);
  width: 100%;
}
.above-text { grid-column: 2 / 7; align-self: center; padding-right: var(--col-gap); }
.above-got { margin: clamp(16px, 2vw, 28px) 0 0; }
.above-area { grid-column: 7 / 11; display: flex; flex-direction: column-reverse; justify-content: flex-start; gap: 20px; }
.above-area > p { margin: 0; }
.above-me {
  max-width: 7.5em;
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 0.8rem + 5vw, 6rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.9;
  letter-spacing: -0.012em;
}
.above-b {
  max-width: 17em;
  font-family: var(--font-read);
  font-size: clamp(1.25rem, 0.9rem + 1.3vw, 2.125rem);
  line-height: 1.2;
}
.above.is-static .above-stage { display: block; padding-block: clamp(48px, 8vw, 112px); }
.above.is-static .above-grid,
html:not(.js) .above-grid { align-items: center; }
html.js .above:not(.is-static) .above-grid { height: 100%; }
html.js .above:not(.is-static) .above-area { position: relative; display: block; }
html.js .above:not(.is-static) .above-area > p { position: absolute; left: 0; top: 0; will-change: transform; }
@media (max-width: 899px) {
  .above-grid { grid-template-columns: minmax(0, 1fr); }
  .above-text,
  .above-area { grid-column: 1; }
  .above.is-static .above-area,
  html:not(.js) .above-area { margin-top: 32px; }
  html.js .above:not(.is-static) .above-grid { grid-template-rows: minmax(0, 1fr) auto; }
  html.js .above:not(.is-static) .above-area { grid-row: 1; }
  html.js .above:not(.is-static) .above-text { grid-row: 2; padding-bottom: clamp(24px, 5vh, 48px); }
}

/* Parts that rise into place with the scroll (the sign-off). site.js sets --rise from 0 to 1
   by where each part is on the screen, with no timing, so scrolling back up lowers them again.
   A field the reader has focused is never left faded. */
html.can-rise [data-rise] {
  opacity: var(--rise, 0);
  transform: translate3d(0, calc((1 - var(--rise, 0)) * 28px), 0);
  will-change: transform, opacity;
}
html.can-rise [data-rise]:focus-within { opacity: 1; transform: none; }

/* FAQ answers ease open and closed instead of snapping (where the browser supports it). */
@media (prefers-reduced-motion: no-preference) {
  .faq-list { interpolate-size: allow-keywords; }
  .faq-item::details-content {
    height: 0;
    overflow: clip;
    transition: height 0.28s cubic-bezier(0.23, 1, 0.32, 1), content-visibility 0.28s allow-discrete;
  }
  .faq-item[open]::details-content { height: auto; }
  .faq-item[open] .faq-answer { transition: opacity 0.24s ease-out 0.04s; }
  @starting-style { .faq-item[open] .faq-answer { opacity: 0; } }
}

/* Set pieces. Each chapter has one held moment that plays out under the reader's scroll, and
   each moves like the material it belongs to: the core's fragments build the words and are then
   clenched, driven and held, the mantle flows, the email that was wrong gives way, and the crust
   breaks (the break, the largest of them). site.js draws them; stages never set `position`
   (the engine makes them sticky). With reduced motion each one is a still, not a hold. */

/* Built, then held. The stage is see-through: the fragments are on the title page's canvas,
   behind it, and the chapter's own ground shows through. */
.core-build-stage { display: flex; align-items: center; }
html:not(.can-build) .core-build-stage { flex-direction: column; justify-content: center; }

/* The sentence the fragments finish. As plain type (reduced motion, no script) it shows whole,
   the second half set large in the display face. While the fragments build it (html.can-build),
   only the first half shows, in the middle of the screen above them (site.js sets its top), and
   the second half stays in the page for screen readers. */
.core-found {
  margin: 0 0 clamp(32px, 5vw, 56px);
  padding-inline: var(--gutter);
  text-align: center;
  font-family: var(--font-read);
  font-style: italic;
  font-size: clamp(1.375rem, 1.05rem + 1.3vw, 2.125rem);
  line-height: 1.3;
  color: var(--text-on-dark);
}
.cf-found,
.cf-built { display: block; }
.cf-built {
  margin-top: 0.3em;
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 900;
  font-stretch: 75%;
  font-size: clamp(3rem, 1rem + 8vw, 8rem);
  line-height: 0.9;
  letter-spacing: -0.012em;
}
html.can-build .core-build:not(.is-static) .core-found {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  top: 30%;
  margin: 0;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
}
html.can-build .core-build:not(.is-static) .cf-built {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
/* Held: the night my dad caught me. The first line takes over from "Worth can never be found." in
   its place and at its size, so it reads as the next thing said; the two from the book are each
   set by the fragments they belong to (site.js places them): under the knot as it is clenched,
   then under the fist where it was stopped. As plain type they follow the sentence, one under
   the other. */
.core-held {
  margin: 0 0 clamp(40px, 6vw, 72px);
  padding-inline: var(--gutter);
  text-align: center;
  font-family: var(--font-read);
  font-style: italic;
  font-size: clamp(1.1875rem, 1rem + 0.7vw, 1.625rem);
  line-height: 1.35;
  color: var(--text-on-dark);
}
.ch-night,
.ch-fist,
.ch-stop { display: block; }
html.can-build .core-build:not(.is-static) .core-held {
  position: absolute;
  z-index: 2;
  inset: 0;
  margin: 0;
  padding: 0;
  pointer-events: none;
}
html.can-build .core-build:not(.is-static) :is(.ch-fist, .ch-stop) {
  position: absolute;
  left: 0;
  top: 0;
  white-space: nowrap;
  opacity: 0;
  will-change: opacity, transform;
}
html.can-build .core-build:not(.is-static) .ch-night {
  position: absolute;
  left: 0;
  right: 0;
  top: 30%;
  padding-inline: var(--gutter);
  font-size: clamp(1.375rem, 1.05rem + 1.3vw, 2.125rem);
  line-height: 1.3;
  opacity: 0;
  will-change: opacity;
}
.core-build .chapter-open { position: relative; z-index: 1; width: 100%; padding-top: 0; }
html.can-build .core-build:not(.is-static) .chapter-open--core .intertitle { will-change: opacity; }
.core-build.is-static .core-build-stage { padding-top: var(--space-section); }

/* The mantle pours in. */
.pour-stage { background: var(--night); }
.pour-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
/* The molten surface cools inward: a hot edge, then rust, basalt, and the mantle's own dark. */
.pf-heat { fill: var(--sky); }
.pf-rust { fill: var(--nila-lit); }
.pf-basalt { fill: color-mix(in srgb, var(--nila-lit) 45%, var(--nila)); }
.pf-dark { fill: var(--nila); }
.pour-blobs ellipse { fill: var(--nila-lit); stroke: var(--sky); stroke-width: 2.5; }
.pour.is-static { height: 60vh; height: 60svh; }
.pour.is-static .pour-stage { position: relative; height: 100%; overflow: hidden; }

/* The email that was wrong. As a still (reduced motion, no script, a screen too short to hold
   it) the lines stack in reading order: the first email, ERROR, the second. Held, ERROR waits
   above one place the two emails share, and site.js plays it: ERROR arrives, "not" falls out
   of the first email and off the bottom of the screen, and the first gives way to the second. */
.wrong-stage { display: flex; align-items: center; }
.wrong-stage > .wrap { width: 100%; }
.wrong-before { margin: clamp(24px, 3vw, 40px) 0 0; max-width: 34em; color: var(--muted); text-wrap: balance; }
.wrong-mail {
  margin: clamp(20px, 2.4vw, 32px) 0 0;
  max-width: 22em;
  font-size: clamp(1.625rem, 1.05rem + 2.3vw, 2.875rem);
  line-height: 1.18;
  text-wrap: balance;
  color: var(--fg);
}
.wrong-not { display: inline-block; }
.wrong-error {
  margin: clamp(20px, 2.4vw, 32px) 0 0;
  font-family: var(--font-display);
  font-size: clamp(3.5rem, 1.2rem + 8vw, 9rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.85;
  text-transform: uppercase;
  color: var(--fg);
}
.wrong-source { margin: 18px 0 0; font-size: 0.9375rem; color: var(--muted); }
.wrong.is-static .wrong-stage { display: block; padding-block: clamp(24px, 4vw, 48px) clamp(48px, 7vw, 96px); }
html.js .wrong:not(.is-static) .wrong-body {
  display: grid;
  grid-template-areas: "head" "before" "error" "mail" "source";
  align-items: start;
}
html.js .wrong:not(.is-static) .wrong-body > h2 { grid-area: head; }
html.js .wrong:not(.is-static) .wrong-before { grid-area: before; }
html.js .wrong:not(.is-static) .wrong-error { grid-area: error; opacity: 0; }
html.js .wrong:not(.is-static) .wrong-mail { grid-area: mail; }
html.js .wrong:not(.is-static) .wrong-mail--second { opacity: 0; }
html.js .wrong:not(.is-static) .wrong-source { grid-area: source; }
html.js .wrong:not(.is-static) :is(.wrong-error, .wrong-mail, .wrong-not, .wrong-source) { will-change: transform, opacity; }

/* ---------- The author page ------------------------------------------ */
/* Four moments from the book, each moving the way its own story does (site.js sections 4 and 5),
   and what my logo is made of. As stills (no script, reduced motion) each is ordinary, complete type. */

/* Haaland or Sparsh. The question I was asked at football, the name I chose, my answer, who I
   am, and the portrait. Held, the stage is the screen: the question starts in its middle,
   "Haaland" goes dark, and the rest rises in under the question as it settles. */
.name-piece { padding-block: clamp(24px, 4vw, 56px) clamp(48px, 7vw, 96px); }
.name-grid { align-items: center; }
.name-ask {
  margin: 0;
  max-width: 16em;
  font-size: clamp(1.875rem, 1rem + 3vw, 3.75rem);
  line-height: 1.16;
  text-wrap: balance;
  color: var(--fg);
}
.name-other,
.name-mine { display: inline-block; }
.name-title { margin-top: clamp(18px, 2.2vw, 32px); font-size: clamp(3.25rem, 1rem + 8vw, 8rem); }
.name-answer { margin: clamp(18px, 2vw, 28px) 0 0; max-width: 30em; font-style: italic; color: var(--fg); }
.name-intro { margin: 14px 0 0; max-width: 30em; color: var(--muted); }
/* The portrait on the left (2026-10-11, as on the homepage). On a phone it heads the column, small,
   above the question, and fades in there as the rest arrives. */
@media (min-width: 900px) {
  .name-copy { grid-column: 6 / 13; grid-row: 1; }
  .name-portrait { grid-column: 2 / 5; grid-row: 1; }
  .name-portrait img { max-height: 70vh; max-height: 70svh; }
}
@media (max-width: 899px) {
  .name-copy,
  .name-portrait { grid-column: 1 / -1; }
  .name-portrait { order: -1; max-width: 112px; margin: 0 0 20px; }
}
html.js .name-piece:not(.is-static) { padding: 0; }
.name-stage { display: flex; align-items: center; }
.name-stage > .wrap { width: 100%; }
html.js .name-piece:not(.is-static) :is(.name-title, .name-answer, .name-intro, .name-portrait) { opacity: 0; }
/* The column moves on every frame of the hold's first half (the question gliding from the middle of
   the screen to its place), so it is a layer of its own and its type is never drawn again as it
   moves (2026-10-11). */
html.js .name-piece:not(.is-static) .name-copy { will-change: transform; }

/* I tried to buy my worth. The amounts I took stand in a margin beside the story, each as big
   as it was: its area grows with the amount (the type's size with its square root, --k), so
   $50 is five times the height of $2. site.js grows each in as its paragraph is read (--g) and
   drains them all away as my dad's question arrives (--drain). */
.buy-title { margin-bottom: clamp(28px, 3.5vw, 48px); }
.buy-amounts { display: flex; flex-direction: column; align-items: flex-start; gap: 0.12em; }
.buy-amt {
  --base: clamp(1.25rem, 0.8rem + 1vw, 2rem);
  display: block;
  font-family: var(--font-display);
  font-size: calc(var(--base) * var(--k, 1));
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.9;
  font-variant-numeric: lining-nums;
  color: var(--fg);
  transform-origin: 0 100%;
}
html.can-buy .buy-amt {
  opacity: calc(var(--g, 0) * (1 - var(--drain, 0)));
  transform: translate3d(0, calc(var(--drain, 0) * 56px), 0) scale(calc(0.4 + 0.6 * var(--g, 0)));
}
@media (min-width: 900px) {
  .buy-title { grid-column: 2 / 12; }
  .buy-margin { grid-column: 2 / 5; grid-row: 2; }
  .buy-story { grid-column: 5 / 12; grid-row: 2; }
  .buy-amounts { position: sticky; top: 16vh; top: 16svh; }
}
/* On a phone the amounts ride in a row at the top of the screen while the story passes under. */
@media (max-width: 899px) {
  .buy-margin {
    position: sticky;
    z-index: 2;
    top: 0;
    grid-column: 1 / -1;
    margin: 0 calc(var(--gutter) * -1) 12px;
    padding: 12px var(--gutter) 14px;
    background: var(--bg);
  }
  .buy-amounts { flex-direction: row; align-items: flex-end; gap: 0.4em; }
  .buy-amt { --base: 0.95rem; }
}

/* Pitch black. site.js sets --dark (0 to 1) as the passage reaches the middle of the screen, and
   --lit-at, where the reading line crosses it. Everything around it goes dark, the rest of the
   page included (a layer fixed to the screen, under this passage and over everything else), and
   the passage itself is masked to a band a line deep at the reading line. */
.pitch { padding-top: 0; }
@media (min-width: 900px) { .pitch-story { grid-column: 5 / 12; } }
html.can-pitch .pitch { position: relative; z-index: 3; }
html.can-pitch .pitch::before {
  content: "";
  position: fixed;
  z-index: -1;
  inset: 0;
  background: var(--pitch-black);
  opacity: var(--dark, 0);
  pointer-events: none;
}
html.can-pitch .pitch-story {
  --lo: calc(1 - 0.9 * var(--dark, 0));
  --band: calc(var(--lh, 32px) * 0.6);
  --fade: calc(var(--lh, 32px) * 1.1);
  -webkit-mask-image: linear-gradient(to bottom,
    rgb(0 0 0 / var(--lo)) calc(var(--lit-at, 0px) - var(--band) - var(--fade)),
    #000 calc(var(--lit-at, 0px) - var(--band)),
    #000 calc(var(--lit-at, 0px) + var(--band)),
    rgb(0 0 0 / var(--lo)) calc(var(--lit-at, 0px) + var(--band) + var(--fade)));
  mask-image: linear-gradient(to bottom,
    rgb(0 0 0 / var(--lo)) calc(var(--lit-at, 0px) - var(--band) - var(--fade)),
    #000 calc(var(--lit-at, 0px) - var(--band)),
    #000 calc(var(--lit-at, 0px) + var(--band)),
    rgb(0 0 0 / var(--lo)) calc(var(--lit-at, 0px) + var(--band) + var(--fade)));
}

/* One, two, three. As a still: each habit's name large, my sentence under it, then the line.
   Held, the three sit in a row, each as wide as the screen (--lens-w), and site.js moves the
   whole row as one camera: close on each in turn, then pulled back until all three are small. */
.lens.is-static,
html:not(.js) .lens { padding-block: var(--space-section); }
.lens-world { display: grid; gap: clamp(40px, 6vw, 80px); padding-inline: var(--gutter); }
.lens-habit { margin: 0; }
.lens-name {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(3.25rem, 1rem + 9vw, 10rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.88;
  letter-spacing: -0.012em;
  color: var(--fg);
}
.lens-said {
  display: block;
  max-width: 18em;
  margin-top: 0.5em;
  font-size: clamp(1.375rem, 0.9rem + 1.6vw, 2.5rem);
  line-height: 1.2;
  color: var(--fg);
}
.lens-far {
  margin: clamp(40px, 5vw, 64px) 0 0;
  padding-inline: var(--gutter);
  max-width: 34em;
  font-size: clamp(1.25rem, 1rem + 1vw, 1.875rem);
  line-height: 1.3;
  color: var(--fg);
}
@media (min-width: 900px) {
  .lens-world,
  .lens-far { padding-inline: max(var(--gutter), calc((100% - var(--max)) / 2 + var(--gutter))); }
}
html.js .lens:not(.is-static) .lens-stage { overflow: clip; }
html.js .lens:not(.is-static) .lens-world {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  gap: 0;
  width: max-content;
  padding: 0;
  transform-origin: 0 0;
}
html.js .lens:not(.is-static) .lens-habit {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: var(--lens-w, 100vw);
  padding-inline: clamp(24px, 8vw, 160px);
}
/* Close up, each habit fills the screen. */
html.js .lens:not(.is-static) .lens-name { font-size: min(15vw, 30vh); font-size: min(15vw, 30svh); white-space: nowrap; }
/* Every sentence keeps room for three lines, so pulled back the three names sit on one line. */
html.js .lens:not(.is-static) .lens-said { max-width: 16em; min-height: 3.6em; font-size: clamp(1.5rem, 0.9rem + 2.4vw, 3.5rem); }
html.js .lens:not(.is-static) .lens-far {
  position: absolute;
  left: 0;
  right: 0;
  max-width: none;
  padding-inline: var(--gutter);
  text-align: center;
  opacity: 0;
}

/* What my logo is made of (2026-10-05). As a still: the whole logo beside four paragraphs. Held,
   the logo is built one part at a time (the dark, the cursor, the planet laid layer by layer),
   then made small beside the book's name; a line runs from each paragraph to its part and the
   paragraph's first line stands on it. site.js sizes the logo to the screen (--mark-s) and places
   everything on the line. "First, the dark": as the first paragraph comes in, the stage sinks from
   nila to night (.mark-dark, --dark), so the logo is seen on its own ground in its own colours, and
   the section after it starts as night and turns to nila, like a mantle section after the core.
   As a still it sits on the nila, so there its frame's edge is the ground's rule colour (a nila edge
   would vanish into the nila around it). */
.mark-tour.is-static,
html:not(.js) .mark-tour { padding-block: 0 var(--space-section); }
.mark-title { grid-column: 1 / -1; margin-bottom: clamp(28px, 3.5vw, 48px); }
.mark-figure { max-width: 240px; }
.mark-figure svg { display: block; width: 100%; height: auto; }
.mt-field { fill: var(--night); }
.mt-planet,
.mt-band { fill: var(--nila); }
.mt-edge { fill: var(--rule-nila); }
html.js .mark-tour:not(.is-static) .mt-edge { fill: var(--nila); }
.mt-cursor { fill: var(--sky); }
.mt-band { display: none; }
.mark-beats { margin-top: clamp(24px, 4vw, 40px); }
.mark-beat {
  max-width: 26em;
  font-size: clamp(1.1875rem, 1.05rem + 0.5vw, 1.4375rem);
  line-height: 1.5;
  color: var(--fg);
}
.mark-name,
.mark-line { display: none; }
@media (min-width: 900px) {
  .mark-title { grid-column: 2 / 13; }
  .mark-figure { grid-column: 2 / 7; max-width: 420px; }
  .mark-beats { grid-column: 8 / 13; margin-top: 0; }
}
html.js .mark-tour:not(.is-static) { padding: 0; }
.mark-stage { display: flex; align-items: center; }
.mark-stage > .wrap { position: relative; width: 100%; }
.mark-dark { display: none; }
html.js .mark-tour:not(.is-static) .mark-dark {
  display: block;
  position: absolute;
  inset: 0;
  background: var(--night);
  opacity: 0;
  pointer-events: none;
}
html.js .mark-tour:not(.is-static) + .section { background: linear-gradient(to bottom, var(--night), var(--nila) 360px); }
html.js .mark-tour:not(.is-static) .mark-grid { position: relative; align-items: start; }
html.js .mark-tour:not(.is-static) .mark-figure {
  width: var(--mark-s, 160px);
  max-width: 100%;
  margin-bottom: var(--mark-under, 0px);
}
html.js .mark-tour:not(.is-static) .mt-svg { transform-origin: 0 0; will-change: transform; }
html.js .mark-tour:not(.is-static) .mt-planet { display: none; }
html.js .mark-tour:not(.is-static) .mt-band { display: inline; opacity: 0; }
html.js .mark-tour:not(.is-static) .mt-cursor { opacity: 0; }
.mt-cursor.is-blinking { animation: edge-blink 1.1s steps(1, end) infinite; }
html.js .mark-tour:not(.is-static) .mark-beats { display: grid; }
html.js .mark-tour:not(.is-static) .mark-beat { grid-area: 1 / 1; margin: 0; opacity: 0; will-change: transform, opacity; }
html.js .mark-tour:not(.is-static) .mark-name {
  display: block;
  position: absolute;
  left: 0;
  top: 0;
  margin: 0;
  white-space: nowrap;
  font-family: var(--font-display);
  font-weight: 800;
  font-stretch: 75%;
  letter-spacing: 0.01em;
  line-height: 1;
  color: var(--fg);
  opacity: 0;
}
html.js .mark-tour:not(.is-static) .mark-line {
  display: block;
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 1px;
  background: var(--muted);
  transform-origin: 0 0;
  opacity: 0;
}

/* ---------- The practices page ---------------------------------------- */
/* Each practice is told through its own story from the book draft, and each is set its own way
   (site.js sections 4 and 5): the last rep is held and pushed up by the scroll, the ledge is
   3 centimetres wide, the five core skills fill only while they are read, and the list fills the
   page. The Mantle and Crust are still being written, and each is told through the story it has:
   "Selected." turns out to be only the top layer, the greetings go out and one question comes
   back, and the pressure is redirected. As stills (no script, reduced motion) each is ordinary,
   complete type. */

/* Dawn, practice by practice: "You start at the centre, where nobody's watching, and work
   outward to the part people actually see." site.js paints the sky behind the page (the body)
   the colour at the reading line, from the night, through pitch black at Practice 1, up into a
   nila a little lighter than the mantle's, so the sections' own grounds step aside for it.
   Without script they stay nila. The page then rises into morning for the Crust, in a band with
   no text on it, from the same lightest nila site.js ends on. Keyed to html.js (set in the
   page's head, before the first paint) rather than to site.js running, and the body starts at
   the night the page opens on, so a refresh never flashes the sections' nila first. */
html.js .dawn > .layer-mantle { background-color: transparent; }
html.js body:has(> main.dawn) { background-color: var(--night); }
.rise--dawn { background: linear-gradient(to bottom, var(--nila), var(--morning)); }

/* Found underneath: the opening. The practices in the order I first wrote them in, then the two
   I found underneath them. The numbers are places and never move; site.js moves the titles past
   them and brings the first two up out of the dark. As a still (no script, reduced motion, a
   screen too short) it is the list in its order and the sentence that says how it got there. */
.found { padding-block: clamp(32px, 5vw, 72px) clamp(24px, 3vw, 40px); }
.found-copy { grid-column: 1 / -1; }
@media (min-width: 900px) { .found-copy { grid-column: 2 / 12; } }
.found-list { margin: clamp(24px, 3.2vw, 44px) 0 0; padding: 0; list-style: none; }
/* The titles are the opening's display type, as large as six of them can be and still fit the
   screen with the title, so the hold is kept on ordinary laptop screens. The numbers are set in
   the same column as each practice's number further down. */
.found-row {
  display: grid;
  grid-template-columns: clamp(3rem, 7vw, 6rem) minmax(0, 1fr);
  gap: 0 clamp(16px, 3vw, 40px);
  align-items: baseline;
  padding-block: clamp(4px, 0.9vh, 10px);
  font-family: var(--font-display);
  font-size: min(clamp(1.5rem, 0.9rem + 3.2vw, 4rem), 6vh);
  font-weight: 800;
  font-stretch: 75%;
}
.found-num {
  font-size: 1.2em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
.found-name { line-height: 1.02; text-wrap: balance; }
/* The two things I say about the list share one place under it: how it started, which is pushed
   down with the first order and goes, and how it ended. */
.found-foot {
  display: grid;
  margin-top: clamp(24px, 3.2vw, 44px);
  font-size: clamp(1.25rem, 1rem + 0.9vw, 1.75rem);
  line-height: 1.4;
}
.found-foot > p { grid-area: 1 / 1; max-width: 26em; margin: 0; }
.found-after { padding-top: clamp(24px, 3vw, 40px); }
.found.is-static .found-first,
html:not(.js) .found-first { display: none; }
/* Held: the stage is the screen. The first half of the last line has already been seen, as the
   list moved, so it is kept for screen readers only. */
html.js .found:not(.is-static) { padding: 0; }
html.js .found:not(.is-static) .found-first { will-change: transform, opacity; }
html.js .found:not(.is-static) .found-stage { display: flex; align-items: center; }
html.js .found:not(.is-static) .found-stage > .wrap { width: 100%; }
html.js .found:not(.is-static) .found-was {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}
html.js .found:not(.is-static) :is(.found-row--under .found-name, .found-row:nth-child(n+5) .found-num, .found-then) { opacity: 0; }
html.js .found:not(.is-static) .found-row:not(.found-row--under) .found-name { will-change: transform; }
/* On a phone some titles wrap to two lines, and every place is as tall as the tallest, so each
   title sits in the middle of its place and the list stays evenly spaced. */
@media (max-width: 899px) {
  html.js .found:not(.is-static) .found-row { align-items: center; }
}
html.js .rise--dawn { background: linear-gradient(to bottom, color-mix(in srgb, var(--nila) 70%, var(--nila-lit)), var(--morning)); }

.practice { padding-top: clamp(64px, 8vw, 120px); }
.practice-head {
  display: grid;
  grid-template-columns: clamp(3rem, 7vw, 6rem) minmax(0, 1fr);
  gap: 0 clamp(16px, 3vw, 40px);
  align-items: start;
  padding-top: clamp(20px, 2.4vw, 30px);
  border-top: 1px solid var(--rule);
}
.practice-body { margin-top: clamp(28px, 3.5vw, 48px); font-size: var(--step-read); line-height: 1.65; }
.practice-body p { max-width: 34em; }
.practice-body .link-cta { margin-top: 4px; }
@media (min-width: 900px) {
  /* The story lines up with the title, past the number. */
  .practice-body,
  .earn { padding-left: calc(clamp(3rem, 7vw, 6rem) + clamp(16px, 3vw, 40px)); }
  /* Search for the Truth sits to the right, away from the others. */
  .practice--trail .practice-body { padding-left: 0; width: fit-content; margin-left: auto; }
}
.practice-later .practice-body { padding-left: 0; }
.crust-story { margin-top: clamp(28px, 3.5vw, 40px); }

/* The ledge: "about 3 centimetres wide", so the passage is set 3 centimetres wide, and the rest
   of the width beside it is the drop. */
.ledge {
  width: 3cm;
  margin-block: clamp(36px, 5vw, 64px);
  font-size: 1rem;
  line-height: 1.5;
  hyphens: none;
  overflow-wrap: normal;
  text-wrap: wrap;
}

/* The last rep. As a still: the story in order, with "One more." set large after the first line.
   Held: the story on the left a line at a time, and "One more." in a lane of its own on the right
   (below on a phone), where site.js moves it up and down the lane. */
.rep { padding-top: clamp(40px, 5vw, 72px); }
.rep-grid > * { grid-column: 1 / -1; }
@media (min-width: 900px) { .rep-grid > * { grid-column: 3 / 11; } }
.rep-line {
  max-width: 22em;
  margin: 0 0 0.8em;
  font-size: clamp(1.25rem, 1rem + 0.9vw, 1.75rem);
  line-height: 1.35;
  text-wrap: balance;
  color: var(--fg);
}
.rep-lane { margin: 0.1em 0 0.35em; }
.rep-weight {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(3rem, 1rem + 7vw, 7rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.9;
  white-space: nowrap;
  color: var(--fg);
}
html.js .rep:not(.is-static) { padding: 0; }
html.js .rep:not(.is-static) .rep-stage { display: flex; align-items: center; }
html.js .rep:not(.is-static) .rep-stage > .wrap { width: 100%; }
html.js .rep:not(.is-static) .rep-grid { align-items: center; }
html.js .rep:not(.is-static) .rep-line { grid-row: 1; margin: 0; opacity: 0; }
html.js .rep:not(.is-static) .rep-beat { opacity: 0; }
html.js .rep:not(.is-static) .rep-lane {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 50vh;
  height: 50svh;
  margin: 0;
}
html.js .rep:not(.is-static) .rep-weight { font-size: min(21vw, 12vh); font-size: min(21vw, 12svh); transform-origin: 50% 100%; will-change: transform; }
@media (min-width: 900px) {
  html.js .rep:not(.is-static) .rep-line { grid-column: 2 / 7; }
  html.js .rep:not(.is-static) .rep-lane { grid-row: 1; grid-column: 7 / 13; height: min(76vh, 720px); height: min(76svh, 720px); }
  html.js .rep:not(.is-static) .rep-weight { font-size: min(9vw, 16vh); font-size: min(9vw, 16svh); }
}
@media (max-width: 899px) {
  html.js .rep:not(.is-static) .rep-line { align-self: end; }
  html.js .rep:not(.is-static) .rep-lane { grid-row: 2; margin-top: 12px; }
}

/* You can't buy everything. The five core skills, each in the heaviest type. site.js shows each
   hollow until it has been read for a moment, filling it from the baseline up (--earn, 0 to 1). */
.earn { margin-top: clamp(48px, 6vw, 88px); }
.earn-lead {
  max-width: 30em;
  margin: 0;
  font-size: clamp(1.1875rem, 1.05rem + 0.5vw, 1.4375rem);
  line-height: 1.5;
  color: var(--fg);
}
.earn-list { margin: clamp(28px, 3.5vw, 48px) 0; padding: 0; list-style: none; }
.earn-word {
  position: relative;
  isolation: isolate;
  width: fit-content;
  font-family: var(--font-display);
  font-size: clamp(2.75rem, 1rem + 6.4vw, 7.5rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 1;
  letter-spacing: -0.012em;
}
.earn-fill { display: block; color: var(--fg); }
.earn-empty { display: none; }
/* The fill is a window that rises from the baseline, with the word held still inside it: the
   window moves down by what is not yet earned and the word moves up by the same, so it is only
   ever moved, never masked, and filling costs no drawing (a clip-path redrew the word every
   frame). The 0.1em of room on every side keeps the letters' edges whole. */
/* Its own formatting context, so the window's negative margins don't collapse through it. */
html.can-earn .earn-word { display: flow-root; }
html.can-earn .earn-fill {
  margin: -0.1em;
  padding: 0.1em;
  overflow: hidden;
  overflow: clip;
  transform: translate3d(0, calc((1 - var(--earn, 0)) * 100%), 0);
  will-change: transform;
}
html.can-earn .earn-ink {
  display: block;
  transform: translate3d(0, calc((var(--earn, 0) - 1) * (100% + 0.2em)), 0);
  will-change: transform;
}
html.can-earn .earn-empty {
  position: absolute;
  z-index: -1;
  inset: 0;
  display: block;
  color: transparent;
  -webkit-text-stroke: 1px var(--muted);
  pointer-events: none;
}
.earn-after { max-width: 30em; margin: 0; color: var(--muted); }

/* The list that could fill the chapter. As a still: "Life is short.", the five sentences and
   the line that answers them. Held: the sentences arrive one at a time in a page that site.js
   then fills with the list, over and over, until "They need awareness." stops it. */
.waste { padding-top: clamp(40px, 5vw, 72px); }
.waste-grid > * { grid-column: 1 / -1; }
@media (min-width: 900px) {
  .waste-grid > * { grid-column: 2 / 11; }
  /* Set solid, like a page of the book. */
  html.js .waste:not(.is-static) .waste-page { grid-column: 2 / 12; text-align: justify; }
}
.waste-short {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 1rem + 5vw, 5.5rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.9;
  color: var(--fg);
}
.waste-soon { max-width: 30em; margin: 16px 0 0; color: var(--muted); }
.waste-page {
  max-width: 40em;
  margin: clamp(24px, 3vw, 40px) 0 0;
  font-size: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
  line-height: 1.55;
  color: var(--fg);
}
.waste-could { font-style: italic; }
.waste-more > span { color: var(--muted); }
.waste-need {
  max-width: 14em;
  margin: clamp(28px, 3.5vw, 48px) 0 0;
  font-family: var(--font-display);
  font-size: clamp(2rem, 1rem + 3.6vw, 4.25rem);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 1;
  text-wrap: balance;
  color: var(--fg);
}
html.js .waste:not(.is-static) { padding: 0; }
html.js .waste:not(.is-static) .waste-stage { display: flex; align-items: center; }
html.js .waste:not(.is-static) .waste-stage > .wrap { width: 100%; }
html.js .waste:not(.is-static) .waste-page {
  grid-row: 2;
  max-width: none;
  height: 56vh;
  height: 56svh;
  overflow: hidden;
  font-size: clamp(1.1875rem, 0.85rem + 1vw, 1.75rem);
  -webkit-mask-image: linear-gradient(to bottom, #000 80%, transparent);
  mask-image: linear-gradient(to bottom, #000 80%, transparent);
}
html.js .waste:not(.is-static) .waste-need { grid-row: 2; z-index: 1; align-self: center; margin: 0; opacity: 0; }
html.js .waste:not(.is-static) :is(.waste-s, .waste-more > span) { opacity: 0; }

/* Small moments in the reading. Each belongs to the sentence it sits in and is moved by where
   that sentence is on the screen (site.js section 4); without script, or with reduced motion,
   the words are simply set.
   By the slightest: the paragraph turns upward about its left edge. */
.slight { transform-origin: 0 50%; }
/* Fell away: the friend's words, each able to leave the line on its own. */
.fall-w { display: inline-block; }
/* Stood still: the line keeps its place on the screen while the page goes on past it, and the
   next line comes up to meet it. */
/* (The room is content, not padding: a sticky line can't travel into its box's padding.) */
.still-hold { margin-bottom: 1em; }
.still-hold::after { content: ""; display: block; height: 24vh; height: 24svh; }
.still { position: sticky; top: 44vh; top: 44svh; }
@media (prefers-reduced-motion: reduce) {
  .still-hold::after { display: none; }
  .still { position: static; }
}
/* Built it myself: the columns this site is laid out on, the same twelve (one on a phone),
   behind the paragraph. site.js places them and brings them up and down with the reading. */
.has-guides { position: relative; isolation: isolate; }
.guides {
  position: absolute;
  z-index: -1;
  left: var(--gutter);
  right: var(--gutter);
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap);
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 22%, #000 78%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 22%, #000 78%, transparent);
}
.guides > i {
  background: color-mix(in srgb, var(--accent) 7%, transparent);
  box-shadow: inset 1px 0 0 color-mix(in srgb, var(--accent) 22%, transparent), inset -1px 0 0 color-mix(in srgb, var(--accent) 22%, transparent);
}
@media (max-width: 899px) {
  .guides { grid-template-columns: minmax(0, 1fr); }
  .guides > i { background: none; }
  .guides > i:nth-child(n + 2) { display: none; }
}
/* Way off: the paragraph drifts from its top-left corner. */
.drift { transform-origin: 0 0; }

/* Where the layers came from. As a still: the third try, "Selected.", how it felt, the two layers
   under it, and the line. Held: "Selected." sits high, its layer name beside it; the two lines
   come in under it and go, and the same place then opens into the layers beneath it (site.js). */
.soon { padding-top: clamp(40px, 5vw, 72px); }
.soon-grid > * { grid-column: 1 / -1; }
@media (min-width: 900px) { .soon-grid > * { grid-column: 2 / 12; } }
.soon-try { margin: 0; color: var(--muted); font-size: var(--step-read); }
.soon-top,
.soon-layer {
  display: grid;
  grid-template-columns: clamp(5.25rem, 11vw, 9.5rem) minmax(0, 1fr);
  gap: 0 clamp(12px, 2vw, 28px);
  align-items: baseline;
}
.soon-top { margin-top: 8px; }
.soon-name {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.125rem, 0.9rem + 0.9vw, 1.75rem);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 1;
  letter-spacing: -0.012em;
  color: var(--accent);
}
.soon-word {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(3.25rem, 1rem + 9vw, 8.5rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.9;
  color: var(--fg);
}
.soon-lines { margin-top: clamp(24px, 3vw, 40px); }
.soon-line {
  max-width: 22em;
  margin: 0 0 0.5em;
  font-size: clamp(1.375rem, 1rem + 1.2vw, 2.125rem);
  line-height: 1.3;
  text-wrap: balance;
  color: var(--fg);
}
.soon-under { margin-top: clamp(24px, 3vw, 40px); }
.soon-layer { padding-block: clamp(14px, 2.2vh, 26px); border-top: 1px solid var(--rule); }
.soon-said {
  max-width: 24em;
  margin: 0;
  font-size: clamp(1.25rem, 1rem + 0.9vw, 1.875rem);
  line-height: 1.35;
  text-wrap: balance;
  color: var(--fg);
}
.soon-from {
  margin: clamp(20px, 3vh, 36px) 0 0;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1rem + 1.8vw, 2.75rem);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 1.05;
  color: var(--fg);
}
.soon-how { margin-top: clamp(40px, 5vw, 64px); }
@media (min-width: 900px) { .practice-later .soon-how { padding-left: calc(clamp(5.25rem, 11vw, 9.5rem) + clamp(12px, 2vw, 28px)); } }
html.js .soon:not(.is-static) { padding: 0; }
html.js .soon:not(.is-static) .soon-stage { display: flex; align-items: center; }
html.js .soon:not(.is-static) .soon-stage > .wrap { width: 100%; }
/* Held, the two lines and the layers share one place; the line under them is set below both. */
html.js .soon:not(.is-static) .soon-try { grid-row: 1; padding-left: calc(clamp(5.25rem, 11vw, 9.5rem) + clamp(12px, 2vw, 28px)); }
html.js .soon:not(.is-static) .soon-top { grid-row: 2; }
html.js .soon:not(.is-static) .soon-lines,
html.js .soon:not(.is-static) .soon-under { grid-row: 3; align-self: start; }
html.js .soon:not(.is-static) .soon-lines { padding-left: calc(clamp(5.25rem, 11vw, 9.5rem) + clamp(12px, 2vw, 28px)); }
html.js .soon:not(.is-static) .soon-from { grid-row: 4; padding-left: calc(clamp(5.25rem, 11vw, 9.5rem) + clamp(12px, 2vw, 28px)); opacity: 0; }
html.js .soon:not(.is-static) .soon-word { font-size: min(19vw, 17vh); font-size: min(19vw, 17svh); will-change: transform; }
html.js .soon:not(.is-static) :is(.soon-word, .soon-line, .soon-top .soon-name, .soon-layer) { opacity: 0; }
@media (max-width: 599px) {
  .soon { --soon-label: 4.25rem; }
  .soon-top,
  .soon-layer { grid-template-columns: var(--soon-label) minmax(0, 1fr); }
  html.js .soon:not(.is-static) :is(.soon-try, .soon-lines, .soon-from) { padding-left: calc(var(--soon-label) + clamp(12px, 2vw, 28px)); }
  html.js .soon:not(.is-static) .soon-word { font-size: min(14vw, 11vh); font-size: min(14vw, 11svh); }
}

/* The other gate. As a still: the greeting, the two lines before the question, the question, and
   who asked it. Held: the greetings are copied into the band and carried off to the right
   (site.js); the question comes in from the right and stops where they started; the three lines
   take turns in one place under it. */
.gate { padding-top: clamp(40px, 5vw, 72px); }
.gate-grid > * { grid-column: 1 / -1; }
@media (min-width: 900px) { .gate-grid > * { grid-column: 2 / 12; } }
.gate-out {
  max-width: 34em;
  margin: 0;
  font-size: var(--step-read);
  line-height: 1.5;
  color: var(--fg);
}
.gate-said,
.gate-hello {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1rem + 1.8vw, 2.75rem);
  font-weight: 700;
  font-stretch: 75%;
  line-height: 1.1;
  white-space: nowrap;
}
.gate-said { display: block; margin-top: 8px; }
.gate-band { display: none; }
.gate-in {
  max-width: 11em;
  margin: clamp(24px, 3vw, 40px) 0;
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 1rem + 6vw, 7rem);
  font-weight: 900;
  font-stretch: 75%;
  line-height: 0.92;
  text-wrap: balance;
  color: var(--fg);
}
.gate-cap {
  max-width: 30em;
  margin: 0 0 0.8em;
  font-size: clamp(1.1875rem, 1rem + 0.6vw, 1.5rem);
  line-height: 1.4;
  text-wrap: pretty;
  color: var(--fg);
}
html.js .gate:not(.is-static) { padding: 0; }
html.js .gate:not(.is-static) .gate-stage { display: flex; align-items: center; overflow: hidden; }
html.js .gate:not(.is-static) .gate-stage > .wrap { width: 100%; }
html.js .gate:not(.is-static) .gate-out { grid-row: 1; }
/* The greeting itself is said by the copies; it stays here for screen readers only. */
html.js .gate:not(.is-static) .gate-said {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
html.js .gate:not(.is-static) .gate-band {
  grid-row: 2;
  display: block;
  position: relative;
  height: 42vh;
  height: 42svh;
  margin-block: clamp(12px, 2vh, 24px);
}
.gate-hello { position: absolute; left: 0; top: 0; color: var(--fg); opacity: 0; will-change: transform, opacity; }
html.js .gate:not(.is-static) .gate-in { grid-row: 2; z-index: 1; align-self: center; margin: 0; opacity: 0; will-change: transform; }
html.js .gate:not(.is-static) .gate-cap { grid-row: 3; align-self: start; margin: 0; opacity: 0; }
@media (max-width: 899px) {
  html.js .gate:not(.is-static) .gate-band { height: 38vh; height: 38svh; }
  html.js .gate:not(.is-static) .gate-in { font-size: min(13vw, 8vh); font-size: min(13vw, 8svh); }
}

/* Pressure, redirected. Both lines are set in the heaviest face; how much of the pressure is on
   each is how squeezed and how heavy it is (site.js moves it from the first to the second as the
   calls are read). Without script it has already moved. */
.press { margin-top: clamp(40px, 5vw, 72px); }
.press-line {
  max-width: 14em;
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2.25rem, 1rem + 4.6vw, 5.5rem);
  line-height: 0.95;
  text-wrap: balance;
  color: var(--fg);
}
.press-was { font-weight: 500; font-stretch: 100%; letter-spacing: 0.005em; }
.press-now { font-weight: 900; font-stretch: 75%; letter-spacing: -0.01em; }
/* Between the face's steps each line is stretched by what's left to go, from its left edge, on a
   layer of its own so the stretch is never drawn again (2026-10-06). */
html.can-press .press-line { transform-origin: 0 50%; will-change: transform; }
.press-calls { margin-block: clamp(28px, 3.5vw, 48px); }
.press-now + .practice-body { margin-top: clamp(28px, 3.5vw, 48px); }

/* The close answers Max's question. */
.asked { margin-top: clamp(72px, 9vw, 136px); padding-top: clamp(20px, 2.4vw, 30px); border-top: 1px solid var(--rule); }
.asked-q { margin: 0; font-size: var(--step-read); color: var(--fg); }
.asked-a {
  max-width: 17em;
  margin: 12px 0 0;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 1rem + 2.6vw, 3.25rem);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 1.05;
  text-wrap: balance;
  color: var(--fg);
}

/* ---------- Reduced motion -------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }
  .cursor { animation: none; opacity: 1; }
  .core::after { animation: none; opacity: 0.4; }
}

