/* NEWPOINT — reskin of Airview. Serif display + mono slate, hairline rules, red as the only accent. */
:root{
  --black:#000; --near:#070707; --ink:#0b0b0b;
  --g1:#3a3a3a; --g2:#6f6f6f; --g3:#9a9a9a; --e6:#E6E6E6;
  --red:#9E2828;
  --blue:#275F9F;
  --green:#2FA75A;
  --line:rgba(255,255,255,.13);
  --display:"Archivo",system-ui,sans-serif;
  --sans:"Archivo",system-ui,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,monospace;
  --pad:clamp(18px,4vw,60px);
  --maxw:1720px;
}
*{margin:0;padding:0;box-sizing:border-box}
/* overflow-x must be set on BOTH html and body. iOS Safari does not reliably
   honour it on body alone — desktop Chrome does, which is why a resized
   laptop window never reproduced the founder's horizontal scroll. */
html{scroll-behavior:smooth;overflow-x:hidden}
body{background:var(--black);color:var(--e6);font-family:var(--sans);font-weight:350;font-variation-settings:"wdth" 100;-webkit-font-smoothing:antialiased;overflow-x:hidden}
a{color:inherit;text-decoration:none}
img{display:block;max-width:100%}
/* Native <button> carries its own background and chrome in many engines —
   WebKit in-app browsers (Facebook's, Instagram's) especially, where an
   unset background renders as white-on-white. Every button in this file
   defines its own treatment, so normalise them all to a clean baseline;
   variants that want a background (.btn--fill, .lb__opt) set it below. */
button{appearance:none;-webkit-appearance:none;background:transparent;border:0;color:inherit;font:inherit;cursor:pointer}
::selection{background:var(--red);color:#fff}

.slate{font-family:var(--mono);font-size:11px;font-weight:400;letter-spacing:.12em;text-transform:uppercase;color:var(--g3)}
.display{font-family:var(--display);font-weight:800;line-height:.94;letter-spacing:-.03em}
.it{font-style:normal;font-weight:350;letter-spacing:-.02em;color:var(--e6)}
.mark{display:inline-block;width:1em;height:1em;vertical-align:middle;fill:var(--red)}
.mark--r{transform:rotate(90deg)}

/* ── nav ───────────────────────────────────────────────── */
/* `transform` is transitioned so the footer hand-off in newpoint.js eases
   rather than tracking every scroll event verbatim. .is-away is set once the
   nav is fully translated off-screen — it is already out of the viewport by
   then, but this guarantees it can never intercept a footer click. */
.nav{position:fixed;top:0;left:0;right:0;z-index:100;display:flex;align-items:baseline;justify-content:space-between;padding:20px var(--pad);transition:background .4s,padding .35s,border-color .4s,transform .35s;border-bottom:1px solid transparent}
.nav.is-away{pointer-events:none}
/* Nav legibility scrim. .hero__scrim's stops are percentages of .hero, which is
   100vh — but the nav is a CONSTANT 99px tall (measured), so how much cover it
   gets moves with viewport height. Worse, object-fit:cover crops a wide/short
   viewport to a brighter part of the footage: measured against the brightest
   real hero frame, the background behind the links went from rgb(28) at
   1440x900 to rgb(119) at 1512x700 — 6.06:1 contrast down to 1.57:1.
   This is sized in FIXED PIXELS so its cover no longer depends on hero height.
   It is deliberately separate from .hero__scrim, which is left untouched.
   z-index:-1 keeps it behind the nav's own links; it fades out once .solid
   supplies a real background, so it never doubles up while scrolled. */
.nav::before{content:"";position:absolute;top:0;left:0;right:0;height:130px;pointer-events:none;z-index:-1;transition:opacity .4s;background:linear-gradient(180deg,rgba(0,0,0,.66) 0%,rgba(0,0,0,.60) 46%,rgba(0,0,0,.34) 72%,rgba(0,0,0,0) 100%)}
.nav.solid::before{opacity:0}
.nav.solid{background:rgba(7,7,7,.9);backdrop-filter:blur(12px);padding:13px var(--pad);border-bottom:1px solid var(--line)}
/* Wordmark plus a quiet local-first signal. Deliberately small and low
   contrast — it sits under the logo without competing with it. */
.nav__logo{display:flex;flex-direction:column;align-items:flex-start;gap:3px}
.nav__logo img{height:clamp(36px,3.4vw,44px);width:auto;display:block;transform:translateY(5.5%)}
/* font-size here is only the pre-JS default — newpoint.js measures the logo
   and rewrites it so this line stays exactly as wide as the wordmark across
   the whole responsive range (the logo's width is not fixed: height:clamp
   plus width:auto). If JS never runs, this static size is the graceful
   fallback. letter-spacing is in em so it scales with the computed size;
   the .22 value is mirrored in newpoint.js as NAV_TRACK — keep them in sync. */
/* Literal rather than var(--g2): this line sits halfway between --g2 and
   white, and --g2 has 13 other consumers that must stay at the darker shade. */
.nav__place{font-family:var(--mono);font-size:9.5px;font-weight:400;letter-spacing:.22em;text-transform:uppercase;color:#B7B7B7;line-height:1;white-space:nowrap}
.nav__links{display:flex;gap:30px;align-items:baseline;font-family:var(--mono);font-size:11.5px;letter-spacing:.08em;text-transform:uppercase}
.nav__links a{color:var(--g3);transition:color .25s}
.nav__links a:hover{color:var(--e6)}
.nav__cta{display:flex;align-items:baseline;gap:8px;font-family:var(--mono);font-size:11.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--e6)}
.nav__cta .mark{width:8px;height:10px;transition:transform .3s;align-self:center}
.nav__cta:hover .mark{transform:rotate(90deg) translateY(-4px)}
@media(max-width:820px){.nav__links{display:none}}

/* ── hero ──────────────────────────────────────────────── */
.hero{position:relative;height:100vh;min-height:520px;overflow:hidden}
.hero__media{position:absolute;inset:0;z-index:0}
.hero__media image-slot{width:100%;height:100%}
.hero__media .kb{position:absolute;inset:0}
.hero__scrim{position:absolute;inset:0;z-index:1;pointer-events:none;background:linear-gradient(180deg,rgba(0,0,0,.6) 0%,rgba(0,0,0,.2) 20%,rgba(0,0,0,.06) 40%,rgba(0,0,0,.34) 70%,rgba(0,0,0,.72) 100%)}
.hero__dim{position:absolute;inset:0;z-index:2;background:#000;opacity:0;pointer-events:none;will-change:opacity}
.hero__grain{position:absolute;inset:0;z-index:2;pointer-events:none;opacity:.055;mix-blend-mode:screen}
.hero__inner{position:absolute;left:0;right:0;bottom:0;z-index:3;padding:0 var(--pad) clamp(30px,6vh,64px);display:grid;grid-template-columns:1fr auto;align-items:end;gap:36px}
.hero__h1{font-family:var(--display);font-weight:800;font-size:clamp(1.6rem,5.6vw,5.75rem);line-height:1.09;letter-spacing:-.035em;max-width:18ch;text-wrap:nowrap}
.hero__aside{display:flex;flex-direction:column;gap:16px;align-items:flex-end;text-align:right}
.hero__acts{display:flex;gap:12px;flex-wrap:wrap;margin-top:clamp(22px,3.4vh,38px)}
.btn{appearance:none;-webkit-appearance:none;background:transparent;display:inline-flex;align-items:center;gap:10px;font-family:var(--mono);font-size:12.5px;letter-spacing:.1em;text-transform:uppercase;padding:14px 24px;transition:background .3s,border-color .3s,color .3s}
.btn .mark{width:9px;height:11px;fill:currentColor}
.btn--fill{background:var(--red);color:#fff;border:1px solid var(--red)}
.btn--fill:hover{background:#b83030;border-color:#b83030;color:#fff}
.btn--ghost{border:1px solid rgba(255,255,255,.34);color:var(--e6)}
.btn--ghost:hover{border-color:#fff;background:rgba(255,255,255,.07)}
/* .hero__view removed with CPO-0015 — "Selected work" is now one of the two
   hero actions in .hero__acts and uses the shared .btn treatment instead. */
@media(max-width:760px){.hero__inner{grid-template-columns:1fr}.hero__aside{align-items:flex-start;text-align:left}}
@media(max-height:640px){.hero__h1{font-size:clamp(2.2rem,6vw,3.4rem)}.hero__acts{margin-top:16px}.hero__inner{padding-bottom:24px}}

/* ── section frame ─────────────────────────────────────── */
.sec{position:relative;padding:clamp(70px,11vh,136px) var(--pad) clamp(40px,7vh,88px);max-width:var(--maxw);margin:0 auto}
.sec__head{display:flex;align-items:flex-end;justify-content:space-between;gap:28px;padding-bottom:22px;border-bottom:1px solid var(--line);margin-bottom:clamp(30px,5vh,56px)}
.sec__head h2{font-family:var(--display);font-weight:800;font-size:clamp(1.9rem,4.2vw,4.2rem);line-height:.94;letter-spacing:-.03em}
.sec__idx{font-family:var(--mono);font-size:11px;letter-spacing:.1em;color:var(--g2);text-transform:uppercase;padding-bottom:8px;white-space:nowrap}
/* The section head is a flex row of <h2> + a nowrap index label. On phone
   widths their combined min-content width exceeds the viewport, which is
   the actual source of the horizontal overflow — body{overflow-x:hidden}
   was hiding the scrollbar without removing the cause. Let the row wrap
   and the label break; the side-by-side layout is kept above 600px. */
@media(max-width:600px){
  .sec__head{flex-wrap:wrap;align-items:flex-start;gap:8px}
  .sec__idx{white-space:normal;padding-bottom:0}
}

/* ── intro ─────────────────────────────────────────────── */
.intro{max-width:var(--maxw);margin:0 auto;padding:clamp(64px,11vh,132px) var(--pad);border-bottom:1px solid var(--line);display:flex;justify-content:center}
.intro p{font-family:var(--sans);font-weight:350;font-size:clamp(1.15rem,1.75vw,1.65rem);line-height:1.5;letter-spacing:-.015em;color:var(--e6);max-width:44ch;text-align:center;text-wrap:pretty}
.intro p em{font-style:normal;font-weight:600;color:var(--e6)}

/* ── capabilities ──────────────────────────────────────── */
.caps{border-top:1px solid transparent}
.cap{display:grid;grid-template-columns:auto 1fr;gap:clamp(16px,3vw,54px);padding:clamp(26px,3.6vh,44px) 0;border-bottom:1px solid var(--line);align-items:start}
.caps .cap:first-child{border-top:0}
.cap__no{font-family:var(--mono);font-size:12px;color:var(--g2);letter-spacing:.08em;padding-top:.5em}
.cap__body h3{font-family:var(--display);font-weight:800;font-size:clamp(1.35rem,2.6vw,2.3rem);line-height:1.02;letter-spacing:-.03em;margin-bottom:13px}
.cap__body p{color:var(--g3);font-size:clamp(14px,1.1vw,16.5px);line-height:1.7;max-width:62ch}

/* ── work grid ─────────────────────────────────────────── */
.reels{display:grid;grid-template-columns:1fr;gap:clamp(9px,1.1vw,16px)}
@media(min-width:760px){.reels{grid-template-columns:1fr 1fr}}
.work{display:grid;grid-template-columns:repeat(12,1fr);gap:clamp(9px,1.1vw,16px);grid-auto-flow:dense}
.tile{position:relative;overflow:hidden;background:var(--ink);cursor:pointer}
.tile image-slot{width:100%;height:100%}
.tile .kb{position:absolute;inset:0;transition:transform 1.1s cubic-bezier(.2,.7,.2,1)}
.tile:hover .kb{transform:scale(1.045)}
.tile__scrim{position:absolute;inset:0;pointer-events:none;background:linear-gradient(180deg,transparent 44%,rgba(0,0,0,.84) 100%)}
.tile__meta{position:absolute;left:0;right:0;bottom:0;padding:clamp(13px,1.3vw,22px);z-index:2}
/* Role tag. Plain red text sat directly on tile photography that is often
   red-toned itself, which was unreadable. This is the site's own ::selection
   treatment (red fill, white text) made permanent. inline-flex so the box
   shrink-wraps the text — it must stay a tight tag and never extend across
   the photograph. */
.tile__meta .role{display:inline-flex;align-items:center;gap:6px;background:var(--red);color:#fff;font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;padding:3px 8px 4px;margin-bottom:8px}
.tile__meta .role .mark{width:7px;height:9px;fill:currentColor;flex:0 0 auto}
.tile__meta .ttl{font-family:var(--display);font-size:clamp(1rem,1.4vw,1.4rem);line-height:1.06;font-weight:700;letter-spacing:-.02em;color:var(--e6)}
.tile__meta .cl{font-family:var(--mono);font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--g2);margin-top:7px;opacity:0;transform:translateY(4px);transition:.4s}
.tile:hover .tile__meta .cl{opacity:1;transform:none}
/* .tile__dart removed with CPO-0015 — the hover-reveal corner arrow was
   unrequested and served no purpose. The lightbox picker's own .lb__optdart
   is a separate element and is intentionally left in place. */
.tile--reel{aspect-ratio:16/9}
.tile--a7{grid-column:span 7;aspect-ratio:1.88}
.tile--a5{grid-column:span 5;aspect-ratio:4/3}
.tile--a4{grid-column:span 4;aspect-ratio:4/3}
.tile--a6{grid-column:span 6;aspect-ratio:16/9}
@media(max-width:900px){.tile:not(.tile--reel){grid-column:span 12 !important;aspect-ratio:16/9 !important}}

/* ── sectors index ─────────────────────────────────────── */
.sectors-idx{max-width:var(--maxw);margin:0 auto;padding:0 var(--pad) clamp(56px,9vh,110px)}
.srow{position:relative;display:grid;grid-template-columns:auto 1fr;align-items:start;gap:clamp(16px,3vw,54px);padding:clamp(24px,3.4vh,42px) 0;border-top:1px solid var(--line);overflow:hidden}
.sectors-idx .srow:first-child{border-top:0}
.sectors-idx .srow:last-child{border-bottom:1px solid var(--line)}
.srow__no{font-family:var(--mono);font-size:12px;color:var(--g2);letter-spacing:.08em;padding-top:.55em}
.srow__ttl{font-family:var(--display);font-weight:800;font-size:clamp(1.4rem,3vw,2.9rem);line-height:1;letter-spacing:-.03em;margin-bottom:15px;transition:color .4s}
.srow__body p{color:var(--g3);font-size:clamp(14px,1.1vw,16.5px);line-height:1.7;max-width:62ch;margin-bottom:12px}
.srow__built{font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--g2);max-width:60ch}
.srow__peek{position:absolute;inset:0;z-index:-1;opacity:0;transition:opacity .5s}
.srow__peek image-slot{width:100%;height:100%}
.srow__peek::after{content:"";position:absolute;inset:0;background:rgba(0,0,0,.86)}
.srow:hover .srow__peek{opacity:1}
.srow:hover .srow__ttl{color:#fff}

/* ── credits ───────────────────────────────────────────── */
.credits{display:grid;grid-template-columns:repeat(12,1fr);gap:clamp(10px,1.2vw,18px)}
/* 7 credits = a full 4-up row + a full 3-up row — equal widths within each row, so no card is ever stretched */
.credits > *{grid-column:span 3}
.credits > :nth-child(n+5){grid-column:span 4}
.credit__poster{width:100%;aspect-ratio:2/3;object-fit:cover;background:#0e0e0e;margin-bottom:4px}
.credit{position:relative;background:var(--ink);border:1px solid var(--line);padding:clamp(16px,1.6vw,24px);display:flex;flex-direction:column;gap:10px;transition:border-color .35s,background .35s}
.credit__poster{display:block}
.credit:hover{border-color:rgba(255,255,255,.28);background:#0e0e0e}
.credit__body{display:contents}
.credit__role{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--red)}
.credit__ttl{font-family:var(--display);font-weight:700;font-size:clamp(1.05rem,1.35vw,1.3rem);line-height:1.1;letter-spacing:-.02em;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.credit__ttl .yr{font-family:var(--mono);font-size:11px;color:var(--g2);letter-spacing:.06em}
.credit__meta{font-family:var(--mono);font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--g2);line-height:1.5;margin-top:auto}
.credit__imdb{font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--g3);border-bottom:1px solid var(--line);align-self:flex-start;padding-bottom:3px;transition:color .3s,border-color .3s}
.credit:hover .credit__imdb{color:var(--e6);border-color:var(--red)}
/* narrow: full-width card, compact horizontal layout — must follow the base .credit rules to win the cascade */
@media(max-width:680px){
  .credits > *,.credits > :nth-child(n+5){grid-column:span 12}
  .credit{flex-direction:row;align-items:flex-start;gap:16px}
  .credit__poster{width:86px;flex:0 0 auto;margin-bottom:0}
  .credit__body{display:flex;flex-direction:column;gap:9px;min-width:0}
  .credit__meta{margin-top:0}
}

/* ── cta band ──────────────────────────────────────────── */
.cta{max-width:var(--maxw);margin:0 auto;padding:clamp(80px,13vh,170px) var(--pad)}
.cta h2{font-family:var(--display);font-weight:800;font-size:clamp(2rem,4.8vw,5rem);line-height:.96;letter-spacing:-.035em}
.cta__btn{display:inline-flex;align-items:center;gap:14px;margin-top:28px;font-family:var(--display);font-weight:700;letter-spacing:-.02em;font-size:clamp(1.15rem,2vw,1.75rem);border-bottom:1px solid var(--line);padding-bottom:6px;transition:border-color .3s}
.cta__btn:hover{border-color:var(--red)}
.cta__btn .mark{width:.42em;height:.52em}

/* ── showreel lightbox ─────────────────────────────────── */
.lb{position:fixed;inset:0;z-index:200;background:rgba(4,4,4,.94);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;padding:clamp(16px,4vw,56px);opacity:0;transition:opacity .26s}
.lb[hidden]{display:none}
.lb.is-open{opacity:1}
.lb__close{position:absolute;top:clamp(14px,2.4vw,26px);right:clamp(14px,2.4vw,26px);background:none;border:0;color:var(--g3);font-family:var(--mono);font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;cursor:pointer;padding:8px;transition:color .25s}
.lb__close:hover{color:var(--e6)}
.lb__inner{width:100%;max-width:1180px}
.lb__picklab{display:block;margin-bottom:clamp(14px,2vh,22px);color:var(--g2)}
.lb__opts{display:grid;grid-template-columns:1fr;gap:clamp(10px,1.4vw,18px)}
@media(min-width:720px){.lb__opts{grid-template-columns:1fr 1fr}}
.lb__opt{position:relative;overflow:hidden;background:var(--ink);border:1px solid var(--line);padding:0;cursor:pointer;aspect-ratio:16/9;transition:border-color .3s}
.lb__opt:hover{border-color:rgba(255,255,255,.4)}
.lb__opt img{width:100%;height:100%;object-fit:cover;transition:transform 1s cubic-bezier(.2,.7,.2,1)}
.lb__opt:hover img{transform:scale(1.04)}
.lb__opt::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,transparent 42%,rgba(0,0,0,.84) 100%)}
.lb__optmeta{position:absolute;left:0;bottom:0;z-index:2;padding:clamp(14px,1.5vw,22px);display:flex;flex-direction:column;gap:7px;text-align:left}
/* Same pill mechanism as .tile__meta .role (CPO-0015): solid red fill, white
   text, dart-prefixed — plain red text sat on the reel thumbnail had the same
   legibility problem here. Sized up a touch for the picker's larger scale.
   NOTE: .lb__optmeta is a COLUMN FLEX container, so inline-flex alone would
   still stretch this to full width — align-self:flex-start is what actually
   shrink-wraps it to the text. It must never extend across the thumbnail. */
.lb__optmeta .r{display:inline-flex;align-self:flex-start;align-items:center;gap:7px;background:var(--red);color:#fff;font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;padding:4px 9px 5px}
.lb__optmeta .r .mark{width:8px;height:10px;fill:currentColor;flex:0 0 auto}
.lb__optmeta .t{font-family:var(--display);font-weight:800;font-size:clamp(1.3rem,2.2vw,2rem);line-height:1;letter-spacing:-.03em;color:var(--e6)}
.lb__optdart{position:absolute;top:clamp(14px,1.5vw,22px);right:clamp(14px,1.5vw,22px);z-index:2;opacity:0;transition:opacity .3s}
.lb__opt:hover .lb__optdart{opacity:1}
.lb__optdart .mark{width:15px;height:18px}
.lb__stage{width:100%;position:relative}
/* max-width guards against the aspect-ratio/max-height pair ever resolving
   to a box wider than the viewport on tall, narrow screens. */
.lb__video{width:100%;max-width:100%;max-height:78vh;aspect-ratio:16/9;background:#000;display:block}
.lb__bar{display:flex;align-items:center;justify-content:space-between;gap:18px;margin-top:14px}
.lb__back{background:none;border:0;color:var(--g3);font-family:var(--mono);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;cursor:pointer;padding:6px 0;border-bottom:1px solid var(--line);transition:color .25s,border-color .25s}
.lb__back:hover{color:var(--e6);border-color:var(--red)}

/* ── fullscreen playback ────────────────────────────────────────────
   Native fullscreen is requested in JS and is what makes landscape
   rotation behave. This CSS state is the fallback for engines that
   refuse or lack the Fullscreen API (iOS in-app webviews especially):
   it drops the framing padding and the 78vh / 16:9 caps so the video
   fills the viewport in whatever shape the device actually is. */
.lb.is-playing{padding:0}
.lb.is-playing .lb__inner{max-width:none;width:100%;height:100%;display:flex;flex-direction:column}
.lb.is-playing .lb__stage{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
.lb.is-playing .lb__video{flex:1 1 auto;min-height:0;width:100%;height:auto;max-height:none;aspect-ratio:auto;object-fit:contain}
.lb.is-playing .lb__bar{flex:0 0 auto;margin:0;padding:10px clamp(12px,3vw,22px);background:rgba(0,0,0,.55)}
.lb.is-playing .lb__close{z-index:3;background:rgba(0,0,0,.5);border-radius:2px}

/* When the browser does grant native fullscreen, the stage is the root
   element — it must paint black edge to edge and let the video fill it. */
.lb__stage:fullscreen{background:#000;padding:0}
.lb__stage:fullscreen .lb__video{width:100%;height:100%;max-height:none;aspect-ratio:auto;object-fit:contain}
.lb__stage:fullscreen .lb__bar{display:none}
.lb__stage:-webkit-full-screen{background:#000;padding:0}
.lb__stage:-webkit-full-screen .lb__video{width:100%;height:100%;max-height:none;aspect-ratio:auto;object-fit:contain}
.lb__stage:-webkit-full-screen .lb__bar{display:none}

/* ── end card (shown when a showreel finishes) ─────────────────────── */
.lb__end{position:absolute;inset:0;z-index:4;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:clamp(16px,3vh,26px);background:rgba(4,4,4,.9);backdrop-filter:blur(6px);padding:clamp(16px,4vw,40px);text-align:center}
.lb__end[hidden]{display:none}
.lb__endlab{font-family:var(--mono);font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--g3)}
.lb__endttl{font-family:var(--display);font-weight:800;font-size:clamp(1.4rem,3.4vw,2.4rem);line-height:1.02;letter-spacing:-.03em;color:var(--e6);max-width:22ch}
.lb__endacts{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:clamp(10px,1.6vw,16px)}

/* ── enquiry lightbox + form ───────────────────────────── */
.cb{align-items:center;overflow:hidden}
/* Two separate problems, two fixes — both are needed.
   1. Classic scrollbars (Windows, Linux, macOS with "always show") take
      layout space: scrollbar-gutter:stable reserves the track up front so
      the text is never pushed under it when content passes 88vh.
   2. OVERLAY scrollbars (iOS, macOS default) are drawn ON TOP of content
      and occupy no layout space at all — scrollbar-gutter reserves nothing
      for them, so it cannot fix this case. That was the reported symptom
      on the founder's phone. The inline padding is what clears the text
      there, and it doubles as the fallback for engines with no gutter
      support. Keep the padding even though the gutter is declared. */
.cb__panel{width:100%;max-width:1240px;margin:auto;padding:clamp(20px,2.6vw,34px) clamp(14px,1.6vw,20px);max-height:88vh;overflow-y:auto;scrollbar-gutter:stable}
@supports not (scrollbar-gutter: stable){.cb__panel{padding-right:calc(clamp(14px,1.6vw,20px) + 16px)}}
.ct__head{border-bottom:1px solid var(--line);padding-bottom:clamp(20px,3vh,32px);margin-bottom:clamp(24px,3.6vh,40px)}
.ct__head h2{font-family:var(--display);font-weight:800;font-size:clamp(1.9rem,4.2vw,3.6rem);line-height:.96;letter-spacing:-.035em;margin-bottom:18px}
.ct__lede{color:var(--g3);font-size:clamp(13.5px,1.05vw,16px);line-height:1.65;max-width:60ch}
.ct__grid{display:grid;grid-template-columns:1fr;gap:clamp(32px,4vw,64px)}
@media(min-width:960px){.ct__grid{grid-template-columns:1.25fr .75fr}}
.ct__side{display:flex;flex-direction:column;gap:clamp(24px,3.4vh,36px)}
.ct__block .slate{display:block;margin-bottom:15px;color:#fff}
.ct__steps{list-style:none;display:flex;flex-direction:column;gap:12px}
.ct__steps li{display:grid;grid-template-columns:auto 1fr;gap:13px;align-items:baseline;border-top:1px solid var(--line);padding-top:12px}
.ct__steps .n{font-family:var(--mono);font-size:11px;color:var(--red);letter-spacing:.08em}
.ct__steps .t{color:var(--g3);font-size:14px;line-height:1.55}
.ct__note{color:var(--g3);font-size:14px;line-height:1.7;max-width:46ch}
.ct__facts{display:flex;flex-direction:column;gap:11px;font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--g2)}
.ct__facts .row{display:flex;justify-content:space-between;gap:18px;border-bottom:1px solid var(--line);padding-bottom:10px}
.ct__facts .row b{color:var(--e6);font-weight:400;text-align:right}
.footer__link{background:none;border:0;padding:0;font:inherit;font-family:var(--mono);letter-spacing:inherit;text-transform:inherit;cursor:pointer;-webkit-appearance:none;appearance:none}
.footer__link:hover{color:var(--e6)}.nav__cta{background:none;border:0;cursor:pointer}
.cta__btn{background:none;border:0;border-bottom:1px solid var(--line);cursor:pointer;text-align:left}


.ct__form{display:grid;grid-template-columns:1fr;gap:clamp(16px,2vw,24px)}
@media(min-width:640px){.ct__form{grid-template-columns:1fr 1fr}.fld--wide{grid-column:1/-1}}
.fld{display:flex;flex-direction:column;gap:9px;min-width:0}
.fld label{font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:#fff}
.fld label .opt{color:var(--g3);letter-spacing:.08em}
.fld input,.fld select,.fld textarea{width:100%;background:var(--ink);border:1px solid var(--line);color:var(--e6);font-family:var(--sans);font-weight:350;font-size:15px;padding:14px 15px;border-radius:0;transition:border-color .25s,background .25s;-webkit-appearance:none;appearance:none}
.fld textarea{resize:vertical;line-height:1.6;min-height:150px}
.fld select{background-image:linear-gradient(45deg,transparent 49%,var(--g2) 50%),linear-gradient(-45deg,transparent 49%,var(--g2) 50%);background-position:calc(100% - 20px) 50%,calc(100% - 14px) 50%;background-size:6px 6px;background-repeat:no-repeat;padding-right:44px}
.fld select option{background:#0e0e0e;color:var(--e6)}
.fld input:hover,.fld select:hover,.fld textarea:hover{border-color:rgba(255,255,255,.26)}
.fld input:focus,.fld select:focus,.fld textarea:focus{outline:none;border-color:var(--red);background:#0e0e0e}
.fld input[aria-invalid="true"],.fld select[aria-invalid="true"],.fld textarea[aria-invalid="true"]{border-color:var(--red);background:rgba(158,40,40,.09)}
.fld input::placeholder,.fld textarea::placeholder{color:var(--g2)}
.fld .hint{font-family:var(--mono);font-size:10.5px;letter-spacing:.06em;color:var(--g3)}
.fld--trap{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.ct__submit{grid-column:1/-1;display:flex;align-items:center;gap:20px;flex-wrap:wrap;margin-top:4px}
.ct__submit .btn{border:1px solid var(--red);cursor:pointer;font-family:var(--mono)}
.ct__submit .btn[disabled]{opacity:.55;cursor:default}
.ct__status{font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;line-height:1.5;max-width:42ch}
.ct__status.is-ok{color:var(--g3)}
.ct__status.is-err{color:#d8666f}


/* ── footer ────────────────────────────────────────────── */
.footer{border-top:1px solid var(--line);padding:32px var(--pad);max-width:var(--maxw);margin:0 auto;display:flex;align-items:baseline;justify-content:space-between;gap:20px;flex-wrap:wrap;font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--g2)}
/* The footer wordmark is the easter-egg trigger: press and hold. The bar below
   it is the only tell — it fills over the hold so the gesture never feels like
   nothing is happening, and springs back if released early. Nothing announces
   itself; the people who go looking will find it. */
.footer__logo{display:block;position:relative;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
.footer__logo img{height:34px;width:auto;display:block;transform:translateY(5.5%);-webkit-user-drag:none;user-drag:none;pointer-events:none}
.footer__logo::after{content:"";position:absolute;left:0;right:0;bottom:-6px;height:2px;background:var(--red);transform:scaleX(var(--hold,0));transform-origin:left center;transition:opacity .25s;opacity:var(--hold-vis,0);pointer-events:none}
@media(prefers-reduced-motion:reduce){.footer__logo::after{transition:none}}
/* CRT hint. A clue that the wordmark is holdable: every so often it blips to
   phosphor for a fraction of a second, and it sits in that state on hover.
   Pure CSS on purpose — the real shader lives in invaders.js, which must stay
   unloaded for anyone who never goes looking, so a hint cannot pull it in.

   Same tube as the game: an RGB triad every 3 DEVICE pixels, one phosphor per
   device pixel. Expressed in CSS px per dpr below so it lands on whole device
   pixels either way and cannot shimmer. Scan pitch is 6 device px — two triads,
   close to the game's 7 and, unlike it, exactly divisible by the grille. */
.footer__logo{--ph:1px;--scan:6px}
@media(min-resolution:2dppx){.footer__logo{--ph:.5px;--scan:3px}}
.footer__logo::before{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:2;
  /* The wordmark is nudged down by translateY(5.5%) (see .footer__logo img),
     so it hangs below this box. Mirror the nudge or the bottom sliver of the
     logo — the base of the roundel — stays unmasked and reads as a white
     edge under the phosphor. Same constant as the rule above, deliberately. */
  transform:translateY(5.5%);
  opacity:0;transition:opacity .10s ease;
  mix-blend-mode:multiply;
  background-image:
    repeating-linear-gradient(90deg,
      #ff5252 0 var(--ph),
      #52ff52 var(--ph) calc(var(--ph)*2),
      #5252ff calc(var(--ph)*2) calc(var(--ph)*3)),
    repeating-linear-gradient(180deg,
      #ffffff 0 calc(var(--scan) - 1px),
      #8a8a8a calc(var(--scan) - 1px) var(--scan));
  background-blend-mode:multiply;
}
/* Rollover only where a real pointer exists. On touch, :hover latches on tap
   and does not clear until you tap something else — press-and-hold on the
   wordmark left it stuck in the CRT state until a page reload. The blip is
   class-driven so it still works everywhere. */
@media(hover:hover) and (pointer:fine){.footer__logo:hover::before{opacity:1}}
/* The blip snaps on with no transition and decays out through the base one —
   a tube strikes instantly and the phosphor fades. An eased fade IN just reads
   as a cross-dissolve, and at 45ms of on-time it never even reaches full. */
.footer__logo.is-crt::before{opacity:1;transition:none}
@media(prefers-reduced-motion:reduce){.footer__logo::before{transition:none}}
/* Easter-egg screen. No housing, no bezel, no chrome of any kind — just the
   shaded picture on black, per the spec. Click the surround or press Esc. */
.np-crt{position:fixed;inset:0;z-index:9999;background:#000;display:flex;align-items:center;justify-content:center;opacity:1;transition:opacity .26s}
.np-crt canvas{cursor:none}
.np-crt canvas{display:block;image-rendering:pixelated;image-rendering:crisp-edges;touch-action:none}
/* Touch controls. Real, visible buttons — the previous invisible tap-zones
   gave a first-time player nothing to discover. Deliberately a DOM overlay
   sitting ON TOP of the canvas, never drawn into the 320x200 source and never
   put through the CRT pass: they are functional chrome, so they stay crisp
   while the game stays degraded. Shown only on a coarse pointer; on desktop
   the keyboard already works and these would be clutter.
   The band is reserved in JS (PAD_H) so the picture is fitted ABOVE it and
   the buttons can never cover the ship, bunkers or the invader rows. */
.np-crt--touch{padding-bottom:120px}
.np-pad{position:absolute;left:0;right:0;bottom:0;height:120px;display:flex;align-items:center;justify-content:space-between;padding:0 clamp(16px,6vw,44px);pointer-events:none;box-sizing:border-box}
.np-pad__move{display:flex;gap:clamp(14px,4vw,26px)}
/* Control styling follows the Droneroids reference rather than the site
   palette, so the two games' controls feel like the same family: 1px
   rgba(244,242,238,.3) hairline, rgba(8,8,8,.5) ground, flex-centred,
   uppercase letter-spaced labels. Square corners — no rounding. */
.np-btn{pointer-events:auto;touch-action:none;-webkit-tap-highlight-color:transparent;user-select:none;-webkit-user-select:none;
  display:flex;align-items:center;justify-content:center;
  border:1px solid rgba(244,242,238,.3);background:rgba(8,8,8,.5);border-radius:0;
  color:rgba(244,242,238,.85);
  font-family:var(--mono);font-size:11px;font-weight:400;letter-spacing:.28em;text-transform:uppercase;line-height:1;
  padding:0 0 0 .28em;                      /* recentre against the trailing letter-space */
  transition:background .12s,border-color .12s}
.np-btn--dir{width:72px;height:72px}
.np-btn--fire{width:108px;height:72px}
.np-btn.is-on{background:rgba(8,8,8,.85);border-color:rgba(244,242,238,.72);color:#fff}
/* The only way out besides Escape. Same Droneroids treatment as the pad
   buttons, deliberately outside the canvas so it takes no shader pass. */
.np-close{position:absolute;top:clamp(12px,2.4vw,26px);right:clamp(12px,2.4vw,26px);width:44px;height:44px;display:flex;align-items:center;justify-content:center;border:1px solid rgba(244,242,238,.3);background:rgba(8,8,8,.5);border-radius:0;color:rgba(244,242,238,.85);font-family:var(--mono);font-size:20px;line-height:1;cursor:pointer;-webkit-tap-highlight-color:transparent;user-select:none;-webkit-user-select:none;transition:background .12s,border-color .12s,color .12s}
.np-close:hover,.np-close:focus-visible{background:rgba(8,8,8,.85);border-color:rgba(244,242,238,.72);color:#fff}
@media(prefers-reduced-motion:reduce){.np-close{transition:none}}
@media(prefers-reduced-motion:reduce){.np-btn{transition:none}}
.footer__meta{display:flex;gap:26px;align-items:baseline}
.footer__meta a,.footer__meta .footer__link{color:var(--g2);transition:color .25s}
.footer__meta a:hover,.footer__meta .footer__link:hover{color:var(--e6)}

/* reveal */
.rise{opacity:0;transform:translateY(22px);transition:opacity .9s cubic-bezier(.2,.7,.2,1),transform .9s cubic-bezier(.2,.7,.2,1)}
.rise.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){.rise{opacity:1;transform:none}}
