/* ============================================================
   Stream Swap — YouTube while queued, real-time while driving
   ============================================================ */

.ss-app {
  height: 100%;
  display: grid;
  grid-template-rows: auto 1fr;
  background: var(--bg);
  color: var(--fg);
}

/* ────────────── top bar additions ────────────── */
/* minmax(0, auto), not auto: an `auto` track refuses to shrink below its
   content, and the pills never wrap - so a wide pill grew the header past the
   viewport instead of giving way, pushing the avatar and Log-out button
   off-screen. minmax(0, ...) lets the middle column yield; the rules below
   decide what gives way inside it. */
.ss-topbar { display: grid; grid-template-columns: 1fr minmax(0, auto) 1fr; align-items: center; gap: 24px; padding: 10px 16px; border-bottom: 1px solid var(--border); background: linear-gradient(180deg, rgba(10,9,8,0.95), rgba(10,9,8,0.7)); }
/* min-width: 0 defeats the default `min-width: auto` on flex items, which is
   what was propagating the pills' intrinsic width up to the grid track. */
.ss-topbar .pills { display: flex; gap: 8px; align-items: center; min-width: 0; }
.ss-topbar .pills > .pill { min-width: 0; }

/* The mod-only robot telemetry pill is the widest thing in the bar, and the
   only one whose width is data-dependent: the AP label falls back to a raw
   17-char BSSID when the AccessPoint table doesn't know it. Ellipsize the AP
   name rather than let it shove the user block off-screen - the full value
   stays in the title attribute.

   WHICH fields are shown at a given width is decided in TopBar.jsx (see
   BP_DROP_*), not here. The separator dots live between fields, so hiding a
   field with `display: none` left a dangling "· " behind - and CSS can't
   renumber separators. Doing it in JS also keeps the shedding scoped to the
   mod pill without :has(), which failed open in the wrong direction: a browser
   without :has() support dropped the shedding rules but kept flex-shrink: 0,
   leaving a non-shrinking pill and no relief at all. */
.ss-topbar .rd-ap { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; max-width: 18ch; }

/* The telemetry pill stops giving way; the shedding in TopBar.jsx pays for it.
   Without this the flex box squeezes the pill and silently clips the field that
   sits last - the throttle badge - which is the one field that must never
   vanish. */
.ss-topbar .robot-debug { flex-shrink: 0; }
.ss-topbar .pill-muted { color: var(--dim); }
.ss-topbar .pill.status.is-realtime { color: #fff; }
.ss-topbar .pill.status.is-realtime .dot { background: var(--ok); box-shadow: 0 0 10px var(--ok); animation: pulse 1.6s ease-in-out infinite; }
.ss-topbar .pill.status strong { font-weight: 600; }
.ss-state-toggle {
  position: absolute;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 7;
  display: inline-flex;
  gap: 0;
  padding: 3px;
  background: rgba(10,9,8,0.78);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: 0 8px 24px -8px rgba(0,0,0,0.6);
}
.ss-state-toggle button { background: transparent; border: 0; color: var(--dim); font-family: inherit; font-size: 11px; padding: 5px 11px; border-radius: 999px; cursor: pointer; transition: all 0.15s; white-space: nowrap; }
.ss-state-toggle button:hover { color: var(--fg-2); }
.ss-state-toggle button.is-active { background: var(--fg); color: #1a0e0a; font-weight: 600; }
.ss-state-toggle .mono { font-size: 10px; letter-spacing: 0.04em; }

/* ────────────── main grid ────────────── */
.ss-main {
  display: grid;
  grid-template-columns: 1fr 360px;
  gap: 0;
  min-height: 0;
  position: relative;
}
.ss-main.is-fullbleed { grid-template-columns: 1fr; }

/* ────────────── stage ────────────── */
.ss-stage {
  position: relative;
  background: #000;
  overflow: hidden;
  min-height: 0;
}

.ss-stage .yt-frame,
.ss-stage .rt-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transition: opacity 0.5s ease;
}
.ss-stage .yt-frame { z-index: 1; }
.ss-stage .rt-frame { z-index: 2; opacity: 0; }
.ss-stage.is-driving .rt-frame { opacity: 1; }
.ss-stage.is-driving .yt-frame { opacity: 0; }

.yt-iframe { width: 100%; height: 100%; border: 0; display: block; }
.yt-fallback { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; filter: brightness(0.92) contrast(1.08) saturate(1.05); }

.rt-feed { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; filter: brightness(0.92) contrast(1.08) saturate(1.05); }
.rt-vignette {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(0,0,0,0.45) 0%, transparent 18%, transparent 70%, rgba(0,0,0,0.65) 100%);
}

/* HUD on driving feed */
.rt-hud { position: absolute; color: rgba(255,255,255,0.9); text-shadow: 0 1px 3px rgba(0,0,0,0.7); pointer-events: none; }
.rt-hud-tl { top: 14px; left: 18px; font-size: 12px; font-family: var(--mono); }
.rt-hud-tr { top: 14px; right: 18px; text-align: right; display: flex; flex-direction: column; gap: 3px; font-family: var(--mono); font-size: 11px; align-items: flex-end; }

/* ────────────── source / latency badge ────────────── */
.feed-badge {
  position: absolute;
  bottom: 14px;
  left: 14px;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 6px 8px;
  background: rgba(10,9,8,0.78);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  font-size: 11px;
  color: var(--fg-2);
  font-family: var(--mono);
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.feed-badge .feed-src { color: var(--fg); font-weight: 600; }
.feed-badge .feed-sep { color: var(--dim); }
.feed-badge.is-realtime { background: rgba(126,210,122,0.12); border-color: rgba(126,210,122,0.35); color: var(--ok); }
.feed-badge.is-realtime .feed-src { color: var(--ok); }
.feed-badge .blink { width: 6px; height: 6px; border-radius: 50%; background: currentColor; animation: blink 1.2s ease-in-out infinite; }
@keyframes blink { 50% { opacity: 0.35; } }

/* delay disclaimer when watching */
.feed-disclaimer {
  position: absolute;
  bottom: 14px;
  right: 14px;
  z-index: 4;
  font-family: var(--mono);
  font-size: 10px;
  color: rgba(255,255,255,0.5);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-shadow: 0 1px 2px rgba(0,0,0,0.7);
  max-width: 260px;
  text-align: right;
  line-height: 1.4;
}

/* ────────────── queue panel (spectating) ────────────── */
.queue-panel {
  position: absolute;
  left: 24px;
  bottom: 24px;
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 320px;
  padding: 14px;
  /* 0.92 alpha so the panel reads as solidly opaque regardless of
     the stream background. The earlier 0.72 looked fine over dark
     scenes but turned semi-transparent over a snowy bright scene -
     SignedOutPanel and EmptyQueuePanel both share this rule, so a
     bright background made the SignedOut copy hard to read while
     the EmptyQueue copy stayed legible by luck of staging. */
  background: rgba(10,9,8,0.92);
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.queue-panel .qp-eyebrow { display: flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em; color: var(--dim); text-transform: uppercase; white-space: nowrap; }
.queue-panel .qp-eyebrow .blink { background: var(--ok); }
.queue-panel .qp-state { font-size: 18px; font-weight: 600; line-height: 1.25; color: var(--fg); }
.queue-panel .qp-sub { font-size: 13px; color: var(--fg-2); line-height: 1.4; }
.queue-panel .qp-sub strong { color: var(--fg); font-weight: 600; }
.queue-panel .qp-list { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; padding-top: 10px; border-top: 1px solid var(--border); }
.queue-panel .qp-row { display: flex; align-items: center; gap: 9px; padding: 5px 0; font-size: 12px; color: var(--fg-2); min-width: 0; }
.queue-panel .qp-row.me { color: var(--fg); }
.queue-panel .qp-pos { width: 18px; flex: none; font-family: var(--mono); font-size: 10px; color: var(--dim); }
.queue-panel .qp-row.me .qp-pos { color: var(--accent); font-weight: 600; }
/* min-width:0 lets a flex child shrink below its content size so the
   overflow-ellipsis actually fires; without it, a long username
   forces the row to overflow horizontally and the .qp-eta column
   gets pushed outside the panel (see the "driving" leak bug). */
.queue-panel .qp-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.queue-panel .qp-row.me .qp-name::after { content: " · you"; color: var(--accent); font-size: 11px; }
.queue-panel .qp-eta { flex: none; font-family: var(--mono); font-size: 10px; color: var(--dim); white-space: nowrap; }
.queue-panel .qp-cta-row { display: flex; gap: 8px; margin-top: 4px; }
.queue-panel .qp-cta {
  flex: 1;
  background: var(--accent);
  color: #1a0e0a;
  border: 0;
  font-family: inherit;
  font-weight: 600;
  font-size: 13px;
  padding: 10px 12px;
  border-radius: 10px;
  cursor: pointer;
  transition: filter 0.15s, transform 0.06s;
}
.queue-panel .qp-cta:hover { filter: brightness(1.1); }
.queue-panel .qp-cta:active { transform: scale(0.98); }
.queue-panel .qp-cta.secondary { background: rgba(255,255,255,0.06); color: var(--fg); border: 1px solid var(--border-2); }
.queue-panel .qp-cta.secondary:hover { background: rgba(255,255,255,0.1); }

/* empty-queue open-invitation variant — wider, friendlier */
.queue-panel.is-invite { width: 340px; }
.queue-panel.is-invite .qp-state { font-size: 22px; line-height: 1.1; }
.queue-panel .qp-eyebrow.ok { color: var(--ok); }
.queue-panel .qp-eyebrow.ok .blink { background: var(--ok); box-shadow: 0 0 8px var(--ok); }
.queue-panel .qp-cta-big {
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 18px;
  font-size: 15px;
  border-radius: 12px;
  box-shadow: 0 12px 30px -8px var(--accent);
  margin-top: 4px;
}
.queue-panel.is-invite .yt-btn-block { padding: 13px 14px; font-size: 14px; }

/* ────────────── up-next readiness modal ────────────── */
.upnext-modal {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 9;
  width: min(420px, calc(100% - 48px));
  padding: 28px 28px 20px;
  background: rgba(10,9,8,0.92);
  backdrop-filter: blur(24px) saturate(140%);
  -webkit-backdrop-filter: blur(24px) saturate(140%);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 18px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 8px;
  box-shadow: 0 30px 80px -10px rgba(0,0,0,0.7), 0 0 0 6px rgba(226,106,77,0.08);
  color: var(--accent);
  animation: unPop 0.3s ease-out;
}
.upnext-modal.is-urgent {
  color: #ff6f4e;
  box-shadow: 0 30px 80px -10px rgba(0,0,0,0.7), 0 0 0 6px rgba(255,80,52,0.18);
  animation: unPop 0.3s ease-out, unPulse 0.9s ease-in-out infinite;
}
.upnext-modal.is-acked {
  color: var(--ok);
  box-shadow: 0 30px 80px -10px rgba(0,0,0,0.7), 0 0 0 6px rgba(126,210,122,0.18);
  animation: unPop 0.3s ease-out;
}
.upnext-modal.is-acked .un-ready {
  background: var(--ok);
  box-shadow: 0 12px 30px -8px var(--ok);
  opacity: 0.95;
  cursor: default;
}
.upnext-modal.is-acked .un-check {
  position: absolute;
  color: var(--ok);
  animation: checkPop 0.4s ease-out;
}
.upnext-modal.is-acked .un-ring.spinner {
  animation: spin 1.4s linear infinite;
  transform-origin: 50% 50%;
}
.upnext-modal.is-acked .un-num,
.upnext-modal.is-acked .un-headline { color: var(--fg); }
@keyframes checkPop { from { transform: scale(0.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes unPop { from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); } to { opacity: 1; transform: translate(-50%, -50%) scale(1); } }
@keyframes unPulse { 50% { box-shadow: 0 30px 80px -10px rgba(0,0,0,0.7), 0 0 0 10px rgba(255,80,52,0.28); } }

.upnext-modal .un-eyebrow {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: currentColor;
  margin-bottom: 4px;
}
.upnext-modal .un-eyebrow .blink { width: 7px; height: 7px; border-radius: 50%; background: currentColor; box-shadow: 0 0 10px currentColor; animation: blink 1.2s ease-in-out infinite; }
.upnext-modal .un-headline {
  font-size: 26px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--fg);
  line-height: 1.1;
}
.upnext-modal .un-sub {
  font-size: 13px;
  color: var(--fg-2);
  line-height: 1.45;
  max-width: 330px;
  margin: 2px 0 10px;
}

.upnext-modal .un-timer-wrap {
  position: relative;
  width: 140px;
  height: 140px;
  display: grid;
  place-items: center;
  margin: 4px 0 14px;
  color: var(--accent);
}
.upnext-modal.is-urgent .un-timer-wrap { color: #ff6f4e; }
.upnext-modal.is-acked .un-timer-wrap { color: var(--ok); }
.upnext-modal .un-ring { position: absolute; inset: 0; }
.upnext-modal .un-timer { display: flex; align-items: baseline; gap: 4px; font-family: var(--mono); }
.upnext-modal .un-num { font-size: 56px; font-weight: 600; color: var(--fg); line-height: 1; font-variant-numeric: tabular-nums; }
.upnext-modal .un-unit { font-size: 13px; color: var(--dim); letter-spacing: 0.06em; text-transform: uppercase; }
.upnext-modal.is-urgent .un-num { color: #ff8e75; }

.upnext-modal .un-ready {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 14px 18px;
  background: var(--accent);
  border: 0;
  border-radius: 12px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  color: #1a0e0a;
  cursor: pointer;
  transition: transform 0.06s, filter 0.15s, box-shadow 0.15s, background 0.15s;
  box-shadow: 0 12px 30px -8px var(--accent);
}
.upnext-modal.is-urgent .un-ready {
  background: #ff6f4e;
  box-shadow: 0 12px 30px -8px #ff6f4e;
}
.upnext-modal .un-ready > * { color: #1a0e0a; }
.upnext-modal .un-ready:hover { filter: brightness(1.08); }
.upnext-modal .un-ready:active { transform: scale(0.98); }

.upnext-modal .un-skip {
  background: transparent;
  border: 0;
  color: var(--dim);
  font-family: inherit;
  font-size: 12px;
  padding: 6px 10px;
  cursor: pointer;
  margin-top: 6px;
}
.upnext-modal .un-skip:hover { color: var(--fg-2); }

.upnext-modal .un-hint { font-size: 10px; color: var(--dim); letter-spacing: 0.04em; margin-top: 2px; }
.upnext-modal .un-hint kbd {
  font-family: var(--mono);
  font-size: 10px;
  padding: 1px 6px;
  background: rgba(255,255,255,0.06);
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: 4px;
  color: var(--fg-2);
}

/* ────── Chat-ready handshake tones ──────
   The modal now drives identity verification through stream chat;
   tone classes layer on top of the base modal:
     .is-default - waiting for the chat token to arrive
     .is-warn    - timer running low / no token seen yet (late nudge)
     .is-danger  - token posted from a different YouTube account
     .is-ok      - acked (same shape as legacy is-acked) */
.upnext-modal.is-warn {
  color: var(--warn);
  box-shadow: 0 30px 80px -10px rgba(0,0,0,0.7), 0 0 0 6px rgba(240,166,74,0.18);
  border-color: rgba(240,166,74,0.32);
}
.upnext-modal.is-warn .un-timer-wrap,
.upnext-modal.is-warn .un-num { color: #f6c280; }
.upnext-modal.is-warn .un-ready.is-fallback {
  background: var(--warn);
  box-shadow: 0 12px 30px -8px var(--warn);
}
.upnext-modal.is-danger {
  color: #ff8a7a;
  box-shadow: 0 30px 80px -10px rgba(0,0,0,0.7), 0 0 0 6px rgba(229,74,74,0.20);
  border-color: rgba(229,74,74,0.36);
}
.upnext-modal.is-danger .un-timer-wrap,
.upnext-modal.is-danger .un-num { color: #ff8a7a; }
.upnext-modal.is-ok { /* same shape as legacy is-acked */
  color: var(--ok);
  box-shadow: 0 30px 80px -10px rgba(0,0,0,0.7), 0 0 0 6px rgba(126,210,122,0.18);
}

/* The token row - hero of the waiting state. The token itself is a
   pill so it reads as something you copy/type, not a count. */
.upnext-modal .un-token-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  width: 100%;
  background: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.015));
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 12px;
  margin: 2px 0;
}
.upnext-modal .un-token-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dim);
  white-space: nowrap;
}
.upnext-modal .un-token {
  flex: 1;
  font-family: var(--mono);
  font-size: 24px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--fg);
  background: rgba(226,106,77,0.14);
  border: 1px solid rgba(226,106,77,0.4);
  border-radius: 8px;
  padding: 6px 14px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 0 0 4px rgba(226,106,77,0.06);
}
.upnext-modal.is-warn .un-token {
  background: rgba(240,166,74,0.12);
  border-color: rgba(240,166,74,0.4);
  color: #f6c280;
  box-shadow: 0 0 0 4px rgba(240,166,74,0.06);
}
.upnext-modal .un-token-arrow { color: var(--dim); flex: none; }
.upnext-modal .un-token-inline {
  font-family: var(--mono);
  font-size: 0.92em;
  letter-spacing: 0.04em;
  color: var(--accent);
  background: rgba(226,106,77,0.12);
  border: 1px solid rgba(226,106,77,0.32);
  padding: 1px 8px;
  border-radius: 5px;
  font-variant-numeric: tabular-nums;
}

/* Identity card - reinforces "we know who you signed in as" so a
   mismatch later is legible. */
.upnext-modal .un-identity {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 12px;
  background: rgba(255,255,255,0.025);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 10px;
  text-align: left;
  margin-top: 6px;
}
.upnext-modal .un-id-icon {
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--accent);
  color: #1a0e0a;
  display: grid; place-items: center;
  font-size: 12px; font-weight: 700;
  flex: none;
}
.upnext-modal.is-warn .un-id-icon { background: var(--warn); }
.upnext-modal.is-danger .un-id-icon { background: #e54a4a; color: #fff; }
.upnext-modal .un-id-info { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.upnext-modal .un-id-label {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--dim);
}
.upnext-modal .un-id-name { font-size: 13px; color: var(--fg); font-weight: 500; }
.upnext-modal .un-id-handle { color: var(--dim); font-weight: 400; }

/* Mismatch-state "sign in as the chat account" button - red primary
   that sits above the secondary "drive as me anyway" fallback. */
.upnext-modal .un-ready-danger {
  background: #e54a4a;
  color: #fff;
  box-shadow: 0 12px 30px -8px #e54a4a;
}
.upnext-modal .un-ready-danger > * { color: #fff; }

/* Disabled "Still waiting on chat" indicator shown in the late-nudge
   state. There's no backdoor - this is just a visual cue that we're
   actively polling and the only thing left to do is post the token. */
.upnext-modal .un-still-waiting {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 12px 14px;
  background: rgba(240,166,74,0.10);
  border: 1px solid rgba(240,166,74,0.32);
  border-radius: 10px;
  color: #f6c280;
  font-size: 13px;
  font-weight: 500;
  font-family: inherit;
  cursor: default;
}
.upnext-modal .un-spinner {
  width: 14px; height: 14px;
  flex: none;
  border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.25);
  border-top-color: #f6c280;
  animation: unSpin 0.9s linear infinite;
}
@keyframes unSpin { to { transform: rotate(360deg); } }

/* Secondary "Drive as me anyway" button - clearly demoted vs the
   primary "Sign in as them" so the user lands on the safer recovery
   first. Mismatch-only. */
.upnext-modal .un-ready-secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 11px 14px;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 10px;
  color: var(--fg);
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s;
  margin-top: 8px;
}
.upnext-modal .un-ready-secondary:hover {
  background: rgba(255,255,255,0.1);
}

/* Foot notes - tradeoff / no-exceptions copy beneath the actions.
   Always small, dim, and behind the primary affordance hierarchy. */
.upnext-modal .un-foot-note {
  font-size: 11px;
  line-height: 1.45;
  color: var(--dim);
  text-align: center;
  margin-top: 8px;
  max-width: 340px;
}
.upnext-modal .un-foot-note strong {
  color: var(--fg-2);
  font-weight: 600;
}

/* ────────────── status banner (degraded / offline / failure modes) ────────────── */
.status-banner {
  position: absolute;
  left: 50%;
  top: 20px;
  transform: translateX(-50%);
  z-index: 8;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px 10px 12px;
  max-width: min(520px, calc(100% - 48px));
  border-radius: 10px;
  background: rgba(10,9,8,0.92);
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  border: 1px solid var(--border);
  box-shadow: 0 18px 40px -10px rgba(0,0,0,0.5);
  color: var(--fg);
  animation: unPop 0.25s ease-out;
}
.status-banner.is-warn { border-color: rgba(240,166,74,0.45); }
.status-banner.is-warn .sb-icon { color: var(--warn); }
.status-banner.is-error { border-color: rgba(229,74,74,0.5); box-shadow: 0 18px 40px -10px rgba(229,74,74,0.18); }
.status-banner.is-error .sb-icon { color: #ff8a7a; }
.status-banner .sb-icon { flex: none; display: grid; place-items: center; }
.status-banner .sb-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.status-banner .sb-title { font-size: 13px; font-weight: 600; color: var(--fg); }
.status-banner .sb-sub { font-size: 11.5px; color: var(--fg-2); line-height: 1.4; }
.status-banner .sb-action {
  flex: none;
  background: rgba(255,255,255,0.06);
  border: 1px solid var(--border-2);
  color: var(--fg);
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  padding: 6px 11px;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.15s;
  white-space: nowrap;
}
.status-banner .sb-action:hover { background: rgba(255,255,255,0.12); border-color: rgba(255,255,255,0.22); }
.status-banner .sb-pulse {
  position: absolute;
  inset: -1px;
  border-radius: 10px;
  border: 1px solid rgba(229,74,74,0.5);
  pointer-events: none;
  animation: sbPulse 1.6s ease-in-out infinite;
}
@keyframes sbPulse {
  0%,100% { box-shadow: 0 0 0 0 rgba(229,74,74,0.4); }
  50% { box-shadow: 0 0 0 8px rgba(229,74,74,0); }
}

/* ────────────── robot offline placeholder ────────────── */
.ss-stage.is-offline .rt-frame { opacity: 0; }
.ss-stage.is-offline .yt-frame { opacity: 0; }
.rt-offline {
  position: absolute; inset: 0;
  z-index: 3;
  background: #0a0908;
  display: grid;
  place-items: center;
  overflow: hidden;
}
.rt-static {
  position: absolute; inset: 0;
  opacity: 0.12;
  background-image:
    repeating-linear-gradient(0deg, rgba(255,255,255,0.5) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.3) 0 1px, transparent 1px 2px);
  animation: staticShift 0.18s steps(2) infinite;
  mix-blend-mode: screen;
}
@keyframes staticShift {
  0% { transform: translate(0,0); }
  100% { transform: translate(-2px,1px); }
}
.rt-offline-inner {
  position: relative;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  color: var(--fg-2);
  z-index: 2;
}
.rt-offline-icon {
  width: 72px; height: 72px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(229,74,74,0.08);
  border: 1px solid rgba(229,74,74,0.3);
  color: var(--fg-2);
}
.rt-offline-title {
  font-size: 22px;
  font-weight: 600;
  color: var(--fg);
  letter-spacing: -0.005em;
}
.rt-offline-sub {
  font-size: 13px;
  color: var(--fg-2);
  max-width: 340px;
  line-height: 1.4;
}

/* ────────────── control panel: degraded / offline variants ────────────── */
.ss-control-panel.is-degraded {
  border-color: rgba(240,166,74,0.35);
}
.ss-control-panel.is-degraded .cp-state {
  background: rgba(240,166,74,0.12);
  color: #f6c280;
}
.ss-control-panel.is-degraded .cp-state .dot.warn { background: var(--warn); box-shadow: 0 0 8px var(--warn); }

.ss-control-panel.is-offline {
  border-color: rgba(229,74,74,0.35);
  filter: grayscale(0.2);
}
.ss-control-panel.is-offline .cp-state {
  background: rgba(229,74,74,0.12);
  color: #ff8e75;
}
.ss-control-panel.is-offline .cp-state .dot.warn { background: #ff6f4e; }
.ss-control-panel.is-offline .dpad-btn,
.ss-control-panel.is-reconnecting .dpad-btn { opacity: 0.4; cursor: not-allowed; }
.ss-control-panel.is-offline .dpad-btn:hover,
.ss-control-panel.is-reconnecting .dpad-btn:hover { background: linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.02)); }

/* Drive-blocked variant (no GPS fix / no geofence). Amber like .is-degraded
   (a fix or a geofence is coming, not a fault). The buttons are dimmed to
   match offline/reconnecting, but NOT HTML-disabled - a press still reaches
   onPress, which answers with the reason-matched toast instead of a silently-
   dropped command - so the hover override keeps a dimmed button from lighting
   up under the cursor as if it were live. */
.ss-control-panel.is-driveblocked { border-color: rgba(240,166,74,0.35); }
.ss-control-panel.is-driveblocked .cp-state { background: rgba(240,166,74,0.12); color: #f6c280; }
.ss-control-panel.is-driveblocked .cp-state .dot.warn { background: var(--warn); box-shadow: 0 0 8px var(--warn); }
.ss-control-panel.is-driveblocked .dpad-btn { opacity: 0.4; cursor: not-allowed; }
.ss-control-panel.is-driveblocked .dpad-btn:hover { background: linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.02)); }
/* Reason glyph (satellite / map) above the scrim's default-amber spinner + label. */
.dpad-lock-sat { font-size: 20px; line-height: 1; filter: drop-shadow(0 0 8px rgba(240,166,74,0.45)); }

/* D-pad lock scrim (issue #121). Sits over the button grid whenever
   the pad is locked out (WS reconnecting / robot offline) so a
   disabled pad is unmistakable, not just a slightly dimmer button.
   pointer-events:none - the buttons underneath are already disabled;
   the scrim is purely a visual signal and must not itself eat clicks
   once the pad comes back. .dpad is position:relative (styles.css). */
.dpad-lock {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: 12px;
  background: rgba(10,9,8,0.62);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  pointer-events: none;
  text-align: center;
}
.dpad-lock-spinner {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid rgba(240,166,74,0.25);
  border-top-color: var(--warn);
  animation: spin 0.9s linear infinite;
}
.dpad-lock.is-offline .dpad-lock-spinner {
  border-color: rgba(229,74,74,0.25);
  border-top-color: #ff6f4e;
  animation: none;
}
.dpad-lock-label {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--warn);
}
.dpad-lock.is-offline .dpad-lock-label { color: #ff8e75; }

.ss-control-panel.is-reconnecting {
  border-color: rgba(240,166,74,0.35);
}
.ss-control-panel.is-reconnecting .cp-state {
  background: rgba(240,166,74,0.12);
  color: #f6c280;
}
.ss-control-panel.is-reconnecting .cp-state .dot.warn { background: var(--warn); box-shadow: 0 0 8px var(--warn); animation: blink 0.9s ease-in-out infinite; }

.rt-offline-icon.is-reconnecting {
  background: rgba(240,166,74,0.1);
  border-color: rgba(240,166,74,0.35);
  color: var(--warn);
}
.rt-offline-icon.is-reconnecting svg { animation: spin 1.4s linear infinite; transform-origin: 50% 50%; }

/* ────────────── topbar pill: degraded ────────────── */
.ss-topbar .pill.status.is-degraded { color: var(--warn); }
.ss-topbar .pill.status.is-degraded .dot { background: var(--warn); box-shadow: 0 0 10px var(--warn); animation: pulse 1.6s ease-in-out infinite; }
.ss-topbar .pill.status.is-down { color: #ff8a7a; }
.ss-topbar .pill.status.is-down .dot { background: #ff6f4e; }

/* ────────────── end-of-turn wrap-up modal ────────────── */
.endingturn-modal {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 9;
  width: min(440px, calc(100% - 48px));
  padding: 28px 28px 22px;
  background: rgba(10,9,8,0.92);
  backdrop-filter: blur(24px) saturate(140%);
  -webkit-backdrop-filter: blur(24px) saturate(140%);
  border: 1px solid rgba(126,210,122,0.28);
  border-radius: 18px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 8px;
  color: var(--ok);
  box-shadow: 0 30px 80px -10px rgba(0,0,0,0.7), 0 0 0 6px rgba(126,210,122,0.10);
  animation: unPop 0.3s ease-out;
}
.endingturn-modal .et-eyebrow {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ok);
  margin-bottom: 4px;
}
.endingturn-modal .et-eyebrow .blink {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--ok); box-shadow: 0 0 10px var(--ok);
  animation: blink 1.6s ease-in-out infinite;
}
.endingturn-modal .et-headline {
  font-size: 30px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--fg);
  line-height: 1.05;
  margin-top: 2px;
}
.endingturn-modal .et-sub {
  font-size: 13.5px;
  color: var(--fg-2);
  line-height: 1.5;
  max-width: 340px;
  margin: 6px 0 18px;
}
.endingturn-modal .et-buttons {
  display: flex;
  gap: 10px;
  width: 100%;
}
.endingturn-modal .et-primary {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 13px 18px;
  background: var(--accent);
  border: 0;
  border-radius: 12px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  color: #1a0e0a;
  cursor: pointer;
  transition: transform 0.06s, filter 0.15s;
  box-shadow: 0 12px 30px -8px var(--accent);
}
.endingturn-modal .et-primary:hover { filter: brightness(1.08); }
.endingturn-modal .et-primary:active { transform: scale(0.98); }
.endingturn-modal .et-secondary {
  padding: 13px 22px;
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--border-2);
  border-radius: 12px;
  font-family: inherit;
  font-size: 14px;
  color: var(--fg-2);
  cursor: pointer;
  transition: all 0.15s;
}
.endingturn-modal .et-secondary:hover { background: rgba(255,255,255,0.1); color: var(--fg); }
.endingturn-modal .et-auto {
  font-size: 10px;
  color: var(--dim);
  letter-spacing: 0.04em;
  margin-top: 12px;
}

/* ────────────── ending-soon warning on driving panel ────────────── */
.ss-control-panel.is-ending-soon {
  border-color: rgba(255,80,52,0.4);
  box-shadow: var(--shadow), 0 0 0 1px rgba(255,80,52,0.25);
  animation: endSoonPulse 1.2s ease-in-out infinite;
}
.ss-control-panel.is-ending-soon .cp-state {
  background: rgba(255,80,52,0.14);
  border-color: rgba(255,80,52,0.3);
  color: #ff8e75;
}
.ss-control-panel.is-ending-soon .cp-state .dot.warn {
  background: #ff6f4e;
  box-shadow: 0 0 8px #ff6f4e;
  animation: blink 0.9s ease-in-out infinite;
}
@keyframes endSoonPulse {
  50% { box-shadow: var(--shadow), 0 0 0 1px rgba(255,80,52,0.4), 0 0 24px -2px rgba(255,80,52,0.35); }
}

/* ────────────── skipped toast ────────────── */
.skipped-toast {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 9;
  width: min(420px, calc(100% - 48px));
  padding: 18px 22px;
  background: rgba(10,9,8,0.92);
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  border: 1px solid rgba(229,74,74,0.3);
  border-radius: 14px;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  color: var(--fg-2);
  box-shadow: 0 20px 50px -10px rgba(0,0,0,0.6);
  animation: unPop 0.25s ease-out;
}
.skipped-toast > svg { flex: none; color: #ff8a7a; margin-top: 2px; }
.skipped-toast .st-title { font-size: 14px; font-weight: 600; color: var(--fg); }
.skipped-toast .st-sub { font-size: 12px; color: var(--fg-2); line-height: 1.45; margin-top: 3px; }

/* ────────────── controls overlay (driving) ────────────── */
.ss-control-panel {
  position: absolute;
  left: 24px;
  bottom: 24px;
  z-index: 5;
  /* 348, not 320, so the mod-takeover head fits on one line: the
     "Mod driving / held 0:30" status pill (~189px) plus the
     "Return wheel" hold button (~108px) plus their 10px gap need ~307px
     of content width, which 320px (290px after padding+border) couldn't
     give — the pill wrapped. 348 (318px content) leaves ~11px slack,
     enough that even a double-digit hold timer ("held 12:30", a wider
     pill) stays on one line. Mobile overrides this to full-width. */
  width: 348px;
  padding: 14px;
  border-radius: var(--radius);
  background: rgba(10,9,8,0.72);
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* ────────────── chat: floating glass card ────────────── */
.ss-chat-float {
  position: absolute;
  right: 24px;
  bottom: 24px;
  width: 360px;
  max-height: calc(100% - 48px);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  z-index: 12;
}
/* Chat FAB needs to sit above the YouTube iframe in the stage,
   which can otherwise float to its own paint layer. */
.chat-fab { z-index: 12; }
.ss-chat-float .chat-resize {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 10px;
  cursor: ns-resize;
  display: flex; align-items: center; justify-content: center;
  z-index: 2;
}
.ss-chat-float .chat-resize-grip {
  width: 36px; height: 3px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
  transition: background 0.15s;
}
.ss-chat-float .chat-resize:hover .chat-resize-grip { background: rgba(255,255,255,0.35); }

.ss-chat-frame-wrap {
  flex: 1;
  min-height: 0;
  position: relative;
  background: #0f0f0f;
  overflow: hidden;
}
.ss-chat-iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  background: #0f0f0f;
  color-scheme: dark;
}

/* TTS notice strip shown while driving — sits below the chat iframe,
   right where the driver's eye lands as they go to type. */
.ss-tts-notice {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: linear-gradient(180deg, rgba(126,210,122,0.13), rgba(126,210,122,0.06));
  border-top: 1px solid rgba(126,210,122,0.22);
  color: var(--fg);
  position: relative;
}
.ss-tts-notice::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--ok);
  box-shadow: 0 0 12px var(--ok);
}
.ss-tts-notice > svg { flex: none; color: var(--ok); }
.ss-tts-notice-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.ss-tts-notice-title { font-size: 12.5px; font-weight: 600; color: var(--fg); letter-spacing: 0.005em; }
.ss-tts-notice-sub { font-size: 11px; color: var(--fg-2); line-height: 1.35; }
.ss-chat-head {
  padding: 11px 12px 10px 14px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  background: rgba(0,0,0,0.18);
}
.ss-chat-head .ch-title { font-size: 13px; font-weight: 600; letter-spacing: 0.01em; white-space: nowrap; }
.ss-chat-head .ch-source {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: 10px;
  color: var(--dim); letter-spacing: 0.04em; text-transform: uppercase;
  white-space: nowrap;
}
.ss-chat-head .ch-source-dot { width: 6px; height: 6px; border-radius: 50%; background: #ff4d4d; animation: blink 1.6s ease-in-out infinite; }

.ss-chat-toolbar {
  display: flex; align-items: center; gap: 6px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  background: rgba(0,0,0,0.2);
}
.ss-chat-pill {
  font-family: var(--mono); font-size: 10px;
  padding: 3px 8px; border-radius: 999px;
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--border);
  color: var(--fg-2);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}
.ss-chat-pill.live { color: var(--ok); border-color: rgba(126,210,122,0.3); background: rgba(126,210,122,0.08); }
.ss-chat-count { font-family: var(--mono); font-size: 11px; color: var(--dim); margin-left: auto; white-space: nowrap; }
.ss-chat-count strong { color: var(--fg-2); font-weight: 500; }

.ss-chat-list {
  flex: 1;
  overflow-y: auto;
  padding: 8px 4px 8px 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  scroll-behavior: smooth;
}
.ss-chat-list::-webkit-scrollbar { width: 6px; }
.ss-chat-list::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 999px; }

/* chat message row */
.ss-msg {
  display: flex;
  gap: 8px;
  padding: 5px 8px;
  font-size: 13px;
  line-height: 1.45;
  border-radius: 6px;
  word-wrap: break-word;
  align-items: baseline;
}
.ss-msg:hover { background: rgba(255,255,255,0.025); }
.ss-msg.is-you { background: rgba(226,106,77,0.05); }
.ss-msg .ss-msg-time { flex: none; font-family: var(--mono); font-size: 9px; color: var(--dim); width: 28px; padding-top: 2px; opacity: 0.7; }
.ss-msg .ss-msg-body { flex: 1; min-width: 0; }
.ss-msg .ss-msg-badges { display: inline-flex; gap: 3px; vertical-align: middle; margin-right: 4px; }
.ss-badge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px;
  vertical-align: middle;
  border-radius: 3px;
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0;
}
.ss-badge.member { background: var(--accent); color: #1a0e0a; }
.ss-badge.sub { background: rgba(126,210,122,0.25); color: var(--ok); border: 1px solid rgba(126,210,122,0.5); }
.ss-badge.mod { background: rgba(78,163,226,0.25); color: #6cb6e9; border: 1px solid rgba(78,163,226,0.5); }
.ss-badge.owner { background: #f0a64a; color: #1a0e0a; }
.ss-msg .ss-msg-user { font-weight: 600; color: var(--fg); margin-right: 5px; }
.ss-msg.is-you .ss-msg-user { color: var(--accent); }
.ss-msg .ss-msg-text { color: var(--fg-2); }
.ss-msg .ss-msg-text .em { font-size: 16px; vertical-align: -2px; }

/* super chat */
.ss-superchat {
  margin: 4px 8px;
  padding: 10px 12px;
  border-radius: 10px;
  background: linear-gradient(180deg, var(--sc-color), var(--sc-color-dark));
  color: #1a0e0a;
  display: flex;
  flex-direction: column;
  gap: 4px;
  border: 1px solid rgba(0,0,0,0.12);
  box-shadow: 0 2px 0 rgba(0,0,0,0.08), 0 8px 20px -10px rgba(0,0,0,0.4);
}
.ss-superchat .sc-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12px; font-weight: 600; }
.ss-superchat .sc-user { display: inline-flex; align-items: center; gap: 6px; }
.ss-superchat .sc-amount { font-family: var(--mono); font-weight: 700; font-size: 13px; }
.ss-superchat .sc-text { font-size: 13px; line-height: 1.4; color: rgba(26,14,10,0.92); }
.ss-superchat .sc-avatar { width: 18px; height: 18px; border-radius: 50%; background: rgba(0,0,0,0.18); display: grid; place-items: center; font-size: 10px; font-weight: 700; }

/* system message */
.ss-sys {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 12px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--dim);
}
.ss-sys::before, .ss-sys::after { content: ""; flex: 1; height: 1px; background: var(--border); }

/* emote-only spam line */
.ss-spam {
  padding: 3px 12px;
  font-size: 18px;
  letter-spacing: 0.05em;
  color: var(--fg-2);
}

/* chat compose */
.ss-chat-compose {
  border-top: 1px solid var(--border);
  background: rgba(0,0,0,0.25);
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ss-mode-toggle { display: flex; gap: 4px; align-items: center; }
.ss-mode-btn {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 6px 10px;
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.03);
  color: var(--dim);
  border-radius: 8px;
  font-family: inherit;
  font-size: 11px;
  cursor: pointer;
  transition: all 0.15s;
  white-space: nowrap;
}
.ss-mode-btn:hover { color: var(--fg-2); border-color: var(--border-2); }
.ss-mode-btn.is-active { color: var(--fg); background: rgba(226,106,77,0.12); border-color: rgba(226,106,77,0.4); }
.ss-mode-btn.is-active.robot-mode { background: rgba(126,210,122,0.12); border-color: rgba(126,210,122,0.4); color: var(--ok); }
.ss-mode-btn svg { flex: none; }

.ss-compose-row { display: flex; gap: 8px; }
.ss-compose-row input {
  flex: 1;
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--border);
  color: var(--fg);
  border-radius: 8px;
  padding: 9px 12px;
  font-family: inherit;
  font-size: 13px;
  outline: none;
  transition: border-color 0.15s, background 0.15s;
}
.ss-compose-row input::placeholder { color: var(--dim); }
.ss-compose-row input:focus { border-color: var(--accent); background: rgba(255,255,255,0.08); }
.ss-compose-row input.robot-mode:focus { border-color: var(--ok); }
.ss-compose-row .ss-send {
  background: var(--accent);
  color: #1a0e0a;
  border: 0;
  padding: 0 14px;
  border-radius: 8px;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.ss-compose-row .ss-send.robot { background: var(--ok); }
.ss-compose-row .ss-send:hover { filter: brightness(1.1); }

.ss-tts-helper {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--ok);
  padding: 0 2px;
  letter-spacing: 0.04em;
  display: flex; align-items: center; gap: 6px;
}
.ss-tts-helper .blink { background: var(--ok); }

/* ────────────── transition shimmer ────────────── */
.swap-flash {
  position: absolute;
  inset: 0;
  z-index: 10;
  background: linear-gradient(180deg, rgba(126,210,122,0.06), rgba(0,0,0,0.4));
  display: grid;
  place-items: center;
  pointer-events: none;
  animation: swapFlash 1.6s ease-out forwards;
}
.swap-flash .sf-inner {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 22px 30px; border-radius: 16px;
  background: rgba(10,9,8,0.85);
  border: 1px solid rgba(126,210,122,0.3);
  box-shadow: 0 0 0 1px rgba(126,210,122,0.1), 0 24px 60px -10px rgba(0,0,0,0.6);
}
.swap-flash .sf-label { font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ok); }
.swap-flash .sf-from { color: var(--dim); font-size: 13px; font-family: var(--mono); }
.swap-flash .sf-arrow { color: var(--ok); animation: arrowSlide 0.8s ease-in-out infinite; }
.swap-flash .sf-to { color: var(--ok); font-size: 13px; font-family: var(--mono); }
.swap-flash .sf-bar { width: 220px; height: 3px; border-radius: 999px; background: rgba(255,255,255,0.1); overflow: hidden; }
.swap-flash .sf-bar i { display: block; height: 100%; background: var(--ok); animation: swapBar 1.4s ease-in-out forwards; }
@keyframes swapFlash { 0% { opacity: 0; } 12% { opacity: 1; } 85% { opacity: 1; } 100% { opacity: 0; } }
@keyframes swapBar { from { width: 0; } to { width: 100%; } }
@keyframes arrowSlide { 50% { transform: translateX(4px); } }
.sf-stack { display: flex; align-items: center; gap: 10px; }

/* viewer count overlay */
.viewer-overlay {
  position: absolute; top: 14px; right: 14px; z-index: 4;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 9px;
  background: rgba(10,9,8,0.78);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--fg-2);
}
.viewer-overlay .blink { width: 6px; height: 6px; border-radius: 50%; background: #ff4d4d; }
.viewer-overlay strong { color: var(--fg); font-weight: 600; }

/* small screens */
@media (max-width: 900px) {
  .ss-chat-float { right: 12px; bottom: 12px; left: 12px; width: auto; max-height: 45%; }
  .queue-panel, .ss-control-panel { width: calc(100% - 24px); left: 12px; right: 12px; }
}
