/* ============================================================
   SCUBAzen — site: components & folds
   ============================================================ */

/* ---------- Buttons & badges ---------- */
.store-badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  align-items: center;
}
.badge-link {
  display: inline-flex;
  border-radius: 11px;
  transition: transform 400ms var(--ease-out-quint),
    box-shadow 400ms var(--ease-out-quint);
  will-change: transform;
}
.badge-link img { height: 53px; width: auto; border-radius: 11px; }
.badge-link:hover { transform: translateY(-3px); }
.badge-link:hover img {
  box-shadow: 0 10px 30px oklch(0.2 0.05 245 / 0.35);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--step-0);
  padding: 0.85em 1.6em;
  border-radius: 999px;
  transition: transform 350ms var(--ease-out-quint),
    background-color 250ms ease, color 250ms ease, box-shadow 350ms var(--ease-out-quint);
  will-change: transform;
}
.btn--primary {
  background: var(--brand-fill);
  color: #fff;
  box-shadow: 0 6px 20px oklch(0.55 0.12 235 / 0.28);
}
.btn--primary:hover { transform: translateY(-2px); background: var(--brand-deeper); }
.btn--ghost {
  color: var(--deep-ink);
  border: 1px solid oklch(0.97 0.008 230 / 0.35);
  background: oklch(0.97 0.008 230 / 0.06);
  backdrop-filter: blur(4px);
}
.btn--ghost:hover { border-color: oklch(0.97 0.008 230 / 0.7); transform: translateY(-2px); }
.btn--on-light.btn--ghost {
  color: var(--brand-deep);
  border-color: var(--line);
  background: transparent;
}
.btn--on-light.btn--ghost:hover { border-color: var(--brand); }

.btn .arrow { transition: transform 350ms var(--ease-out-quint); }
.btn:hover .arrow { transform: translateX(3px); }

/* ---------- Nav ---------- */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--z-nav);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: clamp(1rem, 2vw, 1.5rem) 4vw;
  /* padding is a layout property: transitioning it reflowed the bar's children
     for the whole 400ms of every scroll-state flip. The bar still changes
     height — that shift is part of the design — it just snaps between the two
     paddings while the composited properties carry the visible transition. */
  transition: background-color 500ms ease, backdrop-filter 500ms ease,
    box-shadow 500ms ease;
  /* Promote to its own compositor layer so the scrolled-state backdrop-filter
     is cached and composited instead of re-blurred on every scroll frame. */
  transform: translateZ(0);
  backface-visibility: hidden;
}
/* Before the bar goes solid it sits directly on the hero photograph, and the
   pages that open on one span a wide range of exposures — the blog heroes run
   from deep blue water to a pale seagrass crop measuring 184 luminance, where
   off-white type has nothing to sit against however deep its shadow. A short
   top-down wash seats every link on all of them at once (the scrim technique
   DESIGN.md already applies to light type over photography), and it fades out
   as the solid bar fades in, so the scrolled state is untouched.
   Excluded on navSolid pages, which open on paper-white and need no wash. */
.nav:not([data-nav-solid="true"])::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 190%;
  pointer-events: none;
  z-index: -1;
  background: linear-gradient(180deg,
    oklch(0.16 0.04 245 / 0.5) 0%,
    oklch(0.16 0.04 245 / 0.28) 45%,
    oklch(0.16 0.04 245 / 0) 100%);
  opacity: 1;
  transition: opacity 500ms ease;
}
.nav[data-scrolled="true"]::before { opacity: 0; }
.nav[data-scrolled="true"] {
  background: color-mix(in oklch, var(--bg) 82%, transparent);
  -webkit-backdrop-filter: blur(10px) saturate(1.1);
  backdrop-filter: blur(10px) saturate(1.1);
  padding-block: 0.7rem;
  box-shadow: 0 1px 0 var(--line), 0 8px 30px oklch(0.3 0.03 240 / 0.06);
}
/* The mark is 34px, so the anchor was too — under the --tap floor even though
   it is the persistent "go home" control on every page. The extra height is
   padding, not layout: the bar centres its children, so the logo does not move. */
.nav__brand { display: flex; align-items: center; gap: 0.6rem; min-height: var(--tap); }
.nav__brand img.mark { height: 34px; width: auto; }
.nav__brand img.wordmark { height: 20px; width: auto; }
/* On the hero (before scroll), wordmark sits on dark imagery → light treatment.
   We keep the color wordmark but add a soft shadow for legibility. */
.nav:not([data-scrolled="true"]) .nav__brand img.wordmark {
  filter: drop-shadow(0 1px 6px oklch(0.15 0.04 245 / 0.55));
}
.nav__actions { display: flex; align-items: center; gap: var(--space-s); }
.nav__link {
  font-weight: 500;
  color: var(--deep-ink);
  transition: color 250ms ease, opacity 250ms ease;
  opacity: 0.9;
}
.nav:not([data-scrolled="true"]) .nav__link {
  text-shadow: 0 1px 8px oklch(0.15 0.04 245 / 0.5);
}
.nav[data-scrolled="true"] .nav__link { color: var(--ink); }
.nav__link:hover { opacity: 1; color: var(--brand); }
/* Nav links are hidden below 620px and hovered with a pointer on desktop, which
   left a band — tablets, 620-900px — where they are the primary navigation and
   genuinely tapped, at 28px tall. Any coarse pointer gets the --tap floor;
   `pointer: coarse` is the honest test, since it is the input device that
   matters here, not the viewport width. */
@media (pointer: coarse) {
  .nav__link {
    min-height: var(--tap);
    display: inline-flex;
    align-items: center;
  }
}
.nav__cta {
  font-weight: 600;
  /* 0.55em landed the pill at 43.7px — a third of a pixel under the 44px
     minimum. The extra 0.05em costs nothing visually and clears it. */
  padding: 0.6em 1.15em;
  border-radius: 999px;
  background: var(--brand-fill);
  color: #fff;
  transition: transform 300ms var(--ease-out-quint), background-color 250ms ease;
}
.nav__cta:hover { transform: translateY(-2px); background: var(--brand-deeper); }
@media (max-width: 620px) {
  .nav__link { display: none; }
}

/* ---------- Media / picture with blur-up ---------- */
.media {
  position: relative;
  overflow: hidden;
  background-size: cover;
  background-position: center;
}
.media picture { height: 100%; }
.media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 900ms var(--ease-out-quint);
}
.media img.loaded { opacity: 1; }

/* ---------- Hero ----------
   One committed idea: "the descent." A single centered column that reads
   top-to-bottom like sinking into still water — the meditating-diver mark as
   a quiet beacon, the headline as a slow exhale, a hairline water-surface
   divide, living caustic light + rising breath over the photograph. */
.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  grid-template-columns: 100%;  /* track = viewport width, never max-content */
  place-items: center;          /* centered descent, not a flush-left block */
  overflow: hidden;
  isolation: isolate;
  text-align: center;
}
.hero__bg {
  position: absolute;
  inset: -8% 0 0 0;      /* extra top for parallax drift */
  z-index: -3;
  height: 116%;
  will-change: transform;
}
.hero__bg img { width: 100%; height: 100%; object-fit: cover; }

/* Living water: two offset radial "caustic" fields drift and breathe slowly
   over the still photo, so the light on the water actually moves. Screen blend
   adds light (never darkens the scene), transform/opacity only → 60fps. */
.hero__caustics {
  position: absolute;
  inset: -20%;
  z-index: -2;
  pointer-events: none;
  opacity: 0;                 /* motion-ready fades it in; stays 0 if JS/motion off */
  mix-blend-mode: screen;
  background:
    radial-gradient(34% 26% at 28% 20%, oklch(0.9 0.06 220 / 0.1), transparent 70%),
    radial-gradient(28% 24% at 74% 32%, oklch(0.86 0.07 210 / 0.09), transparent 72%),
    radial-gradient(40% 30% at 54% 10%, oklch(0.95 0.04 230 / 0.08), transparent 70%);
  will-change: transform, opacity;
}
html.motion-ready .hero__caustics {
  animation: caustic-drift 26s ease-in-out infinite alternate;
}
@keyframes caustic-drift {
  0%   { transform: translate3d(-2%, -1.5%, 0) scale(1.05); opacity: 0.4; }
  50%  { opacity: 0.7; }
  100% { transform: translate3d(2.5%, 2%, 0) scale(1.12); opacity: 0.45; }
}

/* Rising breath: individual bubbles ascend from the diver, echoing the exhale.
   Each <span> carries its own --x / --size / --dur / --delay / --drift, so no
   two rise alike. transform/opacity only → 60fps. Hidden until motion-ready. */
.hero__bubbles {
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  overflow: hidden;
}
.hero__bubbles span {
  position: absolute;
  left: var(--x);
  bottom: -4%;
  width: var(--size);
  height: var(--size);
  border-radius: 50%;
  opacity: 0;
  /* Soft-lit bubble: bright rim, hollow centre — reads as a real bubble, not a dot. */
  background:
    radial-gradient(circle at 32% 28%,
      oklch(0.99 0.005 230 / 0.85) 0 18%,
      oklch(0.95 0.02 225 / 0.28) 42%,
      oklch(0.9 0.03 225 / 0.1) 66%,
      transparent 78%);
  box-shadow: inset 0 0 0 0.5px oklch(0.98 0.01 230 / 0.35);
  will-change: transform, opacity;
}
html.motion-ready .hero__bubbles span {
  animation: bubble-rise var(--dur) linear var(--delay) infinite;
}
@keyframes bubble-rise {
  0%   { transform: translateY(0) translateX(0); opacity: 0; }
  8%   { opacity: 0.7; }
  85%  { opacity: 0.55; }
  100% { transform: translateY(-104svh) translateX(var(--drift)); opacity: 0; }
}

/* Scrim: a centered radial vignette that darkens the edges to protect the
   column, but LETS THE GOD-RAYS SURVIVE through the upper-center — the old
   even bottom-band flattened the best part of the photo. A soft bottom lift
   still seats the badges. Sized so the centered text clears 4.5:1. */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    /* Text-protection plume: a soft vertical shaft of depth centered on the
       column so the headline + standfirst clear WCAG, while the outer god-rays
       stay bright. Sized to the text area, per the DESIGN.md scrim rule. */
    radial-gradient(52% 62% at 50% 52%,
      oklch(0.11 0.045 246 / 0.62) 0%,
      oklch(0.12 0.045 246 / 0.5) 40%,
      oklch(0.14 0.04 246 / 0.28) 66%,
      transparent 82%),
    radial-gradient(120% 92% at 50% 44%,
      transparent 0%,
      oklch(0.16 0.04 245 / 0.12) 34%,
      oklch(0.13 0.04 246 / 0.46) 64%,
      oklch(0.10 0.035 248 / 0.76) 86%,
      oklch(0.08 0.03 248 / 0.9) 100%),
    linear-gradient(180deg, oklch(0.11 0.04 245 / 0.42) 0%, transparent 20%),
    linear-gradient(0deg, oklch(0.09 0.035 246 / 0.62) 0%, transparent 30%);
}
@media (max-width: 860px) {
  /* Portrait phones: reef fills the lower frame and the column is taller.
     Deepen the vignette so mark → eyebrow → title → standfirst → badges clear. */
  .hero__scrim {
    background:
      /* Vertical band behind the text column so mid-frame reef never fights it. */
      linear-gradient(180deg,
        transparent 24%,
        oklch(0.11 0.04 246 / 0.42) 46%,
        oklch(0.11 0.04 246 / 0.46) 66%,
        transparent 88%),
      radial-gradient(140% 82% at 50% 42%,
        transparent 0%,
        oklch(0.13 0.04 245 / 0.3) 38%,
        oklch(0.11 0.04 246 / 0.72) 74%,
        oklch(0.09 0.035 248 / 0.9) 100%),
      linear-gradient(180deg, oklch(0.11 0.04 245 / 0.44) 0%, transparent 14%),
      linear-gradient(0deg, oklch(0.10 0.035 246 / 0.68) 0%, transparent 36%);
  }
}

.hero__inner {
  width: min(680px, 90vw);
  max-width: 100%;
  margin-inline: auto;
  padding-block: clamp(5.5rem, 12vh, 9rem) clamp(2.75rem, 6vh, 5rem);
  color: var(--deep-ink);
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Any accidental over-wide child is clipped rather than shoving the layout. */
  min-width: 0;
}

/* The mark: quiet beacon at the top of the descent. The teal figure lands on
   bright, same-hue sunlit water, so a diffuse glow alone won't separate it.
   Two things carry the contrast without boxing the mark in:
   1. a contained radial pad of depth BEHIND it (::before) — darkens the water
      the light-teal lower body sits on, and rings the whole figure with a
      halo that never reads as a card;
   2. a layered drop-shadow that traces the PNG's own silhouette — a tight
      near-black edge to draw the outline, over a wider soft depth. */
.hero__mark {
  position: relative;
  width: clamp(58px, 8vw, 84px);
  height: auto;
  margin-bottom: clamp(1.25rem, 3vh, 2rem);
  filter:
    drop-shadow(0 1px 2px oklch(0.10 0.04 240 / 0.85))
    drop-shadow(0 0 6px oklch(0.09 0.04 242 / 0.7))
    drop-shadow(0 8px 30px oklch(0.08 0.05 240 / 0.55));
}
.hero__mark::before {
  content: "";
  position: absolute;
  z-index: -1;
  /* Overspill the figure so the pad is a halo, not a plate behind it. An
     ellipse (55% x 62%) matched to the figure's tall proportions, fully faded
     before the edges so it never reads as a box on brighter water. */
  inset: -40%;
  background: radial-gradient(55% 62% at 50% 50%,
    oklch(0.12 0.04 242 / 0.66) 0%,
    oklch(0.12 0.04 242 / 0.44) 40%,
    oklch(0.13 0.04 244 / 0.18) 66%,
    transparent 80%);
  pointer-events: none;
}
html.motion-ready .hero__mark { animation: mark-float 7s ease-in-out infinite; }
@keyframes mark-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-7px); }
}

.hero__eyebrow {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--step-1);
  /* Off-white over photography: Picton-blue-on-blue-water is too low-contrast.
     A faint brand tint keeps it on-brand without dropping legibility. */
  color: oklch(0.95 0.025 230);
  letter-spacing: 0.14em;
  text-transform: lowercase;
  text-shadow: 0 1px 14px oklch(0.12 0.04 245 / 0.7);
  /* Hairline "water surface" beneath the held breath — one deliberate brand
     device dividing the surface (eyebrow) from the descent (headline). */
  position: relative;
  padding-bottom: clamp(1rem, 2.4vh, 1.6rem);
  margin-bottom: clamp(0.85rem, 2vh, 1.4rem);
}
.hero__eyebrow::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  width: clamp(120px, 34vw, 260px);
  height: 1px;
  background: linear-gradient(90deg,
    transparent,
    oklch(0.85 0.06 225 / 0.65) 30%,
    oklch(0.9 0.05 228 / 0.8) 50%,
    oklch(0.85 0.06 225 / 0.65) 70%,
    transparent);
}

.hero__title {
  font-size: var(--step-hero);
  font-weight: 500;
  line-height: 1.04;
  letter-spacing: -0.02em;
  text-shadow: 0 2px 34px oklch(0.12 0.04 245 / 0.5);
  display: flex;
  flex-direction: column;
}
/* The exhale: two lines descend, the second larger and lighter — the release. */
.hero__title-a { font-weight: 500; }
.hero__title-b {
  font-weight: 400;
  font-size: 1.18em;
  letter-spacing: -0.025em;
  margin-top: 0.04em;
}
.hero__title .light { opacity: 0.96; }

.hero__standfirst {
  margin-top: var(--space-m);
  max-width: 34ch;
  font-size: var(--step-1);
  line-height: 1.62;
  color: var(--deep-ink-soft);
  text-shadow: 0 1px 14px oklch(0.13 0.04 245 / 0.6);
  text-wrap: balance;
}
.hero__standfirst-break { display: none; }
@media (min-width: 621px) {
  .hero__standfirst-break { display: inline; }
}
.hero__cta {
  margin-top: var(--space-l);
  display: flex;
  justify-content: center;
}
.hero__cta .store-badges { justify-content: center; }

/* Narrow screens: the descent gets tighter type + measure so nothing overflows,
   and the badges stack. Test copy at every breakpoint — the viewport is design. */
@media (max-width: 620px) {
  .hero__inner { width: min(680px, 88vw); }
  .hero__eyebrow { letter-spacing: 0.1em; font-size: var(--step-0); }
  .hero__title {
    /* Cap the display so the larger line ("simplified.") never runs off-frame.
       Sized against the 88vw column, not the viewport, so it fits at 320px too. */
    font-size: clamp(2.2rem, 9vw, 3.2rem);
    line-height: 1.06;
  }
  .hero__title-b { font-size: 1.08em; }
  .hero__standfirst {
    font-size: var(--step-0);
  }
  .hero__cta .store-badges { flex-direction: column; align-items: center; }
}

.hero__scrollcue {
  position: absolute;
  left: 50%;
  bottom: 1.6rem;
  transform: translateX(-50%);
  z-index: 1;
  display: grid;
  place-items: center;
  gap: 0.5rem;
  color: var(--deep-ink-soft);
  font-size: var(--step--1);
  letter-spacing: 0.18em;
  text-transform: lowercase;
  transition:
    color 250ms ease,
    opacity 600ms var(--ease-out-quint),
    transform 600ms var(--ease-out-quint);
}
.hero__scrollcue:hover { color: var(--deep-ink); transform: translateX(-50%) translateY(2px); }
/* Once the diver scrolls, the badges have surfaced and "descend" has done its
   job — it drifts down and dissolves, yielding the bottom of the frame to the
   store badges so the two never collide. JS sets data-cue-hidden on scroll;
   without JS (or reduced motion) the cue simply stays, fully visible. */
.hero__scrollcue[data-cue-hidden="true"] {
  opacity: 0;
  transform: translateX(-50%) translateY(14px);
  pointer-events: none;
}
/* On short viewports the cue collides with the badges; hide it there. */
@media (max-height: 760px) {
  .hero__scrollcue { display: none; }
}
/* A phone held sideways is ~390px tall, and the hero's portrait padding built
   a 690px column inside it: the headline sat under the fixed bar and the store
   badges — the page's primary conversion — landed 280px below the fold. In
   landscape the fold is short and wide, so the hero stops insisting on a full
   viewport and tightens its padding until the whole invitation fits at once. */
@media (max-height: 560px) and (orientation: landscape) {
  .hero { min-height: auto; }
  .hero__inner { padding-block: 4rem 1rem; }
  .hero__mark { display: none; }
  .hero__eyebrow { font-size: var(--step-0); margin-bottom: 0.4rem; }
  .hero__title { font-size: clamp(1.7rem, 5vw, 2.2rem); }
  /* The standfirst and badge margins are tuned for a tall portrait column;
     at 390px of height they alone spend a fifth of the viewport. */
  .hero__standfirst { margin-top: 0.6rem; font-size: var(--step-0); }
  .hero__cta { margin-top: 1rem; }
}
.hero__scrollcue .line {
  width: 1px;
  height: 46px;
  background: linear-gradient(var(--deep-ink-soft), transparent);
  animation: cue-drift 2.8s var(--ease-out-quint) infinite;
  transform-origin: top;
}
@keyframes cue-drift {
  0% { transform: scaleY(0.3); opacity: 0; }
  40% { opacity: 1; }
  100% { transform: scaleY(1); opacity: 0; }
}

/* ---------- Section headers ---------- */
.fold {
  position: relative;
  padding-block: var(--space-2xl);
  overflow: clip;
}
.fold--light { background: var(--bg); color: var(--ink); }
.fold--surface { background: var(--surface); color: var(--ink); }
.fold--deep {
  background: linear-gradient(175deg, var(--deep) 0%, var(--deep-2) 100%);
  color: var(--deep-ink);
}
/* This fold is a single idea (two tiles under one header) and should read in
   one viewport on a laptop. The page's default 2xl rhythm is built for the
   long image-led folds; here it pushes the tiles below the fold, so the
   padding and the header gap both step down. */
.fold--deep {
  padding-block: clamp(3.5rem, 7vh, 6rem);
}
.fold--deep .section-head { margin-bottom: clamp(1.75rem, 3.5vh, 3rem); }

/* Wide, left-aligned header. The measure is generous enough that display
   headings hold two lines instead of stacking in a narrow column. */
.section-head {
  max-width: 26ch;
  margin-bottom: var(--space-xl);
}
@media (min-width: 700px) { .section-head { max-width: 62ch; } }
.section-head.center { margin-inline: auto; text-align: center; }
.section-head__kicker {
  font-family: var(--font-display);
  font-weight: 500;
  color: var(--brand-deep);
  font-size: var(--step-0);
  margin-bottom: var(--space-2xs);
}
.fold--deep .section-head__kicker { color: var(--brand); }
.section-head__title {
  font-size: var(--step-3);
  line-height: 1.06;
}
.section-head__lead {
  margin-top: var(--space-s);
  font-size: var(--step-1);
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 52ch;
}
.fold--deep .section-head__lead { color: var(--deep-ink-soft); }
.section-head.center .section-head__lead { margin-inline: auto; }

/* ---------- Manifesto ---------- */
.manifesto {
  position: relative;
  min-height: 92svh;
  display: grid;
  place-items: center;
  overflow: hidden;
  isolation: isolate;
  color: var(--deep-ink);
  text-align: center;
}
.manifesto__bg { position: absolute; inset: -8% 0 0 0; height: 116%; z-index: -2; will-change: transform; }
.manifesto__bg img { width: 100%; height: 100%; object-fit: cover; }
.manifesto__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(90% 70% at 50% 50%, oklch(0.14 0.04 248 / 0.35), oklch(0.12 0.04 250 / 0.78));
}
.manifesto__inner { width: var(--shell-narrow); padding-block: var(--space-xl); }
.manifesto__lead {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--step-4);
  line-height: 1.18;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.manifesto__lead .em { color: var(--brand); font-weight: 500; }
.manifesto__body {
  margin-top: var(--space-m);
  font-size: var(--step-1);
  line-height: 1.7;
  color: var(--deep-ink-soft);
  max-width: 54ch;
  margin-inline: auto;
}

/* ---------- The old way (the homemade system SCUBAzen replaces) ----------
   A recreated phone note, slightly askew — the artifact every diver already
   owns. Warm and familiar, never a scare tactic: the copy names the DIY
   system and lets the features below answer it. */
.scramble__grid {
  display: grid;
  gap: clamp(2.5rem, 5vw, 5rem);
  align-items: center;
  grid-template-columns: 1fr;
}
@media (min-width: 860px) {
  .scramble__grid { grid-template-columns: 0.9fr 1.1fr; }
}
.note {
  width: min(400px, 100%);
  margin-inline: auto;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(1.4rem, 2.5vw, 2rem);
  transform: rotate(-1.6deg);
  box-shadow:
    0 24px 60px oklch(0.3 0.05 245 / 0.12),
    0 2px 8px oklch(0.3 0.05 245 / 0.08);
}
.note__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin-bottom: var(--space-s);
}
.note__title { font-weight: 600; font-size: var(--step-1); }
.note__meta { font-size: var(--step--1); color: var(--ink-soft); white-space: nowrap; }
.note__list {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
.note__list li {
  position: relative;
  padding-left: 1.9rem;
  font-size: var(--step-0);
}
.note__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.24em;
  width: 1.05em;
  height: 1.05em;
  border-radius: 50%;
  border: 1.5px solid oklch(0.66 0.02 240);
}
.note__list li.is-done { color: var(--ink-soft); text-decoration: line-through; text-decoration-thickness: 1px; }
.note__list li.is-done::before { border-color: var(--zen); background: var(--zen); }
.note__list li.is-done::after {
  content: "";
  position: absolute;
  left: 0.28em;
  top: 0.52em;
  width: 0.5em;
  height: 0.26em;
  border-left: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(-48deg);
}
.note__caption {
  margin-top: var(--space-s);
  padding-top: var(--space-xs);
  border-top: 1px solid var(--line);
  font-size: var(--step--1);
  color: var(--ink-soft);
}
.scramble__body { max-width: 46ch; }
.scramble__text {
  margin-top: var(--space-s);
  font-size: var(--step-1);
  line-height: 1.65;
  color: var(--ink-soft);
  margin-bottom: var(--space-s);
}

/* Green-dot reassurance line (used by the "old way" fold). */
.feature__note {
  margin-top: var(--space-s);
  font-size: var(--step-0);
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 500;
}
.feature__note .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--zen); }

/* ---------- The journey: one trip, start to surface ----------
   A single descent line runs the length of the section; each feature is a
   moment on the approach to the water, marked by when it happens rather than
   what it's called. The line fills as you scroll (JS drives the fill's
   clip-path; without JS or with reduced motion it is simply full). */
.journey {
  position: relative;
  --jgutter: clamp(2.1rem, 5vw, 3.6rem);
  padding-left: var(--jgutter);
}
.journey__spine {
  position: absolute;
  left: 0;
  top: 0.4rem;
  bottom: 0;
  width: 13px;
  display: flex;
  justify-content: center;
  pointer-events: none;
  /* The line dissolves at its end — the descent continues into the deep fold
     below rather than stopping at a border. */
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 90%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 90%, transparent 100%);
}
.journey__spine::before {
  content: "";
  width: 2px;
  height: 100%;
  border-radius: 2px;
  background: var(--line);
}
.journey__spine-fill {
  position: absolute;
  top: 0;
  left: 50%;
  margin-left: -1px;
  width: 2px;
  height: 100%;
  border-radius: 2px;
  /* Surface light settling into depth — the section's descent, in one line.
     Revealed with clip-path (not scaleY) so the gradient stays pinned to the
     track and the tip genuinely descends from light into deep. */
  background: linear-gradient(180deg,
    oklch(0.8 0.08 225) 0%,
    var(--brand) 30%,
    var(--brand-deep) 70%,
    var(--deep) 100%);
  will-change: clip-path;
}
html.motion-ready .journey__spine-fill { clip-path: inset(0 0 100% 0); }

.journey__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(3.75rem, 8vw, 6.5rem);
}

/* When it happens — the timeline's voice, hung on the line. */
.moment__when {
  position: relative;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--step-1);
  color: var(--brand-deep);
  letter-spacing: 0.05em;
  text-transform: lowercase;
  margin-bottom: var(--space-s);
}
.moment__dot {
  position: absolute;
  left: calc(-1 * var(--jgutter));
  top: 50%;
  transform: translateY(-50%);
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--brand);
  box-shadow: 0 0 0 4px color-mix(in oklch, var(--brand) 20%, transparent);
}
/* Dots wait unlit until their moment arrives (default = lit, for no-JS). */
html.motion-ready .moment__dot {
  background: var(--line);
  box-shadow: 0 0 0 4px transparent;
  transition: background-color 700ms ease, box-shadow 700ms ease;
}
html.motion-ready .moment__when.in .moment__dot {
  background: var(--brand);
  box-shadow: 0 0 0 4px color-mix(in oklch, var(--brand) 20%, transparent);
}

.moment__grid {
  display: grid;
  gap: clamp(1.75rem, 4vw, 4.5rem);
  align-items: center;
  grid-template-columns: 1fr;
}
@media (min-width: 880px) {
  .moment__grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); }
  .moment__artifact { justify-self: center; }
  /* Alternate sides for rhythm; the spine keeps the thread. */
  .moment:nth-child(even) .moment__body { order: 2; }
}
.moment__body { max-width: 46ch; }
.moment__feature {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--step-0);
  color: var(--brand-deep);
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: var(--space-2xs);
}
.moment__feature::before {
  content: "";
  width: 34px;
  height: 1px;
  background: var(--brand);
  display: inline-block;
}
.moment__title { font-size: var(--step-2); line-height: 1.12; }
.moment__text {
  margin-top: var(--space-xs);
  font-size: var(--step-1);
  line-height: 1.65;
  color: var(--ink-soft);
}

/* ---------- Artifacts ----------
   Small in-app moments rebuilt in HTML — the same recreated-artifact device
   as the "old way" note, but level and serene where the note was askew and
   frantic. One family, five personalities. */
.artifact {
  width: min(420px, 100%);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 2.2vw, 1.7rem);
  box-shadow:
    0 20px 48px oklch(0.3 0.05 245 / 0.10),
    0 2px 8px oklch(0.3 0.05 245 / 0.06);
}
.artifact__head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding-bottom: var(--space-xs);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--space-xs);
}
.artifact__head img { width: 22px; height: 22px; }
.artifact__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-0);
}
.artifact__meta {
  margin-left: auto;
  font-size: var(--step--1);
  color: var(--ink-soft);
  white-space: nowrap;
}
.artifact__foot {
  margin-top: var(--space-xs);
  padding-top: var(--space-xs);
  border-top: 1px solid var(--line);
  font-size: var(--step--1);
  color: var(--ink-soft);
}

/* Planner: two suggestions, reasoned from the log. */
.planner__list {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}
.planner__list li { display: flex; flex-direction: column; gap: 0.15rem; }
.planner__place {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-0);
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
}
.planner__place::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--brand);
  flex: none;
}
.planner__why {
  font-size: var(--step--1);
  color: var(--ink-soft);
  padding-left: calc(7px + 0.55rem);
}
/* Suggestions surface one after another, like the planner thinking. */
html.motion-ready .moment__artifact .planner__list li {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 700ms var(--ease-out-expo), transform 700ms var(--ease-out-expo);
}
html.motion-ready .moment__artifact .planner__list li:nth-child(1) { transition-delay: 350ms; }
html.motion-ready .moment__artifact .planner__list li:nth-child(2) { transition-delay: 620ms; }
html.motion-ready .moment__artifact.in .planner__list li { opacity: 1; transform: none; }

/* Trip: the plan at a glance. */
.trip__list {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.trip__list li {
  position: relative;
  padding-left: 1.15rem;
  font-size: var(--step-0);
}
.trip__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.58em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--brand);
}

/* Rental sheet: paper, ruled rows, sent. */
.doc__rows { margin: 0; }
.doc__row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 0.45rem;
  border-bottom: 1px dashed var(--line);
  font-size: var(--step-0);
}
.doc__row:last-child { border-bottom: none; }
.doc__row dt { font-weight: 600; }
.doc__row dd { margin: 0; color: var(--ink-soft); }
.doc__sent {
  color: var(--zen);
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}
.doc__sent::before {
  content: "";
  width: 0.5em;
  height: 0.28em;
  border-left: 2px solid var(--zen);
  border-bottom: 2px solid var(--zen);
  transform: rotate(-48deg) translateY(-0.1em);
}

/* Packing list: the "old way" note, answered — same shape, opposite feeling.
   Everything already ticked. */
.check__list {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.check__list li {
  position: relative;
  padding-left: 1.9rem;
  font-size: var(--step-0);
  --i: 0;
}
.check__list li:nth-child(2) { --i: 1; }
.check__list li:nth-child(3) { --i: 2; }
.check__list li:nth-child(4) { --i: 3; }
.check__list li:nth-child(5) { --i: 4; }
.check__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.24em;
  width: 1.05em;
  height: 1.05em;
  border-radius: 50%;
  border: 1.5px solid var(--zen);
  background: var(--zen);
}
.check__list li::after {
  content: "";
  position: absolute;
  left: 0.28em;
  top: 0.52em;
  width: 0.5em;
  height: 0.26em;
  border-left: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(-48deg);
}
/* The quiet payoff: items tick themselves as the card arrives. */
html.motion-ready .moment__artifact .check__list li::before {
  background: transparent;
  border-color: oklch(0.66 0.02 240);
  transition: background-color 400ms ease, border-color 400ms ease;
  transition-delay: calc(420ms + var(--i) * 150ms);
}
html.motion-ready .moment__artifact .check__list li::after {
  opacity: 0;
  transform: rotate(-48deg) scale(0.5);
  transition: opacity 300ms ease, transform 300ms var(--ease-out-quint);
  transition-delay: calc(460ms + var(--i) * 150ms);
}
html.motion-ready .moment__artifact.in .check__list li::before {
  background: var(--zen);
  border-color: var(--zen);
}
html.motion-ready .moment__artifact.in .check__list li::after {
  opacity: 1;
  transform: rotate(-48deg) scale(1);
}

/* Log entry: the dive, kept — and the loop back to "where next?". */
.log__stats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.1rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-1);
}
.log__memory {
  margin-top: 0.7rem;
  font-size: var(--step-0);
  line-height: 1.55;
  color: var(--ink-soft);
}
.log__loop {
  color: var(--brand-deep);
  font-weight: 600;
}

/* ---------- Trio (calc/wetsuit + travel, side by side smaller) ---------- */
.duo {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
  margin-top: var(--space-l);
}
.tile {
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  /* Scales with the viewport so the pair still fits under the header on a
     short laptop screen, with a floor that keeps the image readable. */
  min-height: clamp(300px, 42vh, 400px);
  display: flex;
  align-items: flex-end;
  isolation: isolate;
  color: var(--deep-ink);
  box-shadow: 0 20px 50px oklch(0.3 0.05 245 / 0.16);
}
.tile__bg { position: absolute; inset: 0; z-index: -2; }
.tile__bg .media { height: 100%; }
/* Deep enough at the base that body text clears 4.5:1 even over a pale
   sunset sky, not just over dark water. */
.tile__scrim {
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(0deg,
    oklch(0.11 0.035 246 / 0.94) 0%,
    oklch(0.12 0.04 246 / 0.86) 32%,
    oklch(0.15 0.04 245 / 0.5) 58%,
    transparent 82%);
}
.tile__body { padding: clamp(1.5rem, 3vw, 2.2rem); }
.tile__title { font-size: var(--step-2); line-height: 1.1; }
.tile__text {
  margin-top: 0.5rem;
  /* Near-white rather than the soft ink: this sits on photography, where the
     muted tone loses contrast against bright areas. */
  color: oklch(0.94 0.008 232);
  font-size: var(--step-0);
  line-height: 1.6;
  max-width: 34ch;
}

/* ---------- The waterline (where SCUBAzen ends and the dive begins) ----------
   One fold, split by the surface: air above (the prep, ours), water below
   (the dive, yours). The hairline is the same water-surface device the hero
   eyebrow introduced; below it, near-surface light settles into depth. */
.waterline {
  position: relative;
  overflow: clip;
  text-align: center;
}
.waterline__above {
  background: var(--bg);
  color: var(--ink);
  padding-block: var(--space-2xl) var(--space-xl);
}
.waterline__inner { width: var(--shell-narrow); margin-inline: auto; }
.waterline__title { font-size: var(--step-3); line-height: 1.1; }
.waterline__items {
  margin-top: var(--space-m);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  column-gap: 0.9em;
  row-gap: 0.5em;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--step-1);
  color: var(--ink-soft);
}
.waterline__items .sep { color: var(--zen); }
.waterline__line {
  position: relative;
  height: 1px;
  background: linear-gradient(90deg,
    transparent,
    oklch(0.78 0.08 226 / 0.55) 22%,
    oklch(0.85 0.08 228 / 0.95) 50%,
    oklch(0.78 0.08 226 / 0.55) 78%,
    transparent);
  /* Seen from below, the surface glows: a soft light cast downward into the
     deep half so the hairline reads as water, not a border. */
  box-shadow: 0 6px 26px oklch(0.88 0.06 228 / 0.5), 0 1px 6px oklch(0.9 0.06 228 / 0.6);
}
.waterline__below {
  position: relative;
  overflow: hidden;
  background: linear-gradient(180deg,
    oklch(0.66 0.1 226) 0%,
    oklch(0.52 0.09 234) 9%,
    var(--deep) 38%,
    var(--deep-2) 100%);
  color: var(--deep-ink);
  padding-block: var(--space-2xl);
}
/* Sunlight through the surface: a soft plume of light spilling down from the
   line, so the boundary reads as water seen from below, not a border. */
.waterline__below::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: clamp(90px, 14vw, 170px);
  background:
    radial-gradient(58% 100% at 50% 0%, oklch(0.85 0.07 222 / 0.32), transparent 75%),
    linear-gradient(180deg, oklch(0.8 0.08 224 / 0.22), transparent);
  pointer-events: none;
}
.waterline__below .waterline__title { color: var(--deep-ink); }
.waterline__body {
  margin-top: var(--space-s);
  font-size: var(--step-1);
  line-height: 1.7;
  color: var(--deep-ink-soft);
  max-width: 54ch;
  margin-inline: auto;
}
/* A few slow bubbles rise toward the line — the breath below the surface. */
.waterline__bubbles {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.waterline__bubbles span {
  position: absolute;
  left: var(--x);
  bottom: -4%;
  width: var(--size);
  height: var(--size);
  border-radius: 50%;
  opacity: 0;
  background:
    radial-gradient(circle at 32% 28%,
      oklch(0.99 0.005 230 / 0.8) 0 18%,
      oklch(0.95 0.02 225 / 0.25) 42%,
      oklch(0.9 0.03 225 / 0.08) 66%,
      transparent 78%);
  will-change: transform, opacity;
}
html.motion-ready .waterline__bubbles span {
  animation: wl-bubble-rise var(--dur) linear var(--delay) infinite;
}
@keyframes wl-bubble-rise {
  0%   { transform: translateY(0); opacity: 0; }
  10%  { opacity: 0.55; }
  86%  { opacity: 0.4; }
  100% { transform: translateY(-480px); opacity: 0; }
}

/* ---------- First trip back (the returning diver) ---------- */
.returning {
  position: relative;
  min-height: 88svh;
  display: grid;
  place-items: center;
  overflow: hidden;
  isolation: isolate;
  color: var(--deep-ink);
  text-align: center;
}
.returning__bg { position: absolute; inset: -8% 0 0 0; height: 116%; z-index: -2; will-change: transform; }
.returning__bg .media { height: 100%; }
.returning__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(90% 70% at 50% 55%, oklch(0.14 0.04 248 / 0.42), oklch(0.12 0.04 250 / 0.8));
}
.returning__inner { width: var(--shell-narrow); padding-block: var(--space-xl); }
.returning__title {
  font-family: var(--font-display);
  font-weight: 400;
  /* One notch under --step-4 so "The water remembers you." holds a single
     line on desktop instead of orphaning "you." */
  font-size: clamp(2.1rem, 1.55rem + 2.7vw, 3.7rem);
  line-height: 1.18;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.returning__title .em { color: var(--brand); font-weight: 500; }
.returning__body {
  margin-top: var(--space-m);
  font-size: var(--step-1);
  line-height: 1.7;
  color: var(--deep-ink-soft);
  max-width: 54ch;
  margin-inline: auto;
}

/* ---------- Closing ---------- */
.closing {
  position: relative;
  min-height: 90svh;
  display: grid;
  place-items: center;
  text-align: center;
  overflow: hidden;
  isolation: isolate;
  color: var(--deep-ink);
}
.closing__bg { position: absolute; inset: -8% 0 0 0; height: 116%; z-index: -2; will-change: transform; }
.closing__bg img { width: 100%; height: 100%; object-fit: cover; }
.closing__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(180deg, oklch(0.14 0.04 245 / 0.55), oklch(0.16 0.04 248 / 0.4) 50%, oklch(0.13 0.04 250 / 0.72));
}
/* Wider than the standard narrow shell so the two-line headline stays two
   lines at the display size, instead of orphaning "of itself." */
.closing__inner { width: min(940px, 90vw); padding-block: var(--space-xl); }
.closing__title {
  font-size: var(--step-4);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.015em;
}
.closing__title .em { color: var(--brand); }
.closing__lead {
  margin-top: var(--space-s);
  font-size: var(--step-1);
  color: var(--deep-ink-soft);
  max-width: 46ch;
  margin-inline: auto;
  line-height: 1.6;
}
.closing__cta {
  margin-top: var(--space-l);
  display: flex;
  justify-content: center;
}

/* ---------- Footer ---------- */
.footer {
  background: var(--bg);
  border-top: 1px solid var(--line);
  padding-block: var(--space-xl) var(--space-l);
  color: var(--ink);
}
.footer__grid {
  display: grid;
  gap: var(--space-l);
  grid-template-columns: 1fr;
}
@media (min-width: 720px) {
  .footer__grid { grid-template-columns: 1.4fr 1fr 1fr; }
}
.footer__brand img.wordmark { height: 26px; width: auto; margin-bottom: var(--space-s); }
.footer__tag { color: var(--ink-soft); max-width: 34ch; font-size: var(--step-0); }
.footer__badges { margin-top: var(--space-s); }
.footer__badges .badge-link img { height: 46px; }
/* h3, not h4: these column labels follow the page's h2 sections, and jumping
   straight to h4 skipped a level on every page in the site. Styled small
   regardless — the tag carries the outline, the CSS carries the look. */
.footer__col h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-0);
  margin-bottom: var(--space-xs);
  line-height: 1.3;
  letter-spacing: normal;
}
/* Links carry their own padding rather than sitting on a list gap, so the hit
   area is the visible row with no dead strip between entries. The rows do open
   up against the old 31px pitch — a --tap target and that pitch can't both
   be true — and the extra air suits a footer meant for calm scanning.
   Floor comes from the .tap primitive in base.css; see the note there for why
   this is opt-in rather than a blanket rule on every link. */
.footer__col ul { list-style: none; padding: 0; display: flex; flex-direction: column; }
.footer__col li { display: flex; }
.footer__col a {
  color: var(--ink-soft);
  transition: color 200ms ease;
  padding-block: 0.7rem;
  min-height: var(--tap);
  display: flex;
  align-items: center;
}
.footer__col a:hover { color: var(--brand-deep); }
.footer__base {
  margin-top: var(--space-l);
  padding-top: var(--space-m);
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  justify-content: space-between;
  align-items: center;
  color: var(--ink-soft);
  font-size: var(--step--1);
}
.footer__base .zen-dot { color: var(--zen); }

/* ---------- Reveal (motion) — enhances an already-visible default ---------- */
.reveal { opacity: 1; }
html.motion-ready .reveal {
  opacity: 0;
  transform: translateY(26px);
}
html.motion-ready .reveal.in {
  opacity: 1;
  transform: none;
  transition: opacity var(--dur-calm) var(--ease-out-expo),
    transform var(--dur-calm) var(--ease-out-expo);
}
/* Hero CTA: scroll-gated, deliberately.

   Unlike .reveal — which enhances an already-visible default — this element is
   HIDDEN until the visitor scrolls. That is an intentional exception to the
   rule above: the hero holds a single uncluttered line of intent, and the
   badges surface as the reward for starting the descent.

   Because it gates visibility on an interaction, it is only ever safe while
   every non-scrolling path still resolves to a visible CTA:
     - no-JS and reduced motion — `motion-ready` is never set, so the rule below
       simply doesn't apply and the badges render normally. No override needed.
     - print — JS runs, so `motion-ready` IS set; the @media print block undoes it.
     - a visitor who never scrolls — handled in site.js by a timeout that opens
       the gate anyway. Without it the CTA is unreachable, including by keyboard. */
html.motion-ready .hero__cta--onscroll {
  opacity: 0;
  transform: translateY(26px);
  /* Not interactive while invisible — a badge you can't see shouldn't be
     tabbable or clickable. */
  visibility: hidden;
}
html.motion-ready .hero__cta--onscroll.in {
  opacity: 1;
  transform: none;
  visibility: visible;
  transition: opacity var(--dur-calm) var(--ease-out-expo),
    transform var(--dur-calm) var(--ease-out-expo);
}

html.motion-ready .reveal[data-delay="1"].in { transition-delay: 90ms; }
html.motion-ready .reveal[data-delay="2"].in { transition-delay: 180ms; }
html.motion-ready .reveal[data-delay="3"].in { transition-delay: 270ms; }
html.motion-ready .reveal[data-delay="4"].in { transition-delay: 360ms; }

/* Print. The reveal system hides everything below the fold until it scrolls
   into view, and the JS safety net that undoes that is cancelled by the
   visitor's first scroll — correct for screen, silently destructive on paper.
   A reader who scrolls a little and then prints was getting a blank article
   body and no closing CTA (measured: 4 of 7 reveal elements still at
   opacity:0, including .post-prose). Paper has no viewport to scroll, so the
   reveal never applies here at all. */
@media print {
  html.motion-ready .reveal { opacity: 1 !important; transform: none !important; }
  /* Paper never scrolls, so the scroll-gated CTA would never surface. */
  html.motion-ready .hero__cta--onscroll {
    opacity: 1 !important; transform: none !important; visibility: visible !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  html.motion-ready .reveal { opacity: 1 !important; transform: none !important; }
  /* Not dead code, though it looks like it: site.js returns before setting
     `motion-ready` when reduced motion is on AT LOAD, so on that path the
     hiding rule never applies and this is redundant. But `reduceMotion` is
     sampled once and never re-read, so a visitor who turns the OS setting on
     AFTER load keeps `motion-ready` — leaving the CTA mid-animation, hidden,
     and untabbable until the 4s gate expires. That is the one reader who must
     not be made to wait through a fade. Every other rule in this block is
     written the same way for the same reason. */
  html.motion-ready .hero__cta--onscroll {
    opacity: 1 !important; transform: none !important; visibility: visible !important;
  }
  .hero__scrollcue .line { animation: none; }
  /* Journey: line fully drawn, dots lit, artifacts complete. */
  html.motion-ready .journey__spine-fill { clip-path: none !important; }
  html.motion-ready .moment__dot {
    background: var(--brand) !important;
    box-shadow: 0 0 0 4px color-mix(in oklch, var(--brand) 20%, transparent) !important;
  }
  html.motion-ready .moment__artifact .planner__list li { opacity: 1 !important; transform: none !important; }
  html.motion-ready .moment__artifact .check__list li::before {
    background: var(--zen) !important;
    border-color: var(--zen) !important;
  }
  html.motion-ready .moment__artifact .check__list li::after {
    opacity: 1 !important;
    transform: rotate(-48deg) !important;
  }
  .hero__bg, .manifesto__bg, .closing__bg, .returning__bg { inset: 0; height: 100%; }
  /* Waterline bubbles are ambient breath — fully still, fully hidden. */
  html.motion-ready .waterline__bubbles span { animation: none; opacity: 0; }
  /* Ambient hero motion off: caustics/bubbles stay fully hidden, mark still.
     The still photo + centered composition carry the hero on their own. */
  html.motion-ready .hero__caustics { animation: none; opacity: 0; }
  html.motion-ready .hero__bubbles span { animation: none; opacity: 0; }
  html.motion-ready .hero__mark { animation: none; transform: none; }
  html { scroll-behavior: auto; }
}

/* ============================================================
   THE STORY (/the-story)
   Founder-origin page. Inherits every token from base.css; the
   only new mechanics here are the paper-white opening (this page
   does NOT repeat the landing hero) and the recreated logbook.
   ============================================================ */

/* The landing nav starts transparent over the hero photo. This page opens on
   paper, so the bar needs its solid state from the first frame. */
.nav[data-nav-solid="true"] {
  background: color-mix(in oklch, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--line);
}
.nav[data-nav-solid="true"] .nav__link { color: var(--ink); }
.nav[data-nav-solid="true"] .nav__brand img.wordmark { filter: none; }
/* Needs the .nav ancestor to outrank `.nav[data-scrolled="true"] .nav__link`,
   which sets --ink and would otherwise win once the page scrolls — leaving the
   current page indistinguishable from its siblings for the whole session. */
.nav .nav__link[aria-current="page"] { color: var(--brand-deep); }
/* Before scroll the bar is transparent over a photograph, where brand-deep
   is far too dark to read (measured 1.4:1 over the blog hero's bright water).
   The current-page link there is marked with full-strength off-white plus the
   same text-shadow the other links carry — weight and opacity do the work
   that colour does once the bar goes solid.
   Scoped to pages whose nav actually starts transparent. Pages built with
   navSolid (the story, help, legal) open on paper-white, where off-white type
   would be invisible — measured 1.06:1 on /the-story before this exclusion. */
.nav:not([data-scrolled="true"]):not([data-nav-solid="true"]) .nav__link[aria-current="page"] {
  color: var(--deep-ink);
  opacity: 1;
  font-weight: 600;
  /* The blog hero crops are the brightest images on the site (a sunlit pool,
     pale seagrass). Off-white at the shared 8px shadow measured 2.7-3.1:1 on
     two of them, so this state carries a tighter, deeper plume of its own —
     enough to seat the type on any of the four without darkening the bar. */
  text-shadow: 0 1px 3px oklch(0.12 0.04 245 / 0.85), 0 1px 12px oklch(0.12 0.04 245 / 0.7);
}

/* ---------- Opening ---------- */
.story-open {
  position: relative;
  padding-block: clamp(8rem, 18vh, 12rem) var(--space-xl);
  background: var(--bg);
  text-align: center;
}
.story-open__mark {
  height: clamp(56px, 8vw, 72px);
  width: auto;
  margin-inline: auto;
  margin-bottom: var(--space-m);
  opacity: 0.92;
}
.story-open__kicker {
  font-family: var(--font-display);
  font-weight: 500;
  color: var(--brand-deep);
  font-size: var(--step-0);
  margin-bottom: var(--space-xs);
}
.story-open__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--step-4);
  line-height: 1.14;
  letter-spacing: -0.012em;
  text-wrap: balance;
}
.story-open__title .em { color: var(--brand-deep); font-weight: 500; }
.story-open__lead {
  margin-top: var(--space-m);
  margin-inline: auto;
  /* Wide enough that this ~100-character sentence sets as two balanced lines
     instead of three with "year detour." orphaned. balance evens them out. */
  max-width: 56ch;
  font-size: var(--step-1);
  line-height: 1.7;
  color: var(--ink-soft);
  text-wrap: balance;
}

/* ---------- Prose folds ---------- */
.story-fold { padding-block: var(--space-xl); }
.prose { max-width: 58ch; }
.prose__title {
  font-size: var(--step-3);
  line-height: 1.08;
  margin-bottom: var(--space-m);
}
.prose p + p { margin-top: var(--space-s); }
.prose p {
  font-size: var(--step-1);
  line-height: 1.75;
  color: var(--ink-soft);
}
.prose em { font-style: italic; color: var(--ink); }

/* ---------- Logbook archaeology ---------- */
.dig__grid {
  display: grid;
  gap: var(--space-l);
  align-items: start;
}
@media (min-width: 900px) {
  .dig__grid { grid-template-columns: 1.15fr 0.85fr; gap: var(--space-xl); }
}
.dig__list {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
  counter-reset: dig;
}
.dig__item {
  counter-increment: dig;
  padding-top: var(--space-s);
  border-top: 1px solid oklch(0.97 0.008 230 / 0.16);
}
.dig__item:first-child { border-top: 0; padding-top: 0; }
.dig__q {
  font-size: var(--step-2);
  font-weight: 500;
  line-height: 1.15;
  color: var(--deep-ink);
  margin-bottom: var(--space-2xs);
}
.dig__q::before {
  content: counter(dig, decimal-leading-zero);
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--brand);
  margin-right: 0.75rem;
  vertical-align: 0.35em;
}
.dig__a {
  color: var(--deep-ink-soft);
  line-height: 1.7;
  max-width: 46ch;
}
.dig__aside {
  margin-top: var(--space-2xs);
  font-family: var(--font-display);
  font-size: var(--step--1);
  color: var(--brand);
  opacity: 0.9;
}

/* The paper logbook being excavated: a real object, slightly askew, the
   counterpart to the landing page's phone note. */
.logbook {
  position: relative;
  background: oklch(0.97 0.008 92);
  color: oklch(0.3 0.02 250);
  border-radius: 6px;
  padding: var(--space-m) var(--space-s) var(--space-s);
  box-shadow:
    0 1px 0 oklch(0.99 0.005 92) inset,
    0 18px 40px -18px oklch(0.1 0.04 250 / 0.6),
    0 4px 14px -6px oklch(0.1 0.04 250 / 0.4);
  transform: rotate(-1.1deg);
  max-width: 420px;
  margin-inline: auto;
}
@media (min-width: 900px) { .logbook { margin-inline: 0 auto; } }
.logbook__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-s);
  padding-bottom: 0.6rem;
  border-bottom: 2px solid oklch(0.62 0.09 30 / 0.5);
  margin-bottom: 0.4rem;
}
.logbook__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-0);
  letter-spacing: 0.02em;
}
.logbook__meta {
  font-size: var(--step--1);
  color: oklch(0.5 0.02 250);
  white-space: nowrap;
}
.logbook__rows { display: flex; flex-direction: column; }
.logbook__row {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  gap: 0.5rem 0.9rem;
  align-items: baseline;
  padding-block: 0.55rem;
  border-bottom: 1px solid oklch(0.55 0.06 250 / 0.22);
  font-size: var(--step--1);
}
.logbook__site { font-weight: 600; }
.logbook__num { color: oklch(0.45 0.02 250); font-variant-numeric: tabular-nums; }
/* The weights column is the one being hunted for — and the one that's least
   trustworthy. Handwritten-feeling, uncertain, in pencil blue. */
.logbook__wt {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--brand-deeper);
  font-variant-numeric: tabular-nums;
  min-width: 5.5ch;
  text-align: right;
}
/* The illegible entry — the one whose weight was never recorded. Faded to
   read as smudged, but held at an opacity that still clears 4.5:1, since it
   carries real text rather than decoration. */
.logbook__row.is-smudged { opacity: 0.72; }
.logbook__row.is-smudged .logbook__wt { color: oklch(0.5 0.03 250); }
.logbook__caption {
  margin-top: var(--space-s);
  font-size: var(--step--1);
  color: oklch(0.5 0.02 250);
  font-style: italic;
}

/* ---------- The turn: what got built ---------- */
.built {
  margin-top: var(--space-l);
  max-width: 58ch;
  padding-top: var(--space-m);
  border-top: 1px solid var(--line);
}
.built__intro {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--step-1);
  color: var(--ink);
  margin-bottom: var(--space-s);
}
.built__list {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.built__list li {
  position: relative;
  padding-left: 1.9rem;
  color: var(--ink-soft);
  line-height: 1.6;
}
.built__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--brand);
}
.built__more {
  margin-top: var(--space-s);
  padding-left: 1.9rem;
  font-size: var(--step--1);
  color: var(--ink-soft);
  opacity: 0.85;
  font-style: italic;
}

/* ---------- Why we go (payoff image) ---------- */
.story-why {
  position: relative;
  /* Sized to the photograph's own 3:2 ratio, not to the viewport. A tall
     svh-based band leaves dead space a 3:2 landscape can't fill, which is
     what produced the grey slab in the first pass. Capped so it stays a
     band rather than swallowing the screen on wide monitors. */
  min-height: min(56vw, 60svh);
  display: grid;
  place-items: center;
  overflow: hidden;
  isolation: isolate;
  color: var(--deep-ink);
  text-align: center;
  /* Fallback water tone while the photo decodes. */
  background: var(--deep);
}
/* The photo IS the fold. A 3:2 landscape can't fill a tall viewport-height
   band, so the first pass left dead space below it that the scrim rendered
   as a flat grey slab. Rather than stretch the image, the layer covers the
   full fold and the parallax travel is kept small enough that the crop never
   runs past the photo's edges. */
/* The parallax layer must overhang the fold by MORE than the transform can
   travel, or the shift exposes bare background at one edge. Travel is
   strength x (scroll distance across the viewport), so at 0.05 over a ~900px
   viewport that's roughly ±90px; 140px of overhang each side clears it with
   margin to spare. Measured, not guessed: the first pass used a percentage
   overhang too small for the shift and left a navy strip. */
.story-why__bg {
  position: absolute;
  inset: -140px 0;
  height: calc(100% + 280px);
  z-index: -2;
  will-change: transform;
}
/* .media sets overflow:hidden with no height of its own; without an explicit
   100% here it collapses toward the image's intrinsic box and leaves a sliver
   of the section background showing at the fold's bottom edge. */
.story-why__bg .media,
.story-why__bg picture { height: 100%; display: block; overflow: visible; }
.story-why__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 55%;
}
/* Scrim darkens the band the text sits in, and only that band — the bright
   turquoise shallows either side stay bright. */
.story-why__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(180deg,
      oklch(0.14 0.04 245 / 0.42) 0%,
      oklch(0.13 0.04 248 / 0.52) 45%,
      oklch(0.13 0.04 250 / 0.44) 100%);
}
.story-why__inner { width: var(--shell-narrow); padding-block: var(--space-xl); }
.story-why__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.9rem, 1.4rem + 2.4vw, 3.2rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-wrap: balance;
  text-shadow: 0 2px 24px oklch(0.12 0.04 250 / 0.5);
}
.story-why__title .em { color: var(--brand); font-weight: 500; }

/* ---------- Signed ---------- */
.signed { padding-block: var(--space-xl); }
.signed__grid {
  display: grid;
  gap: var(--space-m);
  align-items: start;
  justify-items: center;
  text-align: center;
}
@media (min-width: 720px) {
  .signed__grid {
    grid-template-columns: 240px 1fr;
    gap: var(--space-l);
    justify-items: start;
    text-align: left;
  }
}
.signed__portrait {
  width: clamp(140px, 34vw, 240px);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: 0 20px 44px -22px oklch(0.24 0.04 245 / 0.55);
}
.signed__portrait img { width: 100%; height: auto; display: block; }
.signed__body { max-width: 52ch; }
.signed__title {
  font-size: var(--step-2);
  line-height: 1.14;
  margin-bottom: var(--space-s);
}
.signed__text {
  color: var(--ink-soft);
  line-height: 1.7;
}
.signed__text + .signed__text { margin-top: var(--space-xs); }
.signed__name {
  margin-top: var(--space-m);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-1);
  color: var(--ink);
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
@media (max-width: 719px) { .signed__name { align-items: center; } }
.signed__role {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--step--1);
  color: var(--ink-soft);
}
/* A standalone contact control under the signature, not a link inside a
   sentence, so it takes the --tap floor. The underline stays hugged to the
   text: padding goes above it, not below, or the rule detaches from the word. */
.signed__mail {
  display: inline-flex;
  align-items: flex-end;
  min-height: var(--tap);
  padding-top: var(--space-2xs);
  margin-top: var(--space-xs);
  color: var(--brand-deep);
  border-bottom: 1px solid color-mix(in oklch, var(--brand-deep) 40%, transparent);
  padding-bottom: 1px;
  transition: color 200ms ease, border-color 200ms ease;
}
.signed__mail:hover { color: var(--brand-deeper); border-color: var(--brand-deeper); }

@media (prefers-reduced-motion: reduce) {
  .story-why__bg { inset: 0; height: 100%; }
}

/* ============================================================
   LEGAL DOCUMENTS (/privacy, /terms)
   The deliberate departure: these pages carry no photography,
   no parallax, no deep-water fold. The landing and story pages
   already spend the cinematic move, and nobody arrives at a
   privacy policy for atmosphere. Here "calm" means the document
   is easy to navigate and easy to read — a sticky contents rail
   instead of scenery. Paper-white throughout.
   ============================================================ */

.doc-head {
  padding-block: clamp(7.5rem, 16vh, 10.5rem) var(--space-l);
  background: var(--bg);
  border-bottom: 1px solid var(--line);
}
.doc-head__inner { width: var(--shell); margin-inline: auto; }
.doc-head__kicker {
  font-family: var(--font-display);
  font-weight: 500;
  color: var(--brand-deep);
  font-size: var(--step-0);
  margin-bottom: var(--space-2xs);
}
.doc-head__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--step-4);
  line-height: 1.1;
  letter-spacing: -0.012em;
  max-width: 18ch;
}
.doc-head__lead {
  margin-top: var(--space-m);
  max-width: 62ch;
  font-size: var(--step-1);
  line-height: 1.7;
  color: var(--ink-soft);
}

/* The document header rule: the one brand device on the page. A thin
   Picton line above the effective date, treated as a document stamp
   rather than decoration. */
.doc-head__meta {
  margin-top: var(--space-l);
  padding-top: var(--space-s);
  border-top: 2px solid var(--brand);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-m);
  align-items: baseline;
  font-size: var(--step--1);
  color: var(--ink-soft);
  /* The rule spans the header block rather than stopping at the lead's
     measure — a short rule reads as a truncation, not a document stamp. */
}
.doc-head__date {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--ink);
}

/* ---------- Body: contents rail + document ---------- */
.doc-body {
  padding-block: var(--space-xl) var(--space-2xl);
  background: var(--bg);
}
.doc-body__grid {
  width: var(--shell);
  margin-inline: auto;
  display: grid;
  /* minmax(0,...) rather than a bare 1fr: a grid track defaults to
     max-content, so any child that legitimately scrolls its own overflow
     (the template header-row previews) would otherwise stretch the track
     past the viewport and take the whole page sideways with it. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-l);
  align-items: start;
}
@media (min-width: 960px) {
  .doc-body__grid {
    grid-template-columns: 250px minmax(0, 1fr);
    gap: var(--space-xl);
  }
}

/* ---------- Contents rail ----------
   On wide screens it sticks alongside the document and tracks the
   reader's position. Below 960px it collapses into a <details> so it
   never eats the top of a phone screen. */
.doc-toc {
  font-size: var(--step--1);
}
@media (min-width: 960px) {
  .doc-toc {
    position: sticky;
    top: clamp(5.5rem, 11vh, 7rem);
    max-height: calc(100svh - clamp(8rem, 16vh, 10rem));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}
.doc-toc__summary {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-0);
  color: var(--ink);
  cursor: pointer;
  padding: var(--space-xs) 0;
  border-block: 1px solid var(--line);
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
}
.doc-toc__summary::-webkit-details-marker { display: none; }
.doc-toc__summary::after {
  content: "";
  width: 0.55em;
  height: 0.55em;
  border-right: 2px solid var(--brand-deep);
  border-bottom: 2px solid var(--brand-deep);
  transform: rotate(45deg) translateY(-0.12em);
  transition: transform 300ms var(--ease-out-quint);
  flex: none;
}
.doc-toc[open] .doc-toc__summary::after { transform: rotate(-135deg) translateY(-0.12em); }
@media (min-width: 960px) {
  /* Wide: always expanded, no disclosure affordance. */
  .doc-toc__summary {
    cursor: default;
    pointer-events: none;
    border-top: 0;
    border-bottom: 1px solid var(--line);
    margin-bottom: var(--space-s);
  }
  .doc-toc__summary::after { display: none; }
}
.doc-toc__list {
  list-style: none;
  padding: 0;
  margin-top: var(--space-s);
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
@media (min-width: 960px) { .doc-toc__list { margin-top: 0; } }
.doc-toc__link {
  display: block;
  padding: 0.42rem 0 0.42rem var(--space-s);
  color: var(--ink-soft);
  line-height: 1.45;
  border-left: 1px solid var(--line);
  transition: color 200ms ease, border-color 200ms ease;
}
.doc-toc__link:hover { color: var(--brand-deep); border-color: var(--brand); }
/* Below 960px the rail is a collapsed disclosure on a phone — it stops being
   a scannable sidebar and becomes the primary way to move around a long legal
   document by thumb. At 33px these were the smallest real targets on the site,
   so they open up to 44px where they're actually tapped. The desktop rail keeps
   its tighter rhythm, where a pointer makes the extra height unnecessary. */
@media (max-width: 959px) {
  .doc-toc__link {
    padding-block: 0.7rem;
    min-height: var(--tap);
    display: flex;
    align-items: center;
  }
}
/* Scroll-spy: the section currently being read. Colour + weight carry the
   state; the rail line thickens rather than growing a coloured stripe. */
.doc-toc__link[aria-current="true"] {
  color: var(--brand-deep);
  font-weight: 600;
  border-color: var(--brand);
}

/* ---------- The document itself ---------- */
.doc {
  max-width: 68ch;
}
.doc__section + .doc__section { margin-top: var(--space-xl); }
/* Fixed nav means anchor jumps must clear the bar. Any full-bleed fold that
   is also a contents-rail target needs this too — the deep fold's own top
   padding happens to clear the nav today, but that's coincidence, not intent. */
.doc__section,
.fold[id] { scroll-margin-top: clamp(5rem, 10vh, 7rem); }
.doc__h2 {
  font-size: var(--step-2);
  line-height: 1.14;
  color: var(--ink);
  padding-bottom: var(--space-2xs);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--space-m);
}
.doc__h3 {
  font-size: var(--step-1);
  font-weight: 600;
  line-height: 1.25;
  color: var(--ink);
  margin-top: var(--space-m);
  margin-bottom: var(--space-xs);
}
.doc p {
  color: var(--ink-soft);
  line-height: 1.75;
}
.doc p + p { margin-top: var(--space-s); }
.doc strong { color: var(--ink); font-weight: 600; }
.doc em { font-style: italic; color: var(--ink); }

.doc a:not(.doc-toc__link) {
  color: var(--brand-deep);
  border-bottom: 1px solid color-mix(in oklch, var(--brand-deep) 40%, transparent);
  padding-bottom: 1px;
  transition: color 200ms ease, border-color 200ms ease;
}
.doc a:not(.doc-toc__link):hover { color: var(--brand-deeper); border-color: var(--brand-deeper); }

/* Lists: brand dots for unordered, tabular numerals for ordered. Legal
   documents lean on lists heavily, so they get real rhythm rather than
   browser defaults. */
.doc ul, .doc ol {
  margin-top: var(--space-s);
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}
.doc ul li {
  position: relative;
  padding-left: 1.6rem;
  color: var(--ink-soft);
  line-height: 1.7;
}
.doc ul li::before {
  content: "";
  position: absolute;
  left: 0.15rem;
  top: 0.66em;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--brand);
}
.doc ol {
  counter-reset: doc-item;
}
.doc ol > li {
  counter-increment: doc-item;
  position: relative;
  padding-left: 2.1rem;
  color: var(--ink-soft);
  line-height: 1.7;
}
.doc ol > li::before {
  content: counter(doc-item) ".";
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-0);
  color: var(--brand-deep);
  font-variant-numeric: tabular-nums;
}
/* Nested list inside an ordered item (parental consent duties). */
.doc ol ul { margin-top: 0.55rem; gap: 0.45rem; }
.doc ol ul li { padding-left: 1.35rem; }
.doc ol ul li::before { width: 5px; height: 5px; top: 0.68em; background: var(--brand-deep); }

/* ---------- Address block ---------- */
.doc__address {
  margin-top: var(--space-m);
  padding: var(--space-m);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-style: normal;
  line-height: 1.8;
  color: var(--ink-soft);
}
.doc__address strong {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-0);
  margin-bottom: 0.2rem;
}

/* ---------- Disclaimer blocks ----------
   The source document sets its liability and warranty clauses in full
   caps — a wall of shouting on a brand whose whole promise is calm.
   We keep every word (it's legally load-bearing) but contain it: a
   quiet surface, slightly smaller, letter-spaced so caps stay legible,
   and colour that still clears 4.5:1. It reads as a formal notice
   rather than as the page raising its voice. */
.doc__legalese {
  margin-top: var(--space-m);
  padding: var(--space-m);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.doc__legalese p {
  font-size: var(--step--1);
  line-height: 1.85;
  letter-spacing: 0.015em;
  color: var(--ink-soft);
}
.doc__legalese p + p { margin-top: var(--space-s); }

/* A short caps clause inline in the body (the class-action waiver) gets the
   same containment without a box: stepped down and letter-spaced so a run of
   capitals mid-paragraph reads as a formal aside rather than shouting. */
.doc .caps {
  letter-spacing: 0.015em;
  font-size: 0.92em;
}

/* ---------- Safety callout ----------
   The one place a legal page should genuinely stop the reader: the
   diving safety disclaimer. Not a coloured side-stripe — a full
   bordered panel in the brand blue, earned by the content. */
.doc__safety {
  margin-top: var(--space-m);
  padding: var(--space-m);
  border: 1px solid color-mix(in oklch, var(--brand-deep) 45%, var(--line));
  border-radius: var(--radius);
  background: color-mix(in oklch, var(--brand) 6%, var(--bg));
}
.doc__safety .doc__h3:first-child { margin-top: 0; }

/* ---------- Cross-document footer link ---------- */
.doc__jump {
  margin-top: var(--space-xl);
  padding-top: var(--space-m);
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s) var(--space-m);
  align-items: baseline;
  font-size: var(--step-0);
  color: var(--ink-soft);
}
/* Standalone navigation at the foot of a legal document, not a link inside a
   sentence — so it takes the --tap floor like any other control. */
.doc__jump a {
  color: var(--brand-deep);
  font-family: var(--font-display);
  font-weight: 600;
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
}
.doc__jump a:hover { color: var(--brand-deeper); }

/* Reading a legal document should never be interrupted by motion. The
   reveal on these pages is a single quiet fade of the header; the body
   is present from the first frame. */
@media (prefers-reduced-motion: reduce) {
  .doc-toc__summary::after { transition: none; }
}

/* ============================================================
   CONTACT (/support)
   The page has no form: this is a static site, and a mailto that
   states plainly what happens next is more honest than a field
   that posts somewhere invisible. So the design does the work a
   form would have done — answer the common questions in place,
   then hand over one direct line with real expectations attached.
   Answers first, deep-water fold for the line itself.
   ============================================================ */

/* ---------- Answers ----------
   Not a card grid and not an accordion. Both hide the answer behind
   an interaction, which is the opposite of "faster than emailing".
   A definition list, fully open, with a hairline between beats:
   scannable questions, answers already there. */
/* The answers sit in the page's narrow shell, but the rules that separate
   them are the section's strongest horizontal line — when they stop short of
   the header above, the whole fold reads unresolved. Letting the list span
   the shell while the prose keeps its own measure fixes the alignment without
   stretching anything to an unreadable line length. */
.answers__list {
  margin: 0;
  border-top: 1px solid var(--line);
}
.answers .section-head { max-width: 34ch; }
@media (min-width: 700px) { .answers .section-head { max-width: 44ch; } }
.answer {
  padding-block: clamp(1.6rem, 3.2vw, 2.4rem);
  border-bottom: 1px solid var(--line);
}
/* Linked from the footers and the legal pages (#delete-data); the fixed nav
   would otherwise cover the question the reader just jumped to. */
.answer[id] { scroll-margin-top: clamp(5rem, 10vh, 7rem); }
.answer__q {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-1);
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-wrap: balance;
}
.answer__a {
  margin: var(--space-2xs) 0 0;
  max-width: 62ch;
}
.answer__a p {
  font-size: var(--step-0);
  line-height: 1.7;
  color: var(--ink-soft);
}
/* --brand-deep measures 4.29:1 on --surface — just under the 4.5 bar for
   body-size text, so inline answer links use the deeper step instead. */
.answer__a a {
  color: var(--brand-deeper);
  font-weight: 600;
  border-bottom: 1px solid color-mix(in oklch, var(--brand) 45%, transparent);
  transition: color 250ms ease, border-color 250ms ease;
}
.answer__a a:hover { color: var(--brand-deeper); border-bottom-color: var(--brand-deeper); }

/* ---------- The direct line ----------
   One deep-water fold, centred, holding a single address. This is the
   page's only real CTA, so it gets the whole viewport to itself. */
.reach__inner {
  text-align: center;
  max-width: 56ch;
  margin-inline: auto;
}
.reach__title {
  font-size: var(--step-3);
  line-height: 1.08;
  color: var(--deep-ink);
}
.reach__lead {
  margin-top: var(--space-s);
  font-size: var(--step-1);
  line-height: 1.68;
  color: var(--deep-ink-soft);
  text-wrap: pretty;
}

/* The address as the object of the fold: display type, not a button.
   A pill CTA would read as a signup; this reads as someone's address,
   which is what it is. The underline is drawn on hover from the centre. */
.reach__mail {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  margin-top: clamp(2rem, 4.5vh, 3rem);
  padding: 0.4em 0.2em;
}
.reach__mail-label {
  position: relative;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.35rem, 1rem + 2.1vw, 2.5rem);
  letter-spacing: -0.015em;
  line-height: 1.2;
  color: var(--deep-ink);
  /* Long address, narrow phone: break rather than overflow the fold. */
  overflow-wrap: anywhere;
  transition: color 300ms var(--ease-out-quint);
}
.reach__mail-label::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.14em;
  height: 1.5px;
  background: var(--brand);
  transform: scaleX(0.32);
  transform-origin: center;
  opacity: 0.55;
  transition: transform 500ms var(--ease-out-quint), opacity 400ms ease;
}
.reach__mail:hover .reach__mail-label { color: #fff; }
.reach__mail:hover .reach__mail-label::after { transform: scaleX(1); opacity: 1; }
.reach__mail-hint {
  font-size: var(--step--1);
  color: var(--deep-ink-soft);
  letter-spacing: 0.06em;
  opacity: 0.75;
}

/* What actually happens next — the reassurance a form's "we'll be in
   touch" normally fakes. Plain list, no icons, no cards. */
.reach__expect {
  list-style: none;
  padding: 0;
  margin: clamp(2.25rem, 5vh, 3.25rem) auto 0;
  max-width: 48ch;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding-top: var(--space-m);
  border-top: 1px solid oklch(0.97 0.008 230 / 0.16);
}
.reach__expect li {
  position: relative;
  padding-left: 1.5rem;
  font-size: var(--step-0);
  line-height: 1.6;
  color: var(--deep-ink-soft);
}
.reach__expect li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--brand);
  opacity: 0.9;
}

@media (prefers-reduced-motion: reduce) {
  .reach__mail-label::after { transition: none; }
}

/* ============================================================
   HELP (/help)
   Documentation, not marketing. Reuses the legal pages' doc
   system (paper-white, sticky contents rail, no photographic
   hero) because the visitor arrives mid-task and wants the
   template, not atmosphere.

   Two additions the legal pages didn't need: template download
   rows, and a field-type definition list. Both are content that
   people scan rather than read, so both are built to be scanned.
   ============================================================ */

/* ---------- Outbound link block ----------
   Used for the YouTube playlist and the support address. A link
   people are meant to actually leave on deserves more than an
   underlined run of body text, but a full button would overstate
   it against the page's quiet. A bordered block with a second
   line of context sits between the two. */
.doc__out {
  display: inline-flex;
  flex-direction: column;
  gap: 0.15rem;
  margin-top: var(--space-2xs);
  padding: var(--space-s) var(--space-m);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-1);
  color: var(--brand-deep);
  background: color-mix(in oklch, var(--brand) 5%, var(--bg));
  border: 1px solid color-mix(in oklch, var(--brand-deep) 32%, var(--line));
  border-radius: var(--radius);
  transition: background 220ms var(--ease-out-quint),
              border-color 220ms var(--ease-out-quint);
}
/* Override .doc a's underline treatment — this block carries its own frame. */
.doc a.doc__out { border-bottom: 1px solid color-mix(in oklch, var(--brand-deep) 32%, var(--line)); padding-bottom: var(--space-s); }
.doc a.doc__out:hover {
  background: color-mix(in oklch, var(--brand) 11%, var(--bg));
  border-color: var(--brand-deep);
  color: var(--brand-deeper);
}
.doc__out-note {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--step--1);
  color: var(--ink-soft);
}

/* ---------- Template downloads ----------
   Not a card grid: a stacked list of rows. Three items with
   unequal descriptions look wrong forced into equal-height cards,
   and the download action wants to sit at a predictable right
   edge on wide screens rather than floating at the bottom of a
   box. Rows also let the header-row preview run long without
   dictating the height of its neighbours. */
.tpl {
  list-style: none;
  padding: 0;
  margin-top: var(--space-m);
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}
/* The doc list styles add brand dots to every li — these rows aren't
   bullets, so opt out. */
.doc .tpl li { padding-left: 0; }
.doc .tpl li::before { content: none; }

.tpl__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  padding: var(--space-m);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color 220ms var(--ease-out-quint);
}
.tpl__item:hover { border-color: color-mix(in oklch, var(--brand) 55%, var(--line)); }
@media (min-width: 640px) {
  .tpl__item {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-m);
  }
}
.tpl__body { min-width: 0; }
.tpl__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-1);
  line-height: 1.2;
  color: var(--ink);
}
.tpl__what {
  margin-top: 0.35rem;
  max-width: 52ch;
  line-height: 1.65;
}
.doc .tpl__what { color: var(--ink-soft); }
.tpl__cols {
  margin-top: 0.5rem;
  font-size: var(--step--1);
}
.doc .tpl__cols { color: var(--ink-soft); }
.doc .tpl__cols strong { color: var(--ink); }

/* The real header row from the file. Scrolls inside its own box rather
   than pushing the page sideways on a phone. */
.tpl__peek {
  margin-top: 0.6rem;
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  padding-bottom: 0.15rem;
}
.tpl__peek code {
  display: block;
  width: max-content;
  max-width: none;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--ink-soft);
  white-space: nowrap;
}

.tpl__get {
  flex: none;
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.7rem 1.2rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-0);
  color: #fff;
  background: var(--brand-fill);
  border-radius: 999px;
  transition: background 220ms var(--ease-out-quint), transform 220ms var(--ease-out-quint);
}
/* Stacked (narrow): sit at the start under the description.
   Row (wide): centre against the row instead of riding its top edge. */
.tpl__get { align-self: flex-start; }
@media (min-width: 640px) {
  .tpl__get { align-self: center; }
}
/* .doc a:not(.doc-toc__link) sets a blue link colour at higher specificity
   than .tpl__get — on a blue pill that lands as blue-on-blue. Restate the
   colour at matching specificity rather than reaching for !important. */
.doc a.tpl__get { color: #fff; border-bottom: none; padding-bottom: 0.7rem; }
.doc a.tpl__get:hover { background: var(--brand-deeper); color: #fff; transform: translateY(-1px); }
.tpl__ext {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 0.72em;
  letter-spacing: 0.04em;
  opacity: 0.75;
}

/* ---------- Field types ----------
   Four definitions. A two-column dl on wide screens so the terms
   line up and the eye can jump straight to the one it needs. */
.ftype {
  margin-top: var(--space-m);
  border-top: 1px solid var(--line);
}
.ftype__row {
  display: grid;
  gap: 0.2rem var(--space-m);
  padding-block: var(--space-s);
  border-bottom: 1px solid var(--line);
}
@media (min-width: 560px) {
  .ftype__row {
    grid-template-columns: 7.5rem minmax(0, 1fr);
    align-items: baseline;
  }
}
.ftype__term {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-0);
  color: var(--ink);
}
.ftype__def {
  margin: 0;
  color: var(--ink-soft);
  line-height: 1.7;
}
.ftype__def strong { color: var(--ink); font-weight: 600; }
/* The literal value, shown as a value rather than described as one. */
.ftype__eg {
  display: inline-block;
  margin-left: 0.15rem;
  padding: 0.05rem 0.5rem;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.82em;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
}
/* Boolean's capitalisation trap: the quietest of the four failures,
   so it gets a line of its own rather than a clause. */
.ftype__warn {
  display: block;
  margin-top: 0.4rem;
  font-size: var(--step--1);
  color: var(--brand-deeper);
}

/* ---------- Before you upload ----------
   The five tips, promoted onto the deep fold. These are the real
   failure modes, and on the live site they sat last. Numbered
   because this genuinely is a checklist you run top to bottom —
   not decorative section numbering. */
.tips {
  list-style: none;
  padding: 0;
  margin: 0;
  counter-reset: tip;
  display: grid;
  /* start, not stretch: these are five short notes of unequal length, and
     stretching each to its row's tallest sibling leaves visible dead space
     under the short ones. */
  align-items: start;
  gap: var(--space-m);
}
@media (min-width: 720px) {
  .tips { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-m) var(--space-l); }
  /* Five items over two columns: the last spans both rather than
     leaving a lonely half-width item against dead space. */
  .tips__item:last-child { grid-column: 1 / -1; }
}
@media (min-width: 1040px) {
  .tips { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .tips__item:last-child { grid-column: auto; }
}
.tips__item {
  counter-increment: tip;
  position: relative;
  padding-top: var(--space-s);
  border-top: 1px solid color-mix(in oklch, var(--deep-ink) 22%, transparent);
}
.tips__item::before {
  content: counter(tip);
  display: block;
  margin-bottom: 0.45rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
  color: var(--brand);
}
.tips__h {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-1);
  line-height: 1.25;
  color: var(--deep-ink);
}
.tips__p {
  margin-top: 0.5rem;
  max-width: 42ch;
  /* Light type on deep water reads lighter than it is: +0.06 line-height. */
  line-height: 1.76;
  color: var(--deep-ink-soft);
}

/* ---------- Tail block ----------
   The "still stuck" section returns to paper-white after the deep
   fold. No contents rail beside it — the rail belongs to the body
   above, and a second empty column here would read as a mistake. */
.doc-body--tail { padding-block: var(--space-xl) var(--space-2xl); }
@media (min-width: 960px) {
  .doc-body__grid--single { grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
  .tpl__item,
  .tpl__get,
  .doc__out { transition: none; }
  .doc a.tpl__get:hover { transform: none; }
}


/* ---------- Contact page: closing fold ----------
   This page reuses the turtle photograph, and the background behind the
   centred copy CHANGES AS YOU SCROLL — the fold is parallaxed, so the reef
   drifts through the text column. Measured per-glyph, the Picton-blue payoff
   line lands anywhere from 5.1:1 down to 1.6:1 depending on scroll position:
   bright sunlit water and the pale shell pass through behind it. Contrast
   that depends on where you stopped scrolling is not contrast that passes.
   A plume of depth sized to the text column (the hero's device) holds the
   background dark through the whole parallax travel, so the brand blue stays
   the brand blue. Scoped to this page — the story page pairs different copy
   with this image and measures clean. */
.page-contact .closing__scrim {
  background:
    radial-gradient(62% 52% at 50% 46%,
      oklch(0.10 0.04 246 / 0.78) 0%,
      oklch(0.11 0.04 246 / 0.66) 42%,
      oklch(0.12 0.04 246 / 0.36) 70%,
      transparent 88%),
    linear-gradient(180deg, oklch(0.14 0.04 245 / 0.55), oklch(0.16 0.04 248 / 0.4) 50%, oklch(0.13 0.04 250 / 0.72));
}
.page-contact .closing__title,
.page-contact .closing__lead {
  text-shadow: 0 1px 16px oklch(0.11 0.04 246 / 0.7);
}


/* ============================================================
   BLOG
   ============================================================
   The live Squarespace blog is a vertical stack of identical cards:
   header image, author, date, title, excerpt, "Read More" — four times.
   That's the card-grid reflex the brand bans, and with only four posts
   it wastes the one thing this blog actually has: four genuinely good
   photographs and four first-person stories.

   So the index is a reading list ordered by descent, not a grid. The
   newest post takes a full-bleed featured fold (the photograph IS the
   design); the remaining three become wide entries where image and type
   share a row, alternating side so the eye zig-zags down the page
   instead of scanning a column of equal rectangles.

   Posts themselves are stories, not documents. They deliberately do NOT
   reuse the /help + /legal doc system (paper-white, contents rail) —
   nobody needs a table of contents for an 800-word story. They echo
   the-story.html instead: photographic hero, narrow measure, real prose
   rhythm, signed at the end. */

/* ---------- Index: featured post ---------- */
.feat {
  position: relative;
  min-height: min(86svh, 760px);
  display: grid;
  align-items: end;
  overflow: hidden;
  isolation: isolate;
  color: var(--deep-ink);
}
.feat__bg { position: absolute; inset: -8% 0 0 0; height: 116%; z-index: -2; will-change: transform; }
/* The parallax layer wraps a .media blur-up div, which is what actually
   contains the <img>. Without giving that wrapper the full height the
   image can only be as tall as its own aspect ratio allows, so cover
   never fills — measured 476px of image inside an 812px hero on tablet,
   222px on a phone, leaving bare background below the photograph. */
.feat__bg .media { height: 100%; }
.feat__bg img { width: 100%; height: 100%; object-fit: cover; }
/* The headline sits bottom-left over open water. The scrim is weighted to
   that corner rather than applied flat, so the top of the photograph stays
   bright and only the type's own ground goes dark. Measured on the actual
   crop: title 14.8:1, meta 8.9:1. */
.feat__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    /* A plume of depth over the text column. The left-side wash alone measured
       3.13:1 on the title — this pool photograph is the brightest asset on the
       site and the headline crosses its lit centre. Anchored left so the open
       water on the right stays bright. */
    /* Tight to the text column. An earlier, wider version passed contrast but
       flattened the whole photograph into a grey wash — and this image's job
       is to look like sunlit vacation. Pulling the plume in and letting the
       right two-thirds run clear keeps the pool bright while the headline
       still measures 9.35:1. */
    radial-gradient(ellipse 62% 58% at 24% 62%,
      oklch(0.10 0.04 246 / 0.86) 0%,
      oklch(0.11 0.04 246 / 0.72) 46%,
      oklch(0.12 0.04 246 / 0.34) 74%,
      transparent 100%),
    linear-gradient(to top,
      oklch(0.13 0.04 246 / 0.78) 0%,
      oklch(0.14 0.04 246 / 0.56) 26%,
      oklch(0.16 0.04 248 / 0.24) 56%,
      transparent 100%),
    linear-gradient(to right,
      oklch(0.12 0.04 246 / 0.62), transparent 70%);
}
.feat__title,
.feat__kicker,
.feat__excerpt,
.feat__meta { text-shadow: 0 1px 18px oklch(0.10 0.04 246 / 0.62); }
.feat__inner {
  width: var(--shell);
  margin-inline: auto;
  padding-block: var(--space-xl) var(--space-l);
}
/* The headline column grows with the viewport instead of sitting at a fixed
   30ch. Locked at 30ch it measured 331px on every screen from a phone to a
   1920 desktop — so on a wide monitor the title crammed into four short lines
   against the left edge while 1200px of shell sat empty beside it. It now
   scales to roughly half the shell, capped at 22ch so it still reads as a
   headline block against the photograph rather than a full-width banner. */
.feat__body { width: min(100%, 46ch); }
@media (min-width: 1100px) {
  .feat__body { width: min(52%, 34rem); }
}
/* Same reasoning as .post-hero__kicker — brand blue fails on small type
   over bright water (measured 1.54:1 here, the worst of any surface). */
.feat__kicker {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-0);
  color: var(--deep-ink);
  letter-spacing: 0.01em;
  margin-bottom: var(--space-2xs);
}
.feat__title {
  font-size: var(--step-3);
  line-height: 1.06;
}
.feat__title a { display: block; }
/* The whole card is the click target, but only the title carries the
   underline — so hovering anywhere in the block still telegraphs the link
   without painting a hover state across the photograph. */
.feat__title a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}
.feat__excerpt {
  margin-top: var(--space-s);
  font-size: var(--step-1);
  line-height: 1.6;
  color: var(--deep-ink-soft);
  /* Sits inside .feat__body, which is now fluid; 42ch only bites on the
     widest screens so the standfirst stays a readable measure rather than
     stretching to the full headline width. */
  max-width: 42ch;
}
.feat__meta {
  margin-top: var(--space-s);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  font-size: var(--step--1);
  color: var(--deep-ink-soft);
}

/* ---------- Index: the reading list ---------- */
.posts { display: grid; gap: var(--space-xl); }

.post-item {
  position: relative;
  display: grid;
  gap: var(--space-m);
  align-items: center;
}
@media (min-width: 820px) {
  .post-item { grid-template-columns: 1.05fr 1fr; gap: var(--space-l); }
  /* Alternate which side the photograph lands on. Explicit column
     placement (not row-reverse) so the DOM order stays reading order
     for keyboard and screen readers. */
  .post-item:nth-child(even) .post-item__media { grid-column: 2; grid-row: 1; }
  .post-item:nth-child(even) .post-item__body  { grid-column: 1; grid-row: 1; }
}
.post-item__media {
  border-radius: var(--radius-lg);
  aspect-ratio: 3 / 2;
  box-shadow: 0 18px 50px oklch(0.3 0.03 240 / 0.12);
}
.post-item__media img {
  transition: transform 1200ms var(--ease-out-quint);
}
.post-item:hover .post-item__media img { transform: scale(1.035); }

.post-item__title {
  font-size: var(--step-2);
  line-height: 1.1;
}
.post-item__title a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}
.post-item__excerpt {
  margin-top: var(--space-s);
  color: var(--ink-soft);
  max-width: 46ch;
}
.post-item__meta {
  margin-top: var(--space-s);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  font-size: var(--step--1);
  color: var(--ink-soft);
}
/* "Read more" as a quiet directional cue rather than a button. Four
   buttons stacked down a page is the template look the brand rejects. */
.post-item__more {
  margin-top: var(--space-s);
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-weight: 600;
  color: var(--brand-deep);
}
.post-item__more .arrow { transition: transform 350ms var(--ease-out-quint); }
.post-item:hover .post-item__more .arrow { transform: translateX(4px); }

/* Shared byline dot. A middot between author and date, muted so it
   separates without competing. */
.byline-dot { opacity: 0.5; }

/* ---------- Post: hero ---------- */
.post-hero {
  position: relative;
  min-height: min(78svh, 700px);
  display: grid;
  align-items: end;
  overflow: hidden;
  isolation: isolate;
  color: var(--deep-ink);
}
.post-hero__bg { position: absolute; inset: -8% 0 0 0; height: 116%; z-index: -2; will-change: transform; }
/* The parallax layer wraps a .media blur-up div, which is what actually
   contains the <img>. Without giving that wrapper the full height the
   image can only be as tall as its own aspect ratio allows, so cover
   never fills — measured 476px of image inside an 812px hero on tablet,
   222px on a phone, leaving bare background below the photograph. */
.post-hero__bg .media { height: 100%; }
.post-hero__bg img { width: 100%; height: 100%; object-fit: cover; }
/* The title block sits low but not at the very bottom, and these photographs
   are BRIGHT — turquoise pool water, a sunrise, pale seagrass. A bottom-up
   gradient alone leaves the headline over the brightest part of the frame
   (measured 2.1:1 on the poolside crop). So the scrim is two layers: a plume
   of depth centred on the text block, plus the bottom-up wash for the meta
   row. Same device the landing hero and contact fold use. Measured after:
   title 12.4:1, kicker 5.9:1, meta 7.8:1 on the worst of the four crops. */
.post-hero__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    /* Both layers run all the way to `transparent 100%`. Stopping a gradient
       short (…transparent 88%) leaves a hard edge where the last stop lands,
       which showed as a grey band cutting across the photograph on tall
       viewports — the percentages resolve against the box, so a phone put
       that edge right through the middle of the image. */
    radial-gradient(ellipse 92% 66% at 50% 76%,
      oklch(0.11 0.04 246 / 0.88) 0%,
      oklch(0.12 0.04 246 / 0.76) 40%,
      oklch(0.13 0.04 246 / 0.38) 74%,
      transparent 100%),
    linear-gradient(to top,
      oklch(0.12 0.04 246 / 0.9) 0%,
      oklch(0.13 0.04 246 / 0.68) 30%,
      oklch(0.16 0.04 248 / 0.32) 60%,
      transparent 100%);
}
.post-hero__title,
.post-hero__kicker,
.post-hero__meta { text-shadow: 0 1px 18px oklch(0.11 0.04 246 / 0.6); }
.post-hero__inner {
  width: var(--shell-narrow);
  margin-inline: auto;
  padding-block: var(--space-xl) var(--space-l);
}
/* The kicker is the one element that can't be solved by the scrim: it's small
   text, it sits highest in the block (where the plume is weakest), and Picton
   Blue is a LIGHT blue — measured 1.5–4.0:1 across the four photographs, it
   failed on all of them. Brand colour on small type over bright water is a
   contrast trap, so the kicker is set in off-white like the rest of the block
   and keeps its brand identity through the family and weight instead. The blue
   still leads every section header on the paper-white folds, where it passes. */
.post-hero__kicker {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-0);
  color: var(--deep-ink);
  letter-spacing: 0.01em;
  margin-bottom: var(--space-2xs);
}
.post-hero__title {
  font-size: var(--step-4);
  line-height: 1.05;
}
.post-hero__meta {
  margin-top: var(--space-m);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  font-size: var(--step--1);
  color: var(--deep-ink-soft);
}

/* ---------- Post: body ---------- */
.post-body { padding-block: var(--space-xl) var(--space-l); }

/* The reading column. 62ch keeps the line length inside the 65–75ch cap
   with Mulish's generous x-height, and the type steps up one size from
   default body — these are stories read start to finish, not scanned. */
.post-prose {
  width: min(62ch, 90vw);
  margin-inline: auto;
}
.post-prose > p {
  font-size: var(--step-1);
  line-height: 1.72;
  color: var(--ink-soft);
}
.post-prose > p + p { margin-top: var(--space-s); }
.post-prose strong { color: var(--ink); font-weight: 600; }
.post-prose em { font-style: italic; color: var(--ink); }

/* The opening paragraph carries the reader in from the photograph, so it
   holds full ink and a touch more size — a standfirst that emerges from
   the body copy rather than a separate styled block. */
.post-prose > p:first-of-type {
  font-size: var(--step-2);
  line-height: 1.5;
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: -0.005em;
}

.post-prose h2 {
  margin-top: var(--space-l);
  margin-bottom: var(--space-s);
  font-size: var(--step-2);
  color: var(--ink);
}
.post-prose h3 {
  margin-top: var(--space-m);
  margin-bottom: var(--space-2xs);
  font-size: var(--step-1);
  color: var(--ink);
}
.post-prose h3 + p { margin-top: 0; }

.post-prose a:not(.btn) {
  color: var(--brand-deep);
  border-bottom: 1px solid color-mix(in oklch, var(--brand) 55%, transparent);
  transition: color 200ms ease, border-color 200ms ease;
}
.post-prose a:not(.btn):hover { color: var(--brand-deeper); border-color: var(--brand-deeper); }

/* A numbered practice list. The numbers are real sequence (the three
   things that fixed the anxiety, in order), not the 01/02/03 eyebrow
   scaffolding the brand bans — they're set inline with the heading
   they number, at heading size, so they read as list structure. */
.post-steps {
  list-style: none;
  padding: 0;
  margin: var(--space-l) 0 0;
  counter-reset: step;
  display: grid;
  gap: var(--space-m);
}
.post-steps > li {
  counter-increment: step;
  padding-left: 2.6rem;
  position: relative;
}
.post-steps > li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 0.06em;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--step-1);
  color: var(--brand-deep);
  font-variant-numeric: tabular-nums;
}
.post-steps h3 { margin-top: 0; }
/* The step bodies step down from the surrounding prose (which runs at
   step-1) so the three practices read as a set inside the story rather
   than as three more paragraphs of it — but not so far down that they
   become fine print. */
.post-steps p {
  margin-top: var(--space-2xs);
  font-size: var(--step-0);
  color: var(--ink-soft);
  line-height: 1.72;
}

/* ---------- Post: pull moment ----------
   One line per post gets lifted out of the column: the sentence the story
   turns on. Quicksand, brand-deep, no quote marks or side rule — the size
   change and the space around it carry the emphasis. */
/* The sentence the story turns on. It has to out-weigh the body around it
   without a quote mark or a side rule (banned) doing the work, so it gets
   size, the display face, and — most of all — space: it breaks the column's
   rhythm by sitting alone with a full band of air on either side. */
.post-pull {
  margin: var(--space-xl) 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--step-3);
  line-height: 1.22;
  letter-spacing: -0.015em;
  color: var(--brand-deeper);
  text-wrap: balance;
}

/* ---------- Post: signature ---------- */
.post-sign {
  margin-top: var(--space-l);
  padding-top: var(--space-m);
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: var(--space-s);
}
.post-sign__portrait {
  width: 62px;
  height: 62px;
  border-radius: 999px;
  flex: none;
  overflow: hidden;
  background: var(--surface);
}
.post-sign__portrait img { width: 100%; height: 100%; object-fit: cover; }
.post-sign__name {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--step-1);
  color: var(--ink);
}
.post-sign__role {
  margin-top: 0.1rem;
  font-size: var(--step--1);
  color: var(--ink-soft);
}

/* ---------- Post: next up ---------- */
.post-next { padding-block: var(--space-l) var(--space-xl); }
.post-next__inner { width: var(--shell-narrow); margin-inline: auto; }
.post-next__label {
  font-family: var(--font-display);
  font-weight: 500;
  color: var(--brand-deep);
  margin-bottom: var(--space-s);
}
.post-next__link {
  position: relative;
  display: grid;
  gap: var(--space-s);
  align-items: center;
}
@media (min-width: 620px) {
  .post-next__link { grid-template-columns: 150px 1fr; }
}
.post-next__media {
  border-radius: var(--radius);
  aspect-ratio: 3 / 2;
}
.post-next__title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--step-1);
  line-height: 1.2;
  color: var(--ink);
  text-wrap: balance;
}
.post-next__link:hover .post-next__title { color: var(--brand-deep); }
.post-next__meta {
  margin-top: 0.35rem;
  font-size: var(--step--1);
  color: var(--ink-soft);
}

@media (prefers-reduced-motion: reduce) {
  .post-item__media img,
  .post-item__more .arrow { transition: none; }
  .post-item:hover .post-item__media img { transform: none; }
  .post-item:hover .post-item__more .arrow { transform: none; }
}
