/* meet405 — стили. Один раз вырезаны из app.css chat405 по СЕЛЕКТОРАМ, дальше
 * файл живёт руками.
 *
 * ⚑ Оставлены правила, чьи классы встречаются в разметке и коде этого
 * приложения (плюс сброс, токены темы, шрифты и анимации). Из 5664 строк
 * мессенджера осталась примерно пятая часть: чат-лист, лента сообщений,
 * композер, стикеры, админка и правая колонка сюда не приехали.
 *
 * 🔴 ⛔ ЧЕМ ЭТА РЕЗКА ОПАСНА, на живом примере. Инструмент оставлял правило,
 * если в его селекторе есть используемый класс ИЛИ это селектор по элементу.
 * Глобальное `[hidden] { display: none !important }` — ни то, ни другое, и оно
 * выпало. На проде 26.08 это выглядело так: человек входит через 405, сессия
 * заводится, /api/me отвечает 200, приложение работает — и показывает экран
 * входа, потому что ОБЕ панели нарисованы одна под другой. Ни одной ошибки
 * нигде.
 *
 * Мораль не про этот файл, а про приём: вырезание по селекторам молча теряет
 * правила, у которых нет ни класса, ни имени элемента. Если понадобится
 * повторить — сначала выписать такие правила отдельно, потом резать.
 */

/* 🔴 Атрибут `hidden` обязан РЕАЛЬНО скрывать. Браузерная таблица говорит
   [hidden]{display:none}, но ЛЮБОЕ авторское правило со своим display бьёт её —
   а он есть почти у всего (у .meet-login и .meet-app это flex, у .field тоже).
   Отказ молчаливый и каждый раз одинаковый: код ставит `hidden`, тест проверяет
   `el.hidden === true` и проходит, а штука стоит на экране.
   В chat405 это стоило трёх разных сообщений за один день; здесь — одного
   «после входа снова вход». Одно правило вместо того, чтобы каждый раз помнить
   про пару; частные `[hidden]`-правила ниже теперь избыточны, но безвредны. */
[hidden] { display: none !important; }
*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  overflow: hidden; /* the app manages its own internal scroll regions */
}
h1, p, ul, li, form { margin: 0; padding: 0; list-style: none; }
button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}
input, textarea {
  font: inherit;
  color: inherit;
}
img, svg { display: block; }
a { color: inherit; }
:root {
  color-scheme: dark;

  --font-sans: 'Open Sans', 'Segoe UI', system-ui, -apple-system, sans-serif; /* tdesktop ships Open Sans — the text texture is half of why it looked foreign */

  --bg-app: #0e1621;
  --bg-sidebar: #17212b;
  --bg-thread: #1c2b26;
  /* Обои чата: четыре цвета из ConstructDefault(), приглушённые под ночь —
     ярко-зелёная стена под тёмными пузырями читалась бы как чужая. */
  --chat-wallpaper:
    radial-gradient(78% 78% at 18% 12%, #233a30 0%, rgba(35, 58, 48, 0) 72%),
    radial-gradient(78% 78% at 84% 16%, #1d3b31 0%, rgba(29, 59, 49, 0) 72%),
    radial-gradient(80% 80% at 12% 88%, #223526 0%, rgba(34, 53, 38, 0) 74%),
    radial-gradient(86% 86% at 88% 84%, #1a2f28 0%, rgba(26, 47, 40, 0) 74%);
  --chat-wallpaper-pattern: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22260%22%20height%3D%22260%22%20viewBox%3D%220%200%20260%20260%22%3E%3Cg%20fill%3D%22none%22%20stroke%3D%22%23ffffff%22%20stroke-width%3D%222.4%22%20stroke-linecap%3D%22round%22%20opacity%3D%220.06%22%3E%3Ccircle%20cx%3D%2238%22%20cy%3D%2242%22%20r%3D%2219%22%2F%3E%3Ccircle%20cx%3D%22232%22%20cy%3D%2270%22%20r%3D%2211%22%2F%3E%3Ccircle%20cx%3D%22128%22%20cy%3D%22166%22%20r%3D%2227%22%2F%3E%3Ccircle%20cx%3D%2260%22%20cy%3D%22228%22%20r%3D%2214%22%2F%3E%3Cpath%20d%3D%22M132%2016%20a26%2026%200%200%201%2044%2020%22%2F%3E%3Cpath%20d%3D%22M196%20196%20a22%2022%200%200%200%20-38%2016%22%2F%3E%3Cpath%20d%3D%22M14%20128%20a20%2020%200%200%201%2030%20-10%22%2F%3E%3Cpath%20d%3D%22M162%2096%20q12%20-12%2024%200%20t24%200%22%2F%3E%3Cpath%20d%3D%22M28%20168%20q10%2010%2020%200%20t20%200%22%2F%3E%3Cpath%20d%3D%22M92%2044%20l16%20-16%22%2F%3E%3Cpath%20d%3D%22M100%2052%20l16%20-16%22%2F%3E%3Cpath%20d%3D%22M214%20140%20l14%2014%22%2F%3E%3Cpath%20d%3D%22M222%20132%20l14%2014%22%2F%3E%3Cpath%20d%3D%22M188%2060%20h16%20M196%2052%20v16%22%2F%3E%3Cpath%20d%3D%22M74%20122%20h14%20M81%20115%20v14%22%2F%3E%3Cpath%20d%3D%22M240%20214%20h14%20M247%20207%20v14%22%2F%3E%3Crect%20x%3D%2286%22%20y%3D%22196%22%20width%3D%2226%22%20height%3D%2226%22%20rx%3D%228%22%2F%3E%3Crect%20x%3D%22176%22%20y%3D%22240%22%20width%3D%2220%22%20height%3D%2220%22%20rx%3D%226%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23ffffff%22%20opacity%3D%220.06%22%3E%3Ccircle%20cx%3D%22166%22%20cy%3D%2246%22%20r%3D%223.5%22%2F%3E%3Ccircle%20cx%3D%2222%22%20cy%3D%2296%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%22252%22%20cy%3D%22118%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%22110%22%20cy%3D%2292%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%2246%22%20cy%3D%22152%22%20r%3D%223.5%22%2F%3E%3Ccircle%20cx%3D%22204%22%20cy%3D%22168%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%22148%22%20cy%3D%22232%22%20r%3D%223.5%22%2F%3E%3Ccircle%20cx%3D%2296%22%20cy%3D%22258%22%20r%3D%223%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
  --bg-panel: #17212b;
  --bg-elevated: #1f2b38;
  --bg-hover: #1c2733;
  --bg-active: #2b5278;
  --bg-input: #242f3d;

  --border-subtle: #1e2933;
  --border-strong: #2b3947;

  --text-primary: #e9edef;
  --text-secondary: #8296a8;
  --text-tertiary: #5d707f;
  --text-on-accent: #ffffff;

  --accent: #4ea4f5;
  --accent-strong: #2b96e8;
  /* The info column's action tiles. tdesktop paints them with the accent at
     infoProfileTopBarActionButtonBgOpacity = 0.16 rather than with a grey, so
     the row of them reads as one control strip instead of four buttons. */
  --accent-soft: rgba(78, 164, 245, 0.16);
  /* activeButtonSecondaryFg — the count inside FORWARD 3 / DELETE 3, which
     tdesktop draws dimmer than the label (lib_ui colors.palette says so in as
     many words: "selected messages counter in forward / delete buttons"). */
  --accent-btn-count: #9abfe7;

  --bubble-own-bg: #2b5278;
  --bubble-own-text: #eaf3ff;
  --bubble-other-bg: #182533; /* tdesktop night incoming */
  --bubble-other-text: #e5e9ec;
  --bubble-quote-bg: rgba(255, 255, 255, 0.08);

  --unread-badge-bg: #4082bc; /* dialogsUnreadBg night */
  --unread-badge-text: #ffffff;
  --unread-badge-muted-bg: #35424e;
  --unread-badge-muted-text: #8296a8;

  --tick-sent-color: #8296a8;
  /* historyOutIconFg #6bbfff: tdesktop uses ONE colour for the single and the
     double tick — sent vs read differ by COUNT, not colour. Our two-colour
     scheme was invented. historySendingOutIconFg is the pending clock. */
  --tick-read-color: #6bbfff;
  --tick-own-sent: #6bbfff;
  --flash-overlay: rgba(255, 255, 255, 0.16);
  --tick-clock: #70a4d2;
  --msg-time-in: #6d7f8f;   /* msgInDateFg */
  --msg-time-out: #7da8d3;  /* msgOutDateFg */

  /* A SELECTED message. Telegram repaints the bubble rather than washing the
     row, and in the night theme msgInBgSelected and msgOutBgSelected are the
     SAME blue — a selection reads down a mixed conversation at a glance
     because both directions land on one colour. */
  --bubble-selected-bg: #2e70a5;      /* msgInBgSelected */
  --bubble-own-selected-bg: #2e70a5;  /* msgOutBgSelected */
  --msg-time-selected: #ffffff;       /* msgInDateFgSelected */
  --msg-time-own-selected: #ffffff;   /* msgOutDateFgSelected */
  --tick-selected: #ffffff;           /* historyOutIconFgSelected */
  --select-overlay: #3585d44c;        /* msgSelectOverlay, for media */
  /* msgSelectionCheck: a 2px windowBg ring over msgServiceBg, filled with
     boxTextFgGood when checked and the check drawn in windowBg. */
  --check-ring: #17212b;              /* windowBg */
  --check-ring-bg: #213040d5;         /* msgServiceBg */
  --check-checked-bg: #5598db;        /* boxTextFgGood, night */
  --check-checked-fg: #17212b;        /* overviewCheckFgActive = windowBg */

  --danger: #f2555a;
  --divider-unread-color: #4ea4f5;
  --presence-online: #43b581;

  --scrollbar-thumb: #2b3947;

  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-bubble: 16px; /* tdesktop bubbleRadiusLarge */

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;

  --shadow-panel: 0 12px 32px rgba(0, 0, 0, 0.45);
  --sidebar-width: 300px;
}
:root[data-theme="light"] {
  color-scheme: light;

  --bg-app: #eef2f5;
  --bg-sidebar: #ffffff;
  --bg-thread: #a8c69a; /* база под градиент обоев */
  /* Обои чата ровно из первоисточника (data_wall_paper.cpp,
     WallPaper::ConstructDefault): rgb(219,221,187) / rgb(107,165,135) /
     rgb(213,216,141) / rgb(136,184,132), узор интенсивности 50. */
  --chat-wallpaper:
    radial-gradient(72% 72% at 16% 12%, #dbddbb 0%, rgba(219, 221, 187, 0) 70%),
    radial-gradient(72% 72% at 86% 18%, #6ba587 0%, rgba(107, 165, 135, 0) 70%),
    radial-gradient(74% 74% at 12% 86%, #d5d88d 0%, rgba(213, 216, 141, 0) 72%),
    radial-gradient(80% 80% at 90% 88%, #88b884 0%, rgba(136, 184, 132, 0) 74%);
  --chat-wallpaper-pattern: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22260%22%20height%3D%22260%22%20viewBox%3D%220%200%20260%20260%22%3E%3Cg%20fill%3D%22none%22%20stroke%3D%22%23335c42%22%20stroke-width%3D%222.4%22%20stroke-linecap%3D%22round%22%20opacity%3D%220.14%22%3E%3Ccircle%20cx%3D%2238%22%20cy%3D%2242%22%20r%3D%2219%22%2F%3E%3Ccircle%20cx%3D%22232%22%20cy%3D%2270%22%20r%3D%2211%22%2F%3E%3Ccircle%20cx%3D%22128%22%20cy%3D%22166%22%20r%3D%2227%22%2F%3E%3Ccircle%20cx%3D%2260%22%20cy%3D%22228%22%20r%3D%2214%22%2F%3E%3Cpath%20d%3D%22M132%2016%20a26%2026%200%200%201%2044%2020%22%2F%3E%3Cpath%20d%3D%22M196%20196%20a22%2022%200%200%200%20-38%2016%22%2F%3E%3Cpath%20d%3D%22M14%20128%20a20%2020%200%200%201%2030%20-10%22%2F%3E%3Cpath%20d%3D%22M162%2096%20q12%20-12%2024%200%20t24%200%22%2F%3E%3Cpath%20d%3D%22M28%20168%20q10%2010%2020%200%20t20%200%22%2F%3E%3Cpath%20d%3D%22M92%2044%20l16%20-16%22%2F%3E%3Cpath%20d%3D%22M100%2052%20l16%20-16%22%2F%3E%3Cpath%20d%3D%22M214%20140%20l14%2014%22%2F%3E%3Cpath%20d%3D%22M222%20132%20l14%2014%22%2F%3E%3Cpath%20d%3D%22M188%2060%20h16%20M196%2052%20v16%22%2F%3E%3Cpath%20d%3D%22M74%20122%20h14%20M81%20115%20v14%22%2F%3E%3Cpath%20d%3D%22M240%20214%20h14%20M247%20207%20v14%22%2F%3E%3Crect%20x%3D%2286%22%20y%3D%22196%22%20width%3D%2226%22%20height%3D%2226%22%20rx%3D%228%22%2F%3E%3Crect%20x%3D%22176%22%20y%3D%22240%22%20width%3D%2220%22%20height%3D%2220%22%20rx%3D%226%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23335c42%22%20opacity%3D%220.14%22%3E%3Ccircle%20cx%3D%22166%22%20cy%3D%2246%22%20r%3D%223.5%22%2F%3E%3Ccircle%20cx%3D%2222%22%20cy%3D%2296%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%22252%22%20cy%3D%22118%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%22110%22%20cy%3D%2292%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%2246%22%20cy%3D%22152%22%20r%3D%223.5%22%2F%3E%3Ccircle%20cx%3D%22204%22%20cy%3D%22168%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%22148%22%20cy%3D%22232%22%20r%3D%223.5%22%2F%3E%3Ccircle%20cx%3D%2296%22%20cy%3D%22258%22%20r%3D%223%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
  --bg-panel: #ffffff;
  --bg-elevated: #f3f5f7;
  --bg-hover: #f2f4f6;
  --bg-active: #419fd9; /* tdesktop day: the active chat row is SOLID blue with white text */
  --bg-input: #eef1f4;

  --border-subtle: #e4e8ec;
  --border-strong: #d5dbe1;

  --text-primary: #17212b;
  --text-secondary: #6d7883;
  --text-tertiary: #98a1a9;
  --text-on-accent: #ffffff;

  --accent: #3390ec;
  --accent-strong: #2077cf;
  --accent-soft: rgba(51, 144, 236, 0.12);
  --accent-btn-count: #cceeff;

  /* THE Telegram day signature: outgoing is pale GREEN, not blue. The blue
     bubble was the single biggest "this is not Telegram" tell in the light
     theme — every other messenger is blue; Telegram day is #effdde with
     green ticks. */
  --bubble-own-bg: #effdde;
  --bubble-own-text: #141414;
  --bubble-other-bg: #ffffff;
  --bubble-other-text: #1a232c;
  --bubble-quote-bg: rgba(17, 51, 85, 0.06);

  --unread-badge-bg: #40a7e3; /* dialogsUnreadBg day = windowBgActive */
  --unread-badge-text: #ffffff;
  --unread-badge-muted-bg: #d7dce1;
  --unread-badge-muted-text: #6d7883;

  --tick-sent-color: #9aa4ac;
  --tick-read-color: #57b84c; /* historyOutIconFg — one colour for 1 and 2 ticks */
  --tick-own-sent: #57b84c;
  /* msgSelectOverlay: the wash tdesktop paints over a jumped-to bubble. Dark
     on a light theme, light on a dark one — it must read on the pale green
     outgoing bubble AND on white. */
  --flash-overlay: rgba(17, 51, 85, 0.14);
  --tick-clock: #98d292;
  --msg-time-in: #a0acb6;
  --msg-time-out: #6db566;

  /* Day, and here the two directions genuinely differ: bluish for incoming,
     teal for outgoing, and the checked circle is GREEN (boxTextFgGood
     #4ab44a) rather than the night theme's blue. */
  --bubble-selected-bg: #c2dcf2;      /* msgInBgSelected */
  --bubble-own-selected-bg: #b7dbdb;  /* msgOutBgSelected */
  --msg-time-selected: #6a9cc5;       /* msgInDateFgSelected */
  --msg-time-own-selected: #56b2a6;   /* msgOutDateFgSelected */
  --tick-selected: #45a3aa;           /* historyOutIconFgSelected */
  --select-overlay: #358cd44c;        /* msgSelectOverlay */
  --check-ring: #ffffff;              /* windowBg */
  --check-ring-bg: #517c417f;         /* msgServiceBg */
  --check-checked-bg: #4ab44a;        /* boxTextFgGood, day */
  --check-checked-fg: #ffffff;        /* overviewCheckFgActive = windowBg */

  --danger: #e0393e;
  --divider-unread-color: #2077cf;
  --presence-online: #2fa860;

  --scrollbar-thumb: #d1d7dc;

  --shadow-panel: 0 12px 32px rgba(20, 30, 40, 0.16);
}
body {
  background: var(--bg-app);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
}
.icon {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
}
* { scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb) transparent; }
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb);
  border-radius: 8px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
.icon-btn:focus-visible, .theme-toggle:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: inherit;
}
.avatar {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  overflow: hidden;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 0.02em;
  color: #ffffff;
  background: linear-gradient(160deg, hsl(var(--avatar-hue, 210) 62% 52%), hsl(var(--avatar-hue, 210) 62% 38%));
}
.avatar--saved .icon { width: 55%; height: 55%; color: inherit; }
.avatar--channel .icon { color: inherit; width: 22px; height: 22px; }
.avatar--lg { width: 72px; height: 72px; font-size: 24px; }
.menu-item .icon { color: var(--text-secondary); flex: 0 0 auto; }
.menu-item-danger, .menu-item-danger .icon { color: var(--danger, #e5534b); }
.row-ticks .icon { width: 15px; height: 10px; }
.row-ticks--clock .icon { width: 11px; height: 11px; }
.chat-row--archive .chat-row-archive-icon .icon { width: 22px; height: 22px; }
.thread-header-identity .avatar { width: 40px; height: 40px; font-size: 13.5px; }
@keyframes typing-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.5; }
  30% { transform: translateY(-3px); opacity: 1; }
}
.ticks .icon { width: 15px; height: 10px; }
@keyframes bubble-flash {
  0%   { box-shadow: inset 0 0 0 400px transparent; }
  12%  { box-shadow: inset 0 0 0 400px var(--flash-overlay); }
  100% { box-shadow: inset 0 0 0 400px transparent; }
}
.msg-action-btn .icon { width: 15px; height: 15px; }
.file-download .icon { width: 16px; height: 16px; }
.send-btn .icon { width: 18px; height: 18px; }
.info-tile .icon { width: 23px; height: 23px; }
.info-row .icon { width: 22px; height: 22px; flex: 0 0 auto; color: var(--text-secondary); }
.info-row--danger .info-row-value, .info-row--danger .icon { color: var(--danger); }
.btn {
  height: 40px;
  padding: 0 var(--space-5);
  border-radius: var(--radius-md);
  font-weight: 600;
  font-size: 14px;
  width: 100%;
}
.btn--primary { background: var(--accent); color: #fff; }
.btn--primary:hover { background: var(--accent-strong); }
.btn--danger {
  margin-top: var(--space-5);
  background: transparent;
  color: var(--danger);
  border: 1px solid var(--danger);
}
.btn--danger:hover { background: rgba(242, 85, 90, 0.1); }
.message-check .icon { width: 12px; height: 12px; stroke-width: 3; }
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  /* Without this the default `stretch` makes every dialog as tall as the
     overlay, and max-height then clamps it — which is why "Forward to…" with
     two rows in it, "New poll" and "New group" were all exactly the same
     height with half the window empty. A Telegram box is as tall as what is
     in it; max-height still caps the ones that genuinely are long, and their
     inner list keeps scrolling. */
  align-items: flex-start;
  padding-top: 12vh;
}
.modal-overlay[hidden] { display: none; }
.modal {
  width: 480px;
  max-width: calc(100vw - 48px);
  max-height: 70vh;
  background: var(--bg-panel);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-panel);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.modal-header .icon { color: var(--text-tertiary); }
.modal-search-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 36px;
  background: var(--bg-input);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  padding: 0 var(--space-3);
  color: var(--text-primary);
  font-size: 14px;
}
.modal-search-input:focus { outline: none; border-color: var(--accent); }
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 12.5px;
  color: var(--text-secondary);
  font-weight: 600;
}
.field input {
  height: 40px;
  background: var(--bg-input);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  padding: 0 var(--space-3);
  color: var(--text-primary);
  font-size: 14px;
}
.field input:focus { outline: none; border-color: var(--accent); }
.field input::placeholder { color: var(--text-tertiary); }
.field select, .field textarea {
  background: var(--bg-input);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3);
  color: var(--text-primary);
  font-size: 14px;
  font-family: inherit;
}
.field select { height: 40px; }
.field textarea { resize: vertical; min-height: 72px; }
.field select:focus, .field textarea:focus { outline: none; border-color: var(--accent); }
@media (max-width: 1000px) {
  :root { --sidebar-width: 280px; }
}
.lightbox-nav .icon { width: 22px; height: 22px; }
.lightbox-next .icon { transform: rotate(180deg); }
.emoji-panel-search .icon { width: 15px; height: 15px; color: var(--text-tertiary); flex: 0 0 auto; }
.pinned-bar-close .icon { width: 14px; height: 14px; }
.audio-bar-btn .icon { width: 14px; height: 14px; }
.audio-bar-close .icon { width: 14px; height: 14px; }
.admin-tab-btn .icon { flex: 0 0 auto; }
.settings-avatar-row .btn { width: auto; padding: 0 var(--space-4); height: 34px; }
.admin-pager-next .icon { transform: rotate(180deg); }
.admin-confirm-overlay, .admin-secret-overlay, .admin-form-overlay { z-index: 250; padding-top: 16vh; }
.admin-confirm-modal, .admin-secret-modal, .admin-form-modal { padding: var(--space-5); max-height: 80vh; overflow-y: auto; gap: var(--space-3); display: flex; flex-direction: column; width: 420px; }
.admin-confirm-title { font-size: 16px; font-weight: 700; }
.admin-form { display: flex; flex-direction: column; gap: var(--space-3); }
.admin-field { gap: 6px; }
.admin-form-error,
.settings-2fa-error { font-size: 12.5px; font-weight: 600; color: var(--danger); }
.admin-form-actions { display: flex; gap: var(--space-3); justify-content: flex-end; }
.admin-form-actions .btn { width: auto; padding: 0 var(--space-5); }
.new-chat-hint {
  font-size: 12.5px;
  color: var(--text-secondary);
  line-height: 1.5;
  background: var(--bg-elevated);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
}
.new-chat-chip-remove .icon { width: 12px; height: 12px; }
.admin-audit-back .icon { width: 16px; height: 16px; }
@media (max-width: 900px) {
  .admin-confirm-modal, .admin-secret-modal, .admin-form-modal, .admin-csv-modal { width: 100%; max-width: calc(100vw - 32px); }
}
.voice-play .icon { width: 16px; height: 16px; }
.voice-play .icon { transform: rotate(0deg); }
@keyframes recording-pulse { 50% { opacity: 0.25; } }
.call-overlay {
  position: fixed; inset: 0; z-index: 60;
  background: var(--bg-app);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-3);
  /* Nothing in a call may paint outside the window: whatever else goes wrong
     with sizing, the controls stay the last row ON the screen. */
  overflow: hidden;
}
.call-actions { flex: none; }
.call-share-stage, .call-grid { min-height: 0; }
.call-status { font-size: 14px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.call-actions { display: flex; gap: var(--space-4); margin-top: var(--space-2); }
.call-btn {
  width: 56px; height: 56px; border-radius: 50%; border: none; cursor: pointer;
  background: var(--bg-elevated); color: var(--text-primary);
  display: flex; align-items: center; justify-content: center;
}
.call-btn .icon { width: 22px; height: 22px; }
.call-btn--off { background: var(--text-tertiary); color: var(--bg-app); }
.call-btn--end { background: var(--danger); color: #fff; }
.call-grid {
  display: grid;
  gap: var(--space-2);
  width: min(92vw, 960px);
  grid-template-columns: 1fr;
}
.call-grid[data-count="2"] { grid-template-columns: repeat(2, 1fr); }
.call-grid[data-count="3"],
.call-grid[data-count="4"] { grid-template-columns: repeat(2, 1fr); }
.call-grid[data-count="5"],
.call-grid[data-count="6"] { grid-template-columns: repeat(3, 1fr); }
.call-grid:not([data-count="1"]):not([data-count="2"]):not([data-count="3"]):not([data-count="4"]):not([data-count="5"]):not([data-count="6"]) {
  grid-template-columns: repeat(4, 1fr);
}
.call-tile {
  position: relative;
  aspect-ratio: 4 / 3;
  background: #000;
  border-radius: var(--radius-md);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.call-tile-video { width: 100%; height: 100%; object-fit: cover; display: block; }
.call-tile-avatar { position: absolute; }
.call-tile-name {
  position: absolute;
  left: var(--space-2);
  bottom: var(--space-2);
  padding: 2px 8px;
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 13px;
  max-width: calc(100% - var(--space-4));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.call-tile--self .call-tile-video { transform: scaleX(-1); }
.call-tile--speaking { outline: 3px solid var(--accent); outline-offset: -3px; }
.call-tile-hand {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  font-size: 20px;
  line-height: 1;
  padding: 4px 6px;
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.55);
}
.call-tile-hand[hidden] { display: none; }
.call-tile--hand { outline: 2px solid #f0b429; outline-offset: -2px; }
.call-tile--speaking.call-tile--hand { outline-color: var(--accent); }
.call-share-stage {
  position: relative;
  width: min(92vw, 960px);
  max-height: 52vh;
  background: #000;
  border-radius: var(--radius-md);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.call-share-stage[hidden] { display: none; }
.call-share-video {
  width: 100%;
  max-height: 52vh;
  /* `contain`, never `cover`: a screen is text, and cropping the edges off a
     terminal or a slide is worse than letterboxing it. */
  object-fit: contain;
  display: block;
}
.call-share-full {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-md);
  color: #fff;
  background: rgba(0, 0, 0, 0.55);
  opacity: 0;
  transition: opacity 120ms ease;
}
.call-share-stage:hover .call-share-full,
.call-share-full:focus-visible { opacity: 1; }
.call-share-full:hover { background: rgba(0, 0, 0, 0.75); }
.call-share-full .icon { width: 18px; height: 18px; }
.call-overlay:fullscreen { padding: 0; justify-content: center; }
.call-overlay:fullscreen .call-share-stage {
  width: 100vw;
  max-height: calc(100vh - 140px);
  border-radius: 0;
}
.call-overlay:fullscreen .call-share-video { max-height: calc(100vh - 140px); }
.screen-pick-modal { width: min(880px, 92vw); }
.screen-pick-body { max-height: 60vh; overflow-y: auto; margin: var(--space-4) 0; }
.screen-pick-section {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary);
  margin: var(--space-4) 0 var(--space-2);
}
.screen-pick-section:first-child { margin-top: 0; }
.screen-pick-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: var(--space-3);
}
.screen-pick-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-2);
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  text-align: left;
  width: 100%;
}
.screen-pick-item:hover, .screen-pick-item:focus-visible {
  background: var(--bg-hover);
  border-color: var(--border-strong);
}
.screen-pick-thumb {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: contain;
  background: #000;
  border-radius: var(--radius-sm);
  display: block;
}
.screen-pick-thumb--empty {
  display: grid;
  place-items: center;
  font-size: 12px;
  color: var(--text-secondary);
  background: var(--bg-input);
}
.screen-pick-label { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.screen-pick-icon { width: 16px; height: 16px; flex: none; }
.screen-pick-name {
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.call-share-stage:not([hidden]) ~ .call-grid {
  display: flex;
  flex-wrap: nowrap;
  justify-content: center;
  height: 22vh;
  max-height: 22vh;
  overflow-x: auto;
  overflow-y: hidden;
}
.call-share-stage:not([hidden]) ~ .call-grid .call-tile {
  aspect-ratio: 16 / 9;
  height: 100%;
  flex: 0 0 auto;
}
.call-btn--on { background: var(--accent); color: #fff; }
.settings-notif-row .btn[hidden] { display: none; }
.btn--outline {
  width: auto;
  padding: 0 var(--space-5);
  background: var(--bg-input);
  border: 1px solid var(--border-strong);
}
.btn--outline:hover { background: var(--bg-hover); }
.btn--outline:disabled { opacity: 0.6; cursor: default; }
.call-btn--recording { background: var(--danger); color: #fff; }
.call-toast {
  position: fixed; left: 50%; bottom: 32px; transform: translateX(-50%); z-index: 70;
  max-width: min(90vw, 480px);
  background: var(--bg-elevated); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: var(--space-3) var(--space-4); font-size: 13px; line-height: 1.5;
  box-shadow: 0 8px 24px rgba(0,0,0,0.35);
}
.info-media-photo-fallback .icon { width: 28px; height: 28px; }
.info-media-play .icon { width: 12px; height: 12px; }
.ticks--clock .icon { width: 12px; height: 12px; }
.send-files-remove .icon { width: 11px; height: 11px; }
.send-files-checkbox .icon { width: 12px; height: 12px; color: #fff; }
.send-files-emoji .icon { width: 18px; height: 18px; }
.send-files-actions .btn { width: auto; padding: 6px 16px; }
.send-files-row .icon { flex: none; color: var(--accent); }
.menu-readby .icon { flex: none; width: 14px; height: 14px; margin-top: 1px; }
.scheduled-chip .icon { width: 15px; height: 15px; flex: none; }
.poll-option-mark .icon { width: 14px; height: 14px; color: var(--accent); }
.settings-2fa-secret .btn { width: auto; flex: none; }
.chat-row-menu .menu-item .icon { width: 20px; height: 20px; flex: 0 0 20px; }
.modal-overlay .btn,
.admin-form-overlay .btn,
.admin-confirm-overlay .btn,
.admin-secret-overlay .btn {
  height: 34px;
  padding: 0 var(--space-4);
  background: transparent;
  border: none;
  color: var(--accent);
  font-size: 14px;
  font-weight: 600;
}
.modal-overlay .btn:hover,
.admin-form-overlay .btn:hover,
.admin-confirm-overlay .btn:hover,
.admin-secret-overlay .btn:hover { background: var(--bg-hover); }
.modal-overlay .btn--danger,
.admin-form-overlay .btn--danger,
.admin-confirm-overlay .btn--danger,
.admin-secret-overlay .btn--danger { color: var(--danger); background: transparent; }
.panel-pin .icon { width: 15px; height: 15px; }
.catalogue-actions .btn { width: auto; padding: 6px 14px; }
.catalogue-chosen-remove .icon { width: 10px; height: 10px; }
.settings-form .admin-form-actions { justify-content: flex-end; }
.manage-photo-cam .icon { width: 12px; height: 12px; }
@keyframes kb-spin { to { transform: rotate(360deg); } }
.confirm-overlay { z-index: 200; }
.confirm-box {
  width: 340px;
  max-width: calc(100vw - 32px);
  background: var(--bg-panel);
  border-radius: 12px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, .45);
  padding: 18px 20px 10px;
}
.confirm-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.confirm-avatar { width: 40px; height: 40px; flex: 0 0 auto; font-size: 15px; }
.confirm-title { font-size: 16px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.confirm-text { font-size: 14px; line-height: 1.45; color: var(--text-primary); white-space: pre-line; }
.confirm-check-row {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  margin-top: 14px; font-size: 14px; color: var(--text-primary);
}
.confirm-check {
  width: 20px; height: 20px; flex: 0 0 auto; border-radius: 4px;
  border: 2px solid var(--border-strong); display: grid; place-items: center;
  color: transparent;
}
.confirm-check-row--on .confirm-check { background: var(--accent); border-color: var(--accent); color: #fff; }
.confirm-check .icon { width: 13px; height: 13px; }
.confirm-actions { display: flex; justify-content: flex-end; gap: 4px; margin-top: 16px; }
.confirm-btn {
  width: auto; padding: 9px 16px; background: transparent;
  color: var(--accent); font-size: 14px; font-weight: 600;
}
.confirm-btn:hover { background: var(--bg-hover); }
.confirm-overlay .confirm-btn--danger { color: var(--danger); }
.confirm-overlay .confirm-btn { font-size: 14px; height: auto; padding: 9px 16px; }
/* Главный экран: панель действий, фильтры и ТАБЛИЦА комнат.
 *
 * ⚑ 31.08.2026 карточки заменены строками — комнат у человека бывает порядка
 * тысячи (почему именно так, написано в шапке public/js/ui/rooms.js). Отсюда
 * всё в этом блоке: строка в 40 px вместо карточки в 76, колонки постоянной
 * ширины, чтобы глаз шёл вниз по одной вертикали, разделители вместо отступов
 * и СВОЯ область прокрутки у таблицы — заголовок, поиск и счётчик не должны
 * уезжать вверх, пока листают тысячу строк.
 */
.rooms-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6) var(--space-6);
}
.rooms-toolbar { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; flex: 0 0 auto; }
.rooms-title {
  margin: 0; flex: 1 1 auto; min-width: 0;
  display: flex; align-items: baseline; gap: var(--space-2);
  font-size: 20px; font-weight: 700;
}
.rooms-count { font-size: 13px; font-weight: 400; color: var(--text-tertiary); }
.rooms-toolbar-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.rooms-code-input { width: 160px; }
.rooms-btn { width: auto; padding: 0 var(--space-4); height: 38px; white-space: nowrap; }
/* У .btn нет своего фона вовсе: в плотной строке «просто текст» не читается
   как то, на что можно нажать. */
.rooms-btn:not(.btn--primary) { background: var(--bg-input); border: 1px solid var(--border-strong); }
.rooms-btn:not(.btn--primary):hover { background: var(--bg-hover); }
.rooms-btn--sm { height: 32px; padding: 0 12px; font-size: 13px; }
.rooms-btn--go, .rooms-btn--go:not(.btn--primary) {
  background: var(--accent-soft); border-color: transparent; color: var(--accent);
}
.rooms-btn--go:not(.btn--primary):hover { background: rgba(78, 164, 245, 0.24); }
/* Отзыв ссылки стоит в том же ряду, что и «открыть»: тихим до наведения на
   него самого, чтобы разрушительное действие не выглядело как соседнее. */
.rooms-btn--danger, .rooms-btn--danger:not(.btn--primary) {
  margin-top: 0; background: transparent; border: 1px solid transparent; color: var(--danger);
}
.rooms-btn--danger:not(.btn--primary):hover { background: rgba(242, 85, 90, 0.1); border-color: var(--danger); }

.rooms-filters { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; flex: 0 0 auto; }
.rooms-search {
  flex: 0 1 340px; min-width: 180px; height: 36px;
  background: var(--bg-input);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  padding: 0 var(--space-3);
  color: var(--text-primary);
  font-size: 14px;
}
.rooms-search::placeholder { color: var(--text-tertiary); }
.rooms-search:focus { outline: none; border-color: var(--accent); }
.rooms-chips { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.rooms-chip {
  height: 28px; padding: 0 12px; border-radius: 14px;
  font-size: 12.5px; font-weight: 600; color: var(--text-secondary);
}
.rooms-chip:hover { background: var(--bg-hover); }
.rooms-chip--on { background: var(--accent-soft); color: var(--accent); }

.rooms-table {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg-panel);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.rooms-thead, .rooms-row { display: flex; align-items: center; gap: var(--space-4); padding: 0 var(--space-4); }
.rooms-thead {
  flex: 0 0 auto;
  height: 32px;
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-tertiary);
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
}
.rooms-col-name { flex: 1 1 auto; min-width: 0; }
.rooms-col-code { flex: 0 0 120px; }
.rooms-col-link { flex: 0 0 104px; }
.rooms-col-access { flex: 0 0 104px; }
.rooms-col-tail { flex: 0 0 300px; }
.rooms-thead .rooms-col-tail { text-align: right; }
.rooms-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
/* Заголовок группы липкий: пролистав триста строк, человек обязан видеть, ЧТО
   он листает, — иначе «идут сейчас» и «все комнаты» различимы только по цвету
   строки. */
.rooms-group {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: 28px;
  padding: 0 var(--space-4);
  background: var(--bg-app);
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
}
.rooms-group-n { color: var(--text-tertiary); }
.rooms-row {
  height: 40px;
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  font-size: 12.5px;
}
.rooms-row:hover, .rooms-row--open { background: var(--bg-hover); }
.rooms-row--live { background: rgba(78, 164, 245, 0.08); }
.rooms-row--live:hover { background: rgba(78, 164, 245, 0.14); }
.rooms-row-name { display: flex; align-items: center; gap: 9px; }
.rooms-row-title {
  font-size: 14px; font-weight: 600; color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rooms-row--dead .rooms-row-title { color: var(--text-secondary); }
.rooms-dot {
  width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
  background: var(--presence-online);
  box-shadow: 0 0 0 3px rgba(67, 181, 129, 0.18);
}
/* Место под точку занято ВСЕГДА: иначе названия комнат стоят на двух разных
   вертикалях — с идущей встречей и без, — и колонка перестаёт читаться
   сверху вниз. */
.rooms-dot--off { background: transparent; box-shadow: none; }
.rooms-row-code {
  font-family: var(--font-mono, ui-monospace, Consolas, monospace);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rooms-row-link { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rooms-row--dead .rooms-row-link { color: var(--danger); font-weight: 600; }
.rooms-row-access { white-space: nowrap; }
/* Кто может войти по ссылке — единственное на строке, что стоит цвета: это
   ответ на «а не пустит ли она постороннего». */
.rooms-row-access--guests { color: #f0b429; font-weight: 600; }
.rooms-row-tail { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-2); }
.rooms-row-slot { position: relative; flex: 1 1 auto; min-width: 0; display: flex; align-items: center; justify-content: flex-end; }
.rooms-row-when { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rooms-row-when--live { color: var(--presence-online); font-weight: 600; }
/* Действия занимают место «последней встречи» и появляются на наведении.
   ⚑ visibility, а не display: место под них занято всегда, поэтому строки не
   дёргаются, когда мышь идёт вниз по списку. */
.rooms-row-actions {
  position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  display: flex; align-items: center; gap: 6px;
  visibility: hidden;
}
/* ⚑ Подмена «последней встречи» действиями — ТОЛЬКО там, где мышь есть. На
   тач-экране :hover срабатывает от касания и залипает: строка, по которой
   ткнули, теряла бы дату и показывала ряд кнопок, в который человек не целился.
   Там вместо ряда — одна кнопка «⋯» и лист снизу. */
@media (hover: hover) {
  .rooms-row:hover .rooms-row-when,
  .rooms-row:focus-within .rooms-row-when { visibility: hidden; }
  .rooms-row:hover .rooms-row-actions,
  .rooms-row:focus-within .rooms-row-actions { visibility: visible; }
}
/* «Войти» у идущей встречи видно ВСЕГДА и она стоит вне подменяемой ячейки:
   это единственное действие, ради которого на этот экран приходят срочно. */
.rooms-row-join { flex: 0 0 auto; }
.rooms-sentinel { height: 1px; }
.rooms-empty { color: var(--text-tertiary); font-size: 13px; padding: var(--space-4); }
.rooms-foot {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  height: 36px;
  padding: 0 var(--space-4);
  border-top: 1px solid var(--border-subtle);
  background: var(--bg-app);
  color: var(--text-tertiary);
  font-size: 12px;
}

/* Того, что ниже, на широком экране с мышью нет вовсе: вторая строка под
   названием, кнопка «⋯», нижняя панель. Появляются они только там, где нужны, —
   см. два медиазапроса в конце файла. */
.rooms-row-lines { min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 3px; }
.rooms-row-sub { display: none; }
.rooms-row-more { display: none; }
.rooms-bar { display: none; }

/* Нижний лист: всё, что не помещается в строку на телефоне.
   ⚑ Не confirmBox: тот спрашивает «да/нет» по центру экрана, а здесь нужен
   список действий у нижнего края, куда достаёт большой палец. */
.rooms-sheet-overlay {
  position: fixed;
  inset: 0;
  z-index: 110;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.rooms-sheet {
  width: min(520px, 100%);
  max-height: 80vh;
  overflow-y: auto;
  background: var(--bg-panel);
  border-top: 1px solid var(--border-strong);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: 0 -12px 32px rgba(0, 0, 0, 0.45);
  display: flex;
  flex-direction: column;
  /* Вырез под жест «домой» на телефоне: без этого последняя строка листа
     оказывается ровно под полосой, которой закрывают приложение. */
  padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
}
.rooms-sheet-grip { width: 36px; height: 4px; border-radius: 2px; background: var(--border-strong); margin: 8px auto 4px; }
.rooms-sheet-head {
  padding: 8px var(--space-5) 14px;
  display: flex; flex-direction: column; gap: 4px;
  border-bottom: 1px solid var(--border-subtle);
}
.rooms-sheet-title { font-size: 16px; font-weight: 700; }
.rooms-sheet-sub { font-family: var(--font-mono, ui-monospace, Consolas, monospace); font-size: 13px; color: var(--text-secondary); }
/* 56 px: строка листа — это цель для пальца, а не для курсора. */
.rooms-sheet-item {
  height: 56px;
  padding: 0 var(--space-5);
  display: flex;
  align-items: center;
  font-size: 15.5px;
  text-align: left;
  color: var(--text-primary);
}
.rooms-sheet-item:hover { background: var(--bg-hover); }
.rooms-sheet-item--go { color: var(--accent); font-weight: 600; }
.rooms-sheet-item--danger { color: var(--danger); }
.rooms-sheet-sep { height: 1px; margin: 6px var(--space-5); background: var(--border-subtle); }
.rooms-sheet-form { display: flex; gap: var(--space-2); padding: var(--space-4) var(--space-5) var(--space-2); }
.rooms-sheet-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 48px;
  background: var(--bg-input);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  padding: 0 var(--space-3);
  color: var(--text-primary);
  /* 🔴 16px, а не 15: Safari на айфоне ЗУМИТ страницу на фокусе в поле с
     меньшим шрифтом, и человек проваливается в увеличенный экран, из которого
     потом выбирается руками. */
  font-size: 16px;
}
.rooms-sheet-input:focus { outline: none; border-color: var(--accent); }
.rooms-sheet-go { width: auto; flex: 0 0 auto; height: 48px; padding: 0 var(--space-5); }

/* Тач без мыши (телефон, планшет, тач-ноутбук): ряд кнопок на наведении
   недостижим, поэтому его нет, а есть «⋯». */
@media (hover: none) {
  .rooms-row-actions { display: none; }
  .rooms-row-more { display: flex; }
}

/* Телефон. Колонок нет — вместо них вторая строка под названием; заголовок с
   его кнопками уезжает вниз, под большой палец. */
@media (max-width: 760px) {
  .meet-head { height: 52px; padding: 0 16px; }
  /* Имя не нужно: кто вошёл, говорит кружок, а место на 375 px дорогое. */
  .meet-me { display: none; }
  .meet-main > .rooms-body { padding: 0; gap: 0; }

  .rooms-toolbar { display: none; }
  .rooms-filters {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    padding: 12px 16px 10px;
    border-bottom: 1px solid var(--border-subtle);
  }
  .rooms-search { flex: 0 0 auto; max-width: none; height: 40px; font-size: 16px; }
  /* Фильтры прокручиваются вбок, а не переносятся: перенос съедает вторую
     строку экрана ради четырёх слов. */
  .rooms-chips { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .rooms-chips::-webkit-scrollbar { display: none; }
  .rooms-chip { flex: 0 0 auto; height: 32px; padding: 0 14px; font-size: 13px; }
  .rooms-entry { padding: 12px 16px 0; }

  .rooms-table { border: none; border-radius: 0; background: transparent; }
  .rooms-thead { display: none; }
  /* Счётчик внизу — десктопная мебель: числа и так стоят в заголовках групп. */
  .rooms-foot { display: none; }
  .rooms-col-code, .rooms-col-link, .rooms-col-access { display: none; }
  .rooms-row-when { display: none; }

  .rooms-row { height: 64px; gap: 12px; padding: 0 4px 0 16px; }
  .rooms-row-title { font-size: 15.5px; }
  .rooms-row-sub {
    display: block;
    font-size: 13px;
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .rooms-row-sub--live { color: var(--presence-online); font-weight: 600; }
  /* Мёртвая ссылка красная и во второй строке тоже: на широком экране это
     отдельная колонка, и терять её цвет при переходе на телефон — значит
     терять единственное, что об этой комнате нужно знать. */
  .rooms-row-sub-dead { color: var(--danger); font-weight: 600; }
  .rooms-col-tail { flex: 0 0 auto; gap: 4px; }
  .rooms-row-slot { position: static; flex: 0 0 auto; }
  .rooms-row-more { width: 44px; height: 44px; border-radius: 22px; color: var(--text-secondary); align-items: center; justify-content: center; flex: 0 0 auto; }
  .rooms-row-more .icon { width: 20px; height: 20px; }
  .rooms-row-join { height: 40px; border-radius: 20px; padding: 0 18px; font-size: 14px; }
  .rooms-history { padding: var(--space-3) 16px; }

  .rooms-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 0 0 auto;
    padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px));
    background: var(--bg-panel);
    border-top: 1px solid var(--border-subtle);
  }
  .rooms-bar-code { width: auto; flex: 0 0 auto; height: 48px; padding: 0 18px; border-radius: 12px; background: var(--bg-input); border: 1px solid var(--border-strong); font-size: 15px; }
  .rooms-bar-new { flex: 1 1 auto; height: 48px; border-radius: 12px; font-size: 15px; }
}
.rooms-entry { flex: 0 0 auto; }
.rooms-entry-card {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
  background: var(--accent-soft);
}
.rooms-entry-main { flex: 1 1 auto; min-width: 0; }
.rooms-entry-name { font-weight: 700; font-size: 16px; }
.rooms-entry-people {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: 6px;
  color: var(--text-secondary);
  font-size: 13px;
}
.rooms-entry-empty { color: var(--text-tertiary); }
.rooms-entry-loading { color: var(--text-secondary); font-size: 13px; }
.rooms-entry-dead {
  padding: var(--space-4);
  border: 1px solid var(--danger);
  border-radius: var(--radius-md);
  color: var(--danger);
  font-size: 13.5px;
}
.rooms-stack { display: flex; }
.rooms-stack-avatar {
  width: 26px; height: 26px; font-size: 11px;
  border: 2px solid var(--bg-app);
  margin-left: -8px;
}
.rooms-stack-avatar:first-child { margin-left: 0; }
.rooms-options { display: flex; flex-direction: column; gap: var(--space-2); margin: var(--space-3) 0; }
.rooms-option {
  display: flex;
  gap: var(--space-3);
  width: 100%;
  text-align: left;
  padding: 12px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: transparent;
  height: auto;
}
.rooms-option--on { border-color: var(--accent); background: var(--accent-soft); }
.rooms-radio {
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid var(--text-tertiary);
  flex: 0 0 auto;
  margin-top: 2px;
}
.rooms-option--on .rooms-radio { border-color: var(--accent); box-shadow: inset 0 0 0 3px var(--accent); }
.rooms-option-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.rooms-option-title { font-weight: 600; font-size: 13.5px; color: var(--text-primary); }
.rooms-option-hint { color: var(--text-secondary); font-size: 12.5px; line-height: 1.45; white-space: normal; }
.rooms-form-note { color: var(--text-tertiary); font-size: 12px; line-height: 1.45; margin-bottom: var(--space-2); }
.rooms-toast {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translateX(-50%);
  z-index: 200;
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-panel);
  padding: 10px 16px;
  font-size: 13.5px;
}
.call-room-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
}
.call-lobby {
  /* Floated over the tiles rather than stacked above them, and that is a fix,
     not a preference: as a flex child it grew the overlay's column until the
     controls at the bottom — Remove among them — sat outside the viewport.
     Every computed style was correct and the button could not be clicked,
     which is the failure that looks like nothing at all. */
  position: absolute;
  top: var(--space-3);
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  width: min(90vw, 420px);
  max-height: 40vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.call-lobby[hidden] { display: none; }
.call-lobby-card {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 10px 14px;
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  border: 1px solid #f0b429; /* the same amber the raised-hand outline uses: "needs a person" */
  box-shadow: var(--shadow-panel);
}
.call-lobby-card--in { border-color: var(--border-strong); }
.call-lobby-main { flex: 1 1 auto; min-width: 0; }
.call-lobby-name { font-weight: 600; font-size: 13.5px; }
.call-lobby-sub { color: var(--text-secondary); font-size: 12px; margin-top: 2px; }
.call-lobby-actions { display: flex; gap: var(--space-2); flex: 0 0 auto; }
.call-lobby-btn { width: auto; height: 32px; padding: 0 12px; font-size: 13px; }
.call-tile-guest {
  margin-left: 6px;
  padding: 1px 5px;
  border-radius: 4px;
  background: #f0b429;
  color: #20160a;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.guest-page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-app);
  color: var(--text-primary);
}
.guest-bar {
  flex: 0 0 auto;
  height: 52px;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 0 var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-panel);
  font-weight: 700;
}
.guest-room-name { color: var(--text-secondary); font-weight: 400; }
.guest-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 44px;
  flex-wrap: wrap;
  padding: var(--space-6);
}
.guest-preview {
  position: relative;
  width: min(90vw, 520px);
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
  background: #0a0f15;
  border: 1px solid var(--border-strong);
  overflow: hidden;
}
.guest-preview-video {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transform: scaleX(-1); /* your own camera, mirrored, as every video app does */
}
.guest-preview-placeholder {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: var(--text-tertiary); font-size: 13px;
}
.guest-preview-placeholder[hidden] { display: none; }
.guest-preview-bar {
  position: absolute; left: 0; right: 0; bottom: 12px;
  display: flex; justify-content: center; gap: var(--space-3);
}
/* Строка про устройства над кнопками превью: «микрофон недоступен — можно
   войти слушателем» / «браузер спрашивает микрофон». Та же роль, что у
   j-prejoin-ok у сотрудника. */
.guest-preview-note {
  position: absolute; left: 12px; right: 12px; bottom: 60px;
  text-align: center; color: var(--text-secondary); font-size: 12.5px; line-height: 1.4;
  text-shadow: 0 1px 2px rgba(0,0,0,.8);
}
.guest-preview-note--warn { color: #f0b429; }
.guest-preview-note[hidden] { display: none; }
.guest-side { width: min(90vw, 340px); }
.guest-title { font-size: 22px; margin: 0 0 6px; }
.guest-sub { color: var(--text-secondary); font-size: 13.5px; margin: 0 0 20px; line-height: 1.5; }
.guest-label { display: block; color: var(--text-secondary); font-size: 12.5px; margin-bottom: 6px; }
.guest-form[hidden], .guest-waiting[hidden], .guest-dead[hidden] { display: none; }
.guest-join-btn { width: 100%; justify-content: center; height: 44px; margin-top: var(--space-3); }
.guest-note { color: var(--text-tertiary); font-size: 12px; line-height: 1.5; margin-top: var(--space-3); }
.guest-waiting {
  display: flex; align-items: center; gap: var(--space-3);
  color: var(--text-secondary); font-size: 13.5px;
}
.guest-spinner {
  width: 18px; height: 18px; flex: 0 0 auto;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
  border-top-color: var(--accent);
  animation: guest-spin 0.9s linear infinite;
}
@keyframes guest-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .guest-spinner { animation: none; }
}
.guest-dead {
  padding: var(--space-4);
  border: 1px solid var(--danger);
  border-radius: var(--radius-md);
  color: var(--danger);
  font-size: 13.5px;
}
.guest-employee { margin-top: var(--space-6); color: var(--text-tertiary); font-size: 12.5px; }
.guest-employee a { color: var(--accent); }
.rooms-guests-row { display: flex; align-items: flex-start; gap: var(--space-3); margin: var(--space-3) 0 var(--space-2); }
.rooms-switch {
  width: 38px; height: 22px; flex: 0 0 auto; margin-top: 2px;
  border-radius: 11px; background: var(--border-strong);
  position: relative; padding: 0; border: none;
}
.rooms-switch-knob {
  position: absolute; top: 3px; left: 3px;
  width: 16px; height: 16px; border-radius: 50%;
  background: #8fa3b5;
  transition: left 0.12s ease, background 0.12s ease;
}
.rooms-switch--on { background: var(--accent); }
.rooms-switch--on .rooms-switch-knob { left: 19px; background: #fff; }
/* История встреч комнаты. Раскрывается СЛЕДУЮЩЕЙ строкой под своей комнатой, а
   не внутри неё: строка — это одна линия из пяти колонок, и вложенный список
   встреч растянул бы колонки всех соседей. */
.rooms-history {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-app);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.rooms-history-loading { color: var(--text-secondary); font-size: 12.5px; }
.rooms-meeting {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--bg-input);
}
.rooms-meeting-when {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: 12.5px;
  font-weight: 600;
}
.rooms-meeting-dur { color: var(--text-secondary); font-weight: 400; }
.rooms-meeting-guests {
  color: #f0b429;
  font-weight: 700;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.rooms-meeting-who {
  color: var(--text-secondary);
  font-size: 12.5px;
  /* A long roster must not stretch the card sideways. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rooms-meeting-audio { width: 100%; max-width: 420px; margin-top: 4px; }
/* Сетка лиц: 16:9, и не во всю ширину списка — это запись прошедшей встречи, а
   не сама встреча. */
.rooms-meeting-video {
  width: 100%; max-width: 420px; margin-top: 4px;
  aspect-ratio: 16 / 9; background: #000;
  border-radius: var(--radius-sm);
}
.rooms-meeting-wip { color: var(--text-secondary); font-size: 12px; }
.rooms-meeting-norec { color: var(--danger); font-size: 12px; }

/* ---------------------------------------------------------------------------
 * Оболочка meet405
 *
 * Единственное, что здесь дописано руками поверх вырезанного из chat405:
 * шапка приложения, экран входа и полоса «нет связи». Всё остальное — комнаты,
 * встреча, гостевая страница, коробка подтверждения, пикер экрана — приехало
 * со своими стилями и не трогалось.
 * ------------------------------------------------------------------------- */

.meet-body {
  margin: 0;
  background: var(--bg-app);
  color: var(--text-primary);
  font-family: var(--font-sans);
}

/* Высота ОКНА, а не «не меньше окна»: список комнат прокручивается внутри
   себя, и чтобы у него была своя область прокрутки, у оболочки должна быть
   конечная высота. */
.meet-app {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.meet-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 20px;
  height: 56px;
  background: var(--bg-sidebar);
  border-bottom: 1px solid var(--border-subtle);
  flex: 0 0 auto;
}

.meet-brand {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--text-primary);
}

.meet-head-spacer { flex: 1 1 auto; }

.meet-me {
  font-size: 14px;
  color: var(--text-secondary);
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 🔴 width: auto ОБЯЗАТЕЛЕН. У .btn ширина 100% — она нужна кнопке в форме и
   разрушительна в шапке: кнопка «Выйти» получала базой всю ширину строки,
   ужималась флексом до середины и стояла посреди пустой шапки, а имя человека
   при этом обрезалось до «Mat…». Ровно это и было видно на проде. */
.meet-signout, .meet-upgrade { width: auto; flex: 0 0 auto; }
.meet-signout { padding: 6px 14px; font-size: 13px; }

/* Кто вошёл: кружок с инициалами и имя. Тот же кружок, что в ростере встречи, —
   один человек выглядит одинаково везде, где он назван. */
.meet-who { display: flex; align-items: center; gap: 9px; min-width: 0; flex: 0 1 auto; }
.meet-avatar { width: 28px; height: 28px; font-size: 11px; }

/* Прокручивается не главная область, а таблица внутри неё: заголовок, поиск и
   счётчик обязаны стоять на месте, пока листают тысячу строк. */
.meet-main {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  display: flex;
  justify-content: center;
}

/* Предел ширины: пять колонок, растянутые на 27 дюймов, читаются хуже, а не
   лучше — глазу нечем связать имя комнаты с её последней встречей. */
.meet-main > .rooms-body { width: 100%; max-width: 1200px; }

/* Вход. Одна кнопка — пароля у этого приложения нет вовсе. */
.meet-login {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.meet-login-card {
  width: min(360px, 100%);
  text-align: center;
  background: var(--bg-panel);
  border: 1px solid var(--border-subtle);
  border-radius: 14px;
  padding: 36px 28px;
}

.meet-login-card .meet-brand { font-size: 24px; display: block; margin-bottom: 6px; }

.meet-login-sub {
  margin: 0 0 24px;
  color: var(--text-secondary);
  font-size: 14px;
}

.meet-login-btn {
  display: inline-block;
  text-decoration: none;
  padding: 10px 22px;
}

/* Причина неудачного входа. Красным и словами: молча показанная кнопка «Войти»
   после отказа — это круг, в котором человек жмёт одно и то же. */
.meet-login-note {
  margin: 18px 0 0;
  font-size: 13px;
  color: #e8737a;
  line-height: 1.45;
}

.meet-offline {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 60;
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  color: var(--text-primary);
  border-radius: 999px;
  padding: 8px 18px;
  font-size: 13px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
}

/* Быстрое создание встречи без входа (26.08.2026). Второй путь на экране входа,
   и он СВЕРХУ: это то, зачем сюда чаще всего приходят. */
.meet-quick {
  display: flex;
  flex-direction: column;
  gap: 10px;
  text-align: left;
}

.meet-quick-label {
  font-size: 12px;
  color: var(--text-secondary);
}

.meet-quick-hint {
  margin: 0;
  font-size: 12px;
  color: var(--text-tertiary);
  text-align: center;
}

/* Разделитель «or»: линия, разорванная словом. Без него две кнопки подряд
   читаются как «одна из них главная, а вторая непонятно зачем». */
.meet-or {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 18px 0 14px;
  color: var(--text-tertiary);
  font-size: 12px;
}

.meet-or::before,
.meet-or::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: var(--border-strong);
}

.meet-upgrade { padding: 6px 14px; font-size: 13px; text-decoration: none; }

/* Выбор устройств во встрече (27.08.2026).
 *
 * Борис на первой живой встрече: «не хватает возможности выбрать источник
 * звука, видео». Панель всплывает НАД строкой кнопок и внутри оверлея — не
 * отдельным экраном: её открывают ровно тогда, когда идёт разговор, и уходить
 * из него ради настроек нельзя. */
.call-devices {
  position: absolute;
  left: 50%;
  bottom: 92px;
  transform: translateX(-50%);
  z-index: 30;
  min-width: 260px;
  max-width: min(360px, 90vw);
  /* Устройств может быть много — список скроллится сам, а не растёт за экран. */
  max-height: min(60vh, 420px);
  overflow-y: auto;
  padding: 8px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55);
}

.call-devices-label {
  padding: 10px 10px 4px;
  font-size: 11px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text-tertiary);
}

.call-devices-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-primary);
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  /* Длинное имя устройства («Микрофон (Realtek(R) Audio)») не должно ломать
     ширину панели: оно переносится, а не растягивает список. */
  overflow-wrap: anywhere;
}

.call-devices-item:hover { background: var(--bg-hover); }
.call-devices-item--on { color: var(--accent); }

/* Галочка занимает своё место ВСЕГДА, даже когда её нет: иначе выбранная
   строка прыгает вбок относительно остальных. */
.call-devices-check {
  flex: 0 0 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.call-devices-check .icon { width: 14px; height: 14px; }

/* 🔴 Плитки не смеют накрывать кнопки.
 *
 * Найдено тестом 27.08.2026: у .call-tile aspect-ratio 4/3, а ширина приходит
 * от сетки (min(92vw, 960px)) — значит ВЫСОТА выводится из ширины и на неё
 * ничто не смотрит. Один участник = плитка 960×720, две строки = 1440, и всё
 * это рисуется поверх строки кнопок: до микрофона, камеры и «выйти» физически
 * не дотянуться.
 *
 * ⚑ Приехало из chat405, где групповой звонок в одиночестве длился секунду и
 * никто не замечал. Здесь ПЕРВЫЙ вошедший в комнату всегда один — и часто ждёт,
 * пока постучатся, — поэтому случай стал обычным, а не краевым.
 *
 * Потолок задаётся по числу плиток, рядом с таблицей колонок выше и в тех же
 * терминах: столько-то плиток — столько-то строк — вот доля экрана на строку.
 * object-fit: cover у видео означает, что чуть более широкая, чем 4:3, плитка
 * по-прежнему выглядит правильно. */
.call-grid { max-height: 100%; align-content: center; }
.call-tile { min-height: 0; }

/* одна строка */
.call-grid[data-count="1"] .call-tile,
.call-grid[data-count="2"] .call-tile { max-height: 62vh; }
/* две строки */
.call-grid[data-count="3"] .call-tile,
.call-grid[data-count="4"] .call-tile,
.call-grid[data-count="5"] .call-tile,
.call-grid[data-count="6"] .call-tile { max-height: 31vh; }
/* три строки и больше */
.call-grid:not([data-count="1"]):not([data-count="2"]):not([data-count="3"]):not([data-count="4"]):not([data-count="5"]):not([data-count="6"]) .call-tile {
  max-height: 22vh;
}

/* Когда кто-то показывает экран, сетка уже сжата до 22vh полосой выше —
   собственный потолок плиток здесь только мешал бы. */
.call-share-stage:not([hidden]) ~ .call-grid .call-tile { max-height: 100%; }

/* ============================================================================
 * СКИН JITSI — 100% сходство (Борис, 27.08.2026: «нужно 100% сходство»).
 *
 * Каждое значение ниже СНЯТО, а не придумано: с живого alpha.jitsi.net
 * (текущий master, computed styles) и meet.jit.si, плюс токены из
 * jitsi/jitsi-meet tokens.json. Рядом с правилом — откуда оно.
 *
 * ⚑ Секция идёт ПОСЛЕ старых правил и побеждает каскадом при той же
 * специфичности. Иконки — фирменные SVG Jitsi (Apache-2.0), заливка, не линия.
 * ========================================================================== */

.call-overlay {
  background: #040404;                 /* largeVideoBg, замер */
  color: #F1F1F1;                      /* базовый текст Jitsi — НЕ чистый белый */
  justify-content: flex-start;
  gap: 0;
}

/* Иконки-заливка: у .icon больше нет обводки. fill сидит на самом символе. */
.icon { stroke: none; fill: currentColor; }

/* ---- тулбар: контейнер #141414, r6, p6, двойная тень; снизу 16px ---- */
.call-actions {
  position: absolute;
  left: 50%; bottom: 16px; transform: translateX(-50%);
  margin: 0;
  background: #141414;
  border-radius: 6px;
  padding: 6px;
  gap: 0;                              /* кнопки впритык, как в замере */
  box-shadow: rgba(0,0,0,.25) 0 2px 8px 4px, rgba(0,0,0,.15) 0 0 0 1px;
  z-index: 20;
}
.call-btn {
  width: 48px; height: 48px;
  border-radius: 3px;                  /* замер: кнопки r3, контейнер r6 */
  background: transparent;
  color: #fff;
}
.call-btn:hover { background: #3D3D3D; }        /* hover05 */
.call-btn .icon { width: 24px; height: 24px; }  /* замер: svg 24×24 */
.call-btn--off { background: transparent; color: #fff; }
.call-btn--on  { background: #525252; color: #fff; }   /* toggled: surface05 */
.call-btn--end {
  background: #CB2233;                 /* замер hangup */
  border-radius: 3px; width: 48px; height: 48px;
  margin-left: 0;
}
.call-btn--end:hover { background: #D83848; }   /* action03 */

/* Пара иконок в одной кнопке: вкл/выкл переключается классом, не перерисовкой. */
.call-btn .icon--on  { display: block; }
.call-btn .icon--off { display: none; }
.call-btn--off .icon--on  { display: none; }
.call-btn--off .icon--off { display: block; }

/* Шеврон над кнопкой — как в Jitsi: маленький ^ у верхней кромки тулбара. */
.t-wrap { position: relative; }
.t-chev {
  position: absolute; top: -10px; right: 2px;
  width: 20px; height: 16px; border: 0; border-radius: 3px;
  background: #141414; color: #fff;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; padding: 0;
}
.t-chev:hover { background: #3D3D3D; }
.t-chev .icon { width: 12px; height: 12px; }
.t-chev--open { background: #525252; }

/* Счётчик участников: белый кружок с тёмной цифрой, как в замере. */
.t-count {
  position: absolute; top: -8px; right: 2px;
  min-width: 16px; height: 16px; border-radius: 8px; padding: 0 4px;
  background: #fff; color: #040404;
  font-size: 11px; font-weight: 600; line-height: 16px; text-align: center;
}

/* ---- имя комнаты + таймер сверху по центру (замер: y=20, h=28) ---- */
.j-subject {
  position: absolute; top: 20px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: stretch; height: 28px;
  border-radius: 3px; overflow: hidden; z-index: 15;
  font-size: 14px;
}
.j-subject-name {
  background: rgba(0,0,0,.6); color: #fff;
  display: flex; align-items: center; padding: 0 12px;
  max-width: 40vw; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.j-subject-timer {
  background: #000; color: #fff;
  display: flex; align-items: center; padding: 0 8px;
  font-size: 12px; font-variant-numeric: tabular-nums;
}

/* ---- сцена (вид «говорящий») + правая плёнка миниатюр ---- */
.j-stage {
  position: absolute; inset: 0; right: 140px;   /* плёнка = 140px, замер */
  display: flex; align-items: center; justify-content: center;
}
.j-stage video { width: 100%; height: 100%; object-fit: contain; display: block; }
.j-stage .avatar--stage {
  width: 200px; height: 200px; border-radius: 50%;   /* замер: аватар 200 */
  font-size: 64px;
}
.j-stage-name {
  position: absolute; left: 12px; bottom: 12px;
  background: rgba(0,0,0,.6); color: #fff; border-radius: 3px;
  padding: 4px 10px; font-size: 13px;
}
/* Плёнка — ОКНО из шести миниатюр (плюс своя), не прокрутка (план C4):
   overflow-y:auto держал бы в DOM полсотни <video>, а прокрученные за край
   всё равно декодируют. Листается ▲▼ пейджером под ней (.j-pager--strip),
   снизу под него оставлено место. */
.j-filmstrip {
  position: absolute; top: 0; right: 0; bottom: 72px; width: 140px;  /* замер */
  display: flex; flex-direction: column; align-items: center;
  padding: 9px; gap: 8px; overflow: hidden; z-index: 10;
}
/* Миниатюра: 122×71, r4 — замер. Переиспользует .call-tile, чтобы тесты и
   подсветки работали в обоих видах без второго набора классов. */
.j-filmstrip .call-tile {
  width: 122px; height: 71px; flex: 0 0 71px;
  aspect-ratio: auto; max-height: none;
  border-radius: 4px;
}
.j-filmstrip .call-tile-name {
  left: 50%; transform: translateX(-50%); bottom: 4px;
  font-size: 12px; font-weight: 600; padding: 0 6px;
  max-width: 114px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.j-filmstrip .call-tile-avatar { width: 40px; height: 40px; font-size: 15px; }
/* В виде «плиткой» сцена и плёнка уходят, сетка остаётся прежней. */
.call-overlay--tiles .j-stage,
.call-overlay--tiles .j-filmstrip { display: none; }
.call-overlay:not(.call-overlay--tiles) .call-grid { display: none; }
.call-overlay--tiles .call-grid {
  position: absolute; inset: 60px 0 90px;
  display: flex; flex-wrap: wrap; align-content: center; justify-content: center;
  width: auto; max-width: none; gap: 8px; padding: 0 16px;
}
/* Плитка 16:9 (замер Jitsi), ширина от числа участников; высота из пропорции,
   потолки по vh оставляют тулбар досягаемым при любом счёте. */
.call-overlay--tiles .call-grid .call-tile {
  aspect-ratio: 16 / 9; height: auto; max-height: none; flex: 0 0 auto;
}
.call-overlay--tiles .call-grid[data-count="1"] .call-tile { width: min(90vw, calc(75vh * 16 / 9)); }
.call-overlay--tiles .call-grid[data-count="2"] .call-tile { width: min(45vw, calc(62vh * 16 / 9)); }
.call-overlay--tiles .call-grid[data-count="3"] .call-tile,
.call-overlay--tiles .call-grid[data-count="4"] .call-tile { width: min(45vw, calc(38vh * 16 / 9)); }
.call-overlay--tiles .call-grid[data-count="5"] .call-tile,
.call-overlay--tiles .call-grid[data-count="6"] .call-tile { width: min(30vw, calc(38vh * 16 / 9)); }
/* Семь и больше — страница 3×3 (я + восемь, план C4), плитка ФИКСИРОВАННАЯ:
   на 1080p это 480×270 (25vh × 16/9), три в ряд с зазорами — 1456 из 1920,
   три ряда — 826 из 930 между шапкой и тулбаром. От data-count больше не
   зависит: на странице их не бывает больше девяти, остальные — «+41 in the
   list» у пейджера. */
.call-overlay--tiles .call-grid:not([data-count="1"]):not([data-count="2"]):not([data-count="3"]):not([data-count="4"]):not([data-count="5"]):not([data-count="6"]) .call-tile,
/* …и на любой странице страничной сетки: последняя страница из четырёх —
   не комната на четверых, плитка та же, что была на предыдущей. */
.call-overlay--tiles .call-grid.call-grid--paged .call-tile {
  width: min(30vw, calc(25vh * 16 / 9));
}

/* ---- пейджер плиток: «‹ 1/6 ›  +41 in the list» (план C4) ----
   В сетке — слева внизу, на уровне тулбара: там пусто при любом числе
   плиток, а под шапкой третий ряд 3×3 на невысоком экране уже начинается. */
.j-pager {
  position: absolute; bottom: 24px; left: 20px;
  display: flex; align-items: center; gap: 6px; z-index: 15;
  font-size: 13px; color: #F1F1F1; font-variant-numeric: tabular-nums;
}
.j-pager[hidden] { display: none; }
.j-pager-btn {
  width: 28px; height: 28px; border: 0; border-radius: 3px; cursor: pointer;
  background: rgba(0,0,0,.6); color: #fff; font-size: 18px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.j-pager-btn:hover { background: #3D3D3D; }
.j-pager-btn:disabled { opacity: .35; cursor: default; }
.j-pager-label { background: rgba(0,0,0,.6); border-radius: 3px; padding: 4px 8px; }
.j-pager-rest { color: #C2C2C2; margin-left: 6px; }
.j-pager-rest[hidden] { display: none; }
/* В плёнке — столбик под миниатюрами: ▲ ▼ в ряд, под ними «2/7» и «+41». */
.j-pager--strip {
  bottom: 12px; left: auto; right: 0;
  width: 140px; flex-wrap: wrap; justify-content: center; gap: 4px 8px;
  font-size: 12px;
}
.j-pager--strip .j-pager-btn { font-size: 12px; width: 32px; height: 24px; }
.j-pager--strip .j-pager-label { order: 1; }
.j-pager--strip .j-pager-rest { order: 2; margin: 0; width: 100%; text-align: center; }
.call-overlay--pane .j-pager--strip { right: 315px; }

/* ---- полоска «Screens: Ivan · Pyotr · You» — две и больше шары ---- */
.j-screens {
  position: absolute; top: 56px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 4px; z-index: 15;
  background: rgba(0,0,0,.6); border-radius: 3px; padding: 3px 6px;
  font-size: 13px; color: #F1F1F1; max-width: 70vw; overflow: hidden;
}
.j-screens[hidden] { display: none; }
.j-screens-label { color: #C2C2C2; margin-right: 4px; }
.j-screens-btn {
  border: 0; border-radius: 3px; cursor: pointer; padding: 3px 8px;
  background: transparent; color: #fff; font-size: 13px; white-space: nowrap;
}
.j-screens-btn:hover { background: #3D3D3D; }
.j-screens-btn--on { background: #525252; }
.call-overlay--pane .j-screens { left: calc(50% - 157px); }

/* Значок «делится экраном» на плитке — без картинки: экран на сцене один. */
.call-tile-share {
  position: absolute; top: var(--space-2); left: var(--space-2);
  width: 26px; height: 22px; border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.55); color: #fff;
  display: flex; align-items: center; justify-content: center;
}
.call-tile-share .icon { width: 16px; height: 16px; }
.call-tile-share[hidden] { display: none; }
.j-filmstrip .call-tile-share { top: 4px; left: 4px; width: 20px; height: 16px; }
.j-filmstrip .call-tile-share .icon { width: 12px; height: 12px; }
/* Пин на сцену — кликом по миниатюре; сама миниатюра это показывает. */
.j-filmstrip .call-tile { cursor: pointer; }
.j-filmstrip .call-tile--self { cursor: default; }
.call-tile--pinned { outline: 2px solid #4687ED; outline-offset: -2px; }

/* ---- меню реакций: reactionsMenuBackground #242528 (Tokens.ts) ---- */
.j-reactions {
  position: absolute; bottom: 76px; left: 50%; transform: translateX(-50%);
  background: #242528; border-radius: 6px; padding: 8px;
  display: flex; gap: 4px; z-index: 30;
  box-shadow: rgba(0,0,0,.25) 0 2px 8px 4px;
}
.j-reactions button {
  width: 40px; height: 40px; border: 0; border-radius: 3px;
  background: transparent; font-size: 22px; cursor: pointer; line-height: 1;
}
.j-reactions button:hover { background: #3D3D3D; }
/* Взлетающая реакция */
.j-float {
  position: absolute; bottom: 90px; z-index: 25;
  font-size: 30px; pointer-events: none;
  animation: j-float-up 3.2s ease-out forwards;
}
.j-float small {
  display: block; text-align: center; font-size: 10px; color: #C2C2C2;
  background: rgba(0,0,0,.5); border-radius: 3px; padding: 0 4px; margin-top: 2px;
}
@keyframes j-float-up {
  0%   { transform: translateY(0);      opacity: 0; }
  10%  { opacity: 1; }
  80%  { opacity: 1; }
  100% { transform: translateY(-46vh); opacity: 0; }
}

/* ---- панель участников: 315px, #141414 — замер ---- */
.j-pane {
  position: absolute; top: 0; right: 0; bottom: 0; width: 315px;
  background: #141414; z-index: 40;
  display: flex; flex-direction: column;
  padding: 16px;
}
.call-overlay--pane .j-stage { right: 455px; }       /* сцена уступает панели */
.call-overlay--pane .j-filmstrip { right: 315px; }
.call-overlay--pane .call-actions { left: calc(50% - 157px); }
.j-pane-close {
  position: absolute; top: 16px; right: 16px;
  width: 32px; height: 32px; border: 0; border-radius: 3px;
  background: transparent; color: #fff; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.j-pane-close:hover { background: #3D3D3D; }
.j-pane-close .icon { width: 20px; height: 20px; }
.j-pane h3 { font-size: 14px; font-weight: 600; color: #fff; margin: 8px 0 16px; }
.j-pane-invite {
  height: 40px; border: 0; border-radius: 6px; cursor: pointer;
  background: #4687ED; color: #fff; font-size: 14px; font-weight: 600;
  display: flex; align-items: center; justify-content: center; gap: 8px;
}
.j-pane-invite:hover { background: #246FE5; }        /* action04 */
.j-pane-invite .icon { width: 20px; height: 20px; }
.j-pane-search {
  margin-top: 8px; height: 40px; border: 0; border-radius: 6px;
  background: #3D3D3D; color: #fff; font-size: 14px; padding: 0 16px;
}
.j-pane-search::placeholder { color: #C2C2C2; }
.j-pane-list { flex: 1; overflow-y: auto; margin-top: 8px; }
.j-pane-section {
  font-size: 11px; letter-spacing: .4px; text-transform: uppercase;
  color: #858585; margin: 14px 0 6px;
}
.j-pane-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 4px; border-radius: 6px; font-size: 14px; color: #fff;
}
.j-pane-row:hover { background: #292929; }
.j-pane-row .avatar { width: 32px; height: 32px; font-size: 12px; flex: 0 0 32px; }
.j-pane-row-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.j-pane-row-sub { display: block; font-size: 12px; font-weight: 400; color: #C2C2C2; }
.j-pane-row .icon { width: 18px; height: 18px; color: #C2C2C2; flex: 0 0 18px; }
.j-pane-act { display: flex; gap: 6px; }
.j-pane-act .btn--primary {
  height: 28px; padding: 0 10px; font-size: 12px; border-radius: 6px;
}
.j-pane-act .j-deny {
  height: 28px; padding: 0 10px; font-size: 12px; border-radius: 6px;
  background: transparent; border: 1px solid #3D3D3D; color: #fff; cursor: pointer;
}
/* Индикаторы в строке участника (план C4): говорит (зелёная точка), камера,
   экран — без видео: панель показывает всех, плитки — только страницу. */
.j-pane-ind { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.j-pane-ind-speaking {
  width: 8px; height: 8px; border-radius: 50%; background: #189B55;
  opacity: 0; transition: opacity .15s;
}
.j-pane-row--speaking .j-pane-ind-speaking { opacity: 1; }
.j-pane-row--speaking .j-pane-row-name { color: #fff; }
.j-pane-ind-cam .icon, .j-pane-ind-share .icon { width: 16px; height: 16px; color: #C2C2C2; }

/* ---- стук в дверь: карточка-уведомление слева сверху, как в Jitsi ---- */
.call-lobby {
  position: absolute; top: 20px; left: 20px; right: auto; bottom: auto;
  /* 🔴 transform: none — обязательно. Базовое правило выше центрирует полосу
     `left: 50%` + `translateX(-50%)`; здесь `left` переопределён, а transform
     наследовался и сдвигал карточку на полширины ЗА левый край: на экране
     оставались только кнопки «Впустить»/«Отклонить», имя гостя — за кадром
     (meet-a, 17.09.2026). Ширина — не больше экрана, чтобы на узком окне
     кнопки не уехали за правый край тем же способом. */
  transform: none;
  width: min(320px, calc(100vw - 40px)); z-index: 35;
  display: flex; flex-direction: column; gap: 10px;
}
.call-lobby-card {
  background: #141414; border: 1px solid #3D3D3D; border-radius: 8px;
  padding: 14px; box-shadow: rgba(0,0,0,.25) 0 2px 8px 4px;
}

/* ---- приджоин: экран #141414, колонка 300px, значения — замер master ---- */
.j-prejoin {
  position: fixed; inset: 0; z-index: 55;
  background: #141414;
  display: flex;
}
.j-prejoin-col {
  width: 400px; flex: 0 0 400px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 32px;
}
.j-prejoin-brand { position: absolute; top: 20px; left: 24px; font-size: 17px; font-weight: 700; color: #fff; }
.j-prejoin-title { font-size: 28px; font-weight: 600; color: #fff; text-align: center; }
.j-prejoin-room  { font-size: 15px; font-weight: 600; color: #C2C2C2; margin-top: 8px; text-align: center;
  max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.j-prejoin-who   { margin-top: 20px; width: 300px; height: 40px; border-radius: 6px;
  background: #3D3D3D; color: #fff; font-size: 14px;
  display: flex; align-items: center; padding: 0 16px; }
.j-prejoin-join {
  margin-top: 12px; width: 300px; height: 38px; border: 0; border-radius: 6px;
  background: #4687ED; color: #fff; font-size: 14px; font-weight: 600; cursor: pointer;
}
.j-prejoin-join:hover { background: #246FE5; }
.j-prejoin-devices { margin-top: 24px; display: flex; gap: 18px; }
.j-prejoin-devices .t-wrap .call-btn { background: transparent; }
.j-prejoin-devices .t-wrap .call-btn:hover { background: #3D3D3D; }
.j-prejoin-devices .t-chev { background: #292929; }
.j-prejoin-ok { margin-top: 24px; display: flex; align-items: center; gap: 10px;
  font-size: 13px; color: #C2C2C2; max-width: 300px; }
.j-prejoin-ok i { width: 10px; height: 10px; border-radius: 50%; background: #189B55; flex: 0 0 auto; }
/* Та же строка, но про недоступный микрофон: янтарная, потому что это не
   поломка и не запрет — войти можно, слушать можно, говорить нет. */
.j-prejoin-ok--warn { color: #F1F1F1; }
.j-prejoin-ok--warn i { background: #f0b429; }
.j-prejoin-preview { flex: 1; background: #292929; position: relative;
  display: flex; align-items: center; justify-content: center; overflow: hidden; }
/* 🔴 Видео ВНЕ потока. Пока камера выключена, пустой <video> оставался
   флекс-элементом шириной во всё превью и выталкивал кружок с инициалами к
   правому краю, наполовину за экран. А выключенная камера здесь — состояние ПО
   УМОЛЧАНИЮ (wantCam = false в prejoin.js), то есть так этот экран видел
   каждый входящий. */
.j-prejoin-preview video {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; transform: scaleX(-1);
}
.j-prejoin-preview .avatar--stage { width: 130px; height: 130px; font-size: 44px; border-radius: 50%; }
.j-prejoin-camoff {
  position: absolute; left: 50%; bottom: 26px; transform: translateX(-50%);
  background: rgba(0,0,0,.55); border-radius: 6px; padding: 6px 14px;
  font-size: 13px; color: #E0E0E0;
}

/* Меню устройств живёт и в приджоине — но привязано к СВОЕЙ кнопке.
 *
 * 🔴 Здесь стояло `.call-devices { bottom: auto; }` — без всякой области
 * действия, то есть и для встречи тоже. Оно убивало `bottom: 92px`, и меню
 * вставало по своей статической позиции: в приджоине это верх экрана, где оно
 * висело оторванным от шеврона и обрезалось краем.
 *
 * Теперь в приджоине меню вешается на .t-wrap своей кнопки (prejoin.js) — а
 * .t-wrap уже position: relative. Во встрече меню по-прежнему уходит в оверлей
 * и стоит над панелью кнопок, как и было задумано.
 *
 * ⚑ Раскрывается ВНИЗ, а не вверх: кнопки устройств стоят ПОД формой, и меню,
 * раскрытое вверх, накрывало бы «Join meeting» — единственную кнопку этого
 * экрана. Снизу же пусто до самого края. */
.t-wrap .call-devices { top: calc(100% + 10px); bottom: auto; }
/* …кроме невысокого окна: там снизу пусто НЕ до края. Замерено — при высоте
   620 меню уходило за нижний край на 39 px, и последний пункт списка терялся.
   Порог: колонка отцентрована, поэтому под кнопками остаётся примерно
   (высота / 2 − 130) px, а меню просит около 223. */
@media (max-height: 720px) {
  .t-wrap .call-devices { top: auto; bottom: calc(100% + 10px); }
}

/* ---- гостевая страница: тот же приджоин (контент слева, превью справа) ---- */
.guest-body { flex-direction: row-reverse; }

/* ---- вход: hero как на welcome-странице Jitsi ---- */
.meet-login { background: #040404; align-items: stretch; padding: 0; flex-direction: column; }
.meet-login-card {
  width: 100%; max-width: none; background: transparent; border: 0;
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 24px; position: relative;
}
.meet-login-card .meet-brand { position: absolute; top: 22px; left: 28px; font-size: 20px; }
.meet-login-sub { font-size: 38px; font-weight: 600; color: #fff; margin-bottom: 8px; }
.meet-quick { width: min(560px, 92%); }
.meet-quick-label { display: none; }               /* строка Jitsi: без подписи */
.meet-quick-row {
  display: flex; background: #fff; border-radius: 8px; padding: 4px; gap: 4px;
}
.meet-quick-row input {
  flex: 1; border: 0; outline: 0; background: transparent; color: #040404;
  font-size: 15px; padding: 0 14px; height: 48px;
}
.meet-quick-row input::placeholder { color: #858585; }
.meet-quick-row .meet-login-btn {
  height: 48px; padding: 0 22px; white-space: nowrap; border-radius: 6px;
  background: #4687ED; border: 0; color: #fff;
}
.meet-quick-hint { margin-top: 12px; }

/* 🔴 На телефоне эта строка ВЫЛЕЗАЛА за экран, и «New meeting» — единственная
   кнопка, ради которой сюда приходят без учётки, — оказывалась наполовину за
   правым краем. Классическая ловушка флексбокса: у `flex: 1` подразумевается
   min-width: auto, поэтому поле отказывалось ужиматься уже своего содержимого и
   выталкивало кнопку из строки (при ширине окна 375 документ разъезжался до
   381).
   Одного min-width: 0 мало: тогда поле схлопывается в полоску, потому что у
   кнопки текст в одну строку и она забирает всю ширину. Значит на узком экране
   строка складывается в столбик — поле и кнопка во всю ширину, по 48 px.
   ⚑ flex: 0 0 auto у поля обязателен: в колонке `flex: 1` считает уже ВЫСОТУ, и
   поле садится до высоты своего текста (20 px). */
@media (max-width: 420px) {
  .meet-quick-row { flex-direction: column; gap: 8px; padding: 0; background: transparent; }
  .meet-quick-row input { flex: 0 0 auto; min-width: 0; height: 48px; background: #fff; border-radius: 8px; }
  .meet-quick-row .meet-login-btn { width: 100%; }
}

/* ---- доводка 1:1 после сверки скриншотов с эталоном (27.08) ---- */
/* Hero: подзаголовок и серый вход, дословно по одобренному макету. */
.meet-hero-sub { margin: 0 0 26px; color: #C2C2C2; font-size: 16px; }
.meet-login-card .meet-signin {
  display: inline-block; text-decoration: none;
  align-self: center; width: auto;   /* карточка flex-стретчит детей */
  background: #2b2b2b; border: 1px solid #3D3D3D; border-radius: 8px;
  color: #F1F1F1; font-size: 14px; padding: 12px 20px;
}
.meet-login-card .meet-signin:hover { background: #3D3D3D; }

/* Приджоин: у Jitsi кнопки устройств прозрачные, имя комнаты — белый жирный. */
.j-prejoin .call-btn { background: transparent; color: #F1F1F1; }
.j-prejoin .call-btn:hover { background: #292929; }
.j-prejoin .call-btn--off { background: transparent; color: #F1F1F1; }
.j-prejoin-room { color: #F1F1F1; font-weight: 600; font-size: 16px; }

/* Панель: у Jitsi плейсхолдер поиска стоит по центру. */
.j-pane-search { text-align: center; }

/* Вотермарка в углу встречи — как «jitsi» слева сверху. */
.j-watermark {
  position: absolute; top: 18px; left: 20px; z-index: 5; pointer-events: none;
  color: #fff; opacity: .55; font-size: 19px; font-weight: 600;
}

/* ============================================================================
 * РЕЖИМ «ЭКОНОМИЯ» — .call-overlay--eco (план C5). Умолчание.
 *
 * Парк работает через RDP на слабых ПК: каждый композитный слой, маска и
 * анимация — это не «чуть плавнее», а лишние перерисовки, которые RDP гонит
 * по сети целыми прямоугольниками. Класс ставит group-call.js (openOverlay /
 * applyQualityChoice); «полное качество» его снимает — и только его.
 *
 * ⚑ Секция в КОНЦЕ файла и с удвоенной специфичностью (.call-overlay.…):
 * она обязана побеждать любое правило скина выше при том же весе, и
 * будущее правило с transition не должно обойти её случайно.
 * ========================================================================== */

/* Ни одного перехода в оверлее: hover-кнопка полного экрана, точка
   «говорит» в панели — всё мгновенно. */
.call-overlay.call-overlay--eco,
.call-overlay.call-overlay--eco * { transition: none; }

/* Реакция не взлетает — стоит 3 с и исчезает (onReaction снимает узел):
   анимация transform+opacity поверх сцены — это перерисовка всего экрана
   60 раз в секунду три секунды подряд. */
.call-overlay.call-overlay--eco .j-float { animation: none; }

/* Плитка без скруглений: border-radius + overflow:hidden над <video> — это
   маска слоя у КАЖДОЙ плитки (девять на странице), и Chromium тянет её через
   отдельный композитный слой. overflow: clip вместо hidden — тот же срез без
   контейнера прокрутки. contain: strict — плитка не влияет на раскладку
   соседей и перерисовывается только сама: ширина у неё явная в обоих видах
   (122×71 в плёнке, min(30vw, …) в сетке), высота — из aspect-ratio, и
   size-containment тут ничего не ломает. will-change НЕ ставить: слой на
   каждую плитку — ровно то, чего избегаем. */
.call-overlay.call-overlay--eco .call-tile {
  border-radius: 0;
  overflow: hidden;
  overflow: clip;
  contain: strict;
}
/* Границу плитки рисует outline, а не скругление, — и только там, где её не
   рисуют уже «говорит» / «рука» / «пин» (у них свой outline, он важнее). */
.call-overlay.call-overlay--eco .call-tile:not(.call-tile--speaking):not(.call-tile--hand):not(.call-tile--pinned) {
  outline: 1px solid #292929;
  outline-offset: -1px;
}
/* Своя камера без зеркала: scaleX(-1) — трансформ на живом видео, ещё один
   слой. На сцене то же решает renderStage (inline-стиль). */
.call-overlay.call-overlay--eco .call-tile--self .call-tile-video { transform: none; }
