/* ==========================================================================
   DVAL Reveal — ported from design_handoff_dval_reveal/reveal.css
   Self-hosted fonts, same palette, same keyframes.
   ========================================================================== */

/* ---------- Self-hosted fonts ---------- */
@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 300;
    font-display: swap;
    src: url('fonts/IBMPlexMono-300.woff2') format('woff2');
}
@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/IBMPlexMono-400.woff2') format('woff2');
}
@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('fonts/IBMPlexMono-500.woff2') format('woff2');
}
@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('fonts/IBMPlexMono-600.woff2') format('woff2');
}

/* Space Grotesk is served as a single variable font by Google Fonts —
   one file covers weights 300..700. Declare the same file for each weight
   so the browser can pick the right instance. Italic is browser-synthesized. */
@font-face {
    font-family: 'Space Grotesk';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/SpaceGrotesk-variable.woff2') format('woff2');
}
@font-face {
    font-family: 'Space Grotesk';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('fonts/SpaceGrotesk-variable.woff2') format('woff2');
}
@font-face {
    font-family: 'Space Grotesk';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('fonts/SpaceGrotesk-variable.woff2') format('woff2');
}
@font-face {
    font-family: 'Space Grotesk';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('fonts/SpaceGrotesk-variable.woff2') format('woff2');
}

/* ---------- Tokens ---------- */
:root {
    --ink: #f4ede0;
    --ink-dim: #c9bfad;
    --ink-ghost: #7a7266;
    --bg: #0e0f10;
    --bg-2: #16171a;
    --bg-3: #1e2024;
    --panel: #1a1b1d;
    --amber: #ffb347;
    --amber-hot: #ff8c42;
    --amber-glow: #ffd27a;
    --red: #e25c3f;
    --rule: rgba(244, 237, 224, 0.14);
    --rule-strong: rgba(244, 237, 224, 0.3);
    --crt-intensity: 0.8;
    --f-mono: 'IBM Plex Mono', 'Courier New', monospace;
    --f-disp: 'Space Grotesk', system-ui, sans-serif;
}

[data-palette="navy-cream"] {
    --ink: #f2ebd7;
    --ink-dim: #cfc7ac;
    --bg: #0a1628;
    --bg-2: #0f1e35;
    --bg-3: #152844;
    --panel: #11213a;
    --amber: #f2ebd7;
    --amber-hot: #e8c55c;
    --amber-glow: #f5e9b2;
}

[data-palette="midnight-gold"] {
    --ink: #f4edd7;
    --ink-dim: #c9bc91;
    --bg: #08070c;
    --bg-2: #11101a;
    --bg-3: #1b1928;
    --panel: #15131f;
    --amber: #d4a857;
    --amber-hot: #e8b96a;
    --amber-glow: #f3d488;
}

*, *::before, *::after { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--f-mono);
    height: 100%;
    overflow: hidden;
}

#app-root { height: 100%; }

/* Offscreen helper for aria-live announcements */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ==========================================================================
   Teaser (Screen 1)
   ========================================================================== */
.teaser-root {
    position: relative;
    width: 100%;
    height: 100vh;
    background: radial-gradient(ellipse at 50% 60%, #1a1b1e 0%, var(--bg) 65%);
    display: flex;
    flex-direction: column;
    color: var(--ink);
    overflow: hidden;
}

.teaser-grid {
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(to right, rgba(255, 179, 71, 0.035) 1px, transparent 1px),
        linear-gradient(to bottom, rgba(255, 179, 71, 0.035) 1px, transparent 1px);
    background-size: 48px 48px;
    -webkit-mask-image: radial-gradient(ellipse at 50% 50%, black 30%, transparent 75%);
    mask-image: radial-gradient(ellipse at 50% 50%, black 30%, transparent 75%);
    pointer-events: none;
}

.teaser-grain {
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: 0.35;
    mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.6'/></svg>");
}
[data-grain="0"] .teaser-grain { display: none; }

.teaser-top {
    position: relative;
    z-index: 2;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 28px 48px;
    font-size: 11px;
    letter-spacing: 0.2em;
    color: var(--ink-dim);
    border-bottom: 1px solid var(--rule);
}

.teaser-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--amber);
}

.teaser-dot {
    width: 8px;
    height: 8px;
    background: var(--amber);
    border-radius: 50%;
    box-shadow: 0 0 12px var(--amber-glow);
    animation: pulse 1.6s ease-in-out infinite;
}

.teaser-meta {
    display: flex;
    gap: 12px;
}

.teaser-sep { color: var(--ink-ghost); }

.teaser-main {
    position: relative;
    z-index: 2;
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    padding: 40px 48px;
    gap: 32px;
}

.teaser-kicker {
    display: flex;
    align-items: center;
    gap: 18px;
    font-size: 11px;
    letter-spacing: 0.35em;
    color: var(--amber);
}

.teaser-kicker-rule {
    display: inline-block;
    width: 56px;
    height: 1px;
    background: var(--amber);
    opacity: 0.65;
}

.teaser-h1 {
    font-family: var(--f-disp);
    font-weight: 500;
    font-size: clamp(56px, 8.5vw, 128px);
    line-height: 0.92;
    letter-spacing: -0.035em;
    margin: 0;
    color: var(--ink);
    text-wrap: balance;
}

.teaser-lede {
    max-width: 560px;
    font-family: var(--f-mono);
    font-size: 13px;
    line-height: 1.7;
    color: var(--ink-dim);
    letter-spacing: 0.02em;
    margin: 0;
    text-wrap: pretty;
}

.trigger-btn {
    margin-top: 12px;
    display: inline-flex;
    align-items: center;
    gap: 14px;
    background: transparent;
    border: 1px solid var(--amber);
    color: var(--amber);
    font-family: var(--f-mono);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0.25em;
    padding: 18px 32px;
    cursor: pointer;
    transition: all 0.25s ease;
    position: relative;
}

.trigger-btn::before {
    content: '';
    position: absolute;
    inset: -4px;
    border: 1px solid var(--amber);
    opacity: 0;
    transition: all 0.25s ease;
    pointer-events: none;
}

.trigger-btn:hover {
    background: var(--amber);
    color: var(--bg);
    box-shadow: 0 0 40px rgba(255, 179, 71, 0.35);
}
.trigger-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--amber-glow);
}
.trigger-btn:hover::before { opacity: 0.4; inset: -8px; }

.trigger-bracket { color: var(--amber-hot); font-weight: 400; }
.trigger-btn:hover .trigger-bracket { color: var(--bg); }
.trigger-arrow { transition: transform 0.25s ease; }
.trigger-btn:hover .trigger-arrow { transform: translateX(4px); }

.teaser-hint {
    font-size: 10px;
    letter-spacing: 0.3em;
    color: var(--ink-ghost);
    text-transform: uppercase;
}

.teaser-bot {
    position: relative;
    z-index: 2;
    padding: 16px 0;
    border-top: 1px solid var(--rule);
    overflow: hidden;
}

.teaser-ticker {
    font-size: 11px;
    letter-spacing: 0.2em;
    color: var(--amber);
    opacity: 0.7;
    white-space: nowrap;
    overflow: hidden;
}

.ticker-track {
    display: inline-block;
    animation: tickscroll 60s linear infinite;
}

@keyframes tickscroll {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

@keyframes pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50%      { opacity: 0.4; transform: scale(0.85); }
}

/* ==========================================================================
   Reveal shell (Screen 2)
   ========================================================================== */
.reveal-root {
    position: fixed;
    inset: 0;
    background: var(--bg);
    overflow: hidden;
    z-index: 1;
    font-family: var(--f-mono);
}

.reveal-stage-container {
    position: absolute;
    inset: 0;
}

.reveal-chrome {
    position: absolute;
    top: 20px;
    right: 20px;
    display: flex;
    gap: 8px;
    z-index: 20;
}

.chrome-btn {
    background: rgba(14, 15, 16, 0.7);
    border: 1px solid var(--rule-strong);
    color: var(--ink-dim);
    font-family: var(--f-mono);
    font-size: 10px;
    letter-spacing: 0.25em;
    padding: 8px 12px;
    cursor: pointer;
    transition: all 0.2s;
}
/* Inline SVG speaker glyph used by the mute chrome button. Sized to
   sit cleanly with the 10px mono label, picks up currentColor. */
.speaker-icon {
    display: inline-block;
    width: 14px;
    height: 12px;
    vertical-align: -2px;
    margin-right: 6px;
    /* Strip the wide letter-spacing inherited from .chrome-btn — we
       don't want gaps between the SVG strokes and the next char. */
    letter-spacing: 0;
}

.chrome-btn:hover { color: var(--amber); border-color: var(--amber); }
.chrome-btn:focus-visible {
    outline: none;
    color: var(--amber);
    border-color: var(--amber);
    box-shadow: 0 0 0 2px var(--amber-glow);
}

/* Step-mode review bar (bottom-left). Only rendered when ?step is set. */
.reveal-step-bar {
    position: absolute;
    bottom: 20px;
    left: 20px;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    background: rgba(14, 15, 16, 0.85);
    border: 1px solid var(--rule-strong);
    font-family: var(--f-mono);
    font-size: 10px;
    letter-spacing: 0.25em;
    color: var(--ink-dim);
    z-index: 25;
}
.step-badge-label { color: var(--amber); }
.step-badge-stage {
    color: var(--ink);
    padding: 0 6px;
    border-left: 1px solid var(--rule-strong);
    border-right: 1px solid var(--rule-strong);
}
.reveal-step-bar .chrome-btn.is-ready {
    /* Pulses gently once the current stage's animation has completed,
       hinting that the reviewer can safely advance. */
    color: var(--amber);
    border-color: var(--amber);
    animation: step-ready-pulse 1.6s ease-in-out infinite;
}
@keyframes step-ready-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(255, 179, 71, 0.0); }
    50%      { box-shadow: 0 0 0 3px rgba(255, 179, 71, 0.25); }
}
@media (prefers-reduced-motion: reduce) {
    .reveal-step-bar .chrome-btn.is-ready { animation: none; }
}

.reveal-stage-indicator {
    position: absolute;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 20;
}

.stage-dots { display: flex; gap: 10px; }

.stage-dot {
    width: 24px;
    height: 2px;
    background: var(--rule-strong);
    transition: all 0.4s ease;
}
.stage-dot.active { background: var(--amber); box-shadow: 0 0 8px var(--amber-glow); }

/* ==========================================================================
   CRT Overlay
   ========================================================================== */
.crt-overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 15;
    opacity: var(--crt-intensity);
    transition: opacity 0.6s ease;
}

.crt-scanlines {
    position: absolute;
    inset: 0;
    background: repeating-linear-gradient(
        to bottom,
        rgba(0, 0, 0, 0) 0px,
        rgba(0, 0, 0, 0) 2px,
        rgba(0, 0, 0, 0.18) 3px,
        rgba(0, 0, 0, 0) 4px
    );
    mix-blend-mode: multiply;
}

.crt-vignette {
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse at center, transparent 40%, rgba(0, 0, 0, 0.65) 100%);
}

.crt-flicker {
    position: absolute;
    inset: 0;
    background: rgba(255, 179, 71, 0.02);
    animation: flicker 0.15s steps(2) infinite;
}

@keyframes flicker {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.85; }
}

/* ==========================================================================
   Stage 0 — Intro flash
   ========================================================================== */
.intro-stage {
    position: absolute;
    inset: 0;
    background: #000;
    display: flex;
    align-items: center;
    justify-content: center;
}

.intro-flash {
    position: absolute;
    inset: 0;
    background: var(--amber-glow);
    animation: flashOn 1.5s ease-out forwards;
    opacity: 0;
}

.intro-dot {
    width: 3px;
    height: 3px;
    background: var(--amber);
    border-radius: 50%;
    animation: dotExpand 1.4s ease-out forwards;
    box-shadow: 0 0 30px var(--amber-glow);
}

@keyframes flashOn {
    0%   { opacity: 0; }
    8%   { opacity: 0.9; }
    14%  { opacity: 0.2; }
    20%  { opacity: 0.7; }
    30%  { opacity: 0; }
    100% { opacity: 0; }
}

@keyframes dotExpand {
    0%   { transform: scale(0); opacity: 0; }
    15%  { transform: scale(1); opacity: 1; }
    50%  { transform: scale(1); opacity: 1; }
    80%  { transform: scaleX(160) scaleY(0.4); opacity: 0.6; }
    100% { transform: scaleX(400) scaleY(400); opacity: 0; }
}

/* ==========================================================================
   Stage 1 — Boot terminal
   ========================================================================== */
.boot-stage {
    position: absolute;
    inset: 0;
    background: #0a0a0a;
    padding: 6vh 8vw;
    overflow: hidden;
    animation: stageFadeIn 0.3s ease;
}

@keyframes stageFadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.boot-inner {
    font-family: var(--f-mono);
    font-size: clamp(13px, 1.4vw, 18px);
    line-height: 1.55;
    color: var(--amber);
    text-shadow:
        0 0 6px rgba(255, 179, 71, 0.5),
        0 0 18px rgba(255, 140, 66, 0.2);
    max-width: 900px;
    /* Horizontally center the terminal block on wider viewports.
       Text inside stays left-aligned (terminal lines, not prose). */
    margin: 0 auto;
    white-space: pre;
}

.boot-line {
    letter-spacing: 0.02em;
    min-height: 1.4em;
}

/* Two-column boot line: label on left, flush-right status, dotted leader
   fills the gap regardless of label or status length. */
.boot-line--2col {
    display: flex;
    align-items: baseline;
    gap: 0.75ch;
    white-space: nowrap;
}
.boot-label { flex: 0 0 auto; }
.boot-status { flex: 0 0 auto; }
.boot-leader {
    flex: 1 1 auto;
    min-width: 1ch;
    overflow: hidden;
    white-space: nowrap;
    opacity: 0.75;
}
.boot-leader::before {
    /* 160 ". " pairs — far more than any realistic line needs; the
       flex-child overflow: hidden clips them to the available width. */
    content: ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .";
    letter-spacing: 0;
}

.boot-cursor {
    display: inline-block;
    margin-left: 2px;
    color: var(--amber-glow);
    animation: cursorBlink 0.9s steps(2) infinite;
}

@keyframes cursorBlink { 50% { opacity: 0; } }

/* ==========================================================================
   Stage 2 — Loading bars
   ========================================================================== */
.load-stage {
    position: absolute;
    inset: 0;
    background: var(--bg);
    padding: 10vh 10vw;
    animation: stageFadeIn 0.3s ease;
    display: flex;
    align-items: center;
    justify-content: center;
}

.load-inner {
    width: 100%;
    max-width: 1100px;
    font-family: var(--f-mono);
    color: var(--amber);
}

.load-header {
    display: flex;
    gap: 14px;
    font-size: 12px;
    letter-spacing: 0.3em;
    color: var(--ink-dim);
    padding-bottom: 12px;
    border-bottom: 1px solid var(--rule-strong);
    margin-bottom: 24px;
    flex-wrap: wrap;
}

.load-kicker { color: var(--amber); }
.load-sep { color: var(--ink-ghost); }

.load-blink {
    margin-left: auto;
    color: var(--amber-hot);
    animation: blink 1s steps(2) infinite;
}

@keyframes blink { 50% { opacity: 0.35; } }

.load-tasks {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 32px;
}

.load-task {
    display: grid;
    grid-template-columns: 60px 1fr 60px;
    gap: 16px;
    font-size: 14px;
    padding: 6px 0;
    letter-spacing: 0.1em;
    transition: all 0.3s;
}
.load-task.done {
    color: var(--ink-dim);
    opacity: 0.6;
}
.load-task.active {
    color: var(--amber-glow);
    text-shadow: 0 0 10px rgba(255, 179, 71, 0.45);
}
.load-task.active .load-check {
    color: var(--amber-hot);
    animation: blink 0.4s steps(2) infinite;
}

.load-check { font-family: var(--f-mono); }
.load-pct { text-align: right; }

.load-bar-wrap { margin-bottom: 40px; }

.load-bar-track {
    height: 22px;
    background: var(--bg-2);
    border: 1px solid var(--rule-strong);
    position: relative;
    padding: 2px;
}

.load-bar-fill {
    height: 100%;
    background: repeating-linear-gradient(
        90deg,
        var(--amber) 0 8px,
        var(--amber-hot) 8px 16px
    );
    box-shadow: 0 0 16px rgba(255, 179, 71, 0.6);
    transition: width 0.08s linear;
}

/* Glitch-state bar: red stripes, stronger glow, rapid strobe. */
.load-bar-fill.glitch {
    background: repeating-linear-gradient(
        90deg,
        #e25c3f 0 8px,
        #c44a30 8px 16px
    );
    box-shadow: 0 0 24px rgba(226, 92, 63, 0.85);
    animation: load-bar-glitch 0.18s steps(2) infinite;
    transition: width 0.25s ease-out;  /* smoother snap-back on resolve */
}
@keyframes load-bar-glitch {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.55; }
}

/* Row decorations during the glitch phases. */
.load-task.glitch-active {
    color: #ffb0a0;
    text-shadow: 0 0 10px rgba(226, 92, 63, 0.6);
}
.load-task.glitch-active .load-check {
    color: #e25c3f;
    animation: blink 0.2s steps(2) infinite;  /* faster than normal */
}
.load-task.resolved .load-check {
    color: var(--amber-glow);
    animation: none;
}

/* Countdown easter egg's SUCCESS state — pop green so it reads as a
   deliberate punchline against the all-amber terminal. Persists into
   the .done state so the joke stays visible for the rest of the stage. */
.load-task.countdown-task.resolved {
    color: #4ade80;
    text-shadow: 0 0 10px rgba(74, 222, 128, 0.55);
}
.load-task.countdown-task.resolved .load-check,
.load-task.countdown-task.resolved .load-pct {
    color: #4ade80;
}
/* Don't let .done's dim-amber styling drag the completed green row down. */
.load-task.done.countdown-task.resolved {
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
    .load-bar-fill.glitch { animation: none; }
    .load-task.glitch-active .load-check { animation: none; }
}

.load-ticks {
    display: flex;
    justify-content: space-between;
    margin-top: 6px;
    color: var(--ink-ghost);
}

.load-ticks span {
    width: 1px;
    height: 6px;
    background: var(--ink-ghost);
}
.load-ticks span:nth-child(5n+1) {
    height: 10px;
    background: var(--amber);
}

.load-telemetry {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 20px;
    padding: 16px 0;
    border-top: 1px solid var(--rule);
    border-bottom: 1px solid var(--rule);
    font-size: 12px;
}

.tl-k {
    color: var(--ink-ghost);
    margin-right: 8px;
    letter-spacing: 0.2em;
}
.tl-v { color: var(--amber); }

/* ==========================================================================
   Stage 3 — Boarding pass
   ========================================================================== */
.bp-stage {
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse at top, #1a1b1e 0%, #09090a 70%);
    display: flex;
    align-items: center;
    justify-content: center;
    animation: stageFadeIn 0.3s ease;
    padding: 20px;
}

.bp-printer {
    position: relative;
    width: min(640px, 90vw);
    display: flex;
    flex-direction: column;
    align-items: center;
}

.bp-pass-wrap {
    position: relative;
    width: 100%;
    height: 62vh;
    max-height: 560px;
    overflow: hidden;
    filter: drop-shadow(0 20px 50px rgba(0, 0, 0, 0.6));
}

.bp-pass {
    width: 100%;
    height: 100%;
    background: #f4ede0;
    color: #0e0f10;
    padding: 36px 32px 24px;
    font-family: var(--f-mono);
    display: flex;
    flex-direction: column;
    gap: 18px;
    position: relative;
    background-image:
        repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.02) 0 1px, transparent 1px 8px),
        linear-gradient(180deg, #f4ede0 0%, #eadfc6 100%);
    transition: clip-path 0.1s linear;
}

.bp-perforation {
    position: absolute;
    left: 0;
    right: 0;
    height: 1px;
    background: repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.35) 0 6px, transparent 6px 12px);
    pointer-events: none;
    z-index: 3;
}

.bp-perf-top { top: 0; }

.bp-perf-bot {
    box-shadow: 0 0 24px rgba(255, 179, 71, 0.4);
    transition: top 0.1s linear;
}

.bp-top {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    border-bottom: 2px dashed rgba(0, 0, 0, 0.25);
    padding-bottom: 14px;
}

.bp-brand {
    display: flex;
    align-items: center;
    gap: 12px;
}

.bp-mark {
    width: 36px;
    height: 36px;
    background: #0e0f10;
    color: var(--amber);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 22px;
}

.bp-brand-name {
    font-family: var(--f-disp);
    font-size: 26px;
    font-weight: 700;
    letter-spacing: 0.04em;
    line-height: 1;
}

.bp-brand-sub {
    font-size: 9px;
    letter-spacing: 0.3em;
    color: #555;
    margin-top: 3px;
}

.bp-label {
    font-size: 10px;
    letter-spacing: 0.4em;
    color: #555;
    padding: 6px 10px;
    border: 1px solid rgba(0, 0, 0, 0.35);
}

.bp-route {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 14px;
    align-items: center;
    padding: 14px 0;
}

.bp-city { text-align: center; }

.bp-iata {
    font-family: var(--f-disp);
    /* The redacted bars are U+2588 FULL BLOCK glyphs — height scales
       directly with font-size. Clip the line-box vertically to trim
       bar height without shrinking bar width. */
    font-size: clamp(36px, 6vw, 56px);
    font-weight: 600;
    letter-spacing: 0.03em;
    line-height: 0.6;
    height: 0.6em;
    overflow: hidden;
}

.bp-cityname {
    font-size: 10px;
    letter-spacing: 0.25em;
    color: #555;
    margin-top: 14px;
}

.bp-arrow {
    color: #0e0f10;
    width: 80px;
}

.bp-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 14px 18px;
    padding-top: 12px;
    border-top: 1px dashed rgba(0, 0, 0, 0.25);
}

.bp-field .bp-k {
    font-size: 8.5px;
    letter-spacing: 0.28em;
    color: #666;
    margin-bottom: 4px;
}

.bp-field .bp-v {
    font-family: var(--f-disp);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0.04em;
}

.bp-flash {
    color: #b5411f;
    animation: blink 0.9s steps(2) infinite;
}

.bp-barcode {
    display: flex;
    align-items: flex-end;
    gap: 1px;
    height: 38px;
    margin-top: auto;
}

.bp-barcode span {
    display: inline-block;
    height: 100%;
    background: #0e0f10;
}

.bp-foot {
    display: flex;
    justify-content: space-between;
    font-size: 9px;
    letter-spacing: 0.2em;
    color: #555;
}

.bp-printer-slot {
    width: 100%;
    height: 14px;
    background: #050505;
    border-radius: 0 0 4px 4px;
    box-shadow: inset 0 8px 20px rgba(0, 0, 0, 0.9);
    margin-top: -2px;
}

.bp-printer-body {
    width: 100%;
    background: linear-gradient(180deg, #2a2b2e 0%, #1a1b1e 100%);
    border: 1px solid #333;
    padding: 14px 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-radius: 0 0 6px 6px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.6);
}

.bp-printer-label {
    font-size: 9px;
    letter-spacing: 0.35em;
    color: var(--ink-ghost);
}

.bp-printer-leds {
    display: flex;
    gap: 8px;
}

.led {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #1a1b1e;
    border: 1px solid #333;
}
.led.led-on {
    background: #3aff88;
    box-shadow: 0 0 8px #3aff88;
    border-color: transparent;
}
.led.led-blink {
    background: var(--amber);
    box-shadow: 0 0 8px var(--amber-glow);
    border-color: transparent;
    animation: blink 0.4s steps(2) infinite;
}

/* ==========================================================================
   Stage 4 — Logo lockup
   ========================================================================== */
.logo-stage {
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse at 50% 55%, #18181c 0%, var(--bg) 70%);
    display: flex;
    align-items: center;
    justify-content: center;
    animation: stageFadeIn 0.4s ease;
}

.logo-bloom {
    position: absolute;
    width: 600px;
    height: 600px;
    background: radial-gradient(circle, var(--amber-glow) 0%, transparent 60%);
    opacity: 0;
    filter: blur(40px);
    transition: opacity 1.5s ease;
    pointer-events: none;
}
.logo-bloom.phase-1 { opacity: 0.05; }
.logo-bloom.phase-2,
.logo-bloom.phase-3 {
    opacity: 0.22;
    transition: opacity 0.9s ease;
}

.logo-lockup {
    position: relative;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 18px;
    padding: 40px;
}

.logo-reveal-kicker {
    display: flex;
    align-items: center;
    gap: 18px;
    font-family: var(--f-mono);
    font-size: 11px;
    letter-spacing: 0.4em;
    color: var(--amber);
    opacity: 0;
    transition: opacity 0.6s ease;
    margin-bottom: 14px;
}
.logo-reveal-kicker.phase-1,
.logo-reveal-kicker.phase-2,
.logo-reveal-kicker.phase-3 { opacity: 1; }

.logo-kicker-rule {
    display: inline-block;
    width: 48px;
    height: 1px;
    background: var(--amber);
    opacity: 0.55;
}

.logo-image-wrap {
    width: min(360px, 58vw);
    position: relative;
    opacity: 0;
    transform: translateX(-120vw) scaleX(2.2) scaleY(0.7);
    filter: blur(24px) saturate(0.6) brightness(0.8);
    transition: none;
}
.logo-image-wrap.phase-1 {
    animation: logoSwoosh 1.35s cubic-bezier(0.19, 1, 0.22, 1) forwards;
}
.logo-image-wrap.phase-2,
.logo-image-wrap.phase-3 {
    opacity: 1;
    transform: translateX(0) scale(1);
    filter: blur(0) drop-shadow(0 0 28px rgba(255, 179, 71, 0.45));
    animation: logoIdle 3.2s ease-in-out infinite;
}

@keyframes logoSwoosh {
    0% {
        opacity: 0;
        transform: translateX(-120vw) scaleX(2.2) scaleY(0.7);
        filter: blur(24px) saturate(0.5) brightness(0.7);
    }
    35% {
        opacity: 1;
        transform: translateX(-20vw) scaleX(1.6) scaleY(0.85);
        filter: blur(10px) saturate(1) brightness(1.15);
    }
    70% {
        opacity: 1;
        transform: translateX(6vw) scaleX(0.95) scaleY(1.06);
        filter: blur(2px) saturate(1.1) brightness(1.2);
    }
    85% {
        opacity: 1;
        transform: translateX(-1.5vw) scale(1.02);
        filter: blur(0) drop-shadow(0 0 40px rgba(255, 179, 71, 0.65));
    }
    100% {
        opacity: 1;
        transform: translateX(0) scale(1);
        filter: blur(0) drop-shadow(0 0 28px rgba(255, 179, 71, 0.45));
    }
}

@keyframes logoIdle {
    0%, 100% { filter: blur(0) drop-shadow(0 0 24px rgba(255, 179, 71, 0.4)); }
    50%      { filter: blur(0) drop-shadow(0 0 36px rgba(255, 179, 71, 0.6)); }
}

.logo-image {
    width: 100%;
    height: auto;
    display: block;
}

.logo-streak {
    position: absolute;
    top: 50%;
    left: 0;
    width: 140%;
    height: 6px;
    transform: translate(-100%, -50%);
    background: linear-gradient(
        90deg,
        transparent 0%,
        rgba(255, 210, 122, 0) 20%,
        rgba(255, 210, 122, 0.9) 48%,
        rgba(255, 255, 255, 1) 50%,
        rgba(255, 210, 122, 0.9) 52%,
        rgba(255, 210, 122, 0) 80%,
        transparent 100%
    );
    filter: blur(3px);
    opacity: 0;
    box-shadow: 0 0 24px rgba(255, 210, 122, 0.7);
    pointer-events: none;
    z-index: 1;
}
.logo-streak.phase-1 {
    animation: streakGo 1.1s cubic-bezier(0.22, 0.8, 0.22, 1) forwards;
}

@keyframes streakGo {
    0%   { transform: translate(-100%, -50%); opacity: 0; height: 2px; }
    15%  { opacity: 1; height: 4px; }
    55%  { opacity: 1; height: 8px; }
    80%  { opacity: 0.8; height: 4px; }
    100% { transform: translate(40%, -50%); opacity: 0; height: 2px; }
}

.logo-tagline {
    font-family: var(--f-disp);
    font-size: clamp(16px, 1.8vw, 22px);
    font-style: italic;
    font-weight: 400;
    color: var(--ink-dim);
    opacity: 0;
    transform: translateY(10px);
    transition: all 0.8s ease;
    margin-top: 16px;
    text-wrap: balance;
    text-align: center;
}
.logo-tagline.phase-2,
.logo-tagline.phase-3 {
    opacity: 1;
    transform: translateY(0);
}

.logo-meta {
    display: flex;
    gap: 14px;
    font-family: var(--f-mono);
    font-size: 11px;
    letter-spacing: 0.3em;
    color: var(--ink-ghost);
    opacity: 0;
    transition: opacity 0.6s ease;
    margin-top: 24px;
}
.logo-meta.phase-2,
.logo-meta.phase-3 { opacity: 1; }

.logo-meta-dot { color: var(--amber); }

.logo-cta {
    margin-top: 36px;
    opacity: 0;
    transform: translateY(8px);
    transition: all 0.5s ease;
}
.logo-cta.phase-3 {
    opacity: 1;
    transform: translateY(0);
}

.replay-btn {
    background: transparent;
    border: 1px solid var(--amber);
    color: var(--amber);
    font-family: var(--f-mono);
    font-size: 12px;
    letter-spacing: 0.3em;
    padding: 14px 26px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 12px;
    transition: all 0.25s ease;
}
.replay-btn:hover {
    background: var(--amber);
    color: var(--bg);
    box-shadow: 0 0 30px rgba(255, 179, 71, 0.35);
}
.replay-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--amber-glow);
}

.replay-arrow { font-size: 16px; }
.replay-btn:hover .replay-arrow { animation: spin 0.6s ease; }

@keyframes spin {
    to { transform: rotate(360deg); }
}

/* ==========================================================================
   Reduced motion — gate cinematic motion, preserve content
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
    /* Kill the repeating / cinematic animations. */
    .crt-flicker,
    .teaser-dot,
    .load-blink,
    .load-task.active .load-check,
    .bp-flash,
    .led.led-blink,
    .boot-cursor,
    .ticker-track,
    .logo-image-wrap.phase-2,
    .logo-image-wrap.phase-3 {
        animation: none !important;
    }
    /* Replace the swoosh + streak with a plain cross-fade in. */
    .logo-image-wrap.phase-1,
    .logo-image-wrap.phase-2,
    .logo-image-wrap.phase-3 {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
        filter: blur(0) drop-shadow(0 0 28px rgba(255, 179, 71, 0.45)) !important;
        transition: opacity 0.6s ease !important;
    }
    .logo-image-wrap {
        opacity: 0;
        transform: none;
        filter: blur(0) drop-shadow(0 0 28px rgba(255, 179, 71, 0.45));
        transition: opacity 0.6s ease;
    }
    .logo-streak { display: none !important; }
    /* Plain cross-fade for stage-level enters. */
    .boot-stage,
    .load-stage,
    .bp-stage,
    .logo-stage {
        animation: stageFadeIn 0.3s ease !important;
    }
    /* Intro dot — short fade instead of explosive grow. */
    .intro-flash { animation: none; opacity: 0.25; }
    .intro-dot { animation: none; transform: scale(1); }
    /* Scanlines stay but static; no flicker. */
}

/* ==========================================================================
   Stage 3.5 — Announcement (Star Wars-style crawl)
   ========================================================================== */
.announcement-stage {
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse at center 55%, #18181c 0%, var(--bg) 70%);
    overflow: hidden;
    cursor: default;
    animation: stageFadeIn 0.4s ease;
}

/* Soft fade gradients top + bottom so text materializes / dissolves
   into the dark instead of hard-cutting at the viewport edges. */
.announcement-stage::before,
.announcement-stage::after {
    content: '';
    position: absolute;
    left: 0; right: 0;
    pointer-events: none;
    z-index: 2;
}
.announcement-stage::before {
    top: 0;
    height: 18vh;
    background: linear-gradient(to bottom, var(--bg) 0%, rgba(14,15,16,0.6) 50%, transparent 100%);
}
.announcement-stage::after {
    bottom: 0;
    height: 14vh;
    background: linear-gradient(to top, var(--bg) 0%, rgba(14,15,16,0.6) 50%, transparent 100%);
}

.announcement-crawl {
    position: absolute;
    left: 50%;
    top: 0;
    /* Wider on desktop so long lines breathe; still constrained by
       viewport on narrow screens. */
    width: min(1200px, 92vw);
    /* Start fully below the viewport. */
    transform: translate(-50%, 100vh);
    color: var(--ink);
    font-family: var(--f-disp);
    font-weight: 400;
    font-size: clamp(16px, 1.55vw, 19px);
    line-height: 1.85;
    letter-spacing: 0.005em;
    will-change: transform;
}
.announcement-crawl.is-crawling {
    /* Duration sized so the proceed button reaches its rest line at
       the bottom of the viewport at a comfortable reading pace. JS in
       announcement.js freezes the animation when the button bottom
       crosses the rest line, so the keyframe `to` value mostly just
       needs to put the button past that line on tall viewports too. */
    animation: announcementCrawl 71s linear forwards;
}

@keyframes announcementCrawl {
    from { transform: translate(-50%, 100vh); }
    to   { transform: translate(-50%, -180%); }
}

/* Once the rAF watcher detects the proceed button has reached its rest
   line, the crawl converts to natural document flow inside a scrollable
   stage. This lets the user scroll up to re-read what just passed by. */
.announcement-crawl.is-settled {
    position: relative;
    top: auto;
    transform: translateX(-50%);
    /* Top padding pushes content down so even on tall desktops the
       page reliably overflows the viewport — guarantees the user can
       scroll up to re-read.
       Bottom padding ensures the button sits at the rest line at max
       scroll instead of being flush against the viewport edge. */
    padding-top: 14vh;
    padding-bottom: 9vh;
    will-change: auto;
}

.announcement-stage.is-scrollable {
    overflow-y: auto;
    /* iOS momentum scroll. */
    -webkit-overflow-scrolling: touch;
}
/* In scrollable / typewriter mode the fade gradients were obscuring
   text the user is trying to read. Hide both so scrolled content is
   clean edge-to-edge. */
.announcement-stage.is-scrollable::before,
.announcement-stage.is-scrollable::after,
.announcement-stage.is-typewriter::before,
.announcement-stage.is-typewriter::after {
    display: none;
}

/* Typewriter mode (desktop) — text reveals one char at a time inside a
   centered, scrollable column. No transform animation; no fade masks. */
.announcement-stage.is-typewriter {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 8vh 4vw;
}
.announcement-typewriter {
    margin: 0 auto;
    max-width: min(1200px, 92vw);
    color: var(--ink);
    font-family: var(--f-disp);
    font-weight: 400;
    font-size: clamp(15px, 1.55vw, 19px);
    line-height: 1.85;
    letter-spacing: 0.005em;
}
/* In typewriter mode the proceed button starts hidden and fades in once
   typing completes. (In crawl mode it's visible and travels with the
   text — a different visual story.) */
.announcement-typewriter .announcement-proceed-btn {
    opacity: 0;
    transform: translateY(8px);
    transition:
        background 0.2s, color 0.2s, box-shadow 0.25s,
        opacity 0.6s ease, transform 0.6s ease;
}
.announcement-typewriter .announcement-proceed-btn.is-ready {
    opacity: 1;
    transform: translateY(0);
}

.announcement-p {
    margin: 0 0 1.4em 0;
}
.announcement-p:last-of-type {
    margin-bottom: 0;
}

/* Brand mentions — same amber halo family as the final logo. The
   third (60px-radius) text-shadow layer is a wide soft halo well
   outside the glyph; the pulse animation breathes that outer layer's
   blur + opacity to give a living-glow feel without any layout cost. */
.announcement-glow {
    color: var(--amber);
    font-weight: 600;
    animation: announcementGlowPulse 3.2s ease-in-out infinite;
}
@keyframes announcementGlowPulse {
    0%, 100% {
        text-shadow:
            0 0 6px rgba(255, 179, 71, 0.70),
            0 0 18px rgba(255, 140, 66, 0.42),
            0 0 38px rgba(255, 179, 71, 0.28);
    }
    50% {
        text-shadow:
            0 0 10px rgba(255, 179, 71, 0.85),
            0 0 28px rgba(255, 140, 66, 0.62),
            0 0 60px rgba(255, 179, 71, 0.50);
    }
}
@media (prefers-reduced-motion: reduce) {
    .announcement-glow {
        animation: none;
        text-shadow:
            0 0 6px rgba(255, 179, 71, 0.70),
            0 0 18px rgba(255, 140, 66, 0.42),
            0 0 38px rgba(255, 179, 71, 0.28);
    }
    /* Crawl animation collapsed — show text statically, allow scrolling. */
    .announcement-stage { overflow-y: auto; }
    .announcement-crawl,
    .announcement-crawl.is-crawling,
    .announcement-crawl.is-finished {
        transform: translate(-50%, 4vh);
        animation: none;
        opacity: 1;
        position: relative;
        left: 50%;
        margin-bottom: 16vh;
    }
}

/* PROCEED button — last child of the crawl, so it travels up with the
   text. Disabled (pointer-events: none) until the rAF watcher in
   announcement.js detects it has reached the rest position; then
   `.is-ready` flips it on with a soft amber pulse. */
.announcement-proceed-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    margin: 3em auto 0;
    padding: 14px 28px;
    background: rgba(14, 15, 16, 0.7);
    border: 1px solid var(--amber);
    color: var(--amber);
    font-family: var(--f-mono);
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.3em;
    cursor: default;
    pointer-events: none;
    opacity: 0.92;
    transition: background 0.2s, color 0.2s, box-shadow 0.25s, opacity 0.4s;
}
.announcement-proceed-btn.is-ready {
    cursor: pointer;
    pointer-events: auto;
    opacity: 1;
    animation: announcementBtnPulse 1.6s ease-in-out infinite;
}
@keyframes announcementBtnPulse {
    0%, 100% { box-shadow: 0 0 18px rgba(255, 179, 71, 0.30); }
    50%      { box-shadow: 0 0 36px rgba(255, 179, 71, 0.65); }
}
.announcement-proceed-btn.is-ready:hover,
.announcement-proceed-btn.is-ready:focus-visible {
    outline: none;
    background: var(--amber);
    color: var(--bg);
    box-shadow:
        0 0 30px rgba(255, 179, 71, 0.55),
        0 0 0 1px var(--amber-glow) inset;
    animation: none;
}
.announcement-proceed-btn.is-ready:hover .announcement-proceed-arrow {
    transform: translateX(4px);
}
.announcement-proceed-arrow {
    display: inline-block;
    transition: transform 0.2s ease;
}

@media (prefers-reduced-motion: reduce) {
    .announcement-proceed-btn {
        transition: opacity 0.2s ease;
        transform: none;
    }
    .announcement-proceed-btn.is-ready { transform: none; }
}

/* ==========================================================================
   Mobile — keep from breaking. Deferred polish work.
   ========================================================================== */
@media (max-width: 768px) {
    .teaser-top { padding: 20px 24px; }
    .teaser-main { padding: 32px 24px; gap: 24px; }
    .load-stage { padding: 8vh 6vw; }
    .load-header { font-size: 10px; gap: 8px; }
    .load-telemetry { grid-template-columns: repeat(3, 1fr); gap: 12px; font-size: 10px; }
    .bp-pass { padding: 24px 20px 18px; }
    .bp-grid { grid-template-columns: repeat(2, 1fr); }
    .reveal-chrome { top: 12px; right: 12px; }
    .reveal-stage-indicator { bottom: 12px; }
}
