html,body{height:100%}/* ---------- audio toggle: same control as console.html's HUD stat, pinned
     top-right. Held at opacity:0 and revealed on the same fade-up schedule
     as .gate below rather than visible pre-boot — audio can't play before
     the first interaction anyway (browser autoplay policy). */header{position:fixed;top:clamp(16px, 3vw, 28px);right:clamp(16px, 3vw, 28px);z-index:10;opacity:0}.hud-audio{cursor:pointer;background:none;border:none;padding:0;font:inherit;text-align:right}.hud-audio .k{font-family:var(--font-mono);font-size:10px;letter-spacing:0.12em;color:var(--steel-dim);text-transform:uppercase}.hud-audio .v{font-family:var(--font-mono);font-size:14px;color:var(--phosphor);margin-top:2px}.hud-audio .v.signal{color:var(--signal)}.hud-audio:hover .v,.hud-audio:focus-visible .v{color:var(--signal)}.hud-audio:focus-visible{outline:1px solid var(--signal);outline-offset:4px}.gate-screen{min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px;text-align:center}/* Old-CRT signal hiccup: a jagged ~250ms tear burst near the start of every
     10.6s loop, then flat for the rest. The first burst is delayed a full
     10.6s so it doesn't collide with the emblem/wordmark/caption/gate reveal
     (finishes ~2.3s in); later cycles repeat at the normal period. Two parts
     read as "glitch": .gate-screen snaps position/contrast in hard steps()
     and grows a red/phosphor ghost double-image via drop-shadow (chromatic
     aberration in this theme's own palette, not an unrelated color); a fixed
     ::after sweeps a bright band top-to-bottom, like lost vertical hold. */@media (prefers-reduced-motion: no-preference){.gate-screen.play{animation:glitch 10.6s steps(1, jump-end) 10.6s infinite}.gate-screen.play::after{animation:glitch-roll 10.6s steps(1, jump-end) 10.6s infinite}}.gate-screen::after{content:"";position:fixed;inset:0;z-index:60;pointer-events:none;opacity:0;background:linear-gradient(to bottom,
      transparent 0%,
      rgba(244, 242, 236, 0.05) 46%,
      rgba(255, 49, 49, 0.16) 50%,
      rgba(244, 242, 236, 0.05) 54%,
      transparent 100%);background-size:100% 260%;background-repeat:no-repeat}@keyframes glitch-roll{0%,100%{opacity:0;background-position:0 -30%}0.4%{opacity:0.9;background-position:0 -10%}0.9%{background-position:0 30%}1.4%{background-position:0 65%}1.9%{background-position:0 100%;opacity:0.7}2.4%{opacity:0;background-position:0 130%}}@keyframes glitch{0%,100%{transform:translate(0, 0);filter:brightness(1) contrast(1) drop-shadow(0 0 0 transparent) drop-shadow(0 0 0 transparent)}0.4%{transform:translate(-6px, 2px);filter:brightness(1.3) contrast(1.4) drop-shadow(-3px 0 var(--signal)) drop-shadow(3px 0 var(--phosphor))}0.9%{transform:translate(5px, -3px);filter:brightness(0.8) contrast(1.3) drop-shadow(4px 0 var(--signal)) drop-shadow(-4px 0 var(--phosphor))}1.4%{transform:translate(-4px, 1px);filter:brightness(1.25) contrast(1.2) drop-shadow(-2px 0 var(--signal)) drop-shadow(2px 0 var(--phosphor))}1.9%{transform:translate(3px, -1px);filter:brightness(0.9) contrast(1.15) drop-shadow(2px 0 var(--signal)) drop-shadow(-2px 0 var(--phosphor))}2.4%{transform:translate(0, 0);filter:brightness(1) contrast(1) drop-shadow(0 0 0 transparent) drop-shadow(0 0 0 transparent)}}/* ---------- emblem: three separate clip-path shapes with real gaps between them ---------- */.emblem{position:relative;width:clamp(200px, 42vw, 380px);aspect-ratio:3/2;clip-path:inset(0 0 100% 0)}.tri{position:absolute;inset:0;background:repeating-linear-gradient(to bottom,
      var(--signal) 0px, var(--signal) 5px, transparent 5px, transparent 9px)}/* all three shapes are plotted in the same 0-100% box, so the gaps between
     them are just the space no polygon covers, not a shape drawn on top */.tri-left{clip-path:polygon(32.76% 39.93%, 47.36% 66.97%, 47.36% 93.65%, 5.19% 93.65%)}.tri-right{clip-path:polygon(65.99% 39.93%, 51.39% 66.97%, 51.39% 93.65%, 93.56% 93.65%)}.tri-diamond{clip-path:polygon(49.47% 9.62%, 63.02% 34.12%, 49.47% 60.80%, 35.93% 34.12%)}@keyframes emblem-reveal{to{clip-path:inset(0 0 0% 0)}}@keyframes emblem-glow{0%,100%{filter:drop-shadow(0 0 0 transparent)}50%{filter:drop-shadow(0 0 26px var(--signal-glow))}}/* ---------- staged type reveal ---------- */.wordmark,.caption,.gate{opacity:0}.wordmark{font-family:var(--font-mono);font-weight:700;font-size:clamp(38px, 10vw, 92px);letter-spacing:0.05em;color:var(--phosphor);margin:0.35em 0 0}.caption{font-family:var(--font-mono);font-size:clamp(10px, 1.6vw, 14px);letter-spacing:0.3em;text-transform:uppercase;color:var(--signal-dim);margin:0.7em 0 0}@keyframes flicker-in{0%,19%,21%,23%{opacity:0}20%,22%,100%{opacity:1}}@keyframes fade-up{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}/* boot sequence is held until first interaction (see JS), then this block
     drives emblem/wordmark/caption/gate in — kept out of the reduced-motion
     path entirely so those users never get it, regardless of the .play class */@media (prefers-reduced-motion: no-preference){.gate-screen.play .emblem{animation:emblem-reveal 1.38s cubic-bezier(.2, .7, .3, 1) forwards,emblem-glow 4.5s ease-in-out 2.75s infinite}.gate-screen.play .wordmark{animation:flicker-in 0.63s steps(6, end) 1.31s forwards}.gate-screen.play .caption{animation:fade-up 0.63s ease-out 1.88s forwards}.gate-screen.play .gate{animation:fade-up 0.63s ease-out 2.31s forwards}/* header is a sibling of .gate-screen, not a descendant, so beginBoot()
       (gate.js) adds .play to it directly. Same timing as .gate so the
       audio control appears alongside the form. */header.play{animation:fade-up 0.63s ease-out 2.31s forwards}}@media (prefers-reduced-motion: reduce){.emblem{clip-path:inset(0 0 0% 0)}.wordmark,.caption,.gate,header{opacity:1}.boot-prompt{display:none;animation:none}}/* ---------- prompt ---------- */.gate-slot{display:grid;margin-top:clamp(28px, 6vw, 48px)}.gate-slot > *{grid-area:1/1}.gate{margin-top:0}.boot-prompt{align-self:center;font-family:var(--font-mono);font-size:11px;letter-spacing:0.16em;text-transform:uppercase;color:var(--steel-dim);animation:blink 1.6s steps(2, jump-none) infinite}@keyframes blink{50%{opacity:0.25}}.gate-screen.play .boot-prompt{display:none}.gate-label{display:block;font-family:var(--font-mono);font-size:10px;letter-spacing:0.16em;text-transform:uppercase;color:var(--steel-dim);margin-bottom:8px}.gate-row{display:flex;align-items:center;gap:8px;width:min(360px, 78vw);border-bottom:1px solid var(--panel-edge);padding-bottom:8px}.gate-row.ok{border-color:var(--cleared)}.gate-row.shake{animation:shake 0.35s ease;border-color:var(--signal)}@keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}.gate-caret{font-family:var(--font-mono);color:var(--signal);font-size:16px}.gate-row input{flex:1;min-width:0;background:none;border:none;font-family:var(--font-mono);font-size:15px;color:var(--phosphor);caret-color:var(--signal)}.gate-row input:focus{outline:none}.gate-msg{min-height:16px;margin:8px 0 0;font-family:var(--font-mono);font-size:11px;letter-spacing:0.06em;color:var(--steel-dim)}.gate-msg.ok{color:var(--cleared)}