/* ==========================================================================
   gc-crt.css — the shared CRT kit.

   Extracted from tv.html's inline block (itself lifted from onboarding.html,
   whose power-off collapse came from overlay-legacy.css) so pages other than
   the TV set can wear the network look without a fourth private copy.
   tv.html still carries its own inline kit for now — its class names differ
   (.scanlines vs .crt-scanlines) and that page is churned by other work, so
   adopting this file there is a separate, deliberate step.

   Class names and keyframes are all gc/crt-prefixed so this file can coexist
   with any page's local styles. Colors lean on gc-theme.css tokens with
   literal fallbacks so the file also works standalone.
   ========================================================================== */

:root {
    --crt-ease: cubic-bezier(0.22, 1, 0.36, 1);
    --phosphor: #58e05d;
    --phosphor-red: #ff5a5a;
    --phosphor-gold: #f2c14e;
}

/* ---------- the set: bezel + tube ---------- */

.crt-bezel {
    position: relative;
    background: #08090b;
    border: 1px solid var(--line-strong, rgba(255, 255, 255, .14));
    padding: 12px;
    box-shadow:
        inset 0 0 0 1px rgba(0, 0, 0, .65),
        inset 0 0 24px rgba(0, 0, 0, .8),
        0 0 46px rgba(22, 105, 183, .12);
    transition: box-shadow .6s;
}
.crt-bezel.glow-red {
    box-shadow:
        inset 0 0 0 1px rgba(0, 0, 0, .65),
        inset 0 0 24px rgba(0, 0, 0, .8),
        0 0 46px rgba(225, 29, 72, .16);
}
.crt-bezel.glow-green {
    box-shadow:
        inset 0 0 0 1px rgba(0, 0, 0, .65),
        inset 0 0 24px rgba(0, 0, 0, .8),
        0 0 46px rgba(88, 224, 93, .14);
}

.crt-tube {
    position: relative;
    aspect-ratio: 16 / 9;
    background: #000;
    overflow: hidden;
}

/* ---------- glass dressing (paint these on OUR surfaces only — never over a
   third-party embed: tinting an embedded player tints the ads inside it) ---------- */

.crt-scanlines {
    position: absolute; inset: 0; z-index: 4;
    background: repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.16) 0 1px, transparent 1px 3px);
    pointer-events: none;
}
@media (min-width: 1500px) { .crt-scanlines { opacity: .6; } }

.crt-vignette {
    position: absolute; inset: 0; z-index: 5;
    background: radial-gradient(ellipse at center, transparent 58%, rgba(0, 0, 0, .38) 100%);
    pointer-events: none;
}

/* ---------- analog static. One layer, two moods: an infinite HOLD that covers
   a wait, and a timed BURST envelope. The noise tile only scrolls while a mood
   class is on, so an idle layer animates nothing. Removing .hold fades out
   through the opacity transition — that fade is the "settle". ---------- */

.crt-static {
    position: absolute; inset: 0; z-index: 50;
    overflow: hidden; pointer-events: none;
    opacity: 0;
    transition: opacity .25s ease-out;
}
.crt-static::before {
    content: '';
    position: absolute; top: -50%; left: -50%;
    width: 200%; height: 200%;
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.5' numOctaves='6' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.9'/%3E%3C/svg%3E");
    background-size: 256px 256px;
}
.crt-static.hold, .crt-static.burst { opacity: 1; }
.crt-static.hold::before, .crt-static.burst::before {
    animation: gcStaticScroll 0.03s steps(10) infinite;
}
.crt-static.hold { opacity: .92; transition: none; }
.crt-static.burst { animation: gcSwitchStatic 0.8s ease-out forwards; }

/* Coarse, quieter grain for card backgrounds (dead air / no signal). */
.crt-grain::after {
    content: '';
    position: absolute; top: -50%; left: -50%;
    width: 200%; height: 200%;
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
    background-size: 128px 128px;
    animation: gcStaticScroll 0.08s steps(4) infinite;
    opacity: 0.3;
    pointer-events: none;
}

/* ---------- SMPTE-ish test bars in the gc palette ---------- */

.crt-bars {
    background: linear-gradient(90deg,
        #9aa5b1 0 14.28%, var(--gold, #f2b705) 14.28% 28.57%, #3fbcd4 28.57% 42.85%,
        var(--green, #22c55e) 42.85% 57.14%, #b0589f 57.14% 71.42%, var(--red, #e11d48) 71.42% 85.71%,
        var(--blue, #1669b7) 85.71% 100%);
}

/* ---------- phosphor OSD type. Position is the page's business; this is only
   the glow. ---------- */

.crt-osd {
    font-weight: 800; letter-spacing: .2em; text-transform: uppercase;
    font-variant-numeric: tabular-nums;
    color: var(--phosphor); text-shadow: 0 0 8px rgba(88, 224, 93, .8);
}
.crt-osd.red  { color: var(--phosphor-red);  text-shadow: 0 0 8px rgba(255, 90, 90, .8); }
.crt-osd.gold { color: var(--phosphor-gold); text-shadow: 0 0 8px rgba(242, 193, 78, .8); }

/* The classic phosphor block bar (volume / progress). Mark blocks lit with .on. */
.crt-blocks { display: flex; gap: 3px; }
.crt-blocks i {
    width: clamp(8px, 1.1vw, 14px); height: clamp(12px, 1.6vw, 20px);
    background: rgba(88, 224, 93, .18);
    border: 1px solid rgba(88, 224, 93, .35);
}
.crt-blocks i.on {
    background: var(--phosphor);
    box-shadow: 0 0 6px rgba(88, 224, 93, .8);
}

/* Blinking live dot — pair with color from the page. */
.crt-blink { animation: gcBlink 1.6s ease-in-out infinite; }

/* ---------- keyframes ---------- */

@keyframes gcCrtOn {
    0%   { opacity: 0; transform: scale(0.985); filter: brightness(1.5) saturate(0.6); }
    55%  { opacity: 1; filter: brightness(1.12) saturate(0.9); }
    100% { opacity: 1; transform: scale(1); filter: brightness(1) saturate(1); }
}
.crt-on { animation: gcCrtOn .5s var(--crt-ease) both; }

@keyframes gcStaticScroll {
    0%   { transform: translate(0, 0); }
    25%  { transform: translate(-10%, -15%); }
    50%  { transform: translate(5%, 10%); }
    75%  { transform: translate(-5%, 5%); }
    100% { transform: translate(10%, -10%); }
}
@keyframes gcSwitchStatic {
    0%, 100% { opacity: 0; }
    5%, 25%  { opacity: 0.9; }
    30%, 50% { opacity: 0.4; }
    55%      { opacity: 0; }
}
@keyframes gcOsdFlash { 0% { opacity: 0; } 8%, 70% { opacity: 1; } 100% { opacity: 0; } }
@keyframes gcBlink { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@keyframes gcPsPulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

/* ---------- power-on intro (static/js/gc/power-on.js) ----------
   The first page of a visit opens like a set being switched on: a white dot,
   a scanline, the tube opening onto static, then the page settling from
   over-bright. It is the TV page's crtTurnOffViolent run backwards.

   Two layers, so it can never strand a black page:
   1. html.gc-po::after - a plain black cover painted from the very first frame
      (an inline <head> script adds the class). It fades itself out at 2.5s on
      a CSS animation alone, so a script that never loads still uncovers the page.
   2. .gc-poweron - the real intro, built by power-on.js; it removes the class
      the moment it is attached, and removes itself when its animation ends. */

html.gc-po::after {
    content: ''; position: fixed; inset: 0; z-index: 2147483000; background: #000;
    pointer-events: none;
    animation: gcPoCover 2.5s step-end forwards;
}
@keyframes gcPoCover { to { visibility: hidden; } }

.gc-poweron {
    position: fixed; inset: 0; z-index: 2147483001; background: #000; cursor: pointer;
    animation: gcPoFade 2.1s linear forwards;
}
.gc-poweron .gc-po-tube {
    position: absolute; inset: 0; overflow: hidden; background: #000;
    animation: gcPoTube 2.1s linear forwards;
}
.gc-poweron canvas { width: 100%; height: 100%; display: block; filter: contrast(1.25) brightness(.9); }
.gc-poweron .gc-po-tube::after {
    content: ''; position: absolute; inset: 0;
    background: repeating-linear-gradient(0deg, rgba(0, 0, 0, .35) 0 1px, transparent 1px 3px);
}
.gc-poweron .gc-po-roll {
    position: absolute; left: 0; right: 0; height: 30%; top: -30%;
    background: linear-gradient(180deg, transparent, rgba(255, 255, 255, .10) 45%, rgba(0, 0, 0, .25) 60%, transparent);
    animation: gcPoRoll 1.1s linear infinite;
}
.gc-poweron .gc-po-flash {
    position: absolute; inset: 0; background: #fff;
    box-shadow: 0 0 80px 40px rgba(255, 255, 255, .8);
    animation: gcPoFlash 2.1s linear forwards;
}
.gc-poweron .gc-po-osd {
    position: absolute; top: max(28px, env(safe-area-inset-top, 0px)); left: 32px; z-index: 2;
    display: flex; flex-direction: column; gap: 4px; opacity: 0;
    font-family: 'Oxanium', 'Trebuchet MS', sans-serif; color: var(--phosphor, #58e05d);
    text-shadow: 0 0 12px rgba(88, 224, 93, .7);
    background: rgba(0, 0, 0, .55); padding: 10px 14px;
    animation: gcPoOsd 2.1s linear forwards;
}
.gc-poweron .gc-po-osd b { font-size: clamp(32px, 5vw, 64px); font-weight: 800; line-height: 1; }
.gc-poweron .gc-po-osd span { font-size: 13px; font-weight: 700; letter-spacing: .3em; }
.gc-poweron .gc-po-skip {
    position: absolute; right: 24px; bottom: max(20px, env(safe-area-inset-bottom, 0px)); z-index: 2;
    font-family: 'Oxanium', 'Trebuchet MS', sans-serif; font-size: 11px; letter-spacing: .2em;
    text-transform: uppercase; color: rgba(255, 255, 255, .75);
    background: rgba(0, 0, 0, .6); padding: 6px 10px;
}
/* The page underneath, settling from over-bright once the tube clears. */
html.gc-po-settle { animation: gcPoSettle .45s ease-out both; }

@keyframes gcPoTube {
    0%    { opacity: 0; transform: scale(.004, .004); }
    4%    { opacity: 1; transform: scale(.004, .004); }
    9.5%  { opacity: 1; transform: scale(.004, .004); }
    20%   { opacity: 1; transform: scale(1, .006); }
    33%   { opacity: 1; transform: scale(1, 1); animation-timing-function: cubic-bezier(.2, .9, .3, 1); }
    100%  { opacity: 1; transform: scale(1, 1); }
}
@keyframes gcPoFlash { 0%, 30% { opacity: 1; } 42%, 100% { opacity: 0; } }
@keyframes gcPoOsd { 0%, 36% { opacity: 0; } 40%, 76% { opacity: 1; } 80%, 100% { opacity: 0; } }
@keyframes gcPoFade {
    0%, 80% { opacity: 1; }
    86% { opacity: .35; }
    89% { opacity: .7; }
    100% { opacity: 0; visibility: hidden; }
}
@keyframes gcPoRoll { from { top: -30%; } to { top: 100%; } }
/* Filter only, and only ever on <html>: a filter or transform on any other
   ancestor becomes the containing block for position:fixed, and the navbar
   would jump for the length of the animation. */
@keyframes gcPoSettle {
    0%   { filter: brightness(1.6) saturate(.5); }
    60%  { filter: brightness(1.15) saturate(.85); }
    100% { filter: none; }
}

/* ---------- motion off means static off ---------- */

@media (prefers-reduced-motion: reduce) {
    .crt-on, .crt-static.burst { animation: none !important; }
    .crt-static::before, .crt-grain::after { animation: none !important; }
    .crt-static, .crt-grain::after { display: none !important; }
    .crt-blink { animation: none !important; }
    /* power-on.js never starts for these visitors; this is the belt to its braces. */
    html.gc-po::after, .gc-poweron { display: none !important; }
    html.gc-po-settle { animation: none !important; }
}
