/* === KEANU bundled .css — generated by build.py — DO NOT EDIT === */
/* source: /styles/{01-tokens.css, 02-typography.css, 02a-fonts.css, 03-layout-components.css, 04-story-desktop.css, 04b-hero-visual-deck.css, 05-story-mobile.css} */

/* --- /styles/01-tokens.css --- */
/* === 01-tokens.css (auto-split from style.css) === */
/* ===== KEANU RESIDENCES — unified interface system ===== */
:root{
  --paper:#f4f2ec; --paper-2:#ece4d4; --ink:#463526; --muted:#8c765f;
  --line:rgba(70,53,38,.16); --accent:#a86a4f; --night:#171109; --cream:#e7ddca;
  --olive:#525a44; --olive-deep:#3f4634;
  --hd:"Cardo","Times New Roman",serif; --bd:"Lato",system-ui,sans-serif;
  --gut:7vw; --maxw:1280px; --rhythm:clamp(120px,18vh,220px);
  /* expo-out — slow finish, premium glide */
  --ease:cubic-bezier(.16, 1, .3, 1);
  /* in-out-quart — for two-way motions like header swap */
  --ease-io:cubic-bezier(.83, 0, .17, 1);
}
*,*::before,*::after{box-sizing:border-box;}
html{scroll-behavior:auto;overflow-x:hidden;width:100%;}
body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--bd);font-weight:300;line-height:1.6;-webkit-font-smoothing:antialiased;overflow-x:hidden;width:100%;max-width:100vw;}
img{display:block;max-width:100%;}
a{color:inherit;text-decoration:none;}
::selection{background:var(--accent);color:var(--paper);}

/* --- /styles/02-typography.css --- */
/* === 02-typography.css (auto-split from style.css) === */
/* type */
.wordmark{display:inline-flex;flex-direction:column;align-items:center;line-height:0;color:inherit;}
.wordmark img{display:block;width:auto;height:34px;transition:filter .5s var(--ease);}
.eyebrow{font-family:var(--bd);font-size:11px;font-weight:400;letter-spacing:.38em;text-transform:uppercase;color:var(--accent);margin:0;}
.statement{font-family:var(--hd);font-weight:400;font-size:clamp(30px,4.2vw,58px);line-height:1.16;letter-spacing:.005em;color:var(--ink);margin:0;}
.statement em{font-style:italic;}
.lead{font-family:var(--hd);font-weight:400;font-size:clamp(20px,2vw,27px);line-height:1.5;color:var(--ink);margin:0;}
.body{font-size:clamp(15px,1.05vw,17px);line-height:1.85;color:var(--ink);margin:0;font-weight:300;}

/* --- /styles/02a-fonts.css --- */
/* Self-hosted Cardo + Lato — Latin + Latin-ext subsets only.
   Source: Google Fonts. SIL Open Font License. */

@font-face {
  font-family: 'Cardo';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/wlpxgwjKBV1pqhv97I0x3F5O.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Cardo';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/wlpxgwjKBV1pqhv97IMx3A.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Cardo';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/wlp_gwjKBV1pqhv23IEp2A.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Cardo';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/wlp_gwjKBV1pqhv43IE.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Cardo';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/wlpygwjKBV1pqhND-ZQY-WN3aQ.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Cardo';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/wlpygwjKBV1pqhND-ZQW-WM.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('/assets/fonts/S6u9w4BMUTPHh7USSwaPGR_p.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('/assets/fonts/S6u9w4BMUTPHh7USSwiPGQ.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/S6uyw4BMUTPHjxAwXjeu.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/S6uyw4BMUTPHjx4wXg.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/S6u9w4BMUTPHh6UVSwaPGR_p.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/S6u9w4BMUTPHh6UVSwiPGQ.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- /styles/03-layout-components.css --- */
/* === 03-layout-components.css (auto-split from style.css) === */
/* layout */
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--gut);}
.sec{position:relative;z-index:2;background:var(--paper);padding:var(--rhythm) 0;}
.sec.alt{background:var(--paper-2);}
.block{max-width:760px;margin:0 auto;text-align:center;display:flex;flex-direction:column;align-items:center;gap:30px;}
.block .body{max-width:600px;}
.split{display:grid;grid-template-columns:1fr 1fr;gap:8vw;align-items:center;}
.split .col{display:flex;flex-direction:column;gap:26px;}
.full{width:100vw;position:relative;left:50%;margin-left:-50vw;}
.figure{overflow:hidden;background:var(--paper-2);}
.figure img{width:100%;height:100%;object-fit:cover;display:block;}

/* Architecture pencil-drawing figure — source is architecture.png with
   REAL alpha transparency (PIL-extracted olive ink lines, baked cream/white
   bg made transparent at threshold). No mix-blend-mode needed; the PNG
   sits cleanly on any section background. */
.figure.figure--ink{background:transparent;overflow:visible;}
.figure.figure--ink img{
  width:100%;height:auto;object-fit:contain;display:block;
}

/* button */
.pill{display:inline-block;border:1px solid currentColor;border-radius:40px;padding:15px 38px;font-family:var(--bd);font-size:10.5px;letter-spacing:.26em;text-transform:uppercase;color:var(--ink);position:relative;overflow:hidden;transition:color .8s var(--ease),border-color .8s var(--ease);}
.pill::before{content:"";position:absolute;inset:0;background:var(--ink);transform:translateY(101%);transition:transform .8s var(--ease);z-index:-1;}
.pill:hover{color:var(--paper);}
.pill:hover::before{transform:none;}
.pill.on-dark{color:#fff;border-color:rgba(255,255,255,.55);}
.pill.on-dark::before{background:#fff;}
.pill.on-dark:hover{color:var(--ink);}

/* reveal — long, late, luxury */
.reveal{opacity:0;transform:translateY(56px) scale(.985);filter:blur(6px);transition:opacity 1.6s var(--ease),transform 1.6s var(--ease),filter 1.4s var(--ease);}
.reveal.in{opacity:1;transform:none;filter:none;}
.reveal.d1{transition-delay:.18s;}
.reveal.d2{transition-delay:.36s;}
.reveal.d3{transition-delay:.54s;}
.reveal.d4{transition-delay:.72s;}
.reveal-l{opacity:0;transform:translateX(-64px) scale(.99);filter:blur(4px);transition:opacity 1.5s var(--ease),transform 1.5s var(--ease),filter 1.3s var(--ease);}
.reveal-r{opacity:0;transform:translateX(64px)  scale(.99);filter:blur(4px);transition:opacity 1.5s var(--ease),transform 1.5s var(--ease),filter 1.3s var(--ease);}
.reveal-l.in,.reveal-r.in{opacity:1;transform:none;filter:none;}
@supports not (filter:blur(1px)){
  .reveal,.reveal-l,.reveal-r{filter:none !important;}
}

/* ============================================================
   TOPBAR — minimal, transparent over hero, soft blurred on scroll
   ============================================================ */
.topbar{
  position:fixed;inset:0 0 auto 0;z-index:60;
  display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:48px;
  padding:26px var(--gut);
  color:var(--cream);
  border-bottom:1px solid transparent;
  transition:
    color .9s var(--ease-io),
    background-color .9s var(--ease-io),
    padding .8s var(--ease-io),
    backdrop-filter .9s var(--ease-io),
    -webkit-backdrop-filter .9s var(--ease-io),
    border-color .9s var(--ease-io);
}
/* Header sits CLEANLY over the hero — no ::before gradient strip, no
   stacked overlays. Background goes opaque only when scrolled past the hero
   so nav text remains legible on light sections. */
.topbar.dark{
  color:var(--ink);
  background-color:rgba(244,242,236,.86);
  backdrop-filter:blur(18px) saturate(118%);
  -webkit-backdrop-filter:blur(18px) saturate(118%);
  padding-top:18px;padding-bottom:18px;
  border-bottom-color:var(--line);
}

/* dual logo: white on dark hero, brown after scroll */
.topbar .wordmark.dual{position:relative;display:inline-block;line-height:0;height:28px;}
.topbar .wordmark.dual img{height:28px;width:auto;display:block;transition:opacity .9s var(--ease-io);}
.topbar .wordmark.dual img.dark{position:absolute;inset:0;opacity:0;}
.topbar.dark .wordmark.dual img.lite{opacity:0;}
.topbar.dark .wordmark.dual img.dark{opacity:1;}

/* centered nav — refined, widely spaced uppercase */
.topbar nav{display:flex;justify-content:center;gap:36px;}
.topbar nav a{
  font-family:var(--bd);font-size:11px;font-weight:400;
  letter-spacing:.24em;text-transform:uppercase;
  opacity:.78;position:relative;
  transition:opacity .6s var(--ease),color .6s var(--ease);
}
.topbar nav a::after{
  content:"";position:absolute;left:0;bottom:-6px;
  width:100%;height:1px;background:currentColor;
  transform:scaleX(0);transform-origin:left;
  transition:transform .7s var(--ease);
}
.topbar nav a:hover{opacity:1;}
.topbar nav a:hover::after{transform:scaleX(1);}

/* right side: invite link + menu button */
.topbar .right{display:flex;align-items:center;gap:28px;justify-self:end;}
.topbar .invite{
  font-family:var(--bd);font-size:10.5px;font-weight:400;
  letter-spacing:.24em;text-transform:uppercase;
  opacity:.78;position:relative;
  transition:opacity .6s var(--ease);
}
.topbar .invite::after{
  content:"";position:absolute;left:0;bottom:-6px;
  width:100%;height:1px;background:currentColor;
  transform:scaleX(0);transform-origin:left;
  transition:transform .7s var(--ease);
}
.topbar .invite:hover{opacity:1;}
.topbar .invite:hover::after{transform:scaleX(1);}

.menu-btn{
  display:flex;align-items:center;gap:12px;
  background:none;border:none;color:inherit;cursor:pointer;
  font-family:var(--bd);font-size:10.5px;font-weight:400;
  letter-spacing:.24em;text-transform:uppercase;
  opacity:.85;transition:opacity .6s var(--ease);padding:0;
}
.menu-btn:hover{opacity:1;}
.menu-btn i{display:block;width:24px;height:1px;background:currentColor;position:relative;}
.menu-btn i::after{content:"";position:absolute;top:5px;left:0;width:24px;height:1px;background:currentColor;}

/* ============================================================
   COOKIE CONSENT BANNER — privacy-first, quiet editorial style
   ============================================================ */
.cookie-banner{
  position:fixed;left:18px;right:18px;bottom:18px;z-index:90;
  max-width:540px;margin:0 auto;
  background:rgba(23,17,9,.94);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  color:var(--cream);
  border:1px solid rgba(231,221,202,.16);
  border-radius:6px;
  padding:18px 20px;
  display:flex;flex-direction:column;gap:14px;
  box-shadow:0 18px 50px rgba(15,11,6,.4);
  opacity:0;transform:translateY(16px);
  transition:opacity .6s var(--ease),transform .6s var(--ease);
}
.cookie-banner.show{opacity:1;transform:none;}
.ck-text{
  font-family:var(--bd);font-size:12.5px;line-height:1.6;font-weight:300;
  color:rgba(231,221,202,.9);margin:0;
}
.ck-text a{color:var(--cream);text-decoration:underline;text-underline-offset:2px;}
.ck-actions{display:flex;gap:10px;justify-content:flex-end;}
.ck-btn{
  font-family:var(--bd);font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
  padding:10px 22px;border-radius:3px;cursor:pointer;
  transition:opacity .4s var(--ease),background .4s var(--ease);
}
.ck-decline{
  background:transparent;border:1px solid rgba(231,221,202,.4);color:var(--cream);
}
.ck-decline:hover{border-color:var(--cream);}
.ck-accept{
  background:var(--cream);border:1px solid var(--cream);color:var(--olive-deep);
}
.ck-accept:hover{opacity:.88;}

@media (max-width:480px){
  .cookie-banner{left:12px;right:12px;bottom:12px;padding:16px;}
  .ck-actions{justify-content:stretch;}
  .ck-btn{flex:1;}
}

/* --- /styles/04-story-desktop.css --- */
/* === 04-story-desktop.css (auto-split from style.css) === */
/* ============================================================
   HERO — cinematic editorial, lower-right copy stack
   ============================================================ */
/* HERO REFACTOR — split architecture (May 2026):
   .hero is now a transparent scroll-BUDGET div (height only, no content).
   The cinematic frame lives in .hero-frame as position:fixed overlay.
   JS fades .hero-frame opacity → 0 as user scrolls past the hero budget,
   then sets visibility:hidden. Estate section follows IMMEDIATELY in the
   document flow, so there is ZERO dead zone — the old position:sticky
   architecture always left a sticky.height empty gap that we kept fighting.
   Now: scroll budget = 150vh on desktop. State 3 fadeOut (0.92-1.0) is
   synced with hero-frame fadeOut so the entire cinematic exits as one
   continuous gesture and Estate's paper background appears next frame. */
.hero{
  /* 450vh budget = ~4.5 viewport-heights of scroll → each of the 3 states
     gets one full screen of HOLD time, plus a slow ~35vh fade-out, plus a
     small ~18vh "breath" of pure cinematic frame between states. This is
     the depth the editorial design needs — previous state fully closes
     before next one opens. State pacing is in STATE_RANGES (script.js). */
  height:450vh;width:100%;max-width:100vw;position:relative;
  background:transparent;
}
.hero-frame{
  /* Fixed overlay — independent of document scroll. Sits behind topbar(60),
     cue(55), menu(80), wa(70), loader(99); above section content (z:2)
     visually, but Estate's z:2 wins as user scrolls down through it which
     is exactly what we want for the handoff.
     Height cascade: vh first (universal), then dvh (modern mobile —
     dynamic, follows URL bar). Without dvh, iOS Safari's collapsing
     URL bar would leave a gap at the bottom of the fixed frame.
     translateZ(0) creates the composite layer HERE on the parent, so the
     children (.state) can paint without their own layers (the source of
     the iOS scroll-repaint bug). */
  position:fixed;top:0;left:0;width:100vw;height:100vh;height:100dvh;
  overflow:hidden;z-index:1;
  opacity:1;will-change:opacity;
  transform:translateZ(0);
  -webkit-transform:translateZ(0);
}
.hero-frame video,
.hero-frame .hero-poster{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  /* gentle parallax — JS sets --par */
  transform:translate3d(0, var(--par, 0px), 0) scale(1.04);
  will-change:transform;
}
.hero-frame .veil{
  position:absolute;inset:0;pointer-events:none;
  /* One smooth top→bottom gradient — single layer, no flat band.
     Strong top darkening so the bright sunset portion of the video reads
     as one uniformly muted area behind the nav (no perceived "stripe"). */
  background:linear-gradient(
    180deg,
    rgba(15,11,6,.78) 0%,
    rgba(15,11,6,0)   46%,
    rgba(15,11,6,.62) 100%
  );
}

/* ============================================================
   HERO CONTENT — 3 scroll-driven states, one moment at a time
   Each state lives in the same stage. Only opacity + a faint
   vertical translateY change. No carousel, no horizontal motion.
   ============================================================ */
.hero-c{
  position:absolute;inset:0;z-index:4;
  padding:clamp(110px,14vh,160px) clamp(28px,6vw,80px) clamp(80px,11vh,140px);
  color:var(--cream);pointer-events:none;
}
.stage{position:relative;width:100%;height:100%;}

.state{
  position:absolute;margin:0;
  opacity:0;
  /* CSS variable lets JS drive subtle vertical motion without
     fighting per-state base centering transforms. */
  --rise:0px; --base-x:0px; --base-y:0px;
  transform:translate(var(--base-x), calc(var(--base-y) + var(--rise)));
  /* NO CSS transition — JS sets opacity every rAF based on scroll. */
  /* CRITICAL iOS Safari fix:
     - Don't use will-change here. On iOS Safari, will-change:opacity inside
       a position:fixed parent creates a composite layer that doesn't repaint
       during native scroll → states freeze visually even though JS opacity
       value changes correctly. Without will-change, the browser paints the
       state on the parent's layer where scroll triggers normal repaints.
     - Don't use translate3d. The Z-axis forces another composite layer with
       the same iOS scroll-repaint issue. Plain 2D translate is enough for
       our subtle motion (vertical RISE px only).
     - backface-visibility:hidden + transform:translateZ(0) on the PARENT
       (.hero-frame) instead — concentrates compositing there, not here. */
  backface-visibility:hidden;
  pointer-events:none;
}

/* STATE 1 — editorial intro, bottom-right (keeps existing visual direction) */
.state[data-state="1"]{
  right:0;bottom:0;
  max-width:min(540px, 80%);
  text-align:right;
  display:flex;flex-direction:column;align-items:flex-end;gap:24px;
  opacity:1; /* visible from page load */
}
.state[data-state="1"] .eb{
  font-family:var(--bd);font-size:11px;font-weight:400;
  letter-spacing:.46em;text-transform:uppercase;
  color:var(--cream);opacity:.86;margin:0;
}
.state[data-state="1"] .hd{
  font-family:var(--hd);font-style:normal;font-weight:400;
  font-size:clamp(36px,4.6vw,64px);line-height:1.08;letter-spacing:.005em;
  color:#fff;margin:0;max-width:14ch;
  text-shadow:0 2px 30px rgba(0,0,0,.55),0 0 80px rgba(0,0,0,.35);
}
.state[data-state="1"] .hd em{font-style:italic;display:block;}
.state[data-state="1"] .actions{
  display:flex;align-items:center;gap:28px;margin-top:4px;pointer-events:auto;
}

/* STATE 2 — scarcity centered (the "10" is the cinematic moment) */
.state[data-state="2"]{
  top:50%;left:50%;
  --base-x:-50%; --base-y:-50%;
  display:flex;flex-direction:column;align-items:center;gap:18px;
  text-align:center;
}
.state[data-state="2"] .num{
  font-family:var(--hd);font-style:italic;font-weight:400;
  font-size:clamp(140px,22vw,300px);line-height:.82;letter-spacing:-.02em;
  color:var(--cream);
  text-shadow:0 6px 60px rgba(0,0,0,.55),0 0 120px rgba(0,0,0,.35);
}
.state[data-state="2"] .lbl{
  font-family:var(--bd);font-size:clamp(11px,1.05vw,14px);font-weight:400;
  letter-spacing:.5em;text-transform:uppercase;
  color:var(--cream);opacity:.82;padding-left:.5em;
  text-shadow:0 1px 18px rgba(0,0,0,.6);
}

/* STATE 3 — poetic supporting line centered */
.state[data-state="3"]{
  top:50%;left:50%;
  --base-x:-50%; --base-y:-50%;
  max-width:min(820px, 86%);
  text-align:center;
}
.state[data-state="3"] .hd-poetic{
  font-family:var(--hd);font-style:italic;font-weight:400;
  font-size:clamp(22px,2.6vw,36px);line-height:1.45;letter-spacing:.005em;
  color:#fff;margin:0;
  text-shadow:0 2px 30px rgba(0,0,0,.6),0 0 80px rgba(0,0,0,.35);
}

.btn-ghost{
  display:inline-block;
  border:1px solid rgba(255,255,255,.55);
  border-radius:2px;
  padding:14px 28px;
  font-family:var(--bd);font-size:10.5px;font-weight:400;
  letter-spacing:.28em;text-transform:uppercase;
  color:#fff;background:transparent;
  position:relative;overflow:hidden;
  transition:color .8s var(--ease),border-color .8s var(--ease);
}
.btn-ghost::before{
  content:"";position:absolute;inset:0;background:#fff;
  transform:translateY(101%);transition:transform .8s var(--ease);z-index:-1;
}
.btn-ghost:hover{color:var(--ink);border-color:#fff;}
.btn-ghost:hover::before{transform:none;}

.btn-text{
  font-family:var(--bd);font-size:11px;font-weight:400;
  letter-spacing:.24em;text-transform:uppercase;
  color:#fff;opacity:.85;
  transition:opacity .6s var(--ease),gap .6s var(--ease);
  display:inline-flex;align-items:center;gap:9px;
}
.btn-text span{transition:transform .6s var(--ease);display:inline-block;}
.btn-text:hover{opacity:1;}
.btn-text:hover span{transform:translateX(6px);}

/* scroll cue — minimal, lower-center, fades after first scroll */
.cue{
  position:fixed;bottom:30px;left:50%;transform:translateX(-50%);
  z-index:55;color:var(--cream);opacity:.7;
  transition:opacity .9s var(--ease);
  display:flex;flex-direction:column;align-items:center;gap:14px;
}
.cue span{
  font-family:var(--bd);font-size:9px;font-weight:400;
  letter-spacing:.5em;text-transform:uppercase;
}
.cue::after{
  content:"";display:block;width:1px;height:34px;
  background:linear-gradient(180deg,var(--cream),transparent);
  animation:cue 3.4s ease-in-out infinite;
}
@keyframes cue{0%,100%{opacity:.25;transform:translateY(-6px)}50%{opacity:1;transform:translateY(6px)}}

/* menu — full-screen overlay. Hidden state combines transform + visibility +
   overflow:hidden so the scaled .pic/.pane .bg children (scale 1.06 for
   Ken-Burns) CANNOT bleed past the menu's bbox into the top of the viewport. */
.menu{
  position:fixed;inset:0;z-index:80;
  display:grid;grid-template-columns:1fr 1fr;
  transform:translateY(-101%);
  visibility:hidden;
  pointer-events:none;
  overflow:hidden;  /* clip scaled children — fixes top-of-viewport sliver */
  will-change:transform;
  /* When closing: animate transform, then hard-hide visibility after */
  transition:transform 1.1s var(--ease), visibility 0s 1.1s;
}
.menu.open{
  transform:none;
  visibility:visible;
  pointer-events:auto;
  /* When opening: make visible immediately, transform animates in */
  transition:transform 1.1s var(--ease), visibility 0s 0s;
}
.menu .pic{background-size:cover;background-position:center;transform:scale(1.06);transition:transform 1.4s var(--ease) .15s;}
.menu.open .pic{transform:scale(1);}
.menu .pane{background:var(--olive);position:relative;display:flex;flex-direction:column;justify-content:center;align-items:flex-end;padding:0 8vw;}
.menu .pane .bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.9;transform:scale(1.06);transition:transform 1.4s var(--ease) .15s;}
.menu.open .pane .bg{transform:scale(1);}
.menu .links{position:relative;z-index:2;display:flex;flex-direction:column;align-items:flex-end;gap:24px;}
.menu .links a{font-family:var(--hd);font-size:clamp(22px,2.6vw,34px);color:var(--cream);opacity:0;transform:translateY(18px);transition:opacity .9s var(--ease),transform .9s var(--ease),padding-right .55s var(--ease);}
.menu.open .links a{opacity:.92;transform:none;}
.menu.open .links a:nth-child(1){transition-delay:.30s;}
.menu.open .links a:nth-child(2){transition-delay:.38s;}
.menu.open .links a:nth-child(3){transition-delay:.46s;}
.menu.open .links a:nth-child(4){transition-delay:.54s;}
.menu.open .links a:nth-child(5){transition-delay:.62s;}
.menu.open .links a:nth-child(6){transition-delay:.70s;}
.menu.open .links a:nth-child(7){transition-delay:.78s;}
.menu .links a:hover{opacity:1;padding-right:14px;}
.menu .mcta{position:relative;z-index:2;align-self:flex-end;margin-top:48px;background:var(--cream);color:var(--olive-deep);border-radius:40px;padding:14px 38px;font-family:var(--bd);font-size:10.5px;letter-spacing:.26em;text-transform:uppercase;box-shadow:0 10px 30px rgba(15,11,6,.22);opacity:0;transform:translateY(18px);transition:opacity .9s var(--ease) .9s,transform .9s var(--ease) .9s,background .55s var(--ease),color .55s var(--ease),box-shadow .55s var(--ease);}
.menu.open .mcta{opacity:1;transform:none;}
.menu .mcta:hover{background:#fff;transform:translateY(-2px);box-shadow:0 16px 38px rgba(15,11,6,.3);}
.menu .mword{position:absolute;top:36px;left:50%;transform:translateX(-50%);color:var(--cream);opacity:0;z-index:3;transition:opacity .9s var(--ease) .25s;}
.menu.open .mword{opacity:.95;}
.menu .mword img{height:34px;}
.menu .close{position:absolute;top:34px;right:38px;z-index:3;width:30px;height:30px;background:none;border:none;cursor:pointer;opacity:0;transition:opacity .9s var(--ease) .25s,transform .6s var(--ease);}
.menu.open .close{opacity:1;}
.menu .close:hover{transform:rotate(90deg);}
.menu .close::before,.menu .close::after{content:"";position:absolute;top:50%;left:0;width:100%;height:1px;background:var(--cream);}
.menu .close::before{transform:rotate(45deg);}.menu .close::after{transform:rotate(-45deg);}

/* chapter scene */
.scene{position:relative;height:92vh;min-height:560px;overflow:hidden;}
.scene img{width:100%;height:100%;object-fit:cover;transform:scale(1.08);transition:transform 2.6s var(--ease);will-change:transform;}
.scene.in img{transform:scale(1);}
.scene.shade::after{content:"";position:absolute;inset:0;background:rgba(15,11,6,.42);transition:background 1.4s var(--ease);}
.scene .cap{position:absolute;inset:0;z-index:2;display:flex;align-items:center;justify-content:center;text-align:center;padding:0 8vw;opacity:0;transform:translateY(28px);transition:opacity 1.6s var(--ease) .25s,transform 1.6s var(--ease) .25s;}
.scene.in .cap{opacity:1;transform:none;}
.scene .cap .statement{color:#fff;max-width:980px;text-shadow:0 2px 30px rgba(0,0,0,.5);}

/* facts */
.facts{display:flex;flex-wrap:wrap;justify-content:center;}
.facts span{font-size:11px;letter-spacing:.26em;text-transform:uppercase;color:var(--muted);padding:0 28px;position:relative;opacity:0;transform:translateY(14px);transition:opacity 1.1s var(--ease),transform 1.1s var(--ease);}
.facts.in span{opacity:1;transform:none;}
.facts.in span:nth-child(1){transition-delay:.1s;}
.facts.in span:nth-child(2){transition-delay:.2s;}
.facts.in span:nth-child(3){transition-delay:.3s;}
.facts.in span:nth-child(4){transition-delay:.4s;}
.facts.in span:nth-child(5){transition-delay:.5s;}
.facts.in span:nth-child(6){transition-delay:.6s;}
.facts span+span::before{content:"";position:absolute;left:0;top:50%;width:1px;height:12px;background:var(--line);transform:translateY(-50%);}

/* location map — full Figma render (silhouette + olive dots + labels + KEANU seal
   all baked in at exact Figma positions). HTML overlay only adds clickable + pulse. */
.mapfig{position:relative;width:100%;max-width:1060px;margin:14px auto 0;overflow:visible;}
.mapfig .map-base{
  width:100%;display:block;
  /* no separate transform — pin position must stay aligned with baked-in seal */
}
.mapfig .pins{position:absolute;inset:0;pointer-events:none;}

/* Each .pin is a zero-size anchor at (left,top). Dot is centered on it.
   Label is absolutely placed beside/below the dot — never moves it. */
.pin{
  position:absolute;width:0;height:0;
  opacity:0;transition:opacity .9s var(--ease);
  pointer-events:none;
}
a.pin{text-decoration:none;color:inherit;}
.mapfig.in .pin{opacity:1;}
.mapfig.in .pin:nth-child(1){transition-delay:.05s;}
.mapfig.in .pin:nth-child(2){transition-delay:.16s;}
.mapfig.in .pin:nth-child(3){transition-delay:.24s;}
.mapfig.in .pin:nth-child(4){transition-delay:.32s;}
.mapfig.in .pin:nth-child(5){transition-delay:.40s;}
.mapfig.in .pin:nth-child(6){transition-delay:.48s;}

/* landmark dot — mini Figma scallop (same shape as KEANU seal, just smaller).
   Uses pin-mini.svg as background so it scales crisp + matches brand mark exactly. */
.pin .dot{
  position:absolute;left:0;top:0;
  width:14px;height:14px;
  background:url('assets/pin-mini.svg') center/contain no-repeat;
  transform:translate(-50%,-50%) scale(.7);
  opacity:0;
  transition:transform .9s var(--ease),opacity .9s var(--ease),filter .55s var(--ease);
  pointer-events:auto;
  filter:drop-shadow(0 2px 4px rgba(15,11,6,.35));
}
.mapfig.in .pin .dot{transform:translate(-50%,-50%) scale(1);opacity:1;}
.pin:hover .dot{transform:translate(-50%,-50%) scale(1.25);filter:drop-shadow(0 3px 6px rgba(15,11,6,.5));}

/* landmark label — cream uppercase, NO chip background (Figma editorial).
   Sits directly on the brown silhouette; subtle shadow keeps it readable. */
.pin .lbl{
  position:absolute;
  font-family:var(--bd);font-size:10px;font-weight:400;
  letter-spacing:.32em;text-transform:uppercase;
  color:var(--cream);
  white-space:nowrap;
  text-shadow:0 1px 2px rgba(15,11,6,.45);
  opacity:0;
  transition:opacity 1.1s var(--ease) .25s,color .5s var(--ease),transform .55s var(--ease);
  pointer-events:auto;
}
.mapfig.in .pin .lbl{opacity:1;}
.pin[data-place="right"] .lbl{left:14px;top:0;transform:translateY(-50%) translateX(-6px);}
.pin[data-place="left"]  .lbl{right:14px;top:0;transform:translateY(-50%) translateX(6px);text-align:right;}
.pin[data-place="above"] .lbl{bottom:14px;left:0;transform:translateX(-50%) translateY(6px);}
.pin[data-place="below"] .lbl{top:14px;left:0;transform:translateX(-50%) translateY(-6px);}
/* once revealed, settle to final position with no offset */
.mapfig.in .pin[data-place="right"] .lbl{transform:translateY(-50%);}
.mapfig.in .pin[data-place="left"]  .lbl{transform:translateY(-50%);}
.mapfig.in .pin[data-place="above"] .lbl{transform:translateX(-50%);}
.mapfig.in .pin[data-place="below"] .lbl{transform:translateX(-50%);}
.pin:hover .lbl{color:#fff;}
.pin:hover[data-place="right"] .lbl{transform:translateY(-50%) translateX(3px);}
.pin:hover[data-place="left"]  .lbl{transform:translateY(-50%) translateX(-3px);}

/* brand pin: clickable anchor → Google Maps Keramas. CRITICAL — must override
   the base .pin rule (which has pointer-events:none for the zero-sized wrapper),
   otherwise the entire anchor is non-interactive and the K cannot be clicked. */
.pin.pin--brand{
  z-index:6;cursor:pointer;outline:none;text-decoration:none;
  pointer-events:auto;          /* override base .pin pointer-events:none */
  /* CRITICAL: base .pin is width:0;height:0 → a 0×0 anchor has NO clickable
     area, so tapping the K did nothing. Give it a real 44×44 hit target
     (Apple's recommended min) centered on the Keramas point via the
     translate. The K image is centered inside this box. */
  width:44px;height:44px;
  transform:translate(-50%,-50%);
  display:block;
}

/* No halo / no glass effect — just the K letter, exactly as the
   reference image shows. K-letter image stands alone on the brown map. */
.pin.pin--brand::before,
.pin.pin--brand::after{
  display:none !important;
}

/* K-letter mark — clean, no hover scale, no glass effects.
   max-width:none overrides the global `img{max-width:100%}` rule
   (would compute 0 against the .pin parent's width:0;height:0 base). */
.pin.pin--brand .k-mark{
  /* Centered INSIDE the 44×44 anchor hit-box. */
  position:absolute;left:50%;top:50%;display:block;
  /* 22px — smaller for harmony with the landmark dots (which are 14px).
     Olive #525645 matches the dots' color (recolored in keanu-k3.png). */
  width:22px;height:auto;max-width:none;
  transform:translate(-50%,-50%);
  pointer-events:none;       /* clicks fall through to the anchor */
  filter:drop-shadow(0 1px 2px rgba(15,11,6,.25));
}

/* pulse halo — two concentric rings staggered for richer breathing */
.pin.pin--brand .ring{
  position:absolute;top:0;left:0;
  width:50px;height:50px;border-radius:50%;
  border:1.5px solid var(--olive);
  transform:translate(-50%,-50%);
  pointer-events:none;opacity:0;
}
.mapfig.in .pin.pin--brand .ring--1{animation:pinPulse 3.6s cubic-bezier(.16,1,.3,1) 1.2s infinite;}
.mapfig.in .pin.pin--brand .ring--2{animation:pinPulse 3.6s cubic-bezier(.16,1,.3,1) 3.0s infinite;}
.pin.pin--brand:hover .ring--1,
.pin.pin--brand:hover .ring--2{border-color:var(--accent);}
@keyframes pinPulse{
  0%  {opacity:.55;transform:translate(-50%,-50%) scale(1);}
  85% {opacity:0;  transform:translate(-50%,-50%) scale(2.8);}
  100%{opacity:0;  transform:translate(-50%,-50%) scale(2.8);}
}

/* TEAM 3 timeline — uniform photos, slide-in */
.timeline{position:relative;max-width:1000px;margin:84px auto 0;}
.timeline::before{content:"";position:absolute;top:8px;bottom:8px;left:50%;width:1px;background:var(--line);transform:translateX(-.5px);}
.member{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:7vw;align-items:center;margin-bottom:clamp(56px,8vh,104px);}
.member:last-child{margin-bottom:0;}
/* Editorial 4:5 portrait — uniform across all 4 members. Source JPGs are
   PRE-PROCESSED to exactly 1200×1500 (0.800 aspect), so object-fit:cover
   shows the full pre-composed frame with no further cropping.
   IMPORTANT: default transform must be 1.0 (no scale). The prior design
   used scale(1.06) on load that scaled to 1.0 only when .in fired — if
   IntersectionObserver was suppressed (some environments, embedded views),
   the image stayed permanently zoomed and cropped Charlie's head off. */
.member .pfig{width:100%;aspect-ratio:4/5;overflow:hidden;background:var(--paper-2);}
.member .pfig img{
  width:100%;height:100%;object-fit:cover;
  /* object-position center 22% preserves the UPPER THIRD of portraits
     when cropping to fit. On mobile .pfig becomes 4:3 landscape, so
     portrait 1200×1500 sources get vertically cropped — without the 22%
     bias, center-crop cuts faces (Bernhard especially). */
  object-position:center 22%;
  transform:none;transition:transform 1.6s var(--ease);
}
.member:hover .pfig img{transform:scale(1.04);}
.member .name{font-family:var(--hd);font-size:clamp(22px,2vw,30px);line-height:1.1;margin:0 0 6px;color:var(--ink);}
.member .role{font-size:10px;letter-spacing:.26em;text-transform:uppercase;color:var(--accent);margin:0 0 16px;}
.member .desc{font-size:14px;line-height:1.65;color:var(--muted);max-width:330px;margin:0;}
.member .dot{position:absolute;left:50%;top:50%;width:9px;height:9px;border-radius:50%;background:var(--paper);border:1px solid var(--accent);transform:translate(-50%,-50%);}
.member.right .pfig{order:2;}
.member.right .info{order:1;text-align:right;}
.member.right .desc{margin-left:auto;}

/* ownership steps */
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:5vw;}
.step{padding-top:28px;border-top:1px solid var(--line);}
.step .no{font-family:var(--hd);font-size:22px;color:var(--accent);margin:0 0 16px;}
.step h4{font-size:12px;letter-spacing:.06em;font-weight:700;margin:0 0 12px;color:var(--ink);text-transform:uppercase;}
.step p{font-size:14px;line-height:1.7;color:var(--muted);margin:0;font-weight:300;}

/* ============================================================
   PRIVATE RELEASE — quiet invitation card on dark beachfront
   ============================================================ */
.final{position:relative;z-index:2;min-height:88vh;display:flex;align-items:center;justify-content:center;padding:120px 24px;overflow:hidden;background:var(--night);}
.final img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.78;transform:scale(1.08);transition:transform 3.4s var(--ease),opacity 1.8s var(--ease);}
.final.in img{transform:scale(1);}
.final::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(15,11,6,.3),rgba(15,11,6,.45) 55%,rgba(15,11,6,.72));}

.release-card{
  position:relative;z-index:2;
  width:100%;max-width:520px;
  background:rgba(15,11,6,.46);
  backdrop-filter:blur(14px) saturate(120%);
  -webkit-backdrop-filter:blur(14px) saturate(120%);
  border:1px solid rgba(231,221,202,.18);
  padding:clamp(40px,5vw,68px) clamp(32px,4.5vw,56px);
  color:var(--cream);
  text-align:left;
  display:flex;flex-direction:column;gap:22px;
}
.release-label{
  font-family:var(--bd);font-size:10.5px;font-weight:400;
  letter-spacing:.5em;text-transform:uppercase;
  color:var(--cream);opacity:.7;margin:0;
}
.release-lead{
  font-family:var(--hd);font-style:italic;font-weight:400;
  font-size:clamp(28px,3vw,42px);line-height:1.16;
  color:#fff;margin:0;
}
.release-body{
  font-family:var(--bd);font-size:14px;font-weight:300;
  line-height:1.75;color:var(--cream);opacity:.86;
  margin:0;max-width:42ch;
}
.release-actions{
  display:flex;align-items:center;gap:24px;flex-wrap:wrap;margin-top:10px;
}
.btn-ghost.on-dark{color:#fff;border-color:rgba(255,255,255,.5);}
.btn-ghost.on-dark::before{background:#fff;}
.btn-ghost.on-dark:hover{color:var(--ink);border-color:#fff;}
.btn-text.on-dark{color:#fff;}

/* footer — single elegant lockup, no duplicates */
/* position:relative + z-index:2 = footer ALWAYS paints above the fixed
   .hero-frame (z-index:1). Without this, the footer sits at z:0 under the
   hero overlay and links become unclickable if the JS hasn't toggled the
   hero-frame's pointer-events off (Lenis/ScrollTrigger desync edge case). */
footer{position:relative;z-index:2;background:var(--night);color:var(--cream);padding:96px var(--gut) 56px;}
.f-stack{max-width:820px;margin:0 auto;display:flex;flex-direction:column;align-items:center;gap:48px;text-align:center;}
.f-stack .f-logo{height:54px;width:auto;opacity:.94;display:block;}
.f-links{display:flex;gap:38px;flex-wrap:wrap;justify-content:center;}
.f-links a{font-size:11px;letter-spacing:.26em;text-transform:uppercase;opacity:.7;transition:opacity .7s var(--ease);}
.f-links a:hover{opacity:1;}

/* Contact strip — WhatsApp + Email, slightly smaller than primary nav */
.f-contact{display:flex;gap:28px;flex-wrap:wrap;justify-content:center;}
.f-contact a{font-size:11px;letter-spacing:.22em;text-transform:uppercase;opacity:.6;transition:opacity .7s var(--ease);}
.f-contact a:hover{opacity:1;}

/* Fine print — small editorial body, wider max so it reads as a paragraph */
.f-fineprint{
  max-width:680px;margin:0 auto;font-size:11px;line-height:1.7;
  letter-spacing:.02em;color:rgba(231,221,202,.55);text-align:center;
}

/* Legal links — smallest tier, more transparent than primary nav */
.f-legal{display:flex;gap:24px;flex-wrap:wrap;justify-content:center;}
.f-legal a{font-size:10px;letter-spacing:.22em;text-transform:uppercase;opacity:.42;transition:opacity .7s var(--ease);}
.f-legal a:hover{opacity:.85;}

.f-bot{width:100%;display:flex;gap:12px 28px;flex-wrap:wrap;justify-content:center;align-items:center;font-size:10px;letter-spacing:.28em;text-transform:uppercase;opacity:.45;padding-top:32px;border-top:1px solid rgba(231,221,202,.12);}
.f-bot span+span::before{content:"·";margin-right:28px;color:rgba(231,221,202,.4);}

/* whatsapp */
.wa{position:fixed;right:26px;bottom:26px;z-index:70;display:flex;align-items:center;height:56px;width:56px;border-radius:40px;background:var(--night);color:var(--cream);overflow:hidden;text-decoration:none;box-shadow:0 12px 34px rgba(15,11,6,.34);transition:width .9s var(--ease),background .7s var(--ease),box-shadow .7s var(--ease);}
.wa .ico{flex:0 0 56px;width:56px;height:56px;display:flex;align-items:center;justify-content:center;}
.wa .ico svg{width:24px;height:24px;transition:transform .8s var(--ease);}
.wa:hover .ico svg{transform:scale(1.08);}
.wa .lbl{white-space:nowrap;font-size:11px;letter-spacing:.22em;text-transform:uppercase;padding-right:24px;opacity:0;transition:opacity .55s var(--ease) .25s;}
.wa:hover{width:212px;background:var(--accent);box-shadow:0 16px 42px rgba(168,106,79,.4);}
.wa:hover .lbl{opacity:1;}

/* loader */
#loader{position:fixed;inset:0;z-index:99;background:var(--night);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:28px;transition:opacity 1.2s var(--ease),visibility 1.2s;}
#loader.hide{opacity:0;pointer-events:none;visibility:hidden;}
#loader .ll img{height:52px;width:auto;opacity:.94;animation:llIn 2s var(--ease) both;}
@keyframes llIn{from{opacity:0;transform:translateY(10px) scale(.985);}to{opacity:.94;transform:none;}}
#loader .bar{position:relative;width:160px;height:1px;background:rgba(231,221,202,.16);overflow:hidden;}
#loader .bar #bar-fill{position:absolute;inset:0;width:0%;background:var(--accent);transition:width .55s var(--ease);}
#loader .pct{font-family:var(--bd);font-size:10px;letter-spacing:.45em;text-transform:uppercase;color:var(--cream);opacity:.55;}

/* responsive */
@media (max-width:1100px){
  .topbar nav{display:none;}
  .topbar .invite{display:none;}
  /* Narrow desktop / tablet: keep state 1 anchored bottom-right but constrain
     hard so headlines + supporting cannot overflow the viewport edge. */
  .state[data-state="1"]{
    max-width:min(540px, calc(100vw - 56px));
    right:clamp(20px, 4vw, 60px);
  }
}

/* --- /styles/04b-hero-visual-deck.css --- */
/* === 04b-hero-visual-deck.css ============================================
   Mobile cinematic system — CANVAS-based, single ScrollTrigger.

   Architecture:
   - .hero-frame-canvas    = single <canvas> drawImage'd per scroll tick.
                             No src swap, no per-frame decode jank.
   - .hero-detail          = scarcity scene foreground ("10 Residences only")
   - HARD DISABLE all legacy layers (visual deck, video, poster img) so
     iOS Safari doesn't waste GPU compositing fullscreen layers we removed.
   - NO filter:blur on mobile — kills perf during scroll.
   ========================================================================= */

/* Desktop: hide canvas + detail layer + mobile-only poetic line. */
.hero-frame-canvas{ display:none; }
.hero-detail{ display:none; }
.state .poetic-mobile{ display:none; }

@media (max-width:820px){
  /* Canvas takes the full hero-frame, drawn at devicePixelRatio for sharp
     rendering on retina. Poster image as background = NO BLACK FLASH on
     idle before canvas draws frame 0. Once canvas drawImage fires, the
     opaque-pixel context overlays the bg automatically. */
  .hero-frame-canvas{
    display:block;
    position:absolute;inset:0;
    width:100%;height:100%;
    background:url('/assets/poster.jpg') center/cover no-repeat #080706;
    z-index:0;
  }

  /* HARD-disable every legacy visual layer on mobile — prevents GPU from
     compositing invisible fullscreen elements that still consume layer
     memory. Was the source of perf debt after the canvas refactor. */
  .hero-frame > video,
  .hero-frame > img.hero-poster,
  .hero-frame-scrub,
  .hero-visual-deck,
  .hero-visual{
    display:none !important;
  }

  /* Stronger gradient veil for editorial text legibility across all 32 frames */
  .hero-frame .veil{
    background:linear-gradient(
      180deg,
      rgba(15,11,6,.55) 0%,
      rgba(15,11,6,.15) 38%,
      rgba(15,11,6,.78) 100%
    );
  }

  /* "10 Residences only" = PRIMARY editorial statement → upper-centered,
     dominant. Poetic line = SECONDARY supporting copy → lower-centered.
     Eye reads big claim first, then quiet supporting line below.
     Visual hierarchy: scarcity statement (top) > elaboration (bottom). */
  .hero-detail{
    display:flex;
    flex-direction:column;
    align-items:center;
    justify-content:flex-start;
    position:absolute;inset:0;z-index:3;
    padding:clamp(150px, 22vh, 200px) 24px 0;
    pointer-events:none;
    opacity:0;
    text-align:center;
  }
  .hero-detail .giant-number{
    position:static;
    font-family:var(--hd);font-style:italic;font-weight:400;
    font-size:clamp(140px,44vw,200px);line-height:.82;letter-spacing:-.02em;
    color:rgba(255,255,255,.96);margin:0;
    text-shadow:0 6px 60px rgba(0,0,0,.55), 0 0 120px rgba(0,0,0,.35);
  }
  .hero-detail .giant-label{
    position:static;
    margin-top:18px;
    font-family:var(--bd);font-size:10.5px;font-weight:400;
    letter-spacing:.5em;text-transform:uppercase;
    color:rgba(255,255,255,.82);
    text-shadow:0 1px 18px rgba(0,0,0,.6);
  }

  /* KILL all filter:blur on mobile — most expensive per-frame paint cost. */
  .state,
  .hero-detail,
  .statement.reveal{
    filter:none !important;
  }

  /* MOBILE-ONLY state 2: hide num+lbl (giant "10" + "Residences only" is in
     .hero-detail above), show the poetic complement instead. This kills
     the "10 Residences only" content duplication where both .hero-detail
     and state[2] showed the same exact words simultaneously. */
  .state[data-state="2"] .num,
  .state[data-state="2"] .lbl{
    display:none;
  }
  .state[data-state="2"] .poetic-mobile{
    display:block;
    font-family:var(--hd);font-style:italic;font-weight:400;
    font-size:clamp(18px,4.6vw,24px);line-height:1.45;letter-spacing:.005em;
    color:rgba(255,255,255,.92);margin:0;text-align:center;
    max-width:min(420px, calc(100vw - 64px));
    text-shadow:0 2px 30px rgba(0,0,0,.6),0 0 80px rgba(0,0,0,.35);
  }
  /* State 2 (poetic line) on mobile = SUPPORTING line, sits in lower
     portion below the dominant "10" statement.
     Final composition:
       ┌──────────────────┐
       │  topbar          │
       │  (sky/sun)       │
       │       10         │  ← upper-center, BIG italic (dominant)
       │  RESIDENCES ONLY │  ← small caps label below
       │  (villas/ocean)  │  ← middle breathing space
       │  A small private │  ← lower-center poetic (supporting)
       │  estate, held…   │
       │  quieter rhythm. │
       │  (safe bottom)   │
       └──────────────────┘
     */
  /* Full-width container so flex can horizontally center the child.
     Why not left:50% + translate(-50%, 0)? Because the master ST uses
     gsap.quickSetter(s, 'y', 'px') which writes transform:translate(0,Ypx)
     and OVERRIDES the CSS variable translate — state ended up shifted right.
     With left:0;right:0 the state IS full width, poetic-mobile child centers
     via justify-content:center, and GSAP's y transform is purely vertical. */
  .state[data-state="2"]{
    top:auto;
    bottom:clamp(90px, 14vh, 140px);
    left:0;right:0;
    --base-x:0; --base-y:0;
    width:auto;max-width:none;
    display:flex;align-items:center;justify-content:center;
    padding:0 24px;
  }
}

/* --- /styles/05-story-mobile.css --- */
/* === 05-story-mobile.css (auto-split from style.css) === */
@media (max-width:820px){
  :root{--gut:22px;--rhythm:clamp(90px,14vh,150px);}
  /* keep the 3-col grid (auto 1fr auto) — middle column empty when nav hides,
     pushing the menu cleanly to the right. Don't override to `auto auto`
     because that drops the right slot out of the grid entirely. */
  .topbar{padding:16px 22px;gap:0;}
  .topbar .wordmark.dual,.topbar .wordmark.dual img{height:22px;}

  /* Mobile hero 260svh = 2.6 screens. Within the QA-enforced 240-340svh
     range. Long enough for 32 frames to feel like continuous video motion
     (not slideshow), short enough not to bore the thumb-swipe user. */
  .hero{height:260svh;}
  .hero-frame video,.hero-frame .hero-poster{transform:translate3d(0,var(--par,0px),0) scale(1.02);}

  .hero-c{
    padding:calc(env(safe-area-inset-top,0px) + 96px) 22px
            calc(env(safe-area-inset-bottom,0px) + 64px);
  }

  /* STATE 1 — move to bottom-left, left-aligned for natural mobile reading */
  .state[data-state="1"]{
    right:auto;bottom:0;left:0;
    max-width:calc(100vw - 44px);
    text-align:left;align-items:flex-start;
    gap:20px;
  }
  .state[data-state="1"] .eb{font-size:10px;letter-spacing:.36em;}
  .state[data-state="1"] .hd{font-size:clamp(34px,9vw,46px);line-height:1.08;max-width:none;}
  .state[data-state="1"] .actions{gap:18px;flex-wrap:wrap;}

  /* STATE 2 — keep centered, scale down the "10" */
  .state[data-state="2"] .num{font-size:clamp(120px,40vw,200px);}
  .state[data-state="2"] .lbl{font-size:10px;letter-spacing:.4em;}

  /* STATE 3 — poetic line scaled for mobile reading */
  .state[data-state="3"]{max-width:calc(100vw - 44px);}
  .state[data-state="3"] .hd-poetic{font-size:clamp(18px,4.4vw,24px);line-height:1.5;}

  /* KEEP scroll cue on mobile — without it users often don't realize the
     hero IS scroll-driven storytelling (just looks like a static photo).
     Smaller + tucked bottom-right so it doesn't compete with state 1 copy. */
  .cue{bottom:18px;left:auto;right:18px;transform:none;opacity:.55;gap:8px;}
  .cue span{font-size:8px;letter-spacing:.4em;}
  .cue::after{height:22px;}

  .btn-ghost{padding:13px 24px;font-size:10px;}
  .btn-text{font-size:10.5px;}

  .menu{grid-template-columns:1fr;} .menu .pic{display:none;}
  .menu .pane{align-items:center;padding:0 24px;} .menu .links{align-items:center;} .menu .mcta{align-self:center;}
  .split{grid-template-columns:1fr;gap:42px;}
  .grid-3{grid-template-columns:1fr;gap:42px;}

  /* Estate facts on mobile = SINGLE-COLUMN EDITORIAL LIST.
     Previous flex-wrap produced uneven 2+2+1 rows ("disordered" feedback).
     Vertical stack reads cleanly, every fact on its own line, all centered. */
  .facts{
    display:flex;flex-direction:column;
    align-items:center;justify-content:center;
    gap:14px;padding-top:6px;
  }
  .facts span{
    padding:0;font-size:11px;
    letter-spacing:.32em;text-transform:uppercase;
    color:var(--muted);flex:0 0 auto;
  }
  .facts span+span::before{display:none;}

  /* CRITICAL: .reveal-l / .reveal-r use translateX(±64px) which pushes
     elements off-screen horizontally before IntersectionObserver fires.
     On mobile single-column layout this causes horizontal overflow alerts
     and visible scroll-bounce. Mobile gets Y-only reveal instead. */
  .reveal-l,.reveal-r{
    transform:translateY(36px) scale(.99) !important;
  }
  .reveal-l.in,.reveal-r.in{
    transform:none !important;
  }

  /* Team timeline → simple vertical list, no dot rail */
  .timeline::before{display:none;}
  .member,.member.right{grid-template-columns:1fr;gap:18px;margin-bottom:60px;padding-left:0;}
  /* On mobile single column stack — wider 4:3 reads better than narrow
     4:5 portrait when the pfig is full viewport width. */
  /* Match the 4:5 source photos exactly so object-fit:cover shows the FULL
     portrait with zero vertical crop — no more cut faces (Charlie etc.).
     Was 4:3 landscape which sliced the top+bottom off every portrait. */
  .member .pfig{order:1 !important;aspect-ratio:4/5;}
  .member .info{order:2 !important;text-align:center !important;}
  .member .name{font-size:22px;}
  .member .desc{margin:0 auto !important;}
  .member .dot{display:none;}

  .scene{height:70vh;min-height:420px;}
  .final{padding:80px 22px;}
  .release-card{padding:40px 28px;}
  .release-actions{flex-direction:column;align-items:flex-start;gap:18px;}

  .wa{right:16px;bottom:16px;height:50px;width:50px;}
  .wa .ico{flex-basis:50px;width:50px;height:50px;}
  .wa .ico svg{width:22px;height:22px;}
  .wa:hover{width:50px;background:var(--night);box-shadow:0 12px 34px rgba(15,11,6,.34);}
  .wa:hover .lbl{opacity:0;}

  /* Map pins on mobile: keep dots for ALL Figma pins (visual density preserved),
     but hide labels of secondary landmarks to avoid text collisions on small viewport.
     Primary labels (Ubud, Green School, Sanur Beach, Airport) stay visible. */
  .pin .dot{width:11px;height:11px;}
  .pin .lbl{font-size:8.5px;letter-spacing:.26em;}
  .pin[data-priority="secondary"] .lbl{display:none;}
  /* K mark on mobile — small + olive to sit harmoniously with landmark dots. */
  .pin.pin--brand .k-mark{width:18px;}
  /* Mobile: drop the cream halo behind the K — Polina wants K sitting
     directly on the map for a more elegant, less "button"-like presentation
     on small screens. Drop-shadow on the K still gives legibility. */
  /* No halo on mobile — matches desktop, just the K letter alone. */
  .pin.pin--brand::before{display:none !important;}

  footer{padding:64px 22px 48px;}
  .f-stack{gap:32px;}
  .f-stack .f-logo{height:44px;}
  .f-links{gap:18px 28px;}
  .f-contact{gap:18px;}
  .f-fineprint{font-size:10.5px;line-height:1.7;padding:0 8px;}
  .f-legal{gap:14px 18px;}
  .f-legal a{font-size:9.5px;}

  /* PERF: kill expensive paint effects on mobile */
  .topbar.dark{
    background-color:rgba(244,242,236,.96);
    backdrop-filter:none;-webkit-backdrop-filter:none;
  }
  .release-card{backdrop-filter:none;-webkit-backdrop-filter:none;background:rgba(15,11,6,.66);}
  .reveal,.reveal-l,.reveal-r{filter:none !important;}
  .scene img,.final img,.member .pfig img,.menu .pic,.menu .pane .bg{
    transform:none !important; transition:none !important;
  }
  .hero-frame video,.hero-frame .hero-poster{will-change:auto;transform:none !important;}
  .wa{box-shadow:0 8px 20px rgba(15,11,6,.28);}
}

@media (max-width:480px){
  .hero{height:240svh;}
  .state[data-state="1"] .hd{font-size:clamp(30px,9.2vw,38px);}
  .state[data-state="2"] .num{font-size:clamp(110px,42vw,160px);}
  .state[data-state="3"] .hd-poetic{font-size:clamp(17px,4.6vw,21px);}
}

/* Touch devices regardless of size: drop hover-only motion */
@media (hover:none){
  .member:hover .pfig img,.member.in:hover .pfig img{transform:scale(1);}
  .wa:hover{width:50px;background:var(--night);}
  .wa:hover .lbl{opacity:0;}
  .pin:hover .lbl{opacity:.55;}
}

@media (prefers-reduced-motion:reduce){
  .reveal,.reveal-l,.reveal-r{opacity:1 !important;transform:none !important;filter:none !important;}
  .scene img,.final img,.member .pfig img,.menu .pic,.menu .pane .bg{transform:none !important;}
  .cue::after,.pin.pin--brand .ring{animation:none;}
  .menu .links a,.menu .mcta,.menu .mword,.menu .close{opacity:1 !important;transform:none !important;transition:none !important;}
}

