/* ─────────────────────────────────────────────────────────
   СКИНЫ. Вся палитра/шрифты/тени/радиусы — переменные, поэтому
   скин — это просто набор переопределений на [data-theme="id"].
   Ниже — дефолтный, "яркий" скин (без атрибута на <html>, он же
   brutal в THEMES из app.js): неоновая мастерская в темноте.
   Тёмный фон остаётся — вокруг видео это единственное, что
   работает — но всё, что раньше было тихим и приглушённым, теперь
   очерчено толстой светлой линией и держит жёсткую офсетную тень
   (привет, toooolzy-kit.html). Один акцент был — стал три: hivis
   жёлтый (основное), rust (тревога/выход), steel (второстепенное).
   Тень — не чёрная (она бы просто исчезла на тёмном фоне), а
   бумажная или акцентная — ровно как в референсе, где чёрная тень
   на ink живёт бок о бок с цветной shadow-nb-hivis / shadow-nb-rust.
   Второй скин — "спокойный" (calm) — сразу под этим блоком: свой
   набор тех же переменных плюс несколько точечных переопределений
   для деталей, которые не сводятся к переменной (текстура фона
   лобби, uppercase-лейблы). Третий-пятый скин добавляются так же:
   блок токенов тут + запись в THEMES в app.js — разметка и JS
   переключателя тем самих скинов не знают. */
:root {
  --night:   #14111c;
  --night-2: #1c1826;
  --edge:    #2b2537;
  --paper:   #f1efea;
  --muted:   #8b8199;

  --hivis:     #ffc400;
  --hivis-ink: #241703;
  --rust:      #e8552a;
  --steel:     #2e5d7d;

  --display: 'Unbounded', system-ui, sans-serif;
  --body:    'Inter Tight', system-ui, sans-serif;
  --mono:    'JetBrains Mono', ui-monospace, monospace;

  --title-font:      var(--display);
  --title-transform: uppercase;

  --r:    16px;
  --rb:   12px;
  --line: 2px;

  --shadow-sm:    2px 2px 0 0 var(--paper);
  --shadow-md:    4px 4px 0 0 var(--paper);
  --shadow-lg:    6px 6px 0 0 var(--paper);
  --shadow-hivis: 4px 4px 0 0 var(--hivis);
  --shadow-rust:  4px 4px 0 0 var(--rust);
  --shadow-steel: 4px 4px 0 0 var(--steel);

  --shadow-primary: var(--shadow-rust);
  --shadow-primary-hover: 6px 6px 0 0 var(--rust);
  --shadow-primary-active: 1px 1px 0 0 var(--rust);
  --shadow-btn-active: 1px 1px 0 0 var(--paper);
  --shadow-leave:        4px 4px 0 0 var(--night);
  --shadow-leave-hover:  6px 6px 0 0 var(--night);
  --shadow-leave-active: 1px 1px 0 0 var(--night);

  --lift-hover:  translate(-1px, -1px);
  --lift-active: translate(1px, 1px);

  --stage-bg:   #0e0c14;
  --overlay-bg: rgba(14, 12, 20, .72);
  --warn-bg:    rgba(232, 85, 42, .1);
  --warn-text:  #f6b39d;
  --placeholder: #574d66;

  --texture-noise: none;

  /* Видео-сцена нарочно остаётся тёмной в обоих скинах (иначе рамки
     вокруг камеры съедают контраст с картинкой), а --paper на неё
     не завязан — иначе текст поверх (например, "ждём собеседника")
     в спокойном скине станет тёмным на тёмном. */
  --on-dark:        var(--paper);
  --on-dark-muted:  var(--muted);
}

/* "Спокойный" скин: не белый экран, а тёплый картон/крафт-бумага —
   на глаз это середина между тёмным и светлым, а не яркий белый лист.
   Один сдержанный синий (приглушённый, не рекламный) акцент вместо
   жёлтого, тонкие рамки вместо толстых, мягкая едва заметная тень
   вместо жёсткой офсетной. Плюс лёгкое зерно (--texture-noise ниже) —
   фактура мятой бумаги, а не гладкий пластик. */
[data-theme="calm"] {
  --night:   #d9cfba;
  --night-2: #efe8d8;
  --edge:    #c1b294;
  --paper:   #332b1f;
  --muted:   #7c6f57;

  --hivis:     #3f6ea0;
  --hivis-ink: #ffffff;
  --rust:      #b5533a;
  --steel:     #6b6152;

  --title-font:      var(--body);
  --title-transform: none;

  --r:    10px;
  --rb:   8px;
  --line: 1px;

  --shadow-sm:    0 1px 2px rgba(51, 43, 31, .10);
  --shadow-md:    0 3px 10px rgba(51, 43, 31, .14);
  --shadow-lg:    0 10px 26px rgba(51, 43, 31, .18);
  --shadow-hivis: 0 0 0 3px rgba(63, 110, 160, .22);
  --shadow-rust:  0 0 0 3px rgba(181, 83, 58, .20);
  --shadow-steel: 0 0 0 3px rgba(107, 97, 82, .20);

  --shadow-primary: var(--shadow-hivis);
  --shadow-primary-hover:  0 4px 12px rgba(63, 110, 160, .32);
  --shadow-primary-active: 0 1px 4px rgba(63, 110, 160, .32);
  --shadow-btn-active: 0 1px 3px rgba(51, 43, 31, .16);
  --shadow-leave:        none;
  --shadow-leave-hover:  0 4px 12px rgba(181, 83, 58, .30);
  --shadow-leave-active: 0 1px 4px rgba(181, 83, 58, .30);

  --lift-hover:  none;
  --lift-active: none;

  --stage-bg:   #221d16;
  --overlay-bg: rgba(26, 21, 14, .55);
  --warn-bg:    #f3ded1;
  --warn-text:  #7a3320;
  --placeholder: #a8967a;

  --on-dark:        #f1e9d8;
  --on-dark-muted:  #c9bda2;

  /* Едва заметное зерно: SVG feTurbulence как повторяющийся фон,
     смешанный поверх картонного цвета через overlay — читается как
     фактура бумаги, не как "шум" на изображении. */
  --texture-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.08 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Детали, которые не сводятся к переменной: технократичные uppercase
   мелкие лейблы мелким моноширинным шрифтом — фирменная черта яркого
   скина, в спокойном — обычный текст обычным шрифтом. Пунктирные
   линии (разделитель, код комнаты, сноска диагностики) там же меняем
   на сплошные — пунктир читается как "набросок", не как корпоративный UI. */
[data-theme="calm"] .field__label,
[data-theme="calm"] .lobby__divider,
[data-theme="calm"] .mic-meter__label,
[data-theme="calm"] .stats__title,
[data-theme="calm"] .stats__subtitle,
[data-theme="calm"] .chat__title,
[data-theme="calm"] .link__badge,
[data-theme="calm"] .tile__label {
  font-family: var(--body);
  text-transform: none;
  letter-spacing: normal;
}
[data-theme="calm"] .lobby__divider::before,
[data-theme="calm"] .lobby__divider::after,
[data-theme="calm"] .stats__note {
  border-top-style: solid;
  border-top-width: 1px;
}
[data-theme="calm"] .room {
  border-style: solid;
}
[data-theme="calm"] .lobby {
  background-color: var(--night);
  background-image: var(--texture-noise);
  background-blend-mode: overlay;
}

* { box-sizing: border-box; }

/* Без этого [hidden] ничего не значит: у .lobby и .call ниже свой
   безусловный display:grid, а авторские правила всегда перебивают
   display:none из UA-стиля для [hidden], даже при равной специфичности. */
[hidden] { display: none !important; }

/* Вход по ссылке (глобал): вместо лобби — размытая комната и записка
   поверх, пока браузер спрашивает камеру и микрофон. Класс ставит
   скрипт в <head>, снимает enterRoom. */
.entering-note { display: none; }
html.entering #lobby { display: none !important; }
html.entering #call[hidden] { display: grid !important; }
html.entering #call { filter: blur(12px); pointer-events: none; user-select: none; }
html.entering .entering-note {
  display: grid;
  place-items: center;
  position: fixed;
  inset: 0;
  z-index: 50;
  padding: 16px;
}
html.entering .entering-note .modal__text { margin: 0; }

/* Режим деплоя: сервер вписывает data-app-mode в <html> (см. APP_MODE
   в server.js). Семейное лишнее на проде и наоборот — прячем до первой
   отрисовки, без мелькания. */
html[data-app-mode="prod"] .family-only,
html:not([data-app-mode="prod"]) .prod-only { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  background-color: var(--night);
  background-image: var(--texture-noise);
  background-blend-mode: overlay;
  color: var(--paper);
  font-family: var(--body);
  -webkit-font-smoothing: antialiased;
}

button { font: inherit; cursor: pointer; }

:focus-visible { outline: 3px solid var(--hivis); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; }
}

/* ── ЛОББИ ───────────────────────────────────────────── */
.lobby {
  min-height: 100%;
  display: grid;
  place-items: center;
  padding: 24px;
  background:
    radial-gradient(120% 80% at 85% -10%, rgba(255,196,0,.14), transparent 60%),
    radial-gradient(circle at 1px 1px, rgba(241,239,234,.09) 1px, transparent 0) 0 0/22px 22px,
    var(--night);
}

/* Ширина лобби подросла: заголовок и действия слева, превью камеры
   справа — раскладка в две колонки, чтобы всё влезало по высоте без
   скролла (см. .lobby__grid ниже). */
.lobby__inner { width: min(880px, 100%); }

.lobby__heading {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin: 0 0 20px;
}

.lobby__title {
  font-family: var(--title-font);
  font-weight: 900;
  text-transform: var(--title-transform);
  font-size: clamp(24px, 3.6vw, 36px);
  line-height: 1.05;
  letter-spacing: -.01em;
  margin: 0;
  color: var(--hivis);
}

/* Шапка глобала — верх билета: название слева, проект живем со ссылками
   на его сети справа, под ними та же линия отрыва с пробитыми краями,
   что у корешка внизу (кружки — общие правила с .site-foot). */
html[data-app-mode="prod"] .lobby__heading {
  position: relative;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 24px;
  padding-bottom: 18px;
  border-bottom: 2px dashed var(--edge);
}
.brand-head .site-foot__label { margin: 0 0 2px; }
.brand-link + .brand-link { margin-left: 20px; }
/* Ссылки на сети проекта — шрифтом заголовков, но строчными, как в логотипе. */
.brand-link {
  font-family: var(--title-font);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -.01em;
  color: var(--paper);
  text-decoration: none;
  border-bottom: 1.5px solid var(--edge);
  padding-bottom: 1px;
  transition: color .15s, border-color .15s;
}
.brand-link:hover, .brand-link:focus-visible { color: var(--hivis); border-color: var(--hivis); }

/* Два равных столбца: слева — как войти, справа — превью себя.
   На узких экранах превью показываем первым (видно себя, потом
   действия) — так это устроено в большинстве видеозвонков. */
.lobby__grid {
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  grid-template-areas: "actions preview";
  gap: 36px;
  align-items: start;
}
.lobby__col--actions { grid-area: actions; }
.lobby__col--preview { grid-area: preview; }

@media (max-width: 760px) {
  .lobby__grid {
    grid-template-columns: 1fr;
    grid-template-areas: "preview" "actions";
  }
}

.field { display: block; margin-bottom: 16px; }
.field__label {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}
.field__input {
  width: 100%;
  padding: 14px 16px;
  background: var(--night-2);
  border: var(--line) solid var(--paper);
  border-radius: var(--rb);
  color: var(--paper);
  font-family: var(--mono);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: .02em;
  outline: none;
  box-shadow: var(--shadow-sm);
  transition: box-shadow .15s, transform .15s, border-color .15s;
}
.field__input::placeholder { color: var(--placeholder); }
.field__input:focus-visible {
  border-color: var(--hivis);
  box-shadow: var(--shadow-hivis);
  outline: none;
}

.field__row { display: flex; gap: 8px; }
.field__row .field__input { flex: 1; min-width: 0; }
.field__row .btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
}

/* Две закреплённые комнаты — главный, самый частый путь входа, в один
   ряд, одинакового размера. "Мы" — жёлтая, с полным press-physics
   поведением из референса; "Тест" — контурная. Разница в заливке
   достаточно читается как "основное / запасное". */
.quick-rooms {
  display: flex;
  gap: 10px;
  margin: 0 0 10px;
}
.quick-rooms .btn { flex: 1; }

.quick-rooms__hint {
  margin: 0 0 18px;
  color: var(--muted);
  font-size: 12.5px;
}

/* Разделитель перед "продвинутым" способом входа — по коду вручную.
   Пунктир вместо сплошной линии — деталь из квитанции в референсе. */
.lobby__divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 18px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.lobby__divider::before, .lobby__divider::after {
  content: '';
  flex: 1;
  height: 0;
  border-top: 2px dashed var(--edge);
}

/* Превью своей камеры — до входа в комнату. Показываем "спокойную"
   заглушку (иконка + кнопка запроса разрешения), пока поток не получен
   или если получить его не вышло — вход в комнату это не блокирует.
   Рамка и тень как у "браузерного" мокапа в референсе. */
.preview {
  position: relative;
  width: 100%;
  max-width: 440px;
  aspect-ratio: 4 / 3;
  margin: 0 0 14px;
  border-radius: var(--r);
  overflow: hidden;
  background: var(--night-2);
  border: 3px solid var(--paper);
  box-shadow: var(--shadow-lg);
}
.preview video {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scaleX(-1); /* отзеркалено, как в зеркале */
}
.preview__overlay {
  position: absolute; inset: 0;
  display: grid;
  place-items: center;
  gap: 10px;
  padding: 16px;
  text-align: center;
}
.preview__ico { font-size: 38px; opacity: .5; }
.preview__note {
  margin: 0;
  max-width: 22ch;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.4;
}

/* Индикатор уровня микрофона — единственное место, где допустима
   постоянная перерисовка: он живёт только тут, в лобби, до входа
   в комнату, и останавливается сразу же при входе (см. stopMicMeter). */
.mic-meter {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  max-width: 440px;
  margin: 0 0 14px;
}
.mic-meter__label {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  flex-shrink: 0;
}
.mic-meter__track {
  flex: 1;
  height: 8px;
  border-radius: 999px;
  background: var(--night-2);
  border: 2px solid var(--paper);
  overflow: hidden;
}
.mic-meter__fill {
  height: 100%;
  width: 0%;
  background: var(--hivis);
  border-radius: inherit;
  transition: width .08s linear;
}

/* Статус комнаты по мере ввода кода: пусто / ждёт один человек / уже
   двое. Обновляется по таймеру в app.js, не наша забота тут. */
.room-status {
  margin: -8px 0 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}
.room-status--warn { color: var(--rust); }

/* Неверный код: красная строка под полем, рамка поля красная, само поле
   коротко вздрагивает — заметно, даже если смотрели на кнопку. */
.code-error {
  margin: -8px 0 16px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.45;
  color: var(--rust);
}
.field__input.is-invalid,
.field__input.is-invalid:focus-visible { border-color: var(--rust); box-shadow: var(--shadow-rust); }
.field__input.shake { animation: field-shake .4s ease-in-out; }
@keyframes field-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(4px); }
}
@media (prefers-reduced-motion: reduce) {
  .field__input.shake { animation: none; }
}

/* Подсказка про особенности браузера (сейчас — про звук при показе
   экрана в Firefox/Safari). Текст скрыт, пока не наведут курсор или
   не сфокусируют клавиатурой — постоянно видимым текстом это было
   слишком навязчиво для не самого частого случая. Кружок иконки —
   как значок "i" на бейдже в референсе. */
.hint {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  padding: 0;
  border: none;
  background: none;
  color: var(--muted);
  font-family: var(--body);
  font-weight: 600;
  font-size: 12.5px;
  cursor: help;
  text-align: left;
}
/* Подсказка "как это работает" рядом с заголовком выравниваем по
   низу строки текста, а не по центру иконки. */
.hint--about { align-self: flex-end; margin-bottom: 5px; }
.hint:hover, .hint:focus-visible { color: var(--paper); }

.hint__ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 17px; height: 17px;
  border-radius: 50%;
  border: 2px solid var(--edge);
  font-family: var(--mono);
  font-weight: 700;
  font-size: 10.5px;
  font-style: normal;
}
.hint:hover .hint__ico, .hint:focus-visible .hint__ico { border-color: var(--hivis); color: var(--hivis); }

.hint__bubble {
  position: absolute;
  bottom: calc(100% + 12px);
  left: 0;
  width: 270px;
  max-width: 80vw;
  padding: 13px 15px;
  border-radius: var(--rb);
  border: 2px solid var(--paper);
  box-shadow: var(--shadow-md);
  background: var(--night-2);
  color: var(--paper);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.5;
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  transition: opacity .15s, transform .15s;
  pointer-events: none;
  z-index: 5;
}
.hint:hover .hint__bubble, .hint:focus-visible .hint__bubble {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* У заголовка подсказка всплывает не вверх (там некуда — край экрана),
   а вниз. */
.hint--about .hint__bubble {
  bottom: auto;
  top: calc(100% + 12px);
  transform: translateY(-4px);
}

.lobby__actions { display: flex; gap: 10px; flex-wrap: wrap; }
/* Лобби глобала: две дорожки — бесплатная проба и вход по коду. Сверху
   проба (новый человек), а если пришли по ссылке с кодом — код
   (.code-first на колонке, см. applyLobbyOrder в app.js). Порядок —
   через order, чтобы общие с семейным элементы не переставлять в DOM. */
html[data-app-mode="prod"] .lobby__col--actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
html[data-app-mode="prod"] .lobby__col--actions > * { order: 20; }
html[data-app-mode="prod"] .lobby__col--actions > .free-block { order: 1; align-self: stretch; }
html[data-app-mode="prod"] .lobby__col--actions > .code-divider { order: 2; align-self: stretch; }
html[data-app-mode="prod"] .lobby__col--actions > .field { order: 3; align-self: stretch; }
html[data-app-mode="prod"] .lobby__col--actions > #codeError { order: 3; } /* сразу под полем: тот же order, в разметке следом */
html[data-app-mode="prod"] .lobby__col--actions > #roomStatus { order: 4; }
html[data-app-mode="prod"] .lobby__col--actions > #codeHint { order: 5; }
html[data-app-mode="prod"] .code-first > .field { order: 1; }
html[data-app-mode="prod"] .code-first > #codeError { order: 1; }
html[data-app-mode="prod"] .code-first > #roomStatus { order: 2; }
html[data-app-mode="prod"] .code-first > #codeHint { order: 3; }
html[data-app-mode="prod"] .code-first > .code-divider { order: 4; }
html[data-app-mode="prod"] .code-first > .free-block { order: 5; }
/* "Войти" переезжает в строку с полем (см. applyLobbyOrder); копировать
   ссылку в лобби незачем — её копируют уже в комнате, для партнёра. */
html[data-app-mode="prod"] #lobbyCopyBtn,
html[data-app-mode="prod"] .lobby__actions { display: none; }
/* Над полем кода подпись нужна, только когда код сверху: иначе про него
   уже сказал разделитель "есть код доступа?". */
html[data-app-mode="prod"] .lobby__col--actions:not(.code-first) .field__label.prod-only { display: none; }
.lobby__divider.prod-only { margin-top: 20px; }
.free-btn.btn--primary { width: 100%; }
.free-block__hint { margin-top: 10px; }
.code-first .free-btn { margin-bottom: 10px; }
/* Коды доступа выдаются заглавными (K7QM-2XR9-VLP4) — так и показываем,
   что бы ни набрали; на сервер всё равно уходит в нижнем регистре. */
html[data-app-mode="prod"] #roomInput { text-transform: uppercase; }

/* Тарифы глобала: две колонки "Бесплатно / Полная" под превью камеры. */
.plans {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 20px;
}
.plan {
  border: var(--line) solid var(--edge);
  border-radius: var(--rb);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
}
.plan--full { border-color: var(--hivis); }
.plan__name {
  margin: 0 0 6px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}
.plan--full .plan__name { color: var(--hivis); }
.plan__price { margin: 0 0 2px; font-weight: 700; font-size: 16px; }
.plan__price span { font-weight: 500; font-size: 13px; color: var(--muted); }
.plan__list {
  margin: 10px 0 0;
  padding-left: 18px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}
.plan__buy { margin-top: 14px; }
.plan__note { margin: 8px 0 0; font-size: 12px; line-height: 1.45; color: var(--muted); }
.plan__foreign { margin: 6px 0 0; font-size: 12px; line-height: 1.45; color: var(--muted); }

/* Шаги "как поставить иконку вручную" в окне installHelp. */
.install-steps {
  margin: 0 0 20px;
  padding-left: 20px;
  text-align: left;
  font-size: 14px;
  line-height: 1.55;
}
.install-steps li + li { margin-top: 6px; }
@media (max-width: 420px) {
  .plans { grid-template-columns: 1fr; }
}

/* Тарифы на десктопе: четыре компактные карточки в ряд под лобби.
   На узком экране — наоборот, остаются две карточки .plans (см. выше),
   а ряд прячется: четыре карточки подряд на телефоне — длинная прокрутка. */
.tiers { margin-top: 36px; }
/* "Остальные вопросы можно задать в Telegram" — в окнах подробностей. */
.ask { margin: 14px 0 0; font-size: 13.5px; line-height: 1.5; color: var(--muted); }
.ask__link { color: var(--paper); }
.ask__link:hover, .ask__link:focus-visible { color: var(--hivis); }
.tiers__common, .tiers__note {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}
.tiers__row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin: 14px 0;
}
.tier {
  border: var(--line) solid var(--edge);
  border-radius: var(--rb);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
}
.tier--best { border-color: var(--hivis); }
.tier__name {
  margin: 0 0 6px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}
.tier--best .tier__name { color: var(--hivis); }
.tier__badge {
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--hivis);
  color: var(--hivis-ink);
  font-size: 10px;
  letter-spacing: .06em;
}
.tier__price { margin: 0; font-weight: 700; font-size: 18px; white-space: nowrap; }
.tier__price span { font-weight: 500; font-size: 13px; color: var(--muted); }
.tier__desc {
  margin: 8px 0 14px;
  flex: 1; /* кнопки всех карточек — на одной линии внизу */
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}
.tier__btn { align-self: stretch; }

/* Низ лобби глобала — корешок билета: пунктирная линия отрыва с
   пробитыми краями, под ней подробности (открывают окна .info), а
   наклейка проекта живем прилеплена наискось поверх линии справа.
   Ссылки набраны тем же моноширинным капсом, что подписи полей и
   разделители: это служебная навигация, не текст. */
.site-foot {
  position: relative;
  margin-top: 30px;
  padding: 14px 130px 0 0;
  border-top: 2px dashed var(--edge);
}
.site-foot::before, .site-foot::after,
html[data-app-mode="prod"] .lobby__heading::before,
html[data-app-mode="prod"] .lobby__heading::after {
  content: '';
  position: absolute;
  top: -12px;
  width: 22px; height: 22px;
  border-radius: 50%;
  border: 2px solid var(--edge);
  background: var(--night);
}
.site-foot::before, .lobby__heading::before { left: -32px; }
.site-foot::after, .lobby__heading::after { right: -32px; }
html[data-app-mode="prod"] .lobby__heading::before,
html[data-app-mode="prod"] .lobby__heading::after {
  top: auto; bottom: -12px;
  background: none; /* под шапкой фон с отсветом — заливка выглядела бы пятном */
}

.site-foot__label {
  margin: 0 0 6px;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--hivis);
}

.info-links { display: flex; flex-wrap: wrap; gap: 4px 20px; }
.info-links__break { flex-basis: 100%; height: 0; }
.info-link {
  padding: 4px 0;
  border: 0;
  background: none;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--muted);
  cursor: pointer;
}
.info-link:hover, .info-link:focus-visible {
  color: var(--paper);
  text-decoration: underline dashed var(--hivis);
  text-decoration-thickness: 2px;
  text-underline-offset: 6px;
}
[data-theme="calm"] .info-link {
  font-family: var(--body);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
}

.brand-foot__sticker-link {
  position: absolute;
  right: 8px; top: -24px;
  transform: rotate(22deg);
}
/* Обводка по контуру картинки и тень со сдвигом, как у главной кнопки:
   наклейка читается как то, на что можно нажать. drop-shadow, а не
   border/box-shadow — чтобы шло по форме PNG, а не по прямоугольнику. */
.brand-foot__sticker {
  display: block; width: 150px; height: auto; transition: transform .2s;
  filter:
    drop-shadow(2px 0 0 var(--paper)) drop-shadow(-2px 0 0 var(--paper))
    drop-shadow(0 2px 0 var(--paper)) drop-shadow(0 -2px 0 var(--paper))
    drop-shadow(4px 4px 0 var(--rust));
}
.brand-foot__sticker-link:hover .brand-foot__sticker { transform: rotate(-3deg) scale(1.04); }

@media (max-width: 760px) {
  .site-foot { padding-right: 0; }
  .site-foot::before, .lobby__heading::before { left: -20px; }
  .site-foot::after, .lobby__heading::after { right: -20px; }
  /* Наклейка встаёт под подробностями, в поток. */
  .brand-foot__sticker-link { position: static; display: inline-block; margin-top: 20px; transform: rotate(-5deg); }
}
@media (prefers-reduced-motion: reduce) {
  .brand-foot__sticker { transition: none; }
}

/* Окно подробностей: шире окна выхода, текст слева, длинное — прокручивается. */
.modal__card.info__card {
  width: min(560px, 100%);
  max-height: calc(100dvh - 48px);
  overflow-y: auto;
  text-align: left;
}
.info__card .modal__actions { margin-top: 20px; }
.info__subtitle { margin: 18px 0 8px; font-size: 15px; }
.info__steps, .info__list { margin: 0; padding-left: 20px; }
.info__steps li, .info__list li { margin-bottom: 8px; }
.info__steps, .info__list, .info__text, .faq p { font-size: 14px; line-height: 1.55; }
.info__text { margin: 14px 0 0; color: var(--muted); }
.faq p { color: var(--muted); }
.info__card > .ph { margin-top: 14px; }
.faq { border-top: 1px solid var(--edge); padding: 10px 0; }
.faq summary { cursor: pointer; font-weight: 600; font-size: 14.5px; }
.faq p { margin: 8px 0 0; }
.info__card .ask { margin-top: 12px; }

/* Заглушка под будущий текст: видно, что место занято, и что в него лечь должно. */
.ph {
  margin: 0;
  padding: 8px 10px;
  border: 1px dashed var(--edge);
  border-radius: 6px;
  color: var(--muted);
  font-size: 13.5px;
  line-height: 1.5;
  font-style: italic;
}

@media (min-width: 761px) {
  .plans { display: none !important; }
}
@media (max-width: 760px) {
  .tiers { display: none !important; }
}

/* ── КНОПКИ: press physics ─────────────────────────────
   Толстая бумажная рамка + жёсткая офсетная тень. При наведении
   кнопка приподнимается и тень растёт; при нажатии — вжимается,
   тень почти пропадает. Ровно as-is из спецификации референса. */
.btn {
  border: var(--line) solid var(--paper);
  border-radius: var(--rb);
  padding: 13px 22px;
  font-weight: 700;
  font-size: 15px;
  background: var(--night-2);
  color: var(--paper);
  box-shadow: var(--shadow-sm);
  transition: transform .12s, box-shadow .12s, background .18s, border-color .18s;
}
.btn:hover { transform: var(--lift-hover); box-shadow: var(--shadow-md); }
.btn:active { transform: var(--lift-active); box-shadow: var(--shadow-btn-active); }
.btn:focus-visible { outline: 3px solid var(--hivis); outline-offset: 2px; }
.btn:disabled { opacity: .4; cursor: not-allowed; transform: none; box-shadow: none; }

.btn--primary { background: var(--hivis); color: var(--hivis-ink); box-shadow: var(--shadow-primary); }
.btn--primary:hover { background: #ffd23f; box-shadow: var(--shadow-primary-hover); }
.btn--primary:active { box-shadow: var(--shadow-primary-active); }

.btn--ghost { background: transparent; color: var(--paper); }
.btn--ghost:hover { border-color: var(--hivis); }

.btn--tiny {
  background: var(--night-2);
  color: var(--paper);
  border-width: 1.5px;
  padding: 7px 12px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 9px;
  box-shadow: none;
}
.btn--tiny:hover { transform: var(--lift-hover); box-shadow: var(--shadow-sm); border-color: var(--paper); }
.btn--tiny:active { transform: translate(0, 0); box-shadow: none; }

.lobby__hint { color: var(--muted); font-size: 13.5px; line-height: 1.5; margin: 14px 0 0; }

.warn {
  margin-top: 20px;
  padding: 13px 15px;
  border-radius: var(--rb);
  border: 2px solid var(--rust);
  box-shadow: var(--shadow-rust);
  background: var(--warn-bg);
  color: var(--warn-text);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.5;
}

/* Переключатель скина — угол экрана, а не в потоке формы: это
   настройка отображения, а не шаг входа в комнату, и в большинстве
   привычных интерфейсов такой тумблер живёт именно в углу. Только
   в лобби (см. THEMES в app.js); [hidden] на #lobby прячет его вместе
   со всем остальным при входе в звонок, отдельно прятать не нужно.
   Кнопки — просто цветной кружок, без подписи (тот же язык, что у
   .ctl на экране звонка): название скина — в aria-label/title. */
.theme-switch {
  position: fixed;
  top: calc(14px + env(safe-area-inset-top));
  right: 16px;
  z-index: 20;
}
.theme-switch__options { display: flex; gap: 8px; }
.theme-switch__opt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px; height: 34px;
  padding: 0;
  border-radius: 50%;
  border: 2px solid var(--edge);
  background: var(--night-2);
  box-shadow: var(--shadow-sm);
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.theme-switch__opt:hover { transform: var(--lift-hover); box-shadow: var(--shadow-md); }
.theme-switch__opt:focus-visible { outline: 3px solid var(--hivis); outline-offset: 2px; }
.theme-switch__opt[aria-checked="true"] { border-color: var(--hivis); box-shadow: var(--shadow-hivis); }
.theme-switch__swatch {
  width: 16px; height: 16px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1px solid rgba(0,0,0,.15);
}

/* ── ЭКРАН ЗВОНКА ────────────────────────────────────── */
.call {
  height: 100%;
  display: grid;
  grid-template-rows: auto 1fr auto;
}

.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: calc(14px + env(safe-area-inset-top)) 18px 14px;
  border-bottom: 3px solid var(--paper);
  flex-wrap: wrap;
  background: var(--night-2);
}

.ctl:disabled {
  opacity: .32;
  cursor: not-allowed;
  border-color: var(--edge);
  box-shadow: none;
  transform: none;
}

/* margin-left:auto, а не только justify-content:space-between на .bar —
   когда линк-визуализация слева скрыта (собеседнику её не показываем,
   см. hasDiagAccess), это единственный видимый flex-элемент, и без
   явного auto-margin его бы прижало к левому краю. */
.bar__right { display: flex; align-items: center; gap: 10px; margin-left: auto; }

.room {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--paper);
  padding: 6px 10px;
  border: 2px dashed var(--edge);
  border-radius: 9px;
}

/* Запасной путь для копирования ссылки, когда navigator.clipboard
   недоступен: показываем поле с уже выделенным текстом ссылки. */
.copy-fallback {
  font-family: var(--mono);
  font-size: 12px;
  width: 200px;
  max-width: 40vw;
  padding: 6px 10px;
  border-radius: 9px;
  border: 2px solid var(--hivis);
  background: var(--night-2);
  color: var(--paper);
  outline: none;
}

/* Таймер: сколько времени длится звонок с момента коннекта —
   бейдж, как "Dallas–Fort Worth · live" в шапке референса. */
/* Спокойный, не яркое пятно на всю шапку — просто "сколько идёт
   разговор", не требует внимания. Точка статична, без пульсации. */
.timer {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--muted);
  padding: 6px 10px;
  border-radius: 999px;
  border: 1.5px solid var(--edge);
  background: transparent;
  font-variant-numeric: tabular-nums;
}
.timer::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--rust);
  flex-shrink: 0;
}
/* Остаток бесплатного времени: без точки "идёт звонок", а в последние
   минуты подсвечивается, чтобы конец не стал сюрпризом. */
.timer--quota::before { display: none; }
.timer--quota[data-low="true"] { color: var(--hivis); border-color: var(--hivis); }

/* Сигнатура: живая схема соединения.
   Провод пунктирный и бежит, пока ICE перебирает пути.
   Становится сплошным жёлтым, когда канал поднялся — трафик-лайт
   из точек rust/hivis/steel как в шапке браузерного мокапа. */
.link { display: flex; align-items: center; gap: 10px; }

.link__node { display: flex; align-items: center; gap: 6px; }
.link__node em {
  font-style: normal;
  font-weight: 600;
  font-size: 13px;
  color: var(--paper);
}
.dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--edge);
  border: 2px solid var(--night-2);
  display: block;
  transition: background .3s;
}

.link__wire {
  width: 64px; height: 3px;
  background: var(--edge);
  position: relative;
  overflow: hidden;
  border-radius: 2px;
}
.link__wire i {
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--hivis), transparent);
  transform: translateX(-100%);
  opacity: 0;
}

.link__badge {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 4px 10px;
  border-radius: 999px;
  border: 2px solid var(--edge);
  background: var(--night);
}

.link[data-state="checking"] .link__wire i { opacity: 1; animation: run 1.1s linear infinite; }
.link[data-state="checking"] .dot { background: var(--steel); }

.link[data-state="live"] .link__wire { background: var(--hivis); }
.link[data-state="live"] .dot { background: var(--hivis); }
.link[data-state="live"] .link__badge { color: var(--hivis-ink); background: var(--hivis); border-color: var(--paper); }

.link[data-state="lost"] .link__wire { background: var(--rust); }
.link[data-state="lost"] .dot { background: var(--rust); }
.link[data-state="lost"] .link__badge { color: #fff; background: var(--rust); border-color: var(--paper); }

@keyframes run { to { transform: translateX(100%); } }

@media (prefers-reduced-motion: reduce) {
  .link__wire i { animation: none !important; opacity: .5 !important; transform: none !important; }
}

/* ── СЦЕНА + ЧАТ РЯДОМ ───────────────────────────────── */
/* Общая строка грида .call (та самая 1fr между шапкой и кнопками).
   .stage — резиновый (flex:1, сжимается сам и вместе с ним
   пересчитывается его внутренний грид из плиток), .chat — вторая
   колонка фиксированной ширины, когда открыт (см. медиа-запрос
   в конце блока .chat ниже: на узком экране докать некуда, там
   он остаётся всплывающей карточкой поверх видео, как раньше). */
.call__body {
  min-height: 0;
  display: flex;
  gap: 10px;
  padding: 12px 18px;
}
.call__body .stage { flex: 1; min-width: 0; }

@media (max-width: 680px) {
  /* Экран и так тесный (см. scroll-cue) — оставляем самую малость
     воздуха, чтобы скругление читалось, не отъедая место у видео. */
  .call__body { gap: 6px; padding: 6px 8px; }
}

/* ── СЦЕНА ───────────────────────────────────────────── */
/* Два режима, оба — сеточные, задаёт JS через data-mode на #stage:

   split — общей презентации нет: собеседники равнозначны, сцена
           делится пополам.
   share — кто-то шарит экран: контент занимает бОльшую часть сцены,
           а обе камеры уезжают в колонку (на телефоне — в строку)
           сбоку, как в Google Meet. См. applyLayout() в app.js —
           он только переключает data-mode и прячет неактивный
           экранный тайл, вся раскладка — на CSS-гриде. */
.stage {
  position: relative;
  overflow: hidden;
  background: var(--stage-bg);
  display: grid;
  gap: 3px;
  border-radius: var(--r);
  border: 2px solid var(--paper);
  box-shadow: var(--shadow-lg);
}

.tile { position: relative; overflow: hidden; background: var(--stage-bg); }
.tile[hidden] { display: none; }

.tile video {
  display: block;
  width: 100%; height: 100%;
  background: var(--stage-bg);
}
.tile[data-kind="cam"] video {
  object-fit: cover;
  /* Ландшафтная камера (16:9) на портретном телефоне обрезается очень
     сильно — cover масштабирует по высоте контейнера и режет бока. Лицо
     в кадре обычно в верхней трети, а не по центру, поэтому точку
     обрезки сдвигаем вверх, чтобы не срезало макушку. */
  object-position: 50% 30%;
}
.tile[data-kind="screen"] video { object-fit: contain; }
/* Своя камера — зеркалим, как в любом видеозвонке */
#localCam { transform: scaleX(-1); }

.tile__label {
  position: absolute;
  left: 8px; bottom: 8px;
  z-index: 1;
  padding: 4px 11px;
  border-radius: 999px;
  border: 2px solid var(--paper);
  background: var(--night);
  font-family: var(--mono);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--paper);
}

/* Без общей презентации: два равнозначных окна */
.stage[data-mode="split"] {
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr;
}

/* Только тестовая комната, пока второй участник не подключился:
   своя камера во весь экран, без пустой плитки собеседника. */
.stage[data-mode="solo"] {
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
}
@media (max-width: 680px) {
  .stage[data-mode="split"] { grid-template-columns: 1fr; grid-template-rows: 1fr 1fr; }
}

/* Показ экрана: контент — крупно слева, обе камеры — колонкой справа */
.stage[data-mode="share"] {
  grid-template-columns: 1fr clamp(160px, 18vw, 240px);
  grid-template-rows: 1fr 1fr;
}
.stage[data-mode="share"] .tile[data-kind="screen"] { grid-column: 1; grid-row: 1 / span 2; }
.stage[data-mode="share"] #tileRemoteCam { grid-column: 2; grid-row: 1; }
.stage[data-mode="share"] #tileLocalCam { grid-column: 2; grid-row: 2; }

@media (max-width: 680px) {
  .stage[data-mode="share"] {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: 1fr 96px;
  }
  .stage[data-mode="share"] .tile[data-kind="screen"] { grid-column: 1 / span 2; grid-row: 1; }
  .stage[data-mode="share"] #tileRemoteCam { grid-column: 1; grid-row: 2; }
  .stage[data-mode="share"] #tileLocalCam { grid-column: 2; grid-row: 2; }
}

/* Предупреждение о плохой связи. position:absolute — не участвует
   в грид-раскладке тайлов ниже, просто плавает поверх сцены. */
.quality-warn {
  position: absolute;
  top: 10px; left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  margin: 0;
  padding: 7px 16px;
  border-radius: 999px;
  border: 2px solid var(--paper);
  background: var(--rust);
  color: #fff;
  font-weight: 700;
  font-size: 12.5px;
  white-space: nowrap;
  max-width: calc(100% - 24px);
  text-overflow: ellipsis;
  overflow: hidden;
}

.stage__idle {
  position: absolute; inset: 0;
  display: grid; place-content: center; text-align: center;
  padding: 24px;
  z-index: 2;
  background: var(--overlay-bg);
  backdrop-filter: blur(6px);
}
.stage__idle p {
  font-family: var(--title-font);
  text-transform: var(--title-transform);
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -.01em;
  margin: 0;
  color: var(--on-dark);
}
.stage__idle-sub {
  font-family: var(--body) !important;
  font-size: 14px !important;
  font-weight: 500 !important;
  text-transform: none !important;
  color: var(--on-dark-muted);
  margin-top: 8px !important;
  max-width: 34ch;
}

.stage__idle #pingBtn { margin-top: 14px; }
.stage__idle-cooldown {
  font-family: var(--body) !important;
  font-size: 12px !important;
  font-weight: 500 !important;
  text-transform: none !important;
  color: var(--on-dark-muted);
  opacity: .7;
  margin: 8px 0 0 !important;
}

/* ── ДИАГНОСТИКА ─────────────────────────────────────── */
/* Видна только на устройствах с доступом (см. hasDiagAccess в
   app.js) — собеседнику весь блок вообще не попадает в разметку. */
.stats {
  position: absolute;
  right: 18px; top: 70px; bottom: 18px;
  width: min(340px, calc(100% - 36px));
  overflow-y: auto;
  background: var(--night-2);
  border: 2px solid var(--paper);
  border-radius: var(--r);
  box-shadow: var(--shadow-lg);
  padding: 18px;
  z-index: 5;
}
.stats__title {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--hivis);
  margin: 0 0 14px;
}
.stats__subtitle {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 16px 0 8px;
}
.stats__subtitle:first-of-type { margin-top: 0; }
.stats__grid { margin: 0; display: grid; gap: 9px; }
.stats__grid > div { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.stats__grid dt { color: var(--muted); font-size: 13px; }
.stats__grid dd { margin: 0; font-family: var(--mono); font-weight: 600; font-size: 12.5px; text-align: right; }
.stats__note {
  margin: 14px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
  border-top: 2px dashed var(--edge);
  padding-top: 12px;
}

/* ── ЧАТ ─────────────────────────────────────────────── */
/* Свой DataChannel, мимо сервера. Базово — всплывающая карточка
   поверх сцены (та же врезка, что у панели диагностики): это
   поведение для узкого экрана, где камеры и так вынуждены стоять
   в столбик и докать чат сбоку попросту некуда.

   На широком экране ниже переопределяем в докнутую колонку внутри
   .call__body — тогда .stage реально сжимается и его сетка плиток
   пересчитывается на оставшуюся ширину, а не просто закрывается
   карточкой сверху. */
.chat {
  position: absolute;
  right: 18px; top: 70px; bottom: 88px;
  width: min(320px, calc(100% - 36px));
  display: flex;
  flex-direction: column;
  background: var(--night-2);
  border: 2px solid var(--paper);
  border-radius: var(--r);
  box-shadow: var(--shadow-lg);
  padding: 16px;
  z-index: 5;
}
.chat__title {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--hivis);
  margin: 0 0 12px;
  flex-shrink: 0;
}
.chat__messages {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-right: 2px;
}
.chat__msg { display: flex; flex-direction: column; max-width: 86%; }
.chat__msg[data-from="me"] { align-self: flex-end; align-items: flex-end; }
.chat__msg[data-from="peer"] { align-self: flex-start; align-items: flex-start; }

.chat__bubble {
  margin: 0;
  padding: 8px 12px;
  border-radius: 12px;
  border: 2px solid var(--paper);
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.4;
  word-break: break-word;
  white-space: pre-wrap;
}
.chat__msg[data-from="me"] .chat__bubble { background: var(--hivis); color: var(--hivis-ink); }
.chat__msg[data-from="peer"] .chat__bubble { background: var(--night); color: var(--paper); }
/* Пока нет подтверждения от собеседника — приглушаем, отличимо от
   доставленных. Не ошибка, просто "в пути". */
.chat__msg--pending .chat__bubble { opacity: .55; }

.chat__time {
  font-family: var(--mono);
  font-size: 9.5px;
  color: var(--muted);
  margin-top: 3px;
}

.chat__hint {
  margin: 8px 0 0;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--rust);
  flex-shrink: 0;
}

.chat__form { display: flex; gap: 8px; margin-top: 10px; flex-shrink: 0; }
.chat__input {
  flex: 1;
  min-width: 0;
  padding: 10px 12px;
  background: var(--night);
  border: 2px solid var(--paper);
  border-radius: var(--rb);
  color: var(--paper);
  font-size: 14px;
  font-weight: 500;
  outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.chat__input:focus-visible { border-color: var(--hivis); box-shadow: var(--shadow-hivis); }

/* Кнопка чата теперь просто иконка без подписи — бейдж непрочитанных
   сидит в углу поверх неё, а не рядом строкой. */
.chat-badge {
  position: absolute;
  top: -5px; right: -5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--rust);
  border: 1.5px solid var(--paper);
  color: #fff;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
}

/* От этой ширины есть смысл докать чат колонкой, а не класть его
   карточкой поверх: сцене остаётся достаточно места, чтобы плитки
   не превратились в марки. Ниже порога — старое всплывающее
   поведение выше, без переопределений. Скругление и рамка — как
   у сцены рядом: те же токены, чтобы читалось одной парой карточек,
   а не сценой + случайной панелью сбоку. */
@media (min-width: 900px) {
  .chat {
    position: static;
    flex: 0 0 min(340px, 30vw);
    width: auto;
    top: auto; right: auto; bottom: auto;
  }
}

/* ── КНОПКИ ЗВОНКА ───────────────────────────────────── */
/* Три зоны в ряд: слева — комната/ссылка (как у Google Meet — код
   встречи в углу, не в центре внимания), по центру — сами кнопки
   управления, справа — пустой распорщик той же ширины, что и левая
   зона, чтобы центральная группа была центрирована по всей панели,
   а не только по остатку места. На узком экране зоны просто
   складываются в столбик (см. медиа-запрос ниже). */
.controls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 14px 18px calc(14px + env(safe-area-inset-bottom));
  border-top: 3px solid var(--paper);
  background: var(--night-2);
}
.controls__side { flex: 1 1 0; display: flex; align-items: center; gap: 8px; min-width: 0; }
.controls__side--left { justify-content: flex-start; }
.controls__side--right { justify-content: flex-end; }
.controls__main { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }

@media (max-width: 680px) {
  .controls { justify-content: center; }
  .controls__side--left { order: -1; flex: 0 0 100%; justify-content: center; }
  .controls__side--right { display: none; }
  .controls__main { flex: 0 0 100%; }
}

/* Только иконки — общеузнаваемые (микрофон, камера и т.д.), подпись
   не нужна и просто отвлекает; имя кнопки для скринридеров и подсказка
   при наведении — через aria-label/title в разметке. Квадратные,
   одного размера, чтобы ряд читался ровно. */
.ctl {
  position: relative; /* якорь для всплывашки мини-окна ниже */
  display: flex; align-items: center; justify-content: center;
  width: 50px; height: 50px;
  background: var(--night);
  border: 2px solid var(--paper);
  color: var(--paper);
  border-radius: var(--rb);
  box-shadow: var(--shadow-sm);
  transition: box-shadow .15s, transform .15s, border-color .15s, background .18s, opacity .18s;
}
.ctl:hover { transform: var(--lift-hover); box-shadow: var(--shadow-md); }
.ctl:active { transform: var(--lift-active); box-shadow: none; }
.ctl:focus-visible { outline: 3px solid var(--hivis); outline-offset: 2px; }
.ctl__ico { font-size: 19px; line-height: 1; }
/* Трубка под углом — узнаваемый "положить трубку", без подписи. */
.ctl__ico--hangup { display: inline-block; transform: rotate(135deg); }

.ctl[data-on="false"] { opacity: .5; box-shadow: none; }
.ctl[data-on="false"] .ctl__ico { filter: grayscale(1); }

#screenBtn[data-on="true"] { background: var(--steel); border-color: var(--paper); color: #fff; box-shadow: var(--shadow-steel); opacity: 1; }
#screenBtn[data-on="true"] .ctl__ico { filter: none; }

/* Запись — редкое действие, поэтому активное состояние подчёркиваем
   тревожным цветом (тот же rust, что у кнопки завершения звонка),
   чтобы не забыть, что запись идёт. */
#recBtn[data-on="true"] { background: var(--rust); border-color: var(--paper); color: #fff; box-shadow: var(--shadow-leave); opacity: 1; animation: rec-pulse 1.6s ease-in-out infinite; }
#recBtn[data-on="true"] .ctl__ico { filter: none; }
@keyframes rec-pulse {
  0%, 100% { box-shadow: var(--shadow-leave); }
  50% { box-shadow: var(--shadow-leave-hover); }
}
@media (prefers-reduced-motion: reduce) {
  #recBtn[data-on="true"] { animation: none; }
}

#chatBtn[aria-expanded="true"] { background: var(--hivis); border-color: var(--paper); color: var(--hivis-ink); box-shadow: var(--shadow-hivis); }

#pipBtn[data-on="true"] { background: var(--hivis); border-color: var(--paper); color: var(--hivis-ink); box-shadow: var(--shadow-hivis); opacity: 1; }
#pipBtn[data-on="true"] .ctl__ico { filter: none; }

/* Пробел как рация: пока держим — микрофон явно светится, отличимо
   от обычного "включён вручную". Жёлтый контур + тень, без анимации. */
#micBtn[data-ptt="true"] {
  background: var(--hivis);
  border-color: var(--paper);
  color: var(--hivis-ink);
  box-shadow: var(--shadow-hivis);
}

.ctl--leave { background: var(--rust); border-color: var(--paper); color: #fff; box-shadow: var(--shadow-leave); }
.ctl--leave:hover { box-shadow: var(--shadow-leave-hover); }
.ctl--leave:active { box-shadow: var(--shadow-leave-active); }

/* Подсказка на кнопке "Мини-окно": зачем она вообще нужна. Всплывает
   по наведению/фокусу, как .hint в лобби, плюс кнопка "Понятно" внутри,
   которая гасит её насовсем на этом устройстве (см. pipHintDismissed
   в app.js) — после этого .ctl-wrap получает data-dismissed и hover
   больше её не поднимает. */
.ctl-wrap { position: relative; display: inline-flex; }
.ctl__hint {
  position: absolute;
  bottom: calc(100% + 12px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  width: 260px;
  padding: 13px 15px;
  border-radius: var(--rb);
  border: 2px solid var(--paper);
  box-shadow: var(--shadow-md);
  background: var(--night-2);
  text-align: left;
  opacity: 0;
  visibility: hidden;
  transition: opacity .15s, transform .15s;
  pointer-events: none;
  z-index: 6;
}
.ctl__hint p { margin: 0 0 10px; font-size: 12.5px; font-weight: 500; line-height: 1.5; color: var(--paper); }
.ctl-wrap:not([data-dismissed="true"]):hover .ctl__hint,
.ctl-wrap:not([data-dismissed="true"]):focus-within .ctl__hint,
.ctl-wrap[data-open="true"]:not([data-dismissed="true"]) .ctl__hint {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}
/* "Ярлык звонка" стоит у левого края панели — подсказка растёт вправо
   от кнопки, а не по центру, иначе уезжает за экран. */
.ctl__hint--start { left: 0; transform: translateY(4px); }
.ctl-wrap:not([data-dismissed="true"]):hover .ctl__hint--start,
.ctl-wrap:not([data-dismissed="true"]):focus-within .ctl__hint--start,
.ctl-wrap[data-open="true"]:not([data-dismissed="true"]) .ctl__hint--start { transform: translateY(0); }
/* Хвостик снизу — показывает, к какой кнопке относится подсказка. */
.ctl__hint::after {
  content: '';
  position: absolute;
  bottom: -8px;
  left: 50%;
  width: 12px;
  height: 12px;
  margin-left: -7px;
  background: var(--night-2);
  border-right: 2px solid var(--paper);
  border-bottom: 2px solid var(--paper);
  transform: rotate(45deg);
}
.ctl__hint--start::after { left: 40px; }
/* На узком экране левая зона панели центрируется и кнопка оказывается
   у правого края — подсказка растёт влево от неё. */
@media (max-width: 680px) {
  .ctl__hint--start { left: auto; right: 0; }
  .ctl__hint--start::after { left: auto; right: 40px; }
}

/* ── МОДАЛКА ПОДТВЕРЖДЕНИЯ ВЫХОДА ─────────────────────── */
.modal {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--overlay-bg);
  backdrop-filter: blur(3px);
}
.modal__card {
  width: min(360px, 100%);
  padding: 22px;
  border-radius: var(--r);
  border: 3px solid var(--paper);
  box-shadow: var(--shadow-lg);
  background: var(--night-2);
  text-align: center;
}
.modal__title {
  font-family: var(--title-font);
  text-transform: var(--title-transform);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -.01em;
  margin: 0 0 10px;
}
.modal__text { margin: 0 0 20px; color: var(--muted); font-size: 14px; line-height: 1.5; }
/* Окно из одного вопроса ("Завершить звонок?") — без текста, воздух как с ним. */
.modal__title + .modal__actions { margin-top: 20px; }
.modal__actions { display: flex; gap: 10px; justify-content: center; }
.modal__actions .btn { flex: 1; }

.ctl--leave-solid {
  background: var(--rust);
  color: #fff;
  border: 2px solid var(--paper);
  box-shadow: var(--shadow-leave);
}
.ctl--leave-solid:hover { box-shadow: var(--shadow-leave-hover); }
.ctl--leave-solid:active { box-shadow: var(--shadow-leave-active); transform: var(--lift-active); }

/* ── ТОСТ ────────────────────────────────────────────── */
.toast {
  position: fixed;
  left: 50%; bottom: 96px;
  transform: translateX(-50%);
  background: var(--night-2);
  border: 2px solid var(--paper);
  border-left: 5px solid var(--hivis);
  border-radius: var(--rb);
  box-shadow: var(--shadow-md);
  padding: 12px 16px;
  font-size: 14px;
  font-weight: 500;
  max-width: min(460px, calc(100% - 36px));
  z-index: 10;
  line-height: 1.45;
}

/* ── ПОДСКАЗКА "ПРОКРУТИТЕ ВНИЗ" ─────────────────────── */
/* Показывается, только когда экран звонка реально не помещается
   в высоту вьюпорта — например на невысоких телефонах, где шапка
   и панель кнопок вместе не оставляют места под видео. */
.scroll-cue {
  position: fixed;
  left: 50%; top: calc(10px + env(safe-area-inset-top));
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 8px;
  background: var(--hivis);
  color: var(--hivis-ink);
  border: 2px solid var(--paper);
  border-radius: 999px;
  padding: 10px 16px;
  font-family: var(--mono);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: .04em;
  box-shadow: var(--shadow-rust);
  z-index: 30;
  animation: cueBounce 1.4s ease-in-out infinite;
}
.scroll-cue i { font-style: normal; font-size: 15px; line-height: 1; }
.scroll-cue:active { transform: translateX(-50%) translateY(2px); }

@keyframes cueBounce {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(4px); }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-cue { animation: none; }
}

@media (max-width: 560px) {
  .link__wire { width: 36px; }
}
