/* =========================
   AJA Interkom – mobilny UI
   Bez frameworków; flex/grid; zoptymalizowany pod dotyk
   ========================= */
:root{
  --bg: #0a0a0a;            /* tło – prawie czerń */
  --bg-2: #111315;          /* panele/karty – neutralna szarość */
  --card: #0f1011;          /* karty/sheet – neutral */
  --fg: #e9eef5;            /* główny tekst */
  --muted: #9aa3af;         /* opisowy, wtórny */

  /* Akcenty: żółto–pomarańczowe dla Talk/primary; niebieski zostaje dla Listen */
  --accent: #ffd54f;        /* brand yellow – Talk / PTT / primary */
  --accent-2:#0ea5e9;       /* blue – Listen */
  --danger:#ef4444;

  /* FIOLET = DOMENA VIDEO w całym AJA Intercom (sekcja 23). Ta sama wartość co `--adm-video`
     w panelu administratora, gdzie kolumna uprawnienia V była fioletowa od początku — teraz
     obowiązuje wszędzie: V, LIVE, MAIN, AUTO VIDEO i Ustawienia → VIDEO.
     Fiolet opisuje FUNKCJĘ, nigdy stanu nadawania: TX zostaje czerwony (`--danger`),
     a runtime własnej kamery ma własne kolory (READY = żółty, LIVE = czerwony, sekcja 24). */
  --video:#8b5cf6;          /* violet – VIDEO / V / LIVE / MAIN / AUTO VIDEO */
  --video-ink:#0d1013;      /* tekst na wypełnieniu fioletem */
  --video-dim:#c4b5fd;      /* fiolet stłumiony – obramowania, ikony w spoczynku */
  --ring-video: rgba(139,92,246,.30);

  /* CZERWIEŃ ADMINISTRATORSKA — ta sama wartość co `--adm-admin` w panelu administratora.
     Znaczy zawsze jedno: „to robi/widzi administrator", a nie alarm i nie funkcja VIDEO.
     Używana wyłącznie przez ramkę PODGLĄDU ADMINISTRATORA na scenie wideo. */
  --admin-eye:#d98a8a;
  --ring-admin-eye: rgba(217,138,138,.28);

  /* Chipy / kafelki */
  --chip:#151617;           
  --chip-active:#1a1b1d;    

  /* Pierścienie focus/selection */
  --ring: rgba(255, 213, 79, .35);    /* żółty glow (Talk) */
  --ring-blue: rgba(14,165,233,.30);  /* niebieski glow (Listen) */
  --ring-red: rgba(239,68,68,.32);     /* czerwony glow (aktywne nadawanie) */

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
}

*{ box-sizing:border-box; }
html,body{ height:100%; }
body{
  margin:0;
  background:var(--bg);
  color:var(--fg);
  font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* ---------- Przyciski i pola ---------- */
.btn{
  display:inline-flex; align-items:center; justify-content:center;
  gap:.6rem; min-height:52px; padding:.95rem 1.1rem; /* większy, wygodniejszy przycisk */
  background:#1f1f1f; color:var(--fg); border:0; border-radius:14px;
  font-weight:600; cursor:pointer; font-size:1rem;
}
.btn:hover{ filter:brightness(1.06); }
.btn:active{ transform:translateY(1px); }
.btn-primary{ background:var(--accent); color:#0a0a0a; }
.btn-danger{ background:var(--danger); }
.icon-btn{
  width:40px; height:40px; display:inline-flex; align-items:center; justify-content:center;
  background:transparent; border:1px solid #2a2a2a; border-radius:12px; color:var(--fg);
}
.input, select{
  width:100%; min-height:52px; padding:.85rem 1rem; /* większe pola dla lepszej czytelności */
  border-radius:12px; border:1px solid #2a2a2a;
  background:#111111; color:var(--fg); outline:none; font-size:16px;
}
.input:focus, select:focus{ border-color:var(--accent); box-shadow:0 0 0 6px var(--ring); }

/* ---------- Login ---------- */
.login-view{
  height:100svh;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:28px; /* większy oddech na krawędziach */
}
.login-card{
  width:min(640px, 100%); /* większe okno logowania */
  background:var(--card); border:1px solid #20293a; border-radius:20px;
  padding:28px 24px 22px; /* trochę większy padding */
  box-shadow:0 10px 40px rgba(0,0,0,.3);
}
/* Po zalogowaniu: jeśli panel jest widoczny, ukryj sekcję logowania,
   żeby nie zostawał duży czarny blok nad panelem */
body:has(#panel:not([style*="display:none"])) .login-view{
  display: none !important;
}
.app-title{ margin:0 0 8px; font-size:28px; letter-spacing:.3px; }
.subtitle{ margin:0 0 18px; color:var(--muted); }
.field{ display:flex; flex-direction:column; gap:.45rem; margin-bottom:12px; }
.server-fields{
  display:grid;
  grid-template-columns:minmax(0, 1fr) 112px;
  gap:10px;
  align-items:end;
}
.server-fields[hidden]{ display:none; }
.server-host-field,
.server-port-field{
  display:flex;
  flex-direction:column;
  gap:.45rem;
  min-width:0;
}
.server-host-field span,
.server-port-field span{
  color:var(--muted);
  font-size:.92rem;
}
.server-port-field .input{
  text-align:center;
  font-variant-numeric:tabular-nums;
}
@media (max-width:420px){
  .server-fields{ grid-template-columns:minmax(0, 1fr) 94px; }
}
.secondary-toggle{ display:flex; align-items:center; justify-content:space-between; gap:1rem; width:100%; background:none; border:0; padding:14px 15px; color:var(--fg); font:inherit; cursor:pointer; text-align:left; }
.secondary-toggle > span:first-child{ display:flex; flex-direction:column; gap:3px; }
.secondary-toggle small{ color:var(--muted); font-weight:400; }
.secondary-toggle-arrow{ display:inline-flex; width:24px; height:24px; flex:none; align-items:center; justify-content:center; color:var(--muted); font-size:1.25rem; line-height:1; }
.login-card .secondary-field{ margin:2px 0 14px; }
.login-card .secondary-toggle{ padding:11px 12px; border:1px solid #25282c; border-radius:12px; background:#131416; }
.login-card .secondary-toggle:hover{ background:#17191c; border-color:#30343a; }
.login-card .secondary-toggle b{ font-size:.9rem; }
.login-card .secondary-toggle small{ font-size:.74rem; }
.login-card #secondaryServerFields{ margin-top:10px; }
#settingsSecondaryFields{ display:flex; flex-direction:column; gap:.7rem; padding:0 15px 15px; }
#settingsSecondaryFields[hidden]{ display:none; }
.field-row{ display:flex; flex-wrap:wrap; gap:10px; }
.check{ display:flex; align-items:center; gap:.55rem; color:var(--muted); }
.hint{ margin-top:8px; color:var(--muted); font-size:.92rem; }
.login-error{
  margin:0 0 12px; padding:10px 12px; border:1px solid #7f1d1d; border-radius:10px;
  background:#2a0d0d; color:#fecaca; font-size:.9rem; line-height:1.35;
}
.login-error[hidden]{ display:none; }
#login_password.remembered-credential::placeholder{
  color:#d1d5db; opacity:1; letter-spacing:.18em;
}
.secure-connection-help{
  display:flex; flex-direction:column; gap:9px; margin-top:12px; padding:12px;
  border:1px solid #8a621d; border-radius:12px; background:#211a0d; color:#ffe0a3;
  font-size:.86rem; line-height:1.4;
}
.secure-connection-help[hidden]{ display:none; }
.secure-connection-help .btn{ align-self:flex-start; padding:9px 12px; }

/* ---------- Topbar ---------- */
.topbar{
  min-height:calc(58px + var(--safe-top));
  padding:calc(7px + var(--safe-top)) calc(10px + var(--safe-right)) 7px calc(10px + var(--safe-left));
  display:flex; align-items:center; gap:7px;
  background:linear-gradient(180deg, #0b0b0b, #090909);
  border-bottom:1px solid #1a1a1a; position:sticky; top:0; z-index:5;
}

/* --- iOS/standalone PWA: respektuj notch i status bar --- */
@media (display-mode: standalone), (display-mode: fullscreen) {
  .topbar{
    /* Bezpieczne marginesy również w landscape z notchem. */
    min-height: calc(58px + var(--safe-top));
    padding-top: calc(7px + var(--safe-top));
    padding-bottom: 7px;
    padding-left: calc(12px + var(--safe-left));
    padding-right: calc(12px + var(--safe-right));
  }
}
/* --- iOS/standalone PWA: respektuj notch i status bar --- */

.badge{
  font-size:.86rem; color:var(--muted); background:#10151d; border:1px solid #1f2937; padding:.25rem .5rem; border-radius:10px;
  white-space:nowrap;
}
.topbar-brand{ display:flex; align-items:center; gap:7px; min-width:64px; flex:1 1 auto; overflow:hidden; }
.topbar-logo{ width:34px; height:34px; flex:none; border-radius:9px; object-fit:cover; }
.topbar-identity{ display:flex; flex-direction:column; justify-content:center; min-width:0; line-height:1.12; }
.topbar-app-name{ color:var(--fg); font-size:.88rem; font-weight:750; white-space:nowrap; }
.topbar-user-line{ display:flex; align-items:center; gap:4px; min-width:0; margin-top:3px; color:var(--muted); font-size:.69rem; }
.user-name{
  color:var(--muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:2ch;
}
.user-name.admin-mode{
  color:#ffc400; font-weight:850;
}
/* Tekstowe uzupełnienie koloru (LAN/NET) — pokazywane, gdy przeglądarka nie zna transportu
   fizycznego i miejsce po ikonie jest wolne. Źródłem jest ta sama trasa co dla koloru kropki. */
.endpoint-label{ flex:none; color:#16a34a; font-size:.62rem; font-weight:800; letter-spacing:.06em; }
.endpoint-label.net{ color:#3b82f6; }
.topbar-status, .topbar-actions{ display:flex; align-items:center; gap:4px; flex:none; }
.topbar-metric{
  min-height:36px; padding:4px 7px; display:inline-flex; align-items:center; justify-content:center; gap:4px;
  border:1px solid #252525; border-radius:11px; background:#111315; color:#cbd5e1;
  white-space:nowrap; font-size:.68rem;
}
.topbar-metric[hidden]{ display:none; }
.topbar-metric svg{ flex:none; color:#aeb7c4; }
.topbar-metric-button{ font:inherit; cursor:pointer; }
.topbar-metric-button:active{ transform:translateY(1px); }
.metric-value{ font-size:.66rem; letter-spacing:.02em; font-variant-numeric:tabular-nums; }
.metric-unit{ margin-left:-3px; color:var(--muted); font-size:.58rem; }
/* Kolor kropki wynika WYŁĄCZNIE z TRASY sesji AJA (`data-connection-path`, ustawiane przez
   updateConnectionStatusIndicator w public/js/user.js). Fizyczny transport urządzenia — Ethernet,
   Wi-Fi, sieć komórkowa — jest osobną, mniejszą ikoną obok i NIGDY nie zmienia tego koloru:
     zielony  = AJA połączony lokalnie (sieć lokalna / hairpin NAT),
     niebieski = AJA połączony przez Internet / publiczny endpoint / VPS,
     czerwony = brak połączenia z AJA. */
.connection-dot{ width:8px; height:8px; border-radius:50%; flex:none; background:#dc2626; box-shadow:0 0 0 3px rgba(220,38,38,.14); }
.connection-metric[data-connection-path="offline"] .connection-dot{ background:#dc2626; box-shadow:0 0 0 3px rgba(220,38,38,.14); }
.connection-metric[data-connection-path="local"] .connection-dot{ background:#16a34a; box-shadow:0 0 0 3px rgba(22,163,74,.14); }
.connection-metric[data-connection-path="internet"] .connection-dot{ background:#3b82f6; box-shadow:0 0 0 3px rgba(59,130,246,.18); }
/* „Łączę" nie jest trasą, tylko stanem przejściowym — dopóki sesja nie jest gotowa, kropka
   pozostaje żółta, żeby zielony/niebieski zawsze znaczyły „działa". */
.connection-metric:has(#ws_state.reconnecting) .connection-dot{ background:#f59e0b; box-shadow:0 0 0 3px rgba(245,158,11,.14); }
.connection-transport-icon{ width:18px; height:18px; flex:none; color:#aeb7c4; }
.connection-transport-icon svg{ display:block; width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; }
.connection-transport-icon svg[hidden]{ display:none; }
.connection-state{ font-size:.62rem; }
.topbar-actions .icon-btn{ flex:none; }
@media (max-width: 420px) {
  .topbar{ gap:4px; padding-left:calc(7px + var(--safe-left)); padding-right:calc(7px + var(--safe-right)); }
  .topbar-brand{ gap:5px; }
  .topbar-logo{ width:31px; height:31px; border-radius:8px; }
  .topbar-status, .topbar-actions{ gap:3px; }
  .topbar-metric{ min-height:34px; padding:3px 5px; gap:3px; }
  .topbar-metric svg{ width:16px; height:16px; }
  .icon-btn{ width:36px; height:36px; }
}
@media (max-width: 350px) {
  .topbar-app-name{ font-size:.78rem; }
  .topbar-user-line{ font-size:.61rem; }
  .topbar-metric{ padding-inline:4px; }
  .topbar-metric .metric-value{ font-size:.59rem; }
  .connection-metric{ gap:2px; }
}

/* ---------- Layout ---------- */
.app-view{ height:100svh; display:flex; flex-direction:column; }
.intercom-layout{
  flex:1; min-height:0; display:grid; grid-template-rows: auto minmax(176px, 1fr) auto;
  height:calc(100svh - 58px - var(--safe-top)); /* topbar odjęty */
  padding:10px 12px calc(12px + var(--safe-bottom)); gap:10px; overflow:hidden;
}
/* `overflow:auto` + `safe center`: gdy chipy (2 rzędy przy >3 kanałach) nie mieszczą się w
   przydzielonym `1fr` wiersza `.intercom-layout` (bo środkowy wiersz z PTT urósł szerokościowo —
   patrz `.ptt-circle`), zwykłe `justify-content:center` w połączeniu z `overflow:hidden` na
   rodzicu obcinało treść symetrycznie, więc znikał GÓRNY rząd, a widoczny zostawał tylko drugi.
   `safe center` centruje tylko wtedy, gdy się mieści, w przeciwnym razie zachowuje się jak
   `flex-start` (patrz spec CSS Box Alignment) — nic nie znika, a jeśli mimo to zabraknie miejsca,
   panel dostaje własny scroll zamiast być obcięty przez `overflow:hidden` rodzica. Druga
   deklaracja `justify-content` jest CELOWA: przeglądarki bez wsparcia `safe` ignorują ją i
   zostają przy zwykłym `center` wyżej. */
.panel{
  background:var(--bg-2); border:1px solid #1f1f1f; border-radius:18px; padding:10px;
  display:flex; flex-direction:column; justify-content:center; justify-content:safe center;
  overflow:auto;
}
.panel-head{ display:flex; align-items:baseline; justify-content:space-between; margin-bottom:6px; }
.panel-title{ font-weight:700; letter-spacing:.08em; color:#e4e4e7; }
.panel-subtitle{ font-size:.85rem; color:var(--muted); }

/* ---------- Chips (kanały) ---------- */
/* 3 kolumny (jak w natywnej apce Android — ChannelGrid.chunked(3)), żeby układ przycisków
   nadawania i odsłuchu był identyczny na obu platformach. */
.chips{ display:grid; gap:8px; grid-template-columns: repeat(3, 1fr); }
.chip{
  user-select:none; -webkit-user-select:none;
  background:var(--chip); border:1px solid #2a2a2a; border-radius:14px;
  padding:.4rem .6rem; min-height:54px; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:2px; position:relative;
  font-weight:700; letter-spacing:.02em; color:#e4e4e7; cursor:pointer;
}
/* Nazwa pozostaje większa od numeru, ale obie linie używają stłumionego koloru. Dzięki temu
   kafelki nie konkurują wizualnie z nagłówkami sekcji i stanami aktywności. */
.chip-num{ font-weight:500; font-size:.80rem; line-height:1.1; color:var(--muted); }
.chip-name{
  font-weight:600; font-size:.91rem; line-height:1.15; color:var(--muted);
  max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.chip[data-disabled="true"]{ opacity:.45; filter:grayscale(1); pointer-events:none; }
/* Kanał zarządzany przez administratora: użytkownik NADAL widzi, gdzie jest aktywny, ale nie
   może tego zmienić. Kłódka jest jedynym dodatkiem — bez popupów przy każdym dotknięciu. */
.chip[data-managed="1"]::after{
  content:"🔒"; position:absolute; top:3px; right:5px; font-size:.62rem;
  line-height:1; opacity:.75; pointer-events:none;
}
.chip[data-managed="1"]{ cursor:default; }
.chip.talk.selected{ outline:2px solid var(--accent); box-shadow:0 0 0 6px var(--ring); }
.chip.listen.active{
  background:var(--chip-active);
  border-color:#2a2a2a;
  outline:2px solid var(--accent-2);
  box-shadow:0 0 0 6px var(--ring-blue);
}
/* PTT = ZABARWIENIE. Świadomie bez outline/box-shadow: ramka niesie informację „ten kanał
   mam włączony", a wcześniej czerwień od cudzego PTT ją zamalowywała i nie dało się poznać,
   czy odsłuch jest aktywny. */
.chip.talk.transmitting,
.chip.listen.talking{
  background:rgba(239,68,68,.20);
}
/* Ramkę przebarwia wyłącznie WŁASNE nadawanie. Na odsłuchu obramowanie zostaje niebieskie
   niezależnie od tego, kto mówi — cudze PTT niesie samo zabarwienie chipa. */
.chip.talk.transmitting{
  border-color:var(--danger);
}

/* REALNA MOWA. Drugi, niezależny stan obok PTT: na ODSŁUCHU „tam trwa rozmowa" (także na
   kanale, którego nie słuchasz), na NADAWANIU „mój mikrofon faktycznie coś nadaje", czyli
   odpowiedź na pytanie „trzymam PTT, ale czy mnie słychać?".

   Ramkę przebarwia na czerwono tylko WŁASNE nadawanie. Przy odbiorze obwódka zostaje
   niebieska cały czas — jednoznacznie „mam ten kanał włączony" — a to, że ktoś na nim mówi,
   niesie samo pulsujące zabarwienie chipa. Wcześniejsze przełączanie ramki na czerwień mieszało
   te dwa komunikaty. */
.chip.talk.selected.audio-active{
  outline-color:var(--danger);
  box-shadow:0 0 0 6px var(--ring-red);
}

/* Zakres pulsu jest w całości JAŚNIEJSZY od statycznego zabarwienia PTT (.20), więc
   „realnie mówi" nigdy nie wygląda słabiej niż „tylko trzyma mikrofon". */
@keyframes aja-audio-pulse{
  from{ background-color:rgba(239,68,68,.22); }
  to  { background-color:rgba(239,68,68,.40); }
}
.chip.listen.audio-active{
  animation: aja-audio-pulse 750ms ease-in-out infinite alternate;
}
/* Operator w hałasie potrzebuje różnicy, nie migania. */
@media (prefers-reduced-motion: reduce){
  .chip.listen.audio-active{
    animation:none;
    background-color:rgba(239,68,68,.34);
  }
}
/* --- TALLY LIGHTS (public/js/tally.js, docs/TALLY.md) ---------------------------------
   Nakładka ponad CAŁYM UI: fixed + inset:0 + pointer-events:none. Ramka jest rysowana
   w pseudo-elementach nakładki, więc nie zmienia layoutu i nie zabiera miejsca interkomowi.
   Animowana jest wyłącznie przezroczystość poświaty (bez geometrii i bez migania). */
.tally-overlay{
  position:fixed; inset:0; z-index:2147483000; pointer-events:none; display:none;
  --tally-color:#22c55e; --tally-glow:rgba(34,197,94,.55); --tally-edge:6px; --tally-period:1.8s;
}
.tally-overlay[data-state="PREVIEW"],
.tally-overlay[data-state="PROGRAM"]{ display:block; }
.tally-overlay[data-state="PROGRAM"]{
  --tally-color:#ff2a2a; --tally-glow:rgba(255,42,42,.70); --tally-edge:8px; --tally-period:1.2s;
}
.tally-overlay::before,
.tally-overlay::after{ content:""; position:absolute; inset:0; pointer-events:none; }
.tally-overlay::before{ border:var(--tally-edge) solid var(--tally-color); }
.tally-overlay::after{
  box-shadow:inset 0 0 34px 12px var(--tally-glow);
  animation:aja-tally-glow var(--tally-period) ease-in-out infinite alternate;
}
.tally-overlay__label{
  /* z-index: nad poświatą ::after, żeby napis był zawsze w pełni czytelny. */
  /* Wspólna reguła z iOS/Android: dolna krawędź etykiety (22 px) = safe-area-top + 8 px,
     czyli etykieta siedzi w strefie status baru / wycięcia, a nie na pasku narzędzi. */
  position:absolute; z-index:1; left:50%; top:max(0px, calc(env(safe-area-inset-top, 0px) - 14px)); transform:translateX(-50%);
  box-sizing:border-box; height:22px; display:flex; align-items:center;
  padding:0 16px; border-radius:0 0 9px 9px;
  background:var(--tally-color); color:#fff;
  font:800 13px/1.1 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; letter-spacing:.16em;
  text-shadow:0 1px 1px rgba(0,0,0,.35); box-shadow:0 2px 12px var(--tally-glow);
  pointer-events:none; user-select:none;
}
.tally-overlay[data-state="PREVIEW"] .tally-overlay__label{ color:#04160a; text-shadow:none; }
@keyframes aja-tally-glow{
  from{ opacity:.35; }
  to  { opacity:1; }
}
@media (prefers-reduced-motion: reduce){
  .tally-overlay::after{ animation:none; opacity:.8; }
}
/* --- AUTO VIDEO przy kafelku SLYSZE (sekcje 16-17, 31) ---------------------------------
   Kontrolka jest RODZENSTWEM kafelka, nie jego potomkiem: przycisk w przycisku jest
   niepoprawny w HTML i dawalby dwa nakladajace sie hitboxy. Slot przejmuje miejsce w gridzie,
   a `#listen_<ch>` zachowuje swoja geometrie i cala dotychczasowa logike. */
.chip-slot{ position:relative; display:flex; min-width:0; }
.chip-slot > .chip{ flex:1 1 auto; min-width:0; }
/* OSTRZEGAWCZA kamerka: „tu leci obraz, ktorego NIE ogladasz automatycznie" (sekcje 2-4).
   Pojawia sie WYLACZNIE przy AUTO OFF + realnie nadajacym zrodle. AUTO ON jest stanem
   normalnym i nie dostaje zadnego oznaczenia — kafelek zostaje czysty.
   Lewy gorny rog; prawy jest zajety przez klodke kanalu zarzadzanego (`[data-managed]`). */
.chip-video-missed{
  position:absolute; top:3px; left:4px; z-index:2;
  display:flex; align-items:center; justify-content:center;
  width:22px; height:22px; padding:0; border-radius:7px; cursor:pointer;
  color:var(--video); background:rgba(139,92,246,.14); border:1px solid rgba(139,92,246,.45);
  -webkit-tap-highlight-color: transparent;
}
.chip-video-missed:hover{ background:rgba(139,92,246,.26); }
.chip-video-missed[hidden]{ display:none !important; }
.chip-video-missed:focus-visible{ outline:2px solid var(--video); outline-offset:1px; }
/* Liczba POMIJANYCH streamow — tylko gdy jest ich wiecej niz jeden. Pochodzi z listy, ktora
   klient juz ma: nie powstaje dla niej ani jeden dodatkowy Consumer (sekcja 4). */
.chip-video-count{
  position:absolute; top:5px; left:28px; z-index:2; pointer-events:none;
  font-size:.6rem; font-weight:800; line-height:1; color:var(--video);
}
.chip-video-count[hidden]{ display:none !important; }
/* Kafelek SLYSZE ma wlasne przytrzymanie (wylacznik AUTO VIDEO), wiec dotyk nie moze
   uruchamiac zaznaczania tekstu ani menu kontekstowego. */
.chip.listen{ -webkit-touch-callout:none; }

/* --- TX VIDEO na kafelku MOWIE DO (sekcje 10-13) ---------------------------------------
   „Moj obraz wychodzi na ten kanal" — czyli `MOWIE DO ∩ T ∩ V`, a NIE samo uprawnienie V
   ani samo zaznaczenie TALK. Ten sam fioletowy symbol co przy SLYSZE, ale inne znaczenie:
   tam chodzi o cudzy obraz, ktory mnie omija (RX), tutaj o moj wlasny (TX). Rozroznia je
   sekcja ekranu. Swiadomie BEZ ramki i bez hitboxu: to czysta informacja, nie kontrolka. */
.chip-video-tx{
  position:absolute; top:4px; left:5px; z-index:2; pointer-events:none;
  display:flex; align-items:center; justify-content:center; color:var(--video);
}
.chip-video-tx[hidden]{ display:none !important; }

.chip .vu{
  position:absolute; left:0; bottom:0; height:2px; width:100%; background:#0a0a0a; border-radius:0 0 12px 12px; overflow:hidden;
}
.chip .vu > span{ display:block; height:100%; width:0%; background:var(--accent-2); transition:width .08s linear; }

/* ---------- PTT ---------- */
.ptt-panel{
  padding:8px 6px;
  position:relative;
  overflow:visible;
  min-height:0;
}
.ptt-actions{
  position:relative;
  display:flex;
  align-items:center;
  justify-content:center;
  width:100%;
  height:100%;
}
.ptt-btn{
  width:auto; background:transparent; border:0; color:inherit; cursor:pointer;
  display:flex; align-items:center; justify-content:center; flex-direction:column; gap:0;
}
.pttx-btn{
  position:absolute;
  right:calc(8px + var(--safe-right));
  bottom:8px;
  z-index:4;
  width:72px; min-width:72px; height:72px; margin:0; border-radius:21px;
  border:2px solid #334155; background:linear-gradient(180deg,#172033,#0d1320); color:#dbeafe;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:1px;
  font-weight:850; letter-spacing:.05em; touch-action:none; user-select:none; -webkit-user-select:none;
  box-shadow:0 8px 22px rgba(0,0,0,.42); cursor:pointer;
}
.pttx-btn small{ color:#93a4bb; font-size:.66rem; font-weight:650; letter-spacing:.02em; }
.pttx-btn.gesture-active{ border-color:#60a5fa; box-shadow:0 0 0 7px rgba(59,130,246,.18),0 8px 22px rgba(0,0,0,.4); }
.pttx-edge-tree{
  position:fixed; inset:0; z-index:1100; pointer-events:none; display:none;
  background:rgba(0,0,0,.64);
}
.pttx-edge-tree[aria-hidden="false"]{ display:block; }
.pttx-edge-main,.pttx-edge-child{
  position:fixed; width:112px; height:54px;
  border:2px solid #334155; border-radius:18px; background:rgba(10,16,28,.97); color:#e5eefb;
  display:flex; align-items:center; justify-content:center; gap:7px; padding:6px 8px;
  text-align:center; box-shadow:0 8px 24px rgba(0,0,0,.5); transition:transform .08s,border-color .08s,background .08s;
}
.pttx-edge-main{ z-index:2; }
.pttx-edge-child{ z-index:4; width:124px; border-color:#64748b; background:rgba(10,16,28,.99); font-weight:850; }
.pttx-edge-main span,.pttx-edge-child span{ min-width:0; font-size:.7rem; line-height:1.08; overflow-wrap:anywhere; }
.pttx-edge-main.active,.pttx-edge-child.active{ border-color:#fff; background:#1d4ed8; transform:scale(1.04); }
.pttx-edge-main.branch-active{ z-index:3; border-color:#fff; box-shadow:0 0 0 3px rgba(255,255,255,.22),0 8px 24px rgba(0,0,0,.5); }
.pttx-edge-main[data-color="green"],.pttx-edge-child[data-color="green"]{ border-color:#22c55e; }
.pttx-edge-main[data-color="yellow"],.pttx-edge-child[data-color="yellow"]{ border-color:#eab308; }
.pttx-edge-main[data-color="red"],.pttx-edge-child[data-color="red"]{ border-color:#ef4444; }
.pttx-edge-main[data-color="blue"],.pttx-edge-child[data-color="blue"]{ border-color:#3b82f6; }
.pttx-edge-main.active,.pttx-edge-child.active,.pttx-edge-main.branch-active{ border-color:#fff; }
.pttx-edge-preview{ position:fixed; z-index:6; top:calc(var(--safe-top) + 12px); left:50%; width:min(300px,calc(100vw - 24px)); min-height:76px; transform:translateX(-50%); display:flex; align-items:center; justify-content:center; gap:12px; padding:11px 14px; border:3px solid #64748b; border-radius:18px; background:rgba(10,16,28,.99); color:#fff; box-shadow:0 12px 34px rgba(0,0,0,.62); }
.pttx-edge-preview.neutral{ border-style:dashed; color:#94a3b8; font-size:.72rem; font-weight:800; letter-spacing:.06em; }
.pttx-edge-preview span{ display:flex; flex-direction:column; min-width:0; }.pttx-edge-preview strong{ overflow-wrap:anywhere; font-size:1.05rem; line-height:1.12; }.pttx-edge-preview small{ margin-top:4px; color:#94a3b8; font-size:.58rem; font-weight:850; letter-spacing:.05em; }
.pttx-edge-preview[data-color="green"]{ border-color:#22c55e; }.pttx-edge-preview[data-color="yellow"]{ border-color:#eab308; }.pttx-edge-preview[data-color="red"]{ border-color:#ef4444; }.pttx-edge-preview[data-color="blue"]{ border-color:#3b82f6; }

/* PRIORITY_MODE — lokalny wybór jednorazowego priorytetu przypięty do JEDNEGO kafla EDGE-TREE.
   Po ~2 s świadomego przytrzymania nad kaflem pojawiają się trzy małe znaczniki bezpośrednio
   nad nim (fallback: pod nim). To nie jest osobny panel ani kolejny poziom drzewa. */
.pttx-priority-markers{ position:fixed; inset:0; z-index:8; pointer-events:none; }
.pttx-prio-mark{
  position:fixed; display:flex; align-items:center; justify-content:center;
  border:2px solid #475569; border-radius:10px; background:rgba(8,13,22,.99); color:#cbd5e1;
  font-size:.66rem; font-weight:850; letter-spacing:.04em; box-shadow:0 8px 22px rgba(0,0,0,.6);
  transition:transform .08s,border-color .08s,background .08s,color .08s;
}
.pttx-prio-mark[data-priority="LOW"]{ border-color:#64748b; }
.pttx-prio-mark[data-priority="MEDIUM"]{ border-color:#eab308; }
.pttx-prio-mark[data-priority="HIGH"]{ border-color:#ef4444; }
.pttx-prio-mark.current{ color:#fff; transform:scale(1.06); }
.pttx-prio-mark.current[data-priority="LOW"]{ background:#334155; border-color:#cbd5e1; }
.pttx-prio-mark.current[data-priority="MEDIUM"]{ background:#78591a; border-color:#fde047; }
.pttx-prio-mark.current[data-priority="HIGH"]{ background:#7f1d1d; border-color:#fca5a5; }

/* W PRIORITY_MODE drzewo jest lokalnie zamrożone: aktywny kafel wyróżniony, reszta wygaszona
   i nie łapie pointer/touch eventów (hit-testing należy do znaczników). */
.pttx-edge-tree.pttx-priority-mode .pttx-edge-main:not(.priority-locked),
.pttx-edge-tree.pttx-priority-mode .pttx-edge-child:not(.priority-locked){
  pointer-events:none; opacity:.28; filter:saturate(.4);
}
.pttx-edge-main.priority-locked,
.pttx-edge-child.priority-locked{
  border-color:#fff; box-shadow:0 0 0 3px rgba(255,255,255,.28),0 10px 26px rgba(0,0,0,.55);
}

/* Subtelny feedback dwell: cienkie narastające obramowanie (0→100% w PTTX_PRIORITY_HOLD_MS).
   Ma tylko sugerować „potrzymaj chwilę dłużej, pojawi się wybór priorytetu". */
.pttx-edge-main.pttx-dwelling::after,
.pttx-edge-child.pttx-dwelling::after{
  content:''; position:absolute; left:0; bottom:0; height:3px; width:0;
  border-bottom-left-radius:16px; border-bottom-right-radius:16px;
  background:rgba(147,197,253,.9);
  animation:pttxHoldProgress var(--pttx-hold-ms,2000ms) linear forwards;
}
.pttx-edge-main.pttx-dwelling,
.pttx-edge-child.pttx-dwelling{ overflow:hidden; }
@keyframes pttxHoldProgress{ from{ width:0; } to{ width:100%; } }
@media (prefers-reduced-motion: reduce){
  .pttx-edge-main.pttx-dwelling::after,
  .pttx-edge-child.pttx-dwelling::after{ animation:none; width:100%; opacity:.5; }
}

/* Dwie klasy są celowe: późniejsza bazowa reguła `.sheet { z-index:20 }` nie może
   zepchnąć panelu pod scrim (z-index:44), bo wtedy niewidoczny scrim przechwytuje
   wszystkie kliknięcia, fokus pól i gest przewijania. */
.sheet.pttx-sheet{ z-index:45; pointer-events:auto; }
.pttx-sheet + .sheet-scrim{ z-index:44; }
.pttx-subtitle{ color:var(--muted); font-size:.75rem; margin-top:2px; }
.pttx-groups-heading{ display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap:4px 12px; }
.pttx-reset-defaults{
  flex:none; max-width:100%; border:0; background:none; padding:4px 2px; color:#93a4bb; cursor:pointer;
  font:inherit; font-size:.68rem; font-weight:700; text-decoration:underline;
}
.pttx-reset-defaults::before{ content:"↺ "; }
.pttx-reset-defaults:hover,.pttx-reset-defaults:focus-visible{ color:var(--fg); outline:none; }
.pttx-reset-defaults[hidden]{ display:none; }
.pttx-preset-list{ display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,340px),1fr)); align-items:start; gap:9px; margin-top:10px; }
.pttx-group-card{ display:flex; min-width:0; overflow:hidden; border:1px solid #263243; border-left:5px solid #64748b; border-radius:12px; background:rgba(255,255,255,.025); }
.pttx-group-card[data-color="green"]{ border-left-color:#22c55e; }.pttx-group-card[data-color="yellow"]{ border-left-color:#eab308; }.pttx-group-card[data-color="red"]{ border-left-color:#ef4444; }.pttx-group-card[data-color="blue"]{ border-left-color:#3b82f6; }
.pttx-group-open{ display:flex; flex:1; min-width:0; flex-direction:column; gap:7px; border:0; background:transparent; color:var(--fg); padding:10px; text-align:left; cursor:pointer; }
.pttx-group-open:hover,.pttx-group-open:focus-visible{ background:rgba(255,255,255,.045); outline:none; }
.pttx-group-head{ display:grid; grid-template-columns:32px minmax(0,1fr) auto; align-items:center; gap:9px; color:#bfdbfe; font-size:.84rem; }
.pttx-group-head strong{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pttx-position-number{ width:27px; height:27px; display:grid; place-items:center; border-radius:50%; background:#1e293b; color:#dbeafe; font-size:.72rem; }
.pttx-group-edit{ color:#94a3b8; font-size:.64rem; font-weight:700; white-space:nowrap; }
.pttx-group-summaries{ display:flex; flex-direction:column; gap:4px; }
.pttx-item-summary{ display:grid; grid-template-columns:82px minmax(0,1fr) 20px 12px; align-items:center; gap:5px; min-width:0; }
.pttx-item-summary small{ color:#7f91a8; font-size:.57rem; font-weight:800; }
.pttx-item-summary > span{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:.76rem; font-weight:650; }
.pttx-item-summary > i{ min-height:1px; font-size:.68rem; font-style:normal; text-align:center; }
.pttx-summary-color{ width:10px; height:10px; border-radius:50%; background:#64748b; }.pttx-summary-color[data-color="green"]{ background:#22c55e; }.pttx-summary-color[data-color="yellow"]{ background:#eab308; }.pttx-summary-color[data-color="red"]{ background:#ef4444; }.pttx-summary-color[data-color="blue"]{ background:#3b82f6; }
.pttx-custom-section textarea,.pttx-save-row select{
  min-height:42px; border:1px solid #303947; border-radius:9px; background:#10151d; color:var(--fg); padding:8px;
}
.pttx-send-preset{ align-self:center; width:48px; height:48px; margin:0 8px 0 4px; border:0; border-radius:50%; background:transparent; color:#60a5fa; cursor:pointer; font-size:1.5rem; line-height:1; }
.pttx-send-preset:hover,.pttx-send-preset:focus-visible{ background:#17365f; color:#bfdbfe; outline:none; }
.pttx-editor-backdrop{ position:absolute; z-index:1; inset:0; border-radius:18px 18px 0 0; background:rgba(2,6,12,.76); backdrop-filter:blur(2px); }
.pttx-editor-backdrop[hidden]{ display:none; }
.pttx-preset-editor{ position:absolute; z-index:2; left:50%; top:50%; width:min(620px,calc(100% - 28px)); max-height:calc(100% - 28px); transform:translate(-50%,-50%); display:flex; flex-direction:column; overflow:hidden; border:1px solid #3b4d65; border-radius:16px; background:#0d1420; box-shadow:0 24px 70px rgba(0,0,0,.65); }
.pttx-preset-editor[hidden]{ display:none; }
.pttx-editor-header{ display:flex; align-items:flex-start; justify-content:space-between; gap:12px; padding:14px 14px 11px; border-bottom:1px solid #263243; }
.pttx-editor-header .icon-btn{ flex:none; font-size:1.7rem; line-height:1; }
.pttx-editor-items{ display:flex; flex-direction:column; gap:10px; overflow-y:auto; padding:12px 14px; }
.pttx-editor-item{ display:flex; flex-direction:column; gap:8px; padding:11px; border:1px solid #263243; border-left:4px solid #64748b; border-radius:11px; background:rgba(255,255,255,.02); }
.pttx-editor-item[data-color="green"]{ border-left-color:#22c55e; }.pttx-editor-item[data-color="yellow"]{ border-left-color:#eab308; }.pttx-editor-item[data-color="red"]{ border-left-color:#ef4444; }.pttx-editor-item[data-color="blue"]{ border-left-color:#3b82f6; }
.pttx-editor-item-heading{ color:#94a3b8; font-size:.65rem; font-weight:850; letter-spacing:.05em; }
.pttx-editor-field{ display:flex; flex-direction:column; gap:6px; color:#bfdbfe; font-size:.78rem; font-weight:700; }
.pttx-editor-field input,.pttx-editor-field select{ width:100%; min-height:46px; border:1px solid #303947; border-radius:9px; background:#10151d; color:var(--fg); padding:9px 10px; font:inherit; font-size:1rem; }
.pttx-editor-controls{ display:grid; grid-template-columns:1fr; gap:8px; }
.pttx-editor-control{ display:flex; min-width:0; flex-direction:column; gap:6px; color:#bfdbfe; font-size:.78rem; font-weight:700; }
.pttx-editor-control select{ width:100%; min-height:46px; border:1px solid #303947; border-radius:9px; background:#10151d; color:var(--fg); padding:9px 10px; font:inherit; }
.pttx-editor-speak{ min-height:40px; }
.pttx-editor-actions{ display:grid; grid-template-columns:1fr 1fr; gap:8px; padding:11px 14px calc(11px + var(--safe-bottom)); border-top:1px solid #263243; background:#0d1420; }
.pttx-custom-section{ display:flex; flex-direction:column; gap:8px; }
.pttx-custom-section textarea{ width:100%; resize:vertical; font:inherit; }
.pttx-custom-meta{ display:flex; align-items:center; justify-content:space-between; gap:10px; color:var(--muted); font-size:.75rem; }
.pttx-speak-option{ display:inline-flex; align-items:center; gap:7px; color:#bfdbfe; font-size:.78rem; font-weight:700; cursor:pointer; }
.pttx-speak-option input{ width:18px; height:18px; margin:0; accent-color:#3b82f6; }
/* Priorytet presetu w edytorze: Niski / Średni / Wysoki (LOW domyślny). Osobno od „Czytaj". */
.pttx-editor-priority{ margin-top:2px; }
.pttx-priority-group{ display:grid; grid-template-columns:repeat(3,1fr); gap:6px; }
.pttx-priority-choice{
  min-height:42px; border:1px solid #303947; border-radius:9px; background:#10151d; color:#9fb0c3;
  font:inherit; font-size:.78rem; font-weight:800; letter-spacing:.02em; cursor:pointer;
}
.pttx-priority-choice[aria-pressed="true"]{ background:#1d4ed8; border-color:#93c5fd; color:#fff; }
.pttx-priority-choice[data-priority="MEDIUM"][aria-pressed="true"]{ background:#78591a; border-color:#fde047; }
.pttx-priority-choice[data-priority="HIGH"][aria-pressed="true"]{ background:#7f1d1d; border-color:#fca5a5; }
/* Dyskretny link „przywróć domyślne" przy checkboxie „Czytaj wiadomość" — pojawia się tylko
   gdy `speak` odbiega od domyślnej wartości dla wybranego priorytetu. */
.pttx-speak-reset{
  margin-left:auto; border:0; background:none; padding:4px 2px; cursor:pointer;
  color:#93a4bb; font:inherit; font-size:.68rem; font-weight:700; text-decoration:underline;
}
.pttx-speak-reset:hover,.pttx-speak-reset:focus-visible{ color:var(--fg); outline:none; }
.pttx-speak-reset[hidden]{ display:none; }
.pttx-editor-speak{ display:flex; align-items:center; gap:7px; }
.pttx-summary-prio{ font-style:normal; font-weight:900; font-size:.72rem; color:#94a3b8; }
.pttx-summary-prio[data-priority="MEDIUM"]{ color:#eab308; }
.pttx-summary-prio[data-priority="HIGH"]{ color:#ef4444; }
.pttx-save-row{ display:grid; grid-template-columns:110px 1fr; gap:8px; }
.presence-pttx-last{ display:block; color:#bfdbfe; font-size:.73rem; font-weight:650; margin-top:2px; white-space:normal; }
.presence-pttx-last[data-color="green"]{ color:#22c55e; }
.presence-pttx-last[data-color="yellow"]{ color:#eab308; }
.presence-pttx-last[data-color="red"]{ color:#ef4444; }
.presence-pttx-last[data-color="blue"]{ color:#3b82f6; }
.presence-pttx-history{ border-top:1px solid rgba(255,255,255,.08); padding-top:10px; }
.presence-pttx-history-title{ color:#9fb0c3; font-size:.75rem; font-weight:750; margin-bottom:6px; }
.presence-pttx-history-row{ display:grid; grid-template-columns:48px 1fr; gap:5px; font-size:.74rem; padding:3px 0 3px 6px; border-left:3px solid #64748b; }
.presence-pttx-history-row[data-color="green"]{ border-left-color:#22c55e; }
.presence-pttx-history-row[data-color="yellow"]{ border-left-color:#eab308; }
.presence-pttx-history-row[data-color="red"]{ border-left-color:#ef4444; }
.presence-pttx-history-row[data-color="blue"]{ border-left-color:#3b82f6; }

@media (max-width:900px){
  .pttx-preset-list{ display:flex; flex-direction:column; }
  .pttx-group-card{ width:100%; }
}

@media (max-width:520px){
  .pttx-btn{ width:64px; min-width:64px; height:64px; border-radius:19px; }
  .pttx-edge-main{ width:104px; }
  .pttx-edge-child{ width:116px; }
  .pttx-item-summary{ grid-template-columns:76px minmax(0,1fr) 18px 10px; }
  .pttx-send-preset{ width:42px; margin-inline:2px 4px; }
  .pttx-preset-editor{ inset:0; width:auto; max-height:none; transform:none; border-width:0; border-radius:18px 18px 0 0; }
  .pttx-editor-header{ padding:12px; }
  .pttx-editor-items{ padding:10px 12px; }
  .pttx-editor-item{ padding:10px; }
  .pttx-editor-actions{ padding-inline:12px; }
}
.ptt-btn:focus,
.ptt-btn:focus-visible{
  outline:none;
}

/* Stały środkowy pas dostaje wolną wysokość. Rośnie wyłącznie jego zawartość:
   LISTEN/TALK zachowują pozycje przy wejściu/wyjściu VIDEO. */
.ptt-stage-wrap{ position:relative; display:inline-flex; }
.ptt-stage-wrap[data-video="true"]{
  /* `--stage-ratio` pochodzi z metadanych wideo. Dzięki temu obrys stage'a kończy
     się razem z kadrem, zamiast obejmować szeroki letterbox na dużych ekranach. */
  /* Wysokość pozostaje ograniczona do środkowego pasa — LISTEN/TALK zachowują
     swoje kafelki nad i pod podglądem. Szerokość wynika wyłącznie z proporcji kadru. */
  width:auto; height:min(560px, calc(100% - 80px)); max-width:100%;
  aspect-ratio:var(--stage-ratio, 16 / 9); max-height:calc(100% - 80px);
  transform:translateY(-40px);
}
.ptt-stage-wrap[data-video="true"] .ptt-btn{ width:100%; height:100%; padding:0; }
.ptt-stage-wrap[data-video="true"] .ptt-circle{
  width:100%; height:100%; min-height:0; aspect-ratio:auto;
}
/* Pauza FOLLOW_PTT ma natychmiast przywrocic zwykly footprint PTT. To jest zabezpieczenie
   warstwy prezentacji: Consumer i srcObject moga pozostac cieple, ale nie utrzymuja geometrii
   playera ani jego OSD. */
.ptt-stage-wrap[data-video="false"]{
  width:auto; height:auto; max-height:none; transform:none;
}
.ptt-stage-wrap[data-video="false"] .ptt-stage-video,
.ptt-stage-wrap[data-video="false"] .ptt-stage-meta,
.ptt-stage-wrap[data-video="false"] .ptt-stage-controls{ display:none !important; }
.cam-ptxt-bar{
  position:absolute; bottom:0; right:0; left:0;
  display:flex; align-items:center; justify-content:flex-end; gap:10px;
}
.cam-ptxt-bar .pttx-btn{ position:static; }
/* Własny podgląd. Jeden `<video>` w kontenerze `#cam_self_pip`; zmiana main <-> pip <-> pip
   powiększony to WYŁĄCZNIE zmiana CSS, więc lokalny track i srcObject pozostają stabilne. */
.cam-self-pip{
  position:absolute; z-index:2; overflow:hidden; background:#000; padding:0; margin:0;
  border:0; -webkit-tap-highlight-color:transparent; touch-action:none;
  transition:width .18s ease, height .18s ease, inset .18s ease, border-radius .18s ease;
}
.cam-self-pip[hidden]{ display:none !important; }
.cam-self-preview{ width:100%; height:100%; object-fit:contain; background:#000; pointer-events:none; display:block; }
/* Brak zdalnego obrazu: własny podgląd wypełnia CAŁĄ scenę i przepuszcza dotyk do PTT. */
.ptt-stage-wrap[data-self="main"] .cam-self-pip{
  inset:0; width:100%; height:100%; border-radius:14px; pointer-events:none; cursor:default;
}
/* Zdalny obraz na scenie: dolny lewy dok, pomiedzy stage'em i dolnymi akcjami. Gorna krawedz
   nachodzi na kadr o stale 16 px — wystarczajaco, by pokazac relacje, ale nie zaslaniac twarzy.
   Te same proporcje i maksymalny rozmiar ma wariant natywny. */
.ptt-stage-wrap[data-self="pip"] .cam-self-pip{
  inset:calc(100% - 16px) auto auto 8px;
  width:clamp(96px, 40%, 170px); height:auto; aspect-ratio:16/9;
  max-width:calc(100% - 16px); max-height:calc(100% - 16px);
  border:1px solid rgba(255,255,255,.72); border-radius:10px;
  box-shadow:0 6px 20px rgba(0,0,0,.6); cursor:grab; pointer-events:auto;
}
.ptt-stage-wrap[data-self="pip"] .cam-self-pip[data-expanded="true"]{
  inset:auto auto -72px 8px;
  width:clamp(160px, 62%, 280px);
}
.ptt-stage-wrap[data-self="pip"] .cam-self-pip[data-dragging="true"]{ cursor:grabbing; transition:none; }
.ptt-stage-wrap[data-self="pip"] .cam-self-pip:focus-visible{ outline:2px solid var(--video, #8b5cf6); outline-offset:2px; }
/* Ikona-podpowiedź „zmień rozmiar" w rogu nakładki; sam obraz i tak jest klikalny.
   Glif (⤢ / ⤡) przełącza `videoPanel.js` razem z `data-expanded`. */
.cam-self-pip-hint{
  position:absolute; right:5px; bottom:4px; z-index:2; pointer-events:none;
  font-size:.8rem; line-height:1; color:#fff; text-shadow:0 1px 3px #000; opacity:.85;
}
.ptt-stage-wrap[data-self="main"] .cam-self-pip-hint{ display:none; }
/* ---------- PODGLĄD ADMINISTRATORA ----------
   Operator ma WIDZIEĆ, że ktoś patrzy w jego kamerę. Ramka obejmuje CAŁĄ scenę (razem z
   własnym podglądem, niezależnie od tego, czy jest nakładką, czy wypełnia kadr), więc jest
   nie do przeoczenia i nie zależy od trybu `data-self`. Świadomie NIE blokuje żadnej akcji:
   CAM OFF działa normalnie — to nadal kamera użytkownika.
   `armed` = kamerę uruchomił administrator do podglądu (obraz nigdzie nie idzie),
   `live`   = administrator ogląda obraz, który i tak już nadajesz. */
.ptt-stage-wrap[data-admin-preview="armed"],
.ptt-stage-wrap[data-admin-preview="live"]{
  outline:3px solid var(--admin-eye);
  outline-offset:2px;
  border-radius:16px;
  box-shadow:0 0 0 8px var(--ring-admin-eye);
}
.stage-admin-preview{
  position:absolute; top:6px; left:50%; transform:translateX(-50%); z-index:4;
  pointer-events:none; white-space:nowrap;
  padding:3px 9px; border-radius:999px;
  color:#1a0c0d; background:var(--admin-eye);
  font-size:.6rem; font-weight:850; letter-spacing:.08em;
  box-shadow:0 2px 10px rgba(0,0,0,.55);
}
.stage-admin-preview[hidden]{ display:none !important; }
/* Kamera uruchomiona przez administratora tylko do podglądu pulsuje — to stan przejściowy,
   który za chwilę albo pójdzie na kanały, albo zgaśnie. */
.ptt-stage-wrap[data-admin-preview="armed"] .stage-admin-preview{ animation:adminEyePulse 1.6s ease-in-out infinite; }
@keyframes adminEyePulse{ 0%,100%{ opacity:1; } 50%{ opacity:.55; } }
@media (prefers-reduced-motion: reduce){
  .ptt-stage-wrap[data-admin-preview="armed"] .stage-admin-preview{ animation:none; }
}

/* „TY" w rogu nakładki — czytelne oznaczenie, że to WŁASNY obraz, nie kadr gościa. */
.stage-self-badge{
  position:absolute; top:6px; left:6px; z-index:2; pointer-events:none;
  padding:2px 5px; border-radius:5px; color:#fff; background:rgba(0,0,0,.62);
  font-size:.58rem; font-weight:850; letter-spacing:.08em;
}
.ptt-stage-wrap[data-self="main"] .stage-self-badge{ display:none; }
.cam-ptxt-bar #btn_video{ min-height:44px; width:96px; min-width:96px; touch-action:manipulation; }
/* PTXT zachowuje własny gest, poza obrazem i poza hitboxem PTT. Tylko małe miejsce
   przy prawej krawędzi, bez rezerwowania bocznej kolumny na całą wysokość. */
/* Author display:flex nadpisuje przeglądarkowe [hidden]. Usuwamy także hitbox i focus. */
.ptt-stage-controls[hidden], .ptt-stage-meta[hidden], .ptt-stage-video[hidden],
.stage-badge[hidden], .stage-btn[hidden], .stage-self-badge[hidden],
.video-quick-notice[hidden]{ display:none !important; }
.video-quick{ display:flex; position:relative; align-items:center; gap:4px; }
.video-quick[hidden]{ display:none !important; }
#btn_video{
  white-space:nowrap; font-size:0; font-weight:800; line-height:1.05;
  display:inline-flex; flex-direction:column; align-items:center; justify-content:center;
}
#btn_video::before, #btn_video::after{ font-size:.68rem; line-height:1.05; }
#btn_video::before{ content:"CAM"; }
#btn_video::after{ content:"OFF"; }
#btn_video[data-state="VIDEO_ARMED"]::after{ content:"ON"; }
#btn_video[data-state="VIDEO_LIVE"]::after{ content:"LIVE"; }
#btn_video[data-state="VIDEO_ERROR"]::after{ content:"BŁĄD"; }
/* CAM opisuje RUNTIME wlasnej kamery, nie funkcje VIDEO: OFF neutralny,
   ON zolty (przygotowana, ale nie nadaje), LIVE czerwony (klatki plyna), ERROR bledny.
   Fiolet jest tu swiadomie NIEUZYWANY — nalezy do domeny VIDEO, nie do stanu nadawania. */
#btn_video[data-state="VIDEO_ARMED"]{ color:var(--accent); border-color:var(--accent); }
#btn_video[data-state="VIDEO_LIVE"]{ color:#ffe4e2; background:#3a1613; border-color:var(--danger); font-weight:850; }
#btn_video[data-state="VIDEO_ERROR"]{ color:var(--danger); }
#btn_video[aria-disabled="true"]{ color:var(--muted); background:transparent; border-color:#454545; }
/* Wskazanie WLASNEGO zrodla jako MAIN — akcja administratora w Ustawieniach → VIDEO. */
.video-main-toggle{ white-space:nowrap; font-size:.62rem; font-weight:800; letter-spacing:.05em;
  color:var(--video-dim); border-color:var(--video); }
.video-main-toggle[aria-pressed="true"]{ color:var(--video-ink); background:var(--video); border-color:var(--video); }
.video-main-toggle[hidden]{ display:none !important; }
#btn_video_settings{ min-width:34px; font-size:.8rem; font-weight:800; color:var(--video-dim); border-color:var(--video); }
.video-quick-notice{
  position:absolute; bottom:calc(100% + 4px); right:0; width:max-content;
  max-width:min(300px, 85vw); padding:4px 8px; z-index:12;
  color:var(--fg); background:var(--bg-2); border:1px solid #454545; border-radius:8px;
  font-size:.75rem;
}

/* Obraz jest WARSTWA W SRODKU istniejacego hitboxu PTT. `pointer-events:none` sprawia, ze
   dotyk przechodzi przez niego wprost do `.ptt-circle` — czyli do niezmienionych handlerow PTT.
   `contain` + letterbox: rozne proporcje zrodel nie ruszaja kwadratowego footprintu PTT. */
.ptt-stage-video{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:contain; background:#000;
  border-radius:14px;
  pointer-events:none;
  z-index:1;
}
/* Androidowy kompromis prezentacyjny: pionowy kadr w inline PTT wypełnia szeroki stage
   przez crop, więc nie ma czarnych boków. Fullscreen niżej zawsze wraca do pełnego kadru. */
.ptt-stage-wrap[data-frame-orientation="portrait"]:not(:fullscreen) .ptt-stage-video,
.ptt-stage-wrap[data-frame-orientation="portrait"]:not(:fullscreen) .cam-self-preview{ object-fit:cover; }
/* Klasyczna twarz PTT i obraz to dwie alternatywne zawartosci TEGO SAMEGO stage. Znika sam
   NAPIS PTT — pasek VU zostaje, bo to jedyny wskaznik „czy mnie faktycznie slychac", i byloby
   regresja operatorska gasic go tylko dlatego, ze leci obraz. Siedzi nad kontrolkami, wiec
   nic sie nie nakłada i nic nie zasłania srodka kadru. */
.ptt-btn[data-video="true"] .ptt-circle-inner{
  position:absolute; left:0; right:0; bottom:44px; top:auto;
  width:auto; height:auto; z-index:2; pointer-events:none;
  background:none; border:0; gap:0;
}
.ptt-btn[data-video="true"] .ptt-text,
.ptt-btn[data-video="true"] .ptt-channel{ display:none; }
.ptt-btn[data-video="true"] .ptt-ptt-vu{ height:45%; margin-top:0; }
.ptt-btn[data-video="true"] .ptt-circle{ background:#000; }

/* Dyskretny pasek opisu przy GORNEJ krawedzi — nigdy na srodku obrazu (sekcja 2). */
.ptt-stage-meta{
  position:absolute; top:6px; left:8px; right:8px; z-index:3;
  display:flex; gap:6px; align-items:center; pointer-events:none;
  font-size:.72rem; line-height:1;
}
.stage-name{
  color:#e5e7eb; text-shadow:0 1px 3px #000;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.stage-badge{ font-weight:800; letter-spacing:.06em; padding:3px 6px; border-radius:5px; }
/* Header playera niesie JEDNA mocna informacje: `MAIN · nazwa` (sekcja 16). MAIN jest
   fioletowym PREFIKSEM nazwy, a nie konkurencyjnym badge'em, wiec nie psuje jej czytelnosci. */
.stage-main-prefix{
  color:var(--video); font-weight:850; letter-spacing:.06em; text-shadow:0 1px 3px #000;
}
.stage-main-prefix[hidden]{ display:none !important; }
/* LIVE to juz tylko mala fioletowa kropka — obraz i tak realnie sie renderuje. */
.stage-live-dot{
  width:7px; height:7px; border-radius:50%; background:var(--video);
  box-shadow:0 0 0 2px rgba(0,0,0,.55); flex:none;
}
.stage-live-dot[hidden]{ display:none !important; }
/* Rzadziej uzywane kontrolki chowaja sie pod „⋯" — stale widoczne zostaja pelny ekran
   i zamkniecie (sekcja 15). */
.stage-more-group{ display:flex; gap:4px; }
.stage-more-group[hidden]{ display:none !important; }

/* Male kontrolki przy DOLNEJ krawedzi. Sa rodzenstwem `#pttBtn`, wiec ich dotyk fizycznie nie
   moze trafic w hitbox PTT; `stopPropagation` w videoPanel.js jest druga, jawna warstwa. */
.ptt-stage-controls{
  position:absolute; bottom:6px; right:8px; z-index:3;
  display:flex; gap:4px;
}
.stage-btn{
  min-width:28px; height:28px; padding:0 6px;
  font:inherit; font-size:.72rem; font-weight:700; line-height:1;
  color:#ede9fe; background:rgba(14,10,26,.72); border:1px solid rgba(139,92,246,.67);
  border-radius:8px; cursor:pointer;
}
.stage-btn:hover{ background:rgba(30,20,55,.85); }
.stage-btn[aria-pressed="true"]{ color:var(--video-ink); background:var(--video); border-color:var(--video); }
.stage-btn-close{ color:#ffd9d5; border-color:#ef4444aa; }
.stage-btn-close:hover{ background:rgba(60,16,16,.85); }

/* Pelny ekran pokazuje TEN SAM element `<video>` i TEGO SAMEGO Consumera — zero ponownego
   consume. Kolo traci kwadratowy footprint tylko na czas fullscreena, wiec cala powierzchnia
   nadal jest hitboxem PTT. */
.ptt-stage-wrap[data-video="true"]:fullscreen{ width:100vw; height:100vh; max-height:none; transform:none; background:#000; }
.ptt-stage-wrap[data-video="true"]:fullscreen .ptt-btn{ width:100%; height:100%; }
.ptt-stage-wrap[data-video="true"]:fullscreen .ptt-circle{
  width:100%; height:100%; max-width:none; max-height:none;
  aspect-ratio:auto; border-radius:0;
}
.ptt-stage-wrap[data-video="true"]:fullscreen .ptt-stage-video,
.ptt-stage-wrap[data-video="true"]:fullscreen .cam-self-preview{
  object-fit:contain; border-radius:0;
}
.ptt-stage-wrap[data-self="main"]:fullscreen .cam-self-pip{ border-radius:0; }
.ptt-stage-wrap[data-self="pip"]:fullscreen .cam-self-pip{
  inset:auto auto 16px 16px;
  width:clamp(180px, 28vw, 320px); max-width:calc(100% - 32px); max-height:calc(100% - 32px);
}
.ptt-stage-wrap[data-self="pip"]:fullscreen .cam-self-pip[data-expanded="true"]{
  width:clamp(280px, 48vw, 560px);
}
.ptt-label-top{ color:var(--muted); font-size:.95rem; }
/* `min(48vw, 30svh)`, nie goły `48vw`: środkowy wiersz `.intercom-layout` jest `auto`, więc
   rozmiar koła PTT bezpośrednio odbiera miejsce panelom LISTEN/TALK nad i pod nim (oba `1fr`
   w tej samej, zafiksowanej wysokości siatki). Przy samym `48vw` rozciąganie okna W POZIOMIE
   (bez zmiany wysokości) powiększało koło i ściskało panele czipów aż ich drugi rząd przestawał
   się mieścić — patrz komentarz przy `.panel`. Dodatkowy człon `30svh` nie pozwala kołu urosnąć
   ponad rozsądny ułamek dostępnej WYSOKOŚCI, niezależnie od szerokości okna. */
.ptt-circle{
  width: clamp(160px, min(48vw, 30svh), 280px);
  height: clamp(160px, min(48vw, 30svh), 280px);
  border-radius:16px; /* było 50% */
  background: linear-gradient(180deg, #1a1a1a 0%, #0f0f0f 100%); /* lepsze dla prostokąta */
  border: 2px solid #262626; 
  box-shadow:
    inset 0 8px 30px rgba(0,0,0,.55),
    0 10px 30px rgba(0,0,0,.35);
  display:grid; place-items:center; position:relative;
  aspect-ratio: 1 / 1; /* gwarancja kwadratu przy zmianach layoutu */
}

.ptt-btn:not([data-transmitting="true"]) .ptt-circle:hover{
  box-shadow:
    inset 0 8px 30px rgba(0,0,0,.55),
    0 10px 30px rgba(0,0,0,.35),
    0 0 0 3px rgba(154,163,175,.12);
}

.ptt-btn:not([data-transmitting="true"]):focus-visible .ptt-circle{
  box-shadow:
    inset 0 8px 30px rgba(0,0,0,.55),
    0 10px 30px rgba(0,0,0,.35),
    0 0 0 4px rgba(154,163,175,.16);
}
.ptt-circle-inner{
  width: 78%; height: 78%; border-radius:50%;
  background: radial-gradient(100% 100% at 50% 0%, #121212 0%, #0d0d0d 100%);
  border:1px solid #1a1a1a; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:8px;
}
.ptt-text{ font-size: 2.2rem; font-weight: 800; letter-spacing:.03em; color:var(--fg); }
.ptt-channel{ font-weight:700; color:var(--muted); }
.ptt-ptt-vu{
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  width: 6px;
  height: 60%;
  background: rgba(0,0,0,0.4);
  border-radius: 4px;
  overflow: hidden;
  visibility: hidden;
  transition: visibility 0.15s ease;
}
.ptt-ptt-vu > span{
  display: block;
  width: 100%;
  height: 0%;
  background: #22c55e;
  border-radius: 4px;
  transition: height 0.04s linear, background-color .12s linear;
  position: absolute;
  bottom: 0;
}
.ptt-ptt-vu .vu-peak,
.ptt-ptt-vu .vu-peak-hold{
  position:absolute;
  left:0;
  right:0;
  height:2px;
  pointer-events:none;
  transform:translateY(-1px);
}
.ptt-ptt-vu.visible{
  visibility: visible;
}
.ptt-btn[data-transmitting="true"] .ptt-circle{
  border-color:var(--danger);
  outline:3px solid var(--danger);
  box-shadow:0 0 0 10px var(--ring-red), 0 10px 30px rgba(0,0,0,.35);
}
.ptt-btn[data-transmitting="true"] .ptt-circle-inner{
  background:radial-gradient(100% 100% at 50% 0%, rgba(239,68,68,.25) 0%, #160d0d 100%);
  border-color:rgba(239,68,68,.55);
}
.ptt-btn[data-transmitting="true"] .ptt-text{
  color:#ff6b6b;
  text-shadow:0 1px 0 #3b0b0b;
}
.ptt-btn[data-transmitting="true"] .ptt-channel{
  color:#fca5a5;
}


/* --- Tiny screens (np. iPod touch, bardzo małe wysokości) --- */
@media (max-height: 620px){
  /* pozwól całej aplikacji się przewinąć, jeśli treści jest więcej */
  .app-view{
    height: auto;
    min-height: 100svh;
  }
  .intercom-layout{
    height: auto; /* nie przycinaj sztucznie */
    min-height: calc(100svh - 52px - var(--safe-top));
    overflow-y: auto;         /* zamiast globalnego overflow:hidden */
    overflow-x: hidden;
    grid-template-rows: auto auto auto auto; /* elastycznie – panele dostosują się do treści */
    padding:6px 8px calc(8px + var(--safe-bottom));
    gap:6px;
  }
  .panel{ padding:8px; }
  .chips{ gap:6px; }
  .chip{
    min-height:42px;
    padding:.28rem .48rem;
    font-size:.90rem;
  }
  .chip-num{ font-size:.70rem; }
  .chip-name{ font-size:.80rem; }
  .ptt-circle{
    width: clamp(120px, 40vw, 200px);
    height: clamp(120px, 40vw, 200px);
  }
  .ptt-text{ font-size: 1.9rem; }
  .intercom-layout{ grid-template-rows:auto minmax(240px, 1fr) auto; }
}
/* ---------- Sheet (ustawienia) ---------- */
.sheet{
  position:fixed; left:0; right:0; bottom:-94vh; width:100%; max-width:100%; height:min(88dvh, 820px); z-index:20;
  background:var(--card); border-top-left-radius:18px; border-top-right-radius:18px;
  border-top:1px solid #243044; box-shadow:0 -12px 40px rgba(0,0,0,.45);
  transition:bottom .22s ease; padding:10px 14px calc(14px + var(--safe-bottom)); box-sizing:border-box; overflow:hidden;
  display:flex; flex-direction:column;
}
.sheet[aria-hidden="false"]{ bottom:0; }
.sheet-header{ flex:none; display:flex; align-items:center; justify-content:space-between; padding:6px 2px 10px; border-bottom:1px solid #242424; }
.sheet-title{ font-weight:750; font-size:1.12rem; }
.sheet-content{ flex:1 1 auto; min-width:0; min-height:0; height:auto; padding:14px 2px 6px; display:flex; flex-direction:column; gap:12px; overflow-x:hidden; overflow-y:auto; overscroll-behavior:contain; -webkit-overflow-scrolling:touch; }
.readonly{ color:var(--fg); font-weight:650; overflow-wrap:anywhere; }
.sheet-actions{ padding:0 2px 6px; display:flex; }
.sheet-actions .btn{ width:100%; background:rgba(239,68,68,.12); color:#ff7777; border:1px solid rgba(239,68,68,.26); }
.settings-section{ flex:0 0 auto; min-width:0; width:100%; background:#181a1d; border:1px solid #30343a; border-radius:16px; padding:0; overflow:hidden; }
.settings-video{ order:1; display:flex; flex-direction:column; }
.settings-audio{ order:2; }
.settings-behavior{ order:3; }
.settings-connection{ order:4; }
.settings-account{ order:5; }
.settings-section:has(#settings_language){ order:6; }
.sheet-actions{ order:7; }
.settings-section-title{ margin:0 0 13px; color:#aeb5bf; font-size:.74rem; font-weight:750; letter-spacing:.08em; text-transform:uppercase; }
.settings-section > .settings-section-title{ margin:0; padding:13px 14px; border-bottom:1px solid #2d3035; }
.settings-section .field{ margin:0; min-height:58px; padding:9px 14px; display:flex; flex-direction:row; align-items:center; justify-content:space-between; gap:12px; border-bottom:1px solid #2d3035; }
.settings-section .field > label{ min-width:0; flex:1 1 auto; overflow-wrap:anywhere; font-size:.88rem; font-weight:650; }
.settings-section .field > select,.settings-section .field > input{ flex:0 1 58%; width:58%; min-width:0; max-width:58%; margin:0; color:var(--fg); font-weight:700; text-align:right; text-overflow:ellipsis; border:1px solid #4a515c; border-radius:10px; background:#22262c; cursor:pointer; }
.settings-section .field > select:hover,.settings-section .field > select:focus{ border-color:var(--accent); background:#282d34; }
.settings-section .field > select:disabled{ cursor:not-allowed; opacity:.55; }
.settings-vu-field{ margin-top:2px; }
.settings-inline-label{ display:flex; justify-content:space-between; align-items:baseline; }
.settings-inline-label small{ color:var(--muted); }
.settings-options{ flex:0 0 auto; margin:0; border-top:0; }
.settings-options .check, .settings-options .row{ min-height:58px; margin:0; padding:10px 14px; display:flex; align-items:center; justify-content:space-between; gap:14px; border-bottom:1px solid #292b2e; color:var(--fg); }
.settings-options .check:last-child, .settings-options .row:last-child{ border-bottom:0; }
.settings-options .check > span, .settings-options .row > span{ display:flex; flex:1; min-width:0; flex-direction:column; gap:3px; }
.settings-options b{ font-size:.93rem; }
.settings-options small{ color:var(--muted); font-size:.76rem; line-height:1.3; }
.settings-info{ position:relative; display:inline-flex; flex:none; width:25px; height:25px; align-items:center; justify-content:center; border:1px solid #505762; border-radius:50%; color:var(--muted); font-size:.72rem; font-style:normal; font-weight:800; cursor:help; }
.settings-info::after{ content:attr(data-help); position:absolute; right:0; bottom:calc(100% + 8px); z-index:4; width:min(260px,70vw); padding:10px 12px; border:1px solid #414852; border-radius:10px; background:#252a31; color:var(--fg); box-shadow:0 10px 30px rgba(0,0,0,.45); font-size:.75rem; font-weight:400; line-height:1.35; opacity:0; pointer-events:none; transform:translateY(4px); transition:.14s ease; }
.settings-info:hover::after,.settings-info:focus::after{ opacity:1; transform:none; }
.settings-options input[type="checkbox"]{ appearance:none; -webkit-appearance:none; flex:none; width:46px; height:28px; margin:0; border:1px solid #4b4f55; border-radius:999px; background:#303338; position:relative; cursor:pointer; transition:.18s ease; }
.settings-options input[type="checkbox"]::after{ content:""; position:absolute; top:3px; left:3px; width:20px; height:20px; border-radius:50%; background:#fff; box-shadow:0 1px 3px rgba(0,0,0,.45); transition:transform .18s ease; }
.settings-options input[type="checkbox"]:checked{ border-color:var(--accent); background:var(--accent); }
.settings-options input[type="checkbox"]:checked::after{ transform:translateX(18px); background:#fff; }
.settings-options-compact .row:has(select){ align-items:center; flex-direction:row; }
.settings-options-compact .row:has(select) select{ width:58%; min-width:0; max-width:58%; margin:0; border:1px solid #4a515c; border-radius:10px; background:#22262c; color:var(--fg); font-weight:700; cursor:pointer; }
.settings-note{ margin:9px 2px 0; color:var(--muted); font-size:.78rem; line-height:1.4; }
.settings-full-button{ width:100%; min-height:46px; font-size:.9rem; }
.settings-section-collapsible{ padding:0; overflow:hidden; }
.settings-collapsible-title{ margin:0 !important; }
.settings-section-collapsible .secondary-toggle{ border-top:1px solid #2d3035; }
.settings-account-row{ display:flex; justify-content:space-between; gap:14px; align-items:center; padding:12px 14px; color:var(--muted); font-size:.86rem; border-bottom:1px solid #2d3035; }
.settings-link-button{ display:flex; width:100%; justify-content:space-between; align-items:center; padding:13px 14px; border:0; border-top:1px solid #292b2e; background:none; color:var(--fg); font:inherit; text-align:left; cursor:pointer; }
.settings-link-button span{ color:var(--muted); font-size:1.4rem; }
.settings-certificate-help{ margin-top:10px; color:var(--muted); font-size:.78rem; }
.settings-certificate-help summary{ cursor:pointer; }
.settings-certificate-help small{ display:block; margin-top:8px; line-height:1.5; }
.btn[aria-busy="true"]{ opacity:.72; cursor:wait; pointer-events:none; }
@media (min-width:700px){ .sheet{ left:50%; right:auto; width:min(560px, calc(100% - 28px)); transform:translateX(-50%); border-radius:20px 20px 0 0; } }

.sheet-scrim{
  position:fixed; inset:0; background:rgba(0,0,0,.35); opacity:0; pointer-events:none; z-index:19;
  transition:opacity .2s ease;
}
.sheet-scrim[aria-hidden="false"]{ opacity:1; pointer-events:auto; }

/* Szybki wybór wyjścia audio z paska – krótszy niż pełne ustawienia. */
.audio-quick-sheet{
  position:fixed; left:50%; bottom:calc(12px + var(--safe-bottom)); z-index:22;
  width:min(440px, calc(100% - 20px)); max-height:min(62vh, 520px); overflow:auto;
  padding:12px; border:1px solid #2b3440; border-radius:18px; background:var(--card);
  box-shadow:0 18px 60px rgba(0,0,0,.6); transform:translate(-50%, calc(100% + 40px));
  opacity:0; pointer-events:none; transition:transform .2s ease, opacity .16s ease;
}
.audio-quick-sheet[aria-hidden="false"]{ transform:translate(-50%, 0); opacity:1; pointer-events:auto; }
.audio-quick-subtitle{ margin-top:3px; color:var(--muted); font-size:.78rem; }
.audio-quick-list{ display:flex; flex-direction:column; gap:6px; margin-top:9px; }
.audio-quick-option{
  width:100%; min-height:48px; padding:9px 11px; display:flex; align-items:center; gap:10px;
  border:1px solid #272b31; border-radius:12px; background:#131517; color:var(--fg);
  font:inherit; text-align:left; cursor:pointer;
}
.audio-quick-option.selected{ border-color:var(--accent); background:rgba(255,213,79,.08); }
.audio-quick-option-icon{ width:24px; flex:none; color:var(--muted); text-align:center; }
.audio-quick-option-label{ min-width:0; flex:1; overflow-wrap:anywhere; }
.audio-quick-check{ flex:none; color:var(--accent); font-size:1.15rem; font-weight:800; }
.audio-quick-empty{ padding:16px 10px; color:var(--muted); text-align:center; }
.audio-quick-scrim{
  position:fixed; inset:0; z-index:21; background:rgba(0,0,0,.48); opacity:0; pointer-events:none;
  transition:opacity .16s ease;
}
.audio-quick-scrim[aria-hidden="false"]{ opacity:1; pointer-events:auto; }

/* Szczegóły połączenia (dot + LAN/NET w pasku) — ten sam wygląd co audio-quick-sheet, bo to
   też krótka, jednorazowa lista informacji, nie pełne ustawienia. */
.connection-details-list{ display:flex; flex-direction:column; gap:2px; margin-top:6px; }
.connection-detail-row{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:9px 4px; border-bottom:1px solid #202429; color:var(--muted); font-size:.86rem;
}
/* Autorskie `display:flex` wyżej wygrywa ze stylem przeglądarki `[hidden]{display:none}`,
   więc wiersze bez danych (transport, WebRTC, adres logiczny, diagnostyka) mimo ustawienia
   `hidden` nadal pokazywały pustą kreskę. Reguła musi być jawna. */
.connection-detail-row[hidden]{ display:none; }
.connection-detail-row:last-child{ border-bottom:none; }
.connection-detail-row b{ color:var(--fg); font-weight:650; font-variant-numeric:tabular-nums; }
.connection-mode-control{ display:flex; flex-direction:column; gap:6px; margin-top:10px; padding-top:12px; border-top:1px solid #2b3440; }
.connection-mode-control label{ color:var(--fg); font-size:.8rem; font-weight:700; }
.connection-mode-control select{ width:100%; min-height:42px; border:1px solid #303947; border-radius:10px; background:#10151d; color:var(--fg); padding:8px 10px; font:inherit; }
.connection-mode-control small{ color:var(--muted); font-size:.67rem; line-height:1.35; }
.network-history{ margin-top:12px; padding-top:12px; border-top:1px solid #2b3440; }
.network-history-head{ display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:8px; font-size:.82rem; }
.network-history-range{ display:flex; padding:2px; border:1px solid #2b3440; border-radius:8px; background:#171a1e; }
.network-history-range button{ min-height:26px; padding:3px 8px; border:0; border-radius:6px; background:transparent; color:var(--muted); font:inherit; font-size:.66rem; font-weight:700; cursor:pointer; }
.network-history-range button[aria-pressed="true"]{ background:#29313a; color:var(--fg); }
.network-history-range button:focus-visible{ outline:2px solid var(--accent); outline-offset:1px; }
.network-history-chart,.network-history-empty{ width:100%; height:112px; border-radius:12px; background:#171a1e; }
.network-history-chart{ display:block; }
.network-history-chart[hidden],.network-history-empty[hidden],.network-history-summary[hidden]{ display:none; }
.network-history-empty{ display:flex; align-items:center; justify-content:center; padding:12px; color:var(--muted); font-size:.75rem; text-align:center; }
.network-history-summary{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:12px; margin-top:8px; }
.network-history-summary div{ min-width:0; }
.network-history-summary b{ display:block; font-size:.82rem; font-variant-numeric:tabular-nums; }
.network-history-summary span{ display:block; margin-top:1px; color:var(--muted); font-size:.58rem; }
.network-history-coverage{ min-height:14px; margin-top:5px; color:var(--muted); font-size:.62rem; }
.network-history-legend{ display:flex; flex-wrap:wrap; gap:5px 12px; margin-top:5px; color:var(--muted); font-size:.62rem; }
.network-history-legend span{ display:inline-flex; align-items:center; gap:4px; }
.network-history-legend i{ width:7px; height:7px; border-radius:50%; background:#22c55e; }
.network-history-legend i.degraded{ background:#ffd54f; }
.network-history-legend i.offline{ background:#ef4444; }
.network-history-legend i.ping{ background:#0ea5e9; }
.network-history p{ margin:7px 0 0; color:var(--muted); font-size:.62rem; line-height:1.35; }

/* ---------- VU ---------- */
.vu{ position:relative; width:100%; height:8px; background:#0c121a; border:1px solid #1d2736; border-radius:8px; overflow:hidden; }
.vu > span{ display:block; height:100%; width:0%; background:#22c55e; transition:width .04s linear, background-color .12s linear; }
.vu-level-low > span{ background:#f59e0b; }
.vu-level-clip > span{ background:#ef4444; }
.vu-peak,
.vu-peak-hold{
  position:absolute;
  top:0;
  bottom:0;
  left:0;
  width:2px;
  pointer-events:none;
  transform:translateX(-1px);
}
/* PTT VU specific - vertical override */
.ptt-ptt-vu .vu-peak,
.ptt-ptt-vu .vu-peak-hold{
  position:absolute;
  left:0;
  right:0;
  height:2px;
  pointer-events:none;
  transform:translateY(-1px);
}
.vu-peak{ background:rgba(255,255,255,.48); }
.vu-peak-hold{ background:#fff; box-shadow:0 0 3px rgba(255,255,255,.8); }
.vu-level-clip .vu-peak-hold{ width:3px; background:#ef4444; box-shadow:0 0 5px #ef4444; }

/* ---------- Focus i dostępność ---------- */
:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:12px; }

/* ---------- Drobiazgi ---------- */
.hidden{ display:none !important; }

/* ---------- Blokada zaznaczania tekstu (mobilne PTT i klikalne UI) ---------- */
/* Uwaga: celowo NIE dotyczy pól formularzy, żeby można było zaznaczać/edytować tekst w inputach. */
.no-select,
.ptt-panel,
.ptt-btn,
.ptt-circle,
.ptt-circle-inner,
.ptt-text,
.ptt-label-top,
.chips,
.chip,
.btn,
.icon-btn,
.panel,
.topbar {
  -webkit-user-select: none; /* iOS/Safari */
  -moz-user-select: none;    /* Firefox */
  -ms-user-select: none;     /* stary Edge/IE */
  user-select: none;         /* standard */
  -webkit-touch-callout: none; /* wyłącza menu kontekstowe na iOS po długim przytrzymaniu */
}

/* === Admin: tabela routingu – neutralna, profesjonalna kolorystyka (patrz AJA Device Manager) === */
#tbl_users{
  width:100%;
  display:block;                 /* poziomy scroll tylko na tabeli */
  max-width:100%;
  overflow-x:auto;               /* przewijanie poziome na wąskich ekranach */
  -webkit-overflow-scrolling:touch;
  border-collapse:separate;      /* zaokrąglenia i obramowania */
  border-spacing:0;
  table-layout:fixed;
  background: #14171c;
  border:1px solid #262c34;
  border-radius:8px;
  font-size:13.5px;              /* czytelniej odrobinę większą bazą */
  min-width: 880px;              /* logiczne minimum dla kolumn TL */
  color: #e8ebee;
}

/* komórki */
#tbl_users thead th,
#tbl_users tbody td{
  padding:8px 8px;               /* komfortowy rytm pionowy */
  text-align:center;
  border-bottom:1px solid #262c34; /* delikatne linie oddzielające wiersze */
  line-height:1.25;              /* wyższa czytelność */
  vertical-align: middle;
  background-clip:padding-box;   /* brak przenikania pod obramowania */
}

/* pionowe separatory pomiędzy kolumnami (bez ostatniej) */
#tbl_users thead th:not(:last-child),
#tbl_users tbody td:not(:last-child){
  border-right:1px solid #262c34;
}

/* zebra striping – subtelne, spójne z panelem */
#tbl_users tbody tr:nth-child(even){ background:#14171c; }
#tbl_users tbody tr:nth-child(odd){  background:#171a1f; }

/* podświetlenie wiersza – akcent jako cienki lewy pasek i delikatne tło */
#tbl_users tbody tr:hover{
  background:#1f242b;
  box-shadow: inset 3px 0 0 0 #3b9dff;
}

/* --- Minimalne podświetlenie całego wiersza (hover + focus) --- */
#tbl_users tbody tr:hover td,
#tbl_users tbody tr:focus-within td{
  background:#1f242b !important;
}

#tbl_users tbody tr:hover,
#tbl_users tbody tr:focus-within{
  box-shadow: inset 3px 0 0 0 #3b9dff;
}

/* nagłówki */
#tbl_users thead th{
  position: sticky;
  top: 0;                        /* przyklejony nagłówek przy pionowym scrollu */
  z-index: 3;
  background:#1a1e24;
  font-weight:600;
  color:#e8ebee;
  border-bottom:1px solid #262c34;
}
#tbl_users thead .th-center{ text-align:center; font-weight:600; letter-spacing:.02em; color:#6c757f; text-transform:uppercase; font-size:10.5px; }
#tbl_users thead .th-ch{ text-align:center; }
#tbl_users thead .th-ch .ch-number{ display:block; font-weight:700; line-height:1; color:#e8ebee; }
#tbl_users thead .th-ch .ch-title{ display:block; font-weight:600; line-height:1.05; font-size:12.5px; color:#e8ebee; }
#tbl_users thead .th-ch .ch-sub{ display:block; font-size:10.5px; opacity:.85; line-height:1.05; color:#a4adb8; }

/* komórki – obcinanie długich treści wielokropkiem */
#tbl_users td{
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}

/* lepka kolumna na desktopie – WYŁĄCZNIE nazwa użytkownika (checkbox ma własną
   sticky regułę niżej; rola/akcje celowo NIE są sticky, żeby przy poziomym scrollu
   nie zasłaniały kolumn kanałów). */
#tbl_users thead tr:first-child th:nth-child(2),
#tbl_users tbody td:nth-child(2){
  position: sticky;
  left: 24px;                    /* checkbox column width */
  z-index: 2;                    /* ponad innymi komórkami, ale pod nagłówkiem */
  background:#14171c;            /* pełne tło, by zebra nie prześwitywała */
  min-width: 190px;
  text-align:left; padding-left:12px;
  box-shadow: 1px 0 0 #262c34 inset; /* separator po prawej */
}
#tbl_users tbody td:nth-child(2){ font-size:13.5px; font-weight:600; letter-spacing:.01em; }

/* nagłówek dla lepkiej kolumny – dopasowanie tła i z-index */
#tbl_users thead tr:first-child th:nth-child(2){
  background:#1a1e24;
  z-index: 10; /* wyższy niż elementy wewnątrz komórek */
}

/* akcje w wierszu – kompaktowo i czytelnie */
#tbl_users .th-actions{ width:48px; text-align:center; }
#tbl_users .td-actions{ width:48px; text-align:center; padding-left:4px; padding-right:4px; }
#tbl_users .row-actions{ position:relative; display:inline-block; }
#tbl_users .menu-toggle{ font-size:18px; line-height:1; }
#tbl_users .row-actions .menu[hidden]{ display:none !important; }
#tbl_users .row-actions .menu{
  position:absolute; right:0; top:calc(100% + 6px);
  min-width:190px; background:#1a1e24; border:1px solid #333b45; border-radius:8px; padding:6px;
  box-shadow:0 10px 30px rgba(0,0,0,.45); z-index:10000; transform:translateZ(0);
}
#tbl_users .row-actions .menu .menu-item{
  display:flex; width:100%; align-items:center; justify-content:flex-start; gap:8px;
  padding:8px 10px; border:0; background:transparent; color:#e8ebee;
  border-radius:5px; cursor:pointer; font-size:13px; text-align:left;
}
#tbl_users .row-actions .menu .menu-item:hover,
#tbl_users .row-actions .menu .menu-item:focus{ background:#1f242b; outline:none; }
#tbl_users .row-actions .menu .menu-item.danger{ color:#f0574c; }
#tbl_users .row-actions .menu .menu-item.danger:hover{ background:rgba(240,87,76,.12); }

/* przyciski i ikony w tabeli – gęstsze, ale dotykalne */
#tbl_users .btn{ min-height:32px; padding:.38rem .55rem; font-size:.9rem; border-radius:6px; }
#tbl_users .icon-btn{ width:32px; height:32px; border-radius:6px; }

/* checkboksy kanałów – większe cele dotykowe i neutralny accent */
#tbl_users input[type="checkbox"]{
  transform: scale(1.1);
  accent-color: #3b9dff;
}
#tbl_users input[type="checkbox"]:focus-visible{ outline:2px solid #3b9dff; outline-offset:2px; border-radius:4px; }

/* responsywność */
@media (max-width:1200px){
  #tbl_users{ font-size:13px; }
  #tbl_users thead th, #tbl_users tbody td{ padding:6px 6px; }
}
@media (max-width:800px){
  #tbl_users{ font-size:12.5px; }
  #tbl_users thead .th-ch .ch-title{ font-size:11.5px; }
  #tbl_users thead .th-ch .ch-sub{ font-size:10.5px; }
}

/* Na małych ekranach TYLKO kolumna z nazwą użytkownika zostaje sticky (zwężona,
   żeby nie zabierała zbyt dużo miejsca) — rola i akcje nigdy nie są sticky
   (patrz reguła wyżej), więc nie trzeba ich tu osobno „odklejać”. */
@media (max-width:640px){
  #tbl_users{ font-size:12px; min-width: 760px; }
  #tbl_users thead th, #tbl_users tbody td{ padding:5px 5px; }

  #tbl_users thead tr:first-child th:nth-child(2),
  #tbl_users tbody td:nth-child(2){
    left:0;                       /* checkbox nie jest tu sticky (patrz .td-select niżej) */
    min-width:140px;
    width:140px;
    padding-left:8px;
  }

  #tbl_users .row-actions .menu{ min-width:160px; }
  #tbl_users input[type="checkbox"]{ transform: scale(1.15); }
}

@media (max-width:480px){
  #tbl_users{ font-size:11.5px; min-width: 700px; }
  #tbl_users thead .th-ch .ch-title{ font-size:10.5px; }
  #tbl_users thead .th-ch .ch-sub{ font-size:9.8px; }
}

/* === Offline banner & badges === */
/* Świadomie NIE position:fixed — baner jest wstawiany jako pierwsze dziecko kontenera
   (patrz ensureOfflineBanner() w user.js/admin.js), więc odpycha topbar/nagłówek w dół
   zamiast go zasłaniać (wcześniej zasłaniał przyciski Ustawienia/Obecność, uniemożliwiając
   np. wyłączenie beepa offline w trakcie samego bycia offline). */
.offline-banner {
  padding: 10px 14px;
  background: linear-gradient(180deg, #3a0d0d, #220808);
  color: #fecaca; /* jasny czerwony */
  border-bottom: 1px solid #7f1d1d;
  text-align: center;
  font-weight: 700;
  letter-spacing: .02em;
  flex-shrink: 0;
}
.offline-banner .dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: #ef4444; margin-right: 8px; vertical-align: middle;
  animation: offlineBlink 1.2s linear infinite;
}
@keyframes offlineBlink { 0%, 100% { opacity: .4 } 50% { opacity: 1 } }

/* === BUZZER: krótkotrwały wizualny puls całego ekranu ===
   Odpowiednik BuzzerPulseOverlay z natywnej appki (Compose) — bez pointer-events, więc
   nigdy nie blokuje dotyku/PTT pod spodem. */
.buzzer-pulse-overlay {
  position: fixed;
  inset: 0;
  z-index: 999;
  pointer-events: none;
  opacity: 0;
  background: var(--accent);
}
.buzzer-pulse-overlay.buzz {
  animation: buzzerPulseBuzz 620ms ease-out 1;
}
.buzzer-pulse-overlay.emergency {
  background: var(--danger);
  animation: buzzerPulseEmergency 180ms ease-in-out 6;
}
@keyframes buzzerPulseBuzz {
  0% { opacity: 0; }
  15% { opacity: .30; }
  100% { opacity: 0; }
}
@keyframes buzzerPulseEmergency {
  0%, 100% { opacity: 0; }
  50% { opacity: .35; }
}

/* === Toasty (powiadomienia) === */
#toasts {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  gap: 8px;
  padding: 10px 14px calc(16px + env(safe-area-inset-bottom, 0px));
  z-index: 1000;
  pointer-events: none;
}
#toasts:empty{ display:none; }
/* Komunikaty techniczne są zakotwiczone na granicy ODSŁUCH/PTT i nie uczestniczą w układzie.
   Przy małej wysokości mogą wejść na górę PTT, ale nigdy go nie przesuwają. */
.ptt-panel > #toasts{
  position:absolute;
  left:50%;
  right:auto;
  top:0;
  bottom:auto;
  width:min(calc(100% - 24px), 480px);
  padding:0;
  transform:translate(-50%, -50%);
  z-index:6;
}
.toast {
  position:relative;
  pointer-events: auto;
  max-width: min(92vw, 480px);
  padding: 11px 42px 11px 14px;
  border-radius: 6px;
  background: #1a1e24;
  color: #e8ebee;
  border: 1px solid #333b45;
  border-left: 3px solid #3b9dff;
  box-shadow: 0 8px 24px rgba(0,0,0,.4);
  font-weight: 600;
  letter-spacing: .01em;
  text-align: left;
  animation: toastIn .18s ease-out;
}
.toast.warn {
  background:#1a1e24;
  color:#e8ebee;
  border-color:#333b45;
  border-left-color:#e8b13a;
}
.toast.error {
  border-left-color:#ef4444;
}
.toast.critical {
  background:linear-gradient(180deg,#650b0b,#320606);
  color:#fff;
  border-color:#ef4444;
}
.toast-dismiss{
  position:absolute;
  top:50%;
  right:8px;
  width:28px;
  height:28px;
  padding:0;
  transform:translateY(-50%);
  border:0;
  border-radius:5px;
  background:transparent;
  color:#a4adb8;
  font:600 20px/1 ui-sans-serif,system-ui,sans-serif;
  cursor:pointer;
}
.toast-dismiss:hover,
.toast-dismiss:focus-visible{
  color:#e8ebee;
  background:rgba(255,255,255,.08);
  outline:none;
}
.toast.pttx-overlay {
  position: fixed;
  z-index: 1200;
  top: calc(10px + env(safe-area-inset-top, 0px));
  left: 50%;
  transform: translateX(-50%);
  width: min(calc(100vw - 24px), 520px);
  margin: 0;
  padding:12px clamp(14px, 4vw, 20px);
  border-radius:10px;
  background:linear-gradient(180deg, #3a0d0d, #220808);
  color:#fecaca;
  border: 4px solid #64748b;
  font-weight:700;
  animation: pttxToastIn .18s ease-out;
}
.pttx-overlay[data-color="neutral"]{ border-color:#64748b; }
.pttx-overlay[data-color="green"]{ border-color:#22c55e; }
.pttx-overlay[data-color="yellow"]{ border-color:#eab308; }
.pttx-overlay[data-color="red"]{ border-color:#ef4444; }
.pttx-overlay[data-color="blue"]{ border-color:#3b82f6; }
/* Odbiór wg priorytetu. Kolor ramki nadal pochodzi z wiadomości (data-color) — priorytet
   dokłada tylko siłę wyróżnienia. LOW = obecny wygląd. */
.toast.pttx-overlay[data-pttxpriority="MEDIUM"]{
  border-width:5px;
  box-shadow:0 0 0 3px rgba(234,179,8,.28),0 12px 34px rgba(0,0,0,.62);
}
.toast.pttx-overlay[data-pttxpriority="HIGH"]{
  border-width:6px;
  background:linear-gradient(180deg,#4a0d0d,#280606);
  box-shadow:0 0 0 4px rgba(239,68,68,.38),0 18px 46px rgba(0,0,0,.72);
  animation:pttxHighPulse 1.4s ease-in-out infinite alternate;
}
.toast.pttx-overlay .toast-marker{
  display:inline-block; margin-right:8px; padding:2px 8px; border-radius:8px;
  background:rgba(255,255,255,.14); font-size:.62em; font-weight:900; letter-spacing:.1em;
  vertical-align:middle;
}
.toast.pttx-overlay .toast-hint{
  margin-top:9px; font-size:clamp(.62rem, 2.5vw, .72rem); font-weight:500;
  letter-spacing:.01em; line-height:1.25;
  color:#e2e8f0; text-align:center; opacity:.68;
}
@keyframes pttxHighPulse{
  from{ box-shadow:0 0 0 3px rgba(239,68,68,.28),0 18px 46px rgba(0,0,0,.72); }
  to  { box-shadow:0 0 0 8px rgba(239,68,68,.5),0 18px 46px rgba(0,0,0,.72); }
}
@media (prefers-reduced-motion: reduce){
  .toast.pttx-overlay[data-pttxpriority="HIGH"]{ animation:none; }
}
/* Drugi badge przy przycisku Obecność — tylko nieprzeczytane PTXT. Kolor ustawiany inline
   z ostatniej nieprzeczytanej wiadomości; tu tylko rozmiar/pozycja po przeciwnej stronie. */
.badge-count.badge-ptxt{
  right:auto; left:-6px; min-width:15px; height:15px; line-height:15px;
  font-size:9px; background:#64748b; color:#fff;
}
.toast.pttx-overlay.toast-structured{ text-align:center; }
.toast.pttx-overlay .toast-message{
  margin:0;
  color:#bfdbfe;
  font-size:clamp(.78rem,3vw,.92rem);
  line-height:1.3;
  font-weight:750;
  overflow-wrap:anywhere;
  text-align:center;
}
.toast.pttx-overlay .toast-title{
  justify-content:center;
  margin-top:6px;
  font-size:clamp(1.2rem,4.8vw,1.8rem);
  line-height:1.15;
  text-align:center;
}
.toast.pttx-overlay.toast-structured{
  width:min(calc(100vw - 24px),520px);
  padding:clamp(12px,3.5vw,18px) clamp(14px,4vw,20px);
}
.toast.toast-structured {
  width:min(92vw,520px);
  padding:18px 20px;
  border-width:3px;
}
.toast-title {
  display:flex;
  align-items:center;
  justify-content:center;
  gap:10px;
  font-size:clamp(1.35rem,5vw,2.25rem);
  line-height:1.1;
  font-weight:900;
  overflow-wrap:anywhere;
}
.toast-icon { font-size:1.25em; line-height:1; }
.toast-message { margin-top:9px; color:#bfdbfe; font-size:.9rem; }
.toast[data-color="neutral"]{ border-color:#64748b; }
.toast[data-color="green"]{ border-color:#22c55e; }
.toast[data-color="yellow"]{ border-color:#eab308; }
.toast[data-color="red"]{ border-color:#ef4444; }
.toast[data-color="blue"]{ border-color:#3b82f6; }
@keyframes toastIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes pttxToastIn {
  from { opacity: 0; transform: translate(-50%, -8px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

/* wzmocnienie znacznika w topbar */
.badge.offline { color: #fca5a5; border-color: #7f1d1d; background:#1a0f0f; }
.badge.reconnecting { color:#fde68a; border-color:#92400e; background:#1f1305; }

/* === Admin: poprawka 2 — stabilizacja widoczności menu i więcej „powietrza” na dole === */

/* Kontenery na stronie admina nie mogą przycinać popupów/menu */
.container,
.card {
  overflow: visible;
}

/* Tabela: pionowo nie przycinamy (poziomy scroll zostaje z wcześniejszego overflow-x:auto) */
#tbl_users {
  overflow-y: visible;
  position: relative; /* baza dla absolutów, jeśli będą potrzebne */
}

/* Więcej miejsca pod ostatnim wierszem, by menu i dół tabeli nie „kleiły się” do krawędzi */
#tbl_users::after {
  content: "";
  display: block;
  height: 160px; /* można skorygować np. 120–200px wg uznania */
}

/* Lokalne elementy akcji też nie powinny niczego ucinać */
#tbl_users .td-actions,
#tbl_users .row-actions {
  overflow: visible;
}

/* Menu z kropek zawsze na wierzchu i w osobnym kontekście malowania */
#tbl_users .row-actions .menu {
  z-index: 10000;
  transform: translateZ(0);
}

.sessions-section { margin-top: 16px; }
.sessions-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 12px;
}
.sessions-title { font-weight: 700; letter-spacing: .02em; }
.sessions-actions .btn { white-space: nowrap; }
.sessions-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px;
}
.sessions-empty {
  opacity: .75;
  font-size: .9rem;
  padding: 6px 0;
}
.session-card {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 12px;
  border: 1px solid #262c34;
  border-radius: 8px;
  background: #14171c;
}
.session-card__main { flex: 1; min-width: 0; }
.session-card__title { font-weight: 700; }
.session-card__meta {
  font-size: .85rem;
  opacity: .75;
  margin-top: 2px;
}
.session-card__actions { display: flex; gap: 8px; flex-wrap: wrap; }
.session-card .btn { min-height: 34px; padding: .45rem .7rem; border-radius: 10px; }

/* === Admin: neutralny, profesjonalny layout (kolorystyka jak w AJA Device Manager) === */
.admin-page{
  /* Górny pasek (.admin-header) nie jest już sticky (żeby nie zajmował miejsca przy scrollu),
     więc pozostałe sticky elementy (np. nagłówek tabeli routingu) przyklejają się od razu do
     samej góry viewportu zamiast pod nim — stąd offset 0, nie jego dawna wysokość. */
  --admin-sticky-offset:0px;

  --adm-bg: #0b0c0e;
  --adm-bar: #0e1013;          /* pasek górny i pasek zakładek */
  --adm-surface: #0f1113;      /* karty i wiersze tabeli */
  --adm-subhead: #101215;      /* legenda, nagłówek tabeli, paski narzędzi */
  --adm-surface-2: #14161a;
  --adm-surface-hover: #14171b;
  --adm-surface-selected: #15181d;
  --adm-border: #1c2025;
  --adm-border-soft: #16191d;  /* linie między wierszami */
  --adm-border-strong: #262b31;

  --adm-text: #e6e8ea;
  --adm-text-mid: #c8ccd2;
  --adm-text-dim: #8b9098;
  --adm-text-faint: #6b7280;
  --adm-text-ghost: #5c636b;

  --adm-accent: #3d7fd6;       /* LISTEN / L */
  --adm-accent-dim: #26364a;
  --adm-accent-ink: #0d1013;   /* tekst na wypełnieniu L */

  --adm-ok: #4f9d69;
  --adm-warn: #d3a12c;         /* TALK / T */
  --adm-warn-ink: #15171a;     /* tekst na wypełnieniu T */

  --adm-video: #8b5cf6;        /* VIDEO / V */
  --adm-video-ink: #0d1013;    /* tekst na wypełnieniu V */
  --adm-error: #f0574c;        /* ALARM: PTT/MÓW, niska bateria, akcje destrukcyjne */
  --adm-pending: #b48ce8;

  /* Czerwień „administratorska”: rola admina ORAZ każda opcja, którą administrator
     zablokował użytkownikowi w konfiguracji beltpacka. Celowo stonowana i odrębna od
     --adm-error, żeby „zablokowane przez admina” nie krzyczało tak jak realny alarm. */
  --adm-admin: #d98a8a;
  --adm-admin-border: #4a2a2c;
  --adm-admin-bg: rgba(160,60,60,.10);
  --adm-admin-bg-strong: rgba(160,60,60,.16);

  /* Systemowy mono — panel działa też offline w LAN, więc żadnych fontów z CDN. */
  --adm-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --adm-radius: 8px;
  --adm-radius-sm: 5px;

  height:auto;
  min-height:100%;
  background: var(--adm-bg);
  color: var(--adm-text);
}
.admin-page .container{
  width:calc(100% - 80px);
  max-width:none;
  margin-inline:auto;
}
.admin-header{
  border-bottom:1px solid var(--adm-border);
  background: var(--adm-bg);
}
.admin-header__inner{
  min-height:56px;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:20px;
}
.admin-header__stats{
  display:none;
  flex:1;
  justify-content:center;
  margin:0;
}
.admin-brand{
  display:flex;
  align-items:center;
  gap:11px;
  min-width:0;
}
.admin-brand img{
  display:block;
  border-radius:6px;
}
.admin-brand div{ display:flex; flex-direction:column; line-height:1.15; }
.admin-brand strong{ font-size:14px; font-weight:700; letter-spacing:.02em; color:var(--adm-text); }
.admin-brand span{ margin-top:4px; color:var(--adm-text-faint); font-size:11px; }
.admin-account-menu{ position:relative; flex:0 0 auto; z-index:20; }
.admin-account-menu__toggle{
  display:flex;
  align-items:center;
  gap:8px;
  min-height:36px;
  padding:5px 9px 5px 6px;
  border:1px solid var(--adm-border-strong);
  border-radius:var(--adm-radius-sm);
  background:var(--adm-surface);
  color:var(--adm-text-dim);
  font:600 12px/1 system-ui,sans-serif;
  cursor:pointer;
  transition:.12s ease;
}
.admin-account-menu__toggle:hover,
.admin-account-menu__toggle[aria-expanded="true"]{
  color:var(--adm-text);
  border-color:var(--adm-accent);
  background:var(--adm-surface-hover);
}
.admin-account-menu__toggle:focus-visible{ outline:2px solid var(--adm-accent); outline-offset:2px; }
.admin-account-menu__avatar{
  display:grid;
  place-items:center;
  width:24px;
  height:24px;
  border-radius:50%;
  background:var(--adm-accent-dim);
  color:#fff;
  font-size:11px;
  font-weight:800;
}
.admin-account-menu__chevron{ margin-top:-3px; color:var(--adm-text-faint); font-size:14px; }
.admin-account-menu__label{
  max-width:140px;
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}
.admin-account-menu__panel{
  position:absolute;
  top:calc(100% + 8px);
  right:0;
  width:min(240px,calc(100vw - 24px));
  padding:6px;
  border:1px solid var(--adm-border-strong);
  border-radius:var(--adm-radius);
  background:var(--adm-surface-2);
  box-shadow:0 16px 40px rgba(0,0,0,.55);
}
.admin-account-menu__panel[hidden]{ display:none; }
.admin-account-menu__item{
  display:flex;
  align-items:center;
  justify-content:space-between;
  width:100%;
  min-height:38px;
  padding:8px 10px;
  border:0;
  border-radius:var(--adm-radius-sm);
  background:transparent;
  color:var(--adm-text);
  text-decoration:none;
  text-align:left;
  font:600 12px/1.25 system-ui,sans-serif;
  cursor:pointer;
}
/* Pozycje menu mają własne `display:flex`, więc `hidden` (pozycje widoczne dopiero
   po zalogowaniu) bez tej reguły niczego nie chowa. */
.admin-account-menu__item[hidden]{ display:none; }
.admin-account-menu__item:hover,
.admin-account-menu__item:focus-visible{ background:var(--adm-surface-hover); outline:none; }
.admin-account-menu__item--danger{ color:#ff938b; }
.admin-account-menu__item--danger:hover,
.admin-account-menu__item--danger:focus-visible{ background:rgba(240,87,76,.12); }
.admin-account-menu__language{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:12px;
  min-height:42px;
  padding:6px 10px;
  color:var(--adm-text-dim);
  font-size:12px;
  font-weight:600;
}
.admin-account-menu__language select{
  min-width:96px;
  min-height:30px;
  padding:3px 6px;
  border:1px solid var(--adm-border);
  border-radius:var(--adm-radius-sm);
  background:var(--adm-surface);
  color:var(--adm-text);
  font-size:12px;
}
.admin-account-menu__separator{ height:1px; margin:5px 4px; background:var(--adm-border); }
.admin-main{ padding-top:20px; padding-bottom:32px; }
.admin-page .card{
  background: var(--adm-surface);
  border:1px solid var(--adm-border);
  border-radius:var(--adm-radius);
}
.admin-page .login-view{
  height:calc(100svh - 112px);
  min-height:540px;
  padding:32px 0;
}
.admin-login-card{
  width:min(400px, 100%);
  padding:26px;
}
.admin-login-card h1,
.routing-head h1,
.admin-dialog h2{
  margin:5px 0 0;
  color: var(--adm-text);
  font-weight:650;
  letter-spacing:-.01em;
}
.admin-login-card h1{ font-size:22px; }
.admin-eyebrow{
  color: var(--adm-text-faint);
  font-size:10px;
  font-weight:700;
  letter-spacing:.14em;
  text-transform:uppercase;
}
.admin-lead,
.routing-head p,
.admin-dialog__lead{
  color: var(--adm-text-dim);
  line-height:1.55;
}
.admin-lead{ margin:10px 0 24px; font-size:13px; }
.admin-login-fields{ display:grid; gap:14px; }
.admin-page label{
  display:grid;
  gap:6px;
  color: var(--adm-text-dim);
  font-size:12px;
  font-weight:600;
  letter-spacing:.01em;
}
.admin-page .input,
.admin-page select{
  min-height:38px;
  border-radius:var(--adm-radius-sm);
  border:1px solid var(--adm-border-strong);
  background: var(--adm-bg);
  color: var(--adm-text);
}
.admin-page .input:focus,
.admin-page select:focus{
  border-color: var(--adm-accent);
  box-shadow:none;
}
.admin-page .btn{
  min-height:34px;
  padding:.5rem .8rem;
  border-radius:var(--adm-radius-sm);
  font-size:12.5px;
  font-weight:600;
  background: var(--adm-surface-2);
  color: var(--adm-text);
  border:1px solid var(--adm-border-strong);
}
/* `.btn` i `.icon-btn` ustawiają własny `display:inline-flex`, który wygrywa z regułą
   przeglądarki `[hidden]{display:none}` — bez tego `el.hidden = true` w admin.js zostawia
   przycisk widoczny i klikalny (np. „Unieważnij"/„Kopiuj link" w dialogu linku dostępu
   albo „Resetuj poziomy głośności" w trybie zbiorczym). */
.admin-page .btn[hidden],
.admin-page .icon-btn[hidden]{ display:none; }
.admin-page .btn:hover{ background: var(--adm-surface-hover); border-color: var(--adm-accent); }
.admin-page .btn-primary{
  background: var(--adm-accent);
  border-color: var(--adm-accent);
  color:#06121e;
  box-shadow:none;
}
.admin-page .btn-primary:hover{ background:#57abff; border-color:#57abff; }
.admin-login-fields .btn{ width:100%; margin-top:2px; }
.admin-login-note{ margin:18px 0 0; color:var(--adm-text-faint); font-size:11px; text-align:center; }
.admin-panel{ display:grid; gap:12px; }
.admin-sessionbar{
  min-height:42px;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:12px;
  color: var(--adm-text-dim);
  font-size:12px;
}
.admin-sessionbar__identity,
.admin-sessionbar__actions{
  display:flex;
  align-items:center;
  gap:8px;
}
.admin-sessionbar__identity strong{ color: var(--adm-text); }
.admin-session-dot{
  width:7px;
  height:7px;
  border-radius:999px;
  background: var(--adm-ok);
}
.admin-tabs{
  display:inline-flex;
  justify-self:start;
  gap:3px;
  padding:3px;
  background:var(--adm-surface);
  border:1px solid var(--adm-border);
  border-radius:var(--adm-radius);
}
.admin-tab{
  min-height:34px;
  padding:7px 14px;
  color:var(--adm-text-dim);
  background:transparent;
  border:0;
  border-radius:var(--adm-radius-sm);
  font:inherit;
  font-size:12px;
  font-weight:650;
  cursor:pointer;
}
.admin-tab:hover{ color:var(--adm-text); background:var(--adm-surface-hover); }
.admin-tab.is-active{
  color:#06121e;
  background:var(--adm-accent);
}
.admin-tab:focus-visible{ outline:2px solid var(--adm-accent); outline-offset:2px; }
.admin-tab-view[hidden]{ display:none !important; }
.admin-config-view{ display:grid; gap:12px; }
.recording-session-card,.recording-player-card{ padding:18px; min-width:0; margin-bottom:12px; }
.recording-toolbar,.recording-player-head,.recording-session-controls,.recording-player-controls,.recording-range-controls{ display:flex; align-items:center; flex-wrap:wrap; gap:10px; }
.recording-toolbar,.recording-player-head{ justify-content:space-between; }
.recording-toolbar h1,.recording-player-head h2{ margin:2px 0 0; font-size:18px; }
.recording-toolbar__actions{ display:flex; align-items:center; gap:10px; }
.recording-rec{ color:var(--adm-error); border-color:rgba(240,87,76,.55); font-weight:800; }
.recording-rec.is-recording{ color:#fff; background:var(--adm-error); }
.recording-state{ color:var(--adm-text-dim); font:700 11px var(--adm-mono,monospace); }
.recording-session-controls{ margin-top:14px; }
.recording-session-controls label,.recording-player-head label{ display:grid; gap:4px; color:var(--adm-text-dim); font-size:10px; text-transform:uppercase; }
.recording-session-controls select{ min-width:280px; }
.recording-storage{ margin-top:10px; color:var(--adm-text-faint); font-size:11px; }
.recording-now{ display:flex; justify-content:space-between; gap:12px; margin:15px 0 7px; color:var(--adm-text-dim); font:12px var(--adm-mono,monospace); }
.recording-now strong{ color:var(--adm-text); }
.recording-timeline{ position:relative; height:82px; overflow:hidden; border:1px solid var(--adm-border-strong); border-radius:8px; background:var(--adm-bg); cursor:crosshair; }
.recording-timeline__segments,.recording-timeline__markers{ position:absolute; inset:0; }
.recording-timeline__segment{ position:absolute; top:0; bottom:0; background:rgba(62,207,142,.035); border-right:1px solid rgba(255,255,255,.08); }
.recording-timeline__gap{ position:absolute; top:0; bottom:0; background:repeating-linear-gradient(135deg,rgba(240,87,76,.14) 0 5px,transparent 5px 10px); }
.recording-marker{ position:absolute; top:18px; height:34px; min-width:3px; padding:0; overflow:hidden; border:0; border-radius:3px; background:var(--adm-accent); opacity:.76; cursor:pointer; }
.recording-marker:hover,.recording-marker.is-selected{ opacity:1; box-shadow:0 0 0 2px rgba(255,255,255,.55); }
.recording-marker.has-overlap{ top:50px; height:20px; background:#f4c66a; }
.recording-timeline__playhead{ position:absolute; z-index:5; top:0; bottom:0; width:2px; left:0; background:#fff; pointer-events:none; }
.recording-timeline__selection{ position:absolute; z-index:2; top:0; bottom:0; background:rgba(56,155,255,.2); border:1px solid var(--adm-accent); pointer-events:none; }
.recording-seek{ width:100%; margin:5px 0 8px; accent-color:var(--adm-accent); }
.recording-player-controls{ justify-content:center; }
.recording-live{ color:var(--adm-error); border-color:rgba(240,87,76,.45); }
.recording-range-controls{ margin-top:12px; padding-top:12px; border-top:1px solid var(--adm-border); color:var(--adm-text-dim); font-size:11px; }
.communication-log-table tbody tr[data-playable="true"]{ cursor:pointer; }
.communication-log-replay{ white-space:nowrap; }
.communication-log-replay button{ min-width:34px; min-height:28px; }
.communication-log-card{ padding:18px; min-width:0; }
.communication-log-head{
  display:flex; align-items:flex-start; justify-content:space-between; gap:20px;
}
.communication-log-head h1{ margin:2px 0 0; font-size:20px; }
.communication-log-head p{ margin:6px 0 0; max-width:720px; color:var(--adm-text-dim); font-size:12px; }
.communication-log-live{ display:flex; align-items:center; gap:8px; color:var(--adm-text-dim); font-size:11px; white-space:nowrap; }
.communication-log-live__dot{ width:7px; height:7px; border-radius:50%; background:var(--adm-ok); box-shadow:0 0 0 3px rgba(62,207,142,.12); }
.communication-log-live.is-history .communication-log-live__dot{ background:var(--adm-text-faint); box-shadow:none; }
.communication-log-active{
  margin-top:14px; padding:10px 12px; border:1px solid rgba(62,207,142,.28);
  border-radius:8px; background:rgba(62,207,142,.035);
}
.communication-log-active[hidden]{ display:none; }
.communication-log-active__title{
  margin-bottom:8px; color:var(--adm-ok); font-size:9.5px; font-weight:800;
  letter-spacing:.12em;
}
.communication-log-active__list{ display:grid; gap:7px; }
.admin-live-transcript{
  display:grid; gap:3px; padding:8px 10px; border-left:2px solid rgba(62,207,142,.58);
  border-radius:4px; background:var(--adm-bg);
}
.admin-live-transcript__head{
  color:var(--adm-text); font-size:10px; font-weight:750; letter-spacing:.045em;
  text-transform:uppercase;
}
.admin-live-transcript__text{ color:var(--adm-text); font-size:13px; line-height:1.45; word-break:break-word; }
.admin-live-transcript__current{ color:var(--adm-text-dim); font-style:italic; }
.communication-log-filters{ display:flex; flex-wrap:wrap; gap:10px; margin:16px 0 10px; }
.communication-log-filters label{ display:grid; gap:5px; min-width:190px; color:var(--adm-text-dim); font-size:10px; letter-spacing:.04em; text-transform:uppercase; }
.communication-log-filters .input{ min-height:36px; }
.communication-log-table-wrap{ overflow-x:auto; border-top:1px solid var(--adm-border); }
.communication-log-table{ width:100%; min-width:680px; border-collapse:collapse; font-size:12px; }
.communication-log-table th{
  padding:9px 10px; color:var(--adm-text-faint); font-size:9.5px; font-weight:700;
  letter-spacing:.12em; text-align:left; text-transform:uppercase; border-bottom:1px solid var(--adm-border);
}
.communication-log-table td{ padding:10px; color:var(--adm-text-mid); border-bottom:1px solid var(--adm-border); vertical-align:middle; }
.communication-log-table tbody tr:hover td{ background:var(--adm-surface-hover); }
.communication-log-table tbody tr.is-live td{ background:rgba(62,207,142,.045); }
.communication-log-table__time,
.communication-log-table__duration{ font-family:var(--adm-mono,ui-monospace,monospace); font-variant-numeric:tabular-nums; white-space:nowrap; }
.communication-log-table__user{ color:var(--adm-text) !important; font-weight:700; }
.communication-log-table__channel{ white-space:nowrap; }
.communication-log-flags{ display:flex; flex-wrap:wrap; gap:5px; }
.communication-log-flag{ display:inline-flex; align-items:center; min-height:20px; padding:2px 6px; border:1px solid var(--adm-border-strong); border-radius:999px; color:var(--adm-text-dim); font-size:9px; font-weight:750; letter-spacing:.05em; }
.communication-log-flag--live{ color:var(--adm-ok); border-color:rgba(62,207,142,.45); }
.communication-log-flag--overlap{ color:#f4c66a; border-color:rgba(244,198,106,.45); }
.communication-log-flag--no-audio,
.communication-log-flag--interrupted{ color:var(--adm-error); border-color:rgba(240,87,76,.42); }
.communication-log-empty{ margin:22px 0 8px; color:var(--adm-text-faint); font-size:12px; text-align:center; }
.communication-log-empty[hidden]{ display:none; }
.communication-log-footer{ display:flex; align-items:center; justify-content:space-between; gap:12px; min-height:42px; padding-top:10px; color:var(--adm-text-faint); font-size:11px; }
.communication-log-footer .btn{ margin-left:auto; }
.communication-log-search{ margin-left:auto; }
.communication-log-table__transcript{ max-width:280px; }
/* Dziennik komunikacji: zwarte wpisy (jedno PTT/Latch = jeden wpis), rozwijane fragmenty. */
.communication-log-older{ display:flex; justify-content:center; margin-top:6px; }
.communication-log-older[hidden]{ display:none; }
.clog-scroll-wrap{ position:relative; border-top:1px solid var(--adm-border); margin-top:8px; min-width:0; }
.clog-list{ max-height:min(68vh,720px); overflow-y:auto; overflow-x:hidden; overflow-anchor:none; min-width:0; }
.clog-separator{
  position:sticky; top:0; z-index:2; display:flex; align-items:baseline; gap:10px; padding:6px 10px 4px;
  background:var(--adm-surface,var(--adm-bg)); border-bottom:1px solid var(--adm-border-strong);
  color:var(--adm-text-dim); font-size:11px; font-weight:750; letter-spacing:.06em;
}
.clog-separator__time{ font-family:var(--adm-mono,ui-monospace,monospace); font-variant-numeric:tabular-nums; color:var(--adm-text); }
.clog-separator__day{ text-transform:uppercase; color:var(--adm-text-faint); font-weight:600; }
.clog-entry{ border-bottom:1px solid var(--adm-border); min-width:0; }
.clog-entry.is-live{ background:rgba(62,207,142,.045); }
.clog-head{
  display:grid; grid-template-columns:9.6rem 8.5rem 7.5rem minmax(0,1fr) auto; gap:4px 12px; align-items:start;
  padding:9px 10px; cursor:pointer; font-size:12px; color:var(--adm-text-mid);
}
.clog-head:hover,.clog-head:focus-visible{ background:var(--adm-surface-hover); outline:none; }
.clog-time{ font-family:var(--adm-mono,ui-monospace,monospace); font-variant-numeric:tabular-nums; color:var(--adm-text); white-space:nowrap; }
.clog-channel{ color:var(--adm-text-dim); font-size:11px; overflow-wrap:anywhere; }
.clog-user{ color:var(--adm-text); font-weight:700; overflow-wrap:anywhere; }
.clog-main{ min-width:0; overflow-wrap:anywhere; }
.clog-preview{ color:var(--adm-text); }
.clog-preview.is-placeholder{ color:var(--adm-text-faint); font-style:italic; }
.clog-frags{ color:var(--adm-text-faint); white-space:nowrap; }
.clog-hit{ margin-top:3px; color:var(--adm-text-dim); font-size:11px; }
.clog-hit__time{ font-family:var(--adm-mono,ui-monospace,monospace); margin-right:8px; color:var(--adm-text-faint); }
.clog-side{ display:flex; align-items:center; gap:8px; justify-content:flex-end; white-space:nowrap; }
.clog-duration{ font-family:var(--adm-mono,ui-monospace,monospace); font-variant-numeric:tabular-nums; color:var(--adm-text-dim); }
.clog-live{ color:var(--adm-ok); font-size:10px; font-weight:800; letter-spacing:.06em; }
.clog-flag{ color:var(--adm-error); font-size:9px; font-weight:750; letter-spacing:.05em; }
.clog-play{ min-width:30px; min-height:24px; padding:1px 6px; }
.clog-chevron{ width:12px; text-align:center; color:var(--adm-text-faint); }
.clog-mark{ background:rgba(244,198,106,.35); color:inherit; border-radius:2px; padding:0 1px; }
.clog-body{ padding:2px 10px 12px calc(9.6rem + 22px); display:grid; gap:6px; }
.clog-frag{ display:grid; grid-template-columns:4.6rem minmax(0,1fr); gap:10px; font-size:12.5px; line-height:1.4; color:var(--adm-text); }
.clog-frag__time{ font-family:var(--adm-mono,ui-monospace,monospace); font-variant-numeric:tabular-nums; color:var(--adm-text-faint); font-size:11px; padding-top:1px; }
.clog-frag__text{ overflow-wrap:anywhere; }
.clog-frag.is-draft .clog-frag__text{ opacity:.78; font-style:italic; }
.clog-frag.is-hit{ background:rgba(244,198,106,.07); box-shadow:-6px 0 0 rgba(244,198,106,.07); }
.clog-frag.is-empty{ display:block; color:var(--adm-text-faint); font-style:italic; }
.clog-actions{ margin-top:2px; }
.clog-new{
  position:absolute; left:50%; bottom:12px; transform:translateX(-50%); z-index:3; min-height:30px; padding:4px 14px;
  border-radius:999px; font-size:12px; font-weight:700; box-shadow:0 4px 14px rgba(0,0,0,.35);
}
.clog-new[hidden]{ display:none; }
@media (max-width:900px){
  .clog-head{ grid-template-columns:auto minmax(0,1fr) auto; grid-template-areas:'time time side' 'ch user user' 'main main main'; }
  .clog-time{ grid-area:time; }
  .clog-channel{ grid-area:ch; }
  .clog-user{ grid-area:user; }
  .clog-side{ grid-area:side; }
  .clog-main{ grid-area:main; }
  .clog-body{ padding-left:14px; }
}
}
.stt-transcript-quote{ color:var(--adm-text); font-style:italic; word-break:break-word; }
.stt-transcript-pending{ color:var(--adm-text-faint); font-style:italic; }
.stt-transcript-error{ color:var(--adm-error); }
.stt-transcript-nospeech{ color:var(--adm-text-faint); font-size:10px; letter-spacing:.04em; text-transform:uppercase; }
.stt-transcript-action{ margin-left:6px; min-height:24px; padding:2px 8px; font-size:11px; }
.stt-status-bar{
  display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-top:10px; padding:8px 12px;
  border:1px solid var(--adm-border-strong); border-radius:8px; background:var(--adm-bg); font-size:11px; color:var(--adm-text-dim);
}
.stt-status-bar__title{ color:var(--adm-text-faint); font-weight:750; letter-spacing:.08em; }
.stt-status-pill{ display:inline-flex; align-items:center; min-height:20px; padding:2px 8px; border:1px solid var(--adm-border-strong); border-radius:999px; font-size:9.5px; font-weight:750; letter-spacing:.05em; text-transform:uppercase; }
.stt-status-pill--ready{ color:var(--adm-ok); border-color:rgba(62,207,142,.45); }
.stt-status-pill--error{ color:var(--adm-error); border-color:rgba(240,87,76,.42); }
.stt-status-bar__auto{ display:flex; align-items:center; gap:6px; margin-left:auto; }
.recording-session-controls--stt{ margin-top:10px; padding-top:10px; border-top:1px solid var(--adm-border); }
.stt-session-only-missing{ display:flex; align-items:center; gap:6px; color:var(--adm-text-dim); font-size:11px; }
@media (max-width:780px){
  .recording-session-card,.recording-player-card{ padding:14px 12px; }
  .recording-session-controls select{ min-width:0; width:100%; }
  .recording-session-controls label{ width:100%; }
  .recording-now{ display:grid; }
  .communication-log-card{ padding:14px 12px; }
  .communication-log-head{ display:grid; gap:12px; }
  .communication-log-live{ white-space:normal; flex-wrap:wrap; }
  .communication-log-filters{ display:grid; grid-template-columns:1fr 1fr; }
  .communication-log-filters label{ min-width:0; }
  .communication-log-search{ margin-left:0; grid-column:1 / -1; }
  .communication-log-table__transcript{ max-width:160px; }
  .stt-status-bar__auto{ margin-left:0; }
}
.admin-page .admin-btn-quiet{
  min-height:32px;
  padding:.42rem .64rem;
  color: var(--adm-text-dim);
  background:transparent;
  border:1px solid var(--adm-border-strong);
}
.admin-page .admin-btn-quiet:hover{ color: var(--adm-text); background: var(--adm-surface-hover); }
.admin-page .admin-btn-danger-quiet{
  color: var(--adm-error);
  background:transparent;
  border:1px solid rgba(240,87,76,.35);
}
.admin-page .admin-btn-danger-quiet:hover{ background:rgba(240,87,76,.12); }
.admin-page .public-web-card{ padding:16px 18px; }
.public-web-head{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:20px;
}
.public-web-head h2{ margin:2px 0 0; font-size:17px; }
.public-web-head p{ margin:6px 0 0; max-width:720px; color:var(--adm-text-dim); font-size:12px; }
.public-web-fields{
  display:grid;
  grid-template-columns:minmax(180px,.7fr) minmax(260px,1.5fr) minmax(150px,.5fr);
  gap:12px;
  margin-top:15px;
}
.public-web-fields label{ display:grid; gap:6px; color:var(--adm-text-dim); font-size:11px; }
.public-web-fields .input:disabled{ opacity:.58; cursor:not-allowed; }
.public-web-note,
.public-web-effective{ margin:9px 0 0; color:var(--adm-text-faint); font-size:11px; }
.public-web-effective{ color:var(--adm-text-dim); }
.public-web-warning{
  margin-top:10px;
  padding:9px 10px;
  color:var(--adm-warn);
  background:rgba(232,177,58,.08);
  border:1px solid rgba(232,177,58,.32);
  border-radius:var(--adm-radius-sm);
  font-size:11px;
  line-height:1.45;
}
.routing-card{ padding:18px; }
/* ---- TALLY LIGHTS (panel admina) ---- */
.tally-view{ display:grid; gap:12px; }
.admin-page .tally-card{ padding:16px 18px; min-width:0; }
.tally-head h2{ margin:2px 0 0; font-size:17px; }
.tally-head p{ margin:6px 0 0; max-width:720px; color:var(--adm-text-dim); font-size:12px; }
.tally-fields{
  display:grid;
  grid-template-columns:minmax(150px,.6fr) minmax(220px,1.3fr) minmax(110px,.45fr) minmax(180px,.9fr) auto;
  align-items:end;
  gap:12px;
  margin-top:15px;
}
.tally-fields label{ display:grid; gap:6px; color:var(--adm-text-dim); font-size:11px; }
.tally-fields label[hidden]{ display:none; }
.tally-actions{ display:flex; gap:8px; }
.tally-status{
  display:flex; align-items:center; flex-wrap:wrap; gap:8px;
  margin-top:14px; font-size:12px; color:var(--adm-text-dim);
}
.tally-status__dot{ width:9px; height:9px; border-radius:50%; background:var(--adm-text-ghost); }
.tally-status__label{ font-family:var(--adm-mono); font-weight:700; letter-spacing:.06em; color:var(--adm-text-mid); }
.tally-status[data-state="CONNECTED"] .tally-status__dot{ background:var(--adm-ok); box-shadow:0 0 0 3px rgba(79,157,105,.18); }
.tally-status[data-state="CONNECTED"] .tally-status__label{ color:var(--adm-ok); }
.tally-status[data-state="CONNECTING"] .tally-status__dot,
.tally-status[data-state="RECONNECTING"] .tally-status__dot{ background:var(--adm-warn); }
.tally-status[data-state="RECONNECTING"] .tally-status__label{ color:var(--adm-warn); }
.tally-status[data-state="ERROR"] .tally-status__dot{ background:var(--adm-error); }
.tally-status[data-state="ERROR"] .tally-status__label{ color:var(--adm-error); }
.tally-error{
  margin-top:10px; padding:9px 10px; font-size:11.5px; line-height:1.45;
  color:var(--adm-warn); background:rgba(232,177,58,.08);
  border:1px solid rgba(232,177,58,.32); border-radius:var(--adm-radius-sm);
}
.tally-error[hidden]{ display:none; }
.tally-diagnostics{
  display:grid; grid-template-columns:repeat(6, minmax(0,1fr)); gap:10px 14px;
  margin:14px 0 0; padding-top:12px; border-top:1px solid var(--adm-border-soft);
}
.tally-diagnostics dt{ font-size:9.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--adm-text-ghost); }
.tally-diagnostics dd{ margin:3px 0 0; font-family:var(--adm-mono); font-size:12px; color:var(--adm-text-mid); overflow-wrap:anywhere; }
/* Jedna linia na użytkownika (jak w tabeli AUDIO/VIDEO ROUTING) — na dużym ekranie mieści się
   więcej userów na wysokość; dopiero na małych ekranach wiersz się rozbija na dwie linie.
   Kolumny mają STAŁE szerokości (nie `fr`) i każdy element ma jawny `grid-column` — dzięki temu
   wiersz bez żadnego przypisania wygląda TAK SAMO jak wiersz z przypisaniem (pusta kolumna, a nie
   przesunięcie reszty w lewo, gdy hint jest pusty/`hidden`). Dane trzymają się blisko siebie:
   user/hint/stan/numer mają stałą szerokość, a TYLKO ostatnia kolumna (nazwa źródła z dropdownu)
   dostaje 1fr — nie ma czego innego dalej w tym wierszu, więc na szerokim ekranie może się
   rozciągnąć i pokazać pełną nazwę zamiast być na siłę ucinana. */
.tally-routing{ display:grid; margin-top:4px; }
.tally-route{
  display:grid; grid-template-columns:minmax(64px,140px) minmax(0,160px) 52px 52px minmax(150px,1fr) auto auto;
  align-items:center; gap:8px; padding:6px 0; border-top:1px solid var(--adm-border-soft);
}
.tally-route:first-child{ border-top:0; }
.tally-route__user{ grid-column:1; font-size:13px; color:var(--adm-text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.tally-route__hint{
  grid-column:2; font-family:var(--adm-mono); font-size:10.5px; color:var(--adm-text-ghost);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.tally-route__state{ grid-column:3; font-family:var(--adm-mono); font-size:10.5px; font-weight:700; letter-spacing:.08em; text-align:center; }
.tally-route[data-state="PREVIEW"] .tally-route__state{ color:#0b1a0f; background:#2fbf5b; border-radius:4px; padding:2px 0; }
.tally-route[data-state="PROGRAM"] .tally-route__state{ color:#fff; background:#e5322d; border-radius:4px; padding:2px 0; }
.tally-route__number{ grid-column:4; min-width:0; width:100%; text-align:center; padding-left:4px; padding-right:4px; }
.tally-route__select{ grid-column:5; min-width:0; width:100%; }
/* Talent + PRV/PGM TEST na końcu tej samej linii (kolumny 6-7); bez poszerzania widoku. */
.tally-route__user,.tally-route__hint,.tally-route__state,.tally-route__number,.tally-route__select{ grid-row:1; }
.admin-page .tally-route .tally-route__talent{
  grid-column:6; grid-row:1; display:flex; flex-direction:row; align-items:center; gap:4px;
  font-size:10.5px; color:var(--adm-text-ghost); cursor:pointer; user-select:none; white-space:nowrap;
}
.admin-page .tally-route .tally-route__talent input{ width:auto; min-width:0; margin:0; flex:none; transform:scale(.85); }
.tally-route__tests{ grid-column:7; grid-row:1; display:flex; align-items:center; gap:4px; }
/* Przyciski przytrzymywane: brak przewijania/zaznaczania/menu długiego dotyku, kolory jak stany PREVIEW/PROGRAM. */
.tally-test-btn{
  touch-action:none; user-select:none; -webkit-user-select:none; -webkit-touch-callout:none;
  min-height:24px; padding:2px 6px; font-family:var(--adm-mono); font-size:9.5px; font-weight:700; letter-spacing:.04em; white-space:nowrap;
}
.admin-page .tally-route .tally-test-btn[data-test-state="PREVIEW"]{ border-color:rgba(47,191,91,.45); color:#2fbf5b; opacity:.75; }
.admin-page .tally-route .tally-test-btn[data-test-state="PROGRAM"]{ border-color:rgba(229,50,45,.45); color:#ff5a55; opacity:.75; }
.admin-page .tally-route .tally-test-btn:hover{ opacity:1; }
.admin-page .tally-route .tally-test-btn[data-test-state="PREVIEW"][data-active="true"]{ background:#2fbf5b; color:#0b1a0f; opacity:1; }
.admin-page .tally-route .tally-test-btn[data-test-state="PROGRAM"][data-active="true"]{ background:#e5322d; color:#fff; opacity:1; }
.admin-page .tally-route .tally-test-btn:disabled{ opacity:.4; cursor:not-allowed; }
@media (max-width:980px){
  .tally-fields{ grid-template-columns:1fr 1fr; }
  .tally-actions{ grid-column:1 / -1; }
  .tally-diagnostics{ grid-template-columns:repeat(3, minmax(0,1fr)); }
  .tally-route{ grid-template-columns:minmax(60px,1fr) minmax(0,1fr) 52px 52px minmax(120px,1fr) auto auto; }
}
@media (max-width:620px){
  .tally-fields{ grid-template-columns:1fr; }
  .tally-actions .btn{ flex:1; min-height:44px; }
  .tally-diagnostics{ grid-template-columns:repeat(2, minmax(0,1fr)); }
  .tally-route{
    grid-template-columns:1fr 56px auto; grid-template-rows:auto auto auto; row-gap:4px;
  }
  .tally-route__user{ grid-column:1; grid-row:1; }
  .tally-route__state{ grid-column:2; grid-row:1; }
  .tally-route__number{ grid-column:3; grid-row:1; }
  .tally-route__select{ grid-column:1 / -1; grid-row:2; }
  .tally-route__hint{ grid-column:1 / -1; grid-row:3; overflow:visible; white-space:normal; }
  .admin-page .tally-route .tally-route__talent{ grid-column:1; grid-row:4; }
  .tally-route__tests{ grid-column:2 / -1; grid-row:4; justify-content:flex-end; }
  .tally-test-btn{ min-height:40px; padding:4px 10px; }
}

.routing-head{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:24px;
}
.routing-head h1{ font-size:19px; }
.routing-head p{ margin:6px 0 0; max-width:650px; font-size:12px; }
.routing-head__actions{ display:flex; align-items:center; gap:8px; flex-shrink:0; }

/* Pasek operacji grupowych pojawia się dopiero po zaznaczeniu użytkownika. */
.admin-page .admin-bulk-actions{
  position:fixed;
  left:50%;
  bottom:max(16px, env(safe-area-inset-bottom));
  transform:translate(-50%, 12px);
  align-items:center;
  justify-content:space-between;
  gap:16px;
  width:min(760px, calc(100% - 32px));
  background:var(--adm-surface-2);
  border:1px solid var(--adm-border-strong);
  border-radius:var(--adm-radius);
  padding:10px 12px;
  display:flex;
  box-shadow:0 14px 42px rgba(0,0,0,.48);
  z-index:1000;
  opacity:0;
  visibility:hidden;
  pointer-events:none;
  transition:opacity .16s ease, transform .16s ease, visibility .16s;
}
.admin-page .admin-bulk-actions.visible{
  opacity:1;
  visibility:visible;
  pointer-events:auto;
  transform:translate(-50%, 0);
}
.admin-page .admin-bulk-actions__summary{
  display:flex;
  align-items:baseline;
  gap:6px;
  flex-shrink:0;
  color:var(--adm-text-dim);
  font-size:11px;
  white-space:nowrap;
}
.admin-page .admin-bulk-actions__summary strong{
  color:var(--adm-text);
  font-size:16px;
  font-variant-numeric:tabular-nums;
}
.admin-page .admin-bulk-actions__buttons{
  display:flex;
  align-items:center;
  justify-content:flex-end;
  gap:7px;
  min-width:0;
}
.admin-page .admin-btn-success-quiet{
  color:var(--adm-ok);
  background:transparent;
  border:1px solid rgba(62,207,142,.4);
}
.admin-page .admin-btn-success-quiet:hover{ background:rgba(62,207,142,.1); }
.admin-page .admin-bulk-actions__close{
  flex:0 0 32px;
  width:32px;
  height:32px;
  color:var(--adm-text-dim);
  cursor:pointer;
}
.admin-stats{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  margin-top:14px;
}
.admin-stat{
  display:flex;
  align-items:center;
  gap:7px;
  min-height:30px;
  padding:5px 10px;
  color: var(--adm-text-dim);
  background: var(--adm-surface);
  border:1px solid var(--adm-border);
  border-radius:var(--adm-radius-sm);
  font-size:11px;
}
.admin-stat strong{ color: var(--adm-text); font-size:13px; font-variant-numeric:tabular-nums; }
.admin-stat__dot{ width:6px; height:6px; border-radius:50%; background: var(--adm-text-faint); }
.admin-stat__dot--online{ background: var(--adm-ok); }
.admin-stat--ptt{
  background:rgba(240,87,76,.08);
  border-color:rgba(240,87,76,.34);
}
.admin-stat--ptt span:last-child{ color: var(--adm-error); font-weight:600; }
/* Kropka = odpowiednik plakietki NADAJE, czyli realny sygnał audio. */
.admin-stat__dot--audio{ background: var(--adm-error); }
.routing-legend{
  display:flex;
  align-items:center;
  flex-wrap:wrap;
  gap:9px 16px;
  margin:13px 0 10px;
  padding:9px 11px;
  color: var(--adm-text-dim);
  background: var(--adm-surface);
  border:1px solid var(--adm-border);
  border-radius:var(--adm-radius-sm);
  font-size:11px;
}
.routing-legend > span{ display:inline-flex; align-items:center; gap:6px; }
.routing-auto-pair{
  display:inline-flex;
  align-items:center;
  gap:7px;
  min-height:26px;
  padding:3px 9px;
  color: var(--adm-text-dim);
  background: var(--adm-surface-2);
  border:1px solid var(--adm-border-strong);
  border-radius:var(--adm-radius-sm);
  cursor:pointer;
  white-space:nowrap;
}
.routing-auto-pair:hover{ background: var(--adm-surface-hover); }
.routing-auto-pair input{
  width:14px;
  height:14px;
  margin:0;
  accent-color: var(--adm-accent);
}
.routing-auto-pair:has(input:focus-visible){
  outline:2px solid var(--adm-accent);
  outline-offset:2px;
}
.routing-legend__hint{ margin-left:auto; color: var(--adm-text-faint); }
.legend-pill{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:20px;
  height:20px;
  border-radius:var(--adm-radius-sm);
  font-size:10px;
  font-weight:700;
}
.legend-t{ color:#06121e; background: var(--adm-warn); }
.legend-l{ color:#06121e; background: var(--adm-accent); }
.legend-v{ color: var(--adm-video-ink, #0d1013); background: var(--adm-video, #8b5cf6); }
.legend-ptt{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-width:34px;
  height:20px;
  padding:0 6px;
  color: var(--adm-error);
  background:rgba(240,87,76,.08);
  border:1px solid rgba(240,87,76,.4);
  border-radius:var(--adm-radius-sm);
  font-size:10px;
  font-weight:700;
  letter-spacing:.04em;
}
.routing-table-shell{
  position:relative;
  width:100%;
  overflow:visible;
  border:1px solid var(--adm-border);
  border-radius:var(--adm-radius);
  background: var(--adm-surface);
  scrollbar-color:#3b4048 #111317;
}
.btn-add-row{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:.4rem;
  width:100%;
  margin-top:10px;
  padding:.6rem;
  border:1px dashed var(--adm-border-strong);
  border-radius:var(--adm-radius);
  background:transparent;
  color: var(--adm-text-dim);
  font-size:.9rem;
  font-weight:600;
  cursor:pointer;
  transition:background-color .15s ease, border-color .15s ease, color .15s ease;
}
.btn-add-row span{ font-size:1rem; line-height:1; color: var(--adm-accent); }
.btn-add-row:hover,
.btn-add-row:focus-visible{
  border-color: var(--adm-accent);
  color: var(--adm-text);
  background: var(--adm-surface-hover);
}
.btn-add-row:focus-visible{ outline:2px solid var(--adm-accent); outline-offset:2px; }
.admin-page #tbl_users{
  display:table;
  width:100%;
  margin:0;
  min-width:1080px;
  /* Suma kolumn (24+190+112+52+112*6+180 = 1230px) — węższe niż poprzednio, żeby na
     ekranie mieściło się więcej kolumn na raz; na szerokim ekranie tabela przestaje
     rosnąć tutaj, a nadmiar zostaje pustym marginesem po prawej zamiast rozciągać
     kolumny kanałów (patrz `.routing-col-channel`). */
  max-width:1230px;
  overflow:visible;
  border:0;
  border-radius:0;
  background:transparent;
  font-size:12px;
  table-layout:fixed;
}
.admin-page #tbl_users .routing-col-select{ width:24px; }
.admin-page #tbl_users .routing-col-user{ width:190px; }
.admin-page #tbl_users .routing-col-role{ width:82px; }
.admin-page #tbl_users .routing-col-actions{ width:142px; }
/* Stała, zwarta geometria operatorska: T/L muszą zmieścić się w jednym rzędzie bez
   zawijania, a kolumny kanałów nie mogą się rozciągać proporcjonalnie na szerokim
   ekranie — patrz `#tbl_users{ max-width }` niżej, gdzie nadmiar szerokości zostaje
   pustym marginesem zamiast rozciągać te kolumny. Zwężone względem T/L (28px×2+6px
   gap = 62px treści), żeby kolumny kanałów nie zajmowały więcej miejsca niż muszą. */
.admin-page #tbl_users .routing-col-channel{ width:112px; }

/* Kolumna checkboxów - bardzo wąska i sticky */
.admin-page #tbl_users .th-select,
.admin-page #tbl_users .td-select{
  width:24px !important;
  min-width:24px !important;
  max-width:24px !important;
  text-align:center;
  padding:8px 4px;
  position:sticky;
  left:0;
  z-index:1;
  background:#14171c;
  box-shadow:1px 0 0 #262c34 inset;
}
.admin-page #tbl_users .th-select{
  background:#1a1e24;
  z-index:4;
}
.admin-page #tbl_users::after{ display:none; }
.admin-page #tbl_users thead th{ padding:6px 7px; }
.admin-page #tbl_users tbody td{ padding:4px 6px; }
.admin-page #tbl_users thead th{
  top:var(--admin-sticky-offset);
  z-index:4;
  background: var(--adm-surface-2);
  border-bottom-color: var(--adm-border);
}
.admin-page #tbl_users thead tr:first-child th{
  top:var(--admin-sticky-offset);
}
.admin-page #tbl_users thead tr:nth-child(2) th{
  top:calc(var(--admin-sticky-offset) + 34px);
}
.admin-page #tbl_users thead tr:first-child th:first-child,
.admin-page #tbl_users thead tr:first-child th:nth-child(2){ z-index:6; }
.admin-page #tbl_users thead .th-center{
  height:34px;
  color: var(--adm-text-faint);
  font-size:10px;
  font-weight:600;
  letter-spacing:.13em;
  text-transform:uppercase;
}
.admin-page #tbl_users thead .th-ch{
  height:78px;
  padding:7px 10px 6px;
  border-right-color: var(--adm-border);
}
.admin-page #tbl_users thead .th-ch .ch-number{
  margin-bottom:3px;
  font-size:14px;
}
.admin-page #tbl_users thead .th-ch .ch-title{
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
  font-size:12px;
}
.admin-page #tbl_users thead .th-ch .ch-sub{
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:2px;
  width:100%;
  margin:5px auto 0;
  opacity:1;
}
.admin-page #tbl_users thead .th-ch .column-toggle{
  appearance:none;
  min-width:28px;
  min-height:24px;
  padding:3px 7px;
  color: var(--adm-text-faint);
  background:transparent;
  border:1px solid transparent;
  border-radius:var(--adm-radius-sm);
  cursor:pointer;
  font-size:9px;
  font-weight:700;
  letter-spacing:.08em;
}
.admin-page #tbl_users thead .th-ch .column-toggle:hover{ background: var(--adm-surface-hover); }
.admin-page #tbl_users thead .th-ch .column-toggle:focus-visible{
  outline:2px solid currentColor;
  outline-offset:1px;
}
.admin-page #tbl_users thead .th-ch .column-toggle--talk{ color: var(--adm-warn); }
.admin-page #tbl_users thead .th-ch .column-toggle--listen{ color: var(--adm-accent); }
.admin-page #tbl_users thead .th-ch .column-toggle--video{ color: var(--adm-video); }
.admin-page #tbl_users.is-painting,
.admin-page #tbl_users.is-painting *{ user-select:none; }
.admin-page #tbl_users.is-painting .tl-i{ cursor:crosshair; }
.admin-page #tbl_users .tl-i.paint-hit{
  background:transparent;
  box-shadow:none;
}
.admin-page #tbl_users tbody tr:nth-child(odd),
.admin-page #tbl_users tbody tr:nth-child(even){ background: var(--adm-surface); }
.admin-page #tbl_users tbody tr{ height:46px; }
/* Focus oznacza trwającą edycję i zachowuje dotychczasowe, spokojne zaznaczenie. */
.admin-page #tbl_users tbody tr:focus-within td{ background: var(--adm-surface-hover) !important; }
.admin-page #tbl_users tbody tr.is-selected td{
  background:rgba(59,157,255,.1) !important;
}
/* Trwały znacznik zaznaczonego wiersza na kolumnie nazwy — odpowiednik fioletowej
   kreski `.video-user-cell` w tabeli wideo, ale w kolorze domeny audio (accent),
   bo fiolet jest zarezerwowany dla VIDEO. Bez tego audio nie miało żadnego trwałego
   (nie tylko hover) znacznika zaznaczenia, w odróżnieniu od tabeli wideo. */
.admin-page #tbl_users tbody tr.is-selected td:nth-child(2){
  box-shadow: inset 3px 0 0 0 var(--adm-accent), 1px 0 0 #262c34 inset;
}
.admin-page #tbl_users tbody tr.is-selected:focus-within td{
  background:rgba(59,157,255,.16) !important;
}
/* Hover myszy jest celowo mocniejszy od zaznaczenia pozostającego podczas edycji. */
@media (hover:hover) and (pointer:fine){
  .admin-page #tbl_users tbody tr:hover{
    box-shadow:
      inset 4px 0 0 var(--adm-accent),
      inset 0 1px 0 rgba(59,157,255,.34),
      inset 0 -1px 0 rgba(59,157,255,.34);
  }
  .admin-page #tbl_users tbody tr:hover td{
    background:#263544 !important;
  }
  .admin-page #tbl_users tbody tr.is-selected:hover td{
    background:#29405a !important;
  }
}
.admin-page #tbl_users tbody td:first-child,
.admin-page #tbl_users tbody td:nth-child(2),
.admin-page #tbl_users tbody td:nth-child(3){ background: var(--adm-surface); }
.admin-page #tbl_users tbody td:nth-child(2){ font-size:13px; }
.admin-page #tbl_users .td-user.editing{
  overflow:hidden !important;
  white-space:nowrap !important;
  padding-top:7px;
  padding-bottom:7px;
}
.admin-page #tbl_users .td-user.editing .status-dot,
.admin-page #tbl_users .td-user.editing .battery-badge,
.admin-page #tbl_users .td-user.editing .ptt-live-summary{
  display:none !important;
}
.admin-page #tbl_users .uname-input{
  display:block;
  width:100%;
  min-width:0;
  min-height:36px;
  height:36px;
  margin:0;
  padding:6px 9px;
  border-radius:var(--adm-radius-sm);
  font-size:13px;
  font-weight:600;
  line-height:1.2;
  background: var(--adm-bg);
  border-color: var(--adm-accent);
}
.admin-page #tbl_users .uname-input:focus{
  border-color: var(--adm-accent);
  box-shadow:none;
}
.admin-page #tbl_users tbody td[data-ptt-uid]{
  position:relative;
  border-right-color: var(--adm-border);
}
.admin-page #tbl_users .tl{
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  align-items:center;
  gap:0;
  width:100%;
  margin-inline:auto;
}
.admin-page #tbl_users .tl-i{
  display:flex;
  align-items:center;
  justify-content:center;
  justify-self:center;
  gap:6px;
  width:40px;
  min-height:30px;
  padding:4px;
  border:1px solid var(--adm-border-strong);
  border-radius:var(--adm-radius-sm);
  background: var(--adm-surface-2);
  cursor:pointer;
}
.admin-page #tbl_users .tl-t{ border-color: rgba(232,177,58,.35); }
.admin-page #tbl_users .tl-l{ border-color: rgba(59,157,255,.35); }
.admin-page .user-drag-handle{ cursor:grab; color:var(--adm-text-dim); display:inline-block; margin-right:.35rem; user-select:none; touch-action:none; }
.admin-page .user-drag-handle:active{ cursor:grabbing; }
.admin-page #tbl_users tbody tr.is-user-dragging{ opacity:.45; }
.admin-page #tbl_users tbody tr.is-user-drop-target td{ box-shadow:inset 0 3px 0 var(--adm-accent); }
.admin-page #tbl_users .tl-i:hover{ background: var(--adm-surface-hover); }
.admin-page #tbl_users .tl-k{
  font-size:10px;
  font-weight:700;
  line-height:1;
}
.admin-page #tbl_users .tl-t .tl-k{ color: var(--adm-warn); }
.admin-page #tbl_users .tl-l .tl-k{ color: var(--adm-accent); }
.admin-page #tbl_users .td-actions{ width:196px; }
/* Jeden przycisk, dwa stany: kolor zależy WYŁĄCZNIE od tego, czy latch jest teraz
   włączony (kolory ostatecznie ustala sekcja „Admin: odświeżony wygląd" niżej w tym
   pliku — tu zostaje tylko geometria, żeby nie duplikować reguł koloru w dwóch miejscach). */
.admin-page #tbl_users .latch-toggle-fast{
  margin-left:5px;
  min-height:30px;
  padding:.35rem .5rem;
  font-size:10px;
}
.admin-page #tbl_users .buzz-fast{
  --buzz-progress: 0;
  position:relative;
  overflow:hidden;
  margin-left:5px;
  min-height:30px;
  padding:.35rem .5rem;
  font-size:10px;
  touch-action:none; /* nie przewijaj strony podczas przytrzymania na dotyku */
  user-select:none;
}
.admin-page #tbl_users .buzz-fast::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:-1;
  width:calc(var(--buzz-progress) * 100%);
  background:rgba(59,157,255,.28);
  pointer-events:none;
}
.admin-page #tbl_users .buzz-fast.buzz-armed{
  background:rgba(240,87,76,.14);
  border-color: var(--adm-error);
  color: var(--adm-error);
  font-weight:700;
}
.admin-page #tbl_users .buzz-fast.buzz-armed::before{
  background:rgba(240,87,76,.4);
}
.admin-page #tbl_users input[type="checkbox"]{
  width:17px;
  height:17px;
  margin:0;
  transform:none;
  cursor:pointer;
}
.admin-page #tbl_users .ptt-live-marker{
  position:absolute;
  top:3px;
  right:3px;
  margin:0;
  padding:2px 4px;
  font-size:7px;
  pointer-events:none;
}
.admin-page #tbl_users .row-actions .menu{
  z-index:10000;
  box-shadow:0 18px 55px rgba(0,0,0,.5);
}
.admin-page .sessions-section{ padding:16px 18px; }
.admin-page .sessions-title{ font-size:15px; }
.admin-page .session-card{ background: var(--adm-surface); border-color: var(--adm-border); }
.admin-footer{
  padding:8px 0 20px;
  color: var(--adm-text-faint, #6c757f);
  font-size:10px;
  text-align:center;
}
.admin-dialog{
  width:min(480px, calc(100% - 28px));
  max-width:none;
  padding:0;
  color: var(--adm-text, #e8ebee);
  background:transparent;
  border:0;
  overflow:visible;
}
.admin-dialog::backdrop{
  background:rgba(3,5,8,.7);
}
.admin-dialog__card{
  padding:20px;
  background: var(--adm-surface, #14171c);
  border:1px solid var(--adm-border-strong, #333b45);
  border-radius:var(--adm-radius, 8px);
  box-shadow:0 24px 80px rgba(0,0,0,.5);
}
.admin-dialog__head{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:18px;
}
.admin-dialog h2{ font-size:18px; }
.admin-dialog__head .icon-btn{ font-size:20px; cursor:pointer; }
.admin-dialog__lead{ margin:9px 0 18px; font-size:12px; }
.admin-dialog__fields{ display:grid; gap:14px; }
.admin-password-field{ position:relative; }
.admin-password-field .input{ padding-right:70px; }
.admin-password-toggle{
  position:absolute;
  right:8px;
  top:50%;
  transform:translateY(-50%);
  padding:6px 7px;
  color: var(--adm-text-dim, #a4adb8);
  background:transparent;
  border:0;
  border-radius:var(--adm-radius-sm, 5px);
  cursor:pointer;
  font-size:11px;
  font-weight:600;
}
.admin-password-toggle:hover{ color: var(--adm-text, #e8ebee); background:rgba(255,255,255,.06); }
.admin-dialog__info{
  margin-top:15px;
  padding:10px 11px;
  color: var(--adm-text-dim, #a4adb8);
  background:rgba(59,157,255,.07);
  border:1px solid rgba(59,157,255,.22);
  border-radius:var(--adm-radius-sm, 5px);
  font-size:11px;
  line-height:1.45;
}
.admin-dialog__actions{
  display:flex;
  justify-content:flex-end;
  gap:8px;
  margin-top:18px;
}

/* Bootstrap przez bezpieczny link */
.join-card{ text-align:center; align-items:center; }
.join-logo{ display:block; margin:0 auto 14px; border-radius:18px; }
.join-spinner{
  width:34px; height:34px; margin:18px auto 2px;
  border:3px solid rgba(255,255,255,.18); border-top-color:#3b9dff; border-radius:50%;
  animation:join-spin .85s linear infinite;
}
.join-card.is-error .join-spinner{ display:none; }
@keyframes join-spin{ to{ transform:rotate(360deg); } }
@media (prefers-reduced-motion:reduce){ .join-spinner{ animation-duration:1.8s; } }

/* Dialog linku dostępu w panelu */
.admin-dialog--access-link{ width:min(560px, calc(100% - 28px)); }
/* Szeroki ekran: link obok kodu QR. Wąski: flex-wrap układa kod pod linkiem. */
.access-link-share{ display:flex; flex-wrap:wrap; align-items:flex-start; gap:16px; margin-top:15px; }
/* Bez `hidden` własne `display` wygrałoby z regułą przeglądarki i pokazywało pusty kod QR. */
.access-link-share [hidden]{ display:none; }
.access-link-value{ display:grid; gap:7px; flex:1 1 220px; min-width:0; color:var(--adm-text-dim); font-size:11px; }
.access-link-value .input{ width:100%; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:11px; }
.access-link-qr{ display:grid; gap:8px; justify-items:center; flex:0 0 auto; margin:0; max-width:100%; }
/* Biała podkładka pod kodem — czytelny kontrast niezależnie od tła panelu. */
.access-link-qr__code{
  width:220px;
  height:220px;
  max-width:100%;
  padding:8px;
  background:#ffffff;
  border:1px solid var(--adm-border-strong, #333b45);
  border-radius:var(--adm-radius-sm, 5px);
  box-sizing:border-box;
}
.access-link-qr__code svg{ display:block; width:100%; height:100%; }
.access-link-qr__caption{ max-width:236px; color:var(--adm-text-dim); font-size:10px; line-height:1.4; text-align:center; }
.access-link-qr__error{ max-width:236px; margin:0; color:var(--adm-warn, #d3a12c); font-size:10px; line-height:1.4; text-align:center; }
.access-link-note{ margin:10px 0 0; color:var(--adm-text-faint,#6c757f); font-size:10px; line-height:1.45; }
.access-link-actions{ flex-wrap:wrap; }
.access-link-actions .btn-danger{ margin-right:auto; }

/* Powiadomienia w panelu admina — płaska karta z akcentem po lewej, bez czerwonego
   gradientu odziedziczonego po widoku mobilnym (tam czerwień jest domyślnym tłem toastu). */
.admin-page .toast{
  background: var(--adm-surface-2, #1a1e24);
  color: var(--adm-text, #e8ebee);
  border:1px solid var(--adm-border-strong, #333b45);
  border-left:3px solid var(--adm-accent, #3b9dff);
  border-radius:var(--adm-radius-sm, 5px);
  font-weight:600;
  box-shadow:0 8px 24px rgba(0,0,0,.4);
}
.admin-page .toast.warn{
  background: var(--adm-surface-2, #1a1e24);
  color: var(--adm-text, #e8ebee);
  border-color: var(--adm-border-strong, #333b45);
  border-left-color: var(--adm-warn, #e8b13a);
}
@media (max-width:800px){
  .admin-page .container{ width:min(100% - 40px, 1440px); }
  .public-web-fields{ grid-template-columns:1fr 1fr; }
  .public-web-fields label:nth-child(2){ grid-column:1 / -1; grid-row:2; }
  .routing-head{ flex-direction:column; gap:14px; }
  .routing-head__actions{ width:100%; }
  .routing-head__actions .btn:first-child{ flex:1; }
  .routing-legend__hint{ width:100%; margin-left:0; }
  .admin-page #tbl_users{ min-width:1080px; }
  .admin-header__inner{ gap:10px; }
  .admin-header__stats{ justify-content:flex-end; }
  .admin-header__stats .admin-stat span:last-child{ display:none; }
}
@media (max-width:560px){
  .admin-page{ --admin-sticky-offset:0px; }
  .admin-header__inner{ min-height:58px; }
  .admin-brand img{ width:34px; height:34px; }
  .admin-brand span{ display:none; }
  .admin-account-menu__label{ display:none; }
  .admin-account-menu__toggle{ gap:5px; padding-right:7px; }
  .admin-header__stats{ gap:4px; }
  .admin-header__stats .admin-stat{ min-width:0; padding:5px 7px; }
  .admin-header__stats .admin-stat__dot{ display:none; }
  .admin-main{ padding-top:8px; }
  .admin-sessionbar{ align-items:flex-start; }
  .admin-sessionbar__actions{ gap:4px; }
  .admin-page .admin-btn-quiet{ padding:.4rem .5rem; font-size:10px; }
  .public-web-head{ flex-direction:column; gap:12px; }
  .public-web-head .btn{ width:100%; }
  .public-web-fields{ grid-template-columns:1fr; }
  .public-web-fields label:nth-child(2){ grid-column:auto; grid-row:auto; }
  .routing-card{ padding:13px; }
  .routing-head h1{ font-size:21px; }
  .routing-head__actions{ flex-direction:column; align-items:stretch; }
  .routing-head__actions .btn{ width:100%; }
  .admin-stat{ flex:1; min-width:94px; justify-content:center; }
  .admin-dialog__card{ padding:18px; }
  .admin-page .admin-bulk-actions{
    align-items:stretch;
    gap:8px;
    width:calc(100% - 20px);
    padding:9px;
  }
  .admin-page .admin-bulk-actions__summary{ align-items:center; padding-inline:4px; }
  .admin-page .admin-bulk-actions__summary span{ display:none; }
  .admin-page .admin-bulk-actions__buttons{ flex-wrap:wrap; }
  .admin-page .admin-bulk-actions__buttons .btn{ flex:1 1 auto; min-height:38px; }
}

@media (max-width:640px){
  /* Domknij wcześniejszą regułę mobilną: późniejszy, bardziej szczegółowy styl kolumny
     wyboru nie może ponownie przykleić checkboxów wierszy podczas przewijania w bok. */
  .admin-page #tbl_users .td-select{ position:static; left:auto; z-index:auto; }
  .admin-page #tbl_users .th-select{ left:auto; }
}


/* === Ustawienia zarządzane przez administratora ==================================== */
/* Kontrolka pozostaje widoczna wraz z aktualną wartością — zmieniona jest wyłącznie
   możliwość jej edycji (patrz public/js/userConfigPolicy.js). */
.managed-note{ display:block; color:var(--accent); font-size:.72rem; letter-spacing:.02em; }
.managed-note::before{ content:"🔒 "; }
[data-managed="1"] > span > b,
[data-managed="1"] > span{ opacity:.85; }
.settings-options [data-managed="1"] input[type="checkbox"]:disabled{ opacity:.5; cursor:not-allowed; }
.settings-options [data-managed="1"] select:disabled{ opacity:.5; cursor:not-allowed; }
.presence-managed-note{
  margin:6px 0 2px; padding:8px 10px; border-radius:10px;
  background:rgba(255,255,255,.04); color:var(--muted); font-size:.78rem; line-height:1.35;
}
.presence-volume-slider:disabled{ opacity:.5; cursor:not-allowed; }
.volume-reset-all:disabled{ opacity:.5; cursor:not-allowed; }


/* === Panel: konfiguracja beltpacka (dialog) ========================================= */
/* Czytelność przed liczbą kontrolek: trzy sekcje, w każdej wartość po lewej, a prawo do jej
   zmiany po prawej. To rozdzielenie jest sednem funkcji — patrz server/userConfig.js. */
.admin-dialog--wide{ width:min(720px, calc(100vw - 32px)); }
/* Wysoki dialog (konfiguracja beltpacka): karta ograniczona do okna, środek się przewija,
   a pasek akcji z przyciskiem „Zapisz/Zastosuj” zostaje przypięty i zawsze widoczny. */
.admin-dialog--wide .admin-dialog__card{
  display:flex; flex-direction:column;
  max-height:calc(100vh - 32px);
}
.admin-dialog--wide .uc-body{
  flex:1 1 auto; min-height:0; max-height:none;
}
.admin-dialog--wide .admin-dialog__actions{ flex:0 0 auto; }
.uc-body{ display:grid; gap:16px; max-height:min(70vh, 640px); overflow-y:auto; }
.uc-section{
  padding:13px 14px;
  border:1px solid var(--adm-border, #262d36);
  border-radius:var(--adm-radius-sm, 5px);
  background:rgba(255,255,255,.02);
}
.uc-section__title{
  margin:0 0 10px; font-size:11px; letter-spacing:.09em; text-transform:uppercase;
  color:var(--adm-text-dim, #a4adb8);
}
.uc-row{ display:grid; gap:8px; padding:8px 0; border-top:1px solid var(--adm-border, #262d36); }
.uc-section .uc-row:first-of-type{ border-top:0; padding-top:0; }
.uc-row--inline{ grid-template-columns:1fr auto; align-items:center; }
.uc-row__head{ display:flex; align-items:center; justify-content:space-between; gap:14px; flex-wrap:wrap; }
.uc-row strong{ font-size:13px; }
.uc-control{ display:flex; gap:4px; padding:2px; border-radius:999px; background:rgba(255,255,255,.05); }
.uc-control label{
  display:inline-flex; align-items:center; gap:5px; padding:4px 10px;
  border-radius:999px; font-size:11px; color:var(--adm-text-dim, #a4adb8); cursor:pointer;
}
.uc-control label:has(input:checked){ background:var(--adm-accent, #3b9dff); color:#08101a; font-weight:700; }
.uc-control input{ accent-color:#08101a; margin:0; }
.uc-channels{ display:flex; flex-wrap:wrap; gap:6px; }
.uc-channel{
  display:inline-flex; align-items:center; gap:6px; padding:5px 9px;
  border:1px solid var(--adm-border, #262d36); border-radius:999px;
  font-size:12px; cursor:pointer; background:rgba(255,255,255,.03);
}
.uc-channel:has(input:checked){ border-color:var(--adm-accent, #3b9dff); background:rgba(59,157,255,.14); }
/* Tak samo jak u użytkownika: LISTEN / „SŁYSZĘ” jest niebieskie, a TALK / „MÓWIĘ DO”
   żółte. Selektory są ograniczone do routingu beltpacka, więc nie zmieniają innych kontrolek. */
#uc_listen_channels .uc-channel input{ accent-color:var(--adm-accent, #3b9dff); }
#uc_talk_channels .uc-channel input{ accent-color:var(--adm-warn, #e8b13a); }
#uc_talk_channels .uc-channel:has(input:checked){
  border-color:var(--adm-warn, #e8b13a);
  background:rgba(232,177,58,.14);
}
.uc-channel.is-denied{ opacity:.4; cursor:not-allowed; }
.uc-channel input{ margin:0; }
.uc-audio-row{
  display:grid; grid-template-columns:1fr auto auto; align-items:center; gap:12px;
  padding:8px 0; border-top:1px solid var(--adm-border, #262d36);
}
.uc-audio-row:first-child{ border-top:0; padding-top:0; }
.uc-hint{ margin:9px 0 0; font-size:11px; line-height:1.45; color:var(--adm-text-dim, #a4adb8); }
#btn_uc_reset_volumes{ margin-top:10px; }
/* Plakietka w wierszu tabeli: operator ma jednym spojrzeniem widzieć, kto jest zarządzany. */
.managed-badge{
  display:inline-flex; align-items:center; gap:3px; margin-left:6px;
  padding:1px 6px; border-radius:999px; font-size:10px; font-weight:700; letter-spacing:.04em;
  color:#08101a; background:var(--adm-accent, #3b9dff);
}
.managed-badge[hidden]{ display:none; }
.managed-badge[role="button"]{ cursor:pointer; }
.managed-badge[role="button"]:hover{ filter:brightness(1.12); }
.managed-badge[role="button"]:focus-visible{ outline:2px solid var(--adm-accent, #3b9dff); outline-offset:2px; }

/* ---- Konfiguracja grupowa beltpacków: tri-state (ALL_ON / ALL_OFF / MIXED) ---- */
.uc-bulk-hint{
  margin:8px 0 0; padding:8px 11px; font-size:12px; line-height:1.5;
  border:1px solid var(--adm-border, #262d36); border-radius:8px;
  background:rgba(59,157,255,.06); color:var(--adm-text-dim, #a4adb8);
}
.uc-bulk-hint[hidden]{ display:none; }
.uc-tri{
  display:inline-flex; align-items:center; gap:7px; padding:5px 11px;
  border-radius:999px; background:rgba(255,255,255,.05); font-size:12px; cursor:pointer;
  border:1px solid transparent;
}
.uc-tri input{ margin:0; accent-color:var(--adm-accent, #3b9dff); }
.uc-mixed-tag{ font-size:10px; font-style:italic; opacity:.75; letter-spacing:.02em; }
.uc-tri:not(.is-mixed) .uc-mixed-tag{ display:none; }
/* Kontener radiogroup nie dubluje tła, gdy trzyma pojedynczy tri-state checkbox. */
.uc-control:has(.uc-tri){ background:none; padding:0; }
.uc-control .uc-tri:has(input:checked){ background:var(--adm-accent, #3b9dff); color:#08101a; font-weight:700; }
/* „Dotknięte” = trafi do zapisu i zostanie wymuszone wszystkim zaznaczonym. */
.uc-tri.is-touched,
.uc-channel.is-touched{ box-shadow:inset 0 0 0 1px var(--adm-accent, #3b9dff); }
.uc-audio-row.is-touched{ box-shadow:inset 3px 0 0 var(--adm-accent, #3b9dff); }
.uc-channel.is-mixed{ border-style:dashed; border-color:var(--adm-text-dim, #a4adb8); background:rgba(255,255,255,.04); }
.uc-channel input:indeterminate{ opacity:.9; }
/* i18n: native language names remain readable in every locale; controls may grow with translations. */
.language-field select {
  min-width: 8.5rem;
  max-width: 100%;
}
.btn, button, label, .panel-title, .panel-subtitle, .admin-tab, .admin-stat {
  overflow-wrap: anywhere;
}

/* ==================================================================================
   MOBILNY ADMIN — dedykowany UX poniżej ~780 px
   Desktop (> 780 px) niezmieniony: #mobile_routing i .admin-bottomnav są display:none,
   a #tbl_users działa jak dotąd. Poniżej breakpointu chowamy desktopową tabelę i
   dolną nawigację pokazujemy jako główny sposób przełączania Routing / Konfiguracja.
   ================================================================================== */

/* --- elementy domyślnie ukryte (tryb desktop) --- */
#mobile_routing{ display:none; }
.admin-bottomnav{ display:none; }

/* --- Mobilna macierz routingu (style bazowe, aktywne dopiero gdy kontener widoczny) --- */
.mtx-wrap{ margin:12px 0 4px; }
.mtx-legend{
  display:flex; flex-wrap:wrap; align-items:center; gap:6px 12px;
  margin-bottom:8px; padding:8px 10px; font-size:11px;
  color:var(--adm-text-dim); background:var(--adm-surface);
  border:1px solid var(--adm-border); border-radius:var(--adm-radius-sm);
}
.mtx-legend__hint{ flex:1 1 100%; color:var(--adm-text-faint); }
.mtx-scroll{
  position:relative;
  overflow:auto;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;
  border:1px solid var(--adm-border);
  border-radius:var(--adm-radius-sm);
  background:var(--adm-bg);
}
table.mtx{
  border-collapse:separate;
  border-spacing:0;
  table-layout:fixed;
  width:max-content;
  font-size:12px;
  color:var(--adm-text);
}
table.mtx th,
table.mtx td{
  margin:0;
  border-right:1px solid var(--adm-border);
  border-bottom:1px solid var(--adm-border);
  background:var(--adm-surface);
  vertical-align:middle;
}
/* Sticky: nagłówek kanałów u góry, kolumna użytkownika po lewej, róg w obu osiach. */
table.mtx thead th{ position:sticky; top:0; z-index:3; background:var(--adm-surface-2); }
table.mtx tbody th.mtx-user{ position:sticky; left:0; z-index:2; }
table.mtx thead th.mtx-corner{ left:0; z-index:4; }
.mtx-corner,
.mtx-user{ width:132px; min-width:132px; max-width:132px; }
.mtx-chh,
.mtx-cell{ width:96px; min-width:96px; max-width:96px; }
.mtx-corner{
  padding:6px 8px; font-size:10px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--adm-text-faint); font-weight:700;
}
.mtx-chh{ padding:5px 6px; text-align:center; }
.mtx-chh__num{ display:block; font-size:10px; color:var(--adm-text-faint); font-weight:700; }
.mtx-chh .ch-title{
  display:block; margin:1px 0 4px; font-size:11px; font-weight:600;
  color:var(--adm-text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  cursor:pointer;
}
.mtx-chh .ch-title:focus-visible{ outline:2px solid var(--adm-accent); outline-offset:1px; }
.mtx-chh__toggles{ display:flex; gap:4px; justify-content:center; }
.mtx-chh__toggles .column-toggle{
  flex:1; min-height:26px; padding:0; border-radius:6px; font-size:11px; font-weight:700;
  border:1px solid var(--adm-border-strong); background:var(--adm-surface-2); cursor:pointer;
}
.mtx-chh__toggles .column-toggle--talk{ color:var(--adm-warn); }
.mtx-chh__toggles .column-toggle--listen{ color:var(--adm-accent); }
.mtx-chh__toggles .column-toggle--video{ color:var(--adm-video); }
.mtx-chh__toggles .column-toggle:active{ transform:scale(.95); }

.mtx-user{ padding:5px 8px; text-align:left; }
.mtx-user__line{ display:flex; align-items:center; gap:5px; }
.mtx-user__line .user-name{
  font-size:12px; font-weight:600; color:var(--adm-text);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:pointer;
}
.mtx-user__meta{ display:flex; align-items:center; gap:5px; margin-top:4px; flex-wrap:wrap; }
.mtx-user__meta .role-badge{ font-size:10px; padding:0 5px; }
.mtx-user__meta .battery-badge{ margin-left:0; }
.mtx-detail{
  margin-left:auto; min-width:30px; min-height:26px; padding:0 6px;
  border:1px solid var(--adm-border-strong); border-radius:6px;
  background:var(--adm-surface-2); color:var(--adm-text-dim);
  font-size:15px; line-height:1; cursor:pointer;
}
.mtx-detail:active{ transform:scale(.95); }

.mtx-cell{ position:relative; padding:4px 5px; }
.mtl-pair{ display:flex; gap:4px; }
.mtl{
  flex:1; min-height:40px; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
  border:1px solid var(--adm-border-strong); border-radius:7px;
  background:transparent; color:var(--adm-text-faint);
  font-size:13px; font-weight:800; letter-spacing:.03em; cursor:pointer;
  transition:transform .06s ease;
  touch-action:manipulation;
}
.mtl:active{ transform:scale(.94); }
.mtl:focus-visible{ outline:2px solid var(--adm-accent); outline-offset:2px; }
.mtl-t.is-on{ background:var(--adm-warn); border-color:var(--adm-warn); color:#1b1304; }
.mtl-l.is-on{ background:var(--adm-accent); border-color:var(--adm-accent); color:#06121e; }
.mtl-v.is-on{ background:var(--adm-video); border-color:var(--adm-video); color:var(--adm-video-ink); }
.mtx-cell.ptt-live-cell{ box-shadow:inset 0 0 0 2px var(--adm-error); }
.mtx-cell.audio-live-cell{ background:rgba(240,87,76,.26); }
.mtx-cell .ptt-live-marker{
  position:absolute; top:2px; right:3px; margin:0;
  padding:0 4px; font-size:8px; line-height:1.4;
}
.mtx-empty{ padding:18px; text-align:center; color:var(--adm-text-faint); }

/* --- Panel szczegółów użytkownika (mobile bottom sheet) --- */
.user-sheet__body{ display:grid; gap:14px; margin-top:12px; }
.ud-section{
  padding:11px 12px; border:1px solid var(--adm-border); border-radius:var(--adm-radius-sm);
  background:rgba(255,255,255,.02);
}
.ud-section__title{
  margin:0 0 9px; font-size:10px; letter-spacing:.09em; text-transform:uppercase;
  color:var(--adm-text-dim);
}
.ud-chips{ display:flex; flex-wrap:wrap; gap:6px; }
.ud-chip{
  display:inline-flex; align-items:center; gap:4px;
  padding:3px 8px; border-radius:999px; font-size:11px; font-weight:600;
  color:var(--adm-text-dim); background:var(--adm-surface-2); border:1px solid var(--adm-border);
}
.ud-chip--ok{ color:var(--adm-ok); border-color:rgba(62,207,142,.4); }
.ud-chip--off{ color:var(--adm-text-faint); }
.ud-chip--warn{ color:var(--adm-error); border-color:rgba(240,87,76,.4); }
.ud-chip--live{ color:#fff; background:var(--adm-error); border-color:var(--adm-error); }
.ud-inline{ display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
.ud-check{ display:inline-flex; align-items:center; gap:6px; font-size:12px; }
.ud-btn-grid{ display:grid; grid-template-columns:1fr 1fr; gap:8px; }
.ud-btn-grid .btn{ width:100%; min-height:44px; }

/* --- Dolna nawigacja --- */
.admin-bottomnav{
  position:fixed; left:0; right:0; bottom:0; z-index:40;
  gap:2px; padding:4px 4px calc(4px + env(safe-area-inset-bottom));
  background:var(--adm-surface); border-top:1px solid var(--adm-border-strong);
}
.admin-bottomnav__btn{
  flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:2px; min-height:52px; padding:6px 4px;
  border:0; border-radius:var(--adm-radius-sm); background:transparent;
  color:var(--adm-text-dim); font:inherit; font-size:11px; font-weight:650; cursor:pointer;
}
.admin-bottomnav__ico{ font-size:17px; line-height:1; }
.admin-bottomnav__btn.is-active{ color:var(--adm-accent); background:var(--adm-surface-2); }
.admin-bottomnav__btn:focus-visible{ outline:2px solid var(--adm-accent); outline-offset:-2px; }

@media (max-width:780px){
  body.admin-authed .admin-tabs{ display:none; }
  body.admin-authed .admin-bottomnav{ display:flex; }
  .routing-table-shell,
  #btn_open_add_user_bottom{ display:none; }
  #mobile_routing{ display:block; }
  .admin-main{ padding-bottom:calc(64px + env(safe-area-inset-bottom)); }

  /* Elementy panelu to komórki gridu (.admin-panel). Bez min-width:0 komórka
     rozszerza się do max-content swojej zawartości (szeroka macierz) i rozpycha
     całą stronę w poziomie — wtedy overflow:auto w .mtx-scroll nigdy nie zadziała. */
  .admin-panel{ min-width:0; }
  .admin-panel > *,
  .admin-tab-view,
  .routing-card,
  #mobile_routing{ min-width:0; }

  /* Panel techniczny: minimum chrome nad macierzą, żeby zmieściła się w kadrze
     z własnym pionowym scrollem (sticky nagłówki kanałów działają tylko wewnątrz
     .mtx-scroll). */
  .mtx-scroll{ max-height:calc(100vh - 150px); max-height:calc(100dvh - 150px); }
  .mtx-wrap{ margin-top:8px; }

  /* desktopowa legenda: zwięzła, zostaje tylko przełącznik Auto T/L */
  .routing-legend{ margin:8px 0 6px; padding:6px 9px; font-size:10px; gap:6px 10px; }
  .routing-legend > span,
  .routing-legend__hint{ display:none; }
  .routing-legend .routing-auto-pair{ display:inline-flex; }
  /* zwięzła legenda macierzy: same instrukcje dotyku, bez powtórki plakietek */
  .mtx-legend > span:not(.mtx-legend__hint){ display:none; }
  .mtx-legend{ margin-bottom:6px; padding:6px 9px; }
  .mtx-legend__hint{ flex:1; }

  /* nagłówek panelu — zwięźle */
  .admin-header__inner{ flex-wrap:wrap; gap:8px 10px; }
  .admin-account-menu{ margin-left:auto; }
  .routing-head{ flex-direction:row; flex-wrap:wrap; align-items:center; gap:8px; }
  .routing-head > div:first-child{ flex:1 1 100%; }
  .routing-head .admin-eyebrow{ display:none; }
  .routing-head h1{ font-size:15px; margin:0; }
  .routing-head__actions{ display:flex; flex-direction:row; gap:8px; width:100%; }
  .routing-head__actions .btn{ flex:1 1 0; width:auto; min-width:0; min-height:40px; font-size:12px; }

  /* bulk-actions: nie rozpychaj strony gdy ukryty */
  .admin-bulk-actions{ max-width:calc(100vw - 20px); }
  .admin-bulk-actions__buttons{ flex-wrap:wrap; }

  /* dialogi na całą szerokość, z przewijaną treścią i przypiętym paskiem akcji */
  .admin-dialog,
  .admin-dialog--wide{ width:100%; max-width:100%; }
  .admin-dialog__card{
    max-height:88vh; max-height:92dvh; overflow-y:auto;
    border-radius:14px 14px 0 0;
  }
  /* <dialog> (showModal) jest centrowany przez margin:auto — pinujemy go do dołu
     jako mobilny arkusz, zostawiając górny margines elastyczny. */
  .admin-dialog{ margin-block:auto 0; }
  .admin-dialog--wide .admin-dialog__card{ max-height:88vh; max-height:92dvh; }

  .user-sheet__card{ border-radius:16px 16px 0 0; }
  .user-sheet__head{
    position:sticky; top:0; z-index:2; padding-top:2px;
    background:var(--adm-surface); border-bottom:1px solid var(--adm-border);
  }
}

@media (max-width:780px) and (orientation:landscape){
  /* więcej kanałów naraz: węższa kolumna użytkownika, niższy kadr macierzy */
  .mtx-corner,
  .mtx-user{ width:104px; min-width:104px; max-width:104px; }
  .mtx-chh,
  .mtx-cell{ width:88px; min-width:88px; max-width:88px; }
  .mtx-scroll{ max-height:calc(100dvh - 150px); }
  .ud-btn-grid{ grid-template-columns:1fr 1fr 1fr; }
}

@media (max-width:400px){
  .mtx-corner,
  .mtx-user{ width:118px; min-width:118px; max-width:118px; }
  .mtx-chh,
  .mtx-cell{ width:88px; min-width:88px; max-width:88px; }
}

/* =======================================================================
   Admin — odświeżony wygląd (makieta „Panel administratora”)
   -----------------------------------------------------------------------
   Sekcja celowo na końcu pliku: nadpisuje wcześniejsze reguły panelu, ale
   NIE dotyka `display` elementów przełączanych w media queries (.admin-tabs,
   .admin-bottomnav, #mobile_routing), więc układ mobilny zostaje nietknięty.

   Trzy zasady kolorystyczne, na których stoi cały panel:
     1. Czerwień administratorska (--adm-admin) = „to należy do administratora
        i użytkownik tego nie zmieni”: rola admin, plakietka 🔒 w wierszu oraz
        każda zablokowana opcja w konfiguracji beltpacka.
     2. Czerwień alarmowa (--adm-error) = coś dzieje się TERAZ i wymaga uwagi:
        PTT/MÓW oraz niski poziom baterii.
     3. Bursztyn = TALK, błękit = LISTEN — bez zmian względem reszty aplikacji.
   ======================================================================= */

/* ---- Typografia pomocnicza ---- */
.admin-page .adm-mono,
.admin-page .admin-eyebrow,
.admin-page .admin-brand span,
.admin-page .admin-stat span,
.admin-page #tbl_users thead th,
.admin-page .routing-auto-pair span,
.admin-page .uc-section__title{
  font-family: var(--adm-mono);
  font-variant-ligatures: none;
}
.admin-page .admin-eyebrow{ font-size:9.5px; font-weight:600; letter-spacing:.16em; color:var(--adm-text-ghost); }

/* ---- Pasek górny ---- */
.admin-header{ background:var(--adm-bar); border-bottom:1px solid var(--adm-border); }
.admin-header__inner{ min-height:58px; gap:20px; }
.admin-brand img{ width:30px; height:30px; border-radius:7px; }
.admin-brand strong{ font-size:13px; font-weight:600; letter-spacing:.01em; }
.admin-brand span{ margin-top:2px; font-size:9.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--adm-text-faint); }

/* Statystyki bez „pigułek” — liczby rozdzielone włoskowymi kreskami, jak w makiecie. */
.admin-header__stats{ gap:0; }
.admin-header__stats .admin-stat{
  gap:7px; padding:0 16px; min-height:18px;
  background:transparent; border:0; border-left:1px solid #1f2429; border-radius:0;
  font-size:10px; letter-spacing:.1em; text-transform:uppercase; color:var(--adm-text-faint);
}
.admin-header__stats .admin-stat:first-child{ border-left:0; }
.admin-header__stats .admin-stat strong{ font-family:var(--adm-mono); font-size:13px; font-weight:500; }
.admin-header__stats .admin-stat--ptt{ background:transparent; border-color:#1f2429; }
.admin-header__stats .admin-stat--ptt span:last-child{ color:var(--adm-text-faint); font-weight:400; }
.admin-header__stats .admin-stat--ptt strong{ color:var(--adm-text-dim); }
.admin-stat__dot--all{ display:none; }

/* Konto = administrator, więc awatar nosi czerwień administratorską. */
.admin-account-menu__toggle{
  min-height:32px; padding:5px 10px 5px 6px; gap:9px;
  border-color:var(--adm-border-strong); background:transparent;
  font:400 12.5px/1 system-ui,sans-serif; color:var(--adm-text-mid);
}
.admin-account-menu__toggle:hover,
.admin-account-menu__toggle[aria-expanded="true"]{
  border-color:#2e343b; background:var(--adm-surface-2); color:var(--adm-text);
}
.admin-account-menu__avatar{
  width:22px; height:22px; font-size:11px; font-weight:600;
  background:var(--adm-admin-bg-strong); color:var(--adm-admin);
  border:1px solid var(--adm-admin-border);
}
.admin-account-menu__chevron{ font-size:9px; color:var(--adm-text-ghost); }

/* ---- Zakładki: podkreślenie zamiast pigułek ---- */
.admin-tabs{
  width:100%; gap:0; padding:0; margin-bottom:18px;
  background:transparent; border:0; border-bottom:1px solid var(--adm-border); border-radius:0;
}
.admin-tab{
  min-height:0; padding:11px 4px 10px; margin-right:18px;
  border-radius:0; border-bottom:2px solid transparent;
  font-size:12.5px; font-weight:500; color:var(--adm-text-dim);
}
.admin-tab:hover{ color:var(--adm-text-mid); background:transparent; }
.admin-tab.is-active{ color:var(--adm-text); background:transparent; border-bottom-color:#d8dbdf; }

/* ---- Karty, nagłówki, przyciski ---- */
.admin-page .card{ background:var(--adm-surface); border-color:var(--adm-border); border-radius:10px; }
/* Bez `overflow:hidden` — rozwijane menu wiersza (`.row-actions .menu`) jest
   pozycjonowane absolutnie wewnątrz komórki, a `.routing-table-shell` celowo ma
   `overflow:visible`, żeby go nie ucinać. Zaokrąglenie rogów nie jest tego warte. */
.admin-page .routing-card{ padding:0; }
.routing-head{ padding:15px 18px 14px; margin:0; border-bottom:1px solid var(--adm-border-soft); }
.routing-head h1{ font-size:16.5px; font-weight:500; }
.admin-login-card h1{ font-size:20px; font-weight:500; }

.admin-page .btn{ border-radius:7px; font-weight:500; background:transparent; border-color:var(--adm-border-strong); color:var(--adm-text-dim); }
.admin-page .btn:hover{ background:var(--adm-surface-2); border-color:#333a41; color:var(--adm-text); }
.admin-page .btn-primary{
  background:#e2e5e8; border-color:#e2e5e8; color:#0f1113; font-weight:500;
}
.admin-page .btn-primary:hover{ background:#fff; border-color:#fff; color:#0f1113; }
.admin-page .admin-btn-danger-quiet{ color:var(--adm-text-dim); border-color:var(--adm-border-strong); }
.admin-page .admin-btn-danger-quiet:hover{ color:#d98080; border-color:#4a2a2c; background:rgba(160,60,60,.08); }
.admin-page .input,
.admin-page select{ border-color:var(--adm-border-strong); background:var(--adm-bg); border-radius:7px; }
.btn-add-row{ border-color:var(--adm-border-strong); border-radius:8px; font-size:12.5px; font-weight:400; }
.btn-add-row span{ color:var(--adm-text-dim); }
.btn-add-row:hover,
.btn-add-row:focus-visible{ border-color:#3a4046; color:var(--adm-text-mid); background:transparent; }
.admin-page .routing-card .btn-add-row{ width:calc(100% - 36px); margin:10px 18px 14px; }

/* ---- Legenda routingu ---- */
.routing-legend{
  margin:0; padding:11px 18px; gap:8px 20px;
  background:var(--adm-subhead); border:0; border-bottom:1px solid var(--adm-border-soft);
  border-radius:0; font-size:11.5px; color:var(--adm-text-dim);
}
.legend-pill{ width:19px; height:19px; border-radius:4px; font-family:var(--adm-mono); font-size:10px; font-weight:600; }
.legend-t{ background:var(--adm-warn); color:var(--adm-warn-ink); }
.legend-l{ background:var(--adm-accent); color:var(--adm-accent-ink); }
.legend-v{ background:var(--adm-video); color:var(--adm-video-ink); }
.legend-ptt{
  min-width:0; height:auto; padding:2px 7px; border-radius:4px;
  font-family:var(--adm-mono); font-size:9.5px; letter-spacing:.06em;
  color:#c97b7b; background:transparent; border-color:#5b3436;
}
.routing-auto-pair{
  min-height:26px; padding:5px 10px 5px 8px; border-radius:7px;
  background:transparent; border-color:var(--adm-border-strong);
}
.routing-auto-pair:hover{ background:transparent; border-color:#333a41; }
.routing-auto-pair span{ font-size:10px; letter-spacing:.08em; text-transform:uppercase; color:#9aa1a9; }
.routing-legend__hint{ color:var(--adm-text-ghost); font-size:11px; }

/* ---- Tabela routingu ---- */
.routing-table-shell{ border:0; border-radius:0; background:transparent; }
.admin-page #tbl_users thead th{
  padding:12px 9px;
  background:var(--adm-subhead);
  border-bottom:1px solid var(--adm-border-strong);
  font-size:9.5px; font-weight:400; letter-spacing:.14em; text-transform:uppercase;
  color:var(--adm-text-faint);
}
.admin-page #tbl_users thead .th-ch{ border-left:1px solid var(--adm-border-strong); }
.admin-page #tbl_users thead .th-ch .ch-number{ font-family:var(--adm-mono); font-size:12px; font-weight:500; color:var(--adm-text-mid); }
.admin-page #tbl_users thead .th-ch .ch-title{
  font-family:system-ui,sans-serif; font-size:10.5px; font-weight:400;
  letter-spacing:0; text-transform:none; color:var(--adm-text-faint);
}
.admin-page #tbl_users thead .th-ch .column-toggle{
  border-radius:3px; font-family:var(--adm-mono); font-size:9px; font-weight:600;
  background:transparent;
}
.admin-page #tbl_users thead .th-ch .column-toggle--talk{ color:#a8791f; border-color:#2c2a22; }
.admin-page #tbl_users thead .th-ch .column-toggle--talk:hover{ color:var(--adm-warn); border-color:#4a3f22; background:transparent; }
.admin-page #tbl_users thead .th-ch .column-toggle--listen{ color:#4a7fb8; border-color:#222731; }
.admin-page #tbl_users thead .th-ch .column-toggle--listen:hover{ color:var(--adm-accent); border-color:#26364a; background:transparent; }
.admin-page #tbl_users thead .th-ch .column-toggle--video{ color:#6b56a3; border-color:#241f38; }
.admin-page #tbl_users thead .th-ch .column-toggle--video:hover{ color:var(--adm-video); border-color:#332a4a; background:transparent; }

.admin-page #tbl_users tbody tr{ height:auto; }
.admin-page #tbl_users tbody tr:nth-child(odd),
.admin-page #tbl_users tbody tr:nth-child(even),
.admin-page #tbl_users tbody td:first-child,
.admin-page #tbl_users tbody td:nth-child(2),
.admin-page #tbl_users tbody td:nth-child(3){ background:transparent; }
.admin-page #tbl_users tbody td{ padding:7px 9px; border-bottom:1px solid var(--adm-border-soft); }
.admin-page #tbl_users tbody td:nth-child(2){ font-size:12.5px; }
.admin-page #tbl_users tbody tr.is-selected td,
.admin-page #tbl_users tbody tr.is-selected:focus-within td{ background:var(--adm-surface-selected) !important; }
.admin-page #tbl_users tbody tr:focus-within td{ background:var(--adm-surface-hover) !important; }
@media (hover:hover) and (pointer:fine){
  .admin-page #tbl_users tbody tr:hover{ box-shadow:none; }
  .admin-page #tbl_users tbody tr:hover td{ background:var(--adm-surface-hover) !important; }
  .admin-page #tbl_users tbody tr.is-selected:hover td{ background:#181c22 !important; }
}
.admin-page .user-drag-handle{ color:#3a4046; font-size:11px; letter-spacing:-1px; }
.admin-page #tbl_users tbody td[data-ptt-uid]{ border-right:0; border-left:1px solid var(--adm-border-strong); }

/* Pionowe podświetlenie kolumny kanału na hover — analogiczne do istniejącego poziomego
   podświetlenia wiersza (patrz `tbody tr:hover td` wyżej), żeby było widać, do którego
   kanału przypisujemy uprawnienie, nie tylko któremu użytkownikowi. Indeksy nth-child
   5..10 to sześć kolumn kanałów (patrz kolejność w <colgroup>: select, user, rola, ptxt,
   6× kanał, akcje). */
@media (hover:hover) and (pointer:fine){
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(5):hover) thead th:nth-child(5),
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(5):hover) tbody td:nth-child(5){ background:var(--adm-surface-hover) !important; }
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(6):hover) thead th:nth-child(6),
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(6):hover) tbody td:nth-child(6){ background:var(--adm-surface-hover) !important; }
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(7):hover) thead th:nth-child(7),
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(7):hover) tbody td:nth-child(7){ background:var(--adm-surface-hover) !important; }
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(8):hover) thead th:nth-child(8),
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(8):hover) tbody td:nth-child(8){ background:var(--adm-surface-hover) !important; }
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(9):hover) thead th:nth-child(9),
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(9):hover) tbody td:nth-child(9){ background:var(--adm-surface-hover) !important; }
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(10):hover) thead th:nth-child(10),
  .admin-page #tbl_users:has(tbody td[data-ptt-uid]:nth-child(10):hover) tbody td:nth-child(10){ background:var(--adm-surface-hover) !important; }
}

/* Komórki T/L: pełne kafelki zamiast checkboxów. Natywny input zostaje w DOM
   (tylko wizualnie ukryty), więc malowanie przeciągnięciem, Shift+klik, focus
   klawiaturą i cała logika w admin.js działają bez żadnej zmiany. */
.admin-page #tbl_users .tl{
  grid-template-columns:repeat(2,28px);
  justify-content:center;
  gap:6px;
}
.admin-page #tbl_users .tl-i{
  width:28px; justify-self:center; min-height:28px; height:28px; padding:0; gap:0;
  border-radius:4px; background:transparent; border:1px solid transparent;
  transition:background-color .1s ease, border-color .1s ease;
}
.admin-page #tbl_users .tl-i input[type="checkbox"]{
  position:absolute; width:1px; height:1px; opacity:0; margin:0; pointer-events:none;
}
.admin-page #tbl_users .tl-k{ font-family:var(--adm-mono); font-size:9.5px; font-weight:600; color:#454c53; }
.admin-page #tbl_users .tl-t,
.admin-page #tbl_users .tl-l,
.admin-page #tbl_users .tl-v{ border-color:transparent; }
.admin-page #tbl_users .tl-t{ border-color: rgba(232,177,58,.35); }
.admin-page #tbl_users .tl-l{ border-color: rgba(59,157,255,.35); }
.admin-page #tbl_users .tl-t:hover{ border-color:rgba(232,177,58,.5); }
.admin-page #tbl_users .tl-t:hover .tl-k{ color:var(--adm-warn); }
.admin-page #tbl_users .tl-l:hover{ border-color:rgba(59,157,255,.5); }
.admin-page #tbl_users .tl-l:hover .tl-k{ color:var(--adm-accent); }
.admin-page #tbl_users .tl-v:hover{ border-color:transparent; }
.admin-page #tbl_users .tl-v:hover .tl-k{ color:var(--adm-video); }
.admin-page #tbl_users .tl-i:hover{ background:transparent; }
.admin-page #tbl_users .tl-t:has(input:checked){ background:var(--adm-warn); border-color:transparent; }
.admin-page #tbl_users .tl-t:has(input:checked) .tl-k{ color:var(--adm-warn-ink); }
.admin-page #tbl_users .tl-l:has(input:checked){ background:var(--adm-accent); border-color:transparent; }
.admin-page #tbl_users .tl-l:has(input:checked) .tl-k{ color:var(--adm-accent-ink); }
.admin-page #tbl_users .tl-v:has(input:checked){ background:var(--adm-video); border-color:transparent; }
.admin-page #tbl_users .tl-v:has(input:checked) .tl-k{ color:var(--adm-video-ink); }
/* Stan przełącznika jest sygnalizowany wyłącznie pełnym wypełnieniem kafelka. */

.admin-page #tbl_users .latch-toggle-fast,
.admin-page #tbl_users .buzz-fast{
  min-height:24px; padding:4px 8px; border-radius:5px;
  font-family:var(--adm-mono); font-size:9px; letter-spacing:.1em; font-weight:400;
  color:var(--adm-text-dim); border-color:var(--adm-border);
}
.admin-page #tbl_users .latch-toggle-fast[data-active="0"]{ color:var(--adm-text-dim); border-color:var(--adm-border); }
.admin-page #tbl_users .latch-toggle-fast[data-active="0"]:hover{ color:var(--adm-text); border-color:#333a41; background:transparent; }
/* `data-active="1"` = latch AKTUALNIE włączony u użytkownika (przycisk proponuje wtedy
   akcję „Latch OFF") — to stan na żywo, więc czerwień alarmowa, tak jak PTT/MÓW.
   `.ptt-live-action` (wstrzykiwane w admin.js) maluje to samo, ten selektor jest
   zapasowy na wypadek gdyby klasa się nie zsynchronizowała ze stanem `data-active`. */
.admin-page #tbl_users .latch-toggle-fast[data-active="1"]{
  color:#fff; background:var(--adm-error); border-color:var(--adm-error); font-weight:600;
}
.admin-page #tbl_users .latch-toggle-fast[data-active="1"]:hover{
  background:#ff6a5f; border-color:#ff6a5f;
}
.admin-page #tbl_users .buzz-fast:hover{ color:var(--adm-text); border-color:#333a41; }
/* CAM ON/OFF (siłowa, żywa akcja admina — włącz/wyłącz TERAZ) mieszka w macierzy VIDEO ROUTING,
   w JEDNEJ linii ze stałym uprawnieniem CAMERA: CAM | ON/OFF. Kolumna CAM ma 100px, a USER
   oddał jej tyle samo, więc „USER + CAM = 378px” (wyrównanie z tabelą AUDIO) zostaje. Etykiety
   są skrócone do ON/OFF — CAM już nazywa kolumnę. */
.video-cam-group{ display:flex; flex-direction:row; align-items:center; justify-content:center; gap:4px; }
.video-permissions-table .video-cam-cell{ padding-inline:4px; }
#tbl_video_permissions .cam-toggle-fast{
  min-width:38px; min-height:20px; padding:2px 4px; border-radius:5px;
  font-family:var(--adm-mono); font-size:9px; letter-spacing:.05em; font-weight:400;
  color:var(--adm-text-dim); border-color:var(--adm-border);
}
#tbl_video_permissions .cam-toggle-fast[data-active="0"]{ color:var(--adm-text-dim); border-color:var(--adm-border); }
#tbl_video_permissions .cam-toggle-fast[data-active="0"]:hover{ color:var(--adm-text); border-color:#333a41; background:transparent; }
/* `data-active="1"` = kamera TERAZ nadaje (przycisk proponuje wtedy akcję OFF) — fiolet
   domeny VIDEO (sekcja 23), a nie czerwień alarmowa PTT, bo to inna domena niż Latch. */
#tbl_video_permissions .cam-toggle-fast[data-active="1"]{
  color:#fff; background:var(--adm-video); border-color:var(--adm-video); font-weight:600;
}
#tbl_video_permissions .cam-toggle-fast[data-active="1"]:hover{
  background:#a487fa; border-color:#a487fa;
}
/* 👁 PODGLĄD SOLO. Czerwień administratorska (nie fiolet VIDEO i nie czerwień alarmu):
   to akcja, którą wykonuje ADMINISTRATOR na cudzej kamerze — i tak samo jest oznaczona
   po stronie użytkownika (ramka „PODGLĄD ADMINISTRATORA"). */
#tbl_video_permissions .cam-preview-toggle{
  min-width:26px; min-height:20px; padding:2px 4px; border-radius:5px;
  font-size:10px; line-height:1; font-weight:400;
  color:var(--adm-admin); border-color:var(--adm-admin-border); background:transparent;
}
#tbl_video_permissions .cam-preview-toggle:hover{ background:var(--adm-admin-bg); border-color:var(--adm-admin); }
/* Źródło widoczne WYŁĄCZNIE w podglądzie administratora — stan przejściowy, nie ustawienie. */
#tbl_video_permissions .cam-preview-toggle[data-preview="1"]{
  color:#1a0c0d; background:var(--adm-admin); border-color:var(--adm-admin); font-weight:600;
}

/* ---- Okno PODGLĄDU SOLO KAMERY (adminCameraPreview.js) ---- */
.camera-preview__stage{
  position:relative; margin:10px 0 0; border-radius:10px; overflow:hidden;
  background:#000; border:1px solid var(--adm-border, #262d36);
  aspect-ratio:16/9; max-height:min(52vh, 420px);
}
.camera-preview__video{ width:100%; height:100%; object-fit:contain; background:#000; display:block; }
/* Ta sama informacja, którą widzi u siebie użytkownik — żeby administrator ani przez chwilę
   nie był w błędzie co do tego, czy obraz już gdzieś idzie. */
.camera-preview__badge{
  position:absolute; top:8px; left:8px; z-index:2; pointer-events:none;
  padding:3px 8px; border-radius:999px; font-family:var(--adm-mono);
  font-size:10px; font-weight:700; letter-spacing:.06em;
  color:#1a0c0d; background:var(--adm-admin);
}
.camera-preview__badge[hidden]{ display:none !important; }
.camera-preview__actions{ flex-wrap:wrap; }
.camera-preview__note{ margin:8px 0 0; color:var(--adm-text-faint, #7c8794); font-size:11px; line-height:1.45; }
#camera_preview_mode[data-mode="armed"]{ color:var(--adm-admin); }

/* ---- Czerwień administratorska: rola i zamki ---- */
.admin-page .managed-badge{
  padding:2px 6px; border-radius:4px; font-family:var(--adm-mono);
  font-size:9px; font-weight:600; letter-spacing:.06em;
  color:var(--adm-admin); background:var(--adm-admin-bg);
  border:1px solid var(--adm-admin-border);
}
.admin-page .managed-badge[role="button"]:hover{ filter:none; background:var(--adm-admin-bg-strong); }
.admin-page .managed-badge[role="button"]:focus-visible{ outline:2px solid var(--adm-admin); outline-offset:2px; }

/* Konfiguracja beltpacka: kto może zmieniać dane ustawienie. Dwie opcje, dwa różne
   kolory — żadna nie jest „domyślnie neutralna”, bo obie są aktywnym wyborem:
     - „Użytkownik” — bursztyn, ten sam co TALK w macierzy routingu (T),
     - „Administrator” — czerwień administratorska, ta sama co rola „Administrator”
       i plakietka 🔒 w wierszu.
   Rozróżnienie kolorem ma być natychmiast czytelne, nie tylko z tekstu etykiety. */
.uc-control label{ border-radius:999px; box-shadow:none; }
.uc-control label:has(input:checked){ background:#2a3037; color:var(--adm-text); font-weight:600; }
.uc-control label[data-lock="user"]:has(input:checked){
  background:var(--adm-warn); color:var(--adm-warn-ink);
}
.uc-control label[data-lock="admin"]:has(input:checked){
  background:var(--adm-admin-bg-strong); color:var(--adm-admin);
  box-shadow:inset 0 0 0 1px var(--adm-admin-border);
}
.uc-control label[data-lock="user"] input{ accent-color:var(--adm-warn); }
.uc-control label[data-lock="admin"] input{ accent-color:var(--adm-admin); }
/* Tryb grupowy zna tylko „Tylko administrator” (tri-state) — nie ma symetrycznej
   opcji „Użytkownik” do pomalowania na bursztyn, więc zostaje przy czerwieni admina
   dla stanu zaznaczonego i neutralnym tle, gdy nie jest zaznaczony. */
.uc-control .uc-tri--lock:has(input:checked){
  background:var(--adm-admin-bg-strong); color:var(--adm-admin);
  border-color:var(--adm-admin-border); font-weight:600;
}
.uc-tri--lock input{ accent-color:var(--adm-admin); }
/* Cały wiersz czyta się jako „zablokowany” albo „w rękach użytkownika”, nie tylko
   sama kontrolka. */
.uc-row:has(.uc-control label[data-lock="admin"] input:checked) > .uc-row__head > strong,
.uc-row--inline:has(.uc-control label[data-lock="admin"] input:checked) > strong,
.uc-audio-row:has(.uc-control label[data-lock="admin"] input:checked) > div > strong,
.uc-row:has(.uc-tri--lock input:checked) > .uc-row__head > strong,
.uc-row--inline:has(.uc-tri--lock input:checked) > strong,
.uc-audio-row:has(.uc-tri--lock input:checked) > div > strong{ color:var(--adm-admin); }
.uc-row:has(.uc-control label[data-lock="user"] input:checked) > .uc-row__head > strong,
.uc-row--inline:has(.uc-control label[data-lock="user"] input:checked) > strong,
.uc-audio-row:has(.uc-control label[data-lock="user"] input:checked) > div > strong{ color:var(--adm-warn); }
.uc-section{ border-color:var(--adm-border); background:rgba(255,255,255,.015); }
.uc-section__title{ font-size:9.5px; letter-spacing:.16em; color:var(--adm-text-ghost); }

/* ---- Bateria: zielona dla znanego i sprawnego poziomu — szary wyglądał jak
   „nieaktywna/brak danych" i mylił się z prawdziwym stanem „unknown". Czerwień
   zostaje zarezerwowana wyłącznie dla alarmu (niski poziom). ---- */
.battery-badge{
  gap:5px; margin-left:.45rem; padding:1px 2px; border-radius:5px;
  font-family:var(--adm-mono); font-size:9.5px; font-weight:500; letter-spacing:0;
  color:var(--adm-ok); background:transparent; border:1px solid transparent;
}
.battery-badge .battery-icon{ display:block; flex:none; }
.battery-badge .battery-icon .battery-shell{ fill:none; stroke:currentColor; stroke-width:1; opacity:.85; }
.battery-badge .battery-icon .battery-cap{ fill:currentColor; opacity:.85; }
.battery-badge .battery-icon .battery-fill{ fill:currentColor; }
.battery-badge .battery-bolt{ display:block; flex:none; fill:currentColor; }
/* Jedyny naprawdę szary stan: serwer nie ma żadnego odczytu baterii tego urządzenia. */
.battery-badge.unknown{ color:#3f454b; font-weight:400; }
.battery-badge.unknown .battery-icon .battery-shell,
.battery-badge.unknown .battery-icon .battery-cap{ opacity:.6; }
/* Ładowanie (poza alarmem) — dalej ten sam zielony „ok", tylko z delikatną obwódką/tłem,
   żeby błyskawica rzucała się w oczy na pierwszy rzut oka, a nie tylko po najechaniu. */
.battery-badge.charging:not(.low){
  background:rgba(79,157,105,.12); border-color:rgba(79,157,105,.45); padding:1px 5px;
}
/* Alarm — jedyny stan, w którym bateria jest czerwona. Ładowanie tego nie kasuje: dopóki
   poziom jest niski, plakietka nadal krzyczy czerwienią, a błyskawica obok mówi, że
   przynajmniej już się ładuje. */
.battery-badge.low,
.battery-badge.low.charging{
  color:var(--adm-error); font-weight:600;
  background:rgba(240,87,76,.08); border-color:rgba(240,87,76,.4); padding:1px 5px;
}
.battery-badge.low .battery-icon .battery-shell,
.battery-badge.low .battery-icon .battery-cap{ opacity:1; }
.battery-badge:hover{ filter:brightness(1.2); }
.battery-badge.unknown:hover{ filter:none; color:var(--adm-text-dim); }
.battery-badge.low:hover{ color:var(--adm-error); background:rgba(240,87,76,.14); filter:none; }
.battery-badge:focus-visible{ outline:2px solid var(--adm-text-dim); outline-offset:2px; }
.battery-badge.low:focus-visible{ outline-color:var(--adm-error); }

/* ---- Reszta panelu w nowej palecie ---- */
.admin-page .admin-bulk-actions{ background:var(--adm-subhead); border-color:var(--adm-border); }
.admin-page .sessions-section,
.admin-page .public-web-card{ background:var(--adm-surface); }
.admin-dialog__card{ background:var(--adm-surface); border-color:var(--adm-border-strong); border-radius:10px; }
.admin-footer{ color:var(--adm-text-ghost); }
.admin-page .status-dot.online{ background:var(--adm-ok); }
.admin-page .status-dot.offline{ background:#31373d; }

/* Plakietka roli w wierszu: „Użytkownik” neutralnie, „Administrator” czerwienią
   administratorską — ten sam kolor, którym w konfiguracji beltpacka oznaczone są
   opcje zablokowane dla użytkownika. */
.admin-page .role-badge{
  display:inline-flex; align-items:center; padding:3px 9px; border-radius:5px;
  font-size:11px; white-space:nowrap;
  color:var(--adm-text-dim); background:transparent; border:1px solid var(--adm-border);
}
.admin-page .role-badge.role-admin{
  color:var(--adm-admin); background:var(--adm-admin-bg); border-color:var(--adm-admin-border);
}
/* Macierz mobilna korzysta z tych samych tuszów co kafelki T/L na desktopie. */
.mtl-t.is-on{ color:var(--adm-warn-ink); }
.mtl-l.is-on{ color:var(--adm-accent-ink); }

/* ---- Korekty po złożeniu makiety ---- */
/* „Administrator” to najdłuższa etykieta roli i musi mieścić się bez ucinania. */
.admin-page #tbl_users .routing-col-role{ width:112px; }
.admin-page #tbl_users .routing-col-ptxt{ width:52px; }
/* Kolumna akcji musi pomieścić „Latch ON" + BUZZ + ⋯ — przy 142 px ostatni przycisk
   był ucinany (table-layout:fixed, więc decyduje <colgroup>, nie szerokość <td>). */
.admin-page #tbl_users .routing-col-actions{ width:180px; }
/* `.admin-page label{display:grid}` ma wyższą specyficzność niż `.routing-auto-pair`,
   przez co checkbox lądował nad etykietą zamiast obok niej. */
.admin-page .routing-auto-pair{ display:inline-flex; }
.admin-page .routing-auto-pair input{ width:15px; height:15px; accent-color:var(--adm-text-dim); }
/* Checkboxy pomocnicze (zaznaczanie wierszy, PTXT) są neutralne — kolor w tabeli
   niosą wyłącznie kafelki T/L oraz czerwienie: administratorska i alarmowa. */
.admin-page #tbl_users input[type="checkbox"]{ width:15px; height:15px; accent-color:var(--adm-text-dim); }
.admin-page #tbl_users input[type="checkbox"].chk-ptxt{ accent-color:var(--adm-text-dim); }
.admin-page #tbl_users .td-ptxt{ text-align:center; }
.admin-page #tbl_users input[type="checkbox"]:disabled{ opacity:.45; cursor:not-allowed; }
.admin-page .managed-badge{ gap:4px; }
.admin-page .managed-badge__lock{ display:block; flex:none; }
.admin-page .managed-badge__marks{ line-height:1; }

/* ---- Widok mobilny: przywróć to, co powyższa sekcja nadpisała ----
   Powyższe reguły są pisane pod desktopową kartę „od krawędzi do krawędzi”. Na
   mobile kartę wypełnia macierz `.mtx-*`, więc karta musi odzyskać własny padding,
   a nagłówek i legenda — swój kompaktowy układ. */
@media (max-width:780px){
  .admin-page .routing-card{ padding:13px; overflow:visible; }
  .routing-head{ padding:0 0 8px; border-bottom:0; }
  .routing-legend{
    margin:8px 0 6px; padding:6px 9px; border-radius:var(--adm-radius-sm);
    border:1px solid var(--adm-border);
  }
  .mtx-user__meta .role-badge{ padding:1px 6px; font-size:10px; }
  .mtx-user__meta .battery-badge{ margin-left:0; }
  .admin-page #tbl_users .tl-i{ height:auto; min-height:26px; }
}
@media (max-width:560px){
  .admin-header__stats .admin-stat{ padding:0 8px; }
}
/* Etykiety w pasku statystyk znikają na wąskich ekranach, więc sama liczba nie może
   się łamać na dwie linie — bez tego „16” czytało się jako „1 / 6”. */
.admin-header__stats .admin-stat{ white-space:nowrap; }

/* ---- Resztki starej palety zapisane na sztywno w regułach tabeli ---- */
.admin-page #tbl_users thead tr:first-child th:nth-child(2),
.admin-page #tbl_users thead tr:first-child th:nth-child(3){ background:var(--adm-subhead); }
.admin-page #tbl_users .row-actions .menu{
  background:var(--adm-surface-2); border-color:var(--adm-border-strong); border-radius:8px;
}
.admin-page #tbl_users .row-actions .menu .menu-item{ color:var(--adm-text); font-size:12.5px; }
.admin-page #tbl_users .row-actions .menu .menu-item:hover,
.admin-page #tbl_users .row-actions .menu .menu-item:focus{ background:#1c2026; }
.admin-page #tbl_users .row-actions .menu .menu-item.danger{ color:var(--adm-error); }
.admin-page #tbl_users .menu-toggle{ color:var(--adm-text-faint); font-size:12px; letter-spacing:1px; }
.admin-page #tbl_users .menu-toggle:hover{ color:var(--adm-text-mid); }
.admin-page #tbl_users input[type="checkbox"]{ transform:none; }
.admin-page #tbl_users input[type="checkbox"]:focus-visible{
  outline:2px solid var(--adm-text-dim); outline-offset:2px; border-radius:4px;
}
/* Akcje destrukcyjne (np. „Unieważnij” link dostępu) muszą zostać czerwone —
   `.admin-page .btn` ma wyższą specyficzność niż globalne `.btn-danger`. */
.admin-page .btn-danger{
  color:var(--adm-error); background:rgba(240,87,76,.10); border-color:rgba(240,87,76,.4);
}
.admin-page .btn-danger:hover{ color:#ff8078; background:rgba(240,87,76,.18); border-color:var(--adm-error); }

/* Operational video: independent panel; closing it releases only the selected video. */
/* --- USTAWIENIA -> VIDEO (sekcja 27) ---------------------------------------------------- */
.settings-video-fields{ flex:0 0 auto; order:2; border:0; margin:0; padding:0; display:flex; flex-direction:column; gap:0; min-width:0; width:100%; }
.settings-video-fields:disabled{ opacity:.55; }
.settings-video .settings-section-title{ color:var(--video); }
.settings-video > .settings-section-title{ order:0; }
.settings-video > .settings-note:not(#video_routing):not(#video_quality_help){ order:1; }
.settings-video-fields .field:has(#video_type){ order:1; }
.settings-video-fields .field:has(#video_device){ order:2; }
.settings-video-fields #video_devices{ order:3; }
.settings-video-fields .field:has(#video_quality_mode){ order:4; }
.settings-video-fields .field:has(#video_profile){ order:5; }
.settings-video-fields #video_quality_help{ order:6; }
.settings-video-fields .field:has(#video_name){ order:7; }
.settings-video-fields .field:has(#video_publish_mode){ order:8; }
.settings-video #video_routing{ order:11; }
.settings-video .settings-video-state{ order:12; }
.settings-video .settings-video-main{ order:13; }
.settings-video #btn_video_diagnostics{ order:14; }
.settings-video .field > select:focus,.settings-video .field > select:hover{ border-color:var(--video); }
.settings-video .field > select{ color:var(--video-dim); }
.settings-video .settings-note{ margin:0; padding:10px 14px; }
.settings-video .video-routing-mode{ margin:0; padding:0; border:0; }
.settings-video .video-routing-mode #video_tx_channel_group{ padding:9px 14px; border-bottom:1px solid #2d3035; }
.settings-video-fields:disabled .field,.settings-video-fields:disabled + *{ opacity:.55; }
.settings-video-state{ display:flex; }
.settings-video .settings-link-button{ color:var(--video-dim); }
.settings-video-main{
  display:flex; flex-direction:column; gap:8px; padding:10px;
  border:1px solid rgba(139,92,246,.35); border-radius:9px; background:rgba(139,92,246,.06);
}
.settings-video-main[hidden]{ display:none !important; }
.settings-video-main > div:first-child{ display:flex; flex-direction:column; gap:2px; }
.settings-video-main small{ color:var(--muted); }
.settings-video-main-actions{ display:flex; flex-wrap:wrap; gap:8px; }
.settings-video-main-actions .settings-link-button{ width:auto; flex:1 1 190px; }

/* --- Presence: zdalne discovery VIDEO (sekcje 4, 5, 6, 8) -------------------------------
   Uzytkownik BEZ widocznego, nadajacego zrodla nie ma tu ZADNEGO elementu — brak oznaczenia
   znaczy brak dostepnego VIDEO (sekcja 3). */
.presence-video{
  display:inline-flex; align-items:center; gap:4px; flex:none;
  min-height:24px; padding:2px 6px; border-radius:7px; cursor:pointer;
  font:inherit; font-size:.6rem; font-weight:800; letter-spacing:.05em;
  color:var(--video); background:rgba(139,92,246,.12); border:1px solid rgba(139,92,246,.45);
}
.presence-video:hover{ background:rgba(139,92,246,.22); }
.presence-video:focus-visible{ outline:2px solid var(--video); outline-offset:2px; }
.presence-video-live{ color:var(--video); }
/* MAIN to rola sesji — pelne wypelnienie, tak samo jak badge na centralnym stage. */
.presence-video-main{ color:var(--video-ink); background:var(--video); padding:1px 4px; border-radius:4px; }
.presence-video-set-main{
  flex:none; min-height:24px; padding:2px 7px; border-radius:7px; cursor:pointer;
  font:inherit; font-size:.6rem; font-weight:800; letter-spacing:.05em;
  color:var(--video-dim); background:transparent; border:1px solid rgba(139,92,246,.45);
}
.presence-video-set-main[data-main="1"]{ color:var(--video-ink); background:var(--video); border-color:var(--video); }
.presence-video-set-main:focus-visible{ outline:2px solid var(--video); outline-offset:2px; }

.video-panel { width:min(940px, 94vw); max-height:92dvh; overflow:auto; color:var(--text, #eee); background:#171c23; border:1px solid #556171; border-radius:14px; padding:18px; }
.video-panel::backdrop { background:#000a; }
.video-panel header, .video-controls { display:flex; flex-wrap:wrap; gap:12px; align-items:center; }
.video-panel header { justify-content:space-between; }
.video-panel h2 { font-size:20px; margin:0 0 12px; }
.video-panel video { width:100%; aspect-ratio:16/9; max-height:48vh; object-fit:contain; background:#080b0f; border-radius:8px; }
.video-panel #video_local { max-width:320px; margin-top:12px; }
.video-panel label { display:flex; gap:6px; align-items:center; flex-wrap:wrap; }
.video-panel input, .video-panel select, .video-panel button { font:inherit; color:inherit; background:#26303d; border:1px solid #64758a; border-radius:6px; padding:8px; }
.video-panel button { cursor:pointer; min-height:40px; }
.video-panel button:disabled { opacity:.5; cursor:default; }
.video-panel fieldset { border:0; margin:12px 0; padding:0; }
.video-panel summary { cursor:pointer; padding:12px 0; }
/* GOTOWA / LIVE / BŁĄD — minimalny wskaźnik runtime publikacji (sekcja 14/15). Pełny design
   (ikonka kamery, badge LIVE, turkus wideo) przychodzi w osobnym etapie. */
.video-state { font-weight:700; letter-spacing:.04em; padding:6px 10px; border-radius:999px; border:1px solid #64758a; }
/* Runtime WLASNEJ kamery: READY zolty, LIVE czerwony (sekcja 24). Fiolet opisuje funkcje
   VIDEO, wiec swiadomie nie pojawia sie w stanie nadawania. */
.video-state[data-state="VIDEO_ARMED"] { color:#ffe6a3; border-color:#8a6a1f; background:#3a2f10; }
.video-state[data-state="VIDEO_LIVE"] { color:#ffd9d5; border-color:#9c3a33; background:#3a1613; }
.video-state[data-state="VIDEO_ERROR"] { color:#ffb0a8; border-color:#9c4038; background:#3a1a17; }
.video-sources { display:grid; gap:8px; margin:16px 0; }
.video-sources button { text-align:left; }
.video-sources button[aria-pressed=true] { border-color:#58cc99; background:#174838; }
/* Jeden wiersz = źródło + ewentualna akcja admina. Sam przycisk źródła rośnie, akcja nie. */
.video-source-row { display:flex; gap:8px; align-items:stretch; }
.video-source-row > button:first-child { flex:1 1 auto; }
.video-source-row .video-main-set { flex:0 0 auto; white-space:nowrap; }
/* MAIN — główny stream sesji. Minimalne oznaczenie tego etapu; pełny design (badge LIVE,
   turkus, centralny player) przychodzi osobno. */
.video-sources button[data-main=true] { border-color:#e0a83c; box-shadow:inset 3px 0 0 #e0a83c; }
.video-routing-mode{border:1px solid rgba(139,92,246,.34);border-radius:14px;padding:12px;margin:10px 0 14px}
.video-routing-mode legend{padding:0 6px;color:#a78bfa;font-weight:800;text-transform:uppercase;letter-spacing:.06em;font-size:.78rem}
.video-routing-choice{display:flex;gap:10px;align-items:flex-start;padding:8px 4px;cursor:pointer}
.video-routing-choice span{display:grid;gap:2px}.video-routing-choice small{opacity:.72}
.video-tx-channels{display:flex;gap:7px;flex-wrap:wrap;margin-top:8px}
.video-tx-channel{border-color:rgba(139,92,246,.45)}
.video-tx-channel[aria-pressed="true"]{background:#7c3aed;color:#fff;border-color:#a78bfa}
.routing-domain-heading{margin:14px 0 8px;font-size:1rem;letter-spacing:.08em}
.video-permissions-section{margin-top:24px;padding-top:18px;border-top:1px solid rgba(139,92,246,.25)}
.video-permissions-heading{display:flex;align-items:end;justify-content:space-between;gap:12px;margin-bottom:10px;flex-wrap:wrap}
.video-permissions-heading h2{margin:2px 0 0;color:#a78bfa}
.video-permissions-legend{display:flex;gap:12px;color:#a78bfa;font-size:.78rem;font-weight:700;flex-wrap:wrap;margin-top:4px}
.video-legend-tx{color:var(--adm-warn)}
.video-legend-rx{color:var(--adm-accent)}
/* Bez ramki i promienia — żeby lewa krawędź tabeli VIDEO leżała dokładnie tam, gdzie
   lewa krawędź tabeli audio (analogicznie do `.routing-table-shell{border:0}`).
   Przewijanie i sticky obu tabel: sekcja „ROUTING: przewijanie i sticky” na końcu pliku. */
.video-permissions-shell{border:0;border-radius:0;background:var(--adm-surface,#0f1113)}

/* Macierz VIDEO — bliźniaczo z audiową #tbl_users; wiersz = użytkownik:
     USER | CAM | CH1 TX RX … CH6 TX RX | OUT 1 … OUT n
   1) Układ MUSI pozostać tabelaryczny — `display:flex` na <td>/<th> wypycha komórki z
      algorytmu tabeli i wszystkie kolumny danych zapadają się pod kanał 1. Flex trzymamy
      więc na wrapperach (.video-permission-group, .video-column-actions).
   2) USER + CAM = 378 px = select+user+rola+PTXT w AUDIO, kanały 112 px — przy przewinięciu
      obu tabel do lewej kolumny kanałów leżą dokładnie pod sobą.
   3) Szerokość tabeli = suma kolumn (`table-layout:fixed` + `width:max-content`): kolumny się
      nie rozciągają, a wiele wyjść po prostu przewija się w poziomie. */
.video-permissions-table{
  --video-user-w:278px;
  --video-cam-w:100px;
  --video-channel-w:112px;
  --video-output-w:76px;
  display:table;
  width:max-content;
  margin:0;
  table-layout:fixed;
  border-collapse:separate;
  border-spacing:0;
  color:var(--adm-text,#e6e8ea);
  font-size:12px;
}
.video-permissions-table .video-col-user,
.video-permissions-table .video-user-cell{width:var(--video-user-w);min-width:var(--video-user-w);max-width:var(--video-user-w)}
.video-permissions-table .video-col-cam,
.video-permissions-table .video-cam-head,
.video-permissions-table .video-cam-cell{width:var(--video-cam-w);min-width:var(--video-cam-w);max-width:var(--video-cam-w)}
.video-permissions-table .video-col-channel,
.video-permissions-table .video-ch-head,
.video-permissions-table .video-permission-cell{width:var(--video-channel-w);min-width:var(--video-channel-w);max-width:var(--video-channel-w)}
.video-permissions-table .video-col-output,
.video-permissions-table .video-out-head,
.video-permissions-table .video-out-cell{width:var(--video-output-w);min-width:var(--video-output-w);max-width:var(--video-output-w)}
.video-permissions-table thead th,
.video-permissions-table tbody th,
.video-permissions-table tbody td{
  padding:5px 7px;
  text-align:center;
  vertical-align:middle;
  line-height:1.25;
  white-space:nowrap;
  border-bottom:1px solid var(--adm-border-soft,#16191d);
}
/* Separator kolumn po LEWEJ pierwszej kolumny za użytkownikiem i dalej — jak `.th-ch{border-left}`
   w audio. */
.video-permissions-table thead th:not(:first-child),
.video-permissions-table tbody th:not(:first-child),
.video-permissions-table tbody td:not(:first-child){
  border-left:1px solid var(--adm-border-strong,#262b31);
}
.video-permissions-table thead th{
  padding:8px 7px;
  background:var(--adm-subhead,#101215);
  font-size:9.5px;font-weight:400;letter-spacing:.14em;text-transform:uppercase;
  color:var(--adm-text-faint,#6b7280);
  border-bottom:1px solid var(--adm-border-strong,#262b31);
}
.video-permissions-table .video-user-cell{text-align:left;overflow:hidden}
/* Wiersze: PEŁNE kolory w każdym stanie — pod USER i CAM przewijają się kanały i wyjścia. */
.video-permissions-table tbody tr:nth-child(odd) > *{background:var(--adm-surface,#0f1113)}
.video-permissions-table tbody tr:nth-child(even) > *{background:var(--adm-surface-2,#14161a)}
.video-permissions-table tbody tr.is-selected > *{background:var(--adm-surface-selected,#15181d)}
.video-permissions-table tbody tr:hover > *{background:var(--adm-surface-hover,#14171b)}
.video-permissions-table tbody tr.is-selected .video-user-cell{box-shadow:inset 3px 0 0 0 var(--adm-accent,#3d7fd6)}
.video-permissions-table tbody tr:hover .video-user-cell{box-shadow:inset 3px 0 0 0 var(--adm-video,#8b5cf6)}

/* Nagłówek kanału: numer + nazwa + przełączniki kolumny, zwarcie jak w audio. */
.video-permissions-table .ch-number{display:block;font-family:var(--adm-mono,ui-monospace,monospace);font-weight:500;font-size:12px;line-height:1;color:var(--adm-text-mid,#c8ccd2)}
.video-channel-name{display:block;max-width:100%;margin:1px auto 4px;overflow:hidden;text-overflow:ellipsis;font-size:10.5px;font-weight:400;letter-spacing:0;text-transform:none;color:var(--adm-text-faint,#6b7280)}
.video-column-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2px;width:100%;margin:0 auto}
.video-permission-group{display:inline-flex;justify-content:center;gap:4px}
.video-column-actions button{appearance:none;min-height:22px;padding:2px 6px;border:1px solid rgba(139,92,246,.28);border-radius:3px;background:transparent;color:#6b56a3;font-family:var(--adm-mono,ui-monospace,monospace);font-size:9px;font-weight:600;letter-spacing:.06em;cursor:pointer}
.video-column-actions button[data-type="videoTx"]{color:var(--adm-warn)}
.video-column-actions button[data-type="videoRx"]{color:var(--adm-accent)}
.video-column-actions button:hover{color:var(--adm-video,#8b5cf6);border-color:#332a4a;background:transparent}
.video-column-actions button[data-type="videoTx"]:hover{color:var(--adm-warn);border-color:rgba(250,204,21,.5)}
.video-column-actions button[data-type="videoRx"]:hover{color:var(--adm-accent);border-color:rgba(59,130,246,.5)}
.video-permission{min-width:38px;border:1px solid rgba(139,92,246,.35);border-radius:6px;background:transparent;color:#a78bfa;font-weight:800;font-size:.72rem;padding:4px 7px;cursor:pointer}
.video-permission--tx{color:var(--adm-warn)}
.video-permission--rx{color:var(--adm-accent)}
.video-permission[aria-pressed="true"]{background:#8b5cf6;color:#120d20;border-color:#8b5cf6}
.video-permission--tx[aria-pressed="true"]{background:#8b5cf6;color:#120d20;border-color:var(--adm-warn)}
.video-permission--rx[aria-pressed="true"]{background:#8b5cf6;color:#120d20;border-color:var(--adm-accent)}
.video-permission:focus-visible,.video-column-actions button:focus-visible{outline:2px solid var(--adm-video,#8b5cf6);outline-offset:1px}
/* Malowanie przeciągnięciem po TX/RX — ten sam sygnał wizualny co w tabeli AUDIO. */
#tbl_video_permissions.is-painting,
#tbl_video_permissions.is-painting *{user-select:none}
#tbl_video_permissions.is-painting .video-permission{cursor:crosshair}
.video-permissions-table tbody td.video-permission-cell--live{
  position:relative;
  background:rgba(139,92,246,.10);
  box-shadow:inset 0 0 0 2px var(--adm-video,#8b5cf6);
}
.video-permissions-table tbody tr:hover td.video-permission-cell--live{
  background:rgba(139,92,246,.15);
  box-shadow:inset 0 0 0 2px var(--adm-video,#8b5cf6);
}
/* TX bez CAMERA nie ma czego nadawać: zostaje edytowalne (routing na później), ale przygasa. */
.video-permissions-table tbody tr[data-camera="false"] .video-permission--tx{opacity:.45}

/* CAM — globalne prawo do WŁASNEGO źródła VIDEO. Fiolet = funkcja VIDEO dostępna; odebrane —
   stonowana czerwień „zablokowane przez administratora”, ten sam ton co plakietka roli. */
.video-permissions-table .video-cam-head{letter-spacing:.1em;color:#8f7bc8}
.video-camera-toggle{
  appearance:none;min-width:44px;min-height:28px;padding:4px 7px;
  border:1px solid color-mix(in srgb, var(--adm-admin,#d98a8a) 45%, transparent);border-radius:6px;
  background:transparent;color:var(--adm-admin,#d98a8a);
  font-family:var(--adm-mono,ui-monospace,monospace);font-size:.68rem;font-weight:800;letter-spacing:.06em;
  cursor:pointer;
}
.video-camera-toggle[aria-pressed="true"]{background:var(--adm-video,#8b5cf6);border-color:var(--adm-video,#8b5cf6);color:var(--adm-video-ink,#0d1013)}
.video-camera-toggle:hover{border-color:var(--adm-video,#8b5cf6)}
.video-camera-toggle[data-pending="true"]{background:var(--adm-pending,#b48ce8);border-color:var(--adm-pending,#b48ce8);color:var(--adm-video-ink,#0d1013);cursor:progress}

/* VIDEO OUTPUTS — drugi widok przypisań z sekcji VIDEO OUTPUTS, odseparowany od kanałów. */
.video-permissions-table .video-out-head--first,
.video-permissions-table .video-out-cell--first{border-left:2px solid rgba(139,92,246,.55)}
.video-out-eyebrow{display:block;margin-bottom:3px;font-family:var(--adm-mono,ui-monospace,monospace);font-size:8.5px;font-weight:600;letter-spacing:.12em;color:#8f7bc8}
.video-out-toggle{
  appearance:none;min-width:34px;min-height:28px;padding:3px 6px;
  border:1px solid rgba(139,92,246,.35);border-radius:6px;
  background:transparent;color:var(--adm-text-faint,#6b7280);
  font-family:var(--adm-mono,ui-monospace,monospace);font-size:.72rem;font-weight:800;
  cursor:pointer;
}
.video-out-toggle:hover{color:var(--adm-text,#e6e8ea);border-color:var(--adm-video,#8b5cf6)}
.video-out-toggle[aria-pressed="true"]{background:var(--adm-video,#8b5cf6);border-color:var(--adm-video,#8b5cf6);color:var(--adm-video-ink,#0d1013)}
/* Przypisany, ale źródło teraz nie nadaje (offline / CAM OFF / brak Producera). Przypisanie trwa. */
.video-out-toggle[aria-pressed="true"][data-live="false"]{background:rgba(139,92,246,.16);border-style:dashed;color:#c4b5fd}
.video-out-toggle[data-pending="true"]{background:var(--adm-pending,#b48ce8);border-color:var(--adm-pending,#b48ce8);border-style:solid;color:var(--adm-video-ink,#0d1013)}
.video-camera-toggle:focus-visible,.video-out-toggle:focus-visible{outline:2px solid var(--adm-video,#8b5cf6);outline-offset:1px}

/* Komórka użytkownika w JEDNEJ linii — odpowiednik `.td-user`. */
.video-user-line{display:flex;align-items:center;gap:7px;min-width:0}
.video-runtime-dot{flex:none;font-size:11px;line-height:1;color:#80838d}
.video-runtime-dot[data-live="true"]{color:var(--adm-video,#8b5cf6)}
/* Kropka online i badge baterii — te same elementy (i ten sam globalny stan) co w tabeli
   AUDIO, patrz `.status-dot`/`.battery-badge` w admin.js. Tutaj tylko dopasowanie do
   jednolinijkowego flex-layoutu wiersza wideo: stały rozmiar, bez własnego marginesu
   (odstęp daje `gap` rodzica), żeby nie dublować odstępów. */
.video-user-line .status-dot{flex:none;margin-right:0}
.video-user-line .battery-badge{flex:none;font-size:11px}
/* Nazwa ma pierwszeństwo przed plakietkami: przy przewijaniu operator MUSI widzieć, kogo edytuje.
   Nie kurczy się (najwyżej szerokość komórki minus kropka/status/bateria), a plakietki
   trybu skracają się do zera pierwsze (patrz `.video-mode-badge`). */
.video-user-name{flex:0 0 auto;max-width:calc(100% - 66px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12.5px;font-weight:600;color:var(--adm-text,#e6e8ea)}
/* Plakietki trybu przyciągnięte do prawej krawędzi komórki (`margin-left:auto`), więc przy
   różnej długości nazw użytkowników zawsze stoją w jednej linii, zamiast „pływać” tuż za
   nazwą — patrz zgłoszenie: przy dłuższych nazwach nie były równo w rzędzie. */
.video-mode-badges{display:flex;align-items:center;gap:7px;margin-left:auto;min-width:0;flex:0 1 auto}
.video-mode-badge{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin:0;padding:1px 7px;border:1px solid rgba(139,92,246,.35);border-radius:999px;background:transparent;color:#a78bfa;font:inherit;font-size:.62rem;font-weight:700;letter-spacing:.04em;line-height:1.4;cursor:help}
.video-mode-badge:hover,.video-mode-badge[aria-expanded="true"]{background:rgba(139,92,246,.14)}
.video-mode-badge:focus-visible{outline:2px solid var(--adm-video,#8b5cf6);outline-offset:1px}
.video-mode-badge--preview:hover,.video-mode-badge--preview[aria-expanded="true"]{background:var(--adm-admin-bg-strong)}
.mode-help-popover{max-width:300px}
.video-mode-badge--always{border-color:rgba(34,197,94,.48);color:#86efac}
.video-mode-badge--independent{border-color:rgba(139,92,246,.48);color:#c4b5fd}
/* „TYLKO PODGLĄD” nie jest trybem konfiguracji jak dwie powyższe plakietki, tylko chwilowym
   stanem operacyjnym — stąd czerwień administratorska i wypełnienie zamiast samego obrysu. */
.video-mode-badge--preview{border-color:var(--adm-admin);background:var(--adm-admin-bg-strong);color:var(--adm-admin);font-weight:800}
.video-legend-cam{color:var(--adm-video,#8b5cf6)}
.video-legend-out{color:#c4b5fd}
@media(max-width:780px){.video-permissions-heading{align-items:start;flex-direction:column}.video-permissions-shell{margin-inline:-12px}}

/* Na małych ekranach 308 px dla użytkownika zajmowałoby prawie cały widok — zwężamy go do
   szerokości kolumny użytkownika z mobilnego AUDIO. CAM idzie za nim (ta sama zmienna). */
@media (max-width:640px){
  .video-permissions-table{ font-size:11.5px; --video-user-w:140px; }
  .video-permissions-table .video-user-cell{ padding-left:8px; }
  /* 140 px starcza wyłącznie na nazwę + kropkę online — tryb publikacji/routingu i bateria
     widać na szerszym ekranie. `.video-user-line` (w przeciwieństwie do mobilnej AUDIO,
     gdzie `.mtx-user__meta` ma `flex-wrap:wrap`) jest jedną sztywną linią bez zawijania,
     więc bateria musi się tu chować zamiast zawijać. */
  /* Plakietki trybu chowamy na wąskich ekranach, ale NIE tę jedną: „TYLKO PODGLĄD" mówi, że
     czyjaś kamera jest teraz włączona i nie idzie na kanały — to musi być widoczne zawsze. */
  .video-permissions-table .video-mode-badge:not(.video-mode-badge--preview){ display:none; }
  .video-permissions-table .video-user-line .battery-badge{ display:none; }
  .video-permissions-table .video-user-name{ max-width:calc(100% - 26px); }
}

/* ==================================================================================
   ROUTING: przewijanie i sticky — AUDIO i VIDEO według JEDNEJ zasady
   ----------------------------------------------------------------------------------
   Standardowy wzorzec „sticky w normalnym przepływie strony” (tabele GitHub/Notion/
   Airtable), NIE panel z własnym paskiem przewijania. Wcześniejsza wersja nadawała
   wrapperowi `overflow:auto` + `max-height`, co robiło z niego OSOBNY viewport — kółko myszy
   nad tabelą przewijało NAJPIERW ten kontener do jego limitu i dopiero potem stronę, co czuło
   się jak „zacinanie się”. Teraz wrapper dostaje WYŁĄCZNIE `overflow-x:auto` (poziomy scroll
   szerokiej tabeli), bez ograniczenia wysokości — strona przewija się cały czas normalnie,
   niezależnie od tabeli, i nie ma czego „utknąć w środku”.
     • lewe sticky kolumny — AUDIO: zaznaczenie + użytkownik, VIDEO: użytkownik + CAM —
       to czyste `position:sticky; left:` (z-index 2). Działa w 100% w CSS: to WŁAŚCIWA oś,
       w której `.routing-table-shell`/`.video-permissions-shell` faktycznie SĄ scrollportem.
     • górny nagłówek NIE MOŻE być czystym `position:sticky; top:0` — nadanie przodkowi
       `overflow-x:auto` zmienia (CSS Overflow Module Level 3) obliczoną wartość jego
       `overflow-y` z `visible` na `auto`, nawet gdy treść nigdy realnie nie przewija się
       w pionie. To czyni go „kontenerem przewijania”, do którego sticky przykleja się
       ZAMIAST do okna — a że kontener sam nigdy się nie przewija (jego wysokość = wysokość
       treści), sticky nie ma czego robić (zmierzone: nagłówek jedzie 1:1 ze scrollem,
       identycznie jak bez sticky). To udokumentowane ograniczenie platformy (`overflow-y:
       clip` nie pomaga — w parze z `auto` na drugiej osi ta sama specyfikacja degraduje je
       do `hidden`, czyli znów kontenera przewijania), nie błąd tego kodu. Stąd niewielka
       symulacja w JS: `stickyTableHeader.js` liczy `transform: translateY()`, który
       wizualnie przykleja `<thead>` do góry okna i odkleja go dokładnie na końcu tabeli —
       nagłówek „odjeżdża” razem z ostatnim wierszem, nigdy dalej. Pozioma pozycja
       nagłówka NADAL nie wymaga JS: to fizyczna część tej samej przewijanej w bok tabeli
       co wiersze, więc scroll poziomy przesuwa ją automatycznie razem z kolumnami.
     • róg (nagłówki lewych sticky kolumn) — sticky left (CSS) + ten sam transform JS co
       reszta nagłówka (z-index 4), nad jednym i drugim.
   Przyklejone komórki mają PEŁNE, nieprzezroczyste tło w każdym stanie wiersza, bo przewijane
   komórki przechodzą POD nimi.
   ================================================================================== */
.admin-page .routing-table-shell,
.admin-page .video-permissions-shell{
  overflow-x:auto;
  /* Poziomy „overscroll” nie może stać się gestem Wstecz przeglądarki (trackpad). */
  overscroll-behavior-x:contain;
  scrollbar-color:#3b4048 #111317;
}

/* --- AUDIO --- */
.admin-page #tbl_users thead th{ position:sticky; top:0; z-index:3; }
.admin-page #tbl_users thead tr:first-child th:first-child,
.admin-page #tbl_users thead tr:first-child th:nth-child(2){ z-index:4; }
.admin-page #tbl_users tbody td.td-select,
.admin-page #tbl_users tbody td.td-user{
  position:sticky;
  z-index:2;
  /* Sekcja „odświeżony wygląd” zostawiała tu `transparent` — zawartość przewijana w bok
     prześwitywała spod nazwy użytkownika. Hover/fokus/zaznaczenie mają już pełne kolory. */
  background:var(--adm-surface);
  background-clip:border-box;
}
.admin-page #tbl_users tbody td.td-select{ left:0; }
.admin-page #tbl_users tbody td.td-user{ left:24px; box-shadow:inset -1px 0 0 var(--adm-border-strong); }
.admin-page #tbl_users thead tr:first-child th:nth-child(2){ box-shadow:inset -1px 0 0 var(--adm-border-strong); }
/* Znacznik wiersza pod kursorem — ten sam mechanizm co `tr:hover .video-user-cell` w VIDEO
   ROUTING, tylko w czerwieni administratorskiej zamiast fioletu VIDEO. Musi być ZANIM
   `.is-selected`/`.ptt-live-row` w kaskadzie, żeby te dwa (silniejsze, stanowe znaczniki)
   nadal wygrywały podczas hover nad zaznaczonym/nadającym wierszem. */
.admin-page #tbl_users tbody tr:hover td.td-user{
  box-shadow:inset 3px 0 0 var(--adm-admin), inset -1px 0 0 var(--adm-border-strong);
}
.admin-page #tbl_users tbody tr.is-selected td.td-user{
  box-shadow:inset 3px 0 0 var(--adm-accent), inset -1px 0 0 var(--adm-border-strong);
}
.admin-page #tbl_users tbody tr.ptt-live-row td.td-user{
  box-shadow:inset 4px 0 0 var(--adm-error), inset -1px 0 0 var(--adm-border-strong);
}
/* Przeciągany wiersz przygasa treścią, nie tłem — tło przyklejonych komórek zostaje pełne. */
.admin-page #tbl_users tbody tr.is-user-dragging{ opacity:1; }
.admin-page #tbl_users tbody tr.is-user-dragging td > *{ opacity:.45; }

/* --- VIDEO --- */
.video-permissions-table thead th{ position:sticky; top:0; z-index:3; }
.video-permissions-table .video-user-cell{ position:sticky; left:0; z-index:2; }
.video-permissions-table .video-cam-head,
.video-permissions-table .video-cam-cell{
  position:sticky;
  left:var(--video-user-w);
  z-index:2;
  box-shadow:inset -1px 0 0 var(--adm-border-strong,#262b31);
}
.video-permissions-table thead .video-user-cell,
.video-permissions-table thead .video-cam-head{ z-index:4; }

/* Kontenery routingu są komórkami gridu `.admin-panel`. Bez `min-width:0` komórka rośnie do
   max-content szerokiej macierzy i rozpycha CAŁĄ stronę w poziomie — przewijałaby się wtedy
   strona, a nie tabela, i przyklejone kolumny traciłyby sens (mobile miał to już < 780 px). */
.admin-page .admin-panel,
.admin-page .admin-panel > *,
.admin-page .admin-tab-view,
.admin-page .routing-card{ min-width:0; }
.live-transcript-phrase{
  position:fixed; z-index:1200; top:max(74px, calc(env(safe-area-inset-top) + 64px));
  left:50%; transform:translateX(-50%); width:min(620px, calc(100vw - 32px));
  box-sizing:border-box; padding:9px 14px; border:1px solid rgba(55,162,255,.75);
  border-radius:10px; background:rgba(26,30,36,.96); color:#fff;
  box-shadow:0 8px 24px rgba(0,0,0,.5); text-align:center; pointer-events:none;
}
.live-transcript-phrase[hidden]{ display:none; }
.live-transcript-phrase strong{ display:block; margin-bottom:5px; color:#50adff; font-size:11px; }
.live-transcript-phrase span{ display:block; font-size:17px; line-height:1.25; font-weight:650; }
.communication-log-phrase{ display:grid; grid-template-columns:auto 1fr; gap:8px; align-items:baseline; margin:3px 0; }
.communication-log-phrase small{ color:var(--adm-text-dim, #8b9098); white-space:nowrap; }
.communication-log-phrase--partial span{ opacity:.78; font-style:italic; }

/* ============================================================================
   CAPTIONS LIVE — panel administratora (docs/CAPTIONS_LIVE.md).
   Sam output napisów ma własny, minimalny arkusz: public/css/captions-out.css.
   ============================================================================ */
.captions-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:16px; flex-wrap:wrap; }
.captions-head h2{ margin:2px 0 0; font-size:17px; }
.captions-head p{ margin:6px 0 0; max-width:760px; color:var(--adm-text-dim); font-size:12px; }
.captions-list{ display:grid; gap:10px; margin-top:16px; }
.captions-empty{ margin:14px 0 0; color:var(--adm-text-dim); font-size:12px; }
.captions-empty[hidden]{ display:none; }
.captions-status{ margin:10px 0 0; min-height:16px; color:var(--adm-text-dim); font-size:12px; }

.captions-output{
  border:1px solid var(--adm-border);
  border-radius:var(--adm-radius);
  background:var(--adm-surface-2);
  padding:12px 14px;
}
.captions-output__head{ display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; }
.captions-output__title{ display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; }
.captions-output__title strong{ font-size:14px; }
.captions-output__channel{ color:var(--adm-text-dim); font-size:12px; font-family:var(--adm-mono); }
.captions-output__state{
  font-size:11px; letter-spacing:.06em; padding:3px 9px; border-radius:999px;
  border:1px solid var(--adm-border-strong); color:var(--adm-text-dim);
}
/* LIVE = ktoś to naprawdę ogląda. UNAVAILABLE używa czerwieni alarmowej, bo to realny
   problem produkcyjny (kanał zniknął), a nie blokada nadana przez administratora. */
.captions-output__state[data-state="LIVE"]{ color:var(--adm-ok); border-color:var(--adm-ok); }
.captions-output__state[data-state="UNAVAILABLE"]{ color:var(--adm-error); border-color:var(--adm-error); }
.captions-output__state[data-state="DISABLED"]{ color:var(--adm-text-faint); }
.captions-output__summary{
  display:flex; gap:14px; flex-wrap:wrap; margin-top:8px;
  color:var(--adm-text-dim); font-size:11px; font-family:var(--adm-mono);
}
.captions-output__actions{ display:flex; gap:8px; flex-wrap:wrap; margin-top:12px; }

.captions-settings{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(170px,1fr)); gap:12px;
  margin-top:14px; padding-top:14px; border-top:1px solid var(--adm-border-soft);
}
.captions-field{ display:grid; gap:6px; color:var(--adm-text-dim); font-size:11px; }

/* Podgląd rysuje ten sam model co publiczny output — bez iframe i bez drugiego arkusza.
   Celowo MAŁY kafelek 16:9: ma pokazać tło, pozycję i rozmiar tekstu, a nie zająć pół ekranu. */
.captions-preview{
  grid-column:1/-1; position:relative; aspect-ratio:16/9;
  width:100%; max-width:400px; justify-self:start;
  border:1px solid var(--adm-border-strong); border-radius:var(--adm-radius-sm);
  display:flex; justify-content:center; overflow:hidden;
  /* Marginesy bezpieczne w px, NIE w procentach: procentowy padding liczy się od szerokości
     KOMÓRKI GRIDU (pełna szerokość karty), a nie od przyciętego max-width kafelka — przez co
     podgląd pokazywałby napisy wyraźnie wyżej, niż wyglądają na antenie. */
  padding:16px 24px;
}
.captions-preview[data-bg="BLACK"]{ background:#000; }
.captions-preview[data-bg="GREEN"]{ background:#00b140; }
/* Szachownica = miejsce, w którym w OBS/vMix widać obraz spod napisów. */
.captions-preview[data-bg="TRANSPARENT"]{
  background-color:#2a2d31;
  background-image:linear-gradient(45deg,#3a3e44 25%,transparent 25%,transparent 75%,#3a3e44 75%),
    linear-gradient(45deg,#3a3e44 25%,transparent 25%,transparent 75%,#3a3e44 75%);
  background-size:16px 16px; background-position:0 0,8px 8px;
}
.captions-preview[data-pos="BOTTOM"]{ align-items:flex-end; }
.captions-preview[data-pos="CENTER"]{ align-items:center; }
.captions-preview[data-pos="TOP"]{ align-items:flex-start; }
.captions-preview__box{
  width:100%; overflow:hidden; display:flex; flex-direction:column; justify-content:flex-end;
  --cap-preview-size:15px; line-height:1.24;
  height:calc(var(--cap-preview-lines,2) * 1.24em); font-size:var(--cap-preview-size);
}
.captions-preview[data-scale="SMALL"] .captions-preview__box{ --cap-preview-size:10px; }
.captions-preview[data-scale="MEDIUM"] .captions-preview__box{ --cap-preview-size:12.5px; }
.captions-preview[data-scale="LARGE"] .captions-preview__box{ --cap-preview-size:15px; }
.captions-preview[data-scale="XL"] .captions-preview__box{ --cap-preview-size:19px; }
.captions-preview__text{
  margin:0; color:#fff; font-weight:650; overflow-wrap:anywhere;
  text-shadow:0 2px 6px rgba(0,0,0,.85), 0 0 2px rgba(0,0,0,.9);
}
.captions-preview[data-align="CENTER"] .captions-preview__text{ text-align:center; }
.captions-preview[data-align="LEFT"] .captions-preview__text{ text-align:left; }
.captions-preview__name{ font-weight:800; opacity:.92; }

@media (max-width:760px){
  .captions-output__actions .btn{ flex:1 1 auto; }
}

/* =========================================================================================
   DZIENNIK KOMUNIKACJI — układ warsztatowy
   Górny pasek stanu (+ REC), zwarty wiersz filtrów, lista jako główna przestrzeń robocza,
   kontekstowy inspektor po prawej i oś aktywności na dole. Odtwarzacz, Recording Sessions,
   Napisy Live i LOCAL STT to te same moduły co wcześniej — zmienił się sposób dostępu.
   ========================================================================================= */
.clog-view{ display:flex; flex-direction:column; gap:12px; min-width:0; }

/* --- górny pasek ------------------------------------------------------------------- */
.clogbar{
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  padding:10px 14px; border:1px solid var(--adm-border); border-radius:var(--adm-radius,10px);
  background:var(--adm-surface); min-width:0;
}
.clogbar__identity{ min-width:0; }
.clogbar__identity h1{ margin:1px 0 0; font-size:18px; line-height:1.2; }
.clogbar__chips{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; min-width:0; }
.clogbar__rec{ display:flex; align-items:center; gap:8px; margin-left:auto; flex-wrap:wrap; }
.clogbar__settings{ min-width:34px; padding:.42rem .5rem; font-size:14px; }

.clog-chip{
  display:inline-flex; align-items:center; gap:6px; min-height:28px; padding:3px 9px;
  border:1px solid var(--adm-border-strong); border-radius:999px;
  background:var(--adm-bg); color:var(--adm-text-dim);
  font:650 11px/1.2 inherit; white-space:nowrap;
}
.clog-chip--action{ cursor:pointer; }
.clog-chip--action:hover{ color:var(--adm-text); background:var(--adm-surface-hover); }
.clog-chip--action:focus-visible{ outline:2px solid var(--adm-accent); outline-offset:2px; }
.clog-chip__key{ color:var(--adm-text-faint); font-weight:750; letter-spacing:.06em; text-transform:uppercase; font-size:9.5px; }
/* LOW STORAGE nigdy nie jest chowane „dla estetyki” — plakietka zmienia kolor i wagę. */
.clog-chip[data-state="LOW"]{ color:var(--adm-error); border-color:rgba(240,87,76,.55); background:rgba(240,87,76,.1); font-weight:800; }
.clog-chip[data-state="LOW"] .clog-chip__key{ color:var(--adm-error); }
.clog-view .communication-log-live{ font-size:11px; }
.clog-view .communication-log-live.is-history .communication-log-live__dot{ background:var(--adm-text-faint); box-shadow:none; }

.clog-inline-error{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:0; padding:8px 12px;
  border:1px solid rgba(240,87,76,.45); border-radius:8px; background:rgba(240,87,76,.08);
  color:var(--adm-error); font-size:12px;
}
.clog-inline-error[hidden]{ display:none !important; }
.clog-inline-error .btn{ margin-left:auto; min-height:26px; padding:2px 10px; font-size:11px; }

/* --- filtry ------------------------------------------------------------------------- */
.clog-filters{
  display:flex; align-items:end; gap:10px; flex-wrap:wrap; min-width:0;
  padding:10px 14px; border:1px solid var(--adm-border); border-radius:var(--adm-radius,10px);
  background:var(--adm-surface);
}
.clog-filters label{
  display:grid; gap:4px; min-width:130px;
  color:var(--adm-text-dim); font-size:9.5px; letter-spacing:.05em; text-transform:uppercase;
}
.clog-filters .input{ min-height:34px; }
.clog-filters__search{ flex:1 1 220px; min-width:180px; }
.clog-filters__more{ position:relative; margin-left:auto; }
.clog-more-panel{
  position:absolute; z-index:40; right:0; top:calc(100% + 6px); min-width:240px; padding:12px;
  border:1px solid var(--adm-border-strong); border-radius:9px; background:var(--adm-surface-2,#1a1e24);
  box-shadow:0 14px 34px rgba(0,0,0,.5);
}
.clog-more-panel[hidden]{ display:none !important; }
.clog-more-panel__hint{ margin:10px 0 0; color:var(--adm-text-faint); font-size:11px; line-height:1.45; }

/* --- przestrzeń robocza: lista + inspektor ----------------------------------------- */
.clog-workspace{ display:grid; grid-template-columns:minmax(0,62fr) minmax(320px,38fr); gap:12px; align-items:start; min-width:0; }
.clog-listcard{ display:flex; flex-direction:column; min-width:0; padding:12px 14px; height:min(68vh,760px); }
.clog-view .clog-scroll-wrap{ flex:1; min-height:0; margin-top:6px; }
.clog-view .clog-list{ max-height:none; height:100%; }
.clog-view .communication-log-footer{ min-height:32px; padding-top:8px; }
.clog-view .communication-log-older{ margin:0 0 2px; }
.clog-entry.is-selected{ background:rgba(56,155,255,.1); box-shadow:inset 3px 0 0 var(--adm-accent); }
.clog-entry.is-selected.is-live{ background:rgba(62,207,142,.08); }
.clog-view .clog-chevron{ width:auto; min-width:26px; min-height:24px; padding:1px 6px; }

.clog-inspector{
  display:flex; flex-direction:column; min-width:0;
  height:min(68vh,760px); padding:0; overflow:hidden;
}
/* Dojechanie do końca listy/inspektora NIE ma pociągać strony — bez tego kółko myszy
   „przeskakuje" z panelu na dokument i widok ucieka spod kursora. */
.clog-view .clog-list,
.clog-inspector__body{ overscroll-behavior:contain; }
.clog-inspector__tabs{
  display:flex; gap:2px; flex-wrap:wrap; padding:8px 10px 0;
  border-bottom:1px solid var(--adm-border);
}
.clog-inspector__tab{
  min-height:30px; padding:5px 10px; border:0; border-radius:6px 6px 0 0;
  background:transparent; color:var(--adm-text-dim); font:650 11.5px/1.2 inherit; cursor:pointer;
}
.clog-inspector__tab:hover{ color:var(--adm-text); background:var(--adm-surface-hover); }
.clog-inspector__tab.is-active{ color:var(--adm-text); background:var(--adm-bg); box-shadow:inset 0 -2px 0 var(--adm-accent); }
.clog-inspector__tab:focus-visible{ outline:2px solid var(--adm-accent); outline-offset:-2px; }
.clog-inspector__body{ flex:1; min-height:0; overflow-y:auto; padding:12px 14px 16px; }
.clog-inspector__panel[hidden]{ display:none !important; }
.clog-inspector__section{ margin-top:16px; padding-top:12px; border-top:1px solid var(--adm-border); }
.clog-inspector__heading{ margin:0 0 8px; font-size:12px; letter-spacing:.05em; text-transform:uppercase; color:var(--adm-text-dim); }
.clog-inspector__hint{ margin:8px 0 0; color:var(--adm-text-faint); font-size:11px; line-height:1.5; }
.clog-details[hidden]{ display:none !important; }
.clog-details__summary{ cursor:pointer; margin:0; list-style:none; }
.clog-details__summary::-webkit-details-marker{ display:none; }
.clog-details__summary::before{ content:'›'; display:inline-block; width:12px; color:var(--adm-text-faint); transition:transform .15s ease; }
.clog-details[open] .clog-details__summary::before{ transform:rotate(90deg); }
.clog-details__summary:hover{ color:var(--adm-text); }
.clog-details__summary:focus-visible{ outline:2px solid var(--adm-accent); outline-offset:2px; }
.clog-details[open] .clog-facts{ margin-top:8px; }

/* tryb bezczynny — nigdy pusty prostokąt */
.clog-idle__lead{ margin:0 0 12px; color:var(--adm-text-dim); font-size:12px; line-height:1.5; }
.clog-facts{ display:grid; grid-template-columns:auto minmax(0,1fr); gap:5px 12px; margin:0 0 12px; font-size:12px; }
.clog-facts dt{ color:var(--adm-text-faint); font-size:10.5px; letter-spacing:.04em; text-transform:uppercase; align-self:center; }
.clog-facts dd{ margin:0; color:var(--adm-text); overflow-wrap:anywhere; }
.clog-facts dd[data-state="LOW"]{ color:var(--adm-error); font-weight:750; }
.clog-facts dd[data-state="ON"]{ color:var(--adm-error); font-weight:750; }

.clog-entry-head{ display:flex; align-items:baseline; justify-content:space-between; gap:10px; flex-wrap:wrap; margin-bottom:10px; }
/* Reguła klasowa z `display` przykrywa `[hidden]{display:none}` z arkusza przeglądarki. */
.clog-entry-head[hidden]{ display:none !important; }
.clog-entry-actions[hidden]{ display:none !important; }
.clog-transcript[hidden],.clog-facts[hidden]{ display:none !important; }
.clog-entry-head strong{ font-size:14px; }
.clog-entry-head__sub{ margin-left:8px; color:var(--adm-text-dim); font-size:11.5px; }
.clog-entry-head__time{ color:var(--adm-text-dim); font-family:var(--adm-mono,ui-monospace,monospace); font-variant-numeric:tabular-nums; font-size:11.5px; white-space:nowrap; }
.clog-entry-actions{ display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px; }

.clog-transcript{ display:grid; gap:6px; }
.clog-transcript__line{ display:grid; grid-template-columns:4.6rem minmax(0,1fr) auto; gap:10px; align-items:baseline; font-size:12.5px; line-height:1.45; color:var(--adm-text); }
.clog-transcript__time{ font-family:var(--adm-mono,ui-monospace,monospace); font-variant-numeric:tabular-nums; color:var(--adm-text-faint); font-size:11px; }
.clog-transcript__text{ overflow-wrap:anywhere; }
.clog-transcript__line.is-partial .clog-transcript__text,
.clog-transcript__line.is-pending .clog-transcript__text{ opacity:.78; font-style:italic; }
.clog-transcript__line.is-error .clog-transcript__text{ color:var(--adm-error); }
.clog-transcript__line.is-nospeech .clog-transcript__text{ color:var(--adm-text-faint); font-style:italic; }
.clog-transcript__badge{ color:var(--adm-text-faint); font-size:9px; font-weight:750; letter-spacing:.05em; }
.clog-transcript__empty{ margin:0; color:var(--adm-text-faint); font-size:12px; font-style:italic; }

/* odtwarzacz w inspektorze — ten sam canonical playback, zwarta prezentacja */
.clog-view .recording-player{ margin-bottom:2px; }
.clog-view .recording-now{ margin:9px 0 5px; }
.clog-view .recording-seek{ margin:3px 0 6px; }
.clog-view .recording-range-controls{ margin-top:9px; padding-top:9px; }
.clog-view .clog-inspector__section{ margin-top:12px; padding-top:10px; }
.clog-view .recording-player-head{ display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap; }
.clog-view .recording-player-head label{ display:grid; gap:4px; color:var(--adm-text-dim); font-size:9.5px; text-transform:uppercase; }
.clog-view .recording-timeline{ height:46px; }
.clog-view .recording-marker{ top:9px; height:20px; }
.clog-view .recording-marker.has-overlap{ top:30px; height:12px; }
.clog-view .recording-player-controls{ justify-content:space-between; gap:6px; }
.clog-view .recording-player-controls .btn{ flex:1 1 auto; min-width:0; padding:.42rem .3rem; }
.clog-view .recording-range-controls{ gap:8px; }
.clog-view .recording-session-controls{ margin-top:0; }
.clog-view .recording-session-controls select{ min-width:0; width:100%; }
.clog-view .recording-session-controls label{ flex:1 1 100%; }
.clog-view .recording-session-controls__actions{ display:flex; gap:8px; flex-wrap:wrap; width:100%; }
.clog-view .recording-storage{ margin-top:10px; font-size:11px; }
/* `.recording-session-controls label{display:grid}` ma wyższą specyficzność niż
   `.stt-session-only-missing{display:flex}`, więc checkbox „tylko bez transkryptu" rozjeżdżał
   się na całą szerokość kolumny. W inspektorze ustawiamy go wprost. */
.clog-view .stt-session-only-missing{
  display:flex; align-items:center; gap:8px; flex:1 1 100%;
  font-size:11.5px; text-transform:none; letter-spacing:0; color:var(--adm-text-dim);
}
.clog-view .stt-session-only-missing input{ flex:0 0 auto; width:15px; height:15px; margin:0; }
.clog-view .recording-range-controls .input{ flex:1 1 140px; min-width:0; }
.clog-view #recording_export_status{ flex:1 1 100%; font-size:11px; color:var(--adm-text-dim); overflow-wrap:anywhere; }
.clog-view #stt_session_status{ flex:1 1 100%; font-size:11px; color:var(--adm-text-dim); }
.clog-view #recording_range_label{ font-family:var(--adm-mono,ui-monospace,monospace); font-size:11px; }
.clog-view .stt-status-bar{ margin-top:0; }
.clog-view .stt-status-bar__auto{ margin:10px 0 0; font-size:12px; color:var(--adm-text-dim); }
.clog-view .captions-head h3{ margin:2px 0 0; }
.clog-view .captions-head p{ font-size:11.5px; }

/* --- oś aktywności ------------------------------------------------------------------ */
.clog-activity{ padding:10px 14px 12px; min-width:0; }
.clog-activity__head{ display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin-bottom:8px; }
.clog-activity__title{ margin:0; font-size:13px; letter-spacing:.04em; text-transform:uppercase; color:var(--adm-text-dim); }
.clog-activity__legend{ display:flex; align-items:center; gap:6px; flex-wrap:wrap; color:var(--adm-text-faint); font-size:10px; letter-spacing:.04em; }
.clog-activity__legend span:not(.clog-activity__key){ margin-right:8px; }
.clog-activity__key{ width:12px; height:8px; border-radius:2px; background:var(--adm-accent); }
.clog-activity__key--live{ background:var(--adm-ok); }
.clog-activity__key--no-audio{ background:var(--adm-text-faint); }
.clog-activity__key--interrupted{ background:#f4c66a; }
.clog-activity__key--rec{ background:rgba(62,207,142,.3); }
.clog-activity__range{ margin-left:auto; color:var(--adm-text-dim); font-family:var(--adm-mono,ui-monospace,monospace); font-size:11px; white-space:nowrap; }
.clog-activity__ticks{ position:relative; height:14px; margin-left:86px; color:var(--adm-text-faint); font-size:9.5px; }
.clog-activity__tick{ position:absolute; top:0; transform:translateX(-50%); font-family:var(--adm-mono,ui-monospace,monospace); white-space:nowrap; }
.clog-activity__lanes{ display:grid; gap:2px; }
.clog-activity__lane{ display:grid; grid-template-columns:86px minmax(0,1fr); gap:8px; align-items:center; }
.clog-activity__label{ color:var(--adm-text-dim); font-size:10px; letter-spacing:.03em; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.clog-activity__track{
  position:relative; height:13px; border-radius:3px;
  background:var(--adm-bg); border:1px solid var(--adm-border);
}
.clog-activity__lane.is-rec .clog-activity__track{ height:8px; }
.clog-activity__block{ position:absolute; top:1px; bottom:1px; min-width:2px; padding:0; border:0; border-radius:2px; background:var(--adm-accent); opacity:.85; }
button.clog-activity__block{ cursor:pointer; }
button.clog-activity__block:hover,.clog-activity__block.is-selected{ opacity:1; box-shadow:0 0 0 2px rgba(255,255,255,.6); }
.clog-activity__block.is-live{ background:var(--adm-ok); }
.clog-activity__block.is-no-audio{ background:var(--adm-text-faint); }
.clog-activity__block.is-interrupted{ background:#f4c66a; }
.clog-activity__block.is-rec{ background:rgba(62,207,142,.28); }
.clog-activity__block.is-gap{ background:repeating-linear-gradient(135deg,rgba(240,87,76,.22) 0 5px,transparent 5px 10px); }
.clog-activity__empty{ margin:10px 0 0; color:var(--adm-text-faint); font-size:11.5px; text-align:center; }
.clog-activity__empty[hidden]{ display:none !important; }
.clog-activity__toggle{ min-width:30px; padding:.2rem .45rem; font-size:13px; line-height:1; }
.clog-activity__toggle span{ display:inline-block; transition:transform .15s ease; }
.clog-activity.is-collapsed .clog-activity__toggle span{ transform:rotate(-90deg); }
/* Zwinięta oś oddaje wysokość liście, ale zostaje widoczna jako pasek z zakresem czasu. */
.clog-activity.is-collapsed{ padding-bottom:10px; }
.clog-activity.is-collapsed .clog-activity__ticks,
.clog-activity.is-collapsed .clog-activity__lanes,
.clog-activity.is-collapsed .clog-activity__empty,
.clog-activity.is-collapsed .clog-activity__legend{ display:none; }
.clog-activity.is-collapsed .clog-activity__head{ margin-bottom:0; }

/* --- responsywność ------------------------------------------------------------------ */
@media (min-width:1181px){
  /* Wysokość liczy admin.js (`--clog-shell-height`), bo nagłówek panelu potrafi się zawinąć
     i stała wartość w CSS rozjechałaby się przy innej szerokości okna. */
  .clog-view{
    height:var(--clog-shell-height, calc(100dvh - 210px));
    min-height:430px;
    overflow:hidden;
  }
  .clog-workspace{ flex:1; min-height:0; align-items:stretch; }
  .clog-workspace > *{ min-height:0; max-height:100%; }
  .clog-listcard{ height:auto; min-height:0; }
  .clog-inspector{ height:auto; min-height:0; }
}
@media (max-width:1180px){
  /* Na laptopie inspektor schodzi pod listę zamiast ściskać obie kolumny. */
  .clog-workspace{ grid-template-columns:minmax(0,1fr); }
  .clog-listcard{ height:min(52vh,560px); }
  .clog-inspector{ height:auto; max-height:none; overflow:visible; }
  .clog-inspector__body{ overflow:visible; max-height:none; }
  .clog-inspector__tabs{ position:sticky; top:0; z-index:2; background:var(--adm-surface); }
}
@media (max-width:780px){
  .clogbar{ padding:10px 12px; }
  .clogbar__rec{ margin-left:0; width:100%; }
  .clogbar__rec .recording-rec{ flex:1 1 auto; }
  .clog-filters{ display:grid; grid-template-columns:1fr 1fr; padding:10px 12px; }
  .clog-filters label{ min-width:0; }
  .clog-filters__search{ grid-column:1 / -1; }
  .clog-filters__more{ grid-column:1 / -1; margin-left:0; }
  .clog-more-panel{ right:auto; left:0; width:100%; }
  .clog-listcard{ padding:10px 12px; height:min(58vh,520px); }
  .clog-activity__ticks,.clog-activity__lane{ margin-left:0; }
  .clog-activity__lane{ grid-template-columns:62px minmax(0,1fr); }
  .clog-activity__ticks{ margin-left:62px; }
  .clog-transcript__line{ grid-template-columns:3.6rem minmax(0,1fr); }
  .clog-transcript__badge{ display:none; }
}
