/* ──────────────────────────────────────────────────────────────
   KSCH — design tokens
   Broadcast console at night: matte black panels, one amber
   backlit dial, one red ON AIR lamp. Amber = the station.
   Red = live / recording. Nothing else gets a colour.
   ────────────────────────────────────────────────────────────── */
:root {
  --ink: #121317;
  --ink-2: #191b21;
  --ink-3: #23262e;
  --ink-4: #2b2f38;
  --line: #2e323c;
  --line-2: #3a3f4b;
  --text: #ece8de;
  --text-2: #a9a79e;
  --muted: #6e717c;
  --dial: #f0b13b;
  --dial-2: #ffcf6a;
  --dial-dim: rgba(240, 177, 59, .14);
  --dial-line: rgba(240, 177, 59, .35);
  --lamp: #e6392f;
  --lamp-dim: rgba(230, 57, 47, .16);
  --lamp-glow: 0 0 22px rgba(230, 57, 47, .55), 0 0 4px rgba(230, 57, 47, .9);
  --ok: #58c39a;
  --warn: #f0b13b;
  --font-display: "Barlow Condensed", "Bahnschrift", "DIN Alternate", "Roboto Condensed", "Arial Narrow", sans-serif;
  --font-body: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --chrome: #0e0f13;
  --chrome-2: #16181d;
  --r: 8px;
  --r-sm: 4px;
  --r-btn: 6px;
  --shadow: 0 10px 30px rgba(0, 0, 0, .45);
  --bar-h: 84px;
  --safe-b: env(safe-area-inset-bottom, 0px);
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; background: var(--ink); color-scheme: dark; }
body {
  margin: 0; font-family: var(--font-body); font-size: 15px; line-height: 1.45; color: var(--text);
  background: var(--ink);
  min-height: 100vh;
}
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
img { display: block; max-width: 100%; }
h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -.01em; }
p { margin: 0; }
:focus-visible { outline: 2px solid var(--dial); outline-offset: 2px; border-radius: 4px; }
::selection { background: var(--dial-dim); }
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } }

/* ─── Type roles ─── */
.display { font-family: var(--font-display); font-weight: 600; letter-spacing: .005em; line-height: .95; }
.eyebrow { font-family: var(--font-display); font-weight: 600; font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: var(--muted); }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.muted { color: var(--muted); }
.dim { color: var(--text-2); }
.small { font-size: 13px; }
.tiny { font-size: 12px; }
.amber { color: var(--dial); }
.red { color: var(--lamp); }
.ok { color: var(--ok); }
.truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hidden { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/* ─── Buttons ─── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 34px; padding: 0 14px; border-radius: var(--r-btn); border: 1px solid var(--line-2);
  background: var(--ink-3); color: var(--text); cursor: pointer; white-space: nowrap;
  font-weight: 500; font-size: 14px; transition: background .12s, border-color .12s, transform .06s;
}
.btn:hover { background: var(--ink-4); border-color: var(--muted); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .45; cursor: default; }
.btn.primary { background: var(--dial); border-color: var(--dial); color: #1a1408; font-weight: 600; }
.btn.primary:hover { background: var(--dial-2); border-color: var(--dial-2); }
.btn.lamp { background: var(--lamp); border-color: var(--lamp); color: #fff; font-weight: 600; }
.btn.lamp:hover { box-shadow: var(--lamp-glow); }
.btn.lamp.on { box-shadow: var(--lamp-glow); animation: pulse 1.6s ease-in-out infinite; }
.btn.ghost { background: transparent; border-color: transparent; }
.btn.ghost:hover { background: var(--ink-3); }
.btn.outline { background: transparent; }
.btn.sm { height: 28px; padding: 0 10px; font-size: 13px; }
.btn.lg { height: 44px; padding: 0 22px; font-size: 15px; }
.btn.icon { width: 34px; padding: 0; }
.btn.icon.sm { width: 28px; }
.btn.icon.lg { width: 56px; height: 56px; }
.btn.danger:hover { border-color: var(--lamp); color: var(--lamp); }
.btn svg { width: 18px; height: 18px; flex: none; }
.btn.sm svg { width: 15px; height: 15px; }
.btn.lg svg { width: 22px; height: 22px; }
@keyframes pulse { 0%, 100% { box-shadow: var(--lamp-glow); } 50% { box-shadow: 0 0 6px rgba(230, 57, 47, .4); } }

/* ─── Inputs ─── */
.input, select.input, textarea.input {
  width: 100%; height: 34px; padding: 0 10px; border-radius: var(--r-sm); border: 1px solid var(--line-2);
  background: var(--ink); color: var(--text);
}
textarea.input { height: auto; min-height: 80px; padding: 10px 12px; resize: vertical; }
.input:focus { border-color: var(--dial); outline: none; }
.input::placeholder { color: var(--muted); }
select.input { appearance: none; padding-right: 32px; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236e717c' stroke-width='2.5'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; }
.field { display: grid; gap: 6px; }
.field > label { font-size: 12px; font-weight: 500; color: var(--text-2); letter-spacing: .02em; }
.field .hint { font-size: 12px; color: var(--muted); }
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }
.check { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; }
.check input { accent-color: var(--dial); width: 16px; height: 16px; }
.range { -webkit-appearance: none; appearance: none; height: 4px; background: var(--line-2); border-radius: 2px; width: 100%; cursor: pointer; }
.range::-webkit-slider-thumb { -webkit-appearance: none; width: 14px; height: 14px; border-radius: 50%; background: var(--dial); border: 2px solid var(--ink); }
.range::-moz-range-thumb { width: 12px; height: 12px; border-radius: 50%; background: var(--dial); border: 2px solid var(--ink); }

/* ─── Surfaces ─── */
.panel { background: var(--ink-2); border: 1px solid var(--line); border-radius: var(--r); }
.panel-h { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--line); }
.panel-b { padding: 16px 18px; }
.panel.flush .panel-b { padding: 0; }
.stack { display: grid; gap: 12px; }
.row { display: flex; align-items: center; gap: 10px; }
.row.wrap { flex-wrap: wrap; }
.row.between { justify-content: space-between; }
.grow { flex: 1; min-width: 0; }
.pill { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px; border-radius: 999px; font-size: 12px; font-weight: 500; background: var(--ink-3); border: 1px solid var(--line); color: var(--text-2); white-space: nowrap; }
.pill.amber { background: var(--dial-dim); border-color: var(--dial-line); color: var(--dial); }
.pill.red { background: var(--lamp-dim); border-color: rgba(230, 57, 47, .4); color: #ff8b84; }
.pill.ok { background: rgba(88, 195, 154, .12); border-color: rgba(88, 195, 154, .35); color: var(--ok); }
/* The watchdog badge (1.52). Three states a listener can tell apart without
   reading the label: listening, away, switched off. The icon changes with the
   state as well as the colour, because a colour alone is not a state. */
.pill.wd svg { width: 14px; height: 14px; }
.pill.wd.online { background: rgba(88, 195, 154, .12); border-color: rgba(88, 195, 154, .35); color: var(--ok); }
.pill.wd.online svg { animation: wd-breathe 3.2s ease-in-out infinite; }
.pill.wd.offline { background: var(--ink-3); border-color: var(--line); color: var(--muted); }
.pill.wd.off { background: transparent; border-style: dashed; color: var(--muted); }
@keyframes wd-breathe { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .pill.wd.online svg { animation: none; opacity: 1; } }
/* ─── The watchdog's card (1.52.3) ─── */
/* Drawn at real pixel width, so nothing here sets a width on the svg itself. */
.wdcard .wdhead { gap: 10px; }
.wdchart { width: 100%; }
/* The base rule below (`svg { width:18px; height:18px }`) is the icon set's, and
   it squashes a chart to an 18px stamp. The dial has the same override. */
.wdchart svg { display: block; width: 100%; height: auto; flex: none; overflow: visible; }
.wdchart .wdaxis { stroke: var(--line); stroke-width: 1; }
.wdchart .wdidle { fill: var(--muted); opacity: .8; }
.wdchart .wdlbl { fill: var(--muted); font-family: var(--font-mono); font-size: 10px; }
.wdlegend { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
.wdkey { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-2); }
.wdkey i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
.wdkey.idle i { height: 3px; border-radius: 1.5px; background: var(--muted); }
.wdline { color: var(--text-2); }
.wddonewrap .k { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin-bottom: 4px; }
.wddone { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.wddone li { display: grid; grid-template-columns: 64px 1fr; gap: 10px; font-size: 13px; color: var(--text-2); }
.wddone li.empty { grid-template-columns: 1fr; color: var(--muted); }
.wddone .t { font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
@media (max-width: 700px) { .wddone li { grid-template-columns: 56px 1fr; gap: 8px; } }
.divider { height: 1px; background: var(--line); margin: 6px 0; }
.empty { padding: 36px 20px; text-align: center; color: var(--muted); }
.empty strong { display: block; color: var(--text-2); margin-bottom: 4px; font-weight: 500; }
.kbd { font-family: var(--font-mono); font-size: 11px; padding: 1px 6px; border: 1px solid var(--line-2); border-bottom-width: 2px; border-radius: 4px; color: var(--text-2); background: var(--ink); }

/* ─── ON AIR lamp ─── */
.lamp { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-display); font-weight: 700; font-size: 13px; letter-spacing: .2em; text-transform: uppercase; color: var(--muted); }
.lamp::before { content: ""; width: 10px; height: 10px; border-radius: 50%; background: var(--ink-4); border: 1px solid var(--line-2); transition: background .2s, box-shadow .2s; }
.lamp.on { color: #ff8b84; }
.lamp.on::before { background: var(--lamp); border-color: var(--lamp); box-shadow: var(--lamp-glow); }
.lamp.auto { color: var(--dial); }
.lamp.auto::before { background: var(--dial); border-color: var(--dial); box-shadow: 0 0 12px rgba(240, 177, 59, .6); }

/* ─── Program dial (signature) ─── */
.dial { position: relative; width: 100%; user-select: none; }
.dial svg { width: 100%; height: auto; display: block; overflow: visible; }
.dial .tick { stroke: var(--line-2); stroke-width: 1; }
.dial .tick.major { stroke: var(--text-2); stroke-width: 1.2; }
.dial .num { font-family: var(--font-mono); font-size: 9px; fill: var(--muted); }
.dial .band { rx: 2; opacity: .9; }
.dial .band.song { fill: var(--dial); opacity: .55; }
.dial .band.song.played { opacity: .22; }
.dial .band.song.playing { opacity: 1; }
.dial .band.spot { fill: var(--lamp); opacity: .8; }
.dial .band.spot.played { opacity: .3; }
.dial .band.imaging, .dial .band.legal_id, .dial .band.psa, .dial .band.promo, .dial .band.cart { fill: var(--text); opacity: .7; }
.dial .band.voicetrack { fill: var(--ok); }
.dial .band.pending.song { opacity: .35; }
.dial .needle { stroke: var(--dial-2); stroke-width: 1.5; }
.dial .needle-cap { fill: var(--dial-2); }
.dial .needle-time { font-family: var(--font-mono); font-size: 10px; fill: var(--dial-2); }
.dial .band:hover { opacity: 1; cursor: pointer; }
.dial-legend { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 8px; font-size: 11px; color: var(--muted); }
.dial-legend span::before { content: ""; display: inline-block; width: 10px; height: 6px; border-radius: 2px; margin-right: 6px; vertical-align: 1px; background: var(--dial); opacity: .7; }
.dial-legend .l-spot::before { background: var(--lamp); }
.dial-legend .l-imaging::before { background: var(--text); }
.dial-legend .l-vt::before { background: var(--ok); }

/* ─── Level meter ─── */
.meter { display: flex; align-items: flex-end; gap: 2px; height: 28px; width: 120px; }
.meter { padding: 3px 4px; background: rgba(0,0,0,.3); border: 1px solid var(--line); border-radius: var(--r-sm); }
.meter i { flex: 1; background: var(--dial); opacity: .22; border-radius: 1px; min-height: 3px; transition: height .06s linear, opacity .06s linear; }
.meter i.on { opacity: 1; height: 100%; }
.meter i.hot { background: var(--lamp); }

/* ─── Artwork ─── */
.art { background: var(--ink-3); border-radius: var(--r-sm); overflow: hidden; aspect-ratio: 1; display: grid; place-items: center; color: var(--muted); position: relative; }
.art img { width: 100%; height: 100%; object-fit: cover; }
.art svg { width: 40%; height: 40%; opacity: .4; }
/* Quiet by default so a page of them is not a wall of amber; the station
   colour is saved for the one that is actually on the air. */
.art svg.plate { width: 100%; height: 100%; opacity: 1; color: var(--line-2); padding: 9%; }
.con-now .art svg.plate, .hero .art svg.plate, .np-full .art svg.plate { color: var(--dial); opacity: .85; }
.art.round { border-radius: 50%; }
.art.xl { border-radius: 14px; box-shadow: var(--shadow); }

/* ──────────────────────────────────────────────────────────────
   Public radio page
   ────────────────────────────────────────────────────────────── */
.topbar { position: sticky; top: 0; z-index: 30; display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 24px; background: rgba(18, 19, 23, .85); backdrop-filter: blur(14px); border-bottom: 1px solid var(--line); }
.wordmark { display: flex; align-items: baseline; gap: 10px; }
.wordmark .call { font-family: var(--font-display); font-weight: 700; font-size: 26px; letter-spacing: .06em; color: var(--dial); }
.wordmark .tag { font-size: 13px; color: var(--text-2); }
.topnav { display: flex; align-items: center; gap: 4px; }
.topnav a { padding: 6px 12px; border-radius: 999px; color: var(--text-2); font-size: 14px; }
.topnav a:hover, .topnav a.active { color: var(--text); background: var(--ink-3); }

.radio { max-width: 1180px; margin: 0 auto; padding: 32px 24px 80px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 28px; }
.hero { display: grid; grid-template-columns: minmax(220px, 340px) 1fr; gap: 36px; align-items: start; }
.hero .art { width: 100%; }
.hero-body { display: grid; gap: 14px; align-content: start; min-width: 0; }
.hero-title { font-size: clamp(38px, 6vw, 76px); font-family: var(--font-display); font-weight: 700; line-height: .92; letter-spacing: -.005em; overflow-wrap: anywhere; }
.hero-artist { font-size: clamp(18px, 2.4vw, 26px); color: var(--text-2); }
.hero-artist b { color: var(--text); font-weight: 500; }
.progress { height: 3px; background: var(--line); border-radius: 2px; overflow: hidden; }
.progress i { display: block; height: 100%; background: var(--dial); width: 0; transition: width 1s linear; }
.listen { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: 6px; }
.vol { display: flex; align-items: center; gap: 8px; width: 160px; }
.show-card { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: var(--r); background: var(--ink-2); border: 1px solid var(--line); }
.show-card .swatch { width: 4px; align-self: stretch; border-radius: 2px; background: var(--dial); }
.two-col { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; }
.list { list-style: none; margin: 0; padding: 0; }
.list li { display: flex; align-items: center; gap: 12px; padding: 10px 18px; border-top: 1px solid var(--line); }
.list li:first-child { border-top: 0; }
.list .art { width: 44px; flex: none; }
.list .meta { min-width: 0; flex: 1; }
.list .meta .t { font-weight: 500; }
.list .meta .a { font-size: 13px; color: var(--text-2); }
.list .when { font-family: var(--font-mono); font-size: 12px; color: var(--muted); white-space: nowrap; }
.req-results { display: grid; gap: 4px; max-height: 260px; overflow: auto; }
.req-results button { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 8px 10px; border-radius: var(--r-sm); border: 1px solid transparent; background: transparent; cursor: pointer; }
.req-results button:hover, .req-results button.sel { background: var(--ink-3); border-color: var(--line-2); }
.req-results .art { width: 36px; }
.sched { display: grid; gap: 10px; }
.sched-day { display: grid; grid-template-columns: 64px 1fr; gap: 12px; align-items: start; }
.sched-day .d { font-family: var(--font-display); font-weight: 600; font-size: 16px; letter-spacing: .08em; color: var(--muted); padding-top: 6px; }
.sched-show { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-radius: var(--r-sm); background: var(--ink-2); border: 1px solid var(--line); margin-bottom: 6px; }
.sched-show .swatch { width: 3px; height: 26px; border-radius: 2px; }
.stream-urls { display: flex; flex-wrap: wrap; gap: 8px; }
.stream-urls code { font-family: var(--font-mono); font-size: 12px; padding: 6px 10px; background: var(--ink); border: 1px solid var(--line); border-radius: var(--r-sm); color: var(--text-2); }
.foot { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding-top: 28px; border-top: 1px solid var(--line); color: var(--muted); font-size: 13px; }

/* ──────────────────────────────────────────────────────────────
   Library (Apple Music / Spotify feel, on the console palette)
   ────────────────────────────────────────────────────────────── */
.lib { display: grid; grid-template-columns: 240px 1fr; min-height: 100vh; padding-bottom: calc(var(--bar-h) + var(--safe-b)); }
.side { position: sticky; top: 0; height: calc(100vh - var(--bar-h) - var(--safe-b)); overflow: auto; padding: 18px 12px; border-right: 1px solid var(--line); background: var(--ink-2); display: flex; flex-direction: column; gap: 6px; }
.side .wordmark { padding: 4px 10px 14px; }
.side a.nav { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--r-sm); color: var(--text-2); font-size: 14px; }
.side a.nav svg { width: 18px; height: 18px; }
.side a.nav:hover { background: var(--ink-3); color: var(--text); }
.side a.nav.active { background: var(--dial-dim); color: var(--dial); }
.side .eyebrow { padding: 16px 10px 6px; }
.side .pl { display: block; padding: 6px 10px; border-radius: var(--r-sm); color: var(--text-2); font-size: 13px; }
.side .pl:hover, .side .pl.active { background: var(--ink-3); color: var(--text); }
.side .spacer { flex: 1; }
.main { padding: 22px 28px 40px; min-width: 0; }
.main-h { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 18px; flex-wrap: wrap; }
.main-h h1 { font-family: var(--font-display); font-weight: 700; font-size: 34px; letter-spacing: .01em; }
.searchbar { position: relative; max-width: 520px; }
.searchbar input { padding-left: 38px; height: 42px; border-radius: 999px; }
.searchbar svg { position: absolute; left: 14px; top: 12px; width: 18px; height: 18px; color: var(--muted); }
.section { margin-bottom: 30px; }
.section-h { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 12px; }
.section-h h2 { font-size: 19px; font-weight: 600; }
.section-h a { font-size: 13px; color: var(--muted); }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 18px; }
.card { display: grid; gap: 8px; min-width: 0; cursor: pointer; }
.card .art { position: relative; }
.card .play-ov { position: absolute; right: 8px; bottom: 8px; width: 40px; height: 40px; border-radius: 50%; background: var(--dial); color: #1a1408; display: grid; place-items: center; opacity: 0; transform: translateY(6px); transition: opacity .15s, transform .15s; border: 0; cursor: pointer; }
.card:hover .play-ov { opacity: 1; transform: none; }
.card .play-ov svg { width: 18px; height: 18px; }
.card .t { font-weight: 500; font-size: 14px; }
.card .s { font-size: 13px; color: var(--muted); }
.hero-album { display: grid; grid-template-columns: 220px 1fr; gap: 26px; align-items: end; margin-bottom: 24px; }
.hero-album h1 { font-family: var(--font-display); font-weight: 700; font-size: 44px; line-height: .95; }
.hero-album .sub { color: var(--text-2); margin-top: 8px; }
.tracks { width: 100%; border-collapse: collapse; }
.tracks th { text-align: left; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); font-weight: 500; padding: 6px 10px; border-bottom: 1px solid var(--line); }
.tracks td { padding: 8px 10px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.tracks tr { cursor: pointer; }
.tracks tr:hover td { background: var(--ink-2); }
.tracks tr.cur td { color: var(--dial); }
.tracks .n { width: 36px; font-family: var(--font-mono); font-size: 12px; color: var(--muted); text-align: right; }
.tracks .n svg { width: 14px; height: 14px; }
.tracks .dur { width: 60px; text-align: right; font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
.tracks .acts { width: 90px; text-align: right; white-space: nowrap; }
.tracks .acts .btn { opacity: 0; }
.tracks tr:hover .acts .btn, .tracks .acts .btn.on { opacity: 1; }
.tracks .sub { font-size: 12px; color: var(--muted); }
.tracks .artc { width: 40px; }
.tracks .artc .art { width: 32px; }
.letters { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 16px; }
.letters a { font-family: var(--font-mono); font-size: 12px; padding: 4px 8px; border-radius: 4px; color: var(--muted); }
.letters a:hover { background: var(--ink-3); color: var(--text); }
.artist-index h3 { font-family: var(--font-display); font-size: 28px; color: var(--dial); margin: 22px 0 8px; }
.artist-index .grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
.bio { color: var(--text-2); max-width: 720px; }

/* Transport bar */
.bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; height: calc(var(--bar-h) + var(--safe-b)); padding: 0 16px var(--safe-b); background: rgba(25, 27, 33, .96); backdrop-filter: blur(16px); border-top: 1px solid var(--line); display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 16px; }
.bar .np { display: flex; align-items: center; gap: 12px; min-width: 0; }
.bar .np .art { width: 54px; flex: none; cursor: pointer; }
.bar .np .t { font-weight: 500; }
.bar .np .a { font-size: 13px; color: var(--text-2); }
.bar .ctl { display: grid; gap: 6px; justify-items: center; }
.bar .ctl .row { gap: 4px; }
.bar .seek { display: flex; align-items: center; gap: 10px; width: min(520px, 40vw); }
.bar .seek .mono { font-size: 11px; color: var(--muted); width: 40px; }
.bar .seek .mono:last-child { text-align: right; }
.bar .right { display: flex; align-items: center; justify-content: flex-end; gap: 6px; }
.bar .btn.on { color: var(--dial); }
.bar .icon.play { background: var(--text); color: var(--ink); border-color: var(--text); width: 42px; height: 42px; }
.bar .icon.play:hover { background: #fff; }

/* Full-screen now playing + lyrics */
.np-full { position: fixed; inset: 0; z-index: 50; background: var(--ink); display: grid; grid-template-columns: minmax(280px, 46%) 1fr; overflow: hidden; }
.np-full::before { content: ""; position: absolute; inset: 0; background: var(--np-bg, none); background-size: cover; background-position: center; filter: blur(80px) saturate(1.3) brightness(.45); transform: scale(1.3); opacity: .9; }
.np-full > * { position: relative; }
.np-full .left { display: grid; align-content: center; justify-items: center; gap: 22px; padding: 40px; }
.np-full .left .art { width: min(420px, 70%); }
.np-full .left .title { font-family: var(--font-display); font-weight: 700; font-size: 34px; text-align: center; line-height: 1; }
.np-full .left .sub { color: var(--text-2); text-align: center; font-size: 16px; }
.np-full .close { position: absolute; top: 16px; right: 16px; z-index: 2; }
.lyrics { overflow: auto; padding: 46vh 48px; scroll-behavior: smooth; mask-image: linear-gradient(transparent, #000 15%, #000 85%, transparent); }
.lyrics p { font-family: var(--font-display); font-weight: 600; font-size: clamp(26px, 3.2vw, 40px); line-height: 1.15; color: rgba(236, 232, 222, .32); margin: 0 0 22px; transition: color .25s, transform .25s; transform-origin: left; cursor: pointer; }
.lyrics p.cur { color: var(--text); transform: scale(1.03); }
.lyrics p.past { color: rgba(236, 232, 222, .18); }
.lyrics.plain p { font-family: var(--font-body); font-weight: 400; font-size: 18px; color: var(--text-2); margin: 0 0 6px; cursor: default; }
.lyrics .none { color: var(--muted); font-size: 16px; font-family: var(--font-body); font-weight: 400; }
.queue-drawer { position: fixed; right: 0; top: 0; bottom: calc(var(--bar-h) + var(--safe-b)); width: min(420px, 100vw); z-index: 45; background: var(--ink-2); border-left: 1px solid var(--line); display: grid; grid-template-rows: auto 1fr; box-shadow: var(--shadow); }
.queue-drawer .list { overflow: auto; }
.queue-drawer li.cur .meta .t { color: var(--dial); }

/* ──────────────────────────────────────────────────────────────
   Studio
   ────────────────────────────────────────────────────────────── */
.studio {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "console console" "rail main";
  min-height: 100vh;
  --console-h: 258px;
}

/* ─── The console: one strip across the top, the way a desk is laid out ─── */
.console {
  grid-area: console; position: sticky; top: 0; z-index: 40;
  background: var(--chrome); border-bottom: 1px solid var(--line-2);
}
.con-top { display: flex; align-items: center; gap: 0; height: 104px; padding: 0 18px 0 0; }
.con-sep { width: 1px; align-self: stretch; margin: 18px 16px; background: var(--line); flex: none; }
.con-brand { display: flex; align-items: center; gap: 18px; flex: none; width: 186px; padding-left: 18px; }
.con-brand .wordmark { flex-direction: column; align-items: flex-start; gap: 0; line-height: 1; }
.con-brand .wordmark .call { font-size: 31px; }
.con-brand .wordmark .tag { font-size: 12px; letter-spacing: .2em; text-transform: uppercase; color: var(--muted); }

.con-now { display: flex; align-items: center; gap: 16px; min-width: 300px; flex: 2 1 470px; }
.con-now .art { width: 72px; height: 72px; flex: none; border-radius: var(--r-sm); }
.con-now .cn-txt { min-width: 0; flex: 1; }
.con-now .cn-t { font-family: var(--font-display); font-weight: 700; font-size: 30px; line-height: 1.08; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.con-now .cn-a { font-size: 16px; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.con-now .cn-time { flex: none; text-align: right; }
.con-now .cn-rem { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 40px; font-weight: 600; line-height: 1; transition: color .3s; }
.con-now .cn-rem.hot { color: var(--lamp); animation: pulse-t 1s ease-in-out infinite; }
.con-now .cn-rem.warm { color: var(--dial); }
.con-now .cn-el { font-family: var(--font-mono); font-size: 14px; color: var(--muted); margin-top: 2px; }
@keyframes pulse-t { 50% { opacity: .45; } }

.con-next { flex: 1 1 300px; min-width: 0; display: grid; grid-template-columns: 52px minmax(0, 1fr) auto; column-gap: 14px; row-gap: 6px; align-items: baseline; }
.con-cue { display: contents; }
.con-cue .lab { font-family: var(--font-display); font-size: 13px; font-weight: 700; letter-spacing: .16em; color: var(--muted); }
.con-cue.next .lab { color: var(--dial); }
.con-cue .val { font-size: 17px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-2); }
.con-cue.next .val { color: var(--text); font-weight: 500; }
.con-cue .in { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 16px; color: var(--muted); }
.con-cue.next .in { color: var(--dial); }
.con-vox { grid-column: 2 / -1; font-size: 14px; color: var(--ok); }
@media (max-width: 1560px) { .con-cue.then .lab, .con-cue.then .val, .con-cue.then .in { display: none; } }

.con-meters { display: flex; align-items: center; gap: 26px; flex: none; }
.con-m { display: grid; gap: 1px; }
.con-m .v { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 28px; line-height: 1; }
.con-m .k { font-size: 11px; letter-spacing: .13em; text-transform: uppercase; color: var(--muted); margin-top: 3px; }
.con-health { display: grid; gap: 4px; flex: none; }

.con-trans { display: flex; align-items: center; gap: 10px; flex: none; margin-left: 18px; }
/* The air monitor (1.10): one player in the studio that plays the air. */
/* The on-the-air bar under the bus (1.10 T7): what is playing, and LISTEN,
   read like BREAK IN — one press to hear the station on every page. */
.con-air { display: flex; align-items: center; gap: 10px; height: 40px; padding: 0 18px; background: var(--chrome-2); border-top: 1px solid var(--line); }
.con-air .live-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 8px rgba(88,195,154,.7); flex: none; }
.con-air.off .live-dot { background: var(--muted); box-shadow: none; }
.con-air .t { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.con-air .a { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.con-air .grow { flex: 1; }
.con-air .mon-vol { width: 90px; accent-color: var(--dial); }
.con-air .mon-st { white-space: nowrap; }
.btn.listen { height: 30px; padding: 0 16px; font-family: var(--font-display); font-weight: 700; font-size: 13px; letter-spacing: .12em; border-color: var(--dial-line); color: var(--dial); background: transparent; }
.btn.listen:hover { background: var(--dial-dim); }
.btn.listen.on { background: var(--dial); border-color: var(--dial); color: #1a1408; box-shadow: 0 0 18px rgba(240,177,59,.45); }
.btn.listen svg { width: 16px; height: 16px; }
@media (max-width: 1100px) { .con-air .a, .con-air .mon-st { display: none; } .con-air .mon-vol { width: 60px; } }
.con-trans .btn.lamp { height: 64px; padding: 0 26px; font-size: 17px; font-weight: 700; letter-spacing: .07em; }
.con-trans .btn.lamp svg { width: 22px; height: 22px; }
.con-trans .btn.lamp.join { border-color: var(--ok); color: var(--ok); }
.con-trans .btn.lamp.held { border-color: var(--line-2); color: var(--muted); background: var(--ink-3); letter-spacing: .05em; }
.con-trans .btn.skip { height: 64px; padding: 0 20px; font-size: 15px; }
.con-trans .btn.skip svg { width: 20px; height: 20px; }

/* segmented control: one control, three states, no wandering checkboxes */
.seg { display: inline-flex; border: 1px solid var(--line-2); border-radius: var(--r-btn); overflow: hidden; background: var(--ink); }
.seg button { height: 36px; padding: 0 14px; font-size: 14px; background: transparent; border: 0; border-left: 1px solid var(--line); color: var(--text-2); cursor: pointer; white-space: nowrap; }
.seg button:first-child { border-left: 0; }
.seg button:hover { background: var(--ink-3); color: var(--text); }
.seg button.on { background: var(--dial-dim); color: var(--dial); font-weight: 600; }
.seg button.on.live { background: var(--lamp-dim); color: #ff8b84; }

/* the always-on timeline strip */
.con-strip { position: relative; border-top: 1px solid var(--line); background: #0b0c0f; }
.rib { position: relative; }
.rib canvas { display: block; width: 100%; }
.rib-zoom { position: absolute; top: 3px; right: 6px; display: flex; gap: 2px; }
.rib canvas { cursor: grab; }
.rib-zoom button { height: 24px; padding: 0 11px; font-size: 12px; font-family: var(--font-mono); background: rgba(20,22,28,.9); border: 1px solid var(--line); border-radius: 4px; color: var(--muted); cursor: pointer; }
.rib-now { position: absolute; top: 3px; left: 50%; transform: translateX(-50%); height: 24px; padding: 0 13px; font-size: 12px; background: var(--lamp); border: 0; border-radius: 4px; color: #fff; font-weight: 600; cursor: pointer; z-index: 4; }
.rib-grip { position: absolute; left: 0; right: 0; bottom: 0; height: 7px; cursor: ns-resize; }
/* The cue-marker timers (1.10 T5): an SVG over the canvas, pointer-transparent. */
.rib-marks { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.rib-mark line { stroke-width: 2; }
.rib-mark rect { fill: rgba(9,10,13,.82); }
.rib-mark text { font: 700 11px var(--font-mono, ui-monospace, monospace); dominant-baseline: auto; }
.rib-mark.post line { stroke: var(--ok); }
.rib-mark.post text { fill: var(--ok); }
.rib-mark.segue line { stroke: rgba(255,255,255,.55); stroke-dasharray: 3 3; }
.rib-mark.segue text { fill: rgba(255,255,255,.9); }
.rib-grip::after { content: ""; position: absolute; left: 50%; bottom: 2px; transform: translateX(-50%); width: 46px; height: 3px; border-radius: 2px; background: var(--line-2); }
.rib-grip:hover::after { background: var(--dial); }
.rib-zoom button:hover { color: var(--text); border-color: var(--line-2); }
.rib-zoom button.on { background: var(--dial-dim); border-color: var(--dial-line); color: var(--dial); }
.rib-tip { position: absolute; bottom: 6px; display: grid; gap: 1px; max-width: 240px; padding: 6px 9px; background: rgba(14,15,19,.96); border: 1px solid var(--line-2); border-radius: var(--r-sm); pointer-events: none; box-shadow: var(--shadow); z-index: 3; }
.rib-tip strong { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rib-tip .a { font-size: 13px; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rib-tip .w { font-family: var(--font-mono); font-size: 12.5px; color: var(--dial); }

/* the live desk, folded into the console */
.con-live { display: grid; gap: 10px; padding: 12px 16px 14px; background: var(--chrome-2); border-top: 1px solid var(--lamp); }
.con-live .btn.lg { min-width: 170px; }
.con-alert { position: absolute; inset: 0; display: flex; align-items: center; gap: 12px; padding: 0 16px; background: var(--lamp-dim); border-top: 1px solid var(--lamp); }
.con-alert .t { font-family: var(--font-display); font-weight: 700; letter-spacing: .14em; color: #ff8b84; }

/* the feed lives in a tray, not a column */
.con-tray { position: absolute; top: 100%; left: 0; right: 0; z-index: 39; max-height: min(46vh, 460px); overflow: auto; background: var(--chrome-2); border-bottom: 1px solid var(--line-2); box-shadow: var(--shadow); padding: 12px 16px 16px; }
.con-tray .feed { max-width: 1100px; }
.feed .n { font-family: var(--font-mono); font-size: 10px; color: var(--muted); border: 1px solid var(--line); border-radius: 3px; padding: 0 4px; margin-left: 6px; }
.tray-btn { position: relative; }
.tray-btn .dot { position: absolute; top: 5px; right: 5px; width: 6px; height: 6px; border-radius: 50%; background: var(--dial); }

.rail { grid-area: rail; position: sticky; top: var(--console-h); height: calc(100vh - var(--console-h)); overflow: auto; background: var(--chrome); border-right: 1px solid var(--line); padding: 14px 8px; display: flex; flex-direction: column; gap: 2px; }
.rail a.nav { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border-radius: var(--r-sm); color: var(--text-2); font-size: 13.5px; }
.rail a.nav svg { width: 16px; height: 16px; }
.rail a.nav:hover { background: var(--ink-3); color: var(--text); }
.rail a.nav.active { background: var(--dial-dim); color: var(--dial); box-shadow: inset 2px 0 0 var(--dial); }
.rail a.nav .badge { margin-left: auto; font-family: var(--font-mono); font-size: 11px; background: var(--lamp); color: #fff; border-radius: 999px; padding: 1px 7px; }
.rail .spacer { flex: 1; }
.rail .eyebrow { font-size: 10px; letter-spacing: .16em; }

.studio-main { grid-area: main; padding: 20px 24px 60px; min-width: 0; }

/* page header: a title and its actions, nothing else */
.phead { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 16px; }
.phead h1 { font-family: var(--font-display); font-weight: 700; font-size: 23px; letter-spacing: .01em; }
.phead .sub { font-size: 13px; color: var(--muted); margin-top: 1px; }
.studio-main > h1 { font-family: var(--font-display); font-weight: 700; font-size: 23px; margin-bottom: 4px; }
.studio-main > .lede { color: var(--muted); font-size: 13px; margin-bottom: 16px; }
.stat { display: grid; gap: 2px; }
.stat .v { font-family: var(--font-mono); font-size: 22px; }
.stat .k { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; }
.work { display: grid; gap: 16px; align-items: start; }
@media (min-width: 1500px) { .work { grid-template-columns: minmax(0, 1.75fr) minmax(320px, 1fr); } }
.stats .panel-b { padding: 12px 14px; }

/* Program log */
.log-hour { margin-bottom: 18px; }
.log-hour .hh { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 14px; background: var(--ink-3); border: 1px solid var(--line); border-radius: var(--r) var(--r) 0 0; }
.log-hour .hh .t { font-family: var(--font-display); font-weight: 700; font-size: 22px; }
.log { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-top: 0; border-radius: 0 0 var(--r) var(--r); overflow: hidden; }
/* The row is a table: twelve cells, in the order a jock's log has always put
   them. THE TRACK COUNT MUST MATCH THE VISIBLE CELLS at every breakpoint —
   that is what broke the narrow layout before, so log-harness.mjs counts them.
   children: time · state · bar-t · aud · uid · art · meta · intro · dur · cat · yr
   (.acts is lifted out of the flow — see below) */
.log li, .log-head { display: grid; grid-template-columns: 72px 56px 4px 32px 46px 34px minmax(0, 1fr) 46px 52px 100px 44px; align-items: center; gap: 10px; padding: 7px 12px 7px 10px; }
.log li { position: relative; border-top: 1px solid var(--line); background: var(--ink-2); cursor: default; }
.log li:first-child { border-top: 0; }
.log li .time { font-family: var(--font-mono); font-size: 12px; color: var(--muted); white-space: nowrap; }
.log li .bar-t { width: 4px; height: 100%; min-height: 34px; border-radius: 2px; background: var(--dial); opacity: .6; }
.log li.spot .bar-t { background: var(--lamp); }
.log li.imaging .bar-t, .log li.legal_id .bar-t, .log li.psa .bar-t, .log li.promo .bar-t, .log li.cart .bar-t { background: var(--text); }
.log li.voicetrack .bar-t { background: var(--ok); }
.log li .art { width: 40px; }
.log li .art.type { font-family: var(--font-display); font-weight: 700; font-size: 11px; letter-spacing: .06em; color: var(--text-2); }
.log li .meta .t { font-weight: 500; }
.log li .meta .a { font-size: 12px; color: var(--text-2); }
.log li .dur { font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
.log li .num, .log-head .num { font-family: var(--font-mono); font-size: 12px; text-align: right; }
.log li .uid { font-family: var(--font-mono); font-size: 11px; color: var(--muted); opacity: .7; }
.log li .intro { color: var(--text-2); }
/* 1.8: who voiced a break, and who has an hour. The chip is a child of the
   title cell, never of the row — every log row keeps the same eleven grid
   children and test/log-harness.mjs counts them at ten widths. */
.log li .meta .t .aichip { display: inline-block; margin-right: 6px; padding: 0 5px; border: 1px solid var(--line);
  border-radius: 3px; font-size: 10px; letter-spacing: .04em; text-transform: uppercase; vertical-align: 1px; white-space: nowrap; }
.log li .meta .t .aichip.draft { border-style: dashed; opacity: .85; }
.aichip.asked { border-style: dashed; animation: pulse 1.6s ease-in-out infinite; }
.hstrip .htab .hwho { display: inline-block; margin-right: 3px; font-weight: 700; font-size: 10px; }
.hstrip .htab .hwho.fallback { opacity: .45; font-weight: 500; }
/* The roster: seven rows of twenty-four. Small on purpose — a week has to be
   readable at a glance before it is clickable. */
.roster { display: grid; grid-template-columns: 42px repeat(24, 1fr); gap: 2px; margin-top: 10px; user-select: none; }
.roster .rlbl { font-size: 11px; color: var(--muted); display: flex; align-items: center; }
.roster .rhh { font-size: 9px; color: var(--muted); text-align: center; }
.roster .rcell { height: 22px; border: 1px solid var(--line); border-radius: 2px; background: var(--ink-3);
  font-size: 9px; font-weight: 700; color: var(--ink); display: flex; align-items: center; justify-content: center; cursor: pointer; }
.roster .rcell:hover { outline: 1px solid var(--text-2); }
.roster .rcell.fallback { opacity: .38; }
.roster .rcell.over { box-shadow: inset 0 -3px 0 var(--dial); }
/* The three states a person has to tell apart at a glance (1.9): painted is
   solid; unassigned is the default's initial, dimmed and dashed; an explicit
   Nobody is hatched with a dash, because it is a decision, not an absence. */
.roster .rcell.fallback { opacity: .42; border-style: dashed; border-color: var(--line-2); }
.roster .rcell.nobody { background: repeating-linear-gradient(135deg, var(--ink-3) 0 3px, var(--ink-4) 3px 6px); color: var(--muted); border-color: var(--line-2); }
.roster .rcell.painted:not(.nobody) { border-color: transparent; }

/* ─── Settings → Virtual jock (1.9) ─── */
.jock .jock-nav { width: max-content; max-width: 100%; overflow-x: auto; }
.jock .jock-nav button { height: 32px; font-size: 13.5px; }
.jock .jock-nav button.adv { color: var(--muted); }
.jock .jock-nav button.adv.on { color: var(--text-2); background: var(--ink-3); }
.jock .jfill .lbl { font-size: 14px; font-weight: 500; }
.jock .jfill .desc { font-size: 12.5px; color: var(--muted); margin-top: 3px; }
.jock .hint.red { color: var(--lamp); }
.jock .jstats { grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); }
.jock .jtile .panel-b { padding: 10px 12px; }
.jock .jtile .v.amber { color: var(--dial); }
.jock .pill.ok .dot { background: var(--ok); }
.jock .pill.amber .dot { background: var(--dial); }
.jock .jcard > .panel-b > .row:first-child .swrow { margin-left: auto; }
.jock .jrows { display: grid; }
.jock .jrow { display: grid; grid-template-columns: 64px 150px 150px minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 8px 14px; border-top: 1px solid var(--line); min-width: 0; }
.jock .jrows.coming .jrow { grid-template-columns: 64px 150px 130px minmax(0, 1fr) auto; }
.jock .jrow:first-child { border-top: 0; }
.jock .jrow .jscript { font-size: 13.5px; line-height: 1.4; min-width: 0; overflow-wrap: anywhere; }
.jock .jrow .jwhen { color: var(--text-2); }
.jock .jcard { border-left: 3px solid var(--line-2); }
.jock .jcard .srow { grid-template-columns: minmax(150px, 220px) minmax(0, 1fr); }
.jock .jweights { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 8px 16px; }
.jock .jweight { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 10px; align-items: start; }
.jock .jshape { padding: 8px 0; border-top: 1px solid var(--line); }
.jock .jshape:first-child { border-top: 0; padding-top: 0; }
.jock .jtline .input { flex: 1; min-width: 0; }
.jock .jpreview { padding: 8px 10px; background: var(--ink-3); border: 1px solid var(--line); border-radius: var(--r-sm); font-style: italic; }
.jock .jpreview:empty { display: none; }
.jock .jbrush .sw, .jock .jlegend .sw { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; border-radius: 3px; margin-right: 6px; font-size: 9px; font-weight: 700; color: var(--ink); vertical-align: -2px; }
.jock .jlegend .sw.fb { background: var(--ink-4); color: var(--text-2); border: 1px dashed var(--line-2); opacity: .7; }
.jock .jlegend .sw.nb { background: repeating-linear-gradient(135deg, var(--ink-3) 0 3px, var(--ink-4) 3px 6px); color: var(--muted); border: 1px solid var(--line-2); }
.jock .jlegend .sw.ov { box-shadow: inset 0 -3px 0 var(--dial); background: var(--ink-3); border: 1px solid var(--line-2); }
.jock .roster-tabs { width: max-content; }
.jock .jkind { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 10px; align-items: start; }
.jock .jlist { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.jock .jterm { height: 26px; padding-right: 2px; gap: 2px; }
.jock .jterm .btn { width: 22px; height: 22px; }
.jock .input.invalid { border-color: var(--lamp); }
@media (max-width: 1100px) {
  .jock .jrow, .jock .jrows.coming .jrow { grid-template-columns: 56px 120px minmax(0, 1fr) auto; }
  .jock .jrow .jtype { display: none; }
  .jock .jrows.coming .jrow > :nth-child(4) { display: none; }
}
/* A song nobody has scanned says so with a dot, not a fake number. */
.log li .intro.unknown { color: var(--lamp); opacity: .55; text-align: center; }
.log li .cat, .log li .yr { font-size: 12px; color: var(--text-2); }
.log li .cat { font-size: 11px; letter-spacing: .02em; text-transform: uppercase; color: var(--muted); }

/* The header that makes them read as columns rather than a list. */
.log-head { padding-top: 6px; padding-bottom: 6px; background: var(--ink-3); border: 1px solid var(--line); border-bottom: 0;
  font-size: 10px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); position: sticky; top: 0; z-index: 4; }
.log-head .meta { font-size: 10px; letter-spacing: .12em; }
.log-head .num { font-size: 10px; letter-spacing: .08em; }
.log-hour .hh { border-radius: var(--r) var(--r) 0 0; }
.log-hour .log-head + .log { border-top: 0; border-radius: 0 0 var(--r) var(--r); }

/* Dense: the same hour, a third less screen. */
.dense .log li { padding: 2px 12px 2px 10px; }
.dense .log li .art { visibility: hidden; }
.dense .log li .meta .a { display: none; }
.dense .log li .meta .t { font-size: 13px; }
.dense .log li .bar-t { min-height: 20px; }
.dense .log-hour { margin-bottom: 12px; }

/* Colour by type. The left bar carries it, and a whisper of tint keeps whole
   blocks — a stopset, a sweep of imaging — legible at a glance in the dark. */
.log li.song .bar-t { background: var(--dial); }
.log li.song { background: color-mix(in srgb, var(--dial) 3%, var(--ink-2)); }
.log li.spot { background: color-mix(in srgb, var(--ok) 5%, var(--ink-2)); }
.log li.imaging, .log li.legal_id, .log li.psa, .log li.promo, .log li.cart, .log li.jingle, .log li.sweeper, .log li.liner {
  background: color-mix(in srgb, var(--lamp) 4%, var(--ink-2)); }
.log li.voicetrack { background: color-mix(in srgb, var(--ok) 8%, var(--ink-2)); }
.log li.voicetrack .bar-t { background: var(--ok); }

/* The on-air row draws how far through it is, in the bar it already has. */
.log li.playing .bar-t {
  background: linear-gradient(to top, var(--dial) var(--played, 0%), color-mix(in srgb, var(--dial) 22%, transparent) var(--played, 0%));
  opacity: 1;
}
.log li.playing .dur { color: var(--dial); font-weight: 600; }
.log li.cued .state { color: var(--ok); }
.log li .acts { position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  display: flex; gap: 2px; opacity: 0; padding: 2px 4px; border-radius: var(--r-sm);
  background: var(--ink-4); box-shadow: 0 2px 12px rgba(0, 0, 0, .5); }
.log li:hover .acts, .log li.selected .acts { opacity: 1; }
/* On deck (1.10 T3): a cued row is already with the transmitter and the playing
   row is on the air. Both are locked, and both look it — a solid tint across
   the whole row, a bar down the left, and the state cell in capitals. Same
   eleven grid children; the label lives in .state, where it always was. */
.log li.playing { background: rgba(240, 177, 59, .20); box-shadow: inset 4px 0 0 var(--dial); }
.log li.playing .meta .t { color: var(--dial); }
.log li.cued { background: rgba(88, 195, 154, .16); box-shadow: inset 4px 0 0 var(--ok); }
.log li.cued .meta .t { color: var(--ok); }
.log li.ondeck .state { font-size: 10.5px; font-weight: 700; opacity: 1; }
.log li.ondeck .acts .btn[disabled] { opacity: .35; cursor: not-allowed; }
.log li.ondeck { cursor: default; }
.menu-item.off { opacity: .45; cursor: not-allowed; }
.ondeck-note { display: flex; align-items: center; gap: 8px; background: var(--dial-dim); border-bottom: 1px solid var(--dial-line); }
.log li.played, .log li.dropped, .log li.skipped, .log li.failed { opacity: .45; }
.log li.failed .meta .t { color: var(--lamp); }
.log li.slotvt { border-style: dashed; }

/* ─── Settings: an index and one section at a time ─── */
.settings { display: grid; grid-template-columns: 216px minmax(0, 1fr); gap: 28px; align-items: start; }
.set-nav { position: sticky; top: calc(var(--console-h) + 20px); display: grid; gap: 1px; }
.set-nav .grp { font-family: var(--font-display); font-size: 10px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); padding: 14px 10px 5px; }
.set-nav .grp:first-child { padding-top: 0; }
.set-nav button { display: flex; align-items: center; gap: 9px; width: 100%; text-align: left; padding: 7px 10px; border: 0; border-radius: var(--r-sm); background: transparent; color: var(--text-2); font-size: 13.5px; cursor: pointer; }
.set-nav button svg { width: 15px; height: 15px; flex: none; opacity: .8; }
.set-nav button:hover { background: var(--ink-3); color: var(--text); }
.set-nav button.on { background: var(--dial-dim); color: var(--dial); box-shadow: inset 2px 0 0 var(--dial); }
.set-nav .adv { margin-top: 14px; padding: 10px 10px 0; border-top: 1px solid var(--line); }
.set-body { display: grid; gap: 16px; min-width: 0; max-width: 940px; }
.set-body > .panel > .panel-b { padding: 4px 18px 12px; }
.set-head { margin-bottom: 2px; }
.set-head h2 { font-family: var(--font-display); font-weight: 700; font-size: 20px; }
.set-head .sub { font-size: 13px; color: var(--muted); margin-top: 2px; }

/* label and its reason on the left, the control on the right */
.srow { display: grid; grid-template-columns: minmax(180px, 300px) minmax(0, 1fr); gap: 24px; padding: 14px 0; border-top: 1px solid var(--line); align-items: start; }
.srow:first-child { border-top: 0; }
.srow .lbl { font-size: 14px; font-weight: 500; }
.srow .desc { font-size: 12.5px; color: var(--muted); margin-top: 3px; line-height: 1.45; }
.srow .ctl { max-width: 430px; display: grid; gap: 8px; }
.srow.wide .ctl { max-width: none; }
.srow .ctl .hint { font-size: 12px; color: var(--muted); }
@media (max-width: 1100px) { .settings { grid-template-columns: 1fr; } .set-nav { position: static; grid-auto-flow: column; grid-auto-columns: max-content; overflow-x: auto; } .set-nav .grp, .set-nav .adv { display: none; } .srow { grid-template-columns: 1fr; gap: 8px; } }

/* a switch reads as on or off from across the room; a checkbox does not */
.switch { position: relative; display: inline-block; width: 40px; height: 22px; flex: none; }
.switch input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; z-index: 2; }
.switch i { position: absolute; inset: 0; border-radius: 999px; background: var(--ink-4); border: 1px solid var(--line-2); transition: background .15s, border-color .15s; }
.switch i::after { content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: var(--text-2); transition: transform .15s, background .15s; }
.switch input:checked + i { background: var(--dial-dim); border-color: var(--dial-line); }
.switch input:checked + i::after { transform: translateX(18px); background: var(--dial); }
.swrow { display: flex; align-items: center; gap: 10px; }
.swrow .st { font-size: 12.5px; color: var(--muted); }

/* the save bar only exists when there is something to save */
.savebar { position: sticky; bottom: 16px; z-index: 20; display: flex; align-items: center; gap: 12px; padding: 10px 14px; background: var(--chrome-2); border: 1px solid var(--dial-line); border-radius: var(--r); box-shadow: var(--shadow); }
.savebar .t { font-size: 13.5px; color: var(--dial); flex: 1; }

/* Voice-track studio: the take is editable after it is laid down */
.vt-takebar { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; padding: 10px 12px; background: var(--ink-3); border: 1px solid var(--line-2); border-radius: var(--r-sm); }
.vt-takebar .row { gap: 8px; }
.vt-trim { position: absolute; top: 0; bottom: 0; width: 9px; cursor: ew-resize; z-index: 4; background: linear-gradient(var(--ok), var(--ok)); opacity: .35; }
.vt-trim:hover { opacity: .9; }
.vt-trim.l { left: 0; border-radius: var(--r-sm) 0 0 var(--r-sm); }
.vt-trim.r { right: 0; border-radius: 0 var(--r-sm) var(--r-sm) 0; }
.vt-clip.v.empty .vt-trim { display: none; }
.vt-mark { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--dial-2); z-index: 7; cursor: ew-resize; }
.vt-mark span { position: absolute; top: 0; left: 4px; font: 700 9px var(--font-display); letter-spacing: .12em; text-transform: uppercase; color: var(--dial-2); white-space: nowrap; }
.vt-ruler { cursor: crosshair; }

/* Cart wall */
.carts { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.cart { position: relative; display: grid; align-content: space-between; gap: 6px; min-height: 104px; padding: 12px; border-radius: var(--r); background: var(--ink-3); border: 1px solid var(--line-2); border-left: 4px solid var(--cart, var(--dial)); cursor: pointer; text-align: left; transition: transform .06s, background .12s; }
.cart:hover { background: var(--ink-4); }
.cart:active, .cart.firing { transform: scale(.98); background: var(--dial-dim); }
.cart .t { font-family: var(--font-display); font-weight: 600; font-size: 17px; line-height: 1.05; }
.cart .m { display: flex; justify-content: space-between; font-family: var(--font-mono); font-size: 11px; color: var(--muted); }
.cart .modes { display: flex; gap: 4px; }
.cart .modes button { flex: 1; height: 24px; font-size: 11px; border-radius: 4px; border: 1px solid var(--line-2); background: var(--ink); cursor: pointer; color: var(--text-2); }
.cart .modes button:hover { border-color: var(--dial); color: var(--dial); }

/* Clocks */
.clock-el { display: grid; grid-template-columns: 32px 1fr auto; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--ink-2); margin-bottom: 6px; }
.clock-el .sw { width: 6px; height: 32px; border-radius: 3px; background: var(--dial); }
.clock-el.stopset .sw { background: var(--lamp); }
.clock-el.imaging .sw, .clock-el.legal_id .sw, .clock-el.promo .sw { background: var(--text); }
.clock-el.voicetrack .sw { background: var(--ok); }
.clock-el .f { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.clock-el .f .input { width: auto; height: 30px; }
.clock-total { font-family: var(--font-mono); color: var(--text-2); }

/* Weekly grid */
.wgrid { display: grid; grid-template-columns: 44px repeat(7, 1fr); gap: 3px; font-size: 11px; }
.wgrid .hd { text-align: center; color: var(--muted); font-family: var(--font-display); font-size: 13px; letter-spacing: .08em; padding: 4px 0; }
.wgrid .hr { font-family: var(--font-mono); color: var(--muted); display: flex; align-items: center; justify-content: flex-end; padding-right: 6px; }
.wgrid .cell { height: 26px; border-radius: 4px; border: 1px solid var(--line); background: var(--ink-2); cursor: pointer; overflow: hidden; padding: 0 6px; color: var(--text-2); white-space: nowrap; text-align: left; }
.wgrid .cell:hover { border-color: var(--dial); }
.wgrid .cell.sel { outline: 2px solid var(--dial); }

/* Listener chart */
.chart { width: 100%; height: 180px; }
.chart svg { width: 100%; height: 100%; }
.chart .area { fill: var(--dial-dim); }
.chart .line { fill: none; stroke: var(--dial); stroke-width: 1.5; }
.chart .grid { stroke: var(--line); stroke-width: 1; }
.chart .lbl { font-family: var(--font-mono); font-size: 10px; fill: var(--muted); }

/* Tables */
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th { text-align: left; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); font-weight: 500; padding: 8px 10px; border-bottom: 1px solid var(--line); }
.table td { padding: 8px 10px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.table tr:hover td { background: var(--ink-2); }
.table .acts { text-align: right; white-space: nowrap; }
.table .acts .btn { opacity: .6; }
.table tr:hover .acts .btn { opacity: 1; }

/* Events feed */
.feed { display: grid; gap: 6px; font-size: 13px; }
.feed div { display: grid; grid-template-columns: 52px 1fr; gap: 10px; }
.feed .ts { font-family: var(--font-mono); font-size: 11px; color: var(--muted); padding-top: 2px; }
.feed .k-deadair { color: var(--lamp); }
.feed .k-live { color: #ff8b84; }
.feed .k-request { color: var(--dial); }

/* Modal, toast, login */
.modal-bg { position: fixed; inset: 0; z-index: 60; background: rgba(0, 0, 0, .6); display: grid; place-items: center; padding: 20px; }
.modal { width: min(640px, 100%); max-height: 90vh; overflow: auto; background: var(--ink-2); border: 1px solid var(--line-2); border-radius: 14px; box-shadow: var(--shadow); }
.modal.wide { width: min(1220px, 100%); }
/* The segue studio is a workbench, not a dialog: it gets the desk. */
.modal.full { width: min(1720px, 97vw); max-height: 94vh; }
.modal.full .vt-lanes { min-height: 340px; }
.toast { position: fixed; left: 50%; bottom: calc(var(--bar-h) + 16px + var(--safe-b)); transform: translateX(-50%); z-index: 70; padding: 10px 16px; border-radius: 999px; background: var(--ink-3); border: 1px solid var(--line-2); box-shadow: var(--shadow); font-size: 14px; animation: rise .18s ease-out; }
.toast.error { border-color: var(--lamp); color: #ff8b84; }
.toast.ok { border-color: var(--ok); }
@keyframes rise { from { opacity: 0; transform: translate(-50%, 8px); } }
.login { min-height: 100vh; display: grid; place-items: center; padding: 24px; }
.login .panel { width: min(400px, 100%); }
.login .wordmark { justify-content: center; margin-bottom: 8px; }

/* Studio recording indicator */
.rec { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: 13px; color: #ff8b84; }
.rec::before { content: ""; width: 10px; height: 10px; border-radius: 50%; background: var(--lamp); box-shadow: var(--lamp-glow); animation: pulse 1s infinite; }

/* ─── Responsive ─── */
/* From here down the song on the air gives way before the controls do (J5):
   the block used to refuse to shrink below 300 px, so the header ran past
   the window from 1360 down to 1024. Its text truncates; nothing else. */
/* S2 (1.53): 1439, not 1360. BREAK IN and Skip are `flex: none` and rightly
   never shrink, so the console's width is the fixed parts added up — and the
   meters were being shown from 1361 when there is no room for them until 1440.
   Measured on every studio page: 38 px over the window through that band, 18 px
   to spare below it, 2 px to spare at 1440. So the meters now appear exactly
   where they fit, and the band closes. */
@media (max-width: 1439px) { .con-meters { display: none; } .con-top { min-width: 0; } .con-now { min-width: 0; flex: 1 1 240px; } }
@media (max-width: 1180px) {
  .con-brand { width: auto; }
  .con-brand .wordmark .tag { display: none; }
  .con-next { display: none; }
  .con-now { flex: 1 1 200px; gap: 10px; }
  .con-sep { margin: 18px 8px; }
  .con-trans { margin-left: 8px; gap: 8px; }
  .con-trans .btn.lamp { padding: 0 16px; }
  .con-trans .btn.skip { padding: 0 12px; }
}
/* Below this the mode buttons live in the break-in drawer instead, so the
   song on the air keeps the room it needs to be readable. */
@media (max-width: 1080px) { .con-trans .seg, .con-trans .check { display: none; } }
@media (max-width: 1100px) {
  .studio { grid-template-columns: 1fr; grid-template-areas: "console" "rail" "main"; }
  /* A strip of tabs under the console, and it stays put like the console
     does (1.12 N4): sticky at the console's measured bottom edge. */
  .rail { position: sticky; top: var(--console-h); z-index: 35; height: auto; flex-direction: row; overflow-x: auto; padding: 8px; border-right: 0; border-bottom: 1px solid var(--line); }
  .rail .spacer, .rail .rail-foot, .rail .eyebrow { display: none; }
  .rail a.nav { flex: none; white-space: nowrap; }
}
@media (max-width: 800px) {
  .hero { grid-template-columns: 1fr; }
  .hero .art { max-width: 320px; }
  .two-col { grid-template-columns: minmax(0, 1fr); }
  .lib { grid-template-columns: 1fr; }
  .side { position: fixed; left: 0; right: 0; bottom: calc(var(--bar-h) + var(--safe-b)); top: auto; height: auto; flex-direction: row; overflow-x: auto; padding: 6px 8px; gap: 4px; border-right: 0; border-top: 1px solid var(--line); z-index: 35; }
  .side .wordmark, .side .eyebrow, .side .pl, .side .spacer, .side .side-foot { display: none; }
  .side a.nav { flex: none; flex-direction: column; gap: 3px; font-size: 11px; padding: 6px 10px; }
  .main { padding: 16px 14px 90px; }
  .bar { grid-template-columns: 1fr auto; }
  .bar .seek { display: none; }
  .bar .right { display: none; }
  .np-full { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .np-full .left { padding: 60px 24px 10px; }
  .np-full .left .art { width: min(240px, 60%); }
  .lyrics { padding: 20px 24px 40vh; }
  .studio { grid-template-columns: 1fr; grid-template-areas: "console" "rail" "main"; }
  .rail { position: static; height: auto; flex-direction: row; overflow-x: auto; padding: 8px; z-index: 35; }
  .rail .spacer, .rail .rail-foot { display: none; }
  .rail a.nav { flex: none; font-size: 13px; }
  .con-top { height: auto; flex-wrap: wrap; gap: 10px; padding: 10px 12px; }
  .con-sep { display: none; }
  .studio-main { padding: 16px 14px 40px; }
  /* Below 800 the artwork is hidden AND the state column is (from the 860
     block, which comes later in this file and would otherwise win), so this
     rule is written stronger than it looks to keep the row in step. */
  /* Below 800 the artwork, the UID and the category go too. Written stronger
     than it looks because the 860 block sits later in this file. */
  ul.log li, div.log-head { grid-template-columns: 46px 4px 32px minmax(0, 1fr) 40px 48px; }
  ul.log li .uid, .log-head .uid, ul.log li .cat, .log-head .cat, .log-head .art { display: none; }
  .log li .art { display: none; }
  .log li .acts { opacity: 1; }
  .topbar { padding: 10px 14px; }
  .radio { padding: 20px 14px 60px; }
  .hero-album { grid-template-columns: 1fr; }
  .hero-album .art { max-width: 220px; }
}

/* ── The voice-track segue studio ─────────────────────────────────────────── */
.vt { width: min(1060px, 100%); }
.vt-lanes { overflow-x: auto; padding: 4px 2px 10px; border: 1px solid var(--line); border-radius: var(--r); background: var(--ink); }
.vt-ruler { position: relative; height: 18px; margin: 2px 0 4px; }
.vt-ruler span { position: absolute; top: 0; height: 14px; padding-left: 4px; border-left: 1px solid var(--line-2); font: 10px var(--font-mono); color: var(--muted); }
.vt-track { position: relative; }
.vt-lane { position: relative; height: 66px; border-top: 1px dashed var(--line); }
.vt-lane.bed { height: 52px; }
.vt-clip { position: absolute; top: 5px; bottom: 5px; border-radius: var(--r-sm); background: var(--ink-3); border: 1px solid var(--line-2); overflow: hidden; cursor: grab; touch-action: none; user-select: none; }
.vt-clip:active { cursor: grabbing; }
.vt-clip canvas { position: absolute; left: 0; top: 11px; pointer-events: none; }
.vt-clip.a { background: rgba(240, 177, 59, .10); border-color: var(--dial-line); cursor: default; }
.vt-clip.v { background: rgba(88, 195, 154, .12); border-color: rgba(88, 195, 154, .45); }
.vt-clip.b { background: rgba(240, 177, 59, .07); border-color: var(--dial-line); }
.vt-clip.d { background: rgba(236, 232, 222, .05); }
.vt-clip.empty { border-style: dashed; background: transparent; cursor: pointer; }
.vt-tag { position: absolute; left: 8px; top: 2px; font: 600 10px var(--font-display); letter-spacing: .14em; text-transform: uppercase; color: var(--text-2); white-space: nowrap; pointer-events: none; }
.vt-vhint { display: flex; align-items: center; justify-content: center; gap: 8px; height: 100%; color: var(--muted); font-size: 12px; pointer-events: none; }
.vt-shade { position: absolute; top: 0; height: 66px; z-index: 2; pointer-events: none; border-left: 1px solid var(--dial-line); background: repeating-linear-gradient(-55deg, transparent 0 7px, rgba(240, 177, 59, .05) 7px 9px); }
.vt-cut { position: absolute; top: -2px; bottom: 0; width: 2px; background: var(--dial); cursor: ew-resize; touch-action: none; z-index: 4; }
.vt-cut::after { content: ''; position: absolute; left: -6px; right: -6px; top: 0; bottom: 0; }
.vt-cut span { position: absolute; top: -1px; left: 5px; padding: 1px 6px; border: 1px solid var(--dial-line); border-radius: 999px; background: var(--ink); font: 600 9px var(--font-display); letter-spacing: .12em; text-transform: uppercase; color: var(--dial); white-space: nowrap; }
.vt-post { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--ok); opacity: .85; z-index: 3; pointer-events: none; }
.vt-post span { position: absolute; bottom: 2px; left: 4px; font: 600 9px var(--font-display); letter-spacing: .12em; text-transform: uppercase; color: var(--ok); }
.vt-post.late { background: var(--lamp); }
.vt-post.late span { color: var(--lamp); }
.vt-playhead { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--text); opacity: .85; z-index: 5; pointer-events: none; }
.vt-readout { font-family: var(--font-mono); font-size: 12px; color: var(--text-2); white-space: nowrap; }
.vt-x { position: absolute; right: 3px; top: 2px; width: 20px; height: 20px; display: grid; place-items: center; border: 0; border-radius: 50%; background: rgba(0, 0, 0, .35); color: var(--text-2); cursor: pointer; z-index: 2; }
.vt-x:hover { color: var(--text); background: rgba(0, 0, 0, .55); }
.vt-x svg { width: 12px; height: 12px; }
.vt-meter { align-self: center; border: 1px solid var(--line); border-radius: 3px; background: var(--ink); }

/* ── Spot studio & cart preview ───────────────────────────────────────────── */
.vt.spotwide { width: min(1180px, 100%); }
.vt-wrap { display: flex; border: 1px solid var(--line); border-radius: var(--r); background: var(--ink); overflow: hidden; }
.vt-heads { width: 96px; flex: none; border-right: 1px solid var(--line); background: var(--ink-2); }
.vt-heads .sp { height: 24px; }
.vt-heads .hd { height: 62px; display: flex; align-items: center; padding: 0 10px; border-top: 1px dashed var(--line); font: 600 10px var(--font-display); letter-spacing: .14em; text-transform: uppercase; color: var(--text-2); }
.vt-wrap .vt-lanes { border: 0; border-radius: 0; flex: 1; }
.vt-lane.spot { height: 62px; }
.vt-cursor { position: absolute; top: 0; bottom: 0; width: 0; border-left: 1px dashed var(--text-2); opacity: .55; pointer-events: none; z-index: 3; }
.vt-target { position: absolute; top: -2px; bottom: 0; width: 2px; background: var(--ok); z-index: 4; pointer-events: none; }
.vt-target span { position: absolute; top: -1px; left: 5px; padding: 1px 6px; border: 1px solid rgba(88, 195, 154, .4); border-radius: 999px; background: var(--ink); font: 600 9px var(--font-display); letter-spacing: .12em; color: var(--ok); }
.vt-clip.sel { outline: 2px solid var(--text); outline-offset: 1px; }
.vt-grip { position: absolute; top: 0; bottom: 0; width: 9px; cursor: ew-resize; z-index: 2; }
.vt-grip.l { left: 0; }
.vt-grip.r { right: 0; }
.cart.previewing { outline: 2px solid var(--ok); }
.cart .modes button:hover { background: var(--lamp); border-color: var(--lamp); color: #fff; }

/* Live talk-up: the on-air position riding the outgoing waveform */
.vt-onair { position: absolute; top: 0; height: 66px; width: 2px; background: var(--lamp); z-index: 6; pointer-events: none; box-shadow: 0 0 8px var(--lamp-glow); }
.vt-onair span { position: absolute; top: -1px; left: 4px; font: 600 9px var(--font-display); letter-spacing: .12em; text-transform: uppercase; color: var(--lamp); white-space: nowrap; }

/* The mic meter idles small until it's armed (no more mystery box) */
.vt-meter { width: 96px; height: 12px; }

/* The timeless bus readout */
.busread { display: grid; gap: 8px; }
.busrow { display: grid; grid-template-columns: 62px minmax(0, 1fr) auto; gap: 12px; align-items: baseline; }
.buslabel { font: 700 10px var(--font-display); letter-spacing: .18em; color: var(--dial); }
.busclock.pulse { animation: busPulse 1s ease-in-out infinite; }
@keyframes busPulse { 50% { opacity: .55; } }

/* Sound bite pads: one tap, on the air */
.cart.bite { border: 1px solid var(--ok); }
.cart.bite .modes { display: none; }

/* Folded history on the program log */
li.histhide { display: none; }

/* Multi-select in the library */
td.selc, th.selc { width: 30px; text-align: center; }
input.selcb { accent-color: var(--dial); width: 15px; height: 15px; cursor: pointer; }
.selbar { position: fixed; left: 50%; bottom: 84px; transform: translateX(-50%); display: flex; gap: 10px; align-items: center;
  background: var(--panel, #1a1b20); border: 1px solid var(--dial); border-radius: 999px; padding: 8px 16px; z-index: 60;
  box-shadow: 0 6px 24px rgba(0,0,0,.5); }

/* The phone-only chrome is BUILT on every page but only styled inside the
   width query below — without this it renders unstyled in the corner of a
   desktop window, which is exactly the smudge that showed up bottom-left. */
.navbtn, .navswitch, .navscrim { display: none; }

/* ─── Phones ──────────────────────────────────────────────────────────────
   Desktop is the working surface and is untouched; everything here is behind
   a width query. Rules are written defensively — the drawers state their own
   layout rather than inheriting it, because inheriting it went badly. */
@media (max-width: 860px) {
  .lib, .studio { grid-template-columns: 1fr !important; grid-template-areas: "console" "rail" "main" !important; }

  /* The slide-over navigation. It declares its own stacking so nothing it
     sits inside can turn it into a row again. */
  .lib > .side, .studio > .rail {
    position: fixed !important; top: 0; left: 0; bottom: 0; right: auto;
    width: min(80vw, 290px); height: 100%;
    display: flex !important; flex-direction: column !important;
    flex-wrap: nowrap !important; align-items: stretch !important;
    transform: translateX(-101%); transition: transform .18s ease;
    z-index: 70; overflow-y: auto; overscroll-behavior: contain;
    box-shadow: 0 0 40px rgba(0,0,0,.65);
    padding-top: calc(14px + env(safe-area-inset-top));
  }
  .lib > .side.open, .studio > .rail.open { transform: none; }
  .lib > .side > *, .studio > .rail > * { flex: 0 0 auto; width: 100%; }
  .lib > .side .spacer, .studio > .rail .spacer { flex: 1 1 auto; min-height: 12px; }
  .lib > .side a.nav, .studio > .rail a.nav { padding: 12px 12px; font-size: 15px; }

  .navscrim { display: block; position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 65; }
  .navscrim.hidden { display: none; }
  .navbtn {
    position: fixed; left: 8px; top: calc(8px + env(safe-area-inset-top)); z-index: 75;
    width: 38px; height: 38px; display: grid; place-items: center;
    background: rgba(20,22,28,.92); border: 1px solid var(--line);
    border-radius: 10px; color: var(--text); backdrop-filter: blur(6px);
  }

  .main, .studio-main { padding: 56px 12px calc(var(--bar-h) + 40px); }
  .main-h h1, .studio-main > h1 { font-size: 23px; }

  /* The console still comes first, but it flows at its natural height so the
     BREAK IN key is never inside a little scroll box. */
  .studio > .console { position: static !important; }
  .con-top { height: auto; flex-wrap: wrap; gap: 12px; padding: 50px 12px 12px; }
  .con-brand { width: auto; padding-left: 0; }
  .con-now { flex: 1 1 100%; }
  .con-trans { margin-left: 0; flex: 1 1 100%; }
  .con-trans .btn { flex: 1; }
  .con-live .btn.lg { min-width: 0; flex: 1; }

  /* Song lists lose the column a thumb can't use and gain room to tap. */
  .tracks .col-album { display: none; }
  .tracks td.n { display: none; }
  .tracks td { padding: 11px 8px; }

  .grid { grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)) !important; gap: 12px !important; }

  /* Modals fill the screen — the Go Live console especially. */
  .modal, .modal.wide {
    width: 100vw !important; max-width: 100vw !important;
    height: 100dvh; max-height: 100dvh; border-radius: 0; overflow-y: auto;
  }
  .panel-b.form-grid { grid-template-columns: 1fr !important; }

  /* Fingers, not cursors. */
  .btn { min-height: 40px; }
  .btn.sm { min-height: 34px; }
  input, select, textarea { font-size: 16px; }   /* stops iOS zooming on focus */

  .busrow { grid-template-columns: 54px minmax(0, 1fr); }
  .busrow > :last-child { grid-column: 2; text-align: left !important; }
  .busclock { font-size: 36px !important; }

  .selbar { bottom: calc(var(--bar-h) + 12px); width: calc(100vw - 24px); justify-content: center; }

  /* One tap between the radio, the library and the studio. */
  .navswitch {
    display: flex; position: fixed; right: 8px; top: calc(8px + env(safe-area-inset-top)); z-index: 75;
    display: flex; gap: 2px; padding: 3px;
    background: rgba(20,22,28,.92); border: 1px solid var(--line);
    border-radius: 10px; backdrop-filter: blur(6px);
  }
  .navswitch a { display: grid; place-items: center; width: 36px; height: 32px; border-radius: 7px; color: var(--text-2); }
  .navswitch a svg { width: 17px; height: 17px; }
  .navswitch a.on { background: var(--dial-dim); color: var(--dial); }

  /* ── What a listener actually opens ──
     The public page stops jumping: the art reserves its square before it
     loads, the title is sized so a long song title doesn't reflow the world,
     and everything is one calm column with the play button in reach. */
  .hero { grid-template-columns: 1fr !important; gap: 16px !important; justify-items: center; text-align: center; }
  .hero .art { width: min(74vw, 300px) !important; aspect-ratio: 1 / 1; object-fit: cover; }
  .hero-body { justify-items: center; gap: 10px; width: 100%; }
  .hero-title { font-size: clamp(24px, 6.4vw, 32px) !important; line-height: 1.08; min-height: 2.2em; display: flex; align-items: center; justify-content: center; }
  .hero-artist { font-size: 15px !important; min-height: 1.4em; }
  .hero-album { grid-template-columns: 1fr !important; justify-items: center; text-align: center; gap: 14px !important; }
  .hero-album h1 { font-size: 26px; }
  .hero-album .art, .hero-album img { width: min(60vw, 220px) !important; aspect-ratio: 1 / 1; }
}

/* Every icon is a 24-unit glyph emitted WITHOUT width or height, so anywhere a
   sizing rule didn't exist it grew to fill its container — which is how a mic
   icon ended up the size of the screen on the carts page. This is the floor;
   every rule that wants a different size is a class selector and still wins. */
svg { width: 18px; height: 18px; flex: none; }
.vt-vhint { display: grid; place-items: center; gap: 4px; height: 100%; font-size: 11px; color: var(--muted); text-align: center; padding: 4px; }

/* The voice changer's control grid. Fixed columns for the label and the
   readout, the slider taking whatever is left — the earlier version let the
   three collide into each other and scroll sideways. */
.vcgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 6px 22px; }
.vcrow { display: grid; grid-template-columns: 92px minmax(80px, 1fr) 56px; align-items: center; gap: 10px; min-width: 0; }
.vcrow label { font-size: 12px; color: var(--text-2); }
.vcrow input[type="range"] { width: 100%; min-width: 0; }
.vcrow .mono { font-size: 11px; color: var(--muted); text-align: right; }
@media (max-width: 860px) { .vcgrid { grid-template-columns: 1fr; } }

/* The Stream Deck button maker: a wall of buttons laid out the way the
   hardware is, so what you build is what you look at. */
.deckwall { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 10px; }
.deckcard { display: grid; gap: 5px; padding: 8px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--ink-2); align-content: start; }
.deckcard canvas { justify-self: center; }
.deckcard .input.sm { font-size: 12px; padding: 4px 6px; }
.deckcard.off { opacity: .42; }
.deckcard.off canvas { filter: grayscale(1); }
@media (max-width: 860px) { .deckwall { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); } }

/* What every log row IS, said in words. Dimming alone made an already-aired
   song look like a fault to anyone who hadn't learned the code. */
.log li .state {
  font: 600 9.5px var(--font-mono, ui-monospace, monospace);
  letter-spacing: .07em; text-transform: uppercase; text-align: right;
  white-space: nowrap; opacity: .9;
}
.log li .state.st-done { color: var(--muted); }
.log li .state.st-live { color: var(--dial); opacity: 1; }
.log li .state.st-cued { color: var(--ok); }
.log li .state.st-plan { color: var(--text-2); opacity: .6; }
.log li .state.st-skip { color: var(--lamp); }
/* An aired row is quiet but never looks broken. */
.log li.played { opacity: .62; }
.log li.skipped, .log li.failed { opacity: .55; }
/* On a phone the row is already colour-coded, and 52px is a title's worth of
   space, so the column folds away. */
@media (max-width: 860px) {
  /* state and year go first — the row still reads without them */
  .log li, .log-head { grid-template-columns: 54px 4px 32px 46px 34px minmax(0, 1fr) 42px 50px 92px; }
  .log li .state, .log-head .state, .log li .yr, .log-head .yr { display: none; }
}

/* The chat: a small room, readable at a glance, quiet enough to sit under a
   now-playing panel without shouting. */
.chatlog { display: grid; gap: 8px; max-height: 320px; overflow-y: auto; padding: 4px 2px; }
.chatmsg { border-left: 2px solid var(--line-2); padding: 4px 0 4px 10px; position: relative; }
.chatmsg.dj { border-left-color: var(--dial); }
.chatmsg.dj strong { color: var(--dial); }
.chatmsg.hid { opacity: .4; text-decoration: line-through; }
.chatmsg .btn.icon { position: absolute; right: 0; top: 2px; opacity: 0; transition: opacity .12s; }
.chatmsg:hover .btn.icon { opacity: 1; }

/* ── The studio line ───────────────────────────────────────────────────────
   A listener should be able to see, without being told, that somebody is at
   the other end. So the room reads like a conversation rather than a form:
   your own words on the right, the station's in its own colour, and a lamp
   when the mic is open. */
.room-panel { border-color: var(--dial-line, var(--line)); }
.chatlog.room { min-height: 220px; max-height: 340px; }
.chatmsg .body { font-size: 13.5px; line-height: 1.45; overflow-wrap: anywhere; }
.chatmsg.mine { border-left-color: var(--ok); }
.chatmsg.mine strong { color: var(--ok); }
.chatmsg.pending { opacity: .6; }
.chatmsg.failed { border-left-color: var(--lamp); }
.chatmsg.failed .small.dim { color: var(--lamp); }
.roomempty { display: grid; gap: 4px; place-items: center; text-align: center; padding: 34px 16px; color: var(--text-2); }
/* The track line that used to appear in the room on every song change is
   gone (1.31): the room is for people. */
.pill .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--lamp);
  display: inline-block; margin-right: 6px; animation: livePulse 1.6s ease-in-out infinite; }
@keyframes livePulse { 50% { opacity: .35; } }

/* ── 1.2: one clock, one microphone ─────────────────────────────────────── */
/* The playhead is moved with a transform, never `left`: transforms are
   composited, so the line rides the audio clock at the display's frame rate
   instead of waiting on layout. */
.vt-playhead { left: 0; will-change: transform; width: 2px; box-shadow: 0 0 6px rgba(255, 255, 255, .35); }
.vt-onair { left: 0; will-change: transform; }
.pill.sm { height: 20px; padding: 0 8px; font-size: 11px; }
.pill.micstat::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; opacity: .9; }
.pill.micstat.ok::before { box-shadow: 0 0 6px rgba(88, 195, 154, .8); }
.pill.micstat.red::before { animation: pulse 1.2s ease-in-out infinite; }
.btn.icon.previewing { color: var(--ok); outline: 1px solid var(--ok); }

/* ── Audition ──────────────────────────────────────────────────────────────
   The play button is a column, not a hover action: a jock's log has always had
   one, and an action you go looking for is an action you stop using. */
.log li .aud { opacity: .5; transition: opacity .12s, color .12s; }
.log li span.aud { display: block; }
.log li:hover .aud, .log li.selected .aud { opacity: 1; }
.log li .aud.auditioning { opacity: 1; color: var(--ok); }
.log li.auditioning { background: color-mix(in srgb, var(--ok) 9%, var(--ink-2)); }
.log li.auditioning .meta .t { color: var(--ok); }
.log li.selected { background: var(--ink-4); box-shadow: inset 3px 0 0 var(--dial); }
.log li.selected.auditioning { background: color-mix(in srgb, var(--ok) 12%, var(--ink-4)); }

/* ── A log you can leave open ──────────────────────────────────────────────
   Rows are reconciled, not rebuilt, so these only ever run on what actually
   changed: something arriving, or something changing state under you. */
@keyframes rowIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@keyframes rowFlash { 0% { background: color-mix(in srgb, var(--dial) 28%, transparent); } 100% { background: transparent; } }
.log li.row-in { animation: rowIn .18s ease-out; }
.log li.row-flash { animation: rowFlash 1.1s ease-out; }
@media (prefers-reduced-motion: reduce) {
  .log li.row-in, .log li.row-flash { animation: none; }
}

/* Back to what's on the air, when the presenter has scrolled away from it. */
.backnow { position: sticky; bottom: 84px; z-index: 21; margin: 8px auto 0; display: flex; box-shadow: var(--shadow); }
.backnow.hidden { display: none; }

/* A cut voice track, ticked off the way a station log does. */
.vtdone { display: inline-flex; vertical-align: -2px; margin-right: 5px; color: var(--ok); }
.vtdone svg { width: 14px; height: 14px; }

/* "Needs a take": the hour narrowed to the breaks still to record. */
.only-untracked .log li:not(.slotvt),
.only-untracked .log li.marker,
.only-untracked .log-head { display: none; }
.only-untracked .log-hour .hh { opacity: .8; }

/* ── Direct manipulation ───────────────────────────────────────────────────
   Drag a row where it goes; the line shows where it will land, and a row that
   cannot take it says so instead of pretending. */
.log li.pending:not([data-locked="1"]) { cursor: grab; }
body.log-dragging { cursor: grabbing; user-select: none; }
body.log-dragging .log li { cursor: grabbing; }
.log li.dragging { opacity: .4; }
.log li.drop-above { box-shadow: inset 0 2px 0 var(--dial); }
.log li.drop-below { box-shadow: inset 0 -2px 0 var(--dial); }
.log li.drop-no { box-shadow: inset 0 0 0 1px var(--lamp); cursor: not-allowed; }

/* The row menu: what you can do to this row, where you right-clicked. */
.rowmenu { position: fixed; z-index: 90; min-width: 232px; padding: 4px; border-radius: var(--r);
  border: 1px solid var(--line-2); background: var(--ink-3); box-shadow: 0 12px 40px rgba(0,0,0,.6); }
.rowmenu-h { padding: 6px 9px 7px; font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); border-bottom: 1px solid var(--line); margin-bottom: 4px; }
.menu-item { display: flex; align-items: center; gap: 9px; width: 100%; padding: 7px 9px; cursor: pointer;
  font-size: 13px; text-align: left; color: var(--text); background: none; border: 0; border-radius: var(--r-sm); }
.menu-item:hover { background: var(--ink-4); }
.menu-item.danger:hover { background: color-mix(in srgb, var(--lamp) 20%, var(--ink-4)); color: var(--lamp); }
.menu-item svg { width: 15px; height: 15px; opacity: .8; }
.menu-item[disabled] { opacity: .4; cursor: default; }

/* The info card: what IS this, and when did we last play it. */
/* The dialog sizes it (modal `wide`); the card just fills what it is given. */
.infocard { width: 100%; }
.modal.wide:has(.infocard) { width: min(760px, 100%); }
.infocard .facts { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 10px 14px; }
.infocard .fact .k, .infocard .k { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.infocard .fact .v { font-size: 14px; margin-top: 1px; }
.infocard .info-wave { width: 100%; height: 90px; display: block; border-radius: var(--r-sm); }

/* Tail carries its own length, and a caret to change it. */
.tailwrap { display: inline-flex; }
.tailwrap .tail { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.tailwrap .tailpick { width: 20px; padding: 0; margin-left: -1px; border: 1px solid var(--line-2);
  border-top-left-radius: 0; border-bottom-left-radius: 0; font-size: 10px; }
.tailwrap .tailpick:hover { background: var(--ink-4); }
.menu-item.on { color: var(--dial); }

/* The key map behind `?`. */
.keymap { display: grid; grid-template-columns: auto 1fr; gap: 8px 14px; align-items: center; }
.keymap kbd { justify-self: start; font-family: var(--font-mono); font-size: 11px; padding: 2px 7px;
  border: 1px solid var(--line-2); border-bottom-width: 2px; border-radius: 4px; color: var(--text-2); background: var(--ink); }
.keymap span { font-size: 13px; color: var(--text-2); }

/* ── The hour strip ────────────────────────────────────────────────────────
   Every hour of the day one click away, and the over/under for the hour you
   are working never scrolled off the top. */
.hstrip { position: sticky; top: 0; z-index: 22; display: flex; align-items: center; gap: 6px;
  margin-bottom: 12px; padding: 7px 8px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--ink-3); }
.hstrip-day { font-size: 10px; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); white-space: nowrap; padding: 0 2px; }
.hstrip-tabs { display: flex; gap: 2px; overflow-x: auto; flex: 1; scrollbar-width: none; }
.hstrip-tabs::-webkit-scrollbar { height: 0; }
.htab { position: relative; flex: none; min-width: 33px; height: 32px; padding: 0 4px; cursor: pointer;
  font-family: var(--font-mono); font-size: 11px; line-height: 1; color: var(--text-2);
  background: var(--ink); border: 1px solid var(--line); border-radius: var(--r-sm); }
.htab:hover { border-color: var(--line-2); color: var(--text); }
/* An hour with nothing in it is dashed — the plan has a hole in it. */
.htab.empty { border-style: dashed; color: var(--muted); opacity: .6; }
.htab.past { opacity: .45; }
.htab.now { border-color: var(--dial); color: var(--dial); }
.htab.on { background: var(--dial); border-color: var(--dial); color: #17181d; font-weight: 700; }
.htab.on.past { opacity: 1; }
.htab .vt { position: absolute; left: 0; right: 0; bottom: 2px; font-size: 8px; line-height: 1; opacity: .7; }
.htab:has(.vt) { padding-bottom: 9px; }
.hstrip-gap { flex: none; font-family: var(--font-mono); font-size: 12px; color: var(--muted);
  padding: 4px 9px; border-radius: var(--r-sm); background: var(--ink); white-space: nowrap; }
.hstrip-gap.over { color: var(--lamp); }
.hstrip-gap.light { color: var(--dial); }

/* ── Structure markers ─────────────────────────────────────────────────────
   Derived from the clock, never stored: what is fixed in the hour and where
   the break is. They are their own row style so they read as dividers rather
   than as things that will play. */
.log li.marker { display: grid; grid-template-columns: 72px minmax(0, 1fr) auto; gap: 10px;
  padding: 5px 12px 5px 10px; background: var(--ink); border-top: 1px solid var(--line);
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.log li.marker .mk-t { font-family: var(--font-mono); letter-spacing: 0; }
.log li.marker .mk-l { color: var(--text-2); font-weight: 600; }
.log li.marker .mk-r { font-family: var(--font-mono); letter-spacing: 0; text-transform: none; }
.log li.marker .mk-r.over { color: var(--lamp); }
.log li.marker .mk-r.light { color: var(--dial); }
.log li.marker.top { background: color-mix(in srgb, var(--text) 6%, var(--ink)); }
.log li.marker.top .mk-l { color: var(--text); }
.dense .log li.marker { padding: 2px 12px; }
@media (max-width: 800px) {
  .log li.marker { grid-template-columns: 52px minmax(0, 1fr); }
  .log li.marker .mk-r { display: none; }
}

/* The bar sits under the log and stays put. Empty but present, so pressing
   play never shifts the page under the pointer. */
.audbar-dock { position: sticky; bottom: 0; z-index: 20; margin-top: 14px; padding-bottom: 2px; background: linear-gradient(to top, var(--ink) 62%, transparent); }
.audbar { display: grid; grid-template-columns: minmax(120px, 290px) minmax(0, 1fr) auto; align-items: center; gap: 16px; padding: 10px 14px; border: 1px solid var(--line); border-radius: var(--r); background: var(--ink-3); opacity: .72; transition: opacity .15s, border-color .15s; }
.audbar.on { opacity: 1; border-color: var(--line-2); }
.audbar.err .aud-what .a { color: var(--lamp); }
.aud-what .t { font-weight: 600; font-size: 15px; }
.aud-what .a { font-size: 12px; color: var(--text-2); }
.aud-mid { display: grid; gap: 7px; }
.aud-clock { font-size: 12px; color: var(--muted); margin-left: 4px; white-space: nowrap; }
.aud-scrub { padding: 3px 0; cursor: pointer; touch-action: none; }
.aud-rail { position: relative; height: 6px; border-radius: 3px; background: var(--ink); }
.aud-fill { position: absolute; inset: 0 auto 0 0; width: 0; border-radius: 3px; background: var(--ok); }
.aud-head { position: absolute; top: -3px; left: 0; width: 2px; height: 12px; border-radius: 1px; background: var(--text); }
.audbar:not(.on) .aud-head, .audbar:not(.on) .aud-fill { display: none; }
.aud-marks { position: absolute; inset: 0; }
.aud-marks .mk { position: absolute; top: -2px; width: 2px; height: 10px; border-radius: 1px; }
.aud-marks .mk.intro { background: var(--dial); }
.aud-marks .mk.out { background: var(--lamp); }
.aud-right { display: flex; align-items: center; gap: 8px; color: var(--muted); }
.aud-vol { width: 84px; accent-color: var(--ok); }
.audbar button[disabled] { opacity: .35; cursor: default; }
@media (max-width: 860px) {
  .audbar { grid-template-columns: minmax(0, 1fr) auto; gap: 10px; }
  .aud-mid { grid-column: 1 / -1; order: 3; }
  .aud-right .aud-vol { display: none; }
}
/* A pinned cart is on the dashboard wall. Lit = on the wall, dim = not. */
.btn.icon.pinned { color: var(--dial); opacity: 1; }
.btn.icon.pinned svg { fill: var(--dial); }
.log li .acts .btn.previewing { opacity: 1; }
.log li:has(.btn.previewing) .acts { opacity: 1; }
.con-live .pill { align-self: center; }
/* The presenter's profile (1.13 N8): a small grid of plain fields. */
.jprofile { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.jprofile textarea { grid-column: 1 / -1; }
@media (max-width: 800px) { .jprofile { grid-template-columns: 1fr; } }
/* Today on KSCH (1.14): one cell an hour, the presenter's colour, the hour on the air lit. */
.jtoday { display: grid; grid-template-columns: repeat(24, minmax(0, 1fr)); gap: 3px; }
.jhour { --sw: var(--muted); display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px 2px; border-radius: 6px; background: var(--ink-3); border-top: 3px solid var(--sw); font-size: 11px; color: var(--text-2); min-width: 0; }
.jhour .hh { font-family: var(--font-mono); }
.jhour .who { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; color: var(--sw); }
.jhour.on { outline: 2px solid var(--dial); }
.jhour.human { border-style: dashed; }
@media (max-width: 1100px) { .jtoday { grid-template-columns: repeat(12, minmax(0, 1fr)); } }
.jock .jlock.on { border-color: var(--lamp); color: var(--lamp); }
.jock.jlocked [data-page] .panel { opacity: .92; }
/* Who is on the air, and the DJs (1.15 N14). */
.dj-card, .dj-tile { --dj: var(--dial); display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: var(--r-sm); background: var(--ink-3); border-left: 4px solid var(--dj); margin-top: 10px; }
.dj-avatar { width: 40px; height: 40px; border-radius: 50%; background: var(--dj); color: #0b0c0f; display: grid; place-items: center; font-family: var(--font-display); font-weight: 700; font-size: 18px; flex: none; }
.dj-name { font-weight: 600; font-size: 16px; }
.dj-name .dj-show { color: var(--dj); font-weight: 500; }
.djs { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 10px; }
.djs .dj-tile { margin-top: 0; align-items: flex-start; }
/* The Booth (1.15 N12). */
.jdjs { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 10px; }
.jdj { border-left: 4px solid var(--sw); }
.jslider input[type=range] { accent-color: var(--sw, var(--dial)); }
.jhrow { display: flex; align-items: center; gap: 10px; padding: 6px 10px; border-radius: 6px; background: var(--ink-3); }
.jhrow.on { outline: 1px solid var(--dial); }
.jhrow.past { opacity: .5; }
.jhrow .who { font-weight: 500; min-width: 130px; }
.jbench { border-left: 4px solid var(--lamp); }
.jphoto { width: 96px; height: 96px; border-radius: 12px; object-fit: cover; background: var(--ink-3); flex: none; }

/* ─── The listener page (1.17): the art washes the hero, the DJs have faces ─── */
.hero.v2 { position: relative; display: block; border-radius: 18px; overflow: hidden; padding: clamp(18px, 3vw, 36px); background: var(--ink-2); border: 1px solid var(--line); isolation: isolate; }
.hero.v2 .hero-bg { position: absolute; inset: -40px; background-image: var(--hero-art, none); background-size: cover; background-position: center; filter: blur(48px) saturate(1.3); opacity: 1; z-index: -2; transform: scale(1.1); }
.hero.v2::before { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(120deg, rgba(18,19,23,.92) 0%, rgba(18,19,23,.78) 45%, rgba(18,19,23,.6) 100%); }
.hero.v2 .hero-grid { display: grid; grid-template-columns: minmax(220px, 360px) minmax(0, 1fr); gap: 36px; align-items: start; }
.hero.v2 .hero-body { min-width: 0; overflow-wrap: anywhere; }
.hero.v2 .dj-card .dj-name, .hero.v2 .dj-card .small { white-space: normal; }
.hero.v2 .art { width: 100%; box-shadow: 0 24px 60px rgba(0,0,0,.6); }
.hero.v2 .listen .btn.lg.on { border-color: var(--dial); color: var(--dial); }
.lyrics-panel { margin-top: 22px; padding: 16px 18px; border-radius: 12px; background: rgba(14,15,19,.72); border: 1px solid var(--line); backdrop-filter: blur(8px); }
.lyrics-panel .range.lag { width: 160px; accent-color: var(--dial); }
.lyrics-body { max-height: 46vh; overflow: auto; padding: 14px 4px; scroll-behavior: smooth; mask-image: linear-gradient(transparent, #000 12%, #000 88%, transparent); }
.lyrics-body p { margin: 0; padding: 6px 0; font-family: var(--font-display); font-weight: 600; font-size: clamp(20px, 2.6vw, 32px); line-height: 1.15; color: var(--muted); transition: color .25s; }
.lyrics-body p.cur { color: var(--text); }
.lyrics-body p.past { color: var(--text-2); opacity: .7; }
.lyrics-body.plain p { font-size: 18px; font-weight: 500; color: var(--text-2); }
.lyrics-body p.none { color: var(--muted); font-size: 16px; font-family: var(--font-body); font-weight: 400; }
.djs { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; }
.dj-tile.v2 { --dj: var(--dial); display: grid; grid-template-columns: 120px 1fr; gap: 16px; padding: 0; overflow: hidden; border-radius: 14px; background: var(--ink-2); border: 1px solid var(--line); border-left: 4px solid var(--dj); margin-top: 0; }
.dj-tile.v2 .dj-photo { width: 120px; align-self: stretch; overflow: hidden; background: var(--ink-3); }
.dj-tile.v2 .dj-photo img { width: 120px; height: 100%; object-fit: cover; object-position: center top; display: block; min-height: 140px; }
.dj-tile.v2 .dj-text { padding: 14px 16px 14px 0; display: grid; gap: 4px; align-content: start; min-width: 0; }
.dj-tile.v2 .dj-name { font-family: var(--font-display); font-weight: 700; font-size: 26px; line-height: 1; margin: 0; }
.dj-tile.v2 .dj-tag { color: var(--dj); font-weight: 500; }
.dj-tile.v2 .dj-says { display: flex; flex-wrap: wrap; gap: 6px; }
.dj-tile.v2 .dj-says span { font-size: 12px; color: var(--text-2); background: var(--ink-3); border-radius: 999px; padding: 2px 10px; }
.dj-tile.v2 .dj-about { margin: 6px 0 0; color: var(--text-2); line-height: 1.5; font-size: 14px; }
.dj-tile.v2 .btn.sm.ghost { justify-self: start; }
@media (max-width: 800px) {
  .hero.v2 .hero-grid { grid-template-columns: minmax(0, 1fr); }
  .hero.v2 .hero-body { text-align: left; }
  .hero.v2 .art { max-width: 280px; }
  .dj-tile.v2 { grid-template-columns: 96px 1fr; }
  .dj-tile.v2 .dj-photo, .dj-tile.v2 .dj-photo img { width: 96px; }
  .lyrics-panel .row.between.wrap { flex-direction: column; align-items: flex-start; }
}
@media (prefers-reduced-motion: reduce) { .hero.v2 .hero-bg { transition: none; } }
/* A list row never forces the page wider than the phone (1.17.3). */
.list li { min-width: 0; }
.list li .meta { min-width: 0; }
/* The gallery on a DJ card (1.18). */
.dj-tile.v2 .dj-photo { position: relative; }
.dj-tile.v2 .dj-photo > img { transition: opacity .2s; }
.dj-thumbs { position: absolute; left: 6px; right: 6px; bottom: 6px; display: flex; gap: 4px; justify-content: center; }
.dj-thumbs button { width: 22px; height: 22px; padding: 0; border: 2px solid rgba(255,255,255,.55); border-radius: 50%; overflow: hidden; background: var(--ink-3); cursor: pointer; opacity: .85; }
.dj-thumbs button img { width: 100%; height: 100%; object-fit: cover; display: block; }
.dj-thumbs button.on { border-color: var(--dj); opacity: 1; transform: scale(1.12); }
.jgallery { display: flex; flex-wrap: wrap; gap: 8px; }
.jshot { width: 110px; display: grid; gap: 4px; }
.jshot img { width: 110px; height: 110px; object-fit: cover; border-radius: 8px; border: 2px solid transparent; }
.jshot.main img { border-color: var(--dial); }
.dj-avatar.photo { overflow: hidden; }
.dj-avatar.photo img { width: 100%; height: 100%; object-fit: cover; object-position: center top; display: block; }

/* ── The DJs, uniform (1.21) ────────────────────────────────────────────────
   Four presenters came out three-across with one orphan underneath, and the
   bio hid behind a "Read more". These cards pair evenly at every width, stand
   the same height in a row, and carry the whole description in the open. */
/* Two columns, always, above the phone: auto-fit gave three on a wide screen
   and four presenters came out three-and-one again, with the fourth alone and
   a little out of line (1.23). Two by two is the shape that always pairs. */
.djs { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; align-items: stretch; }
@media (max-width: 780px) { .djs { grid-template-columns: minmax(0, 1fr); } }
.dj-tile.v3 { --dj: var(--dial); display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: 0;
  padding: 0; overflow: hidden; border-radius: 16px; background: var(--ink-2);
  border: 1px solid var(--line); border-left: 4px solid var(--dj); margin-top: 0;
  transition: border-color .25s ease, transform .25s ease; }
.dj-tile.v3:hover { border-color: var(--dj); transform: translateY(-2px); }
.dj-tile.v3 .dj-photo { position: relative; width: 150px; align-self: stretch; overflow: hidden; background: var(--ink-3); }
.dj-tile.v3 .dj-photo > img { width: 150px; height: 100%; object-fit: cover; object-position: center top;
  display: block; min-height: 100%; transition: opacity .2s; }
/* The card is a column of three: heading, bio that takes the slack, quotes at
   the foot — so every card in a row lines its quotes up on the same baseline. */
.dj-tile.v3 .dj-text { padding: 16px 18px; display: grid; grid-template-rows: auto 1fr auto; gap: 10px; min-width: 0; }
.dj-tile.v3 .dj-head { display: grid; gap: 3px; min-width: 0; }
.dj-tile.v3 .dj-name { font-family: var(--font-display); font-weight: 700; font-size: 24px; line-height: 1.05; margin: 0; }
.dj-tile.v3 .dj-tag { color: var(--dj); font-weight: 500; font-size: 14px; }
.dj-tile.v3 .dj-hours { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); margin-top: 2px; }
.dj-tile.v3 .dj-hours svg { width: 13px; height: 13px; flex: none; opacity: .8; }
.dj-tile.v3 .dj-body { min-width: 0; }
.dj-tile.v3 .dj-about { margin: 0; color: var(--text-2); line-height: 1.55; font-size: 14px; }
.dj-tile.v3 .dj-says { display: flex; flex-wrap: wrap; gap: 6px; }
.dj-tile.v3 .dj-says span { font-size: 12px; color: var(--text-2); background: var(--ink-3); border-radius: 999px; padding: 3px 10px; }
@media (max-width: 640px) {
  .dj-tile.v3 { grid-template-columns: minmax(0, 1fr); }
  .dj-tile.v3 .dj-photo { width: 100%; height: 190px; }
  .dj-tile.v3 .dj-photo > img { width: 100%; height: 190px; min-height: 0; object-position: center 22%; }
}
@media (prefers-reduced-motion: reduce) { .dj-tile.v3, .dj-tile.v3 .dj-photo > img { transition: none; } }

/* A break shows the announcer, not a blank tile (1.22). The portrait is a
   person, so it is framed from the top rather than centred like a record. */
.art.person img { object-position: center 18%; }
.art.person { box-shadow: inset 0 0 0 2px var(--dial); }

/* Day navigation in the log strip (1.22): Now, tomorrow, two days out, and a
   date box, so a log built three days ahead is one press away at any point. */
.hstrip-days { flex: none; align-items: center; }
.hstrip-days .input.sm { padding: 3px 6px; font-size: 12px; }
@media (max-width: 900px) { .hstrip-days { flex-wrap: wrap; } }

/* A message the line has not taken yet (1.28). It waits rather than failing:
   a listener is never shown a fault, only that the DJ is busy. */
.chatmsg.waiting { opacity: .72; }
.chatmsg.waiting .small.dim { font-style: italic; }

/* ── Back at the desk (1.30) ────────────────────────────────────────────────
   Five lights and a word, for somebody deciding whether they can shut their
   computer down. The colour carries the meaning, and the word carries it too
   so it does not rest on colour alone. */
.desksum { display: grid; gap: 6px; }
.deskbig { display: flex; align-items: center; gap: 10px; font-family: var(--font-display); font-size: 26px; font-weight: 700; }
.deskdot { width: 12px; height: 12px; border-radius: 50%; background: var(--muted); flex: none; box-shadow: 0 0 0 3px rgba(255,255,255,.05); }
.deskbig .deskdot { width: 16px; height: 16px; }
.deskbig.ok { color: #7ec8a9; } .deskbig.ok .deskdot { background: #7ec8a9; }
.deskbig.amber { color: #e8b761; } .deskbig.amber .deskdot { background: #e8b761; }
.deskbig.red { color: #e2694a; } .deskbig.red .deskdot { background: #e2694a; }
.deskrow { display: flex; align-items: flex-start; gap: 12px; padding: 10px 0; border-top: 1px solid var(--line); }
.deskrow:first-child { border-top: 0; }
.deskrow .deskdot { margin-top: 5px; }
.deskrow.ok .deskdot { background: #7ec8a9; }
.deskrow.amber .deskdot { background: #e8b761; }
.deskrow.red .deskdot { background: #e2694a; }
.deskrow .desc { margin-top: 2px; }

/* ── A listener's request, on both lines (1.31) ─────────────────────────────
   The break that introduces it and the record itself share one colour, so the
   pair can be followed down the log by eye. Teal: it belongs to no status. */
.log li.req { position: relative; background: color-mix(in srgb, #7ec8a9 9%, transparent); }
.log li.req::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: #7ec8a9; }
.log li.req.reqintro::before { background: repeating-linear-gradient(180deg, #7ec8a9 0 6px, transparent 6px 10px); }
.log li.req:hover { background: color-mix(in srgb, #7ec8a9 15%, transparent); }
.reqchip { display: inline-block; font-size: 11px; line-height: 1.5; padding: 0 6px; margin-right: 6px; border-radius: 999px;
  color: #7ec8a9; border: 1px solid color-mix(in srgb, #7ec8a9 45%, transparent);
  background: color-mix(in srgb, #7ec8a9 12%, transparent); white-space: nowrap; vertical-align: 1px; }
/* The listener page marks the request the same way. */
.art.request { box-shadow: inset 0 0 0 2px #7ec8a9; }

/* ── Up next, deeper than one hour (1.46 N20) ─────────────────────────────── */
.log li.upmore { display: flex; justify-content: center; padding: 10px 12px; border-top: 1px solid var(--line); }

/* ── What the virtual DJs are up to (1.46 N23) ────────────────────────────── */
/* Four answers on one line at desk width, stacked on a laptop. Nick reads this
   before he decides whether to switch his workstation off, so the verdict is
   the first thing in it and the only thing with a colour. */
.jact { display: grid; gap: 14px; }
@media (min-width: 1100px) { .jact { grid-template-columns: minmax(260px, 1fr) minmax(240px, 1fr) minmax(260px, 1.1fr); align-items: start; } }
.jact .k { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--text-2); margin-bottom: 6px; }
.jv { display: flex; gap: 10px; align-items: flex-start; padding: 10px 12px; border-radius: var(--r); border: 1px solid var(--line); }
.jv svg { flex: none; margin-top: 2px; }
.jv .t { font-weight: 600; }
.jv .d { color: var(--text-2); font-size: 12px; margin-top: 2px; }
.jv.ok { background: color-mix(in srgb, var(--ok, #3fb950) 12%, transparent); border-color: color-mix(in srgb, var(--ok, #3fb950) 40%, var(--line)); }
.jv.busy { background: var(--dial-dim); border-color: var(--dial-line); color: var(--dial); }
.jv.busy .d { color: var(--text-2); }
.jrow { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; margin-bottom: 4px; }
.jrow .who { font-weight: 600; }
.jrow .d { color: var(--text-2); font-size: 12px; }
.jdone { list-style: none; margin: 0; padding: 0; display: grid; gap: 3px; }
.jdone li { display: grid; grid-template-columns: 62px 84px minmax(0, 1fr); gap: 8px; align-items: baseline; font-size: 12px; }
.jdone li.empty { display: block; color: var(--text-2); }
.jdone .t { font-family: var(--font-mono); color: var(--text-2); }
.jdone .who { font-weight: 600; }
.jdone .d { color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── The Virtual DJs panel, shut (1.59 N33) ──────────────────────────────── */
/* Shut is the default, and shut still answers the question the panel exists to
   answer: the verdict and the coverage sit on the header line itself, so a
   glance costs no press. The header wraps at narrow widths rather than
   squeezing the summary to nothing. */
.djpanel .jhead { flex-wrap: wrap; row-gap: 6px; }
.djpanel .jhead h3 { flex: none; }
.jsum { display: flex; align-items: center; gap: 10px; flex: 1 1 260px; min-width: 0; font-size: 12px; }
.djpanel.open .jsum { display: none; }
.jsv { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; white-space: nowrap; }
.jsv svg { width: 14px; height: 14px; flex: none; }
.jsv.ok { color: var(--ok, #3fb950); }
.jsv.busy { color: var(--dial); }
.jsc { color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jtoggle { padding: 4px 6px; }
.jchev { display: inline-flex; transform-origin: 50% 50%; }
/* The shut state is driven by the `hidden` ATTRIBUTE, not by the `.open` class:
   the class flips at the START of a close, and a class-driven `display: none`
   would swallow the tween that is meant to play. JS sets `hidden` when the
   close finishes. `.jact` is a grid, which outranks the browser's own
   `[hidden]` rule, so this has to be said explicitly. */
.djpanel .panel-b[hidden] { display: none !important; }
/* GSAP animates the body's height, so it has to be able to clip while it runs. */
.djpanel .panel-b { overflow: hidden; }

/* ── Reading off the end of the log (1.46 N21) ────────────────────────────── */
/* The sentinel is thin and quiet: it is a place for the observer to notice,
   and the button inside it is the fallback for a browser without one. */
.logedge { display: flex; justify-content: center; padding: 8px 0 14px; }
.logedge.hidden { display: none; }

/* ──────────────────────────────────────────────────────────────
   The cozy screen (1.58) — /cozy
   The library on a television, left running all day.

   Read the burn-in rules before changing anything here, because most of
   this file is a safety measure wearing a nice coat:

   * Nothing holds still. `.cz-stage` orbits, `.cz-art-in` drifts, the
     colour field is redrawn every frame and the arrangement is re-picked
     on every track (`[data-layout]`).
   * That motion is CSS keyframes on purpose, NOT GSAP. GSAP is vendored
     and may be missing; the screen must still protect the panel without
     it. GSAP does the entrances, the lyric river and the mood changes,
     and it gets its own elements so its inline transforms never lose a
     cascade fight with an animation.
   * Nothing is pure white and nothing bright is nailed to a corner. The
     controls do not exist until she touches something.
   * `prefers-reduced-motion` is honoured everywhere else in this file and
     deliberately overridden at the bottom of this block. The global rule
     at the top kills every animation; here the slow drift IS the feature,
     so it is put back — slowly, and with the fast motion still off.
   ────────────────────────────────────────────────────────────── */
body.cz-on { overflow: hidden; }
.cz {
  position: fixed; inset: 0; z-index: 60; overflow: hidden;
  background: #06060a; cursor: none;
  --cz-accent: #ffd39a;
  --cz-ink: rgba(255, 255, 255, .90);   /* never #fff */
}
.cz.awake { cursor: default; }

/* ─── the field ─── */
/* The canvas is a fifth of the screen and is blown up by the compositor;
   that upscale IS the blur, which is why there is no filter here. A
   full-screen CSS blur repainted thirty times a second is what a cheap
   television box cannot do. */
.cz-field { position: absolute; inset: -4%; width: 108%; height: 108%; display: block; transition: opacity 3s ease; }
.cz-grain { position: absolute; inset: -60px; pointer-events: none; opacity: .05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: cz-grain 9s steps(6) infinite; }
@keyframes cz-grain { 0% { transform: translate(0, 0); } 20% { transform: translate(-22px, 14px); } 40% { transform: translate(18px, -20px); } 60% { transform: translate(-14px, -16px); } 80% { transform: translate(20px, 18px); } 100% { transform: translate(0, 0); } }
/* Every twenty minutes a wash crosses the panel — the browser's answer to a
   television's own pixel-refresh sweep, and it happens to look like weather. */
.cz-sweep { position: absolute; top: -60%; left: -70%; width: 46%; height: 220%; pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .055), transparent);
  animation: cz-sweep 1200s linear infinite; }
@keyframes cz-sweep { 0%, 88% { transform: translateX(0) rotate(13deg); } 100% { transform: translateX(430%) rotate(13deg); } }
.cz-night { position: absolute; inset: 0; background: #000; opacity: 0; pointer-events: none; transition: opacity 4s ease; }
.cz[data-dim="night"] .cz-night { opacity: .46; }

/* ─── the orbit: the whole composition walks, slowly, for ever ─── */
.cz-stage { position: absolute; inset: 0; display: grid; padding: 7vmin 7vw; gap: 2.5vmin 5vw;
  animation: cz-orbit 431s ease-in-out infinite; will-change: transform; }
@keyframes cz-orbit {
  0%   { transform: translate3d(-2.2vw, -1.7vh, 0); }
  17%  { transform: translate3d( 1.9vw, -2.5vh, 0); }
  33%  { transform: translate3d( 2.5vw,  1.6vh, 0); }
  51%  { transform: translate3d(-0.7vw,  2.6vh, 0); }
  68%  { transform: translate3d(-2.6vw,  0.5vh, 0); }
  84%  { transform: translate3d( 1.0vw, -2.6vh, 0); }
  100% { transform: translate3d(-2.2vw, -1.7vh, 0); }
}
@keyframes cz-orbit-wide {
  0%   { transform: translate3d(-6vw, -5vh, 0); }
  23%  { transform: translate3d( 5vw, -6vh, 0); }
  46%  { transform: translate3d( 6vw,  5vh, 0); }
  71%  { transform: translate3d(-5vw,  6vh, 0); }
  100% { transform: translate3d(-6vw, -5vh, 0); }
}

/* ─── the record ─── */
.cz-art { grid-area: art; position: relative; width: 100%; max-width: 46vmin; aspect-ratio: 1;
  animation: cz-float 167s ease-in-out infinite; will-change: transform; }
@keyframes cz-float {
  0%   { transform: translate3d(0, 0, 0) rotate(-.7deg); }
  25%  { transform: translate3d(1.6vmin, -2.2vmin, 0) rotate(.5deg); }
  50%  { transform: translate3d(-1.1vmin, 1.8vmin, 0) rotate(.9deg); }
  75%  { transform: translate3d(-2.0vmin, -1.2vmin, 0) rotate(-.4deg); }
  100% { transform: translate3d(0, 0, 0) rotate(-.7deg); }
}
.cz-art-in { position: absolute; inset: 0; }
.cz-art-img { position: absolute; inset: 0; border-radius: 1.6vmin; overflow: hidden; background: #14141a;
  box-shadow: 0 3vmin 9vmin rgba(0, 0, 0, .6), 0 0 0 1px rgba(255, 255, 255, .07); }
.cz-art-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cz-art-img .cz-noart { position: absolute; inset: 26%; width: 48%; height: 48%; color: rgba(255, 255, 255, .22); }
/* A record peeking out from behind the sleeve, turning only while it plays. */
.cz-disc { position: absolute; top: 7%; right: -24%; width: 86%; aspect-ratio: 1; border-radius: 50%;
  background:
    repeating-radial-gradient(circle at 50% 50%, rgba(255, 255, 255, .05) 0 1.5px, rgba(0, 0, 0, .55) 1.5px 4px),
    radial-gradient(circle at 50% 50%, #1a1a22 17%, #0a0a0e 18%, #1d1d25 62%, #0e0e13 100%);
  box-shadow: 0 2vmin 6vmin rgba(0, 0, 0, .6); opacity: .85;
  animation: cz-spin 9s linear infinite; animation-play-state: paused; }
.cz.playing .cz-disc { animation-play-state: running; }
@keyframes cz-spin { to { transform: rotate(360deg); } }
/* Elapsed time traces the sleeve instead of lying across the bottom of the
   screen, because a bar across the bottom is a burn-in line. */
.cz-ring { position: absolute; inset: -2.4vmin; pointer-events: none; }
.cz-ring svg { width: 100%; height: 100%; overflow: visible; }
.cz-ring rect { fill: none; stroke-width: 2; vector-effect: non-scaling-stroke; }
.cz-ring .trk { stroke: rgba(255, 255, 255, .09); }
.cz-ring .arc { stroke: var(--cz-accent); stroke-linecap: round; transition: stroke .8s ease;
  filter: drop-shadow(0 0 5px rgba(255, 220, 180, .35)); }

/* ─── the words ─── */
.cz-words { grid-area: words; width: 100%; max-width: min(54vmin, 46rem); min-width: 0; }
.cz-title { font-family: var(--font-display); font-weight: 700; line-height: .94; letter-spacing: -.012em;
  font-size: clamp(30px, 6.4vmin, 122px); color: var(--cz-ink); overflow-wrap: break-word;
  text-shadow: 0 .4vmin 6vmin rgba(0, 0, 0, .55); }
.cz-artist { font-size: clamp(17px, 3vmin, 48px); color: rgba(255, 255, 255, .82); margin-top: 1.4vmin; font-weight: 500; }
.cz-album { font-size: clamp(13px, 1.9vmin, 28px); color: rgba(255, 255, 255, .52); margin-top: .9vmin; }
.cz-clock { font-size: clamp(12px, 1.5vmin, 22px); color: rgba(255, 255, 255, .40); margin-top: 2.4vmin; letter-spacing: .07em; white-space: nowrap; }

/* ─── arrangements: re-picked on every track, so nothing owns a region ─── */
.cz[data-layout="0"] .cz-stage { grid-template-columns: minmax(0, 46vmin) minmax(0, 1fr); grid-template-areas: "art words"; align-items: center; }
.cz[data-layout="1"] .cz-stage { grid-template-columns: minmax(0, 1fr) minmax(0, 46vmin); grid-template-areas: "words art"; align-items: center; justify-items: end; }
.cz[data-layout="1"] .cz-words { text-align: right; }
.cz[data-layout="2"] .cz-stage { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; grid-template-areas: "art" "words"; justify-items: center; align-items: center; }
.cz[data-layout="2"] .cz-art { max-width: min(40vmin, 52vh); }
.cz[data-layout="2"] .cz-words { text-align: center; max-width: min(62vmin, 52rem); }
.cz[data-layout="3"] .cz-stage { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); grid-template-areas: "art" "words"; justify-items: start; }
.cz[data-layout="3"] .cz-art { max-width: min(28vmin, 34vh); align-self: start; }
.cz[data-layout="3"] .cz-words { align-self: end; max-width: min(62vmin, 52rem); }
.cz[data-layout="4"] .cz-stage { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); grid-template-areas: "art"; place-items: center; padding-bottom: 24vh; }
.cz[data-layout="4"] .cz-art { max-width: min(48vmin, 56vh); }
.cz[data-layout="4"] .cz-words { position: absolute; left: 8vw; right: 8vw; bottom: 7vh; width: auto; max-width: none; text-align: center; }
.cz[data-layout="4"] .cz-title { font-size: clamp(26px, 4.6vmin, 84px); }

/* ─── moods. These come after the arrangements on purpose: same specificity,
       later wins, and the mood is the stronger statement. ─── */
.cz-lyr { display: none; }
.cz[data-mood="lyrics"] .cz-lyr { display: block; }
.cz[data-mood="lyrics"] .cz-stage { grid-template-columns: minmax(0, 34vmin) minmax(0, 1fr); grid-template-rows: min-content min-content;
  grid-template-areas: "art lyr" "words lyr"; align-content: center; justify-items: start; align-items: start; }
.cz[data-mood="lyrics"][data-layout="1"] .cz-stage,
.cz[data-mood="lyrics"][data-layout="3"] .cz-stage { grid-template-columns: minmax(0, 1fr) minmax(0, 34vmin); grid-template-areas: "lyr art" "lyr words"; justify-items: end; }
.cz[data-mood="lyrics"] .cz-art { max-width: 34vmin; }
.cz[data-mood="lyrics"] .cz-words { width: 100%; max-width: 34vmin; margin-top: 2.5vmin; }
.cz[data-mood="lyrics"] .cz-title { font-size: clamp(20px, 3.1vmin, 44px); }
.cz[data-mood="lyrics"] .cz-artist { font-size: clamp(14px, 1.9vmin, 26px); }
.cz[data-mood="lyrics"] .cz-album, .cz[data-mood="lyrics"] .cz-clock { font-size: clamp(11px, 1.4vmin, 18px); }

.cz[data-mood="ambient"] .cz-art, .cz[data-mood="ambient"] .cz-lyr { display: none; }
.cz[data-mood="ambient"] .cz-stage { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); grid-template-areas: "words"; place-items: center;
  animation-name: cz-orbit-wide; animation-duration: 301s; }
.cz[data-mood="ambient"] .cz-words { text-align: center; max-width: 30ch; opacity: .74; }
.cz[data-mood="ambient"] .cz-title { font-size: clamp(20px, 3.2vmin, 50px); }
.cz[data-mood="ambient"] .cz-artist { font-size: clamp(14px, 1.8vmin, 26px); }
.cz[data-mood="ambient"] .cz-album { display: none; }

/* ─── the lyric river ─── */
.cz-lyr { grid-area: lyr; position: relative; width: 100%; display: grid; grid-template-rows: auto minmax(0, 1fr); align-content: center; }
/* The mask lives on the river rather than on .cz-lyr, so the note above it is
   not faded out along with the first line of the song. */
.cz-lyr-river { position: relative; width: 100%; height: min(70vh, 860px); overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 17%, #000 83%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 17%, #000 83%, transparent); }
.cz-lyr-note { font-family: var(--font-display); font-size: clamp(11px, 1.15vmin, 17px); letter-spacing: .14em;
  text-transform: uppercase; color: rgba(255, 255, 255, .34); margin-bottom: 1.4vmin; max-width: 34ch; }
.cz-lyr-note.hidden { display: none; }
.cz-lyr-body { position: absolute; left: 0; right: 0; top: 0; will-change: transform; }
.cz-lyr-body p { margin: 0; padding: .3em 0; font-family: var(--font-display); font-weight: 600; line-height: 1.26;
  font-size: clamp(19px, 3.5vmin, 54px); color: rgba(255, 255, 255, .26); filter: blur(.7px); max-width: 30ch;
  transition: color .55s ease, filter .55s ease, text-shadow .55s ease; overflow-wrap: break-word; }
.cz-lyr-body p.past { color: rgba(255, 255, 255, .14); }
.cz-lyr-body p.near { color: rgba(255, 255, 255, .40); filter: blur(.3px); }
.cz-lyr-body p.cur { color: var(--cz-ink); filter: none; text-shadow: 0 0 4vmin rgba(255, 255, 255, .20); }
/* Unsynced words have no clock to follow, so they drift on their own. */
.cz-lyr-body.plain { animation: cz-drift 300s linear infinite; }
.cz-lyr-body.plain p { color: rgba(255, 255, 255, .55); filter: none; }
@keyframes cz-drift { 0% { transform: translateY(28vh); } 100% { transform: translateY(-100%); } }
.cz-none { color: rgba(255, 255, 255, .42); font-size: clamp(15px, 2vmin, 26px); padding-top: 30vh; }

/* ─── resting: paused and left alone ─── */
.cz.resting .cz-stage { opacity: .30; transition: opacity 4s ease; }
.cz.resting .cz-field { opacity: .55; }

/* ─── controls: absent until she touches something ─── */
.cz-ui { position: absolute; left: 0; right: 0; bottom: 0; z-index: 5; display: flex; justify-content: center;
  padding: 0 3vw calc(3vh + var(--safe-b)); opacity: 0; transform: translateY(16px); pointer-events: none;
  transition: opacity .45s ease, transform .45s ease; }
.cz.awake .cz-ui { opacity: 1; transform: none; pointer-events: auto; }
.cz-bar { display: flex; align-items: center; gap: clamp(8px, 1.6vw, 30px); flex-wrap: wrap; justify-content: center;
  padding: 10px clamp(12px, 1.6vw, 26px); border-radius: 28px; background: rgba(9, 9, 13, .58);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); border: 1px solid rgba(255, 255, 255, .09); }
.cz-grp { display: flex; align-items: center; gap: clamp(2px, .5vw, 10px); }
.cz-b { display: inline-flex; flex-direction: column; align-items: center; gap: 3px; padding: 8px 10px;
  background: transparent; border: 0; border-radius: 14px; color: rgba(255, 255, 255, .74); cursor: pointer; }
.cz-b svg { width: clamp(20px, 1.6vw, 30px); height: clamp(20px, 1.6vw, 30px); }
.cz-b.big svg { width: clamp(28px, 2.4vw, 42px); height: clamp(28px, 2.4vw, 42px); }
.cz-b-l { font-family: var(--font-display); font-size: clamp(9px, .62vw, 13px); letter-spacing: .12em; text-transform: uppercase; opacity: .55; white-space: nowrap; }
.cz-b:hover, .cz-b:focus-visible { color: #fff; background: rgba(255, 255, 255, .09); }
.cz-b.on { color: var(--cz-accent); }
.cz-b.on .cz-b-l { opacity: .8; }
.cz-vi { width: 18px; height: 18px; color: rgba(255, 255, 255, .5); }
.cz-vol { width: clamp(70px, 8vw, 150px); accent-color: var(--cz-accent); background: transparent; }

/* ─── the key card, shown once on the way in ─── */
.cz-card { position: absolute; right: 3vw; bottom: 15vh; z-index: 6; padding: 16px 20px; border-radius: 18px;
  background: rgba(8, 8, 12, .55); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(255, 255, 255, .08); color: rgba(255, 255, 255, .70); font-size: clamp(12px, .9vw, 16px); }
.cz-card-t { font-family: var(--font-display); font-size: 11px; letter-spacing: .2em; text-transform: uppercase; opacity: .55; margin-bottom: 9px; }
.cz-card ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }
.cz-card li { display: flex; gap: 12px; }
.cz-card b { min-width: 56px; color: var(--cz-accent); font-family: var(--font-mono); font-weight: 500; }

/* ─── cold start: she opened /cozy and nothing is playing ─── */
body.cz-on .toast { bottom: calc(13vh + var(--safe-b)); z-index: 71; }
.cz-start { position: absolute; inset: 0; z-index: 7; display: grid; place-content: center; gap: 3.5vh; padding: 6vw; }
.cz-start.hidden { display: none; }
.cz-s-h { font-family: var(--font-display); font-weight: 700; text-align: center; color: var(--cz-ink); font-size: clamp(26px, 5.2vmin, 66px); }
.cz-s-row { display: grid; gap: 14px; min-width: min(560px, 82vw); }
.cz-s { display: flex; align-items: center; gap: 16px; padding: 16px 24px; border-radius: 18px; text-align: left;
  border: 1px solid rgba(255, 255, 255, .14); background: rgba(255, 255, 255, .06); color: var(--cz-ink);
  font-size: clamp(15px, 2vmin, 24px); cursor: pointer; }
.cz-s:hover, .cz-s:focus-visible { background: rgba(255, 255, 255, .13); }
.cz-s svg { width: 24px; height: 24px; flex: none; opacity: .75; }

@media (max-width: 820px) {
  .cz-stage { padding: 6vmin 7vw; }
  .cz[data-layout] .cz-stage { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto; grid-template-areas: "art" "words"; justify-items: center; align-content: center; }
  .cz[data-layout] .cz-art { max-width: min(52vw, 40vh); }
  .cz[data-layout] .cz-words { text-align: center; max-width: 90vw; position: static; }
  .cz[data-mood="lyrics"] .cz-stage { grid-template-areas: "art" "lyr"; grid-template-rows: auto minmax(0, 1fr); }
  .cz[data-mood="lyrics"] .cz-words { display: none; }
  .cz[data-mood="lyrics"] .cz-lyr { height: 46vh; }
  .cz-card { display: none; }
  .cz-b-l { display: none; }
}

/* ─── prefers-reduced-motion, deliberately overridden ───
   app.css opens by killing every animation under this preference. That is
   right for the rest of the station and wrong here: on this screen the slow
   drift is what stops a panel being damaged, and it is slow, low-contrast
   and peripheral — not the motion the preference exists to suppress. The
   fast, expressive motion stays off: GSAP is skipped entirely (see `calm`
   in cozy.js) and the transitions above stay killed by the global rule. */
@media (prefers-reduced-motion: reduce) {
  .cz .cz-stage { animation: cz-orbit 431s ease-in-out infinite !important; }
  .cz[data-mood="ambient"] .cz-stage { animation: cz-orbit-wide 301s ease-in-out infinite !important; }
  .cz .cz-art { animation: cz-float 167s ease-in-out infinite !important; }
  .cz .cz-grain { animation: cz-grain 9s steps(6) infinite !important; }
  .cz .cz-sweep { animation: cz-sweep 1200s linear infinite !important; }
  .cz.playing .cz-disc { animation: cz-spin 9s linear infinite !important; }
  .cz .cz-lyr-body.plain { animation: cz-drift 300s linear infinite !important; }
}
