/* ==========================================================================
   BEACHBOX — STYLESHEET
   --------------------------------------------------------------------------
   Giuseppe: everything you'd want to tweak lives right here at the top.
   Change a hex value below and the whole page updates.
   ========================================================================== */

:root {
  /* ---------- EDIT ME: brand palette ---------- */
  --bone:       #F6F1E4;  /* bleached bone — legacy light bg (photo scrims, dark-surface text) */
  --sand:       #EFE3C6;  /* warm golden sand — bands, alt sections        */
  --pacific:    #0B5E66;  /* deep Pacific teal — brand anchor              */
  --pacific-2:  #084A51;  /* darker teal — dusk ocean                      */
  --tangerine:  #FF8A3D;  /* sunset tangerine — OBJECT PAINT ONLY (logo, cabinet, graffiti, art) */
  --hibiscus:   #F0368B;  /* venice-wall hot pink — use sparingly          */
  --cyan:       #37C1D6;  /* surf cyan — electric accent, use sparingly    */
  --alert:      #D0342C;  /* alarm red — punchlines & error states (the ONE red) */
  --ink:        #22262E;  /* charcoal ink — text                           */
  --paper:      #FDFBF5;  /* warm paper — cards, form fields               */

  /* ---------- Stage B (approved B5 tokens) ---------- */
  --shallows:   #E4EEE9;  /* seafoam glass — RETIRED as ground (FP8); kept for fallbacks */
  --foam:       #F4F8F5;  /* foam white — light chrome & text on cobalt    */
  --signal:     #2153CC;  /* cobalt — legacy accent (graffiti keeps it)    */

  /* ---------- FP8 (founder-directed): the NIGHT register — Kalshi-style
     black grounds with ONE bright electric blue. Replaces the seafoam
     ground everywhere the page is chrome rather than scenery; the set
     pieces (hero photo, dune, sea, newspaper, graffiti wall, gallery
     steel) keep their paint. ---------- */
  --night:     #0A0E15;  /* near-black with a blue cast — the ground      */
  --night-2:   #131A26;  /* raised card surface on night                  */
  --volt:      #3D8BFF;  /* THE electric blue — accents, prices, links    */
  --volt-deep: #1D5EE8;  /* filled volt — pressed states, deposit card    */
  --hairline:  rgba(246, 241, 228, 0.16); /* borders on night             */

  /* sunset sky (Join section — the day ends where you sign up) */
  --dusk-top:   #F97D54;
  --dusk-low:   #FFC98A;

  /* ---------- type (ONE interface family + the evidence serif) ----------
     Plus Jakarta Sans carries display, body AND every small label. There
     is no separate display face and no mono: hierarchy comes from size,
     weight and color, never from a second typeface, ALL CAPS or tracking.
     'Jakarta Fallback' is metrics-adjusted local Arial (per-weight
     size-adjust, measured) so the swap doesn't re-wrap text — the hero
     subhead was the page's one layout shift without it.
     --font-ui is the same family; it exists so small-label rules read as
     a deliberate role rather than "body, but smaller". */
  --font-display: 'Bricolage Grotesque', 'Bricolage Fallback', -apple-system, 'Helvetica Neue', Arial, sans-serif;
  --font-body:    'Plus Jakarta Sans', 'Jakarta Fallback', -apple-system, 'Helvetica Neue', Arial, sans-serif;
  --font-ui:      'Plus Jakarta Sans', 'Jakarta Fallback', -apple-system, 'Helvetica Neue', Arial, sans-serif;
  --font-press:      'Redaction 20', Georgia, 'Times New Roman', serif;
  --font-press-lead: 'Redaction 35', Georgia, 'Times New Roman', serif; /* the lead clipping only */

  /* ---------- tracking ladder (iOS optical sizing: the bigger the type,
     the tighter it sets; small text gets a hair of positive tracking for
     legibility, never the 0.08–0.14em "terminal" spacing this pass
     removed). One of these on every text rule — no ad-hoc values. ------ */
  --track-display: -0.033em;   /* hero + section headlines */
  --track-title:   -0.022em;   /* card titles, prices, big numbers */
  --track-body:    -0.006em;   /* running copy */
  --track-ui:      -0.004em;   /* buttons, nav, labels */
  --track-micro:    0.005em;   /* captions, meta, fine print */

  /* ---------- type scale — one ladder; every page-chrome size is a step.
     (The phone-demo interior and the cabinet's object labels are
     mock-scale miniatures and keep their own tuned sizes.) ---------- */
  /* A4.4 graffiti piece — PROVISIONAL tokens (existing page accents);
     Stage B may re-tune these against the final palette by name */
  /* A5.6: cobalt/object-paint family only — no rainbow */
  --graf-1: #2153CC;                       /* cobalt — the dominant coat  */
  --graf-2: #173C9E;                       /* deep cobalt — alternation   */
  --graf-3: #37C1D6;                       /* surf cyan — sparse          */
  --graf-4: #FF8A3D;                       /* tangerine — two pops only   */
  --graf-line: #22262E;
  --graf-shadow: rgba(20, 18, 26, 0.66);
  --graf-glint: rgba(255, 252, 244, 0.85);

  --text-2xs:  0.75rem;                        /* placards, badges, fine print */
  --text-xs:   0.85rem;                        /* small labels, footnotes      */
  --text-sm:   0.95rem;                        /* secondary copy, nav          */
  --text-base: 1.0625rem;                      /* body                         */
  --text-md:   1.15rem;                        /* emphasized UI, card meta     */
  --text-lg:   1.3rem;                         /* wordmark, card titles        */
  --text-xl:   1.55rem;                        /* tier prices                  */
  --text-copy: clamp(1rem, 2vw, 1.15rem);      /* section body                 */
  --text-lead: clamp(1.05rem, 2.2vw, 1.3rem);  /* leads, subheads, kickers     */
  --text-h2:   clamp(1.9rem, 4.8vw, 3.5rem);   /* section headlines            */
  --text-h1:   clamp(2.6rem, 7.5vw, 5.9rem);   /* hero                         */

  /* ---------- spacing scale — one rhythm ladder on a 4px grid.
     Vertical rhythm (section padding, block margins) sits on these
     steps; component-internal optical padding stays hand-tuned. ---------- */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 2.5rem;
  --space-8: 4rem;
  --space-section: clamp(3.5rem, 9vw, 6.5rem); /* fluid — scales down proportionally on mobile */

  /* ---------- layout ---------- */
  --max-width: 72rem;
  --pad-x: clamp(1.25rem, 4vw, 2.5rem);
  --radius: 16px;
  --unit-pad: clamp(0.6rem, 1.4vw, 1.1rem);

  --stamp-shadow: 0.5rem 0.5rem 0 rgba(34, 38, 46, 0.92);

  /* ---------- motion: real curves, used everywhere ---------- */
  --ease-out:    cubic-bezier(0.22, 1, 0.36, 1);    /* fast start, long settle */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* slight overshoot        */
  --ease-ios:    cubic-bezier(0.32, 0.72, 0, 1);    /* iOS sheet/nav feel      */
  --ease-soft:   cubic-bezier(0.34, 1.3, 0.5, 1);   /* gentler spring — doors  */
  --ease-flight: cubic-bezier(0.4, 0, 0.2, 1);      /* locker-zoom camera move */
}

/* ==========================================================================
   Self-hosted fonts (Plus Jakarta Sans, Redaction — SIL Open Font License)
   --------------------------------------------------------------------------
   TYPE OVERHAUL (founder-directed: "clean, easy, iOS"): ONE variable
   family carries the entire interface — hero, headlines, body, labels,
   buttons, captions — the way a system font does. Weight is the only
   hierarchy lever besides size. Cabinet Grotesk (3 files) and Space
   Mono (2 files) are both retired: the mono was the single biggest
   source of the "techy" read, and one variable face at 21KB replaces
   56KB of static ones. Files stay on disk, unreferenced.
   Redaction (the newspaper evidence stack) is the ONE other voice and
   still loads from deferred.css on purpose: declared here it fetches at
   VeryHigh priority before first paint and costs the LCP ~500ms
   (A/B-measured). The press styles that use it are deferred too.
   ========================================================================== */
@font-face {
  font-family: 'Plus Jakarta Sans';
  src: url('../fonts/jakarta-var.woff2') format('woff2');
  font-weight: 400 800;         /* variable — real weights, no synthesis */
  font-style: normal;
  font-display: swap;
}
/* FP4 (founder: "generic") — the display voice gets its own face:
   Bricolage Grotesque 600–800, chunky ink-trapped warmth for headlines,
   buttons and prices. Jakarta keeps body + small UI. Two voices, two
   jobs — that's the consistency system, not a third accent. */
@font-face {
  font-family: 'Bricolage Grotesque';
  src: url('../fonts/bricolage-var.woff2') format('woff2');
  font-weight: 600 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Bricolage Fallback';
  src: local('Arial');
  font-weight: 600 700;
  size-adjust: 101%;   /* measured vs the page's own headline strings */
}
@font-face {
  font-family: 'Bricolage Fallback';
  src: local('Arial');
  font-weight: 800 900;
  size-adjust: 90%;
}
/* zero-CLS swap: local Arial scaled per weight band to Jakarta's own
   measure (measured against the page's body string — Jakarta runs wider
   than Arial at text weights and much narrower at display weight, so one
   shared number would shift the hero). */
@font-face {
  font-family: 'Jakarta Fallback';
  src: local('Arial');
  font-weight: 400 500;
  size-adjust: 104.5%;
}
@font-face {
  font-family: 'Jakarta Fallback';
  src: local('Arial');
  font-weight: 600 700;
  size-adjust: 99%;
}
@font-face {
  font-family: 'Jakarta Fallback';
  src: local('Arial');
  font-weight: 800 900;
  size-adjust: 88%;
}

/* ==========================================================================
   Reset & base
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 4.5rem;
  /* A4.0: mobile browsers may re-inflate text toward "desktop scale"
     (Safari on rotate, Android font boosting) — the type scale is
     deliberate, keep it */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.55;
  letter-spacing: var(--track-body);
  color: var(--ink);
  background: var(--night); /* FP8: the register stands on night now */
  -webkit-font-smoothing: antialiased;
}

img, svg { max-width: 100%; display: block; }

/* site-wide film grain — felt, not seen */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 98;
  pointer-events: none;
  opacity: 0.05;
  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");
}
h1, h2, h3, p, ol, ul, figure { margin: 0; }
a { color: inherit; }

/* Focus ring: brand teal, not tangerine — tangerine was doing four jobs
   (action, decoration, selection, focus) and read weakly on warm sand.
   Dark surfaces flip the ring to bone so it never disappears. */
:focus-visible {
  outline: 3px solid var(--signal); /* Stage B: cobalt is the one accent */
  outline-offset: 3px;
  border-radius: 4px;
}
.ticker :focus-visible,
.shout :focus-visible,
.section--spec :focus-visible,
.section--canvas :focus-visible,
.join-card--deposit :focus-visible,
.site-footer :focus-visible {
  outline-color: var(--bone);
}

::selection { background: var(--signal); color: var(--foam); }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--ink);
  color: var(--bone);
  padding: 0.75rem 1.25rem;
  font-family: var(--font-ui);
  font-size: var(--text-xs);
}
.skip-link:focus { left: 0.5rem; top: 0.5rem; }

/* screen-reader text: rendered for AT, invisible on screen */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   Placards — the "museum wall label" device
   ========================================================================== */
.placard {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5em;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: var(--track-micro);
  border-top: 2px solid currentColor;
  padding-top: 0.55em;
  margin-bottom: var(--space-4);
}
.placard__dot { opacity: 0.45; }
.placard--outro { margin-top: var(--space-7); margin-bottom: 0; }

/* ==========================================================================
   Header
   ========================================================================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem var(--pad-x);
  /* FP8: the banner goes night — black glass, bone type, volt accents */
  color: var(--bone);
  background: var(--night); /* fallback for browsers without color-mix */
  background: color-mix(in srgb, var(--night) 86%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--hairline);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  text-decoration: none;
  flex-shrink: 0;
}
.brand__mark { width: 1.9rem; height: 1.9rem; }
.brand__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-lg);
  letter-spacing: var(--track-title);
  line-height: 1;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(0.4rem, 2vw, 1.4rem);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.site-nav::-webkit-scrollbar { display: none; }

.site-nav a {
  position: relative;
  /* FP8: the banner speaks the display voice too (founder-directed) —
     Bricolage floor weight is 600, so 600 is the lightest legal step */
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: var(--track-ui);
  text-decoration: none;
  white-space: nowrap;
  padding: 0.35rem 0.15rem;
}
/* invisible hit-area extension — 44px+ touch targets without moving a pixel.
   Horizontal stays inside the min nav gap so neighbors never overlap. */
.site-nav a::before {
  content: "";
  position: absolute;
  left: -0.15rem;
  right: -0.15rem;
  top: -0.55rem;
  bottom: -0.55rem;
}
/* underline that draws itself in from the left */
.site-nav a:not(.site-nav__cta)::after {
  content: "";
  position: absolute;
  left: 0.15rem;
  right: 0.15rem;
  bottom: 0.1rem;
  height: 2px;
  background: var(--volt);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.32s var(--ease-out);
}
.site-nav a:not(.site-nav__cta):hover::after,
.site-nav a:not(.site-nav__cta):focus-visible::after { transform: scaleX(1); }

/* nav CTA: a miniature ticket stub — chamfered cut corner, no pill.
   FP21: joins the sticker-shadow language (one shadow dialect sitewide) */
.site-nav__cta {
  /* FP8: neon stub — volt face, night type (the Kalshi read) */
  background: var(--volt);
  color: var(--night) !important;
  font-weight: 700;
  padding: 0.4rem 0.9rem !important;
  clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 9px, 100% 100%, 0 100%);
  filter: drop-shadow(3px 3px 0 rgba(0, 0, 0, 0.45));
  transition: background 0.15s var(--ease-out), transform 0.3s var(--ease-spring);
}
.site-nav__cta:hover { background: var(--foam); transform: translateY(-1px); }
.site-nav__cta:active { transform: translateY(0) scale(0.96); transition-duration: 0.08s; }
/* clip-path clips the outline — draw the focus ring inside the stub */
.site-nav__cta:focus-visible { outline-color: var(--foam); outline-offset: -4px; }

@media (max-width: 560px) {
  .site-nav a:not(.site-nav__cta) { display: none; }
}

/* ==========================================================================
   Buttons
   ========================================================================== */
/* Stage B: the ticket stub (built exactly like the approved /type-test
   specimen). The element is the 2px ink ring; the inner <span> is the
   ticket face; the chamfer is the same cut on both layers; the hard
   offset shadow is a drop-shadow of the clipped silhouette — no blur,
   no pills, anywhere in the product register. */
/* FP4 (founder: "boxes scream tech startup") — buttons are surfboards
   now: long full-radius decks with the ink ring as the rail and the
   same press-into-the-shadow physics. The stub clip-paths are gone. */
.btn {
  display: inline-block;
  padding: 2px;               /* the ring's thickness — the rail.
     FP21 (panel): bone, so the sticker outline reads on night grounds
     the way the hero's does on sky — ONE button dialect sitewide.
     The hero paints its own ring and is unaffected. */
  background: var(--bone);
  border: none;
  border-radius: 999px;
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  filter: drop-shadow(4px 5px 0 rgba(0, 0, 0, 0.55));
  transition: transform 0.2s var(--ease-out), filter 0.2s var(--ease-out);
}
.btn > span {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-sm);
  letter-spacing: var(--track-ui);
  padding: 0.8rem 1.9rem;
  border-radius: 999px;
}
.btn:hover {
  transform: translate(3px, 3px); /* presses into its own shadow */
  filter: drop-shadow(1px 2px 0 rgba(24, 20, 30, 0.7));
}
.btn:active {
  transform: translate(4px, 5px);
  transition-duration: 0.08s;
  filter: drop-shadow(0 0 0 rgba(24, 20, 30, 0.7));
}
.btn:focus-visible { outline: none; }
.btn:focus-visible > span { outline: 3px solid currentColor; outline-offset: -7px; }

/* FP8: primary actions go volt — night type on the electric blue face
   (5.6:1 on the deck; the old cobalt/foam pair read seafoam-era) */
.btn--primary > span { background: var(--volt); color: var(--night); }
.btn--ghost > span   { background: var(--paper);  color: var(--ink); }
.btn--deposit > span { background: var(--volt); color: var(--night); }
.btn--full    { width: 100%; }

/* ==========================================================================
   Hero — a clear beach day, painted realistically
   ========================================================================== */
.hero {
  /* real golden-hour SoCal photography, with the old painted scene kept
     underneath as a fallback if the image ever goes missing.
     Photo: Unsplash (@nceglia), free commercial license — see README.
     B-LCP: same photo, delivery fixed — AVIF/WebP where supported, a
     1080w file for phones, 1920w for desktop. The 474KB source jpg
     stays in /assets as the archival original; nothing loads it. */
  --hero-sky: linear-gradient(
      to bottom,
      #2478C8 0%,
      #52A8E0 26%,
      #A6DCF5 44%,
      #DCF2FB 47%,
      #146F8C 47%,
      #1E93AC 54%,
      #2FA9BC 60%,
      #F2E4C4 60%,
      #E9D6AC 100%
    );
  position: relative;
  overflow: hidden;
  /* FP25: the founder's generated hero — the unit itself standing on the
     sand, empty sky left for the headline (the manifest's own note). The
     Unsplash photo files stay in /assets as instant revert. WebP+JPEG
     only: the canvas encoder can't emit AVIF, and 95KB webp beats the
     old avif anyway. Mobile file is a right-weighted crop so the unit
     survives the narrow frame. */
  background:
    url('../assets/hero-unit-1536.jpg') center 68% / cover no-repeat,
    var(--hero-sky);
  padding: clamp(2.5rem, 7vw, 5rem) var(--pad-x) clamp(2.5rem, 6vw, 4rem);
}
@supports (background-image: image-set(url('x.webp') type('image/webp'))) {
  .hero {
    background-image:
      image-set(
        url('../assets/hero-unit-1536.webp') type('image/webp'),
        url('../assets/hero-unit-1536.jpg') type('image/jpeg')),
      var(--hero-sky);
  }
}
@media (max-width: 700px) {
  .hero {
    background-image:
      url('../assets/hero-unit-1080.jpg'),
      var(--hero-sky);
    background-position: center 82%;
  }
  @supports (background-image: image-set(url('x.webp') type('image/webp'))) {
    .hero {
      background-image:
        image-set(
          url('../assets/hero-unit-1080.webp') type('image/webp'),
          url('../assets/hero-unit-1080.jpg') type('image/jpeg')),
        var(--hero-sky);
    }
  }
}
/* FP25: with the unit standing in the photo's right half, the copy
   column moves LEFT into the empty sky — the composition the image was
   generated for. Phones get a sky-tinted scrim so text stays legible
   over the tighter crop. */
@media (min-width: 701px) {
  .hero .hero__copy {
    margin-left: clamp(0rem, 3vw, 3rem);
    margin-right: auto;
    max-width: 38rem;
    text-align: left;
  }
  .hero .hero__copy .placard--hero { justify-content: flex-start; }
  .hero .hero__headline { font-size: clamp(2.6rem, 5vw, 4.7rem); }
  .hero .notify__row { justify-content: flex-start; }
  .hero .hero__subhead { margin-left: 0; max-width: 30rem; }
}
@media (max-width: 700px) {
  .hero::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background: linear-gradient(180deg,
      rgba(214, 236, 248, 0.82) 0%,
      rgba(214, 236, 248, 0.6) 42%,
      rgba(214, 236, 248, 0.18) 60%,
      transparent 72%);
  }
  .hero .hero__copy { position: relative; z-index: 3; }
}

/* the honesty chip: the hero is a concept render and says so, quietly */
.hero__tag {
  position: absolute;
  right: 0.9rem;
  bottom: 0.7rem;
  z-index: 2;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: var(--track-micro);
  color: rgba(34, 38, 46, 0.6);
  background: rgba(246, 241, 228, 0.55);
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
}

/* readability scrim over the photo: warm light from the left for the ink
   headline, a whisper of ground shadow at the base for the cabinet */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    linear-gradient(100deg,
      rgba(246, 241, 228, 0.93) 0%,
      rgba(246, 241, 228, 0.78) 30%,
      rgba(246, 241, 228, 0.34) 55%,
      rgba(246, 241, 228, 0) 76%),
    linear-gradient(to top, rgba(20, 24, 30, 0.22), transparent 26%);
}

/* the painted scenery retires in favor of the photograph */
.hero__clouds, .hero__gulls, .hero__shore,
.hero__seawall, .hero__palm, .hero__grain { display: none; }

/* ---------------- drifting clouds ---------------- */
.hero__clouds {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.cloud {
  position: absolute;
  left: 0;
  width: clamp(11rem, 21vw, 19rem);
  animation: cloud-drift linear infinite;
}
/* negative delays chosen so the sky is already populated on page load */
.cloud--1 { top: 4%;  animation-duration: 110s; animation-delay: -51s; }
.cloud--2 { top: 14%; width: clamp(7rem, 13vw, 12rem); opacity: 0.9; animation-duration: 150s; animation-delay: -102s; }
.cloud--3 { top: 26%; width: clamp(5.5rem, 10vw, 9.5rem); opacity: 0.75; animation-duration: 180s; animation-delay: -58s; }
.cloud--4 { top: 8%;  width: clamp(8rem, 15vw, 13rem); opacity: 0.95; animation-duration: 130s; animation-delay: -107s; }
.cloud--5 { top: 20%; width: clamp(6rem, 11vw, 10rem); opacity: 0.65; animation-duration: 170s; animation-delay: -95s; }
.cloud--6 { top: 32%; width: clamp(4.5rem, 8vw, 7.5rem); opacity: 0.5; animation-duration: 210s; animation-delay: -183s; }

@keyframes cloud-drift {
  from { transform: translateX(-30vw); }
  to   { transform: translateX(110vw); }
}

.hero__gulls {
  position: absolute;
  z-index: 1;
  top: 8%;
  right: 24%;
  width: clamp(5rem, 10vw, 8.5rem);
}

/* ambient 1 of 2: a pool of golden glare drifting slowly over the water.
   Transform-only loop (JS fades it as you scroll away); reduced motion
   stops the drift. */
.hero__glare {
  position: absolute;
  z-index: 0;
  top: 10%;
  right: -14%;
  width: clamp(22rem, 52vw, 50rem);
  aspect-ratio: 1;
  pointer-events: none;
  mix-blend-mode: screen;
  background: radial-gradient(circle,
    rgba(255, 219, 153, 0.5) 0%,
    rgba(255, 200, 130, 0.16) 40%,
    transparent 66%);
  animation: glare-drift 38s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes glare-drift {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(-8%, 6%, 0) scale(1.14); }
}

/* shoreline overlay: swell, glitter, foam, wet sand (aligned to the 60% waterline) */
.hero__shore {
  position: absolute;
  z-index: 0;
  left: 0;
  top: 48.9%;
  width: 100%;
  height: 15%;
  pointer-events: none;
}

/* living water: swell drifts sideways, foam breathes up the sand */
.shore-swell, .shore-foam { transform-box: fill-box; }
.shore-swell { animation: swell-drift 12s ease-in-out infinite alternate; }
.shore-foam  { animation: foam-breathe 6s ease-in-out infinite alternate; }

@keyframes swell-drift {
  from { transform: translateX(-3%); }
  to   { transform: translateX(3%); }
}
@keyframes foam-breathe {
  from { transform: translate(-1.6%, -2px); opacity: 0.78; }
  to   { transform: translate(1.6%, 5px);   opacity: 1; }
}

/* painted seawall: full-bleed along the sand, in front of the palm trunks */
.hero__seawall {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  top: 61%;
  height: 10.5%;
  min-height: 3.5rem;
  width: 100%;
}

/* ---------------- palms ---------------- */
.hero__palm {
  position: absolute;
  z-index: 1;                    /* behind the seawall — they rise from beyond it */
  bottom: 33%;
  height: clamp(11rem, 26vw, 21rem);
  width: auto;
  transform-origin: bottom center;
  animation: palm-sway 7s ease-in-out infinite alternate;
}
.hero__palm--back {
  right: clamp(4.5rem, 10vw, 9rem);
  height: clamp(7rem, 16vw, 13rem);
  animation-duration: 9s;
  animation-delay: -4s;
  filter: saturate(0.85) brightness(0.92);  /* a touch hazier, further away */
}
.hero__palm--front {
  right: clamp(-3.5rem, -2vw, -1.25rem);
  transform: scaleX(-1);
  animation-duration: 8.5s;
  animation-delay: -3s;
}

@keyframes palm-sway {
  from { rotate: -2.6deg; }
  to   { rotate:  2.6deg; }
}
.hero__palm--mid {
  right: clamp(7rem, 16vw, 14rem);
  height: clamp(6rem, 13vw, 10.5rem);
  animation-duration: 7.5s;
  animation-delay: -6s;
  filter: saturate(0.8) brightness(0.88);
}
@media (max-width: 900px) { .hero__palm--mid { display: none; } }

@media (max-width: 700px) {
  .hero__palm--back { display: none; }
  .hero__palm--front { bottom: 34%; height: 9.5rem; }
}

/* ---------------- hero copy ---------------- */
/* A4.3: centered as a block — eyebrow, h1, subhead, buttons, chip.
   Alignment only; type, weights, and colors unchanged. */
.hero__copy {
  position: relative;
  z-index: 3;
  max-width: var(--max-width);
  margin: 0 auto;
  text-align: center;
}

.placard--hero { color: var(--ink); }

/* FP3: Jakarta 800, sentence case — the register the founder
   picked off /type-test. No uppercase, no sticker effects: the h1's job
   is tone, and the tone is set by the face now. */
.hero__headline {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--text-h1);
  line-height: 1.02;
  letter-spacing: var(--track-display);
  max-width: 15ch;
  margin: 0.25rem auto 1.25rem;
  text-wrap: balance;
}
/* the accented word — cobalt, plain */
.hero__headline em {
  font-style: normal;
  color: var(--signal);
  /* FP21 (Rio): the one word that gets the artists' treatment — a slight
     hand lean and an off-register tangerine pop, the graffiti wall's own
     print error. Instantly ours; still just type. */
  display: inline-block;
  transform: rotate(-1.6deg);
  text-shadow: 0.055em 0.06em 0 var(--tangerine);
}

.hero__subhead {
  font-size: var(--text-lead);
  font-weight: 500;
  max-width: 34rem;
  text-wrap: pretty;
  margin-inline: auto;
  margin-bottom: var(--space-6);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.25rem;
  justify-content: center;
}
/* FP4 — the hero pair is ONE longboard (founder-directed): both actions
   share a single full-radius deck, the ink gap between them is the
   stringer, and the whole board lies at a beach-towel tilt. The board
   presses into its own shadow as one object; the halves keep their own
   focus rings. Wraps back to two separate boards only if a translation
   ever overflows a phone (flex-wrap above still allows it). */
@media (min-width: 361px) {
  .hero__actions {
    display: inline-flex;
    flex-wrap: nowrap;
    gap: 2px;                 /* the stringer — ink shows through */
    padding: 2px;
    background: var(--ink);
    border-radius: 999px;
    margin-inline: auto;
    transform: rotate(-1.4deg);
    filter: drop-shadow(4px 5px 0 rgba(24, 20, 30, 0.55));
    transition: transform 0.2s var(--ease-out), filter 0.2s var(--ease-out);
  }
  .hero__actions .btn { padding: 0; background: none; filter: none; transition: none; }
  .hero__actions .btn:hover, .hero__actions .btn:active { transform: none; filter: none; }
  .hero__actions .btn > span { border-radius: 0; padding: 0.85rem 1.7rem; }
  .hero__actions .btn:first-child > span { border-radius: 999px 0 0 999px; padding-left: 2.1rem; }
  .hero__actions .btn:last-child > span { border-radius: 0 999px 999px 0; padding-right: 2.1rem; }
  .hero__actions:has(.btn:hover) {
    transform: rotate(-1.4deg) translate(3px, 3px);
    filter: drop-shadow(1px 2px 0 rgba(24, 20, 30, 0.55));
  }
  .hero__actions:has(.btn:active) {
    transform: rotate(-1.4deg) translate(4px, 5px);
    filter: drop-shadow(0 0 0 rgba(24, 20, 30, 0.55));
  }
  .hero__actions .btn > span { white-space: nowrap; } /* a board doesn't fold */
}
@media (min-width: 361px) and (max-width: 430px) {
  .hero__actions .btn > span { font-size: var(--text-xs); padding: 0.8rem 1.15rem; }
  .hero__actions .btn:first-child > span { padding-left: 1.45rem; }
  .hero__actions .btn:last-child > span { padding-right: 1.45rem; }
}

/* FP22 (founder): the hero sells the product — the whole unit stands on
   the hero's own sand, wide and low against the horizon. Critical CSS on
   purpose: it is above the fold, and the img carries width/height so CLS
   stays 0.0000. Small screens get it beneath the capture, modest. */
.hero__unit {
  margin: 1.7rem auto 0;
  max-width: min(21rem, 86vw);
}
.hero__unit img {
  width: 100%;
  height: auto;
  filter:
    drop-shadow(0 4px 7px rgba(20, 16, 8, 0.38))
    drop-shadow(0 16px 30px rgba(20, 16, 8, 0.24));
}
.hero__unit figcaption {
  margin-top: 0.55rem;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: var(--track-micro);
  color: rgba(34, 38, 46, 0.72);
  text-align: center;
}
@media (min-width: 701px) {
  /* in flow, centered under the capture — the eye lands on the product
     right after the headline, and nothing ever collides at any width */
  .hero__unit { margin-top: 2.1rem; max-width: clamp(24rem, 36vw, 30rem); }
}

.hero__trust {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5em;
  margin-top: var(--space-5);
  /* slapped on like a torn ticket, not typeset — no pills in the register */
  transform: rotate(-1.1deg);
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: var(--track-micro);
  color: var(--ink);
  background: rgba(244, 248, 245, 0.8);
  clip-path: polygon(0 0, calc(100% - 11px) 0, 100% 11px, 100% 100%, 0 100%);
  filter: drop-shadow(3px 4px 0 rgba(24, 20, 30, 0.3));
  padding: 0.45rem 1.1rem;
}

/* ==========================================================================
   THE SHORT ANSWERS (FP12, panel-directed) — the band right under the
   hero that answers the three questions people actually arrive with,
   each a one-tap jump. Critical CSS: it sits at the fold line.
   ========================================================================== */
.quick-answers {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  background: var(--night);
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}
.quick-answers a {
  display: block;
  padding: 1.05rem clamp(1rem, 3vw, 2rem) 1.15rem;
  text-decoration: none;
  color: var(--bone);
  border-left: 1px solid var(--hairline);
  transition: background 0.2s var(--ease-out);
}
.quick-answers a:first-child { border-left: none; }
.quick-answers a:hover { background: var(--night-2); }
.quick-answers a:focus-visible { outline-offset: -4px; }
.quick-answers b {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-md);
  letter-spacing: var(--track-title);
  color: var(--volt);
  margin-bottom: 0.2rem;
}
.quick-answers span {
  display: block;
  font-size: var(--text-xs);
  line-height: 1.45;
  color: rgba(246, 241, 228, 0.75);
}
@media (max-width: 740px) {
  .quick-answers { grid-template-columns: 1fr; }
  .quick-answers a { border-left: none; border-top: 1px solid var(--hairline); padding: 0.85rem var(--pad-x) 0.95rem; }
  .quick-answers a:first-child { border-top: none; }
}

/* ==========================================================================
   Waitlist capture (owner-directed, July 2026) — one component, rendered
   in the hero and again in the footer. Critical CSS on purpose: the hero
   instance is above the fold, and deferred.css would flash it. The status
   line reserves its own height so appearing text can't shift layout.
   ========================================================================== */
.notify {
  max-width: 27rem;
  margin: var(--space-5) auto 0;
}
.notify__label {
  display: block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-sm);
  letter-spacing: var(--track-ui);
  margin-bottom: 0.55rem;
}
.notify__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem;
}
.notify__input {
  flex: 1 1 12rem;
  min-width: 0;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--ink);
  background: var(--paper);
  border: 2px solid rgba(34, 38, 46, 0.7);
  border-radius: 999px; /* sits in the surfboard register, not the field one */
  padding: 0.7rem 1.15rem;
  transition: border-color 0.15s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.notify__input:focus { border-color: var(--pacific); box-shadow: 0 0 0 4px rgba(11, 94, 102, 0.14); }
.notify__input:focus-visible { outline-offset: 1px; }
.notify__input.is-invalid { border-color: var(--hibiscus); }
.notify__status {
  /* reserved line — status text must not move the page (min-height
     matches the line box exactly, so the shift is 0, not sub-pixel) */
  line-height: 1.5;
  min-height: 1.5em;
  margin-top: 0.55rem;
  font-weight: 600;
  font-size: var(--text-xs);
}
.notify__status.is-error   { color: var(--alert); }
.notify__status.is-success { color: var(--pacific); }

/* ==========================================================================
   The locker wall — DORMANT since FP23 (founder retired the interaction;
   markup lives in git history at 118624f). Selectors below match nothing
   on the live page; kept for a possible smaller-scale revival.
   ========================================================================== */
.locker-wall {
  position: relative;
  z-index: 3;
  max-width: 80rem;
  margin: clamp(2.5rem, 6vw, 4.5rem) auto 0;
}
/* keep the wall's hint pill clear of the wrapped trust chip */
@media (max-width: 700px) {
  .locker-wall { margin-top: 3.5rem; }
}

.locker-wall__hint {
  display: inline-block;
  font-family: var(--font-body);
  font-style: italic;
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--pacific-2);
  margin-bottom: 0.9rem;
  background: rgba(246, 241, 228, 0.78);
  border-radius: 999px;
  padding: 0.35rem 0.9rem;
}

.locker-wall__track { position: relative; padding-top: 0.25rem; }

/* ---- the idle beachgoer: walks up, stows a bag, walks off ----
   Position (translate3d) is driven by JS; the walk cycle, the bag
   stow, and the color variants live here. Hidden between visits. */
.walker {
  /* variant 1 palette (v2/v3 override below) */
  --w-skin: #C68642;
  --w-top: #37C1D6;
  --w-shorts: #22262E;
  --w-cap: #F0368B;
  --w-bag: #FF8A3D;
  --w-hair: #3A2B1E;
  position: absolute;
  left: 0;
  bottom: 1.35rem; /* feet on the sand line at the plinth */
  width: clamp(4.2rem, 7.5vw, 6rem);
  z-index: 4;
  pointer-events: none;
  transform: translate3d(-140%, 0, 0);
  will-change: transform;
  filter: drop-shadow(0 5px 3px rgba(20, 24, 30, 0.35));
}
.walker[hidden] { display: none; }
.walker svg { width: 100%; height: auto; display: block; overflow: visible; }
.walker--v2 {
  --w-skin: #8D5524;
  --w-top: #FF8A3D;
  --w-shorts: #0B5E66;
  --w-cap: #22262E;
  --w-bag: #F0368B;
  --w-hair: #191410;
}
.walker--v3 {
  --w-skin: #E0AC69;
  --w-top: #F6F1E4;
  --w-shorts: #084A51;
  --w-cap: #0B5E66;
  --w-bag: #37C1D6;
  --w-hair: #6E4A2E;
}

/* walk cycle: legs scissor, back arm counter-swings, body bobs */
.walker__leg, .walker__arm--back {
  transform-box: fill-box;
  transform-origin: 50% 6%;
}
.walker.is-walking svg { animation: walker-bob 0.6s ease-in-out infinite alternate; }
.walker.is-walking .walker__leg--front { animation: walker-step 0.6s ease-in-out infinite alternate; }
.walker.is-walking .walker__leg--back,
.walker.is-walking .walker__arm--back { animation: walker-step 0.6s ease-in-out infinite alternate-reverse; }
@keyframes walker-bob {
  from { transform: translateY(0); }
  to   { transform: translateY(-3px); }
}
@keyframes walker-step {
  from { transform: rotate(13deg); }
  to   { transform: rotate(-13deg); }
}

/* the stow: the tote lifts up into the open door and vanishes */
.walker__bag {
  transform-box: fill-box;
  transition: transform 0.55s var(--ease-ios), opacity 0.4s var(--ease-out) 0.2s;
}
.walker.has-stowed .walker__bag {
  transform: translate(16px, -34px) scale(0.5);
  opacity: 0;
}

.beachbox-unit { position: relative; }

/* ---- the solar roof: four PV panels on low mounts, overhanging the
   cabinet edges a touch — full-roof integration, like the render ---- */
.unit__solar {
  position: relative;
  z-index: 1;
  width: calc(100% + 1.5rem);
  margin: 0 -0.75rem;
  padding-bottom: 0.5rem; /* the air gap where the mounting feet show */
}
/* mounting feet */
.unit__solar::before,
.unit__solar::after {
  content: "";
  position: absolute;
  bottom: 0;
  width: clamp(0.55rem, 1.1vw, 0.85rem);
  height: 0.55rem;
  background: linear-gradient(#2E333B, #191D23);
}
.unit__solar::before { left: 14%; }
.unit__solar::after  { right: 14%; }

.solar-array {
  position: relative;
  display: flex;
  gap: 5px;
  padding: 4px;
  background: linear-gradient(#3A3F47, #22262C);
  border-radius: 4px;
  box-shadow:
    0 3px 7px rgba(20, 24, 30, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
/* two more mounting feet toward the center of the span */
.solar-array::before,
.solar-array::after {
  content: "";
  position: absolute;
  bottom: -0.5rem;
  width: clamp(0.55rem, 1.1vw, 0.85rem);
  height: 0.5rem;
  background: linear-gradient(#2E333B, #191D23);
}
.solar-array::before { left: 38%; }
.solar-array::after  { right: 38%; }
.solar-panel {
  flex: 1;
  height: clamp(1.6rem, 3.2vw, 2.5rem);
  border-radius: 2px;
  border: 1px solid #4A505A;
  background:
    /* cell grid over glass glare over PV blue-black */
    repeating-linear-gradient(90deg, rgba(125, 155, 195, 0.16) 0 1px, transparent 1px 12.5%),
    repeating-linear-gradient(0deg, rgba(125, 155, 195, 0.14) 0 1px, transparent 1px 33.34%),
    linear-gradient(105deg, rgba(150, 180, 220, 0.16) 0%, rgba(150, 180, 220, 0.04) 38%, transparent 62%),
    linear-gradient(180deg, #111A28 0%, #0B111C 55%, #15202F 100%);
}

/* ---- the cabinet body: powder-coated steel ---- */
.unit__body {
  /* brushed micro-lines over the base gradient */
  background:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.02) 0 1px, transparent 1px 3px),
    linear-gradient(#3A404B, #23272E);
  border-radius: 10px 10px 0 0;
  padding: var(--unit-pad);
  box-shadow:
    0 3px 6px rgba(20, 24, 30, 0.35),
    0 26px 52px rgba(20, 24, 30, 0.4),
    inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

/* soft contact shadow where the cabinet meets the sand */
.unit__shadow {
  height: 1.2rem;
  margin: -0.15rem 2.5% 0;
  background: radial-gradient(ellipse 50% 100% at 50% 0%, rgba(20, 24, 30, 0.5), transparent 75%);
  filter: blur(1px);
}

/* wood plinth */
.unit__base {
  height: 0.9rem;
  background:
    repeating-linear-gradient(90deg, transparent 0 5.4rem, rgba(34, 38, 46, 0.35) 5.4rem 5.6rem),
    linear-gradient(#9A6A3E, #7A4E28);
  border-radius: 0 0 6px 6px;
  box-shadow: inset 0 2px 3px rgba(0, 0, 0, 0.35);
}

/* ---- the door grid: 2 tall | 3×4 medium | 3×6 small — the render's
   32-door layout. Real gaps between panels (the cabinet frame shows
   through) instead of painted-on borders. 12 rows: tall spans all 12,
   medium spans 3, small spans 2. ---- */
.unit__doors {
  display: grid;
  grid-template-columns: 90fr 90fr 72fr 72fr 72fr 68fr 68fr 68fr;
  grid-template-rows: repeat(12, 1fr);
  gap: 4px;
  padding: 4px;
  aspect-ratio: 600 / 205;
  background: #14181D;
  border-radius: 6px;
}

/* explicit door placement */
.d-t1 { grid-column: 1; grid-row: 1 / 13; }
.d-t2 { grid-column: 2; grid-row: 1 / 13; }
.d-m1  { grid-column: 3; grid-row: 1 / 4; }
.d-m2  { grid-column: 4; grid-row: 1 / 4; }
.d-m3  { grid-column: 5; grid-row: 1 / 4; }
.d-m4  { grid-column: 3; grid-row: 4 / 7; }
.d-m5  { grid-column: 4; grid-row: 4 / 7; }
.d-m6  { grid-column: 5; grid-row: 4 / 7; }
.d-m7  { grid-column: 3; grid-row: 7 / 10; }
.d-m8  { grid-column: 4; grid-row: 7 / 10; }
.d-m9  { grid-column: 5; grid-row: 7 / 10; }
.d-m10 { grid-column: 3; grid-row: 10 / 13; }
.d-m11 { grid-column: 4; grid-row: 10 / 13; }
.d-m12 { grid-column: 5; grid-row: 10 / 13; }
.d-s1  { grid-column: 6; grid-row: 1 / 3; }
.d-s2  { grid-column: 7; grid-row: 1 / 3; }
.d-s3  { grid-column: 8; grid-row: 1 / 3; }
.d-s4  { grid-column: 6; grid-row: 3 / 5; }
.d-s5  { grid-column: 7; grid-row: 3 / 5; }
.d-s6  { grid-column: 8; grid-row: 3 / 5; }
.d-s7  { grid-column: 6; grid-row: 5 / 7; }
.d-s8  { grid-column: 7; grid-row: 5 / 7; }
.d-s9  { grid-column: 8; grid-row: 5 / 7; }
.d-s10 { grid-column: 6; grid-row: 7 / 9; }
.d-s11 { grid-column: 7; grid-row: 7 / 9; }
.d-s12 { grid-column: 8; grid-row: 7 / 9; }
.d-s13 { grid-column: 6; grid-row: 9 / 11; }
.d-s14 { grid-column: 7; grid-row: 9 / 11; }
.d-s15 { grid-column: 8; grid-row: 9 / 11; }
.d-s16 { grid-column: 6; grid-row: 11 / 13; }
.d-s17 { grid-column: 7; grid-row: 11 / 13; }
.d-s18 { grid-column: 8; grid-row: 11 / 13; }

.door {
  position: relative;
  display: block;
  background: #101318;
  border-radius: 4px;
  perspective: 50rem;
  text-decoration: none;
  /* button reset (peek doors are <button>s) */
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
/* fixed doors are furniture, not controls */
.door--fixed { cursor: default; }
/* a swinging leaf renders above the neighbors */
.door:hover, .door.is-open { z-index: 3; }

/* dark interior behind each door */
.door__inside {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #101318;
  border-radius: 3px;
  overflow: hidden;
}
.door__peek {
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: clamp(0.55rem, 1.1vw, 0.8rem);
  letter-spacing: var(--track-micro);
  color: var(--cyan);
  text-align: center;
  padding: 0 0.4rem;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.3s var(--ease-out) 0.12s, transform 0.3s var(--ease-out) 0.12s;
}
.door__peek i { display: block; font-style: normal; font-size: 1.25em; margin-top: 0.25em; }

/* the door leaf — bare powder-coated steel, like the render */
.door__leaf {
  position: absolute;
  inset: 0;
  border-radius: 3px;
  overflow: hidden;
  background:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.015) 0 1px, transparent 1px 3px),
    linear-gradient(180deg, #3B414B 0%, #2F343D 48%, #272C34 100%);
  transform-origin: left center;
  /* --tilt is the cursor-proximity lean (set by JS on desktop, 0 otherwise) */
  transform: rotateY(var(--tilt, 0deg));
  transition: transform 0.4s var(--ease-soft), filter 0.3s var(--ease-out);
  backface-visibility: hidden;
  will-change: transform;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    inset 0 -2px 4px rgba(0, 0, 0, 0.3),
    inset 1px 0 1px rgba(255, 255, 255, 0.05),
    inset -1px 0 2px rgba(0, 0, 0, 0.25);
}

/* powder-coat sheen — specular top-left, falloff low-right */
.door__leaf::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(115deg,
    rgba(255, 255, 255, 0.1) 0%,
    rgba(255, 255, 255, 0.03) 24%,
    rgba(0, 0, 0, 0.05) 62%,
    rgba(0, 0, 0, 0.18) 100%);
}

/* keypad unit on every door — centered, like the render: lock emblem
   above a button grid on a dark housing */
.door__pad {
  position: absolute;
  left: 50%;
  top: 50%;
  width: clamp(0.85rem, 1.7vw, 1.3rem);
  aspect-ratio: 3 / 4;
  transform: translate(-50%, -50%);
  background: linear-gradient(#20242B, #14181D);
  border-radius: 15%;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.09),
    inset 0 1px 2px rgba(0, 0, 0, 0.6),
    0 1px 1px rgba(255, 255, 255, 0.05);
}
/* circular lock emblem */
.door__pad::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 18%;
  width: 32%;
  aspect-ratio: 1;
  transform: translateX(-50%);
  border-radius: 50%;
  border: 1px solid rgba(154, 165, 177, 0.75);
  background: radial-gradient(circle at 40% 35%, #39404A, #191D23);
}
/* button grid */
.door__pad::after {
  content: "";
  position: absolute;
  left: 22%;
  right: 22%;
  top: 50%;
  bottom: 12%;
  background-image: radial-gradient(circle, #8F99A5 38%, transparent 48%);
  background-size: 33.34% 25%;
}
/* tall doors: bigger unit, mounted at hand height */
.d-t1 .door__pad, .d-t2 .door__pad { width: clamp(1.15rem, 2.2vw, 1.7rem); top: 38%; }
/* small doors are shallow slots — the unit shrinks to fit */
[class*=" d-s"] .door__pad { width: clamp(0.6rem, 1.2vw, 0.95rem); }

/* numbered badge on the five nav doors */
.door__tag {
  position: absolute;
  left: 7%;
  top: 6%;
  min-width: 1.55em;
  padding: 0.05em 0.3em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(0.8rem, 1.6vw, 1.25rem);
  line-height: 1.4;
  text-align: center;
  color: var(--ink);
  background: var(--tangerine);
  border: 2px solid var(--ink);
  border-radius: 999px;
  transform: rotate(-3deg);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}

/* interaction: nav doors navigate, peek doors show what fits inside —
   both crack open fast and settle closed slower. Fixed doors only lean
   with the cursor; they never open. */
@media (hover: hover) {
  .door--nav:hover .door__leaf,
  .door--peek:hover .door__leaf { transform: rotateY(-16deg); transition-duration: 0.28s; filter: brightness(1.04); }
  .door--nav:hover .door__peek { opacity: 1; transform: translateY(0); }
}
.door:focus-visible .door__leaf { transform: rotateY(-16deg); transition-duration: 0.28s; }
.door--nav:focus-visible .door__peek { opacity: 1; transform: translateY(0); }
.door.is-open .door__leaf { transform: rotateY(-80deg); filter: brightness(0.9); }
.door--nav.is-open .door__peek { opacity: 1; transform: translateY(0); }

/* depth response: the interior falls into shadow near the hinge as the
   leaf swings away from it */
.door__inside::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to right, rgba(0, 0, 0, 0.5), transparent 55%);
  opacity: 0;
  transition: opacity 0.45s var(--ease-out);
}
.door--nav:hover .door__inside::after,
.door--peek:hover .door__inside::after,
.door.is-open .door__inside::after { opacity: 1; }

/* item interiors on the peek doors */
.door__inside--items {
  box-shadow: inset 0 6px 14px rgba(0, 0, 0, 0.55), inset 0 -2px 6px rgba(0, 0, 0, 0.4);
}
.door__items {
  width: 78%;
  height: 86%;
  object-fit: contain;
  opacity: 0;
  transform: scale(0.92);
  transition: opacity 0.3s var(--ease-out) 0.15s, transform 0.35s var(--ease-out) 0.15s;
}
.door--peek.is-open .door__items { opacity: 1; transform: scale(1); }

/* legend + mobile swipe */
.locker-wall__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.4rem;
  margin-top: 0.9rem;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: var(--track-micro);
  color: var(--ink);
}
.locker-wall__legend b {
  display: inline-grid;
  place-items: center;
  width: 1.5em;
  height: 1.5em;
  margin-right: 0.45em;
  background: var(--tangerine);
  border: 2px solid var(--ink);
  border-radius: 50%;
  font-family: var(--font-display);
  font-weight: 700;
}

.locker-wall__swipe {
  display: none;
  font-family: var(--font-body);
  font-style: italic;
  font-size: var(--text-xs);
  color: var(--pacific-2);
  text-align: center;
  margin-top: 0.4rem;
}

@media (max-width: 900px) {
  .locker-wall__track {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding: 0.25rem 0.25rem 0.9rem;
  }
  .beachbox-unit { min-width: 54rem; }
  .locker-wall__swipe { display: block; }
}

/* ==========================================================================
   Ticker — the deck's own words, on a loop (Klar-style marquee)
   ========================================================================== */
.ticker {
  overflow: hidden;
  background: var(--ink);
  color: var(--bone);
  padding: 0.75rem 0;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
}
.ticker:hover .ticker__track {
  font-weight: 700; animation-play-state: paused; }
.ticker__track {
  display: inline-flex;
  align-items: baseline;
  gap: 1.6rem;
  white-space: nowrap;
  font-family: var(--font-display);
  font-size: var(--text-base);
  letter-spacing: var(--track-micro);
  animation: ticker-scroll 30s linear infinite;
}
.ticker__track i { font-style: normal; color: var(--tangerine); }
@keyframes ticker-scroll {
  to { transform: translateX(-50%); }
}

/* ==========================================================================
   Sections (shared)
   ========================================================================== */
.section { padding: var(--space-section) var(--pad-x); }

/* B-LCP: skip rendering below-fold sections until approached — first
   paint was laying out the whole 15,000px page. HARD CONSTRAINT: only
   sections BELOW every scroll-timeline subject may do this. A cv
   section ABOVE the pile or the sea sizes itself from the estimate
   until rendered, so the machinery's document position shifts
   mid-scroll and the timeline mapping jumps (measured: broke the
   domino at every width when #canvas/#app had it). #problem (--pile),
   #how (pin), #features (--sea), everything above them, and #story
   (control group) stay fully rendered. `auto` memorizes real size
   after first render. */
/* A5.3b addendum: #pricing and .shout LEFT OUT on purpose — their
   render-in (estimate -> real height) fired scroll anchoring right as
   the wave pin was engaged, a one-time ~15px nudge (measured at 768).
   The remaining three are far enough below the pin zone. */
#art, #faq, #join {
  content-visibility: auto;
}
#art     { contain-intrinsic-size: auto 2140px; }
#faq     { contain-intrinsic-size: auto 720px; }
#join    { contain-intrinsic-size: auto 1390px; }

.section__inner { max-width: var(--max-width); margin: 0 auto; }
.section__inner--narrow { max-width: 46rem; }

.section__headline {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--text-h2);
  line-height: 1.06;
  letter-spacing: var(--track-display);
  margin-bottom: var(--space-4);
  text-wrap: balance;
}

.section__body {
  max-width: 38rem; /* ≤ ~70ch — long prose was pushing 78ch at the clamp floor */
  font-size: var(--text-copy);
  margin-bottom: var(--space-7);
  text-wrap: pretty;
}
.section__body--lg { font-size: var(--text-lead); margin-bottom: 1.25rem; }

.section__footnote {
  margin-top: var(--space-6);
  font-style: italic;
  font-size: var(--text-xs);
  opacity: 0.7;
}

.section .placard { color: var(--pacific); }

/* backgrounds: bone → sand alternation, gallery paper, sunset join */
.section--sand    { background: var(--sand); }
.section--gallery { background: var(--paper); }
/* FP8: The Story is a night boardwalk now — sky gradient here, the
   scene furniture (string lights, neon sign, palms, planks) lives in
   deferred.css with the rest of the section's dressing */
.section--story   {
  background:
    radial-gradient(64rem 32rem at 50% 112%, rgba(61, 139, 255, 0.13), transparent 62%),
    linear-gradient(180deg, #0A0E15 0%, #0D1420 48%, #111A2B 80%, #0B1018 100%);
  color: var(--bone);
}

/* A6 (founder-directed): The Problem is read off a DESK now — dark
   wooden table, a warm lamp pool from the upper right, horizontal
   plank seams, and the grain overlay multiplying like real wood tooth.
   The evidence pile and the two mock devices sit on it like a case
   file. Light type on the wood. */
.section--shore {
  position: relative;
  color: var(--bone);
  background:
    radial-gradient(52rem 30rem at 74% 8%, rgba(255, 208, 138, 0.13), transparent 62%),
    radial-gradient(40rem 22rem at 8% 96%, rgba(0, 0, 0, 0.3), transparent 64%),
    repeating-linear-gradient(180deg, rgba(12, 8, 4, 0.32) 0 2px, rgba(255, 236, 200, 0.03) 2px 4px, transparent 4px 9.5rem),
    linear-gradient(180deg, #46372A 0%, #3B2E22 48%, #33281D 100%);
}
.section--shore .placard { color: #D9B98C; } /* lamp-lit brass, not teal */
.section--shore::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.28; /* wood tooth — the same two-scale grain, multiplied darker */
  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: 180px 180px, 620px 620px;
}

/* How It Works — the dry upper beach: lighter, sun-bleached sand that
   walks down to the shorebreak at the top of the spec section (its
   bottom color hands off to .shorebreak's sand exactly) */
.section--dune {
  position: relative;
  background:
    radial-gradient(44rem 18rem at 76% 12%, rgba(255, 250, 234, 0.6), transparent 64%),
    radial-gradient(36rem 16rem at 8% 86%, rgba(150, 120, 74, 0.07), transparent 60%),
    linear-gradient(180deg, #F3E9CC 0%, #EFE0B9 52%, #EDDCB2 100%);
}
/* A5.5: a drip sandcastle far back on the dune — set-dressing, not
   clip-art. Tonal sand-shadow fills only (no outlines, no flag), low
   contrast, sitting behind the steps; isolation keeps the negative
   z-index layer inside this section instead of behind its ground. */
.section--dune { isolation: isolate; }
.section--dune::after {
  content: "";
  position: absolute;
  z-index: -1;
  right: clamp(0.5rem, 4vw, 4rem);
  bottom: 13.5rem;
  width: clamp(15rem, 30vw, 24rem);
  aspect-ratio: 400 / 230;
  pointer-events: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 230'%3E%3Cg fill='%23967A4A'%3E%3Cpath opacity='0.10' d='M8 214 C70 196 140 190 200 192 C270 194 340 200 396 216 C400 222 398 228 392 229 L12 229 C4 228 2 220 8 214 Z'/%3E%3Cpath opacity='0.13' d='M60 208 C58 186 62 168 60 150 C74 156 72 146 82 150 C90 142 96 154 104 148 C112 154 110 146 118 150 C116 170 120 190 118 208 C100 204 78 204 60 208 Z'/%3E%3Cpath opacity='0.16' d='M148 206 C146 168 152 130 148 96 C160 104 158 88 170 96 C178 84 186 100 196 90 C206 100 212 86 222 96 C232 88 230 102 242 94 C238 132 244 170 240 206 C210 200 178 200 148 206 Z'/%3E%3Cpath opacity='0.13' d='M272 208 C270 180 274 156 272 134 C282 140 282 130 292 136 C300 126 306 140 316 132 C324 140 322 130 330 136 C328 160 332 184 330 208 C312 204 290 204 272 208 Z'/%3E%3Cpath opacity='0.09' d='M156 120 C160 148 158 176 158 198 L166 198 C164 172 166 144 164 118 Z M226 116 C230 146 228 176 230 198 L236 198 C236 170 234 142 232 114 Z'/%3E%3Cpath opacity='0.07' d='M120 210 C160 202 240 202 282 210 C284 214 282 218 278 219 L124 219 C120 218 118 213 120 210 Z'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
}
@media (max-width: 700px) {
  .section--dune::after { bottom: 12.5rem; opacity: 0.85; }
}

.section--dune::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.18; /* A5.4: reads as actual sand, not flat tan */
  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: 180px 180px, 620px 620px;
}

/* deep-water "spec sheet" panel (Built for the Beach) — an actual dive:
   light falls off toward the bottom, bubbles drift up. Remapping
   --pacific to cyan inside flips the inline icon strokes to a color
   that reads on the dark background. */
.section--spec {
  position: relative;
  background:
    radial-gradient(40rem 24rem at 90% 8%, rgba(55, 193, 214, 0.14), transparent 60%),
    radial-gradient(52rem 30rem at 8% 100%, rgba(4, 34, 39, 0.6), transparent 72%),
    linear-gradient(180deg, #0C646D 0%, #0B5E66 32%, #07454D 76%, #05353C 100%);
  color: var(--bone);
  --pacific: var(--cyan);
  /* the swash zone owns the top of the section — content starts below it */
  padding-top: calc(var(--space-section) + 9rem);
  /* A3: the sea panel overlaps the section above by the height of its
     transparent swash zone, so the waterline always rides on the dune
     section's own sand — statically in Firefox/reduced motion, and over
     the pinned, submerging panel where scroll timelines exist */
  margin-top: -12.5rem;
}
/* the sand the wave washes onto: reserve blank dune under the overlap
   so no How It Works content sits beneath the waterline at rest.
   A6: the whole scene — title, steps, beach, waterline — fits ONE
   screen, so the pin aligns it top-of-viewport and holds. Compact
   spacing here on purpose; measure --how-h if you add content. */
/* founder: taller dry-sand band so the objects sit up near the steps.
   The type overhaul's face has a taller line box (+18px measured across
   this panel), so the panel's own rhythm gives that back — the pin
   engages at the same place it did before the new type landed. */
/* FP13b: +4rem dwell sand — more scroll between the steps and the sea's
   arrival, so the 01–04 grid gets read before the sweep starts. The
   12.5rem term stays the shorebreak overlap allowance. */
#how { padding-top: clamp(1.5rem, 4vw, 2.5rem); padding-bottom: calc(9rem + 12.5rem); }
/* FP14 — THE SLIDE (founder: "like a slide in a slideshow, and the wave
   is the transition"). On laptop-height screens the section was taller
   than the viewport, so the pin fell to the bottom-align branch and the
   heading never parked. This tier compacts the dune until it FITS below
   the nav at common laptop heights, which flips the pin to the
   settles-under-the-nav branch: slide holds, wave wipes it, next slide.
   Tall screens keep the roomier layout. */
@media (min-width: 701px) and (max-height: 1080px) {
  #how { padding-top: 1rem; padding-bottom: calc(2rem + 12.5rem); }
  #how .section__headline { font-size: clamp(1.9rem, 4vw, 2.9rem); }
  #how .section__body { margin-bottom: var(--space-2); }
}
/* the tighter tier: sub-860 viewports (1280×800-class laptops) need
   another ~60px shaved before the slide fits under the nav */
@media (min-width: 701px) and (max-height: 860px) {
  #how { padding-top: 0.5rem; padding-bottom: calc(0.5rem + 12.5rem); }
  #how .section__headline { font-size: 2.4rem; }
  #how .section__body { margin-bottom: var(--space-1); }
  #how .steps-flow__num { font-size: 2rem; margin-bottom: 0.3rem; }
  .reg-a #how .steps-flow { gap: var(--space-3) var(--space-5); }
}
/* the nav is sticky glass — anchor jumps should land the section below
   it, not underneath it */
#how { scroll-margin-top: var(--nav-h, 3.5rem); }
#how .section__headline { margin-bottom: var(--space-2); }
#how .section__body { margin-bottom: var(--space-3); }
#how .steps-flow p { max-width: none; } /* full column width wraps fewer lines */

/* A6/A7: kelp blades — the important parts sit on actual kelp: an
   undulating blade ribbon (hand-drawn SVG, lighter mid-rib streaks,
   lobed edges) stretched behind the text, each slab tilted a touch.
   White type on deep kelp green. */
.kelp,
#how .steps-flow h3 {
  display: inline-block;
  color: var(--foam);
  padding: 0.32em 1em 0.38em;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 260 64' preserveAspectRatio='none'%3E%3Cpath d='M6 30 C10 16 28 12 48 14 C60 5 74 8 88 12 C110 7 132 14 150 10 C166 5 184 12 204 12 C224 7 244 14 254 24 C258 32 254 44 244 50 C226 57 204 50 184 54 C162 59 140 52 118 56 C96 59 74 52 54 56 C34 58 14 50 8 42 C4 38 4 34 6 30 Z' fill='%232C5847'/%3E%3Cpath d='M22 34 C60 26 100 34 142 28 C182 23 220 30 242 33 C220 38 182 31 142 36 C100 42 60 34 22 34 Z' fill='%233F7560' opacity='0.55'/%3E%3Cpath d='M40 44 C80 40 130 46 180 42 C210 40 232 44 246 44 C232 48 210 46 180 48 C130 52 80 48 40 44 Z' fill='%231E4033' opacity='0.5'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
  transform: rotate(-0.8deg);
}
#how .steps-flow li:nth-child(even) h3 { transform: rotate(0.9deg); }

/* A6: the wet wash the retreating surf leaves on the dune (JS toggles
   .is-wet on #how while scrubbing up through the sea; it dries a beat
   after the scrubbing stops). Opacity-only. */
.dune-wet {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  /* A7.5: rides the same tide-in latch as the wet band — soaks fast,
     dries over ~2.8s on the latch's own clock */
  transition: opacity 2.8s var(--ease-out);
  /* the wave COVERED the pinned beach (that's the submersion), so the
     recede leaves the whole lower dune soaked — a dark tan-brown,
     deepest at the waterline, dry again by the intro. MULTIPLY keeps
     it reading as wet sand (and keeps the ink type legible) instead
     of a brown film over the section. */
  mix-blend-mode: multiply;
  background: linear-gradient(to top,
    rgb(128, 98, 62) 26%,
    rgb(148, 120, 84) 58%,
    rgb(198, 178, 148) 80%,
    #FFF 94%);
}
main.tide-in .dune-wet { opacity: 1; transition-duration: 0.25s; } /* soaks fast */

/* the crab makes a run for the water on each wetting — a solid
   silhouette in the sand-shadow family, no cartoon features */
.dune-crab {
  position: absolute;
  right: 7%;
  /* A7.1: enters up by the How It Works heading and makes the long run
     down the beach to the water. z-index -1 (inside the section's
     isolation) keeps it ON the sand, passing behind the type. */
  top: 8rem;
  z-index: -1;
  width: 4.6rem;
  aspect-ratio: 10 / 6;
  pointer-events: none;
  opacity: 0;
  filter: drop-shadow(0.2rem 0.3rem 0 rgba(96, 74, 46, 0.35));
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 60'%3E%3Cg fill='%23A6402A'%3E%3Cellipse cx='50' cy='36' rx='23' ry='14'/%3E%3Cpath d='M29 32 L12 18 L17 30 L6 26 L17 38 Z'/%3E%3Cpath d='M71 32 L88 18 L83 30 L94 26 L83 38 Z'/%3E%3Cpath d='M33 47 L21 57 L26 45 Z M43 50 L38 60 L48 51 Z M57 50 L62 60 L52 51 Z M67 47 L79 57 L74 45 Z'/%3E%3C/g%3E%3Cg fill='%237E2E1D'%3E%3Cellipse cx='50' cy='41' rx='16' ry='7'/%3E%3C/g%3E%3Ccircle cx='43' cy='22' r='3.4' fill='%2322262E'/%3E%3Ccircle cx='57' cy='22' r='3.4' fill='%2322262E'/%3E%3C/svg%3E") center / contain no-repeat;
}
/* A7.2: the four objects at the water's edge — casual scatter, partial
   burial baked into each SVG, low enough that the tide reaches every
   one. The spec section (the sea) is a later sibling, so the water
   paints over their lower edges naturally. */
.sand-things { position: absolute; inset: 0; pointer-events: none; }
.thing { position: absolute; }
.thing svg { width: 100%; height: auto; display: block; overflow: visible; } /* the phone's zaps reach past its viewBox */
/* founder pass 2: keys live in the TOP RIGHT of the section (founder-
   placed) — high on the dune, where only the deepest submersion
   reaches them; the wash-away on retreat is theirs alone (see the
   aftermath block in deferred.css + the cover-tracking in main.js).
   The other three spread wider along the dry band under the steps.
   Tops stay clear of the step text (17.5rem padding is the budget). */
.thing--keys     { left: auto; right: 12%; top: 8.75rem; bottom: auto; width: 6.2rem; transform: rotate(-7deg); }
.thing--wallet   { left: 17%; bottom: 12.2rem; width: 6.6rem; transform: rotate(6deg); }
.thing--phone    { left: 41%; bottom: 12.2rem; width: 3.6rem; transform: rotate(64deg); } /* FP8: a step higher */
.thing--passport { left: 65%; bottom: 10.8rem; width: 4.5rem; transform: rotate(-12deg); }
/* FP13: the towel + folded clothes — open sand below the crab, right
   side, level with the 03/04 row. TOP-anchored on purpose: the retreat
   uncovers this height while the tide latch is still wet, so the soaked
   state is actually SEEN before the DRY reset (bottom-band placement
   would only surface below the dry threshold — measured, not guessed). */
.thing--towel   { left: auto; right: 8%; top: 26rem; bottom: auto; width: 8.2rem; transform: rotate(-3deg); }
/* 701–1100: the two-column steps grid runs nearly full width at this
   band, so the towel slips just below the block — still high enough
   that the retreat uncovers it wet (p ≈ 0.33 > the 0.22 dry latch) */
@media (min-width: 701px) and (max-width: 1100px) {
  .thing--towel { top: 36.5rem; right: 4%; width: 6.8rem; }
}
/* founder pass 5: the phone joins the keys up on the dune wherever the
   heading leaves the right side free — beside Meet BeachBox, bigger,
   where its dead-and-zapping aftermath plays center stage instead of
   hiding at the surf line. Its state swap moved off the scroll ranges
   to the same cover-tracking the keys use (main.phone-drowned) — high
   on the beach, the old 38–44% swap would have fired in dry air. */
@media (min-width: 1101px) {
  .thing--phone  { left: auto; right: 26%; top: 5.6rem; bottom: auto; width: 4.3rem; } /* FP8: higher still — shoulder height with the heading */
}
@media (max-width: 700px) {
  /* top right on a phone is the heading — keys take the upper right of
     the sand band instead, still clearly separated from the others */
  .thing--keys     { right: 5%; top: auto; bottom: 13.7rem; width: 5rem; }
  /* phones: the single text column owns the mid-section, so the towel
     drops to the sand band, clear of the keys' corner */
  .thing--towel    { right: 30%; top: auto; bottom: 8rem; width: 5.6rem; }
  .thing--wallet   { left: 16%; bottom: 12.4rem; width: 5.4rem; }
  .thing--phone    { left: 45%; bottom: 11.4rem; width: 3.4rem; }
  .thing--passport { left: 74%; bottom: 10.8rem; width: 4rem; }
}

.dune-crab.is-scuttling { animation: crab-run 6.5s linear forwards; }
/* founder pass: dart-stop-dart — real crabs sprint sideways, freeze,
   sprint again. Each dart covers a lot of ground in a short slice of
   the timeline; the near-still frames between them are the freezes. */
@keyframes crab-run {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg); opacity: 0; }
  4%   { opacity: 1; }
  10%  { transform: translate3d(-3.4rem, 3rem, 0) rotate(7deg); }
  16%  { transform: translate3d(-3.8rem, 3.6rem, 0) rotate(-2deg); }
  26%  { transform: translate3d(-0.6rem, 7.6rem, 0) rotate(-7deg); }
  32%  { transform: translate3d(-1rem, 8.2rem, 0) rotate(2deg); }
  44%  { transform: translate3d(-5rem, 12.8rem, 0) rotate(6deg); }
  50%  { transform: translate3d(-5.4rem, 13.4rem, 0) rotate(-2deg); }
  62%  { transform: translate3d(-2rem, 17.8rem, 0) rotate(-6deg); }
  68%  { transform: translate3d(-2.4rem, 18.4rem, 0) rotate(2deg); }
  84%  { transform: translate3d(-6rem, 23.4rem, 0) rotate(5deg); opacity: 1; }
  100% { transform: translate3d(-4.6rem, 26.5rem, 0) rotate(0deg); opacity: 0; }
}

/* the pinned dune stays painted behind the rest of the document, so
   every section after the sea must be opaque. Bone is exactly what the
   body showed through these before — stating it changes nothing
   visually, it only closes the window to the pinned layer. */
/* Stage B: seafoam ground (#art keeps its steel — the gallery gradient
   paints over this color anyway, and The Story's top wave is locked to
   the steel's #262B33 bottom) */
/* FP8: the product register's ground is NIGHT now (founder-directed —
   "black and neon, Kalshi type of color, but blue"). Bone type, volt
   placards. #art keeps painting its steel over the fallback. */
#pricing, #art, #faq, #join { background-color: var(--night); }
#pricing, #faq, #join { color: var(--bone); }
/* FP21 (Imma's accent rule): volt is INTERACTIVE only — links, focus,
   toggles, CTAs. Section placards on dark grounds are cyan, on light
   grounds pacific (contrast), scene-lit exceptions stay (shore brass). */
#pricing .placard, #faq .placard, #join .placard { color: var(--cyan); }
/* (the FP7 #access section was removed Aug 2026 — founder: nothing is
   free. If a section ever returns between Pricing and the shout, it
   must rejoin the cover-the-pin club: opaque ground + positioned
   layer, or the stuck dune paints through it.) */

/* A3/A6 — THE REVEAL: the dune section pins and the sea panel slides
   up over it. The pin is the PRIMARY motion and it is scroll itself —
   no animation drives it, so engage and release are jump-free by
   construction. A6 (founder-directed, supersedes the A5.3b title-out
   pin): Meet BeachBox now FITS one screen, and it pins once PROPERLY
   ALIGNED — top-aligned when the section fits the viewport (top
   resolves to 0), bottom-at-viewport-bottom on screens shorter than
   the section (nothing unread ever traps under the sea). --how-h is
   measured by main.js on load/resize; without JS the section simply
   scrolls. dvh on purpose: vh janks under the iOS address bar. */
@media (prefers-reduced-motion: no-preference) {
  @supports (top: 1dvh) {
    .js #how {
      position: sticky;
      /* FP15 (founder-directed, SUPERSEDES the A6 bottom-align law): the
         slide stops the moment it hits the bar — "Meet BeachBox." parks
         ~24px under the nav on EVERY viewport, no fallback branch. The
         old second arm (bottom-at-viewport-bottom on short screens) let
         the section keep sliding under the nav before pinning — exactly
         what the founder flagged. Safe now because the FP14 compaction
         means any below-the-fold overflow on short screens is the
         decorative sand band, never text. */
      top: calc(var(--nav-h, 0px) + 24px - var(--how-h2ofs, 24px));
    }
  }
}
.section--spec .section__inner { position: relative; z-index: 1; }

/* ---- THE WAVE: where the sand above meets this section's water.
   The sand continues in from #how (exact color handoff). The tide —
   the section's own blue, carrying a hand-authored irregular leading
   edge with a translucent first few px — sits settled at its
   high-water line; where scroll timelines exist, the settle IS the end
   of a scroll-driven run up the sand (see the Stage A2 block). The
   looping swash sheets and their drifting foam caps ride the tide, and
   the darker wet-sand band above the waterline is what the crest left
   behind. Base styles here ARE the final frame: Firefox and reduced
   motion get this exact settled scene, statically. ---- */
.shorebreak {
  position: absolute;
  top: -1px;
  left: 0;
  right: 0;
  height: 12.5rem;
  overflow: hidden;
  pointer-events: none;
  /* A3: NO painted sand. The zone above the waterline is transparent —
     the beach the water washes onto is the section BENEATH the panel
     (How It Works pins under it and shows through the leading edge). */
}
/* the wet-sand band at the high-water mark — its top edge is the same
   kind of irregular line the water carries (a mask, baked geometry).
   It persists after the crest recedes; under scroll it fades up as the
   crest passes (opacity only). */
.shorebreak__wet {
  position: absolute;
  left: 0;
  right: 0;
  /* the overshoot zone: the tide reaches ~0.7rem past its resting
     line and pulls back — this band is what that reach darkened.
     A4.1: the band DRIES. Two strips (pseudos) fade on their own
     offsets — the thin high-water edge loses its water first, the
     deep saturation near the waterline holds longest. Base opacity
     is 0: dry is the resting (and reduced-motion, and Firefox)
     state; the wet mark exists only around the crest. */
  top: 0;
  height: 1.9rem;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 44' preserveAspectRatio='none'%3E%3Cpath d='M0 18 C70 10 150 22 240 16 C330 10 420 24 520 18 C610 13 690 26 780 20 C870 15 950 8 1040 14 C1120 19 1200 27 1290 20 C1350 15 1410 18 1440 14 L1440 44 L0 44 Z' fill='%23fff'/%3E%3C/svg%3E") 50% 50% / 100% 100% no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 44' preserveAspectRatio='none'%3E%3Cpath d='M0 18 C70 10 150 22 240 16 C330 10 420 24 520 18 C610 13 690 26 780 20 C870 15 950 8 1040 14 C1120 19 1200 27 1290 20 C1350 15 1410 18 1440 14 L1440 44 L0 44 Z' fill='%23fff'/%3E%3C/svg%3E") 50% 50% / 100% 100% no-repeat;
}
/* high water: the thin edge — first wet, first dry */
.shorebreak__wet::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 48%;
  opacity: 0;
  background: linear-gradient(180deg,
    rgba(146, 116, 74, 0.05) 0%,
    rgba(146, 116, 74, 0.38) 100%);
}
/* the deep saturation near the waterline — holds longest */
.shorebreak__wet::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 44%;
  bottom: 0;
  opacity: 0;
  background: linear-gradient(180deg,
    rgba(146, 116, 74, 0.4) 0%,
    rgba(118, 94, 58, 0.48) 100%);
}
/* A7.5 — THE DRY LATCH (state exception, documented in FABLE_STATE):
   drying is a TIME process, not a scroll position. main.js latches
   main.tide-in with hysteresis; these transitions do the rest —
   soak fast, dry over ~3s, thin edge first, deep saturation last. */
.shorebreak__wet::before { transition: opacity 1.2s var(--ease-out) 0.2s; }
.shorebreak__wet::after  { transition: opacity 2.4s var(--ease-out) 0.5s; }
main.tide-in .shorebreak__wet::before { opacity: 0.9; transition-duration: 0.35s; transition-delay: 0s; }
main.tide-in .shorebreak__wet::after  { opacity: 1;   transition-duration: 0.35s; transition-delay: 0s; }
/* the tide: the blue field itself. Its leading edge is one baked SVG —
   asymmetric crests, no repeating period, a translucent film riding
   7px above the waterline and a gradient fill that lets the sand show
   through the first few px of water. */
.shorebreak__tide {
  position: absolute;
  left: 0;
  right: 0;
  top: 2.4rem;
  bottom: -1px;
  will-change: transform;
  background: linear-gradient(180deg,
    rgba(31, 130, 145, 0.5) 0%,
    rgba(12, 100, 109, 0.94) 34%,
    #0C646D 62%,
    #0C646D 100%);
}
.shorebreak__tide::before {
  content: "";
  position: absolute;
  top: -42px;
  left: 0;
  width: 100%;
  height: 44px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 64' preserveAspectRatio='none'%3E%3Cdefs%3E%3ClinearGradient id='w' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%231F8291' stop-opacity='0.26'/%3E%3Cstop offset='0.42' stop-color='%23146E7B' stop-opacity='0.78'/%3E%3Cstop offset='1' stop-color='%230C646D'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath d='M0 40 C52 31 108 47 166 37 C240 28 300 16 348 27 C400 39 428 50 470 44 C540 34 630 20 700 26 C760 31 780 44 812 47 C880 53 990 30 1058 24 C1110 20 1160 34 1240 42 C1300 48 1352 26 1390 24 C1412 23 1430 30 1440 28 L1440 64 L0 64 Z' fill='%231F8291' fill-opacity='0.16' transform='translate(0 -7)'/%3E%3Cpath d='M0 40 C52 31 108 47 166 37 C240 28 300 16 348 27 C400 39 428 50 470 44 C540 34 630 20 700 26 C760 31 780 44 812 47 C880 53 990 30 1058 24 C1110 20 1160 34 1240 42 C1300 48 1352 26 1390 24 C1412 23 1430 30 1440 28 L1440 64 L0 64 Z' fill='url(%23w)'/%3E%3C/svg%3E") 50% 100% / 100% 44px no-repeat;
}
/* a sheet of water lapping over the crest and the wet sand above it:
   the top of the sheet fades to nothing (no box edge to betray it),
   the base deepens to the section's own color and melts into the
   field. The old white foam-cap tiles are gone — they repeated on a
   440px period, which is exactly the template read the leading edge
   is replacing; the tide's own broken foam carries that job now. */
.shorebreak__swash {
  position: absolute;
  left: 0;
  right: 0;
  top: -26px;
  height: 6.5rem;
  will-change: transform;
  animation: swash-run 6.4s ease-in-out infinite; /* A6: livelier surf */
  background: linear-gradient(180deg,
    rgba(78, 178, 194, 0) 0%,
    rgba(78, 178, 194, 0.3) 22%,
    rgba(31, 130, 145, 0.5) 46%,
    rgba(12, 100, 109, 0.9) 76%,
    #0C646D 100%);
}
.shorebreak__swash--back {
  top: -38px;
  opacity: 0.5;
  animation-duration: 8.4s;
  animation-delay: -3.7s;
}
@keyframes swash-run {
  0%, 100% { transform: translate3d(0, 20%, 0) }  /* pulled back */
  44%      { transform: translate3d(0, -20%, 0) } /* run up the sand */
}
/* the tide's foam: one hand-authored broken line (three lumped runs
   and scattered flecks, no repeating period) hugging the leading edge.
   It advances on its own curve under scroll — the shifting offset
   between this and the waterline is what reads as depth. */
.shorebreak__foam {
  position: absolute;
  top: -26px;
  left: 0;
  right: 0;
  height: 30px;
  will-change: transform;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 34' preserveAspectRatio='none'%3E%3Cg fill='%23FFFFFF'%3E%3Cpath d='M0 22 C40 14 90 12 150 16 C210 20 260 12 330 15 C370 17 390 22 360 24 C300 28 220 24 150 26 C90 27 30 27 0 25 Z' opacity='0.7'/%3E%3Cpath d='M420 18 C480 11 560 10 640 14 C700 17 750 12 800 15 C830 17 820 22 780 23 C700 26 620 21 540 23 C490 24 440 23 420 21 Z' opacity='0.55'/%3E%3Cpath d='M880 20 C950 13 1030 11 1110 15 C1170 18 1240 12 1310 15 C1370 17 1430 14 1440 17 L1440 22 C1400 24 1340 21 1280 23 C1200 26 1120 21 1040 24 C970 26 910 25 880 23 Z' opacity='0.65'/%3E%3Ccircle cx='200' cy='10' r='2' opacity='0.4'/%3E%3Ccircle cx='356' cy='13' r='1.5' opacity='0.35'/%3E%3Ccircle cx='610' cy='8' r='2.2' opacity='0.4'/%3E%3Ccircle cx='836' cy='12' r='1.4' opacity='0.35'/%3E%3Ccircle cx='1058' cy='10' r='2' opacity='0.4'/%3E%3Ccircle cx='1330' cy='9' r='1.6' opacity='0.35'/%3E%3Ccircle cx='60' cy='9' r='1.5' opacity='0.3'/%3E%3Ccircle cx='760' cy='7' r='1.3' opacity='0.3'/%3E%3C/g%3E%3C/svg%3E") 50% 50% / 100% 30px no-repeat;
}

@media (max-width: 700px) {
  /* the 1440-wide edge compresses hard at phone widths — shrink its
     height so the crests keep a coastal proportion */
  .shorebreak__tide::before { top: -28px; height: 30px; background-size: 100% 30px; }
  .shorebreak__foam { top: -18px; height: 22px; background-size: 100% 22px; }
  .shorebreak__wet { height: 1.5rem; }
}

/* the sea layer sits behind the content, clipped to the section */
.spec-sea {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

/* bubbles: born in the lower half, wobble up, fade before the top */
.spec-sea__bubbles i {
  position: absolute;
  bottom: -2.5rem;
  border-radius: 50%;
  opacity: 0;
  background:
    radial-gradient(circle at 34% 30%, rgba(255, 255, 255, 0.6) 0 14%, rgba(255, 255, 255, 0.06) 34%, transparent 50%),
    radial-gradient(circle, transparent 56%, rgba(205, 240, 250, 0.5) 72%, transparent 78%);
  animation: bubble-rise linear infinite;
  will-change: transform, opacity;
}
/* A4.2 depth: three rise families — far bubbles are small, SLOW, dim,
   and barely drift; near ones are big, quick, bright, and wobble.
   Prime-ish durations and scattered negative delays so the ensemble
   never visibly repeats. */
.spec-sea__bubbles i:nth-child(1)  { left: 5%;  width: 7px;  height: 7px;  animation-name: bubble-rise-far;  animation-duration: 19s;   animation-delay: -2s; }
.spec-sea__bubbles i:nth-child(2)  { left: 13%; width: 14px; height: 14px; animation-name: bubble-rise-near; animation-duration: 10.5s; animation-delay: -7s; }
.spec-sea__bubbles i:nth-child(3)  { left: 24%; width: 6px;  height: 6px;  animation-name: bubble-rise-far;  animation-duration: 23s;   animation-delay: -11s; }
.spec-sea__bubbles i:nth-child(4)  { left: 35%; width: 11px; height: 11px; animation-duration: 14s;   animation-delay: -5s; }
.spec-sea__bubbles i:nth-child(5)  { left: 47%; width: 7px;  height: 7px;  animation-name: bubble-rise-far;  animation-duration: 20.5s; animation-delay: -1s; }
.spec-sea__bubbles i:nth-child(6)  { left: 58%; width: 16px; height: 16px; animation-name: bubble-rise-near; animation-duration: 9.5s;  animation-delay: -3s; }
.spec-sea__bubbles i:nth-child(7)  { left: 67%; width: 9px;  height: 9px;  animation-duration: 13.5s; animation-delay: -9s; }
.spec-sea__bubbles i:nth-child(8)  { left: 78%; width: 12px; height: 12px; animation-name: bubble-rise-near; animation-duration: 11.5s; animation-delay: -6s; }
.spec-sea__bubbles i:nth-child(9)  { left: 88%; width: 6px;  height: 6px;  animation-name: bubble-rise-far;  animation-duration: 24.5s; animation-delay: -13s; }
.spec-sea__bubbles i:nth-child(10) { left: 94%; width: 10px; height: 10px; animation-name: bubble-rise-near; animation-duration: 12.5s; animation-delay: -8s; }
@keyframes bubble-rise {
  0%   { transform: translate3d(0, 0, 0) scale(0.72); opacity: 0; }
  6%   { opacity: 0.85; }
  46%  { transform: translate3d(9px, -17rem, 0) scale(0.88); }
  82%  { opacity: 0.5; }
  100% { transform: translate3d(-7px, -38rem, 0) scale(1); opacity: 0; }
}
@keyframes bubble-rise-far {
  0%   { transform: translate3d(0, 0, 0) scale(0.6); opacity: 0; }
  8%   { opacity: 0.36; }
  52%  { transform: translate3d(4px, -13rem, 0) scale(0.68); }
  84%  { opacity: 0.2; }
  100% { transform: translate3d(-3px, -29rem, 0) scale(0.74); opacity: 0; }
}
@keyframes bubble-rise-near {
  0%   { transform: translate3d(0, 0, 0) scale(0.8); opacity: 0; }
  5%   { opacity: 0.9; }
  38%  { transform: translate3d(13px, -16rem, 0) scale(0.95); }
  71%  { transform: translate3d(-9px, -29rem, 0) scale(1.02); }
  100% { transform: translate3d(6px, -40rem, 0) scale(1.08); opacity: 0; }
}

/* A4.2 fish: things you half-see at depth. Solid dark silhouettes,
   no features, low contrast, three sizes at three depths — smaller
   is slower is dimmer is further. Time-driven ambience like the
   bubbles (no scroll machinery); prime durations + uneven waypoint
   spacing so nothing loops on a visible period. The section content
   (z-index 1) swims in front of them. */
.spec-sea__fish i {
  position: absolute;
  left: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 132 44'%3E%3Cpath d='M126 22 C104 10 84 6 62 8 C44 10 30 15 20 21 L4 8 C8 16 9 19 9 22 C9 25 8 28 4 36 L20 23 C30 29 44 34 62 36 C84 38 104 34 126 22 Z' fill='%23041D22' fill-opacity='0.85'/%3E%3C/svg%3E") 50% 50% / contain no-repeat;
  will-change: transform;
  transform: translate3d(-16rem, 0, 0);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.spec-sea__fish i:nth-child(1) { bottom: 34%; width: 2.6rem; height: 0.9rem;  opacity: 0.26; animation-name: fish-l2r;   animation-duration: 151s; animation-delay: -47s; }
.spec-sea__fish i:nth-child(2) { bottom: 21%; width: 3.7rem; height: 1.25rem; opacity: 0.38; animation-name: fish-r2l;   animation-duration: 103s; animation-delay: -31s;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 132 44'%3E%3Cpath d='M128 22 C108 13 86 9 64 11 C46 13 32 17 22 21 L6 11 C10 17 11 20 11 22 C11 24 10 27 6 33 L22 23 C32 27 46 31 64 33 C86 35 108 31 128 22 Z' fill='%23041D22' fill-opacity='0.85'/%3E%3C/svg%3E"); }
.spec-sea__fish i:nth-child(3) { bottom: 10%; width: 5.2rem; height: 1.75rem; opacity: 0.5;  animation-name: fish-l2r-b; animation-duration: 73s;  animation-delay: -12s; }
@keyframes fish-l2r {
  from { transform: translate3d(-14rem, 0, 0); }
  23%  { transform: translate3d(26vw, -0.7rem, 0); }
  61%  { transform: translate3d(64vw, 0.5rem, 0); }
  to   { transform: translate3d(104vw, -0.3rem, 0); }
}
@keyframes fish-l2r-b {
  from { transform: translate3d(-16rem, 0, 0); }
  34%  { transform: translate3d(31vw, 0.8rem, 0); }
  72%  { transform: translate3d(70vw, -0.6rem, 0); }
  to   { transform: translate3d(105vw, 0.4rem, 0); }
}
@keyframes fish-r2l {
  from { transform: translate3d(104vw, 0, 0) scaleX(-1); }
  29%  { transform: translate3d(61vw, 0.6rem, 0) scaleX(-1); }
  68%  { transform: translate3d(24vw, -0.7rem, 0) scaleX(-1); }
  to   { transform: translate3d(-15rem, 0.2rem, 0) scaleX(-1); }
}
.section--spec .placard { color: var(--cyan); }
.section--spec .section__footnote { color: rgba(246, 241, 228, 0.65); }
.section--spec .spec { color: var(--bone); }
.section--spec .spec p { color: rgba(246, 241, 228, 0.82); }

/* centered variant (Pricing) */
.section--center .section__inner { text-align: center; }
.section--center .placard { border-top: none; }
.section--center .pricing-card { margin-inline: auto; }

/* ==========================================================================
   STAGE B — LAYOUT A: the ink-rail + marginalia field guide
   --------------------------------------------------------------------------
   THE FLAG: everything here is scoped under main.reg-a (set on <main> in
   index.html). Remove that class and the entire product register reverts
   to Layout B — the centered grammar — in one edit. The .margins asides
   are decorative repeats of on-page copy (aria-hidden) and hide
   themselves without the flag. Register sections: #app, #how, #features,
   #pricing, #art, #faq, #join. The hero is a poster, the evidence stack /
   wave / Story / Canvas are exempt.
   ========================================================================== */
.margins { display: none; }

.reg-a #app > .section__inner,
.reg-a #how > .section__inner,
.reg-a #features > .section__inner,
.reg-a #pricing > .section__inner,
.reg-a #art > .section__inner,
.reg-a #faq > .section__inner,
.reg-a #join > .section__inner {
  /* the rail — currentColor so it's ink on seafoam, bone on the sea/steel */
  border-left: 2px solid currentColor;
  padding-left: clamp(1rem, 3vw, 2rem);
}

/* the field guide reads left, even where B centered it */
.reg-a #pricing .section__inner { text-align: left; }
.reg-a #pricing .pricing-card { margin-inline: 0; }
.reg-a #pricing .placard { border-top: 2px solid currentColor; }
.reg-a #faq > .section__inner { max-width: 62rem; }

/* marginalia: mono annotations on the right rail (stacked below on phones) */
.reg-a .margins {
  display: block;
  list-style: none;
  margin: var(--space-6) 0 0;
  padding: 0;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: var(--track-micro);
  line-height: 1.5;
  opacity: 0.8;
}
.reg-a .margins li {
  position: relative;
  padding: 0.45rem 0 0.45rem 1rem;
  border-bottom: 1px solid;  /* currentColor, softened by the ul opacity */
}
.reg-a .margins li:first-child { border-top: 1px solid; }
.reg-a .margins li::before {
  content: "·";
  position: absolute;
  left: 0.1rem;
}

/* steps read as a 2×2 field-guide grid under the rail, not a 4-across
   strip. A6: 2×2 at EVERY width (compact type on phones) so Meet
   BeachBox fits one screen. */
.reg-a .steps-flow {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  max-width: 44rem;
  gap: var(--space-4) var(--space-5);
}
@media (max-width: 700px) {
  .reg-a .steps-flow li { padding-top: 0.55rem; }
  .reg-a .steps-flow__num { font-size: 1.5rem; margin-bottom: 0.25rem; }
  .reg-a .steps-flow h3 { font-size: 0.8rem; margin-bottom: 0.2rem; }
  .reg-a .steps-flow p { font-size: 0.78rem; line-height: 1.4; }
}

/* ≥980px: content column + marginalia column */
@media (min-width: 980px) {
  .reg-a #app > .section__inner,
  .reg-a #how > .section__inner,
  .reg-a #features > .section__inner,
  .reg-a #pricing > .section__inner,
  .reg-a #art > .section__inner,
  .reg-a #faq > .section__inner,
  .reg-a #join > .section__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(12rem, 16rem);
    column-gap: clamp(2rem, 4vw, 3.25rem);
  }
  .reg-a #app > .section__inner > :not(.margins),
  .reg-a #how > .section__inner > :not(.margins),
  .reg-a #features > .section__inner > :not(.margins),
  .reg-a #pricing > .section__inner > :not(.margins),
  .reg-a #art > .section__inner > :not(.margins),
  .reg-a #faq > .section__inner > :not(.margins),
  .reg-a #join > .section__inner > :not(.margins) { grid-column: 1; }
  .reg-a #app > .section__inner > .margins,
  .reg-a #how > .section__inner > .margins,
  .reg-a #features > .section__inner > .margins,
  .reg-a #pricing > .section__inner > .margins,
  .reg-a #art > .section__inner > .margins,
  .reg-a #faq > .section__inner > .margins,
  .reg-a #join > .section__inner > .margins {
    grid-column: 2;
    grid-row: 1 / span 40;  /* owns the right rail for the whole section */
    align-self: start;
    margin-top: 4.4rem;     /* optically level with the headline */
  }
}

/* painted wave transitions between sections */
.has-wave { position: relative; }
.section__wave {
  position: absolute;
  top: -1px;
  left: 0;
  width: 100%;
  height: clamp(22px, 4vw, 44px);
  pointer-events: none;
}

/* ==========================================================================
   Scroll-reveal — additive only: without JS nothing hides
   ========================================================================== */
/* keyframe-based (not transition-based) so revealed elements keep their
   own hover/press transitions afterward. JS staggers siblings that arrive
   in the same IntersectionObserver batch. */
.js .reveal { opacity: 0; }
.js .reveal.is-visible {
  opacity: 1;
  animation: reveal-in 0.4s var(--ease-out) backwards;
}
/* from-only on purpose: the animation lands on each element's OWN computed
   style (some reveals carry a static transform), and no forwards-fill is
   left behind to block hover transforms afterward */
@keyframes reveal-in {
  from { opacity: 0; transform: translateY(24px); }
}

/* ==========================================================================
   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; }
  /* 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); }
}
