/* ============================================================================
   OJ SCALES — company site, "FLOW" build (third parallel version)
   The Active-Theory-mechanism rebuild: one continuous scroll-driven WebGL
   scene for the first six sections, then a conventional document region for
   the four live embeds and the quote tool.

   Deployed to https://oj-scales-flow.previews.ojscales.com/ ONLY. The root
   domain (arc-reactor build) and the oj-scales-company preview (Matrix build)
   are separate directories and are not touched by this one.

   Register is deliberately different from both of the other two: deeper,
   wider, more cinematic. Cyan into violet with a warm amber accent, on a
   near-black that is a shade cooler than the arc-reactor build's.
   ========================================================================== */

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

:root{
  --void:#03050a;
  --deep:#070b13;
  --panel:#0a0f18;
  --line:rgba(92,224,255,.15);
  --line-hard:rgba(92,224,255,.32);
  --ink:#eaf5fc;
  --mute:#7d91a6;
  --arc:#5ce0ff;          /* primary */
  --vio:#9b6cff;          /* secondary — the scene's violet end */
  --gold:#ffb347;         /* accent */
  --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;
}
img{max-width:100%; display:block}
a{color:var(--arc); text-decoration:none}
::selection{background:rgba(92,224,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)}
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}
/* Each display line is its own inline-block that must never wrap: the glyph
   splitter used by the headline hover rebuilds characters as inline-blocks,
   which otherwise lets the browser break a line anywhere — including orphaning
   a full stop onto its own line. */
.ln{display:inline-block; white-space:nowrap; line-height:1.04}
.big{font-size:clamp(36px,5.9vw,94px); line-height:.96; letter-spacing:-.045em; font-weight:900}
.big .outline{
  -webkit-text-stroke:1.4px rgba(92,224,255,.9); color:transparent;
  text-shadow:0 0 44px rgba(92,224,255,.4);
}
.big .glow{color:#fff; text-shadow:0 0 30px rgba(92,224,255,.55),0 0 90px rgba(155,108,255,.35)}

.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:#b9ccda; letter-spacing:.005em}
.tiny{font:400 13.5px/1.6 var(--sans); color:var(--mute)}
.monolabel{font:600 11px/1 var(--mono); letter-spacing:.26em; text-transform:uppercase; color:var(--mute)}

/* ---- grain + vignette over the whole doc -------------------------------- */
.fx-overlay{
  position:fixed; inset:0; z-index:900; pointer-events:none;
  background:repeating-linear-gradient(180deg,rgba(255,255,255,.018) 0 1px,transparent 1px 3px);
  /* Screen-blended white lifts the blacks, and the landing frame is supposed
     to be genuinely near-black with the mark as the only light in it. Dialled
     back from .55 for exactly that reason. */
  mix-blend-mode:screen; opacity:.30;
}

/* ---- 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(92,224,255,.22); border-top-color:var(--arc);
  animation:spin 1s linear infinite;
  box-shadow:0 0 36px rgba(92,224,255,.45), inset 0 0 22px rgba(155,108,255,.25);
}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---- site header -------------------------------------------------------
   Top right corner, two text links, a hairline between them. No bar across
   the top, no wordmark, no CTA button, no hamburger. The landing frame is
   one lit object in a black room and the header's only job is to not be part
   of that. It stays this size at every breakpoint — there is nothing to
   collapse. */
.site-header{
  position:fixed; top:0; right:0; z-index:800;
  padding:18px 20px; pointer-events:none;
}
.site-nav{
  display:flex; flex-direction:column; align-items:stretch;
  padding:10px 14px; pointer-events:auto;
  transition:background .3s ease;
}
/* No panel behind the links once the page scrolls — a hard-edged dark box
   in the corner is more visible than the two words it is protecting. A
   shadow does the same job and leaves the corner empty. */
.site-header.solid .site-nav a{text-shadow:0 1px 10px rgba(0,0,0,.95),0 0 26px rgba(0,0,0,.8)}
.site-nav a{
  display:block; min-width:92px; padding:8px 0; text-align:right;
  font:600 10.5px/1 var(--mono); letter-spacing:.3em; text-transform:uppercase;
  color:rgba(234,245,252,.68); transition:color .22s ease;
}
.site-nav a:hover{color:#fff}
.site-nav a + a{border-top:1px solid rgba(234,245,252,.17)}
@keyframes pulse{0%,100%{opacity:1; transform:scale(1)}50%{opacity:.55; transform:scale(.82)}}
.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(92,224,255,.5),0 10px 40px -8px rgba(92,224,255,.55);
  transition:transform .18s ease, box-shadow .25s ease, background .25s ease;
}
.btn:hover{transform:translateY(-2px); background:#8aeeff; box-shadow:0 0 0 1px rgba(92,224,255,.85),0 16px 56px -8px rgba(92,224,255,.8)}
.btn.ghost{background:transparent; color:var(--arc); box-shadow:inset 0 0 0 1px var(--line-hard)}
.btn.ghost:hover{background:rgba(92,224,255,.08); color:#a9f2ff; box-shadow:inset 0 0 0 1px var(--arc)}
/* Two 10.5px links in a corner need no breakpoint. The only mobile change is
   pulling them a little tighter to the edge. */
@media (max-width:560px){
  .site-header{padding:12px 12px}
  .site-nav a{min-width:78px; letter-spacing:.24em}
  .snd{left:14px; bottom:14px}
}

/* ---- opt-in sound toggle -----------------------------------------------
   Bottom-left corner, icon only, low contrast. It keeps the feature without
   putting a labelled control anywhere near the mark. */
.snd{
  position:fixed; left:22px; bottom:22px; z-index:800;
  display:inline-flex; align-items:center; cursor:pointer;
  background:transparent; border:0; padding:10px 11px;
  color:rgba(234,245,252,.42); box-shadow:inset 0 0 0 1px rgba(234,245,252,.12);
  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}
.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(92,224,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(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}}

/* =========================================================================
   THE VOLUME LAYER
   One fixed canvas, one fixed CSS-perspective layer over it holding the six
   copy panels as planes in the same 3D space, and an in-flow track of empty
   spacers that exists only to give the single scroll-progress value somewhere
   to travel. z-order, bottom to top:
     0  #flowStage  — the canvas
     1  #flowCopy   — the six copy panels, placed in 3D
     2  #doc        — the document region, opaque, covers the stage
   800  the header and the sound toggle, 900 the grain, 2000 the cursor.
   ======================================================================= */
/* base (no JS, or reduced motion): one static backdrop behind the first
   section only, in normal document flow above it. */
.stage{position:absolute; inset:0 0 auto 0; height:100svh; z-index:0; pointer-events:none}
html.js:not(.rm) .stage{position:fixed; inset:0; height:auto}
.stage canvas{display:block; width:100%; height:100%}
/* What a visitor gets if the WebGL context refuses to create at all (old GPU,
   blocklisted driver, context limit): a dark lit room rather than a black
   rectangle. Much darker than it used to be, because the frame it is standing
   in for is a near-black void with one light in it, and a nebula was the
   wrong promise. */
.stage-fallback{
  position:absolute; inset:0; z-index:-1;
  background:
    radial-gradient(34% 30% at 50% 46%,rgba(92,224,255,.10),transparent 72%),
    radial-gradient(44% 40% at 76% 74%,rgba(155,108,255,.035),transparent 78%);
}
.stage-vig{
  position:absolute; inset:0;
  background:radial-gradient(132% 104% at 50% 48%,transparent 52%,rgba(1,2,5,.72) 100%);
}

/* The scroll distance only exists when the scene layer does. */
.track{display:none}
html.js:not(.rm) .track{display:block; position:relative}
.track .beat{display:block; height:100svh}

/* z-order: 0 stage, 1 copy, 2 document. The document sits ABOVE the copy
   layer deliberately — the panels are all at opacity 0 by the end of the
   track, but "deliberately" is not the same as "cannot", and a fixed layer
   painting over the live embeds would be unrecoverable on a real screen. */
.copy{position:relative; z-index:1}
.sc{position:relative; padding:clamp(80px,11vw,150px) 0}
/* The perspective value itself is set in JS, per resize, because it is solved
   against the shader's field of view rather than chosen by eye — see size()
   in js/app.js. Setting it here too would just be a number that goes stale. */
html.js:not(.rm) .copy{
  position:fixed; inset:0; z-index:1; pointer-events:none;
  perspective-origin:50% 50%;
}
html.js:not(.rm) .sc{
  position:absolute; left:50%; top:50%;
  width:min(980px,88vw); padding:0;
  /* 0 0, NOT 50% 50%. The transform chain already ends in a
     translate(-50%,-50%) to centre the card on its own anchor; a 50% origin
     centres it a SECOND time, and because the extra shift is applied before
     the fit scale rather than after it, the error is (1-fit)*height/2 — i.e.
     invisible on a card that fits and 160px of drop on the one that does
     not, which is precisely the card that could least afford it. */
  transform-origin:0 0;
  /* Starting pose only. Overwritten every frame by sceneSpace() in js/app.js
     from the same camera the shader builds its rays from, so there is no CSS
     transition here to desync — the panel's pose IS its position in the
     room, exactly like the glass pane rendered behind it. */
  opacity:0; visibility:hidden; will-change:opacity,transform;
}
.sc .wrap{width:100%}
html.js:not(.rm) .sc .wrap{padding:0; max-width:none}
html.js:not(.rm) .sc .wrap-narrow{max-width:none}
/* Blocks that resolve only once the camera is close. Starting pose; the live
   values come from sceneSpace(). */
html.js:not(.rm) .sc [data-late]{opacity:0; will-change:opacity,transform}
/* Display type is set at line-height .96–1.02, which is right for the
   headline and far too tight against whatever follows it. On a card there is
   no section padding to hide behind, so the gap has to be explicit. */
html.js:not(.rm) .sc h2{margin-bottom:20px}
html.js:not(.rm) .sc h2.big{margin-bottom:24px}
html.js:not(.rm) .sc .lede + .lede{margin-top:4px}
.sc-body{position:relative; max-width:none}
.sc-left .sc-body,.sc-body.sc-left{max-width:none}
.sc-left{justify-content:flex-start}
.sc-left .sc-body{max-width:min(640px,54vw)}
.sc-2 .lede{max-width:46ch}
/* Inside the volume a card is a bounded plane, so the copy fills it rather
   than hugging one side of a full-bleed viewport. */
html.js:not(.rm) .sc-left .sc-body,html.js:not(.rm) .sc-body.sc-left{max-width:none}
html.js:not(.rm) .sc-2 .lede{max-width:58ch}

/* A contrast floor under the copy, inside the glass. The pane behind each
   card is translucent and the room behind THAT is alive, so a headline
   sitting straight on it loses its edges wherever the light moves. This is
   the dark interior of the pane: it tracks the card because it IS the card's
   own pseudo-element, which also means it cannot desync from the camera. */
.sc::before{display:none}
html.js:not(.rm) .sc::before{
  content:""; display:block; position:absolute; z-index:-1; pointer-events:none;
  /* Sized to sit just inside the glass pane rendered behind it (the pane is
     the card plus 62px horizontally, 46px vertically, in world units), so a
     glass rim is left visible all the way round rather than the dark backing
     ending short and letting the pane's own material read as a halo. */
  inset:-38px -50px;
  border-radius:20px;
  background:
    linear-gradient(180deg,rgba(2,4,8,.90),rgba(2,4,8,.76) 54%,rgba(2,4,8,.88)),
    radial-gradient(120% 100% at 30% 20%,rgba(10,22,40,.5),transparent 70%);
}
/* Station 2's pane carries a photograph — the real KALEIDO hero, which has
   its own large type in it. A gradient that works over a procedural field is
   not enough: without the extra stop the build's own headline reads straight
   through ours. */
html.js:not(.rm) .sc-2::before{
  background:linear-gradient(180deg,rgba(2,4,8,.94),rgba(2,4,8,.86) 50%,rgba(2,4,8,.93));
}
/* Nothing behind the mark. A dark slab over the landing frame is most of what
   was wrong with the first pass. */
html.js:not(.rm) .sc-0::before{display:none}

.note{
  display:none; max-width:48ch; margin:22px 0 0; padding-left:16px;
  position:relative; font:500 13.5px/1.65 var(--mono); letter-spacing:.01em; color:#90a7b9;
}
.note::before{
  content:""; position:absolute; left:0; top:.62em; width:7px; height:7px;
  background:var(--arc); box-shadow:0 0 12px rgba(92,224,255,.9); transform:rotate(45deg);
}
html.flow-on .note{display:block}

/* ---- the landing frame -------------------------------------------------
   Station 0 holds exactly two things: an <h1> nobody sees, and a small quiet
   scroll prompt centred well below the mark. That is the entire first
   screen. */
.hero-h1{
  position:absolute; width:1px; height:1px; margin:-1px; padding:0;
  overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap;
}
/* Station 0 carries no card, so it is not placed in the volume at all: it
   stays a plain viewport-sized box holding the prompt. sceneSpace() fades it
   and leaves its transform alone. */
html.js:not(.rm) .sc-0{left:0; right:0; top:0; bottom:0; width:auto; transform:none}

/* The prompt is anchored to the viewport rather than carried in the 3D layer:
   it is a piece of interface, not an object in the room, and giving it
   parallax would make it read as floating debris. */
.cue{
  display:flex; flex-direction:column; align-items:center; gap:13px;
  font:600 9.5px/1 var(--mono); letter-spacing:.34em; text-transform:uppercase;
  color:rgba(234,245,252,.46);
}
html.js:not(.rm) .cue{
  position:absolute; left:50%; bottom:clamp(40px,8vh,84px); transform:translateX(-50%);
}
.cue i{
  width:1px; height:46px; transform-origin:50% 0;
  background:linear-gradient(180deg,var(--arc),transparent);
  animation:cueSlide 2.4s ease-in-out infinite;
}
@keyframes cueSlide{
  0%{transform:translateY(0) scaleY(.2); opacity:0}
  40%{opacity:.9}
  100%{transform:translateY(16px) scaleY(1); opacity:0}
}

/* scene 1 — manifesto */
.manifesto p{
  position:relative; padding-left:26px; margin:0 0 clamp(18px,2.6vh,30px);
  font:500 clamp(16px,1.85vw,26px)/1.46 var(--sans); letter-spacing:-.012em; color:#c3d6e3;
  max-width:38ch;
}
.manifesto p::before{
  content:""; position:absolute; left:0; top:.5em; width:11px; height:1px; background:var(--arc);
  box-shadow:0 0 10px rgba(92,224,255,.9);
}
.manifesto p:last-child{margin-bottom:0; color:var(--ink)}

/* scene 2 */
.sc-2 .cta{display:flex; align-items:center; gap:16px; flex-wrap:wrap; margin-top:32px}
.scene-tag{
  display:block; margin-top:30px;
  font:600 10px/1.5 var(--mono); letter-spacing:.24em; text-transform:uppercase; color:var(--mute);
}

/* scene 3 — who */
.who{display:grid; grid-template-columns:minmax(0,1.04fr) minmax(0,.96fr); gap:clamp(30px,5vw,76px); align-items:center}
.who-copy h2{margin-bottom:24px}
.who-copy .lede{font-size:clamp(15.5px,1.22vw,17.5px)}
.who-list{list-style:none; margin:26px 0 0; padding:0}
.who-list li{
  position:relative; padding:14px 0 14px 34px; border-top:1px solid var(--line);
  font-size:15px; color:#b8cbd9;
}
.who-list li:last-child{border-bottom:1px solid var(--line)}
.who-list li::before{
  content:""; position:absolute; left:3px; top:22px;
  width:8px; height:8px; border:1px solid var(--arc); transform:rotate(45deg);
  box-shadow:0 0 12px rgba(92,224,255,.8);
}
.who-list li b{color:var(--ink); font-weight:700}
.who-panel .frame{
  position:relative; padding:28px;
  background:linear-gradient(145deg,rgba(92,224,255,.07),transparent 55%),rgba(10,15,24,.82);
  backdrop-filter:blur(7px);
  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)}
.bar{height:1px; background:linear-gradient(90deg,var(--arc),transparent); margin:20px 0}

/* scene 4 — capability */
.statgrid{
  display:grid; grid-template-columns:repeat(3,1fr); gap:1px; margin-top:clamp(26px,4vh,46px);
  background:var(--line); box-shadow:0 0 0 1px var(--line);
}
.statcell{padding:26px 22px 24px; 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;
}
.statlabel{
  display:block; font:800 clamp(17px,1.75vw,22px)/1.25 var(--display); letter-spacing:-.01em;
  color:#fff; text-shadow:0 0 30px rgba(92,224,255,.3);
}
.statcell small{display:block; margin-top:10px; font:400 12.5px/1.55 var(--sans); color:#72869a}
.proof{
  margin-top:26px; padding:22px 26px; background:rgba(10,15,24,.78); backdrop-filter:blur(6px);
  box-shadow:inset 0 0 0 1px var(--line); border-left:2px solid var(--gold);
}
.proof p{font-size:14.5px; color:#a9bdcb; margin-bottom:14px}
.proof p:last-child{margin-bottom:0}
.proof b{color:var(--ink)}

/* scene 5 — pipeline */
.pipeline{
  display:grid; grid-template-columns:repeat(4,1fr); gap:1px;
  margin-top:clamp(26px,4vh,48px); background:var(--line); box-shadow:0 0 0 1px var(--line);
}
.step{padding:26px 22px 24px; position:relative}
.step .n{
  font:800 13px/1 var(--mono); letter-spacing:.1em; color:var(--arc);
  display:inline-block; padding:8px 11px; margin-bottom:18px;
  box-shadow:inset 0 0 0 1px var(--line-hard);
}
.step h3{margin-bottom:10px; font-size:clamp(16px,1.5vw,19px)}
.step p{margin:0; font-size:13.5px; color:var(--mute); line-height:1.58}

/* --- volume layer, narrower viewports --------------------------------- */
@media (max-width:1180px){
  .sc-left .sc-body{max-width:min(620px,78vw)}
  .who{grid-template-columns:1fr; gap:28px}
  html.js:not(.rm) .sc-left .sc-body{max-width:none}
  /* 8 lines of monospace readout do not fit beside the list inside ONE
     viewport once the grid collapses. The stacked page below has no such
     constraint, so this is scoped to the scene layer and nothing is lost. */
  html.js:not(.rm) .who-panel{display:none}
  .statgrid{grid-template-columns:1fr 1fr}
  .pipeline{grid-template-columns:1fr 1fr}
}
@media (max-width:760px){
  .sc .wrap{padding:0 20px}
  .sc-left .sc-body{max-width:none}
  html.js:not(.rm) .sc{width:92vw}
  html.js:not(.rm) .sc .wrap{padding:0}
  html.js:not(.rm) .sc::before{inset:-20px -22px; border-radius:14px}
  .big{font-size:clamp(33px,10vw,54px)}
  .sc-3 h2,.sc-4 h2,.sc-5 h2{font-size:clamp(26px,7.6vw,40px)}
  .manifesto p{font-size:clamp(15.5px,4.3vw,20px); max-width:none; margin-bottom:14px}
  .who-list li{font-size:14px; padding:11px 0 11px 30px}
  .who-list li::before{top:19px}
  /* Portrait has no room for a three-up grid plus a prose block inside one
     viewport. The two big grids become single-column scroll-free stacks with
     the copy tightened, which is what actually fits — and the proof block
     drops out of the scene and is not lost: every sentence in it is still on
     the page, in the footer notes and in the live-work copy. */
  .statgrid,.pipeline{grid-template-columns:1fr; margin-top:18px}
  .statcell,.step{padding:16px 16px 15px}
  html.js:not(.rm) .statcell small{display:none}
  .step p{font-size:12.5px}
  .step .n{margin-bottom:10px; padding:6px 9px}
  html.js:not(.rm) .proof{display:none}
  .sc-4 .lede,.sc-5 .lede{font-size:15px}
  .note{display:none !important}   /* the prompt plus the lede is already a lot
                                       of small type in one portrait viewport */
  /* Every pixel of natural card height saved here is a pixel the fit scaler
     does not have to take out of the type size, and shrinking the type is
     always the worse of the two. Nothing is removed — this is leading and
     size, not content. */
  html.js:not(.rm) .sc .kicker{margin-bottom:14px; font-size:10.5px; letter-spacing:.26em}
  html.js:not(.rm) .manifesto p{font-size:15px; margin-bottom:11px}
  html.js:not(.rm) .who-copy h2{margin-bottom:16px}
  html.js:not(.rm) .who-copy .lede{font-size:13.5px; margin-bottom:12px}
  html.js:not(.rm) .who-list{margin-top:16px}
  html.js:not(.rm) .who-list li{font-size:12.5px; padding:9px 0 9px 26px}
  html.js:not(.rm) .who-list li::before{top:16px}
  html.js:not(.rm) .sc .lede{font-size:14px}
  html.js:not(.rm) .step p{font-size:12px}
  html.js:not(.rm) .step h3{font-size:15px; margin-bottom:7px}
  html.js:not(.rm) .statlabel{font-size:16px}
  html.js:not(.rm) .sc .cta{margin-top:20px}
}

/* =========================================================================
   THE DOCUMENT REGION — conventional scrolling page
   ======================================================================= */
#doc{position:relative; z-index:2; background:var(--void)}
.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(92,224,255,.07),transparent 62%),
  linear-gradient(180deg,var(--deep),var(--void) 78%)}
.devices-band{
  border-top:0;
  background:linear-gradient(180deg,var(--void),var(--deep) 44%,var(--void));
}

.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);
}
.rig .device-foot{margin-top:18px}
@media (max-width:980px){.rig{grid-template-columns:1fr; gap:64px}}

.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(92,224,255,.42);
}
.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}
/* clip-path, not overflow:hidden — overflow does not clip inside a
   preserve-3d chain, which is how a sheen escaped a screen on an earlier
   build of this page and reached 1357px wide. */
.phone .viewport{position:relative; overflow:hidden; clip-path:inset(0 round 42px); border-radius:42px; background:#02060a; height:100%}

/* laptop */
.laptop{width:100%; position:relative}
.laptop .lid{
  position:relative; border-radius:13px 13px 3px 3px; padding:11px 11px 22px;
  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(92,224,255,.36);
}
.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(92,224,255,.5);
}
.laptop .screen{
  position:relative; overflow:hidden; clip-path:inset(0 round 6px); border-radius:6px;
  background:#02060a; aspect-ratio:1440/900;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.9), inset 0 0 70px rgba(0,0,0,.65);
}
.laptop .screen::after{
  content:""; position:absolute; inset:0; pointer-events:none; z-index:4;
  background:linear-gradient(118deg,rgba(255,255,255,.15) 0%,rgba(255,255,255,.045) 22%,transparent 46%);
  opacity:.7;
}
.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);
}

/* 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(3,6,11,.5),rgba(3,6,11,.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(3,6,11,.8);
  box-shadow:inset 0 0 0 1px var(--line-hard),0 0 40px -6px rgba(92,224,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:#a3f1ff}
.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{max-width:620px; margin:0 auto}
}

/* ---- capability marquee ------------------------------------------------ */
.marquee{
  overflow:hidden; border-top:1px solid var(--line); border-bottom:1px solid var(--line);
  padding:22px 0; background:rgba(7,11,19,.8);
}
.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,.42);
}
.marquee-track span:nth-child(3n){-webkit-text-stroke:1px rgba(155,108,255,.5)}
.marquee-track i{font-style:normal; color:var(--arc); font-size:clamp(18px,2vw,30px); align-self:center; opacity:.8}

/* ---- 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(92,224,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(92,224,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)}
@media (max-width:900px){.quote-tool{grid-template-columns:1fr}}

/* ---- 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(92,224,255,.45)}
.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(4,7,12,.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(3,6,11,.78);
  box-shadow:inset 0 0 0 1px var(--line-hard);
}
.card .shot canvas.pixel-reveal{position:absolute; inset:0; width:100%; height:100%; display:block}
@media (max-width:980px){.rail{grid-template-columns:1fr}}

/* ---- 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(92,224,255,.13),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(92,224,255,.13); 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); position:relative; z-index:2}
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:#c4d7e4}
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 + a contextual label. Hidden by default
   so a no-JS or reduced-motion visitor never sees stray divs; cursorFX() in
   js/app.js adds .cx-on to <html> once it is 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(92,224,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(--vio); box-shadow:0 0 24px rgba(155,108,255,.55);
}
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}
}

/* ---- reveal defaults, DOCUMENT REGION ONLY ----------------------------- */
/* There is deliberately not one .reveal anywhere in the scene layer: up there
   a panel's pose is a continuous function of the scroll-progress value, not a
   state that flips. These are only for the conventional sections below. */
.js #doc .reveal{opacity:0}

/* =========================================================================
   REDUCED MOTION
   The single most important degradation on this page, because the default
   experience is a pinned continuous scene: if the fixed layer survived with
   its animation off, the visitor would get six copy panels stacked on top of
   each other over a dead canvas, inside seven viewports of empty scroll —
   i.e. a broken page, not a calm one.

   So the whole mechanism is dismantled: the track collapses, the copy layer
   drops into normal document flow as six ordinary stacked sections, and the
   canvas becomes a single static backdrop behind the first one only. That is
   a conventional page, which is the correct answer to "I do not want motion."
   ======================================================================= */
/* With the stacked page as the base, reduced motion only has to switch off
   the things that are about motion rather than about layout. */
html.rm .note{display:none !important}
html.rm .cue{display:none}
html.rm .scene-tag{display:none}   /* it describes a live refraction effect
                                      that is not running under reduced
                                      motion, so leaving it would be a lie */
html.rm .stage-vig{background:radial-gradient(132% 104% at 50% 48%,transparent 58%,rgba(1,2,5,.82) 100%)}

/* --- stacked-page chrome (base): the six panels as ordinary sections ----- */
/* Reduced motion gets the <h1> on screen. There is no lit object carrying the
   frame for them — the canvas paints exactly one still frame and nothing
   moves — so a wordless landing screen would just be an empty one. Modest
   size on purpose: it is a line of text under a still, not a hero headline. */
.sc-0{min-height:100svh; padding:140px 0 90px; display:flex; align-items:flex-end; justify-content:center; text-align:center}
html:not(.js) .sc-0 .hero-h1,html.rm .sc-0 .hero-h1{
  position:static; width:auto; height:auto; margin:0 auto; max-width:24ch;
  overflow:visible; clip:auto; clip-path:none; white-space:normal;
  font-size:clamp(23px,3.4vw,38px); font-weight:700; letter-spacing:-.025em; line-height:1.18;
  color:var(--ink);
}
html.js:not(.rm) .sc-0{display:block; padding:0; text-align:left}
.sc-1,.sc-3,.sc-5{background:var(--deep)}
.sc-2,.sc-4{background:var(--void)}
.sc + .sc{border-top:1px solid var(--line)}
.statcell,.step{background:var(--panel)}
/* ...all of which the volume layer undoes, because up there the sections are
   planes floating in one room, not blocks stacked on a page. */
html.js:not(.rm) .sc-1,html.js:not(.rm) .sc-2,html.js:not(.rm) .sc-3,
html.js:not(.rm) .sc-4,html.js:not(.rm) .sc-5{background:transparent}
html.js:not(.rm) .sc + .sc{border-top:0}
html.js:not(.rm) .sc-0{min-height:0}
/* No backdrop-filter anywhere inside the volume layer. A blur that has to
   resolve what is behind a plane that is itself inside a 3D transform is both
   the most expensive thing on the page and the least reliable across drivers
   — and this build has still never been measured on real hardware, so it is
   not the place to spend that. Flat alpha reads the same here anyway, because
   what is behind the card is glass over a dark room, not a photograph. */
html.js:not(.rm) .statcell,html.js:not(.rm) .step{background:rgba(10,15,24,.86)}
html.js:not(.rm) .who-panel .frame,html.js:not(.rm) .proof{backdrop-filter:none}

@media (prefers-reduced-motion:reduce){
  .js #doc .reveal{opacity:1 !important; transform:none !important}
  #boot{display:none}
  .fx-overlay{display:none}
  .cue i{animation:none; opacity:.6}
  .snd.on .eq s{animation:none; height:8px}
  *{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}
}
