/* ==========================================================================
   BEACHBOX — DEFERRED STYLESHEET (Stage B critical-CSS split)
   --------------------------------------------------------------------------
   Everything below the first two viewports: the evidence stack + its
   scroll-driven machinery, How It Works, the Spec, Pricing, the Gallery,
   the poster, FAQ, Join, the Canvas, the App demo, and the footer.
   Loaded non-render-blocking from index.html (media=print + onload swap;
   noscript fallback). ORDER MATTERS: these blocks keep their original
   relative order, and the Reduced-motion block is REPEATED at the end so
   its non-!important overrides still win the cascade against the base
   rules in this later-loaded file. Giuseppe: colors still live at the
   top of styles.css.
   ========================================================================== */

/* the evidence stack's display face — grade 20 everywhere (the /type-test
   verdict: clean at both clipping sizes; grade 35 on the lead is DEFERRED
   until it can be phone-checked). Declared HERE, not in styles.css, so the
   68KB file is discovered late and never competes with the hero image
   (moving it into the critical sheet cost the LCP ~500ms, A/B-measured). */
@font-face {
  font-family: 'Redaction 20';
  src: url('../fonts/Redaction20-Bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
/* A5.8b: grade 35 carries the LEAD headline only (Latin subset, 18KB) */
@font-face {
  font-family: 'Redaction 35';
  src: url('../fonts/Redaction35-Bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ==========================================================================
   The evidence (The Problem) — published headlines fall into a stack
   --------------------------------------------------------------------------
   The lead clipping is the only in-flow child (the container auto-sizes to
   it); the four under-papers are absolutely positioned layers that fan UP
   into headroom reserved by padding-top, each showing its dateline +
   headline strip above the paper stacked over it. The drop animates
   transform/opacity only, from-only keyframes, landing on each paper's
   resting rotation. --strip is the per-paper reveal height.
   ========================================================================== */
.press-stack {
  /* Stage B: Redaction 20 wraps taller than the old condensed display
     face — 6rem buried p5 19px and p3 14px at ≥768 (harness-measured).
     Strips are sized to the SERIF's wrap count now. */
  --strip: 6.2rem;
  /* visible height of the data-gap note before the pile overlaps it.
     A4.0: was 8.4rem, which buried the memo's last text line ~7px
     under p5 at desktop widths — only the blank bottom padding is
     sacrificial, never a line of text */
  --note-strip: 9.5rem;
  position: relative;
  max-width: 44rem;
  /* auto inline margins: the section column runs to 72rem at laptop
     widths and the 44rem pile was riding its left edge (448px of dead
     sand on the right at 1280-1600) */
  margin: var(--space-6) auto 0;
  padding-top: calc(var(--strip) * 4 + var(--note-strip));
}

/* OURS, at the bottom of the pile: the data-gap note the press stacks
   onto. A typewritten memo on manila — deliberately not journalism.
   Not linked, nothing highlighted. Its bottom padding is the
   sacrificial zone the first clipping lands on. */
.press-note {
  position: absolute;
  top: 0;
  left: 1%;
  right: 2%;
  z-index: 0;
  background: #F2E8C6;
  border: 1px solid rgba(34, 38, 46, 0.35);
  padding: 0.7rem 0.95rem 2.4rem;
  --rot: -1.3deg;
  --fall: -5deg;
  transform: rotate(var(--rot));
  box-shadow:
    0 2px 5px rgba(8, 6, 4, 0.4),
    0 16px 30px rgba(8, 6, 4, 0.45); /* A6: desk-dark, not sand-warm */
  font-family: var(--font-ui);
}
.press-note__tag {
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 0.3rem;
}
.press-note__text {
  font-size: var(--text-xs);
  line-height: 1.55;
  color: var(--ink);
}

.press {
  /* newsprint: warm paper + a whisper of scanline tooth (CSS only).
     Explicit ink: the desk section around the pile is light-on-dark
     now, and the deck was inheriting bone onto newsprint (invisible). */
  color: var(--ink);
  background:
    repeating-linear-gradient(0deg, rgba(34, 38, 46, 0.03) 0 1px, transparent 1px 3px),
    #F8F4E9;
  border: 1px solid rgba(34, 38, 46, 0.22);
  padding: 0.85rem 1.1rem 1.05rem;
  transform: rotate(var(--rot, 0deg));
  /* contact + ambient, tinted toward the sand the pile lies on */
  box-shadow:
    0 2px 5px rgba(8, 6, 4, 0.4),
    0 16px 30px rgba(8, 6, 4, 0.45); /* A6: desk-dark, not sand-warm */
}

.press--lead {
  position: relative;
  z-index: 5;
  --rot: -1deg;
  --fall: -3deg;
  /* the stamp (~180px tall incl. rotation) may only ever cover blank
     paper: reserve a bottom margin on the page below the stripes so it
     never rides up into the deck text (bug: it did, 375–1024) */
  padding-bottom: 7rem;
}
.press--u    { position: absolute; }
.press--2 { top: calc(var(--strip) * 3 + var(--note-strip)); left: 3%; right: 2%; z-index: 4; --rot:  1.6deg; --fall:  4deg; }
.press--3 { top: calc(var(--strip) * 2 + var(--note-strip)); left: 1%; right: 4%; z-index: 3; --rot: -1.9deg; --fall: -7deg; }
.press--4 { top: calc(var(--strip) * 1 + var(--note-strip)); left: 4%; right: 1%; z-index: 2; --rot:  2.1deg; --fall:  5deg; }
.press--5 { top: var(--note-strip);                          left: 2%; right: 3%; z-index: 1; --rot: -2.3deg; --fall: -6deg; }

.press__folio {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(34, 38, 46, 0.75);
  border-bottom: 2px solid var(--ink);
  padding-bottom: 0.3rem;
  margin-bottom: 0.5rem;
}
.press__folio cite { font-style: normal; color: var(--ink); white-space: nowrap; }
/* the lead carries two cites: the story and the sentencing */
.press__cites {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.15rem 0.9rem;
}
/* the attributions are real links to the real articles — restrained
   affordance (an underline, not a button), 44px+ hit area via ::after */
.press__folio cite a {
  position: relative;
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(34, 38, 46, 0.45);
  text-underline-offset: 2px;
  transition: text-decoration-color 0.15s var(--ease-out);
}
.press__folio cite a:hover,
.press__folio cite a:focus-visible { text-decoration-color: var(--pacific); }
.press__folio cite a::after {
  content: "";
  position: absolute;
  inset: -0.9rem -0.5rem;
}

/* Stage B: the evidence register — Redaction Bold, the paper-of-record
   serif off /type-test. A5.0: clipping type is sized like a newspaper
   HELD IN THE HAND, not poster type — the old scale filled a phone
   screen with one headline fragment. Mechanism: type scale (the card
   already spans the right width; a transform would blur nothing but
   would entangle the scroll-timeline geometry for no gain).
   GEOMETRY NOTE: strip heights are re-measured against these sizes. */
.press__headline {
  font-family: var(--font-press);
  font-weight: 700;
  font-size: var(--text-sm);
  line-height: 1.22;
  letter-spacing: 0;
  color: var(--ink);
}
/* A5.8b: grade 35 on the single lead headline only (founder-approved
   after the phone check of grade 20) — every other clipping stays 20 */
.press--lead .press__headline {
  font-family: var(--font-press-lead, var(--font-press));
  font-size: clamp(1.05rem, 2.1vw, 1.35rem); /* per-composition display clamp */
  line-height: 1.18;
  letter-spacing: 0;
}
/* the standfirst under the lead headline — plain type, no emphasis */
.press__deck {
  margin-top: 0.45rem;
  font-weight: 600;
  font-size: var(--text-xs);
  line-height: 1.4;
}

/* A5.2: the reader's pen — a second, quieter emphasis channel under the
   marker highlights. Hand-drawn ink underline (data-URI stroke with a
   slight wobble), never on marked words, no third color. Static on
   purpose: the marks draw in, the pen is just already there. */
.press u.pen {
  text-decoration: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='90' height='5' viewBox='0 0 90 5'%3E%3Cpath d='M1 3.2 C14 2.1 26 3.9 40 2.9 C54 2 66 3.8 79 2.7 L89 3.1' fill='none' stroke='%2322262E' stroke-width='1.7' stroke-linecap='round' opacity='0.85'/%3E%3C/svg%3E");
  background-repeat: repeat-x;
  background-position: 0 100%;
  background-size: 90px 5px;
  padding-bottom: 0.12em;
}

/* marker highlights — four on the whole page, press cards only.
   A skewed, slightly rotated stroke with soft ends; warm palette
   yellow (from the seawall art), never raw #FFFF00. */
mark.hl {
  background: transparent;
  color: inherit;
  position: relative;
  z-index: 0;
}
mark.hl::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: -0.24em;
  right: -0.12em;
  top: 0.04em;
  bottom: -0.08em;
  background: linear-gradient(97deg,
    rgba(255, 210, 63, 0)    0%,
    rgba(255, 210, 63, 0.55) 5%,
    rgba(255, 199, 44, 0.68) 46%,
    rgba(255, 210, 63, 0.5)  95%,
    rgba(255, 210, 63, 0)    100%);
  border-radius: 0.4em 0.55em 0.35em 0.6em / 0.55em 0.35em 0.6em 0.4em;
  transform: rotate(-1.2deg) skewX(-9deg);
  transform-origin: 0 50%;
}

/* abstract column stripes — suggests body text without faking any */
.press__body { display: grid; grid-template-columns: 2fr 1fr; gap: 0.8rem; margin-top: 0.7rem; }
.press__body i {
  display: block;
  height: 3rem;
  background: repeating-linear-gradient(180deg, rgba(34, 38, 46, 0.13) 0 2px, transparent 2px 7px);
}
.press--lead .press__body i { height: 4.4rem; }

/* ours — a rubber stamp over the pile, deliberately not journalism */
.press-stamp {
  position: absolute;
  z-index: 6;
  right: -0.5rem;
  bottom: -1.4rem;
  max-width: 19rem;
  padding: 0.65rem 0.9rem;
  color: var(--alert);
  background: #FDFBF5;          /* solid for deterministic contrast… */
  mix-blend-mode: multiply;     /* …that melts into the papers below */
  border: 3px solid currentColor;
  border-radius: 6px;
  --rot: -6.5deg;
  transform: rotate(var(--rot));
  font-family: var(--font-ui);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.press-stamp__tag { font-size: var(--text-2xs); margin-bottom: 0.2rem; }
.press-stamp__line { font-size: var(--text-xs); line-height: 1.45; }
.press-stamp__line strong { font-size: var(--text-md); font-weight: 700; }
.press-stamp__src { font-size: var(--text-2xs); margin-top: 0.3rem; letter-spacing: 0.05em; }

/* the drop — hidden pre-trigger only when JS is around to trigger it.
   The data-gap note lands FIRST (the pile stacks onto the absence),
   papers follow at ~85ms stagger, the lead lands last, the stamp
   thumps, and the marker strokes draw in after their papers settle.
   Whole sequence ends at ~1.17s. */
.js .press, .js .press-note, .js .press-stamp { opacity: 0; }
.js .press-stack.is-dropped .press,
.js .press-stack.is-dropped .press-note {
  opacity: 1;
  animation: press-fall 0.38s var(--ease-out) var(--drop, 0ms) backwards;
}
.press-note    { --drop: 0ms; }
.press--5      { --drop: 90ms;  --hl-delay: 0.2s; }
.press--4      { --drop: 175ms; }
.press--3      { --drop: 260ms; --hl-delay: 0.38s; }
.press--2      { --drop: 345ms; }
.press--lead   { --drop: 470ms; --hl-delay: 0.58s; }
.js .press-stack.is-dropped .press--lead {
  animation-name: press-fall-lead;
  animation-duration: 0.4s;
}
.js .press-stack.is-dropped .press-stamp {
  opacity: 1;
  animation: stamp-in 0.26s var(--ease-out) 0.91s backwards;
}
/* marker stroke draws left-to-right while its paper is still falling,
   finishing at or just before touchdown — the yellow catches the eye
   as the pile builds, not after */
.js .press-stack.is-dropped mark.hl::before {
  animation: hl-draw 0.2s var(--ease-out) var(--hl-delay, 1s) backwards;
}
@keyframes hl-draw {
  from { transform: rotate(-1.2deg) skewX(-9deg) scaleX(0); }
}
/* from-only: each paper lands on its own resting rotation; the 84% frame
   is the overshoot — weight, not bounce. A6: papers slide UP the desk
   from the bottom of the frame (no scale — it blurred on phones). */
@keyframes press-fall {
  from { transform: translate3d(0, 12rem, 0) rotate(calc(var(--rot, 0deg) - var(--fall, -6deg) / 2)); opacity: 0; }
  55%  { opacity: 1; }
  84%  { transform: translate3d(0, -0.35rem, 0) rotate(calc(var(--rot, 0deg) + 0.4deg)); }
}
@keyframes press-fall-lead {
  from { transform: translate3d(0, 14rem, 0) rotate(calc(var(--rot) - var(--fall) / 2)); opacity: 0; }
  55%  { opacity: 1; }
  84%  { transform: translate3d(0, -0.45rem, 0) rotate(calc(var(--rot) + 0.3deg)); }
}
@keyframes stamp-in {
  from { transform: rotate(var(--rot)) scale(1.7); opacity: 0; }
  70%  { opacity: 1; }
}

@media (max-width: 700px) {
  /* near-vertical: a fanned stack is unreadable at 375px.
     A5.0: hand-scale newsprint — headline sizes drop to what a paper
     actually looks like held in the hand, card chrome tightens, and
     the strips are re-measured to the NEW wrap counts (harness).
     Reveals must always fit whole clippings. */
  .press-stack { --strip: 5.5rem; --note-strip: 10rem; }
  .press__headline { font-size: 0.82rem; }
  .press--lead .press__headline { font-size: 1.02rem; }
  .press__folio { font-size: 0.62rem; }
  .press__deck { font-size: 0.78rem; }
  .press-note__text { font-size: 0.72rem; line-height: 1.5; }
  .press { padding: 0.7rem 0.85rem 0.9rem; }
  .press--lead { padding-bottom: 6.6rem; } /* stamp landing zone — A0-sampled */
  .press__body i { height: 2.2rem; }
  .press--lead .press__body i { height: 3.2rem; }
  .press__folio > span:first-child { display: none; } /* keep the cites; drop the furniture (the lead's .press__cites wrapper is the 2nd span) */
  .press--lead { --rot: -0.5deg; }
  .press--2 { --rot:  0.8deg; left: 1.5%; right: 0.5%; }
  .press--3 { --rot: -1.1deg; left: 0.5%; right: 1.5%; }
  .press--4 { --rot:  1.2deg; left: 1.5%; right: 0; }
  .press--5 { --rot: -1.4deg; left: 0;    right: 1%; }
  .press-note { --rot: -0.7deg; left: 0.5%; right: 1%; }
  .press-stamp { right: -0.25rem; bottom: -1.1rem; max-width: 15.5rem; }

  /* A7: phones run the time-driven drop (the scroll-driven pile is
     >=701px only) — and the slide is SHORT here: 12rem of travel had a
     card overlapping two neighbors mid-flight on a small screen. */
  @keyframes press-fall {
    from { transform: translate3d(0, 4.5rem, 0) rotate(calc(var(--rot, 0deg) - var(--fall, -6deg) / 3)); opacity: 0; }
    55%  { opacity: 1; }
    84%  { transform: translate3d(0, -0.25rem, 0) rotate(calc(var(--rot, 0deg) + 0.4deg)); }
  }
  @keyframes press-fall-lead {
    from { transform: translate3d(0, 5.5rem, 0) rotate(calc(var(--rot) - var(--fall) / 3)); opacity: 0; }
    55%  { opacity: 1; }
    84%  { transform: translate3d(0, -0.3rem, 0) rotate(calc(var(--rot) + 0.3deg)); }
  }
}

/* the clip frame, at BASE for every width and path (A7): the IO
   stamp scale-in overhangs ~87px at 375 mid-animation without it
   (never clip the stack itself: Safari lacks overflow-clip-margin) */
#problem .section__inner { overflow-x: clip; }

/* ==========================================================================
   Scroll-driven stack (Stage A2) — where the browser supports scroll
   timelines, the pile is a pure function of scroll position on ONE named
   view timeline with two working ranges:
     ENTRY (cover 8-64%) — A5.1: shifted +6 so the pile builds at/just above vertical center: papers DOMINO in from above — strictly
       sequential (each slice opens as the previous paper touches down),
       falling with a tumble that resolves into the resting fan, an
       overshoot-and-settle landing, and a ~1px reaction through the pile
       beneath on every touchdown. The stamp hits last; the pile recoils
       2px under it. The marker strokes draw DURING their paper's fall,
       finishing just before touchdown.
     EXIT (named exit range): as the section leaves the top of the
       viewport the papers sweep off left and right, alternating,
       slightly raised — additive animations, so there is no keyframe
       swap at any progress value and nothing can snap.
   No direction JS, no state machine: scrolling up plays the whole thing
   backward for free. The time-driven IO build above stays untouched as
   the fallback (Firefox et al.). Longhands on purpose: the animation
   shorthand resets animation-timeline/range. LITERAL keyframe values on
   purpose: var() inside keyframes forces scroll-linked animations onto
   the main thread (measured: +200ms TBT).
   ========================================================================== */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
  /* A7: the scroll-driven pile is DESKTOP/TABLET ONLY (>=701px).
     On phones the address-bar collapse resizes the viewport
     mid-scroll, the view-timeline ranges remap, and every paper
     snaps to a new progress value — the founder's thrice-reported
     "bugging/zooming as you scroll" that desktop testing can never
     reproduce. Phones use the time-driven IO drop below instead:
     one clean slide-up per visit, nothing coupled to scroll. */
  @media (min-width: 701px) {

    /* the clip frame: the section inner, so the stamp's small overhang
       on the stack itself survives (Safari has no overflow-clip-margin) */
    #problem .section__inner { overflow-x: clip; }

    .press-stack {
      view-timeline: --pile block;
      /* exit travel is min(96vw, 76rem), baked into the sweep
         keyframes below; papers are never wider than ~96vw so the
         clip frame absorbs the flight at every size */
    }

    /* cancel the time-driven gate — visibility is the timeline's job now */
    .js .press, .js .press-note, .js .press-stamp { opacity: 1; }

    /* three animations per paper: the fall (replace), the pile
       reaction (additive), the exit sweep (additive) */
    .js .press-stack .press,
    .js .press-stack.is-dropped .press,
    .js .press-stack .press-note,
    .js .press-stack.is-dropped .press-note {
      animation-duration: auto, auto, auto;
      animation-timing-function: linear, linear, linear;
      animation-delay: 0s, 0s, 0s;
      animation-fill-mode: both, both, both;
      animation-composition: replace, add, add;
      animation-timeline: --pile, --pile, --pile;
    }

    /* DOMINO SEQUENCE — each fall slice starts as the previous paper
       touches down (touchdown = 80% of the slice). Order: memo, 5, 4,
       3, 2, lead. Every nudge animation shares one range (cover 8-64%)
       so all the touchdown moments map to the same keyframe %.
       Sweep stagger peels the pile top-first on the exit range. */
    .js .press-stack .press-note,
    .js .press-stack.is-dropped .press-note   { animation-name: fall-note, nudge-note, sweep-left;  animation-range: cover 8% cover 16%,  cover 8% cover 64%, exit 62% exit 88%; }
    .js .press-stack .press--5,
    .js .press-stack.is-dropped .press--5     { animation-name: fall-5, nudge-5, sweep-right;       animation-range: cover 14% cover 22%, cover 8% cover 64%, exit 66% exit 90%; }
    .js .press-stack .press--4,
    .js .press-stack.is-dropped .press--4     { animation-name: fall-4, nudge-4, sweep-left;        animation-range: cover 21% cover 29%, cover 8% cover 64%, exit 70% exit 92%; }
    .js .press-stack .press--3,
    .js .press-stack.is-dropped .press--3     { animation-name: fall-3, nudge-3, sweep-right;       animation-range: cover 28% cover 36%, cover 8% cover 64%, exit 74% exit 94%; }
    .js .press-stack .press--2,
    .js .press-stack.is-dropped .press--2     { animation-name: fall-2, nudge-2, sweep-left;        animation-range: cover 35% cover 43%, cover 8% cover 64%, exit 78% exit 96%; }
    .js .press-stack .press--lead,
    .js .press-stack.is-dropped .press--lead  { animation-name: fall-lead, nudge-lead, sweep-right; animation-range: cover 42% cover 52%, cover 8% cover 64%, exit 82% exit 98%; }

    /* marker strokes draw during their paper's fall, done by touchdown */
    .js .press-stack mark.hl::before,
    .js .press-stack.is-dropped mark.hl::before {
      animation-name: hl-draw;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-delay: 0s;
      animation-fill-mode: both;
      animation-timeline: --pile;
    }
    .js .press-stack .press--5 mark.hl::before,
    .js .press-stack.is-dropped .press--5 mark.hl::before    { animation-range: cover 17.5% cover 21%; }
    .js .press-stack .press--3 mark.hl::before,
    .js .press-stack.is-dropped .press--3 mark.hl::before    { animation-range: cover 31.5% cover 35%; }
    .js .press-stack .press--lead mark.hl::before,
    .js .press-stack.is-dropped .press--lead mark.hl::before { animation-range: cover 45.5% cover 49.5%; }

    /* the stamp: hits once the pile is built. Ink bleeds in over the
       first slice; overshoot 1.06 presses through 0.985 and settles at
       1 (weight, not bounce). It rides the lead off on the exit. */
    .js .press-stack .press-stamp,
    .js .press-stack.is-dropped .press-stamp {
      animation-name: stamp-hit, sweep-right;
      animation-duration: auto, auto;
      animation-timing-function: linear, linear;
      animation-delay: 0s, 0s;
      animation-fill-mode: both, both;
      animation-composition: replace, add;
      animation-timeline: --pile, --pile;
      animation-range: cover 54% cover 64%, exit 82% exit 98%;
    }

    /* THE SLIDES (A6, founder-directed) — each paper SLIDES UP from the
       bottom of the frame onto the desk, like a page pushed across a
       table: no scale (the old mid-flight scale rasterized blurry on
       phones), a small rotation drift that resolves into the resting
       fan, a -0.35rem overshoot at 80%, implicit `to` = each paper's
       own base style so the landing is exact at every breakpoint.
       Scrolling up runs them back down the table for free.
       All values literal — see note above. */
    @keyframes fall-note {
      from { transform: translate3d(0, 12rem, 0) rotate(1.8deg); opacity: 0; }
      6%   { opacity: 1; } /* opaque almost immediately: any translucent frame ghost-blends this card's text with the strip beneath it (the A4.0 soup) */
      80%  { transform: translate3d(0, -0.35rem, 0) rotate(-0.9deg); }
    }
    @keyframes fall-5 {
      from { transform: translate3d(0, 12rem, 0) rotate(-4deg); opacity: 0; }
      6%   { opacity: 1; } /* opaque almost immediately: any translucent frame ghost-blends this card's text with the strip beneath it (the A4.0 soup) */
      80%  { transform: translate3d(0, -0.35rem, 0) rotate(-1.9deg); }
    }
    @keyframes fall-4 {
      from { transform: translate3d(0, 12rem, 0) rotate(4.4deg); opacity: 0; }
      6%   { opacity: 1; } /* opaque almost immediately: any translucent frame ghost-blends this card's text with the strip beneath it (the A4.0 soup) */
      80%  { transform: translate3d(0, -0.35rem, 0) rotate(2.5deg); }
    }
    @keyframes fall-3 {
      from { transform: translate3d(0, 12rem, 0) rotate(-4.6deg); opacity: 0; }
      6%   { opacity: 1; } /* opaque almost immediately: any translucent frame ghost-blends this card's text with the strip beneath it (the A4.0 soup) */
      80%  { transform: translate3d(0, -0.35rem, 0) rotate(-1.5deg); }
    }
    @keyframes fall-2 {
      from { transform: translate3d(0, 12rem, 0) rotate(3.6deg); opacity: 0; }
      6%   { opacity: 1; } /* opaque almost immediately: any translucent frame ghost-blends this card's text with the strip beneath it (the A4.0 soup) */
      80%  { transform: translate3d(0, -0.35rem, 0) rotate(2deg); }
    }
    @keyframes fall-lead {
      from { transform: translate3d(0, 14rem, 0) rotate(-2.4deg); opacity: 0; }
      6%   { opacity: 1; } /* opaque almost immediately: any translucent frame ghost-blends this card's text with the strip beneath it (the A4.0 soup) */
      80%  { transform: translate3d(0, -0.45rem, 0) rotate(-0.6deg); }
    }

    /* THE REACTIONS — additive 1px dips through the pile at every later
       touchdown, 2px under the stamp. One shared range (cover 8-64%),
       so the bump positions are the touchdown moments mapped once:
       p5 35.3%, p4 47.8%, p3 60.3%, p2 75.7%(2), lead 75.7%, stamp 95.3%.
       Explicit zero ends: additive keyframes must not inherit the base
       transform. */
    @keyframes nudge-note {
      0%, 21.1% { transform: translate3d(0, 0, 0); }
      22.8%     { transform: translate3d(0, 1px, 0); }
      25.5%, 33.6% { transform: translate3d(0, 0, 0); }
      35.3%     { transform: translate3d(0, 1px, 0); }
      38%, 46.1% { transform: translate3d(0, 0, 0); }
      47.8%     { transform: translate3d(0, 1px, 0); }
      50.5%, 58.6% { transform: translate3d(0, 0, 0); }
      60.3%     { transform: translate3d(0, 1px, 0); }
      63%, 74%  { transform: translate3d(0, 0, 0); }
      75.7%     { transform: translate3d(0, 1px, 0); }
      78.4%, 93.2% { transform: translate3d(0, 0, 0); }
      95.3%     { transform: translate3d(0, 2px, 0); }
      100%      { transform: translate3d(0, 0, 0); }
    }
    @keyframes nudge-5 {
      0%, 33.6% { transform: translate3d(0, 0, 0); }
      35.3%     { transform: translate3d(0, 1px, 0); }
      38%, 46.1% { transform: translate3d(0, 0, 0); }
      47.8%     { transform: translate3d(0, 1px, 0); }
      50.5%, 58.6% { transform: translate3d(0, 0, 0); }
      60.3%     { transform: translate3d(0, 1px, 0); }
      63%, 74%  { transform: translate3d(0, 0, 0); }
      75.7%     { transform: translate3d(0, 1px, 0); }
      78.4%, 93.2% { transform: translate3d(0, 0, 0); }
      95.3%     { transform: translate3d(0, 2px, 0); }
      100%      { transform: translate3d(0, 0, 0); }
    }
    @keyframes nudge-4 {
      0%, 46.1% { transform: translate3d(0, 0, 0); }
      47.8%     { transform: translate3d(0, 1px, 0); }
      50.5%, 58.6% { transform: translate3d(0, 0, 0); }
      60.3%     { transform: translate3d(0, 1px, 0); }
      63%, 74%  { transform: translate3d(0, 0, 0); }
      75.7%     { transform: translate3d(0, 1px, 0); }
      78.4%, 93.2% { transform: translate3d(0, 0, 0); }
      95.3%     { transform: translate3d(0, 2px, 0); }
      100%      { transform: translate3d(0, 0, 0); }
    }
    @keyframes nudge-3 {
      0%, 58.6% { transform: translate3d(0, 0, 0); }
      60.3%     { transform: translate3d(0, 1px, 0); }
      63%, 74%  { transform: translate3d(0, 0, 0); }
      75.7%     { transform: translate3d(0, 1px, 0); }
      78.4%, 93.2% { transform: translate3d(0, 0, 0); }
      95.3%     { transform: translate3d(0, 2px, 0); }
      100%      { transform: translate3d(0, 0, 0); }
    }
    @keyframes nudge-2 {
      0%, 74%   { transform: translate3d(0, 0, 0); }
      75.7%     { transform: translate3d(0, 1px, 0); }
      78.4%, 93.2% { transform: translate3d(0, 0, 0); }
      95.3%     { transform: translate3d(0, 2px, 0); }
      100%      { transform: translate3d(0, 0, 0); }
    }
    @keyframes nudge-lead {
      0%, 93.2% { transform: translate3d(0, 0, 0); }
      95.3%     { transform: translate3d(0, 2px, 0); }
      100%      { transform: translate3d(0, 0, 0); }
    }

    /* THE SWEEPS — additive, shared keyframes (the stagger lives in the
       per-paper exit ranges): lift first, then off-frame, slightly
       raised, a small tumble. Explicit ends for the additive math. */
    @keyframes sweep-left {
      from { transform: translate3d(0, 0, 0) rotate(0deg); }
      20%  { transform: translate3d(-6vw, -1rem, 0) rotate(-1deg); }
      to   { transform: translate3d(calc(-1 * min(96vw, 76rem)), -1.4rem, 0) rotate(-3.5deg); }
    }
    @keyframes sweep-right {
      from { transform: translate3d(0, 0, 0) rotate(0deg); }
      20%  { transform: translate3d(6vw, -1rem, 0) rotate(1deg); }
      to   { transform: translate3d(min(96vw, 76rem), -1.4rem, 0) rotate(3.5deg); }
    }

    @keyframes stamp-hit {
      from { opacity: 0; transform: rotate(-6.5deg) scale(1.06); }
      25%  { opacity: 1; }
      70%  { transform: rotate(-6.5deg) scale(0.985); }
      /* implicit to: the base rotate(-6.5deg) scale(1) — the settle */
    }

    /* A7.3 (drops) DELETED — FP6, founder-directed: the put-down fired
       only once the sea was already on screen (--sea entry can't start
       any earlier than the water itself), so the objects now simply
       REST in place from the start — no entrance, no puffs. The wave
       still takes them (A7.4 below), the keys still wash, the phone
       still drowns. */

    /* ====================================================================
       A7.4 — THE WAVE TAKES THEM. Staging (re-measured after the
       founder pass moved the objects up the beach): the water reaches
       the objects at entry 24–34% and fully covers them by 29–38%
       (measured at 768/1280/1600 — 768 is the latest), so the drag
       starts at 36% with the vanish past full cover, and the state
       swaps run 38–44% — UNDER the water — and are revealed as it
       retreats. Scrolling back up reverses everything: the water
       returns them intact.
       · wallet + keys: a short drag toward the water, then gone
         beneath the foam (never an in-place fade in dry air).
       · phone: crossfades to the dead state (crack, sand in the port,
         beading) — the time-based flicker below sells the damage.
       · passport: crossfades to soaked — darkened, warped, swollen,
         half sunk. Quietly grim; no jokes. ========================== */
    /* founder pass 2: only the wallet rides sea-takes now — the keys
       sit high in the top right and get their own retreat wash-away
       (aftermath block below + cover-tracking in main.js) */
    .thing--wallet svg {
      animation-name: sea-takes;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-delay: 0s;
      animation-fill-mode: both;
      animation-timeline: --sea;
      animation-range: entry 36% entry 50%;
    }
    /* FP5: the phone's swap left these scroll ranges — high on the dune
       the 38–44% window is dry air, so main.js swaps it by actual water
       cover (main.phone-drowned, aftermath block). Passport stays. */
    .pp-dry {
      animation-name: state-out;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-delay: 0s;
      animation-fill-mode: both;
      animation-timeline: --sea;
      animation-range: entry 38% entry 44%;
    }
    .pp-wet {
      animation-name: state-in;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-delay: 0s;
      animation-fill-mode: both;
      animation-timeline: --sea;
      animation-range: entry 38% entry 44%;
    }
    @keyframes sea-takes {
      from { transform: translate3d(0, 0, 0) rotate(0deg); opacity: 1; }
      /* the drag stays fully visible — the vanish only happens once
         the pull has carried them under the foam */
      55%  { transform: translate3d(0, 1.7rem, 0) rotate(-4deg); opacity: 1; }
      82%  { opacity: 0; }
      to   { transform: translate3d(0, 3rem, 0) rotate(-6deg); opacity: 0; }
    }
    @keyframes state-out { to { opacity: 0; } } /* implicit from = base 1 */
    @keyframes state-in  { to { opacity: 1; } } /* implicit from = base 0 */

  } /* end >=701px — the pile's scroll machinery (A7) */

    /* ======================================================================
       THE WAVE (Spec section entrance) — the blue field IS the wave: as
       the section enters, the tide runs up the sand as a function of
       scroll progress. Deceleration is baked into the keyframe offsets
       (water arrives fast and dies slow), it overshoots to its
       high-water mark, holds a beat, and settles back — uncovering the
       wet-sand band it leaves behind. The foam layer advances on its
       own slightly different curve; the varying offset between foam and
       waterline is the depth. Transform + opacity only; the irregular
       edge is baked SVG geometry. Fallback and reduced motion see the
       settled tide (base styles = final state).
       ====================================================================== */
    .section--spec { view-timeline: --sea block; }
    /* hoist --sea to main so the PRECEDING sibling (#how) can hear it —
       a named view-timeline is otherwise visible to descendants only */
    main { timeline-scope: --sea; }

    /* SUBMERSION — the pinned dune goes under: a whisper of dim and a
       small sink as the sea covers it. Compositor-only; if
       timeline-scope is missing the animation simply never advances
       and the base (undimmed) state holds. */
    .js #how {
      animation-name: how-submerge;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-delay: 0s;
      animation-fill-mode: both;
      animation-timeline: --sea;
      animation-range: entry 0% entry 70%; /* A7.6: all dim/sink motion done by 70% — zero residual movement (not even sub-pixel) from well before the sea fills the viewport until release */
    }
    .shorebreak__tide {
      animation-name: tide-run;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-delay: 0s;
      animation-fill-mode: both;
      animation-timeline: --sea;
      animation-range: entry 0% entry 62%; /* FP13b (was 45%): the crest's slip stays alive through ~2/3 of the pass — a longer, calmer rise. The big travel is scroll geometry (the panel riding the pinned dune), so the A7.4 object ranges are untouched: water still reaches them at the same scroll positions. */
    }
    .shorebreak__foam {
      animation-name: foam-run;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-delay: 0s;
      animation-fill-mode: both;
      animation-timeline: --sea;
      animation-range: entry 0% entry 62%; /* FP13b: trails the stretched crest (was 45%) */
    }
    /* A7.5: the wet band is NOT scroll-driven anymore — drying is a
       TIME process, latched by main.js with hysteresis (state
       exception, documented in FABLE_STATE). The transitions live
       with the base styles in styles.css. */
    /* A3: the edge advance is SECONDARY now — the panel rise (scroll
       itself, over the pinned dune) carries the big travel, and the
       crest only slips against the waterline: decelerating, a small
       reach past high water, hold, settle back */
    @keyframes tide-run {
      from { transform: translate3d(0, 2.8rem, 0); }
      38%  { transform: translate3d(0, 0.9rem, 0); }
      62%  { transform: translate3d(0, 0.25rem, 0); }
      78%  { transform: translate3d(0, -0.7rem, 0); }
      88%  { transform: translate3d(0, -0.7rem, 0); }
      to   { transform: translate3d(0, 0, 0); }
    }
    /* the foam trails the slip, gets thrown past the water at the
       reach, settles back onto the edge — the changing offset against
       the waterline is what sells the depth */
    @keyframes foam-run {
      from { transform: translate3d(0, 1.4rem, 0); }
      40%  { transform: translate3d(0, 0.35rem, 0); }
      66%  { transform: translate3d(0, -0.5rem, 0); }
      84%  { transform: translate3d(0, -0.5rem, 0); }
      to   { transform: translate3d(0, 0, 0); }
    }
    /* the dune goes under — tuned low on purpose */
    @keyframes how-submerge {
      from { transform: translate3d(0, 0, 0); opacity: 1; }
      to   { transform: translate3d(0, 0.6rem, 0); opacity: 0.82; }
    }
  }
}

/* ==========================================================================
   How It Works — editorial numbered flow: a rule, a big numeral, and type
   ========================================================================== */
.steps-flow {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6) var(--space-7);
}
@media (min-width: 760px) { .steps-flow { grid-template-columns: repeat(4, 1fr); } }

.steps-flow li { border-top: 2px solid var(--ink); padding-top: 0.9rem; }

.steps-flow__num {
  font-weight: 800;
  display: block;
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 4.5vw, 3.4rem);
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--signal);
  margin-bottom: 0.5rem;
}
.steps-flow h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-md);
  letter-spacing: var(--track-ui);
  margin-bottom: 0.3rem;
}
.steps-flow p { font-size: var(--text-sm); max-width: 16rem; }

/* ---------------- the app, at a glance (decorative phone) ---------------- */
.phone {
  width: clamp(13rem, 17vw, 15.5rem);
  aspect-ratio: 9 / 18.5;
  margin: 0 auto;
  background: linear-gradient(#2B303A, #191D23);
  border-radius: 2.4rem;
  padding: 0.55rem;
  box-shadow:
    0 2px 4px rgba(34, 38, 46, 0.22),
    0 12px 24px rgba(34, 38, 46, 0.2),
    0 32px 64px rgba(34, 38, 46, 0.26),
    inset 0 1px 0 rgba(255, 255, 255, 0.15);
  position: relative;
}
.phone__notch {
  position: absolute;
  top: 0.95rem;
  left: 50%;
  transform: translateX(-50%);
  width: 30%;
  height: 0.55rem;
  background: #10141A;
  border-radius: 999px;
  z-index: 1;
}
.phone__screen {
  height: 100%;
  border-radius: 1.9rem;
  overflow: hidden;
  background: linear-gradient(#EAF6FB, var(--bone));
  display: flex;
  flex-direction: column;
  padding: 2rem 0.9rem 1.1rem;
  gap: 0.7rem;
}
.phone__brand {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  color: var(--pacific);
}
.phone__map {
  position: relative;
  border-radius: 0.9rem;
  overflow: hidden;
  border: 2px solid rgba(34, 38, 46, 0.15);
  flex: 1;
}
.phone__map svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.phone__pin-label {
  position: absolute;
  left: 0.5rem;
  bottom: 0.5rem;
  font-family: var(--font-ui);
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: var(--track-micro);
  background: rgba(246, 241, 228, 0.92);
  border-radius: 999px;
  padding: 0.2rem 0.55rem;
}
.phone__meta {
  font-family: var(--font-ui);
  font-size: 0.62rem;
  text-align: center;
  opacity: 0.65;
}

/* ---- the 3-screen app flow ---- */
.app-screen { display: none; }
.app-screen.is-active {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  flex: 1;
  min-height: 0;
}
.app-screen .phone__map { flex: 1; }

.app-cta {
  font-weight: 700;
  font-family: var(--font-display);
  font-size: 0.95rem;
  letter-spacing: var(--track-ui);
  text-align: center;
  background: var(--tangerine);
  color: var(--ink);
  border-radius: 999px;
  padding: 0.7rem;
  cursor: pointer;
  box-shadow: 0 6px 14px rgba(34, 38, 46, 0.25);
  transition: transform 0.25s var(--ease-spring), box-shadow 0.25s var(--ease-out);
}
.app-cta:hover { transform: translateY(-1px); }
.app-cta:active { transform: scale(0.96); transition-duration: 0.08s; }
.app-cta--end { background: var(--pacific); color: var(--bone); }

.app-ff {
  font-family: var(--font-ui);
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: var(--track-micro);
  text-align: center;
  color: #A9A497;
  cursor: pointer;
  padding: 0.1rem;
}
.app-ff:hover { color: var(--cyan); }

.app-title {
  font-weight: 700;
  font-family: var(--font-display);
  font-size: 0.95rem;
  letter-spacing: var(--track-ui);
}

.app-sizes { display: grid; gap: 0.45rem; flex: 1; align-content: center; }
.app-size {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: 0.6rem;
  align-items: center;
  border: 1.5px solid rgba(34, 38, 46, 0.25);
  border-radius: 12px;
  padding: 0.45rem 0.65rem;
  font-size: 0.68rem;
  line-height: 1.3;
}
.app-size b {
  grid-row: 1 / 3;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.25rem;
}
.app-size em { font-style: normal; font-weight: 700; color: var(--pacific); }
.app-size.is-on { border-color: var(--tangerine); background: rgba(255, 138, 61, 0.12); }

.app-note {
  font-family: var(--font-ui);
  font-size: 0.58rem;
  text-align: center;
  opacity: 0.6;
}

.app-timer {
  font-weight: 700;
  font-family: var(--font-display);
  font-size: 3rem;
  line-height: 1;
  text-align: center;
  color: var(--pacific);
  margin: auto 0 0;
}
.app-timer small { font-size: 0.45em; opacity: 0.6; }
.app-cost {
  font-family: var(--font-ui);
  font-size: 0.62rem;
  text-align: center;
  opacity: 0.75;
  margin-bottom: auto;
}

.phone__dots {
  display: flex;
  justify-content: center;
  gap: 0.4rem;
  padding-top: 0.5rem;
}
.phone__dots i {
  width: 0.42rem;
  height: 0.42rem;
  border-radius: 50%;
  background: rgba(34, 38, 46, 0.25);
}
.phone__dots i.is-on { background: var(--tangerine); }

/* ==========================================================================
   Built for the Beach — hardware spec sheet: hairline rows, no cards
   ========================================================================== */
.spec-list {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  column-gap: clamp(2.5rem, 5vw, 4.5rem);
}
@media (min-width: 820px) { .spec-list { grid-template-columns: 1fr 1fr; } }

.spec {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: 1.1rem;
  align-items: start;
  padding: 1.25rem 0;
  border-top: 1px solid rgba(246, 241, 228, 0.22);
}

.spec__icon { grid-row: 1 / 3; width: 2.3rem; height: 2.3rem; margin-top: 0.15rem; }

/* real product render slot — hidden until the image file actually loads
   (JS adds .is-loaded), so a missing file never shows a broken icon */
.product-shot {
  display: none;
  margin-top: 2.5rem;
}
.product-shot.is-loaded { display: block; }
.product-shot img {
  width: 100%;
  max-width: 56rem;
  /* FP11: the render is a transparent cutout now — shadows must follow
     the unit's silhouette (filter), not the image rectangle (box-shadow) */
  filter:
    drop-shadow(0 4px 8px rgba(2, 20, 24, 0.5))
    drop-shadow(0 26px 48px rgba(2, 20, 24, 0.45));
}
.product-shot figcaption {
  margin-top: 0.8rem;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: var(--track-micro);
  color: rgba(246, 241, 228, 0.7);
}

/* ---------------- WHAT'S IN THE BOX?! (FP11) ----------------
   Four door sizes under the render, drawn in the dune-props style.
   Lives on the sea ground inside #features — no new section, so the
   pin-cover rule never comes into play. */
.inbox { margin-top: clamp(2.5rem, 6vw, 4rem); }
.inbox__headline {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(1.5rem, 3.4vw, 2.4rem);
  letter-spacing: var(--track-title);
  color: var(--bone);
  margin-bottom: 0.35rem;
}
.inbox__kicker {
  font-style: italic;
  font-size: var(--text-xs);
  color: rgba(246, 241, 228, 0.6);
  margin-bottom: 1.6rem;
}
.inbox__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  /* 11rem min so all four tiers sit on ONE row inside the railed column
     at 1280 (13rem wrapped 3+1, orphaning Large) */
  grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
  gap: clamp(0.9rem, 2vw, 1.4rem);
}
.inbox-tier {
  background: rgba(2, 20, 24, 0.38);
  border: 1px solid rgba(246, 241, 228, 0.14);
  border-radius: var(--radius);
  padding: 1.2rem 1.1rem 1.3rem;
  text-align: center;
  transition: transform 0.25s var(--ease-out), border-color 0.25s var(--ease-out);
}
@media (hover: hover) {
  .inbox-tier:hover {
    transform: translateY(-4px);
    border-color: rgba(246, 241, 228, 0.3);
  }
}
.inbox-tier svg {
  width: 100%;
  max-width: 8.5rem;
  height: auto;
  margin: 0 auto 0.8rem;
  overflow: visible;
}
.inbox-tier b {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-md);
  letter-spacing: var(--track-title);
  color: var(--bone);
  margin-bottom: 0.35rem;
}
.inbox-tier span {
  display: block;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: rgba(246, 241, 228, 0.78);
}
.inbox__all {
  margin-top: 1.4rem;
  font-size: var(--text-sm);
  font-weight: 600;
  color: rgba(246, 241, 228, 0.88);
}
.inbox__note {
  margin-top: 0.5rem;
  font-style: italic;
  font-size: var(--text-xs);
  color: rgba(246, 241, 228, 0.6);
}

.spec h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-md);
  letter-spacing: var(--track-ui);
  margin-bottom: 0.25rem;
}
.spec p { font-size: var(--text-sm); }

/* ==========================================================================
   Pricing
   ========================================================================== */
/* Stage B: cards read as printed matter — hard offset shadow, no blur.
   FP8: printed on night stock now — raised black surface, bone type,
   hairline edge, volt where the money is. */
.pricing-card {
  max-width: 34rem;
  background: var(--night-2);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: clamp(1.75rem, 4.5vw, 2.75rem);
  box-shadow: 0.4rem 0.45rem 0 rgba(0, 0, 0, 0.55);
  transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.pricing-card:hover {
  transform: translate(2px, 2px);
  box-shadow: 0.2rem 0.25rem 0 rgba(0, 0, 0, 0.55);
}
.pricing-card__from {
  display: block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.28em;
  letter-spacing: var(--track-micro);
  opacity: 0.65;
  margin-bottom: 0.15em;
}

.pricing-card__price {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3.4rem, 9vw, 5.5rem);
  line-height: 1;
  letter-spacing: -0.015em;
  color: var(--volt);
  margin-bottom: 1rem;
}
.pricing-card__price sup {
  font-size: 0.45em;
  vertical-align: super;
  color: var(--signal);
}
.pricing-card__unit {
  font-size: 0.34em;
  color: var(--ink);
  opacity: 0.75;
  margin-left: 0.2em;
}

.pricing-card__line {
  max-width: 27rem;
  margin: 0 auto 1.6rem;
  font-size: var(--text-base);
}
.pricing-card__line strong { color: var(--volt); }

/* the tier table — the pricing model, published */
.tier-table { margin-bottom: 1.5rem; text-align: left; }
.tier {
  display: grid;
  grid-template-columns: 5.5rem 1fr auto;
  align-items: baseline;
  gap: 1rem;
  padding: 0.85rem 0.15rem;
  border-top: 1px solid var(--hairline);
}
.tier:last-child { border-bottom: 1px solid var(--hairline); }
.tier__size {
  font-family: var(--font-display);
  font-size: var(--text-md);
  letter-spacing: var(--track-title);
  font-weight: 700;
}
.tier__fits { font-size: var(--text-xs); opacity: 0.65; }
.tier__price {
  font-weight: 700;
  font-family: var(--font-display);
  font-size: var(--text-xl);
  color: var(--volt);
  text-align: right;
}
.tier__price i { font-style: normal; font-size: 0.6em; opacity: 0.7; }

.pricing-card__note {
  margin-top: 1.1rem;
  font-style: italic;
  font-size: var(--text-xs);
  opacity: 0.7;
}

/* (the .access-card block that lived here was removed with its section,
   Aug 2026 — founder: nothing is free. Git history has it.) */

/* ==========================================================================
   Gallery (The Art) — the frames hang on the cabinet itself: brushed
   locker steel with faint door-panel seams
   ========================================================================== */
.section--gallery {
  position: relative;
  color: var(--bone);
  background:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.02) 0 1px, transparent 1px 3px),
    linear-gradient(180deg, #333944 0%, #262B33 100%);
}
/* the door seams — the section IS the locker wall */
.section--gallery::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.35;
  background-image:
    repeating-linear-gradient(90deg, rgba(12, 15, 19, 0.5) 0 3px, transparent 3px 21rem),
    repeating-linear-gradient(0deg, rgba(12, 15, 19, 0.4) 0 3px, transparent 3px 14rem);
  background-position: 7rem 4rem;
}
.section--gallery .placard { color: var(--cyan); }
.section--gallery .section__inner { position: relative; }

.art-wall { margin-bottom: 2.25rem; }

.gallery {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.5rem, 4vw, 2.5rem);
}
@media (min-width: 700px) { .gallery { grid-template-columns: repeat(3, 1fr); } }

.frame {
  background: #1B1F26;
  border: 1px solid rgba(246, 241, 228, 0.08);
  border-radius: 6px;
  padding: 0.85rem;
  /* ink-blue tint, contact + ambient — not flat black */
  box-shadow:
    0 2px 5px rgba(22, 28, 42, 0.35),
    0 20px 40px rgba(22, 28, 42, 0.4);
  transition: transform 0.35s var(--ease-spring), box-shadow 0.35s var(--ease-out);
}
.frame:hover {
  transform: translateY(-6px) rotate(-0.4deg);
  box-shadow:
    0 3px 8px rgba(22, 28, 42, 0.32),
    0 30px 52px rgba(22, 28, 42, 0.48);
}

.frame__mat { background: var(--paper); padding: 0.85rem; position: relative; }
/* analog artifact: tape holding the piece up */
.frame__mat::before,
.frame__mat::after {
  content: "";
  position: absolute;
  top: -0.5rem;
  width: 3.2rem;
  height: 1.15rem;
  background: rgba(240, 230, 200, 0.82);
  box-shadow: 0 1px 3px rgba(34, 38, 46, 0.25);
  z-index: 1;
}
.frame__mat::before { left: -0.7rem; transform: rotate(-38deg); }
.frame__mat::after  { right: -0.7rem; transform: rotate(38deg); }

.frame__art { width: 100%; aspect-ratio: 5 / 6; height: auto; }

.frame__placard {
  display: grid;
  gap: 0.15rem;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  letter-spacing: var(--track-micro);
  color: var(--bone);
  padding: 0.8rem 0.2rem 0.1rem;
}
.frame__placard strong { font-weight: 600; letter-spacing: var(--track-micro); }
.frame__placard-note { opacity: 0.55; font-style: italic; }

.art-how { max-width: 38rem; display: grid; gap: 1rem; }
.art-how strong { color: var(--cyan); }

.gallery__invite { font-size: var(--text-base); font-weight: 500; }
.gallery__invite a {
  color: var(--cyan);
  font-weight: 700;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
.gallery__invite a:hover { color: var(--hibiscus); }

/* ==========================================================================
   Why now
   ========================================================================== */
/* the poster moment — deck's closing line, sprayed on a concrete slab */
.shout {
  position: relative;
  background-color: #8B8880;
  background-image:
    radial-gradient(30rem 16rem at 78% 22%, rgba(58, 56, 50, 0.12), transparent 62%),
    radial-gradient(26rem 14rem at 12% 74%, rgba(58, 56, 50, 0.14), transparent 64%),
    radial-gradient(22rem 11rem at 44% 8%, rgba(255, 252, 244, 0.08), transparent 60%),
    linear-gradient(180deg, #93908A 0%, #88857D 55%, #7D7A73 100%);
  color: var(--bone);
  padding: clamp(4rem, 10vw, 7rem) var(--pad-x);
  text-align: center;
  overflow: hidden;
}
/* concrete tooth: grain at two scales, multiplied */
.shout::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.14;
  mix-blend-mode: multiply;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 210px 210px, 560px 560px;
}
/* A4.4 — the piece. Not a font: every letter is a hand-placed skeleton
   stroke (the way a one-liner throwie is actually built — fat round
   cap over a drawn path), so no two letters share a transform, an
   angle, or a baseline. Render stack per letter: displaced solid
   shadow block, hard outline at consistent weight, color coat,
   upper-left glint. Colors are PROVISIONAL tokens (--graf-*) pulled
   from the page's existing accents; Stage B re-tunes by find-replace. */
.shout__piece {
  display: block;
  width: min(44rem, 94%);
  margin-inline: auto;
  transform: rotate(-1.2deg);
}
/* A5.6: harder-edged — square nibs and mitered bends instead of the
   round bubble caps, deeper block shadow, tighter coat over a heavier
   outline. The angularity lives in the skeleton paths (index.html). */
/* FP6 (founder: FP4's bounce read "kiddy"): still a round-cap throwie,
   but STREET — one cobalt coat with a single tangerine pop, every
   letter leaning the SAME way (alternating rotation signs is what
   made it bounce like a playroom), hard slash glints instead of the
   glossy curls, and three paint drips. */
.shout__piece use,
.shout__piece path {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.pg-sh { stroke: var(--graf-shadow); stroke-width: 46; transform: translate(14px, 17px); }
.pg-ln { stroke: var(--graf-line); stroke-width: 46; }
.pg-co { stroke-width: 28; }
.pg-gl { stroke: var(--graf-glint); stroke-width: 5; opacity: 0.7; }
.pg-dl { stroke: var(--graf-line); stroke-width: 15; }
.pg-dc { stroke-width: 8; }

/* ==========================================================================
   FAQ
   ========================================================================== */
/* editorial divider list — no boxes */
.faq-list { display: grid; gap: 0; }

.faq {
  border-top: 1px solid var(--hairline); /* FP8: hairlines on night */
}
.faq:last-child { border-bottom: 1px solid var(--hairline); }

.faq summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  font-weight: 700;
  font-size: var(--text-base);
  padding: 1.15rem 0.15rem;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary { transition: color 0.15s var(--ease-out); }
.faq[open] > p { animation: faq-in 0.4s var(--ease-out); }
@keyframes faq-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
.faq summary::after {
  font-weight: 700;
  content: "+";
  font-family: var(--font-display);
  font-size: 1.4rem;
  color: var(--volt);
  line-height: 1;
  flex-shrink: 0;
  transition: transform 0.2s var(--ease-out);
}
.faq[open] summary::after { content: "–"; color: var(--volt); }
.faq summary:hover { color: var(--volt); }

.faq p {
  padding: 0 0.15rem 1.15rem;
  max-width: 38rem; /* was 42rem ≈ 85ch — the longest prose on the page */
  font-size: var(--text-sm);
  text-wrap: pretty;
}
.faq a { color: var(--volt); font-weight: 600; }

/* ==========================================================================
   The Story — the boardwalk at night (FP8, founder-directed: the sand
   ground read "kinda meh"). CSS/SVG scene: string-light swags, a neon
   VENICE sign, palm silhouettes, plank walk. The copy floats in on a
   glass card riding an anonymous view() timeline (transform only, no
   var() in keyframes, ≥701px + motion-ok + @supports gated — phones,
   Firefox and reduced motion get the plain reveal fades).
   ========================================================================== */
.section--story {
  position: relative;
  overflow: hidden; /* scene furniture bleeds past the edges on purpose */
}
.section--story .section__inner { position: relative; z-index: 1; }
.section--story .placard { color: var(--cyan); }

.story-scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.story-scene__moon {
  position: absolute;
  top: clamp(1.6rem, 4vw, 3.4rem);
  left: clamp(4%, 7vw, 9%);
  width: clamp(7.5rem, 15vw, 12rem);
  height: auto;
}
.story-scene__lights {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: clamp(110px, 14vw, 190px);
}
/* the neon sign — Venice's landmark, wired in volt. Scenery signage,
   like the press caps: an object in the world, not interface type. */
.story-scene__neon {
  position: absolute;
  top: clamp(1.6rem, 4vw, 3.2rem); /* above the card's top edge */
  right: clamp(1rem, 6vw, 5.5rem);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(1.5rem, 3.4vw, 2.7rem);
  letter-spacing: 0.14em; /* neon tubes need air between them */
  color: #9CC6FF;
  text-shadow:
    0 0 6px  rgba(61, 139, 255, 0.95),
    0 0 18px rgba(61, 139, 255, 0.55),
    0 0 44px rgba(61, 139, 255, 0.35);
  transform: rotate(-2deg);
}
.story-scene__palm {
  position: absolute;
  bottom: clamp(2.4rem, 6vw, 3.9rem); /* roots behind the walk's top edge */
  height: clamp(10rem, 24vw, 19rem);
  width: auto;
  transform-origin: bottom center;
}
.story-scene__palm--l { left: clamp(-2.5rem, -2vw, -1rem); }
.story-scene__palm--r { right: clamp(-3rem, -2.5vw, -1.25rem); transform: scaleX(-1); }
/* sway rides the `rotate` property (palm-sway), so the flip transform
   above survives it */
@media (prefers-reduced-motion: no-preference) {
  .story-scene__palm--l { animation: palm-sway 9s ease-in-out infinite alternate; }
  .story-scene__palm--r { animation: palm-sway 7.5s ease-in-out 0.8s infinite alternate; }
}
/* FP17 (founder-directed — "more animations", overriding the FP12 panel
   vote): the boardwalk breathes. All opacity/transform, all inside the
   no-preference gate; reduced motion gets the still scene. */
@media (prefers-reduced-motion: no-preference) {
  .story-scene__bulbs g { animation: bulb-tw 4.6s ease-in-out infinite; }
  .story-scene__bulbs g:nth-child(2n) { animation-delay: 1.1s; animation-duration: 5.3s; }
  .story-scene__bulbs g:nth-child(3n) { animation-delay: 2.3s; }
  .story-scene__bulbs g:nth-child(5n) { animation-delay: 3.1s; animation-duration: 4.1s; }
  .story-scene__neon { animation: neon-flick 9s linear infinite; }
  .story-scene__moon {
    transform-origin: center;
    animation: moon-breathe 12s ease-in-out infinite alternate;
  }
}
@keyframes bulb-tw {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}
/* mostly steady, two quick dips late in the cycle — a real tube, not a rave */
@keyframes neon-flick {
  0%, 81.5%, 83%, 84.2%, 100% { opacity: 1; }
  82%   { opacity: 0.45; }
  83.6% { opacity: 0.6; }
}
@keyframes moon-breathe {
  from { transform: scale(1); }
  to   { transform: scale(1.02); }
}

.story-scene__walk {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: clamp(3.5rem, 8vw, 5.5rem);
  background:
    repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.4) 0 2px, transparent 2px 9rem),
    linear-gradient(180deg, #1E1810 0%, #171208 100%);
  border-top: 2px solid rgba(255, 214, 140, 0.18); /* lamplight kisses the boards */
}

.story-card {
  background: rgba(19, 26, 38, 0.86); /* night-2 glass */
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: clamp(1.75rem, 4.5vw, 3rem);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
  color: var(--bone);
}
.story-card strong { color: var(--volt); }
/* the founder's legacy quote (FP11) — his words, set apart on a volt rail */
.story-legacy {
  margin: 0 0 var(--space-5);
  padding: 0.4rem 0 0.4rem 1.25rem;
  border-left: 3px solid var(--volt);
}
.story-legacy p {
  font-size: var(--text-copy);
  line-height: 1.6;
  color: rgba(246, 241, 228, 0.92);
  margin-bottom: 0.7rem;
}
.story-legacy cite {
  display: block;
  font-style: normal;
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--track-ui);
  color: var(--volt);
}
@media (min-width: 701px) and (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .story-card {
      animation-name: story-rise;
      animation-duration: 1ms; /* timeline-driven; duration is a formality */
      animation-timing-function: var(--ease-out);
      animation-fill-mode: both;
      animation-timeline: view();
      animation-range: entry 8% entry 60%;
    }
  }
}
@keyframes story-rise {
  from { transform: translateY(3.2rem) rotate(-0.7deg); }
  to   { transform: translateY(0) rotate(0deg); }
}

/* ==========================================================================
   Join / Reserve — the sun sets where you sign up
   ========================================================================== */
.section--join {
  position: relative;
  overflow: hidden;
  /* real sunset photography (Unsplash, frank mckenna @frankiefoto — README),
     painted dusk kept underneath as fallback */
  background:
    url('../assets/join-sunset.jpg') center 40% / cover no-repeat,
    linear-gradient(
      to bottom,
      var(--dusk-top)   0%,
      var(--dusk-low)   46%,
      var(--pacific-2)  46% 58%,
      var(--bone)       58% 58.4%,
      var(--sand)       58.4% 100%
    );
}
.section--join::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  /* FP8: the sun has SET where you sign up — same photo, night scrim.
     Heavy at the bottom so the cards and footer handoff read black. */
  background: linear-gradient(to bottom,
    rgba(10, 14, 21, 0.42) 0%,
    rgba(10, 14, 21, 0.72) 46%,
    rgba(10, 14, 21, 0.95) 100%);
}
.section--join .join__palm { display: none; }
.section--join .section__inner { position: relative; z-index: 1; }
.section--join .placard { color: var(--cyan); }

.join__palm {
  position: absolute;
  z-index: 0;
  right: clamp(-3rem, -2vw, -1rem);
  bottom: 30%;
  height: clamp(12rem, 30vw, 26rem);
  width: auto;
  transform-origin: bottom center;
  animation: palm-sway 8s ease-in-out infinite alternate;
}

.join-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(21rem, 100%), 1fr));
  gap: clamp(1.5rem, 4vw, 2.5rem);
  align-items: start;
}

.join-card {
  background: var(--night-2); /* FP8: night stock */
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: clamp(1.5rem, 4vw, 2.25rem);
  box-shadow: 0.4rem 0.45rem 0 rgba(0, 0, 0, 0.55);
  transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.join-card:hover {
  transform: translate(2px, 2px);
  box-shadow: 0.2rem 0.25rem 0 rgba(0, 0, 0, 0.55);
}
.join-card--deposit {
  background: var(--volt-deep); /* FP8: the deposit card carries the volt */
  border-color: rgba(246, 241, 228, 0.28);
  color: var(--foam);
}

.join-card__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-lg);
  margin-bottom: 1.1rem;
}

.join-card__text { margin-bottom: 1.5rem; }

.join-card__reassure {
  font-style: italic;
  font-size: var(--text-xs);
  margin-top: 0.9rem;
  opacity: 0.9;
}

/* ---------------- form ---------------- */
.field { margin-bottom: 1.1rem; }

.field label {
  display: block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-sm);
  margin-bottom: 0.4rem;
}
.field__req { color: #FF8A80; font-weight: 500; font-size: 0.85em; } /* FP8: alert red lifted for night contrast */
.field__opt { opacity: 0.6; font-weight: 500; font-size: 0.85em; }

.field input {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: var(--paper); /* warm paper, not clinical pure white */
  border: 2px solid rgba(34, 38, 46, 0.7);
  border-radius: 10px;
  padding: 0.7rem 0.9rem;
  transition: border-color 0.15s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.field input:focus { border-color: var(--volt); box-shadow: 0 0 0 4px rgba(61, 139, 255, 0.22); }
.field input:focus-visible { outline-offset: 1px; }
.field input.is-invalid { border-color: var(--hibiscus); }

/* founding-member intent checkbox */
.field--check { margin: 1.2rem 0 1.35rem; }
.check {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  cursor: pointer;
  font-size: var(--text-sm);
  font-weight: 500;
  line-height: 1.45;
}
.check input {
  width: 1.15rem;
  height: 1.15rem;
  margin-top: 0.15rem;
  flex-shrink: 0;
  accent-color: var(--signal);
}
.check strong { color: var(--volt); }

.form-status {
  min-height: 1.4em;
  margin-top: 0.9rem;
  font-weight: 600;
  font-size: var(--text-sm);
}
/* FP8: statuses read on night cards now — soft alert pink, volt success */
.form-status.is-error   { color: #FFD9E4; }
.join-card--deposit .form-status.is-error { color: #FFD9E4; }
.form-status.is-success { color: var(--volt); }

.waitlist-success {
  border: 3px dashed var(--volt);
  border-radius: var(--radius);
  padding: 1.75rem 1.5rem;
  text-align: center;
}
.waitlist-success__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-lg);
  color: var(--pacific);
  margin-bottom: 0.5rem;
}

/* ==========================================================================
   The Canvas — back of the box, rotating gallery
   ========================================================================== */
.section--canvas {
  background-color: var(--ink);
  /* overspray haze drifting off the walls — chroma depth, not decoration */
  background-image:
    radial-gradient(42rem 24rem at 86% 4%, rgba(240, 54, 139, 0.13), transparent 62%),
    radial-gradient(36rem 22rem at 4% 94%, rgba(55, 193, 214, 0.11), transparent 62%);
  color: var(--bone);
  /* the 3D turn-around must never hand the page a horizontal scrollbar */
  overflow-x: hidden;
  overflow-x: clip;
}
.section--canvas .placard { color: var(--cyan); }

/* ---- the composite: artwork perspective-mapped onto the rear panel ----
   Today the panel sits on a neutral placeholder stage; when the real
   render (assets/locker-back-blank.png) lands, the base <img> shows
   automatically and only the CORNERS numbers in main.js need re-measuring. */
.composite { max-width: 58rem; margin: 0 auto; perspective: 1400px; }

.composite__stage {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: 14px;
  overflow: hidden;
  /* scroll-driven turn-around: JS scrubs rotateY/translateY/opacity on this
     element as the section walks into view (reduced motion: none of it) */
  will-change: transform, opacity;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
  /* the scene behind the unit: morning sky, a strip of Pacific, the sand
     the cabinet stands on — soft sun haze upper right */
  background:
    radial-gradient(30rem 12rem at 78% 22%, rgba(255, 240, 210, 0.5), transparent 65%),
    linear-gradient(180deg,
      #C2E2EF 0%, #D5ECF5 30%,
      #8FCEDD 36%, #6FB9CC 44%,
      #E9DFC0 46%, #E7D4A6 64%, #DFCB98 100%);
}
/* film grit over the whole scene */
.composite__stage::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  opacity: 0.06;
  mix-blend-mode: multiply;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}

.composite__base {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* the global img { display: block } must not defeat the hidden attr
   (a missing render would otherwise paint its alt text on the stage) */
.composite__base[hidden] { display: none; }

/* ---- the mockup cabinet, built to the founder's renders: the artwork
   panel (mapped by CORNERS in main.js) sits inside this chrome ---- */
.composite__cab { position: absolute; inset: 0; pointer-events: none; }
.has-render .composite__cab { display: none; }

.composite__cab-body {
  position: absolute;
  left: 7%; right: 7%; top: 15.5%; bottom: 10.5%;
  border-radius: 10px;
  background:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.02) 0 1px, transparent 1px 3px),
    linear-gradient(#3A404B, #23272E);
  box-shadow:
    0 3px 6px rgba(20, 24, 30, 0.35),
    0 22px 44px rgba(20, 24, 30, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
.composite__cab-solar {
  position: absolute;
  left: 5%; right: 5%; top: 6.5%; height: 7.5%;
  border-radius: 4px;
  background:
    /* three separators carve the strip into four panels */
    repeating-linear-gradient(90deg, transparent 0 calc(25% - 3px), #2B3038 calc(25% - 3px) 25%),
    repeating-linear-gradient(90deg, rgba(125, 155, 195, 0.15) 0 1px, transparent 1px 3.125%),
    linear-gradient(105deg, rgba(150, 180, 220, 0.15) 0%, rgba(150, 180, 220, 0.04) 38%, transparent 62%),
    linear-gradient(180deg, #111A28 0%, #0B111C 55%, #15202F 100%);
  box-shadow:
    0 3px 7px rgba(20, 24, 30, 0.45),
    inset 0 0 0 1px #3A4048;
}
/* mounting feet between the array and the roof */
.composite__cab-solar::before,
.composite__cab-solar::after {
  content: "";
  position: absolute;
  bottom: -22%;
  width: clamp(0.45rem, 1vw, 0.7rem);
  height: 24%;
  background: linear-gradient(#2E333B, #191D23);
}
.composite__cab-solar::before { left: 16%; }
.composite__cab-solar::after  { right: 16%; }
.composite__cab-base {
  position: absolute;
  left: 7%; right: 7%; top: 89.5%; height: 4%;
  border-radius: 0 0 6px 6px;
  background:
    repeating-linear-gradient(90deg, transparent 0 5.4rem, rgba(34, 38, 46, 0.35) 5.4rem 5.6rem),
    linear-gradient(#9A6A3E, #7A4E28);
  box-shadow: inset 0 2px 3px rgba(0, 0, 0, 0.35);
}
.composite__cab-shadow {
  position: absolute;
  left: 9.5%; right: 9.5%; top: 92.6%; height: 5%;
  background: radial-gradient(ellipse 50% 100% at 50% 0%, rgba(20, 24, 30, 0.4), transparent 75%);
  filter: blur(2px);
}

.composite__panel {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
}

.canvas-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  opacity: 0;
  pointer-events: none;
  backface-visibility: hidden;
}
/* slide changes are a dimensional turn, not a crossfade: the incoming
   sheet swings in from the travel direction (--turn: 1 forward, -1 back),
   the outgoing one swings away. Static opacity keeps both honest if the
   animation never runs. */
.canvas-art.is-on {
  opacity: 1;
  animation: art-turn-in 0.85s var(--ease-out) backwards;
}
.canvas-art.is-off {
  animation: art-turn-out 0.85s var(--ease-out) both;
}
@keyframes art-turn-in {
  from { opacity: 0; transform: perspective(1200px) rotateY(calc(var(--turn, 1) * 34deg)) scale(0.965); }
  55%  { opacity: 1; }
}
@keyframes art-turn-out {
  from { opacity: 1; transform: perspective(1200px) rotateY(0deg) scale(1); }
  to   { opacity: 0; transform: perspective(1200px) rotateY(calc(var(--turn, 1) * -26deg)) scale(0.97); }
}
/* mid-turn, the vinyl catches the light */
.composite.is-turning .composite__sheen { animation: sheen-sweep 0.85s var(--ease-out); }
@keyframes sheen-sweep {
  from { transform: translateX(-9%); }
  to   { transform: translateX(7%); }
}

/* pass 1 — the render's light falls across the vinyl (multiply) */
.composite__shade {
  position: absolute;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: multiply;
  background:
    linear-gradient(105deg, rgba(58, 50, 40, 0.30) 0%, rgba(58, 50, 40, 0.10) 38%, rgba(58, 50, 40, 0.02) 62%),
    linear-gradient(to right, transparent 78%, rgba(30, 26, 22, 0.24));
}
/* pass 2 — satin sheen: cast vinyl, not matte, not gloss */
.composite__sheen {
  position: absolute;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  background: linear-gradient(112deg,
    transparent 26%,
    rgba(255, 250, 238, 0.15) 42%,
    rgba(255, 250, 238, 0.03) 54%,
    transparent 66%);
}
/* pass 3 — grain matched to the (eventual) base render's noise floor */
.composite__grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.1;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---- founding artist — the section-level moment ---- */
.founding-artist {
  margin-top: clamp(3rem, 7vw, 5rem);
  padding-top: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid rgba(246, 241, 228, 0.18);
  display: grid;
  justify-items: center;
  gap: 1.1rem;
  text-align: center;
}
.founding-artist h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.1rem, 5.5vw, 3.9rem);
  line-height: 1.02;
  letter-spacing: -0.01em; /* display tracking: tighter as type grows */
  color: var(--tangerine);
  max-width: 18ch;
  text-wrap: balance;
  transform: rotate(-0.6deg);
  text-shadow: 0 0 26px rgba(255, 138, 61, 0.28);
}
.founding-artist__line {
  font-size: var(--text-lead);
  font-weight: 600;
  max-width: 34rem;
}
.founding-artist__meta {
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--track-micro);
  color: rgba(246, 241, 228, 0.6);
}

.canvas-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.1rem;
  margin-top: 1.1rem;
}
.canvas-btn {
  position: relative;
  display: grid;
  place-items: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  border: 1px solid rgba(246, 241, 228, 0.3);
  background: rgba(246, 241, 228, 0.08);
  color: var(--bone);
  font-size: 1.35rem;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s var(--ease-out), transform 0.25s var(--ease-spring);
}
/* invisible hit-area extension to ~44px (the 1.1rem control gap absorbs it) */
.canvas-btn::after { content: ""; position: absolute; inset: -0.2rem; border-radius: 50%; }
.canvas-btn:hover { background: rgba(246, 241, 228, 0.18); transform: scale(1.08); }
.canvas-btn:active { transform: scale(0.9); transition-duration: 0.08s; }
.canvas-btn svg { width: 0.85rem; height: 0.85rem; fill: currentColor; }
.canvas-btn--pause .icon-play { display: none; }
.canvas-btn--pause.is-paused .icon-play { display: block; }
.canvas-btn--pause.is-paused .icon-pause { display: none; }
.canvas-dots { display: flex; gap: 0.45rem; }
.canvas-dots button {
  width: 0.6rem;
  height: 0.6rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(246, 241, 228, 0.25);
  cursor: pointer;
  transition: transform 0.25s var(--ease-spring), background 0.15s var(--ease-out);
}
.canvas-dots button:hover { transform: scale(1.35); }
.canvas-dots button.is-on { background: var(--tangerine); }

.canvas-placard {
  display: block;
  text-align: center;
  border-top: none;
  margin: 0.9rem auto 0;
  color: rgba(246, 241, 228, 0.75);
}

.canvas-cta {
  margin-top: var(--space-7);
  display: grid;
  gap: 0.9rem;
  justify-items: center;
  text-align: center;
}
.canvas-cta p { font-size: var(--text-md); font-weight: 600; }
.canvas-cta__note {
  font-size: var(--text-xs) !important;
  font-weight: 400 !important;
  font-style: italic;
  color: rgba(246, 241, 228, 0.6);
  max-width: 36rem;
}

/* ==========================================================================
   The App — interactive concept demo
   ========================================================================== */
.section--app { background: var(--night); color: var(--bone); } /* FP8: night register ground */
.section--app .placard { color: var(--cyan); }

.app-layout {
  display: grid;
  gap: clamp(2.25rem, 5vw, 4rem);
  align-items: center;
}
@media (min-width: 980px) { .app-layout { grid-template-columns: 1.1fr 1fr; } }

.app-points {
  list-style: none;
  padding: 0;
  margin: 0 0 1.75rem;
  display: grid;
  gap: 0.6rem;
}
.app-points li { position: relative; padding-left: 1.7rem; }
.app-points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.3em;
  width: 0.95em;
  height: 0.95em;
  border-radius: 50%;
  background: var(--tangerine);
  border: 2px solid var(--ink);
}

.app-demo { display: grid; justify-items: center; gap: 0.8rem; }
.app-demo-note { font-family: var(--font-ui); font-size: var(--text-2xs); opacity: 0.6; }

.phone--big { width: clamp(16.5rem, 24vw, 20rem); aspect-ratio: 9 / 19; }

.phone__screen--app {
  background: #14171D;
  color: #E9E7DE;
  padding: 1.7rem 0.7rem 0.55rem;
  gap: 0.55rem;
}
.phone__screen--app .app-title { color: #F6F1E4; }
.phone__screen--app .app-note { color: #8E8A7E; }
.phone__screen--app .app-size { border-color: rgba(246, 241, 228, 0.22); color: #CFCBC0; }
.phone__screen--app .app-size b { color: #F6F1E4; }
.phone__screen--app .app-size em { color: var(--cyan); }
.phone__screen--app .app-size.is-on { border-color: var(--tangerine); background: rgba(255, 138, 61, 0.14); }
.phone__screen--app .app-timer { color: #F6F1E4; font-size: 2.7rem; margin: auto 0 0.1rem; }
/* the meter lands with a small pop when a session starts */
.session-live .app-timer { animation: timer-in 0.4s var(--ease-spring) backwards; }
@keyframes timer-in {
  from { opacity: 0; transform: scale(0.86); }
}
.phone__screen--app .app-cost { color: #A9A497; margin-bottom: 0; }

.app-view { display: none; }
.app-view.is-active {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  flex: 1;
  min-height: 0;
  /* iOS-feel navigation: screens slide in on a decelerating curve
     (from-only keyframes: no forwards-fill left behind) */
  animation: view-in 0.34s var(--ease-ios) backwards;
}
/* the confirm screen rises like a native sheet */
.app-view[data-view="confirm"].is-active { animation: sheet-in 0.4s var(--ease-ios) backwards; }
@keyframes view-in {
  from { opacity: 0; transform: translateY(12px) scale(0.985); }
}
@keyframes sheet-in {
  from { opacity: 0; transform: translateY(44px); }
}

.app-search { display: flex; gap: 0.45rem; align-items: center; }
.app-search__pill {
  flex: 1;
  background: #232830;
  border-radius: 999px;
  padding: 0.5rem 0.85rem;
  font-size: 0.68rem;
  font-weight: 600;
  color: #CFCBC0;
}
.app-compass {
  width: 2.05rem;
  height: 2.05rem;
  border-radius: 50%;
  background: #232830;
  display: grid;
  place-items: center;
  color: var(--cyan);
}
.app-compass svg { width: 1.15rem; height: 1.15rem; }

.app-map {
  position: relative;
  flex: 1;
  min-height: 0;
  border-radius: 0.9rem;
  overflow: hidden;
}
.app-map svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.app-chip {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  background: #14171D;
  color: #E9E7DE;
  font-family: var(--font-ui);
  font-size: 0.55rem;
  font-weight: 700;
  padding: 0.28rem 0.6rem;
  border-radius: 999px;
}
.map-pulse {
  transform-box: fill-box;
  transform-origin: center;
  animation: map-ping 2.2s ease-out infinite;
}
@keyframes map-ping {
  0%   { transform: scale(0.45); opacity: 0.65; }
  100% { transform: scale(1.7);  opacity: 0; }
}

.app-card {
  background: #232830;
  border-radius: 0.9rem;
  padding: 0.7rem;
  display: grid;
  gap: 0.45rem;
}
.app-card__title { font-size: 0.72rem; font-weight: 700; color: #F6F1E4; }
.app-card__sub { font-size: 0.62rem; color: #A9A497; }

.app-back { font-size: 0.66rem; color: #A9A497; cursor: pointer; }
.app-back:hover { color: #F6F1E4; }

.map-pin { cursor: pointer; }
.map-pin.is-sel rect:first-of-type { stroke: #F6F1E4; }

/* pick-your-locker mini cabinet */
.unit-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(6, 1fr);
  gap: 4px;
  flex: 1;
  min-height: 0;
}
.ud1 { grid-area: 1 / 1 / 7 / 2; }
.ud2 { grid-area: 1 / 2 / 4 / 3; }
.ud3 { grid-area: 4 / 2 / 7 / 3; }
.ud4 { grid-area: 1 / 3 / 3 / 4; }
.ud5 { grid-area: 3 / 3 / 5 / 4; }
.ud6 { grid-area: 5 / 3 / 7 / 4; }
.ud7 { grid-area: 1 / 4 / 3 / 5; }
.ud8 { grid-area: 3 / 4 / 5 / 5; }
.ud9 { grid-area: 5 / 4 / 7 / 5; }

.u-door {
  display: grid;
  place-content: center;
  gap: 1px;
  padding: 0;
  background: #232830;
  border: 1.5px solid rgba(246, 241, 228, 0.22);
  border-radius: 6px;
  color: #A9A497;
  font-family: var(--font-ui);
  font-size: 0.52rem;
  font-weight: 700;
  letter-spacing: var(--track-micro);
  cursor: pointer;
  transition: border-color 0.15s var(--ease-out), background 0.15s var(--ease-out), transform 0.2s var(--ease-spring);
}
.u-door b { font-family: var(--font-display); font-weight: 700; font-size: 0.85rem; color: #F6F1E4; }
.u-door.is-open:hover { border-color: var(--tangerine); background: rgba(255, 138, 61, 0.12); }
.u-door.is-open:active { transform: scale(0.94); transition-duration: 0.08s; }
.u-door.is-taken { opacity: 0.32; cursor: default; }

/* confirm sheet */
.c-rows { display: grid; gap: 0.4rem; flex: 1; align-content: center; }
.c-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: #232830;
  border-radius: 0.6rem;
  padding: 0.5rem 0.7rem;
  font-size: 0.66rem;
  color: #A9A497;
}
.c-row b { color: #F6F1E4; font-weight: 600; }

.session-empty, .session-live { display: flex; flex-direction: column; gap: 0.55rem; flex: 1; }
.session-live[hidden], .session-empty[hidden] { display: none; }
.session-empty { justify-content: center; text-align: center; }

.app-status {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-family: var(--font-ui);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: var(--track-micro);
  color: #7ED9A8;
}
.app-status i {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: #3FA84C;
  box-shadow: 0 0 8px #3FA84C;
}

.app-me {
  display: flex;
  gap: 0.6rem;
  align-items: center;
  color: #F6F1E4;
  font-size: 0.72rem;
  line-height: 1.3;
  padding: 0.3rem 0 0.5rem;
}
.app-me small { color: #A9A497; }
.app-avatar {
  font-weight: 700;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  background: var(--tangerine);
  color: var(--ink);
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-size: 1rem;
}
.app-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: #232830;
  border-radius: 0.7rem;
  padding: 0.55rem 0.7rem;
  font-size: 0.66rem;
  color: #CFCBC0;
}
.app-row b { color: #F6F1E4; font-weight: 600; }
.app-row--toggle { cursor: pointer; }
.app-switch {
  position: relative;
  width: 1.9rem;
  height: 1.05rem;
  border-radius: 999px;
  background: #3A414D;
  transition: background 0.15s var(--ease-out);
}
.app-switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: calc(1.05rem - 4px);
  height: calc(1.05rem - 4px);
  border-radius: 50%;
  background: #F6F1E4;
  transition: left 0.3s var(--ease-spring);
}
.app-switch.is-on { background: var(--cyan); }
.app-switch.is-on::after { left: calc(100% - 1.05rem + 2px); }

.app-tabbar {
  display: flex;
  justify-content: space-around;
  border-top: 1px solid rgba(246, 241, 228, 0.12);
  padding-top: 0.45rem;
}
.app-tab {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 0.18rem;
  font-size: 0.55rem;
  font-weight: 700;
  letter-spacing: var(--track-ui);
  color: #8E8A7E;
  cursor: pointer;
  padding: 0.1rem 0.5rem;
  transition: color 0.15s var(--ease-out), transform 0.25s var(--ease-spring);
}
.app-tab:active { transform: scale(0.9); }
.app-tab svg { width: 1.15rem; height: 1.15rem; }
.app-tab.is-on { color: var(--tangerine); }
.app-tab__dot {
  position: absolute;
  top: -2px;
  right: 14%;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: #3FA84C;
}
.app-tab__dot[hidden] { display: none; }

/* ---- pre-booking: Now/Later segmented control + pickers ---- */
.seg {
  display: flex;
  gap: 3px;
  padding: 3px;
  background: #232830;
  border-radius: 999px;
}
.seg__opt {
  flex: 1;
  text-align: center;
  font-family: var(--font-ui);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: var(--track-ui);
  color: #A9A497;
  border-radius: 999px;
  padding: 0.32rem 0;
  cursor: pointer;
  transition: background 0.25s var(--ease-ios), color 0.15s var(--ease-out), transform 0.25s var(--ease-spring);
}
.seg__opt:active { transform: scale(0.95); transition-duration: 0.08s; }
.seg__opt.is-on { background: var(--tangerine); color: var(--ink); }

.later-picker { display: grid; gap: 0.35rem; }
.later-picker[hidden] { display: none; }

.app-label {
  font-family: var(--font-ui);
  font-size: 0.55rem;
  font-weight: 600;
  letter-spacing: var(--track-micro);
  color: #8E8A7E;
}
.chip-row { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.app-chip-btn {
  font-family: var(--font-ui);
  font-size: 0.58rem;
  font-weight: 700;
  color: #CFCBC0;
  background: #232830;
  border: 1.5px solid rgba(246, 241, 228, 0.18);
  border-radius: 999px;
  padding: 0.3rem 0.6rem;
  cursor: pointer;
  transition: border-color 0.15s var(--ease-out), background 0.15s var(--ease-out), transform 0.2s var(--ease-spring);
}
.app-chip-btn:active { transform: scale(0.94); transition-duration: 0.08s; }
.app-chip-btn.is-on { border-color: var(--tangerine); background: rgba(255, 138, 61, 0.14); color: #F6F1E4; }

/* ---- the reservation card on the Session tab ---- */
.session-reserved { display: flex; flex-direction: column; gap: 0.55rem; flex: 1; }
.session-reserved[hidden] { display: none; }
.app-status--hold { color: #FFC46B; }
.app-status--hold i { background: var(--tangerine); box-shadow: 0 0 8px var(--tangerine); }
.app-hold {
  font-family: var(--font-ui);
  font-size: 0.62rem;
  text-align: center;
  color: #FFC46B;
}
.app-hold b { font-size: 0.9rem; }
.app-hold[hidden] { display: none; }
.app-cta[hidden], .app-ff[hidden] { display: none; }
.app-cta.is-done { background: #3FA84C; color: #F6F1E4; }

/* ==========================================================================
   Hero sand grain + into-the-locker zoom
   ========================================================================== */
.hero__grain {
  position: absolute;
  left: 0;
  right: 0;
  top: 60.5%;
  height: 39.5%;
  width: 100%;
  z-index: 0;
  opacity: 0.16;
  mix-blend-mode: multiply;
  pointer-events: none;
}

.locker-zoom {
  position: fixed;
  z-index: 90;
  display: grid;
  place-items: center;
  background: radial-gradient(circle at 50% 42%, #1C232D, #0C0F14 72%);
  border-radius: 6px;
  transition:
    left 0.4s var(--ease-flight),
    top 0.4s var(--ease-flight),
    width 0.4s var(--ease-flight),
    height 0.4s var(--ease-flight),
    opacity 0.3s var(--ease-out);
}
.locker-zoom span {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(0.85rem, 2vw, 1.05rem);
  letter-spacing: var(--track-ui);
  color: var(--cyan);
  opacity: 0;
  transition: opacity 0.25s var(--ease-out) 0.18s;
}
.locker-zoom.grow { border-radius: 0; }
.locker-zoom.grow span { opacity: 1; }
.locker-zoom.fade { opacity: 0; }

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer {
  background: var(--night); /* FP8: continuous black out of the join dusk */
  color: var(--bone);
  padding: var(--space-8) var(--pad-x) var(--space-7);
}

.site-footer__inner {
  max-width: var(--max-width);
  margin: 0 auto;
  display: grid;
  gap: 0.9rem;
  justify-items: start;
}

.site-footer__brand {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-md);
}
.site-footer__palm {
  width: 1.8rem;
  height: 2.6rem;
  flex-shrink: 0;
  color: var(--tangerine);
}

.site-footer__contact a {
  font-size: var(--text-sm);
  color: var(--volt);
  /* 44px touch target without shifting the footer's rhythm */
  display: inline-block;
  padding: 0.65rem 0;
  margin: -0.65rem 0;
}

.site-footer__host { font-size: var(--text-sm); }
.site-footer__host a { color: var(--volt); font-weight: 600; }

.site-footer__legal { font-size: var(--text-2xs); opacity: 0.6; margin-top: var(--space-3); }

/* the footer render of the waitlist capture — dark-surface recolors only;
   the component itself is critical CSS (styles.css, hero instance) */
.site-footer .notify { margin: var(--space-4) 0 0; max-width: 27rem; }
.site-footer .notify__row { justify-content: flex-start; }
.site-footer .notify__status.is-error   { color: #FFD9E4; } /* legible alert on night */
.site-footer .notify__status.is-success { color: var(--volt); }


/* ==========================================================================
   FOUNDER PASS — THE AFTERMATH RIDES THE DRY LATCH (extends the A7.5
   state exception; FABLE_STATE has the reasoning). The scroll-driven
   state swaps reverse the moment you scroll back below their range, but
   the water only uncovers the objects a few percent EARLIER — so the
   dead phone was never actually on screen dry. Once the tide has been
   up (main.tide-in, WET at 0.45), the aftermath persists through the
   retreat: wallet and keys stay gone, the phone stays dead and zapping,
   the passport stays soaked — all swapped UNDER high water, revealed as
   it pulls back, and restored only at the full DRY latch (0.22) along
   with the drying sand. !important is load-bearing here: it is what
   lets the latch outrank the scroll-driven keyframes during the
   retreat. This is also the only path phones and Firefox have to the
   aftermath at all (no scroll timelines there — the latch is plain JS).
   Time-based zaps live here too, out of the @supports/width gates,
   paced by the .in-sight IO class and masked inside .ph-dead.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  main.tide-in .pp-dry,
  main.tide-in .thing--wallet svg { opacity: 0 !important; }
  main.tide-in .pp-wet { opacity: 1 !important; }
  /* FP5 — the phone drowns by POSITION, not by the tide latch: it sits
     high beside the heading now, so main.js flips main.phone-drowned
     only once the water has actually covered it (swap hidden under
     water at every width), and the retreat reveals it dead and zapping
     beside Meet BeachBox. Reset at the DRY latch with everything else.
     If the water never reached it, it never dies. */
  main.phone-drowned .ph-ok { opacity: 0 !important; }
  main.phone-drowned .ph-dead { opacity: 1 !important; }
  .ph-ok, .ph-dead, .pp-dry, .pp-wet,
  .thing--wallet svg { transition: opacity 0.7s var(--ease-out, ease); }

  /* founder pass 2 — THE RECEDING WAVE TAKES THE KEYS. The keys sit
     high in the top right, so only the deepest submersion reaches
     them. main.js watches the actual waterline against the keys' box:
     when the water has covered them (scroll down) and then lets go of
     them (scroll up), it latches main.keys-washed and this TIME-based
     exit plays once — the keys slide down the beach with the pull of
     the receding water and are gone. Reset only at the DRY latch,
     with everything else. If the water never reached them, they never
     wash: the wave only takes what it touched. */
  main.keys-washed .thing--keys svg {
    animation: keys-washout 1.7s cubic-bezier(0.5, 0, 0.8, 0.4) forwards;
  }
  @keyframes keys-washout {
    12%  { opacity: 1; }
    to   { transform: translate3d(-2.5rem, 9.5rem, 0) rotate(-42deg); opacity: 0; }
  }

  /* FP13 — THE TOWEL GETS SOAKED. Same law as the keys and the phone:
     main.js watches the real waterline against the towel's box and
     latches main.towel-soaked the moment the wave crosses it on the
     way up. Persists through the retreat; the DRY latch resets it —
     the towel dries with the rest of the beach. All motion is
     transform/opacity; keyframe values hardcoded (no var() in
     keyframes, house law). */
  .tw-wet { opacity: 0; transition: opacity 0.7s var(--ease-out, ease); }
  main.towel-soaked .tw-wet { opacity: 1; }
  .tw-puddle, .tw-puddle-soft {
    transform-box: fill-box;
    transform-origin: center;
    transform: scale(0);
  }
  main.towel-soaked .tw-puddle {
    animation: tw-puddle-grow 2.5s cubic-bezier(0.22, 1, 0.36, 1) forwards;
  }
  main.towel-soaked .tw-puddle-soft {
    animation: tw-puddle-grow 2.5s cubic-bezier(0.22, 1, 0.36, 1) 0.15s forwards;
  }
  @keyframes tw-puddle-grow {
    from { transform: scale(0); }
    to   { transform: scale(1); }
  }
  .tw-drop { opacity: 0; }
  main.towel-soaked .tw-drop { animation: tw-drip 3s linear infinite; }
  main.towel-soaked .tw-drop:nth-child(2) { animation-delay: 0.6s; }
  main.towel-soaked .tw-drop:nth-child(3) { animation-delay: 1.3s; }
  main.towel-soaked .tw-drop:nth-child(4) { animation-delay: 1.9s; }
  @keyframes tw-drip {
    0%   { transform: translate3d(0, 0, 0); opacity: 0; }
    8%   { opacity: 0.9; }
    42%  { transform: translate3d(0, 13px, 0); opacity: 0.8; }
    52%  { transform: translate3d(0, 15px, 0); opacity: 0; }
    100% { transform: translate3d(0, 15px, 0); opacity: 0; }
  }

  /* the dead phone's short-circuit: a zap comes off the casing every
     couple of seconds — two spark events per 2.8s cycle, screen blink
     riding the first, port arc riding the second. TIME-based on
     purpose (damage doesn't scrub). */
  #how.in-sight .ph-glow   { animation: ph-flick 2.8s linear infinite; }
  #how.in-sight .ph-arc    { animation: ph-arcs 2.8s linear infinite; }
  #how.in-sight .ph-zap--a { animation: ph-zap-a 2.8s linear infinite; }
  #how.in-sight .ph-zap--b { animation: ph-zap-b 2.8s linear infinite; }
  @keyframes ph-flick {
    0%, 23.5%, 26.5%, 28%, 62%, 66.5%, 100% { opacity: 0; }
    24.5% { opacity: 0.5; }
    25.6% { opacity: 0.14; }
    63.5% { opacity: 0.4; }
  }
  @keyframes ph-arcs {
    0%, 61.5%, 67%, 100% { opacity: 0; }
    63%, 65.5% { opacity: 0.75; }
  }
  @keyframes ph-zap-a {
    0%, 23.5%, 29%, 100% { opacity: 0; }
    24.5% { opacity: 1; }
    26%   { opacity: 0.2; }
    27.5% { opacity: 0.9; }
  }
  @keyframes ph-zap-b {
    0%, 61%, 67.5%, 100% { opacity: 0; }
    62.5% { opacity: 1; }
    64%   { opacity: 0.25; }
    66%   { opacity: 0.85; }
  }
}

/* Reduced motion, repeated from styles.css — see the header note */
/* ==========================================================================
   Reduced motion
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
  .js .reveal { opacity: 1; transform: none; animation: none; }
  .js .reveal.is-visible { animation: none; }
  /* the evidence appears already stacked: a still version, not a degraded one
     (marker highlights are simply already drawn) */
  .js .press, .js .press-note, .js .press-stamp { opacity: 1; animation: none !important; }
  mark.hl::before { animation: none !important; }
  .door__leaf { transform: none !important; filter: none; }
  .door:hover .door__leaf,
  .door:focus-visible .door__leaf,
  .door.is-open .door__leaf { transform: none; }
  /* peek doors still work without the swing: the leaf simply hides */
  .door--peek.is-open .door__leaf { opacity: 0; }
  .door--peek.is-open .door__items { opacity: 1; transform: none; }
  .hero__palm, .join__palm { animation: none; }
  .shore-swell, .shore-foam { animation: none; }
  .ticker__track { animation: none; }
  /* ambient loops off; JS-driven transforms guarded there too, the
     !important lines are the belt to those braces */
  .hero__glare { animation: none; }
  .hero__copy, .locker-wall { transform: none !important; }
  .composite__stage { transform: none !important; opacity: 1 !important; }
  .canvas-art.is-on, .canvas-art.is-off,
  .composite.is-turning .composite__sheen,
  .app-view.is-active,
  .session-live .app-timer,
  .faq[open] > p { animation: none; }
  /* nothing auto-rotates under reduced motion, so there's nothing to pause */
  .canvas-btn--pause { display: none; }
  /* the idle beachgoer never shows up (JS-gated too — belt and braces) */
  .walker { display: none !important; }
  /* FP13: reduced motion gets the towel already soaked (the wet twin and
     puddles render at rest because their hide/scale-0 rules live inside
     the no-preference block) — only the drip loop needs silencing */
  .tw-drop { display: none !important; }
  /* still water: no bubbles; the tide, foam, and wet band need no rules
     here — their only animations live inside the no-preference scroll
     block, so base styles (the settled tide) already apply */
  .spec-sea__bubbles { display: none; }
  .spec-sea__fish { display: none; }
  .dune-crab, .dune-wet { display: none; }
  .ph-glow, .ph-arc, .ph-zap { animation: none !important; }
  /* the shorebreak holds a quiet low tide */
  .shorebreak__swash { animation: none; transform: translate3d(0, 20%, 0); }
  .cloud { animation: none; }
  .cloud--1 { transform: translateX(10vw); }
  .cloud--2 { transform: translateX(46vw); }
  .cloud--3 { transform: translateX(72vw); }
  .cloud--4 { transform: translateX(82vw); }
  .cloud--5 { transform: translateX(28vw); }
  .cloud--6 { transform: translateX(60vw); }
}

/* ==========================================================================
   FP20 — THE ALIVE PASS (visual panel, Aug 2026)
   Diagnosis (4 seats, unanimous): the page was two websites fighting —
   handcrafted scenes vs. flat black chrome panels. Principle (Noe, the
   designer seat): one continuous shoreline; every section, pricing and
   FAQ included, must physically exist inside that world. Everything below
   is static paint — no new animation, nothing for reduced-motion to gate.
   ========================================================================== */

/* ---- PRICING: night beach under a moon-cool sky ---- */
/* was: one card marooned on flat black (the "PowerPoint in a cave"). Now:
   sky gradient into a dark sand floor, faint stars, moonlight from the
   upper right, and the tiers wear painted locker doors. */
#pricing {
  background:
    radial-gradient(1.5px 1.5px at 12% 18%, rgba(246,241,228,0.5), transparent 100%),
    radial-gradient(1px 1px at 34% 9%,  rgba(246,241,228,0.38), transparent 100%),
    radial-gradient(1.5px 1.5px at 57% 22%, rgba(246,241,228,0.32), transparent 100%),
    radial-gradient(1px 1px at 73% 12%, rgba(246,241,228,0.45), transparent 100%),
    radial-gradient(1px 1px at 88% 26%, rgba(246,241,228,0.3), transparent 100%),
    radial-gradient(1.5px 1.5px at 21% 34%, rgba(246,241,228,0.22), transparent 100%),
    radial-gradient(1px 1px at 66% 38%, rgba(246,241,228,0.25), transparent 100%),
    radial-gradient(44rem 24rem at 84% 4%, rgba(61, 139, 255, 0.10), transparent 64%),
    radial-gradient(70rem 30rem at 50% 102%, rgba(46, 38, 26, 0.55), transparent 76%),
    linear-gradient(180deg, #0A0E15 0%, #0B101B 52%, #12110E 82%, #181410 100%);
}
/* the tiers wear their doors — object paint (cyan / tangerine / hibiscus),
   sized to the tier, slight hand-placed lean, handle dot painted in */
.tier { position: relative; padding-left: 3.6rem; }
.tier::before {
  content: "";
  position: absolute;
  left: 0.15rem;
  top: 50%;
  width: 2.3rem;
  border-radius: 5px;
  box-shadow: inset 0 0 0 2px rgba(34, 38, 46, 0.5), 0.18rem 0.22rem 0 rgba(0, 0, 0, 0.45);
}
.tier:nth-child(1)::before {
  height: 2.3rem;
  transform: translateY(-50%) rotate(-2.2deg);
  background-image:
    radial-gradient(circle at 76% 54%, #22262E 0 12%, transparent 14%),
    linear-gradient(160deg, #4ECFE2 0%, #37C1D6 55%, #2AA3B6 100%);
}
.tier:nth-child(2)::before {
  height: 2.75rem;
  transform: translateY(-50%) rotate(1.6deg);
  background-image:
    radial-gradient(circle at 76% 54%, #22262E 0 11%, transparent 13%),
    linear-gradient(160deg, #FF9D55 0%, #FF8A3D 55%, #E0762F 100%);
}
.tier:nth-child(3)::before {
  height: 3.2rem;
  transform: translateY(-50%) rotate(-1.4deg);
  background-image:
    radial-gradient(circle at 76% 54%, #22262E 0 10%, transparent 12%),
    linear-gradient(160deg, #F55CA4 0%, #F0368B 55%, #C92573 100%);
}
/* phones: the three-column tier row wrapped one word per line and the
   price clipped the viewport edge (designer seat caught it live). Restack. */
@media (max-width: 480px) {
  .tier {
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    row-gap: 0.15rem;
  }
  .tier__size  { grid-column: 1; grid-row: 1; }
  .tier__price { grid-column: 2; grid-row: 1; justify-self: end; }
  .tier__fits  { grid-column: 1 / -1; grid-row: 2; }
}

/* ---- THE SPEC: water gets light ---- */
/* flat teal is paint, not ocean — sun shafts angling in from the surface,
   a floor that actually darkens. Static gradients, painted once. */
.section--spec::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    linear-gradient(112deg, transparent 28%, rgba(220, 242, 251, 0.055) 33%, transparent 41%),
    linear-gradient(102deg, transparent 45%, rgba(220, 242, 251, 0.04) 50%, transparent 58%),
    linear-gradient(122deg, transparent 61%, rgba(220, 242, 251, 0.035) 65%, transparent 72%),
    linear-gradient(180deg, transparent 50%, rgba(2, 16, 20, 0.38) 100%);
}
.section--spec > .section__inner { position: relative; z-index: 1; }

/* ---- MARGINALIA: from floating rules to pinned field notes ---- */
/* same copy, now physically pinned to the page — a note card with a
   pushpin and a hand lean, so the right rail reads deliberate */
.reg-a .margins { opacity: 1; }
.reg-a .margins li {
  background: rgba(10, 14, 21, 0.42);
  border: 1px solid rgba(246, 241, 228, 0.2);
  border-radius: 3px;
  padding: 0.55rem 0.75rem 0.55rem 0.85rem;
  transform: rotate(-1.3deg);
  box-shadow: 0.15rem 0.2rem 0 rgba(0, 0, 0, 0.35);
  opacity: 0.92;
}
.reg-a .margins li + li { margin-top: 0.7rem; }
.reg-a .margins li:nth-child(even) { transform: rotate(1deg); }
.reg-a .margins li:first-child { border-top: 1px solid rgba(246, 241, 228, 0.2); }
.reg-a .margins li::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -0.32rem;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #FF9D55, #E0762F 70%);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

/* ---- FAQ: the boardwalk continues ---- */
/* dim plank bands underfoot, the neon and the volt glowing from off-frame,
   and each question as a raised ticket-stub row (punched left edge) */
#faq {
  background:
    radial-gradient(34rem 20rem at 90% 4%, rgba(240, 54, 139, 0.055), transparent 62%),
    radial-gradient(30rem 18rem at 6% 92%, rgba(61, 139, 255, 0.05), transparent 62%),
    repeating-linear-gradient(180deg,
      #0E1118 0, #0E1118 3.3rem,
      #0A0D13 3.3rem, #0A0D13 3.45rem,
      #10120F 3.45rem, #10120F 6.75rem,
      #0A0D13 6.75rem, #0A0D13 6.9rem),
    var(--night);
}
.faq {
  background: rgba(19, 26, 38, 0.6);
  border: 1px solid var(--hairline);
  border-left: 2px dashed rgba(246, 241, 228, 0.28);
  border-radius: 6px;
  padding: 0 1.05rem;
  margin-bottom: 0.65rem;
}
.faq:last-child { border-bottom: 1px solid var(--hairline); }

/* ---- THE APP: the phone stands on something ---- */
.app-demo { position: relative; }
.app-demo::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -1.1rem;
  width: 72%;
  height: 2.1rem;
  transform: translateX(-50%);
  background: radial-gradient(50% 50% at 50% 50%, rgba(0, 0, 0, 0.55), transparent 72%);
  pointer-events: none;
  z-index: -1;
}

/* ---- THE CANVAS: the billboard stands somewhere ---- */
/* stars overhead, a boardwalk railing silhouette underfoot, and print
   grain on the artwork panel so placeholders read as pulled prints,
   not clip-art (the muralist seat's ask) */
.section--canvas { position: relative; }
.section--canvas {
  background-image:
    radial-gradient(1.5px 1.5px at 16% 12%, rgba(246, 241, 228, 0.4), transparent 100%),
    radial-gradient(1px 1px at 42% 7%, rgba(246, 241, 228, 0.3), transparent 100%),
    radial-gradient(1px 1px at 68% 15%, rgba(246, 241, 228, 0.34), transparent 100%),
    radial-gradient(1.5px 1.5px at 87% 9%, rgba(246, 241, 228, 0.28), transparent 100%),
    radial-gradient(42rem 24rem at 86% 4%, rgba(240, 54, 139, 0.13), transparent 62%),
    radial-gradient(36rem 22rem at 4% 94%, rgba(55, 193, 214, 0.11), transparent 62%);
}
.section--canvas::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2.6rem;
  pointer-events: none;
  background:
    linear-gradient(180deg, #0D0B09 0 0.35rem, transparent 0.35rem),
    repeating-linear-gradient(90deg, transparent 0 2.7rem, #0D0B09 2.7rem 3.05rem);
  opacity: 0.75;
}
.composite__panel { position: relative; }
.composite__panel::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.1;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 240px 240px;
}

/* ---- SHOUT WALL: warmer stone, ghosts of buffed pieces ---- */
/* the concrete had tooth but no life — warm the stone, raise the grain,
   and leave faint cobalt/tangerine halos where earlier paint was buffed */
.shout {
  background-color: #8F887C;
  background-image:
    radial-gradient(26rem 13rem at 24% 30%, rgba(33, 83, 204, 0.09), transparent 65%),
    radial-gradient(20rem 11rem at 70% 68%, rgba(255, 138, 61, 0.08), transparent 65%),
    radial-gradient(30rem 16rem at 78% 22%, rgba(58, 56, 50, 0.12), transparent 62%),
    radial-gradient(26rem 14rem at 12% 74%, rgba(58, 56, 50, 0.14), transparent 64%),
    radial-gradient(22rem 11rem at 44% 8%, rgba(255, 252, 244, 0.08), transparent 60%),
    linear-gradient(180deg, #99927F 0%, #8C857A 55%, #7F7970 100%);
}
.shout::before { opacity: 0.19; }

/* ---- THE STORY: lamplight on the card ---- */
/* the founder's best material was presented like a midnight disclaimer —
   the string-light amber now spills onto it */
.story-card {
  box-shadow:
    0 0 5.5rem 1.5rem rgba(255, 196, 107, 0.09),
    0.4rem 0.45rem 0 rgba(0, 0, 0, 0.55);
}

/* ---- JOIN: cards lift off the night ---- */
.join-grid { align-items: stretch; }
.join-card {
  background: #1A2130;
  border-color: rgba(246, 241, 228, 0.22);
}
.join-card--deposit { background: var(--volt-deep); }
/* "(required)" read as an error before anyone typed (parent seat) */
.field__req { color: rgba(246, 241, 228, 0.65); }

/* ==========================================================================
   FP21 — THE CRAFT PASS (design panel: Noe, Imma, Rio · Aug 2026)
   System consensus (Noe + Imma): one button dialect, one shadow language,
   one accent rule (volt = interactive only), one radius scale, seams at one
   weight. The moment (Rio): the drowned phone gets its payoff — see .epi.
   ========================================================================== */

/* ---- accent rule: volt is interactive; prices and emphasis are bone ---- */
.tier__price { color: var(--bone); }
.pricing-card__line strong { color: var(--bone); }
.tier__price i { opacity: 0.55; }
/* app bullets were tangerine (object paint is for objects) — quiet bone */
.app-points li::before { background: rgba(246, 241, 228, 0.55); }

/* ---- radius scale: pill / 12 / 4 (Noe) ---- */
.faq { border-radius: 4px; }
.reg-a .margins li { border-radius: 4px; }
.field input {
  border-radius: 999px;
  padding-left: 1.1rem;
  padding-right: 1.1rem;
}

/* ---- handmade pass: the FAQ planks get a hand lean ---- */
.faq { transform: rotate(-0.2deg); }
.faq:nth-child(even) { transform: rotate(0.25deg); }

/* ---- pricing card: contact with the ground (Noe: no more float) ---- */
.section--center .pricing-card { position: relative; }
.section--center .pricing-card::after {
  content: "";
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: -1.3rem;
  height: 1.6rem;
  background: radial-gradient(50% 50% at 50% 50%, rgba(0, 0, 0, 0.5), transparent 72%);
  pointer-events: none;
  z-index: -1;
}

/* ---- tier doors peek open on hover (Rio's micro-delight) ---- */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .tier { perspective: 420px; }
  .tier::before { transition: transform 0.35s var(--ease-soft); }
  .tier:nth-child(1):hover::before { transform: translateY(-50%) rotate(-2.2deg) rotateY(-22deg); }
  .tier:nth-child(2):hover::before { transform: translateY(-50%) rotate(1.6deg) rotateY(-22deg); }
  .tier:nth-child(3):hover::before { transform: translateY(-50%) rotate(-1.4deg) rotateY(-22deg); }
}

/* ---- shout wall: roller streaks + the open invitation (Noe) ---- */
.shout__tag {
  position: absolute;
  right: clamp(1rem, 4vw, 3rem);
  bottom: 0.9rem;
  font-family: var(--font-ui);
  font-style: italic;
  font-size: var(--text-2xs);
  letter-spacing: var(--track-micro);
  color: rgba(34, 38, 46, 0.62);
  transform: rotate(-1.6deg);
}

/* ==========================================================================
   FP21 — THE PAYOFF (.epi) — Rio's moment
   The wave drowned a phone two screens ago and it stays dead all visit.
   This is the epilogue: same wave, two fates. Lives INSIDE the spec
   section on purpose — no new section, so the pin-cover and ground-
   handoff rules never engage. Door swing is one rotateY on a hinge
   (compositor-safe); reduced motion and no-JS see it already open.
   ========================================================================== */
.epi { margin-top: clamp(2.5rem, 6vw, 4rem); }
.epi__title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(1.5rem, 3.4vw, 2.4rem);
  letter-spacing: var(--track-title);
  color: var(--bone);
  margin-bottom: 1.4rem;
}
.epi__panels {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
  gap: clamp(1.2rem, 3vw, 2rem);
  max-width: 44rem;
}
.epi__panel {
  margin: 0;
  background: rgba(2, 20, 24, 0.38);
  border: 1px solid rgba(246, 241, 228, 0.14);
  border-radius: 4px;
  padding: 1.3rem 1.2rem 1.1rem;
  text-align: center;
}
.epi__panel figcaption {
  margin-top: 0.85rem;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: rgba(246, 241, 228, 0.78);
}
/* the two phones — same flat object dialect as the dune props */
.epi__phone {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  width: 5.2rem;
  height: 9rem;
  border-radius: 12px;
  background: #22262E;
  box-shadow: inset 0 0 0 3px rgba(246, 241, 228, 0.12);
}
.epi__phone--dead::after {
  /* the crack — one jagged line across a dead screen */
  content: "";
  position: absolute;
  inset: 0.55rem;
  border-radius: 8px;
  background:
    linear-gradient(104deg, transparent 46%, rgba(246, 241, 228, 0.28) 47%, transparent 48.5%),
    linear-gradient(168deg, transparent 60%, rgba(246, 241, 228, 0.2) 61%, transparent 62.5%),
    linear-gradient(180deg, #0B0E13 0%, #10141B 100%);
}
.epi__phone--dead b {
  position: relative;
  z-index: 1;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 0.62rem;
  color: rgba(246, 241, 228, 0.45);
}
.epi__phone--alive {
  background: #22262E;
}
.epi__phone--alive::after {
  content: "";
  position: absolute;
  inset: 0.55rem;
  border-radius: 8px;
  background: linear-gradient(180deg, #8FCEDD 0%, #DCF2FB 100%);
}
.epi__phone--alive b,
.epi__phone--alive span {
  position: relative;
  z-index: 1;
  color: #22262E;
  font-family: var(--font-ui);
}
.epi__phone--alive b { font-size: 1.05rem; font-weight: 800; }
.epi__phone--alive span { font-size: 0.5rem; font-weight: 600; padding: 0 0.5rem; line-height: 1.35; }
/* the cell: a BeachBox interior with a shelf shadow and a hinged door */
.epi__cell {
  position: relative;
  display: inline-block;
  padding: 0.65rem;
  border-radius: 8px;
  background:
    linear-gradient(180deg, rgba(0, 0, 0, 0.4), transparent 40%),
    #1A3A40;
  box-shadow: inset 0 0 0 2px rgba(246, 241, 228, 0.14);
  perspective: 700px;
}
.epi__door {
  position: absolute;
  inset: 0;
  border-radius: 8px;
  transform-origin: left center;
  /* resting state = OPEN (no-JS and reduced-motion see the reveal done) */
  transform: rotateY(-74deg);
  background-image:
    radial-gradient(circle at 82% 52%, #22262E 0 7%, transparent 8.5%),
    linear-gradient(160deg, #FF9D55 0%, #FF8A3D 55%, #E0762F 100%);
  box-shadow: inset 0 0 0 3px rgba(34, 38, 46, 0.5);
  backface-visibility: hidden;
}
@media (prefers-reduced-motion: no-preference) {
  /* JS + motion: the door starts shut and swings once the payoff enters */
  .js .epi:not(.is-visible) .epi__door { transform: rotateY(0deg); }
  .js .epi.is-visible .epi__door {
    transition: transform 1s var(--ease-soft) 0.45s;
  }
}

/* ==========================================================================
   FP21 — LOCKED IN (Rio's second micro-delight)
   The waitlist confirmation isn't a toast: a painted locker door slides
   shut over the card. You joined by putting your email in a box.
   The semantic success message stays in the DOM underneath for SR.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  .join-card.is-locked { position: relative; overflow: hidden; }
  .join-card.is-locked::after {
    content: "locked in · you're on the list";
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-lg);
    letter-spacing: var(--track-title);
    color: var(--night);
    text-align: center;
    padding: 1rem;
    background-image:
      radial-gradient(circle at 88% 50%, #22262E 0 1.5%, transparent 2.2%),
      linear-gradient(160deg, #FF9D55 0%, #FF8A3D 55%, #E0762F 100%);
    box-shadow: inset 0 0 0 4px rgba(34, 38, 46, 0.5);
    animation: epi-doorslam 0.45s var(--ease-spring) both;
  }
}
@keyframes epi-doorslam {
  from { transform: translateY(-104%); }
  to   { transform: translateY(0); }
}

/* ==========================================================================
   FP22 — THE CONFIDENCE PASS (founder's sixteen-point brief, Aug 2026)
   Less UI, more product, more beach, more whitespace. The hero sells the
   dream (the unit stands on its own sand); the problem leads with the
   drill everyone knows; the hedges collapse into one confident statement;
   the waitlist becomes participation.
   ========================================================================== */

/* ---- 8. THE PROBLEM LEADS WITH THE DRILL ---- */
.problem-drill {
  display: block;
  margin-bottom: var(--space-4);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.25rem, 2.6vw, 1.9rem);
  line-height: 1.3;
  letter-spacing: var(--track-title);
  text-wrap: balance;
}
.problem-drill span { display: block; }
.problem-drill span:nth-child(2) { opacity: 0.85; }
.problem-drill span:nth-child(3) { opacity: 0.7; }

/* ---- 4. THE DEMO WEARS ITS FLAG ---- */
.phone__flag {
  position: absolute;
  top: -0.7rem;
  left: 50%;
  transform: translateX(-50%) rotate(-1.4deg);
  z-index: 3;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--night);
  background: var(--bone);
  padding: 0.28rem 0.8rem;
  border-radius: 999px;
  box-shadow: 0.14rem 0.18rem 0 rgba(0, 0, 0, 0.4);
  white-space: nowrap;
}

/* ---- 6. THE PRODUCT LEADS THE SPEC ---- */
/* the render moved above the spec list; give it the room a hero object
   deserves and center it so the section reads product-first */
.product-shot { margin-top: 0; margin-bottom: clamp(2rem, 5vw, 3.25rem); text-align: center; }
.product-shot img { max-width: 46rem; }
.product-shot figcaption { text-align: center; }

/* ---- 10. THE STORY FOLDS ITS RESUME ---- */
.story-more { margin-top: -0.4rem; margin-bottom: var(--space-4); }
.story-more summary {
  cursor: pointer;
  list-style: none;
  display: inline-block;
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--track-micro);
  color: var(--volt);
  border-bottom: 1px dashed currentColor;
  padding-bottom: 0.1rem;
}
.story-more summary::-webkit-details-marker { display: none; }
.story-more summary::after { content: " +"; }
.story-more[open] summary::after { content: " \2013"; }
.story-more p {
  margin-top: 0.8rem;
  font-size: var(--text-sm);
  color: var(--text-2, #CFCBC0);
  max-width: 36rem;
}

/* ---- 14. THE BEACH PICKER (participation, not a form field) ---- */
.field--beach { border: 0; padding: 0; margin-inline: 0; min-width: 0; }
.field--beach legend {
  display: block;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: var(--text-xs);
  letter-spacing: var(--track-micro);
  margin-bottom: 0.5rem;
  padding: 0;
}
.beach-picks {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin-bottom: 0.6rem;
}
.beach-pick { position: relative; }
.beach-pick input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}
.beach-pick span {
  display: inline-block;
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--track-micro);
  color: var(--bone);
  background: rgba(10, 14, 21, 0.4);
  border: 1px solid rgba(246, 241, 228, 0.28);
  border-radius: 999px;
  padding: 0.42rem 0.95rem;
  transition: background 0.15s var(--ease-out), border-color 0.15s var(--ease-out), color 0.15s var(--ease-out);
}
.beach-pick input:checked + span {
  background: var(--volt);
  border-color: var(--volt);
  color: var(--night);
}
.beach-pick input:focus-visible + span {
  outline: 3px solid var(--volt);
  outline-offset: 2px;
}
@media (hover: hover) {
  .beach-pick:hover span { border-color: rgba(246, 241, 228, 0.55); }
}
.field--beach input[type="text"] {
  font-size: var(--text-xs);
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

/* ==========================================================================
   FP24 — THE VISUALS LAND (founder-generated concept imagery, Aug 2026)
   Five images, each with one job; everything labeled "concept
   visualization" (honesty canon), lazy-loaded, hard-sized for zero CLS.
   System rules apply: 4px radius, sticker shadows, captions in the micro
   register. Originals: Downloads/BeachBox_Website_Visuals.zip
   ========================================================================== */

/* ---- the see-it-used band (after the ticker) ---- */
.photo-band {
  position: relative;
  background: var(--night);
}
.photo-band img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 78dvh;
  object-fit: cover;
  object-position: center 62%;
}
.photo-band__cap {
  position: absolute;
  left: var(--pad-x);
  bottom: 0.9rem;
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: var(--track-micro);
  color: var(--bone);
  background: rgba(10, 14, 21, 0.55);
  padding: 0.3rem 0.7rem;
  border-radius: 4px;
  transform: rotate(-0.8deg);
}

/* ---- the spec's what-fits photo (replaces the cutout's silhouette
       treatment: this is a rectangle now, so it gets the card grammar) ---- */
.product-shot img {
  filter: none;
  border-radius: 4px;
  box-shadow: 0.4rem 0.45rem 0 rgba(0, 0, 0, 0.45);
  max-width: 52rem;
}

/* ---- the app column's charger detail ---- */
.app-photo {
  margin: 1.4rem 0 0;
  max-width: 21rem;
}
.app-photo img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 4px;
  box-shadow: 0.4rem 0.45rem 0 rgba(0, 0, 0, 0.45);
}
.app-photo figcaption,
.canvas-photo figcaption,
.artist-photo figcaption {
  margin-top: 0.6rem;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: var(--track-micro);
  color: rgba(246, 241, 228, 0.66);
}

/* ---- the canvas: mural wall large, artist at work beside the card ---- */
.canvas-photo {
  margin: 0 0 clamp(2rem, 5vw, 3rem);
}
.canvas-photo img {
  display: block;
  width: 100%;
  max-width: 58rem;
  height: auto;
  border-radius: 4px;
  box-shadow: 0.45rem 0.5rem 0 rgba(0, 0, 0, 0.5);
}
.artist-photo {
  margin: clamp(2rem, 5vw, 3rem) 0 1.2rem;
  max-width: 24rem;
}
.artist-photo img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 4px;
  box-shadow: 0.4rem 0.45rem 0 rgba(0, 0, 0, 0.5);
  transform: rotate(-0.6deg);
}
/* ≥980px: the painter and the founding-artist card share a row */
@media (min-width: 980px) {
  .artist-photo { float: left; margin: 0 2.2rem 1rem 0; }
  .founding-artist { overflow: hidden; } /* wraps beside the float, clears below */
}

/* ==========================================================================
   FP25 — ONE MACHINE (founder's second image batch, Aug 2026)
   The flat-roof unit is now canon everywhere: hero background, family
   band, footprint proof, night photo in The Story, material macros in
   The Spec, painted artwork in the rotator, cafe shot on the operator
   page. All lazy, all hard-sized, all captioned concept.
   ========================================================================== */

/* the night photo under the story card */
.story-photo {
  margin: clamp(2rem, 5vw, 3rem) 0 0;
}
.story-photo img {
  display: block;
  width: 100%;
  max-width: 52rem;
  height: auto;
  border-radius: 4px;
  box-shadow:
    0 0 4rem 1rem rgba(255, 196, 107, 0.07),
    0.4rem 0.45rem 0 rgba(0, 0, 0, 0.55);
}
.story-photo figcaption {
  margin-top: 0.6rem;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: var(--track-micro);
  color: rgba(246, 241, 228, 0.66);
}

/* the material macros — a quiet two-up under the spec list */
.spec-macros {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
  gap: clamp(1rem, 2.5vw, 1.6rem);
  max-width: 34rem;
  margin: clamp(1.6rem, 4vw, 2.4rem) 0 0;
}
.spec-macros figure { margin: 0; }
.spec-macros img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 4px;
  box-shadow: 0.3rem 0.35rem 0 rgba(0, 0, 0, 0.45);
}
.spec-macros figcaption {
  margin-top: 0.5rem;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: var(--track-micro);
  color: rgba(246, 241, 228, 0.66);
}

/* the rotator's painted slide behaves like its SVG siblings */
img.canvas-art {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
