/* =========================================================================
   BOOKS . the v6 experience, preserved whole.
   app.css moved to the v7 tokens (Montserrat, aged gold); this page keeps
   the identity it was designed in. Custom properties inherit, so overriding
   them on the page's body restores every rule below without touching one.
   ========================================================================= */
body.pf-v6 {
  --bg:             #0D0B0A;
  --surface:        #171413;
  --surface-raised: #221D1B;
  --ink:            #E8E1D5;
  --ink-muted:      #9C938A;
  --ink-faint:      #8A8079;
  --accent:         #E0B732;
  --accent-deep:    #A8801A;
  --ember:          #8E1114;
  --ember-deep:     #4A0A0C;
  --ember-lift:     #C81E22;
  --line:           #2C2624;
  --font: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --display-stretch: 79%;
  --display-track: -0.022em;
  --display-weight: 850;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
}
/* =========================================================================
   HOME . chapter layouts

   Three chapters are scroll scenes: the section is several viewports tall and
   its inner panel is sticky, so the panel holds the screen while the scroll
   drives it. The pinning is pure CSS. Script only feeds progress in as custom
   properties, and every default is the safe, readable state.

   Note: scene sections use overflow: clip, never hidden. hidden would make
   them scroll containers and kill the sticky child.
   ========================================================================= */

/* ---------- Split-text primitives (built by script) ---------- */
.pf-w {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  /* Reserve the descender so the mask never clips a g, y or p. */
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}
.pf-c { display: inline-block; will-change: transform; }

/* =========================================================================
   01 . THE OPENING . a forge that holds the screen
   ========================================================================= */
.hero {
  min-height: 100svh;
  padding: 0;
  display: block;
  background: var(--bg);
  overflow: clip;
}
.hero__sticky {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  align-items: center;
  overflow: hidden;
  isolation: isolate;
  padding-top: 132px;
  padding-bottom: var(--s-md);
}

.hero__stage {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(90% 70% at 30% 100%, rgba(142, 17, 20, 0.75) 0%, transparent 62%),
    radial-gradient(70% 55% at 78% 6%, rgba(224, 183, 50, 0.14) 0%, transparent 60%),
    linear-gradient(180deg, var(--surface) 0%, var(--bg) 100%);
}
/* JJ in the ground of the hero. The shader canvas is opaque, so the picture
   has to sit above it and blend rather than hide behind it: screen keeps the
   fire showing through, and because the photograph is nearly black except
   for the face and the crimson wall, only those parts add any light.

   The mask is the load-bearing part. The headline sits between roughly a
   third and four fifths of the panel, and screen-blending anything there
   would eat the contrast, so the picture is held to the band above the copy
   and a whisper at the foot. Blending is confined to the stage, which is
   its own stacking context, so nothing further up the page is touched. */
.hero__photo {
  position: absolute;
  inset: 0;
  background-image: var(--hero-photo);
  background-size: cover;
  /* Framed from the very top of the plate so the whole head is in shot;
     anything further down cut him off at the glasses. */
  background-position: 50% 2%;
  background-repeat: no-repeat;
  mix-blend-mode: screen;
  opacity: 0.85;
  filter: contrast(1.05) saturate(0.95);
  pointer-events: none;
  /* Measured rather than guessed: with this mask wide open the headline
     still holds 8.7:1, so the picture only needs a vignette, not the hard
     band it had before. It stays whole and simply softens toward the
     edges of the plate. */
  -webkit-mask-image: radial-gradient(128% 104% at 50% 30%,
    #000 0%,
    #000 40%,
    rgba(0, 0, 0, 0.72) 62%,
    rgba(0, 0, 0, 0.42) 82%,
    rgba(0, 0, 0, 0.12) 100%);
  mask-image: radial-gradient(128% 104% at 50% 30%,
    #000 0%,
    #000 40%,
    rgba(0, 0, 0, 0.72) 62%,
    rgba(0, 0, 0, 0.42) 82%,
    rgba(0, 0, 0, 0.12) 100%);
}

.hero__gl {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0;
  transition: opacity 1200ms var(--ease);
}
.hero.has-gl .hero__gl { opacity: 1; }

.hero__stage::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(100deg, rgba(13, 11, 10, 0.90) 0%, rgba(13, 11, 10, 0.55) 45%, rgba(13, 11, 10, 0.15) 100%),
    linear-gradient(to top, var(--bg) 1%, transparent 38%);
}

/* The type lifts and fades as the scene is scrolled past. Defaults keep it
   fully visible, so no script means no missing hero. */
.hero__inner {
  position: relative;
  width: 100%;
  z-index: 1;
  text-align: center;
  opacity: var(--hero-alpha, 1);
  transform: translate3d(0, var(--hero-lift, 0px), 0);
  will-change: opacity, transform;
}

.hero__eyebrow { display: block; margin-bottom: var(--s-md); }

.hero__title {
  font-size: clamp(1.75rem, 8.2vw, 7rem);
  margin-bottom: var(--s-md);
}
.hero__line { display: block; }
.hero__title .accent-word { color: var(--accent); }

/* The turn in the sentence gets the gold, as a struck block rather than as
   coloured type. Inline-block so the mark hugs the words, with the left
   padding pulled back so the line still starts on the container edge.
   Default is fully open: if the entrance never runs, the mark is simply
   there. */
.hero__line--mark {
  display: inline-block;
  background: var(--ink);
  color: var(--ember);
  padding: 0.02em 0.22em 0.1em;
  clip-path: inset(0 0 0 0);
}

.hero__foot {
  display: grid;
  gap: var(--s-md);
  justify-items: center;
  margin-top: var(--s-md);
}
.hero__sub {
  color: var(--ink-muted);
  max-width: 52ch;
  margin-inline: auto;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s-sm); justify-content: center; }

/* =========================================================================
   02 . THE MIDDLE . the fire rises through the panel
   ========================================================================= */
.statement {
  min-height: 240svh;
  padding: 0;
  background: var(--bg);
  overflow: clip;
  margin-top: 8svh;
}
.statement__pin {
  position: sticky;
  top: 0;
  height: 100svh;
  display: grid;
  place-items: center;
  overflow: hidden;
  isolation: isolate;
  padding: 104px var(--gutter) var(--s-lg);
}

/* Ember floods up from the floor as the scene is scrolled. --flood defaults
   to 0%, so without script the panel simply stays dark. */
.statement__flood {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(120% 85% at 50% 100%, var(--ember) 0%, var(--ember-deep) 72%),
    var(--ember-deep);
  clip-path: inset(calc(100% - var(--flood, 0%)) 0 0 0);
  will-change: clip-path;
}

.statement__inner {
  position: relative;
  z-index: 2;
  text-align: center;
  max-width: 1000px;
}
/* This panel is read on two grounds: near-black at rest and ember once the
   flood is up. Muted greys pass on the first and fail on the second
   (ink-muted measures 3.1:1 on ember), so the copy here holds one colour that
   passes on both and takes its hierarchy from weight instead. */
.statement__count {
  font-size: var(--t-caption);
  letter-spacing: 0.2em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  margin-bottom: var(--s-md);
}
.statement__title {
  font-size: var(--t-display);
  max-width: 16ch;
  margin-inline: auto;
}
.statement__lines {
  margin-top: var(--s-lg);
  display: grid;
  gap: 6px;
  font-size: var(--t-h3);
  font-weight: 600;
  font-stretch: 90%;
  line-height: 1.15;
  color: var(--ink);
  font-weight: 500;
}
.statement__lines span:first-child { font-weight: 800; }

/* ---------- The field of pressures ----------
   The weights that surround the statement, in the client's own words. They
   sit around the sentence because that is the point: the power is in the
   middle of them, not after them. ---------- */
.statement__chips {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}
.chip {
  position: absolute;
  left: var(--x);
  top: var(--y);
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 9px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: rgba(13, 11, 10, 0.74);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  font-size: var(--t-caption);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-muted);
  white-space: nowrap;
  /* A numeric starting value, so the entrance has something to interpolate
     from. Left at none there is nothing for a blur to animate out of. */
  filter: blur(0px);
}
.chip i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--ember-lift);
  flex-shrink: 0;
}

/* Below the pin's comfortable width the chips stop floating and become a
   plain wrapped row under the statement. They carry real copy, so they are
   never hidden, only re-laid. */
@media (max-width: 899px) {
  .statement__chips {
    position: static;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    margin-top: var(--s-md);
  }
  .chip {
    position: static;
    transform: none;
    white-space: normal;
  }
}

/* =========================================================================
   03 . THE STORY . the figures assemble

   The reference throws its cards in from off their places and lets them
   settle into a row as the reader travels. Each card carries where it comes
   from as three numbers on itself; script only moves one dial between 0 and
   1 and the stylesheet reads those numbers against it.
   ========================================================================= */
.figures {
  min-height: 260svh;
  overflow: clip;
  background: var(--bg);
}
.figures__pin {
  position: sticky;
  top: 0;
  min-height: 100svh;
  display: grid;
  align-content: center;
  gap: clamp(38px, 6vh, 78px);
  padding-block: clamp(72px, 10vh, 120px);
}

.figures__head { text-align: center; }
.figures__eyebrow {
  font-size: 0.75rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.figures__title {
  margin-top: var(--s-sm);
  font-size: clamp(2rem, 5vw, 4.4rem);
}
.figures__lead {
  margin-top: var(--s-md);
  margin-inline: auto;
  max-width: 52ch;
  font-size: var(--t-lead);
  line-height: 1.52;
  color: var(--ink-muted);
}
.figures__cta { margin-top: var(--s-lg); justify-content: center; }

/* ---- the row ---- */
.figures__row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(14px, 1.4vw, 22px);
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
@media (min-width: 900px) { .figures__row { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.figure {
  display: flex;
  flex-direction: column;
  gap: var(--s-sm);
  min-height: clamp(190px, 24vh, 250px);
  padding: clamp(18px, 1.6vw, 26px);
  border-radius: 10px;
  background: linear-gradient(160deg, #1E1A18 0%, #141110 100%);
  box-shadow: 0 1px 0 rgba(232, 225, 213, 0.06) inset, 0 24px 46px rgba(0, 0, 0, 0.42);
  /* --set runs 0 to 1: 0 is where the card was thrown from, 1 is its slot. */
  transform:
    translate3d(
      calc(var(--fx, 0) * (1 - var(--set, 1)) * 1%),
      calc(var(--fy, 0) * (1 - var(--set, 1)) * 1%),
      0)
    rotate(calc(var(--fr, 0) * (1 - var(--set, 1)) * 1deg))
    scale(calc(0.9 + var(--set, 1) * 0.1));
  opacity: calc(0.15 + var(--set, 1) * 0.85);
}

.figure__top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.figure__label {
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  color: var(--ink-faint);
}
.figure__dots { display: flex; gap: 4px; }
.figure__dots i { width: 4px; height: 4px; border-radius: 50%; background: var(--ink-faint); }
.figure__value {
  margin-top: auto;
  font-weight: var(--display-weight);
  font-stretch: var(--display-stretch);
  font-size: clamp(2.1rem, 3.4vw, 3.4rem);
  line-height: 1;
  letter-spacing: var(--display-track);
  color: var(--ink);
}
.figure__note {
  font-size: var(--t-body);
  line-height: 1.45;
  color: var(--ink-muted);
}

@media (max-width: 899px) {
  .figures { min-height: 0; }
  .figures__pin { position: static; min-height: 0; padding-block: var(--s-xxl); }
  .figure { transform: none; opacity: 1; }
}

/* Released: the row is simply a row, and every figure reads where it is. */
@media (prefers-reduced-motion: reduce) {
  .figures { min-height: 0; }
  .figures__pin { position: static; min-height: 0; }
  .figure { transform: none; opacity: 1; }
}

/* =========================================================================
   04 . THE PRINCIPLES . a deck that builds

   Each card is sticky at a top offset one step lower than the card before
   it, so they gather into a visible stack instead of replacing one another.
   No script: the browser does the whole thing, which also means it cannot
   fail into blankness. The section must not clip, or sticky dies.
   ========================================================================= */
.principles {
  padding-block: var(--s-xxl);
  background: var(--bg);
}
/* The intro stacks the way the reference does: the heading runs across,
   the paragraph sits under it and is pushed in from the left. */
.principles__head { display: block; margin-bottom: var(--s-xl); text-align: center; }
.principles__head > p { margin-top: var(--s-md); }
@media (min-width: 900px) {
  .principles__head > p {
    margin-top: var(--s-lg);
    /* Centred, so the measure is set by a width rather than by an indent. */
    margin-inline: auto;
    max-width: 880px;
    font-size: var(--t-lead);
    line-height: 1.5;
  }
}

.principles__foot { margin-top: var(--s-xl); display: flex; justify-content: center; }

/* =========================================================================
   05 . THE PROOF . bento, deliberately unequal
   ========================================================================= */
.proof { background: var(--surface); }
.bento {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  grid-template-columns: 1fr;
}
.bento__cell {
  --mx: 50%;
  --my: 50%;
  position: relative;
  background: var(--bg);
  padding: var(--s-md);
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow: hidden;
  min-height: 190px;
  transition: background-color 420ms var(--ease);
}

/* Content sits above the tint layer. Without this the radial would paint over
   the copy, since a positioned pseudo-element outranks inline flow content. */
.bento__cell > * { position: relative; z-index: 1; }

/* A warm light that follows the pointer inside the cell. Coordinates come in
   as --mx / --my from one listener on the grid, not one per cell. */
.bento__cell::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: radial-gradient(300px circle at var(--mx) var(--my), rgba(224, 183, 50, 0.11), transparent 62%);
  opacity: 0;
  transition: opacity 420ms var(--ease);
  pointer-events: none;
}

/* The top hairline fills with gold: the same structural device the rest of
   the page is built from, used here as the hover signal. */
.bento__cell::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  z-index: 2;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 620ms var(--ease);
  pointer-events: none;
}

.bento__cell:hover::before { opacity: 1; }
.bento__cell:hover::after { transform: scaleX(1); }
.bento__cell:focus-within::after { transform: scaleX(1); }

/* The cell leans toward the pointer. --tx / --ty come in from script and
   default to nothing, so a cell nobody points at is a flat cell. */
.bento__cell {
  transform: rotateY(var(--tx, 0deg)) rotateX(var(--ty, 0deg));
  transform-style: preserve-3d;
  transition: background-color 420ms var(--ease), transform 460ms var(--ease);
}
.bento__cell:hover { z-index: 2; }

@media (prefers-reduced-motion: reduce) {
  .bento__cell { transform: none; transition: none; }
  .bento__cell::before { transition: none; }
}

.bento__name,
.bento__desc,
.bento__cta { transition: transform 520ms var(--ease); }
a.bento__cell:hover .bento__name { transform: translateY(-4px); }
a.bento__cell:hover .bento__desc { transform: translateY(-2px); }
a.bento__cell:hover .bento__cta { transform: translateY(-1px); }

@media (prefers-reduced-motion: reduce) {
  .bento__cell::before,
  .bento__cell::after,
  .bento__name,
  .bento__desc,
  .bento__cta { transition: none; }
}

.proof__bento { grid-template-areas: 'lead' 'n1' 'n2' 'acc'; }
@media (min-width: 700px) {
  .proof__bento {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas: 'lead lead' 'n1 n2' 'acc acc';
  }
}
@media (min-width: 1024px) {
  .proof__bento {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    grid-template-areas:
      'lead lead n1  n2'
      'lead lead acc acc';
  }
}
.proof__lead {
  grid-area: lead;
  justify-content: flex-end;
  min-height: 300px;
  background:
    radial-gradient(85% 110% at 12% 100%, rgba(142, 17, 20, 0.42) 0%, transparent 62%),
    var(--bg);
}
.proof__n1 { grid-area: n1; justify-content: flex-end; }
.proof__n2 {
  grid-area: n2;
  justify-content: flex-end;
  background:
    radial-gradient(100% 120% at 100% 0%, rgba(224, 183, 50, 0.13) 0%, transparent 60%),
    var(--bg);
}
.proof__acc { grid-area: acc; justify-content: center; }

/* ---------- Data grids ----------
   Cells are built by script so the source stays light. Every figure they show
   is one the client has published; nothing is invented or estimated. */
.chart { margin: 0; display: grid; gap: 12px; width: 100%; }
.chart__grid { display: grid; gap: 3px; }
.chart--team .chart__grid { grid-template-columns: repeat(auto-fill, minmax(13px, 1fr)); }
.chart--year .chart__grid { grid-template-columns: repeat(auto-fill, minmax(7px, 1fr)); }
.chart__cell { aspect-ratio: 1; background: var(--ink-faint); border-radius: 1px; opacity: 0.22; }
.chart__cell--key { background: var(--accent); opacity: 1; }
.chart__cap {
  font-size: var(--t-caption);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.figure__value { color: var(--accent); line-height: 0.82; }
.proof__lead .figure__value { font-size: clamp(3.2rem, 7vw, 6rem); }
.figure__label {
  font-size: var(--t-small);
  color: var(--ink-muted);
  max-width: 30ch;
  border-top: 1px solid var(--line);
  padding-top: 12px;
}

.accolades { display: grid; gap: 0; width: 100%; }
.accolade {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px var(--s-md);
  padding-block: 13px;
  border-bottom: 1px solid var(--line);
}
.accolade:last-child { border-bottom: 0; }
.accolade__source {
  font-size: var(--t-h4);
  font-weight: 800;
  font-stretch: 86%;
  text-transform: uppercase;
}
.accolade__what { color: var(--ink-muted); font-size: var(--t-small); }

/* =========================================================================
   05b . THE REEL . five frames, turned by the scroll

   Not a slideshow: the frames are stacked, the later ones paint over the
   earlier, and each one's opacity is the reader's own position between two
   frames. Dragging the scroll backwards runs it backwards, which is what
   makes it read as footage rather than as slides advancing.
   ========================================================================= */
.reel { min-height: 840svh; overflow: clip; background: var(--bg); }
.reel__pin {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: clip;
  background: var(--bg);
}
.reel__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0;
  transition: opacity 600ms var(--ease);
  filter: var(--grade);
}
.reel.is-live .reel__canvas { opacity: 1; }

/* The last frame, standing in until the sequence is loaded, and standing
   in for good if it never is. It is the frame the whole run arrives at. */
.reel__poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: var(--grade);
  transition: opacity 600ms var(--ease);
}
.reel.is-live .reel__poster { opacity: 0; }

.reel__veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(120% 96% at 50% 48%, rgba(13, 11, 10, 0.30) 0%, rgba(13, 11, 10, 0.52) 62%, rgba(13, 11, 10, 0.82) 100%),
    linear-gradient(180deg, transparent 30%, rgba(13, 11, 10, 0.55) 42%, rgba(13, 11, 10, 0.55) 58%, transparent 70%),
    linear-gradient(180deg, rgba(13, 11, 10, 0.85) 0%, transparent 18%, transparent 76%, rgba(13, 11, 10, 0.92) 100%);
}

/* One beat at a time over the footage: a line, sometimes a note under it,
   and at the end the same call the rest of the page uses. They sit above the
   veil's dark band, which is what keeps them readable wherever the frame
   happens to be bright. Each beat lands from its own side. */
.reel__lines {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
}
.reel__beat {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  max-width: min(100%, 1120px);
  opacity: 0;
  transform: translateY(-50%) translateX(var(--from, 0px));
  transition: opacity 620ms var(--ease), transform 820ms var(--ease);
}
.reel__beat[data-pos="left"]  { --from: -46px; margin-right: auto;  text-align: left; }
.reel__beat[data-pos="right"] { --from:  46px; margin-left: auto;   text-align: right; }
.reel__beat[data-pos="right"] .reel__note { margin-left: auto; }
.reel__beat[data-pos="mid"] .reel__note { margin-inline: auto; }
.reel__beat[data-pos="mid"]   { --from: 0px; margin-inline: auto; text-align: center; }
.reel__beat.is-on { opacity: 1; transform: translateY(-50%) translateX(0); pointer-events: auto; }

.reel__line {
  margin: 0;
  font-weight: var(--display-weight);
  font-stretch: var(--display-stretch);
  font-size: clamp(1.55rem, 5.2vw, 4.9rem);
  line-height: 1.02;
  letter-spacing: var(--display-track);
  text-transform: uppercase;
  /* White here rather than the page's bone: this type sits on photographs,
     not on the site's ground. */
  color: #FFFFFF;
  text-shadow: 0 2px 30px rgba(0, 0, 0, 0.85), 0 1px 4px rgba(0, 0, 0, 0.7);
}
.reel__note {
  margin-top: var(--s-sm);
  max-width: 33em;
  font-size: var(--t-lead);
  line-height: 1.5;
  color: #FFFFFF;
  opacity: 0.9;
  text-shadow: 0 1px 16px rgba(0, 0, 0, 0.9);
}
.reel__cta { margin-top: var(--s-md); }
.reel__beat[data-pos="mid"] .reel__cta { display: flex; justify-content: center; }
/* The call arrives after the words it belongs to. */
.reel__beat .reel__cta { opacity: 0; transform: translateY(14px); transition: opacity 520ms var(--ease) 260ms, transform 620ms var(--ease) 260ms; }
.reel__beat.is-on .reel__cta { opacity: 1; transform: none; }

.reel__count {
  position: absolute;
  left: var(--gutter);
  bottom: clamp(24px, 5vh, 56px);
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: var(--t-caption);
  letter-spacing: 0.22em;
  color: var(--ink);
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.7);
}

/* Released: one frame, held. A sequence nobody is scrolling is a picture. */
@media (prefers-reduced-motion: reduce) {
  .reel { min-height: 0; }
  .reel__pin { position: static; height: 78svh; }
}

/* =========================================================================
   06 . THE BOOK . real geometry
   ========================================================================= */
.books__grid {
  display: grid;
  gap: var(--s-lg);
  grid-template-columns: 1fr;
  align-items: center;
}
@media (min-width: 900px) {
  .books__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); gap: clamp(40px, 6vw, 96px); }
}

.book3d {
  position: relative;
  aspect-ratio: 1 / 1;
  max-width: 520px;
  margin-inline: auto;
  width: 100%;
}
.book3d__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 900ms var(--ease);
}
.book3d.is-live .book3d__canvas { opacity: 1; }
.book3d.is-live .book3d__fallback { opacity: 0; }

.book3d__fallback {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(-3deg);
  width: 62%;
  aspect-ratio: 5 / 7;
  transition: opacity 700ms var(--ease);
}
.book3d__fallback .plate { position: absolute; inset: 0; }
.book3d__fallback .plate::after {
  background: linear-gradient(155deg, rgba(232, 225, 213, 0.10), transparent 45%);
}
.book3d__fallback::before {
  content: '';
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 13px;
  background: linear-gradient(to right, rgba(0, 0, 0, 0.6), transparent);
  z-index: 2;
}
.book-cover__type { position: absolute; inset: auto 0 0 0; z-index: 3; padding: 22px 20px; }
.book-cover__title {
  font-size: clamp(1.25rem, 2.6vw, 2rem);
  font-weight: 900;
  font-stretch: 76%;
  text-transform: uppercase;
  line-height: 0.92;
  letter-spacing: -0.02em;
}
.book-cover__author {
  margin-top: 9px;
  font-size: var(--t-caption);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}

.book-body .h2 { margin-bottom: var(--s-md); }
.book-body .body-text { margin-bottom: var(--s-md); }
.retailers {
  display: flex;
  flex-wrap: wrap;
  gap: 10px var(--s-md);
  border-top: 1px solid var(--line);
  padding-top: var(--s-md);
  margin-top: var(--s-md);
}
.retailers a {
  font-size: var(--t-small);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
  transition: color var(--dur-fast) var(--ease);
}
.retailers a:hover { color: var(--accent); }
.retailers span {
  font-size: var(--t-small);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* -------------------------------------------------------------------------
   06b . THE TOME . the object turns, the facts arrive

   Copied from the reference: a small label above, one object holding the
   middle of a pinned panel and turning as the page moves, and a list that
   arrives one line at a time underneath it. The reading copy follows once
   the panel lets go, so nothing that has to be read is trapped in motion.
   ------------------------------------------------------------------------- */
.tome { min-height: 340svh; overflow: clip; }
.tome__pin {
  position: sticky;
  top: 0;
  height: 100svh;
  display: grid;
  grid-template-rows: auto 1fr;
  align-items: center;
  justify-items: center;
  padding-block: clamp(72px, 9vh, 110px) clamp(28px, 5vh, 56px);
  padding-inline: var(--gutter);
}

/* ---- the label ---- */
.tome__label {
  padding: 9px 20px;
  border: 1px solid rgba(20, 16, 15, 0.20);
  border-radius: var(--radius-btn);
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* ---- object between two columns of facts ----
   The reference parks its list under the object, but our object is tall and
   narrow where theirs is wide, so a single row underneath left the middle of
   the panel empty. Flanking it fills the width and lets the lines be read at
   a proper size instead of caption size. */
.tome__grid {
  display: grid;
  grid-template-columns: 1fr;
  align-items: center;
  gap: var(--s-lg);
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
}
@media (min-width: 900px) {
  .tome__grid {
    grid-template-columns: 1fr auto 1fr;
    gap: clamp(24px, 4vw, 76px);
  }
}

.tome__object {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 0;
}
/* The real cover, in place of the modelled one. It floats on its own clock
   so it is alive while the reader is still, and turns with the scroll on
   top of that: --tome-spin is a bare number written by script. */
.tome__book {
  width: min(66vw, 400px);
  transform-style: preserve-3d;
  animation: tome-float 7s ease-in-out infinite;
}
.tome__cover {
  display: block;
  width: 100%;
  height: auto;
  transform:
    perspective(1500px)
    rotateY(calc(var(--tome-spin, 0) * -24deg))
    rotateX(calc(var(--tome-spin, 0) * 5deg))
    scale(calc(1 + var(--tome-spin, 0) * 0.07));
  transform-origin: 50% 60%;
  filter: drop-shadow(0 26px 44px rgba(20, 16, 15, 0.30));
}
@keyframes tome-float {
  0%, 100% { transform: translateY(-8px) rotate(-0.5deg); }
  50%      { transform: translateY(10px) rotate(0.5deg); }
}

/* Held still, but never hidden: the cover is the product. */
@media (prefers-reduced-motion: reduce) {
  .tome__book { animation: none; }
  .tome__cover { transform: none; }
}

.tome__mark {
  margin-top: clamp(8px, 1.6vh, 22px);
  font-weight: 700;
  font-size: clamp(1rem, 1.6vw, 1.4rem);
  letter-spacing: 0.01em;
  white-space: nowrap;
  color: var(--ink);
  pointer-events: none;
}

/* On a phone the flanking scene has nowhere to flank. Held as a 340svh pin
   it spent three and a half screens spreading the label, one list, the cover
   and the second list apart with no hierarchy between them. Below 900 the
   scene stands down -- the same thing this file already does for reduced
   motion -- and the cover leads, with the six lines read straight under it. */
@media (max-width: 899px) {
  .tome { min-height: 0; }
  .tome__pin {
    position: static; height: auto;
    grid-template-rows: auto auto;
    gap: var(--s-lg);
    padding-block: var(--s-xxl);
  }
  .tome__grid { gap: var(--s-lg); }
  .tome__object { order: -1; }
  .tome__book { width: min(62vw, 260px); }
}

/* ---- the lists ---- */
.tome__facts {
  display: grid;
  gap: clamp(18px, 2.6vh, 34px);
  list-style: none;
  margin: 0;
  padding: 0;
}
@media (max-width: 899px) {
  .tome__facts { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
}
/* The right-hand column mirrors the left, so the two read outward from the
   object rather than both marching the same way. */
@media (min-width: 900px) {
  .tome__facts--r .tome__fact { grid-template-columns: 1fr 9px; text-align: right; }
  .tome__facts--r .tome__tick { order: 2; }
}

.tome__fact {
  display: grid;
  grid-template-columns: 9px 1fr;
  align-items: start;
  gap: 14px;
  padding-bottom: clamp(14px, 2vh, 26px);
  border-bottom: 1px solid rgba(20, 16, 15, 0.12);
  font-size: var(--t-lead);
  line-height: 1.35;
  color: var(--ink);
}
.tome__tick {
  width: 9px;
  height: 9px;
  margin-top: 0.42em;
  background: var(--ember-lift);
}

/* Hidden only once script has taken charge of showing them again. Without
   script, or without appetite for motion, every line is simply present.
   Each column slides in from its own side. */
.tome.is-live .tome__fact {
  opacity: 0;
  transform: translateX(-22px);
  transition: opacity 520ms var(--ease), transform 640ms var(--ease);
}
.tome.is-live .tome__facts--r .tome__fact { transform: translateX(22px); }
.tome.is-live .tome__fact.is-on { opacity: 1; transform: none; }

.books__after { padding-top: var(--s-xxl); }
.books__after .body-text { margin-top: var(--s-md); }
.books__after .btn-row { margin-top: var(--s-lg); }

@media (prefers-reduced-motion: reduce) {
  .tome { min-height: 0; }
  .tome__pin { position: static; height: auto; padding-block: var(--s-xxl); }
  .tome__object .book3d { height: min(60vh, 420px); }
  .tome .tome__fact { opacity: 1; transform: none; transition: none; }
}

/* =========================================================================
   06d . THE ANATOMY . the book comes apart

   The reference takes one object, lifts it into its layers as the reader
   travels, and lights the matching line underneath. A book is already a
   stack of sheets, so the layers are flat planes rather than the slabs a
   building needs: separating them along Z, with the whole assembly tilted
   and turned, is the same read.

   Everything moves off four custom properties written by script. The
   stylesheet decides what a degree and a pixel are worth.
   ========================================================================= */
/* Taller on purpose: four pages to read and three turns between them, at a
   reading pace. */
.anat { min-height: 480svh; overflow: clip; background: var(--bg); }
.anat__pin {
  position: sticky;
  top: 0;
  height: 100svh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  align-content: stretch;
  padding-block: clamp(84px, 11vh, 128px) clamp(24px, 4vh, 48px);
  overflow: clip;
}

.anat__head { position: relative; z-index: 2; }
.anat__title { margin-top: var(--s-sm); max-width: 14ch; }
.anat__lede {
  margin-top: var(--s-md);
  max-width: 24em;
  font-size: var(--t-lead);
  line-height: 1.55;
  color: var(--ink-muted);
}

/* ---- the object ----
   A book that opens, rather than a stack that lifts. Each leaf turns on the
   spine, which is what a book actually does, and it also solves the thing
   that looked broken: separated only along Z, all six faces were exactly
   coplanar at rest and fought each other for depth. Turned, they are never
   in the same plane, and a small resting offset gives the shut book real
   thickness. */
.anat__stage {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  perspective: 1600px;
  perspective-origin: 50% 42%;
  pointer-events: none;
}
/* The copy owns the left third; the object is given the rest and nothing
   of it, open or shut, reaches back across. */
@media (min-width: 900px) {
  /* a step further right: the bundle mid-turn was brushing the headline */
  .anat__stage { left: 50%; }
  .anat .anat__book { --oxm: 1; }
}

.anat__book {
  position: relative;
  width: min(32vw, 340px);
  /* The proportion of the crop below, so the cover art is placed and never
     stretched to fit. */
  aspect-ratio: 424 / 706;
  transform-style: preserve-3d;
  --oxm: 0;
  transform:
    translateX(calc(var(--ox, 0) * var(--oxm) * 1%))
    rotateX(calc(var(--ax, 10) * 1deg))
    rotateY(calc(var(--ay, -22) * 1deg))
    rotateZ(-3deg)
    scale(var(--as, 0.9));
}
.anat__slab {
  font-size: clamp(11px, 1.15vw, 16px);
  position: absolute;
  inset: 0;
  border-radius: 2px 5px 5px 2px;
  transform-origin: left center;
  transform:
    translateZ(calc(var(--base, 0) * 1px))
    rotateY(calc(var(--open, 0) * -1deg));
  transition: box-shadow 420ms var(--ease);
}
.anat__slab--board {
  background: linear-gradient(122deg, #2A2422 0%, #14100F 68%);
  box-shadow: 0 30px 60px rgba(0, 0, 0, 0.5);
}
.anat__slab--leaf {
  /* the page is a child with backface-visibility: hidden; that only holds
     if the sheet keeps its children in 3D, otherwise a turned sheet shows
     its text mirrored through the back */
  transform-style: preserve-3d;
  background: linear-gradient(122deg, #F2ECE0 0%, #D6CDBD 100%);
  border-left: 1px solid rgba(20, 16, 15, 0.30);
  /* The fore edge, which is what you actually see of the sheets that carry
     nothing: sixteen of these stacked is what gives the shut book its
     thickness. */
  box-shadow: inset -3px 0 4px -3px rgba(20, 16, 15, 0.55);
}

/* ---- the four sheets that carry a name ---- */
.anat__page {
  position: absolute;
  /* the right margin is wide on purpose: the shut stack is seen at an angle,
     and type set close to the fore edge peeks past the cover */
  inset: 11% 17% 11% 13%;
  display: flex;
  flex-direction: column;
  gap: 0.7em;
  color: #14100F;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.anat__page-num {
  font-size: 0.62em;
  letter-spacing: 0.22em;
  color: rgba(20, 16, 15, 0.45);
}
.anat__page-name {
  font-weight: var(--display-weight);
  font-stretch: var(--display-stretch);
  font-size: 1.3em;
  line-height: 1.02;
  letter-spacing: var(--display-track);
  text-transform: uppercase;
}
/* The printed page: a real entry from Week 1, set in the book's own serif at
   the scale the sheet allows. Overflow is clipped by the sheet's edge. */
.anat__page-body {
  flex: 1; min-height: 0;
  margin-top: 0.45em;
  overflow: hidden;
  font-family: 'Playfair Display', Georgia, serif;
  font-size: 0.74em; line-height: 1.42;
  color: #14100F; text-align: left;
  text-transform: none; letter-spacing: 0;
}
.anat__page-body i { display: block; font-style: italic; }
.anat__page-body b { font-weight: 700; color: var(--ember); }
.anat__pg-k {
  display: block; margin-bottom: 0.6em;
  font-family: var(--font); font-size: 0.78em; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--ember);
}
.anat__pg-t { display: block; margin-bottom: 0.6em; font-weight: 600; font-size: 1.18em; line-height: 1.2; }
.anat__pg-r { display: block; margin: 0.3em 0 0.9em; text-align: right; font-size: 0.9em; color: rgba(20, 16, 15, 0.55); }
.anat__pg-li { display: block; padding: 0.3em 0; border-bottom: 1px solid rgba(20, 16, 15, 0.14); }
.anat__pg-gap { display: block; height: 0.8em; }
/* The live sheet is the one the reader is being told about. */
.anat__slab--page.is-lit { background: linear-gradient(122deg, #FBF7EF 0%, #E4DCCC 100%); }
.anat__slab--cover { background: none; transform-style: preserve-3d; }
.anat__face {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.anat__face--out {
  background-image: url('https://perseveranceprinciples.com/wp-content/uploads/2026/08/JJ_BOOK-DP.webp');
  background-size: 180.19% 114.73%;
  background-position: 55.29% 34.62%;
  background-repeat: no-repeat;
}
/* Past ninety degrees the reader is looking at the inside of the board, and
   the inside of a board is not the cover printed backwards. */
.anat__face--in {
  transform: rotateY(180deg);
  background: linear-gradient(122deg, #2A2422 0%, #14100F 72%);
  box-shadow: inset 0 0 0 1px rgba(224, 183, 50, 0.12);
}
.anat__slab.is-lit {
  box-shadow: 0 0 0 1px var(--accent), 0 18px 50px rgba(224, 183, 50, 0.28);
}

/* ---- the four lines ---- */
.anat__legend { position: relative; z-index: 2; align-self: end; }
.anat__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-md) clamp(20px, 3vw, 56px);
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: anat;
}
@media (min-width: 860px) { .anat__list { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.anat__item { transition: opacity 420ms var(--ease); }
.anat__rule {
  display: block;
  height: 1px;
  margin-bottom: var(--s-sm);
  background: var(--line);
  transform-origin: left;
  transition: background-color 420ms var(--ease);
}
.anat__name {
  font-size: clamp(0.95rem, 1.15vw, 1.125rem);
  font-weight: 600;
  color: var(--ink-faint);
  transition: color 420ms var(--ease);
}
.anat__note {
  margin-top: 6px;
  font-size: 0.875rem;
  line-height: 1.45;
  color: var(--ink-faint);
  transition: color 420ms var(--ease);
}
.anat__item.is-on .anat__rule { background: var(--accent); }
.anat__item.is-on .anat__name { color: var(--ink); }
.anat__item.is-on .anat__note { color: var(--ink-muted); }

/* Released: the panel lets go, the object rests open, and all four lines
   read at once. Nothing here is only visible while something moves. */
@media (prefers-reduced-motion: reduce) {
  .anat { min-height: 0; }
  .anat__pin { position: static; height: auto; padding-block: var(--s-xxl); }
  .anat__stage { position: static; left: auto; margin-block: var(--s-xl); }
  .anat__book { --ax: 12; --ay: -26; --as: 0.9; --ox: 62; }
  .anat__slab[data-slab="1"] { --base: 2;  --open: 26; }
  .anat__slab[data-slab="2"] { --base: 4;  --open: 50; }
  .anat__slab[data-slab="3"] { --base: 6;  --open: 74; }
  .anat__slab[data-slab="4"] { --base: 8;  --open: 100; }
  .anat__slab[data-slab="5"] { --base: 10; --open: 132; }
  .anat__item .anat__rule { background: var(--accent); }
  .anat__item .anat__name { color: var(--ink); }
  .anat__item .anat__note { color: var(--ink-muted); }
}

/* =========================================================================
   07 . THE RELEASE
   ========================================================================= */
.release { position: relative; overflow: clip; padding-block: var(--s-xxl); }
.release__bg { position: absolute; inset: -10% 0; z-index: 0; }
.release__inner { position: relative; z-index: 1; }
/* Daily Perseverance stands beside the copy that announces it. */
.release__grid h2 { font-size: clamp(2.1rem, 4.3vw, 3.7rem); }
.release__cover { justify-self: center; }
.release__cover img {
  display: block;
  width: min(58vw, 260px);
  height: auto;
  filter: drop-shadow(0 24px 40px rgba(0, 0, 0, 0.45));
}
@media (min-width: 860px) {
  .release__cover img { width: min(24vw, 300px); }
}

.release__grid {
  display: grid;
  gap: var(--s-md);
  grid-template-columns: 1fr;
  align-items: end;
  justify-items: start;
}
@media (min-width: 900px) {
  .release__grid { grid-template-columns: auto minmax(min-content, 1.1fr) minmax(0, 1fr); gap: var(--s-lg); align-items: center; }
}
.release__date { color: var(--accent); font-variant-numeric: tabular-nums; }
.release__meta {
  border-left: 1px solid var(--line);
  padding-left: var(--s-md);
  display: grid;
  gap: var(--s-sm);
}

/* =========================================================================
   07b . THE SHELF . one panel a book, each on its own ground

   Copied from the reference: every book takes the whole screen and brings
   its own colour with it, the next sliding up over the last. The ground and
   the ink travel together as one set of properties on the panel, so a new
   book is a new colour and nothing else has to know.
   ========================================================================= */
.shelf { overflow: clip; }
.shelf::after {
  content: '';
  display: block;
  height: 100svh;
}
.shelf__panel {
  position: sticky;
  top: 0;
  display: grid;
  align-content: center;
  min-height: 100svh;
  padding-block: var(--s-xl);
  background: var(--ground);
  color: var(--on);
}
.shelf__grid {
  display: grid;
  grid-template-columns: 1fr;
  align-items: center;
  gap: var(--s-lg);
}
@media (min-width: 900px) {
  .shelf__grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: clamp(32px, 5vw, 90px); }
}

.shelf__meta {
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--on-muted);
}
.shelf__title {
  margin-top: var(--s-sm);
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 400;
  font-size: clamp(2.4rem, 5.6vw, 5rem);
  line-height: 1.02;
  letter-spacing: -0.015em;
  text-transform: none;
  color: var(--on);
}
.shelf__log {
  margin-top: var(--s-md);
  max-width: 38ch;
  font-size: var(--t-lead);
  line-height: 1.55;
  color: var(--on-muted);
}
.shelf__cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: var(--s-lg);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--on-rule);
  font-size: var(--t-caption);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--on);
  text-decoration: none;
  transition: border-color 320ms var(--ease), gap 320ms var(--ease);
}
.shelf__cta:hover { border-color: var(--on); gap: 18px; }
.shelf__cta:focus-visible { outline: 2px solid var(--on); outline-offset: 5px; }

/* ---- the cover, and the number behind it ---- */
.shelf__art {
  position: relative;
  display: grid;
  place-items: center;
}
.shelf__num {
  position: absolute;
  right: -4%;
  top: 50%;
  transform: translateY(-50%);
  font-weight: var(--display-weight);
  font-stretch: var(--display-stretch);
  font-size: clamp(9rem, 26vw, 22rem);
  line-height: 0.8;
  letter-spacing: -0.04em;
  color: var(--on-faint);
  pointer-events: none;
  user-select: none;
}
.shelf__cover {
  position: relative;
  z-index: 1;
  display: block;
  width: min(56vw, 320px);
  height: auto;
  filter: drop-shadow(0 30px 54px rgba(0, 0, 0, 0.34));
  transition: transform 760ms var(--ease);
}
.shelf__panel:hover .shelf__cover { transform: translateY(-10px); }

@media (prefers-reduced-motion: reduce) {
  .shelf__panel { position: static; }
  .shelf__cover { transition: none; }
}

/* =========================================================================
   07c . THE OPENING . a spread you can read

   Two facing pages on paper, turning as the reader travels. The gutter is a
   real gradient rather than a border, because the fold of a book is a
   shadow, not a line.

   The text in here is placeholder and says so on the page. When the real
   pages arrive nothing in this stylesheet needs to change.
   ========================================================================= */
.opening {
  padding-block: clamp(48px, 7vh, 88px);
  overflow: clip;
  background: #EDE7DA;
  --ink: #1B1613;
  --ink-muted: #4B443D;
  --ink-faint: #6B635B;
  color: var(--ink);
}
.opening__pin {
  display: grid;
  gap: var(--s-md);
}

.opening__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-md);
  flex-wrap: wrap;
}
/* The notice is not decoration: it is the difference between a sample and
   a claim about what the book says. */
.opening__draft {
  margin-top: 8px;
  display: inline-block;
  padding: 5px 12px;
  border: 1px dashed rgba(27, 22, 19, 0.45);
  border-radius: var(--radius-btn);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.opening__full {
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-muted);
  text-decoration: none;
  border-bottom: 1px solid rgba(27, 22, 19, 0.28);
  padding-bottom: 4px;
  transition: color 320ms var(--ease), border-color 320ms var(--ease);
}
.opening__full:hover { color: var(--ink); border-color: var(--ink); }

/* ---- the margins ----
   The reference lets the book float on empty paper, which works at its
   width and reads as dead space at ours. The margins get the apparatus a
   printed book keeps out there: the jacket of the thing being sampled on
   one side, the running head and the place in it on the other. They are
   dropped entirely when there is no room to spare. */
.opening__stage {
  display: grid;
  grid-template-columns: 1fr;
  align-items: center;
  gap: var(--s-lg);
  width: 100%;
  padding-inline: var(--gutter);
  max-width: calc(var(--container) + 320px);
  margin-inline: auto;
}
@media (min-width: 1180px) {
  .opening__stage {
    grid-template-columns: minmax(160px, 210px) minmax(0, 1fr) minmax(96px, 132px);
    gap: clamp(28px, 3.4vw, 62px);
  }
}
.opening__rail { display: none; }
@media (min-width: 1180px) { .opening__rail { display: block; } }

.opening__jacket {
  display: block;
  width: 100%;
  height: auto;
}
.opening__jacket-meta {
  margin-top: var(--s-md);
  font-family: var(--font);
  font-size: 0.625rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ember);
}
.opening__jacket-title {
  margin-top: 6px;
  font-family: 'Playfair Display', Georgia, serif;
  font-size: 1.125rem;
  line-height: 1.16;
  color: var(--ink);
}
.opening__jacket-cta {
  display: inline-block;
  margin-top: var(--s-sm);
  padding-bottom: 4px;
  border-bottom: 1px solid rgba(27, 22, 19, 0.28);
  font-family: var(--font);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  transition: border-color 300ms var(--ease);
}
.opening__jacket-cta:hover { border-color: var(--ink); }
.opening__jacket-cta:focus-visible { outline: 2px solid var(--ember); outline-offset: 4px; }

/* ---- the right margin ---- */
.opening__rail--right {
  display: none;
  justify-self: end;
  text-align: right;
}
@media (min-width: 1180px) {
  .opening__rail--right { display: flex; flex-direction: column; align-items: flex-end; gap: var(--s-lg); }
}
/* Set on its side, the way it would read off a spine on a shelf. */
.opening__spine {
  writing-mode: vertical-rl;
  font-family: var(--font);
  font-size: 0.625rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--ink-faint);
  white-space: nowrap;
}
.opening__marks { display: grid; gap: 10px; list-style: none; margin: 0; padding: 0; }
.opening__mark {
  width: 26px;
  height: 1px;
  background: rgba(27, 22, 19, 0.24);
  transition: background-color 360ms var(--ease), width 360ms var(--ease);
}
.opening__mark.is-on { width: 44px; background: var(--ember); }

/* ---- the book ---- */
.opening__book {
  position: relative;
  align-self: center;
  width: min(100%, 1040px, calc((100svh - 250px) * 1.4));
  margin-inline: auto;
  aspect-ratio: 7 / 5;
  perspective: 2200px;
  cursor: grab;
  touch-action: pan-y;
  user-select: none;
  background: #F7F2E7;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.7) inset,
    0 34px 70px rgba(27, 22, 19, 0.22);
}
/* The fold. Two soft gradients meeting, which is what a spine does to the
   light on the paper either side of it. */
.opening__gutter {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 13%;
  transform: translateX(-50%);
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(90deg,
    rgba(27, 22, 19, 0) 0%,
    rgba(27, 22, 19, 0.10) 38%,
    rgba(27, 22, 19, 0.16) 50%,
    rgba(27, 22, 19, 0.10) 62%,
    rgba(27, 22, 19, 0) 100%);
}

.opening__spread {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  opacity: 0;
  transition: opacity 520ms var(--ease);
}
.opening__spread.is-on { opacity: 1; }

.opening__leaf {
  padding: clamp(26px, 4.4vw, 62px) clamp(22px, 3.6vw, 54px);
  font-family: 'Playfair Display', Georgia, serif;
  font-size: clamp(0.8125rem, 1.02vw, 1rem);
  line-height: 1.62;
  color: var(--ink);
  overflow: hidden;
}
.opening__leaf p + p { text-indent: 1.4em; }
.opening__leaf--verso { padding-right: clamp(34px, 5vw, 76px); }
.opening__leaf--recto { padding-left: clamp(34px, 5vw, 76px); }

.opening__gloss {
  margin-top: 34%;
  font-style: italic;
  color: var(--ink-faint);
  text-indent: 0 !important;
}
.opening__label {
  margin-bottom: var(--s-sm);
  font-family: var(--font);
  font-size: 0.625rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ember);
}
/* The capital sits into the first three lines rather than above them. */
.opening__drop {
  float: left;
  margin: 0.04em 0.08em 0 0;
  font-size: 3.1em;
  line-height: 0.82;
  color: var(--ember);
}
.opening__first { text-indent: 0 !important; }
/* the devotional page: the entry's title under its category, and on the
   facing leaf the scripture, its reference, and the anchor -- set the way
   the printed page sets them, the verse italic and the anchor's name bold */
.opening__head {
  margin: 0 0 var(--s-sm);
  font-weight: 600; font-size: 1.18em; line-height: 1.25;
  text-indent: 0 !important;
}
.opening__devotion { margin-top: 26%; }
.opening__verse { font-style: italic; color: var(--ink-2, var(--ink)); text-indent: 0 !important; }
.opening__ref {
  margin-top: 0.5em; text-align: right;
  font-size: 0.92em; font-style: italic; color: var(--ink-faint);
  text-indent: 0 !important;
}
.opening__anchor { margin-top: 1.6em; text-indent: 0 !important; }
.opening__anchor b { font-weight: 700; color: var(--ember); }
@media (max-width: 719px) {
  .opening__devotion { margin-top: var(--s-sm); }
}

.opening__folio {
  justify-self: center;
  font-family: var(--font);
  font-size: 0.6875rem;
  letter-spacing: 0.22em;
  color: var(--ink-faint);
}

@media (max-width: 719px) {
  .opening__book { aspect-ratio: auto; max-height: none; }
  .opening__spread {
    position: static;
    opacity: 1;
    transition: none;
    grid-template-columns: 1fr;
  }
  .opening__leaf {
    font-size: 1rem;
    padding: clamp(22px, 6vw, 34px);
    overflow: visible;
  }
  .opening__leaf--verso { padding-bottom: 0; }
  .opening__leaf--recto { padding-top: 0; }
  .opening__leaf--verso:empty { display: none; }
  .opening__gloss { margin-top: 0; }
  .opening__gutter { display: none; }
}

.opening__book.is-dragging { cursor: grabbing; }

/* ---- the page in the air ----
   One leaf, hinged on the gutter, with the page you are leaving on the
   front and the page you are arriving at on the back. Script fills both
   faces from the spreads either side of the turn, so nothing is duplicated
   in the markup. */
.opening__turner {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 50%;
  z-index: 4;
  transform-style: preserve-3d;
  transform-origin: left center;
  transform: rotateY(calc(var(--turn, 0) * -180deg));
  pointer-events: none;
  visibility: hidden;
}
.opening__turner.is-live { visibility: visible; }
.opening__turner.is-easing { transition: transform 460ms var(--ease); }

.opening__face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  background: #F7F2E7;
  overflow: hidden;
}
/* The cloned leaf fills its face, so it is laid out exactly as it was on
   the block it came from. */
.opening__face > .opening__leaf {
  position: absolute;
  inset: 0;
}
/* The lit edge that runs down a page as it lifts off the block. */
.opening__face--front { box-shadow: inset 14px 0 24px -14px rgba(27, 22, 19, 0.35); }
.opening__face--back {
  transform: rotateY(180deg);
  box-shadow: inset -14px 0 24px -14px rgba(27, 22, 19, 0.35);
}

/* ---- the strip under the book ---- */
.opening__bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-sm);
  flex-wrap: wrap;
}
.opening__step {
  width: 38px;
  height: 38px;
  border: 1px solid rgba(27, 22, 19, 0.24);
  border-radius: 50%;
  background: none;
  color: var(--ink);
  font-size: 0.9rem;
  cursor: pointer;
  transition: border-color 260ms var(--ease), background-color 260ms var(--ease);
}
.opening__step:hover:not(:disabled) { border-color: var(--ink); background: rgba(27, 22, 19, 0.06); }
.opening__step:disabled { opacity: 0.32; cursor: default; }
.opening__step:focus-visible { outline: 2px solid var(--ember); outline-offset: 3px; }
.opening__hint {
  flex-basis: 100%;
  text-align: center;
  font-family: var(--font);
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: opacity 420ms var(--ease);
}
/* The hint has done its job once a page has been turned. */
.opening.is-used .opening__hint { opacity: 0; }

/* Released: the spreads read one after another, in order, on the page. */
@media (prefers-reduced-motion: reduce) {
  .opening__book { aspect-ratio: auto; max-height: none; }
  .opening__spread { position: static; opacity: 1; transition: none; }
  .opening__gutter { display: none; }
}

/* =========================================================================
   08 . THE WORK . replicating the reference scene

   Copied from the source: pale ground, one enormous faint arc, the active
   number set in a serif on that arc with a red dot beside it, a serif title
   in sentence case, grey body copy, outlined pills, and a pale sculptural
   form bleeding off the right edge. Panel sticky at top 0 and 100svh, one
   item at a time.
   ========================================================================= */
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/playfair-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

.scene {
  min-height: 400svh;
  padding: 0;
  overflow: clip;
}
.scene__pin {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  /* The site's own pale ground, so the section reads as light without
     introducing a second cream to the palette. */
  background: #E8E1D5;
  --ink: #14100F;
  --ink-muted: #4B443D;
  --ink-faint: #635B53;
  color: var(--ink);
}

/* The arc. One circle of radius 1600, its centre pushed down and to the right
   so that its left edge sweeps up through the number column: at the middle of
   the panel the edge sits at the numbers, and every 150px below that it has
   travelled 22px further left, which is the offset each marker carries. */
.scene__arc {
  position: absolute;
  left: clamp(14%, 18vw, 22%);
  top: calc(50% + 382px);
  width: 3200px;
  height: 3200px;
  margin-left: -18px;
  transform: translateY(-50%);
  border: 1px solid rgba(20, 16, 15, 0.13);
  border-radius: 50%;
  pointer-events: none;
}
/* ---- the numbers on the arc ----
   The strip slides so the live number sits at the middle of the panel, and
   each number is pushed sideways to meet the arc at the height it lands on.
   That sideways figure is measured off the circle in script, because it is
   the only way the two stay welded together at any viewport. */
.scene__marks {
  position: absolute;
  left: clamp(14%, 18vw, 22%);
  top: 50%;
  display: none;
  transform: translateY(-50%) translateY(var(--mark-shift, 0px));
  transition: transform 660ms var(--ease);
}
@media (min-width: 900px) { .scene__marks { display: block; } }

.scene__num {
  display: flex;
  align-items: center;
  gap: 14px;
  height: 150px;
  font-family: 'Playfair Display', Georgia, serif;
  font-size: 1.75rem;
  font-weight: 400;
  color: rgba(20, 16, 15, 0.28);
  transform: translateX(var(--nx, 0px));
  transition: color 420ms var(--ease), transform 660ms var(--ease);
}
.scene__num.is-on { color: var(--ink); }

.scene__num i {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ember-lift);
  opacity: 0;
  transition: opacity 420ms var(--ease);
}
.scene__num.is-on i { opacity: 1; }

/* ---- the stage ---- */
.scene__stage {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  top: 50%;
  transform: translateY(-50%);
}
@media (min-width: 900px) {
  .scene__stage {
    left: clamp(30%, 32vw, 36%);
    right: var(--gutter);
    width: auto;
    max-width: 760px;
  }
}

.scene__item {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  opacity: 0;
  transform: translateY(20px);
  pointer-events: none;
  transition: opacity 480ms var(--ease), transform 640ms var(--ease);
}
.scene__item[data-item="0"] { position: relative; }
.scene__item.is-on { opacity: 1; transform: none; pointer-events: auto; }

/* The site's own face, one line, sentence case. */
.scene__name {
  font-family: var(--font);
  font-weight: var(--display-weight);
  font-stretch: var(--display-stretch);
  white-space: nowrap;
  font-size: clamp(2.1rem, 4.6vw, 4.1rem);
  line-height: 1.02;
  letter-spacing: var(--display-track);
  text-transform: none;
  color: var(--ink);
  margin-bottom: var(--s-sm);
}
.scene__name span { display: block; }

.scene__desc {
  color: var(--ink-muted);
  max-width: 46ch;
  margin-bottom: var(--s-md);
  font-size: clamp(1rem, 1.25vw, 1.1875rem);
  line-height: 1.55;
}

.scene__tags { display: flex; flex-wrap: wrap; gap: 9px; list-style: none; margin: 0; padding: 0; }
.scene__tags li {
  padding: 11px 21px;
  border: 1px solid rgba(20, 16, 15, 0.16);
  border-radius: var(--radius-btn);
  background: #F3EFE7;
  font-size: 0.875rem;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--ink);
}

/* Released when there is no scroll driver, or no appetite for motion. */
.scene.is-static, 
.scene.is-static .scene__pin { min-height: 0; }
.scene.is-static { padding-block: var(--s-xxl); background: #E8E1D5; }
.scene.is-static .scene__pin { position: static; height: auto; overflow: visible; padding-block: var(--s-xxl); }
.scene.is-static .scene__stage { position: static; transform: none; width: auto; }
.scene.is-static .scene__item,
.scene.is-static .scene__item[data-item="0"] {
  position: static; opacity: 1; transform: none; pointer-events: auto;
  transition: none; margin-bottom: var(--s-lg);
}
.scene.is-static .scene__marks,
.scene.is-static .scene__arc { display: none; }

@media (prefers-reduced-motion: reduce) {
  .scene { min-height: 0; padding-block: var(--s-xxl); background: #E8E1D5; }
  .scene__pin { position: static; height: auto; overflow: visible; }
  .scene__stage { position: static; transform: none; width: auto; }
  .scene__item, .scene__item[data-item="0"] {
    position: static; opacity: 1; transform: none; pointer-events: auto;
    transition: none; margin-bottom: var(--s-lg);
  }
  .scene__marks, .scene__arc { display: none; }
}

/* =========================================================================
   09 . THE PRACTICE . a deck of cards that stack

   Copied from the reference: a band of ghost type running past, then five
   pale cards on the dark ground, each one pinning at the same height so the
   next slides up and covers the one before it. Inside a card: an enormous
   faint word behind, a dark plate holding the drawing, the count at the
   left, the copy and the pills at the right, the signature at the foot.
   ========================================================================= */
.stack {
  padding-block: var(--s-xxl) 0;
  /* clip, never hidden: hidden on any ancestor kills the sticky cards. */
  overflow: clip;
}
.stack__head { margin-bottom: var(--s-xl); }

/* ---- the band of ghost type ---- */
.stack__band {
  overflow: clip;
  margin-bottom: calc(var(--s-xl) * -0.4);
  user-select: none;
}
.stack__track {
  display: flex;
  width: max-content;
  /* Three equal copies, parked one copy in. Set here rather than in script
     so the band is already mid-run with no JavaScript at all, instead of
     showing its own left edge. */
  transform: translateX(-33.3333%);
  will-change: transform;
}
.stack__track span {
  font-family: var(--font-display, inherit);
  font-size: clamp(4rem, 13vw, 12rem);
  font-weight: 800;
  line-height: 0.95;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  white-space: nowrap;
  /* Barely there. It is a texture behind the deck, not a heading. */
  color: transparent;
  -webkit-text-stroke: 1px rgba(232, 225, 213, 0.10);
}

/* ---- the deck ----
   Block, never grid: inside a grid a sticky item is trapped in its own
   cell and the deck never assembles. Every card pins to the same height,
   so each one arrives over the last. */
.stack__cards {
  display: block;
  padding-inline: var(--gutter);
  /* Trailing room so the last card holds the screen as long as the others
     do. It is scrolled behind the pinned card, so it costs nothing to look
     at: without it the whole deck releases the moment card five arrives. */
  padding-bottom: clamp(400px, 84vh, 820px);
}
.card {
  position: sticky;
  top: 92px;
  margin-inline: auto;
  max-width: var(--container);
}
.card + .card { margin-top: var(--s-xl); }

.card__inner {
  position: relative;
  overflow: hidden;
  min-height: min(74vh, 640px);
  padding: clamp(28px, 3.4vw, 54px);
  border-radius: 18px;
  background: #E8E1D5;
  box-shadow: 0 -1px 0 rgba(232, 225, 213, 0.14), 0 40px 80px rgba(0, 0, 0, 0.45);
  --ink: #14100F;
  --ink-muted: #4B443D;
  --ink-faint: #635B53;
  color: var(--ink);
  display: grid;
  grid-template-columns: 1fr;
  align-content: start;
  gap: var(--s-md);
}
@media (min-width: 920px) {
  .card__inner {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto 1fr auto;
    column-gap: clamp(24px, 3vw, 56px);
    row-gap: var(--s-md);
    align-content: stretch;
  }
}

/* On a narrow screen the card stacks into one column and grows taller than
   it does wide, so it pins closer to the top and carries less padding. A
   sticky card taller than the screen still works, but its foot is cut, and
   the signature and the call live there. */
@media (max-width: 919px) {
  .card { top: 24px; }
  .card + .card { margin-top: var(--s-lg); }
  .card__inner {
    min-height: 0;
    padding: clamp(22px, 4vw, 32px);
    gap: var(--s-sm);
  }
}

/* A hairline down the middle and a little warmth in the corner, so the card
   reads as a made object rather than a flat panel. The rule is drawn only
   where there are two columns to divide. */
.card__inner::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(72% 58% at 8% 4%, rgba(255, 252, 246, 0.55) 0%, rgba(255, 252, 246, 0) 60%);
  pointer-events: none;
}
@media (min-width: 920px) {
  .card__inner::after {
    content: '';
    position: absolute;
    left: 50%;
    top: clamp(28px, 3.4vw, 54px);
    bottom: clamp(28px, 3.4vw, 54px);
    width: 1px;
    background: linear-gradient(rgba(20, 16, 15, 0) 0%, rgba(20, 16, 15, 0.14) 18%, rgba(20, 16, 15, 0.14) 82%, rgba(20, 16, 15, 0) 100%);
    pointer-events: none;
  }
}
/* Everything real sits above the wash and the rule. */
.card__ghost, .card__index, .card__copy, .card__tags, .card__sign, .card__cta { position: relative; z-index: 1; }

/* ---- the enormous faint word behind everything ---- */
.card__ghost {
  position: absolute;
  left: clamp(-10px, 0.5vw, 10px);
  top: clamp(6px, 1.4vw, 24px);
  /* Large enough that the word runs on behind the plate and is cut by it,
     the way the reference does it. Longer names simply clip at the card. */
  font-size: clamp(4rem, 11vw, 10.5rem);
  font-weight: var(--display-weight);
  font-stretch: var(--display-stretch);
  line-height: 0.9;
  letter-spacing: var(--display-track);
  text-transform: uppercase;
  color: rgba(20, 16, 15, 0.075);
  pointer-events: none;
  white-space: nowrap;
}

/* ---- the count ---- */
.card__index {
  font-weight: var(--display-weight);
  font-stretch: var(--display-stretch);
  font-size: clamp(1.25rem, 2vw, 1.9rem);
  letter-spacing: 0.02em;
  color: var(--ink-faint);
  align-self: center;
}
.card__index span { color: var(--ink); }
@media (min-width: 920px) { .card__index { grid-column: 1; grid-row: 2; } }

/* ---- the copy ---- */
@media (min-width: 920px) { .card__copy { grid-column: 2; grid-row: 1; } }
.card__kicker {
  font-size: var(--t-caption);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 14px;
}
.card__name {
  font-family: var(--font);
  font-weight: var(--display-weight);
  font-stretch: var(--display-stretch);
  font-size: clamp(2.1rem, 3.6vw, 3.5rem);
  line-height: 1.0;
  letter-spacing: var(--display-track);
  text-transform: uppercase;
  margin-bottom: 16px;
}
.card__desc {
  color: var(--ink-muted);
  max-width: 36ch;
  font-size: var(--t-lead);
  line-height: 1.5;
}

/* ---- the pills ---- */
.card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  align-content: center;
  list-style: none;
  margin: 0;
  padding: 0;
}
@media (min-width: 920px) { .card__tags { grid-column: 2; grid-row: 2; } }
.card__tags li {
  padding: 12px 24px;
  border: 1px solid rgba(20, 16, 15, 0.16);
  border-radius: var(--radius-btn);
  background: #F3EFE7;
  font-size: var(--t-caption);
  color: var(--ink);
}

/* ---- the signature at the foot ---- */
.card__sign { align-self: end; line-height: 1.5; }
@media (min-width: 920px) { .card__sign { grid-column: 1; grid-row: 3; } }
.card__mark {
  display: block;
  font-weight: 700;
  font-size: 1.1875rem;
  letter-spacing: -0.005em;
}
.card__by { display: block; font-size: 0.9375rem; color: var(--ink-faint); }

/* ---- the call, bracketed at the corners ---- */
.card__cta {
  position: relative;
  justify-self: start;
  align-self: end;
  padding: 16px 30px;
  font-size: 0.875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
}
@media (min-width: 920px) { .card__cta { grid-column: 2; grid-row: 3; } }
.card__cta::before,
.card__cta::after {
  content: '';
  position: absolute;
  width: 12px;
  height: 12px;
  border: 1px solid rgba(20, 16, 15, 0.42);
  transition: inset 320ms var(--ease), border-color 320ms var(--ease);
}
.card__cta::before { inset: 0 auto auto 0; border-width: 1px 0 0 1px; }
.card__cta::after  { inset: auto 0 0 auto; border-width: 0 1px 1px 0; }
a.card__cta:hover::before { inset: -4px auto auto -4px; border-color: var(--ember-lift); }
a.card__cta:hover::after  { inset: auto -4px -4px auto; border-color: var(--ember-lift); }
a.card__cta:focus-visible { outline: 2px solid var(--ember-lift); outline-offset: 4px; }
.card__cta--pending { color: var(--ink-faint); }
.card__cta--pending::before,
.card__cta--pending::after { border-color: rgba(20, 16, 15, 0.20); }

/* Nothing here depends on motion: the cards still pin and stack, and with
   the band held still the type behind them simply sits there. */
@media (prefers-reduced-motion: reduce) {
  .card__cta::before, .card__cta::after { transition: none; }
}

/* =========================================================================
   INTERLUDE . one line, held between chapters

   A held breath rather than a section: no heading, no call, nothing to do.
   The words arrive one at a time as the reader travels, which is the whole
   effect. If nothing is driving them they are simply all there, at full
   strength, because a quote nobody can read is worse than no quote.
   ========================================================================= */
.quote {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 86svh;
  padding-block: var(--s-xxl);
  overflow: clip;
  background: #E8E1D5;
  isolation: isolate;
  --ink: #14100F;
  --ink-muted: #4B443D;
  --ink-faint: #635B53;
  color: var(--ink);
}
.quote__inner { position: relative; z-index: 2; text-align: center; }
.quote .container { max-width: 1460px; }

.quote__line {
  font-weight: var(--display-weight);
  font-stretch: var(--display-stretch);
  font-size: clamp(1.45rem, 4.4vw, 4rem);
  line-height: 1.04;
  letter-spacing: var(--display-track);
  text-transform: uppercase;
  max-width: none;
  margin-inline: auto;
  color: var(--ink);
}
/* Words are wrapped by script. Until then the line is a plain line, and
   each written line is its own block so the break falls where it was
   written rather than wherever the column runs out. */
.quote__row { display: block; }

.quote__w { display: inline-block; }
.quote__c { font-style: normal; position: relative; }
/* The sentence, offered once and intact, for anything that reads rather
   than looks. The letters beside it are hidden from it. */
.quote__read {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}
/* Dimmed only once something is driving the reveal. 0.52 measures 4.63:1,
   so even the unlit half is readable rather than merely present. */
/* Held below the line until its turn, then lifted into place. is-live is
   only ever added once something is driving them, so with no script every
   word is simply where it belongs. */
/* A letter snaps on. A slow fade here would read as a dissolve, not as
   writing, so the transition is only long enough to take the hard edge off. */
.quote.is-live .quote__c { opacity: 0; transition: opacity 80ms linear; }
.quote.is-live .quote__c.is-on { opacity: 1; }
/* The write head. Absolute and out of flow, so putting it on a letter or
   taking it off never moves anything. */
.quote.is-live .quote__c.is-head::after {
  content: '';
  position: absolute;
  top: 0.08em;
  bottom: 0.14em;
  right: -0.09em;
  width: 0.06em;
  background: currentColor;
  animation: pf-caret 1s steps(1, end) infinite;
}
@keyframes pf-caret { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

.quote__by {
  margin-top: var(--s-md);
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.quote__by::before { content: ''; display: block; width: 34px; height: 1px; background: var(--accent); margin: 0 auto var(--s-sm); }

.quote__cta { margin-top: var(--s-lg); justify-content: center; }
/* The primary button's face is dark and this section's ink is dark: without
   this the label would be black on black. */
.quote .btn--primary { color: #E8E1D5; }

/* The ember behind the plain one. */
.quote__flare {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(62% 50% at 50% 56%, rgba(142, 17, 20, 0.10) 0%, transparent 70%),
    radial-gradient(44% 34% at 50% 44%, rgba(224, 183, 50, 0.14) 0%, transparent 72%);
}

@media (prefers-reduced-motion: reduce) {
  /* The words are simply all there. */
  .quote__c,
  .quote.is-live .quote__c { opacity: 1; transition: none; }
  .quote.is-live .quote__c.is-head::after { display: none; }
}

/* =========================================================================
   10 . THE VOICES
   ========================================================================= */
.voices { background: var(--surface); overflow: clip; }
.voices__head { margin-bottom: var(--s-xl); }
.voices__track { display: grid; gap: var(--s-lg); }
.voice {
  display: grid;
  gap: var(--s-sm);
  grid-template-columns: 1fr;
  padding-top: var(--s-lg);
  border-top: 1px solid var(--line);
}
@media (min-width: 900px) {
  .voice { grid-template-columns: 0.6fr 1.6fr; gap: var(--s-lg); align-items: start; }
  .voice--wide { grid-template-columns: 1fr; }
}
.voice__quote {
  font-size: clamp(1.15rem, 2.4vw, 1.9rem);
  font-weight: 600;
  font-stretch: 92%;
  line-height: 1.22;
  letter-spacing: -0.015em;
  text-wrap: pretty;
}
.voice--wide .voice__quote { font-size: clamp(1.5rem, 3.9vw, 3rem); font-weight: 700; line-height: 1.1; }
.voice__who { display: grid; gap: 4px; align-content: start; }
.voice__name {
  font-size: var(--t-h4);
  font-weight: 800;
  font-stretch: 86%;
  text-transform: uppercase;
  color: var(--accent);
}
.voice__cred { font-size: var(--t-small); color: var(--ink-muted); max-width: 30ch; }
.voice--wide .voice__who {
  margin-top: var(--s-md);
  grid-template-columns: auto 1fr;
  gap: var(--s-sm);
  align-items: baseline;
}

/* =========================================================================
   11 . THE NEXT BRIDGE . drawn in SVG
   ========================================================================= */
.next { position: relative; overflow: clip; padding-block: var(--s-xl); }
.next__inner { position: relative; z-index: 1; }
.next__title { margin-bottom: var(--s-lg); }

.bridge {
  display: block;
  width: 100%;
  height: auto;
  margin-bottom: var(--s-lg);
  overflow: visible;
}
.bridge__draw {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.4;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.bridge__draw--faint { stroke: var(--line); stroke-width: 1; }


.next__list { border-top: 1px solid var(--line); }
.next__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-md);
  padding-block: clamp(20px, 3.4vw, 38px);
  border-bottom: 1px solid var(--line);
  transition: padding-left var(--dur-std) var(--ease), color var(--dur-std) var(--ease);
}
.next__item:hover { color: var(--accent); padding-left: 14px; }
.next__label {
  font-size: clamp(1.3rem, 3.4vw, 2.5rem);
  font-weight: 800;
  font-stretch: 82%;
  text-transform: uppercase;
  line-height: 1;
  letter-spacing: -0.02em;
}
.next__arrow { font-size: var(--t-h3); transition: transform var(--dur-std) var(--ease); }
.next__item:hover .next__arrow { transform: translateX(10px); }

/* =========================================================================
   12 . THE INVITATION
   ========================================================================= */
.signup__inner {
  display: grid;
  gap: var(--s-md);
  grid-template-columns: 1fr;
  align-items: end;
}
@media (min-width: 900px) {
  .signup__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--s-lg); }
}
.signup__title { font-size: var(--t-h2); }

/* =========================================================================
   Short viewports and reduced motion
   ========================================================================= */
@media (max-height: 760px) and (min-width: 900px) {
  .hero__sticky { padding-top: 112px; }
  .hero__title { font-size: clamp(2.5rem, 6.6vh, 4.5rem); }
  .hero__eyebrow { margin-bottom: var(--s-sm); }
}
@media (max-height: 560px) {
  .hero { min-height: 0; }
  .hero__sticky { position: static; height: auto; padding-top: 108px; padding-bottom: var(--s-md); }
  .hero__title { font-size: clamp(1.9rem, 8vh, 3rem); }
  .hero__sub { font-size: var(--t-body); }
  .statement { min-height: 0; }
  .statement__pin { position: static; height: auto; padding-block: var(--s-xl); }
}

/* A scene needs vertical room to be a scene. Below that the sections become
   ordinary blocks rather than sticky panels squeezed into nothing. */
@media (max-width: 899px) {
  .hero { min-height: 0; }
  .hero__sticky { position: static; height: 100svh; }
  .statement { min-height: 0; }
  .statement__pin { position: static; height: auto; min-height: 78svh; }
}

@media (prefers-reduced-motion: reduce) {
  .hero { min-height: 0; }
  .hero__sticky { position: static; height: 100svh; }
  .hero__inner { opacity: 1 !important; transform: none !important; }
  .statement { min-height: 0; }
  .statement__pin { position: static; height: auto; min-height: 70svh; }
  .statement__flood { clip-path: inset(0 0 0 0); opacity: 0.9; }
  
}

/* ---- the margins come alive ----
   A book left flat is a picture of a book. Given a little height, a little
   lean, and a shadow that answers both, it becomes an object in the room --
   which is the only thing that makes the margin worth its width. All of it is
   slow on purpose: the eye should catch it on the second look, not the first. */
.opening__jacket-stage { perspective: 1000px; perspective-origin: 50% 46%; }
.opening__jacket-turn {
  display: block;
  transform-style: preserve-3d;
  /* Damped, so the jacket answers the cursor with some weight instead of
     snapping to it. */
  transition: transform 420ms var(--ease);
  transform:
    rotateX(calc(var(--jy, 0) * -5deg))
    rotateY(calc(var(--jx, 0) * 9deg + var(--jturn, 0) * 6deg));
}
/* A filter flattens 3D, so the filtered layer sits INSIDE the rotated one. */
.opening__jacket-lift {
  display: block;
  will-change: transform, filter;
  animation: pf-levitate 8.5s ease-in-out infinite;
}
/* The shadow rides the same keyframes as the rise: it drops further and goes
   softer as the book climbs. That contrary motion is the whole tell. */
@keyframes pf-levitate {
  0%, 100% { transform: translate3d(0, 5px, 0);  filter: drop-shadow(0 13px 18px rgba(27, 22, 19, 0.32)); }
  50%      { transform: translate3d(0, -9px, 0); filter: drop-shadow(0 34px 42px rgba(27, 22, 19, 0.16)); }
}

/* ---- the right margin keeps time ---- */
.opening__spine { animation: pf-drift 11s ease-in-out infinite; }
@keyframes pf-drift {
  0%, 100% { transform: translateY(-4px); }
  50%      { transform: translateY(4px); }
}
/* Only the mark you are on breathes; the rest stay still and stay quiet. */
.opening__mark.is-on { animation: pf-mark 2.8s ease-in-out infinite; }
@keyframes pf-mark {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.48; }
}

@media (prefers-reduced-motion: reduce) {
  .opening__jacket-lift,
  .opening__spine,
  .opening__mark.is-on { animation: none; }
  .opening__jacket-lift { filter: drop-shadow(0 20px 30px rgba(27, 22, 19, 0.26)); }
  .opening__jacket-turn { transform: none; transition: none; }
}

/* ---- two books adrift in the margins ----
   The line runs nearly the full width, so there is no room BESIDE it. The
   room is above and below, in the corners, where nothing is ever set. The
   books go there: far enough out to leave the sentence alone, close enough
   to say what the sentence is about. Dropped entirely when the corners
   stop being empty. */
.quote__floats { position: absolute; inset: 0; z-index: 1; pointer-events: none; display: none; }
@media (min-width: 1080px) { .quote__floats { display: block; } }
.quote__float {
  position: absolute;
  width: clamp(96px, 8.5vw, 176px);
  perspective: 1100px;
  perspective-origin: 50% 46%;
}
.quote__float img { display: block; width: 100%; height: auto; }
.quote__float-turn { display: block; transform-style: preserve-3d; transition: transform 520ms var(--ease); }
/* A filter flattens 3D, so the filtered layer sits INSIDE the rotated one. */
.quote__float-lift { display: block; will-change: transform, filter; }

/* Upper left and lower right: opposite corners, opposite lean, and out of
   phase, so the pair never reads as one gesture repeated twice. */
.quote__float--a { top: 4%; left: clamp(12px, 3vw, 74px); }
.quote__float--a .quote__float-turn {
  transform:
    rotateX(calc(var(--jy, 0) * -6deg))
    rotateY(calc(var(--jx, 0) * 11deg + var(--jturn, 0) * 8deg))
    rotate(-7deg);
}
.quote__float--a .quote__float-lift { animation: pf-adrift 9.5s ease-in-out infinite; }

.quote__float--b { bottom: 4%; right: clamp(12px, 3vw, 74px); }
.quote__float--b .quote__float-turn {
  transform:
    rotateX(calc(var(--jy, 0) * -6deg))
    rotateY(calc(var(--jx, 0) * -11deg + var(--jturn, 0) * -8deg))
    rotate(6deg);
}
.quote__float--b .quote__float-lift { animation: pf-adrift 11.5s ease-in-out infinite -4s; }

/* Same contrary shadow as the jacket in the book section: it falls further
   and softens as the book climbs. Tuned darker here, for paper. */
@keyframes pf-adrift {
  0%, 100% { transform: translate3d(0, 7px, 0);   filter: drop-shadow(0 12px 20px rgba(27, 22, 19, 0.26)); }
  50%      { transform: translate3d(0, -11px, 0); filter: drop-shadow(0 32px 44px rgba(27, 22, 19, 0.13)); }
}

@media (prefers-reduced-motion: reduce) {
  .quote__float-lift { animation: none; filter: drop-shadow(0 18px 30px rgba(27, 22, 19, 0.22)); }
  .quote__float-turn { transition: none; }
  .quote__float--a .quote__float-turn { transform: rotate(-7deg); }
  .quote__float--b .quote__float-turn { transform: rotate(6deg); }
}

/* =========================================================================
   04 . THE PRINCIPLES . a ladder beside a counter
   The steps are ordinary blocks in flow, one viewport tall each. The
   counter beside them is sticky and exactly as tall, so it sits still
   while they pass. Because both are the same height, the counter travels
   one step per step: the roll needs no measuring, only the progress.
   The rail is a grid ITEM, and a sticky item is confined to its grid area
   -- which here is the whole row, because the steps column defines the
   row height. align-self: start is what lets it be short and still travel.
   ========================================================================= */
.ladder { display: block; }
@media (min-width: 900px) {
  .ladder {
    display: grid;
    grid-template-columns: minmax(0, 0.72fr) minmax(0, 1fr);
    gap: clamp(28px, 5vw, 88px);
    align-items: start;
  }
}

.step { display: grid; align-content: center; gap: var(--s-sm); padding-block: var(--s-xl); }
@media (min-width: 900px) { .step { min-height: 100svh; padding-block: 0; } }

/* --near is 1 at the middle of the run and 0 at either end. It defaults to
   1, so with no script every step reads at full strength. */
.step__copy {
  opacity: calc(0.14 + var(--near, 1) * 0.86);
  transform: translateY(calc((1 - var(--near, 1)) * 18px));
}
.step__count {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}
.step__name {
  font-size: clamp(2.4rem, 6.4vw, 5.4rem);
  font-weight: var(--display-weight); font-stretch: var(--display-stretch);
  letter-spacing: var(--display-track); text-transform: uppercase; line-height: 0.92;
}
.step__thesis { margin-top: var(--s-sm); font-size: var(--t-h3); font-weight: 600; color: var(--accent); }
.step__desc { margin-top: var(--s-sm); color: var(--ink-muted); max-width: 46ch; }

/* ---- the counter ---- */
.ladder__rail { display: none; }
@media (min-width: 900px) {
  .ladder__rail {
    display: grid; place-items: center end;
    padding-right: clamp(0px, 4vw, 60px);
    position: sticky; top: 0; align-self: start;
    height: 100svh;
    pointer-events: none;
  }
}
.ladder__num {
  font-size: clamp(7rem, min(34vw, 50vh), 34rem);
  font-weight: 900; font-stretch: 70%; line-height: 0.8;
  letter-spacing: -0.03em; color: var(--ember-lift);
  white-space: nowrap;
  /* Without this the 1 is narrower than the 3 and the gap after the 0
     changes as the dial turns. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}
/* The two digits share a baseline: the units box is inline and sized in em,
   so it scales with the number instead of being positioned against it. */
/* An inline-block whose children are all absolute has no line box, so its
   baseline falls to its bottom edge and the two digits stop sharing a line.
   One invisible digit is left in flow to hold the baseline and the width. */
.ladder__units { position: relative; display: inline-block; }
.ladder__ghost { visibility: hidden; }
.ladder__units i {
  position: absolute; top: 0; left: 0; width: 100%;
  display: block; text-align: center; font-style: normal;
  transform: translateY(calc((var(--n, 0) - var(--roll, 0)) * 100%));
  opacity: 0;
}
/* Without the script the counter still reads 01 rather than a pile of digits. */
.ladder__units i:first-child { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .step__copy { opacity: 1; transform: none; }
}

/* ---- narrow ---- 
   Below the two-column layout a step is a few hundred pixels tall, so three
   of them share the screen and the dimming would leave two of them at a
   seventh of full strength at once. It only makes sense when one step fills
   the view, so it is dropped here. And with the rail gone the counter comes
   back inline, above each step, where it can still carry the section. */
@media (max-width: 899px) {
  .step__copy { opacity: 1; transform: none; }
  .step + .step { border-top: 1px solid var(--line); }
  .step::before {
    content: attr(data-num);
    display: block;
    font-size: clamp(3.4rem, 19vw, 7rem);
    font-weight: 900; font-stretch: 70%; line-height: 0.8;
    letter-spacing: -0.03em; color: var(--ember-lift);
    font-variant-numeric: tabular-nums;
    font-feature-settings: 'tnum' 1;
  }
}

/* ---- the linework ----
   Anchored to the sticky rail rather than to the section, so it holds still
   while the steps pass, and wider than the rail so it reaches back across
   the text. Strokes are kept at one pixel through the slice scaling. */
.ladder__art {
  position: absolute; top: 0; right: 0;
  width: 215%; height: 100%;
  /* The global svg reset caps this at 100% of the rail, which would keep
     the linework off the text entirely. */
  max-width: none;
  z-index: 0; pointer-events: none;
}
.ladder__art path { fill: none; stroke: var(--line); stroke-width: 1; vector-effect: non-scaling-stroke; }
.ladder__art path.is-warm { stroke: var(--ember); }
/* The numeral and the steps sit above it. */
.ladder__num { position: relative; z-index: 1; }
.ladder__steps { position: relative; z-index: 1; }

/* =========================================================================
   03c . AT A GLANCE . a bordered grid, not spaced cards
   The cells share hairlines rather than sitting apart: one pixel of gap over
   a line-coloured ground, each cell painting its own. One cell is lifted out
   of it on purpose.
   ========================================================================= */
.glance { padding-block: var(--s-xxl); background: var(--bg); }
.glance__head { margin-bottom: var(--s-xl); }

.glance__grid {
  display: grid;
  /* Sem isto a coluna 'auto' estica ate a largura do conteudo mais largo
     e o documento inteiro ganha scroll lateral no celular. */
  grid-template-columns: minmax(0, 1fr);
  gap: 1px;
  background: var(--line);
  background-clip: content-box;
  border: 0;
  grid-template-areas: "face" "craft" "say" "scale" "work" "count" "books" "day";
}
@media (min-width: 1000px) {
  .glance__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-areas:
      "face craft say"
      "face scale work"
      "face scale count"
      "books day  day";
  }
}

.gcell {
  position: relative; min-width: 0;
  background: var(--bg);
  padding: clamp(20px, 2.1vw, 32px);
  display: flex; flex-direction: column;
}
.gcell--face  { grid-area: face; padding: 0; overflow: clip; min-height: 320px; }
.gcell--craft { grid-area: craft; }
.gcell--say   { grid-area: say; }
.gcell--scale { grid-area: scale; justify-content: center; gap: var(--s-sm); }
.gcell--work  { grid-area: work; min-height: 190px; }
.gcell--count { grid-area: count; flex-direction: row; align-items: center; justify-content: space-between; gap: var(--s-sm); }
.gcell--books { grid-area: books; }
.gcell--day   { grid-area: day; gap: var(--s-md); }

.gcell--face img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---- type inside a cell ---- */
.gcell__label {
  font-family: var(--font); font-size: 0.625rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--ink-faint); margin-bottom: var(--s-sm);
}
.gcell__title { font-size: clamp(1.1rem, 1.7vw, 1.55rem); font-weight: 600; line-height: 1.15; color: var(--ink); }
.gcell__body { margin-top: 10px; font-size: var(--t-body); line-height: 1.5; color: var(--ink-muted); }
.gcell__figure {
  display: flex; align-items: center; gap: 14px;
  font-size: clamp(2rem, 3.4vw, 3rem); font-weight: 900; font-stretch: 70%;
  line-height: 0.9; letter-spacing: -0.02em; color: var(--ink);
}
.gcell__num { font-size: clamp(2.6rem, 4.6vw, 4.2rem); color: var(--ember-lift); }

/* ---- the one lifted cell ---- */
.gcell--say {
  z-index: 2;
  background: var(--surface-raised);
  transform: translate(5px, -13px);
  box-shadow: 0 24px 46px rgba(0, 0, 0, 0.55);
  transition: transform 420ms var(--ease), box-shadow 420ms var(--ease);
}
.gcell--say::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(118% 88% at 88% 0%, rgba(200, 30, 34, 0.24), transparent 62%),
    radial-gradient(92% 82% at 6% 100%, rgba(224, 183, 50, 0.12), transparent 60%);
}
.gcell--say > * { position: relative; z-index: 1; }
.gcell--say:hover { transform: translate(5px, -20px); box-shadow: 0 34px 60px rgba(0, 0, 0, 0.62); }

/* Available to anything that reads, invisible to anything that looks. */
.u-sr {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* ---- the running strip of marks ----
   The gap lives on each mark rather than in the flex gap: with a real gap the
   track is twelve marks plus eleven gaps, so half of it is not one cycle and
   the loop jumps every pass. */
.ticker { margin-top: auto; padding-top: var(--s-md); overflow: clip; }
.ticker__track { display: flex; width: max-content; animation: pf-ticker 30s linear infinite; }
.ticker:hover .ticker__track { animation-play-state: paused; }
@keyframes pf-ticker { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.ticker__mark {
  display: grid; justify-items: center; gap: 10px; margin-right: clamp(26px, 3vw, 46px);
  font-size: 0.625rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink-faint); white-space: nowrap;
}
.ticker__glyph { width: 20px; height: 20px; display: block; }
.ticker__glyph--ring  { border: 2px solid var(--accent); border-radius: 50%; }
.ticker__glyph--bars  { background: repeating-linear-gradient(to bottom, var(--ember-lift) 0 3px, transparent 3px 7px); }
.ticker__glyph--tri   { background: var(--accent); clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.ticker__glyph--dot   { background: var(--ember-lift); border-radius: 50%; transform: scale(0.72); }
.ticker__glyph--sq    { border: 2px solid var(--ember-lift); }
.ticker__glyph--cross { background: linear-gradient(var(--accent), var(--accent)) center/2px 100% no-repeat, linear-gradient(var(--accent), var(--accent)) center/100% 2px no-repeat; }

/* ---- the drifting roles ----
   Scoped to .gcell. Unscoped, this block sat after the statement's own
   @media (max-width: 899px) rule and undid its `position: static`, so the
   statement chips stayed absolute on phones, escaped the pin's overflow
   (the pin is static there, so it is not their containing block) and gave
   the whole page 126px of horizontal scroll. */
.gcell .chip {
  position: absolute; z-index: 1;
  padding: 7px 14px; border-radius: var(--radius-btn);
  font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.04em; white-space: nowrap;
  animation: pf-chip 11s ease-in-out infinite;
}
.gcell .chip--a { top: 52%; left: 7%;  background: var(--ember-lift); color: #F4EFE6; animation-delay: 0s; }
.gcell .chip--b { top: 71%; left: 42%; background: var(--accent); color: #14100F; animation-delay: -3.7s; }
.gcell .chip--c { top: 44%; left: 58%; background: var(--surface-raised); color: var(--ink); border: 1px solid var(--line); animation-delay: -7.4s; }
@keyframes pf-chip {
  0%, 100% { transform: translate(0, 0); }
  33%      { transform: translate(13px, -9px); }
  66%      { transform: translate(-9px, 7px); }
}

/* ---- the four parts of a day ---- */
.track { position: relative; list-style: none; margin: 0; padding: 0; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; }
.track::before, .track::after { content: ''; position: absolute; top: 10px; height: 1px; left: 12%; }
.track::before { right: 12%; background: var(--line); }
.track::after  { width: 0; background: var(--ember-lift); animation: pf-trackline 9s linear infinite; }
.track__step {
  position: relative; display: grid; justify-items: center; gap: 12px;
  font-size: 0.625rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-faint);
}
.track__step i {
  width: 21px; height: 21px; border-radius: 50%; display: block;
  border: 1px solid var(--line); background: var(--bg);
  animation: pf-track 9s linear infinite;
  animation-delay: calc(var(--k, 0) * 1.15s);
}
@keyframes pf-track {
  0%, 3%    { background: var(--bg); border-color: var(--line); }
  7%, 62%   { background: var(--ember-lift); border-color: var(--ember-lift); }
  74%, 100% { background: var(--bg); border-color: var(--line); }
}
@keyframes pf-trackline {
  0%       { width: 0; opacity: 1; }
  58%      { width: 76%; opacity: 1; }
  66%      { width: 76%; opacity: 0; }
  67%,100% { width: 0; opacity: 0; }
}

/* ---- the wreath ---- */
.laurel { flex: none; width: 22px; height: 42px; border: 1px solid var(--ember-lift); border-radius: 50%; opacity: 0.7; }
.laurel--l { border-right-color: transparent; border-top-color: transparent; }
.laurel--r { border-left-color: transparent; border-top-color: transparent; }

/* ---- the two books ---- */
.gbooks { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-md); margin-top: auto; }
.gbook img { width: 100%; height: auto; display: block; }
.gbook figcaption { margin-top: 12px; display: grid; gap: 3px; }
.gbook b { font-size: var(--t-caption); font-weight: 600; color: var(--ink); }
.gbook span { font-size: 0.625rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  .ticker__track, .chip, .track__step i, .track::after { animation: none; }
  .track::after { width: 76%; }
  .track__step i { background: var(--ember-lift); border-color: var(--ember-lift); }
  .gcell--say, .gcell--say:hover { transform: none; }
}

@media (max-width: 999px) {
  /* A 2:3 portrait in a squat box gets cropped to a band. Hold the shape. */
  .gcell--face { aspect-ratio: 4 / 5; min-height: 0; }
  /* In one column the lift only reads as the card being misaligned, so it
     keeps the raised ground and the shadow but stays in line. */
  .gcell--say { transform: none; }
  .gcell--say:hover { transform: none; }
  .gcell--count { flex-direction: column; align-items: flex-start; }
}

/* =========================================================================
   05 . THE NOTE . a letter left on the desk
   The sheet is the one piece of paper in a dark page, so it re-points the
   ink tokens inside itself rather than restating a colour on every line.
   ========================================================================= */
.note { padding-block: var(--s-xxl); background: var(--bg); overflow: clip; }

.note__say { margin-bottom: var(--s-xl); }
.note__statement {
  font-size: clamp(1.45rem, 3.3vw, 3.1rem);
  font-weight: var(--display-weight); font-stretch: var(--display-stretch);
  letter-spacing: var(--display-track); line-height: 1.06;
  text-transform: uppercase; color: var(--ink);
  max-width: 22ch; margin-inline: auto; text-align: center;
}
@media (min-width: 900px) {
  .note__statement { max-width: none; text-wrap: balance; }
}
.note__statement em { font-style: normal; color: var(--ember-lift); }

/* ---- the stack ---- */
.note__stage { position: relative; }
.note__leaf {
  position: absolute;
  top: 26px; bottom: -26px;
  left: calc(var(--gutter) + 15px); right: calc(var(--gutter) - 23px);
  background: #CFC6B6; border-radius: 2px;
  transform: rotate(1.4deg); transform-origin: 50% 100%;
  transition: transform 900ms var(--ease), opacity 900ms var(--ease);
}
.note__leaf--b {
  background: #BCB2A1; transform: rotate(-1.9deg);
  top: 36px; bottom: -36px;
  left: calc(var(--gutter) - 23px); right: calc(var(--gutter) + 15px);
}

/* ---- the sheet ---- */
.note__sheet {
  position: relative; z-index: 2;
  background: #E8E1D5; border-radius: 2px;
  padding: clamp(28px, 4.2vw, 74px);
  box-shadow: 0 34px 60px rgba(0, 0, 0, 0.5);
  --ink: #14100F;
  --ink-muted: #4B443D;
  --ink-faint: #635B53;
  --line: rgba(20, 16, 15, 0.16);
  color: var(--ink);
}

.note__head { position: relative; padding-bottom: var(--s-md); border-bottom: 1px solid var(--line); }
@media (min-width: 760px) { .note__head { padding-right: 34%; } }
.note__title { font-size: clamp(1.5rem, 2.6vw, 2.3rem); font-weight: 600; line-height: 1.1; color: var(--ink); }
.note__kicker { margin-top: 8px; font-size: clamp(0.95rem, 1.3vw, 1.1rem); color: var(--ember); }
.note__draft {
  margin-top: var(--s-sm); display: inline-block;
  padding: 5px 11px; border: 1px dashed rgba(20, 16, 15, 0.34); border-radius: 2px;
  font-family: var(--font); font-size: 0.625rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: #635B53;
}

/* ---- the letter ---- */
.note__body { margin-top: var(--s-lg); max-width: 68ch; }
.note__hail { font-size: var(--t-body); color: var(--ink); }
.note__body > p + p { margin-top: var(--s-md); }
.note__body p { font-size: var(--t-body); line-height: 1.62; color: #3B342E; }
.note__off { margin-top: var(--s-lg) !important; color: var(--ink) !important; }
.note__sign {
  margin-top: 6px;
  font-family: 'Playfair Display', Georgia, serif;
  font-size: clamp(1.8rem, 3vw, 2.6rem) !important;
  line-height: 1 !important; color: var(--ink) !important;
}
.note__role { margin-top: 8px; font-size: 0.8125rem !important; color: #635B53 !important; }
.note__role i { font-style: italic; }

/* ---- the photograph, and the clip holding it ---- */
.note__pin {
  display: block; position: relative; z-index: 3;
  width: clamp(116px, 34vw, 158px);
  margin: 6px 0 var(--s-md) auto;
}
@media (min-width: 760px) {
  .note__pin {
    position: absolute; margin: 0;
    top: clamp(-28px, -2vw, -12px); right: clamp(20px, 3.4vw, 58px);
    width: clamp(120px, 15vw, 196px);
  }
}
.note__pin img {
  display: block; width: 100%; height: auto;
  background: #F4EFE6; padding: 8px 8px 26px;
  box-shadow: 0 16px 30px rgba(0, 0, 0, 0.34);
  /* It hangs from the clip, so it turns about a point just above its own
     top edge rather than about its middle. */
  transform-origin: 50% -8%;
  transform: rotate(3.2deg);
  animation: pf-sway 7.5s ease-in-out infinite;
}
@keyframes pf-sway {
  0%, 100% { transform: rotate(3.2deg); }
  50%      { transform: rotate(-1.6deg); }
}
.note__clip {
  position: absolute; z-index: 4; top: -16px; right: 22%;
  width: 20px; height: 50px;
  border: 2px solid rgba(20, 16, 15, 0.5); border-radius: 10px;
}
.note__clip::after {
  content: ''; position: absolute; left: 4px; right: 4px; top: 8px; bottom: 12px;
  border: 2px solid rgba(20, 16, 15, 0.5); border-bottom: 0; border-radius: 6px 6px 0 0;
}

/* ---- the pulled quote ---- */
.note__pull {
  position: relative; margin-top: var(--s-lg); padding: clamp(18px, 2vw, 26px);
  border: 1px solid rgba(142, 17, 20, 0.34); border-left-width: 3px;
  font-size: clamp(0.95rem, 1.2vw, 1.125rem) !important;
  font-weight: 600; line-height: 1.5; color: var(--ink) !important;
  overflow: clip; isolation: isolate;
}
/* The wash is a child layer rather than a background, so it can be wiped in
   from the left without moving the words. */
.note__pull::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: rgba(224, 183, 50, 0.22);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 900ms var(--ease);
}
.note.is-open .note__pull::before { transform: scaleX(1); }

/* ---- the stack fans out once it is looked at ---- */
.note__leaf { opacity: 0; transform: rotate(0deg); }
.note.is-open .note__leaf--a { opacity: 1; transform: rotate(1.4deg); }
.note.is-open .note__leaf--b { opacity: 1; transform: rotate(-1.9deg); transition-delay: 90ms; }

/* ---- what was earned, carried over from the bento ----
   The strip used to be one bordered block, but it IS the container, and a
   container carries the page gutter as padding -- so its border and ground
   painted 65px out into the margin on both sides, reading as two grey slabs
   bolted to the ends. Each card carries its own edge instead. */
.note__seals {
  margin-top: var(--s-xl);
  display: grid;
  gap: clamp(10px, 1vw, 16px);
  grid-template-columns: repeat(auto-fit, minmax(178px, 1fr));
}

.seal {
  position: relative; overflow: clip; isolation: isolate;
  padding: clamp(22px, 2vw, 30px) clamp(18px, 1.6vw, 24px) clamp(18px, 1.6vw, 24px);
  border: 1px solid var(--line); background: var(--bg);
  opacity: 0; transform: translateY(15px);
  transition: opacity 620ms var(--ease), transform 620ms var(--ease),
              background-color 420ms var(--ease), border-color 420ms var(--ease);
  transition-delay: calc(var(--k, 0) * 85ms);
}
.note.is-open .seal { opacity: 1; transform: none; }

/* One rule drawn across the row rather than five drawn at once: the delay is
   the card index, so it reads left to right as a single gesture. */
.seal__rule {
  position: absolute; top: -1px; left: -1px; right: -1px; height: 2px; z-index: 2;
  background: var(--accent);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 760ms var(--ease), background-color 380ms var(--ease);
  transition-delay: calc(var(--k, 0) * 110ms);
}
.note.is-open .seal__rule { transform: scaleX(1); }

.seal__idx {
  position: absolute; z-index: 2; top: clamp(14px, 1.3vw, 18px); right: clamp(16px, 1.4vw, 20px);
  font-family: var(--font); font-size: 0.625rem; letter-spacing: 0.16em;
  color: var(--ink-faint); transition: color 380ms var(--ease);
}

/* The bloom is a layer, not a background, so it can fade without touching
   the ground colour underneath it. */
.seal::before {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(126% 104% at 0% 0%, rgba(224, 183, 50, 0.15), transparent 64%);
  opacity: 0; transition: opacity 460ms var(--ease);
}
.seal__source { position: relative; z-index: 1; font-size: var(--t-body); font-weight: 600; color: var(--ink); }
.seal__what {
  position: relative; z-index: 1; margin-top: 7px; font-size: var(--t-caption); color: var(--ink-muted);
  transition: color 380ms var(--ease), transform 460ms var(--ease);
}

.note.is-open .seal:hover {
  transform: translateY(-6px); transition-delay: 0s;
  background: var(--surface); border-color: rgba(224, 183, 50, 0.34);
}
.seal:hover::before { opacity: 1; }
.seal:hover .seal__rule { background: var(--ember-lift); transition-delay: 0s; }
.seal:hover .seal__idx { color: var(--accent); }
.seal:hover .seal__what { color: var(--ink); transform: translateX(3px); }

@media (prefers-reduced-motion: reduce) {
  .note__pin img { animation: none; }
  .note__leaf { opacity: 1; transition: none; }
  .note__pull::before { transform: scaleX(1); transition: none; }
  .seal { opacity: 1; transform: none; transition: none; }
  .seal__rule { transform: scaleX(1); transition: none; }
}

/* =========================================================================
   08 . THE WORK . three cards, read in one screen
   The pinned scene this replaced spent four viewports on fifty-one words,
   with the copy filling an eighth of the screen at any moment. Same words,
   all three visible at once, no pin. The page already carries six.
   ========================================================================= */
.work {
  padding-block: var(--s-xxl);
  background: #E8E1D5;
  --ink: #14100F;
  --ink-muted: #4B443D;
  --ink-faint: #635B53;
  --line: rgba(20, 16, 15, 0.16);
  color: var(--ink);
}
.work__head { margin-bottom: var(--s-xl); text-align: center; }
.work__head .eyebrow { color: var(--ember); }
.work__grid {
  display: grid;
  gap: clamp(14px, 1.6vw, 24px);
  grid-template-columns: minmax(0, 1fr);
  align-items: stretch;
}
@media (min-width: 860px) {
  .work__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.wcard {
  position: relative; overflow: clip; isolation: isolate;
  display: flex; flex-direction: column;
  padding: clamp(28px, 2.6vw, 44px);
  background: #F3EFE7;
  border: 1px solid var(--line);
  transition: background-color 420ms var(--ease), border-color 420ms var(--ease),
              box-shadow 420ms var(--ease), transform 420ms var(--ease),
              opacity 420ms var(--ease);
}

/* Drawn after the card has arrived, not with it. */
.wcard__rule {
  position: absolute; top: -1px; left: -1px; right: -1px; height: 2px; z-index: 2;
  background: var(--ember);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 720ms var(--ease);
}
.wcard.is-in .wcard__rule { transform: scaleX(1); transition-delay: 240ms; }

.wcard__num {
  font-family: var(--font); font-weight: 900; font-stretch: 70%;
  font-size: clamp(2.4rem, 3.8vw, 3.4rem); line-height: 0.8; letter-spacing: -0.03em;
  color: rgba(20, 16, 15, 0.16);
  font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1;
  transition: color 420ms var(--ease);
}
.wcard__name { margin-top: var(--s-md); font-size: clamp(1.25rem, 1.9vw, 1.65rem); font-weight: 600; line-height: 1.14; }
.wcard__desc { margin-top: 12px; font-size: var(--t-body); line-height: 1.55; color: var(--ink-muted); }

/* margin-top: auto pins the tags to the foot, so cards of unequal copy still
   line their pills up with one another. */
.wcard__tags {
  margin: auto 0 0; padding: var(--s-md) 0 0; list-style: none;
  display: flex; flex-wrap: wrap; gap: 8px;
}
.wcard__tags li {
  padding: 8px 15px; border-radius: var(--radius-btn);
  border: 1px solid var(--line); background: transparent;
  font-size: var(--t-caption); font-weight: 600; letter-spacing: 0.03em; color: var(--ink);
  transition: background-color 380ms var(--ease), border-color 380ms var(--ease);
}

.wcard::before {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(122% 102% at 0% 0%, rgba(142, 17, 20, 0.10), transparent 62%);
  opacity: 0; transition: opacity 460ms var(--ease);
}
/* Beats .reveal.is-in { transform: none } on specificity, which is the only
   thing standing between the card and its lift. */
.wcard.reveal.is-in:hover {
  transform: translateY(-6px);
  box-shadow: 0 22px 40px rgba(27, 22, 19, 0.17);
  border-color: rgba(142, 17, 20, 0.32);
}
.wcard:hover::before { opacity: 1; }
.wcard:hover .wcard__num { color: var(--ember); }
.wcard:hover .wcard__tags li { background: rgba(255, 255, 255, 0.62); border-color: rgba(20, 16, 15, 0.3); }

@media (prefers-reduced-motion: reduce) {
  .wcard, .wcard.reveal.is-in:hover { transform: none; }
  .wcard__rule { transform: scaleX(1); transition: none; }
}

/* =========================================================================
   10 . THE VOICES . a descending run
   Three endorsements laid out as a run of hops. The curve is an SVG scaled
   with preserveAspectRatio: none, and the dots are HTML placed at the same
   FRACTIONS the curve reaches, so the two stay together at any width without
   anything measuring anything.
   ========================================================================= */
.axis { padding-block: var(--s-xxl); background: var(--bg); overflow: clip; }

.axis__head { display: grid; gap: var(--s-md); margin-bottom: var(--s-xl); }
@media (min-width: 900px) {
  .axis__headline { display: grid; grid-template-columns: minmax(0, 2.33fr) minmax(0, 1fr); gap: clamp(32px, 4.4vw, 64px); align-items: start; }
}
/* ---- three orbs on a thread ----
   In place of a sentence: the same three marks the cascade below uses, drawn
   small and set adrift. Each floats on `translate` so nothing competes with
   the entrance transform, and each is out of phase so the trio never bobs as
   one object. */
.axis__mark { position: relative; height: clamp(120px, 12vw, 160px); }
.axis__thread { position: absolute; inset: 0; width: 100%; height: 100%; }
.axis__thread path {
  fill: none; stroke: var(--line); stroke-width: 1.5;
  stroke-dasharray: 2 7; stroke-linecap: round; vector-effect: non-scaling-stroke;
}
.axis__orb {
  position: absolute; border-radius: 50%;
  animation: pf-orb 7.5s ease-in-out infinite;
}
/* Read off the path itself at t = 0.14 / 0.46 / 0.80. Centred with negative
   margins, not a translate: the float already owns `translate`. */
.axis__orb--a { left: 43.93%; top: 60.13%; width: 13px; height: 13px; margin: -6.5px 0 0 -6.5px; background: var(--ember-lift); animation-delay: 0s; }
.axis__orb--b { left: 80.69%; top: 21.94%; width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px; border: 2px solid var(--accent); animation-delay: -2.5s; }
.axis__orb--c { left: 6.75%;  top: 51.01%; width: 9px;  height: 9px;  margin: -4.5px 0 0 -4.5px; border: 2px solid var(--ink-faint); animation-delay: -5s; }

@media (prefers-reduced-motion: reduce) {
  .axis__orb { animation: none; translate: none; opacity: 1; }
}
.axis__title { font-size: clamp(2rem, 5.4vw, 4.75rem); }

/* the little pill above the heading */


/* ---- narrow: a plain run down the page, no curve to follow ---- */
.axis__stage { display: grid; gap: var(--s-lg); }
.axis__art { display: none; }
.axis__step { position: relative; padding-left: 26px; }
.axis__dot { position: absolute; left: 0; top: 7px; width: 11px; height: 11px; border-radius: 50%; background: var(--ember-lift); }

/* ---- wide: the run ---- */
@media (min-width: 900px) {
  .axis__stage { display: block; position: relative; height: clamp(470px, 37vw, 620px); }
  .axis__art { display: block; position: absolute; inset: 0; width: 100%; height: 100%; }
  .axis__step { position: absolute; width: 30%; padding-left: 0; }
  .axis__dot { left: 0; top: -41px; width: 13px; height: 13px; }
  /* Same fractions as the curve: 2/35.3/68.6 across, 12/30/48 down. */
  .axis__step[data-step="0"] { left: 2%;    top: calc(12% + 34px); }
  .axis__step[data-step="1"] { left: 35.3%; top: calc(30% + 34px); }
  .axis__step[data-step="2"] { left: 68.6%; top: calc(48% + 34px); }
}

.axis__line {
  fill: none; stroke: var(--line); stroke-width: 1.5;
  stroke-dasharray: 2 7; stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.axis__label { display: flex; align-items: baseline; gap: 10px; }
.axis__num { font-family: var(--font); font-size: 1rem; font-weight: 600; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.axis__name { font-size: clamp(1.15rem, 1.7vw, 1.5rem); font-weight: 600; color: var(--ink); }
.axis__cred { margin-top: 6px; font-size: var(--t-caption); letter-spacing: 0.04em; color: var(--accent); }
.axis__quote { margin-top: 14px; font-size: var(--t-body); line-height: 1.6; color: var(--ink-muted); }
.axis__quote::before { content: '\201C'; }
.axis__quote::after  { content: '\201D'; }

.axis__runner { fill: var(--ember-lift); }
@media (prefers-reduced-motion: reduce) {
  .axis__runner { display: none; }
}

/* =========================================================================
   06e . THE RUN . the page moves sideways
   The section is tall; the pin inside it holds one screen still while the
   rail slides across it. The scroll budget is stated in vh and the travel is
   MEASURED, never assumed from vw -- 100vw counts the scrollbar and the
   viewport does not, and four panels of that error leaves the last one short.
   ========================================================================= */
.run { display: block; position: relative; background: var(--bg); height: calc(100svh + 300vh); }
.run__pin {
  position: sticky; top: 0; height: 100svh;
  min-width: 0; max-width: 100%;
  overflow: clip; display: flex; flex-direction: column;
}
/* Not will-change: the rail is four viewports wide, and promoting all of it
   to one layer exceeds texture limits on wide, scaled screens -- the whole
   scene then paints black. Each panel contains its own paint instead. */
.run__rail { display: flex; flex: 1 1 auto; min-height: 0; min-width: 0; }

.slide { flex: 0 0 100vw; display: grid; place-items: center; padding-inline: var(--gutter); contain: layout paint; }
.slide__inner { width: 100%; max-width: var(--container); }
.slide__inner--text { max-width: 48rem; }
.slide__inner--wide { max-width: var(--container); }

@media (min-width: 900px) {
  .slide--open .slide__inner {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 0.62fr);
    gap: clamp(40px, 6vw, 96px); align-items: center;
  }
}

.slide__title {
  margin-top: var(--s-md);
  font-size: clamp(2.6rem, 6.4vw, 5.4rem);
  font-weight: var(--display-weight); font-stretch: var(--display-stretch);
  letter-spacing: var(--display-track); text-transform: uppercase; line-height: 0.94;
}
.slide__sub {
  margin-top: var(--s-md);
  font-size: clamp(1.5rem, 3vw, 2.4rem);
  font-weight: var(--display-weight); font-stretch: var(--display-stretch);
  letter-spacing: var(--display-track); text-transform: uppercase; line-height: 1;
}
.slide__deck { margin-top: var(--s-md); font-size: clamp(1.05rem, 1.6vw, 1.45rem); color: var(--accent); }
.slide__lede { margin-top: 12px; color: var(--ink-muted); max-width: 46ch; }
.slide__body { font-size: var(--t-lead); line-height: 1.55; color: var(--ink-muted); }
.slide__body + .slide__body { margin-top: var(--s-md); }
.slide__body i { font-style: italic; color: var(--ink); }
.slide__for { margin-top: var(--s-md); font-size: var(--t-body); color: var(--ink); max-width: 52ch; }
.slide .tag { margin-bottom: 0; }
.slide .tag + .slide__body { margin-top: var(--s-md); }
.slide .btn-row { margin-top: var(--s-lg); }

.slide__cover img { width: 100%; height: auto; display: block; filter: drop-shadow(0 30px 54px rgba(0, 0, 0, 0.6)); }

.slide__counts { margin-top: var(--s-lg); padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: clamp(24px, 4vw, 64px); }
.slide__counts li { display: flex; flex-direction: column; gap: 4px; }
.slide__counts b { font-weight: 900; font-stretch: 70%; font-size: clamp(2rem, 3.4vw, 3rem); line-height: 0.9; color: var(--ember-lift); font-variant-numeric: tabular-nums; }
.slide__counts span { font-size: 0.625rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-faint); }

.slide__list { margin-top: var(--s-lg); padding: 0; list-style: none; display: grid; gap: 1px; background: var(--line); border-block: 1px solid var(--line); }
.slide__list li {
  background: var(--bg); padding: clamp(16px, 1.5vw, 22px) clamp(10px, 1vw, 18px);
  display: grid; grid-template-columns: 52px 1fr; gap: 14px; align-items: baseline;
  font-size: var(--t-lead); line-height: 1.4; color: var(--ink-muted);
  transition: background-color 360ms var(--ease), color 360ms var(--ease),
              opacity 620ms var(--ease), translate 620ms var(--ease);
}
.slide__mark { font-size: 0.625rem; letter-spacing: 0.16em; color: var(--accent); padding-top: 4px; }
/* ---- the bar along the foot ---- */
.run__bar { position: relative; flex: none; padding: 0 var(--gutter) clamp(18px, 2vh, 30px); }
.run__bar::before { content: ''; position: absolute; left: 0; right: 0; top: 0; height: 1px; background: var(--line); }
.run__fill {
  position: absolute; left: 0; top: 0; height: 1px; background: var(--ember-lift);
  width: calc(var(--p, 0) * 100%);
}
.run__marks { display: flex; justify-content: space-between; gap: 12px; padding-top: clamp(12px, 1.6vh, 20px); }
.run__mark {
  display: flex; align-items: baseline; gap: 8px;
  font-family: var(--font); font-size: 0.5625rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ink-faint); white-space: nowrap;
  transition: color 360ms var(--ease);
}
.run__mark b { font-weight: 600; font-variant-numeric: tabular-nums; }
.run__mark.is-on { color: var(--ink); }
.run__mark.is-on b { color: var(--ember-lift); }
@media (max-width: 700px) { .run__mark span, .run__mark { font-size: 0.5rem; letter-spacing: 0.1em; } }

/* ---- narrow, and anyone who asked for less motion ----
   A sideways rail on a phone means a horizontal drag on a vertical page, so
   below the breakpoint the panels simply stack and read down. */
@media (max-width: 899px) {
  .run { height: auto; }
  .run__pin { position: static; height: auto; overflow: visible; }
  .run__rail { flex-direction: column; transform: none !important; }
  .slide { flex: none; width: 100%; padding-block: var(--s-xl); }
  .run__bar { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .run { height: auto; }
  .run__pin { position: static; height: auto; overflow: visible; }
  .run__rail { flex-direction: column; transform: none !important; }
  .slide { flex: none; width: 100%; padding-block: var(--s-xl); }
  .run__bar { display: none; }
}

/* ---- the margin of the letter ----
   The sheet becomes two columns once there is room: the head runs across the
   top, the letter takes the wide column and the margin the narrow one. The
   photograph is absolute and ends above where the margin starts, so nothing
   has to be pushed out of its way. */
@media (min-width: 900px) {
  .note__sheet {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.42fr);
    column-gap: clamp(40px, 5vw, 84px);
    align-items: start;
  }
  .note__head { grid-column: 1 / -1; }
  .note__body { grid-column: 1; }
  .note__margin { grid-column: 2; margin-top: var(--s-lg); }
}
.note__margin { margin-top: var(--s-xl); }

.note__from {
  font-family: var(--font); font-size: 0.625rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: #635B53;
}
.note__place {
  margin-top: 8px; display: flex; flex-direction: column; gap: 2px;
  font-family: 'Playfair Display', Georgia, serif;
  font-size: clamp(1.15rem, 1.6vw, 1.5rem); line-height: 1.1; color: var(--ink);
}
.note__place span { font-family: var(--font); font-size: var(--t-caption); color: #635B53; }

.note__facts { margin-top: var(--s-lg); padding: 0; list-style: none; }
.note__facts li {
  display: flex; flex-direction: column; gap: 3px;
  padding: 14px 0; border-top: 1px solid var(--line);
}
.note__facts li:last-child { border-bottom: 1px solid var(--line); }
.note__facts b { font-size: var(--t-caption); font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ember); }
.note__facts span { font-size: var(--t-body); color: #3B342E; }

.note__ps { margin-top: var(--s-lg); font-size: var(--t-caption); line-height: 1.6; color: #635B53; }
.note__ps b { font-weight: 600; color: var(--ink); }
.note__ps-link {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 12px;
  padding-bottom: 4px; border-bottom: 1px solid rgba(20, 16, 15, 0.3);
  font-family: var(--font); font-size: 0.6875rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink); text-decoration: none;
  transition: border-color 300ms var(--ease), gap 300ms var(--ease);
}
.note__ps-link:hover { border-color: var(--ink); gap: 13px; }
.note__ps-link:focus-visible { outline: 2px solid var(--ember); outline-offset: 4px; }

/* ---- the seals float ----
   The float rides on `translate`, not on `transform`: transform is already
   carrying the entrance and the hover lift, and a keyframe on it would win
   over both. As separate properties they simply add, so a hovered card is
   lifted AND still breathing.
   The shadow works against the rise -- tight and dark when low, wide and
   faint when high -- which is what reads as height rather than as sliding. */

/* Only once the row has arrived, and out of phase by card index so the five
   never rise together. */
.note.is-open .seal {
  animation: pf-bob 6.5s ease-in-out infinite;
  animation-delay: calc(var(--k, 0) * -1.3s);
}
@media (prefers-reduced-motion: reduce) {
  .note.is-open .seal { animation: none; translate: none; }
}

/* While a number is running it sits a hair higher and brighter, so the count
   reads as an event rather than as text quietly changing. */
.slide__counts b { transition: color 420ms var(--ease), translate 420ms var(--ease); }
.slide__counts b.is-counting { color: var(--accent); translate: 0 -4px; }
@media (prefers-reduced-motion: reduce) {
  .slide__counts b, .slide__counts b.is-counting { translate: none; transition: none; }
}

/* ---- the list arrives a row at a time ----
   Hidden only once the script has taken the rail over (.is-live), so with no
   script the five rows are simply there. The stagger rides on `translate`,
   leaving `transform` free. */
.run.is-live .slide__list li {
  opacity: 0; translate: -20px 0;
  transition-delay: calc(var(--n, 0) * 90ms);
}
.run.is-live [data-slide].is-here .slide__list li { opacity: 1; translate: none; }

.slide__list li:hover { background: var(--surface); color: var(--ink); }
.slide__list li:hover .slide__mark { color: var(--ember-lift); }
.slide__mark { transition: color 360ms var(--ease); }

@media (prefers-reduced-motion: reduce) {
  .run.is-live .slide__list li { opacity: 1; translate: none; transition: none; }
}

/* ---- a ground that changes across a boundary, not at it ----
   Fixed to the viewport and faded by the section it belongs to, so the colour
   is already changing while the edge between the two sections is still on
   screen. Both grounds here are dark, so the ink never has to switch and the
   contrast never dips -- which is the part that usually breaks this effect. */
.release { position: relative; isolation: isolate; }
.ground {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  opacity: 0;
  background:
    radial-gradient(128% 84% at 50% 0%, rgba(142, 17, 20, 0.34) 0%, transparent 64%),
    radial-gradient(90% 60% at 50% 100%, rgba(224, 183, 50, 0.05) 0%, transparent 60%),
    #150C0B;
}

/* =========================================================================
   07d . THE READERS . a held word beside a run of cards
   The left column holds while the cards pass it, which is the whole idea of
   the reference. Light cards on the dark ground carry the same contrast as
   the original did in reverse.
   ========================================================================= */
.readers { padding-block: var(--s-xxl); background: var(--bg); }
.readers__grid { display: grid; gap: var(--s-xl); }
@media (min-width: 900px) {
  .readers__grid { grid-template-columns: minmax(0, 0.86fr) minmax(0, 1fr); gap: clamp(48px, 6vw, 110px); align-items: start; }
  .readers__aside { position: sticky; top: 116px; }
}

.readers__word {
  margin-top: var(--s-md);
  transform-origin: 0 0;
  will-change: transform;
  font-family: 'Playfair Display', Georgia, serif;
  font-size: clamp(3.4rem, 11vw, 9rem); line-height: 0.86;
  letter-spacing: -0.02em; color: var(--ink);
}
.readers__score {
  margin-top: var(--s-xl); padding-top: var(--s-md); border-top: 1px solid var(--line);
  opacity: 1;
}
.readers__stars { font-size: 1.05rem; letter-spacing: 0.18em; color: var(--accent); }
.readers__rate { margin-top: 10px; font-size: var(--t-lead); color: var(--ink); }
.readers__rate b { font-weight: 900; font-stretch: 70%; }
.readers__count { margin-top: 4px; font-size: var(--t-caption); color: var(--ink-muted); }
.readers__link {
  display: inline-flex; align-items: center; gap: 8px; margin-top: var(--s-md);
  padding-bottom: 4px; border-bottom: 1px solid rgba(232, 225, 213, 0.3);
  font-family: var(--font); font-size: 0.6875rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink); text-decoration: none;
  transition: border-color 300ms var(--ease), gap 300ms var(--ease);
}
.readers__link:hover { border-color: var(--ink); gap: 13px; }
.readers__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

.readers__stack { display: grid; gap: clamp(14px, 1.6vw, 22px); }
@media (min-width: 900px) { .readers__stack { padding-top: 58svh; } }
.review {
  position: relative; overflow: clip; isolation: isolate;
  padding: clamp(26px, 2.6vw, 40px);
  background: #E8E1D5; border-radius: 2px;
  --ink: #14100F; --ink-muted: #4B443D; --line: rgba(20, 16, 15, 0.16);
  color: var(--ink);
  transition: transform 460ms var(--ease), box-shadow 460ms var(--ease);
}
.review__top { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
.review__stars { font-size: 0.875rem; letter-spacing: 0.16em; color: var(--ember); }
.review__idx { font-family: var(--font); font-size: 0.625rem; letter-spacing: 0.16em; color: #7B7168; }
.review__title {
  margin-top: var(--s-sm); font-size: clamp(1.1rem, 1.6vw, 1.4rem);
  font-weight: 600; line-height: 1.2; color: var(--ink);
}
.review__body { margin-top: 12px; font-size: var(--t-body); line-height: 1.6; color: #3B342E; }
.review__who { margin-top: var(--s-md); padding-top: var(--s-sm); border-top: 1px solid var(--line); }
.review__name { font-size: var(--t-body); font-weight: 600; color: var(--ink); }
.review__meta { margin-top: 3px; font-size: var(--t-caption); color: #635B53; }

.review:hover { transform: translateY(-4px); box-shadow: 0 22px 40px rgba(0, 0, 0, 0.42); }
@media (prefers-reduced-motion: reduce) { .review, .review:hover { transform: none; } }

/* ---- which book these are for ----
   The section follows a long run about the other book, so the cover and the
   title say which one without the reader having to work it out. */
.readers__book { display: flex; align-items: center; gap: var(--s-sm); margin-bottom: var(--s-md); }
.readers__book img { width: clamp(52px, 6vw, 74px); height: auto; display: block; flex: none; filter: drop-shadow(0 10px 18px rgba(0, 0, 0, 0.45)); }
.readers__book figcaption { display: flex; flex-direction: column; gap: 2px; font-size: var(--t-caption); color: var(--ink-muted); }
.readers__book b { font-size: var(--t-body); font-weight: 600; color: var(--ink); }

/* ODOMETER . copied from home.css -- the figures counters need it v9.57.3 */
.odm { display: inline-flex; align-items: baseline; }
.odm__w { display: inline-block; overflow: clip; height: 1em; line-height: 1; }
.odm__r { display: block; transform: translateY(0); transition: transform 1600ms cubic-bezier(0.16, 1, 0.3, 1); transition-delay: var(--odd, 0ms); }
.odm__r i { display: block; font-style: normal; height: 1em; line-height: 1; font-variant-numeric: tabular-nums; }
.is-odm .odm__r { transform: var(--odt, none); }

/* pf-slides-clip: cada .slide tem 100vw; sem clip no trilho o documento
   inteiro herda a largura somada e ganha scroll lateral. */
.shelf, .glance, .glance__grid { overflow-x: clip; }
/* O trilho horizontal: cada .slide tem 100vw e o flex nao estica o pai,
   entao o excesso escorria para o documento. A secao clipa o trilho. */
/* The pin clips; the rail must not. The rail is one viewport wide and its
   four panels live outside that box, so clipping the rail erased every
   panel after the first the moment the rail moved. */
.run, .run__pin { overflow-x: clip; }
.glance__grid { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1000px) {
  .glance__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* tome-mobile-facts: the .tome.is-live reveal rules live further down this
   file than the phone block above, so the override has to stand after them
   to win the tie. Without it two of the six lines stayed at opacity 0 with
   the scene switched off, and nothing was ever going to turn them on. */
@media (max-width: 899px) {
  .tome.is-live .tome__fact,
  .tome.is-live .tome__facts--r .tome__fact {
    opacity: 1; transform: none; transition: none;
  }
}

/* reel-mobile-run: 840svh of scroll is eight and a half screens of thumb on
   a phone, and the phone reel runs half the frames, so the run is shortened
   to match. 64 frames over ~4000px is one frame every 63px, which is the
   same cadence the desktop run has at 128 over 7560. */
@media (max-width: 999px) {
  .reel { min-height: 480svh; }
}


/* The reel now opens the page (client review 2026-09-10, note 1). When the
   hero's sticky panel goes static on phones and reduced motion, the hero
   itself must stay the containing block for its absolute stage, or the
   stage anchors to the page top and paints over the reel. v12.7.3 */
@media (max-width: 899px), (max-height: 560px), (prefers-reduced-motion: reduce) {
  .hero { position: relative; overflow: clip; }
  .hero__sticky { position: relative; }
}


/* The planner's flat cover (note 3, 2026-09-11): a hair narrower than the
   book renders, a hairline edge, and the linkless door has no hover. */
/* Planner mockup (note 19, 2026-09-16): the render carries its own light
   ground and shadow, so the panel takes that ground and the picture fades
   into it at the edges instead of sitting in a rectangle. */
.shelf__panel[data-panel="2"] .shelf__cover { width: min(78vw, 440px); filter: none; -webkit-mask-image: radial-gradient(ellipse 62% 58% at 50% 50%, #000 58%, transparent 100%); mask-image: radial-gradient(ellipse 62% 58% at 50% 50%, #000 58%, transparent 100%); }
.shelf__cta--soon { cursor: default; }
.shelf__cta--soon:hover { border-color: var(--on-rule); gap: 10px; }

/* v12.12.2: on phones the rail is a plain column and no slide is ever
   marked is-here, so the "Inside, you'll find" rows stayed at opacity 0. */
@media (max-width: 899px) {
  .run.is-live .slide__list li { opacity: 1; translate: none; transition: none; }
}
