/* CRT channel switcher.
   Layered replacement for the static relic image. No JavaScript: the channel
   is a radio group, and the click target is a stack of labels each pointing at
   the next channel.

   Sizing is deliberately NOT restated here — the .tv fills .relic, so it keeps
   the clamp() width, the margins and the landscape-phone rule already in
   main.css. This is a drop-in, not a new layout. */

/* .relic carries pointer-events:none so the static image never stole a click
   from the plates. The dial needs them back. */
.relic {
  pointer-events: auto;

  /* The TV wants to be wider than the 34rem text column (--measure), which the
     plates and copy still want. So it breaks out and centres on the column's
     midline: margin:auto cannot centre a box wider than its parent — it just
     overflows to the right, which is why it sat off-centre. */
  width: clamp(11rem, 62vw, 46rem);
  max-width: calc(100vw - 2rem);
  margin-left: 0;
  margin-right: 0;
  position: relative;
  left: 50%;
  translate: -50% 0;
}

.tv {
  position: relative;
  width: 100%;
  line-height: 0;

  /* Calibration, measured from tv-real43.png (1536x1024) by walking its alpha
     channel — every opening the cabinet punches. Percentages of the cabinet,
     so the whole assembly scales as one.
     Tube is 806x647 = 1.246:1 (5:4), which shows ~80% of the square photo. */
  --screen-x: 15.59%;  --screen-y: 18.90%;
  --screen-w: 52.47%;  --screen-h: 63.18%;

  --knob-x: 84.57%;    --knob-y: 27.10%;   --knob-d: 6.84%;
  --uhf-x:  84.57%;    --uhf-y:  47.71%;   --uhf-d: 6.70%;
  --uhf-angle: -68deg;

  /* The four small openings are punched deliberately — they are reserved for
     controls that do not exist yet. Black discs hold the place so the cabinet
     does not read as damaged and the skyline cannot show through. */
  --p1-x: 79.88%;  --p1-y: 60.94%;  --p1-d: 1.73%;   /* pull-on volume */
  --p2-x: 89.10%;  --p2-y: 60.94%;  --p2-d: 1.73%;   /* contrast */
  --p3-x: 79.88%;  --p3-y: 84.38%;  --p3-d: 1.59%;   /* earphone */
  --p4-x: 89.06%;  --p4-y: 84.38%;  --p4-d: 1.59%;   /* power */

  --knob-zero: 35deg;
  --knob-step: 30deg;
}

/* ── screen, under the cabinet ─────────────────────────────────────────── */
.tv__screen {
  position: absolute;
  left: var(--screen-x); top: var(--screen-y);
  width: var(--screen-w); height: var(--screen-h);
  overflow: hidden;
  background: #05070a;
  /* The tube is convex; square corners read as a sticker. */
  border-radius: 14% / 20%;
}

.ch {
  position: absolute;
  inset: -2%;
  /* opacity:0 still hit-tests. Without pointer-events:none the last channel in
     the DOM sits invisibly on top and swallows clicks meant for the live one. */
  opacity: 0;
  pointer-events: none;
  transition: opacity 160ms steps(2, end);
  display: grid;
  place-items: center;
  text-align: center;
  line-height: 1.7;            /* .relic zeroes it; multi-line text needs it back */
}

/* cover: the photograph fills the tube edge to edge. contain showed the whole
   square but pillarboxed it, and the black bars read as a mistake rather than
   as a picture. */
/* <picture> is a grid item under place-items:center, so it sizes to its content
   and the image's width:100% resolves against the image itself — object-fit
   then has nothing to crop and the photo pillarboxes. Make the wrapper fill. */
.tv .ch > picture { position: absolute; inset: 0; display: block; }

.tv .ch__img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* Top-aligned. The 5:4 tube drops ~20% of the square, and all of it should
     come off the bottom: the top of his head and the whole raised hand are the
     picture. Losing part of the plate is fine — some cake, not all. */
  object-position: 50% 0%;
  display: block;
  /* Same grade the static relic carried, so nothing shifts visually. */
  filter: brightness(0.82) contrast(1.06) saturate(0.72) sepia(0.16);
}

/* The photograph reads better mirrored — the raised hand falls on the side the
   eye reaches last. Done in CSS while it is still a decision; if it stays, bake
   it into the asset so there is no runtime transform. */
.tv .ch--12 .ch__img { transform: scaleX(-1); }

.ch__dead {
  font-family: var(--t-mono, ui-monospace, monospace);
  font-size: 0.6rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: #55636f;
}

/* ── glass: scanlines and falloff, above content, below the cabinet ─────── */
.tv__glass {
  position: absolute;
  left: var(--screen-x); top: var(--screen-y);
  width: var(--screen-w); height: var(--screen-h);
  border-radius: 14% / 20%;
  pointer-events: none;
  background:
    radial-gradient(120% 80% at 22% 12%, rgba(255,255,255,0.10), transparent 55%),
    repeating-linear-gradient(180deg, rgba(0,0,0,0.26) 0 1px, transparent 1px 3px),
    radial-gradient(130% 120% at 50% 50%, transparent 58%, rgba(0,0,0,0.72) 100%);
}

/* ── cabinet, on top, tube and dial centres punched out ────────────────── */
/* pointer-events:none matters: hit testing uses the element box, not the alpha
   channel, so the cabinet would otherwise swallow clicks aimed at the dial. */
.tv .tv__cabinet {
  position: relative;
  display: block;
  width: 100%; height: auto;
  z-index: 2;
  pointer-events: none;
}

/* ── knobs, behind the cabinet, showing through the punched holes ──────── */
.tv .tv__knob, .tv .tv__uhf {
  position: absolute;
  z-index: 1;
  /* height:auto matters — the img height attribute is a presentational hint,
     and a non-auto height makes the browser ignore aspect-ratio. */
  height: auto;
  aspect-ratio: 1;
  transform-origin: 50% 50%;
}

.tv .tv__knob {
  left: var(--knob-x); top: var(--knob-y);
  width: var(--knob-d);
  transform: translate(-50%, -50%) rotate(var(--knob-zero));
  /* Slight overshoot so it lands like a detent rather than easing to a stop. */
  transition: transform 420ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* UHF is scenery: it fills the hole so the cabinet doesn't read as damaged,
   and sits at its own angle so the two dials aren't the same knob twice. */
.tv .tv__uhf {
  left: var(--uhf-x); top: var(--uhf-y);
  width: var(--uhf-d);
  transform: translate(-50%, -50%) rotate(var(--uhf-angle));
}

/* ── placeholder ports ─────────────────────────────────────────────────── */
/* Behind the cabinet like the knobs, so they fill the punched openings. When
   these become real controls, swap the div for a label and give it a target. */
.tv__port {
  position: absolute;
  z-index: 1;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 46% 40%, #21201e 0 42%, #0b0a09 100%);
  transform: translate(-50%, -50%);
}
.tv__port--1 { left: var(--p1-x); top: var(--p1-y); width: var(--p1-d); }
.tv__port--2 { left: var(--p2-x); top: var(--p2-y); width: var(--p2-d); }
.tv__port--3 { left: var(--p3-x); top: var(--p3-y); width: var(--p3-d); }
.tv__port--4 { left: var(--p4-x); top: var(--p4-y); width: var(--p4-d); }

/* ── the control ───────────────────────────────────────────────────────── */
.tv__dial {
  position: absolute;
  z-index: 4;
  left: var(--knob-x); top: var(--knob-y);
  /* Deliberately larger than the artwork: the label is invisible, so a
     comfortable touch target costs nothing visually. */
  width: 13%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  cursor: pointer;
  display: none;
}
.tv__dial:focus-visible { outline: 2px solid var(--gold, #c9a24a); outline-offset: 4px; }

.tv__radio { position: absolute; opacity: 0; width: 1px; height: 1px; }

/* Only the label for the NEXT channel is reachable, so a click advances.
   Generated: 12 positions, clockwise from 12. */
#ch12:checked ~ .tv .tv__dial[for="ch1"],
#ch1:checked ~ .tv .tv__dial[for="ch2"],
#ch2:checked ~ .tv .tv__dial[for="ch3"],
#ch3:checked ~ .tv .tv__dial[for="ch4"],
#ch4:checked ~ .tv .tv__dial[for="ch5"],
#ch5:checked ~ .tv .tv__dial[for="ch6"],
#ch6:checked ~ .tv .tv__dial[for="ch7"],
#ch7:checked ~ .tv .tv__dial[for="ch8"],
#ch8:checked ~ .tv .tv__dial[for="ch9"],
#ch9:checked ~ .tv .tv__dial[for="ch10"],
#ch10:checked ~ .tv .tv__dial[for="ch11"],
#ch11:checked ~ .tv .tv__dial[for="ch12"] { display: block; }

#ch12:checked ~ .tv .ch--12,
#ch1:checked ~ .tv .ch--1,
#ch2:checked ~ .tv .ch--2,
#ch3:checked ~ .tv .ch--3,
#ch4:checked ~ .tv .ch--4,
#ch5:checked ~ .tv .ch--5,
#ch6:checked ~ .tv .ch--6,
#ch7:checked ~ .tv .ch--7,
#ch8:checked ~ .tv .ch--8,
#ch9:checked ~ .tv .ch--9,
#ch10:checked ~ .tv .ch--10,
#ch11:checked ~ .tv .ch--11 { opacity: 1; pointer-events: auto; }

/* Knob angle per channel. 12 is the rest position; each step is 30deg
   clockwise, so the pointer lands on its own numeral. */
#ch1:checked ~ .tv .tv__knob { transform: translate(-50%,-50%) rotate(calc(var(--knob-zero) + 1*var(--knob-step))); }
#ch2:checked ~ .tv .tv__knob { transform: translate(-50%,-50%) rotate(calc(var(--knob-zero) + 2*var(--knob-step))); }
#ch3:checked ~ .tv .tv__knob { transform: translate(-50%,-50%) rotate(calc(var(--knob-zero) + 3*var(--knob-step))); }
#ch4:checked ~ .tv .tv__knob { transform: translate(-50%,-50%) rotate(calc(var(--knob-zero) + 4*var(--knob-step))); }
#ch5:checked ~ .tv .tv__knob { transform: translate(-50%,-50%) rotate(calc(var(--knob-zero) + 5*var(--knob-step))); }
#ch6:checked ~ .tv .tv__knob { transform: translate(-50%,-50%) rotate(calc(var(--knob-zero) + 6*var(--knob-step))); }
#ch7:checked ~ .tv .tv__knob { transform: translate(-50%,-50%) rotate(calc(var(--knob-zero) + 7*var(--knob-step))); }
#ch8:checked ~ .tv .tv__knob { transform: translate(-50%,-50%) rotate(calc(var(--knob-zero) + 8*var(--knob-step))); }
#ch9:checked ~ .tv .tv__knob { transform: translate(-50%,-50%) rotate(calc(var(--knob-zero) + 9*var(--knob-step))); }
#ch10:checked ~ .tv .tv__knob { transform: translate(-50%,-50%) rotate(calc(var(--knob-zero) + 10*var(--knob-step))); }
#ch11:checked ~ .tv .tv__knob { transform: translate(-50%,-50%) rotate(calc(var(--knob-zero) + 11*var(--knob-step))); }

/* Dead air on the last channel keeps its snow up instead of flashing once. */
.ch--11::after { animation: none; opacity: 0.16; }

/* One frame of snow on every change, so the cut feels physical. */
.ch::after {
  content: "";
  position: absolute; inset: 0;
  opacity: 0;
  background-image:
    repeating-conic-gradient(#fff 0 0.0006turn, #000 0 0.0012turn),
    repeating-linear-gradient(90deg, #888 0 2px, #111 2px 3px);
  background-size: 3px 3px, 5px 5px;
  mix-blend-mode: screen;
}
.ch[data-lit]::after { animation: tv-snow 180ms steps(3, end) 1; }
@keyframes tv-snow { 0% { opacity: 0.55 } 70% { opacity: 0.28 } 100% { opacity: 0 } }


@media (prefers-reduced-motion: reduce) {
  .tv .tv__knob, .ch { transition: none; }
  .ch[data-lit]::after { animation: none; }
}
