/* L-Vontronix531 — CRT cabinet + broadcast overlay
   The overlay is a fixed 1920x1080 layer scaled as one unit (see app.js),
   so every graphic keeps its exact position at any window size. */

:root {
  --wood: #4a3427;
  --wood-hi: #6b4c39;
  --panel: #d9cbb2;
  --panel-dark: #b8a887;
  --ink: #2b2318;
  --room: #14100d;
  --knob: #2a2320;
  --led: #ff6a2b;

  /* broadcast-safe-ish white: real character generators never hit 100 IRE */
  --tv-white: #ebebe6;
  --tv-yellow: #e8c33a;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: radial-gradient(circle at 50% 30%, #221b15 0%, var(--room) 70%);
  color: var(--ink);
  font-family: "Jost", ui-sans-serif, system-ui, sans-serif;
  display: grid;
  place-items: stretch;
  padding: clamp(0.4rem, 1.2vw, 1.1rem);
  height: 100dvh;
  overflow: hidden;
}

/* Fill the screen. The set is the room, not a card floating in one. */
.room {
  width: 100%;
  height: 100%;
  max-width: none;
  display: grid;
}

/* ---------- cabinet ---------- */

.cabinet {
  position: relative;
  background-image:
    linear-gradient(160deg, rgba(121, 83, 53, 0.34) 0%, rgba(42, 27, 18, 0.28) 48%, rgba(15, 9, 6, 0.58) 100%),
    url("assets/crt/crt-walnut-veneer.jpg");
  background-size: cover, cover;
  background-position: center;
  background-repeat: no-repeat;
  background-blend-mode: soft-light, normal;
  border-radius: 18px;
  padding: clamp(0.75rem, 2vw, 1.5rem);
  box-shadow:
    0 2px 0 rgba(255, 255, 255, 0.12) inset,
    0 -3px 0 rgba(0, 0, 0, 0.35) inset,
    0 30px 70px rgba(0, 0, 0, 0.7);
  display: grid;
  grid-template-columns: 1fr clamp(200px, 15vw, 300px);
  gap: clamp(0.75rem, 1.4vw, 1.5rem);
  height: 100%;
  min-height: 0;   /* lets the grid children actually shrink to fit */
}

.cabinet.crt2 {
  background-image:
    linear-gradient(145deg, rgba(91, 99, 105, 0.24) 0%, rgba(18, 20, 22, 0.22) 44%, rgba(0, 0, 0, 0.66) 100%),
    url("assets/crt2/crt2-cabinet-graphite.jpg");
  background-blend-mode: soft-light, normal;
  border-radius: 7px;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.16) inset,
    0 -2px 0 rgba(0, 0, 0, 0.75) inset,
    0 30px 72px rgba(0, 0, 0, 0.82);
}

@media (max-width: 760px) {
  .cabinet { grid-template-columns: 1fr; }
}

/* ---------- screen ---------- */

.screen-well {
  position: relative;
  background: #0a0a0a;
  border-radius: 14px;
  padding: clamp(0.5rem, 1.4vw, 1rem);
  box-shadow: 0 0 0 3px #1b1512, 0 8px 24px rgba(0, 0, 0, 0.6) inset;
  /* Centre the picture in whatever space is left. Without min-height:0 the
     grid row refuses to shrink and you get a dead black slab under the tube. */
  display: grid;
  place-items: center;
  min-height: 0;
  overflow: hidden;
}

.crt2 .screen-well {
  border-radius: 6px;
  background: #050607;
  box-shadow:
    0 0 0 2px #25282a,
    0 0 0 4px #080909,
    0 8px 24px rgba(0, 0, 0, 0.78) inset;
}

.cabinet-badge {
  position: absolute;
  z-index: 24;
  left: 50%;
  bottom: -1rem;
  transform: translate(-50%, 50%);
  width: min(64%, 27rem);
  min-height: 2.5rem;
  padding: 0.38rem 0.8rem 0.34rem;
  border: 1px solid #5f6365;
  border-radius: 3px;
  background: linear-gradient(180deg, #25292b 0%, #0d0f10 54%, #050606 100%);
  color: #e6e8e5;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.2) inset,
    0 -1px 0 rgba(0, 0, 0, 0.75) inset,
    0 3px 7px rgba(0, 0, 0, 0.72);
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 1rem;
}

.badge-identity {
  display: grid;
  justify-items: start;
  line-height: 1;
}

.badge-spectrum {
  display: flex;
  gap: 0.22rem;
  margin: 0 0 0.2rem 0.08rem;
}

.badge-spectrum i {
  width: 1.18rem;
  height: 0.38rem;
  border-radius: 50%;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.28) inset, 0 0 5px currentColor;
}

.badge-spectrum i:nth-child(1) { color: #f04b51; background: currentColor; }
.badge-spectrum i:nth-child(2) { color: #f5a23a; background: currentColor; }
.badge-spectrum i:nth-child(3) { color: #37d477; background: currentColor; }
.badge-spectrum i:nth-child(4) { color: #25bcd7; background: currentColor; }
.badge-spectrum i:nth-child(5) { color: #328fea; background: currentColor; }

.badge-name {
  font-size: clamp(0.72rem, 1.45vw, 1.05rem);
  font-weight: 600;
  letter-spacing: 0.19em;
}

.badge-model {
  font-size: clamp(0.86rem, 1.7vw, 1.2rem);
  font-weight: 500;
  letter-spacing: 0.24em;
  color: #c7cbc9;
}

.stage {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #000;
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 0 90px rgba(0, 0, 0, 0.9) inset;
  /* Exact pixel size is set by fitStage() in app.js — CSS alone cannot express
     "biggest 16:9 that fits this box in BOTH directions". The aspect-ratio above
     is the fallback if scripting is off. */
  max-width: 100%;
  max-height: 100%;
}

/* REAL glass, not a painted-on sheen.
   backdrop-filter samples what is behind the element — and it works on a
   cross-origin YouTube iframe, verified in-browser. So this streak genuinely
   brightens and blurs the live picture underneath it, and moves with the video.
   It is masked to a corner sweep and kept faint on purpose: the tube should
   read as glass, not as fog. */
.stage::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 8;
  pointer-events: none;
  border-radius: inherit;
  backdrop-filter: blur(2px) brightness(1.5) saturate(1.15);
  -webkit-backdrop-filter: blur(2px) brightness(1.5) saturate(1.15);
  -webkit-mask-image: linear-gradient(148deg,
    rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.16) 14%, transparent 30%);
  mask-image: linear-gradient(148deg,
    rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.16) 14%, transparent 30%);
  opacity: 0.75;
}

/* Curvature and edge falloff only. No milky tint over the picture. */
.stage::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  border-radius: inherit;
  background: radial-gradient(ellipse at center, transparent 62%, rgba(0, 0, 0, 0.38) 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.07),
    inset 0 0 36px rgba(0, 0, 0, 0.42);
}

@media (prefers-reduced-transparency: reduce) {
  .stage::before { display: none; }
}

/* Player slot. VJ interstitials fade over it using the sibling video layer. */
.yt-slot {
  position: absolute;
  inset: 0;
  z-index: 2;
  opacity: 0;
  transition: opacity 900ms ease;
}

.yt-slot.on { opacity: 1; z-index: 3; }

.vj-layer {
  position: absolute;
  inset: 0;
  z-index: 4;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  pointer-events: none;
  transition: opacity 900ms ease;
}

.vj-layer.on { opacity: 1; }

.yt-slot div, .yt-slot iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .yt-slot { transition: opacity 250ms linear; }
}

/* The design layer: authored at 1920x1080, scaled from the top-left. */
.design {
  position: absolute;
  top: 0;
  left: 0;
  width: 1920px;
  height: 1080px;
  transform-origin: top left;
  pointer-events: none;
  z-index: 5;
}

.scanlines {
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.22) 0px,
    rgba(0, 0, 0, 0.22) 2px,
    transparent 2px,
    transparent 5px
  );
  opacity: 0.55;
  mix-blend-mode: multiply;
}

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

/* channel bug — top right. Bottom right is where YouTube puts its own logo,
   and covering that would obscure their attribution. */
/* Corner mark, not a headline. Small, quiet, and kept off the bottom-right
   corner because that is where YouTube draws its own logo. */
.bug {
  position: absolute;
  right: 84px;
  top: 62px;
  font-size: 21px;
  font-weight: 600;
  letter-spacing: 0.26em;
  color: var(--tv-white);
  text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.9);
  opacity: 0.5;
}

/* ---------- lower third ----------
   Anchored inside title safe (SMPTE ST 2046-1 puts title safe at the central 90%,
   so 1920 * 5% = 96px is the hard edge; 150px keeps clear of it). */
.lower-third {
  position: absolute;
  left: 150px;
  bottom: 110px;
  max-width: 1300px;
  opacity: 0;
  transform: translateX(-24px);
  transition: opacity 320ms ease, transform 320ms ease;
}

.lower-third.on {
  opacity: 1;
  transform: translateX(0);
}

@media (prefers-reduced-motion: reduce) {
  .lower-third { transition: opacity 200ms linear; transform: none; }
  .lower-third.on { transform: none; }
}

.lt-line {
  color: var(--tv-white);
  text-transform: uppercase;
  font-weight: 600;
  font-kerning: normal;
  font-synthesis: none;
  line-height: 1.18;
  /* hard black surround — the character-generator look, not a soft shadow */
  text-shadow:
    3px 3px 0 #000, -3px 3px 0 #000, 3px -3px 0 #000, -3px -3px 0 #000,
    0 3px 0 #000, 0 -3px 0 #000, 3px 0 0 #000, -3px 0 0 #000,
    8px 8px 0 rgba(0, 0, 0, 0.55);
}

.lt-artist { font-size: 62px; letter-spacing: 0.16em; }
.lt-title  { font-size: 48px; letter-spacing: 0.18em; }
.lt-meta   { font-size: 30px; letter-spacing: 0.22em; opacity: 0.9; margin-top: 10px; }

/* ---------- ident card (between videos) ---------- */

.ident {
  position: absolute;
  inset: 0;
  background: #000;
  display: grid;
  place-content: center;
  text-align: center;
  gap: 24px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 380ms ease;
}

.ident.on { opacity: 1; visibility: visible; }

.ident-mark {
  font-size: 118px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--tv-white);
  text-shadow: 10px 10px 0 var(--tv-yellow);
}

.ident-sub {
  font-size: 38px;
  letter-spacing: 0.5em;
  color: var(--tv-yellow);
  text-transform: uppercase;
}

.static {
  position: absolute;
  inset: 0;
  opacity: 0;
  background: repeating-conic-gradient(#1a1a1a 0% 25%, #2e2e2e 0% 50%) 0 0 / 4px 4px;
  transition: opacity 160ms linear;
}

.static.on { opacity: 0.35; }

/* ---------- off state ---------- */

.off-screen {
  position: absolute;
  inset: clamp(0.5rem, 1.4vw, 1rem);
  display: grid;
  place-content: center;
  gap: 1rem;
  text-align: center;
  background: #000;
  border-radius: 10px;
  z-index: 20;
}

.off-screen[hidden] { display: none; }

.power-big {
  font-family: inherit;
  font-size: clamp(1rem, 3vw, 1.6rem);
  font-weight: 700;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: #000;
  background: var(--tv-yellow);
  border: 0;
  border-radius: 999px;
  padding: 0.9em 2.2em;
  cursor: pointer;
}

.power-big:hover { filter: brightness(1.08); }

.power-big:focus-visible,
.knob:focus-visible,
.btn:focus-visible {
  outline: 3px solid var(--led);
  outline-offset: 3px;
}

.off-note {
  margin: 0;
  color: #8b8378;
  font-size: 0.85rem;
  letter-spacing: 0.06em;
}

/* ---------- control panel ---------- */

.controls {
  background: linear-gradient(180deg, var(--panel) 0%, var(--panel-dark) 100%);
  border-radius: 12px;
  padding: 1rem 0.9rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  box-shadow: 0 2px 0 rgba(255, 255, 255, 0.5) inset, 0 -2px 6px rgba(0, 0, 0, 0.3) inset;
}

.crt2 .controls {
  color: #d9dcda;
  background: linear-gradient(180deg, #3a3e40 0%, #202325 48%, #121415 100%);
  border: 1px solid #555b5e;
  border-radius: 4px;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.18) inset,
    0 -2px 8px rgba(0, 0, 0, 0.72) inset;
}

.controls::before {
  content: "";
  height: 3px;
  margin: -0.25rem 0 0;
  border-radius: 999px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.72), transparent);
  opacity: 0.55;
}

.brand {
  font-weight: 700;
  font-size: 1.08rem;
  letter-spacing: 0.055em;
  text-align: center;
  white-space: nowrap;
}

.brand span { font-weight: 400; opacity: 0.6; }

.knob-row {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.5rem 0.4rem;
}

.knob-unit { text-align: center; }

.knob {
  --knob-reactive-color: #ff5a36;
  --knob-reactive-level: 0.3;
  width: 100%;
  aspect-ratio: 1;
  max-width: clamp(58px, 5vw, 92px);
  margin: 0 auto;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #4a413c, var(--knob) 70%);
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.45), 0 1px 0 rgba(255, 255, 255, 0.25) inset;
  cursor: grab;
  touch-action: none;
  display: grid;
  place-items: center;
}

.knob:active { cursor: grabbing; }

.knob-face {
  width: 78%;
  height: 78%;
  border-radius: 50%;
  position: relative;
  transform: rotate(var(--a, 0deg));
  transition: transform 140ms ease;
  background: url("assets/crt/crt-knob.png") center / contain no-repeat;
}

#knobYear .knob-face {
  background-image: url("assets/crt/crt-knob-fine-tune.png");
}

#knobChan .knob-face {
  background-image: url("assets/crt/crt-knob-channel.png");
}

#knobVol .knob-face {
  background-image: url("assets/crt/crt-knob-volume.png");
}

.crt2 #knobYear .knob-face {
  background-image: url("assets/crt2/crt2-knob-fine-tune.png");
}

.crt2 #knobChan .knob-face {
  background-image: url("assets/crt2/crt2-knob-channel.png");
}

.crt2 #knobVol .knob-face {
  background-image: url("assets/crt2/crt2-knob-volume.png");
}

.crt2 #knobFx .knob-face {
  background-image: url("assets/crt2/crt2-knob-aux.png");
}

#knobYear { --knob-reactive-color: #38df78; }
#knobChan { --knob-reactive-color: #34aef2; }
#knobVol  { --knob-reactive-color: #f05b42; }
#knobFx   { --knob-reactive-color: #f1a43c; }

.knob-pointer {
  position: absolute;
  left: 50%;
  top: 2.5%;
  width: 10%;
  height: 19%;
  margin-left: -5%;
  border-radius: 1px 1px 2px 2px;
  color: var(--knob-reactive-color);
  background: currentColor;
  opacity: var(--knob-reactive-level);
  box-shadow: 0 0 4px currentColor, 0 0 10px currentColor;
  transition: opacity 140ms ease, filter 140ms ease;
}

.cabinet:not(.powered) .knob-pointer {
  opacity: 0.16;
  box-shadow: none;
}

.cabinet.powered .knob-pointer { filter: brightness(1.28); }

.speaker-grille {
  position: relative;
  /* Grows to swallow the leftover rail height, instead of leaving a dead gap
     above the readout. */
  flex: 1 1 auto;
  min-height: 4.6rem;
  border-radius: 7px;
  overflow: hidden;
  background:
    linear-gradient(rgba(33, 25, 20, 0.12), rgba(4, 3, 2, 0.28)),
    url("assets/crt/crt-speaker-grille.jpg") center 12% / 18rem auto;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    inset 0 0 12px rgba(0, 0, 0, 0.56),
    0 1px 0 rgba(255, 255, 255, 0.2);
}

.crt2 .speaker-grille {
  border-radius: 2px;
  background:
    linear-gradient(rgba(9, 10, 11, 0.08), rgba(0, 0, 0, 0.36)),
    url("assets/crt2/crt2-speaker-slots.jpg") center / 17rem auto;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    inset 0 0 14px rgba(0, 0, 0, 0.72),
    0 1px 0 rgba(255, 255, 255, 0.08);
}

.knob-label {
  margin-top: 0.35rem;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.18em;
}

.knob-value {
  font-size: 0.7rem;
  font-weight: 500;
  opacity: 0.75;
  min-height: 1.1em;
}

.button-row {
  display: grid;
  grid-template-columns: 1fr;
  align-content: center;
  gap: 0.34rem;
}

.btn {
  font-family: inherit;
  min-height: 1.85rem;
  font-size: 0.61rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  padding: 0.4em 0.56em;
  border: 1px solid #090a0a;
  border-radius: 2px;
  background: linear-gradient(180deg, #575c5f 0%, #282b2d 48%, #151718 100%);
  color: #e1e3df;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.22) inset,
    0 -1px 0 rgba(0, 0, 0, 0.72) inset,
    0 2px 3px rgba(0, 0, 0, 0.42);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.btn:hover { filter: brightness(1.18); }
.btn:active { transform: translateY(1px); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.55); }
.btn b { color: #aeb4b4; font-size: 0.72rem; }

.btn-power { background: linear-gradient(180deg, #49302b, #291c19); color: #f1e5dd; }
.btn-power b { color: #ef5b43; text-shadow: 0 0 6px rgba(239, 91, 67, 0.72); }

.hardware-bank {
  display: grid;
  grid-template-columns: 1fr 2.65rem;
  gap: 0.55rem;
  padding: 0.5rem;
  border: 1px solid #090a0a;
  border-radius: 3px;
  background: linear-gradient(90deg, #17191a 0%, #242729 70%, #111314 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), inset 0 0 10px rgba(0, 0, 0, 0.56);
}

.level-fader {
  display: grid;
  grid-template-rows: auto 1fr;
  justify-items: center;
  gap: 0.28rem;
  min-height: 6.2rem;
  color: #aeb4b4;
  font-size: 0.48rem;
  font-weight: 600;
  letter-spacing: 0.12em;
}

.level-fader input {
  appearance: none;
  writing-mode: vertical-lr;
  direction: rtl;
  width: 1.15rem;
  height: 5rem;
  margin: 0;
  padding: 0;
  background: linear-gradient(90deg, #070808 0 35%, #24282a 35% 65%, #070808 65% 100%);
  border: 1px solid #020303;
  border-radius: 2px;
  cursor: ns-resize;
}

.level-fader input::-webkit-slider-thumb {
  appearance: none;
  width: 1rem;
  height: 0.42rem;
  border: 1px solid #050606;
  border-radius: 1px;
  background: linear-gradient(180deg, #e1e4e2 0%, #747b7e 48%, #242729 100%);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset, 0 0 5px rgba(58, 182, 255, 0.58);
}

.level-fader input::-moz-range-thumb {
  width: 1rem;
  height: 0.42rem;
  border: 1px solid #050606;
  border-radius: 1px;
  background: linear-gradient(180deg, #e1e4e2 0%, #747b7e 48%, #242729 100%);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset, 0 0 5px rgba(58, 182, 255, 0.58);
}

.readout {
  margin-top: auto;
  background: #171310;
  border-radius: 8px;
  padding: 0.6rem;
  color: var(--led);
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  display: grid;
  gap: 0.35rem;
}

.readout-row { display: grid; grid-template-columns: 3.2em 1fr; gap: 0.4rem; }

.readout-row span { opacity: 0.55; }

.readout-row b {
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- notch rings + level reactivity ----------
   The ring is built by app.js so the notch count always matches the knob's
   real number of positions. CSS only styles it. */

.notch-ring {
  position: absolute;
  inset: -14%;
  pointer-events: none;
}

.notch {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 7%;
  height: 7%;
  margin: -3.5% 0 0 -3.5%;
  border-radius: 50%;
  background: #17130f;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
  /* --r is the ring radius, --deg the position on it. Both set by app.js. */
  transform: rotate(var(--deg)) translateY(calc(var(--r) * -1)) rotate(calc(var(--deg) * -1));
  transition: background 120ms ease, box-shadow 160ms ease;
}

.notch.lit {
  background: var(--knob-reactive-color);
  box-shadow:
    0 0 calc(3px + 7px * var(--vu, 0)) var(--knob-reactive-color),
    0 0 calc(6px + 16px * var(--vu, 0)) var(--knob-reactive-color);
}

/* Pointer brightness = the knob's own position, breathing with the level.
   --knob-base is set per knob by app.js; --vu is set on the cabinet. */
.cabinet.powered .knob {
  --knob-reactive-level: calc(var(--knob-base, 0.5) * (0.55 + 0.45 * var(--vu, 0)));
}

/* VU arm button — injected by app.js, styled here so it matches the rail. */
.vu-btn {
  font: inherit;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  padding: 0.45em 0.4em;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 5px;
  background: #23282a;
  color: #cfd3d1;
  cursor: pointer;
}

.vu-btn[data-live="true"] {
  background: var(--led);
  color: #16100a;
  border-color: transparent;
}

@media (prefers-reduced-motion: reduce) {
  .notch.lit { box-shadow: 0 0 4px var(--knob-reactive-color); }
  .cabinet.powered .knob { --knob-reactive-level: 0.8; }
}
