/* ============================================================
   synqa.ca - pass 3 styles
   Chapters 3, 4, 5, 7, 8, 9 + their transitions.
   Pass-1 site.css holds the persistent shell and Ch 1+2.
   Pass-2 (also site.css) holds Ch 6.
   This file ships the rest of the homepage.
   ============================================================ */

/* ----------------------------------------------------------------
   Chapter transitions - shared
   ----------------------------------------------------------------*/

/* M22 hairline weave + M07 wipe are staged together as 100vh
   transition sections. The wipe panel is absolutely positioned
   inside .chapter-wipe and its translateY is driven from site.js.

   The three weave hairlines (one horizontal from left, one diagonal
   from upper-left, one vertical from bottom) draw via stroke-dasharray
   reveal as the visitor enters the transition zone. They converge on
   a Clay period at the center of the viewport.
*/
.chapter-wipe {
  position: relative;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: transparent;
}
/* M07 wipe between Ch 4 and Ch 5 runs over a tighter 50vh runway to
   pair with the M18 50vh hold inside Ch 4.  The wipe-fill animation
   in pass3.js reads data-wipe-runway-vh and adjusts its p-range so
   the fill translates 100% to 0% across exactly 50vh of native scroll. */
#ch-04half-transition.chapter-wipe { height: 75vh; height: 75svh; }

.chapter-wipe-weave {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100vh;
  height: 100svh;
  z-index: 2;
  pointer-events: none;
  display: block;
}
.chapter-wipe-weave line {
  fill: none;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.chapter-wipe-weave .weave-h { stroke: var(--bone-400); }
.chapter-wipe-weave .weave-d { stroke: var(--bone-400); }
.chapter-wipe-weave .weave-v { stroke: var(--bone-400); }
.chapter-wipe[data-from="ink"] .weave-h,
.chapter-wipe[data-from="ink"] .weave-d,
.chapter-wipe[data-from="ink"] .weave-v { stroke: var(--border-on-ink); }
.chapter-wipe-weave .weave-period {
  font-family: var(--font-display);
  font-size: 64px;
  fill: var(--clay);
  dominant-baseline: middle;
  text-anchor: middle;
  opacity: 0;
}

/* The full-bleed wipe panel. Lives behind the weave; translateY is
   driven 1:1 from the transition's scroll progress. The 1px edge
   hairline sits flush along the top edge of the wipe. */
.chapter-wipe-fill {
  position: absolute;
  inset: 0;
  transform: translateY(100%);
  will-change: transform;
  pointer-events: none;
}
.chapter-wipe[data-from="bone"] .chapter-wipe-fill { background: var(--ink); }
.chapter-wipe[data-from="ink"] .chapter-wipe-fill { background: var(--bone); }
.chapter-wipe-fill::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
}
.chapter-wipe[data-from="bone"] .chapter-wipe-fill::before { background: var(--bone-400); }
.chapter-wipe[data-from="ink"]  .chapter-wipe-fill::before { background: var(--border-on-ink); }

/* ----------------------------------------------------------------
   Chapter 03 · The chair
   Bone surface. Headline + three redacted lines + italic close.
   ----------------------------------------------------------------*/

.ch-03 {
  position: relative;
  min-height: 130svh;
  padding: 26vh 0 22vh;
}
.ch-03-inner {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 80px;
  display: flex;
  flex-direction: column;
  gap: 64px;
}
.ch-03-stamp {
  font-family: var(--font-mono);
  font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp);
  text-transform: uppercase;
  color: var(--stone);
}
.ch-03-stamp .period { color: var(--clay); margin: 0 6px; }

.ch-03-head {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(40px, 5.4vw, 84px);
  line-height: 1.04;
  letter-spacing: -0.018em;
  margin: 0;
  color: var(--ink);
  text-wrap: balance;
  max-width: 22ch;
  position: relative;
}
.ch-03-head em { font-style: italic; color: var(--harbor); font-weight: 400; }
.ch-03-head .period { color: var(--clay); }

/* M03 carbon copy on the Ch 3 headline.  Position-locked behind the
   primary; offset reacts to scroll velocity through the global lerp. */
.ch-03-head .carbon {
  position: absolute;
  inset: 0;
  color: rgba(168, 156, 138, 0.42);
  pointer-events: none;
  z-index: -1;
  transform: translate(2px, 2px);
  will-change: transform;
}
.ch-03-head .carbon em { color: rgba(31, 77, 74, 0.32); }
.ch-03-head .carbon .period { color: rgba(181, 87, 58, 0.32); }

/* The redacted line list.  Each row is two elements stacked at the
   same coordinates: the underlying text and the Ink-900 bar painted
   over it.  Cursor proximity within 40px (or click on touch) lifts
   the bar right-to-left. */
.ch-03-lines {
  display: flex;
  flex-direction: column;
  gap: 22px;
  max-width: 920px;
}
.ch-03-line {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 18px;
  padding: 4px 0;
  cursor: default;
}
.ch-03-line .lead {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: 32px;
  color: var(--clay);
  line-height: 1;
  flex: 0 0 auto;
  transform: translateY(-2px);
}
.ch-03-line-body {
  position: relative;
  flex: 1 1 auto;
}
.ch-03-line-text {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(22px, 2.6vw, 34px);
  line-height: 1.2;
  color: var(--ink);
  display: inline-block;
  margin: 0;
}
.ch-03-line-text em { font-style: italic; color: var(--harbor); font-weight: 400; }
/* Reserve baseline space for the bar so the row doesn't reflow when
   it lifts.  The bar paints over the text at the exact same baseline. */
.ch-03-line-bar {
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 100%;
  background: var(--ink-900);
  border-radius: 1px;
  /* Redacted from the first paint: the bar fully covers its text
     (inset 0 on all sides) so the line is never momentarily exposed,
     even before the script runs or on a fast scroll into the chapter.
     When the visitor "lifts" the bar, the inset sweeps to
     inset(0 100% 0 0) from the right edge, revealing the text
     right-to-left.  (The draw-in entrance was removed by request -
     the redaction now reads as covered-by-default.) */
  clip-path: inset(0 0 0 0);
  will-change: clip-path;
  pointer-events: none;
}
.ch-03-line[data-state="drawn"]   .ch-03-line-bar { clip-path: inset(0 0    0 0); }
.ch-03-line[data-state="lifted"]  .ch-03-line-bar { clip-path: inset(0 100% 0 0); }

/* Cursor hint above each line; fades out after the first lift. */
.ch-03-line-hint {
  position: absolute;
  top: -16px; left: 0;
  font-family: var(--font-mono); font-size: 9px;
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
  opacity: 0;
  pointer-events: none;
  transition: opacity 240ms var(--ease-standard);
}
.ch-03-line[data-state="drawn"] .ch-03-line-hint { opacity: 1; }
.ch-03-line[data-state="lifted"] .ch-03-line-hint { opacity: 0; }
.ch-03-line-hint .dot { color: var(--clay); margin-right: 6px; }

/* M21 italic swap-in closing phrase.
   Initial state: Inter, Stone.  After 200ms onscreen, swap to
   Fraunces italic Harbor.  site.js applies the swap by toggling
   data-swapped on the element. */
.ch-03-close {
  margin-top: 12px;
  font-family: var(--font-body);
  font-size: clamp(24px, 2.6vw, 32px);
  color: var(--stone);
  letter-spacing: 0;
  display: inline-block;
}
.ch-03-close[data-swapped="true"] {
  font-family: var(--font-display);
  font-style: italic;
  color: var(--harbor);
}
.ch-03-close .period { color: var(--clay); }

/* ----------------------------------------------------------------
   Chapter 04 · The turn (M18 split scroll)
   290vh chapter, sticky 100vh inner pin.  Two phases, both inside
   the fixed pinned shell - the half containers never translate.
     Phase A (prog 0 to 0.50): content motion inside the halves
       - left half (Bone)   operator-history words rise from below
                            into the centered stack (reads UP)
       - right half (Ink)   "We've been the client." word-spans
                            descend from above into the centered
                            headline (reads DOWN - opposite)
     Phase B (prog 0.50 to 0.80): the unified Ink panel (inset:0,
       full-bleed over both halves) fades in on easeOutQuint and
       resolves the composition with the headline and body.
     prog 0.80 to 1.0 holds the unified panel at full opacity inside
       the phase runway; then the pin holds for a further 90vh of
       native scroll before the M07 wipe to Ch 5 begins.
   ----------------------------------------------------------------*/

.ch-04 {
  position: relative;
  /* Of the pin runway, 100vh drives the M18 phases (prog 0 to 1):
       Phase A (0.00 to 0.30) content motion inside the halves
       Phase B (0.30 to 0.92) the two halves slide vertically
         off-screen, LINEAR - tied 1:1 to the wheel so the parting
         feels physical and takes ~6 wheel clicks rather than a
         front-loaded shoot-then-crawl.  Reveals the unified Ink
         panel underneath as they go.
       Phase C (0.92 to 1.0) held inside the phase runway
     and the trailing 30vh holds the pinned unified Ink composition
     just long enough to read before the M07 wipe begins.
     Keep in sync with pass3.js: CH04_PHASE_RUNWAY_VH (100)
     + CH04_HOLD_VH (30) + 100 (sticky pin) = 230. */
  height: 230svh;
  background: var(--ink); /* the chapter resolves on Ink - chamber matches */
}
.ch-04-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  background: var(--ink);
}

/* Two half-viewport columns, absolutely positioned.  Each half is a
   CARD that slides vertically in Phase B: the left half (bone) rises
   straight up off the top of the viewport, the right half (ink)
   descends off the bottom, revealing the unified Ink composition
   sitting beneath them (.ch-04-unified at z-index 1).  Each half is
   strictly clipped to its own 50vw column - overflow: hidden plus
   exact left/right anchoring guarantees the right half can never
   bleed into the left.  z-index 2 keeps them above the unified panel
   until they slide off. */
.ch-04-half {
  position: absolute;
  top: 0; bottom: 0;
  /* No width.  Each half anchors BOTH horizontal edges to the 50%
     center line of the pin (left: 0 / right: 50% and left: 50% /
     right: 0).  width: 50vw was the trap behind the visible overlap
     seam: vw units include the scrollbar gutter, but right: 0 resolves
     against the scrollbar-excluded content box, so the right half
     landed ~scrollbar-width pixels left of where the left half ended
     and the Ink bled over the Bone.  Anchoring both halves to the
     shared 50% boundary tiles them exactly, scrollbar or not. */
  overflow: hidden;
  z-index: 2;
  will-change: transform;
}
.ch-04-half-left {
  left: 0;
  right: 50%;
  background: var(--bone);
  color: var(--ink);
}
.ch-04-half-right {
  left: 50%;
  right: 0;
  background: var(--ink);
  color: var(--bone);
}

/* Left column - vertical stack of words, each rising from the bottom
   as scroll progresses.  Stack lives at the half-column's center;
   each .ch-04-word translates from below upward into its slot. */
.ch-04-words {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  padding: 0 6vw;
}
.ch-04-word {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(20px, 2.6vw, 40px);
  line-height: 1;
  color: var(--ink);
  letter-spacing: -0.015em;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(48px);
  will-change: opacity, transform;
}
.ch-04-word.is-in { opacity: 1; transform: translateY(0); }
.ch-04-word .period { color: var(--clay); }
.ch-04-half-left-stamp {
  position: absolute;
  top: 96px; left: 6vw; right: 6vw;
  font-family: var(--font-mono);
  font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp);
  text-transform: uppercase;
  color: var(--stone);
}
.ch-04-half-left-stamp .period { color: var(--clay); }

/* Right column - Ink.  "We've been the client." stack, with each
   word descending in from above as scroll progresses.  Stack lives
   at the right half's center. */
.ch-04-right-head {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 6vw;
}
.ch-04-right-head-line {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(40px, 5.8vw, 96px);
  line-height: 1.02;
  letter-spacing: -0.02em;
  color: var(--bone);
  display: flex;
  gap: 0.22em;
  flex-wrap: wrap;
  justify-content: center;
}
.ch-04-right-head-line em { font-style: italic; color: var(--fg-cool-on-ink); font-weight: 400; }
.ch-04-right-head-line .period { color: var(--clay); }
.ch-04-right-word {
  display: inline-block;
  opacity: 0;
  transform: translateY(-72px);
  will-change: opacity, transform;
}
.ch-04-right-word.is-in { opacity: 1; transform: translateY(0); }

.ch-04-half-right-stamp {
  position: absolute;
  bottom: 96px; left: 0; right: 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp);
  text-transform: uppercase;
  color: var(--fg-quiet-on-ink);
}
.ch-04-half-right-stamp .period { color: var(--clay); }

/* Unified body - sits BENEATH the two halves at z-index 1, full-bleed
   on Ink.  Fully painted from the start of the chapter; the halves
   cover it (z-index 2) until Phase B slides them off the top and
   bottom of the viewport, progressively revealing the unified
   composition.  No opacity tween - the reveal is the halves moving. */
.ch-04-unified {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 36px;
  padding: 0 6vw;
  text-align: center;
  pointer-events: none;
  opacity: 1;
  z-index: 1;
  background: var(--ink);
  color: var(--bone);
}
.ch-04-unified-head {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(40px, 5.8vw, 96px);
  line-height: 1.02;
  letter-spacing: -0.02em;
  color: var(--bone);
  margin: 0;
  max-width: 18ch;
}
.ch-04-unified-head em { font-style: italic; color: var(--fg-cool-on-ink); font-weight: 400; }
.ch-04-unified-head .period { color: var(--clay); }
.ch-04-unified-body {
  max-width: 56ch;
  font-family: var(--font-body);
  font-size: 17px; line-height: 1.6;
  color: var(--fg-quiet-on-ink);
  margin: 0;
}
.ch-04-unified-body em {
  font-family: var(--font-display); font-style: italic;
  color: var(--fg-cool-on-ink); font-weight: 400;
}
.ch-04-unified-stamp {
  font-family: var(--font-mono);
  font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp);
  text-transform: uppercase;
  color: var(--stone);
}
.ch-04-unified-stamp .period { color: var(--clay); }

/* Pagination - three thin marks bottom-center showing phase. */
.ch-04-phase {
  position: absolute;
  bottom: 32px; left: 0; right: 0;
  display: flex; justify-content: center; gap: 10px;
  z-index: 4;
  pointer-events: none;
}
.ch-04-phase i {
  display: block; width: 24px; height: 1px;
  background: rgba(199, 190, 169, 0.4);
  transition: background 200ms var(--ease-standard);
}
.ch-04-phase i.is-active { background: var(--clay); }

/* ----------------------------------------------------------------
   Chapter 05 · What we build (services)
   Bone surface.  400vh runway, sticky 100vh pinned shell, horizontal
   track scrubbing through six tiles.  Section header peels in over
   the first ~18% of the runway (M16); tile borders draw in via
   stroke-dasharray (M06) as each tile centers; tile content drops in
   via M02 once the border completes.
   ----------------------------------------------------------------*/

.ch-05 {
  position: relative;
  height: 400svh;
  background: var(--bone);
}
.ch-05-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  background: var(--bone);
  /* Column flex: the header takes its natural height at the top (the
     browser reserves it exactly - no magic-number guess against the
     width-driven peel font), and the tile track fills the rest.  This is
     what keeps the header clear of the tiles at every width/height/zoom. */
  display: flex;
  flex-direction: column;
}

.ch-05-header {
  position: relative;
  flex: 0 0 auto;            /* natural height, reserved at the top */
  padding-top: clamp(64px, 11vh, 120px);
  left: 0; right: 0;
  display: flex; flex-direction: column; gap: 14px;
  align-items: center;
  z-index: 4;
  pointer-events: none;
  will-change: transform, opacity;
}
.ch-05-header .mono {
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
}
.ch-05-header .mono .period { color: var(--clay); margin: 0 4px; }
.ch-05-peel {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(36px, 4.5vw, 64px);
  line-height: 1.05; letter-spacing: -0.015em;
  margin: 0; color: var(--ink);
  text-align: center;
  white-space: nowrap;
}
.ch-05-peel em { font-style: italic; color: var(--harbor); font-weight: 400; }
.ch-05-peel .peel-char {
  display: inline-block;
  clip-path: inset(0 100% 0 0);
  /* Vertical padding (neutralised by equal negative margin) extends each
     char's clip box past its ascenders/descenders so the peel only ever
     clips horizontally - the bottom inset was shearing the "y" tail. */
  padding: 0.3em 0;
  margin: -0.3em 0;
  will-change: clip-path;
}
.ch-05-peel .peel-char.space { width: 0.32em; }
.ch-05-peel .peel-char.is-period { color: var(--clay); }

/* Horizontal track - 6 tile panels.  The track is the remaining column
   space below the reserved header; tiles are vertically centered within
   it and height-capped to fit (see .ch-05-tile), so they can never grow
   up into the header band at any viewport size or zoom.  The horizontal
   scrub (inline translateX from site.js) is unaffected by the switch
   from absolute to in-flow. */
.ch-05-track {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  padding: clamp(16px, 3vh, 40px) 20vw clamp(40px, 7vh, 72px);
  gap: 40px;
  will-change: transform;
}
.ch-05-tile {
  flex: 0 0 62vw;
  height: 78vh;
  min-height: 420px;
  /* Cap to the design size OR the track's height, whichever is smaller -
     so a short/zoomed viewport shrinks the tile to fit rather than
     pushing its top into the header. */
  max-height: min(760px, 100%);
  position: relative;
  /* Raised tonal Bone panel: a faint Ink tint above the page Bone so the
     card reads as editorial structure, not a heavy box. Stays inside the
     five-colour palette (Bone stepped toward Ink). */
  background: color-mix(in oklch, var(--bone), var(--ink) 4%);
  display: flex;
  align-items: stretch;
  justify-content: stretch;
}
/* Hairline L-shaped corner ticks - four small marks, one per corner,
   drawn with a pair of crossed gradients masked to a short arm length.
   Hairline weight (Bone-400), no box, no shadow. */
.ch-05-tile::before,
.ch-05-tile::after {
  content: "";
  position: absolute;
  width: 22px;
  height: 22px;
  pointer-events: none;
  z-index: 3;
}
.ch-05-tile::before {
  top: 14px; left: 14px;
  border-top: 1px solid var(--bone-400);
  border-left: 1px solid var(--bone-400);
}
.ch-05-tile::after {
  bottom: 14px; right: 14px;
  border-bottom: 1px solid var(--bone-400);
  border-right: 1px solid var(--bone-400);
}
.ch-05-tile-inner::before,
.ch-05-tile-inner::after {
  content: "";
  position: absolute;
  width: 22px;
  height: 22px;
  pointer-events: none;
  z-index: 3;
}
/* Offsets cancel the inner padding so these two marks land on the tile's
   top-right and bottom-left corners, mirroring the tile's own ticks. */
.ch-05-tile-inner::before {
  top: calc(-1 * clamp(24px, 4vh, 56px) + 14px);
  right: calc(-1 * clamp(24px, 4vh, 56px) + 14px);
  border-top: 1px solid var(--bone-400);
  border-right: 1px solid var(--bone-400);
}
.ch-05-tile-inner::after {
  bottom: calc(-1 * clamp(24px, 4vh, 56px) + 14px);
  left: calc(-1 * clamp(24px, 4vh, 56px) + 14px);
  border-bottom: 1px solid var(--bone-400);
  border-left: 1px solid var(--bone-400);
}
/* All tiles share the same height and are vertically centered in the
   track via align-items: center. */

/* SVG border on each tile - drawn via stroke-dasharray when the tile
   reaches the viewport's vertical centerline. */
.ch-05-tile-border {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.ch-05-tile-border rect {
  fill: none;
  stroke: var(--bone-400);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  /* stroke-dasharray is set inline by site.js - = perimeter. */
}

.ch-05-tile-inner {
  position: relative;
  padding: clamp(24px, 4vh, 56px);
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: auto 1fr auto;
  gap: 32px;
  width: 100%;
  z-index: 2;
}
.ch-05-tile-num {
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
  opacity: 0;
  transform: translateY(8px);
  will-change: opacity, transform;
}
/* The index figure is the card's structural anchor - rendered in Harbor
   so the eye lands on the count first. The trailing brand period stays
   Clay; Harbor and Clay never sit at equal weight here (the figure leads,
   the period is a single mark). */
.ch-05-tile-num .num { color: var(--harbor); }
.ch-05-tile-num .period { color: var(--clay); }
.ch-05-tile-head {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(34px, 3.2vw, 48px);
  line-height: 1.06;
  letter-spacing: -0.012em;
  color: var(--ink);
  margin: 0;
  max-width: 18ch;
  opacity: 0;
  transform: translateY(20px);
  will-change: opacity, transform;
}
.ch-05-tile-head em { font-style: italic; color: var(--harbor); font-weight: 400; }
.ch-05-tile-head .period { color: var(--clay); }
.ch-05-tile-body {
  font-family: var(--font-body); font-size: 16px; line-height: 1.55;
  color: var(--ink);
  margin: 0;
  max-width: 48ch;
  opacity: 0;
  transform: translateY(12px);
  will-change: opacity, transform;
}
.ch-05-tile-foot {
  display: flex; align-items: baseline; gap: 12px;
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
  opacity: 0;
  transform: translateY(8px);
  will-change: opacity, transform;
}
.ch-05-tile-foot .period { color: var(--clay); }
.ch-05-tile[data-revealed="true"] .ch-05-tile-num,
.ch-05-tile[data-revealed="true"] .ch-05-tile-head,
.ch-05-tile[data-revealed="true"] .ch-05-tile-body,
.ch-05-tile[data-revealed="true"] .ch-05-tile-foot {
  opacity: 1; transform: translateY(0);
  /* Faster reveal so each tile is legible noticeably sooner as it scrolls
     in (was 480ms / 80-240ms stagger - read too slowly while scrolling). */
  transition: opacity 300ms var(--ease-standard), transform 300ms var(--ease-standard);
}
.ch-05-tile[data-revealed="true"] .ch-05-tile-head { transition-delay: 45ms; }
.ch-05-tile[data-revealed="true"] .ch-05-tile-body { transition-delay: 90ms; }
.ch-05-tile[data-revealed="true"] .ch-05-tile-foot { transition-delay: 135ms; }

.ch-05-paging {
  position: absolute;
  bottom: 40px; left: 0; right: 0;
  z-index: 5;
  display: flex; justify-content: center; gap: 10px;
  pointer-events: none;
}
.ch-05-paging i {
  display: block;
  width: 18px; height: 1px;
  background: var(--bone-400);
  transition: background 200ms var(--ease-standard);
}
.ch-05-paging i.is-active { background: var(--clay); }

/* ----------------------------------------------------------------
   Chapter 07 · Theta.  Bone surface, restrained.
   Headline left, mocked WhatsApp-style card right (slides in via M09).
   ----------------------------------------------------------------*/

.ch-07 {
  position: relative;
  background: var(--bone);
  padding: 22vh 0 22vh;
  min-height: 100vh;
  overflow: hidden;
}
.ch-07-inner {
  max-width: 1240px;
  margin: 0 auto;
  padding: 0 80px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 64px;
  align-items: center;
}
.ch-07-meta {
  display: flex; flex-direction: column; gap: 28px;
}
.ch-07-stamp {
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
  display: inline-flex; align-items: baseline; gap: 10px;
}
.ch-07-stamp .label { color: var(--ink); }
.ch-07-stamp .period { color: var(--clay); }
.ch-07-stamp .product { color: var(--ink); font-weight: 500; }
.ch-07-stamp .status { color: var(--clay); }

/* Product wordmark - the hero that names Theta unmistakably.  Standalone
   mark, so the Clay period stays. */
.ch-07-wordmark {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(64px, 8vw, 124px);
  line-height: 0.95; letter-spacing: -0.03em;
  color: var(--ink); margin: 0;
}
.ch-07-wordmark .period { color: var(--clay); }

.ch-07-head {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(48px, 6vw, 96px);
  line-height: 1.02; letter-spacing: -0.02em;
  color: var(--ink); margin: 0;
  position: relative;
  max-width: none;
}
.ch-07-head em { font-style: italic; color: var(--harbor); font-weight: 400; }
.ch-07-head .period { color: var(--clay); }
.ch-07-head .carbon {
  position: absolute; inset: 0;
  color: rgba(168, 156, 138, 0.42);
  z-index: -1;
  transform: translate(2px, 2px);
  pointer-events: none;
  will-change: transform;
}
.ch-07-head .carbon em { color: rgba(31, 77, 74, 0.32); }
.ch-07-head .carbon .period { color: rgba(181, 87, 58, 0.32); }

.ch-07-body {
  font-family: var(--font-body); font-size: 17px; line-height: 1.6;
  color: var(--ink);
  display: flex; flex-direction: column; gap: 14px;
  max-width: 46ch;
}
.ch-07-body p { margin: 0; }
.ch-07-body em {
  font-family: var(--font-display); font-style: italic;
  color: var(--harbor); font-weight: 400;
}

.ch-07-channels {
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
}
.ch-07-channels .period { color: var(--clay); margin: 0 6px; }

.ch-07-cta {
  display: inline-flex; align-self: flex-start;
  align-items: center; gap: 1px;
  background: var(--clay); color: var(--bone);
  font-family: var(--font-body); font-weight: 500; font-size: 15px;
  padding: 14px 24px; border-radius: var(--radius-md);
  border: none; cursor: pointer;
  text-decoration: none;
  border-bottom: none;
  transition: background 40ms var(--ease-standard);
  will-change: transform;
  margin-top: 8px;
}
.ch-07-cta:hover { background: var(--clay-hover); color: var(--bone); }
.ch-07-cta .period { color: var(--bone); }

/* Theta chat-card mock - Bone-100 surface, hairline border, two
   message bubbles.  Slides in from the right via M09. */
.ch-07-card {
  position: relative;
  background: var(--bone-100);
  border: 1px solid var(--bone-400);
  border-radius: var(--radius-lg);
  padding: 28px;
  display: flex; flex-direction: column; gap: 16px;
  transform: translateX(80vw);
  opacity: 0;
  will-change: transform, opacity;
  box-shadow: var(--shadow-sm);
}
.ch-07-card[data-in="true"] {
  transform: translateX(0);
  opacity: 1;
}
/* On product sub-pages the card is in the viewport from frame 0
   (no scroll needed to reveal it), so start at the resolved state.
   M09 tween becomes a no-op, which is correct: the card simply
   appears rather than sliding in from offscreen. */
[data-subpage] .ch-07-card {
  transform: none;
  opacity: 1;
}
.ch-07-card-head {
  display: flex; align-items: center; justify-content: space-between;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--bone-400);
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
}
.ch-07-card-head .channel { color: var(--ink); font-weight: 500; }
.ch-07-card-head .period { color: var(--clay); }
.ch-07-card-head .meta { color: var(--stone); }
.ch-07-bubbles {
  display: flex; flex-direction: column; gap: 12px;
}
.ch-07-bubble {
  font-family: var(--font-body); font-size: 15px; line-height: 1.5;
  padding: 12px 16px;
  border-radius: 14px;
  max-width: 78%;
  position: relative;
}
.ch-07-bubble[data-from="customer"] {
  align-self: flex-start;
  background: var(--bone);
  border: 1px solid var(--bone-400);
  color: var(--ink);
  border-top-left-radius: 4px;
}
.ch-07-bubble[data-from="theta"] {
  align-self: flex-end;
  background: var(--ink);
  color: var(--bone);
  border-top-right-radius: 4px;
  padding-right: 22px;
}
.ch-07-bubble[data-from="theta"]::after {
  content: ".";
  position: absolute;
  top: 6px; right: 8px;
  font-family: var(--font-display);
  color: var(--clay);
  font-size: 22px; line-height: 0;
}
.ch-07-card-foot {
  display: flex; align-items: baseline; justify-content: space-between;
  padding-top: 14px;
  border-top: 1px solid var(--bone-400);
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
}
.ch-07-card-foot .by { color: var(--ink); }
.ch-07-card-foot .period { color: var(--clay); }
.ch-07-card-foot .rt { color: var(--ink); font-variant-numeric: tabular-nums; }

/* ----------------------------------------------------------------
   Chapter 08 · Two continents - Ink surface.
   Arc from Toronto (Clay) to Cape Town (Harbor) on a flat 2D
   equirectangular projection.  Bone-300 dot grid runs reverse-
   parallax behind.  Two columns of body beneath the arc.
   ----------------------------------------------------------------*/

.ch-08 {
  position: relative;
  background: var(--ink);
  color: var(--bone);
  padding: 22vh 0 16vh;
  overflow: hidden;
  min-height: 130svh;
}
/* Dot-grid background - radial-gradient repeat.  M17 reverse-
   parallax driven from site.js sets background-position-y. */
.ch-08-grid {
  position: absolute; inset: -20vh 0 -20vh 0;
  background-image: radial-gradient(circle at 1px 1px, rgba(213, 200, 168, 0.18) 1px, transparent 1px);
  background-size: 36px 36px;
  will-change: transform;
  pointer-events: none;
}
.ch-08-inner {
  position: relative;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 80px;
  display: flex; flex-direction: column; gap: 80px;
  z-index: 2;
}
.ch-08-stamp {
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
}
.ch-08-stamp .period { color: var(--clay); margin: 0 6px; }

.ch-08-head {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(44px, 5.8vw, 92px);
  line-height: 1.02; letter-spacing: -0.02em;
  color: var(--bone); margin: 0;
  text-wrap: balance;
  max-width: 22ch;
}
.ch-08-head em { font-style: italic; color: var(--fg-cool-on-ink); font-weight: 400; }
.ch-08-head .period { color: var(--clay); }

/* Arc panel - SVG containing the dot for each city, the connecting
   arc with a Clay-Stone-Harbor gradient stroke, and the coord
   labels.  Width = full inner width. */
.ch-08-arc-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 1280 / 460;
}
.ch-08-arc-svg {
  width: 100%; height: 100%;
  display: block;
}
.ch-08-arc-svg .arc-line {
  fill: none;
  stroke: url(#archGrad);
  stroke-width: 1.4;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.ch-08-arc-svg .arc-bg-line {
  fill: none;
  stroke: rgba(199, 190, 169, 0.12);
  stroke-width: 0.5;
  stroke-dasharray: 2 5;
  vector-effect: non-scaling-stroke;
}
/* World coastlines under the arc (Natural Earth 110m, same viewBox).
   Faint hairline outline so it reads as a map without competing with
   the arc.  Token colour + stroke-opacity (no alpha hex). */
.ch-08-arc-svg .ch-08-map path {
  fill: none;
  stroke: var(--stone);
  stroke-opacity: 0.3;
  stroke-width: 0.8;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.ch-08-arc-svg .arc-dot { stroke-width: 0; }
.ch-08-arc-svg .arc-dot.toronto { fill: var(--clay); }
.ch-08-arc-svg .arc-dot.capetown { fill: var(--fg-cool-on-ink); }

/* Fixed-size city dots - rendered as HTML elements over the SVG so
   the circles stay 12×12px regardless of viewport width.  Positions
   are the SVG coords (358,119) and (706,317) converted to % of the
   1280×460 viewBox.  Same source of truth as the SVG so they read
   identically; the SVG circles below sit at z-index 1, the HTML
   dots at z-index 3 with the SVG dots hidden. */
.ch-08-arc-svg .arc-dot { display: none; }

.ch-08-city-dot {
  position: absolute;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  z-index: 3;
  pointer-events: none;
}
.ch-08-city-dot.toronto  { left: 27.969%; top: 25.870%; background: var(--clay); }
.ch-08-city-dot.capetown { left: 55.156%; top: 68.913%; background: var(--fg-cool-on-ink); }
.ch-08-arc-svg .arc-coord {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.ch-08-arc-svg .arc-coord.toronto { fill: var(--clay); }
.ch-08-arc-svg .arc-coord.capetown { fill: var(--fg-cool-on-ink); }
.ch-08-arc-svg .arc-period {
  font-family: var(--font-display);
  fill: var(--clay);
  font-size: 24px;
}

.ch-08-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 80px;
}
.ch-08-col {
  display: flex; flex-direction: column; gap: 16px;
  opacity: 0; transform: translateY(20px);
  will-change: opacity, transform;
}
.ch-08-col.is-in {
  opacity: 1; transform: translateY(0);
  transition: opacity 600ms var(--ease-out), transform 600ms var(--ease-out);
}
.ch-08-col-stamp {
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
}
.ch-08-col-stamp.toronto { color: var(--clay); }
.ch-08-col-stamp.capetown { color: var(--fg-cool-on-ink); }
.ch-08-col-stamp .period { color: var(--clay); }
.ch-08-col-head {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(28px, 2.6vw, 36px);
  color: var(--bone); margin: 0;
  letter-spacing: -0.01em;
}
.ch-08-col-body {
  font-family: var(--font-body); font-size: 16px; line-height: 1.6;
  color: var(--fg-quiet-on-ink); margin: 0;
  max-width: 44ch;
}
.ch-08-col-body em {
  font-family: var(--font-display); font-style: italic;
  color: var(--fg-cool-on-ink); font-weight: 400;
}

/* ----------------------------------------------------------------
   Chapter 09 · The close - Bone surface, restrained.
   Headline + contact form.  Only ambient motion is M14 magnetic on
   the submit button.
   ----------------------------------------------------------------*/

.ch-09 {
  position: relative;
  background: var(--bone);
  padding: 22vh 0 18vh;
  min-height: 100svh;
}
.ch-09-inner {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 80px;
  display: grid;
  grid-template-columns: 1fr 1.05fr;
  gap: 96px;
  align-items: start;
}
.ch-09-stamp {
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
  margin-bottom: 28px;
}
.ch-09-stamp .period { color: var(--clay); margin: 0 6px; }

.ch-09-head {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(48px, 6vw, 96px);
  line-height: 1.02; letter-spacing: -0.022em;
  color: var(--ink); margin: 0;
  text-wrap: balance;
  position: relative;
  max-width: 16ch;
}
.ch-09-head em { font-style: italic; color: var(--harbor); font-weight: 400; }
.ch-09-head .period { color: var(--clay); }
.ch-09-head .carbon {
  position: absolute; inset: 0;
  color: rgba(168, 156, 138, 0.42);
  z-index: -1;
  transform: translate(2px, 2px);
  pointer-events: none;
  will-change: transform;
}
.ch-09-head .carbon em { color: rgba(31, 77, 74, 0.32); }
.ch-09-head .carbon .period { color: rgba(181, 87, 58, 0.32); }

.ch-09-body {
  margin-top: 28px;
  font-family: var(--font-body); font-size: 17px; line-height: 1.6;
  color: var(--ink);
  max-width: 44ch;
}
.ch-09-side {
  display: flex; flex-direction: column; gap: 6px;
  margin-top: 18px;
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
}
.ch-09-side a {
  color: var(--ink);
  border-bottom: 1px solid var(--bone-400);
  padding-bottom: 1px;
  transition: color 120ms var(--ease-standard), border-color 120ms var(--ease-standard);
}
.ch-09-side a:hover { color: var(--clay); border-color: var(--clay); }
.ch-09-side .period { color: var(--clay); margin: 0 4px; }

.ch-09-form {
  display: flex; flex-direction: column;
  gap: 20px;
  background: var(--bone-100);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  padding: 40px;
  box-shadow: var(--shadow-sm);
}
.ch-09-form-row {
  display: flex; flex-direction: column; gap: 8px;
}
.ch-09-form label {
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--ink);
  font-weight: 500;
}
.ch-09-form label .period { color: var(--clay); }
.ch-09-form input,
.ch-09-form textarea {
  font-family: var(--font-body); font-size: 16px;
  color: var(--ink);
  background: var(--bone);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  min-height: 46px;
  outline: none;
  resize: none;
  transition: border-color var(--dur-fast) var(--ease-standard);
}
.ch-09-form input::placeholder,
.ch-09-form textarea::placeholder { color: var(--stone); }
.ch-09-form input:hover,
.ch-09-form textarea:hover { border-color: var(--ink); }
.ch-09-form input:focus,
.ch-09-form input:focus-visible,
.ch-09-form textarea:focus,
.ch-09-form textarea:focus-visible {
  border-color: var(--clay);
  outline: 2px solid var(--clay);
  outline-offset: 2px;
}
.ch-09-form textarea { min-height: 132px; line-height: 1.5; padding-top: 12px; }
.ch-09-form-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; flex-wrap: wrap;
  margin-top: 6px;
  font-family: var(--font-mono); font-size: var(--fs-stamp);
  letter-spacing: var(--tracking-stamp); text-transform: uppercase;
  color: var(--stone);
}
.ch-09-form-foot .period { color: var(--clay); }
.ch-09-submit {
  display: inline-flex; align-items: center; gap: 1px;
  background: var(--clay); color: var(--bone);
  font-family: var(--font-display); font-weight: 500;
  font-size: 17px; letter-spacing: -0.005em;
  padding: 16px 32px; border-radius: var(--radius-md);
  border: none; cursor: pointer;
  text-decoration: none;
  min-height: 48px;
  transition: background var(--dur-fast) var(--ease-standard);
  will-change: transform;
}
.ch-09-submit:hover { background: var(--clay-hover); color: var(--bone); }
.ch-09-submit:focus-visible {
  outline: 2px solid var(--clay);
  outline-offset: 2px;
}
.ch-09-submit .period { color: var(--bone); }

/* ----------------------------------------------------------------
   Responsive - Ch 7 hero collapse at tablet and below.
   At 1023px and under, the two-column grid becomes a single column
   so the slot headline reads full-width above the card.
   ----------------------------------------------------------------*/

@media (max-width: 1023px) {
  .ch-07-inner {
    grid-template-columns: 1fr;
    gap: 48px;
    padding: 0 32px;
  }
  .ch-07-head {
    font-size: clamp(40px, 8vw, 72px);
  }
}

@media (max-width: 767px) {
  .ch-07-head {
    font-size: clamp(36px, 10vw, 56px);
  }
  .ch-07-inner {
    padding: 0 24px;
    gap: 36px;
  }
}

