/* ══════════════════════════════════════════════════════════════
   MOCHIP LABS — site.css
   Palette sampled directly from the render clips:
   signal core rgb(6,136,58) · bloom rgb(146,220,150) · HUD panel rgb(43,68,47)
   ══════════════════════════════════════════════════════════════ */

/* ── 1. TOKENS ─────────────────────────────────────────────── */
:root{
  /* ink */
  --ink-000:#050706;
  --ink-050:#070A09;
  --ink-100:#0B100D;
  --ink-200:#111714;
  --ink-300:#1A211D;
  --ink-400:#28312C;

  /* concrete (from the render's floor + walls) */
  --con-100:#C9CFCC;
  --con-200:#9AA3A0;
  --con-300:#7E8884;
  --con-400:#49524E;

  /* signal green */
  --sig:#2FE07E;
  --sig-core:#08883A;
  --sig-bloom:#92DC96;
  --sig-panel:rgba(43,68,47,.78);
  --sig-line:rgba(47,224,126,.42);
  --sig-glow:rgba(47,224,126,.30);

  --paper:#F2F5F3;

  /* type */
  --f-display:'Space Grotesk','Segoe UI',system-ui,-apple-system,sans-serif;
  --f-body:'Inter','Segoe UI',system-ui,-apple-system,sans-serif;
  --f-mono:'JetBrains Mono','SFMono-Regular',Consolas,'Liberation Mono',monospace;

  /* metrics */
  --nav-h:118px;
  --gut:clamp(20px,5vw,72px);
  --maxw:1320px;
  --r:2px;

  /* motion */
  --e-out:cubic-bezier(.16,1,.3,1);
  --e-io:cubic-bezier(.65,0,.35,1);
}

/* ── 2. RESET ──────────────────────────────────────────────── */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body,h1,h2,h3,h4,p,ul,ol,li,figure,form{margin:0;padding:0}
ul,ol{list-style:none}
img,video,svg{display:block;max-width:100%}
button,input{font:inherit;color:inherit}
a{color:inherit;text-decoration:none}

html{scroll-behavior:smooth}
html.is-booting{overflow:hidden}

body{
  font-family:var(--f-body);
  font-size:clamp(15px,.5vw + 14px,17px);
  line-height:1.62;
  color:var(--con-100);
  background:var(--ink-050);
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}

.mono{font-family:var(--f-mono);font-weight:500;letter-spacing:.06em}
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

.skip{
  position:fixed;top:10px;left:10px;z-index:9999;
  padding:12px 18px;background:var(--sig);color:var(--ink-000);
  font-family:var(--f-mono);font-size:13px;border-radius:var(--r);
  transform:translateY(-160%);transition:transform .3s var(--e-out);
}
.skip:focus{transform:none}

:focus-visible{outline:2px solid var(--sig);outline-offset:3px;border-radius:var(--r)}

::selection{background:var(--sig);color:var(--ink-000)}

/* Scrollbar. The page is ~27,000px tall, so the thumb is proportionally tiny
   — at 10px wide with a 3px inset it came out a 4px sliver and read as broken.
   Wider track, and a floor on the thumb so it stays a handle. */
::-webkit-scrollbar{width:17px}
::-webkit-scrollbar-track{background:var(--ink-050)}
::-webkit-scrollbar-thumb{
  background:rgba(47,224,126,.28);
  border:4px solid var(--ink-050);border-radius:99px;
  min-height:56px;
}
::-webkit-scrollbar-thumb:hover{background:var(--sig-core)}
::-webkit-scrollbar-thumb:active{background:var(--sig)}

/* The end buttons. Styling the bar at all makes Chrome fall back to drawing
   its own grey arrows, which sit on the dark track looking pasted on — once
   you take over the scrollbar you have to take over these too. Chrome also
   reserves a second button at each end (start:increment / end:decrement) that
   is normally invisible; left alone it shows up as a dead square. */
::-webkit-scrollbar-button{
  height:15px;
  background-color:var(--ink-050);
  background-repeat:no-repeat;
  background-position:center;
  background-size:9px 6px;
}
::-webkit-scrollbar-button:vertical:decrement{
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 6'%3E%3Cpath d='M1 4.6 4.5 1.4 8 4.6' fill='none' stroke='%232FE07E' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
::-webkit-scrollbar-button:vertical:increment{
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 6'%3E%3Cpath d='M1 1.4 4.5 4.6 8 1.4' fill='none' stroke='%232FE07E' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
::-webkit-scrollbar-button:vertical:hover{background-color:var(--ink-200)}
::-webkit-scrollbar-button:vertical:active{background-color:var(--sig-core)}
/* the phantom second button at each end */
::-webkit-scrollbar-button:vertical:start:increment,
::-webkit-scrollbar-button:vertical:end:decrement,
::-webkit-scrollbar-button:horizontal{display:none}
::-webkit-scrollbar-corner{background:var(--ink-050)}

/* Firefox has no sub-parts to style; this is the whole control. 'auto' rather
   than 'thin' so it matches the width above instead of being half of it. */
html{scrollbar-width:auto;scrollbar-color:rgba(47,224,126,.34) var(--ink-050)}

.wrap{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gut)}

/* ── 3. TYPE SCALE ─────────────────────────────────────────── */
.display{
  font-family:var(--f-display);
  font-weight:600;
  font-size:clamp(2.6rem,7.2vw,6.1rem);
  line-height:.98;
  letter-spacing:-.035em;
  color:var(--paper);
}
.display span{display:block}

.h2{
  font-family:var(--f-display);
  font-weight:600;
  font-size:clamp(1.9rem,3.6vw,3.3rem);
  line-height:1.06;
  letter-spacing:-.03em;
  color:var(--paper);
  max-width:20ch;
}

.lede{
  font-size:clamp(1rem,.5vw + .92rem,1.2rem);
  line-height:1.6;
  color:var(--con-200);
  max-width:46ch;
  margin-top:1.5rem;
}

.sub{color:var(--con-300);max-width:52ch;margin-top:1.1rem}

.eyebrow{
  display:flex;align-items:center;gap:.7rem;
  font-size:.72rem;text-transform:uppercase;letter-spacing:.22em;
  color:var(--sig);margin-bottom:1.5rem;
}
.eyebrow i{
  width:26px;height:1px;background:var(--sig);
  box-shadow:0 0 10px var(--sig-glow);flex:none;
  transform-origin:left;animation:eyeLine 2.4s var(--e-io) infinite;
}
@keyframes eyeLine{0%,100%{transform:scaleX(1);opacity:1}50%{transform:scaleX(.4);opacity:.55}}

/* ── 4. BUTTONS ────────────────────────────────────────────── */
.btn{
  --bg:var(--sig);--fg:var(--ink-000);
  position:relative;display:inline-flex;align-items:center;justify-content:center;
  padding:1.05rem 1.9rem;
  font-family:var(--f-mono);font-size:.8rem;font-weight:500;
  letter-spacing:.1em;text-transform:uppercase;
  color:var(--fg);background:var(--bg);
  border:1px solid var(--bg);border-radius:var(--r);
  overflow:hidden;cursor:pointer;isolation:isolate;
  transition:color .4s var(--e-out),border-color .4s var(--e-out),box-shadow .4s var(--e-out);
}
.btn span{position:relative;z-index:2}
.btn::before{
  content:'';position:absolute;inset:0;z-index:1;background:var(--ink-000);
  transform:translateY(101%);transition:transform .5s var(--e-out);
}
.btn:hover{color:var(--sig);box-shadow:0 0 0 1px var(--sig),0 12px 40px -12px var(--sig-glow)}
.btn:hover::before{transform:translateY(0)}
.btn--ghost{--bg:transparent;--fg:var(--paper);border-color:rgba(255,255,255,.22);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.btn--ghost::before{background:var(--sig)}
.btn--ghost:hover{color:var(--ink-000);border-color:var(--sig)}
.btn--sm{padding:.72rem 1.25rem;font-size:.72rem}

/* ── 5. BOOT SEQUENCE ──────────────────────────────────────── */
.boot{
  position:fixed;inset:0;z-index:1000;
  display:grid;place-items:center;
  background:var(--ink-000);
  transition:opacity .8s var(--e-out),visibility .8s;
}
.boot.is-done{opacity:0;visibility:hidden;pointer-events:none}
.boot__inner{width:min(520px,80vw);text-align:center}
.boot__mark{position:relative;width:min(520px,80vw);margin:0 auto 2.8rem;display:grid;place-items:center}
.boot__logo{
  width:100%;height:auto;
  opacity:0;transform:translateY(10px);
  animation:bootIn .9s var(--e-out) forwards;
}
@keyframes bootIn{to{opacity:1;transform:none}}
.boot__bar{height:2px;background:var(--ink-300);overflow:hidden;border-radius:99px}
.boot__bar i{display:block;height:100%;width:0;background:var(--sig);box-shadow:0 0 14px var(--sig-glow);transition:width .35s var(--e-out)}
.boot__txt{margin-top:1.1rem;font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;color:var(--con-400)}
.caret{display:inline-block;width:7px;height:11px;margin-left:5px;background:var(--sig);vertical-align:-1px;animation:blink 1s steps(2) infinite}
@keyframes blink{50%{opacity:0}}

/* page progress hairline */
.progress{
  position:fixed;top:0;left:0;right:0;z-index:130;
  height:2px;background:rgba(255,255,255,.06);
}
.progress i{
  display:block;height:100%;width:100%;
  background:linear-gradient(90deg,var(--sig-core),var(--sig));
  box-shadow:0 0 12px var(--sig-glow);
  transform:scaleX(var(--p,0));transform-origin:left;
  will-change:transform;
}

/* ── 6. NAV ────────────────────────────────────────────────── */
.nav{
  position:fixed;top:0;left:0;right:0;z-index:120;
  height:var(--nav-h);
  display:flex;align-items:center;gap:2rem;
  padding-inline:var(--gut);
  transition:height .45s var(--e-out),background .45s var(--e-out),border-color .45s var(--e-out),backdrop-filter .45s;
  border-bottom:1px solid transparent;
}
.nav.is-stuck{
  height:84px;
  background:rgba(7,10,9,.72);
  -webkit-backdrop-filter:blur(18px) saturate(140%);backdrop-filter:blur(18px) saturate(140%);
  border-bottom-color:rgba(255,255,255,.07);
}
.nav__brand{margin-right:auto;display:flex;align-items:center}
.nav__brand img{height:clamp(40px,4.4vw,62px);width:auto;transition:height .45s var(--e-out),filter .3s}
.nav__brand:hover img{filter:drop-shadow(0 0 18px var(--sig-glow))}
.nav.is-stuck .nav__brand img{height:clamp(34px,3.4vw,46px)}

.nav__links{display:flex;gap:2.2rem}
.nav__links a{
  position:relative;font-family:var(--f-mono);font-size:.76rem;
  letter-spacing:.09em;color:var(--con-200);
  padding-block:.35rem;transition:color .3s;
}
.nav__links a::after{
  content:'';position:absolute;left:0;bottom:0;height:1px;width:100%;
  background:var(--sig);transform:scaleX(0);transform-origin:right;
  transition:transform .45s var(--e-out);
}
.nav__links a:hover{color:var(--paper)}
.nav__links a:hover::after{transform:scaleX(1);transform-origin:left}

.nav__burger{display:none;flex-direction:column;gap:6px;width:38px;height:38px;
  align-items:center;justify-content:center;background:none;border:1px solid rgba(255,255,255,.16);border-radius:var(--r);cursor:pointer}
.nav__burger i{display:block;width:17px;height:1.5px;background:var(--paper);transition:transform .4s var(--e-out),opacity .3s}
.nav__burger[aria-expanded="true"] i:first-child{transform:translateY(3.75px) rotate(45deg)}
.nav__burger[aria-expanded="true"] i:last-child{transform:translateY(-3.75px) rotate(-45deg)}

/* ── 7. PHASE RAIL ─────────────────────────────────────────── */
/* A HUD module, not floating text: it sits on its own panel so it stays
   readable over whatever part of the render is behind it. */
.rail{
  position:fixed;z-index:110;
  right:clamp(14px,2vw,30px);top:50%;transform:translateY(-50%);
  padding:1rem 1.1rem 1.05rem;
  background:rgba(8,12,10,.80);
  -webkit-backdrop-filter:blur(16px) saturate(140%);backdrop-filter:blur(16px) saturate(140%);
  border:1px solid rgba(255,255,255,.10);
  border-radius:var(--r);
  box-shadow:0 20px 60px -24px rgba(0,0,0,.95);
  opacity:0;pointer-events:none;
  transform:translateY(-50%) translateX(14px);
  transition:opacity .6s var(--e-out),transform .6s var(--e-out);
}
.rail.is-on{opacity:1;pointer-events:auto;transform:translateY(-50%)}

/* scan-bracket corners, same motif as the HUD chips */
.rail::before,.rail::after{
  content:'';position:absolute;width:9px;height:9px;
  border:1px solid var(--sig);opacity:.8;
}
.rail::before{top:-1px;left:-1px;border-right:0;border-bottom:0}
.rail::after{bottom:-1px;right:-1px;border-left:0;border-top:0}

.rail__label{
  display:block;margin-bottom:.85rem;padding-bottom:.7rem;
  border-bottom:1px solid rgba(255,255,255,.10);
  font-size:.62rem;letter-spacing:.3em;text-transform:uppercase;
  color:var(--sig);
}

.rail__list{position:relative;display:flex;flex-direction:column;gap:.1rem}
/* the connecting spine the markers sit on */
.rail__list::before{
  content:'';position:absolute;left:5px;top:12px;bottom:12px;
  width:1px;background:rgba(255,255,255,.13);
}

.rail__list::after{
  content:'';position:absolute;left:5px;top:12px;
  width:1px;height:calc(100% - 24px);
  background:var(--sig);box-shadow:0 0 8px var(--sig-glow);
  transform:scaleY(var(--fp,0));transform-origin:top;
}

.rail__list a{
  position:relative;display:flex;align-items:center;gap:.65rem;
  padding:.46rem .5rem .46rem 0;
  color:var(--con-100);
  transition:color .35s var(--e-out);
}
/* marker on the spine */
.rail__list a::before{
  content:'';position:relative;flex:none;z-index:1;
  width:11px;height:11px;border-radius:99px;
  background:var(--ink-100);
  box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.28);
  transition:box-shadow .35s var(--e-out),background .35s var(--e-out);
}
.rail__list a b{
  font-size:.72rem;letter-spacing:.1em;color:var(--con-200);
  transition:color .35s var(--e-out);
}
.rail__list a span{
  font-family:var(--f-mono);font-size:.78rem;letter-spacing:.06em;
  white-space:nowrap;
}

.rail__list a:hover{color:var(--paper)}
.rail__list a:hover b{color:var(--con-100)}
.rail__list a:hover::before{box-shadow:inset 0 0 0 1.5px var(--sig-bloom)}

.rail__list a.is-active{color:var(--sig)}
.rail__list a.is-active b{color:var(--sig)}
.rail__list a.is-active::before{
  background:var(--sig);
  box-shadow:0 0 0 3px rgba(47,224,126,.16),0 0 14px var(--sig-glow);
}

/* Deep links are the point of the rail as much as navigation is — a phase URL
   is what gets pasted into an email. Shown only when the clipboard API exists. */
.rail__copy{
  display:flex;align-items:center;gap:.5rem;width:100%;
  margin-top:.85rem;padding-top:.75rem;
  background:none;border:0;border-top:1px solid rgba(255,255,255,.10);
  cursor:pointer;
  font-size:.6rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--con-300);transition:color .3s var(--e-out);
}
.rail__copy i{
  flex:none;width:9px;height:9px;
  border:1.5px solid currentColor;border-radius:1px;
  transition:transform .3s var(--e-out),border-color .3s,border-width .3s;
}
.rail__copy:hover{color:var(--sig)}
.rail__copy.is-done{color:var(--sig)}
.rail__copy.is-done i{
  border-width:0 0 1.5px 1.5px;border-radius:0;border-color:var(--sig);
  transform:rotate(-45deg) translate(1px,-2px);
}

/* ── 8. THE FILM ───────────────────────────────────────────── */
.film{position:relative;background:var(--ink-000)}

/* --dur is the phase's clip length in seconds. The pinned scroll distance is
   100vh (the stage) plus a fixed number of vh per second of footage, so every
   act's scroll range maps onto its own segment of the film timeline. */
.act{position:relative;--dur:4;--vhs:45vh;height:calc(100vh + var(--dur) * var(--vhs))}
/* slightly longer than its 8s of footage so act 2 pins after the putaway
   clip has actually started, and so the hero gets extra dwell time */
/* --dur is now how much scroll an act's own timeline is spread over. The
   two long ones are the two that are genuinely scrubbed rather than
   revealed: 04 walks a picker through three bays, 05 runs a five-line
   verification. Giving them a short span makes them flick past. */
#act-1{--dur:8}
#act-2{--dur:5}
#act-3{--dur:5}
#act-4{--dur:9}
#act-5{--dur:9}
#act-6{--dur:6}

/* Each act now carries its own backdrop instead of sharing one film layer.
   The film had to be persistent because it was a single encoded timeline;
   the acts are six different cameras on one procedural world, so there is
   no continuity to preserve between them and a per-act canvas is simpler,
   pins for free with the sticky stage, and works on mobile where nothing
   pins at all. */
.act__bg{
  position:absolute;inset:0;z-index:0;
  width:100%;height:100%;
  background:var(--ink-000);
}
/* The glow acts.js produces: a quarter-size canvas the compositor scales up
   and ADDS over the render. Sits after .act__bg in the DOM at the same
   z-index, so it paints above the render and below the scrim - which dims
   it exactly as much as everything else. plus-lighter where supported,
   screen as the fallback; both only ever brighten. */
.act__glow{
  position:absolute;inset:0;z-index:0;
  width:100%;height:100%;
  pointer-events:none;
  opacity:.85;
  mix-blend-mode:screen;
  mix-blend-mode:plus-lighter;
}

/* ── THE FLIGHT ────────────────────────────────────────────────
   One camera for the whole sequence instead of six plates. The canvas is
   fixed to the viewport, so there is no per-act frame to tear at a section
   boundary: the acts scroll over a window onto one continuous move.

   It only runs where the acts actually pin (site.js adds .is-flight above
   900px, and never under prefers-reduced-motion). Where it does not, the six
   .act__bg canvases are the fallback, unchanged. Both must never draw at
   once, which is what these display:none rules are for — scoped to .act so
   the card-section plates and the CTA plate are untouched. */
#seqBg{
  position:fixed;inset:0;z-index:0;pointer-events:none;
  opacity:0;transition:opacity .2s linear;
}
#seqBg.is-on{opacity:1}
.seq__bg{position:absolute;inset:0;width:100%;height:100%;background:var(--ink-000)}
.seq__scrim{
  position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(100deg,rgba(5,7,6,.94) 0%,rgba(5,7,6,.74) 30%,rgba(5,7,6,.12) 56%,rgba(5,7,6,.52) 100%),
    linear-gradient(to top,rgba(5,7,6,.86) 0%,transparent 34%),
    linear-gradient(to bottom,rgba(5,7,6,.62) 0%,transparent 26%);
}
.is-flight .act .act__bg,
.is-flight .act .act__glow,
.is-flight .act .film__scrim{display:none}

/* --op fades the COPY between acts, never the stage. The stage now holds
   the backdrop, and fading it would dissolve to black at every boundary —
   the old persistent film layer is what used to cover that. */
.act__stage{
  position:sticky;top:0;height:100svh;z-index:1;
  display:grid;
  overflow:hidden;
}

.film__scrim{
  position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(100deg,rgba(5,7,6,.94) 0%,rgba(5,7,6,.74) 30%,rgba(5,7,6,.12) 56%,rgba(5,7,6,.52) 100%),
    linear-gradient(to top,rgba(5,7,6,.86) 0%,transparent 34%),
    linear-gradient(to bottom,rgba(5,7,6,.62) 0%,transparent 26%);
}

/* content grid over the film */
.act__grid{
  position:relative;z-index:2;
  opacity:var(--op,1);
  height:100%;
  width:100%;max-width:var(--maxw);margin-inline:auto;
  /* --nav-h is the nav at REST. Inside a pinned act it is always stuck, and
     stuck is shorter — reserving the full resting height cost every act ~35px
     it could not spare, which is what pushed the bottom of 03 and 06 off the
     stage on a laptop. */
  padding:calc(var(--nav-h) * .8 + 3vh) var(--gut) 12vh;
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,.85fr);
  align-items:center;gap:3rem;
}
/* 34rem was narrower than the longest headline line needs, so the deliberate
   line breaks in .display were being re-broken by wrapping - a three-line
   headline arriving as four ragged ones with an orphan. The lede and ticks
   keep their own measure, so only the headline gains the room. */
.act__copy{max-width:37.5rem}
.act__copy .lede{max-width:34rem}
.act__copy .ticks{max-width:34rem}
.act__cta{display:flex;flex-wrap:wrap;gap:.85rem;margin-top:2.4rem}

/* The phase rail is fixed to the VIEWPORT edge while the grid is capped at
   --maxw and centred, so past about 1650px the grid never reaches the rail
   and this reservation is 190px taken from the headline for nothing. At
   1920 it left a 374px gap on one side of a column too narrow to hold the
   headline on the other. */
@media (min-width:901px) and (max-width:1650px){
  .act__grid{padding-right:calc(var(--gut) + 190px)}
}

/* ── 9. HUD CHIPS ──────────────────────────────────────────── */
.act__hud{
  justify-self:end;align-self:center;
  display:flex;flex-direction:column;align-items:flex-start;gap:.7rem;
  width:min(330px,100%);
}
.chip{
  --p:0;
  position:relative;
  display:flex;align-items:center;gap:.65rem;
  padding:.7rem .95rem;
  background:var(--sig-panel);
  border:1px solid var(--sig-line);
  border-radius:var(--r);
  -webkit-backdrop-filter:blur(10px) saturate(130%);backdrop-filter:blur(10px) saturate(130%);
  box-shadow:0 10px 34px -14px rgba(0,0,0,.9),inset 0 1px 0 rgba(255,255,255,.06);
  color:var(--paper);
  font-size:.74rem;letter-spacing:.04em;
  opacity:0;transform:translateX(26px) scale(.97);
  filter:blur(3px);
  transition:opacity .55s var(--e-out),transform .55s var(--e-out),filter .55s var(--e-out);
  will-change:opacity,transform;
}
.chip.is-on{opacity:1;transform:none;filter:none}
/* corner ticks — the scan-bracket motif from the logo */
.chip::before,.chip::after{
  content:'';position:absolute;width:7px;height:7px;
  border:1px solid var(--sig);opacity:.85;
}
.chip::before{top:-1px;left:-1px;border-right:0;border-bottom:0}
.chip::after{bottom:-1px;right:-1px;border-left:0;border-top:0}

.chip em{
  flex:none;width:14px;height:14px;border-radius:99px;
  border:1px solid var(--sig);position:relative;
}
.chip em::after{
  content:'';position:absolute;inset:3px;border-radius:99px;
  background:var(--sig);box-shadow:0 0 8px var(--sig-glow);
}
.chip.is-on em::before{
  content:'';position:absolute;inset:-1px;border-radius:99px;
  border:1px solid var(--sig);
  animation:pulse 2.2s var(--e-out) infinite;
}
@keyframes pulse{0%{transform:scale(1);opacity:.9}70%,100%{transform:scale(2.1);opacity:0}}

.chip--big{flex-direction:column;align-items:flex-start;gap:.15rem;padding:1rem 1.15rem;min-width:210px}
.chip__k{font-size:.6rem;letter-spacing:.2em;text-transform:uppercase;color:var(--sig-bloom);opacity:.85}
.chip--big b{
  font-size:2rem;font-weight:700;line-height:1.05;letter-spacing:-.02em;
  color:var(--paper);text-shadow:0 0 26px var(--sig-glow);
}
.chip__s{font-size:.63rem;color:var(--con-200);letter-spacing:.06em}

.chip--list{flex-direction:column;align-items:stretch;gap:.5rem;padding:.9rem 1.05rem;min-width:220px}
.chip--list ul{display:flex;flex-direction:column;gap:.34rem}
.chip--list li{
  display:flex;justify-content:space-between;gap:1rem;
  font-size:.68rem;color:var(--con-100);
  padding-bottom:.34rem;border-bottom:1px solid rgba(47,224,126,.16);
}
.chip--list li:last-child{border-bottom:0;padding-bottom:0}
.chip--list li b{color:var(--sig);font-weight:500}

/* scroll cue */
.scrollcue{
  position:absolute;left:var(--gut);bottom:5vh;z-index:3;
  display:flex;align-items:center;gap:.7rem;
  font-size:.62rem;letter-spacing:.28em;text-transform:uppercase;color:var(--con-300);
  transition:opacity .6s var(--e-out);
}
.scrollcue i{
  position:relative;display:block;width:1px;height:38px;background:rgba(255,255,255,.16);overflow:hidden;
}
.scrollcue i::after{
  content:'';position:absolute;inset:0;background:var(--sig);
  animation:cue 2s var(--e-io) infinite;
}
@keyframes cue{0%{transform:translateY(-100%)}55%,100%{transform:translateY(100%)}}
.act--hero .act__stage.is-past .scrollcue{opacity:0}

/* ── 9b. THE HUD PANEL ─────────────────────────────────────────
   Replaces the status chips. Same material as .chip — same green, same
   corner brackets, same blur — but it reports rather than announces:
   sources binding, devices linking, counts resolving, and a live feed
   of what the act's backdrop is actually doing behind it.

   Robotic, not organic: it does not ease in, it snaps to position in
   three discrete servo steps. steps() is doing the whole job. */
.blog{
  position:relative;
  justify-self:end;align-self:center;
  width:min(372px,100%);
  background:var(--sig-panel);
  border:1px solid var(--sig-line);
  border-radius:var(--r);
  -webkit-backdrop-filter:blur(10px) saturate(130%);backdrop-filter:blur(10px) saturate(130%);
  box-shadow:0 10px 34px -14px rgba(0,0,0,.9),inset 0 1px 0 rgba(255,255,255,.06);
  opacity:0;
}
.blog.is-on{animation:servoIn .34s steps(3) forwards}
@keyframes servoIn{
  0%  {opacity:0;transform:translateX(24px)}
  100%{opacity:1;transform:translateX(0)}
}
.blog::before,.blog::after{
  content:'';position:absolute;width:7px;height:7px;
  border:1px solid var(--sig);opacity:.85;
}
.blog::before{top:-1px;left:-1px;border-right:0;border-bottom:0}
.blog::after{bottom:-1px;right:-1px;border-left:0;border-top:0}

.blog__head{
  display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding:.72rem .95rem;border-bottom:1px solid rgba(47,224,126,.18);
  font-family:var(--f-mono);font-size:.6rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--sig-bloom);
}
.blog__head em{display:flex;align-items:center;gap:.45rem;font-style:normal;color:var(--con-300)}
.blog__head em i{
  width:6px;height:6px;border-radius:99px;background:var(--con-400);
  transition:background .1s steps(1),box-shadow .1s steps(1);
}
.blog.is-live .blog__head em i{background:var(--sig);box-shadow:0 0 10px var(--sig)}
.blog.is-live .blog__head em{color:var(--sig)}

.blog__list{padding:.5rem .95rem .72rem}
.blog__list li{
  display:grid;grid-template-columns:auto 1fr auto;align-items:baseline;gap:.55rem;
  font-family:var(--f-mono);font-size:.68rem;letter-spacing:.03em;
  color:var(--con-300);
  padding:.42rem 0;border-bottom:1px solid rgba(47,224,126,.1);
}
.blog__list li:last-child{border-bottom:0}
.blog__list li s{text-decoration:none;color:var(--con-200)}
.blog__list li i{font-style:normal;color:var(--con-400);font-size:.62rem;letter-spacing:.1em}
.blog__list li b{
  font-weight:500;color:var(--con-400);
  font-variant-numeric:tabular-nums;
  /* the value does not fade to green, it latches */
  transition:color .08s steps(1),text-shadow .08s steps(1);
}
.blog__list li.is-bound b{color:var(--sig);text-shadow:0 0 14px var(--sig-glow)}

/* the feed: a transaction out in the volume pushes a line in here, so the
   panel is reporting on the thing behind it rather than running beside it */
.blog__feed{
  padding:0 .95rem;max-height:0;overflow:hidden;
  border-top:1px solid rgba(47,224,126,0);
  transition:max-height .26s steps(3),padding .26s steps(3),border-color .26s steps(3);
}
.blog.is-live .blog__feed{max-height:80px;padding:.44rem .95rem .5rem;border-top-color:rgba(47,224,126,.18)}
.blog__feed li{
  display:grid;grid-template-columns:40px 1fr auto;align-items:baseline;gap:.5rem;
  font-family:var(--f-mono);font-size:.62rem;letter-spacing:.04em;
  color:var(--con-300);padding:.16rem 0;
  animation:feedIn .18s steps(2) both;
}
@keyframes feedIn{0%{opacity:0;transform:translateY(-5px)}100%{opacity:1;transform:none}}
.blog__feed li s{text-decoration:none;color:var(--sig-bloom);opacity:.8}
.blog__feed li em{font-style:normal;color:var(--con-200)}
.blog__feed li b{font-weight:500;color:var(--sig);font-variant-numeric:tabular-nums}
.blog__feed li.is-out b{color:var(--sig-bloom)}

.blog__foot{
  display:flex;align-items:flex-end;justify-content:space-between;gap:1rem;
  padding:.8rem .95rem 1rem;border-top:1px solid rgba(47,224,126,.18);
}
.blog__state{display:flex;flex-direction:column;gap:.22rem}
.blog__state > span{
  font-family:var(--f-mono);font-size:.58rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--sig-bloom);opacity:.85;
}
.blog__state b{
  font-family:var(--f-mono);font-weight:700;font-size:1.42rem;line-height:1;letter-spacing:-.01em;
  color:var(--con-300);transition:color .1s steps(1),text-shadow .1s steps(1);
}
.blog.is-live .blog__state b{color:var(--paper);text-shadow:0 0 26px var(--sig-glow)}
/* stepped, so the meter advances in notches rather than sliding */
.blog__meter{flex:none;width:92px}
.blog__meter i{display:block;height:2px;background:var(--ink-400);overflow:hidden;border-radius:99px}
.blog__meter i b{
  display:block;height:100%;width:0;background:var(--sig);
  box-shadow:0 0 12px var(--sig-glow);
  transition:width .18s steps(4);
}
.blog__meter > span{
  display:block;margin-top:.42rem;text-align:right;
  font-family:var(--f-mono);font-size:.56rem;letter-spacing:.16em;color:var(--con-300);
}

/* the caret that sits at the end of the headline until the line commits */
.tick{
  display:inline-block;width:.4em;height:.84em;margin-left:.14em;
  background:var(--sig);vertical-align:-.02em;
  box-shadow:0 0 18px var(--sig-glow);
  animation:blink 1.05s steps(2) infinite;
}
.tick.is-done{animation:none;opacity:0;transition:opacity .5s var(--e-out)}

/* ── panel shapes ─────────────────────────────────────────────
   The panel is the most dominant element in every frame, and six
   identical ones flatten the acts — the eye reads "same panel,
   therefore same picture". Same material, three shapes. */
.act--strip .act__grid{
  grid-template-columns:minmax(0,1fr);
  grid-template-rows:minmax(0,1fr) auto;
  align-items:center;
  padding-bottom:6vh;
}
.blog--strip{
  justify-self:stretch;align-self:end;
  width:auto;max-width:none;margin-bottom:1.4vh;
}
.blog--strip .blog__list{display:flex;padding:.4rem .45rem}
.blog--strip .blog__list li{
  flex:1;display:flex;align-items:baseline;justify-content:space-between;gap:.7rem;
  border-bottom:0;border-right:1px solid rgba(47,224,126,.12);
  padding:.26rem .9rem;
}
.blog--strip .blog__list li:last-child{border-right:0}
.blog--strip .blog__list li i{display:none}
.blog--strip .blog__list li s{
  font-size:.56rem;letter-spacing:.16em;text-transform:uppercase;color:var(--con-300);
}
.blog--strip .blog__list li b{font-size:.94rem}
.blog--strip .blog__feed{display:flex;gap:1.9rem}
.blog--strip .blog__feed li{display:flex;gap:.6rem;padding:0}
.blog.blog--strip.is-live .blog__feed{max-height:26px;padding:.3rem 1.05rem .5rem}
.blog--strip .blog__foot{padding:.45rem 1.05rem .58rem}
.blog--strip .blog__state{flex-direction:row;align-items:baseline;gap:.7rem}
.blog--strip .blog__state b{font-size:1rem}

.blog--pin{
  width:min(252px,100%);align-self:start;
  margin-top:calc(var(--nav-h) * .5);
}
.blog--pin .blog__list li{font-size:.62rem;padding:.34rem 0}
.blog--pin .blog__state b{font-size:1.1rem}
.blog--pin .blog__meter{width:64px}

/* Act 05's HELD beat. acts.js puts .is-held on the stage while the carton is
   held: the canvas dims the building, and the page follows - the copy steps
   back and the gate panel goes to the white of a read. Stepped both ways. */
#act-5 .act__copy{transition:opacity .18s steps(3)}
#act-5 .blog{transition:border-color .1s steps(1),box-shadow .1s steps(1)}
/* on the flight the canvas is the sequence's, not act 05's, so the held
   beat is flagged at the root instead of on that act's stage */
.act__stage.is-held .act__copy,
.is-held #act-5 .act__copy{opacity:.38}
.act__stage.is-held .blog,
.is-held #act-5 .blog{
  border-color:rgba(234,255,243,.85);
  box-shadow:0 10px 34px -14px rgba(0,0,0,.9),0 0 0 1px rgba(234,255,243,.22),0 0 42px rgba(234,255,243,.14);
}
.act__stage.is-held .blog::before,.act__stage.is-held .blog::after,
.is-held #act-5 .blog::before,.is-held #act-5 .blog::after{border-color:var(--paper)}
.act__stage.is-held .blog__head,
.is-held #act-5 .blog__head{color:var(--paper)}

@media (max-width:900px){
  .blog{display:none}
  .act--strip .act__grid{grid-template-rows:auto}
}
@media (prefers-reduced-motion:reduce){
  .tick{animation:none}
  .blog.is-on{animation:none;opacity:1}
  .blog__feed li{animation:none}
}

/* ── 9c. PINNED ACTS MUST FIT THE VIEWPORT ─────────────────────
   .display sizes off viewport WIDTH (clamp(2.6rem,7.2vw,6.1rem)), but a
   pinned act has to fit viewport HEIGHT. On a wide, short screen the
   headline reaches its 6.1rem ceiling while the height available to hold
   it does not grow to match, and the bottom of the act - the strip panel
   on 03 and 06 - is clipped off the stage with no way to scroll to it.

   So inside an act the headline takes the SHORTER axis. Everywhere else
   .display is unchanged: the contact CTA is a normal section that can
   simply get taller. */
/* 7.2vh, not 8.4: the binding constraint is the COLUMN, not the stage. The
   copy column is ~507px once the rail reservation and the HUD column are
   taken out, and the longest headline line needs 602px at 8.4vh - so the
   deliberate line breaks were being re-broken into ragged four-line
   headlines with an orphan. Measured, not guessed. */
.act .display{font-size:clamp(2.2rem,min(7.2vw,7.2vh),6.1rem)}
/* the two acts carrying a tick list are the tallest; the list is the part
   that can afford to sit closer without losing its rhythm */
.act .ticks{margin-top:1.5rem;gap:.58rem}
.act .act__cta{margin-top:2rem}

/* Below this the type cap alone is not enough and the rhythm has to give
   a little too. Nothing here changes the design above ~820px tall, which
   is where most desktops sit. */
/* SHORT WINDOWS. A browser at 1100x515 is not an edge case - it is what a
   laptop looks like with devtools open, and it is the window this site was
   last reviewed in. The act still has to fit: at this height the headline is
   already at its clamp floor, so the space has to come from the rhythm, and
   the keyboard hint has to get out of the way of the buttons it was sitting
   on top of. */
@media (min-width:901px) and (max-height:640px){
  .act__grid{padding-top:calc(var(--nav-h) * .32 + .5vh);padding-bottom:1.5vh}
  .act .display{font-size:clamp(1.8rem,min(5.2vw,7.8vh),2.6rem);line-height:1.03}
  .act .eyebrow{margin-bottom:.4rem}
  .act .lede{font-size:.82rem;line-height:1.42;margin-top:.42rem}
  /* acts 02 and 04 carry a three-item tick list under the lede, and they are
     the two that overflowed a 515px window - the list is where the space is */
  .act .ticks{margin-top:.45rem;gap:.2rem;font-size:.78rem}
  .act .ticks li{line-height:1.35}
  .act .act__cta{margin-top:.55rem;gap:.55rem}
  .act .btn{padding:.7rem 1.1rem}
  .act--strip .act__grid{padding-bottom:1.4vh}
  .blog__list li{padding:.24rem 0}
  .blog__foot{padding:.45rem .95rem .55rem}
}

/* Below this there is no arrangement of type that fits act 02 and act 04,
   which carry a three-item tick list under the lede. The choice is to clip
   the call to action or to drop the list, and the lede already says what the
   list elaborates - so the list goes and the button stays. */
@media (min-width:901px) and (max-height:560px){
  .act .ticks{display:none}
}

@media (min-width:901px) and (max-height:820px){
  /* The keyboard hint sits in the bottom-left corner, which is where the
     strip panel's own bottom-left corner arrives once the window is short:
     two instruments in one corner, one printed over the other. The hint is
     the one that can go - the shortcuts still work, and the rail is still
     there to click. Base .keyhint is declared later in the file, so this
     needs the specificity to beat it rather than merely match it. */
  html .keyhint{display:none}

  .act__grid{padding-top:calc(var(--nav-h) * .56 + 2vh);padding-bottom:5vh}
  .act .eyebrow{margin-bottom:1rem}
  .act .lede{margin-top:1rem}
  .act .act__cta{margin-top:1.5rem}
  .act .ticks{margin-top:1.2rem;gap:.55rem}
  .act--strip .act__grid{padding-bottom:2.6vh}
  .blog--strip{margin-bottom:.8vh}
  .blog--pin{margin-top:calc(var(--nav-h) * .3)}
}

/* ── 10. TICK LIST ─────────────────────────────────────────── */
.ticks{margin-top:2rem;display:flex;flex-direction:column;gap:.75rem}
.ticks li{
  position:relative;padding-left:1.75rem;
  font-size:.9rem;color:var(--con-200);
}
.ticks li::before{
  content:'';position:absolute;left:0;top:.52em;
  width:9px;height:9px;
  border-left:1.5px solid var(--sig);border-bottom:1.5px solid var(--sig);
  transform:rotate(-45deg) translateY(-1px);
}

/* ── 12b. PRODUCT SCREENS ──────────────────────────────────── */
/* The OS is a light interface and the site is dark, so each screen sits on a
   dark mat with the same scan-bracket corners as the HUD chips. Without that
   they read as pasted in. */
.sect--product{background:var(--ink-100)}

.shot{margin:0}
.shot__frame{
  position:relative;
  padding:clamp(8px,.8vw,12px);
  background:var(--ink-050);
  border:1px solid rgba(255,255,255,.10);
  border-radius:var(--r);
  transition:border-color .5s var(--e-out),box-shadow .5s var(--e-out),transform .5s var(--e-out);
}
.shot__frame::before,.shot__frame::after{
  content:'';position:absolute;width:10px;height:10px;
  border:1px solid var(--sig);opacity:0;
  transition:opacity .5s var(--e-out);
  pointer-events:none;z-index:2;
}
.shot__frame::before{top:-1px;left:-1px;border-right:0;border-bottom:0}
.shot__frame::after{bottom:-1px;right:-1px;border-left:0;border-top:0}
.shot__frame img{
  display:block;width:100%;height:auto;
  border-radius:1px;
}
/* A whole screen at card size is a picture of an interface, not something
   anyone can read. Each shot shows the panel that makes its point (--s/--a/--b
   inline, worked out in source pixels at the frame's own 3:2), and the lens
   still opens the full screen. The lead is the picking screen, and it opens
   on its location card - A03-04, the code the building was just calling out -
   then widens to the whole screen as it comes up the page (--z from site.js). */
.shot__crop{overflow:hidden;border-radius:1px;aspect-ratio:3/2}
.shot__crop img{transform-origin:0 0;transform:translate(var(--a,0%),var(--b,0%)) scale(var(--s,1))}
.shot--lead .shot__crop{--z:0;--s:calc(1 + .8506 * var(--z));--a:calc(-32.17% * var(--z));--b:calc(-19.88% * var(--z))}
.shot--lead .shot__crop img{will-change:transform}
.shot:hover .shot__frame{
  border-color:var(--sig-line);
  box-shadow:0 30px 80px -34px var(--sig-glow);
  transform:translateY(-2px);
}
.shot:hover .shot__frame::before,.shot:hover .shot__frame::after{opacity:.9}

.shot__cap{
  display:flex;align-items:baseline;gap:.8rem;flex-wrap:wrap;
  margin-top:1.05rem;
  font-size:.76rem;letter-spacing:.04em;color:var(--con-300);
}
.shot__cap b{
  flex:none;font-weight:500;color:var(--sig);
  font-size:.62rem;letter-spacing:.2em;text-transform:uppercase;
}

.shot--lead{margin-bottom:clamp(30px,3.4vw,52px)}
.shots{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(22px,2.6vw,38px)}

/* ── 12. SECTIONS ──────────────────────────────────────────── */
.sect{
  position:relative;z-index:3;
  padding:clamp(80px,11vw,150px) 0;
  background:var(--ink-050);
  border-top:1px solid rgba(255,255,255,.06);
}
.sect__head{margin-bottom:clamp(44px,5vw,72px)}

.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:rgba(255,255,255,.08);
  border:1px solid rgba(255,255,255,.08);border-radius:var(--r);overflow:hidden}
.cards--4{grid-template-columns:repeat(4,1fr)}

.card{
  position:relative;background:var(--ink-050);
  padding:clamp(26px,2.8vw,42px);
  overflow:hidden;transition:background .5s var(--e-out);
}
.card::before{
  content:'';position:absolute;inset:0;
  background:radial-gradient(60% 60% at 50% 0%,rgba(8,136,58,.16),transparent 70%);
  opacity:0;transition:opacity .55s var(--e-out);
}
.card:hover{background:var(--ink-100)}
.card:hover::before{opacity:1}
.card>*{position:relative}
.card__n{
  display:block;font-size:.68rem;letter-spacing:.2em;color:var(--sig);
  margin-bottom:1.6rem;
}
.card h3{
  font-family:var(--f-display);font-weight:500;
  font-size:1.28rem;letter-spacing:-.015em;color:var(--paper);margin-bottom:.7rem;
}
.card p{font-size:.9rem;color:var(--con-300);line-height:1.68}
.card__status{
  display:inline-block;margin-top:1.4rem;
  padding:.32rem .6rem;
  font-size:.6rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--con-300);
  border:1px solid rgba(255,255,255,.14);border-radius:var(--r);
}
.card__status.is-now{
  color:var(--sig);border-color:var(--sig-line);
  background:rgba(47,224,126,.07);
}

/* ── 12c. THE WORLD UNDER THE CARDS ─────────────────────────
   The sequence's world does not stop at act 06. The three card sections
   carry it behind them, each on its own camera and driven by its own
   scroll, so the cards become panels over a live building instead of
   opaque tiles on a flat ground. Same materials as the acts — structure
   grey, data green — and a scrim so the words stay the brightest thing
   in the frame. */
.sect--world{overflow:hidden}
.sect__bg{
  position:absolute;inset:0;z-index:0;
  width:100%;height:100%;
  opacity:.9;pointer-events:none;
}
/* sits over the canvas and the glow canvas acts.js inserts beside it,
   and under .wrap — which has to be raised for that to mean anything */
.sect--world::after{
  content:'';position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    linear-gradient(180deg,rgba(5,7,6,.88) 0%,rgba(5,7,6,.3) 22%,rgba(5,7,6,.36) 74%,rgba(5,7,6,.86) 100%),
    linear-gradient(90deg,rgba(5,7,6,.66) 0%,rgba(5,7,6,.04) 44%,rgba(5,7,6,.2) 100%);
}
.sect--world .wrap{position:relative;z-index:1}

/* The cards go translucent so the building reads through them. Every rule
   that sets a card background has to be answered here, or the scan reveal
   snaps back to an opaque tile halfway through its own animation. */
.sect--world .card,
.sect--world .cards.is-scanning .card{background:rgba(9,13,11,.58)}
.sect--world .card:hover{background:rgba(16,23,19,.7)}
.sect--world .cards.grid-armed .card{background:rgba(5,7,6,.82)}
.sect--world .cards{background:rgba(255,255,255,.1)}

/* ── 12c. THE MODEL (ROI) ──────────────────────────────────── */
/* Darkest ground on the page: after two lit sections of screenshots this reads
   as a console you sit down at rather than another block of marketing. */
.sect--calc{
  background:
    radial-gradient(100% 70% at 50% 0%,rgba(8,136,58,.10),transparent 60%),
    var(--ink-000);
}

.calc{
  display:grid;
  grid-template-columns:minmax(0,1.08fr) minmax(0,.92fr);
  gap:clamp(30px,3.4vw,64px);
  align-items:start;
}

/* groups carry a rule + green node so the model reads as part of the page's
   family rather than a bolted-on widget */
.calc__group{position:relative;padding-top:2rem}
.calc__group+.calc__group{margin-top:clamp(38px,4vw,60px)}
.calc__group::before{
  content:'';position:absolute;top:0;left:0;right:0;height:1px;
  background:rgba(255,255,255,.12);
}
.calc__group::after{
  content:'';position:absolute;top:-3px;left:0;width:7px;height:7px;border-radius:99px;
  background:var(--sig);box-shadow:0 0 0 4px rgba(47,224,126,.12),0 0 16px var(--sig-glow);
}
.calc__groupHead{
  display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  margin-bottom:.4rem;
}
.calc__groupHead h3{
  font-size:.66rem;font-weight:500;letter-spacing:.2em;text-transform:uppercase;color:var(--sig);
}
.calc__tag{
  padding:.3rem .55rem;
  font-size:.58rem;letter-spacing:.18em;text-transform:uppercase;color:var(--con-300);
  border:1px solid rgba(255,255,255,.14);border-radius:var(--r);
}
.calc__note{
  font-size:.84rem;line-height:1.66;color:var(--con-300);
  max-width:54ch;margin:.9rem 0 .4rem;
}

.calc__field{
  display:flex;align-items:center;justify-content:space-between;gap:1.4rem;
  padding:1.05rem 0;
  border-bottom:1px solid rgba(255,255,255,.07);
}
.calc__field label{
  font-size:.88rem;line-height:1.5;color:var(--con-100);max-width:30ch;
}
.calc__field label i{
  display:block;font-style:normal;
  font-family:var(--f-mono);font-size:.66rem;letter-spacing:.06em;
  color:var(--con-400);margin-top:.32rem;
}

.calc__ctrl{
  /* wide enough that the slider has real travel — at 210px it read as a
     decoration under the number rather than something worth dragging */
  flex:none;width:min(280px,50%);
  display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:.4rem;
}
.calc__pre,.calc__post{font-size:.8rem;color:var(--con-300)}
.calc__num{
  width:98px;padding:.6rem .7rem;
  background:rgba(255,255,255,.04);
  border:1px solid rgba(255,255,255,.14);border-radius:var(--r);
  color:var(--paper);font-size:.86rem;text-align:right;
  font-variant-numeric:tabular-nums;
  transition:border-color .3s,background .3s,box-shadow .3s;
}
.calc__num:focus{
  outline:none;border-color:var(--sig);background:rgba(47,224,126,.06);
  box-shadow:0 0 0 3px rgba(47,224,126,.12);
}
.calc__num::-webkit-outer-spin-button,
.calc__num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.calc__num[type=number]{-moz-appearance:textfield;appearance:textfield}

/* The slider is a second control on the same value. The number field is the
   accessible one — the range is hidden from AT and the tab order so the value
   is not announced twice. */
.calc__range{
  flex:1 0 100%;
  -webkit-appearance:none;appearance:none;
  height:16px;background:transparent;cursor:ew-resize;margin:0;
}
.calc__range::-webkit-slider-runnable-track{
  height:2px;background:rgba(255,255,255,.14);border-radius:99px;
}
.calc__range::-moz-range-track{height:2px;background:rgba(255,255,255,.14);border-radius:99px}
.calc__range::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:11px;height:11px;margin-top:-4.5px;border-radius:99px;
  background:var(--sig);border:0;
  box-shadow:0 0 0 3px rgba(47,224,126,.14),0 0 14px var(--sig-glow);
  transition:box-shadow .3s;
}
.calc__range::-moz-range-thumb{
  width:11px;height:11px;border-radius:99px;background:var(--sig);border:0;
  box-shadow:0 0 0 3px rgba(47,224,126,.14),0 0 14px var(--sig-glow);
}
.calc__range:hover::-webkit-slider-thumb,
.calc__range:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 5px rgba(47,224,126,.2),0 0 18px var(--sig-glow)}

/* ── readout panel — the HUD chip, grown up ── */
.calc__panel{
  position:sticky;top:calc(var(--nav-h) - 26px);
  padding:clamp(24px,2.4vw,36px);
  background:var(--sig-panel);
  border:1px solid var(--sig-line);
  border-radius:var(--r);
  -webkit-backdrop-filter:blur(10px) saturate(130%);backdrop-filter:blur(10px) saturate(130%);
  box-shadow:0 30px 90px -40px rgba(0,0,0,.9),inset 0 1px 0 rgba(255,255,255,.06);
}
.calc__panel::before,.calc__panel::after{
  content:'';position:absolute;width:10px;height:10px;
  border:1px solid var(--sig);opacity:.85;pointer-events:none;
}
.calc__panel::before{top:-1px;left:-1px;border-right:0;border-bottom:0}
.calc__panel::after{bottom:-1px;right:-1px;border-left:0;border-top:0}

.calc__outHead{
  display:flex;align-items:center;gap:.7rem;
  font-size:.64rem;letter-spacing:.22em;text-transform:uppercase;color:var(--sig);
  margin-bottom:1.6rem;
}
.calc__outHead i{
  width:22px;height:1px;background:var(--sig);box-shadow:0 0 10px var(--sig-glow);flex:none;
}

.calc__big+.calc__big{margin-top:1.4rem}
.calc__big b{
  display:block;
  font-size:clamp(2.1rem,4vw,3.1rem);font-weight:500;line-height:1;
  letter-spacing:-.03em;color:var(--sig);
  font-variant-numeric:tabular-nums;
}
.calc__big--alt b{color:var(--paper)}
.calc__big span{
  display:block;margin-top:.5rem;
  font-size:.78rem;line-height:1.5;color:var(--con-200);max-width:26ch;
}

.calc__rows{margin-top:1.8rem;border-top:1px solid rgba(255,255,255,.12);font-size:.74rem}
.calc__rows div{
  display:flex;align-items:baseline;justify-content:space-between;gap:1rem;
  padding:.62rem 0;border-bottom:1px solid rgba(255,255,255,.07);
}
.calc__rows dt{color:var(--con-200);letter-spacing:.04em}
.calc__rows dd{color:var(--paper);font-variant-numeric:tabular-nums}
.calc__tot{border-bottom:0!important}
.calc__tot dt{color:var(--sig)!important;text-transform:uppercase;letter-spacing:.16em;font-size:.62rem}
.calc__tot dd{color:var(--sig)!important;font-size:.95rem}

.calc__go{margin-top:1.7rem;width:100%}
.calc__disc{
  margin-top:1.1rem;
  font-size:.68rem;line-height:1.6;color:var(--con-300);
}

/* ── the arithmetic, in the open ── */
.calc__how{margin-top:clamp(38px,4vw,60px);border-top:1px solid rgba(255,255,255,.1)}
.calc__how summary{
  padding:1.15rem 0;cursor:pointer;list-style:none;
  display:flex;align-items:center;gap:.7rem;
  font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--con-200);
  transition:color .3s;
}
.calc__how summary::-webkit-details-marker{display:none}
.calc__how summary::before{
  content:'';width:9px;height:9px;flex:none;
  border-left:1.5px solid var(--sig);border-bottom:1.5px solid var(--sig);
  transform:rotate(-45deg) translate(1px,-1px);
  transition:transform .35s var(--e-out);
}
.calc__how[open] summary::before{transform:rotate(135deg) translate(-2px,2px)}
.calc__how summary:hover{color:var(--sig)}
.calc__howBody{padding-bottom:1.6rem;display:grid;grid-template-columns:1.35fr 1fr;gap:clamp(20px,2.6vw,48px)}
.calc__howBody ol{counter-reset:f;font-size:.72rem;line-height:1.7;color:var(--con-300)}
.calc__howBody li{
  position:relative;padding:.42rem 0 .42rem 2.2rem;
  border-bottom:1px solid rgba(255,255,255,.06);
}
.calc__howBody li::before{
  counter-increment:f;content:counter(f,decimal-leading-zero);
  position:absolute;left:0;top:.42rem;color:var(--sig);opacity:.75;
}
.calc__howBody li span{color:var(--paper)}
.calc__howBody li i{font-style:normal;color:var(--con-400)}
.calc__howBody>p{font-size:.82rem;line-height:1.7;color:var(--con-300)}

/* currency switch */
.calc__cur{display:flex;gap:1px;background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.12);border-radius:var(--r)}
.calc__cur button{
  padding:.34rem .72rem;
  background:var(--ink-000);border:0;cursor:pointer;
  font-family:var(--f-mono);font-size:.72rem;color:var(--con-300);
  transition:color .3s,background .3s;
}
.calc__cur button:hover{color:var(--paper)}
.calc__cur button.is-on{color:var(--ink-000);background:var(--sig)}

/* the figures, carried to the enquiry form */
.cta__attach{
  margin-top:2.4rem;width:min(560px,100%);
  padding:1rem 1.2rem;
  background:rgba(47,224,126,.07);
  border:1px solid var(--sig-line);border-radius:var(--r);
  text-align:left;
}
.cta__attach p{font-size:.72rem;line-height:1.7;color:var(--con-200);letter-spacing:.03em}
.cta__attach b{display:block;color:var(--sig);font-weight:500;margin-bottom:.3rem}
.cta__attachX{
  margin-top:.6rem;padding:0;background:none;border:0;cursor:pointer;
  font-size:.64rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--con-300);text-decoration:underline;text-underline-offset:3px;
  transition:color .3s;
}
.cta__attachX:hover{color:var(--sig)}
/* ── 13. CTA ───────────────────────────────────────────────── */
.cta{
  position:relative;z-index:3;overflow:hidden;
  padding:clamp(110px,15vw,200px) 0;
  border-top:1px solid rgba(255,255,255,.06);
  background:var(--ink-000);
  text-align:center;
}
.cta__bg{position:absolute;inset:0;z-index:0}
/* a canvas now, not a video — it draws its own scale, so the 1.08 push the
   clip needed to hide its letterboxing would only crop the render */
.cta__video{display:block;width:100%;height:100%;opacity:.34}
.cta__bg::after{
  content:'';position:absolute;inset:0;
  background:
    radial-gradient(70% 60% at 50% 50%,transparent,rgba(5,7,6,.92) 78%),
    linear-gradient(to bottom,rgba(5,7,6,.8),rgba(5,7,6,.5) 40%,rgba(5,7,6,.95));
}
.cta__inner{position:relative;z-index:2;display:flex;flex-direction:column;align-items:center}
.cta .display{font-size:clamp(2.3rem,6vw,5rem)}
.cta .lede{max-width:44ch;text-align:center}
.cta .eyebrow{justify-content:center}

.cta__form{
  margin-top:2.8rem;
  display:flex;flex-direction:column;gap:.6rem;
  width:min(560px,100%);
}
.cta__row{display:flex;gap:.6rem;flex-wrap:wrap;justify-content:center;width:100%}
/* the optional pair sits quieter than the email line — it must not read as
   two more things standing between someone and getting in touch */
.cta__row--more input{flex:1 1 180px;padding-block:.85rem;font-size:.76rem;background:rgba(255,255,255,.025)}
.cta__row--more input::placeholder{color:var(--con-300)}
.cta__form input{
  flex:1 1 260px;
  padding:1.05rem 1.25rem;
  background:rgba(255,255,255,.04);
  border:1px solid rgba(255,255,255,.16);
  border-radius:var(--r);
  color:var(--paper);
  font-family:var(--f-mono);font-size:.82rem;letter-spacing:.03em;
  transition:border-color .35s,background .35s,box-shadow .35s;
}
.cta__form input::placeholder{color:var(--con-300)}
.cta__form input:focus{
  outline:none;border-color:var(--sig);background:rgba(47,224,126,.06);
  box-shadow:0 0 0 3px rgba(47,224,126,.12);
}
.cta__form input.is-bad{border-color:#E0563F;box-shadow:0 0 0 3px rgba(224,86,63,.14)}
.cta__note{
  margin-top:1.1rem;min-height:1.2em;
  font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--sig);
  opacity:0;transform:translateY(4px);transition:opacity .4s,transform .4s var(--e-out);
}
.cta__note.is-on{opacity:1;transform:none}
.cta__note.is-bad{color:#E0563F}
.cta__note a{color:inherit;text-decoration:underline;text-underline-offset:3px}
.cta__note a:hover{color:var(--sig)}
.cta__alt{margin-top:.4rem}

/* ── 14. FOOTER ────────────────────────────────────────────── */
.foot{
  position:relative;z-index:3;
  padding:clamp(48px,5vw,70px) 0;
  background:var(--ink-050);border-top:1px solid rgba(255,255,255,.07);
}
.foot__inner{
  display:flex;align-items:center;justify-content:space-between;
  gap:2rem;flex-wrap:wrap;
}
.foot__brand{display:flex;align-items:center;gap:1.2rem;flex-wrap:wrap}
.foot__logo{height:clamp(44px,4.6vw,64px);width:auto}
.foot__line{font-size:.8rem;color:var(--con-400)}
.foot__nav{display:flex;gap:1.6rem}
.foot__nav a{font-family:var(--f-mono);font-size:.72rem;letter-spacing:.08em;color:var(--con-300);transition:color .3s}
.foot__nav a:hover{color:var(--sig)}
.foot__copy{font-size:.68rem;letter-spacing:.12em;color:var(--con-400)}

/* ── 15. ATMOSPHERE ────────────────────────────────────────── */
.grain{
  position:fixed;inset:0;z-index:500;pointer-events:none;
  opacity:.045;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grain 1.4s steps(1) infinite;
}
/* Re-randomise which slice of the noise tile is showing. Nothing translates,
   so the texture churns like film grain without shifting the image under it. */
@keyframes grain{
  0%  {background-position:0 0}
  20% {background-position:-37px 53px}
  40% {background-position:91px -29px}
  60% {background-position:-63px -71px}
  80% {background-position:47px 41px}
  100%{background-position:0 0}
}

/* custom scan-bracket cursor — a scanner sight rather than a pointer.
   Free, it is a small bracket frame trailing a precise dot. Over anything
   actionable it locks on: the brackets fly to that element's box, frame it,
   and a mono readout says what the click will do. The native pointer is
   hidden only once this is running (has-cursor), so nothing is lost if the
   script never gets there. */
html.has-cursor,html.has-cursor *{cursor:none !important}
/* while a selection box is being swept over the world, the words behind it
   must not highlight - a marquee that leaves the headline blue is a bug */
html.is-sweeping,html.is-sweeping *{user-select:none !important}

.cursor{
  /* above the screen viewer (700): the native pointer is hidden, so this
     has to be the topmost thing on the page */
  position:fixed;top:0;left:0;z-index:900;pointer-events:none;
  width:34px;height:34px;
  opacity:0;transition:opacity .35s;
  will-change:transform,width,height;
}
.cursor.is-on{opacity:1}
.cursor i{
  position:absolute;width:9px;height:9px;
  border:1.5px solid var(--sig);
  transition:width .3s var(--e-out),height .3s var(--e-out),
             border-color .2s,opacity .2s;
}
.cursor i:nth-of-type(1){top:0;left:0;border-right:0;border-bottom:0}
.cursor i:nth-of-type(2){top:0;right:0;border-left:0;border-bottom:0}
.cursor i:nth-of-type(3){bottom:0;left:0;border-right:0;border-top:0}
.cursor i:nth-of-type(4){bottom:0;right:0;border-left:0;border-top:0}
/* locked on: bigger corners, lit */
.cursor.is-hot i{width:15px;height:15px;box-shadow:0 0 12px var(--sig-glow)}
.cursor.is-down i{border-color:#EAFFF3}
.cursor.is-text i{opacity:0}

/* over a field the sight collapses to a caret */
.cursor__bar{
  position:absolute;left:50%;top:50%;
  width:1.5px;height:100%;margin-left:-.75px;
  transform:translateY(-50%);
  background:var(--sig);box-shadow:0 0 8px var(--sig-glow);
  opacity:0;transition:opacity .2s;
}
.cursor.is-text .cursor__bar{opacity:1;animation:blink 1.06s steps(2) infinite}

/* a click reads as a capture */
.cursor__ring{
  position:absolute;left:50%;top:50%;
  width:26px;height:26px;margin:-13px 0 0 -13px;
  border:1.5px solid var(--sig);border-radius:99px;
  opacity:0;
}
.cursor__ring.is-go{animation:ringPop .5s var(--e-out)}
@keyframes ringPop{
  0%  {opacity:.9;transform:scale(.45)}
  100%{opacity:0;transform:scale(2.4)}
}

/* what the click will do */
.cursor__tag{
  position:absolute;left:50%;top:100%;
  transform:translate(-50%,14px);
  padding:.28rem .5rem;
  white-space:nowrap;
  font-size:.55rem;letter-spacing:.24em;text-transform:uppercase;
  color:var(--ink-000);background:var(--sig);
  border-radius:2px;
  opacity:0;transition:opacity .22s var(--e-out),transform .34s var(--e-out);
}
.cursor.has-tag .cursor__tag{opacity:1;transform:translate(-50%,9px)}

/* the true pointer position, with none of the follow lag */
.cursor__dot{
  position:fixed;top:0;left:0;z-index:901;pointer-events:none;
  width:5px;height:5px;margin:-2.5px 0 0 -2.5px;
  border-radius:99px;background:var(--sig);
  box-shadow:0 0 10px var(--sig),0 0 22px var(--sig-glow);
  opacity:0;transition:opacity .3s;
  will-change:transform;
}
.cursor__dot.is-on{opacity:1}
.cursor__dot.is-text{opacity:0}

/* ── 16. REVEALS ───────────────────────────────────────────── */
[data-fx]{--d:calc(var(--i,0) * 80ms)}
[data-fx="up"]{
  opacity:0;transform:translateY(26px);
  transition:opacity .8s var(--e-out) var(--d),transform .8s var(--e-out) var(--d);
}
[data-fx="lines"] span{
  display:block;opacity:0;transform:translateY(.9em);
  transition:opacity .9s var(--e-out),transform .9s var(--e-out);
}
[data-fx="lines"] span:nth-child(2){transition-delay:.09s}
[data-fx="lines"] span:nth-child(3){transition-delay:.18s}
[data-fx].is-in{opacity:1;transform:none}
[data-fx="lines"].is-in span{opacity:1;transform:none}

/* ── 16b. PHASE SCAN REVEAL ───────────────────────
   Each phase reads like the scanner is reading it: the block flashes as the
   beam fires, a green bar sweeps top to bottom, and every line is uncovered
   — green first, settling to white — as the beam crosses it. The per-line
   delay is set by JS (--sd) from that line's own offset in the block, so the
   text genuinely follows the beam instead of just looking like it. */
.act__copy[data-scan]{position:relative}

/* the scan-fx replaces the generic reveal inside these blocks */
.act__copy[data-scan] [data-fx],
.act__copy[data-scan] [data-fx="lines"] span{opacity:1;transform:none;transition:none}

/* corner brackets — the same scan framing as the cursor */
.act__copy[data-scan]::before,
.act__copy[data-scan]::after{
  content:'';position:absolute;width:22px;height:22px;
  border:1.5px solid var(--sig-line);
  opacity:0;transition:opacity .45s var(--e-out),transform .7s var(--e-out);
  pointer-events:none;
}
.act__copy[data-scan]::before{top:-1.5rem;left:-1.7rem;border-right:0;border-bottom:0;transform:translate(10px,10px)}
.act__copy[data-scan]::after{bottom:-1.5rem;right:-1.7rem;border-left:0;border-top:0;transform:translate(-10px,-10px)}
.act__copy.is-scanning::before,
.act__copy.is-scanning::after{opacity:1;transform:none;animation:scanBracket 1.1s var(--e-out) both}
@keyframes scanBracket{
  0%  {border-color:var(--sig);box-shadow:0 0 20px var(--sig-glow)}
  40% {border-color:var(--sig);box-shadow:0 0 10px var(--sig-glow)}
  100%{border-color:var(--sig-line);box-shadow:none}
}

/* the block flashes once as the scanner fires */
.scanwash{
  position:absolute;left:-1.7rem;right:-1.7rem;top:-1.2rem;bottom:-1.2rem;
  z-index:2;pointer-events:none;opacity:0;
  background:radial-gradient(120% 90% at 50% 0%,rgba(47,224,126,.30),rgba(47,224,126,0) 70%);
  mix-blend-mode:screen;
}
.act__copy.is-scanning .scanwash{animation:scanWash .55s ease-out both}
@keyframes scanWash{0%{opacity:0}18%{opacity:1}100%{opacity:0}}

/* the beam: full height of the block, translated from above it to below */
.scanbeam{
  position:absolute;left:-1.7rem;right:-1.7rem;top:0;height:100%;
  z-index:3;pointer-events:none;opacity:0;
  transform:translateY(-100%);
  will-change:transform;
}
.is-scanning > .scanbeam{
  animation:scanSweep var(--sweep,1600ms) cubic-bezier(.45,.03,.25,1) forwards;
}
/* the trail the beam leaves behind it — tinted, with scanner line texture */
.scanbeam::before{
  content:'';position:absolute;left:0;right:0;bottom:0;height:min(260px,68%);
  background:
    repeating-linear-gradient(to bottom,
      rgba(47,224,126,.13) 0 1px,rgba(47,224,126,0) 1px 4px),
    linear-gradient(to bottom,
      rgba(47,224,126,0) 0%,
      rgba(47,224,126,.10) 45%,
      rgba(47,224,126,.26) 86%,
      rgba(146,220,150,.42) 100%);
  mix-blend-mode:screen;filter:blur(2px);
}
/* the reading line itself — white-hot core, green ends */
.scanbeam::after{
  content:'';position:absolute;left:0;right:0;bottom:0;height:2px;
  background:linear-gradient(90deg,
    transparent 0%,var(--sig) 8%,#EAFFF3 50%,var(--sig) 92%,transparent 100%);
  box-shadow:
    0 0 10px var(--sig),
    0 0 30px var(--sig-glow),
    0 0 70px var(--sig-glow);
}
@keyframes scanSweep{
  0%  {transform:translateY(-100%);opacity:0}
  5%  {opacity:1}
  90% {opacity:1}
  100%{transform:translateY(0);opacity:0}
}

/* every scanned line stays covered until the beam reaches it */
.act__copy[data-scan] .scan-t{
  clip-path:inset(-45% 0 101% 0);
  transform:translateY(12px);
  transition:clip-path .5s var(--e-out) var(--sd,0ms),
             transform .75s var(--e-out) var(--sd,0ms);
}
.act__copy.is-scanning .scan-t{
  clip-path:inset(-45% 0 -45% 0);
  transform:none;
  animation:scanFlash 1.15s var(--e-out) var(--sd,0ms) both;
}
/* once the sweep is over, drop the clip so hover glows aren't cut off */
.act__copy.scan-done .scan-t{clip-path:none;animation:none;transform:none}
/* the line arrives green and cools to its own colour (100% falls back to it) */
@keyframes scanFlash{
  0%  {color:var(--sig);text-shadow:0 0 24px var(--sig),0 0 64px var(--sig-glow);filter:brightness(1.5)}
  40% {color:var(--sig);text-shadow:0 0 14px var(--sig-glow);filter:brightness(1.16)}
  100%{filter:none}
}

@media (max-width:900px){
  .act__copy[data-scan]::before,.act__copy[data-scan]::after{display:none}
  .scanbeam,.scanwash{left:-1rem;right:-1rem}
}

/* ── 16c. SECTION HEAD SCAN ────────────────────────────────────
   The acts get the full sweep; every section head gets the same idea a
   tenth of the size — a green line crosses the head left to right and the
   eyebrow, heading and sub come out behind it. The timing is linear on
   purpose: each line's wipe duration (--sdur) is its own width as a
   fraction of the head's, so the uncovering edge tracks the beam exactly
   instead of drifting ahead of it. */
.sect__head[data-scan-head]{position:relative}
.sect__head[data-scan-head] [data-fx]{opacity:1;transform:none;transition:none}

.headbeam{
  position:absolute;top:-.7rem;bottom:-.7rem;left:0;width:100%;
  z-index:3;pointer-events:none;opacity:0;
  transform:translateX(-100%);will-change:transform;
}
.is-scanning > .headbeam{animation:headSweep var(--sweep,1000ms) linear forwards}
/* the trail, behind the line */
.headbeam::before{
  content:'';position:absolute;top:0;bottom:0;right:0;width:min(200px,45%);
  background:linear-gradient(to right,rgba(47,224,126,0),rgba(47,224,126,.20));
  mix-blend-mode:screen;filter:blur(2px);
}
.headbeam::after{
  content:'';position:absolute;top:0;bottom:0;right:0;width:1.5px;
  background:linear-gradient(to bottom,
    transparent 0%,var(--sig) 14%,#EAFFF3 50%,var(--sig) 86%,transparent 100%);
  box-shadow:0 0 10px var(--sig),0 0 30px var(--sig-glow);
}
@keyframes headSweep{
  0%  {transform:translateX(-100%);opacity:0}
  6%  {opacity:1}
  88% {opacity:1}
  100%{transform:translateX(0);opacity:0}
}

.sect__head[data-scan-head] .scanh{
  clip-path:inset(-35% 101% -35% -35%);
  transition:clip-path var(--sdur,1000ms) linear;
}
.sect__head.is-scanning .scanh{
  clip-path:inset(-35% -35% -35% -35%);
  animation:scanFlash .95s var(--e-out) both;
}
.sect__head.scan-done .scanh{clip-path:none;animation:none}

/* ── 16d. PRODUCT SCREEN BOOT ──────────────────────────────────
   The screenshots are screens of a scanner-driven system, so they arrive
   the way that system would draw them: the frame's corner brackets strike,
   and a plate of green wireframe — desaturating everything under it with a
   backdrop-filter — is wiped off to the right, resolving the real screen
   behind the beam. */
.shot[data-scan-shot]{transition:opacity .5s var(--e-out),transform .85s var(--e-out)}
.shot[data-scan-shot][data-fx]{opacity:1;transform:none}
.shot.scan-armed{opacity:0;transform:translateY(20px)}
.shot.scan-armed.is-scanning{opacity:1;transform:none}

.shot__veil{
  position:absolute;inset:0;z-index:2;
  overflow:hidden;border-radius:var(--r);
  pointer-events:none;opacity:0;
}
.shot.is-scanning .shot__veil{opacity:1}
.shot.scan-done .shot__veil{display:none}
.shot__veil b{
  position:absolute;inset:0;display:block;
  -webkit-backdrop-filter:grayscale(1) brightness(.42) contrast(1.15);
  backdrop-filter:grayscale(1) brightness(.42) contrast(1.15);
  background:
    repeating-linear-gradient(to right,rgba(47,224,126,.11) 0 1px,transparent 1px 44px),
    repeating-linear-gradient(to bottom,rgba(47,224,126,.11) 0 1px,transparent 1px 44px),
    linear-gradient(to right,rgba(8,136,58,.10),rgba(8,136,58,.24));
}
.shot.is-scanning .shot__veil b{
  animation:shotWipe var(--sweep,1150ms) cubic-bezier(.45,.03,.25,1) forwards;
}
.shot__veil b::before{
  content:'';position:absolute;top:0;bottom:0;left:0;width:2px;
  background:linear-gradient(to bottom,
    transparent 0%,var(--sig) 12%,#EAFFF3 50%,var(--sig) 88%,transparent 100%);
  box-shadow:0 0 12px var(--sig),0 0 34px var(--sig-glow);
}
@keyframes shotWipe{0%{transform:translateX(0)}100%{transform:translateX(101.5%)}}

/* the frame strikes green, then hands its corners back to :hover */
.shot.is-scanning .shot__frame{animation:shotEdge 1.5s var(--e-out) both}
.shot.is-scanning .shot__frame::before,
.shot.is-scanning .shot__frame::after{animation:shotBracket 1.5s var(--e-out) both}
.shot.scan-done .shot__frame,
.shot.scan-done .shot__frame::before,
.shot.scan-done .shot__frame::after{animation:none}
@keyframes shotEdge{
  0%  {border-color:var(--sig);box-shadow:0 0 0 1px var(--sig-glow),0 30px 80px -40px var(--sig-glow)}
  55% {border-color:var(--sig-line)}
  100%{box-shadow:none}
}
@keyframes shotBracket{0%{opacity:1}60%{opacity:1}100%{opacity:0}}

/* the caption reads out once the screen has resolved */
.shot.scan-armed .shot__cap{
  clip-path:inset(-35% 101% -35% -35%);
  transition:clip-path .55s var(--e-out) var(--sd,0ms);
}
.shot.is-scanning .shot__cap{
  clip-path:inset(-35% -35% -35% -35%);
  animation:scanFlash .9s var(--e-out) var(--sd,0ms) both;
}
.shot.scan-done .shot__cap{clip-path:none;animation:none}

/* ── 16e. GRIDS, STEPS, PANEL ──────────────────────────────────
   Three more reads for the same scanner. The card grids power up column by
   column as a beam crosses them; the approach steps draw their spine and
   light their markers in sequence; the model panel is read top to bottom and
   its figures roll up from zero. */

/* card grids ------------------------------------------------- */
.cards[data-scan-grid]{position:relative}
.cards[data-scan-grid] > .headbeam{top:0;bottom:0}
.cards[data-scan-grid] [data-fx]{opacity:1;transform:none;transition:none}

.cards[data-scan-grid] .card{transition:background .6s var(--e-out) var(--sd,0ms)}
.cards.grid-armed .card{background:var(--ink-000)}
.cards.is-scanning .card{background:var(--ink-050)}
.cards.scan-done .card{transition:background .5s var(--e-out)}

/* keyed to the JS-added class, never the attribute: if the script never
   runs, none of this is hidden in the first place */
.cards.grid-armed .card > *{
  clip-path:inset(-35% 101% -35% -35%);
  transition:clip-path var(--sdur,420ms) linear var(--sd,0ms);
}
.cards.is-scanning .card > *{clip-path:inset(-35% -35% -35% -35%)}
.cards.scan-done .card > *{clip-path:none;animation:none}

/* the cell edge strikes, and its number comes up like a boot readout */
.cards.is-scanning .card{animation:cardOn 1s var(--e-out) var(--sd,0ms) both}
.cards.scan-done .card{animation:none}
@keyframes cardOn{
  0%  {box-shadow:inset 1px 0 0 var(--sig),0 0 34px -12px var(--sig-glow)}
  60% {box-shadow:inset 1px 0 0 var(--sig-line)}
  100%{box-shadow:none}
}
.cards.is-scanning .card__n{animation:numOn .7s steps(1) var(--sd,0ms) both}
.cards.scan-done .card__n{animation:none}
@keyframes numOn{
  0%  {opacity:0}
  20% {opacity:1;text-shadow:0 0 14px var(--sig)}
  30% {opacity:.25}
  45% {opacity:1;text-shadow:0 0 10px var(--sig-glow)}
  55% {opacity:.5}
  70% {opacity:1}
  100%{opacity:1;text-shadow:none}
}

/* model panel ------------------------------------------------- */
.calc__panel[data-scan-panel]{position:sticky}
.calc__panel[data-scan-panel] > .scanbeam{left:0;right:0}
.calc__panel.is-scanning{animation:panelOn 1.4s var(--e-out) both}
.calc__panel.scan-done{animation:none}
@keyframes panelOn{
  0%  {border-color:var(--sig);box-shadow:0 0 0 1px var(--sig-glow),0 30px 90px -40px rgba(0,0,0,.9)}
  55% {border-color:var(--sig)}
  100%{box-shadow:0 30px 90px -40px rgba(0,0,0,.9),inset 0 1px 0 rgba(255,255,255,.06)}
}

/* ── 17. RESPONSIVE ────────────────────────────────────────── */
@media (max-width:1180px){
  /* the readout drops under the inputs before the columns get too narrow to read */
  .calc{grid-template-columns:1fr;gap:clamp(28px,4vw,44px)}
  .calc__panel{position:static}
  .calc__howBody{grid-template-columns:1fr}
  .cards,.cards--4{grid-template-columns:repeat(2,1fr)}
}

@media (max-width:900px){
  :root{--nav-h:86px}
  .nav.is-stuck{height:66px}
  .nav__brand img{height:clamp(34px,8vw,42px)}
  .nav.is-stuck .nav__brand img{height:clamp(30px,7vw,36px)}
  .foot__logo{height:clamp(38px,9vw,50px)}

  .rail{display:none}
  .cursor,.cursor__dot{display:none}
  .nav__cta{display:none}
  .nav__burger{display:flex}
  .nav__links{
    position:fixed;inset:0;
    flex-direction:column;justify-content:center;align-items:center;gap:1.8rem;
    background:rgba(5,7,6,.96);-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);
    opacity:0;visibility:hidden;transition:opacity .45s var(--e-out),visibility .45s;
  }
  .nav__links.is-open{opacity:1;visibility:visible}
  .nav__links a{font-size:1.4rem;font-family:var(--f-display);letter-spacing:-.01em}
  .nav__burger{z-index:2}

  .act{--vhs:38vh}
  .act__grid{
    grid-template-columns:1fr;
    align-content:center;
    padding-bottom:16vh;
  }
  /* acts 3 and 6 carry four HUD elements; tighten them so the stack
     stays inside the viewport on a phone */
  .act__hud{justify-self:start;width:min(300px,100%);gap:.45rem}
  .chip{padding:.55rem .8rem}
  .chip--big{padding:.75rem .9rem}
  .chip--list{padding:.7rem .85rem;gap:.4rem}
  .act__copy{max-width:none}
  /* site.js does not build the card-section worlds on a phone; without them
     the section scrim would only darken a plain ground, and the canvas would
     sit there unsized */
  .sect--world .sect__bg,.sect--world::after{display:none}
  /* The held beat dims the copy to step it back. On a desktop the words sit
     beside the picture and .38 reads as receding; on a phone the words ARE
     the screen, and .38 made them unreadable for the whole beat. */
  .act__stage.is-held .act__copy,
  .is-held #act-5 .act__copy{opacity:.72}
  /* The phone scrim used to be darkest at the bottom, from when the film
     kept its copy at the foot of the screen. The copy now sits in the upper
     middle, and the foot is where the acts put their instruments on a phone -
     act 03's counts, act 05's carton - so the dark band moves up to protect
     the words, and the foot opens back up. */
  .film__scrim{
    background:
      linear-gradient(to bottom,
        rgba(5,7,6,.74) 0%, rgba(5,7,6,.66) 20%, rgba(5,7,6,.82) 42%,
        rgba(5,7,6,.76) 66%, rgba(5,7,6,.26) 84%, rgba(5,7,6,.12) 100%);
  }
  .foot__inner{flex-direction:column;text-align:center}
}

@media (max-width:640px){
  .calc__field{flex-direction:column;align-items:stretch;gap:.7rem}
  .calc__field label{max-width:none}
  .calc__ctrl{width:100%;justify-content:flex-start}
  .calc__num{flex:1 1 auto;width:auto;text-align:left}
  .cards,.cards--4{grid-template-columns:1fr}
  .shots{grid-template-columns:1fr}
  .act{--vhs:32vh}
  .act__grid{gap:2rem}
  .chip--big b{font-size:1.6rem}
  .act__cta .btn{flex:1 1 100%}
  .foot__nav{flex-wrap:wrap;justify-content:center}
}

/* Short desktop viewports (13" laptops). The phase headline is by far the
   tallest element, so trim it and the stage padding rather than let the copy
   run past the fold. The design is untouched at 861px tall and above. */
@media (min-width:901px) and (max-height:860px){
  .act .display{font-size:clamp(2.2rem,4.4vw,4.2rem)}
  .act__grid{padding-top:calc(var(--nav-h) + 2vh);padding-bottom:8vh}
  .act .lede{margin-top:1.2rem}
  .ticks{margin-top:1.5rem;gap:.6rem}
  .act__cta{margin-top:1.8rem}
}

/* Short viewports: the phase copy and the film carry the story on their own.
   The HUD stack cannot fit beside them without being clipped. */
@media (max-width:900px) and (max-height:700px){
  .act__hud{display:none}
}
@media (max-height:520px) and (min-width:640px){
  .act__hud{display:none}
  .scrollcue{display:none}
}

/* ── 18. 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;
  }
  .grain{display:none}

  /* no pinning: each act becomes a plain section, its canvas filling the
     section instead of a pinned viewport. The renderer draws one settled
     frame here rather than running a loop. */
  .act{height:auto}
  .act__stage{position:relative;height:auto;min-height:100svh}
  .act__stage::after{
    content:'';position:absolute;inset:0;pointer-events:none;
    background:linear-gradient(100deg,rgba(5,7,6,.94),rgba(5,7,6,.6) 55%,rgba(5,7,6,.3));
  }
  .act__grid{z-index:2}

  .chip{opacity:1;transform:none;filter:none}
  [data-fx]{opacity:1;transform:none}
  [data-fx="lines"] span{opacity:1;transform:none}

  /* no sweep: the copy is simply there */
  .act__copy[data-scan] .scan-t{clip-path:none;animation:none;transition:none;transform:none}
  .sect__head[data-scan-head] .scanh,
  .shot[data-scan-shot] .shot__cap{clip-path:none;animation:none;transition:none}
  .shot.scan-armed{opacity:1;transform:none}
  .cards.grid-armed .card{background:var(--ink-050)}
  .cards.grid-armed .card > *{clip-path:none;transition:none}
  .cards.is-scanning .card,.cards.is-scanning .card__n,
  .calc__panel.is-scanning{animation:none}
  .scanbeam,.scanwash,.headbeam,.shot__veil{display:none}
  .act__copy[data-scan]::before,.act__copy[data-scan]::after{opacity:1;transform:none}
}

/* ── 18. SCREEN VIEWER ─────────────────────────────────────────
   The cursor promises "Inspect" over a product screen, so clicking one has
   to deliver: the screenshot opens full size, framed and read in by the same
   wipe the grid uses, with the five screens on the arrow keys. */
.lens{
  position:fixed;inset:0;z-index:700;
  display:flex;align-items:center;justify-content:center;
  padding:clamp(20px,5vh,64px) clamp(20px,6vw,110px);
  opacity:0;transition:opacity .38s var(--e-out);
}
.lens.is-on{opacity:1}
.lens[hidden]{display:none}
.lens__scrim{
  position:absolute;inset:0;
  background:rgba(3,5,4,.90);
  -webkit-backdrop-filter:blur(14px) saturate(120%);backdrop-filter:blur(14px) saturate(120%);
}
.lens__stage{
  position:relative;margin:0;
  width:min(1280px,100%);
  transform:translateY(14px) scale(.985);
  transition:transform .5s var(--e-out);
}
.lens.is-on .lens__stage{transform:none}

.lens__frame{
  position:relative;
  padding:clamp(8px,.8vw,12px);
  background:var(--ink-050);
  border:1px solid var(--sig-line);
  border-radius:var(--r);
  box-shadow:0 50px 140px -50px rgba(0,0,0,.95);
}
.lens__frame::before,.lens__frame::after{
  content:'';position:absolute;width:14px;height:14px;
  border:1px solid var(--sig);pointer-events:none;z-index:3;
}
.lens__frame::before{top:-1px;left:-1px;border-right:0;border-bottom:0}
.lens__frame::after{bottom:-1px;right:-1px;border-left:0;border-top:0}
.lens__frame img{
  display:block;width:100%;height:auto;
  max-height:calc(100vh - 210px);object-fit:contain;
  border-radius:1px;background:var(--ink-100);
}
/* the same plate the grid shots use, re-read on every open */
.lens__frame .shot__veil{opacity:0}
.lens__frame.is-scanning .shot__veil{opacity:1}
.lens__frame.is-scanning .shot__veil b{
  animation:shotWipe 1s cubic-bezier(.45,.03,.25,1) forwards;
}

.lens__cap{
  display:flex;align-items:baseline;gap:.9rem;flex-wrap:wrap;
  margin-top:1.1rem;
  font-size:.78rem;letter-spacing:.04em;color:var(--con-300);
}
.lens__cap b{
  flex:none;font-weight:500;color:var(--sig);
  font-size:.63rem;letter-spacing:.2em;text-transform:uppercase;
}
.lens__cap em{
  margin-left:auto;font-style:normal;
  font-size:.63rem;letter-spacing:.2em;color:var(--con-400,var(--con-300));
}

.lens__x{
  position:absolute;top:clamp(14px,2.6vh,30px);right:clamp(14px,2.6vw,34px);
  width:40px;height:40px;
  display:flex;align-items:center;justify-content:center;
  background:none;border:1px solid rgba(255,255,255,.16);border-radius:var(--r);
  transition:border-color .3s var(--e-out),background .3s var(--e-out);
}
.lens__x i{position:absolute;width:15px;height:1.5px;background:var(--paper)}
.lens__x i:nth-child(1){transform:rotate(45deg)}
.lens__x i:nth-child(2){transform:rotate(-45deg)}
.lens__x:hover{border-color:var(--sig);background:rgba(47,224,126,.10)}
.lens__x:hover i{background:var(--sig)}

.lens__nav{
  position:absolute;top:50%;transform:translateY(-50%);
  width:clamp(38px,4vw,54px);height:clamp(38px,4vw,54px);
  display:flex;align-items:center;justify-content:center;
  background:none;border:1px solid rgba(255,255,255,.16);border-radius:var(--r);
  transition:border-color .3s var(--e-out),background .3s var(--e-out);
}
.lens__nav--prev{left:clamp(8px,1.6vw,26px)}
.lens__nav--next{right:clamp(8px,1.6vw,26px)}
.lens__nav i{
  width:11px;height:11px;
  border-top:1.5px solid var(--paper);border-right:1.5px solid var(--paper);
}
.lens__nav--prev i{transform:rotate(-135deg);margin-left:3px}
.lens__nav--next i{transform:rotate(45deg);margin-right:3px}
.lens__nav:hover{border-color:var(--sig);background:rgba(47,224,126,.10)}
.lens__nav:hover i{border-color:var(--sig)}

/* ── 19. KEY HINT ──────────────────────────────────────────────
   Shown once, the first time someone scrolls into the film, then never
   again on this browser. */
.keyhint{
  position:fixed;left:clamp(14px,2vw,30px);bottom:clamp(14px,2.4vh,28px);z-index:115;
  display:flex;align-items:center;gap:.45rem;
  padding:.6rem .85rem;
  font-size:.6rem;letter-spacing:.14em;text-transform:uppercase;color:var(--con-200);
  background:rgba(8,12,10,.82);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  border:1px solid rgba(255,255,255,.10);border-radius:var(--r);
  opacity:0;transform:translateY(8px);pointer-events:none;
  transition:opacity .5s var(--e-out),transform .5s var(--e-out);
}
.keyhint.is-on{opacity:1;transform:none}
.keyhint b{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:17px;padding:.12rem .22rem;
  font-weight:500;color:var(--sig);
  border:1px solid var(--sig-line);border-radius:3px;
}
.keyhint em{width:1px;height:12px;margin:0 .35rem;background:rgba(255,255,255,.16)}

/* ── 20. PHASE TICKS ───────────────────────────────────────────
   The top bar is whole-page scroll, so each tick is placed at the phase's
   real document position rather than at an even sixth. */
.progress__tick{
  position:absolute;top:0;width:1px;height:100%;
  background:rgba(255,255,255,.22);
  transition:background .4s var(--e-out),box-shadow .4s var(--e-out);
}
.progress__tick.is-on{background:var(--sig);box-shadow:0 0 8px var(--sig-glow)}

/* ── 21. NAV PHASE READOUT ─────────────────────────────────────── */
.nav__phase{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  display:none;align-items:center;gap:.45rem;
  font-size:.58rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--con-200);
  opacity:0;transition:opacity .45s var(--e-out);
  pointer-events:none;white-space:nowrap;
}
.nav__phase i{width:14px;height:1px;background:var(--sig);box-shadow:0 0 8px var(--sig-glow)}
.nav__phase b{color:var(--sig);font-weight:500}
.nav__phase.is-on{opacity:1}

/* ── 22. SECTION EDGE ──────────────────────────────────────────
   A hairline drawn across the boundary as each section arrives, so the page
   below the film still feels assembled rather than stacked. */
.sectedge{
  position:absolute;top:-1px;left:0;right:0;height:1px;
  background:linear-gradient(90deg,var(--sig-core),var(--sig) 45%,var(--sig-bloom));
  box-shadow:0 0 12px var(--sig-glow);
  transform:scaleX(0);transform-origin:left;
  z-index:4;pointer-events:none;
}
.is-edged > .sectedge{transition:transform 1s var(--e-out),opacity .8s linear .9s}
.is-edged > .sectedge{transform:scaleX(1);opacity:.35}

/* ── 23. CARD HOVER SCAN ───────────────────────────────────────── */
.card::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(100deg,
    transparent 42%,rgba(47,224,126,.16) 50%,transparent 58%);
  mix-blend-mode:screen;opacity:0;
}
.card:hover::after{animation:cardSheen .85s var(--e-out)}
@keyframes cardSheen{
  0%  {opacity:1;transform:translateX(-100%)}
  100%{opacity:1;transform:translateX(100%)}
}

/* ── 24. TRANSMIT BAR ──────────────────────────────────────────── */
.cta__bar{
  position:relative;height:2px;margin-top:1.4rem;
  max-width:520px;
  background:rgba(255,255,255,.10);border-radius:99px;overflow:hidden;
  opacity:0;transition:opacity .35s var(--e-out);
}
.cta__bar.is-on{opacity:1}
.cta__bar i{
  display:block;height:100%;width:0;
  background:linear-gradient(90deg,var(--sig-core),var(--sig));
  box-shadow:0 0 14px var(--sig-glow);
  transition:width .5s var(--e-out);
}

/* ── 25. NEW PIECES: RESPONSIVE + REDUCED MOTION ───────────────── */
@media (max-width:900px){
  /* the rail is gone here, so the nav carries the phase instead */
  .nav__phase{display:flex}
  .keyhint{display:none}
  .lens{padding:16px}
  .lens__nav{width:40px;height:40px}
  .lens__frame img{max-height:calc(100vh - 190px)}
}
@media (min-width:901px){
  /* it would only duplicate the rail */
  .nav__phase{display:none !important}
}

@media (prefers-reduced-motion:reduce){
  .lens,.lens__stage,.lens__frame .shot__veil{transition:none}
  .lens__frame.is-scanning .shot__veil{opacity:0}
  .lens__frame.is-scanning .shot__veil b{animation:none}
  .card:hover::after{animation:none}
  .sectedge{transform:scaleX(1);opacity:.35}
  .is-edged > .sectedge{transition:none}
  .keyhint{transition:none}
}

/* ── 26. DOCUMENT PAGES ────────────────────────────────────────
   Long-form pages (privacy, and anything like it) reuse the site's shell
   with a prose column bolted on. No film, so the nav starts stuck. */
.page{background:var(--ink-050)}
.page__main{padding-top:calc(var(--nav-h) + clamp(40px,7vh,90px))}

.prose{max-width:68ch}
.prose h1{margin-bottom:0}
.prose h2{
  font-family:var(--f-display);font-weight:500;
  font-size:1.18rem;letter-spacing:-.01em;color:var(--paper);
  margin:clamp(34px,4vw,52px) 0 .9rem;
  padding-top:1.4rem;border-top:1px solid rgba(255,255,255,.10);
}
.prose p{color:var(--con-200);line-height:1.75;margin-bottom:1rem;max-width:64ch}
.prose .sub{margin-bottom:.5rem}
.prose .ticks{margin:1.1rem 0 1.4rem}
.prose .ticks li{font-size:.95rem;line-height:1.7}
.prose b{color:var(--paper);font-weight:500}
.prose a{color:var(--sig);text-decoration:underline;text-underline-offset:3px}
.prose a:hover{color:var(--sig-bloom)}
.prose__back{margin-top:clamp(38px,5vw,64px)}
.prose__back a{text-decoration:none}
.cta__privacy{
  margin-top:1.15rem;max-width:52ch;
  font-size:.72rem;line-height:1.75;letter-spacing:.02em;
  color:var(--con-300);
}
.cta__privacy a{color:var(--sig);text-decoration:underline;text-underline-offset:3px}
.cta__privacy a:hover{color:var(--sig-bloom)}

/* ── PHONE FIXES (2026-09-15) ─────────────────────────────────── */
/* Once the email and the button can no longer share a line, the button
   wrapped beneath the email and landed BETWEEN it and the optional fields -
   send before you had seen them. Dissolve the two rows into the form's own
   column so the button comes last. Inputs lose their row flex-basis, which in
   a column would be read as a 260px height. */
@media (max-width:560px){
  .cta__form .cta__row{display:contents}
  .cta__form input{flex:none;width:100%}
  .cta__form #email{order:1}
  .cta__form #company{order:2}
  .cta__form #volume{order:3}
  .cta__form button[type=submit]{order:4;width:100%;justify-content:center}
}
/* Below 900px the acts put their world under the buttons, and a transparent
   ghost button let the plan's labels and glow run straight through its text
   (act 06, and the hero's second button). A dark ground keeps it a button. */
@media (max-width:900px){
  .act .btn--ghost{--bg:rgba(5,7,6,.78);background:var(--bg)}
}
