/* Modern Claudefare — voice chat: the speaking indicator and the master-volume notice.
 *
 * WHY THIS IS ITS OWN STYLESHEET.
 * `style.css` is held by another session in this fleet, and two agents appending to
 * one 3,000-line file is how a rule lands inside somebody else's media query. This
 * file owns exactly two elements — `#voice-hud` and `#voice-notice` — both created by
 * js/voice-hud.js, neither present in index.html. index.html carries one added line:
 * the <link> that pulls this in after style.css, so the tokens below are resolved.
 *
 * EVERY POSITION HERE IS A RELATIONSHIP, NOT A NUMBER.
 * `AGENTS.md`: *"Express a layering requirement as a relationship, not a literal …
 * writing it as a number is precisely how `--z-fx` came to equal `--z-modal` and paint
 * the damage vignette over the live endboard."* So:
 *
 *   - `--vh-top` and `--vh-max` are written by js/voice-hud.js from the MEASURED
 *     bottom of `#minimap` and the MEASURED top of `#feed-stack`. The minimap is
 *     `clamp(150px, 13.5vw, 214px)` and the feed-stack grows upward with the killfeed,
 *     so no constant in this file could be right at two window widths.
 *   - the z-index is `calc(var(--z-fx) + 1)`: one above the damage vignette, because a
 *     name you are trying to read must survive being shot at. It is a LOCAL index —
 *     `#hud` carries `z-index: var(--z-hud)` and therefore its own stacking context —
 *     so this cannot reach past the HUD into the modal screens however the scale moves.
 *   - `#voice-notice` sits on `var(--z-toast)` because it IS a toast, and its own
 *     `--vn-top` is measured off `#score-header` so it can never land on the score plate.
 *
 * NO ACCENT BARS, and `--gold` is not used here: this is neither the primary action nor
 * the current selection. Live speech is `--green` (ready/confirmed), which is the token
 * `.lobby-spk.on` already leans on in the lobby, so one player reads the same in both
 * places.
 */

#voice-hud {
  position: absolute;
  left: var(--vh-left, 20px);
  top: var(--vh-top, 232px);
  max-height: var(--vh-max, 40vh);
  width: max-content;
  max-width: min(232px, 22vw);
  overflow: hidden;
  pointer-events: none;
  /* One above the damage vignette (`--z-fx`), inside #hud's own stacking context. */
  z-index: calc(var(--z-fx) + 1);
  /* An empty panel is not a panel. With no rows there is nothing painted at all, which
   * is also why the non-overlap constraint is trivially satisfied while nobody talks. */
  opacity: 0;
  transition: opacity 140ms linear;
}
#voice-hud.has-rows { opacity: 1; }
#voice-hud.is-off { display: none; }

/* A FULL-SCREEN BOARD OWNS THE SCREEN, and this panel steps out of its way.
 *
 * The scoreboard, the end-of-match board, the killcam, the respawn counter, the
 * spawn-in card and the death panel each take over the frame; a speaker list floating
 * over any of them is the "overlapping HUD elements" complaint in its purest form.
 *
 * It is written as a RELATIONSHIP — "while a board is showing, I am not" — rather than
 * as a z-index or an offset, so it survives any of those elements moving, resizing or
 * changing which corner it lives in. `js/hud.js` already toggles `.hidden` on all six
 * as the single expression of "is this board up", so this rule reads the state that
 * already exists instead of inventing a second one that could drift from it. Nothing in
 * js/voice-hud.js has to know these elements exist, which is the point: a JS rule here
 * would be a list somebody has to remember to extend. */
#hud:has(> #scoreboard:not(.hidden)) #voice-hud,
#hud:has(> #endboard:not(.hidden)) #voice-hud,
#hud:has(> #killcam:not(.hidden)) #voice-hud,
#hud:has(> #respawn:not(.hidden)) #voice-hud,
#hud:has(> #spawnin:not(.hidden)) #voice-hud,
#hud:has(> #death-panel:not(.hidden)) #voice-hud { display: none; }

.vh-list {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
}

.vh-row {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 3px 9px 3px 7px;
  max-width: 100%;
  /* A soft scrim for the same reason the score plate needed one: this HUD sits over a
   * bright desert sky and a name at 12.5px has no contrast to spare. Soft-edged so it
   * reads as the HUD on the scene rather than as a panel with a border. */
  background: rgba(6, 8, 10, 0.58);
  color: var(--ink-2);
  font-family: var(--ui);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  text-shadow: var(--hud-shadow);
  opacity: 0.55;
  transition: opacity 120ms linear, color 120ms linear;
}
.vh-row.is-live { opacity: 1; color: var(--ink); }

.vh-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.vh-dot {
  flex: none;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--ink-4);
  transition: background 120ms linear, box-shadow 120ms linear;
}
.vh-row.is-live .vh-dot {
  background: var(--green);
  box-shadow: 0 0 8px rgba(116, 209, 149, 0.85);
}
/* Your own row reads differently from everybody else's, the same way the scoreboard
 * fills the row that is you. It is a surface difference, not a second colour. */
.vh-row.is-self { background: rgba(18, 23, 26, 0.72); }
.vh-row.is-self .vh-name::after {
  content: ' (YOU)';
  color: var(--ink-3);
  font-size: 10.5px;
  letter-spacing: 0.1em;
}

@media (prefers-reduced-motion: reduce) {
  #voice-hud, .vh-row, .vh-dot { transition: none; }
}

/* ---------------------------------------------------------------------------
 * The master-volume notice.
 *
 * It fires when the voice room opens, on every client, and says two things: the
 * master volume moved, and where to move it back. It is NOT `#toast` — that element
 * has exactly one writer in js/main.js with its own dismissal timer, and a second
 * writer on it is how a message vanishes halfway through being read.
 * --------------------------------------------------------------------------- */
#voice-notice {
  position: fixed;
  left: 50%;
  top: var(--vn-top, 16px);
  transform: translateX(-50%) translateY(-6px);
  z-index: var(--z-toast);
  display: none;
  max-width: min(560px, calc(100vw - 40px));
  padding: 10px 16px 11px;
  background: rgba(10, 13, 15, 0.95);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.6);
  font-family: var(--ui);
  text-align: center;
  pointer-events: auto;
  cursor: pointer;
  opacity: 0;
  transition: opacity 160ms linear, transform 160ms var(--ease, ease);
}
#voice-notice.is-up {
  display: block;
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
#voice-notice .vn-title {
  display: block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--green);
}
#voice-notice .vn-body {
  display: block;
  margin-top: 3px;
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--ink-2);
}

@media (prefers-reduced-motion: reduce) {
  #voice-notice { transition: none; }
}
