/* intro.css — the four fly-ins as an OVERLAY on the real Home (intros-260912).
 * Nothing here styles Home. Everything is inside #intro, which /a/intro.js
 * injects and then removes. The engine is #intro[data-e="1|2|3|4"].
 * Ported from gb-flyin: index2/_v1 (engines 1,2), index2 (engine 3), and
 * gb-site-test's own index2.htm CRT wrapper (engine 4). Changed lines are
 * listed in INTROS-2026-09-12.md; the rules themselves are the originals. */

/* Home is painted but not shown until the overlay is up, so no frame of Home
 * leaks before the intro. opacity (not display/visibility) so every bbox the
 * engines measure — above all .brand img — is real from the first frame.
 * build.mjs's inline head script adds the class and carries a 2.5 s failsafe. */
html.intro-pending body { opacity: 0 }

/* CHANGED 260912c (Thom): the page's own "Skip to content" link must never be
 * visible during or after an intro. home.css parks a.skip at left:-9999px until
 * :focus, and the overlay used to hand focus to it on land, which put the pill
 * on screen over the wordmark. While the overlay exists the link is
 * visibility:hidden -- off screen AND out of the accessibility tree, so nothing
 * can focus it; intro.js drops html.intro-on at land and moves focus to #main
 * instead. A keyboard user Tabbing from the top of the landed page still gets
 * the skip link first, it just never appears unsolicited. */
html.intro-on a.skip { visibility: hidden }
/* #main takes the landing focus with tabindex=-1, and shows no focus ring for
 * it: the ring would be a second unsolicited artefact in the same corner. */
#main[tabindex="-1"]:focus, #main[tabindex="-1"]:focus-visible { outline: none }

#intro { position: fixed; inset: 0; z-index: 60; pointer-events: none }
#intro[data-done] { display: none }
/* wireframe.css's #moment contract, reproduced (wireframe.css is NOT loaded on
 * Home: it also styles a wireframe frame we do not want). */
#intro #moment { position: absolute; inset: 0; pointer-events: none }
#intro #moment[data-done] { display: none }
/* engine 4 only: crt.js imports frame.js, which mounts the wireframe into
 * #frame at module scope and later reads `#frame .wf-mark` for its flight
 * target. The frame is kept out of sight but laid out, and intro.js parks the
 * .wf-mark exactly on Home's real .brand img, so the CRT lands on the real
 * mark without crt.js being touched. */
#intro #frame { position: absolute; inset: 0; opacity: 0; pointer-events: none;
  overflow: hidden }
#intro #frame .wf-mark { position: absolute; margin: 0 }

/* ============ engines 1 + 2 — alt v1 (public/index2/_v1/index.html) ========= */
/* CHANGED 260912c (Thom): both engines now stand on a WHITE stage (--stage is
 * the blanket that dissolves to reveal Home).
 * CHANGED 260912d (Thom, off the 390 frames): --field is the layer the letters
 * are punched out of, and it is the ONLY difference between the two engines.
 * Engine 1 keeps alt v1's green field; engine 2 is the same fly-in on a white
 * one. Engine 2's solid-green no-footage wordmark from 260912c is deleted. */
#intro[data-e="1"] { --stage: #fff; --field: #65E782 }
#intro[data-e="2"] { --stage: #fff; --field: #fff }
/* CHANGED 260913e (Thom): engine 3 opens on engine 1's frame and then lifts off
 * the top, so it takes engine 1's two tokens verbatim rather than relying on the
 * var() fallbacks -- the rest frames are asserted identical to within nothing,
 * and a fallback is a second place for that to drift.
 * .i2-lift is added at the moment the lift starts, never at rest: promoting the
 * layer earlier would re-raster the very frame this engine has to match. */
#intro[data-e="3"] { --stage: #fff; --field: #65E782 }
#intro.i2-lift { will-change: transform }
#intro .i2-stage { position: absolute; inset: 0; overflow: hidden;
  pointer-events: none; z-index: 1 }
/* the blanket. Its own layer, so it can dissolve while the footage and the
 * flyer standing on it stay fully opaque and Home is revealed UNDERNEATH. */
#intro .i2-bg { position: absolute; inset: 0; background: var(--stage);
  will-change: opacity }
#intro .i2-scroll { position: absolute; inset: 0; overflow-y: auto; overflow-x: hidden;
  pointer-events: auto; z-index: 2; -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain; scrollbar-width: none }
#intro .i2-scroll::-webkit-scrollbar { display: none }
#intro .i2-run { width: 1px; height: calc(100vh + var(--run, 1200px)) }
#intro .i2-vidbox { position: absolute; left: 0; top: 0; width: 100%; height: 100%;
  transform-origin: 0 0; will-change: transform, clip-path; background: #383636 }
#intro .i2-vidbox video { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; background: #383636 }
#intro .i2-field { position: absolute; left: 0; top: 0; width: 100%; height: 100%;
  background: var(--field, #65E782); transform-origin: 0 0;
  will-change: transform, background-color }
html.i2-lock, html.i2-lock body { overflow: hidden }
#intro .i2-defs { position: absolute; width: 0; height: 0; overflow: hidden }
#intro .i2-ink { position: absolute; display: block; overflow: visible; pointer-events: none }
#intro .i2-ink path { opacity: 0 }
/* the real mark is the 2-colour stacked file: six dark letters, green underscore.
 * The flyer lands on it, so the flyer's ink is that same pair. */
#intro .i2-ink path { fill: #3D3435 }
#intro .i2-ink path:nth-child(7) { fill: #65E686 }
/* CHANGED 260912c: the .i2-patch masks are gone. They painted the stage colour
 * over Home's header, which was invisible while Home itself was opacity:0 and
 * would be a white box now that Home is revealed under the dissolving blanket.
 * Home's own mark is simply not painted until the flyer has landed on it --
 * engine 1 hands over when the overlay is removed (the two marks are identical),
 * engine 2 cross-fades over the last 10 % (its flyer is green, the mark is not).
 * These two rules are the only ones in this file that touch Home, and they are
 * scoped to html.i2-lock, which only engines 1 and 2 ever set. */
html.i2-lock .hdr .brand img { opacity: var(--mark-on, 0) }
html.i2-lock .hdr .brand img { transition: none }

/* home-lock-260913 (Thom): ONE instruction. The scroll_ cue and the SKIP pill are
 * replaced by a single skip_ button at the bottom centre — Inter Tight 13 px, paper
 * letters on the green field, the wordmark's green underscore. Static, not blinking:
 * the wordmark's underscore does not blink either. It is a real <button>, so it keeps
 * a 44 px tap target (padding, not a visible box) and a focus ring, while reading as
 * plain text. Its opacity is driven per-frame from JS on the blanket's own curve. */
#intro .i2-cue { position: absolute; left: 50%;
  bottom: max(24px, calc(env(safe-area-inset-bottom) + 24px));
  transform: translateX(-50%); display: inline-flex; align-items: center;
  min-height: 44px; padding: 0 14px; border: 0; background: transparent;
  font-family: "Inter Tight", system-ui, Helvetica Neue, Arial, sans-serif;
  font-weight: 400; font-size: 13px; letter-spacing: .08em; line-height: 1;
  color: #FBFAF8; cursor: pointer; pointer-events: auto; z-index: 4;
  transition: opacity .2s linear; -webkit-appearance: none; appearance: none }
#intro .i2-cue b { font-weight: 400; color: #65E686 }
#intro .i2-cue:focus-visible { outline: 2px solid #FBFAF8; outline-offset: 3px }
#intro .gb-skip { position: absolute; left: 50%;
  bottom: max(24px, env(safe-area-inset-bottom)); transform: translateX(-50%);
  min-height: 44px; padding: 0 18px; display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid rgba(255,255,255,.6); border-radius: 22px; background: #000; color: #fff;
  font-family: "GB Sans", Helvetica Neue, Arial, sans-serif; font-weight: 500;
  font-size: 13px; letter-spacing: .09em; text-transform: uppercase; cursor: pointer;
  pointer-events: auto; opacity: 1; transition: opacity .25s linear; z-index: 4 }
#intro .gb-skip:hover { opacity: 1 }
#intro .gb-skip:focus-visible { outline: 2px solid #fff; outline-offset: 3px; opacity: 1 }
#intro .i2-late .gb-skip, #intro .i2-late .i2-cue { opacity: 0 }

/* ================= engine 3 — alt v3 (public/index2/index.html) ============ */
#intro .stage { position: absolute; inset: 0; background: #fff; overflow: hidden }
#intro .defs { position: absolute; width: 0; height: 0; overflow: hidden }
#intro .letters { position: absolute; transform: scale(1.55); transform-origin: 50% 50%;
  clip-path: url(#gbletters); -webkit-clip-path: url(#gbletters);
  will-change: transform; backface-visibility: hidden }
#intro .letters video { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; background: #383636 }
#intro .ink { position: absolute; display: block; overflow: visible;
  fill: #383636; opacity: 0; pointer-events: none }
#intro .blind { position: absolute; inset: 0; background: #FFFFFF;
  display: flex; align-items: center; justify-content: center;
  transform: translateY(0); will-change: transform }

/* ============ engine 4 — the CRT wrapper, moved from public/index2.htm ===== */
/* Rules copied from that file unchanged except the #moment prefix becoming
   #intro #moment, and .crt-skip inheriting the shared .gb-skip pill. */
#intro[data-e="4"] #moment { background: #000 }
#intro .crt-cv { position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  background: #000; cursor: pointer; pointer-events: auto }
#intro .crt-lock { position: absolute; left: 0; top: 0; opacity: 0;
  transform-origin: 0 0; pointer-events: none }
#intro #moment.crossed .crt-lock { opacity: 1; transition: opacity .8s linear }
#intro #moment.white .crt-white { opacity: 1; transition: opacity 1s linear }
#intro .crt-lock img { position: absolute; inset: 0; width: 100%; height: 100%;
  display: block; opacity: 0 }
#intro .crt-lock img.on { opacity: 1 }
#intro .crt-white { position: absolute; inset: 0; background: #fff; opacity: 0;
  pointer-events: none }
#intro .crt-cover { position: absolute; inset: 0; display: none; place-items: center;
  background: rgba(0,0,0,.52); -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  border: 0; cursor: pointer; pointer-events: auto; z-index: 3 }
#intro .crt-cover.on { display: grid }
#intro .crt-cover span { width: 78px; height: 78px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.6); background: rgba(0,0,0,.35);
  display: grid; place-items: center; color: #fff; font-size: 26px; line-height: 1 }
#intro .crt-skip { opacity: 0 }
#intro .crt-skip.on, #intro .crt-skip:hover, #intro .crt-skip:focus-visible { opacity: 1 }
#intro #moment.land { background: transparent }
#intro #moment.land .crt-white { opacity: 0;
  transition: opacity .5s cubic-bezier(.3,0,.2,1) .05s }
#intro #moment.land .crt-lock {
  transform: translate(var(--dx,0px), var(--dy,0px)) scale(var(--s,1)); opacity: 0;
  transition: transform .5s cubic-bezier(.7,0,.2,1), opacity .2s linear .18s }
#intro #moment.land .crt-lock img.crt-b { opacity: 0; transition: opacity .2s linear }
#intro #moment.land .crt-lock img.crt-a { opacity: 1; transition: opacity .2s linear }
#intro #moment.land .crt-cv, #intro #moment.land .crt-skip { opacity: 0;
  transition: opacity .3s linear }
#intro .crt-lock .crt-morph { position: absolute; inset: 0; width: 100%; height: 100%;
  display: none }
#intro .crt-lock.morphing .crt-morph { display: block }
#intro .crt-lock.morphing { will-change: transform }
#intro .crt-lock.morphing img { display: none }
#intro #moment.land .crt-lock.morphing { transform: none; opacity: 1; transition: none }
#intro #moment.land .crt-lock.morphing.arrived { opacity: 0; transition: opacity .12s linear }

@media (prefers-reduced-motion: reduce) { #intro { display: none } }

/* engine 4 only: the CRT's flyer morphs to the STRAIGHT mark (the wireframe
   header's shape); Home's header mark is STACKED. Rather than rebuild crt.js,
   the flyer fades across the flight -- t2.html's own v2 note, "gone by 380 ms of
   a 500 ms transform" -- so no frame shows a straight mark standing on a stacked
   one. Remove this when the flyin4 rebuild lands. */
#intro[data-e="4"] #moment.land .crt-lock.morphing { opacity: 0;
  transition: opacity .38s linear .1s }
