/* Studio Stream — Web Player */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* ────────────────────────────────────────
   ROOT — design tokens
──────────────────────────────────────── */
:root {
  --bg:           #07080f;
  --surface:      rgba(11, 13, 22, 0.86);
  --surface-hi:   rgba(16, 18, 30, 0.93);
  --border:       rgba(255,255,255,0.07);
  --border-hi:    rgba(255,255,255,0.12);

  --accent:       #c8d0e0;
  --accent-dim:   rgba(200,208,224,0.14);
  --accent-glow:  rgba(200,208,224,0.28);

  --amber:        #ff9100;
  --amber-dim:    rgba(255,145,0,0.16);

  --green:        #00d964;
  --yellow:       #f5c518;
  --red:          #ff4545;

  --text:         #dde4f2;
  --text-mid:     #8892a8;
  --text-dim:     #6b7591;

  --font-ui:      'Syne', sans-serif;
  --font-mono:    'DM Mono', monospace;
  --blur:         blur(20px) saturate(160%);
}

/* ────────────────────────────────────────
   APP SHELL — full viewport grid
──────────────────────────────────────── */
html, body {
  height: 100%;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  display: grid;
  grid-template-rows: 1fr auto;
  position: relative;
  overflow: hidden;
}

/* ────────────────────────────────────────
   VIDEO AREA
──────────────────────────────────────── */
#video-wrap {
  position: relative;
  background: var(--bg);
  overflow: hidden;
  min-height: 0;
  padding: 16px;
}

/* Inner frame — border/glow around the video */
#video-inner {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,0.35);
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.06) inset,
    0 8px 32px rgba(0,0,0,0.6);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Hidden live video element — feeds frames to canvas via rVFC */
#video-el {
  opacity: 0;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
}

/* Canvas shown instead of #video-el once frame-buffer delay is active.
   CSS object-fit:contain letterboxes the drawn content correctly.
   The canvas intrinsic size (width/height attrs) is updated by player.js
   to match actual video dimensions so the aspect ratio is always correct. */
#video-canvas {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  position: relative;
  z-index: 1;
}

/* ── No-video icon ──
   Shown while the tray reports `muted` or `unavailable`; see index.html.
   Above the canvas (z 1), below the status pill (z 10) and the terminal
   overlay (z 20). */
#video-off {
  display: none;
  position: absolute; inset: 0;
  align-items: center; justify-content: center;
  z-index: 5;
  pointer-events: none;
  color: var(--text-dim);
}

#video-off svg { width: 64px; height: 64px; display: block; }

/* The cut under the slash, in the page background, so the slash reads as a
   break through the screen rather than a line drawn over it. */
#video-off .slash-cut { stroke: var(--bg); stroke-width: 4.6; }

.video-off #video-off { display: flex; }

/* visibility, NEVER display: in mobile portrait the video row is auto-height,
   so its height comes from the canvas's intrinsic size — display:none would
   collapse the area to nothing and the icon would have nowhere to sit. */
.video-off #video-canvas { visibility: hidden; }

/* An ordinary reconnect, and the ended screen: show the dark area rather than
   the frozen last frame.  The render loop clears the class on the first frame
   it draws after the reset. */
.no-frame #video-canvas { visibility: hidden; }

/* ── Status pill ── */
#status-overlay {
  position: absolute;
  top: 16px; left: 50%;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 7px;
  background: var(--surface);
  border: 1px solid var(--border-hi);
  border-radius: 100px;
  padding: 5px 14px 5px 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-mid);
  letter-spacing: 0.05em;
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  pointer-events: none;
  white-space: nowrap;
  box-shadow: 0 1px 0 rgba(255,255,255,0.07) inset, 0 4px 16px rgba(0,0,0,0.4);
  z-index: 10;
}

.status-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--text-dim);
  flex-shrink: 0;
}

#status-overlay.connected .status-dot {
  background: var(--green);
  box-shadow: 0 0 8px var(--green);
  animation: live-pulse 2.4s ease-in-out infinite;
}

#status-overlay.connected { color: var(--text); }

@keyframes live-pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.38; }
}

/* ── Weak-connection pill ──
   Under the status pill, same shape, amber.  It floats over the video area,
   so nothing in the layout moves when it appears, on any viewport. */
#net-pill {
  position: absolute;
  top: 48px; left: 50%;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 7px;
  background: linear-gradient(var(--amber-dim), var(--amber-dim)), var(--surface);
  border: 1px solid rgba(255,145,0,0.45);
  border-radius: 100px;
  padding: 5px 14px 5px 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--amber);
  letter-spacing: 0.05em;
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  pointer-events: none;
  white-space: nowrap;
  box-shadow: 0 1px 0 rgba(255,255,255,0.07) inset, 0 4px 16px rgba(0,0,0,0.4);
  z-index: 10;
}

#net-pill[hidden] { display: none; }

.net-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--amber);
  box-shadow: 0 0 8px var(--amber);
  flex-shrink: 0;
}

/* ── Session badge ── */
#session-badge {
  display: none; /* hidden — re-enable for debugging if needed */
  position: absolute;
  top: 16px; left: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 5px 11px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-dim);
  letter-spacing: 0.09em;
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  pointer-events: none;
  z-index: 10;
}

/* ── Connecting overlay ── */
#connecting-overlay {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 18px;
  background: var(--bg);
  z-index: 20;
}

#connecting-overlay.hidden { display: none; }

.spinner-ring {
  width: 40px; height: 40px;
  border-radius: 50%;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  animation: spin 0.9s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

.conn-text {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-dim);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* The terminal overlay has three kinds: `failed` (the connection could not
   be recovered), `ended` (the session is over on purpose — the engineer
   pressed STOP, the time limit ran out, or the session is gone from the
   server) and `busy` (someone is already listening — item 7).  The ended
   screen carries the title and NOTHING else (owner decision, 2026-09-20): one
   screen for all three reasons.  Ended and busy are brighter than failed
   because they are statements, not warnings. */
#connecting-overlay.ended .conn-text,
#connecting-overlay.busy .conn-text {
  color: var(--text);
  letter-spacing: 0.14em;
}

/* The busy screen's line (item 7): two sentences on two lines, sentence case,
   hidden on every other screen. */
.conn-detail {
  display: none;
  margin: 0;
  max-width: 52ch;   /* each sentence on its own line on desktop */
  padding: 0 16px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-dim);
  text-align: center;
  white-space: pre-line;
}
#connecting-overlay.busy .conn-detail { display: block; }

/* ────────────────────────────────────────
   CONTROL BAR
──────────────────────────────────────── */
#controls {
  position: relative;
  background: var(--surface-hi);
  border-top: 1px solid var(--border-hi);
  padding: 0 20px;
  height: 60px;
  display: flex;
  align-items: center;
  gap: 0;
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow: 0 1px 0 rgba(255,255,255,0.07) inset;
}

#controls::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(200,208,224,0.14) 20%,
    rgba(200,208,224,0.24) 50%,
    rgba(200,208,224,0.14) 80%,
    transparent 100%
  );
}

/* ── Start Audio ── */
#start-audio-btn {
  display: flex; align-items: center; gap: 8px;
  padding: 0 17px;
  height: 36px;
  background: var(--accent);
  color: #0a0c14;
  border: none;
  border-radius: 9px;
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  cursor: pointer;
  flex-shrink: 0;
  margin-right: 18px;
  transition: filter 0.15s, box-shadow 0.15s;
  box-shadow:
    0 0 0 1px rgba(200,208,224,0.35),
    0 4px 18px rgba(200,208,224,0.18),
    0 1px 0 rgba(255,255,255,0.30) inset;
}

/* Ensure the `hidden` HTML attribute hides the button even though
   #start-audio-btn has display:flex — player.js uses btn.hidden = true/false */
#start-audio-btn[hidden] { display: none !important; }

#start-audio-btn:hover {
  filter: brightness(1.08);
  box-shadow:
    0 0 0 1px rgba(200,208,224,0.55),
    0 6px 26px rgba(200,208,224,0.28),
    0 1px 0 rgba(255,255,255,0.30) inset;
}

/* ── Divider ── */
.divider {
  width: 1px; height: 24px;
  background: var(--border);
  flex-shrink: 0;
  margin: 0 16px;
}

/* ── Slider groups ── */
.ctrl-group {
  display: flex; align-items: center;
  gap: 10px; flex-shrink: 0;
}

.ctrl-label {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-dim);
  white-space: nowrap;
}

.ctrl-value {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-mid);
  width: 54px;
  white-space: nowrap;
  flex-shrink: 0;
  text-align: right;
}

input[type="range"] {
  -webkit-appearance: none;
  height: 3px;
  border-radius: 2px;
  background: rgba(255,255,255,0.09);
  cursor: pointer;
  outline: none;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: #c8cce0;
  border: 2px solid rgba(11,13,22,0.95);
  box-shadow: 0 0 0 1px rgba(255,255,255,0.1);
  cursor: pointer;
  transition: background 0.15s, box-shadow 0.15s;
}

input[type="range"]:hover::-webkit-slider-thumb {
  background: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 0 10px var(--accent-glow);
}

#volume        { width: 86px; }
#buffer-target { width: 86px; }

/* ── VU Meters ── */
.meters-wrap {
  display: flex; flex-direction: column;
  gap: 6px; flex: 1;
  max-width: 240px;
  margin: 0 2px;
}

.meter-row {
  display: flex; align-items: center; gap: 7px;
}

.meter-ch {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-dim);
  width: 8px; flex-shrink: 0;
}

.meter-track {
  flex: 1; height: 5px;
  background: rgba(255,255,255,0.05);
  border-radius: 3px;
  overflow: hidden;
}

.meter-fill {
  height: 100%;
  width: 100%;
  border-radius: 3px;
  /* Full-size fill with the gradient painted across the whole track; the
     meter loop reveals the level with a clip-path inset, so each colour sits
     at a fixed position.  Zones: green to -18 dB (70%), yellow to -6 dB
     (90%), red above, with a 4% blend either side of each boundary.
     Resting state: fully hidden until the loop's first frame. */
  clip-path: inset(0 100% 0 0 round 3px);
  background: linear-gradient(90deg,
    var(--green)  0%,
    var(--green)  68%,
    var(--yellow) 72%,
    var(--yellow) 88%,
    var(--red)    92%,
    var(--red)    100%
  );
  transition: clip-path 40ms ease-out;
}

/* ── Buffer stat ── */
.stat-block {
  display: flex; flex-direction: column;
  align-items: flex-end; gap: 1px;
  flex-shrink: 0;
}

.stat-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.stat-value {
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 500;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  width: 58px;
  text-align: right;
}

/* ── Chat toggle buttons ── */
#chat-btn, #chat-btn-mob {
  width: 36px; height: 36px;
  flex-shrink: 0;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text-mid);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  margin-left: 8px;  /* TALK button now provides the right-cluster auto-push */
  transition: background 0.15s, border-color 0.15s, color 0.15s, box-shadow 0.15s;
  position: relative;
}

#chat-btn:hover, #chat-btn-mob:hover {
  background: rgba(255,255,255,0.05);
  border-color: var(--border-hi);
  color: var(--text);
}

#chat-btn.chat-open, #chat-btn-mob.chat-open {
  background: var(--amber-dim);
  border-color: rgba(255,145,0,0.32);
  color: var(--amber);
  box-shadow: 0 0 12px rgba(255,145,0,0.1);
}

.unread-pip {
  position: absolute;
  top: 7px; right: 7px;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--amber);
  box-shadow: 0 0 6px var(--amber);
  display: none;
}

#chat-btn.has-unread .unread-pip,
#chat-btn-mob.has-unread .unread-pip { display: block; }

/* ── PTT TALK buttons (Stage 2: client → engineer) ── */
#talk-btn, #talk-btn-mob {
  height: 36px;
  min-width: 56px;
  padding: 0 10px;
  flex-shrink: 0;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text-mid);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  touch-action: none;  /* prevent scroll/long-press menus while held */
  transition: background 0.15s, border-color 0.15s, color 0.15s, box-shadow 0.15s;
  position: relative;  /* the containing block for .talk-dot */
}

/* Desktop TALK button — solid amber fill matching the chat Send button and
   the mobile portrait TALK button.  Wider min-width (100px) makes it a
   comfortable click target. */
.desktop-controls #talk-btn {
  min-width: 100px;
  text-indent: 0.12em;  /* compensate for letter-spacing trailing on last char */
  background: var(--amber);
  border: 1px solid rgba(255,145,0,0.4);
  color: #0a0500;
  box-shadow:
    0 0 0 1px rgba(255,145,0,0.4),
    0 4px 18px rgba(255,145,0,0.22),
    0 1px 0 rgba(255,255,255,0.25) inset;
}

/* TALK is the auto-push for the right cluster — pushes itself and chat
   to the right edge.  The buffer stat-block stays grouped with the meters
   on the left side (no auto-margin on it). */
.desktop-controls #talk-btn { margin-left: auto; }

/* …but that auto margin collapses to nothing once the meters have given up
   all their slack: measured 2026-09-20, the gap is EXACTLY 0 px at every
   width from 620 to 900 px, so TALK sits flush against the buffer readout in
   any half-screen window (768 CSS px on a 1920 px display at 125 %).  16 px
   is the dividers' own rhythm — a floor under the auto margin, not a
   replacement for it.  Landscape mobile is unaffected: the stat block is
   display:none there. */
.desktop-controls .stat-block { margin-right: 16px; }

/* Desktop hover — brightness adjustment, same DNA as Start Audio hover */
.desktop-controls #talk-btn:hover:not(:disabled):not(.talk-held):not(.talk-acquiring) {
  filter: brightness(1.08);
  background: var(--amber);
  border-color: rgba(255,145,0,0.55);
  color: #0a0500;
}

/* Held = LIVE — solid red fill with strong glow.  Must override the shared
   #talk-btn:hover:not(:disabled) rule that comes later in this file.
   Chaining .talk-held twice raises specificity to (1,3,0), winning over
   the shared hover rule (1,2,0) when the cursor is over the held button.
   transition: none is the § 1.5 snap: transitions are read from the
   DESTINATION state, so entering LIVE is instant ("speak now" must be a
   hard snap, not a blend) while leaving it back to READY still eases via
   the base rule's 0.15s transition. */
.desktop-controls #talk-btn.talk-held.talk-held {
  background: var(--red);
  border-color: rgba(255,69,69,0.7);
  color: #1a0303;
  transition: none;
  box-shadow:
    0 0 0 1px rgba(255,69,69,0.5),
    0 4px 22px rgba(255,69,69,0.45),
    0 1px 0 rgba(255,255,255,0.25) inset;
}

/* ACQUIRING (§ 1.5), desktop — pressed, capture not yet live (getUserMedia
   is ~600 ms of the ~700 ms press-to-live on iOS).  Must read as NOT
   READY: dimmed, desaturated, slow pulse (motion sells the wait; the
   first dip lands ~300 ms in).  Same double-chain specificity trick as
   .talk-held.talk-held above.  :enabled — a disabled button must never
   pulse, whatever the JS ordering.  transition: none = instant entry. */
.desktop-controls #talk-btn.talk-acquiring.talk-acquiring:enabled {
  background: rgba(140, 110, 55, 0.30);
  border-color: rgba(255, 145, 0, 0.28);
  color: rgba(232, 230, 227, 0.55);
  box-shadow: none;
  transition: none;
  animation: talk-acquiring-pulse 0.6s ease-in-out infinite alternate;
}

/* Desktop disconnected — flat dark fill, dimmed (matches mobile portrait) */
.desktop-controls #talk-btn:disabled {
  background: rgba(40,44,58,0.5);
  border: 1px solid rgba(255,255,255,0.07);
  color: var(--text-dim);
  opacity: 0.55;
  cursor: not-allowed;
  box-shadow: none;
}

#talk-btn:hover:not(:disabled),
#talk-btn-mob:hover:not(:disabled) {
  background: rgba(255,255,255,0.05);
  border-color: var(--border-hi);
  color: var(--text);
}

#talk-btn.talk-held,
#talk-btn-mob.talk-held {
  background: rgba(255,69,69,0.16);
  border-color: rgba(255,69,69,0.45);
  color: var(--red);
  transition: none;  /* § 1.5 LIVE snap — see the desktop held rule */
  box-shadow: 0 0 12px rgba(255,69,69,0.18);
}

/* ACQUIRING (§ 1.5), shared base — see the desktop rule for rationale.
   Placed after the shared hover rule so equal-specificity ties resolve to
   this state while pressed. */
#talk-btn.talk-acquiring:enabled,
#talk-btn-mob.talk-acquiring:enabled {
  background: rgba(140, 110, 55, 0.30);
  border-color: rgba(255, 145, 0, 0.28);
  color: rgba(232, 230, 227, 0.55);
  box-shadow: none;
  transition: none;
  animation: talk-acquiring-pulse 0.6s ease-in-out infinite alternate;
}

@keyframes talk-acquiring-pulse {
  from { opacity: 1; }
  to   { opacity: 0.55; }
}

/* Reduced motion: the static dim still carries the not-ready signal.
   The desktop double-chain selector must be repeated here at its own
   specificity (and after that rule in source) or it would outrank this
   override.  The mobile-portrait rule has its own reduced-motion block
   inside the portrait media query, after its acquiring rule, for the same
   source-order reason. */
@media (prefers-reduced-motion: reduce) {
  #talk-btn.talk-acquiring:enabled,
  #talk-btn-mob.talk-acquiring:enabled,
  .desktop-controls #talk-btn.talk-acquiring.talk-acquiring:enabled {
    animation: none;
  }
}

#talk-btn:disabled,
#talk-btn-mob:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  color: var(--text-dim);
}

/* ── TALK level dot (OPEN-TASKS § 3.15) ──
   The listener's own mic level, INSIDE the TALK button just left of its
   label, shown only while the press is LIVE: grey = no signal, green =
   signal, red = too loud.  No text.  player.js sets data-level to
   none / ok / hot while live and to off otherwise; anything else is hidden.
   Sized in em so it scales with each button's own label (10 px on the strip,
   14 px on the portrait button).  The dot only ever shows on the solid red
   LIVE fill, so a dark ring makes grey and green read — and red takes a
   LIGHT ring instead: seen in the harness shots (2026-09-21), a red core on
   the red fill inside a dark ring reads as an empty ring, i.e. as nothing.
   It sits inside the button, so it takes no room in any layout. */
.talk-dot {
  display: none;
  position: absolute;
  top: 50%;
  right: calc(50% + 2.3em);
  width: 0.6em; height: 0.6em;
  margin-top: -0.3em;
  border-radius: 50%;
  box-shadow: 0 0 0 0.3em rgba(10, 5, 0, 0.62);
  pointer-events: none;
}
.talk-dot[data-level="none"] { display: block; background: #a3abbd; }
.talk-dot[data-level="ok"]   { display: block; background: var(--green); }
.talk-dot[data-level="hot"]  { display: block; background: var(--red); box-shadow: 0 0 0 0.2em #fff4f0; }

/* ── Microphone picker icon (OPEN-TASKS § 3.15) ──
   Beside TALK, never on a phone: the buttons ship `hidden` and player.js
   un-hides them (and sets body.mic-pick) only when the device is not a
   phone.  [hidden] must beat the display below. */
#mic-btn, #mic-btn-mob {
  flex-shrink: 0;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text-mid);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  padding: 0;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
#mic-btn[hidden], #mic-btn-mob[hidden] { display: none !important; }

#mic-btn:hover, #mic-btn-mob:hover,
#mic-btn[aria-expanded="true"], #mic-btn-mob[aria-expanded="true"] {
  background: rgba(255,255,255,0.05);
  border-color: var(--border-hi);
  color: var(--text);
}

/* The strip: TALK gives up EXACTLY the icon's footprint — 72 + 4 + 24 is the
   100 px TALK had on its own — so every other position in the strip is
   unchanged at every width: the buffer readout's gap to TALK (§ 3.11), the
   narrow-window overflow onset, the chat button.  Without .mic-pick (a
   phone, or no script) TALK keeps its 100 px. */
.mic-pick .desktop-controls #talk-btn { min-width: 72px; }
.desktop-controls #mic-btn { width: 24px; height: 36px; margin-left: 4px; }

/* ── Microphone popover ── */
#mic-popover {
  position: fixed;
  z-index: 60;
  min-width: 220px;
  max-width: min(320px, calc(100vw - 16px));
  max-height: min(360px, calc(100vh - 16px));
  overflow-y: auto;
  padding: 10px 6px 6px;
  background: var(--surface-hi);
  border: 1px solid var(--border-hi);
  border-radius: 12px;
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.04) inset,
    0 20px 50px rgba(0,0,0,0.6);
}
#mic-popover[hidden] { display: none; }

.mic-pop-title {
  padding: 0 10px 8px;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.13em;
  color: var(--text-dim);
}

.mic-row {
  display: flex; align-items: center; gap: 9px;
  width: 100%;
  min-height: 32px;
  padding: 6px 10px;
  background: transparent;
  border: none;
  border-radius: 7px;
  color: var(--text-mid);
  font-family: var(--font-mono);
  font-size: 11px;
  text-align: left;
  cursor: pointer;
}
/* The radio mark: an outline, filled amber on the chosen row. */
.mic-row::before {
  content: '';
  width: 7px; height: 7px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid var(--text-dim);
}
.mic-row[aria-checked="true"] { color: var(--text); }
.mic-row[aria-checked="true"]::before {
  background: var(--amber);
  border-color: var(--amber);
  box-shadow: 0 0 6px var(--amber);
}
.mic-row:hover, .mic-row:focus-visible {
  background: rgba(255,255,255,0.05);
  color: var(--text);
  outline: none;
}
.mic-row-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

#mic-pop-note {
  padding: 8px 10px 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.5;
  color: var(--text-dim);
}
#mic-pop-note[hidden] { display: none; }

/* Mobile-portrait dedicated TALK area: hidden by default, shown only inside
   the portrait media query below.  Kept hidden in landscape and on desktop
   so the small landscape #talk-btn (in the right-side strip) is the active
   talkback control there. */
#talk-area-mob {
  display: none;
}

/* ── Desktop/landscape controls wrapper ── */
.desktop-controls {
  display: flex;
  align-items: center;
  gap: 0;
  flex: 1;
}

.desktop-controls .ctrl-group { flex-shrink: 0; }
.desktop-controls .meters-wrap { margin: 0 2px; }
/* Chat button uses its base margin-left: 8px in desktop strip, sitting
   flush against TALK.  TALK alone provides the auto-push for the cluster. */
.desktop-controls #chat-btn { margin-left: 8px; }

/* Mobile rows hidden by default (shown only in portrait mobile) */
.mob-ctrl-row,
.mob-indicator-row {
  display: none !important;
}

/* ────────────────────────────────────────
   FLOATING CHAT PANEL
──────────────────────────────────────── */
#chat-panel {
  position: fixed;
  right: 16px;
  bottom: 76px;
  width: 286px;
  background: var(--surface-hi);
  border: 1px solid var(--border-hi);
  border-radius: 14px;
  display: flex; flex-direction: column;
  overflow: hidden;
  z-index: 40;
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.04) inset,
    0 20px 50px rgba(0,0,0,0.6),
    0 0 24px rgba(255,145,0,0.05);
  max-height: 360px;
  opacity: 1;
  transform: translateY(0) scale(1);
  transform-origin: bottom right;
  transition:
    max-height 0.26s cubic-bezier(0.4,0,0.2,1),
    opacity    0.22s ease,
    transform  0.24s cubic-bezier(0.4,0,0.2,1);
}

#chat-panel.chat-hidden {
  max-height: 0;
  opacity: 0;
  transform: translateY(10px) scale(0.97);
  pointer-events: none;
}

#chat-panel::before {
  content: '';
  position: absolute;
  top: 0; left: 20px; right: 20px; height: 1px;
  background: linear-gradient(90deg,
    transparent,
    rgba(255,145,0,0.3) 35%,
    rgba(255,145,0,0.3) 65%,
    transparent
  );
}

/* Chat panel header (id kept as chat-header to match player.js references) */
#chat-header {
  display: flex; align-items: center;
  justify-content: space-between;
  padding: 0 14px;
  height: 40px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  transition: background 0.3s;
}

#chat-header.unread {
  background: rgba(255,145,0,0.08);
}

.chat-head-label {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--amber);
}

.chat-live-dot {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--amber);
  box-shadow: 0 0 6px var(--amber);
  animation: amber-pulse 2.2s ease-in-out infinite;
}

@keyframes amber-pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 6px var(--amber); }
  50%       { opacity: 0.4;  box-shadow: 0 0 3px var(--amber); }
}

#chat-close {
  background: none; border: none;
  color: var(--text-dim);
  cursor: pointer;
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 5px;
  font-size: 11px;
  transition: background 0.15s, color 0.15s;
}

#chat-close:hover { background: rgba(255,255,255,0.07); color: var(--text-mid); }

#chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 12px;
  display: flex; flex-direction: column;
  gap: 8px;
  min-height: 90px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

#chat-messages::-webkit-scrollbar { width: 3px; }
#chat-messages::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }

.chat-msg {
  max-width: 84%;
  padding: 7px 11px;
  border-radius: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  word-break: break-word;
}

.chat-msg.from-host {
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
  color: var(--text-mid);
  align-self: flex-start;
  border-bottom-left-radius: 3px;
}

.chat-msg.from-me {
  background: var(--amber-dim);
  border: 1px solid rgba(255,145,0,0.2);
  color: var(--text);
  align-self: flex-end;
  border-bottom-right-radius: 3px;
}

.chat-time {
  font-size: 9px;
  opacity: 0.34;
  margin-top: 3px;
}

#chat-input-row {
  display: flex; gap: 6px;
  padding: 8px 10px;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

#chat-input {
  flex: 1;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 5px 9px;
  outline: none;
  transition: border-color 0.15s;
}

#chat-input::placeholder { color: var(--text-dim); }
#chat-input:focus { border-color: rgba(255,145,0,0.4); }

/* id renamed from #chat-send → #chat-send-btn to match player.js */
#chat-send-btn {
  background: var(--amber);
  color: #0a0500;
  border: none;
  border-radius: 6px;
  padding: 0 12px;
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
  height: 28px;
  letter-spacing: 0.03em;
  transition: filter 0.15s;
  box-shadow: 0 2px 10px rgba(255,145,0,0.2);
}

#chat-send-btn:hover:not(:disabled) { filter: brightness(1.1); }

/* Once the session has ended the history stays open and readable and only
   SENDING goes (owner decision, 2026-09-20).  The button's background is set
   outright, so a browser's own disabled styling would not show through — same
   dimming language as the disabled TALK button. */
#chat-send-btn:disabled {
  opacity: 0.4;
  cursor: default;
  box-shadow: none;
}

#chat-input:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ── Narrow desktop windows ──
   Below ~675 px the strip used to run off the window entirely (measured
   2026-09-20: 55 px of horizontal page overflow at 620 px, with the chat
   button outside the viewport).  These are the compact sizes the ≤600 px
   mobile rule already ships, applied to the desktop strip so it keeps fitting
   down to ~610 px.  No new vocabulary, and the meters keep absorbing whatever
   slack is left. */
@media (min-width: 601px) and (max-width: 760px) {
  #volume, #buffer-target       { width: 68px; }
  .desktop-controls .ctrl-value { width: 46px; }
  .desktop-controls .divider    { margin: 0 10px; }
}

/* ────────────────────────────────────────
   MOBILE — media queries
──────────────────────────────────────── */
@media (max-width: 600px) {

  .divider { display: none; }

  /* iOS zoom prevention */
  #chat-input { font-size: 16px; }

  /* The no-video icon is smaller on a phone-sized screen. */
  #video-off svg { width: 48px; height: 48px; }

  #volume, #buffer-target,
  #volume-mob, #buffer-target-mob { width: 68px; }
  .ctrl-value { width: 46px; }

  /* ── Portrait mobile ── */
  @media (orientation: portrait) {
    body {
      grid-template-rows: auto 1fr auto;
    }

    /* A session with NO video track at all never creates a canvas, so the
       auto-height video row would have no height to centre the icon in. */
    .video-off #video-inner { aspect-ratio: 16 / 9; }

    /* No canvas yet — before the first video track arrives, and on every
       screen a page can show without ever receiving one (the connecting
       screen, SOMEONE IS ALREADY LISTENING, Connection failed, SESSION ENDED):
       nothing sizes the auto-height row, so it collapsed to its 1 px border
       and the overlay inside it was invisible (owner's iPhone, 2026-09-26).
       Take the same 16:9 height the canvas's own placeholder gives the area
       the moment a track arrives.  `height: auto` is load-bearing: the
       base rule's `height: 100%` is an explicit height, which overrides
       aspect-ratio — which is also why the .video-off rule above never took
       effect by itself.  player.js removes .no-canvas when it inserts the
       canvas, so a page with a canvas (frames, a mute, an ended screen after
       frames) is sized by the canvas exactly as before. */
    #video-inner.no-canvas { height: auto; aspect-ratio: 16 / 9; }

    #video-wrap {
      padding: 0;
    }

    #video-inner {
      border-radius: 0;
      border: none;
      border-bottom: 1px solid rgba(255,255,255,0.35);
      box-shadow: none;
    }

    /* Dedicated TALK area below the video — pinned to the top of the 1fr
       grid row (align-self: start) so the button sits flush below the
       video.  The remaining height of row 2 is the dark gap where the chat
       panel floats; _positionMobileChat() reads this area's bottom edge. */
    #talk-area-mob {
      display: flex;
      align-items: center;
      justify-content: center;
      background: var(--bg);
      padding: 8px 14px;
      flex-shrink: 0;
      grid-row: 2;
      align-self: start;
    }

    #talk-area-mob #talk-btn-mob {
      width: 100%;
      height: 64px;
      min-width: 0;
      padding: 0;
      border-radius: 12px;
      font-size: 14px;
      letter-spacing: 0.18em;

      /* Connected idle (default, when not disabled and not .talk-held):
         amber fill, dark text — matches the chat Send button. */
      background: var(--amber);
      border: 1px solid rgba(255,145,0,0.4);
      color: #0a0500;
      box-shadow:
        0 0 0 1px rgba(255,145,0,0.4),
        0 4px 18px rgba(255,145,0,0.22),
        0 1px 0 rgba(255,255,255,0.25) inset;
    }

    #talk-area-mob #talk-btn-mob:hover:not(:disabled):not(.talk-held):not(.talk-acquiring) {
      filter: brightness(1.08);
    }

    /* A NARROW DESKTOP window lands in this layout too (it is width-keyed),
       and gets the picker icon beside the big TALK.  A phone never does:
       no .mic-pick, the icon stays hidden, TALK keeps the full width. */
    .mic-pick #talk-area-mob #talk-btn-mob { flex: 1 1 auto; width: auto; }
    #talk-area-mob #mic-btn-mob {
      width: 52px;
      height: 64px;
      margin-left: 8px;
      border-radius: 12px;
    }

    /* Held = LIVE — solid red fill, dark text, red glow.  transition: none
       is the § 1.5 snap (see the desktop held rule). */
    #talk-area-mob #talk-btn-mob.talk-held {
      background: var(--red);
      border-color: rgba(255,69,69,0.7);
      color: #1a0303;
      transition: none;
      box-shadow:
        0 0 0 1px rgba(255,69,69,0.5),
        0 4px 22px rgba(255,69,69,0.45),
        0 1px 0 rgba(255,255,255,0.25) inset;
    }

    /* ACQUIRING (§ 1.5) — pressed, capture not yet live.  Dimmed ghost of
       the amber + slow pulse; instant entry.  Outranks the (2,0,0) idle
       rule above at (2,2,0), same source-order arrangement as .talk-held.
       :enabled — a disabled button must never pulse. */
    #talk-area-mob #talk-btn-mob.talk-acquiring:enabled {
      background: rgba(140, 110, 55, 0.30);
      border-color: rgba(255, 145, 0, 0.28);
      color: rgba(232, 230, 227, 0.55);
      box-shadow: none;
      transition: none;
      animation: talk-acquiring-pulse 0.6s ease-in-out infinite alternate;
    }

    /* Must come AFTER the portrait acquiring rule above (equal specificity,
       source order decides) — the shared reduced-motion block earlier in
       the file cannot outrank it. */
    @media (prefers-reduced-motion: reduce) {
      #talk-area-mob #talk-btn-mob.talk-acquiring:enabled {
        animation: none;
      }
    }

    /* Disconnected — flat dark fill, dimmed */
    #talk-area-mob #talk-btn-mob:disabled {
      background: rgba(40,44,58,0.5);
      border: 1px solid rgba(255,255,255,0.07);
      color: var(--text-dim);
      opacity: 0.55;
      cursor: not-allowed;
      box-shadow: none;
    }

    /* Controls become a structured bottom panel with two rows */
    #controls {
      height: auto;
      padding: 0;
      flex-direction: column;
      gap: 0;
      backdrop-filter: var(--blur);
      -webkit-backdrop-filter: var(--blur);
      grid-row: 3; /* push to 3rd row so row 2 (1fr) stays empty = dark gap */
    }

    #start-audio-btn {
      width: 60%;
      max-width: 260px;
      order: -2;
      justify-content: center;
      margin: 10px auto 8px;
      height: 38px;
      font-size: 12px;
      border-radius: 9px;
    }

    /* Row 1: Controls (Vol, Buffer, Chat) */
    .mob-ctrl-row {
      display: flex !important;
      align-items: center;
      justify-content: center;
      gap: 10px;
      padding: 8px 14px;
      border-top: 1px solid var(--border);
      width: 100%;
    }

    /* Row 2: Indicators (Meters, Buffer stat) */
    .mob-indicator-row {
      display: flex !important;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      padding: 7px 14px;
      border-top: 1px solid var(--border);
      width: 100%;
    }

    .meters-wrap {
      flex: 1;
      max-width: none;
      min-width: 90px;
    }

    .stat-block { align-items: flex-end; flex-shrink: 0; }
    .stat-value { font-size: 13px; width: auto; }

    #chat-btn { margin-left: 0; }

    /* Hide desktop controls in portrait; show mobile rows */
    .desktop-controls { display: none !important; }

    /* Chat panel: full-width in the gap between video and controls */
    #chat-panel {
      position: fixed;
      left: 0; right: 0;
      width: 100%;
      border-radius: 0;
      max-height: none;
      transform-origin: center center;
      z-index: 40;
    }

    #chat-panel.chat-hidden {
      opacity: 0;
      transform: translateY(10px);
      max-height: 0;
      pointer-events: none;
    }
  }

}

/* ── Landscape mobile — ALL phones ─────────────────────────────────────────
   max-height:500px targets phones only (phones are ≤430px tall in landscape;
   tablets/desktops are taller). Width is NOT constrained so wide phones like
   iPhone 15 (852×393px landscape) are correctly matched.
   Contains: vertical right-side strip controls + chat panel positioning. */
@media (orientation: landscape) and (max-height: 500px) {
  /* Safari iOS fix: 100vh includes area behind browser chrome, so we use
     100dvh (dynamic viewport height, iOS 15.4+) throughout this block. */

  body {
    min-height: 100dvh;
    grid-template-rows: 1fr;         /* single row — video fills height */
    grid-template-columns: 1fr auto; /* video left, strip right */
  }

  /* PTT is portrait-only — hide all talkback UI in landscape so this layout
     matches its pre-PTT state. */
  #talk-area-mob,
  #talk-area-mob #talk-btn-mob {
    display: none !important;
  }

  #video-wrap {
    padding: 6px;
  }

  /* ── Vertical right-side control strip ── */
  #controls {
    order: unset; /* no longer needs to float above video */
    width: 52px;
    height: 100dvh;
    flex-direction: column;
    padding: 8px 0;
    border-top: none;
    border-bottom: none;
    border-left: 1px solid var(--border-hi);
    box-shadow: -1px 0 0 rgba(255,255,255,0.07) inset;
    align-items: center;
    gap: 6px;
    overflow: visible;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  /* Gradient runs vertically along the left edge of the strip */
  #controls::before {
    top: 20%; bottom: 20%;
    left: 0; right: auto;
    width: 1px; height: auto;
    background: linear-gradient(180deg,
      transparent 0%,
      rgba(200,208,224,0.14) 20%,
      rgba(200,208,224,0.24) 50%,
      rgba(200,208,224,0.14) 80%,
      transparent 100%
    );
  }

  /* Start Audio: centered overlay on the video area (accounts for 52px strip).
     backdrop-filter:none on #controls ensures position:fixed is viewport-relative
     (Safari iOS creates a new containing block for fixed children otherwise). */
  #start-audio-btn {
    display: flex !important;
    position: fixed;
    top: 50%;
    left: calc(50% - 26px); /* offset by half the 52px strip to center over video */
    transform: translate(-50%, -50%);
    z-index: 50;
    margin: 0;
  }

  #start-audio-btn[hidden] { display: none !important; }

  /* Desktop controls: stack vertically, centered in strip */
  .desktop-controls {
    flex-direction: column;
    align-items: center;
    gap: 6px;
    flex: 1;
    width: 100%;
  }

  /* Dividers become thin horizontal lines */
  .divider {
    display: block;
    width: 24px;
    height: 1px;
    margin: 2px 0;
  }

  /* VU Meters — two thin vertical bars side by side */
  .meters-wrap {
    flex-direction: row;
    flex: unset;
    max-width: none;
    min-width: unset;
    gap: 3px;
    width: 100%;
    justify-content: center;
    margin: 0;
    align-items: flex-end;
  }

  .meter-row {
    flex-direction: column-reverse; /* bar on top, label below */
    align-items: center;
    gap: 2px;
  }

  .meter-ch {
    font-size: 7px;
    width: auto;
  }

  .meter-track {
    flex: unset;
    width: 5px;
    height: 80px;
    position: relative;
    overflow: hidden;
  }

  .meter-fill {
    height: 100%;
    position: absolute;
    bottom: 0; left: 0;
    border-radius: 3px;
    /* Vertical: 0deg puts 0% at the bottom, so the stops are the base list
       unchanged; the loop clips from the top.  Width and the clip-path
       transition fall through to the base rule. */
    clip-path: inset(100% 0 0 0 round 3px);
    background: linear-gradient(0deg,
      var(--green)  0%,
      var(--green)  68%,
      var(--yellow) 72%,
      var(--yellow) 88%,
      var(--red)    92%,
      var(--red)    100%
    );
  }

  /* Buffer stat hidden — strip shows meters + volume + chat only */
  .stat-block { display: none; }

  /* Buffer slider group hidden — volume is the only slider in the strip */
  .desktop-controls .ctrl-group:has(#buffer-target) { display: none; }

  /* Slider ctrl-groups — vertical layout */
  .ctrl-group {
    flex-direction: column;
    align-items: center;
    gap: 3px;
  }

  .ctrl-label { font-size: 7px; }

  /* Vertical volume slider — taller now that buffer slider is gone */
  #volume {
    writing-mode: vertical-lr;
    direction: rtl;
    width: 13px;
    height: 80px;
  }

  /* Buffer slider — hidden, but keep vertical orientation in case :has() isn't enough */
  #buffer-target {
    writing-mode: vertical-lr;
    direction: rtl;
    width: 13px;
    height: 80px;
    display: none;
  }

  /* Buffer value shown in tiny text below slider */
  .ctrl-value {
    font-size: 7px;
    width: auto;
    text-align: center;
  }

  /* No PTT in landscape — TALK button removed entirely from the side strip.
     The picker icon goes with it (it belongs beside TALK); this query also
     matches a short desktop window, which is the only way it can be here. */
  #talk-btn,
  #mic-btn {
    display: none !important;
  }
  #chat-btn {
    margin-left: 0 !important;   /* override base 8px */
    margin-right: 0 !important;
    margin-top: auto;            /* now provides the bottom-pin since TALK is gone */
    margin-bottom: 0;
    align-self: center;
  }

  /* ── Chat panel positioning ── */
  #chat-panel {
    position: fixed;
    top: 8px;       /* no top bar — strip is on the right, not top */
    bottom: 8px;    /* hard floor — panel never overflows viewport bottom */
    left: auto;
    right: 60px;    /* 52px strip + 8px gap */
    width: 280px;
    height: auto;
    /* Disable max-height completely — top+bottom define the size.
       !important overrides the base 360px rule. */
    max-height: none !important;
    overflow: hidden;
    border-radius: 12px;
    transform-origin: top right;
    -webkit-overflow-scrolling: touch;
  }

  /* Visibility handled by opacity + transform only.
     max-height: none prevents the base max-height:0 rule from collapsing
     the panel during the show/hide transition. */
  #chat-panel.chat-hidden {
    max-height: none !important;
    opacity: 0;
    transform: translateY(-10px) scale(0.97);
    pointer-events: none;
    -webkit-overflow-scrolling: touch;
  }
}

/* ────────────────────────────────────────
   DEBUG PANEL (Beta — temporary)
   Controlled by DEBUG_PANEL_ENABLED in player.js. Remove this whole block
   when the debug feature is retired.
──────────────────────────────────────── */
#debug-btn {
  position: absolute;
  top: 16px; left: 16px;
  /* Must sit ABOVE #debug-panel (z-index 31) so the user can click ✕ CLOSE
     while the panel is open.  Originally specced at 30 — that put it below
     the panel and made it unreachable once opened. */
  z-index: 32;
  background: var(--surface);
  border: 1px solid var(--border-hi);
  border-radius: 100px;
  padding: 5px 12px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-dim);
  cursor: pointer;
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow: 0 1px 0 rgba(255,255,255,0.07) inset, 0 4px 16px rgba(0,0,0,0.4);
  transition: color 0.15s, border-color 0.15s, background 0.15s;
  white-space: nowrap;
}

#debug-btn:hover {
  color: var(--text-mid);
  border-color: rgba(255,255,255,0.2);
}

#debug-btn.debug-btn-open {
  color: var(--amber);
  border-color: rgba(255,145,0,0.4);
}

#debug-panel {
  position: absolute;
  inset: 0;
  z-index: 31;
  background: rgba(7, 8, 15, 0.92);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  display: none;                  /* JS sets to flex when open */
  flex-direction: column;
  padding: 52px 16px 16px 16px;   /* top room for the DEBUG button */
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text);
}

#debug-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border-hi);
  flex-shrink: 0;
}

#debug-title {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--text);
}

#debug-copy-btn {
  background: var(--surface);
  border: 1px solid var(--border-hi);
  border-radius: 8px;
  color: var(--text-mid);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  padding: 5px 12px;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}

#debug-copy-btn:hover {
  color: var(--text);
  border-color: rgba(255,255,255,0.22);
  background: rgba(255,255,255,0.04);
}

#debug-copy-btn.copied {
  color: var(--green);
  border-color: rgba(0,217,100,0.4);
}

#debug-copy-btn.failed {
  color: var(--red);
  border-color: rgba(255,69,69,0.4);
}

#debug-body {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding-top: 12px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

#debug-body::-webkit-scrollbar { width: 4px; }
#debug-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }

.debug-block {
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}

.debug-block:last-child { border-bottom: none; padding-bottom: 0; }

.debug-block h4 {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--text-dim);
  margin-bottom: 6px;
}

.debug-rows {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.debug-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
}

.debug-key {
  color: var(--text-mid);
  flex-shrink: 0;
}

.debug-val {
  color: var(--text);
  font-variant-numeric: tabular-nums;
  text-align: right;
  word-break: break-all;
}

.debug-val.ok   { color: var(--green); }
.debug-val.warn { color: var(--yellow); }
.debug-val.bad  { color: var(--red); }

.debug-warn-row {
  margin-top: 8px;
  padding: 8px 10px;
  border: 1px solid rgba(255,69,69,0.45);
  border-radius: 6px;
  background: rgba(255,69,69,0.08);
  color: var(--red);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  font-weight: 500;
}

#debug-log {
  min-height: 180px;
  max-height: 40dvh;
  overflow-y: auto;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.45;
  color: var(--text-mid);
  white-space: pre-wrap;
  word-break: break-word;
  background: rgba(0,0,0,0.25);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

#debug-log::-webkit-scrollbar { width: 4px; }
#debug-log::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
