/* =============================================================================
   TVU Go Studio — design system
   One product, two form factors: a mobile-first switcher (the program block is the
   hero) that expands at >=1024px into a full web surface — nav rail, program area,
   side panel. It is its own tool, not a costume of somebody else's desktop app.
   Boldness is spent in one place: the on-air program frame (monitor + red tally +
   tabular-mono telemetry + IS+ concentric pulse). Everything else is quiet.
   All colour lives in :root. No web fonts, no external refs of any kind.
   ============================================================================= */

:root {
  /* --- surface + brand roles (exact spec roles) --- */
  --bg: #191b26;            /* app background + disabled chip bg */
  --card: #141414;          /* INSET-DISPLAY surfaces only (monitor, thumbnails) — darker than bg */
  --panel: #2b2e38;         /* LIFTED containers (sheets, telemetry banner, sticky bars, tiles) */
  --brand: #2AC93A;         /* Sign-in + Go-live CTAs, healthy links, confirm toasts ONLY */
  --info: #44A4FD;          /* scene selection ring, IS+ pulse, help/link text */
  --live: #e56464;          /* on-air only: LIVE pill/tally, End stream, dropped-link chip */
  --text: #e9eaef;
  --text-dim: #9a9fb2;
  --stroke: rgba(255, 255, 255, 0.08);

  /* --- derived / support tokens (kept here so no raw hex leaks into rules) --- */
  --backdrop: #0e0f16;                 /* letterbox around the phone column on tablet widths */
  --on-brand: #05230f;                 /* dark ink on #2AC93A → 7.6:1 (AA large + AA body, AAA large) */
  --on-live: #2b0909;                  /* dark ink on live red → AA */
  --warn: #e6b450;                     /* amber — marginal signal, elevated latency */
  --scrim: rgba(6, 7, 12, 0.62);
  --shimmer: rgba(255, 255, 255, 0.07);
  --flash: rgba(255, 255, 255, 0.9);
  --brand-weak: rgba(42, 201, 58, 0.16);
  --brand-line: rgba(42, 201, 58, 0.42);
  --info-weak: rgba(68, 164, 253, 0.16);
  --info-line: rgba(68, 164, 253, 0.5);
  --live-weak: rgba(229, 100, 100, 0.16);
  --live-line: rgba(229, 100, 100, 0.5);
  --live-glow: rgba(229, 100, 100, 0.55);
  --warn-weak: rgba(230, 180, 80, 0.15);
  --warn-line: rgba(230, 180, 80, 0.45);
  --lock-veil: rgba(20, 20, 20, 0.74);
  --panel-hi: #3a3e4a;                    /* lifted neutral — prominent NON-air CTA (Allow / Continue), keeps --brand reserved */
  --panel-veil: rgba(43, 46, 56, 0.82);   /* --panel with alpha — monitor PREVIEW chip */
  --display-veil: rgba(6, 7, 12, 0.55);   /* readable veil over inset-display content (TC, held label) */
  --backdrop-hi: #14161f;                 /* desktop backdrop gradient top */
  --black: #000000;                       /* held-monitor darken overlay */

  /* --- type ---
     Inter leads the UI stack and is used when the OS already has it installed. It is a
     DECLARATION ONLY — no font file is ever downloaded and no font-loading rule exists in
     this stylesheet — so the app still renders with zero network. Everything after Inter is
     the usual system fallback chain. */
  --ui-sans: Inter, "Inter var", -apple-system, BlinkMacSystemFont, "Segoe UI Variable", "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --ui-mono: ui-monospace, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "DejaVu Sans Mono", monospace;
  --fs-xs: .75rem;  --fs-sm: .875rem; --fs-md: 1rem;
  --fs-lg: 1.25rem; --fs-xl: 1.75rem; --fs-2xl: 2.5rem;

  /* --- spacing (4px grid) + radius + elevation --- */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s6: 24px; --s8: 32px; --s12: 48px;
  --r-sm: 8px; --r-md: 12px; --r-lg: 18px; --r-pill: 999px;
  --shadow: 0 8px 24px rgba(0, 0, 0, .35);
}

/* --- reset --- */
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--backdrop);
  color: var(--text);
  font-family: var(--ui-sans);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
button { font: inherit; color: inherit; background: none; border: none; padding: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; }
input { font: inherit; }
img, svg { display: block; max-width: 100%; }
h1, h2, p { margin: 0; }
.mono { font-family: var(--ui-mono); }
.tnum { font-variant-numeric: tabular-nums; }

:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; border-radius: var(--r-sm); }

/* --- app shell -------------------------------------------------------------
   Mobile: one column — screen host with the tab bar underneath. The desktop rule
   at the bottom of this file re-lays the SAME three elements as rail | program |
   side panel. Inside .screen-host the persistent 16:9 preview owns the top row and
   every screen shares the "stage" row below it. */
.app-shell {
  position: relative;
  width: 100%;
  max-width: 430px;
  height: 100vh;
  height: 100dvh;
  margin: 0 auto;
  background: var(--bg);
  overflow: hidden;
  box-shadow: 0 0 0 1px var(--stroke);
  display: grid;
  grid-template-areas: "screen" "nav";
  grid-template-rows: minmax(0, 1fr) auto;
}
/* The screen host is itself a two-row grid: the persistent 16:9 program frame on top,
   and a single "stage" cell underneath that every screen, nav surface and stub shares.
   Screens/surfaces/stubs are grid items placed in the SAME cell, so they overlap each
   other exactly as they used to — but none of them can ever cover, move or destroy the
   frame above. That is the whole trick: no absolute positioning against the host, no JS
   measuring, no breakpoint logic. See previewStage() in screens.js. */
.screen-host {
  grid-area: screen; position: relative; min-height: 0; overflow: hidden;
  display: grid;
  grid-template-areas: "preview" "stage";
  grid-template-rows: auto minmax(0, 1fr);
}
.app-nav { grid-area: nav; }
.side-panel { grid-area: side; display: none; }

.surface-display { background: var(--card); }
.surface-panel { background: var(--panel); }

/* --- screens --- */
.screen {
  grid-area: stage; position: relative; z-index: 1; min-height: 0; min-width: 0;
  display: flex; flex-direction: column;
  height: 100%;
  animation: screen-in .22s cubic-bezier(.2, .7, .2, 1) both;
}
.screen.no-anim { animation: none; }
@keyframes screen-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* --- icons --- */
.icon { display: inline-flex; width: 20px; height: 20px; line-height: 0; flex: 0 0 auto; }
.icon svg { width: 100%; height: 100%; }
.btn .icon, .btn-ic, .btn-ic-r { width: 18px; height: 18px; }
.btn-ic-r { margin-left: 2px; }

/* --- buttons --- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 0 18px; border-radius: var(--r-md);
  font-weight: 700; font-size: var(--fs-md); border: 1px solid transparent;
  transition: filter .12s ease, transform .06s ease;
}
.btn:active { transform: translateY(1px); }
.btn-lg { min-height: 52px; font-size: 1.0625rem; }
.btn-primary { background: var(--brand); color: var(--on-brand); }
.btn-primary:hover { filter: brightness(1.05); }
.btn-danger { background: var(--live); color: var(--on-live); }
.btn-danger:hover { filter: brightness(1.05); }
.btn-secondary { background: var(--panel); color: var(--text); border-color: var(--stroke); }
.btn-secondary:hover { border-color: var(--info-line); }
/* Prominent NEUTRAL CTA for non-air commit steps (Allow, Continue). Lifted panel + --text
   + hairline: obvious next tap on both --bg and --panel surfaces, without spending --brand. */
.btn-strong { background: var(--panel-hi); color: var(--text); border-color: var(--stroke); }
.btn-strong:hover { filter: brightness(1.08); }
.btn-tertiary { color: var(--info); min-height: 44px; }
.btn-danger-ghost { background: transparent; color: var(--live); border-color: var(--live-line); }
.btn.is-disabled { opacity: .4; pointer-events: none; }
/* Refused, not removed: the IS+ action needs bonded links, so it dims but stays tappable and
   says why + what to do (same idea as the aria-disabled "Use SSO" button on sign-in). */
#reconnect-btn[aria-disabled="true"] { opacity: .55; }
.demo-pill { background: var(--stroke); color: var(--text-dim); font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; padding: 2px 6px; border-radius: var(--r-pill); }

/* --- chips --- */
.link-chip { display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px; border-radius: var(--r-pill); font-size: var(--fs-xs); border: 1px solid var(--stroke); white-space: nowrap; }
.link-chip .chip-ic { width: 14px; height: 14px; }
.link-chip.is-empty { background: var(--bg); color: var(--text-dim); }
.link-chip.is-ok { background: var(--brand-weak); color: var(--brand); border-color: var(--brand-line); }
.link-chip.is-warn { background: var(--warn-weak); color: var(--warn); border-color: var(--warn-line); }

/* --- section labels --- */
.section-eyebrow { color: var(--text-dim); font-size: var(--fs-xs); letter-spacing: .12em; text-transform: uppercase; margin: 2px; }
.section-eyebrow-sp { margin-top: 10px; }
.section-title { font-size: var(--fs-md); font-weight: 700; margin: 2px 0 4px; }
.section-sub { color: var(--text-dim); font-size: var(--fs-sm); margin: 0 0 10px; }

/* =========================================================== BOOT / LOGIN */
.screen-boot { align-items: center; justify-content: center; }
.boot-mark { width: 200px; opacity: .85; }
.boot-mark svg, .login-mark svg, .wordmark { width: 100%; height: auto; }

.screen-login { }
.login-body { flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 18px; padding: 24px; width: 100%; max-width: 360px; margin: 0 auto; }
.login-mark { width: 208px; }
.login-tagline { color: var(--text-dim); font-size: var(--fs-sm); margin-top: -4px; text-align: center; }
.login-form { width: 100%; display: flex; flex-direction: column; gap: 14px; margin-top: 6px; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field-label { font-size: var(--fs-xs); color: var(--text-dim); letter-spacing: .04em; }
.field-input { background: var(--card); border: 1px solid var(--stroke); border-radius: var(--r-md); padding: 14px; color: var(--text); font-size: 15px; min-height: 50px; }
.field-input:focus { outline: none; border-color: var(--info); box-shadow: 0 0 0 3px var(--info-weak); }
.login-form .btn-primary { width: 100%; margin-top: 4px; }
.login-form .btn-tertiary { align-self: center; }
.login-foot { padding: 16px; text-align: center; color: var(--text-dim); font-size: var(--fs-xs); letter-spacing: .04em; }

/* =========================================================== HYDRATE */
.screen-hydrate { align-items: center; justify-content: center; }
.hydrate-inner { display: flex; flex-direction: column; align-items: center; gap: 22px; padding: 24px; width: 100%; max-width: 320px; text-align: center; }
.hydrate-logo { width: 208px; }
.hydrate-log { display: flex; flex-direction: column; gap: 9px; width: 100%; align-items: flex-start; min-height: 84px; }
.hydrate-line { color: var(--text-dim); font-size: var(--fs-sm); display: flex; gap: 8px; align-items: center; opacity: 0; transform: translateY(4px); transition: opacity .25s ease, transform .25s ease; }
.hydrate-line.show { opacity: 1; transform: none; }
.hy-ok { color: var(--brand); width: 16px; height: 16px; }
.progress { width: 100%; height: 3px; background: var(--stroke); border-radius: 2px; overflow: hidden; }
.progress-bar { width: 42%; height: 100%; background: var(--brand); border-radius: 2px; animation: indeterminate 1.15s ease-in-out infinite; }
.progress.progress-static .progress-bar { animation: none; width: 100%; }
.hydrate-hint { color: var(--text-dim); font-size: var(--fs-xs); }
@keyframes indeterminate { 0% { transform: translateX(-120%); } 100% { transform: translateX(320%); } }

/* =========================================================== HOME */
.topbar { display: flex; align-items: center; gap: 12px; padding: 14px 16px; }
.avatar { width: 40px; height: 40px; border-radius: 50%; background: var(--brand); color: var(--on-brand); font-weight: 800; font-size: 15px; display: flex; align-items: center; justify-content: center; flex: 0 0 auto; }
/* Nothing signed in yet: the on-air mark, never a grey silhouette and never invented initials. */
.avatar-mark { background: var(--brand-weak); color: var(--brand); border: 1px solid var(--brand-line); }
.avatar-ic { width: 20px; height: 20px; }
.topbar-org { flex: 1; min-width: 0; }
.topbar-name { font-weight: 700; font-size: 15px; }
.topbar-sub { color: var(--text-dim); font-size: var(--fs-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.home-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 6px 16px 20px; display: flex; flex-direction: column; gap: 12px; }
.home-body { display: flex; flex-direction: column; gap: 12px; }

.source-rows { display: flex; flex-direction: column; gap: 10px; }

/* --- Desktop camera & mic: camera, microphone and screen share in ONE group --- */
.cap-group { border-radius: var(--r-md); border: 1px solid var(--stroke); overflow: hidden; }
.cap-head { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-bottom: 1px solid var(--stroke); }
.cap-head-ic { width: 34px; height: 34px; border-radius: var(--r-sm); background: var(--info-weak); color: var(--info); display: flex; align-items: center; justify-content: center; flex: 0 0 auto; }
.cap-head-ic .icon { width: 20px; height: 20px; }
.cap-head-title { font-weight: 700; flex: 1; min-width: 0; }
.cap-pill { font-size: 11px; font-weight: 700; letter-spacing: .04em; padding: 3px 9px; border-radius: var(--r-pill); border: 1px solid var(--stroke); color: var(--text-dim); white-space: nowrap; }
.cap-pill.is-on { color: var(--brand); border-color: var(--brand-line); background: var(--brand-weak); }
.cap-pill.is-wait { color: var(--info); border-color: var(--info-line); background: var(--info-weak); }
.cap-pill.is-warn { color: var(--warn); border-color: var(--warn-line); background: var(--warn-weak); }

.cap-row { display: flex; flex-direction: column; gap: 10px; padding: 14px; }
.cap-row + .cap-row { border-top: 1px solid var(--stroke); }
.cap-row-sub { background: var(--bg); }
.cap-sub-title { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: var(--fs-sm); }
.cap-sub-ic { width: 18px; height: 18px; color: var(--text-dim); }
.cap-status-head { font-size: var(--fs-sm); font-weight: 600; }
.cap-status-detail { color: var(--text-dim); font-size: var(--fs-xs); line-height: 1.5; margin-top: 3px; }
.cap-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.cap-btn {
  display: inline-flex; align-items: center; gap: 7px; min-height: 40px; padding: 0 13px;
  border-radius: var(--r-md); border: 1px solid var(--stroke); background: var(--card);
  color: var(--text); font-size: var(--fs-sm); font-weight: 600;
}
.cap-btn:hover { border-color: var(--info-line); }
.cap-btn[disabled] { opacity: .45; cursor: default; }
.cap-btn[disabled]:hover { border-color: var(--stroke); }
.cap-btn-ic { width: 16px; height: 16px; color: var(--text-dim); }
.cap-btn.is-pressed { border-color: var(--warn-line); color: var(--warn); }
.cap-btn.is-pressed .cap-btn-ic { color: var(--warn); }
.cap-btn-off { color: var(--live); border-color: var(--live-line); }
.cap-btn-lead { min-height: 44px; }
.cap-waiting { color: var(--info); font-size: var(--fs-sm); font-weight: 600; }
.cap-note { color: var(--text-dim); font-size: var(--fs-xs); line-height: 1.5; }

/* --- which camera, which microphone, which speaker ---
   Its own band inside the group, between the camera row and the screen row. The thumbnail is
   an inset display like every other picture in the app, and it sits beside the lists so the
   device being chosen and the picture it produces are one glance apart. */
.cap-devices { display: flex; flex-direction: column; gap: 12px; padding: 14px; border-top: 1px solid var(--stroke); background: var(--bg); }
.cap-devices[hidden] { display: none; }
.cap-monitor {
  position: relative; width: 100%; max-width: 200px; aspect-ratio: 16 / 9; flex: 0 0 auto;
  border-radius: var(--r-sm); border: 1px solid var(--stroke); overflow: hidden;
  display: flex; align-items: center; justify-content: center; text-align: center;
}
.cap-monitor-vid { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: none; }
.cap-monitor[data-live="on"] .cap-monitor-vid { display: block; }
.cap-monitor[data-live="on"] { border-color: var(--brand-line); }
.cap-monitor-off { color: var(--text-dim); font-size: var(--fs-xs); line-height: 1.4; padding: 0 10px; }

.cap-picks { display: flex; flex-direction: column; gap: 12px; flex: 1; min-width: 0; }
.cap-pick { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.cap-pick-title { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .03em; color: var(--text-dim); }
.cap-select {
  width: 100%; min-height: 40px; padding: 0 10px; border-radius: var(--r-md);
  border: 1px solid var(--stroke); background: var(--card); color: var(--text);
  font-family: inherit; font-size: var(--fs-sm); font-weight: 600;
}
.cap-select:hover { border-color: var(--info-line); }
.cap-select:focus { outline: none; border-color: var(--info); box-shadow: 0 0 0 3px var(--info-weak); }
.cap-select option { background: var(--panel); color: var(--text); }
.cap-pick-note { color: var(--text-dim); font-size: var(--fs-xs); line-height: 1.5; }
.cap-pick-note.is-warn { color: var(--warn); }
.cap-pick-empty { color: var(--text-dim); font-size: var(--fs-xs); line-height: 1.5; }
.cap-allow { align-self: flex-start; }

/* Side by side as soon as there is room for the picture and a full device name at once. */
@media (min-width: 480px) {
  .cap-devices { flex-direction: row; align-items: flex-start; gap: 14px; }
  .cap-monitor { width: 168px; }
}

.add-stack { display: flex; flex-direction: column; gap: 10px; }
.add-tile { display: flex; align-items: center; gap: 14px; padding: 16px; border-radius: var(--r-md); border: 1px solid var(--stroke); text-align: left; }
.add-tile:hover { border-color: var(--info-line); }
.add-tile-ic { width: 46px; height: 46px; border-radius: var(--r-md); display: flex; align-items: center; justify-content: center; flex: 0 0 auto; }
.add-tile-ic .icon { width: 24px; height: 24px; }
.tile-phone .add-tile-ic { background: var(--brand-weak); color: var(--brand); }
.tile-cam .add-tile-ic, .tile-screen .add-tile-ic { background: var(--info-weak); color: var(--info); }
.add-tile-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.add-tile-title { font-weight: 700; }
.add-tile-sub { color: var(--text-dim); font-size: var(--fs-sm); }
.add-tile-plus { margin-left: auto; color: var(--text-dim); width: 20px; height: 20px; }
.add-tile-compact { padding: 12px 14px; }
.add-tile-compact .add-tile-ic { width: 38px; height: 38px; }

.source-row { display: flex; align-items: center; gap: 12px; padding: 10px; border-radius: var(--r-md); border: 1px solid var(--stroke); text-align: left; width: 100%; }
.source-row:hover { border-color: var(--info-line); }
.source-row.is-static { cursor: default; }
.source-row.is-static:hover { border-color: var(--stroke); }
.thumb { position: relative; width: 96px; height: 54px; border-radius: var(--r-sm); overflow: hidden; flex: 0 0 auto; border: 1px solid var(--stroke); }
.thumb-wire { position: absolute; inset: 0; }
.thumb-wire svg { width: 100%; height: 100%; }
.shimmer { position: absolute; inset: 0; background: linear-gradient(100deg, transparent 32%, var(--shimmer) 50%, transparent 68%); transform: translateX(-100%); animation: shimmer 3.4s ease-in-out infinite; }
@keyframes shimmer { 0% { transform: translateX(-100%); } 60%, 100% { transform: translateX(100%); } }
.source-meta { flex: 1; min-width: 0; }
.source-name { font-weight: 600; }
.source-sub { color: var(--text-dim); font-size: var(--fs-xs); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chev { color: var(--text-dim); margin-left: auto; }

.about-card { border-radius: var(--r-md); border: 1px solid var(--stroke); overflow: hidden; }
.about-head { width: 100%; display: flex; align-items: center; gap: 10px; padding: 14px 16px; text-align: left; min-height: 52px; }
.about-ic { color: var(--info); }
.about-title { flex: 1; font-weight: 600; }
.about-chev { color: var(--text-dim); transition: transform .2s ease; }
.about-card.open .about-chev { transform: rotate(180deg); }
.about-body { max-height: 0; overflow: hidden; padding: 0 16px; color: var(--text-dim); font-size: var(--fs-sm); line-height: 1.5; transition: max-height .22s ease, padding .22s ease; }
.about-card.open .about-body { max-height: 140px; padding: 0 16px 16px; }

.continue-cta { width: 100%; margin-top: 8px; }

/* =========================================================== PERSISTENT NAV
   Same six items in both form factors: bottom tab bar on mobile, left rail on
   desktop (see the >=1024px block). Hidden on boot/login/hydrate; greyed out while
   a sheet owns the screen, so the modal step is never ambiguous. */
.app-nav { display: flex; border-top: 1px solid var(--stroke); background: var(--bg); }
.app-shell[data-chrome="off"] .app-nav { display: none; }
.app-shell[data-chrome="modal"] .app-nav { opacity: .4; pointer-events: none; }
.nav-tab {
  position: relative; flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  padding: 8px 2px calc(8px + env(safe-area-inset-bottom));
  color: var(--text-dim); font-size: 10px; min-height: 56px;
}
.nav-label { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-tab:hover { color: var(--text); }
.nav-tab.is-active { color: var(--text); box-shadow: inset 0 2px 0 var(--info); }
.nav-tab.is-active .nav-ic { color: var(--info); }
.nav-tab.is-dim { opacity: .45; }
.nav-ic { width: 22px; height: 22px; }
/* six full labels have to fit a 390px phone without truncating */
@media (max-width: 409.98px) {
  .nav-tab { font-size: 9.5px; padding-left: 1px; padding-right: 1px; }
  .nav-label { letter-spacing: -.01em; }
}
@media (max-width: 344.98px) {
  .nav-tab { font-size: 9px; padding-left: 0; padding-right: 0; }
  .nav-label { letter-spacing: -.03em; }
  .nav-ic { width: 20px; height: 20px; }
}

/* =========================================================== SHEETS */
.sheet { position: absolute; inset: 0; z-index: 40; display: flex; align-items: flex-end; }
.sheet-scrim { position: absolute; inset: 0; background: var(--scrim); animation: fade-in .18s ease both; }
.sheet-panel { position: relative; width: 100%; border-radius: var(--r-lg) var(--r-lg) 0 0; padding: 8px 18px 20px; box-shadow: var(--shadow); animation: sheet-up .2s cubic-bezier(.2, .7, .2, 1) both; }
.sheet.sheet-closing .sheet-panel { animation: sheet-down .2s ease both; }
.sheet.sheet-closing .sheet-scrim { animation: fade-out .2s ease both; }
.sheet.no-anim .sheet-panel, .sheet.no-anim .sheet-scrim { animation: none; }
.sheet-handle { width: 40px; height: 4px; border-radius: 2px; background: var(--stroke); margin: 4px auto 14px; }
@keyframes sheet-up { from { transform: translateY(100%); } to { transform: none; } }
@keyframes sheet-down { from { transform: none; } to { transform: translateY(100%); } }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes fade-out { from { opacity: 1; } to { opacity: 0; } }

.sheet-title { font-weight: 700; font-size: var(--fs-md); }
.sheet-title-lead { font-size: var(--fs-lg); margin-bottom: 14px; }
.sheet-permrow { display: flex; align-items: center; gap: 12px; }
.perm-ic { width: 42px; height: 42px; border-radius: var(--r-md); display: flex; align-items: center; justify-content: center; flex: 0 0 auto; }
.perm-ic .icon { width: 24px; height: 24px; }
.perm-phone { background: var(--brand-weak); color: var(--brand); }
.sim-pill { margin-left: auto; background: var(--info-weak); color: var(--info); font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: var(--r-pill); white-space: nowrap; }
.perm-chips { display: flex; gap: 8px; margin: 14px 0 4px; }
.perm-chip { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--stroke); padding: 7px 12px; border-radius: var(--r-pill); font-size: var(--fs-sm); color: var(--text-dim); }
.perm-chip .pc { width: 16px; height: 16px; }
.sheet-body { color: var(--text-dim); font-size: var(--fs-sm); margin: 10px 0 18px; line-height: 1.55; }
.sheet-actions { display: flex; flex-direction: column; gap: 10px; }
.btn-wide { width: 100%; }

.share-pills { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }
.share-pill { display: flex; align-items: center; gap: 12px; padding: 15px; border-radius: var(--r-md); border: 1px solid var(--stroke); background: var(--card); color: var(--text); text-align: left; width: 100%; font-weight: 600; }
.share-pill:hover { border-color: var(--info-line); }
.share-pill .sp { width: 22px; height: 22px; color: var(--info); }
.share-pill-rec { border-color: var(--info-line); }

.dest-card { padding: 14px; border-radius: var(--r-md); border: 1px solid var(--stroke); margin-bottom: 14px; }
.dest-row { display: flex; justify-content: space-between; align-items: center; }
.dest-label { color: var(--text-dim); font-size: var(--fs-xs); letter-spacing: .04em; text-transform: uppercase; }
.dest-kind { color: var(--info); font-size: var(--fs-xs); }
.dest-name { font-weight: 700; margin-top: 6px; }
.dest-url { color: var(--text-dim); font-size: var(--fs-xs); margin-top: 2px; }
.marginal-note { display: flex; gap: 8px; align-items: center; background: var(--warn-weak); color: var(--warn); border: 1px solid var(--warn-line); padding: 10px 12px; border-radius: var(--r-md); font-size: var(--fs-sm); margin-bottom: 12px; }
.marginal-note .mn-ic { width: 18px; height: 18px; }
.sheet-actions .btn-lg .btn-ic { color: currentColor; }

/* =========================================================== PREVIEW STAGE
   The one 16:9 program frame. It lives in the "preview" row of the screen host and is
   built once (screens.js previewStage), so nothing a screen does can blank it. Width is
   clamped so a 16:9 box always FITS the viewport instead of being squashed out of ratio —
   the frame stays exactly 16:9 at every size, and the controls under it stay reachable. */
.preview-stage { grid-area: preview; padding: 10px 16px 0; min-width: 0; }
.app-shell[data-chrome="off"] .preview-stage { display: none; }
.preview-inner { width: 100%; max-width: max(240px, calc((100dvh - 330px) * 16 / 9)); margin: 0 auto; }

.preview-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: var(--card); display: none; }
/* Layout: which real pictures are on screen, and how the frame is divided. `auto` = no
   scene chosen yet, so show whatever real picture exists (a screen share outranks the
   camera — it is what the creator is looking at while setting one up). */
.preview-stage[data-show="video"][data-cam="on"] #preview-cam { display: block; }
.preview-stage[data-show="video"][data-screen="on"] #preview-screen { display: block; }
.preview-stage[data-show="video"][data-layout="auto"][data-screen="on"] #preview-cam { display: none; }
.preview-stage[data-show="video"][data-layout="cam"] #preview-screen { display: none; }
.preview-stage[data-show="video"][data-layout="screen"] #preview-cam { display: none; }
/* picture-in-picture: the shared screen fills, the camera sits in the bottom-right corner */
.preview-stage[data-layout="pip"] #preview-cam {
  inset: auto 3.2% 4.5% auto; width: 30%; height: auto; aspect-ratio: 16 / 9;
  border-radius: 6px; border: 1.5px solid var(--info); box-shadow: var(--shadow); z-index: 2;
}
/* split 50/50: shared screen left, camera right */
.preview-stage[data-layout="split"] #preview-screen { inset: 0 50% 0 0; width: auto; }
.preview-stage[data-layout="split"] #preview-cam { inset: 0 0 0 50%; width: auto; border-left: 1px solid var(--stroke); }

.monitor-wire, .preview-empty, .overlay-layer { display: none; }
.preview-stage[data-show="wire"] .monitor-wire, .preview-stage[data-show="card"] .monitor-wire { display: block; }
.preview-stage[data-show="empty"] .preview-empty { display: flex; }
/* Overlays draw on whatever the frame is currently showing, including the wireframe and
   the empty state — switching one on has to be visible immediately or the list would be
   claiming something the picture does not show. A standby card is the one exception: it
   is a full-frame cover, so it covers the overlays too. */
.preview-stage:not([data-show="card"]) .overlay-layer { display: block; }
/* Nothing to show yet — this is where a refused camera explains itself and offers the
   one tap that fixes it. It replaces the dashed "No sources yet" box entirely. */
.preview-empty {
  position: absolute; inset: 0; z-index: 3; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 16px; text-align: center;
}
.preview-empty-ic { width: 40px; height: 40px; color: var(--text-dim); }
.preview-empty-ic svg { width: 100%; height: 100%; }
.preview-empty-title { font-weight: 700; font-size: var(--fs-md); }
.preview-empty-body { color: var(--text-dim); font-size: var(--fs-sm); max-width: 46ch; line-height: 1.45; }
.preview-empty-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 4px; }
.preview-empty-actions .btn { min-height: 42px; font-size: var(--fs-sm); }

/* The frame says the state out loud, always, in words: on-air first, then what is in the
   picture and how the session is getting out. No codes — this line is the whole point. */
.preview-status { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 8px; padding: 8px 2px 0; font-size: var(--fs-xs); line-height: 1.45; }
.preview-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-dim); flex: 0 0 auto; align-self: center; }
.preview-stage[data-air="on"] .preview-dot, .preview-stage[data-air="held"] .preview-dot { background: var(--live); box-shadow: 0 0 8px var(--live-glow); }
.preview-status-air { font-weight: 700; color: var(--text); }
.preview-stage[data-air="on"] .preview-status-air, .preview-stage[data-air="held"] .preview-status-air { color: var(--live); }
.preview-status-src { color: var(--text-dim); min-width: 0; }

/* on-air chrome inside the frame */
.preview-stage[data-air="off"] .tally, .preview-stage[data-air="off"] .monitor-tc { display: none; }
.preview-stage[data-air="on"] #preview-chip, .preview-stage[data-air="held"] #preview-chip { display: none; }

/* --- overlays composited on the picture (Overlays tab) --- */
.overlay-layer { position: absolute; inset: 0; z-index: 4; pointer-events: none; }
.ovl { position: absolute; }
.ovl-mark { left: 3%; top: 13%; width: 22%; max-width: 124px; opacity: .92; }   /* clears the tally / PREVIEW chip above it */
.ovl-mark svg { width: 100%; height: auto; }
.ovl-name { left: 3%; bottom: 12%; max-width: 60%; background: var(--panel-veil); border-left: 3px solid var(--brand); border-radius: 0 var(--r-sm) var(--r-sm) 0; padding: 7px 12px; display: flex; flex-direction: column; }
.ovl-name-main { font-weight: 800; font-size: var(--fs-sm); }
.ovl-name-sub { color: var(--text-dim); font-size: 10px; }
.ovl-chat { right: 3%; top: 8%; width: 42%; max-width: 260px; background: var(--display-veil); border: 1px solid var(--stroke); border-radius: var(--r-sm); padding: 7px 9px; display: flex; flex-direction: column; gap: 3px; }
.ovl-chat-row { font-size: 10px; line-height: 1.35; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ovl-chat-who { font-weight: 700; margin-right: 5px; }
.ovl-chat-text { color: var(--text-dim); }
.overlay-card-ic { width: 44px; height: 44px; border-radius: var(--r-sm); background: var(--info-weak); color: var(--info); display: flex; align-items: center; justify-content: center; flex: 0 0 auto; }

/* =========================================================== PROGRAM FRAME */
.monitor { position: relative; aspect-ratio: 16 / 9; border-radius: var(--r-md); overflow: hidden; border: 1px solid var(--stroke); }
.monitor.is-live { border: 2px solid var(--live); box-shadow: 0 0 0 1px var(--live-glow), 0 0 26px var(--live-glow); }
.scanwrap { position: absolute; inset: 0; pointer-events: none; z-index: 5; }
.scanlines { position: absolute; inset: 0; width: 100%; height: 100%; color: var(--text); opacity: .03; }
.monitor-wire { position: absolute; inset: 0; z-index: 1; }
.monitor-wire svg { width: 100%; height: 100%; }
.monitor-topleft { position: absolute; z-index: 6; top: 10px; left: 10px; display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.monitor-chip { background: var(--panel-veil); color: var(--text); font-size: 11px; font-weight: 700; letter-spacing: .1em; padding: 4px 8px; border-radius: var(--r-sm); backdrop-filter: blur(2px); }
.monitor-tc { position: absolute; z-index: 6; bottom: 10px; left: 10px; color: var(--text); font-size: 13px; letter-spacing: .04em; background: var(--display-veil); padding: 3px 7px; border-radius: 6px; }
.monitor-darken { position: absolute; z-index: 2; inset: 0; background: var(--black); opacity: 0; transition: opacity .3s ease; pointer-events: none; }
.monitor.is-held .monitor-darken { opacity: .06; }
.monitor.is-held .scanlines { opacity: .05; }

/* tally = composite: red pill + glow + breathing (the signature on-air treatment) */
.tally { position: relative; display: inline-flex; align-items: center; }
.live-pill { position: relative; z-index: 2; display: inline-flex; align-items: center; gap: 6px; background: var(--live); color: var(--on-live); font-weight: 800; font-size: 12px; letter-spacing: .1em; padding: 5px 10px; border-radius: var(--r-pill); box-shadow: 0 0 12px var(--live-glow); animation: live-breathe 1.1s ease-in-out infinite; }
.live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text); }
@keyframes live-breathe {
  0%, 100% { box-shadow: 0 0 10px var(--live-glow); transform: scale(1); }
  50% { box-shadow: 0 0 22px var(--live-glow); transform: scale(1.03); }
}
/* IS+ concentric protection ring (only during held) */
.is-ring { position: absolute; left: 22px; top: 50%; width: 46px; height: 46px; transform: translate(-50%, -50%); pointer-events: none; display: none; z-index: 1; }
.is-ring.show { display: block; }
.is-ring .ring { position: absolute; inset: 0; border: 2px solid var(--info); border-radius: 50%; opacity: 0; animation: is-pulse 1.4s ease-out infinite; }
.is-ring .ring.r2 { animation-delay: .7s; }
@keyframes is-pulse { 0% { transform: scale(.5); opacity: .75; } 100% { transform: scale(2.3); opacity: 0; } }
.signal-held { display: none; color: var(--info); font-weight: 700; font-size: 11px; letter-spacing: .06em; background: var(--display-veil); padding: 3px 7px; border-radius: 6px; }
.signal-held.show { display: inline-block; }

/* cut-flash on scene switch */
.monitor.cut-flash::after { content: ""; position: absolute; inset: 0; background: var(--flash); z-index: 5; animation: cut .12s ease-out both; }
@keyframes cut { from { opacity: .85; } to { opacity: 0; } }
.tally.tally-flash .live-pill { animation: live-breathe 1.1s ease-in-out infinite, tally-flash .24s ease-out; }
@keyframes tally-flash { 0% { filter: brightness(1.8); transform: scale(1.12); } 100% { filter: none; transform: scale(1); } }

/* =========================================================== SCENES
   Scenes are the layout compositions the switcher cuts between (Presets — the
   standby cards — are a separate surface further down). */
.scene-head { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; }
.scene-eyebrow { color: var(--text-dim); font-size: 11px; letter-spacing: .14em; }
.scenes-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 0 16px 12px; display: flex; flex-direction: column; gap: 16px; }
.scene-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.scene-tile { position: relative; border-radius: var(--r-md); border: 1px solid var(--stroke); overflow: hidden; text-align: left; }
.scene-tile:hover { border-color: var(--info-line); }
.scene-wire { aspect-ratio: 16 / 9; background: var(--card); }
.scene-wire svg { width: 100%; height: 100%; }
.scene-foot { display: flex; align-items: center; justify-content: space-between; padding: 8px 10px; gap: 6px; }
.scene-name { font-size: var(--fs-sm); font-weight: 600; }
.scene-tag { display: none; position: absolute; top: 7px; left: 7px; z-index: 2; font-size: 10px; font-weight: 700; color: var(--info); background: var(--display-veil); border: 1px solid var(--info-line); padding: 1px 6px; border-radius: var(--r-pill); letter-spacing: .06em; }
.scene-tile.is-selected { border-color: var(--info); box-shadow: 0 0 0 1px var(--info); }
.scene-tile.is-selected .scene-tag { display: inline-block; }
/* the live strip's selected tile IS the program — mark it with the on-air colour */
.scene-strip-tile.is-selected .scene-tag { color: var(--live); border-color: var(--live-line); }
.scene-lock { position: absolute; inset: 0; background: var(--lock-veil); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; color: var(--text-dim); font-size: 11px; text-align: center; padding: 10px; }
.scene-lock .lock-ic { width: 20px; height: 20px; }

.sticky-cta { padding: 12px 16px; box-shadow: var(--shadow); }
.take-to-air { width: 100%; }

/* =========================================================== LIVE */
.live-rule { height: 3px; background: var(--live); box-shadow: 0 0 10px var(--live-glow); flex: 0 0 auto; }
.live-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 0 16px 12px; display: flex; flex-direction: column; gap: 14px; }

.tele { display: flex; flex-direction: column; gap: 7px; padding: 2px; }
.tele-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.tele-k { color: var(--text-dim); font-size: 12px; letter-spacing: .1em; }
.tele-v { display: inline-flex; align-items: baseline; gap: 6px; font-variant-numeric: tabular-nums; letter-spacing: .02em; font-size: 15px; }
.tele-u { color: var(--text-dim); font-size: 12px; }
.tele-arrow { color: var(--brand); width: 12px; height: 12px; align-self: center; }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; align-self: center; }
.dot[data-health="ok"] { background: var(--brand); }
.dot[data-health="warn"] { background: var(--warn); }
.dot[data-health="bad"] { background: var(--live); }
.tele-links { user-select: none; }
.link-values { display: inline-flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.link-sep { color: var(--text-dim); }
.link-values .dropped { color: var(--live); text-decoration: line-through; }
.recovered-flash { color: var(--brand); animation: recover-flash .9s ease-out; }
@keyframes recover-flash { 0% { color: var(--brand); } 70% { color: var(--brand); } 100% { color: var(--text); } }

.strip-wrap { display: flex; flex-direction: column; gap: 8px; }
.scene-strip { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; -webkit-overflow-scrolling: touch; }
.scene-strip-tile { flex: 0 0 150px; }
.scene-strip-tile .scene-name {
  font-size: 12px; line-height: 1.3; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}

.live-bottom { flex: 0 0 auto; background: var(--bg); }
.held-banner { margin: 0 16px; border-radius: var(--r-md); border: 1px solid var(--info-line); transform: translateY(14px); opacity: 0; max-height: 0; overflow: hidden; padding: 0 14px; transition: transform .18s ease, opacity .18s ease, max-height .18s ease, padding .18s ease, margin .18s ease; }
.held-banner.show { transform: none; opacity: 1; max-height: 200px; padding: 12px 14px; margin: 0 16px 10px; box-shadow: var(--shadow); }
.held-head { display: flex; align-items: center; gap: 8px; font-weight: 700; letter-spacing: .04em; }
.held-head .held-ic { color: var(--info); width: 18px; height: 18px; }
.held-body { color: var(--text-dim); font-size: 13px; margin-top: 5px; line-height: 1.5; }
.live-actions { display: flex; gap: 10px; padding: 12px 16px; box-shadow: var(--shadow); }
#end-btn { flex: 1; }
#reconnect-btn { flex: 0 0 auto; white-space: nowrap; }
/* narrow phones: both on-air actions keep their full plain-language labels — stack them
   rather than truncate or shrink the tap targets */
@media (max-width: 419.98px) {
  .live-actions { flex-direction: column; }
  #reconnect-btn { width: 100%; }
}

/* =========================================================== OFFAIR */
.screen-offair { align-items: center; justify-content: center; }
.offair-inner { display: flex; flex-direction: column; align-items: center; gap: 10px; color: var(--text-dim); }
.offair-ic { width: 44px; height: 44px; color: var(--brand); }
.offair-title { font-size: var(--fs-lg); font-weight: 700; color: var(--text); }
.offair-sub { font-size: var(--fs-sm); }

/* =========================================================== TOASTS + STUB */
/* Toasts sit above whatever bottom bar the current screen owns, so a transient status
   message can never cover "Go live" / "End stream". The lift is keyed off body[data-state]
   (set by fsm.js) and inherited down to the host. */
body { --toast-lift: 24px; }
body[data-state="SCENES"], body[data-state="PRE_LIVE"] { --toast-lift: 92px; }
body[data-state="LIVE"], body[data-state="LIVE_DEGRADED_HELD"], body[data-state="LIVE_RECOVERED"] { --toast-lift: 160px; }
.toast-host { position: absolute; left: 0; right: 0; bottom: var(--toast-lift, 24px); display: flex; flex-direction: column; align-items: center; gap: 8px; z-index: 60; pointer-events: none; padding: 0 16px; }
.toast { background: var(--panel); color: var(--text); border: 1px solid var(--stroke); padding: 10px 16px; border-radius: var(--r-pill); font-size: var(--fs-sm); box-shadow: var(--shadow); animation: toast-in .2s ease both; max-width: 100%; }
.toast-brand { border-color: var(--brand-line); }
.toast-brand::before { content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--brand); margin-right: 8px; vertical-align: middle; }
.toast-out { animation: toast-out .22s ease both; }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes toast-out { from { opacity: 1; } to { opacity: 0; transform: translateY(6px); } }

.stub { grid-area: stage; position: relative; z-index: 70; background: var(--bg); display: flex; flex-direction: column; min-height: 0; min-width: 0; animation: screen-in .2s ease both; }
.stub-head { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--stroke); }
.stub-title { font-weight: 700; }
.iconbtn { width: 44px; height: 44px; border-radius: var(--r-md); display: flex; align-items: center; justify-content: center; color: var(--text); }
.iconbtn:hover { background: var(--panel); }
.stub-body { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 32px 28px; color: var(--text-dim); text-align: center; }
.stub-ic { width: 40px; height: 40px; color: var(--text-dim); }

/* =========================================================== NAV SURFACES
   Presets / Destinations / Multichat / read-only Sources. These are presentational
   panels over the screen host — they are NOT FSM states, and the nav stays live
   beside them so you can always leave. */
.surface {
  grid-area: stage; position: relative; z-index: 50; background: var(--bg);
  display: flex; flex-direction: column; min-height: 0; min-width: 0;
  animation: screen-in .2s cubic-bezier(.2, .7, .2, 1) both;
}
.surface.no-anim { animation: none; }
.surface-head { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-bottom: 1px solid var(--stroke); flex: 0 0 auto; }
.surface-title { font-size: var(--fs-md); font-weight: 700; }
.surface-body { flex: 1; min-height: 0; overflow-y: auto; padding: 14px 16px 22px; display: flex; flex-direction: column; gap: 12px; }
.surface-note { color: var(--text-dim); font-size: var(--fs-sm); line-height: 1.5; }
.surface-foot { color: var(--text-dim); font-size: var(--fs-xs); }
.empty-note { display: flex; gap: 10px; align-items: flex-start; padding: 16px; border-radius: var(--r-md); border: 1.5px dashed var(--stroke); color: var(--text-dim); font-size: var(--fs-sm); }
.empty-note .empty-ic { width: 20px; height: 20px; flex: 0 0 auto; }

/* --- standby preset cards --- */
.preset-list { display: flex; flex-direction: column; gap: 10px; }
.preset-card { display: flex; gap: 12px; padding: 10px; border-radius: var(--r-md); border: 1px solid var(--stroke); text-align: left; align-items: flex-start; }
.preset-card:hover { border-color: var(--info-line); }
.preset-card-wire { width: 112px; flex: 0 0 auto; aspect-ratio: 16 / 9; background: var(--card); border-radius: var(--r-sm); overflow: hidden; border: 1px solid var(--stroke); }
.preset-card-wire svg { width: 100%; height: 100%; }
.preset-card-meta { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.preset-card-head { display: flex; align-items: center; gap: 8px; }
.preset-card-name { font-weight: 700; }
.preset-card-state { font-size: 10px; letter-spacing: .08em; color: var(--text-dim); border: 1px solid var(--stroke); border-radius: var(--r-pill); padding: 1px 7px; }
.preset-card-note { color: var(--text); font-size: var(--fs-sm); }
.preset-card-hint { color: var(--text-dim); font-size: var(--fs-xs); }
.preset-card.is-active { border-color: var(--info); box-shadow: 0 0 0 1px var(--info); }
.preset-card.is-active .preset-card-state { color: var(--info); border-color: var(--info-line); background: var(--info-weak); }
/* standby card badge on the live monitor */
.standby-chip { position: absolute; z-index: 6; top: 10px; right: 10px; display: none; font-size: 11px; font-weight: 700; letter-spacing: .06em; color: var(--info); background: var(--display-veil); padding: 3px 8px; border-radius: 6px; border: 1px solid var(--info-line); }
.standby-chip.show { display: inline-block; }

/* =========================================================== DESTINATIONS
   Connection and transmitting are two separate facts and are always shown as two.
   Only "sending" borrows the on-air red — everything else stays neutral. */
.dest-list { display: flex; flex-direction: column; gap: 10px; }
.dest-item { display: flex; flex-direction: column; gap: 5px; padding: 12px 14px; border-radius: var(--r-md); border: 1px solid var(--stroke); text-align: left; width: 100%; }
.dest-item:hover { border-color: var(--info-line); }
.dest-line { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.dest-title { font-weight: 700; }
.dest-handle { color: var(--text-dim); font-size: var(--fs-xs); }
.dest-state { display: inline-flex; align-items: center; gap: 6px; font-size: 10px; font-weight: 700; letter-spacing: .1em; color: var(--text-dim); }
.dest-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-dim); flex: 0 0 auto; }
.dest-state[data-mode="sending"], .dest-chip[data-mode="sending"] .dest-chip-state { color: var(--live); }
.dest-state[data-mode="sending"] .dest-dot, .dest-chip[data-mode="sending"] .dest-dot { background: var(--live); box-shadow: 0 0 8px var(--live-glow); }
.dest-state[data-mode="armed"] { color: var(--text); }
.dest-state[data-mode="armed"] .dest-dot, .dest-chip[data-mode="armed"] .dest-dot { background: var(--brand); }
.dest-state[data-mode="auth"], .dest-chip[data-mode="auth"] .dest-chip-state { color: var(--warn); }
.dest-state[data-mode="auth"] .dest-dot, .dest-chip[data-mode="auth"] .dest-dot { background: var(--warn); }
.dest-chip[data-mode="sending"] { border-color: var(--live-line); }
.dest-facts { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 4px; }
.dest-fact { display: flex; flex-direction: column; font-size: var(--fs-sm); }
.dest-fact-k { color: var(--text-dim); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; }
.dest-server { color: var(--text-dim); font-size: 11px; margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.dest-strip { display: flex; gap: 8px; flex-wrap: wrap; }
.dest-chip { display: inline-flex; align-items: center; gap: 7px; padding: 6px 10px; border-radius: var(--r-pill); border: 1px solid var(--stroke); font-size: var(--fs-xs); background: var(--bg); }
.dest-chip-name { color: var(--text); font-weight: 600; }
.dest-chip-state { font-size: 10px; letter-spacing: .06em; }

/* =========================================================== MULTICHAT
   One list, three platforms. The tag is text (mono, dim) — chat rows are for
   reading, not for colour. */
.chat-list { display: flex; flex-direction: column; gap: 2px; }
.chat-row { display: flex; gap: 9px; align-items: baseline; padding: 7px 8px; border-radius: var(--r-sm); font-size: var(--fs-sm); }
.chat-row:nth-child(odd) { background: var(--stroke); }
.chat-tag { flex: 0 0 auto; width: 58px; font-size: 10px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-dim); }
.chat-body { min-width: 0; }
.chat-author { font-weight: 700; margin-right: 6px; }
.chat-text { color: var(--text-dim); }
/* subs/follows are highlighted with --info, NOT --brand: brand green stays reserved for
   sign-in / go-live / healthy-link, and --live red stays the on-air signal. */
.chat-row.is-event .chat-text { color: var(--info); }
.chat-row.is-event { border-left: 2px solid var(--info-line); }

/* =========================================================== SIDE PANEL (desktop)
   Shown only at >=1024px — the same destination rows and chat list the mobile nav
   surfaces use, kept permanently in view next to the program. */
.side-panel { border-left: 1px solid var(--stroke); background: var(--bg); overflow: hidden; }
.app-shell[data-chrome="off"] .side-panel { display: none; }
.side-block { display: flex; flex-direction: column; gap: 10px; padding: 16px; min-height: 0; }
.side-block + .side-block { border-top: 1px solid var(--stroke); }
.side-title { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: var(--fs-sm); font-weight: 700; letter-spacing: .04em; }
.side-hint { color: var(--text-dim); font-size: 10px; font-weight: 500; letter-spacing: .04em; text-transform: uppercase; }
.side-chat { flex: 1; min-height: 0; }
.chat-list.is-side { flex: 1; min-height: 0; overflow-y: auto; }

/* =========================================================== WIREFRAME PARTS
   Thumbnails + composition wireframes — every colour from a token, no <defs> ids. */
.wire-svg { width: 100%; height: 100%; }
.wire-svg .ln { fill: none; stroke: var(--text-dim); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.wire-svg .ln.guide { opacity: .28; stroke-width: 1.4; }
.wire-svg .ln.thin { stroke-width: 1.4; opacity: .7; }
.wire-svg .ln.tick { opacity: .5; stroke-width: 1.6; }
.wire-svg .ln.split { opacity: .5; stroke-dasharray: 3 4; }
.wire-svg .pane { fill: var(--stroke); stroke: var(--text-dim); stroke-width: 1.4; }
.wire-svg .pane.soft { fill: none; opacity: .7; }
.wire-svg .pane.frame { fill: none; stroke-width: 1.6; opacity: .8; }
.wire-svg .accent { fill: none; stroke: var(--info); stroke-width: 2; stroke-linejoin: round; }
.wire-svg .pip { fill: var(--card); stroke: var(--info); stroke-width: 1.6; }
.wire-svg .lbl-fill { fill: var(--text-dim); opacity: .5; }

/* =========================================================== RESPONSIVE
   Mobile (default, above): the phone column — switcher hero, tab bar underneath.
   480–1023px: same column, letterboxed on the backdrop (tablet / narrow window).
   >=1024px: the SAME markup re-lays as a web surface — nav rail | program | side
   panel. No separate desktop app, no separate DOM. */
@media (min-width: 480px) and (max-width: 1023.98px) {
  body { background: radial-gradient(120% 80% at 50% 0%, var(--backdrop-hi) 0%, var(--backdrop) 60%); }
  .app-shell { height: min(920px, 100dvh); margin-top: max(0px, calc((100dvh - 920px) / 2)); border-radius: 22px; }
}

@media (min-width: 1024px) {
  .app-shell {
    max-width: none; width: 100%; height: 100dvh; margin: 0; border-radius: 0; box-shadow: none;
    grid-template-areas: "nav screen side";
    grid-template-columns: 216px minmax(0, 1fr) 320px;
    grid-template-rows: minmax(0, 1fr);
  }
  .side-panel { display: flex; flex-direction: column; min-height: 0; }

  /* nav becomes a left rail */
  .app-nav { flex-direction: column; border-top: 0; border-right: 1px solid var(--stroke); padding: 12px 10px; gap: 2px; align-content: start; }
  .nav-tab {
    flex: 0 0 auto; flex-direction: row; justify-content: flex-start; gap: 12px;
    padding: 10px 12px; min-height: 46px; border-radius: var(--r-md); font-size: var(--fs-sm);
  }
  .nav-tab.is-active { background: var(--panel); box-shadow: inset 2px 0 0 var(--info); }
  .nav-tab:hover { background: var(--panel); }
  .nav-label { max-width: none; }

  /* screens breathe: one centred column of content, wider program block */
  .topbar { padding: 18px 28px; }
  .preview-stage { padding: 14px 28px 0; }
  .home-scroll, .scenes-scroll, .live-scroll, .surface-body { padding-left: 28px; padding-right: 28px; }
  .home-body, .scenes-scroll > *, .live-scroll > *, .surface-body > * { max-width: 980px; width: 100%; margin-left: auto; margin-right: auto; }
  /* the account row and the on-air eyebrow share the same centred column, so the link chip
     is never stranded against the side panel */
  .topbar, .scene-head { max-width: 1036px; margin-left: auto; margin-right: auto; width: 100%; }
  .scene-head { padding: 14px 28px; }
  .sticky-cta, .live-actions { padding-left: 28px; padding-right: 28px; display: flex; justify-content: center; }
  .sticky-cta .take-to-air, #end-btn { width: 320px; max-width: 320px; flex: 0 0 auto; }
  .held-banner, .held-banner.show { margin-left: auto; margin-right: auto; max-width: 980px; }
  .surface-body > * { max-width: 760px; }

  /* Keep the 16:9 frame inside the viewport by clamping its WIDTH — never its height, or
     it would stop being 16:9. The reserve leaves room for the tab content underneath, so
     the preview and the controls that change it are on screen together at 1920x1080. */
  .preview-inner { max-width: max(240px, min(980px, calc((100dvh - 440px) * 16 / 9))); }
  .scene-grid { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
  .scene-strip-tile { flex: 0 0 168px; }
  .add-stack { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
  .preset-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 12px; }
  .tele { flex-direction: row; align-items: flex-start; justify-content: space-between; gap: 20px; padding: 4px 2px; }
  .tele-row { flex-direction: column; align-items: flex-start; gap: 2px; }
  .link-values { justify-content: flex-start; }

  /* sheets stop being phone sheets and become centred dialogs */
  .sheet { align-items: center; justify-content: center; }
  .sheet-panel { width: min(520px, calc(100% - 64px)); border-radius: var(--r-lg); padding: 8px 22px 22px; animation: screen-in .2s cubic-bezier(.2, .7, .2, 1) both; }
  .sheet.sheet-closing .sheet-panel { animation: fade-out .18s ease both; }
  .sheet-handle { display: none; }
  body[data-state="LIVE"], body[data-state="LIVE_DEGRADED_HELD"], body[data-state="LIVE_RECOVERED"] { --toast-lift: 104px; }
}

@media (min-width: 1440px) {
  .app-shell { grid-template-columns: 240px minmax(0, 1fr) 368px; }
}

/* =========================================================== REDUCED MOTION
   One entrance per screen, tally-breathe and IS+ pulse are the only continuous loops
   in the product; the subtle thumbnail shimmer is a low-salience liveness cue. ALL of
   it collapses to static fallbacks here. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
  .screen, .sheet-panel, .sheet-scrim, .toast { animation: none !important; }
  .shimmer { display: none; }
  .progress-bar { animation: none; width: 100%; }
  .live-pill { animation: none; box-shadow: 0 0 14px var(--live-glow); }
  .is-ring .ring { animation: none; opacity: .5; transform: scale(1.4); }
  .is-ring .ring.r2 { display: none; }
  .monitor.cut-flash::after { display: none; }
}
