/* player-rs styles — ported from client/src/styles.css (PR-2).
   The Rust renderer emits the same `src-*` class names the React components use,
   so these styles paint the wasm player identically. client/ is legacy; as the
   port completes this file becomes the player's own stylesheet. */
@import url("https://fonts.googleapis.com/css2?family=Great+Vibes&family=Metal+Mania&family=Pirata+One&family=Press+Start+2P&display=swap");

:root {
  color-scheme: dark;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
  background: #000;
  overflow: hidden;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* The stage: a positioned root so each `.player-layer` (absolute, inset 0) stacks
   inside it by z-index, mirroring the React player's channel/layer model. */
#player {
  position: fixed;
  inset: 0;
}

.player-layer {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
}

/* Canvas-native layer (Starfield, OuijaBoard): the pump paints it via paint_source.
   inset:0 alone won't stretch a replaced <canvas> — set the box explicitly so
   client_width/height (and thus the backing store) fill the stage. */
.player-canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* Idle floor — the always-on VHS/CRT standby screen behind live layers (z 0, never raw black).
   Full-bleed; the `.src-vhs-pause` child is itself position:absolute inset:0. */
.player-idle {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Lifecycle badge (PR-4) — corner status chip reflecting the Phase machine. */
.player-badge {
  position: absolute;
  top: 12px;
  z-index: 9999;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(6px);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.player-badge--right  { right: 12px; }
.player-badge--left   { left: 12px; }
.player-badge--center { left: 50%; transform: translateX(-50%); }
/* Registered so it can TRANSITION (plain custom props can't animate). `--expand` is the only
   animated axis on the chip — the blob stretch on click — while proximity (`--prox`) stays an
   un-animated, instantaneous var so it never stutters. Two independent axes, one chip. */
@property --expand {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}
.player-badge--main {
  /* TWO axes, neither regressing the other:
     1. Proximity widen — the cursor publisher writes `--prox` (0..1, 0 = at REACH px, 1 = direct
        hover) on <body> each mouse frame. Width LERPs off `--prox` between `--w-start`/`--w-end`;
        NO transition on width, so it tracks the cursor 1:1 (a transition would chase a moving
        target and stutter).
     2. Click expand — `--expand` (0→1) blends the compact width into the big `--expanded-w` and
        grows the height + un-rounds the radius. ONLY `--expand` is transitioned, so the toggle
        animates (blob stretch) without touching the proximity smoothness. */
  --w-start: 120px;
  --w-end: 280px;
  --compact-w: calc(var(--w-start) + var(--prox, 0) * (var(--w-end) - var(--w-start)));
  --expanded-w: 360px;
  --h-compact: 34px;
  --h-expanded: 210px;
  --expand: 0;
  padding: 0;
  min-width: 0;
  width: calc(var(--compact-w) + (var(--expanded-w) - var(--compact-w)) * var(--expand));
  height: calc(var(--h-compact) + (var(--h-expanded) - var(--h-compact)) * var(--expand));
  border-radius: calc(999px + (18px - 999px) * var(--expand));
  /* Background rides `--expand`: #222 at the fully-collapsed pill, #111 the moment it starts
     expanding — so the big blob is never lighter, even mid-collapse. */
  background: color-mix(in srgb, #222222 calc((1 - var(--expand, 0)) * 100%), #111111);
  overflow: hidden;
  cursor: pointer;
  transition: --expand 420ms cubic-bezier(0.4, 0, 0.2, 1);
}
.player-badge--main .player-badge__dot { display: none; }
/* Hover darken on the COLLAPSED pill only; the expanded blob is already #111 and uses a default
   cursor with no hover reaction. */
.player-badge--main:not(.is-expanded):hover { background: #111111; }
.player-badge--main.is-expanded {
  --expand: 1;
  cursor: default;
}

/* Compact pill row: label left, placeholder right. Fades OUT as the chip expands; the two texts
   fade IN with proximity (opacity rides `--prox` — same 0→1 keyframe as the width). */
.player-badge__compact {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 14px;
  opacity: calc(1 - var(--expand, 0));
}
.player-badge__label { color: #fff; opacity: var(--prox, 0); }
.player-badge__meta { color: #fff; opacity: var(--prox, 0); }
/* Hamburger: absolutely centred in the chip (NOT a flex item — so the differing label/meta widths
   can't shove it off-centre), full opacity at rest, fades out as the texts fade in on proximity. */
.player-badge__burger {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  color: #fff;
  opacity: calc(1 - var(--prox, 0));
}
.player-badge__burger svg { width: 16px; height: 16px; }

/* Expanded mini-UI: cross-fades in over the compact row (opacity rides `--expand`). */
.player-badge__expanded {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px 18px;
  /* Opacity is class-driven (NOT --expand) with its own fast fade, so on hover-off the mini-UI
     cross-dissolves out quickly + gracefully while the blob morphs back — the Apple feel. */
  opacity: 0;
  transition: opacity 260ms cubic-bezier(0.4, 0, 0.2, 1);
  pointer-events: none;
  text-transform: none;
  letter-spacing: normal;
}
.player-badge--main.is-expanded .player-badge__expanded {
  opacity: 1;
  pointer-events: auto;
}
.mini-ui__title {
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}
.mini-ui__row {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
}
.mini-ui__row span { color: rgba(255, 255, 255, 0.55); }
.mini-ui__row b { color: #fff; font-weight: 600; }
.player-badge__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #f5a623; /* connecting / hydrating */
}
.player-badge.is-live .player-badge__dot,
.player-badge.is-standby .player-badge__dot {
  background: #2ecc71;
}
.player-badge.is-reconnecting .player-badge__dot {
  background: #e74c3c;
}
/* Right chip in code mode: white key icon, sized to match the live chip's 8px dot. */
.player-badge__icon {
  display: inline-flex;
  align-items: center;
  color: #fff;
}
.player-badge__icon svg {
  width: 8px;
  height: 8px;
}
.player-badge--code {
  cursor: pointer;
}

/* Join-code QR dialog — opened by clicking the right code chip. Backdrop dims the show; the
   card centers the scannable QR + the human code. z above the badges (9999). */
.qr-modal {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(4px);
}
.qr-modal__card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 28px 32px;
  border-radius: 16px;
  background: #ffffff;
  color: #111111;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.qr-modal__close {
  position: absolute;
  top: 10px;
  right: 12px;
  border: none;
  background: none;
  font-size: 18px;
  line-height: 1;
  color: #888;
  cursor: pointer;
}
.qr-modal__close:hover {
  color: #111;
}
.qr-modal__title {
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #555;
}
.qr-modal__qr {
  width: 220px;
  height: 220px;
}
.qr-modal__qr svg {
  width: 100%;
  height: 100%;
  display: block;
}
.qr-modal__code {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: 0.12em;
}
.qr-modal__hint {
  font-size: 12px;
  color: #888;
}

/* Left chip = liveness signal. The dot encodes link state by MOTION, not just colour, so
   "blinking = alive" reads at a glance and the séance-red pulse only fires when truly live:
   - live        → red, pulsing (the show is on air)
   - connecting  → amber, steady
   - no signal   → dark, steady (distinct from the pulse so a dropped link never looks live) */
.player-badge--left.is-live .player-badge__dot {
  background: #e74c3c;
  animation: badge-pulse 1.1s ease-in-out infinite;
}
.player-badge--left.is-connecting .player-badge__dot {
  background: #f5a623;
}
.player-badge--left.is-reconnecting .player-badge__dot {
  background: #555555;
}
@keyframes badge-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}

/* Co-watcher cursors — the ephemeral presence overlay. Each peer's cursor is a
   positioned dot (top-left anchored at the relayed client x/y) above all layers. */
.peer-cursor {
  position: absolute;
  z-index: 9998;
  width: 12px;
  height: 12px;
  margin: -6px 0 0 -6px; /* centre the dot on the point */
  border-radius: 50%;
  background: #4aa3ff;
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.55), 0 0 12px rgba(74, 163, 255, 0.7);
  pointer-events: none;
  transition: left 80ms linear, top 80ms linear;
}
.peer-cursor__tag {
  position: absolute;
  left: 14px;
  top: -2px;
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 10px;
  letter-spacing: 0.04em;
  color: #fff;
  background: rgba(74, 163, 255, 0.85);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  white-space: nowrap;
}

/* Un-ported component fallback monitor (was the whole spike output). */
.src-monitor {
  position: absolute;
  inset: 0;
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  color: #d7ffd7;
  background: radial-gradient(120% 120% at 50% 0%, #0a160a 0%, #000 70%);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.src-monitor header {
  display: flex;
  gap: 12px;
  align-items: baseline;
}
.src-monitor .kind {
  text-transform: uppercase;
  font-size: 11px;
  letter-spacing: 0.25em;
  background: #0f0;
  color: #000;
  padding: 2px 8px;
  border-radius: 3px;
}
.src-monitor .name {
  font-size: 28px;
  font-weight: 700;
  color: #eaffea;
}
.src-monitor pre {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: #9fe89f;
  white-space: pre-wrap;
}

/* ── BreakingNews ───────────────────────────────────────────────── */
.src-breaking-news {
  width: 100%;
  padding: 48px;
  background: linear-gradient(0deg, rgba(0, 0, 0, 0.85), transparent);
  color: #fff;
}
.src-breaking-news__tag {
  display: inline-block;
  padding: 4px 12px;
  background: #c0392b;
  font-weight: 700;
  letter-spacing: 0.1em;
  font-size: 14px;
}
.src-breaking-news__headline {
  margin: 12px 0 0;
  font-size: 48px;
  line-height: 1.05;
}
.src-breaking-news__subhead {
  margin: 8px 0 0;
  font-size: 22px;
  opacity: 0.85;
}

/* ── LowerThird ─────────────────────────────────────────────────── */
.src-lower-third {
  width: 100%;
  padding: 0 48px 64px;
}
.src-lower-third__bar {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  padding: 14px 22px;
  background: rgba(20, 40, 90, 0.92);
  border-left: 4px solid #4a90d9;
  color: #fff;
}
.src-lower-third__title {
  font-size: 26px;
  font-weight: 600;
}
.src-lower-third__subtitle {
  font-size: 16px;
  opacity: 0.8;
}

/* ── media ──────────────────────────────────────────────────────── */
.src-media {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ── VHS / CRT pause screen ─────────────────────────────────────── */
.src-vhs-pause {
  --vhs-tint: #171da8;
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--vhs-tint);
  font-family: "Press Start 2P", monospace;
  animation: vhs-flicker 5ms infinite;
}
.src-vhs-pause::after {
  content: "";
  position: absolute;
  inset: 0;
  box-shadow: inset 0 0 10em rgba(0, 0, 0, 0.75);
  pointer-events: none;
}
@keyframes vhs-flicker {
  28% { filter: brightness(1); }
  30% { filter: brightness(0.95); }
  33% { filter: brightness(1); }
  34% { filter: brightness(0.9); }
  35% { filter: brightness(1); }
}
.src-vhs-pause__message {
  position: relative;
  margin: 4em;
  animation: vhs-track 5ms infinite;
}
.src-vhs-pause__message h1 {
  position: absolute;
  left: 0;
  margin: 0;
  font-size: 3em;
  color: #fff;
  filter: blur(3px);
  text-shadow: 1px 3px green, -2px -3px red;
}
.src-vhs-pause__message span {
  animation: vhs-blur 30ms infinite, vhs-flick 50ms infinite, vhs-jump 50ms infinite;
}
@keyframes vhs-blur {
  0% { filter: blur(1px); opacity: 0.8; }
  50% { filter: blur(1px); opacity: 1; }
  100% { filter: blur(1px); opacity: 0.8; }
}
@keyframes vhs-flick {
  50% { left: 2px; }
  51% { left: 0; }
}
@keyframes vhs-jump {
  30% { top: 10px; }
  31% { top: 0; }
}
@keyframes vhs-track {
  40% { opacity: 1; top: 0; left: 0; transform: skew(0, 0); }
  41% { opacity: 0.8; top: 0; left: -100px; transform: skew(50deg, 0); }
  42% { opacity: 0.8; top: 0; left: 100px; transform: skew(-80deg, 0); }
  43% { opacity: 1; top: 0; left: 0; transform: skew(0, 0); }
}
.src-vhs-pause__bottom {
  position: absolute;
  bottom: 0;
  width: 100%;
}
.src-vhs-pause__line {
  position: relative;
  width: 100%;
  height: 3px;
  animation: vhs-appear 1s infinite, vhs-flick 1s infinite, vhs-big-jump 5ms infinite;
}
.src-vhs-pause__white { position: relative; height: 4px; background: #fff; }
.src-vhs-pause__red { position: relative; height: 1px; background: red; }
.src-vhs-pause__green { position: relative; height: 1px; background: green; }
@keyframes vhs-appear {
  0% { filter: blur(5px); opacity: 0.85; }
  50% { filter: blur(3px); opacity: 0.85; }
  100% { filter: blur(4px); opacity: 0.85; }
}
@keyframes vhs-big-jump {
  0% { top: 0; }
  10% { top: -100px; }
  12% { top: 0; }
  54% { top: 0; }
  55% { top: -300px; }
  56% { top: 0; }
  86% { top: 0; }
  87% { top: -600px; }
  88% { top: 0; }
}

/* ── TitleScreen ────────────────────────────────────────────────── */
.src-title-screen {
  --vhs-tint: #171da8;
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.2em;
  overflow: hidden;
  background: var(--vhs-tint);
  font-family: "Press Start 2P", monospace;
}
.src-title-screen::after {
  content: "";
  position: absolute;
  inset: 0;
  box-shadow: inset 0 0 10em rgba(0, 0, 0, 0.75);
  pointer-events: none;
}
.src-title-screen::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.18) 0,
    rgba(0, 0, 0, 0.18) 1px,
    transparent 1px,
    transparent 3px
  );
}
.src-title-screen__logo {
  width: min(50%, 28em);
  height: auto;
  image-rendering: pixelated;
  filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.35));
}
.src-title-screen__logo--mono {
  aspect-ratio: 1 / 1;
  -webkit-mask: var(--logo-src) center / contain no-repeat;
  mask: var(--logo-src) center / contain no-repeat;
  filter: drop-shadow(0 0 8px currentColor);
}
.src-title-screen__presents {
  position: relative;
  z-index: 2;
  margin: 0;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 1.7em;
  font-weight: 800;
  letter-spacing: 0.5em;
  text-indent: 0.25em;
  text-transform: uppercase;
  color: #fff;
}
.src-title-screen__text {
  position: relative;
  z-index: 2;
  margin: 0;
  padding: 0 0.5em;
  font-size: 3em;
  line-height: 1.4;
  color: #fff;
  text-align: center;
}

/* ── SMPTE color bars (EG-1, 75%) ───────────────────────────────── */
.src-smpte {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: #000;
}
.src-smpte__top {
  flex: 0 0 67%;
  display: flex;
}
.src-smpte__mid {
  flex: 0 0 8%;
  display: flex;
}
.src-smpte__top span,
.src-smpte__mid span {
  flex: 1;
}
.src-smpte__bottom {
  flex: 1;
  display: flex;
}
.src-smpte__bottom > span {
  height: 100%;
}
.src-smpte__i {
  flex: 0 0 16.66%;
  background: #00214c;
}
.src-smpte__white {
  flex: 0 0 16.66%;
  background: #fff;
}
.src-smpte__q {
  flex: 0 0 16.66%;
  background: #32006a;
}
.src-smpte__pluge {
  flex: 0 0 25%;
  display: flex;
  background: #131313;
}
.src-smpte__pluge i {
  flex: 1;
  height: 100%;
}
.src-smpte__pluge-sub { background: #0a0a0a; }
.src-smpte__pluge-black { background: #131313; }
.src-smpte__pluge-super { background: #1d1d1d; }
.src-smpte__black {
  flex: 1;
  background: #131313;
}
.src-smpte__label {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 6%;
  text-align: center;
  color: #fff;
  font-family: "Press Start 2P", monospace;
  font-size: 1rem;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.6);
}

/* ── INCOMING TRANSMISSION ──────────────────────────────────────── */
.src-incoming {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.src-incoming__bar {
  width: 100%;
  padding: 3.5vh 0;
  background: #000;
  display: flex;
  align-items: center;
  justify-content: center;
}
.src-incoming__text {
  color: #fff;
  font-family: Helvetica, Arial, "Helvetica Neue", sans-serif;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.35em;
  text-indent: 0.35em;
  font-size: 4vh;
}
.src-incoming__text--blink {
  animation: incoming-blink 1.1s steps(1, end) infinite;
}
@keyframes incoming-blink {
  50% { opacity: 0; }
}

/* ── §ppp · Prince, Powder, Party (NES title card) ──────────────────
   Ported from client styles.css §ppp. Hero words render as LIVE display-
   font text (no PixelText canvas) — .src-ppp__word carries the 8-bit-ish
   drop-shadow; per-word font-family + color set inline by components.rs. */
.src-ppp {
  --vhs-tint: #4a4a4a;
  --ppp-ink: #1c1305;
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6em;
  overflow: hidden;
  background: var(--vhs-tint);
}
.src-ppp::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  box-shadow: inset 0 0 10em rgba(0, 0, 0, 0.75);
}
.src-ppp::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.18) 0,
    rgba(0, 0, 0, 0.18) 1px,
    transparent 1px,
    transparent 3px
  );
}
.src-ppp__graphic {
  width: min(34%, 17em);
  height: auto;
  image-rendering: pixelated;
  filter: drop-shadow(0 3px 0 rgba(0, 0, 0, 0.4));
  z-index: 2;
}
.src-ppp__title {
  position: relative;
  z-index: 2;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.05em;
  text-align: center;
  line-height: 1;
}
.src-ppp__line {
  display: flex;
  align-items: center;
  gap: 0.3em;
}
.src-ppp__small {
  font-family: "Press Start 2P", monospace;
  font-size: 0.85em;
  color: #fff7e6;
  text-transform: uppercase;
  text-shadow: 2px 2px 0 var(--ppp-ink);
}
.src-ppp__word {
  font-size: 3.2em;
  line-height: 0.9;
  text-shadow: 3px 3px 0 var(--ppp-ink);
}
.src-ppp__footer {
  position: relative;
  z-index: 2;
  margin: 0.4em 0 0;
  font-family: "Press Start 2P", monospace;
  font-size: 0.7em;
  letter-spacing: 0.25em;
  text-indent: 0.25em;
  color: #fff;
  text-shadow: 2px 2px 0 var(--ppp-ink);
}
.src-ppp__footer--blink {
  animation: ppp-blink 1.1s steps(1) infinite;
}
@keyframes ppp-blink {
  50% { opacity: 0; }
}
