/* ═══════════════════════════════════════════
   graduation-glow-v2 — the shell (build contract §7.2)

   The stage, its three set-piece canvases, the camera world that holds
   every beat's <section>, the mute control, and the few rules the film
   spine (js/app.js) relies on. Beats style only their own prefixed
   classes; .screen, the stage and the canvases belong here.

   Stacking inside #stage (all position: absolute over one box):
     0  .aurora-bg        fixed warm horizon + wine haze (outside the camera)
     0  #fx-back          the ambient bokeh (film.ambient), under the world
     1  #world            the camera world: the starfield + every beat
     1  .name-in-lights-masthead   hoisted after #world by name-in-lights
     2  #fx-light         nameAssemble, lightDissolve
     3  the hit flash     (.reveel-flash::after), blooming from --flash-x/-y
     4  #fx-burst         goldBurst, brightest of all
     8  #stage-mute
   ═══════════════════════════════════════════ */

html,
body {
    height: 100%;
    margin: 0;
}

body {
    background: var(--void);
    color: var(--text-primary);
    font-family: var(--font-body);
    overflow: hidden;
    overscroll-behavior: none;
    -webkit-tap-highlight-color: transparent;
    -webkit-font-smoothing: antialiased;
}

button {
    font: inherit;
}

/* ───── The stage: ReveelStage's camera box, one phone screen tall ───── */
#stage {
    width: 100%;
    height: 100vh;
    height: 100dvh;
    background:
        radial-gradient(130% 55% at 50% 108%, var(--sky-horizon-glow), transparent 62%),
        radial-gradient(95% 55% at 50% -8%, var(--sky-wine-haze), transparent 70%),
        linear-gradient(180deg, var(--sky-zenith) 0%, var(--sky-mid) 100%);
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
}

/* The primitive's hit flash, its timing untouched: over the world and the
   name's light, under the burst sparks so they read brightest, blooming
   from wherever the set piece is (--flash-x/-y, set on #stage by cap-toss
   at the throw and by years-in-order at the trace) rather than the middle. */
.reveel-stage.reveel-flash::after {
    z-index: 3;
    background: radial-gradient(circle at var(--flash-x, 50%) var(--flash-y, 50%),
        var(--flash-core) 0%, var(--flash-mid) 40%, transparent 75%);
}

/* ───── The aurora: a low warm horizon and a far wine haze ─────
   Outside the camera world, so no camera move drags the sky's glow with
   it. blob-2's shared rose gradient is replaced with an amber-deep one
   (concept.md: the horizon warms without turning pink). */
.reveel-stage > .aurora-bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    opacity: 0.63;                 /* the blobs' own 0.35 -> ~0.22 on the ground */
}
.reveel-stage > .aurora-bg .aurora-blob-2 {
    width: 120vw;
    height: 70vw;
    max-width: 1100px;
    max-height: 700px;
    right: -10vw;
    bottom: -28%;
    background: radial-gradient(ellipse at center, var(--aurora-horizon) 0%, transparent 70%);
}

/* ───── The set-piece canvases: inert, covering the stage ───── */
.fx {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
}
.fx-back { z-index: 0; }
.fx-light { z-index: 2; }
.fx-burst { z-index: 4; }

/* ───── The world the camera moves ───── */
.reveel-stage-world {
    z-index: 1;
}

/* Every beat is a full-bleed layer of the world. Only the director changes
   which one is active (a hard cut on the beat boundary: each beat's exit
   composes the frame for the next, and its entrance cue reveals it, so
   there is no fade and no entrance stagger here). */
.screen {
    position: absolute;
    inset: 0;
    display: none;
    opacity: 0;
}
.screen.active {
    display: flex;
    opacity: 1;
}

/* The overture is a card in screen space. The camera waits far back
   (z -320) through it, which would shrink the card and its full-bleed
   scrim to 74% of the stage; the section cancels the camera's pose so the
   card sits at its layout size and the ember drifts to the same 50%/40%
   point the masthead name stands on. The camera never moves during the
   overture (camera.set), so no transition is needed to stay in step. */
#screen-overture {
    transform:
        rotateY(calc(var(--cam-roty, 0deg) * -1))
        translate3d(calc(var(--cam-x, 0px) * -1), calc(var(--cam-y, 0px) * -1), calc(var(--cam-z, 0px) * -1));
}

/* Entry states are applied instantly (the spine's prepare on goto), never
   animated in. */
.instant,
.instant *,
.instant *::before,
.instant *::after {
    transition: none !important;
}

/* ───── Mute ───── */
.stage-mute {
    position: absolute;
    z-index: 8;
    top: calc(14px + env(safe-area-inset-top, 0px));
    right: 14px;
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.5rem 0.8rem;
    font: 500 0.74rem/1 var(--font-body);
    letter-spacing: 0.06em;
    color: var(--text-primary);
    background: var(--glass);
    border: 1px solid var(--glass-border);
    border-radius: 999px;
    cursor: pointer;
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
}
.stage-mute-icon {
    width: 15px;
    height: 15px;
}
.stage-mute .stage-mute-x { display: none; }
.stage-mute[aria-pressed="true"] .stage-mute-x { display: inline; }
.stage-mute[aria-pressed="true"] .stage-mute-waves { display: none; }
.stage-mute[aria-pressed="true"] {
    color: var(--accent-warm-bright);
    border-color: var(--glass-border-hover);
}
.stage-mute:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 3px;
}

/* ───── Reduced motion: the film still plays in full, calmly ─────
   The camera and shake no-op inside ReveelStage; here the sky holds still. */
@media (prefers-reduced-motion: reduce) {
    .reveel-stage > .aurora-bg .aurora-blob {
        animation: none;
    }
}
