/* Import the base styles - for the shared :root palette, the Damryl/
   Berkley Mono @font-face declarations, AND .countdown/.colon
   themselves (this page's own countdown overlay markup, launch.ejs,
   deliberately reuses those two classes verbatim rather than
   reinventing equivalent rules here - see #launch-countdown's own
   comment below for why that specific reuse, not just matching values
   independently, is what the real site's sizing/spacing/stretch
   actually depends on). base.css's #app-shell/#navbar/#scroll-area/
   #menu rules are unused here, matching nothing in this page's markup -
   this page is deliberately standalone, not part of the app-shell
   pattern the rest of the site shares, same convention every other
   page's stylesheet already follows regardless of how much of base.css
   it actually uses. */
@import url('base.css');

/* html/body/#launch-shell all share ONE height source
   (var(--launch-height, 100dvh) - the JS in launch.ejs measures
   window.innerHeight and sets --launch-height, overriding the dvh
   fallback once that runs) rather than each independently computing
   "the full viewport height" its own way. That distinction is the
   whole reason a long-running "gap at the bottom of the page on
   mobile" bug lived here: a plain 100%/100dvh on iOS Safari can
   resolve against the LARGE (chrome-hidden) viewport rather than the
   CURRENT one - the same recurring vh/dvh-mismatch bug class
   documented elsewhere on this site - so html/body could each end up
   taller than #launch-shell by however much of Safari's toolbar was
   currently showing, with body's own background (the same purple as
   this page's actual content) showing through underneath as an
   apparent gap. Tying all three to the identical variable means they
   can never diverge from EACH OTHER again, regardless of which
   specific browser mechanism is at fault in a given case.
   That alone wasn't sufficient, though - see launch.ejs's own comment
   (right before its height-measurement script) for what else the fix
   actually needed: keeping --launch-height itself fresh via more than
   just a plain resize listener, AND actively nudging Safari's own
   viewport/chrome compositor to resync, since on-device testing proved
   this page's content could render visibly shifted from where every
   JS-readable measurement said it was - a mismatch between what Safari
   reports and what it actually paints, invisible to CSS or JS alike,
   which no amount of correctly-computed height alone could fix. */
html {
    height: var(--launch-height, 100dvh);
}

body {
    margin: 0px;
    padding: 0px;
    background: var(--primary-bg-color);
    font-family: 'Damryl', Fallback, sans-serif;
    position: fixed;
    top: 0;
    left: 0;
    height: var(--launch-height, 100dvh);
    width: 100%;
    overflow: hidden;
}

#launch-shell {
    position: relative;
    width: 100%;
    height: var(--launch-height, 100dvh);
    overflow: hidden;
}

/* Quick, purely CSS-driven reveal - no JS-toggled class, no dependency
   on anything loading first. Shared by #launch-trails and #launch-
   countdown (both below): neither has a slow async pipeline of its own
   (unlike #launch-canvas's three.js/HDRI/OBJ model, which gets its own
   separate, JS-gated fade further down) - they're ready almost
   immediately, and gating them on the MODEL's own load time was the
   real cost of the page's original single-fade-for-everything design:
   a slow model load meant a fully blank page, not just a slow model. */
@keyframes launch-fade-in {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

/* Same sizing as #launch-canvas (below) - sits behind it in the DOM
   (see launch.ejs's own comment on the markup) and gets drawn into by
   a plain 2D canvas script, not three.js. No z-index needed on either
   canvas: #launch-countdown's own z-index:10 already puts it above
   both regardless of DOM order, and between the two canvases
   themselves DOM order alone is enough since neither sets one. */
#launch-trails {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
    animation: launch-fade-in 400ms ease-out;
}

/* opacity:0 until launch.ejs's module script adds .is-ready (once the
   model's loaded, framed, and about to render its first real frame) -
   without this, the model pops in abruptly the moment loading finishes
   (three.js/OBJ/EXR are all async, so that moment is unpredictable).
   The SAME transition serves the shutdown sequence's own exit fade
   (style.opacity set directly, launch.ejs) - one duration for both,
   rather than two separately-tracked numbers to keep in sync.
   will-change:opacity keeps this element on its own compositing layer
   for the WHOLE fade, not just while it's animating - this site has hit
   a confirmed mobile Safari bug before where an element promoted to its
   own layer only AT transition start renders a couple px out of its
   normal position for the transition's duration; same fix applies here
   pre-emptively. */
#launch-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
    opacity: 0;
    transition: opacity 300ms ease-out;
    will-change: opacity;
}

#launch-canvas.is-ready {
    opacity: 1;
}

/* Deliberately mirrors #now (style.css) property-for-property, not
   just "close enough" values chosen independently - color, transform:
   scaleY(1.5), and contain: layout style are copied verbatim (see
   #now's own comment for why contain matters: this element's digits
   get rewritten every animation frame, same as #now's do, so the same
   layout/style containment keeps that from forcing the browser to
   check whether each write could affect anything outside this box).
   font-size: 5.25vw replicated here directly since #now inherits that
   from #container (style.css) instead - this page has no #container
   of its own for a #launch-countdown-shaped element to inherit it
   from, so it's set directly instead, to the identical value.

   This element ALSO carries class="countdown" in the markup
   (launch.ejs), same as #now's own div does (createNowElement) - an
   ID rule alone isn't enough to reproduce #now's actual rendered
   result, since .countdown's own transform:scaleY(1.5) (base.css)
   compounds with an identical child <span class="countdown">'s own
   scaleY(1.5) to a combined 2.25x vertical stretch on every digit
   GROUP specifically - while a <span class="colon"> (no transform of
   its own) only gets the single scaleY(1.5) this outer element itself
   applies. That double-stretch on digits only, not colons, is a real,
   deliberate visual detail of the real site's own countdown look, not
   an accident worth normalizing away - reproducing it needed the same
   two-classes-on-two-nesting-levels structure, not just matching each
   individual property's value some other way. Sizing/spacing came out
   ~50% too WIDE the first time this page tried to approximate that
   layout without literally reusing it (confirmed live) - not from any
   one property being wrong, but from the two-level class structure
   itself being what the real numbers depend on.

   translate(-50%,-50%) added into the SAME transform (rather than a
   separate wrapping element) for the screen-centering this page
   specifically needs that #now itself doesn't (#now is positioned by
   JS-computed absolute top/left pixels instead, to center over the
   scrolling timeline's own navbar-adjusted viewport - meaningless here,
   there's no timeline or navbar on this page, just the one thing to
   center) - percentage translate() resolves against this element's own
   OWN box size regardless of what the rest of the same transform list
   does, so combining them still centers correctly.

   white-space:nowrap - #now doesn't need this (positioned by JS-
   computed absolute pixels, not by left:50% with an auto width), but an
   absolutely-positioned auto-width block with only ONE offset (left)
   specified shrink-to-fits against "containing block width minus that
   offset" - roughly half the viewport at left:50% - not the full
   viewport, so this row (measured at ~71.4vw of real content, always
   comfortably under 100vw) was still wrapping mid-digit-group against
   that halved available width (confirmed live) despite there being
   plenty of real room. nowrap sidesteps that shrink-to-fit quirk
   entirely rather than fighting it with an explicit width. */
#launch-countdown {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scaleY(1.5);
    pointer-events: none;
    z-index: 10;
    white-space: nowrap;
    color: var(--primary-text-color);
    font-size: 5.25vw;
    contain: layout style;
    /* launch-fade-in - see its own comment above #launch-trails. */
    animation: launch-fade-in 400ms ease-out;
    /* transition - separate from the animation above, and unused until
       the shutdown sequence's own final fade (COUNTDOWN_FADE_MS,
       launch.ejs - 300ms, matched here) sets style.opacity directly -
       while .is-blinking (below) is active, the animation's own opacity
       keyframes take priority over this transition per the CSS spec, so
       blinking itself isn't affected by adding this. */
    transition: opacity 300ms ease-out;
}

/* Toggled on for BLINK_MS (launch.ejs, 5000ms) once the countdown's
   frozen at exactly 00000:00:00:00:00. 67ms per full on/off cycle (~15
   flashes/sec) - a deliberate choice, made with the tradeoff on the
   record: this is well past the ~3-flashes-per-second general threshold
   past which flashing content risks triggering photosensitive seizures
   (WCAG 2.1's own general flash guidance), which is exactly why an
   earlier version of this animation was capped at 2.5 flashes/sec.
   steps(1, end) (a hard on/off toggle, not an eased fade) is what makes
   it read as a BLINK rather than a fast fade effect. */
@keyframes launch-countdown-blink {
    0%, 49% {
        opacity: 1;
    }
    50%, 100% {
        opacity: 0;
    }
}

#launch-countdown.is-blinking {
    animation: launch-countdown-blink 67ms steps(1, end) infinite;
}

@media (prefers-reduced-motion: reduce) {
    #launch-canvas {
        transition: none;
    }

    #launch-trails,
    #launch-countdown {
        animation: none;
    }

    #launch-countdown {
        transition: none;
    }

    #launch-countdown.is-blinking {
        /* No flashing for reduced-motion - still visibly signals "done"
           by dropping to half-opacity for the same BLINK_MS duration,
           just without the actual flicker. */
        animation: none;
        opacity: 0.4;
    }
}
