/* ============================================================================
   OJ SCALES — company site
   Dark, sci-fi/HUD register. One person operation; every number on the page is
   measured, not claimed (see the FACTS comments in index.html).
   ========================================================================== */

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

:root{
  --void:#04060a;
  --deep:#070b12;
  --panel:#0b1119;
  --line:rgba(80,220,255,.16);
  --line-hard:rgba(80,220,255,.34);
  --ink:#e8f4fb;
  --mute:#7f93a6;
  --arc:#3ce3ff;          /* arc-reactor cyan */
  --arc-dim:#1b8fab;
  --gold:#ffb63d;         /* repulsor amber */
  --hot:#ff4d6d;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
  --sans:"Space Grotesk","Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --display:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;
}

html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--void); color:var(--ink);
  font:400 17px/1.6 var(--sans);
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
body.lenis-ready{}
img{max-width:100%; display:block}
a{color:var(--arc); text-decoration:none}
::selection{background:rgba(60,227,255,.3); color:#fff}

.wrap{width:100%; max-width:1340px; margin:0 auto; padding:0 28px}
.wrap-narrow{max-width:960px}

h1,h2,h3{font-family:var(--display); font-weight:800; letter-spacing:-.03em; line-height:1.02; margin:0}
h1{font-size:clamp(38px,6.4vw,88px)}
/* Each hero line is its own inline-block that must never wrap. The split-text
   reveal rebuilds every glyph as a separate inline-block span, which lets the
   browser break the line anywhere — including orphaning a full stop onto its
   own line, which is exactly what it did before this. */
.h1line{display:inline-block; white-space:nowrap; line-height:1.04}
h2{font-size:clamp(30px,5vw,64px)}
h3{font-size:clamp(19px,2.2vw,24px); font-weight:700; letter-spacing:-.01em; line-height:1.2}
p{margin:0 0 18px}

.kicker{
  font:600 11.5px/1 var(--mono); letter-spacing:.34em; text-transform:uppercase;
  color:var(--arc); display:inline-flex; align-items:center; gap:10px; margin-bottom:22px;
}
.kicker::before{
  content:""; width:30px; height:1px; background:linear-gradient(90deg,transparent,var(--arc));
}
.kicker.gold{color:var(--gold)}
.kicker.gold::before{background:linear-gradient(90deg,transparent,var(--gold))}

.lede{font:500 clamp(17px,1.5vw,21px)/1.62 var(--sans); color:#b8cbd9; letter-spacing:.005em}
.mute{color:var(--mute)}
.tiny{font:400 13.5px/1.6 var(--sans); color:var(--mute)}
.mono{font-family:var(--mono); font-size:.92em; color:var(--arc)}
.monolabel{font:600 11px/1 var(--mono); letter-spacing:.26em; text-transform:uppercase; color:var(--mute)}

/* ---- shared chrome: HUD corner brackets ---------------------------------- */
.brackets{position:relative}
.brackets::before,.brackets::after{
  content:""; position:absolute; width:22px; height:22px; pointer-events:none;
  border:1px solid var(--line-hard);
}
.brackets::before{top:-1px; left:-1px; border-right:0; border-bottom:0}
.brackets::after{bottom:-1px; right:-1px; border-left:0; border-top:0}

/* ---- scanline + vignette overlay on the whole doc ----------------------- */
.fx-overlay{
  position:fixed; inset:0; z-index:900; pointer-events:none;
  background:
    repeating-linear-gradient(180deg,rgba(255,255,255,.022) 0 1px,transparent 1px 3px),
    radial-gradient(130% 100% at 50% 50%,transparent 42%,rgba(0,0,0,.62) 100%);
  mix-blend-mode:screen; opacity:.5;
}
/* Kept deliberately gentle: at .78 alpha from 40% out this crushed the whole
   page on a tall viewport, dimming the live embeds along with the edges. */
.fx-overlay.vig{mix-blend-mode:normal; background:radial-gradient(135% 105% at 50% 45%,transparent 58%,rgba(2,4,7,.5) 100%); opacity:1}

/* ---- boot sequence ------------------------------------------------------ */
#boot{
  position:fixed; inset:0; z-index:1000; background:var(--void);
  display:flex; align-items:center; justify-content:center; flex-direction:column; gap:20px;
}
#boot .ring{
  width:64px; height:64px; border-radius:50%;
  border:1px solid rgba(60,227,255,.25); border-top-color:var(--arc);
  animation:spin 1s linear infinite;
  box-shadow:0 0 36px rgba(60,227,255,.45), inset 0 0 22px rgba(60,227,255,.22);
}
@keyframes spin{to{transform:rotate(360deg)}}
#boot .lines{font:500 12px/1.9 var(--mono); letter-spacing:.16em; color:var(--arc-dim); text-align:center; min-height:5.7em}
#boot .lines b{color:var(--arc); font-weight:500}

/* ---- site header ------------------------------------------------------- */
.site-header{
  position:fixed; top:0; left:0; right:0; z-index:800; height:68px;
  display:flex; align-items:center;
  background:linear-gradient(180deg,rgba(4,6,10,.92),rgba(4,6,10,0));
  transition:background .3s ease, border-color .3s ease;
  border-bottom:1px solid transparent;
}
.site-header.solid{background:rgba(5,8,13,.9); backdrop-filter:blur(14px) saturate(140%); border-bottom-color:var(--line)}
.site-header .wrap{display:flex; align-items:center; gap:20px}
.brand{display:flex; align-items:center; gap:12px; font:800 19px/1 var(--display); letter-spacing:-.02em; color:var(--ink)}
.brand .dot{
  width:11px; height:11px; border-radius:50%; background:var(--arc);
  box-shadow:0 0 14px var(--arc),0 0 34px rgba(60,227,255,.6);
  animation:pulse 2.6s ease-in-out infinite;
}
@keyframes pulse{0%,100%{opacity:1; transform:scale(1)}50%{opacity:.55; transform:scale(.82)}}
.brand span{color:var(--arc)}
.site-nav{margin-left:auto; display:flex; align-items:center; gap:30px}
.site-nav a{font:600 11.5px/1 var(--mono); letter-spacing:.2em; text-transform:uppercase; color:var(--mute)}
.site-nav a:hover{color:var(--ink)}
.btn{
  display:inline-flex; align-items:center; gap:10px; position:relative;
  font:700 12.5px/1 var(--mono); letter-spacing:.18em; text-transform:uppercase;
  padding:15px 26px; color:var(--void); background:var(--arc);
  clip-path:polygon(9px 0,100% 0,100% calc(100% - 9px),calc(100% - 9px) 100%,0 100%,0 9px);
  box-shadow:0 0 0 1px rgba(60,227,255,.5),0 10px 40px -8px rgba(60,227,255,.6);
  transition:transform .18s ease, box-shadow .25s ease, background .25s ease;
}
.btn:hover{transform:translateY(-2px); background:#6cf0ff; box-shadow:0 0 0 1px rgba(60,227,255,.8),0 16px 56px -8px rgba(60,227,255,.85)}
.btn.ghost{
  background:transparent; color:var(--arc);
  box-shadow:inset 0 0 0 1px var(--line-hard);
}
.btn.ghost:hover{background:rgba(60,227,255,.08); color:#9af4ff; box-shadow:inset 0 0 0 1px var(--arc)}
@media (max-width:900px){.site-nav a{display:none} .site-nav .btn{display:inline-flex}}
/* There is no hamburger on this page: below 900px the nav links go and the
   header keeps exactly two controls, the sound toggle and the CTA. That fitted
   until the sound toggle was added — brand + toggle + "Start a build" measures
   ~446px of content at the old spacing, which is 56px wider than a 390px
   phone, so the CTA ran off the right edge and body{overflow-x:hidden} clipped
   it to "START A BUIL". The label is NOT shortened here: scrambleHover()
   rewrites .btn textContent on hover and would permanently restore the long
   string, so the room is taken out of the spacing instead. */
@media (max-width:560px){
  .site-header .wrap{padding:0 16px; gap:12px}
  .site-nav{gap:12px}
  .snd{padding:8px 9px}
  .site-nav .btn{padding:13px 14px; font-size:11px; letter-spacing:.11em}
}

/* ---- opt-in sound toggle ------------------------------------------------
   Off by default and visibly off: dim, flat bars. On, the equaliser bars run
   and the whole control goes arc-cyan, so the state is legible without the
   custom cursor's label (which is skipped on touch and under reduced-motion).
   Deliberately not a .btn — scrambleHover() rewrites textContent on .btn, and
   this control has an icon child that would be destroyed by that.
------------------------------------------------------------------------- */
.snd{
  display:inline-flex; align-items:center; gap:9px; cursor:pointer;
  background:transparent; border:0; padding:9px 13px;
  font:700 10.5px/1 var(--mono); letter-spacing:.2em; text-transform:uppercase;
  color:var(--mute); box-shadow:inset 0 0 0 1px var(--line);
  transition:color .25s ease, box-shadow .25s ease, background .25s ease;
}
.snd:hover{color:var(--ink); box-shadow:inset 0 0 0 1px var(--line-hard)}
.snd .eq{display:flex; align-items:center; gap:2px; height:12px}
/* Idle state is a static staggered waveform rather than four flat stubs — a
   row of 3px dots read as punctuation sitting next to the word, not as an
   icon. Off is "quiet", not "absent". */
.snd .eq s{width:2px; background:currentColor; text-decoration:none; display:block; transition:height .25s ease; opacity:.8}
.snd .eq s:nth-child(1){height:4px}
.snd .eq s:nth-child(2){height:9px}
.snd .eq s:nth-child(3){height:6px}
.snd .eq s:nth-child(4){height:11px}
.snd.on{color:var(--arc); background:rgba(60,227,255,.08); box-shadow:inset 0 0 0 1px var(--arc)}
.snd.on .eq s{opacity:1; animation:eqbar .9s ease-in-out infinite}
.snd.on .eq s:nth-child(1){animation-delay:0s}
.snd.on .eq s:nth-child(2){animation-delay:.14s}
.snd.on .eq s:nth-child(3){animation-delay:.3s}
.snd.on .eq s:nth-child(4){animation-delay:.46s}
@keyframes eqbar{0%,100%{height:3px}50%{height:12px}}
@media (max-width:900px){.snd .snd-txt{display:none} .snd{padding:9px 11px}}

/* =========================================================================
   SECTION 0 — THE PROLOGUE
   The WebGL set piece, the manifesto that animates in over it, and the two
   live device rigs. Everything here sits in normal flow EXCEPT the canvas,
   which is fixed full-bleed at z-index:-1 — negative-z positioned elements
   paint behind in-flow block backgrounds, so every opaque section further
   down the page covers it without needing a z-index of its own. js/app.js
   also hides it outright once the prologue leaves the viewport; the z-index
   is the belt, the visibility toggle is the braces.
   ======================================================================= */
.prologue{position:relative}
.pg-canvas{
  position:fixed; inset:0; width:100%; height:100%; display:block;
  z-index:-1; pointer-events:none;
}
/* The backdrop that takes over behind the content once the dive is through the
   glass. Deliberately the SAME paint as #pgCast below, so the strip of it that
   shows above the clone's top edge in the last frames of the dive is
   indistinguishable from the clone itself. z-index 0 puts it over the canvas
   (-1) and the scrim (-1) but under the cast (1) and the act-I copy (2).
   Visibility is tied to html.pg-cast-on so it can never survive the prologue
   and paint over the sections below; opacity is written by pgPortal(). */
.pg-void{
  position:fixed; inset:0; z-index:0; pointer-events:none;
  visibility:hidden; opacity:0;
  background:
    radial-gradient(118% 86% at 16% 0%,rgba(60,227,255,.11),transparent 60%),
    radial-gradient(70% 50% at 86% 100%,rgba(255,182,61,.045),transparent 72%),
    linear-gradient(180deg,#070c13,#04060a 76%);
}
html.pg-cast-on .pg-void{visibility:visible}

/* Sinks the set piece away as the manifesto arrives, and lands on solid void
   by the bottom of the prologue so the device section starts clean. Done with
   a gradient rather than a scroll-driven opacity tween because it costs
   nothing and it cannot desync from the scroll position. */
.pg-scrim{
  position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:linear-gradient(180deg,
    rgba(4,6,10,0) 0%, rgba(4,6,10,0) 33%,
    rgba(4,6,10,.5) 50%, rgba(4,6,10,.88) 72%, var(--void) 92%);
}
/* Always-on atmosphere, independent of WebGL: if the context fails to create
   (old GPU, blocklisted driver, context limit already hit by the embeds) the
   first screen still reads as a lit stage rather than a black rectangle. */
.pg-fallback{
  position:absolute; left:0; right:0; top:0; height:100svh;
  z-index:-1; pointer-events:none;
  background:
    radial-gradient(52% 42% at 62% 36%,rgba(60,227,255,.17),transparent 72%),
    radial-gradient(46% 26% at 58% 76%,rgba(255,182,61,.06),transparent 76%);
}

.pg-act{position:relative; min-height:100svh; display:flex}
.pg-act-1{align-items:center; padding:120px 0 70px}
.pg-act-1::after{   /* contrast floor under the headline, over the canvas */
  content:""; position:absolute; inset:auto 0 0 0; height:58%; z-index:-1; pointer-events:none;
  background:linear-gradient(180deg,transparent,rgba(3,5,9,.42) 52%,rgba(3,5,9,.8));
}
.pg-act-1 .wrap{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:40px; align-items:center; width:100%;
}
.pg-copy{grid-column:1; position:relative; z-index:2}
.pg-title{
  font-size:clamp(38px,5.9vw,96px); line-height:.96; letter-spacing:-.045em;
  font-weight:900; margin:0 0 24px;
}
.pg-title .outline{
  -webkit-text-stroke:1.4px rgba(60,227,255,.9); color:transparent;
  text-shadow:0 0 44px rgba(60,227,255,.45);
}
.pg-lede{max-width:44ch; color:#aec2d2}
/* Says what is on the laptop screen. Hidden until pgPortal() confirms the
   portal is actually running — on a machine with no WebGL there is no laptop
   in the frame, so the line would be describing something that is not there. */
.pg-note{
  display:none; max-width:46ch; margin:22px 0 0; padding-left:16px;
  position:relative; font:500 13.5px/1.65 var(--mono); letter-spacing:.01em; color:#8fa6b8;
}
.pg-note::before{
  content:""; position:absolute; left:0; top:.62em; width:7px; height:7px;
  background:var(--arc); box-shadow:0 0 12px rgba(60,227,255,.9); transform:rotate(45deg);
}
html.pg-cast-ready .pg-note{display:block}
.pg-cue{
  display:flex; align-items:center; gap:14px; margin-top:clamp(26px,4vh,42px);
  font:600 9.5px/1 var(--mono); letter-spacing:.3em; text-transform:uppercase; color:var(--mute);
}
.pg-cue i{
  width:66px; height:1px; transform-origin:0 50%;
  background:linear-gradient(90deg,var(--arc),transparent);
  animation:cueSlide 2.1s ease-in-out infinite;
}
@keyframes cueSlide{
  0%{transform:translateX(0) scaleX(.25); opacity:0}
  40%{opacity:1}
  100%{transform:translateX(30px) scaleX(1); opacity:0}
}

.pg-act-2{align-items:center; padding:clamp(80px,13vh,150px) 0}
.pg-act-2 .wrap{width:100%}
.pg-h2{font-size:clamp(28px,4.3vw,58px); margin:0 0 clamp(26px,4vh,44px)}
.pg-manifesto p{
  position:relative; padding-left:26px; margin:0 0 clamp(20px,3vh,32px);
  font:500 clamp(17px,1.95vw,27px)/1.46 var(--sans); letter-spacing:-.012em; color:#c2d5e2;
  max-width:36ch;
}
.pg-manifesto p::before{
  content:""; position:absolute; left:0; top:.5em; width:11px; height:1px; background:var(--arc);
  box-shadow:0 0 10px rgba(60,227,255,.9);
}
.pg-manifesto p:last-child{margin-bottom:0; color:var(--ink)}

/* --- act III: the two live device rigs -------------------------------- */
.pg-devices{
  border-top:0;
  background:linear-gradient(180deg,var(--void),var(--deep) 44%,var(--void));
}
.pg-rig{
  display:grid; grid-template-columns:minmax(0,.72fr) minmax(0,1.28fr);
  gap:clamp(30px,5vw,70px); align-items:center; margin-top:clamp(48px,6vw,82px);
}
.pg-rig .device-foot{margin-top:18px}
@media (max-width:980px){.pg-rig{grid-template-columns:1fr; gap:64px}}

@media (max-width:1060px){
  .pg-act-1{align-items:flex-end; padding:106px 0 clamp(48px,7vh,86px)}
  .pg-act-1 .wrap{grid-template-columns:1fr}
  .pg-lede{max-width:52ch}
  /* Stacked layouts put the copy directly over the lit floor rather than
     beside it, and the desk is the brightest thing in the lower half of a
     portrait frame — so the scrim has to work a lot harder here than it does
     on a wide screen where the copy sits over empty space.

     It also has to stop ENDING at act I's bottom edge. The floor is just as
     bright a few pixels further down, and act II is transparent over the same
     fixed canvas, so an overlay that went opaque and then simply stopped drew
     a hard horizontal line straight across the viewport — clearly visible on
     a phone at a third of the way into the dive, and not visible on a desktop
     where the camera never gets that close to the desk. So it now runs 60svh
     past act I's bottom and fades back out there instead, by which point the
     canvas is being faded out anyway. */
  .pg-act-1::after{
    inset:auto 0 -60svh 0; height:130svh;
    background:linear-gradient(180deg,
      transparent 0%, rgba(3,5,9,.60) 26%, rgba(4,6,10,.93) 50%,
      var(--void) 62%, var(--void) 82%, rgba(4,6,10,0) 100%);
  }
}

/* --- THE PORTAL: act II, projected onto the laptop screen ---------------
   #pgCast is a clone of .pg-act-2 held in a fixed layer and warped onto the
   four projected corners of the shader's screen quad by a 4-point homography
   (transform:matrix3d, see pgPortal() in js/app.js). It is laid out at the
   REAL section's own width and height, so when the dive finishes and the
   matrix resolves to identity the clone is sitting pixel-exactly on top of
   the real .pg-act-2 — at which point the two are swapped and nothing moves.

   Rules this layout has to keep:
     - transform-origin:0 0, so the matrix can work in plain local pixels.
     - z-index 1: above the fixed canvas (-1) and the scrim (-1), below the
       act-I copy (2), the header (800) and the scanline overlay (900). It is
       hidden outright the moment the dive lands or the prologue leaves the
       viewport, because at z-index 1 it would otherwise paint over every
       in-flow section below.
     - Its own page-dark background, because it is standing in for a browser
       window: the real section is transparent over the void. */
#pgCast{
  position:fixed; top:0; left:0; z-index:1; pointer-events:none;
  transform-origin:0 0; backface-visibility:hidden; visibility:hidden;
  background:
    radial-gradient(118% 86% at 16% 0%,rgba(60,227,255,.11),transparent 60%),
    radial-gradient(70% 50% at 86% 100%,rgba(255,182,61,.045),transparent 72%),
    linear-gradient(180deg,#070c13,#04060a 76%);
  box-shadow:inset 0 0 120px rgba(0,0,0,.6);
}
html.pg-cast-on #pgCast{visibility:visible}
/* The real section is held invisible (not hidden) while its clone is standing
   in for it, so it stays in the accessibility tree and in flow — the portal
   lands on its live bounding rect, so it must keep taking up space. */
html.pg-cast-on #pgAct2{opacity:0}
/* Glass, not content: the sheen and scanlines that make the clone read as a
   lit panel rather than a floating div. Faded out by JS as the dive lands,
   because once you are through the screen there is no screen any more. */
#pgCast .pg-cast-glass{
  position:absolute; inset:0; z-index:5; pointer-events:none;
  background:
    repeating-linear-gradient(180deg,rgba(190,240,255,.05) 0 2px,transparent 2px 7px),
    linear-gradient(118deg,rgba(255,255,255,.15) 0%,rgba(255,255,255,.045) 20%,transparent 44%),
    radial-gradient(130% 100% at 50% 50%,transparent 52%,rgba(1,3,6,.55) 100%);
}

/* =========================================================================
   SECTION 1 — HERO
   ======================================================================= */
.hero{
  position:relative; min-height:100svh; display:flex; align-items:center;
  padding:120px 0 70px; overflow:hidden; isolation:isolate;
}
#hero-canvas{position:absolute; inset:0; z-index:-3; display:block; width:100%; height:100%}
.hero-glow{
  position:absolute; z-index:-2; pointer-events:none;
  width:min(1100px,120vw); aspect-ratio:1; left:50%; top:46%; transform:translate(-50%,-50%);
  background:radial-gradient(circle,rgba(60,227,255,.17) 0%,rgba(60,227,255,.05) 36%,transparent 68%);
}
.hero-grid{
  position:absolute; z-index:-2; inset:auto 0 0 0; height:46vh; pointer-events:none;
  background-image:
    linear-gradient(rgba(60,227,255,.14) 1px,transparent 1px),
    linear-gradient(90deg,rgba(60,227,255,.14) 1px,transparent 1px);
  background-size:62px 62px;
  transform:perspective(420px) rotateX(68deg);
  transform-origin:bottom center;
  mask-image:linear-gradient(180deg,transparent,#000 42%,transparent 96%);
  -webkit-mask-image:linear-gradient(180deg,transparent,#000 42%,transparent 96%);
  opacity:.8;
}
.hero-inner{display:grid; grid-template-columns:minmax(0,.93fr) minmax(0,1.07fr); gap:48px; align-items:center; width:100%}

.hero-copy{position:relative; z-index:2}
.hero h1{margin-bottom:26px}
.hero h1 .glow{
  color:#fff;
  text-shadow:0 0 30px rgba(60,227,255,.55),0 0 90px rgba(60,227,255,.3);
}
.hero h1 .outline{
  -webkit-text-stroke:1.4px rgba(60,227,255,.85); color:transparent;
  text-shadow:0 0 40px rgba(60,227,255,.35);
}
.hero .lede{max-width:46ch}
.hero-cta{display:flex; align-items:center; gap:16px; flex-wrap:wrap; margin-top:34px}

.hero-telemetry{
  margin-top:44px; display:flex; gap:30px; flex-wrap:wrap;
  padding-top:20px; border-top:1px solid var(--line);
}
.hero-telemetry div b{display:block; font:800 25px/1 var(--display); letter-spacing:-.02em; color:var(--ink); font-variant-numeric:tabular-nums}
.hero-telemetry div b.arc{color:var(--arc); text-shadow:0 0 22px rgba(60,227,255,.6)}
.hero-telemetry div b.gold{color:var(--gold); text-shadow:0 0 22px rgba(255,182,61,.5)}
.hero-telemetry div span{display:block; margin-top:7px; font:600 10px/1.4 var(--mono); letter-spacing:.2em; text-transform:uppercase; color:var(--mute)}

/* ---- the 3D laptop ----------------------------------------------------- */
.stage{
  perspective:1700px; perspective-origin:50% 44%;
  display:flex; align-items:center; justify-content:center;
  position:relative; z-index:1;
}
.laptop{
  --lid:-16deg; --yaw:-19deg;
  width:min(100%,720px);
  transform-style:preserve-3d;
  transform:rotateX(var(--lid)) rotateY(var(--yaw)) rotateZ(.6deg);
  will-change:transform;
}
.laptop .lid{
  position:relative; transform-style:preserve-3d;
  border-radius:16px 16px 4px 4px;
  padding:13px 13px 26px;
  background:
    linear-gradient(155deg,#2b333d 0%,#161c24 34%,#0d131a 70%,#1c232c 100%);
  box-shadow:
    0 0 0 1px rgba(150,200,225,.16),
    inset 0 1px 0 rgba(255,255,255,.14),
    0 60px 120px -40px rgba(0,0,0,.95),
    0 0 130px -20px rgba(60,227,255,.4);
}
.laptop .cam{
  position:absolute; top:5px; left:50%; transform:translateX(-50%);
  width:6px; height:6px; border-radius:50%; background:#060a0e;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.14),0 0 7px rgba(60,227,255,.5);
}
.laptop .screen{
  position:relative; overflow:hidden; border-radius:6px;
  background:#02060a; aspect-ratio:16/10;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.9), inset 0 0 70px rgba(0,0,0,.65);
}
.laptop .screen img, .laptop .screen iframe{width:100%; height:100%; object-fit:cover; border:0; display:block}
.laptop .screen::after{   /* glass sheen */
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(118deg,rgba(255,255,255,.17) 0%,rgba(255,255,255,.05) 22%,transparent 46%,transparent 100%);
  opacity:.72;
}
.laptop .sheen{
  position:absolute; inset:-40% -120%; pointer-events:none; z-index:3;
  background:linear-gradient(100deg,transparent 42%,rgba(190,245,255,.3) 50%,transparent 58%);
  transform:translateX(-45%);
}
.laptop .hinge{
  height:7px; margin:0 32px;
  background:linear-gradient(180deg,#2a333d,#0b1016);
  box-shadow:0 1px 0 rgba(255,255,255,.08);
}
.laptop .base{
  height:17px; border-radius:0 0 15px 15px;
  background:linear-gradient(180deg,#232b34 0%,#141a21 42%,#0a0e13 100%);
  box-shadow:
    0 0 0 1px rgba(150,200,225,.12),
    0 40px 70px -26px rgba(0,0,0,.95);
  position:relative;
}
.laptop .base::after{
  content:""; position:absolute; left:50%; bottom:3px; transform:translateX(-50%);
  width:16%; height:4px; border-radius:0 0 7px 7px; background:rgba(0,0,0,.6);
}
.laptop .reflect{
  margin:14px 26px 0; height:120px; border-radius:50%;
  background:radial-gradient(ellipse at 50% 0%,rgba(60,227,255,.3),rgba(60,227,255,.05) 48%,transparent 74%);
  filter:blur(16px); opacity:.85;
}
.stage-tag{
  position:absolute; bottom:-6px; left:50%; transform:translateX(-50%);
  font:600 10px/1 var(--mono); letter-spacing:.24em; text-transform:uppercase; color:var(--mute);
  white-space:nowrap;
}

.scroll-hint{
  position:absolute; left:50%; bottom:24px; transform:translateX(-50%);
  display:flex; flex-direction:column; align-items:center; gap:9px; z-index:3;
  font:600 9.5px/1 var(--mono); letter-spacing:.3em; text-transform:uppercase; color:var(--mute);
}
.scroll-hint i{
  width:1px; height:44px; background:linear-gradient(180deg,var(--arc),transparent);
  animation:drop 1.9s ease-in-out infinite;
}
@keyframes drop{0%{opacity:0; transform:scaleY(.2)}40%{opacity:1}100%{opacity:0; transform:translateY(22px) scaleY(.4)}}

@media (max-width:1060px){
  .hero-inner{grid-template-columns:1fr; gap:52px}
  .hero{padding-top:106px}
  .laptop{--lid:-9deg; --yaw:-11deg}
}

/* =========================================================================
   SECTION 2 — WHO (side slide-in)
   ======================================================================= */
.band{position:relative; padding:clamp(90px,11vw,170px) 0; border-top:1px solid var(--line)}
.band.deep{background:
  radial-gradient(90% 70% at 12% 0%,rgba(60,227,255,.08),transparent 62%),
  linear-gradient(180deg,var(--deep),var(--void) 78%)}
.band.gold-wash{background:
  radial-gradient(80% 70% at 88% 10%,rgba(255,182,61,.07),transparent 60%),
  linear-gradient(180deg,var(--void),var(--deep))}

.who{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:clamp(36px,6vw,92px); align-items:center}
.who-copy h2{margin-bottom:26px}
.who-copy h2 em{font-style:normal; color:var(--arc); text-shadow:0 0 34px rgba(60,227,255,.5)}
.who-list{list-style:none; margin:30px 0 0; padding:0}
.who-list li{
  position:relative; padding:16px 0 16px 34px; border-top:1px solid var(--line);
  font-size:16px; color:#b8cbd9;
}
.who-list li:last-child{border-bottom:1px solid var(--line)}
.who-list li::before{
  content:""; position:absolute; left:3px; top:25px;
  width:8px; height:8px; border:1px solid var(--arc); transform:rotate(45deg);
  box-shadow:0 0 12px rgba(60,227,255,.8);
}
.who-list li b{color:var(--ink); font-weight:700}

.who-panel{position:relative}
.who-panel .frame{
  position:relative; padding:28px; background:
    linear-gradient(145deg,rgba(60,227,255,.07),transparent 55%),var(--panel);
  box-shadow:inset 0 0 0 1px var(--line), 0 40px 90px -40px rgba(0,0,0,.9);
  clip-path:polygon(22px 0,100% 0,100% calc(100% - 22px),calc(100% - 22px) 100%,0 100%,0 22px);
}
.who-panel .readout{font:500 12.5px/2 var(--mono); color:var(--mute); margin:0}
.who-panel .readout span{color:var(--arc)}
.who-panel .readout b{color:var(--ink); font-weight:500}
.who-panel h3{margin:0 0 18px; color:var(--ink)}
.who-panel .bar{height:1px; background:linear-gradient(90deg,var(--arc),transparent); margin:20px 0}

@media (max-width:980px){.who{grid-template-columns:1fr; gap:46px}}

/* =========================================================================
   SECTION 3 — LIVE DEVICES
   ======================================================================= */
.devices{
  display:grid; grid-template-columns:minmax(0,.78fr) minmax(0,1.22fr);
  gap:clamp(30px,5vw,70px); align-items:end; margin-top:clamp(50px,6vw,88px);
}
.device-col{position:relative}
.device-head{margin-bottom:26px}
.device-head h3{margin-bottom:9px}
.device-head p{margin:0; font-size:15px; color:var(--mute); line-height:1.55}

/* phone */
.phone{
  position:relative; width:min(100%,352px); margin:0 auto;
  aspect-ratio:430/932; border-radius:52px; padding:11px;
  background:linear-gradient(150deg,#333c46,#141a21 42%,#0b1016 72%,#2a323b);
  box-shadow:
    0 0 0 1px rgba(150,200,225,.18),
    inset 0 1px 0 rgba(255,255,255,.2),
    0 50px 100px -34px rgba(0,0,0,.95),
    0 0 120px -26px rgba(60,227,255,.45);
  transform-style:preserve-3d;
}
.phone .notch{
  position:absolute; top:19px; left:50%; transform:translateX(-50%);
  width:96px; height:26px; border-radius:14px; background:#04070b; z-index:4;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.07);
}
.phone .btn-side{position:absolute; right:-2px; top:22%; width:3px; height:72px; border-radius:2px; background:linear-gradient(180deg,#39424c,#161c23)}
.phone .btn-side.b2{top:14%; right:auto; left:-2px; height:34px}
.phone .viewport{position:relative; overflow:hidden; border-radius:42px; background:#02060a; height:100%}

/* laptop (section 3 variant, flatter + live) */
.laptop.live{--lid:0deg; --yaw:0deg; width:100%; transform:none}
.laptop.live .lid{border-radius:13px 13px 3px 3px; padding:11px 11px 22px}
.laptop.live .screen{aspect-ratio:1440/900}

/* shared iframe shell */
.liveframe{position:relative; width:100%; height:100%; overflow:hidden; background:#02060a}
.liveframe iframe{
  position:absolute; top:0; left:0; border:0; display:block;
  transform-origin:0 0; pointer-events:none;
}
.liveframe.armed iframe{pointer-events:auto}
.liveframe .poster{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:top center;
  z-index:2; transition:opacity .5s ease; pointer-events:none;
}
.liveframe.loaded .poster{opacity:0}
.liveframe .arm{
  position:absolute; inset:0; z-index:3; display:flex; align-items:center; justify-content:center;
  background:radial-gradient(circle at 50% 50%,rgba(4,8,13,.5),rgba(4,8,13,.82));
  cursor:pointer; border:0; width:100%; transition:opacity .35s ease;
  font:700 11px/1 var(--mono); letter-spacing:.22em; text-transform:uppercase; color:var(--arc);
}
.liveframe .arm span{
  padding:14px 22px; background:rgba(4,8,13,.8);
  box-shadow:inset 0 0 0 1px var(--line-hard),0 0 40px -6px rgba(60,227,255,.5);
}
.liveframe.armed .arm{opacity:0; pointer-events:none}
.device-foot{
  display:flex; align-items:center; justify-content:space-between; gap:14px;
  margin-top:20px; padding-top:14px; border-top:1px solid var(--line); flex-wrap:wrap;
}
.device-foot a{font:600 10.5px/1 var(--mono); letter-spacing:.18em; text-transform:uppercase}
.device-foot a:hover{color:#8df1ff}
.livedot{display:inline-flex; align-items:center; gap:8px; font:600 10.5px/1 var(--mono); letter-spacing:.18em; text-transform:uppercase; color:var(--mute)}
.livedot i{width:7px; height:7px; border-radius:50%; background:#43e07f; box-shadow:0 0 11px #43e07f; animation:pulse 2.2s ease-in-out infinite}

@media (max-width:980px){
  .devices{grid-template-columns:1fr; gap:64px; align-items:stretch}
  .laptop.live{max-width:620px; margin:0 auto}
}

/* =========================================================================
   SECTION 4 — MEASURED (stat grid)
   ======================================================================= */
.statgrid{
  display:grid; grid-template-columns:repeat(3,1fr); gap:1px; margin-top:54px;
  background:var(--line);
  box-shadow:0 0 0 1px var(--line);
}
.statcell{background:var(--deep); padding:34px 26px 30px; position:relative; overflow:hidden}
.statcell::before{
  content:""; position:absolute; inset:0 auto 0 0; width:2px;
  background:linear-gradient(180deg,var(--arc),transparent);
  opacity:.7;
}
.statcell.is-zero::before{background:linear-gradient(180deg,var(--gold),transparent)}
.statcell b{
  display:block; font:800 clamp(40px,4.6vw,62px)/1 var(--display); letter-spacing:-.045em;
  color:#fff; font-variant-numeric:tabular-nums; text-shadow:0 0 42px rgba(60,227,255,.4);
}
.statcell.is-zero b{color:var(--gold); text-shadow:0 0 42px rgba(255,182,61,.45)}
.statcell em{font-style:normal; font-size:.55em; letter-spacing:-.01em; opacity:.85}
.statcell span{display:block; margin-top:14px; font:600 11px/1.6 var(--mono); letter-spacing:.14em; text-transform:uppercase; color:var(--mute)}
.statlabel{
  display:block; font:800 clamp(19px,2vw,24px)/1.25 var(--display); letter-spacing:-.01em;
  color:#fff; text-shadow:0 0 30px rgba(60,227,255,.3);
}
.statcell small{display:block; margin-top:10px; font:400 13px/1.55 var(--sans); color:#6d8294}
.proof{
  margin-top:34px; padding:26px 28px; background:rgba(11,17,25,.7);
  box-shadow:inset 0 0 0 1px var(--line); border-left:2px solid var(--gold);
}
.proof p:last-child{margin-bottom:0}
.proof p{font-size:15.5px; color:#a9bdcb}
.proof b{color:var(--ink)}
@media (max-width:1000px){.statgrid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:540px){.statgrid{grid-template-columns:1fr}}

/* =========================================================================
   SECTION 5 — SCOPE IT YOURSELF (quote-scope tool)
   ======================================================================= */
.quote-tool{
  margin-top:48px; display:grid; grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
  gap:36px; align-items:start;
}
.quote-form{display:flex; flex-direction:column; gap:22px}
.quote-form label{display:flex; flex-direction:column; gap:10px}
.qlabel{font:600 11px/1.5 var(--mono); letter-spacing:.14em; text-transform:uppercase; color:var(--mute)}
.quote-form select, .quote-form textarea, .qinput{
  font:500 15px/1.5 var(--sans); color:var(--ink); background:var(--panel);
  border:0; box-shadow:inset 0 0 0 1px var(--line); border-radius:3px;
  padding:13px 16px; width:100%; appearance:none;
}
.quote-form select{
  background-image:linear-gradient(45deg,transparent 50%,var(--arc) 50%),linear-gradient(135deg,var(--arc) 50%,transparent 50%);
  background-position:calc(100% - 20px) center,calc(100% - 15px) center;
  background-size:5px 5px,5px 5px; background-repeat:no-repeat;
}
.quote-form select:focus, .quote-form textarea:focus, .qinput:focus{
  outline:none; box-shadow:inset 0 0 0 1px var(--arc),0 0 0 3px rgba(60,227,255,.18);
}
.quote-form textarea{resize:vertical; font-family:var(--sans)}
.qcheck{flex-direction:row !important; align-items:center; gap:12px !important}
.qcheck input{width:18px; height:18px; flex:none; accent-color:var(--arc)}
.qcheck span{font-size:14.5px; color:var(--ink); line-height:1.4}
#qScopeBtn{align-self:flex-start; margin-top:4px}
.quote-result{
  align-self:stretch; position:relative; padding:28px;
  background:linear-gradient(145deg,rgba(60,227,255,.07),transparent 55%),var(--panel);
  box-shadow:inset 0 0 0 1px var(--line), 0 40px 90px -40px rgba(0,0,0,.9);
  clip-path:polygon(22px 0,100% 0,100% calc(100% - 22px),calc(100% - 22px) 100%,0 100%,0 22px);
}
.quote-result h3{margin:14px 0 10px; font-size:clamp(24px,2.6vw,30px); color:var(--ink)}
.quote-result .bar{height:1px; background:linear-gradient(90deg,var(--arc),transparent); margin:18px 0}
@media (max-width:900px){.quote-tool{grid-template-columns:1fr}}

/* =========================================================================
   SECTION 5 — PIPELINE / HOW
   ======================================================================= */
.pipeline{display:grid; grid-template-columns:repeat(4,1fr); gap:1px; margin-top:56px; background:var(--line); box-shadow:0 0 0 1px var(--line)}
.step{background:var(--panel); padding:34px 26px 32px; position:relative; min-height:260px}
.step .n{
  font:800 13px/1 var(--mono); letter-spacing:.1em; color:var(--arc);
  display:inline-block; padding:8px 11px; margin-bottom:22px;
  box-shadow:inset 0 0 0 1px var(--line-hard);
}
.step h3{margin-bottom:12px}
.step p{margin:0; font-size:15px; color:var(--mute); line-height:1.6}
/* The accent bar at the foot of each step is injected by app.js as a real
   element, not a ::after, so each card's bar can be staggered individually. */
@media (max-width:1000px){.pipeline{grid-template-columns:repeat(2,1fr)}}
@media (max-width:560px){.pipeline{grid-template-columns:1fr} .step{min-height:0}}

/* ---- capability marquee ------------------------------------------------ */
.marquee{
  overflow:hidden; border-top:1px solid var(--line); border-bottom:1px solid var(--line);
  padding:22px 0; background:rgba(7,11,18,.8); margin-top:0;
}
.marquee-track{display:flex; gap:48px; white-space:nowrap; will-change:transform}
.marquee-track span{
  font:800 clamp(22px,3vw,40px)/1 var(--display); letter-spacing:-.03em;
  color:transparent; -webkit-text-stroke:1px rgba(120,210,235,.45);
}
.marquee-track span:nth-child(3n){-webkit-text-stroke:1px rgba(255,182,61,.5)}
.marquee-track i{font-style:normal; color:var(--arc); font-size:clamp(18px,2vw,30px); align-self:center; opacity:.8}

/* =========================================================================
   SECTION 6 — GALLERY RAIL
   ======================================================================= */
.rail{display:grid; grid-template-columns:repeat(3,1fr); gap:22px; margin-top:54px}
.card{
  position:relative; display:block; overflow:hidden; background:var(--panel);
  box-shadow:inset 0 0 0 1px var(--line); transition:transform .35s ease, box-shadow .35s ease;
}
.card:hover{transform:translateY(-6px); box-shadow:inset 0 0 0 1px var(--line-hard),0 30px 70px -30px rgba(60,227,255,.5)}
.card .shot{aspect-ratio:16/10; overflow:hidden; position:relative}
.card .shot img{width:100%; height:100%; object-fit:cover; transition:transform .6s ease; filter:saturate(1.08)}
.card:hover .shot img{transform:scale(1.05)}
.card .shot::after{content:""; position:absolute; inset:0; background:linear-gradient(180deg,transparent 40%,rgba(5,8,13,.85))}
.card .meta{padding:22px 24px 24px}
.card .meta h3{margin-bottom:8px; font-size:19px}
.card .meta p{margin:0; font-size:14px; color:var(--mute); line-height:1.55}
.card .tag{
  position:absolute; top:14px; left:14px; z-index:2;
  font:700 9.5px/1 var(--mono); letter-spacing:.2em; text-transform:uppercase;
  padding:8px 11px; color:var(--arc); background:rgba(4,8,13,.78);
  box-shadow:inset 0 0 0 1px var(--line-hard);
}
@media (max-width:980px){.rail{grid-template-columns:1fr}}

/* =========================================================================
   SECTION 7 — CTA
   ======================================================================= */
.cta-band{
  position:relative; overflow:hidden; text-align:center;
  padding:clamp(100px,13vw,190px) 0;
  border-top:1px solid var(--line);
  background:radial-gradient(70% 90% at 50% 0%,rgba(60,227,255,.14),transparent 62%),var(--void);
}
.cta-band .rings{position:absolute; inset:0; z-index:0; pointer-events:none; display:grid; place-items:center}
.cta-band .rings i{
  position:absolute; border:1px solid rgba(60,227,255,.14); border-radius:50%;
  width:var(--d); height:var(--d);
}
.cta-band .wrap{position:relative; z-index:2}
.cta-band h2{margin-bottom:22px}
.cta-band .lede{margin:0 auto 38px; max-width:60ch}
.cta-row{display:flex; gap:16px; justify-content:center; flex-wrap:wrap}
.cta-mail{
  display:inline-block; margin-top:34px;
  font:800 clamp(18px,3vw,34px)/1.2 var(--display); letter-spacing:-.02em; color:var(--ink);
  word-break:break-word;
}
.cta-mail:hover{color:var(--arc)}

/* =========================================================================
   FOOTER
   ======================================================================= */
footer.site-foot{padding:70px 0 90px; border-top:1px solid var(--line); background:var(--deep)}
footer.site-foot .cols{display:grid; grid-template-columns:1.4fr 1fr 1fr; gap:40px}
footer.site-foot h4{margin:0 0 16px; font:600 10.5px/1 var(--mono); letter-spacing:.24em; text-transform:uppercase; color:var(--arc)}
footer.site-foot p,footer.site-foot li{font-size:14.5px; color:var(--mute); line-height:1.65}
footer.site-foot ul{list-style:none; margin:0; padding:0}
footer.site-foot li{padding:5px 0}
footer.site-foot a{color:#c3d6e3}
footer.site-foot a:hover{color:var(--arc)}
.foot-note{margin-top:46px; padding-top:26px; border-top:1px solid var(--line); font-size:13.5px; color:#60758a}
@media (max-width:860px){footer.site-foot .cols{grid-template-columns:1fr; gap:34px}}

/* =========================================================================
   CUSTOM CURSOR — two lerped layers ("ease" ring + "follow" dot) and a
   contextual label, per Fable's competitor research (Immersive Garden's
   .cursor__follow/.cursor__ease pattern). Hidden by default so a no-JS or
   reduced-motion visitor never sees stray divs; js/app.js's cursorFX() adds
   .cx-on to <html> once it's actually running.
   ======================================================================= */
.cx-ring,.cx-dot,.cx-label{display:none}
html.cx-on{cursor:none}
html.cx-on input,html.cx-on textarea,html.cx-on select{cursor:text}
html.cx-on .cx-ring,html.cx-on .cx-dot,html.cx-on .cx-label{
  display:block; position:fixed; top:0; left:0; z-index:2000; pointer-events:none;
}
html.cx-on .cx-ring{
  width:30px; height:30px; margin:-15px 0 0 -15px; border-radius:50%;
  border:1px solid var(--arc); box-shadow:0 0 18px rgba(60,227,255,.45);
  transition:width .22s ease, height .22s ease, margin .22s ease, border-color .22s ease, opacity .2s ease;
}
html.cx-on .cx-dot{
  width:5px; height:5px; margin:-2.5px 0 0 -2.5px; border-radius:50%;
  background:var(--arc); box-shadow:0 0 10px var(--arc); transition:opacity .2s ease;
}
html.cx-on .cx-label{
  font:700 10px/1 var(--mono); letter-spacing:.18em; text-transform:uppercase;
  color:var(--void); background:var(--arc); padding:4px 9px; margin:14px 0 0 14px;
  white-space:nowrap; opacity:0; transition:opacity .18s ease;
}
html.cx-on.cx-active .cx-ring{
  width:56px; height:56px; margin:-28px 0 0 -28px;
  border-color:var(--gold); box-shadow:0 0 24px rgba(255,182,61,.5);
}
html.cx-on.cx-active .cx-dot{opacity:0}
html.cx-on.cx-active .cx-label{opacity:1}
html.cx-on.cx-hide .cx-ring,html.cx-on.cx-hide .cx-dot,html.cx-on.cx-hide .cx-label{opacity:0}
@media (hover:none),(pointer:coarse){
  html.cx-on{cursor:auto}
  html.cx-on .cx-ring,html.cx-on .cx-dot,html.cx-on .cx-label{display:none}
}

/* ---- pixel-reveal canvas (mosaic-resolve on the rail card images) ------- */
.card .shot canvas.pixel-reveal{
  position:absolute; inset:0; width:100%; height:100%; display:block;
}

/* ---- reveal defaults (JS adds .is-in; no-JS shows everything) ---------- */
.js .reveal{opacity:0}
.js .slide-l{opacity:0; transform:translate3d(-90px,0,0)}
.js .slide-r{opacity:0; transform:translate3d(90px,0,0)}
/* Stacked, .slide-r's resting pose is the one thing on this page that sticks
   out past the right edge of the viewport: 28px of wrap padding + a 334px
   column + 90px of offset = 452px of content inside a 390px phone. body's
   overflow-x:hidden clips the PAINT, but the document is still 452px wide —
   and a mobile browser lays out to the widest content, so the whole page was
   being laid out at 452px and scaled to fit, which is what pushed the
   right-aligned header CTA off the visible edge. (Chromium mobile emulation
   reproduces it exactly: innerWidth came back 453 on a 390px viewport.)
   Below the breakpoint where .who stops being two columns there is no left
   column for it to slide away from anyway, so both halves now come in from
   the same side — and a negative offset cannot widen the document. */
@media (max-width:980px){
  .js .slide-r{transform:translate3d(-70px,0,0)}
}

@media (prefers-reduced-motion:reduce){
  .js .reveal,.js .slide-l,.js .slide-r{opacity:1 !important; transform:none !important}
  /* The prologue set piece is not removed under reduced motion — pgScene()
     renders exactly one static frame of it instead of running a rAF loop, so
     the visitor still gets the image, just not the movement. The portal is
     skipped entirely (pgPortal() returns early), which means the laptop panel
     is dark glass and act II simply reads in flow as a normal section — no
     fixed layer that would need re-projecting on every scroll event. */
  #pgCast{display:none !important}
  /* No portal under reduced motion means no dive, so there is never a sliver
     for the backdrop to fill — and leaving it in the tree risks a stray
     full-bleed layer over a page that is meant to be plain. */
  .pg-void{display:none !important}
  .pg-note{display:none !important}
  #pgAct2{opacity:1 !important}
  .pg-cue i{animation:none; opacity:.6}
  .snd.on .eq s{animation:none; height:8px}
  #boot{display:none}
  .fx-overlay{display:none}
  *{animation-duration:.01ms !important; animation-iteration-count:1 !important}
  html.cx-on{cursor:auto}
  html.cx-on .cx-ring,html.cx-on .cx-dot,html.cx-on .cx-label{display:none}
}
