/* THE TV PAGE'S STYLESHEET (menu build, Task 8; matched to the approved boards).
 *
 * Loaded by the TV page (/tv) and by the staff app for the previews. Every rule
 * is under `.tvr`, so nothing reaches a staff screen; every colour is a token in
 * the one `.tvr` block — the ruled TV tokens (Void … Magenta), what the boards
 * drew beside them and the identify veil; the body is the one literal outside.
 * Pinned by test/unit/tv-style.test.js.
 *
 * THE BOARDS ARE THE TARGET (Chris, 1 Oct 2026: "Match it exactly"): TV-Taps,
 * TV-Promo and TV-Pair, 1920x1080 design px, their sizes, gaps and weights; the
 * smallest text is the "1 of N" box at 16 px. Their glows too ("Put them back
 * now", same day): the wordmark's, the footer mark's, the cyan text glow, the
 * TONIGHT badge's orange (NEXT's cyan) drawn outside its clipped shape (owner
 * ruling, 1 Oct 2026), the code tiles'. Nothing animates but the 400 ms frame
 * fade. Hot orange is TONIGHT's alone (R23).
 *
 * Sizes are LOGICAL px on the 1920x1080 / 1080x1920 canvas; `--k` scales it.
 * Fonts: self-hosted (CSP `font-src 'self'`), latin subsets from @fontsource
 * 5.3.0, OFL licences in fonts/. Chakra Petch 600 is the canvas's weight; IBM
 * Plex Mono is 400 unless the board draws 600 (ABV, code tiles, NEXT date).
 */

@font-face { font-family: 'Unbounded'; font-style: normal; font-weight: 900; font-display: block; src: url('/menu-tv/fonts/unbounded-900.woff2') format('woff2'); }
@font-face { font-family: 'Chakra Petch'; font-style: normal; font-weight: 600; font-display: block; src: url('/menu-tv/fonts/chakra-petch-600.woff2') format('woff2'); }
@font-face { font-family: 'Chakra Petch'; font-style: normal; font-weight: 700; font-display: block; src: url('/menu-tv/fonts/chakra-petch-700.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 400; font-display: block; src: url('/menu-tv/fonts/ibm-plex-mono-400.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 600; font-display: block; src: url('/menu-tv/fonts/ibm-plex-mono-600.woff2') format('woff2'); }

/* The TV page's body: the void before the root is drawn. */
.tv-body { margin: 0; background: #04010A; overflow: hidden; cursor: none; height: 100vh; position: relative; }

/* ── the tokens ─────────────────────────────────────────────────────────── */
.tvr {
  --tv-void: #04010A;
  --tv-panel: #150E21;
  --tv-edge: #4A1F7A;
  --tv-ink: #F3EDF8;
  --tv-dim: #A697B8;
  --tv-signal: #63CFE3;
  --tv-violet: #8331A7;
  --tv-hot: #F18A00;
  --tv-magenta: #FF3DC8;
  --tv-rule: #2E2140;
  --tv-faint: #6E6180;
  --tv-hot-ink: #140B00;
  /* The boards' glows. */
  --tv-glow: rgba(99, 207, 227, 0.5);
  --tv-glow-tile: rgba(99, 207, 227, 0.25);
  --tv-glow-next: rgba(99, 207, 227, 0.6);
  --tv-glow-violet: rgba(195, 104, 255, 0.75);
  --tv-glow-magenta: rgba(255, 61, 200, 0.4);
  --tv-glow-hot: rgba(241, 138, 0, 0.6);
  --tv-veil: rgba(4, 1, 10, 0.86);
}

/* ── the canvas, centred in its box and scaled by --k ───────────────────── */
.tvr {
  --k: 0.5;
  --sx: 0px;
  --sy: 0px;
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1920px;
  height: 1080px;
  margin: -540px 0 0 -960px;
  box-sizing: border-box;
  overflow: hidden;
  transform-origin: 50% 50%;
  transform: scale(var(--k)) translate(var(--sx), var(--sy));
  background: var(--tv-void);
  color: var(--tv-ink);
  font-family: 'Chakra Petch', system-ui, sans-serif;
  font-weight: 600;
  font-size: 24px;
  line-height: normal;
}
.tvr.tall { width: 1080px; height: 1920px; margin: -960px 0 0 -540px; }
/* A turned TV (C18): the tall canvas turns into the landscape screen. */
.tvr.rot-90 { transform: rotate(90deg) scale(var(--k)) translate(var(--sx), var(--sy)); }
.tvr.rot-270 { transform: rotate(-90deg) scale(var(--k)) translate(var(--sx), var(--sy)); }
/* The 2 px shift every 10 min (C26): logical px, so 2 panel pixels on a 1080p TV. */
.tvr.s1 { --sx: 2px; --sy: 0px; }
.tvr.s2 { --sx: 2px; --sy: 2px; }
.tvr.s3 { --sx: 0px; --sy: 2px; }
.tvr * { box-sizing: border-box; }

/* ── frames and the fade ────────────────────────────────────────────────── */
.tvr .tv-layer { position: absolute; left: 0; top: 0; width: 100%; height: 100%; animation: tv-fade 400ms ease-out both; }
@keyframes tv-fade { from { opacity: 0; } to { opacity: 1; } }
.tvr .tv-frame { position: relative; z-index: 0; width: 100%; height: 100%; overflow: hidden; }
.tvr .tv-bg { position: absolute; z-index: -1; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover; }
/* The uploaded wordmark, wherever it is drawn, with the boards' violet + magenta glow. */
.tvr .tv-wordmark { display: block; width: auto; object-fit: contain; filter: drop-shadow(0 0 12px var(--tv-glow-violet)) drop-shadow(0 0 28px var(--tv-glow-magenta)); }

/* ── the menu (TV-Taps) ─────────────────────────────────────────────────── */
.tvr .tv-menu { display: flex; flex-direction: column; gap: 20px; padding: 36px 72px 32px; }
/* Header: the wordmark left; the title and the "1 of N" box right (gap 22). The
   header keeps the wordmark's 110 px when none is uploaded, so nothing moves. */
.tvr .tv-head { flex: none; display: flex; align-items: center; gap: 22px; height: 110px; }
.tvr .tv-head .tv-wordmark { height: 110px; max-width: 60%; margin-right: auto; }
/* The title clips for its ellipsis, so it carries 22 px of padding all round for
   its 22 px glow to show in (a bare box clipped the halo to a hard band), and the
   same negative margin so nothing moves (review M2). */
.tvr .tv-title { min-width: 0; margin: -22px -22px -22px auto; padding: 22px; font-family: 'IBM Plex Mono', monospace; font-weight: 400; font-size: 18px; letter-spacing: 0.34em; text-transform: uppercase; color: var(--tv-signal); text-shadow: 0 0 22px var(--tv-glow); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tvr .tv-pagemark { flex: none; padding: 3px 10px; border: 1px solid var(--tv-edge); border-radius: 6px; font-family: 'IBM Plex Mono', monospace; font-weight: 400; font-size: 16px; letter-spacing: 0.12em; color: var(--tv-dim); white-space: nowrap; }
.tvr .tv-cols { flex: 1 1 0; min-height: 0; display: grid; grid-template-rows: minmax(0, 1fr); column-gap: 72px; }
.tvr .cols-1 { grid-template-columns: minmax(0, 1fr); }
.tvr .cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.tvr .cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* A column: headings at their own height, the item rows sharing the rest — at
   most a sixth (wide) or a twelfth (tall) of the column each, so a column
   with fewer items keeps the rows the size a full one has. The column is a size
   container for those fractions (cqb); Chromium 105+, the Stick runs 118. tv-render.js's ROOM is this column's height. */
.tvr .tv-col { display: flex; flex-direction: column; min-height: 0; min-width: 0; container-type: size; }
.tvr .tv-cell { min-width: 0; }
.tvr .tv-h { flex: none; padding-bottom: 14px; border-bottom: 2px solid var(--tv-edge); font-family: 'Unbounded', Impact, sans-serif; font-weight: 900; font-size: 44px; line-height: 1; letter-spacing: -0.03em; text-transform: uppercase; text-shadow: 0.022em 0 var(--tv-magenta), -0.022em 0 var(--tv-signal); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A following section's heading: the board's 18 px above it. */
.tvr .tv-item + .tv-h { padding-top: 18px; }
/* Sub-heading: tv-render SUB */
.tvr .tv-sh { flex: none; padding: 14px 0 8px; font: 900 40px/1 'Unbounded', Impact, sans-serif; letter-spacing: -0.03em; text-transform: uppercase; color: var(--tv-signal); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* (The boards size boxes without box-sizing, so a drawn "84 px" tile with a 1 px
   border is 86 px across, and the 150 x 190 code tiles with 2 px borders are
   154 x 194; the sizes here are the drawn outer sizes.)
   The item row: logo tile | name / maker · style / description | the right column
   (gaps 22, 3 between text lines). The logo sits outside the grid so the text block
   centres on its own; the name keeps at least 35% of the text area. */
.tvr .tv-item { position: relative; flex: 1 1 0; min-height: 0; overflow: hidden; display: grid; grid-template-columns: minmax(35%, 1fr) auto; grid-template-rows: 1fr auto auto auto 1fr; align-content: center; column-gap: 22px; row-gap: 3px; padding-left: 108px; border-bottom: 1px solid var(--tv-rule); }
.tvr .rows-6 .tv-item { max-height: calc(100cqb / 6); }
.tvr .rows-12 .tv-item { max-height: calc(100cqb / 12); }
.tvr .tv-logo { position: absolute; left: 0; top: 50%; width: 86px; height: 86px; margin-top: -43px; border-radius: 10px; border: 1px solid var(--tv-edge); background: var(--tv-panel); object-fit: contain; }
.tvr .tv-name { grid-column: 1; grid-row: 2; font-size: 36px; font-weight: 700; line-height: 1.05; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tvr .tv-meta { grid-column: 1; grid-row: 3; font-size: 21px; color: var(--tv-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tvr .tv-desc { grid-column: 1; grid-row: 4; font-size: 18px; color: var(--tv-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* One element, a grid: the ABV (data-abv) on top, the size labels (data-oz) beside
   the prices (its text). Prices 34 px bold, brightest, the largest here; labels the
   ABV's 24 px, regular, dim (Chris, 3 Oct 2026). Lines 22 + 3 x 32 + 5 = 123 ARE the
   shortest row (ROOM, POUR_LINE_PX). `top` puts a label on its price's baseline
   (4.5 / 4 / 3 px, measured in tv-layout.test.js); tall 2 / 3: 28 / 20, 22 / 16 px. */
.tvr .tv-right { grid-column: 2; grid-row: 1 / 6; align-self: center; min-width: 0; overflow: hidden; display: grid; grid-template-columns: auto auto; justify-content: end; column-gap: 2ch; font-family: 'IBM Plex Mono', monospace; font-size: 34px; font-weight: 600; line-height: 32px; padding-bottom: 5px; color: var(--tv-ink); text-align: right; white-space: pre; }
.tvr.tall .cols-2 .tv-right { font-size: 28px; }
.tvr.tall .cols-3 .tv-right { font-size: 22px; }
.tvr .tv-right[data-abv]::before { content: attr(data-abv); grid-column: 1 / -1; margin-bottom: 0px; overflow: hidden; text-overflow: ellipsis; font-size: 24px; font-weight: 400; line-height: 22px; color: var(--tv-dim); }
.tvr .tv-right[data-oz]::after { content: attr(data-oz); grid-area: 2 / 1; position: relative; top: 4.5px; font-size: 24px; font-weight: 400; color: var(--tv-dim); }
.tvr .tv-right:not([data-abv])::after { grid-row: 1; }
.tvr .tv-right[data-oz=""] { column-gap: 0; }
.tvr.tall .cols-2 .tv-right::after { font-size: 20px; top: 4px; }
.tvr.tall .cols-3 .tv-right::after { font-size: 16px; top: 3px; }
/* Footer: the mark left, the footer line right. */
.tvr .tv-foot { flex: none; display: flex; align-items: center; justify-content: space-between; height: 40px; font-family: 'IBM Plex Mono', monospace; font-size: 20px; font-weight: 400; color: var(--tv-dim); }
.tvr .tv-mark { flex: none; width: 40px; height: 40px; object-fit: contain; filter: drop-shadow(0 0 10px var(--tv-glow-violet)); }
.tvr .tv-footer { min-width: 0; margin-left: auto; text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ── the promo (TV-Promo, upcoming shows) ───────────────────────────────── */
.tvr .tv-promo { display: flex; gap: 72px; padding: 72px; }
.tvr .tv-poster { flex: none; display: block; width: 604px; height: 100%; object-fit: contain; object-position: center; }
/* The poster column is 604 px: the board's 600 px panel plus its 2 px border each
   side. No poster: that panel where the poster would be, holding the show's date. */
.tvr .tv-poster-text { flex: none; width: 604px; display: flex; align-items: center; justify-content: center; padding: 48px; border: 2px solid var(--tv-edge); border-radius: 16px; background: var(--tv-panel); font-family: 'Unbounded', Impact, sans-serif; font-weight: 900; font-size: 72px; line-height: 1.1; letter-spacing: -0.03em; text-transform: uppercase; text-align: center; text-shadow: 0.022em 0 var(--tv-magenta), -0.022em 0 var(--tv-signal); overflow-wrap: break-word; }
.tvr .tv-promo-text { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; justify-content: space-between; }
.tvr .tv-promo-main { display: flex; flex-direction: column; align-items: flex-start; gap: 26px; min-width: 0; max-width: 100%; }
.tvr .tv-promo .tv-wordmark { height: 120px; max-width: 100%; }
.tvr .tv-badge-row { display: flex; align-items: center; gap: 28px; }
/* The badge's clipped shape is its ::before (colour --tv-badge); the glow is a
   drop-shadow on the badge, which follows the shape and is drawn OUTSIDE it — a
   clip-path clips its own element's glow (owner ruling, 1 Oct 2026: it shows). */
.tvr .tv-badge { position: relative; z-index: 0; padding: 10px 24px; font-weight: 700; font-size: 34px; letter-spacing: 0.15em; }
.tvr .tv-badge::before { content: ''; position: absolute; z-index: -1; left: 0; top: 0; width: 100%; height: 100%; background: var(--tv-badge); clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px); }
.tvr .tv-badge.hot { --tv-badge: var(--tv-hot); color: var(--tv-hot-ink); filter: drop-shadow(0 0 30px var(--tv-glow-hot)); }
/* NEXT (ruling R18, a night with no show): TONIGHT's shape and glow in Signal cyan. */
.tvr .tv-badge.next { --tv-badge: var(--tv-signal); color: var(--tv-void); filter: drop-shadow(0 0 30px var(--tv-glow-next)); }
.tvr .tv-date { font-family: 'IBM Plex Mono', monospace; font-weight: 600; font-size: 34px; letter-spacing: 0.12em; color: var(--tv-signal); text-shadow: 0 0 22px var(--tv-glow); }
.tvr .tv-headliner { max-width: 100%; font-family: 'Unbounded', Impact, sans-serif; font-weight: 900; font-size: 96px; line-height: 1; letter-spacing: -0.03em; text-transform: uppercase; text-shadow: 0.022em 0 var(--tv-magenta), -0.022em 0 var(--tv-signal); overflow-wrap: break-word; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.tvr .tv-support { max-width: 100%; font-size: 38px; color: var(--tv-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tvr .tv-times { font-family: 'IBM Plex Mono', monospace; font-size: 30px; font-weight: 400; color: var(--tv-signal); text-shadow: 0 0 22px var(--tv-glow); }
.tvr .tv-tickets { max-width: 100%; font-size: 28px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tvr .tv-coming { display: flex; flex-direction: column; gap: 18px; padding-top: 28px; border-top: 2px solid var(--tv-edge); }
.tvr .tv-coming-label { font-family: 'IBM Plex Mono', monospace; font-size: 18px; font-weight: 400; letter-spacing: 0.34em; color: var(--tv-signal); text-shadow: 0 0 22px var(--tv-glow); }
.tvr .tv-coming-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; }
.tvr .tv-coming-one { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.tvr .tv-coming-date { font-family: 'IBM Plex Mono', monospace; font-size: 22px; font-weight: 400; color: var(--tv-dim); }
.tvr .tv-coming-name { font-size: 30px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The QR code (lane qr): the text column's bottom right, beside COMING UP; dark on
   light. Tall: the caption left of the code, at the foot's top, so the code is never past the edge. */
.tvr .tv-promo-foot { display: flex; align-items: flex-end; gap: 48px; }
.tvr .tv-promo-foot .tv-coming { flex: 1 1 0; min-width: 0; }
.tvr .tv-qr { flex: none; margin-left: auto; display: flex; flex-direction: column; align-items: center; gap: 10px; font-family: 'IBM Plex Mono', monospace; font-size: 18px; color: var(--tv-dim); white-space: nowrap; }
.tvr .tv-qr svg { display: block; width: 210px; height: 210px; background: var(--tv-ink); border-radius: 8px; shape-rendering: crispEdges; }
.tvr .tv-qr path { fill: var(--tv-void); }
.tvr.tall .tv-qr { flex-direction: row-reverse; gap: 20px; align-self: flex-start; }
.tvr.tall .tv-promo { flex-direction: column; gap: 56px; }
.tvr.tall .tv-poster { width: 100%; height: 860px; }
.tvr.tall .tv-poster-text { width: 100%; height: 860px; }
.tvr.tall .tv-coming-list { grid-template-columns: minmax(0, 1fr); gap: 18px; }

/* ── a photo, the brand page ────────────────────────────────────────────── */
.tvr .tv-photo-img { position: absolute; left: 0; top: 0; width: 100%; height: 100%; object-fit: contain; }
.tvr .tv-brand { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 56px; padding: 72px; }
.tvr .tv-brand .tv-wordmark { height: 300px; max-width: 100%; }
.tvr .tv-brand-title { max-width: 100%; font-family: 'Unbounded', Impact, sans-serif; font-weight: 900; font-size: 64px; line-height: 1.05; letter-spacing: -0.03em; text-transform: uppercase; text-align: center; text-shadow: 0.022em 0 var(--tv-magenta), -0.022em 0 var(--tv-signal); }

/* ── pairing (TV-Pair, contract §E) and identify (C20) ──────────────────── */
.tvr .tv-pair { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 36px; padding: 72px; }
.tvr .tv-pair .tv-wordmark { height: 220px; max-width: 100%; }
.tvr .tv-pair-head { font-family: 'Unbounded', Impact, sans-serif; font-weight: 900; font-size: 52px; line-height: 1; letter-spacing: -0.03em; text-transform: uppercase; text-align: center; text-shadow: 0.022em 0 var(--tv-magenta), -0.022em 0 var(--tv-signal); }
.tvr .tv-code { display: flex; gap: 20px; }
.tvr .tv-code-tile { display: flex; align-items: center; justify-content: center; width: 154px; height: 194px; border-radius: 16px; border: 2px solid var(--tv-signal); background: var(--tv-panel); box-shadow: 0 0 30px var(--tv-glow-tile); font-family: 'IBM Plex Mono', monospace; font-weight: 600; font-size: 120px; color: var(--tv-signal); text-shadow: 0 0 22px var(--tv-glow); }
.tvr .tv-pair-help { max-width: 1500px; font-size: 32px; line-height: 1.5; text-align: center; color: var(--tv-dim); }
.tvr .tv-pair-em { color: var(--tv-ink); }
.tvr .tv-overlay { position: absolute; z-index: 5; left: 0; top: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: var(--tv-veil); }
.tvr .tv-identify { max-width: 100%; padding: 0 72px; }
.tvr .tv-identify-name { font-family: 'Unbounded', Impact, sans-serif; font-weight: 900; font-size: 160px; line-height: 1.05; letter-spacing: -0.03em; text-transform: uppercase; text-align: center; overflow-wrap: break-word; text-shadow: 0.022em 0 var(--tv-magenta), -0.022em 0 var(--tv-signal); }
