/* =====================================================================
   LESTATE REAL — site stylesheet
   Built on the brand kit tokens (css/brand.css).

   Performance contract for every scroll-linked effect in js/:
   only `transform` and `opacity` are written per frame. Nothing here
   animates a property that forces layout or a re-raster — no
   width/height/top/left/border-radius on scroll surfaces.
   ===================================================================== */

*,*::before,*::after{box-sizing:border-box}

html{
  -webkit-text-size-adjust:100%;
  background:var(--canvas);
  scroll-behavior:smooth;
  /* keeps in-page anchors clear of the floating nav */
  scroll-padding-top:104px;
}
body{
  margin:0;color:var(--ink-1);
  font-family:var(--font-sans);letter-spacing:.2px;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  /* clip, not hidden: `hidden` turns body into a scroll container and
     makes position:sticky far more expensive on iOS. */
  overflow-x:clip;
}

/* The architectural grid lives on one fixed, composited layer.
   A scrolling background-image would repaint the whole viewport
   on every scroll tick; this never repaints at all. */
body::before{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background-image:
    linear-gradient(to right,var(--grid-line) 1px,transparent 1px),
    linear-gradient(to bottom,var(--grid-line) 1px,transparent 1px);
  background-size:var(--grid-size) var(--grid-size);
}

img{max-width:100%;display:block}
[hidden]{display:none !important}

/* =====================================================================
   BRAND MARKS
   The three wordmarks have different intrinsic ratios, and the Lestate
   Real lockup stacks two lines plus a tagline — at the same box height
   its letters come out half the size of the single line marks. So every
   mark is sized by height only (the width follows the real ratio, never
   a hand written one) and the lockup gets its own larger height.
   ===================================================================== */
.nav-logo img,.footer-logo,.op-mark,.p-mark{
  width:auto;max-width:none;object-fit:contain;object-position:left center;
}
a{color:inherit;text-decoration:none}
button{font-family:inherit}
::selection{background:var(--blue-accent-tint-2)}

:root{
  --nav-h:60px;
  --ease:cubic-bezier(.22,1,.36,1);
  --ease-io:cubic-bezier(.65,0,.35,1);
  --spring:cubic-bezier(.34,1.42,.5,1);
  --maxw:1160px;
  --pad:32px;
  /* One rhythm for the whole site. Every section pays the same padding
     top and bottom, so the gap between any two sections is identical
     and nothing has to be tuned by hand. */
  --sec-pad:72px;
  --hair:rgba(0,0,0,.07);
}

.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--pad);width:100%}
.section,.stats,.orbit-sec,.contact{position:relative;padding:var(--sec-pad) 0}

/* skip link — keyboard + screen reader entry point */
.skip{
  position:absolute;left:-9999px;top:0;z-index:200;
  padding:12px 18px;border-radius:0 0 12px 0;background:var(--blue-accent);color:#fff;
  font-size:13px;font-weight:700;
}
.skip:focus{left:0}

:where(a,button,input,textarea,select,[tabindex]):focus-visible{
  outline:2px solid var(--blue-accent);outline-offset:3px;border-radius:6px;
}
/* A pill button must keep its own radius when it is focused. A 6px
   outline around a 999px button pushes four square corners past the
   edge of whatever contains it — which is how the Investor Login ring
   broke out of the nav. */
.btn:focus-visible{border-radius:inherit;outline-offset:2px}
.nav .btn:focus-visible{outline-offset:1px}

/* =====================================================================
   TYPE
   ===================================================================== */
.eyebrow{
  margin:0;font-size:12px;font-weight:700;color:var(--blue-accent);
  letter-spacing:1.5px;text-transform:uppercase;
}
h1,h2,h3,h4{margin:0;color:var(--ink-1)}
h2{
  font-size:clamp(28px,3.4vw,44px);font-weight:700;
  letter-spacing:-1.1px;line-height:1.1;
}
h3{font-size:20px;font-weight:700;letter-spacing:-.4px;line-height:1.25}
.h2-sm{font-size:clamp(24px,2.6vw,34px);letter-spacing:-.8px}
.lead{margin:0;font-size:16px;line-height:1.6;color:var(--ink-2);max-width:62ch}
.lead b{color:var(--blue-accent);font-weight:700;font-variant-numeric:tabular-nums}
.muted{color:var(--ink-2)}
.note{margin:0;font-size:12px;color:var(--ink-3);line-height:1.55}
.micro{
  margin:0;font-size:10.5px;font-weight:700;letter-spacing:1.5px;
  text-transform:uppercase;color:var(--ink-3);
}
.sec-head{display:flex;flex-direction:column;gap:16px;max-width:760px}

.list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:9px}
.list li{position:relative;padding-left:18px;font-size:13.5px;line-height:1.55;color:var(--ink-2)}
.list li::before{
  content:"";position:absolute;left:0;top:8px;width:6px;height:6px;border-radius:50%;
  background:var(--blue-accent);
}
.list-green li::before{background:var(--green)}
.list-ink li::before{background:var(--ink-4)}

/* =====================================================================
   BUTTONS
   ===================================================================== */
.btn{
  position:relative;display:inline-flex;align-items:center;justify-content:center;gap:8px;
  font-size:13px;font-weight:700;letter-spacing:.3px;
  padding:13px 26px;border-radius:14px;border:1px solid transparent;cursor:pointer;
  transition:transform .5s var(--ease),background .25s ease,box-shadow .35s ease,
             color .25s ease,border-color .25s ease;
  overflow:hidden;text-align:center;
}
.btn::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:radial-gradient(120px 60px at var(--mx,50%) var(--my,50%),rgba(255,255,255,.32),transparent 70%);
  opacity:0;transition:opacity .3s ease;
}
.btn:hover::after{opacity:1}
.btn-primary{color:#fff;background:var(--blue-accent);box-shadow:0 4px 18px rgba(49,115,246,.32)}
.btn-primary:hover{background:#2765e8;box-shadow:0 10px 30px rgba(49,115,246,.4)}
.btn-primary:active{background:#1f57cf}
.btn-ghost{color:var(--blue-accent);background:var(--blue-accent-tint);border-color:rgba(49,115,246,.16)}
.btn-ghost:hover{background:var(--blue-accent-tint-2)}
.btn-line{color:var(--ink-1);background:transparent;border-color:var(--ink-5)}
.btn-line:hover{border-color:var(--ink-3);background:rgba(0,0,0,.02)}
.btn-sm{padding:9px 18px;border-radius:999px;font-size:12px}
.btn-block{width:100%}

/* the quiet blue used for Investor Login — present, never loud */
.btn-quiet{
  color:var(--blue-accent);background:var(--blue-accent-tint);
  border-color:rgba(49,115,246,.2);box-shadow:none;
}
.btn-quiet:hover{background:var(--blue-accent-tint-2);border-color:rgba(49,115,246,.34)}

.link-arrow{
  display:inline-flex;align-items:center;gap:7px;
  font-size:13px;font-weight:700;color:var(--blue-accent);
}
.link-arrow svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;transition:transform .4s var(--ease)}
.link-arrow:hover svg{transform:translateX(4px)}

/* =====================================================================
   GLASS SURFACE
   ===================================================================== */
.glass{
  background:rgba(255,255,255,.66);
  -webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%);
  border:1px solid rgba(255,255,255,.7);
  box-shadow:0 8px 32px rgba(0,0,0,.08),inset 0 1px 0 rgba(255,255,255,.7);
  border-radius:20px;
}
.card{
  background:rgba(255,255,255,.72);border:1px solid var(--hair);border-radius:20px;
  box-shadow:0 1px 2px rgba(0,0,0,.03);
}

/* =====================================================================
   SCROLL PROGRESS
   ===================================================================== */
.scroll-progress{position:fixed;top:0;left:0;right:0;height:2px;z-index:120;pointer-events:none}
.scroll-progress i{
  display:block;height:100%;width:100%;
  background:linear-gradient(90deg,#6ba3ff,var(--blue-accent));
  transform:scaleX(var(--p,0));transform-origin:left;
}

/* =====================================================================
   NAV
   ===================================================================== */
.nav{
  position:fixed;top:16px;left:50%;z-index:100;
  /* One capsule inside another: the ring left around the Investor Login
     pill can never be wider than the bar's own vertical padding, so the
     right padding matches it exactly. At 10px against 8px the two curves
     converged at the pill's corners and the button read as if it were
     breaking out of the bar. */
  display:flex;align-items:center;gap:20px;padding:10px 10px 10px 22px;
  max-width:calc(100vw - 28px);
  background:rgba(255,255,255,.62);
  -webkit-backdrop-filter:blur(22px) saturate(180%);backdrop-filter:blur(22px) saturate(180%);
  border:1px solid rgba(0,0,0,.06);border-radius:999px;
  box-shadow:0 8px 32px rgba(0,0,0,.09),inset 0 1px 0 rgba(255,255,255,.65);
  transform:translate3d(-50%,var(--ty,0),0);
  transition:transform .55s var(--ease),background .4s ease,box-shadow .4s ease,border-color .4s ease;
}
.nav.hide{--ty:-160%}

/* dark treatment while the nav floats over the hero */
.nav.dark{
  background:rgba(18,18,21,.55);border-color:rgba(255,255,255,.12);
  box-shadow:0 8px 32px rgba(0,0,0,.38),inset 0 1px 0 rgba(255,255,255,.12);
}
.nav.dark .nav-logo img{filter:brightness(0) invert(1)}
.nav.dark .nav-links a{color:rgba(255,255,255,.74)}
.nav.dark .nav-links a:hover,.nav.dark .nav-links a.on{color:#fff}
.nav.dark .nav-pill{background:rgba(255,255,255,.13)}
.nav.dark .btn-quiet{
  color:#a9c8ff;background:rgba(49,115,246,.2);border-color:rgba(140,180,255,.28);
}
.nav.dark .btn-quiet:hover{background:rgba(49,115,246,.34);color:#fff}

.nav-logo{display:flex;align-items:center;flex:none}
.nav-logo img{height:30px;transition:filter .4s ease}

.nav-links{position:relative;display:flex;gap:2px;align-items:center}
.nav-links a{
  position:relative;z-index:1;font-size:12.5px;font-weight:700;letter-spacing:.2px;
  color:var(--ink-2);padding:7px 12px;border-radius:999px;transition:color .3s ease;
  white-space:nowrap;
}
.nav-links a:hover{color:var(--ink-1)}
.nav-links a.on{color:var(--blue-accent)}
/* The pill used to be a 1px box stretched with scaleX, which stretches
   its corner radii with it: a 999px radius resolved down to half a pixel
   and came back out of the scale as a flat-topped rectangle. It carries
   its real width instead, so it is the same pill as the Investor Login
   button beside it. Width is only written when the active link changes,
   never per frame. */
.nav-pill{
  position:absolute;top:0;left:0;height:100%;width:var(--w,0px);border-radius:999px;
  background:rgba(0,0,0,.055);opacity:0;
  transform:translate3d(var(--x,0),0,0);
  transition:transform .5s var(--ease),width .5s var(--ease),opacity .3s ease;
}
.nav-pill.show{opacity:1}
.nav-cta{flex:none}

/* ---------- mobile: the house button ---------- */
.nav-house{
  display:none;width:42px;height:42px;flex:none;padding:0;cursor:pointer;
  align-items:center;justify-content:center;
  border-radius:50%;border:1px solid rgba(0,0,0,.08);
  background:rgba(255,255,255,.72);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  transition:background .3s ease,border-color .3s ease,transform .5s var(--spring);
}
.nav-house:active{transform:scale(.92)}
.nav.dark .nav-house{background:rgba(255,255,255,.13);border-color:rgba(255,255,255,.18)}

.nav-house svg{width:23px;height:23px;overflow:visible}
.nav-house svg *{
  fill:none;stroke:var(--ink-1);stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round;
  transition:transform .55s var(--spring),opacity .3s ease,stroke .3s ease;
}
.nav.dark .nav-house svg *{stroke:#fff}

/* closed → open: the roof lifts and tilts, the walls settle,
   the door swings open. The house literally unfolds the menu. */
.h-roof{transform-origin:16px 12px}
.h-door{transform-origin:12.5px 26px;opacity:1}
.h-walls{transform-origin:16px 22px}
.h-beam{opacity:0;transform-origin:16px 20px;transform:scaleX(0)}

.nav.open .nav-house{background:var(--blue-accent-tint);border-color:rgba(49,115,246,.3)}
.nav.open .nav-house svg *{stroke:var(--blue-accent)}
.nav.open .h-roof{transform:translateY(-6px) rotate(-4deg)}
.nav.open .h-door{transform:scaleX(.1);opacity:0}
.nav.open .h-walls{transform:translateY(2px) scaleX(1.06)}
.nav.open .h-beam{opacity:1;transform:scaleX(1);transition-delay:.12s}

/* ---------- mobile: the sheet that unfolds ---------- */
.nav-sheet{
  position:absolute;top:calc(100% + 12px);right:0;width:min(300px,calc(100vw - 32px));
  display:flex;flex-direction:column;padding:10px;gap:2px;
  background:rgba(255,255,255,.82);
  -webkit-backdrop-filter:blur(26px) saturate(180%);backdrop-filter:blur(26px) saturate(180%);
  border:1px solid rgba(0,0,0,.07);border-radius:22px;
  box-shadow:0 20px 60px rgba(0,0,0,.18);
  transform-origin:calc(100% - 21px) 0;
  opacity:0;transform:translate3d(0,-10px,0) scale(.94);pointer-events:none;
  transition:opacity .26s ease,transform .5s var(--spring);
}
.nav.open .nav-sheet{opacity:1;transform:none;pointer-events:auto}
.nav-sheet a{
  padding:13px 16px;border-radius:14px;font-size:15px;font-weight:700;color:var(--ink-1);
  display:flex;align-items:center;justify-content:space-between;
  opacity:0;transform:translateY(-6px);
  transition:opacity .3s ease,transform .45s var(--ease),background .2s ease;
}
.nav.open .nav-sheet a{opacity:1;transform:none;transition-delay:calc(60ms + var(--i,0) * 34ms)}
.nav-sheet a:active{background:rgba(0,0,0,.05)}
.nav-sheet a.on{color:var(--blue-accent)}
.nav-sheet .sheet-cta{
  margin-top:6px;justify-content:center;
  background:var(--blue-accent-tint);color:var(--blue-accent);
  border:1px solid rgba(49,115,246,.2);
}
.nav-sheet hr{border:none;border-top:1px solid var(--hair);margin:8px 6px}
.nav.dark .nav-sheet{background:rgba(22,22,25,.9);border-color:rgba(255,255,255,.12)}
.nav.dark .nav-sheet a{color:#fff}
.nav.dark .nav-sheet hr{border-top-color:rgba(255,255,255,.12)}

@media (min-width:961px){.nav-sheet{display:none}}

/* =====================================================================
   HERO
   ===================================================================== */
.hero{position:relative;height:340vh;background:#0b0b0d;color:#fff}
/* The frame follows the *dynamic* viewport, not the small one. At 100svh
   it was sized for a phone with its address bar out: the moment the bar
   retracted, the viewport grew and the pinned frame did not, so a black
   band of the hero's own background opened along the bottom edge and only
   closed once the white section below had scrolled up into it. 100dvh is
   always exactly what is on screen, so there is no band to close. */
.hero-pin{
  position:sticky;top:0;height:100dvh;overflow:hidden;
  display:flex;align-items:center;justify-content:center;
}

/* --- the stage: scaled, never re-laid-out ---
   Full bleed from the first frame. It used to open from a rounded 90%
   card, which put a dark margin around the drawing that only closed once
   you scrolled — the hero read as a screenshot of itself. The scroll
   still pushes in (1 → 1.06), it just never starts inset. */
.stage{
  position:absolute;inset:0;overflow:hidden;background:#0d1117;
  transform:scale(var(--s,1)) translateY(var(--sy,0px));
  will-change:transform;
}
.stage-video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .8s ease;
}
.stage.has-video .stage-video{opacity:1}
.stage.has-video .scene{opacity:0}

.stage-vignette{
  position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(100deg,rgba(6,8,12,.9) 0%,rgba(6,8,12,.64) 32%,rgba(6,8,12,.12) 60%,transparent 78%),
    linear-gradient(180deg,rgba(0,0,0,.4) 0%,transparent 22%,transparent 62%,rgba(0,0,0,.6) 100%),
    radial-gradient(130% 100% at 55% 45%,transparent 45%,rgba(0,0,0,.38) 100%);
}
/* static grain — an animated, blended full screen overlay costs a
   full repaint every frame, so it stays still. */
.stage-grain{
  position:absolute;inset:0;pointer-events:none;opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --- the wipe: two transforms, zero repaints --- */
.scene{position:absolute;inset:0;transition:opacity .6s ease}
.scene-layer{position:absolute;inset:0}
.scene-after{
  overflow:hidden;
  transform:scaleX(var(--wipe,0));transform-origin:0 50%;
  will-change:transform;
}
.scene-after .facade{transform:scaleX(var(--wipeInv,1));transform-origin:0 50%}
.scene-after.blank{visibility:hidden}
.scene-seam{
  position:absolute;top:0;bottom:0;left:0;width:2px;
  background:linear-gradient(180deg,transparent,rgba(140,190,255,.95),transparent);
  box-shadow:0 0 26px 5px rgba(49,115,246,.5);
  opacity:var(--seam,0);transform:translate3d(0,0,0);will-change:transform;
}

.facade{position:absolute;inset:0;overflow:hidden}
.facade .sky{position:absolute;inset:0}
.facade[data-facade="before"] .sky{
  background:
    radial-gradient(100% 70% at 62% 96%,rgba(160,175,195,.14),transparent 62%),
    linear-gradient(180deg,#0c0f14 0%,#141a22 55%,#1a222c 100%);
}
.facade[data-facade="after"] .sky{
  background:
    radial-gradient(70% 46% at 66% 92%,rgba(120,180,255,.22),transparent 62%),
    radial-gradient(110% 80% at 30% 8%,rgba(49,115,246,.22),transparent 60%),
    linear-gradient(180deg,#060b13 0%,#0b1725 52%,#122436 100%);
}
.facade .mesh{position:absolute;inset:0;opacity:.45}
.facade[data-facade="before"] .mesh{
  background-image:
    linear-gradient(to right,rgba(255,255,255,.05) 1px,transparent 1px),
    linear-gradient(to bottom,rgba(255,255,255,.05) 1px,transparent 1px);
  background-size:48px 48px;
}
.facade[data-facade="after"] .mesh{
  background-image:
    linear-gradient(to right,rgba(120,180,255,.08) 1px,transparent 1px),
    linear-gradient(to bottom,rgba(120,180,255,.08) 1px,transparent 1px);
  background-size:48px 48px;
}
.facade .horizon{
  position:absolute;left:0;right:0;bottom:14%;height:1px;opacity:0;
  background:linear-gradient(90deg,transparent,rgba(158,208,255,.5),transparent);
}
.facade[data-facade="after"] .horizon{opacity:1}

.facade svg{position:absolute;inset:0;width:100%;height:100%}

.dw{fill:none;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke}
.dw-far  {stroke:rgba(255,255,255,.12);stroke-width:1}
.dw-out  {stroke:rgba(255,255,255,.7);stroke-width:1.6}
.dw-line {stroke:rgba(255,255,255,.26);stroke-width:1}
.dw-win  {stroke:rgba(255,255,255,.36);stroke-width:1;fill:rgba(255,255,255,.04)}
.dw-dim  {stroke:rgba(255,255,255,.28);stroke-width:1;stroke-dasharray:3 4}
.dw-txt-v{fill:rgba(255,255,255,.86);font-size:13px;font-weight:700;letter-spacing:1.2px}

.facade[data-facade="after"] .dw-far  {stroke:rgba(120,180,255,.18)}
.facade[data-facade="after"] .dw-out  {stroke:rgba(158,208,255,.95)}
.facade[data-facade="after"] .dw-line {stroke:rgba(120,180,255,.36)}
.facade[data-facade="after"] .dw-win  {stroke:rgba(158,208,255,.5);fill:rgba(10,30,55,.45)}
.facade[data-facade="after"] .dw-dim  {stroke:rgba(120,180,255,.45)}
.facade[data-facade="after"] .dw-txt-v{fill:#fff}

/* The transformed asset is one drawing in one colour. Marking the added
   storey, the balconies and the retrofit envelope in a second hue turned
   the building into a legend with a key, and the eye read the colours
   instead of the architecture — so everything here is the same light
   blue and only the line weight changes. */
.dw-add  {stroke:rgba(158,208,255,.85);stroke-width:1.4;fill:none}
.dw-add-f{stroke:rgba(158,208,255,.55);stroke-width:1.2;fill:rgba(120,180,255,.06)}
.dw-bal  {stroke:rgba(178,218,255,.72);stroke-width:1.15;fill:none}
.dw-bal-f{stroke:rgba(178,218,255,.78);stroke-width:1;fill:rgba(150,200,255,.16)}
.dw-glass{stroke:rgba(178,218,255,.3);stroke-width:.8;fill:rgba(150,200,255,.09)}
.dw-pv   {stroke:rgba(158,208,255,.9);stroke-width:1.2;fill:rgba(49,115,246,.2)}
.dw-pv-c {stroke:rgba(158,208,255,.55);stroke-width:.7;fill:none}

/* glazing bars, frame rebates, door leaves: the finest line weight in
   the drawing, which is what turns a rectangle into a window */
.dw-glaz {stroke:rgba(255,255,255,.24);stroke-width:.8;fill:none}
.facade[data-facade="after"] .dw-glaz{stroke:rgba(158,208,255,.36)}

/* mullion and transom. Heavier than a glazing bar on purpose: at this
   scale the cross is the whole difference between a window and a hole. */
.dw-bar  {stroke:rgba(255,255,255,.44);stroke-width:1.1;fill:none}
.facade[data-facade="after"] .dw-bar{stroke:rgba(178,218,255,.62)}

/* the added storey fades in behind the crane rather than appearing
   fully built — the outline is there, the substance arrives */
.new-storey{opacity:var(--storey,1)}

/* site infrastructure: crane, scaffold, crew. Present during the
   transformation, gone once the asset is finished. */
.construct{opacity:var(--build,0)}
/* the load on the hook drifts — one tiny composited group, nothing else */
.hoist{animation:hoistDrift 7s ease-in-out infinite}
@keyframes hoistDrift{0%,100%{transform:translate(0,0)}50%{transform:translate(-5px,-7px)}}
.dw-rig  {stroke:rgba(255,255,255,.62);stroke-width:1.3;fill:none}
.dw-rig-f{stroke:rgba(255,255,255,.62);stroke-width:1.3;fill:rgba(255,255,255,.06)}
.dw-crew {stroke:rgba(178,218,255,.8);stroke-width:1.5;fill:none}
.dw-hook {stroke:rgba(255,255,255,.5);stroke-width:1;fill:none}

/* Occupancy, not yellow blocks. A warm fill made a handful of flats
   read as a different material to the rest of the facade, so a lit flat
   is simply a brighter pane of the same blue. */
.dw-win{transition:fill .7s ease,stroke .7s ease}
.facade[data-facade="after"] .dw-win.lit{
  fill:rgba(150,205,255,.17);stroke:rgba(196,228,255,.72);
}

/* --- hero copy --- */
.hero-inner{
  position:relative;z-index:3;width:100%;max-width:var(--maxw);
  padding:0 var(--pad);margin:0 auto;height:100%;
  display:flex;flex-direction:column;justify-content:center;
  pointer-events:none;
}
.hero-inner a,.hero-inner button{pointer-events:auto}
/* faded out is not gone: without this the invisible buttons keep taking
   the tap for the rest of the pinned runway (class set in js/home.js) */
.hero.copy-gone .hero-copy a{pointer-events:none}
.hero-copy{
  max-width:680px;display:flex;flex-direction:column;gap:22px;
  opacity:var(--copyOpacity,1);
  transform:translate3d(0,calc(var(--copyY,0) * -1px),0) scale(var(--copyScale,1));
  will-change:transform,opacity;
}
.hero-copy .eyebrow{color:#6fa6ff;letter-spacing:1.8px}
.hero-h1{
  font-size:clamp(32px,4.6vw,60px);line-height:1.05;font-weight:700;
  letter-spacing:-2px;color:#fff;text-shadow:0 4px 40px rgba(0,0,0,.45);
}
.hero-h1 .line{display:block;overflow:hidden}
.hero-h1 .line>span{display:block;transform:translateY(110%);animation:lineUp 1.05s var(--ease) forwards}
.hero-h1 .line:nth-child(1)>span{animation-delay:.14s}
.hero-h1 .line:nth-child(2)>span{animation-delay:.26s}
.hero-h1 .line:nth-child(3)>span{animation-delay:.38s}
@keyframes lineUp{to{transform:translateY(0)}}
/* the sentence and the buttons: two rows of the copy on desktop, one
   shared place at the foot of the screen on a phone (see RESPONSIVE) */
.hero-swap{display:flex;flex-direction:column;gap:22px}
.hero-sub{margin:0;font-size:17px;line-height:1.6;color:rgba(255,255,255,.78);max-width:560px}
.hero-cta{display:flex;gap:12px;flex-wrap:wrap}
/* the same quiet blue Investor Login carries in the nav, in the nav's own
   dark treatment: over the drawing it must never become a light surface */
.hero-cta .btn-quiet{
  color:#a9c8ff;background:rgba(49,115,246,.2);
  border-color:rgba(140,180,255,.28);box-shadow:none;
}
.hero-cta .btn-quiet:hover{background:rgba(49,115,246,.34);color:#fff}
.hero-cta .btn-ghost{color:#fff;background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.18)}
.hero-cta .btn-ghost:hover{background:rgba(255,255,255,.22)}

.hero-scroll{
  position:absolute;right:var(--pad);bottom:12vh;
  display:flex;align-items:center;gap:12px;
  font-size:11px;font-weight:700;letter-spacing:1.4px;text-transform:uppercase;
  color:rgba(255,255,255,.58);opacity:var(--scrollOpacity,1);
}
.hero-scroll-rail{display:block;width:70px;height:2px;background:rgba(255,255,255,.22);position:relative;overflow:hidden}
.hero-scroll-rail i{
  position:absolute;inset:0;background:#fff;transform:translateX(-100%);
  animation:railRun 2.2s var(--ease-io) infinite;
}
@keyframes railRun{0%{transform:translateX(-100%)}55%{transform:translateX(0)}100%{transform:translateX(100%)}}

/* =====================================================================
   MARKET STATS
   No rules, no dividers: the numbers carry the section on their own.
   Everything that moves here is a transform or an opacity.
   ===================================================================== */
/* the pinned section that follows brings its own vertical slack, so this
   one does not pay for the gap twice */
.stats{padding:44px 0 0}
.stats-h{max-width:22ch;font-size:clamp(26px,3vw,38px);letter-spacing:-.9px}
.stats-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:14px;margin-top:34px}
.stat{
  position:relative;display:flex;flex-direction:column;gap:12px;
  padding:18px 16px 18px 0;border-radius:18px;
  transition:transform .55s var(--ease);
}

/* the number rides up out of a mask while it counts */
.stat-val{display:block;overflow:hidden;padding-bottom:4px;margin-bottom:-4px}
.stat-v{
  display:block;font-size:clamp(34px,4vw,52px);font-weight:700;letter-spacing:-2px;
  color:var(--blue-accent);font-variant-numeric:tabular-nums;line-height:1.04;
  transform:translate3d(0,108%,0);
  transition:transform 1s var(--ease);
  transition-delay:calc(var(--d,0) * 1ms + 60ms);
}
.reveal.in .stat-v{transform:none}

.stat-l{
  font-size:13.5px;line-height:1.45;color:var(--ink-2);max-width:19ch;font-weight:700;
  opacity:0;transform:translate3d(0,10px,0);
  transition:opacity .7s var(--ease),transform .7s var(--ease);
  transition-delay:calc(var(--d,0) * 1ms + 320ms);
}
.reveal.in .stat-l{opacity:1;transform:none}

/* a bloom behind the figure as it lands, then it settles back to almost
   nothing — a single keyframe, so it never repaints again afterwards */
.stat-glow{
  position:absolute;left:-30px;top:-20px;width:200px;height:136px;pointer-events:none;
  background:radial-gradient(closest-side,var(--blue-accent-tint-2),transparent 72%);
  opacity:0;
}
.reveal.in .stat-glow{
  animation:statBloom 1.7s var(--ease) forwards;
  animation-delay:calc(var(--d,0) * 1ms + 140ms);
}
@keyframes statBloom{
  0%  {opacity:0;transform:scale(.68)}
  42% {opacity:1;transform:scale(1.04)}
  100%{opacity:.32;transform:scale(1)}
}

@media (hover:hover){
  .stat:hover{transform:translateY(-5px)}
  .stat:hover .stat-l{color:var(--ink-1)}
}

/* --- desktop: the figures sit beside the headline, not under it ---
   Five numbers at 52px across the full column outweighed everything else
   on the page — they were the first and loudest thing after the hero.
   Beside the headline they become what they are: the evidence for it.
   Each one is a row, so the figure can shrink without the labels
   crowding, and the column reads top to bottom like a fact sheet. */
@media (min-width:1081px){
  /* centred, not top aligned: the headline is the claim and the column
     beside it is the evidence, so the two read as one statement rather
     than as a heading with a list hanging off its first line. */
  .stats .wrap{
    display:grid;grid-template-columns:minmax(0,1.08fr) minmax(0,.92fr);
    gap:60px;align-items:center;
  }
  .stats-h{max-width:none;font-size:clamp(26px,2.7vw,35px);letter-spacing:-.8px}

  .stats-grid{display:flex;flex-direction:column;gap:0;margin-top:0}
  .stat{
    flex-direction:row;align-items:baseline;gap:20px;
    padding:15px 0;border-radius:0;border-top:1px solid var(--hair);
  }
  .stat:first-child{border-top:none;padding-top:0}
  .stat:last-child{padding-bottom:0}

  /* wide enough for `0.67 %`, the longest figure, and nothing more —
     any slack here opens a gap the label has to reach across */
  .stat-val{flex:none;width:96px}
  .stat-v{font-size:clamp(24px,2.2vw,30px);letter-spacing:-1.1px}
  .stat-l{max-width:none;font-size:13px}
  .stat-glow{left:-24px;top:-16px;width:140px;height:88px}
}
/* the lift belongs to a tile; in a row list the figure nudges instead */
@media (min-width:1081px) and (hover:hover){
  .stats-grid .stat:hover{transform:translateX(4px)}
}

/* =====================================================================
   DIMENSIONS — pinned horizontal track
   ===================================================================== */
/* --pull is measured in js/home.js: it takes back the empty space the
   sticky frame leaves above and below the composition, so this section
   sits in the same rhythm as every other one. */
.dims{height:330vh;position:relative;margin:calc(-1 * var(--pull,0px)) 0}
/* The pinned frame is a fixed 100svh, so whatever the content does not
   use turns into slack above and below it — which is what made the gap
   into this section twice the size of every other one. The card height
   is set so the composition fills the frame and the slack lands close to
   the site's normal section gap. */
.dims-pin{
  position:sticky;top:0;height:100svh;overflow:hidden;
  display:flex;flex-direction:column;justify-content:center;gap:32px;
}
.dims-top{display:flex;flex-direction:column;gap:24px}
.dims-head h2{max-width:22ch}
/* the label sits with the cards it describes, not underneath them */
.dims-meta{display:flex;align-items:center;gap:20px}
.dims-label{font-size:12px;font-weight:700;letter-spacing:.4px;color:var(--ink-2);white-space:nowrap}
.dims-bar{flex:1;height:2px;background:rgba(0,0,0,.09);position:relative;overflow:hidden}
.dims-bar i{position:absolute;inset:0;background:var(--blue-accent);transform:scaleX(var(--p,0));transform-origin:left}

.dims-rail{
  width:100%;
  /* the rail clips horizontally, so it needs vertical room for the
     hover lift — otherwise the top edge of a card gets shaved off */
  padding:26px 0;margin:-26px 0;overflow:hidden;
}
.dims-track{
  display:flex;gap:20px;
  padding:0 max(var(--pad),calc((100vw - var(--maxw))/2 + var(--pad)));
  transform:translate3d(var(--x,0px),0,0);will-change:transform;
}
.dim{
  position:relative;flex:none;width:min(26vw,320px);height:min(46vh,370px);
  border-radius:24px;padding:26px;overflow:hidden;
  background:linear-gradient(165deg,rgba(255,255,255,.9) 0%,rgba(244,244,247,.9) 100%);
  border:1px solid var(--hair);
  display:flex;flex-direction:column;justify-content:space-between;
  transition:transform .5s var(--ease),box-shadow .5s var(--ease),border-color .4s ease;
}
.dim-n{
  font-size:15px;font-weight:700;letter-spacing:2px;color:var(--ink-4);
  font-variant-numeric:tabular-nums;position:relative;z-index:1;
}
.dim-icon{
  position:absolute;right:-14px;top:34%;width:190px;height:190px;
  transform:translateY(-50%);opacity:.12;pointer-events:none;
  transition:opacity .5s var(--ease),transform .6s var(--ease);
}
.dim-icon svg{width:100%;height:100%;fill:none;stroke:var(--blue-accent);stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round}
.dim-body{position:relative;z-index:1;display:flex;flex-direction:column;gap:6px}
.dim h3{font-size:26px;letter-spacing:-.6px}
.dim p{margin:0;font-size:13.5px;color:var(--ink-3);line-height:1.5}
.dim-glow{
  position:absolute;inset:auto -30% -60% -30%;height:70%;pointer-events:none;
  background:radial-gradient(closest-side,rgba(49,115,246,.2),transparent);
  opacity:0;transition:opacity .5s ease;
}
@media (hover:hover){
  .dim:hover{transform:translateY(-6px);box-shadow:var(--shadow-lg);border-color:rgba(49,115,246,.35)}
  .dim:hover .dim-icon{opacity:.22;transform:translateY(-50%) scale(1.05)}
  .dim:hover .dim-glow{opacity:1}
}

/* the success checkmark draws itself with this */
@keyframes drawIn{to{stroke-dashoffset:0}}

/* =====================================================================
   THE SELECTOR — platform stages and transformation measures
   ---------------------------------------------------------------------
   This was a ring of buttons around a circle, with a blue arc sweeping
   round it on a loop, a green value arc growing on every turn, and a
   panel that replaced itself every few seconds. Three animations, one
   decision, and copy nobody could finish reading.

   What replaced it: a list you choose from, a pair of arrows for the
   same job, and a panel that changes only when asked. Same component
   twice, same markup, no timer.
   ===================================================================== */
.orbit-sec{padding:var(--sec-pad) 0}

/* =====================================================================
   THE LOOP
   Three companies, one closed loop, drawn once directly under the claim
   it illustrates and before the selector that details each of them.
   It sits on the site's own canvas: the wordmarks are the delivered
   files and they are already dark ink, so nothing is tinted, and every
   line is the same blue the rest of the page accents with.

   No script. The whole sequence hangs off the .in class that the reveal
   observer in js/site.js adds once and then stops watching for, so it
   plays a single time and holds its finished state.
   ===================================================================== */
/* The claim and the loop stand beside each other on a desktop and are
   centred against one another: the middle of the copy block meets the
   middle of the ring. Below the breakpoint they simply stack. */
.plat-top{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:56px;align-items:center;
}
.plat-top .sec-head{max-width:560px}
.plat-top .fw{margin:0;max-width:560px}

.fw{margin:52px auto 0;max-width:720px;display:flex;flex-direction:column;align-items:center}
.fw-svg{width:100%;height:auto;display:block;overflow:visible}

.fw-ring{fill:none;stroke:rgba(17,17,17,.09);stroke-width:1;stroke-dasharray:3 7}
.fw-arc{
  fill:none;stroke:var(--blue-accent);stroke-width:2;stroke-linecap:round;
  stroke-dasharray:100;stroke-dashoffset:100;
}
.fw-head{
  fill:none;stroke:var(--blue-accent);stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;opacity:0;
}
/* All three nodes are drawn the same. Marking one of them said Lestate
   Real mattered more than the other two, which is the opposite of what a
   closed loop of equal parts is for. */
.fw-pill{fill:#fff;stroke:rgba(17,17,17,.13);stroke-width:1.2}
.fw-role{fill:var(--ink-3);font-family:var(--font-sans);font-size:11px;letter-spacing:.1px}
/* what each company is, set opposite its own node */
.fw-side{
  fill:var(--blue-accent);font-family:var(--font-sans);
  font-size:10.5px;font-weight:700;letter-spacing:1.1px;text-transform:uppercase;
}
.fw-node{opacity:0;transform:scale(.94);transform-box:fill-box;transform-origin:50% 50%}

/* --- the sequence: nodes, then the arrows in loop order, then one pulse --- */
.fw.in .fw-node{
  opacity:1;transform:none;
  transition:opacity .7s var(--ease),transform .7s var(--ease);
  transition-delay:calc(var(--k) * 140ms);
}
.fw.in .fw-arc{
  stroke-dashoffset:0;
  transition:stroke-dashoffset .85s var(--ease);
  transition-delay:calc(620ms + var(--k) * 340ms);
}
.fw.in .fw-head{
  opacity:1;transition:opacity .3s ease;
  transition-delay:calc(1330ms + var(--k) * 340ms);
}

@media (max-width:980px){
  .plat-top{grid-template-columns:minmax(0,1fr);gap:0}
  .plat-top .sec-head{max-width:760px}
  .plat-top .fw{margin:44px auto 0}
}

/* The ring is the drawing at every width. On a phone it gets the whole
   column, js/home.js tightens the viewBox around it, and the type is set
   larger in the viewBox's own units — the drawing scales, so a caption
   fixed at 11 units arrives at six pixels on a 390px screen. These sizes
   land at about the size the desktop ring renders them at.

   The two side labels move under their own boxes here. Beside them they
   need 110 units of canvas each, which on a phone is a third of the
   width spent on two words — and "Infrastructure" ran off the screen. */
@media (max-width:720px){
  .fw,.plat-top .fw{margin-top:40px;max-width:none;width:100%}
  .fw-role{font-size:15.7px}
  .fw-side{font-size:12.9px;letter-spacing:1.4px;text-anchor:middle}
  .fw-node:nth-of-type(2) .fw-side{transform:translate(-100px,44px)}
  .fw-node:nth-of-type(3) .fw-side{transform:translate(100px,44px)}
}

@media (prefers-reduced-motion:reduce){
  .fw-node{opacity:1;transform:none}
  .fw-arc{stroke-dashoffset:0}
  .fw-head{opacity:1}
  .fw.in .fw-node,.fw.in .fw-arc,.fw.in .fw-head{transition:none}
}
.picker{display:grid;grid-template-columns:320px 1fr;gap:56px;align-items:start;margin-top:48px}
.picker-side{display:flex;flex-direction:column;gap:22px;position:sticky;top:108px}

.picker-list{display:flex;flex-direction:column}
.pick{
  position:relative;width:100%;cursor:pointer;text-align:left;
  display:grid;grid-template-columns:auto 1fr;gap:3px 13px;align-items:baseline;
  padding:17px 4px 17px 16px;background:none;border:none;
  border-top:1px solid var(--hair);
  transition:border-color .35s ease;
}
.pick:last-child{border-bottom:1px solid var(--hair)}
/* the marker that says which one you are reading */
.pick::before{
  content:"";position:absolute;left:0;top:50%;width:2px;height:0;
  background:var(--blue-accent);border-radius:2px;translate:0 -50%;
  transition:height .45s var(--ease);
}
.pick-n{
  font-size:11px;font-weight:700;letter-spacing:1.6px;color:var(--ink-4);
  font-variant-numeric:tabular-nums;transition:color .3s ease;
}
.pick-t{
  font-size:17px;font-weight:700;letter-spacing:-.3px;color:var(--ink-2);
  transition:color .3s ease;
}
.pick-s{
  grid-column:2;font-style:normal;font-size:12px;line-height:1.4;color:var(--ink-4);
  transition:color .3s ease;
}
.pick:hover .pick-t{color:var(--ink-1)}
.pick.on::before{height:calc(100% - 26px)}
.pick.on .pick-t{color:var(--ink-1)}
.pick.on .pick-n,.pick.on .pick-s{color:var(--blue-accent)}

.picker-nav{display:flex;align-items:center;gap:10px}
.pick-arrow{
  width:40px;height:40px;flex:none;display:grid;place-items:center;cursor:pointer;
  border-radius:999px;border:1px solid var(--hair);background:rgba(255,255,255,.7);
  transition:border-color .3s ease,background .3s ease,transform .5s var(--spring);
}
.pick-arrow svg{
  width:15px;height:15px;fill:none;stroke:var(--ink-2);stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;transition:stroke .3s ease;
}
.pick-arrow:hover{border-color:rgba(49,115,246,.34);background:#fff}
.pick-arrow:hover svg{stroke:var(--blue-accent)}
.pick-arrow:active{transform:scale(.94)}
.pick-at{
  margin-left:6px;font-size:11px;font-weight:700;letter-spacing:1.4px;
  text-transform:uppercase;color:var(--ink-4);font-variant-numeric:tabular-nums;
}
.pick-at b{color:var(--ink-1)}

/* --- the panel --- */
.picker-panel{
  position:relative;padding:36px;border-radius:24px;overflow:hidden;
  min-height:400px;display:flex;flex-direction:column;gap:22px;
}
.op-head{display:flex;flex-direction:column;gap:12px}
.op-step{font-size:11px;font-weight:700;letter-spacing:1.6px;text-transform:uppercase;color:var(--ink-4)}
.op-mark{height:26px}
.op-mark[src*="lestate-real"]{height:46px}
.op-mark-txt{font-size:23px;font-weight:700;letter-spacing:-.6px}
.op-head h3{font-size:23px;letter-spacing:-.6px;line-height:1.3;max-width:30ch}
.op-tag{margin:0;font-size:16px;line-height:1.5;color:var(--ink-2);max-width:44ch}
/* description across the full width, facts underneath — side by side
   the fact tiles get so narrow that every label wraps three times */
.op-body{display:flex;flex-direction:column;gap:22px}
.op-desc{margin:0;font-size:14px;line-height:1.65;color:var(--ink-2);max-width:62ch}
.op-facts{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.op-fact{
  padding:14px 16px;border-radius:14px;background:rgba(255,255,255,.7);
  border:1px solid var(--hair);display:flex;flex-direction:column;gap:3px;
}
.op-fact span{font-size:9.5px;font-weight:700;letter-spacing:1.3px;text-transform:uppercase;color:var(--ink-4)}
.op-fact b{font-size:13.5px;font-weight:700;letter-spacing:-.1px;color:var(--ink-1);line-height:1.3}
.op-layer{
  margin-top:auto;font-size:11px;font-weight:700;letter-spacing:1.5px;
  text-transform:uppercase;color:var(--ink-4);
}
/* a short settle on the new content, not a transition anybody waits out */
.picker-panel.is-in>*{animation:panelIn .3s var(--ease) both}
@keyframes panelIn{from{opacity:0}to{opacity:1}}

#measures .op-head h3{font-size:27px;max-width:24ch}

/* =====================================================================
   CONTACT
   ===================================================================== */
.contact{padding:var(--sec-pad) 0;position:relative;overflow:hidden}
.contact::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(60% 55% at 12% 0%,rgba(49,115,246,.09),transparent 62%),
    radial-gradient(46% 46% at 92% 100%,rgba(52,199,89,.08),transparent 62%);
}
.contact-grid{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:60px;align-items:start}
.contact-copy{display:flex;flex-direction:column;gap:18px}
.contact-reach{display:flex;flex-direction:column;gap:8px;margin-top:8px}
.contact-reach a{font-size:14px;font-weight:700;color:var(--blue-accent)}

.form-card{padding:32px;border-radius:24px}
.form-card form{display:flex;flex-direction:column;gap:16px}
.field{display:flex;flex-direction:column;gap:7px}
.field label,.field-label{font-size:13px;font-weight:700;color:var(--ink-1)}
.field input,.field textarea{
  font-family:inherit;font-size:14px;padding:13px 15px;border-radius:12px;
  border:1px solid var(--grey-300);background:#fff;outline:none;letter-spacing:.2px;
  color:var(--ink-1);width:100%;
  transition:border-color .25s ease,box-shadow .25s ease;
}
.field textarea{resize:vertical;min-height:104px;line-height:1.5}
.field input::placeholder,.field textarea::placeholder{color:var(--ink-4)}
.field input:focus,.field textarea:focus{border-color:var(--blue-accent);box-shadow:0 0 0 3px rgba(49,115,246,.16)}
.field input.err,.field textarea.err{border-color:var(--red);box-shadow:0 0 0 3px rgba(255,59,48,.14)}

.chips{display:flex;gap:8px;flex-wrap:wrap}
.chips button{
  font-size:12.5px;font-weight:700;padding:10px 15px;border-radius:12px;cursor:pointer;
  border:1px solid var(--grey-300);background:#fff;color:var(--ink-2);letter-spacing:.2px;
  transition:border-color .25s ease,background .25s ease,color .25s ease,transform .4s var(--spring);
}
.chips button:hover{border-color:var(--ink-4)}
.chips button:active{transform:scale(.96)}
.chips button.on{border-color:var(--blue-accent);background:var(--blue-accent-tint);color:var(--blue-accent)}

/* The three companies answer the question by their wordmark. Equal cells,
   the delivered lockups on white where they are already dark ink, so
   nothing here is tinted and the selected one is marked by its edge. */
.chips-brand{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.chips-brand button{
  display:grid;place-items:center;padding:16px 12px;min-height:64px;
}
.chips-brand img{
  width:auto;max-width:100%;display:block;object-fit:contain;
  opacity:.62;transition:opacity .25s ease;
}
.chips-brand button:nth-child(1) img{height:15px}
.chips-brand button:nth-child(2) img{height:23px}
.chips-brand button:nth-child(3) img{height:15px}
.chips-brand button:hover img,.chips-brand button.on img{opacity:1}
.chips-more{margin-top:8px}
@media (max-width:420px){
  .chips-brand{grid-template-columns:1fr;gap:6px}
  .chips-brand button{min-height:56px;padding:13px 12px}
}
.form-error{margin:0;font-size:12.5px;color:var(--red);font-weight:700}
.form-done{display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;padding:52px 0}
.form-done h3{font-size:19px}
.form-done p{margin:0;font-size:13.5px;color:var(--ink-2);max-width:38ch}
.form-done .note a{color:var(--blue-accent);font-weight:700}
.check{width:52px;height:52px;border-radius:50%;background:var(--green-tint);display:grid;place-items:center}
.check svg{width:26px;height:26px;fill:none;stroke:var(--green);stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round}
.check svg path{stroke-dasharray:26;stroke-dashoffset:26;animation:drawIn .6s var(--ease) .15s forwards}

/* =====================================================================
   FOOTER
   ===================================================================== */
/* the bottom bar (copyright + brand marks) is gone, so the columns are the
   last thing in the footer and need their own closing space */
/* The background is stated rather than inherited, so that the same
   footer markup lands the same way whatever the section above it did.
   Every page ends on the canvas today, so it changes nothing; it is what
   keeps a page that ends on a dark section from rendering light grey
   type on near black. */
.footer{position:relative;background:var(--canvas);color:var(--ink-1);
  border-top:1px solid var(--hair);padding:64px 0 64px;margin-top:0}
.footer-top{display:grid;grid-template-columns:1.6fr 1fr 1fr;gap:40px}
.footer-brand{display:flex;flex-direction:column;gap:16px;max-width:280px;align-items:flex-start}
.footer-logo{height:34px}
.footer-brand p{margin:0;font-size:13px;line-height:1.6;color:var(--ink-3)}
.footer-mail{font-size:13.5px;font-weight:700;color:var(--blue-accent);transition:opacity .25s ease}
.footer-mail:hover{opacity:.72}
.footer-col{display:flex;flex-direction:column;gap:12px}
.footer-col h4{font-size:10.5px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;color:var(--ink-4)}
.footer-col a{font-size:13.5px;color:var(--ink-2);transition:color .25s ease;width:fit-content}
.footer-col a:hover{color:var(--blue-accent)}

/* =====================================================================
   SUBPAGES
   ===================================================================== */
.page-hero{padding:180px 0 72px;position:relative}
.page-hero .eyebrow{margin-bottom:16px}
.page-hero h1{font-size:clamp(34px,5vw,62px);font-weight:700;letter-spacing:-2px;line-height:1.05}
.page-hero .lead{margin-top:20px;font-size:17px}
.page-hero-inner{max-width:820px;display:flex;flex-direction:column}

/* --- legal pages --- */
.legal{padding:0 0 120px}
.legal-inner{max-width:760px}
.legal h2{font-size:22px;letter-spacing:-.5px;margin:44px 0 14px}
.legal h3{font-size:16px;margin:26px 0 10px}
.legal p,.legal li{font-size:14.5px;line-height:1.7;color:var(--ink-2)}
.legal p{margin:0 0 14px}
.legal ul{margin:0 0 14px;padding-left:20px;display:flex;flex-direction:column;gap:6px}
.legal a{color:var(--blue-accent);font-weight:700}

/* --- investor login ---
   One column at every width. Side by side, the sign-in card competed
   with the capital story for the same first look and neither won; in
   sequence the page states the proposition, offers the door, and then
   explains the mechanics to whoever wants them. */
/* 820px, the same reading column the page hero above it uses */
.login-grid{
  display:flex;flex-direction:column;gap:64px;
  max-width:820px;padding-bottom:110px;
}
.login-card{
  padding:36px;border-radius:24px;display:flex;flex-direction:column;gap:20px;
  width:100%;max-width:520px;
}
.login-card h2{font-size:22px;letter-spacing:-.5px}
.login-card form{display:flex;flex-direction:column;gap:16px}
/* the answer to a sign in that finds nothing: the failure is stated in
   red above the button, and this is the one route that does work */
.login-notice{
  margin:0;padding-top:15px;border-top:1px solid var(--hair);
  font-size:12.5px;line-height:1.55;color:var(--ink-3);
}
.login-notice a{color:var(--blue-accent);font-weight:700}

.login-meta{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}
.login-meta a{font-size:12.5px;font-weight:700;color:var(--blue-accent)}

/* the capital loop, now living on the investor page */
.loop{position:relative;width:340px;height:340px;margin:0 auto}
.loop-ring{position:absolute;inset:0}
.loop-svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible;transform:rotate(-90deg)}
.loop-track{fill:none;stroke:rgba(0,0,0,.08);stroke-width:1.5}
.loop-fill{
  fill:none;stroke:var(--blue-accent);stroke-width:3;stroke-linecap:round;
  stroke-dasharray:741;stroke-dashoffset:calc(741 - 741 * var(--p,0));
}
.loop-dot{fill:#fff;stroke:var(--blue-accent);stroke-width:3}
.loop-steps{position:absolute;inset:0}
.loop-steps span{
  position:absolute;left:50%;top:50%;
  transform:rotate(var(--a)) translate(166px) rotate(calc(-1 * var(--a))) translate(-50%,-50%);
  display:flex;flex-direction:column;gap:1px;white-space:nowrap;
  font-size:12px;font-weight:700;letter-spacing:.2px;color:var(--ink-4);
  transition:color .35s ease;
}
.loop-steps span em{font-style:normal;font-size:10px;font-weight:400;color:var(--ink-4)}
.loop-steps span.on{color:var(--ink-1)}
.loop-steps span.on em{color:var(--blue-accent)}
.loop-core{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  display:flex;flex-direction:column;align-items:center;gap:2px;text-align:center;
}
.loop-core span{font-size:21px;font-weight:700;letter-spacing:-.4px;color:var(--blue-accent)}
.loop-core em{font-style:normal;font-size:10.5px;letter-spacing:1.4px;text-transform:uppercase;color:var(--ink-4)}

/* --- 404 --- */
.nf{min-height:70svh;display:flex;flex-direction:column;justify-content:center;gap:20px;align-items:flex-start;padding:160px 0 100px}
.nf-code{font-size:clamp(64px,12vw,140px);font-weight:700;letter-spacing:-5px;line-height:1;color:var(--blue-accent)}

/* =====================================================================
   REVEAL
   ===================================================================== */
.reveal{
  opacity:0;transform:translate3d(0,24px,0);
  transition:opacity .8s var(--ease),transform .8s var(--ease);
  transition-delay:calc(var(--d,0) * 1ms);
}
.reveal.in{opacity:1;transform:none}

/* =====================================================================
   RESPONSIVE
   ===================================================================== */
@media (max-width:1180px){
  .nav-links a{padding:7px 10px;font-size:12px}
  .nav{gap:14px}
}
@media (max-width:1080px){
  :root{--sec-pad:64px}
  .stats-grid{grid-template-columns:repeat(3,1fr);gap:26px 14px}
  .picker{grid-template-columns:1fr;gap:34px}
  .picker-side{position:static}
  .contact-grid{grid-template-columns:1fr;gap:44px}
  .login-grid{gap:48px}
  .footer-top{grid-template-columns:1fr 1fr;gap:36px}
  .footer-brand{grid-column:1 / -1;max-width:none}
}
@media (max-width:960px){
  :root{--pad:20px;--sec-pad:56px}
  .nav{
    left:14px;right:14px;width:auto;gap:12px;padding:8px 8px 8px 16px;
    transform:translate3d(0,var(--ty,0),0);
  }
  .nav-links{display:none}
  .nav-cta{display:none}
  .nav-house{display:flex;margin-left:auto}

  .stats{padding-top:32px}
  /* Each figure and its label is one block, centred in its own half of
     the grid but set flush left inside itself: the number and the words
     under it keep one edge, so the pair still reads as one fact rather
     than as two centred lines.
     The rows used to stand 50px apart (14px padding either side of a
     22px gap), which spread five facts over a screen and a half. Half
     that, and the block below the headline reads as one list. */
  .stats-grid{grid-template-columns:1fr 1fr;gap:11px 14px}

  /* The fifth has no partner to hold an edge with, so it is centred
     outright: full width, the figure over the middle of its own line,
     both on the middle of the screen. The 19ch cap that keeps the four
     labels in the columns off their neighbour comes off with it, so the
     line does not break — and the bloom moves to the middle too, by
     margin rather than by transform, which the bloom's own keyframes
     would otherwise overwrite. */
  .stats-grid .stat:last-child{grid-column:1 / -1;text-align:center}
  .stats-grid .stat:last-child .stat-l{max-width:none}
  .stats-grid .stat:last-child .stat-glow{left:50%;margin-left:-75px}
  .stat{justify-self:center;padding:7px 0}
  .stat-v{font-size:clamp(25px,7.2vw,30px);letter-spacing:-1.2px}
  .stat-l{font-size:12.5px}
  .stat-glow{left:-22px;width:150px;height:110px}

  .dims{height:280vh}
  .dim{width:74vw;height:auto;min-height:300px}
  .dims-top{gap:18px}
  .dims-pin{gap:26px}

  .hero{height:300vh}

  /* On a phone the scene is the whole screen, not a band inside a column.
     The band framed itself from its own box: at 390px wide that box was
     roughly 350×280, which fitScene reads as a landscape frame and answers
     with ~940 units across, so the building drew at 36% of the width and
     its hairlines had no pixels left to sit on. Full bleed hands it a
     portrait frame (~530 units) and the same vectors draw at close to
     twice the size in both axes. The copy sits over the scene the way it
     does on desktop. */

  /* no transform runs here (see js/home.js), so the promotion hint comes
     off with it — an un-animated composited layer only costs the drawing
     a rasterisation it has no use for. */
  .stage{transform:none;will-change:auto}

  /* --- the drawing does not follow the address bar ---
     The frame around it does: it is 100dvh, so nothing black can open
     along the bottom edge when the bar retracts. But if the drawing were
     refitted to that height too, the ground line would travel a quarter
     of the screen every time the bar came and went — measured at 579px
     against 748px on a 393×660 phone. So the drawing keeps the small
     viewport's height and hangs from the top edge, the one edge the bar
     never moves, and the strip the bar leaves behind is filled by the sky
     and the vignette, which do span the whole frame. The ground line then
     holds its place on screen and the transformation builds on it. */
  .facade svg{inset:0 0 auto 0;height:100svh}
  .facade .horizon{top:86svh;bottom:auto}
  .scene-seam{bottom:auto;height:100svh}

  /* The top padding is measured from the nav, not guessed: the bar sits at
     top:16px and is 58px tall (42px house button + 2 × 8px padding), so it
     ends at 74px. 84px left barely 10px under it while the eyebrow had 14px
     plus the headline's leading below it — the label read as stuck to the
     bar. 96px gives it the same air above as below. */
  .hero-inner{
    max-width:none;justify-content:flex-start;
    padding:96px var(--pad) calc(20px + env(safe-area-inset-bottom,0px));
  }
  /* the column owns the whole frame, so the swap below can sit on its
     floor rather than under the headline */
  .hero-copy{max-width:none;gap:16px;flex-grow:1}

  .hero-h1{font-size:clamp(30px,7.8vw,44px);letter-spacing:-1.2px}
  /* The three fixed lines are a desktop composition. On a phone they
     orphan single words, so the headline flows and reveals as one.
     `backwards` rather than `both`: a filling animation would outrank
     the opacity above and the headline could never fade out again. */
  .hero-h1 .line{display:inline;overflow:visible}
  .hero-h1 .line>span{display:inline;transform:none;animation:none}
  .hero-h1{animation:heroIn 1s var(--ease) .1s backwards}
  @keyframes heroIn{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
  .hero-sub{font-size:15px}

  /* --- the foot of the screen: one place, two occupants ---
     The sentence and the buttons used to stack right under the headline,
     in the middle of the frame, straight across the building. Here they
     share a single cell on the floor of the column: the sentence holds it
     at rest, and the first stretch of scroll cross fades the buttons in
     over it (--swap, written in js/home.js). The cell keeps the taller
     of the two heights, so nothing under it ever shifts, and the scene
     keeps the full frame — nothing is covered but the ground hatching. */
  .hero-swap{margin-top:auto;display:grid;gap:16px}
  .hero-swap>*{grid-area:1 / 1;align-self:center}
  /* One leaves before the other arrives. Fading both across the same
     range put two half-transparent things on the same four lines, and
     the sentence read through the buttons. The sentence owns the first
     half of the handover and rises out; the buttons own the second and
     come up into the place it left. */
  .hero-sub{
    opacity:clamp(0,calc(1 - var(--swap,0) * 2),1);
    transform:translate3d(0,calc(var(--swap,0) * -8px),0);
  }
  /* Side by side at their own width: stretched to the full column they
     read as two slabs and outweighed the headline above them.
     Hidden rather than merely transparent — a button at zero opacity is
     still clickable and still reachable by keyboard. Visibility flips at
     the moment its opacity leaves zero, so it never appears mid fade. */
  .hero-cta{
    flex-direction:row;align-items:center;gap:10px;
    opacity:clamp(0,calc(var(--swap,0) * 2 - 1),1);
    transform:translate3d(0,calc((1 - var(--swap,0)) * 8px),0);
    visibility:hidden;
  }
  .hero.swapping .hero-cta{visibility:visible}
  .hero-cta .btn{width:auto;padding:12px 20px}

  .hero-scroll{display:none}
  /* the copy is back over the drawing, so the wash is too: weighted to
     the head for the headline and open through the middle where the
     building stands. */
  .stage-vignette{
    background:
      linear-gradient(180deg,rgba(6,8,12,.92) 0%,rgba(6,8,12,.7) 24%,rgba(6,8,12,.16) 50%,transparent 66%),
      linear-gradient(0deg,rgba(6,8,12,.86) 0%,rgba(6,8,12,.3) 14%,transparent 30%),
      radial-gradient(130% 92% at 50% 48%,transparent 54%,rgba(0,0,0,.42) 100%);
  }

  .pick{padding:15px 4px 15px 14px}
  .pick-t{font-size:16px}
  .pick-arrow:active{transform:scale(.94)}
  .picker-panel{padding:26px;min-height:0}
  .op-body{grid-template-columns:1fr;gap:20px}
  .op-head h3{font-size:20px}
  #measures .op-head h3{font-size:21px}

  .page-hero{padding:130px 0 56px}

  /* the capital loop gets the same treatment as the wheels: the ring
     keeps filling, the stages become a readable row beneath it */
  .loop{
    width:100%;height:auto;
    display:flex;flex-direction:column;align-items:center;gap:22px;
  }
  .loop-ring{position:relative;width:min(240px,62vw);height:min(240px,62vw);flex:none}
  .loop-steps{position:static;display:flex;flex-wrap:wrap;justify-content:center;gap:8px}
  .loop-steps span{
    position:static;left:auto;top:auto;transform:none;
    flex-direction:row;align-items:baseline;gap:6px;
    padding:9px 13px;border-radius:12px;font-size:12px;
    background:rgba(255,255,255,.72);border:1px solid var(--hair);
  }
  .loop-steps span.on{border-color:rgba(49,115,246,.34);background:#fff}
  .form-card,.login-card{padding:24px}
}
@media (max-width:640px){
  :root{--sec-pad:48px}
  .footer-top{grid-template-columns:1fr}
  .dim{width:82vw}
  .op-facts{grid-template-columns:1fr}
}

/* The hero column is the one composition on the site with a hard height
   budget: everything in it has to fit 100svh, and whatever the copy does
   not use is what the animation gets. On a short phone the headline eats
   the band, so the type tightens rather than the scene disappearing. */
@media (max-width:960px) and (max-height:740px){
  /* same clearance under the nav, tightened to the smaller inner gap */
  .hero-inner{padding:90px var(--pad) calc(18px + env(safe-area-inset-bottom,0px))}
  .hero-copy{gap:13px}
  .hero-h1{font-size:clamp(26px,6.6vw,34px)}
  .hero-sub{font-size:14px}
}

/* A phone held sideways keeps the same composition on barely a third of
   the height. Everything tightens one more step instead of anything
   being dropped. */
@media (max-width:960px) and (max-height:460px){
  .hero-inner{padding:80px var(--pad) calc(14px + env(safe-area-inset-bottom,0px))}
  .hero-copy{gap:8px}
  .hero-h1{font-size:clamp(20px,4.4vw,26px);letter-spacing:-.8px}
  .hero-sub{font-size:13px}
  .hero-cta .btn{padding:10px 16px;font-size:12px}
}

/* On touch devices the blur budget is tight — soften every glass
   surface so scrolling stays at frame rate. */
@media (hover:none){
  .glass,.nav,.nav-sheet,.nav-house{
    -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  }
  .glass{background:rgba(255,255,255,.86)}
}

/* =====================================================================
   REDUCED MOTION
   ===================================================================== */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.01ms !important;animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
  .reveal{opacity:1;transform:none}
  .hero-h1 .line>span{transform:none}
  /* one screen, no runway — so the frame is measured the same way the
     section is, and nothing scroll driven has to run for the copy to be
     complete: the sentence and the buttons stand under each other. */
  .hero{height:100svh}
  .hero-pin{height:100svh}
  .hero-swap{display:flex}
  .hero-sub{opacity:1;transform:none}
  .hero-cta{opacity:1;transform:none;visibility:visible}
  .dims{height:auto}
  .dims-pin{position:static;height:auto;padding:80px 0}
  .dims-rail{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .dims-track{transform:none}
  /* static end states for everything that normally arrives on scroll */
  .stat-v{transform:none}
  .stat-l{opacity:1;transform:none}
  .stat-glow{opacity:.32}
}
