/* 25-listen.css — LISTEN LIVE, the board's most prominent control.

   Monitors the station's pre-downmix STEREO bus. Deliberately the loudest thing
   in the transmitter strip: it is the only way to hear the station without
   joining the Space, and DIAGNOSTICS' unsolved "silent-but-live" failure can
   only be caught by a human listening.

   Amber in BOTH states, never red. Red is the ON AIR lamp exclusively, and this
   button reports nothing about whether the station is on air — a red "listening"
   state would read as an air state and undo the one colour rule the board has. */

.listen-btn{
  display:inline-flex; align-items:center; gap:8px; flex:none;
  font-family:var(--font-mono); font-size:12.5px; font-weight:600;
  letter-spacing:.08em; line-height:1;
  color:var(--ink-on-accent); background:var(--accent);
  border:1px solid var(--accent); border-radius:4px;
  padding:9px 16px; cursor:pointer; white-space:nowrap;
  box-shadow:0 0 0 1px rgba(0,0,0,.35), 0 2px 10px var(--accent-glow);
  transition:filter var(--t-fast) ease, box-shadow var(--t-fast) ease, transform .06s ease;
}
.listen-btn:hover{ filter:brightness(1.1); box-shadow:0 0 0 1px rgba(0,0,0,.35), 0 2px 16px var(--accent-glow); }
.listen-btn:active{ transform:translateY(1px); }
.listen-btn[disabled]{ opacity:.4; cursor:default; filter:none; }

.listen-ico{ width:16px; height:16px; flex:none; }

/* ---- playing ---- */
/* Inset + dimmed amber so "on" is unmistakable without borrowing the lamp's red,
   with a live equaliser standing in for the meaning red would have carried. */
.listen-btn[aria-pressed="true"]{
  color:var(--accent); background:var(--accent-well); border-color:var(--accent);
  box-shadow:inset 0 1px 6px rgba(0,0,0,.55), 0 0 12px var(--accent-glow);
}
.listen-btn[aria-pressed="true"] .listen-ico{ display:none; }
.listen-btn[aria-pressed="true"] .listen-eq{ display:inline-flex; }

/* ---- equaliser (visible only while playing) ---- */
.listen-eq{ display:none; align-items:flex-end; gap:2px; height:14px; width:16px; flex:none; }
.listen-eq i{
  display:block; width:3px; height:30%; background:currentColor; border-radius:1px;
  animation:listen-eq 900ms ease-in-out infinite;
}
.listen-eq i:nth-child(2){ animation-delay:-600ms; }
.listen-eq i:nth-child(3){ animation-delay:-300ms; }
.listen-eq i:nth-child(4){ animation-delay:-150ms; }
@keyframes listen-eq{ 0%,100%{ height:25%; } 50%{ height:100%; } }

/* ---- connecting ---- */
.listen-btn.connecting{ filter:saturate(.6); }
.listen-btn.connecting .listen-ico{ animation:listen-pulse 900ms ease-in-out infinite; }
@keyframes listen-pulse{ 50%{ opacity:.3; } }

/* ---- pop-out to a raw stream URL (VLC, another tab) ---- */
.listen-pop{
  font-family:var(--font-mono); font-size:13px; line-height:1;
  color:var(--accent); border:1px solid var(--accent-dim); border-radius:4px;
  padding:8px 8px; flex:none; text-decoration:none;
}
.listen-pop:hover{ background:var(--accent-ghost); text-decoration:none; }

#listen-audio{ display:none; }

@media (prefers-reduced-motion: reduce){
  .listen-eq i{ animation:none; height:60%; }
  .listen-btn.connecting .listen-ico{ animation:none; opacity:.6; }
}

/* The strip gets dense before it gets narrow: drop the pop-out, then the label,
   but never the button itself — it stays a tap target at every width. */
@media (max-width: 1100px){ .listen-pop{ display:none; } }
@media (max-width: 720px){
  .listen-cap{ display:none; }
  .listen-btn{ padding:9px 11px; }
}

/* ---- PUBLIC STREAM panel (Console section) ---- */
/* Publishing is independent of X, so it lives beside the transport controls
   rather than under Space. */
#public-card input[type="text"]{
  width:100%; margin-top:9px; font-family:var(--font-mono); font-size:12px;
  color:var(--text); background:rgba(0,0,0,.28); border:1px solid var(--line);
  border-radius:4px; padding:8px 9px;
}
#public-card input[readonly]{ color:var(--accent); }
.pub-hd{
  font-family:var(--font-mono); font-size:10px; letter-spacing:.12em;
  text-transform:uppercase; color:var(--accent-dim);
  border:1px solid var(--accent-dim); border-radius:3px; padding:3px 6px; margin-left:auto;
}
.pub-note{ font-size:12px; color:var(--muted); margin-top:9px; }
.pub-link-row{ display:flex; gap:7px; align-items:center; margin-top:9px; }
.pub-link-row input{ flex:1; min-width:0; }
.pub-link-row .btn{ flex:none; }

/* ============================================================================
   OPERATOR MIC DOCK — #mic-dock, in the transmitter strip beside LISTEN LIVE.

   Hank's own microphone on the station bus at 48 kHz: the high-bandwidth twin
   of calling in on 650649HANK, and the reason the strip now has two audio
   controls that must never be open at once.

   ON THE RED. 00-tokens.css says "RED IS ON AIR. --live exists for genuine
   on-air state ONLY." A mic that is actually streaming into onair_<sid> during
   a live Space is not adjacent to the on-air state — it IS the on-air state,
   reported at finer grain than the lamp reports it. So the LIVE chip and the
   armed button take --live, and nothing else in this block does: connecting,
   muted and the profile control are amber, off is neutral, error is brick text.
   Never hue alone either way — the chip grammar in 30-panels.css supplies the
   pip shape, the label always rides inside, and the meter and the elapsed timer
   carry the same fact a third and fourth time.

   Dark-only, like the rest of AIRWAVE (:root{color-scheme:dark}, and there is
   not one prefers-color-scheme or [data-theme] hit anywhere in css/). Adding a
   light palette here would make this the board's first, in the strip, which is
   the worst place to start. Tokens only — no new raw hex. */

.mic-dock{
  position:relative;
  display:inline-flex; align-items:center; gap:var(--s2); flex:none;
}

/* ---- the arm/disarm key ---- */
.mic-btn{
  display:inline-flex; align-items:center; gap:7px; flex:none;
  font-family:var(--font-mono); font-size:12.5px; font-weight:600;
  letter-spacing:.08em; line-height:1;
  color:var(--text); background:var(--key-face);
  border:1px solid var(--line-strong); border-radius:var(--radius-sm);
  padding:9px 13px; cursor:pointer; white-space:nowrap;
  box-shadow:var(--bezel), var(--shadow-1);
  transition:filter var(--t-fast) ease, box-shadow var(--t-fast) ease,
             color var(--t-fast) ease, border-color var(--t-fast) ease,
             transform .06s ease;
}
.mic-btn:hover{ filter:brightness(1.12); }
.mic-btn:active{ transform:translateY(1px); }
.mic-btn[disabled]{ opacity:.4; cursor:default; filter:none; }
.mic-ico{ width:16px; height:16px; flex:none; }

/* ARMED = genuinely on the bus. The one place in this file that borrows the
   lamp's red, and it borrows it because it is reporting the same fact. */
.mic-dock[data-state="live"] .mic-btn{
  color:var(--live); border-color:var(--live-line);
  background:var(--surface-2);
  box-shadow:inset 0 1px 6px rgba(0,0,0,.55), 0 0 12px var(--live-glow);
}
/* MUTED is still a held mic — amber, not red, because nothing is airing. */
.mic-dock[data-state="muted"] .mic-btn{
  color:var(--accent); border-color:var(--accent-line);
  background:var(--accent-well);
  box-shadow:inset 0 1px 6px rgba(0,0,0,.55);
}
.mic-dock[data-state="requesting"] .mic-btn,
.mic-dock[data-state="connecting"] .mic-btn{
  color:var(--warn); border-color:var(--warn-line);
}
.mic-dock[data-state="requesting"] .mic-ico,
.mic-dock[data-state="connecting"] .mic-ico{
  animation:mic-pulse 900ms ease-in-out infinite;
}
@keyframes mic-pulse{ 50%{ opacity:.25; } }

/* A hot mic must read as hot from across the room, the way the lamp does. */
.mic-dock[data-state="live"] .mic-ico{
  animation:mic-hot 1.6s ease-in-out infinite;
}
@keyframes mic-hot{ 50%{ opacity:.55; } }

/* ---- state chip. Shape + fill + label come from the grammar in 30-panels.css;
   only the colour triple is picked here. The id selector is deliberate: it has
   to outrank `.chip.on{color:var(--accent)}` in 60-radio.css, which loads after
   this file and would otherwise paint a hot mic amber. ---- */
#mic-chip{ font-variant-numeric:tabular-nums; }
#mic-chip.live{ color:var(--live); border-color:var(--live-line); }
#mic-chip.armed{ color:var(--accent); border-color:var(--accent-line); }
#mic-chip.off{ color:var(--muted); border-color:var(--line); }
#mic-chip.pending{ color:var(--warn); border-color:var(--warn-line); }
#mic-chip.removing{ color:var(--err); border-color:var(--err-line); text-transform:none;
  letter-spacing:0; max-width:34ch; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; }

/* ---- the live cluster: mute, meter, elapsed ---- */
.mic-live{ display:inline-flex; align-items:center; gap:var(--s2); }
.mic-live.hidden{ display:none; }

.mic-mutebtn{
  font-family:var(--font-mono); font-size:var(--fs-2xs); font-weight:600;
  letter-spacing:.1em; line-height:1;
  color:var(--accent); background:transparent;
  border:1px solid var(--accent-dim); border-radius:3px;
  padding:6px 9px; cursor:pointer;
}
.mic-mutebtn:hover{ background:var(--accent-ghost); }
.mic-mutebtn[aria-pressed="true"]{
  color:var(--ink-on-accent); background:var(--accent); border-color:var(--accent);
}
.mic-mutebtn.hidden{ display:none; }

/* THE HONEST METER. Segments read local microphone RMS out of the audio
   worklet — the samples actually being sent. Kept visually distinct from
   #strip-vu on purpose: that one is derived from LISTENER COUNTS and adds
   random ±1 flutter so it "reads as a living signal". This one is a signal.
   Do not unify them, and never move this measurement server-side: a level
   readout of the bus means opening onair_*.monitor, which is the #1 audio
   killer in DIAGNOSTICS and took the station off air for a night. */
.mic-meter{
  display:inline-flex; align-items:center; gap:2px; flex:none;
  height:16px; padding:0 3px;
  background:var(--surface-2); border:1px solid var(--line);
  border-radius:2px; box-shadow:var(--well-inset);
}
.mic-meter i{
  display:block; width:3px; height:8px; border-radius:1px;
  background:var(--line-strong);
  transition:background var(--t-fast) linear;
}
.mic-meter i.lit{ background:var(--ok); }
.mic-meter i:nth-child(8).lit{ background:var(--gold); }
.mic-meter i:nth-child(9).lit,
.mic-meter i:nth-child(10).lit{ background:var(--live); }

/* The single most effective anti-hot-mic device on the board is a number that
   has visibly been climbing for forty minutes. It runs in MUTED too. */
.mic-elapsed{
  font-family:var(--font-mono); font-size:var(--fs-xs);
  font-variant-numeric:tabular-nums; color:var(--muted); min-width:5ch;
}
.mic-dock[data-state="live"] .mic-elapsed{ color:var(--live); }
.mic-elapsed.hidden{ display:none; }

/* ---- profile pill (SAFE / STUDIO) — also the way back to the attestation ---- */
.mic-prof{
  font-family:var(--font-mono); font-size:var(--fs-2xs); font-weight:500;
  letter-spacing:.1em; line-height:1;
  color:var(--accent-dim); background:transparent;
  border:1px dashed var(--accent-line); border-radius:3px;
  padding:5px 7px; cursor:pointer;
}
.mic-prof:hover{ color:var(--accent); border-style:solid; }

/* ---- attestation sheet ---- */
.mic-attest{
  position:absolute; top:calc(100% + 8px); right:0; z-index:60;
  width:min(380px, calc(100vw - 32px));
  padding:var(--s4);
  background:var(--panel-face); border:1px solid var(--line-strong);
  border-radius:var(--radius); box-shadow:var(--shadow-3);
  text-align:left;
}
.mic-attest.hidden{ display:none; }
.mic-attest h4{
  font-family:var(--font-display); font-size:var(--fs-d4);
  letter-spacing:.02em; margin:0 0 var(--s2);
}
.mic-attest p{ font-size:var(--fs-sm); color:var(--muted); margin:0 0 var(--s3); }
.mic-attest-row{
  display:flex; align-items:flex-start; gap:var(--s2);
  font-size:var(--fs-md); color:var(--text);
  padding:var(--s2) var(--s3); margin-bottom:var(--s3);
  background:var(--surface-2); border:1px solid var(--line);
  border-radius:var(--radius-sm); cursor:pointer;
}
.mic-attest-row input{ margin-top:2px; flex:none; accent-color:var(--accent); }
.mic-attest-fine{ font-size:var(--fs-xs); }
.mic-attest-btns{ display:flex; flex-wrap:wrap; gap:var(--s2); }
.mic-attest-btns .btn{ flex:none; }

/* ---- LISTEN LIVE, locked out while the mic is open ----
   The mechanism is in js/40-mic.js (Air holds one claim, taken synchronously
   before any await); this is only what that looks like. Both controls are
   struck through rather than merely dimmed, because a dimmed control reads as
   "loading" and gets clicked. */
.listen-btn[disabled]{ text-decoration:line-through; }
.listen-pop.locked{
  pointer-events:none; opacity:.35; text-decoration:line-through;
}

@media (prefers-reduced-motion: reduce){
  .mic-dock[data-state="requesting"] .mic-ico,
  .mic-dock[data-state="connecting"] .mic-ico,
  .mic-dock[data-state="live"] .mic-ico{ animation:none; opacity:1; }
  .mic-meter i{ transition:none; }
}

/* The strip gets dense before it gets narrow. Shed the profile pill, then the
   meter, then the button's label — but never the button, the chip or the
   elapsed timer: those three are how an operator knows the mic is still hot. */
@media (max-width: 1280px){ .mic-prof{ display:none; } }
@media (max-width: 1100px){ .mic-meter{ display:none; } }
@media (max-width: 720px){
  .mic-cap{ display:none; }
  .mic-btn{ padding:9px 11px; }
  .mic-attest{ right:auto; left:0; }
}
