:root {
  color-scheme: light dark;
  --accent: #3390ec;          /* синий Telegram */
  --bg: #ffffff;
  --bg-chat: #e6ebee;         /* фон ленты сообщений */
  --bubble-in: #ffffff;
  --bubble-out: #eeffde;      /* зелёный «свои» как в Telegram */
  --text: #000000;
  --muted: #707579;
  --line: #e4e4e5;
  --header: #ffffff;
}
/* Тёмная тема. Значения одни и те же в двух местах, и это осознанно: своя
   тема должна побеждать системную, а через одну переменную такое в CSS не
   выражается. data-theme ставит короткий скрипт в шапке — до первой отрисовки,
   иначе на секунду мигает белым. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #17212b;
    --bg-chat: #0e1621;
    --bubble-in: #182533;
    --bubble-out: #2b5278;
    --text: #ffffff;
    --muted: #8a949d;
    --line: #101921;
    --header: #17212b;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #17212b;
  --bg-chat: #0e1621;
  --bubble-in: #182533;
  --bubble-out: #2b5278;
  --text: #ffffff;
  --muted: #8a949d;
  --line: #101921;
  --header: #17212b;
}
:root[data-theme="light"] { color-scheme: light; }

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
/* hidden обязан побеждать: любое display в правилах ниже перебивает его
   по специфичности, и «скрытый» элемент остаётся на экране пустым. */
[hidden] { display: none !important; }
/* Двойной тап больше не зумит страницу — это мессенджер, а не документ. */
html { touch-action: manipulation; }
/* Высота корня = настоящая высота окна. Нужна странице переписки: см. .chatpage. */
html { height: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 16px/1.35 -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
}

/* ---------- вход ---------- */
/* Вход: два способа друг под другом, а не бок о бок. В строку они не влезали
   на телефон и уезжали за край экрана. */
.center {
  display: flex; flex-direction: column; min-height: 100vh;
  align-items: center; justify-content: center;
  padding: 24px 16px; padding-bottom: max(24px, env(safe-area-inset-bottom));
}
.card {
  display: flex; flex-direction: column; gap: 12px; padding: 0;
  width: 100%; max-width: 320px;
}
.card + .or, .or + .card { margin-top: 18px; }
.or {
  display: flex; align-items: center; gap: 10px;
  width: 100%; max-width: 320px; color: var(--muted); font-size: 13px;
}
.or::before, .or::after {
  content: ""; flex: 1; height: 1px; background: var(--line);
}
.card h1 { text-align: center; }
.error { color: #e53935; margin: 0; text-align: center; }

/* Сообщение, от которого в базе не осталось ни текста, ни вложения. Бледно и
   курсивом: это не слова гостя, а наша приписка о том, что смотреть надо в
   самом мессенджере. */
.no-body { color: var(--muted); font-style: italic; }

/* Кнопка «Выезд…» с родным календарём внутри. Само поле прячем: на телефоне
   оно рисуется по-своему в каждом браузере и в ряд чипсов не встаёт, а
   нажатие по кнопке всё равно открывает календарь. */
.chip-date { position: relative; overflow: hidden; }
.chip-date input[type="date"] {
  position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%;
  border: 0; padding: 0;
}
/* Крестик «снять день» поверх невидимого поля: иначе касание уходит в поле и
   открывает календарь. Живёт только у включённого чипа. */
.chip-date.on { padding-right: 30px; }
.chip-date .chip-x {
  position: absolute; top: 0; bottom: 0; right: 0; z-index: 1;
  width: 30px; height: auto; padding: 0; border: 0; border-radius: 0;
  background: transparent; color: inherit; font-size: 13px; line-height: 1;
}

/* Запасной путь на втором шаге входа. Нарочно тихая: главная кнопка тут одна
   — «Войти», а «прислать на почту» нужна, только когда телеграм молчит. */
button.quiet {
  background: transparent; color: var(--muted);
  border: 1px solid var(--line); font-size: 13px;
}

/* ---------- шапка ---------- */
header {
  display: flex; gap: 10px; align-items: center;
  padding: 10px 14px; padding-top: max(10px, env(safe-area-inset-top));
  background: var(--header); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 5;
}
h1 { font-size: 19px; margin: 0; flex: 1; font-weight: 600; min-width: 0; }
/* Значков в шапке пять, и выпадающий список аккаунтов вытеснял последний за
   край экрана. Пусть ужимается он, а кнопки остаются целыми. */
#account-filter {
  min-width: 0; flex: 0 1 auto; max-width: 42vw;
  overflow: hidden; text-overflow: ellipsis;
}
header .gear { flex: none; }
.badge:not(:empty) {
  background: var(--accent); color: #fff; border-radius: 12px;
  padding: 1px 8px; font-size: 13px; font-weight: 500; vertical-align: middle;
}

input, button, select { font: inherit; }
input, select {
  padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--bg); color: var(--text);
}
button {
  padding: 10px 14px; border: 0; border-radius: 10px;
  background: var(--accent); color: #fff; cursor: pointer;
}
select { padding: 6px 10px; font-size: 16px; }   /* 16px — без зума iPhone при фокусе */

#enable-push {
  display: block; width: calc(100% - 28px); margin: 10px 14px;
  background: var(--accent); font-size: 15px;
}
#enable-push.hint { background: transparent; color: var(--muted); font-size: 14px;
                    border: 1px solid var(--line); cursor: default; }

/* ---------- список чатов ---------- */
ul { list-style: none; margin: 0; padding: 0; }
.chat a {
  display: grid; grid-template-columns: 48px 1fr;
  grid-template-areas: "av row1" "av item" "av row2" "av acc";
  column-gap: 12px; align-items: center;
  padding: 9px 14px; text-decoration: none; color: inherit;
}
.chat + .chat a { border-top: 1px solid var(--line); }
.chat a:active { background: var(--bg-chat); }

.av-wrap { grid-area: av; position: relative; width: 48px; height: 48px;
           flex-shrink: 0; }
.chan {
  position: absolute; right: -3px; bottom: -3px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--bg); padding: 1.5px;
  display: flex; align-items: center; justify-content: center;
}
/* img — для иконок, вшитых картинкой (Циан); остальные значки SVG. */
.chan svg, .chan img { width: 100%; height: 100%; display: block;
                       border-radius: 50%; }
.chatpage header .av-wrap { width: 36px; height: 36px; }
.chatpage header .chan { width: 15px; height: 15px; font-size: 8px; }

.avatar {
  width: 48px; height: 48px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 17px; font-weight: 600; letter-spacing: .5px;
  flex-shrink: 0;
}
.avatar.photo { background-size: cover; background-position: center; }
.avatar.small { width: 36px; height: 36px; font-size: 14px; }
/* min-width:0 обязателен: без него flex-элемент с длинным текстом отказывается
   сжиматься, строка распирается и залезает на соседей. */
.row1 { grid-area: row1; display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.row2 { grid-area: row2; display: flex; align-items: center; gap: 8px; min-width: 0; }
/* Обычный вес у всех: раньше было 600 против 700 у непрочитанного — разница
   на телефоне неразличима, и весь список выглядел непрочитанным.
   Признак непрочитанного — синий счётчик, как в Telegram. */
.chat .title { font-weight: 500; flex: 1; min-width: 0; overflow: hidden;
               text-overflow: ellipsis; white-space: nowrap; }
.chat .time { font-size: 12px; color: var(--muted); flex-shrink: 0; }
.chat .preview {
  flex: 1; min-width: 0; font-size: 15px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat .preview .mine { color: var(--accent); }
.chat .count {
  background: var(--accent); color: #fff; border-radius: 11px;
  min-width: 22px; height: 22px; padding: 0 6px; font-size: 13px; font-weight: 500;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.chat .account { grid-area: acc; font-size: 12px; color: var(--muted); opacity: .8; }
.chat.unread .title { font-weight: 700; }
.chat.unread .preview { color: var(--text); }
/* Кнопка — сосед ссылки во flex, а не наложение поверх неё:
   иначе она перекрывает превью и счётчик непрочитанного. */
.chat { display: flex; align-items: center; }
.chat > a { flex: 1; min-width: 0; }
.noreply {
  flex-shrink: 0; margin: 0 14px 0 4px;
  width: 36px; height: 36px; padding: 0; border-radius: 50%;
  font-size: 17px; line-height: 1;
  background: transparent; color: var(--muted); border: 1px solid var(--line);
}
.noreply:active { background: var(--accent); color: #fff; border-color: var(--accent); }
.gear { text-decoration: none; font-size: 20px; color: var(--muted); padding: 0 2px; }

/* ---------- настройки ---------- */
.settings section { padding: 14px; border-bottom: 1px solid var(--line); }
.settings h2 { font-size: 14px; text-transform: uppercase; letter-spacing: .5px;
               color: var(--muted); margin: 0 0 10px; font-weight: 600; }
.settings .note { font-size: 13px; color: var(--muted); margin: 8px 0 0; }
.settings code { font-size: 12px; word-break: break-all; }
.settings #enable-push { width: 100%; margin: 0; }
.accounts li { display: grid; grid-template-columns: 10px 1fr auto;
               grid-template-areas: "dot label state" ". phone state";
               gap: 2px 10px; align-items: center; padding: 8px 0;
               border-bottom: 1px solid var(--line); }
.accounts li:last-child { border-bottom: 0; }
.accounts .dot { grid-area: dot; width: 8px; height: 8px; border-radius: 50%; }
.accounts .dot.ok { background: #4caf50; }
.accounts .dot.bad { background: #e53935; }
.accounts .label { grid-area: label; font-weight: 600; }
.accounts .phone { grid-area: phone; font-size: 13px; color: var(--muted); }
.accounts .state { grid-area: state; font-size: 13px; color: var(--muted); }
button.danger { background: transparent; color: #e53935;
                border: 1px solid var(--line); width: 100%; }

/* ---------- переписка ---------- */
/* Высоту берём из «видимой области», а не из окна. На айфоне полоса браузера
   прячется при прокрутке, и окно оказывается выше того, что реально видно:
   под строкой ввода зияла пустота, а стоило потянуть страницу — она
   схлопывалась. Отсюда 100dvh.

   Но на андроиде в установленном приложении Chrome врёт в другую сторону:
   100dvh = 787 при окне 730 — он прибавляет высоту своей панели адреса,
   которой в приложении нет вовсе (снято с Samsung, Chrome 152, standalone).
   Страница выходила на 57px выше экрана, и строка ввода целиком уезжала за
   нижний край. Поэтому ещё и не выше настоящего окна: 100% от html — это
   documentElement.clientHeight, и он там честный. На айфоне в приложении
   обе величины равны, min ничего не меняет.

   Клавиатура ни одну из этих величин не уменьшает: она лишь урезает видимую
   область и сдвигает её к полю ввода. На это время страницу сажает на
   видимую область скрипт — top и height строкой стиля, см.
   перепискаПодКлавиатурой в app.js; для top и нужен position: relative ниже. */
.chatpage { display: flex; flex-direction: column; height: 100dvh;
            height: min(100dvh, 100%); }
.chatpage header .who { display: flex; flex-direction: column; line-height: 1.2; }
/* Обёртка «аватар + имя» (08.10.2026) нужна только «стеклу» — без него её как
   бы нет, и порядок в шапке прежний: назад, аватар, поиск, колокольчик, имя. */
.chatpage header .who-pill { display: contents; }
.chatpage header .back { order: 0; }
.chatpage header .av-wrap { order: 1; }
.chatpage header #find-btn { order: 2; }
.chatpage header #remind { order: 3; }
.chatpage header .who { order: 4; }
.chatpage header .lead-head { order: 5; }
.chatpage header .name { font-weight: 600; font-size: 17px; }
.chatpage header .account { font-size: 12px; color: var(--muted); }
.back { text-decoration: none; font-size: 30px; color: var(--accent);
        line-height: 1; padding: 0 6px 4px 0; }

#feed {
  flex: 1; overflow-y: auto; background: var(--bg-chat);
  padding: 12px 10px; display: flex; flex-direction: column; gap: 4px;
  /* Дотянул ленту до края — прокрутка не должна переходить на страницу:
     при открытой клавиатуре это уводит шапку (см. touchmove в 15-клавиатура.js). */
  overscroll-behavior-y: contain;
}
.msg {
  position: relative; max-width: 80%; width: fit-content;
  padding: 6px 10px 6px 10px; border-radius: 12px;
  /* Долгое нажатие открывает меню — выделять текст при этом нельзя: лупа с
     «копировать» перекрывает кнопки. Копирование есть отдельным пунктом. */
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  background: var(--bubble-in); box-shadow: 0 1px 1px rgba(0,0,0,.08);
  font-size: 16px; word-wrap: break-word; overflow-wrap: anywhere;
}
.msg.in  { align-self: flex-start; border-bottom-left-radius: 4px; }
.msg.out { align-self: flex-end; background: var(--bubble-out);
           border-bottom-right-radius: 4px; }
.msg .text { white-space: pre-wrap; }
.msg .meta { font-size: 11px; color: var(--muted); float: right;
             margin: 6px 0 0 8px; user-select: none; }
/* Ещё не ушедшее сообщение заметно бледнее отправленного: по одному только
   значку в углу разница не читается, а на бегу нужно видеть её боковым
   зрением. */
.msg.out.pending { opacity: .6; }

/* Настоящий вращающийся кружок вместо мигающего символа: мигание читается
   как ошибка, вращение — как работа. Рисуем рамкой, чтобы не тащить картинку. */
.ticks.sending {
  display: inline-block; width: 9px; height: 9px; vertical-align: -1px;
  border: 1.5px solid currentColor; border-top-color: transparent;
  border-radius: 50%; animation: вертушка .8s linear infinite;
  opacity: .8; margin-left: 2px;
}
@keyframes вертушка { to { transform: rotate(360deg); } }
/* Кто отключил анимации в системе — тому статичный кружок, а не мельтешение. */
@media (prefers-reduced-motion: reduce) {
  .ticks.sending { animation: none; border-top-color: currentColor; opacity: .5; }
}
.msg.out.failed { background: #e57373; color: #fff; }
.msg.out.failed .meta, .msg.out.failed .err { color: rgba(255,255,255,.85); }
/* Постоянный размер рамки: картинка грузится лениво, и без фиксированной
   высоты лента дёргалась бы под пальцем по мере подгрузки. */
img.media, video.media {
  width: 240px; max-width: 100%; height: 180px; object-fit: cover;
  border-radius: 8px; display: block; margin: -2px 0 4px;
  background: rgba(128,128,128,.18);
}
/* «Переслано от …» — зелёная строка над содержимым, как в Telegram. */
.msg .fwd { display: block; font-size: 12px; color: #2e7d32; margin: 0 0 4px; line-height: 1.2; }
.msg.out .fwd { color: #1e6b2e; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .msg .fwd { color: #93d69a; } }
:root[data-theme="dark"] .msg .fwd { color: #93d69a; }
/* Фото с известными размерами: рамка по пропорциям (ширина и высота заданы
   inline из рамкаФото), как в Telegram — вертикальный скриншот высокий,
   горизонтальное фото широкое, ничего не обрезается. */
img.media.photo.sized { object-fit: contain; max-width: 100%; }
/* Крошка-заглушка растянута под рамку и слегка размыта; сама картинка
   ложится сверху, когда загрузится. */
img.media.photo.blurred { background-color: transparent; }

/* Внутри формы поля ввода, над её верхом: поле растёт с текстом, и отсчёт
   от низа страницы прятал кнопку под полем со второй строки (аудит
   17.09.2026). Селекторы с #composer — иначе побеждает «#composer button». */
#composer #scroll-down {
  position: absolute; right: 12px; bottom: calc(100% + 12px);
  width: 40px; height: 40px; padding: 0; border-radius: 50%;
  font-size: 20px; line-height: 1;
  background: var(--header); color: var(--accent);
  box-shadow: 0 2px 8px rgba(0,0,0,.2);
  opacity: 0; pointer-events: none; transition: opacity .15s;
}
#composer #scroll-down.shown { opacity: 1; pointer-events: auto; }
/* Над полем бывают плашки «в ответ на» (~46px с отступом) и «пишет ответ»
   (~38px) — кнопка поднимается над ними, иначе ложилась на крестик «не
   отвечать» (08.10.2026). */
#quote-bar:not([hidden]) ~ #composer #scroll-down { bottom: calc(100% + 58px); }
#others-draft:not([hidden]) ~ #composer #scroll-down { bottom: calc(100% + 50px); }
#others-draft:not([hidden]) ~ #quote-bar:not([hidden]) ~ #composer #scroll-down { bottom: calc(100% + 96px); }
.chatpage { position: relative; top: 0; }
/* Под клавиатурой страницу сажает на видимую область скрипт (см.
   перепискаПодКлавиатурой в app.js). Браузер рисует сдвиг области анимацией
   в четверть секунды, а сообщает о нём сразу конечный — переезжаем той же
   анимацией, чтобы шапка на экране не двигалась. Только на телефоне: на
   компьютере высота меняется от окна, и ехать ей незачем. */
@media (hover: none) and (pointer: coarse) {
  .chatpage { transition: top .25s ease-in-out, height .25s ease-in-out; }
}

/* Полоска «загружаю более раннее».

   До этой правки у неё не было НИ ОДНОГО правила стилей, и стояла она обычным
   блоком ПОСЛЕ ленты. Пока она видна, лента (flex:1) ровно на её высоту
   короче — а значит содержимое, прижатое к низу, дёргается дважды: когда
   полоска появилась и когда исчезла. Между этими двумя мгновениями проходит
   целый поход в сеть: показ идёт ДО fetch, скрытие в finally после него.

   На айфоне это и есть «при открытии некоторых чатов сообщения один раз слегка
   подпрыгивают». Поймал оператор записью экрана; ни один замер до этого не
   помог, потому что искали изменение высоты СОДЕРЖИМОГО, а менялась высота
   самой ленты. Различитель тоже сходится: полоска показывается только там, где
   есть что подгружать сверху, то есть в переписках длиннее шестидесяти
   сообщений.

   Теперь она висит НАД лентой и в раскладке места не занимает вовсе, поэтому
   подвинуть ничего не может. Отступ снизу тот же, что у кнопки «вниз», — он
   уже выверен по высоте поля ввода. */
#composer #load-older {
  position: absolute; left: 50%; bottom: calc(100% + 12px); transform: translateX(-50%);
  z-index: 4; pointer-events: none;
  padding: 5px 12px; border-radius: 14px;
  background: var(--header); color: var(--muted); font-size: 13px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .18);
}

/* Стикер — без пузыря, как в Telegram */
.msg.bare { background: none; box-shadow: none; padding: 2px 0; max-width: 60%; }
.msg.bare .meta { color: var(--muted); }
.sticker { width: 160px; height: 160px; object-fit: contain; display: block; }
.file { color: var(--accent); text-decoration: none; }
/* Документ с превью: первая страница PDF слева, имя файла справа — как в
   Telegram. Пока картинка не приехала (или её нет вовсе), ряд выглядит как
   прежняя строка со скрепкой: класс has-page ставит скрипт по загрузке. */
.file.with-page { display: flex; align-items: center; gap: 8px; }
.file .page {
  width: 44px; height: 58px; object-fit: cover; object-position: top center;
  border-radius: 6px; border: 1px solid var(--line); background: #fff;
  flex: 0 0 auto;
}
.file .nm { min-width: 0; word-break: break-word; }
/* Со страницей скрепка лишняя: картинка и так говорит, что это файл. */
.file .clip { margin-right: 4px; }
.file.has-page .clip { display: none; }
.msg .err { display: block; font-size: 12px; margin-top: 2px; }
.retry { font-size: 12px; padding: 3px 10px; margin-top: 6px;
         background: rgba(255,255,255,.25); }

#composer {
  display: flex; gap: 6px; align-items: center; padding: 4px 10px;
  /* Полоса под полем — место домашней «палочки» айфона. Полный отступ там
     лишний: строка ввода и без того отодвинута собственным полем, и внизу
     зияла пустая белая полоса в палец высотой. Оставляем ровно столько,
     чтобы палец не попадал в системный жест. */
  padding-bottom: max(4px, calc(env(safe-area-inset-bottom) - 22px));
  /* Подложка тянется до самого низа экрана: иначе под строкой видна белая
     полоса фона страницы — та самая, что не давала покоя. */
  box-shadow: 0 40px 0 var(--header);
  background: var(--header); border-top: 1px solid var(--line);
}
/* Поле растёт вместе с текстом, как в телеграме: длинную ссылку или абзац
   нельзя править вслепую в одну строку. Потолок — ниже (~15 видимых строк
   при border-box), дальше поле прокручивается внутри себя. */
#composer #text {
  flex: 1; min-width: 0; border-radius: 20px; padding: 11px 16px;
  /* До шестнадцати строк поле растёт, дальше прокручивается внутри себя.
     Тексты для гостей длинные, с абзацами, и править их в окошко на шесть
     строк — значит не видеть, что пишешь. */
  overflow-y: auto; max-height: 21.6em; line-height: 1.35;
  font: inherit; font-size: 16px;   /* меньше 16px — iOS зумит страницу при фокусе */
  border: 1px solid var(--line); background: var(--bg); color: var(--text);
  white-space: pre-wrap; word-break: break-word; outline: none;
  -webkit-user-select: text; user-select: text;
}
/* Подсказка вместо placeholder: у contenteditable его нет. */
#composer #text:empty::before {
  content: attr(data-placeholder); color: var(--muted); pointer-events: none;
}
#composer { align-items: flex-end; }   /* кнопки держатся низа, поле растёт вверх */
#composer button { border-radius: 50%; width: 42px; height: 42px; padding: 0;
                   font-size: 17px; flex-shrink: 0; }
#composer #plus {
  background: transparent; color: var(--muted); font-size: 26px;
  font-weight: 300; line-height: 1; position: relative;
}

#attach-bar, #schedule-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px; font-size: 14px;
  background: var(--header); border-top: 1px solid var(--line); color: var(--muted);
}
#attach-bar span, #schedule-bar label { flex: 1; min-width: 0;
                                        overflow: hidden; text-overflow: ellipsis;
                                        white-space: nowrap; }
#attach-bar button, #schedule-bar button {
  width: 28px; height: 28px; padding: 0; font-size: 14px;
  background: transparent; color: var(--muted); border: 1px solid var(--line);
  border-radius: 50%; flex-shrink: 0;
}
#schedule-bar input { padding: 6px 8px; font-size: 14px; margin-left: 6px; }
/* Техническая приписка моста («бронь оформлена 12.09 в 16:45»): отдельной
   бледной строкой — это не слова гостя, а пометка системы. */
.msg .tech { display: block; font-size: 11px; color: var(--muted); margin-top: 3px; }
.msg .scheduled { display: block; font-size: 12px; opacity: .85; margin-top: 2px; }

/* Отложенная отправка: таймер рядом с «отправить», как в Telegram */

#sched-badge {
  position: absolute; top: -2px; right: -4px;
  background: var(--accent); color: #fff; border-radius: 9px;
  font-size: 10px; line-height: 1; padding: 3px 5px; font-weight: 600;
}
#schedule-pop {
  position: absolute; right: 10px; bottom: 68px; z-index: 10;
  min-width: 210px; max-width: calc(100vw - 20px);
  background: var(--header); border: 1px solid var(--line); border-radius: 14px;
  padding: 10px; box-shadow: 0 6px 24px rgba(0,0,0,.28);
  display: flex; flex-direction: column; gap: 6px; font-size: 15px;
}
#schedule-pop .title { font-size: 12px; color: var(--muted);
                       text-transform: uppercase; letter-spacing: .4px;
                       padding: 2px 4px 4px; }
#schedule-pop .quick {
  background: transparent; color: var(--text); text-align: left;
  padding: 10px 12px; border-radius: 10px; font-size: 15px;
}
#schedule-pop .quick:active { background: var(--bg-chat); }
#schedule-pop .custom { display: flex; flex-direction: column; gap: 6px;
                        font-size: 12px; color: var(--muted);
                        padding: 6px 4px 2px; border-top: 1px solid var(--line); }
#schedule-pop .custom input { width: 100%; font-size: 16px; color: var(--text); }  /* 16px — без зума на iPhone */
#schedule-pop .row { display: flex; gap: 8px; }
#schedule-pop button { width: auto; height: auto; border-radius: 8px;
                       padding: 8px 14px; font-size: 14px; }
#sched-clear { background: transparent; color: var(--muted);
               border: 1px solid var(--line); }
.msg .scheduled button { width: auto; height: auto; border-radius: 8px;
                         padding: 2px 8px; font-size: 11px; margin-left: 6px;
                         background: rgba(255,255,255,.3); color: inherit; }

/* Настройки */
.toggle { display: flex; align-items: center; gap: 10px; font-size: 15px; }
.toggle input { width: 20px; height: 20px; }
button.wide { width: 100%; }
.settings textarea, .settings input:not([type=checkbox]), .settings select {
  width: 100%; font: inherit; padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--bg); color: var(--text);
}

.msg .ticks { opacity: .7; }
.msg .ticks.read { color: #4fae4e; opacity: 1; }
/* Две галочки ставим внахлёст: врозь они читаются как два отдельных значка,
   а это один знак «прочитано». Правый отступ возвращаем, чтобы съеденное
   letter-spacing место не липло к краю пузыря. */
.msg .ticks.read { letter-spacing: -0.32em; padding-right: 0.32em; }
.msg.out .ticks.read { color: #59b96a; }
.msg .edited { font-size: 11px; color: var(--muted); margin-left: 6px; }
/* Кто отправил — тише времени: подпись нужна, когда её ищут глазами, и не
   должна спорить с текстом сообщения. */
.msg .by {
  font-size: 11px; color: var(--muted); opacity: .75;
  float: right; margin: 6px 0 0 8px; user-select: none;
}
/* Долгое нажатие вместо клика: курсор-указатель обманывал бы. */
.msg.out[data-sent="1"] { cursor: default; -webkit-touch-callout: none; }

/* Окно ввода: prompt() браузера однострочный и режет длинный текст */
.modal-back {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(0,0,0,.45);
  display: flex; align-items: flex-end; justify-content: center;
  padding: 12px; padding-bottom: max(12px, env(safe-area-inset-bottom));
  /* Страница растянута под статус-бар (viewport-fit=cover): высокое окно,
     отцентрованное в видимой над клавиатурой области, верхом заезжало под
     часы. Сверху отступаем на высоту статус-бара. */
  padding-top: max(12px, env(safe-area-inset-top));
  /* На iPhone клавиатура не сжимает окно страницы, а сдвигает его вверх, и
     всё, что стоит fixed, уезжает под статус-бар. Подложку сажаем на
     видимую область (visualViewport, см. подогнатьОкна в app.js) — окна
     внутри центрируются уже в ней и, если не влезают, прокручиваются. */
  box-sizing: border-box;
  /* Подложка обрезана ровно по верху клавиатуры, а клавиатура iOS 26 —
     полупрозрачная: её верхние ~45px (ряд «< > Готово») показывают страницу
     ПОД собой, и та там не затемнена — над панелью висит светлая полоса с
     текстом чата (снято в симуляторе 13.09.2026, окна залога). Тень с
     разлётом продолжает затемнение под клавиатурой; сверху и по бокам она
     уходит за экран. */
  box-shadow: 0 0 0 200vh rgba(0,0,0,.45);
}
/* В установленном приложении на iPhone окно страницы — 894pt при экране 956:
   нижние 62pt под окном WebKit красит только цветом холста, и ни fixed-подложка,
   ни её тень туда не достают — под открытым окном оставалась белая полоса
   (снято в симуляторе 13.09.2026; в тёмной теме полоса тёмная — это холст).
   Пока окно открыто, холст красим в тот же затемнённый цвет. Цвет полосы
   WebKit берёт у body (у html — нет, проверено), и только цвет, без картинки:
   поэтому у body затемнённый ЦВЕТ, а поверх него градиент цвета страницы —
   сама страница остаётся прежней, полоса под ней темнеет. */
html:has(.modal-back:not([hidden])),
body:has(.modal-back:not([hidden])) {
  background-color: color-mix(in srgb, var(--bg) 55%, black);
  background-image: linear-gradient(var(--bg), var(--bg));
}
/* Фото во весь экран и обрезка — почти чёрные, и полоса под ними тоже
   (раньше светлела под чёрным экраном; 08.10.2026). */
html:has(.lightbox), body:has(.lightbox),
html:has(#crop-back:not([hidden])), body:has(#crop-back:not([hidden])) {
  background-color: #0b0b0b;
  background-image: linear-gradient(var(--bg), var(--bg));
}
@media (min-height: 600px) { .modal-back { align-items: center; } }
/* Окна с полями ввода (доплата, залог, заявка, заметка) на телефоне прижаты
   к ВЕРХУ видимой области, а не к центру. Центрированное окно при клавиатуре
   приходилось везти вверх в такт её выезду — по памяти высоты, которая для
   полей формы не сходилась на панель «< > Готово», и окно дёргалось дважды.
   Прижатому к верху ехать некуда: клавиатура накрывает его низ, и только.
   Кнопки под клавиатурой — как в любой форме на телефоне: «Готово», и они на
   месте. См. подогнатьОкна в app.js. На компьютере клавиатуры нет — по центру. */
@media (hover: none) and (pointer: coarse) {
  /* Сдвиг области за окном (36px, см. посадить в перепискаПодКлавиатурой)
     iPhone рисует за ~165 мс с быстрым стартом — подложка едет той же
     кривой, что и страница, иначе окно на кадр проседает или перелетает. */
  .modal-back { transition: top 165ms cubic-bezier(.25,.85,.35,1) 30ms; }
  .modal-back.form { align-items: flex-start;
    /* Не под самый верх: окно закрывало шапку чата и плашку брони — кто гость,
       какие даты, какой апартамент, — а именно с этим сверяются, заполняя
       долг, залог или заявку. Отступ оставляет на виду шапку и две строки
       плашки (13.09.2026, просьба владельца). С клавиатурой окну остаётся
       меньше места — оно прокручивается внутри, как и раньше. */
    padding-top: calc(env(safe-area-inset-top) + 112px); }
  /* Окно денег поверх окна правки брони — чуть ниже, чтобы было видно, что
     это второй слой, а не подмена (владелец, 15.09.2026). */
  .modal-back.form.stacked { padding-top: calc(env(safe-area-inset-top) + 168px); }
}
@media not all and (hover: none) and (pointer: coarse) {
  .modal-back.stacked { align-items: flex-start; padding-top: 120px; }
}
.modal {
  width: 100%; max-width: 460px;
  background: var(--bg); border-radius: 16px; padding: 16px;
  display: flex; flex-direction: column; gap: 12px;
  box-shadow: 0 10px 40px rgba(0,0,0,.35);
  /* Потолок высоты обязателен. Список действий по нажатию на имя вырос до
     полутора десятков пунктов — метки, тишина, переименование, номер,
     привязка брони, — и без потолка лист вылезал за края окна сразу вверх и
     вниз: он центрируется, а лишнее у центрированного элемента уходит в обе
     стороны. Первые и последние пункты становились недоступны совсем. */
  max-height: 100%; overflow-y: auto; overscroll-behavior: contain;
}
.modal-title { font-weight: 600; font-size: 16px; }

/* Долгое нажатие открывает лист действий, а не выделение текста. Лист
   появляется под ещё прижатым пальцем, и iPhone выделял подпись кнопки
   «Закрыть» с системным «Скопировать · Найти · Перевести» поверх. Поля
   ввода в окнах — исключение, там выделение нужно. */
.modal-back, .modal-back * {
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.modal-back input, .modal-back textarea, .modal-back select {
  -webkit-user-select: text; user-select: text;
}
/* На сенсорном экране долгое нажатие на пузырь — наше меню, а не системное
   выделение; на компьютере выделение мышью остаётся. */
@media (hover: none) and (pointer: coarse) {
  #feed .msg { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
}

/* Лист действий по долгому нажатию: пункты во всю ширину, палец попадает
   не целясь. Промах здесь дорог — рядом «отменить отправку». */
.modal.sheet { gap: 8px; }
.sheet-item {
  width: 100%; font: inherit; font-size: 16px; text-align: left;
  padding: 14px 16px; border-radius: 12px; border: 1px solid var(--line);
  background: var(--bg); color: var(--text); cursor: pointer;
}
.sheet-item.danger { color: #e53935; border-color: rgba(229,57,53,.35); }
.sheet-item.cancel { text-align: center; color: var(--muted); }
.modal textarea {
  width: 100%; font: inherit; font-size: 16px; line-height: 1.4;
  padding: 12px; border-radius: 10px; resize: vertical;
  border: 1px solid var(--line); background: var(--bg); color: var(--text);
}
.modal-row { display: flex; gap: 10px; justify-content: flex-end; }
.modal-row button { padding: 10px 18px; }
.modal-row .cancel { background: transparent; color: var(--muted);
                     border: 1px solid var(--line); }

/* Ссылки в сообщениях */
.msg a { color: var(--accent); word-break: break-all; }
.msg.out a { color: #1a6ea8; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .msg.out a { color: #8fd0ff; }
}
:root[data-theme="dark"] .msg.out a { color: #8fd0ff; }

/* Прежний текст отредактированного сообщения — раскрывается по стрелке */
.msg .orig { margin-top: 4px; }
.msg .orig summary { font-size: 11px; color: var(--muted); cursor: pointer;
                     list-style: none; user-select: none; }
.msg .orig summary::-webkit-details-marker { display: none; }
.msg .orig summary::before { content: "▸ "; }
.msg .orig[open] summary::before { content: "▾ "; }
.msg .was { display: block; font-size: 14px; opacity: .75;
            text-decoration: line-through; margin-top: 2px; white-space: pre-wrap; }

/* Номера апартаментов — отдельная страница.
   Классы называются apt-*, а не advert-*: блокировщик рекламы в Chrome
   вырезает элементы, у которых в классе есть «advert», — список из-за этого
   не отображался вовсе, при живом HTML в DOM. */
.apt-page { max-width: 640px; margin: 0 auto; padding: 0 14px 24px; }
.apt-page .note { padding: 12px 0; }
.apt-page section { border: 0; padding: 0; margin-top: 18px; }
.apt-page h2 { display: flex; align-items: baseline; gap: 8px; padding: 0 0 6px; }
.apt-count { font-size: 12px; font-weight: 400; color: var(--muted);
             background: var(--line); border-radius: 10px; padding: 2px 8px;
             text-transform: none; letter-spacing: 0; }
.apt-count.done { color: #2e7d32; background: rgba(76,175,80,.16); }

.apt-list { background: var(--bg); border-radius: 14px; overflow: hidden; }
/* Название и поле в одну строку: места хватает, а «в столбик» на 17 позиций
   превращается в простыню. На узком экране строка переносится сама. */
.apt-list li { display: flex; flex-wrap: wrap; gap: 6px 12px;
               align-items: center; padding: 10px 12px;
               border-bottom: 1px solid var(--line); }
.apt-list li:last-child { border-bottom: 0; }
.apt-title { flex: 1 1 200px; font-size: 14px; line-height: 1.3; color: var(--text); }
.apt-list li .apt-no { flex: 0 0 116px; width: 116px; padding: 8px 10px;
                       font-size: 15px; text-align: center; }
.apt-no:placeholder-shown { background: transparent; }

/* Разделитель дня в переписке */
.day-sep {
  align-self: center; margin: 10px 0 6px;
  padding: 3px 12px; border-radius: 12px;
  background: rgba(0,0,0,.10); color: var(--muted);
  font-size: 12px; font-weight: 500;
}
@media (prefers-color-scheme: dark) { .day-sep { background: rgba(255,255,255,.10); } }

/* Дата при прокрутке (как в Telegram) — плашка посередине над лентой, пока
   листаешь; гаснет через секунду после остановки. Обёртка нулевой высоты
   стоит вплотную над #feed, поэтому верх плашки — всегда верх ленты, что бы
   ни было над ней (карточка брони, заметка, поиск). Размер — как у
   разделителя дня, но поверх пузырей нужна сплошная подложка, иначе текст
   сообщения просвечивает сквозь число. */
.feed-date { position: relative; height: 0; z-index: 4; pointer-events: none;
             display: flex; justify-content: center; }
.feed-date span {
  position: absolute; top: 8px;
  padding: 3px 12px; border-radius: 12px; white-space: nowrap;
  font-size: 12px; font-weight: 500; line-height: 16px;
  color: var(--muted); background: var(--header);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .14);
  opacity: 0; transform: translateY(-4px);
  transition: opacity .4s ease, transform .4s ease;
}
.feed-date.shown:not(.covered) span {
  opacity: 1; transform: none; transition-duration: .15s;
}

/* Автоответы */
.head-btn { padding: 8px 12px; font-size: 14px; border-radius: 10px; }
.ar-list { padding: 8px 0; }
.ar-item { display: grid; grid-template-columns: 10px 1fr auto; gap: 4px 10px;
           align-items: center; padding: 12px 14px;
           border-bottom: 1px solid var(--line); cursor: pointer; }
.ar-item.active { background: var(--bg-chat); }
.ar-item .dot { width: 8px; height: 8px; border-radius: 50%; }
.ar-item .dot.ok { background: #4caf50; }
.ar-item .dot.off { background: #bbb; }
.ar-item .ar-name { font-weight: 600; }
.ar-item .ar-kind { font-size: 12px; color: var(--muted); }
.row-field { display: flex; align-items: center; justify-content: space-between;
             gap: 12px; padding: 8px 0; font-size: 15px; }
.row-field input { width: 120px; }
.muted { color: var(--muted); }

/* Закрепление чата свайпом */
.chat { transition: transform .18s ease; position: relative; }
.chat.will-pin { background: rgba(51,144,236,.12); }
.chat.pinned { background: rgba(128,128,128,.06); }
.pin-mark { font-size: 11px; flex-shrink: 0; }

/* Статистика */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
         gap: 8px; margin: 4px 0 8px; }
.tile { background: var(--bg-chat); border-radius: 12px; padding: 12px 10px;
        text-align: center; }
.tile b { display: block; font-size: 20px; font-weight: 700; }
.tile span { font-size: 12px; color: var(--muted); }
.tile.warn b { color: #e8890c; }
.tile.bad b { color: #e53935; }
.bar-track { background: var(--bg-chat); border-radius: 6px; height: 18px; }
.bar-fill { display: block; height: 100%; border-radius: 6px; background: var(--accent); }
.bar-fill.alt { background: #7bc862; }
.hours { display: flex; align-items: flex-end; gap: 2px; height: 70px; margin-top: 6px; }
.hour { flex: 1; height: 100%; display: flex; align-items: flex-end; }
.hour-fill { width: 100%; background: var(--accent); border-radius: 2px 2px 0 0;
             min-height: 1px; }
.hours-axis { display: flex; justify-content: space-between; font-size: 11px;
              color: var(--muted); margin-top: 4px; }
.ar-tabs a.ar-tab { text-decoration: none; }

/* Вкладки периода (стили потерялись при переделке экрана автоответов) */
.ar-tabs { display: flex; gap: 8px; padding: 12px 14px 4px; }
.ar-tab {
  flex: 1; text-align: center; padding: 10px 8px; font-size: 14px;
  border: 1px solid var(--line); border-radius: 10px;
  background: transparent; color: var(--muted); text-decoration: none;
  display: flex; align-items: center; justify-content: center; gap: 6px;
}
.ar-tab.active { background: var(--accent); color: #fff; border-color: var(--accent); }

/* Подпись НАД полосой: рядом с ней длинные названия каналов обрезались
   до неразличимого «Авито AV A…» — а начинаются они одинаково. */
.bar-block { padding: 6px 0; }
.bar-name { display: flex; justify-content: space-between; gap: 10px;
            font-size: 14px; margin-bottom: 4px; }
.bar-num { color: var(--muted); flex-shrink: 0; }
/* span внутри блока остаётся строчным, и height к нему не применяется —
   полосы просто исчезали. */
.bar-block .bar-track { display: block; width: 100%; }

/* Кадр из видео: у MAX прямой ссылки на файл нет, поэтому вместо плеера
   показываем картинку со значком — чтобы не выглядело сломанным видео. */
.video-frame { position: relative; display: inline-block; }
.video-frame .play-mark {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 44px; height: 44px; border-radius: 50%;
  background: rgba(0, 0, 0, .55); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; padding-left: 3px; pointer-events: none;
}

/* Не отправленное сообщение видно прямо в списке: иначе про сорвавшуюся
   отправку узнаёшь, только открыв переписку. */
/* Кадр видео кликабелен — показываем это. */
.video-frame[data-play] { cursor: pointer; }
/* Видео не открылось (ролика у нас нет или телефон его не играет): слова на
   месте значка ▶ вместо чёрного прямоугольника с перечёркнутым ▶
   (27.09.2026, «Видео вотсап не открывается после отправки»). */
.video-frame .gone-note {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: max-content; max-width: 80%; padding: 6px 10px; border-radius: 12px;
  background: rgba(0, 0, 0, .6); color: #fff; font-size: 13px; line-height: 1.3;
  text-align: center; pointer-events: none;
}
.failed-dot { color: #e53935; font-size: 15px; line-height: 1;
              margin-left: 6px; flex-shrink: 0; }

/* Скрипты: список над полем ввода. Вставляют текст, но НЕ отправляют —
   отправку оператор нажимает сам, посмотрев на подставленное. */
#composer #scripts-btn { font-weight: 700; font-size: 20px; line-height: 1; }
#scripts-pop {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  max-height: 70vh; display: flex; flex-direction: column;
  background: var(--bg); border-top: 1px solid var(--line);
  border-radius: 14px 14px 0 0; box-shadow: 0 -8px 30px rgba(0,0,0,.18);
}
#scripts-pop .sc-head { display: flex; gap: 8px; padding: 10px 12px;
                        border-bottom: 1px solid var(--line); }
#scripts-pop #sc-search { flex: 1; min-width: 0; border-radius: 12px; padding: 9px 12px; }
#scripts-pop #sc-close { width: 38px; background: transparent; color: var(--muted);
                         font-size: 17px; }
#sc-items { overflow-y: auto; padding: 4px 0 max(8px, env(safe-area-inset-bottom)); }

/* Гифки: та же панель снизу, что у скриптов; сетка в три колонки, плитки —
   живые превью, как в Telegram; нажатие — отправка. */
#gif-pop {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  max-height: 70vh; display: flex; flex-direction: column;
  background: var(--bg); border-top: 1px solid var(--line);
  border-radius: 14px 14px 0 0; box-shadow: 0 -8px 30px rgba(0,0,0,.18);
}
/* На телефоне панели стоят от посаженной страницы (body.chatpage —
   position: relative, под клавиатурой сидит на видимой области), а не от
   окна: fixed при открытой клавиатуре iPhone стоял низом под ней — видны
   были только верхние ~280px, а короткая панель пряталась целиком (аудит
   17.09.2026). Потолок — в процентах от той же страницы. */
/* Без overflow на панели: overflow-x: hidden делал её прокручиваемой по
   вертикали, и WebKit при фокусе в поле поиска считал «видимую» часть
   вытянутого поля, а не всё поле — страница на 0,1 с уезжала на ~200px
   (симулятор 18.09.2026). Ширину держит min-width: 0 у поля. */
@media (hover: none) and (pointer: coarse) {
  #scripts-pop, #gif-pop { position: absolute; max-height: 70%; }
}
#gif-pop .sc-head { display: flex; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--line); align-items: center; }
/* Вкладки GIF | Избранное — как в Telegram; во вкладке избранного вместо
   поиска — «+» (добавить с устройства). */
.gif-tabs { display: flex; gap: 2px; background: var(--bg-chat); border-radius: 10px; padding: 2px; flex: none; }
.gif-tab { width: auto; height: auto; padding: 6px 10px; border-radius: 8px; font-size: 13px;
           background: transparent; color: var(--muted); }
.gif-tab.on { background: var(--bg); color: var(--text); box-shadow: 0 1px 2px rgba(0,0,0,.12); }
#gif-pop[data-tab="fav"] #gif-hints,
#gif-pop[data-tab="st"] #gif-search, #gif-pop[data-tab="st"] #gif-hints { display: none; }
#gif-pop[data-tab="fav"] .gif-add { flex: none; width: 42px; }
#gif-grid .gif .fav-tag { position: absolute; right: 4px; bottom: 4px; font-size: 11px; font-weight: 700; padding: 1px 6px;
                          border-radius: 6px; background: rgba(255,255,255,.85); color: #222; max-width: 70%;
                          overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#st-sets { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
#st-sets::-webkit-scrollbar { display: none; }
#st-sets button { width: auto; height: auto; padding: 4px 10px; border-radius: 12px; font-size: 13px;
                  background: var(--bg-chat); color: var(--text); white-space: nowrap; flex: none; }
#st-sets button.on { background: var(--accent); color: #fff; }
#st-add { font-size: 14px; flex: 1; }
/* Стикеры мельче гифок: четыре в ряд, без обрезки. */
#gif-pop[data-tab="st"] #gif-grid { grid-template-columns: repeat(4, 1fr); grid-auto-rows: 84px; }
#gif-grid .gif.st { background: transparent; }
#gif-grid .gif.st img { object-fit: contain; }
.gif-add { flex: 1; display: flex; align-items: center; justify-content: center; height: 38px;
           border: 1px dashed var(--line); border-radius: 12px; color: var(--accent); font-size: 22px; cursor: pointer; }
#gif-grid .gif img { width: 100%; height: 100%; object-fit: cover; display: block; }
#gif-grid .gif .fav-kind { position: absolute; left: 4px; bottom: 4px; font-size: 10px; padding: 1px 5px;
                           border-radius: 6px; background: rgba(0,0,0,.55); color: #fff; }
#gif-grid .empty { grid-column: 1 / -1; color: var(--muted); font-size: 14px; padding: 20px 8px; text-align: center; }
/* min-width: 0 — иначе поле не ужимается ниже своей «естественной» ширины,
   «+» и «✕» уезжали за правый край, а документ становился шире окна: при
   фокусе в поле WebKit прокручивал страницу вбок на ~20px (симулятор,
   18.09.2026, панель absolute от страницы). */
#gif-pop #gif-search { flex: 1; min-width: 0; border-radius: 12px; padding: 9px 12px; }
#gif-pop #gif-close { width: 38px; background: transparent; color: var(--muted); font-size: 17px; }
#gif-hints { display: flex; gap: 6px; flex-wrap: wrap; padding: 8px 12px 0; }
#gif-hints button { width: auto; height: auto; padding: 4px 10px; border-radius: 12px; font-size: 13px;
                    background: var(--bg-chat); color: var(--text); }
#gif-hints button.on { background: var(--accent); color: #fff; }
/* Ряды — фиксированной высоты: с aspect-ratio на плитках grid считал ряды
   нулевыми (0,47px), плитки ложились друг на друга, а наблюдатель видимости
   грузил все 50 роликов разом (проверено на бою 15.09.2026). */
#gif-grid {
  overflow-y: auto; padding: 8px 8px max(8px, env(safe-area-inset-bottom));
  display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 112px; gap: 6px;
  min-height: 120px; align-content: start;
}
#gif-grid .gif {
  position: relative; border-radius: 8px; overflow: hidden; background: var(--bg-chat);
  cursor: pointer; padding: 0; border: 0; width: 100%; height: 100%;
  background-size: cover; background-position: center;
}
#gif-grid .gif video { width: 100%; height: 100%; object-fit: cover; display: block; position: absolute; inset: 0; }
#gif-grid .gif img.poster { width: 100%; height: 100%; object-fit: cover; display: block; }
#gif-grid .gif.sending { opacity: .5; }
#gif-state { padding: 0 12px 8px; margin: 0; }
/* Значок GIF — внутри поля справа, как значок стикеров в Telegram: не ест
   место в строке (владелец, 15.09.2026). При переводе (tr-btn) он сдвигается левее. */
#composer #gif-btn {
  position: absolute; top: 50%; transform: translateY(-50%); right: 66px; z-index: 2;
  width: 26px; height: 26px; min-width: 0; padding: 0; border: 0; border-radius: 6px;
  background: transparent; color: var(--muted); opacity: .6; display: grid; place-items: center;
}
#composer #gif-btn:active { opacity: 1; }
#composer.with-gif #text { padding-right: 40px; }
#composer.with-gif #tr-btn { right: 96px; }
#composer.with-gif.with-tr #text { padding-right: 66px; }
/* Часы отложенных — слева от значка стикера, в том же поле. */
#composer #sched-btn {
  position: absolute; top: 50%; transform: translateY(-50%); right: 96px; z-index: 2;
  width: 26px; height: 26px; min-width: 0; padding: 0; border: 0; border-radius: 6px;
  background: transparent; color: var(--accent); opacity: .8; display: grid; place-items: center;
}
#composer.with-sched.with-gif #text { padding-right: 70px; }
#composer.with-sched.with-gif #tr-btn { right: 126px; }
#composer.with-sched.with-gif.with-tr #text { padding-right: 96px; }
#composer:not(.with-gif) #sched-btn { right: 66px; }
#composer.with-sched:not(.with-gif) #text { padding-right: 40px; }
.sched-items { list-style: none; margin: 0; padding: 0; }
.sched-items li { padding: 10px 0; border-bottom: 1px solid var(--line); }
.sched-items li:last-child { border-bottom: 0; }
.sched-items .s-when { font-size: 12px; color: var(--accent); font-weight: 600; }
.sched-items .s-text { margin: 4px 0 8px; white-space: pre-wrap; word-break: break-word; font-size: 15px; }
.sched-items .s-acts { display: flex; flex-wrap: wrap; gap: 6px; }
.sched-items .s-acts button { width: auto; height: auto; padding: 5px 10px; font-size: 13px; border-radius: 10px;
                              background: var(--bg-chat); color: var(--text); }
.sched-items .s-acts button.danger { color: #d33a2c; }
.sched-items .empty { color: var(--muted); font-size: 14px; padding: 12px 0; }
@media (min-width: 900px) { #gif-pop { left: 50%; margin-left: calc(var(--окно) / -2); right: auto; width: var(--окно); bottom: var(--поле); } }
@media (min-width: 1000px) { .panes #gif-pop { margin-left: calc(var(--окно) / -2 + var(--список)); width: calc(var(--окно) - var(--список)); } }
#sc-items li { padding: 10px 14px; border-bottom: 1px solid var(--line);
               cursor: pointer; }
#sc-items li:active { background: rgba(127,127,127,.12); }
#sc-items .sc-name { display: block; font-size: 15px; }
#sc-items .sc-preview, .sc-list .sc-preview {
  display: block; font-size: 13px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Разделитель «дальше — скрипты других каналов» */
#sc-items li.other-first { border-top: 1px solid var(--line); margin-top: 6px; }
#sc-items li.other-first::before, .sc-tag {
  display: inline-block; font-size: 11px; color: var(--muted);
  background: var(--line); border-radius: 8px; padding: 1px 7px; }
#sc-items li.other-first::before { content: "другие каналы"; margin-bottom: 6px; }
.sc-list li { padding: 12px 0; border-bottom: 1px solid var(--line); cursor: pointer; }
.sc-list .sc-name { font-size: 15px; margin-right: 6px; }

/* Один чип с тегом канала над списком — фильтр, а не подпись у каждой строки. */
.sc-tagbar { display: flex; align-items: center; gap: 8px;
             padding: 8px 14px 4px; }
.sc-chip { font-size: 13px; padding: 4px 12px; border-radius: 12px;
           background: var(--line); color: var(--text); }
.sc-chip.on { background: var(--accent, #3b82f6); color: #fff; }
.sc-hint { font-size: 12px; color: var(--muted); }

/* Браузер не считает раскладку строк за пределами экрана. На списке в три
   сотни чатов это разница между «сразу нажимается» и «пару секунд не реагирует».
   Высота-заглушка нужна, чтобы полоса прокрутки не скакала. */
.chat { content-visibility: auto; contain-intrinsic-size: 0 76px; }

/* Кроме списка на телефоне. Там прокручивается сама страница, и iPhone (iOS 26,
   PWA) при быстром пролистывании не успевает признать строки видимыми: низ
   экрана стоит белым, строки обрываются ровно по границе строки и дорисовываются
   через секунду-две (видео владельца 27.09.2026, повторено в симуляторе).
   Замер на 800 чатах в WebKit: без пропуска полная перерисовка списка дороже на
   ~50 мс (115 → 165), перераскладка не дороже — «пару секунд» выше не про сейчас.
   На компьютере список — своя колонка с прокруткой, там всё в порядке. */
@media (hover: none) and (pointer: coarse) {
  #chats .chat { content-visibility: visible; }
}

/* «Ответ не требуется» — тонкая текстовая кнопка под полем ввода, слева.
   То же действие, что и ✓ в списке: снимает непрочитанное у нас и отправляет
   гостю отчёт о прочтении. */
/* Полоска «ответ не требуется» прижата к строке ввода: раньше между ней и
   последним сообщением зияла пустая полоса в треть пальца. */
/* Подложка как у ленты сообщений, а не как у строки ввода. Прозрачным блоком
   сквозь него светился белый фон страницы, а с цветом строки ввода получалась
   та же белая полоса — просто на строку ниже. Серый фон ленты делает эту
   надпись частью переписки, чем она и является. */
/* Без подложки: любой фон здесь читался полосой поперёк экрана. Просто
   подпись в конце переписки. */
.under-composer {
  align-self: center; line-height: 1;
  padding: 2px 10px 6px; background: transparent;
}
.under-composer button {
  background: transparent; color: var(--muted); font-size: 13px;
  padding: 2px 0; border: 0; width: auto;
}
.under-composer button:disabled { opacity: .6; }
.under-composer button.done { color: #2e7d32; }

/* Полоска лида в конце ленты — как подпись «ответ не требуется», но с
   кнопкой «не забронировал». У чата без лида на том же месте — «пометить
   как лид». */
.lead-strip {
  align-self: center; display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--muted); padding: 2px 10px; line-height: 1.2;
  margin-top: 10px;   /* отступ от последнего пузыря — строка не липнет к нему */
}
.lead-strip[hidden] { display: none; }
.lead-strip button, .lead-head {
  width: auto; padding: 2px 10px; border-radius: 12px; font-size: 13px;
  border: 1px solid #2e7d32; background: transparent; color: #2e7d32;
}
/* «Это лид» в шапке переписки: справа от имени, в углу. Открытый лид — на
   том же месте овал «Лид ›» с заливкой: тап открывает лист причин. */
.chatpage header .lead-head { flex: none; height: auto; line-height: 1.3; margin-left: 4px; }
.lead-head[hidden] { display: none; }
.chatpage header .lead-head.lead-open { background: #2e7d32; color: #fff; font-weight: 600; padding: 3px 9px 3px 11px; }
.lead-open-caret { opacity: .75; margin-left: 2px; }
/* Пузырь CRM: синий, слева, с кнопками. Технический — и должен читаться так,
   а не как слова гостя. */
.msg.system.crm-ask {
  align-self: flex-start; background: #e3efff; color: #123c73; max-width: 88%;
  border-bottom-left-radius: 4px;
}
.msg.system .crm-head { display: block; font-size: 11px; font-weight: 700;
  letter-spacing: .04em; color: #1a56c4; margin-bottom: 2px; }
.msg.system .crm-btns { display: flex; gap: 8px; margin-top: 8px; }
.msg.system .crm-btn { width: auto; padding: 4px 12px; border-radius: 14px;
  font-size: 13px; border: 1px solid #1a56c4; background: #fff; color: #1a56c4; }
.msg.system .crm-btn:disabled { opacity: .6; }
.msg.system.crm-ask .meta { color: #4a6a99; }
/* После ответа — серая строка-след по центру, как разделитель дня. */
.msg.system.crm-done {
  align-self: center; background: transparent; box-shadow: none;
  font-size: 12px; color: var(--muted); padding: 2px 8px; max-width: 95%;
}
.msg.system.crm-done .meta { float: none; margin: 0 0 0 6px; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .msg.system.crm-ask { background: #16304f; color: #cfe1ff; }
  :root:not([data-theme="light"]) .msg.system .crm-btn { background: transparent; color: #8fd0ff; border-color: #8fd0ff; }
  :root:not([data-theme="light"]) .msg.system .crm-head,
  :root:not([data-theme="light"]) .msg.system.crm-ask .meta { color: #8fd0ff; }
  :root:not([data-theme="light"]) .lead-strip button,
  :root:not([data-theme="light"]) .lead-head { color: #93d69a; border-color: #93d69a; }
  :root:not([data-theme="light"]) .lead-head.lead-open { background: #2e7d32; color: #fff; border-color: #2e7d32; }
}
:root[data-theme="dark"] .msg.system.crm-ask { background: #16304f; color: #cfe1ff; }
:root[data-theme="dark"] .msg.system .crm-btn { background: transparent; color: #8fd0ff; border-color: #8fd0ff; }
:root[data-theme="dark"] .msg.system .crm-head, :root[data-theme="dark"] .msg.system.crm-ask .meta { color: #8fd0ff; }
:root[data-theme="dark"] .lead-strip button, :root[data-theme="dark"] .lead-head { color: #93d69a; border-color: #93d69a; }
:root[data-theme="dark"] .lead-head.lead-open { background: #2e7d32; color: #fff; border-color: #2e7d32; }

/* Брони по объявлению — прямо над перепиской. Сроки обмена контактами Авито
   в API не отдаёт, считаем от даты заезда, поэтому подпись прямая: до какого
   числа нельзя. */
.bookings { padding: 6px 10px; background: var(--header);
            border-bottom: 1px solid var(--line);
            display: flex; flex-direction: column; gap: 6px;
            max-height: 30vh; overflow-y: auto; }
/* Обёртка карточек для живой подмены шапки — без своей коробки: карточки
   и «жил · …» остаются прямыми участниками колонки переписки, как раньше. */
#chat-cards { display: contents; }

/* Свайп по строке чата — наш жест, а не браузерный «назад».
   touch-action: pan-y отдаёт браузеру только вертикальную прокрутку,
   overscroll-behavior-x гасит навигацию по горизонтальному оттягиванию. */
html, body { overscroll-behavior-x: none; }
#chats .chat { touch-action: pan-y; }

/* Статус собеседника в шапке. Есть только у Telegram и MAX — у Авито и Циан
   его в API нет, и строка просто не появляется. */
.presence { color: #4fae4e; }

/* Поиск по диалогам. Прячется за кнопкой: строка поиска, висящая всегда,
   съедает экран телефона, а ищут раз в день. */
#search-bar {
  display: flex; gap: 8px; align-items: center;
  padding: 8px 12px; border-bottom: 1px solid var(--line);
  background: var(--bg); position: sticky; top: 0; z-index: 5;
}
#search {
  flex: 1; font: inherit; font-size: 16px;   /* 16px — иначе iOS зумит поле */
  padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--bg); color: var(--text);
}
#search-clear {
  border: none; background: none; color: var(--muted);
  font-size: 18px; padding: 6px 8px; cursor: pointer;
}

/* Пометка черновика в списке чатов: недописанное важнее последней реплики,
   иначе про него забываешь до следующего случайного захода в чат. */
.draft-mark { color: #e53935; }

/* Чужой черновик над полем ввода. Не запрещаем писать — просто показываем,
   что ответ уже готовят: жёсткая блокировка мешала бы в запаре сильнее. */
.others-draft {
  display: flex; gap: 6px; align-items: baseline;
  padding: 6px 14px; font-size: 13px; color: var(--muted);
  border-top: 1px solid var(--line);
}
.others-draft[hidden] { display: none; }
.others-draft b { color: var(--accent); font-weight: 600; }
.others-draft .what-text {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1;
}
/* Крестик держим бледным: убирать чужой черновик — действие редкое, и
   заметная кнопка над полем ввода мешала бы больше, чем сам черновик. */
.others-draft .drop-draft {
  flex: none; border: 0; background: none; cursor: pointer;
  color: var(--muted); opacity: .6; font-size: 14px; line-height: 1;
  padding: 2px 4px; border-radius: 6px;
}
.others-draft .drop-draft:hover { opacity: 1; background: var(--bg-chat); }

/* Заголовок работает кнопкой — показываем это, но без вида ссылки. */
#inbox-title { cursor: pointer; user-select: none; }
#inbox-title.filtered { color: var(--accent); }

/* Операторы */
.op {
  border: 1px solid var(--line); border-radius: 12px;
  padding: 12px; margin-bottom: 12px;
}
.op-name {
  flex: 1; font: inherit; font-size: 16px; font-weight: 600;
  border: none; background: none; color: var(--text); padding: 4px 0;
}
.op-me { font-size: 12px; color: var(--muted); }
.op-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.op-pin {
  flex: 1; min-width: 120px; font: inherit; font-size: 16px;
  padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--bg); color: var(--text);
}
.op-state:empty { display: none; }

/* Стадия брони рядом с объявлением: видно, гость будущий, живущий или уже
   уехавший, — не заходя в переписку. */
.stage {
  display: inline-block; margin-right: 6px; padding: 0 6px;
  border-radius: 6px; font-size: 12px; line-height: 18px; font-weight: 600;
  vertical-align: 1px;
}
.stage[hidden] { display: none; }
/* Открытый лид: обведённый овал у имени, без заливки — залитые плашки во
   второй строке это стадии брони, и путать их нельзя. Тот же овал стоит и
   в полоске лида в переписке. */
.chat .lead, .lead-strip .lead {
  display: inline-block; padding: 0 7px; border-radius: 10px; font-size: 11px;
  line-height: 16px; font-weight: 600; color: #2e7d32; border: 1px solid #2e7d32;
  vertical-align: 1px;
}
/* В строке списка — на месте стадии брони, во второй строке перед превью. */
.chat .row2 .lead { margin-right: 6px; }
.chat .lead[hidden] { display: none; }
/* Чип «Лиды N» под шапкой: зелёная обводка, как у овала; включённый — залит.
   Два класса в селекторе не случайно: одиночный .lead-chip перебивался
   общим .chip, который стоит ниже по файлу, и чип оставался серым. */
.chip.lead-chip { color: #2e7d32; border-color: #2e7d32; font-weight: 600; }
.chip.lead-chip.on { background: #2e7d32; border-color: #2e7d32; color: #fff; }
#leads-count:empty { display: none; }
#board-link, #list-link, #checkins-link { text-decoration: none; margin-left: auto; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .chat .lead,
  :root:not([data-theme="light"]) .lead-strip .lead,
  :root:not([data-theme="light"]) .chip.lead-chip:not(.on) { color: #93d69a; border-color: #93d69a; }
}
:root[data-theme="dark"] .chat .lead, :root[data-theme="dark"] .lead-strip .lead,
:root[data-theme="dark"] .chip.lead-chip:not(.on) { color: #93d69a; border-color: #93d69a; }

.stage-request  { background: #fff3cd; color: #8a6d1f; }
.stage-booked   { background: #d9f0da; color: #2e7d32; }
.stage-canceled { background: #fbe0e0; color: #c62828; }
.stage-left     { background: var(--bg-chat); color: var(--muted); }
/* Значок залога у «выехал»: вернули — зелёный, не вернули — красный. */
.dep-back { display: inline-block; margin-right: 6px; padding: 0 5px; border-radius: 6px;
            font-size: 12px; line-height: 18px; font-weight: 700; vertical-align: 1px; }
.dep-back[hidden] { display: none; }
.dep-back.ok  { background: #d9f0da; color: #2e7d32; }
.dep-back.bad { background: #fbe0e0; color: #c62828; }
/* Тёмные цвета стадий — как у всего остального: по системной теме, но НЕ
   когда в настройках выбрана светлая. Без этой оговорки на телефоне с
   тёмной системой и светлым инбоксом плашка «бронь» стояла чёрной. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .stage-request  { background: #4a3c10; color: #ffd970; }
  :root:not([data-theme="light"]) .stage-booked   { background: #1f4020; color: #93d69a; }
  :root:not([data-theme="light"]) .stage-canceled { background: #4a1f1f; color: #ff9a9a; }
  :root:not([data-theme="light"]) .dep-back.ok  { background: #1f4020; color: #93d69a; }
  :root:not([data-theme="light"]) .dep-back.bad { background: #4a1f1f; color: #ff9a9a; }
  :root:not([data-theme="light"]) .stage-checkin  { background: #16304f; color: #8fd0ff; }
  :root:not([data-theme="light"]) .stage-living   { background: #1f4020; color: #93d69a; }
}
:root[data-theme="dark"] .stage-request  { background: #4a3c10; color: #ffd970; }
:root[data-theme="dark"] .stage-booked   { background: #1f4020; color: #93d69a; }
:root[data-theme="dark"] .stage-canceled { background: #4a1f1f; color: #ff9a9a; }
:root[data-theme="dark"] .dep-back.ok  { background: #1f4020; color: #93d69a; }
:root[data-theme="dark"] .dep-back.bad { background: #4a1f1f; color: #ff9a9a; }
:root[data-theme="dark"] .stage-checkin  { background: #16304f; color: #8fd0ff; }
:root[data-theme="dark"] .stage-living   { background: #1f4020; color: #93d69a; }

/* Внутренняя заметка: висит над перепиской мелко и бледно — не спорит с
   сообщениями, но всегда на глазах. Гость её не видит. */
.note-strip {
  padding: 6px 14px; font-size: 12.5px; line-height: 1.35;
  color: var(--muted); background: var(--bg-chat);
  border-bottom: 1px solid var(--line);
  cursor: pointer; white-space: pre-wrap;
}
.note-strip[hidden] { display: none; }
.note-add {
  align-self: flex-start; margin: 4px 14px 0; padding: 0;
  border: 0; background: none; color: var(--muted);
  font-size: 12px; opacity: .65; cursor: pointer; width: auto;
}
.note-add[hidden] { display: none; }

/* Строка со свёрнутыми выборками: одна кнопка и название включённой. */
#filter-line {
  display: flex; align-items: center; gap: 10px; padding: 6px 14px;
  border-bottom: 1px solid var(--line); background: var(--bg);
  font-size: 13px; color: var(--muted);
}
#filter-toggle {
  width: auto; height: auto; padding: 4px 10px; border-radius: 14px;
  border: 1px solid var(--line); background: var(--bg-chat);
  color: var(--text); font-size: 13px;
}
#filter-toggle[aria-expanded="true"] .caret { display: inline-block;
                                              transform: rotate(180deg); }
#filter-now { color: var(--accent); font-weight: 600; }

/* Полоска выборок «по делу»: узкая, прокручивается вбок — на телефоне
   вертикальное место дороже горизонтального. */
#filter-bar {
  display: flex; gap: 8px; padding: 8px 14px;
  overflow-x: auto; scrollbar-width: none;
  border-bottom: 1px solid var(--line); background: var(--bg);
}
#filter-bar::-webkit-scrollbar { display: none; }
#filter-bar[hidden] { display: none; }
.chip {
  flex: none; width: auto; padding: 6px 12px; border-radius: 16px;
  border: 1px solid var(--line); background: var(--bg-chat);
  color: var(--text); font-size: 13px; white-space: nowrap; cursor: pointer;
}
.chip.on { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Подпись под именем меняется: сперва «был в сети», затем объявление.
   Текст подменяем в той же строке — так шапка не дёргается и ничего не
   накладывается друг на друга. */
#sub-line {
  transition: opacity .4s ease; display: flex; min-width: 0;
  /* В одну строку: длинное название объявления иначе делает шапку выше и
     сдвигает всю переписку. */
  white-space: nowrap; overflow: hidden;
}
/* Урезаем название, а цену держим целой — она короткая и нужна чаще, чем
   хвост названия. */
.sub-title { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.sub-price { flex: none; }
#sub-line.faded { opacity: 0; }
/* Блок с именем должен уметь ужиматься: без min-width флекс-элемент
   раздувается по содержимому, и длинное название уезжает за край экрана. */
.who { min-width: 0; flex: 1; }
.who .name {
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* «Кто это»: узкая полоска над перепиской. Показываем, ПО ЧЕМУ опознали —
   совпадение по имени слабее совпадения по телефону, и оператор должен
   видеть разницу, а не доверять вслепую. */
.guest-card {
  display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline;
  padding: 7px 14px; font-size: 13px;
  background: var(--bg-chat); border-bottom: 1px solid var(--line);
}
.guest-card b { font-weight: 600; }
.guest-card .g-apt, .guest-card .g-when { color: var(--muted); }
.guest-card .g-tel { color: var(--accent); text-decoration: none; }
.guest-card .g-how { color: var(--muted); opacity: .7; margin-left: auto; }

/* Колокольчик в шапке чата: зажигается, когда напоминание поставлено. */
/* Колокольчик без напоминания — просто значок, без голубой плашки (она
   доставалась от базового button; владелец, 15.09.2026). С напоминанием —
   лёгкая голубая подложка, чтобы было видно, что оно стоит. */
#remind { opacity: .55; background: transparent; border-radius: 8px; }
#remind.on { opacity: 1; background: #e3efff; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) #remind.on { background: #16304f; }
}
:root[data-theme="dark"] #remind.on { background: #16304f; }

/* Имя гостя в строке брони — первым и заметнее прочего: по апартаменту
   броней несколько, и без имени непонятно, чья перед тобой. */

/* Стадии брони: заезд и «живёт» — рабочие состояния, их видно чаще всего. */
.stage-checkin { background: #e8f0fe; color: #1a56c4; }
.stage-living  { background: #e6f4ea; color: #1e7a34; }

/* «Печатает» — зелёным, как присутствие: это тоже про «человек здесь». */
.typing-mark { color: #2e7d32; }
#sub-line.typing { color: #2e7d32; }

/* Можно ли обмениваться контактами. Мелко и в один цвет со смыслом: запрет
   площадки стоит денег, а разрешение нужно не пропустить. */
.contacts-hint {
  padding: 5px 14px; font-size: 12px;
  border-bottom: 1px solid var(--line); background: var(--bg-chat);
}
.contacts-hint.no { color: #b3261e; }
.contacts-hint.ok { color: #1e7a34; }

/* Фото во весь экран. Поверх всего, тёмный фон — как в мессенджерах. */
.lightbox {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(0, 0, 0, .92);
  display: flex; align-items: center; justify-content: center;
  padding: env(safe-area-inset-top) 0 env(safe-area-inset-bottom);
}
.lightbox img {
  max-width: 100%; max-height: 100%;
  object-fit: contain; user-select: none;
}
/* Аватарка меньше экрана: растягиваем её до разумного размера, иначе
   открытая «во весь экран» карточка показывает кружок с ноготь. */
.lightbox img.avatar-photo {
  width: min(100%, 480px); height: auto;
}
.lb-close {
  position: absolute; top: max(12px, env(safe-area-inset-top)); right: 12px;
  width: 40px; height: 40px; border-radius: 50%; border: 0;
  background: rgba(255, 255, 255, .15); color: #fff; font-size: 18px;
}
img.media { cursor: zoom-in; }

/* Реакции под пузырём — мелкой плашкой, как в мессенджерах. */
/* Реакция висит отдельной строкой под текстом и чуть растягивает пузырь —
   как в телеграме. Инлайновая плашка липла к последнему слову и терялась. */
.reacts {
  /* Строку плашке даёт <br> в самой разметке, а не display: block. Разница
     принципиальная: инлайновая плашка остаётся в потоке, и время (оно
     float: right) встаёт справа от неё, на той же строке. Блочная выталкивала
     время на третью строку — пузырь рос вдвое больше нужного.
     А без переноса вовсе плашка липла к последнему слову
     («Спасибо огромное!!) ❤️») и читалась как часть самого сообщения. */
  display: inline-flex; align-items: center; gap: 4px;
  margin: 6px 0 0; padding: 3px 9px; border-radius: 13px;
  background: rgba(0, 0, 0, .07); font-size: 15px; line-height: 1.1;
}
.msg.out .reacts { background: rgba(0, 0, 0, .09); }

/* Цитата в пузыре — как в телеграме: подложка, толстая полоска слева и имя
   автора сверху. Без имени по цитате не понять, кого именно цитируют, а это
   в переписке на четверых главное. */
.quote {
  display: block; margin-bottom: 4px; padding: 3px 8px 4px 8px;
  border-left: 3px solid var(--accent); border-radius: 4px;
  background: rgba(47, 127, 209, .10); color: var(--text);
  font-size: 13px; line-height: 1.25;
}
.quote .q-who { display: block; font-weight: 600; color: var(--accent);
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.quote .q-body { display: block; color: var(--muted);
                 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.quote.mine { border-left-color: #2e7d32; background: rgba(46, 125, 50, .10); }
.quote.mine .q-who { color: #2e7d32; }

/* Пузырь на свайпе едет за пальцем; у порога чуть подсвечиваем, чтобы было
   видно, что отпускание сработает. */
.msg.will-quote { box-shadow: 0 1px 1px rgba(0,0,0,.08), -3px 0 0 var(--accent); }

/* На что отвечаем — над полем ввода. */
#quote-bar {
  display: flex; gap: 8px; align-items: center;
  padding: 6px 14px; font-size: 13px; color: var(--muted);
  border-top: 1px solid var(--line);
}
#quote-bar[hidden] { display: none; }
#quote-bar .q-text { flex: 1; overflow: hidden; text-overflow: ellipsis;
                     white-space: nowrap; }
#quote-bar .q-drop { border: 0; background: none; color: var(--muted);
                     font-size: 16px; width: auto; padding: 2px 4px; }

/* Закреплённое сообщение — узкой полоской под шапкой, всегда на виду. */
.pinned-strip {
  display: flex; gap: 8px; align-items: center;
  padding: 6px 14px; font-size: 13px; cursor: pointer;
  background: var(--bg-chat); border-bottom: 1px solid var(--line);
}
.pinned-strip[hidden] { display: none; }
.pinned-strip .pin-text { flex: 1; overflow: hidden; text-overflow: ellipsis;
                          white-space: nowrap; color: var(--muted); }
.pinned-strip .pin-drop { border: 0; background: none; color: var(--muted);
                          font-size: 15px; width: auto; padding: 2px 4px; }
/* Подсветка сообщения, к которому прыгнули по закреплению. */
.msg.flash { animation: вспышка 1.2s ease-out; }
@keyframes вспышка {
  0% { background: rgba(82, 148, 226, .35); }
  100% { background: inherit; }
}

/* Выбор чата для пересылки. */
.fwd-search {
  width: 100%; font: inherit; font-size: 16px; padding: 10px 12px;
  border-radius: 10px; border: 1px solid var(--line);
  background: var(--bg); color: var(--text);
}
/* flex: none — как у .cart-items: единственный прокручиваемый ребёнок
   flex-колонки окна под клавиатурой сжимался в полоску (аудит 17.09.2026). */
.fwd-list { list-style: none; margin: 0; padding: 0; max-height: 40vh;
            overflow-y: auto; flex: none; }
.fwd-list li {
  padding: 11px 4px; border-bottom: 1px solid var(--line); cursor: pointer;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fwd-list li:active { background: var(--bg-chat); }

/* Кнопка записи: во время записи заметно горит — иначе непонятно, идёт ли. */
/* touch-action и запрет выделения обязательны: иначе Safari на долгом
   нажатии показывает лупу с «копировать» и забирает жест себе. */
#mic { background: transparent; color: var(--muted); font-size: 19px;
       touch-action: none; -webkit-touch-callout: none;
       -webkit-user-select: none; user-select: none;
       transition: transform .14s, box-shadow .14s, background .14s; }
/* Во время записи кнопка вырастает: держать палец на маленьком кружке неудобно,
   и промах по нему обрывал запись. */
#mic.recording { background: #2f7fd1; color: #fff; transform: scale(1.5);
                 box-shadow: 0 0 0 12px rgba(47,127,209,.16); }
/* Ждём микрофон: кнопка уже выросла под палец, но серая — записи ещё нет. */
#mic.waiting { background: #9aa4ad; color: #fff; transform: scale(1.5);
               box-shadow: 0 0 0 12px rgba(154,164,173,.18); }
#mic.cancelling { background: #e53935;
                  box-shadow: 0 0 0 12px rgba(229,57,53,.16); }

/* «en» — в правом верхнем углу поля ввода, мелко и полупрозрачно. Появляется
   только когда нужен: в переписке с иностранцем или когда набран латинский
   текст. Постоянно висящая кнопка в углу мешает читать написанное. */
#composer #tr-btn {
  position: absolute; top: 5px; right: 70px; z-index: 2;
  width: auto; height: auto; min-width: 0;
  padding: 2px 4px;
  font-size: 11px; font-weight: 700; letter-spacing: .5px; line-height: 1;
  text-transform: lowercase;
  color: var(--accent); background: transparent; border: 0; border-radius: 0;
  opacity: .45; cursor: pointer;
}
#composer #tr-btn:active, #composer #tr-btn.busy { opacity: 1; }
#composer #tr-btn[disabled] { opacity: .3; }
/* Пока кнопка видна — отступ под неё, чтобы текст не заезжал под буквы. */
#composer.with-tr #text { padding-right: 34px; }

/* Панель записи занимает место поля ввода, а не ложится поверх: абсолютная
   позиция промахивалась мимо строки — форма выше поля на safe-area снизу. */
#rec-bar {
  flex: 1; min-width: 0; height: 42px; display: flex; align-items: center;
  gap: 10px; padding: 0 14px; border-radius: 20px; font-size: 15px;
  color: var(--text); background: var(--bg); border: 1px solid var(--line);
}
#rec-bar[hidden] { display: none; }
/* Пока идёт запись, всё остальное прячем: писать текст всё равно нельзя. */
#composer.recording #text, #composer.recording #attach, #composer.recording #scroll-down,
#composer.recording #scripts-btn, #composer.recording #schedule { display: none; }
.rec-dot { width: 9px; height: 9px; border-radius: 50%; background: #e53935;
           flex-shrink: 0; animation: rec-pulse 1.3s infinite; }
@keyframes rec-pulse { 50% { opacity: .1; } }
.rec-time { font-variant-numeric: tabular-nums; min-width: 42px; }
/* Ждём микрофон: точка не мигает, счётчик приглушён — записи ещё нет. */
#rec-bar.waiting .rec-dot { animation: none; opacity: .35; }
#rec-bar.waiting .rec-time { opacity: .35; }
.rec-hint { flex: 1; text-align: center; color: var(--muted);
            white-space: nowrap; overflow: hidden; }
#composer #rec-bar button { width: auto; height: auto; border-radius: 8px;
  padding: 6px 10px; font-size: 15px; font-weight: 600; background: transparent; }
#composer #rec-bar .rec-cancel { color: #e53935; }
#composer #rec-bar .rec-send { color: #2f7fd1; margin-left: auto; }

/* Замок висит над кнопкой: ведём палец вверх — запись остаётся без руки. */
#rec-lock {
  /* Кнопка при записи вырастает в полтора раза и вылезает над строкой ввода —
     замок стоял на ней (13.09.2026, замечание владельца): поднимаем выше. */
  position: absolute; right: 12px; bottom: calc(100% + 14px); z-index: 3;
  display: flex; flex-direction: column; align-items: center; line-height: 1;
  gap: 3px; padding: 9px 7px; border-radius: 16px; font-size: 14px;
  color: var(--muted); background: var(--bg); border: 1px solid var(--line);
  transition: transform .14s, color .14s;
}
#rec-lock span { font-size: 11px; }
#rec-lock.armed { color: #2f7fd1; transform: translateY(-6px); }

#rec-toast {
  position: fixed; left: 50%; bottom: 84px; transform: translateX(-50%);
  z-index: 40; padding: 9px 15px; border-radius: 18px; font-size: 14px;
  color: #fff; background: rgba(0,0,0,.78); pointer-events: none;
}
/* На странице чата — от посаженной страницы, а не от окна: fixed при
   открытой клавиатуре iPhone стоял под ней, и «не отправилось: …» никто не
   видел. body.chatpage — position: relative и под клавиатурой сидит на
   видимой области (аудит 17.09.2026). */
body.chatpage #rec-toast { position: absolute; }

/* «Нет связи с сервером» — после двух сбоев опроса подряд (02.10.2026): без
   неё замершая на смене сети переписка ничем не отличалась от тихой. Сверху,
   под «чёлкой» айфона, и не ловит касания — работать с лентой не мешает. */
#no-net {
  position: fixed; left: 50%; top: calc(env(safe-area-inset-top) + 8px);
  transform: translateX(-50%); z-index: 45; padding: 6px 14px;
  border-radius: 14px; font-size: 13px; color: #fff;
  background: rgba(176, 40, 40, .92); pointer-events: none;
}

/* Карточка контакта: имя и нажимаемый телефон — как в мессенджерах. */
.contact-card {
  display: flex; flex-direction: column; gap: 2px;
  padding: 6px 10px; border-left: 3px solid var(--accent);
  background: rgba(0, 0, 0, .04); border-radius: 6px;
}
.contact-card .c-name { font-weight: 600; }
.contact-card .c-tel { color: var(--accent); text-decoration: none; }

/* Окно пересылки: чипы каналов, заголовок списка и две строки на диалог. */
.fwd-chips { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
.fwd-chips .chip {
  padding: 5px 10px; border-radius: 14px; font-size: 13px;
  border: 1px solid var(--line); background: var(--bg); color: var(--muted);
  width: auto; height: auto;
}
.fwd-chips .chip.on { background: var(--accent); border-color: var(--accent);
                      color: #fff; }
.fwd-head { font-size: 12px; color: var(--muted); margin: 8px 0 4px; }
.fwd-list li { display: flex; flex-direction: column; gap: 1px; }
.fwd-list .fwd-name { font-size: 15px; }
.fwd-list .fwd-where { font-size: 12px; color: var(--muted);
                       overflow: hidden; text-overflow: ellipsis;
                       white-space: nowrap; }

/* У кружка пузыря быть не должно вовсе — в мессенджере он висит прямо на фоне
   переписки. Прямоугольная подложка вокруг круга выглядит рамкой от картины. */
.msg.round-note {
  background: none; box-shadow: none; padding: 0; max-width: none;
}
.msg.round-note .meta { float: none; display: block; text-align: right;
                        margin: 2px 4px 0 0; }

/* Кружок из телеграма: круглым он и записан, и показывать его прямоугольником
   значит обрезать человеку лицо по краям. */
.video-frame.round, video.media.round {
  border-radius: 50%; overflow: hidden;
  width: 200px; height: 200px; max-width: 62vw; max-height: 62vw;
}
.video-frame.round img.media { width: 100%; height: 100%; object-fit: cover; }
video.media.round { object-fit: cover; background: #000; }

.theme-pick, .chip-row { display: flex; gap: 8px; flex-wrap: wrap; }

/* Полоска выбранных файлов: миниатюры с крестиком и обрезкой по нажатию. */
#attach-bar { flex-wrap: wrap; }
#attach-thumbs { display: flex; gap: 6px; flex-wrap: wrap; width: 100%; }
/* Селектор с id намеренно: правило #attach-bar span { flex: 1 } старше
   классового и растягивало миниатюры в широкие полосы — по ним не понять,
   что за фото отправляешь. */
#attach-thumbs .att {
  position: relative; flex: 0 0 64px; width: 64px; height: 64px;
  border-radius: 8px; overflow: hidden; background: var(--bg-chat);
}
#attach-thumbs .att img, #attach-thumbs .att video {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* Документ в полоске вложений: миниатюры у PDF и docx нет, поэтому плитка
   сама говорит, что приложено, — расширение и имя файла. */
#attach-thumbs .att .doc {
  width: 100%; height: 100%; box-sizing: border-box; padding: 5px 3px;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 2px; text-align: center;
  background: var(--bubble-in); border: 1px solid var(--line);
  border-radius: 8px; color: var(--text);
}
#attach-thumbs .att .doc .ext {
  font-size: 10px; font-weight: 700; letter-spacing: .3px; color: var(--accent);
  flex: 0 0 auto;
}
#attach-thumbs .att .doc .nm {
  font-size: 8px; line-height: 1.2; color: var(--muted); width: 100%;
  overflow: hidden; word-break: break-word; flex: 0 1 auto; min-height: 0;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  /* Правило `#attach-bar span` старше классового и запрещает перенос —
     без этого имя ужималось в одну строку с многоточием. */
  white-space: normal; text-overflow: clip;
}
#attach-thumbs .att .x {
  position: absolute; top: 1px; right: 1px; width: 18px; height: 18px;
  border-radius: 50%; border: 0; padding: 0; line-height: 18px;
  background: rgba(0,0,0,.6); color: #fff; font-size: 12px;
}
#attach-thumbs .att .cut {
  position: absolute; bottom: 1px; left: 1px; width: 18px; height: 18px;
  border-radius: 50%; border: 0; padding: 0; line-height: 18px;
  background: rgba(0,0,0,.6); color: #fff; font-size: 11px;
}

/* Обрезка фото — как в «Фото» на айфоне: рамка стоит, фото под ней двигают
   и приближают, углы рамки тянутся. Сцена ловит все жесты сама
   (touch-action: none), рамка касаний не перехватывает — только её углы. */
#crop-back {
  position: fixed; inset: 0; z-index: 60; background: rgba(0,0,0,.92);
  display: flex; flex-direction: column;
  /* Сцена начинается под статус-баром: в приложении страница лежит под ним,
     и верхние углы рамки оказывались в его зоне — касания туда не доходят
     (айфон владельца, 13.09.2026). */
  padding-top: env(safe-area-inset-top);
}
#crop-stage { flex: 1; position: relative; overflow: hidden; touch-action: none;
              user-select: none; -webkit-user-select: none; cursor: grab; }
#crop-stage img { position: absolute; left: 0; top: 0; transform-origin: 0 0;
                  max-width: none; max-height: none; will-change: transform;
                  pointer-events: none; }
#crop-frame {
  position: absolute; border: 1.5px solid #fff; box-sizing: border-box;
  box-shadow: 0 0 0 9999px rgba(0,0,0,.55); pointer-events: none;
  /* Сетка третей — по ней ровняют горизонт и лица. */
  background-image:
    linear-gradient(to right, transparent calc(33.3% - .5px), rgba(255,255,255,.35) calc(33.3% - .5px), rgba(255,255,255,.35) calc(33.3% + .5px), transparent calc(33.3% + .5px)),
    linear-gradient(to right, transparent calc(66.6% - .5px), rgba(255,255,255,.35) calc(66.6% - .5px), rgba(255,255,255,.35) calc(66.6% + .5px), transparent calc(66.6% + .5px)),
    linear-gradient(to bottom, transparent calc(33.3% - .5px), rgba(255,255,255,.35) calc(33.3% - .5px), rgba(255,255,255,.35) calc(33.3% + .5px), transparent calc(33.3% + .5px)),
    linear-gradient(to bottom, transparent calc(66.6% - .5px), rgba(255,255,255,.35) calc(66.6% - .5px), rgba(255,255,255,.35) calc(66.6% + .5px), transparent calc(66.6% + .5px));
}
/* Углы — крупные мишени под палец, рисуем уголком. */
#crop-frame .h {
  position: absolute; width: 36px; height: 36px; pointer-events: auto;
  touch-action: none;
}
#crop-frame .h::after { content: ""; position: absolute; inset: 9px; width: 18px; height: 18px;
                        border: 3px solid #fff; box-sizing: border-box; }
#crop-frame .nw { left: -18px; top: -18px; cursor: nwse-resize; }
#crop-frame .nw::after { border-right: 0; border-bottom: 0; }
#crop-frame .ne { right: -18px; top: -18px; cursor: nesw-resize; }
#crop-frame .ne::after { border-left: 0; border-bottom: 0; }
#crop-frame .sw { left: -18px; bottom: -18px; cursor: nesw-resize; }
#crop-frame .sw::after { border-right: 0; border-top: 0; }
#crop-frame .se { right: -18px; bottom: -18px; cursor: nwse-resize; }
#crop-frame .se::after { border-left: 0; border-top: 0; }
#crop-hint { margin: 0; padding: 8px 16px 0; background: #000; color: #9a9a9a;
             font-size: 12px; text-align: center; }
#crop-bar {
  display: flex; gap: 10px; align-items: center; justify-content: space-between;
  padding: 12px 16px; padding-bottom: max(12px, env(safe-area-inset-bottom));
  background: #000; color: #fff;
}
#crop-bar button { width: auto; height: auto; padding: 8px 14px;
                   border-radius: 10px; background: transparent; color: #fff;
                   font-size: 15px; }
#crop-bar .ok { background: var(--accent); font-weight: 600; }

/* Поле с кнопкой в одну строку: «Кому» + «Вставить». */
.row-inline { display: flex; gap: 8px; align-items: center; }
.row-inline input { flex: 1; min-width: 0; }
.row-inline button { width: auto; height: auto; padding: 9px 14px;
                     border-radius: 10px; font-size: 15px; }

/* Пузырь загрузки: сам файл и кружок, который заполняется по кругу, — как в
   мессенджерах. Глаз в момент отправки смотрит в переписку, а не под неё. */
.msg.local-upload { position: relative; padding: 4px; }
.msg.local-upload .media { max-width: 220px; border-radius: 10px; display: block; }
.up-ring {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 2px;
  color: #fff; pointer-events: none;
}
.up-ring svg { width: 56px; height: 56px; transform: rotate(-90deg); }
.up-ring circle { fill: rgba(0, 0, 0, .45); stroke-width: 3.5; }
.up-ring circle.bg { stroke: rgba(255, 255, 255, .3); }
.up-ring circle.val { fill: none; stroke: #fff; stroke-linecap: round;
                      transition: stroke-dashoffset .2s linear; }
/* Отправляет воркер — процентов он не сообщает, поэтому просто крутим. */
.up-ring.wait svg { animation: up-spin 1.1s linear infinite; }
@keyframes up-spin { to { transform: rotate(270deg); } }
.up-ring .up-pct { position: absolute; font-size: 12px; font-weight: 600;
                   font-variant-numeric: tabular-nums; }
/* Этап под кольцом: «проверяю», «загружаю», «отправляю». Кольцо — колонка
   (svg, затем слово), процент живёт поверх svg. */
.up-ring .up-stage { position: absolute; top: calc(50% + 32px); font-size: 11px;
                     font-weight: 600; text-shadow: 0 1px 2px rgba(0,0,0,.6); }

/* Ход видео на плитке вложения: ролик готовится сразу после выбора. Полоса
   снизу заполняется по доле, слово — этап; «✓» — уже на сервере. */
#attach-thumbs .att .vjob {
  position: absolute; left: 0; right: 0; bottom: 0; height: 18px;
  display: flex; align-items: center; justify-content: center;
  font-size: 9px; font-weight: 700; color: #fff; white-space: nowrap;
  background: linear-gradient(90deg, rgba(36,129,204,.85) calc(var(--доля, 0) * 100%),
                              rgba(0,0,0,.55) calc(var(--доля, 0) * 100%));
  pointer-events: none;
}
#attach-thumbs .att .vjob[data-stage="готово"] { background: rgba(46,160,67,.9); font-size: 11px; }
#attach-thumbs .att .vjob[data-stage="ошибка"] { background: rgba(200,40,40,.9); }

/* Чем сейчас занято неотправленное сообщение: «сжимаю видео…». */
.send-note { display: block; margin-top: 3px; font-size: 12px;
             color: var(--muted); font-style: italic; }

/* Полоска «непрочитанные»: во всю ширину, чтобы граница читалась сразу. */
.unread-sep {
  align-self: stretch; width: 100%; border-radius: 0;
  background: rgba(51, 144, 236, .12); color: var(--accent);
  font-size: 12px; text-align: center; padding: 3px 0;
}

/* Ручная пометка «вернуться к этому»: синяя точка без числа. */
.mark-dot {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  background: var(--accent); margin-left: 6px; vertical-align: middle;
}
.mark-dot[hidden] { display: none; }
/* Строка едет за пальцем, у порога подсвечивается справа. */
.chat.will-mark { box-shadow: inset -3px 0 0 var(--accent); }

/* Рамка вместо превью: файл остался у воркера, показать нечего. */
.up-stub { display: flex; align-items: center; justify-content: center;
           width: 200px; height: 130px; border-radius: 10px;
           background: var(--bg-chat); font-size: 34px; }
/* Та же рамка, но с именем файла: документ во время отправки. */
.up-stub.doc { flex-direction: column; gap: 6px; padding: 8px 10px;
               box-sizing: border-box; font-size: 28px; }
.up-stub.doc .nm { font-size: 12px; line-height: 1.2; color: var(--muted);
                   text-align: center; word-break: break-word;
                   display: -webkit-box; -webkit-line-clamp: 2;
                   -webkit-box-orient: vertical; overflow: hidden; }

/* Подключение канала по коду — прямо в настройках. */
.connect { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.connect select, .connect input { flex: 1; min-width: 120px; }
.connect button { width: auto; padding: 9px 14px; border-radius: 10px; }
#connect-box { margin-top: 12px; text-align: center; }
#connect-qr { width: 240px; max-width: 80vw; image-rendering: pixelated;
              background: #fff; padding: 8px; border-radius: 10px; }
/* Код входа WhatsApp по номеру: его перепечатывают глазами в другое
   приложение — крупно, моноширинно, с разрывом посередине. */
.pair-code { font: 600 30px/1.2 ui-monospace, Menlo, monospace; letter-spacing: 3px;
             margin: 12px 0 4px; user-select: all; }
#connect-alt { margin-top: 12px; }

/* Метки диалога — подписями под строкой: цвет подсказывает, слово называет.
   Строка от этого чуть выше, но только у помеченных чатов. */
.row-labels { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 3px; }
.row-labels[hidden] { display: none; }
.row-tag {
  font-size: 11px; line-height: 1.4; padding: 0 6px; border-radius: 8px;
  border: 1px solid currentColor; white-space: nowrap;
}
/* Точка в списке действий: связь «цвет — смысл» видна там же, где метку ставят. */
.sheet-dot { width: 10px; height: 10px; border-radius: 50%;
             display: inline-block; margin-right: 8px; vertical-align: middle; }
/* Метки в шапке чата — уже словами: там есть место и важен смысл. */
.chat-labels { display: flex; gap: 6px; flex-wrap: wrap; padding: 6px 14px;
               background: var(--header); border-bottom: 1px solid var(--line); }
.chat-labels .lbl {
  display: inline-flex; align-items: center; gap: 5px; font-size: 12px;
  padding: 3px 9px; border-radius: 12px; border: 1px solid var(--line);
  background: var(--bg); color: var(--text);
}
.chat-labels .lbl i { width: 8px; height: 8px; border-radius: 50%; }
.chat-labels .lbl.off { opacity: .45; }

/* Управление каналом в настройках. Выключенный виден, но приглушён: он
   остаётся в базе со всей перепиской, просто сообщения по нему не ходят. */
.accounts li.off { opacity: .55; }
.accounts li.tappable { cursor: pointer; }
.accounts li.tappable:active { background: var(--bg-chat); }
/* Признак «здесь есть что нажать» — тонкая стрелка, а не кнопки в строке. */
.accounts li.tappable::after { content: "›"; color: var(--muted); font-size: 18px;
                               margin-left: 2px; }

/* Гости ближайших заездов на экране «написать первым». */
.guests { list-style: none; margin: 0; padding: 0; }
.guests li { display: flex; align-items: center; gap: 8px; padding: 7px 0;
             border-bottom: 1px solid var(--line); font-size: 14px; }
.guests .g-name { flex: 1; min-width: 0; overflow: hidden;
                  text-overflow: ellipsis; white-space: nowrap; }
.guests .g-when { color: var(--muted); font-size: 12px; white-space: nowrap; }
.guests .g-pick { width: auto; padding: 4px 10px; border-radius: 8px;
                  font-size: 13px; }
.guests .g-open { font-size: 13px; color: var(--accent); text-decoration: none; }

/* ---------- найденное в тексте переписки ---------- */
/* Отдельным блоком под списком чатов: чат и фраза внутри чата — разные вещи,
   и в одной ленте оператор перестаёт понимать, на что смотрит. */
.hits-title {
  padding: 14px 12px 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  border-top: 1px solid var(--line);
}
#hits { list-style: none; margin: 0; padding: 0; }
.hit a {
  display: block;
  padding: 8px 12px 10px;
  border-bottom: 1px solid var(--line);
  color: var(--text);
  text-decoration: none;
}
.hit-head { display: flex; justify-content: space-between; gap: 8px; }
.hit-chat {
  font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hit-time { color: var(--muted); font-size: 13px; flex: none; }
.hit-text {
  display: block;
  margin-top: 2px;
  /* Три строки — предел: дальше уже не «где это было», а чтение переписки. */
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
.hit-text b { background: rgba(51, 144, 236, .22); font-weight: 600; }
.hit-acc { display: block; margin-top: 2px; font-size: 12px; color: var(--muted); }

/* Куда прыгнули — из поиска или по цитате. Подсветка гаснет сама, чтобы не
   мешать читать дальше. */
.msg.found { animation: нашлось 2.4s ease-out; }
/* Цитата кликабельна: ведёт к тому сообщению, на которое отвечают. */
.quote { cursor: pointer; }
@keyframes нашлось {
  0%, 55% { box-shadow: 0 0 0 3px rgba(51, 144, 236, .55); }
  100%    { box-shadow: 0 0 0 3px rgba(51, 144, 236, 0); }
}

/* ---------- таблица «кто отвечал» ---------- */
table.ops { width: 100%; border-collapse: collapse; font-size: 15px; }
table.ops th {
  text-align: left; font-weight: 600; font-size: 13px; color: var(--muted);
  padding: 4px 6px; border-bottom: 1px solid var(--line);
}
table.ops td { padding: 7px 6px; border-bottom: 1px solid var(--line); }
table.ops th:not(:first-child), table.ops td:not(:first-child) { text-align: right; }
/* Автоответы — не работа человека, и в таблице должны читаться как фон. */
table.ops tr.auto td { color: var(--muted); }

/* ---------- дни недели у правила автоответа ---------- */
.days { padding: 6px 0 2px; }
.days-title { display: block; font-size: 13px; color: var(--muted); margin-bottom: 6px; }
.days-row { display: flex; gap: 6px; flex-wrap: wrap; }
.day { position: relative; }
.day input { position: absolute; opacity: 0; pointer-events: none; }
.day span {
  display: inline-block; min-width: 38px; padding: 7px 0;
  text-align: center; border: 1px solid var(--line); border-radius: 9px;
  color: var(--muted); background: transparent; cursor: pointer;
  user-select: none;
}
.day input:checked + span {
  background: var(--accent); border-color: var(--accent); color: #fff;
}

/* ---------- сообщение, удалённое собеседником ---------- */
/* Текст оставляем зачёркнутым, а не прячем: это часть разговора, и без него
   наш ответ висит без вопроса. */
.msg.peer-deleted .text, .msg.gone .text, .msg.deleting .text {
  text-decoration: line-through;
  opacity: .65;
}
/* Вложение зачеркнуть нельзя — гасим целиком, иначе удалённое фото выглядит
   таким же живым, как остальные. */
.msg.gone img, .msg.gone video, .msg.deleting img, .msg.deleting video,
.msg.gone .file, .msg.deleting .file { opacity: .45; }
.gone-mark.bad { color: #e53935; font-style: normal; }
.gone-mark {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  color: var(--muted);
  font-style: italic;
}

/* ---------- перевод ---------- */
/* Перевод под оригиналом и мельче: оригинал главный, перевод — подсказка. */
.tr-text {
  display: block;
  margin-top: 3px;
  padding-top: 3px;
  border-top: 1px dashed rgba(128, 128, 128, .35);
  font-size: 13px;
  opacity: .8;
  white-space: pre-wrap;
}
/* Значок языка в углу поля ввода: заметен, когда ищешь, и не мешает, когда
   не нужен. */
#tr-btn {
  position: absolute;
  top: 2px;
  right: 4px;
  z-index: 2;
  padding: 1px 5px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .5px;
  line-height: 1.4;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
}
#tr-btn:active, #tr-btn.busy { color: var(--accent); border-color: var(--accent); }
#tr-btn[disabled] { opacity: .5; }
#composer { position: relative; }

/* Маленькая кнопка перевода в пузыре — только у чужих сообщений без
   кириллицы. Автоперевода нет: платить за каждое сообщение незачем. */
.tr-ask {
  display: block;
  margin-top: 3px;
  padding: 0;
  font-size: 12px;
  color: var(--accent);
  background: transparent;
  border: none;
  cursor: pointer;
  opacity: .85;
}
.tr-ask[disabled] { color: var(--muted); }

/* Итоги поиска человека по всем аккаунтам. Список, а не одна строка,
   потому что ответ у каждого аккаунта свой: человека с закрытым поиском по
   номеру находят только те, у кого он записан в контактах. */
#found:not(:empty) { margin-top: 8px; }
#found .lk-yes, #found .lk-no, #found .lk-wait, #found .lk-hint {
  padding: 4px 0;
  font-size: 14px;
  line-height: 1.35;
}
#found .lk-yes { color: var(--text); }
#found .lk-no, #found .lk-wait { color: var(--muted); }
#found .lk-hint { color: var(--muted); font-size: 13px; padding-top: 8px; }
#found .lk-pick {
  margin-left: 6px;
  padding: 2px 8px;
  font-size: 13px;
  color: var(--accent);
  background: transparent;
  border: 1px solid var(--accent);
  border-radius: 12px;
  cursor: pointer;
}

/* ---------- оглавление настроек ---------- */
/* Девять разделов подряд на одной странице читались только пролистыванием
   целиком. Теперь оглавление: название, состояние подписью и стрелка.
   Подпись не украшение — по ней видно, надо ли вообще заходить внутрь. */
.settings.hub { background: var(--bg-chat); }
.hub-group {
  display: block;
  margin: 12px;
  background: var(--bg);
  border-radius: 14px;
  overflow: hidden;
}
.hub-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  color: var(--text);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
}
.hub-item:last-child { border-bottom: 0; }
.hub-item:active { background: var(--bg-chat); }
/* Цветная плашка со значком: канал, люди, автоответы различаются с одного
   взгляда, без чтения. Размер 32 — крупнее теряет строку в высоте. */
.hub-ico {
  flex: 0 0 32px;
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 9px;
  color: #fff;
}
.hub-ico svg { width: 20px; height: 20px; }
.ico-green  { background: #34c759; }
.ico-violet { background: #7d5fff; }
.ico-blue   { background: #3390ec; }
.ico-orange { background: #f5a623; }
.ico-teal   { background: #14b8a6; }
.ico-red    { background: #ef4444; }
.ico-indigo { background: #5b6ee1; }
.hub-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.hub-title { font-size: 16px; line-height: 1.25; }
.hub-sub { font-size: 13px; color: var(--muted); line-height: 1.25; }
.hub-go { color: var(--muted); font-size: 20px; line-height: 1; }
/* Оранжевая стрелка — единственное место, где список кричит: там что-то
   требует человека (канал отвалился, уведомления никому не приходят). */
.hub-go.warn { color: #e0803a; }
.hub-foot { padding: 6px 12px 24px; }
.hub-foot .note { padding: 0 2px 10px; }

/* Строка канала: логотип вместо цветной точки, номер под названием. */
.accounts .ch-ico { grid-area: dot; width: 28px; height: 28px; border-radius: 8px; }
.accounts .ch-text { grid-area: label; display: flex; flex-direction: column; gap: 1px;
                     min-width: 0; }
.accounts li:has(.ch-ico) {
  grid-template-columns: 28px 1fr auto 8px;
  grid-template-areas: "dot label state dot2";
  padding: 9px 0;
}
.accounts li:has(.ch-ico) .dot { grid-area: dot2; }
.accounts li:has(.ch-ico) .phone { grid-area: auto; font-size: 12px; }
.accounts li.tappable:has(.ch-ico)::after { content: none; }
button.wide.primary {
  width: 100%; margin-top: 12px;
  background: var(--accent); color: #fff; border: 0;
  border-radius: 12px; padding: 13px; font-size: 16px;
}
/* Значок канала в списке аккаунтов — тот же логотип, что в ленте чатов. */
.accounts .chan-slot { display: flex; align-items: center; justify-content: center; }
.accounts .chan-slot svg { width: 28px; height: 28px; border-radius: 50%; }
/* Список каналов карточкой, как оглавление: страница перестаёт быть
   «строками, приклеенными к краю экрана». */
.settings .accounts {
  background: var(--bg); border-radius: 14px; padding: 2px 12px; margin: 0;
}
.settings section:has(.accounts) { background: var(--bg-chat); border-bottom: 0; }
/* Название аккаунта — обычным весом: в списке из пятнадцати строк жирный
   шрифт перестаёт что-либо выделять и просто утяжеляет экран. */
.settings .accounts .label { font-weight: 500; font-size: 16px; }
.settings .accounts .state { font-size: 13px; }
.settings .connect {
  background: var(--bg); border-radius: 14px; padding: 12px; margin-top: 12px;
}
.settings .connect select, .settings .connect input { margin: 0 0 8px; }

/* ---------- операторы ---------- */
.op-face {
  flex: 0 0 34px; width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; color: #fff; font-size: 14px; font-weight: 600;
}
.op-face.big { width: 64px; height: 64px; font-size: 24px; margin: 0 auto 10px; }
.op-me {
  margin-left: 6px; padding: 1px 7px; border-radius: 9px;
  font-size: 11px; font-weight: 500;
  color: var(--accent); background: rgba(51,144,236,.14);
}
.hub-item .op-state { font-size: 13px; color: #34c759; }
.hub-item .op-state.off { color: var(--muted); }

.op-hero { padding: 18px 14px 6px; text-align: center; }
.op-hero #op-name {
  width: 100%; max-width: 320px; margin: 0 auto; text-align: center;
  font-size: 18px; font-weight: 600;
}
.op-hero .note { margin-top: 6px; }
.op-block { padding: 4px 14px 12px; }
.op-block h2 {
  font-size: 13px; text-transform: uppercase; letter-spacing: .4px;
  color: var(--muted); font-weight: 600; margin: 12px 0 6px;
}
.op-block .note { padding-bottom: 4px; }
/* Одно право — одна строка: название слева, переключатель справа. В прежнем
   виде галочка стояла ПЕРЕД текстом, и восемь строк читались как список
   покупок, а не как настройка доступа. */
.op-right {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 0; border-bottom: 1px solid var(--line);
  font-size: 15px; cursor: pointer;
}
.op-right:last-of-type { border-bottom: 0; }
.op-right > span:first-child { flex: 1; min-width: 0; }
.op-right .sw { position: absolute; opacity: 0; pointer-events: none; }
.op-right .sw-track {
  flex: 0 0 46px; width: 46px; height: 28px; border-radius: 14px;
  background: var(--line); position: relative; transition: background .15s;
}
.op-right .sw-track::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 24px; height: 24px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.25); transition: transform .15s;
}
.op-right .sw:checked + .sw-track { background: var(--accent); }
.op-right .sw:checked + .sw-track::after { transform: translateX(18px); }
.op-card .op-row { display: flex; gap: 8px; align-items: center; }
.op-card .op-row input, .op-card .op-row select { margin: 0; }
a.wide.primary {
  display: block; text-align: center; text-decoration: none;
  width: 100%; margin-top: 12px; padding: 13px;
  background: var(--accent); color: #fff; border-radius: 12px; font-size: 16px;
}

/* ---------- переписка: геометрия по макету ---------- */
/* Одинаковый радиус без «хвоста» у последнего пузыря: хвост имеет смысл там,
   где сообщения идут вперемешку от разных людей, а в переписке с одним
   гостем он только рвёт ритм ленты. */
.msg { border-radius: 18px; padding: 7px 12px; }
.msg.in { border-bottom-left-radius: 18px; }
.msg.out { border-bottom-right-radius: 18px; }
/* Сообщения одного отправителя стоят плотно, смена стороны — с воздухом:
   так видно реплики разговора, а не однородную ленту. */
#feed { gap: 2px; }
.msg.in + .msg.out, .msg.out + .msg.in { margin-top: 9px; }
.msg .meta { margin: 4px 0 0 10px; }
/* Картинка занимает пузырь целиком: рамка вокруг фото съедала ширину и
   делала вложение мельче, чем оно есть. */
.msg:has(.media) { padding: 3px; }
.msg:has(.media) .meta { margin: 2px 8px 4px 10px; }
.msg:has(.media) .text { display: block; padding: 4px 9px 2px; }

/* ---------- список чатов: плотнее ---------- */
/* Было до пяти строк на чат: имя, объявление, превью, метки, аккаунт. На
   экране помещалось восемь переписок из четырёхсот. Теперь две строки, а
   третья появляется только там, где есть метки или нужен ярлык аккаунта. */
.chat a {
  grid-template-areas: "av row1" "av row2" "av row3";
  padding: 8px 14px;
}
.chat .row1 { gap: 6px; }
/* Апартамент рядом с именем: «Анастасия · апарт 7012» — одна мысль, и
   разносить её на две строки значило терять строку экрана на каждом чате. */
.chat .apt {
  flex: 0 1 auto; min-width: 0;
  font-size: 13px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat .apt[hidden] { display: none; }
/* Ужимается в первую очередь апартамент, потом имя; время и ярлык аккаунта
   не ужимаются никогда — иначе на узком экране от них остаётся многоточие,
   а именно они отвечают на вопрос «кому и с какого аккаунта отвечать». */
/* Порядок важности в строке: имя → апартамент → аккаунт → время. Ужимается
   всё в обратном порядке, поэтому у аккаунта самый большой коэффициент
   сжатия: «апарт 7012» отвечает на вопрос «о чём речь», а ярлык аккаунта —
   только «кому отвечать», и его можно дочитать в самом чате. */
.chat .title { flex: 0 1 auto; min-width: 7em; }
.chat .apt { flex: 0 8 auto; }
.chat .row1 .account {
  margin-left: auto; flex: 0 200 auto; min-width: 0;
  font-size: 12px; color: var(--muted);
  overflow: hidden; text-overflow: clip; white-space: nowrap;
}
.chat .time { flex: none; }
.chat .row3 {
  grid-area: row3; display: flex; align-items: center; gap: 6px;
  min-width: 0; margin-top: 2px;
}
.chat .row3[hidden] { display: none; }
.chat .row3 .row-labels { margin: 0; }
.chat .row2 .stage { margin-right: 6px; }

/* Шапка: заголовок со счётчиком в одну строку и не переносится. */
h1 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#filter-line #account-filter {
  max-width: 46vw; font-size: 13px; padding: 4px 8px; border-radius: 14px;
}

/* ---------- шапка списка и панель каналов ---------- */
header .ico-btn, #menu-btn {
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0;
  background: transparent; border: 0; color: var(--accent);
  text-decoration: none; cursor: pointer;
}
#menu-btn { color: var(--text); margin-left: -6px; }
header .ico-btn svg, #menu-btn svg {
  width: 23px; height: 23px; fill: none; stroke: currentColor;
  stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
}
header .ico-btn:active { opacity: .5; }

/* Панель выезжает слева и толкает список вправо — не на весь экран: видно,
   что список никуда не делся и панель закрывается касанием мимо. */
#side {
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 20;
  width: 76vw; max-width: 300px;
  padding: max(12px, env(safe-area-inset-top)) 0 12px;
  background: var(--header); border-right: 1px solid var(--line);
  transform: translateX(-100%); transition: transform .2s ease;
  overflow-y: auto; overscroll-behavior: contain;
}
body.side-open #side { transform: none; }
#side-back {
  position: fixed; inset: 0; z-index: 15; background: rgba(0,0,0,.28);
  opacity: 0; transition: opacity .2s ease;
}
body.side-open #side-back { opacity: 1; }
/* Список остаётся на месте и виден полосой справа — по нему понятно, что
   панель наложена на то же окно и закрывается касанием мимо.
   Сдвигать сам body нельзя: он становится точкой отсчёта для position:fixed,
   и панель уезжает вместе с ним. */
body.side-open { overflow: hidden; }
#side { box-shadow: 0 0 24px rgba(0,0,0,.18); }
.side-head {
  padding: 6px 16px 10px; font-size: 13px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .4px; color: var(--muted);
}
.side-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 11px 16px; border: 0; background: transparent;
  font: inherit; font-size: 16px; color: var(--text); text-align: left;
  cursor: pointer;
}
.side-item:active { background: var(--bg-chat); }
.side-item.on { color: var(--accent); font-weight: 600; }
.side-item .chan-slot { flex: none; width: 26px; height: 26px; display: flex; }
.side-item .chan-slot svg, .side-item .chan-slot img {
  width: 26px; height: 26px; border-radius: 50%;
}
.side-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
             white-space: nowrap; }
/* Разделы инбокса — выше каналов (владелец, 23.09.2026). */
.side-nav { display: flex; flex-direction: column; padding-bottom: 6px;
            margin-bottom: 4px; border-bottom: 1px solid var(--line); }
.side-link { display: flex; align-items: center; gap: 12px; padding: 11px 16px;
             color: var(--text); text-decoration: none; font-size: 16px; }
.side-link svg { width: 22px; height: 22px; flex: none; fill: none; stroke: var(--muted);
                 stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.side-link.on { color: var(--accent); font-weight: 600; }
.side-link.on svg { stroke: var(--accent); }
.side-link:active { background: var(--bg-chat); }
.side-n { margin-left: auto; font-size: 13px; font-weight: 600; color: #d33a2c; }
.side-channels summary { padding: 11px 16px; color: var(--muted); font-size: 14px;
                         cursor: pointer; list-style: none; }
.side-channels summary::-webkit-details-marker { display: none; }
.side-channels summary::after { content: ' ▾'; }
.side-channels[open] summary::after { content: ' ▴'; }
#checkins-count:not(:empty) { color: #d33a2c; font-weight: 600; }

/* ---------- поиск внутри переписки ---------- */
#find-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 7px 10px; background: var(--header);
  border-bottom: 1px solid var(--line);
}
#find-bar[hidden] { display: none; }
#find-input {
  flex: 1; min-width: 0; margin: 0; padding: 8px 12px;
  font-size: 16px;                /* меньше — iOS зумит страницу при фокусе */
  border: 1px solid var(--line); border-radius: 18px;
  background: var(--bg); color: var(--text);
}
#find-count { font-size: 13px; color: var(--muted); white-space: nowrap; }
#find-bar button {
  flex: none; width: 32px; height: 32px; padding: 0; margin: 0;
  background: transparent; border: 0; color: var(--accent); font-size: 16px;
}
/* Найденное — жёлтой заливкой по самому слову, а не по всему пузырю: так
   видно, за что зацепился поиск. Текущее совпадение обведено, чтобы не
   теряться среди десятка одинаковых. */
mark.find-hit {
  background: rgba(255,214,0,.55); color: inherit;
  border-radius: 3px; padding: 0 1px;
}
:root[data-theme="dark"] mark.find-hit { background: rgba(255,214,0,.35); }
.msg.found-now { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Кнопка поиска в шапке чата — рисунком и без подложки: рядом с аватаркой
   любой фон читается как второй значок канала. */
#find-btn { background: transparent; border: 0; padding: 0 2px;
            color: var(--muted); line-height: 0; }
#find-btn svg { display: block; }
/* День выезда до расчётного часа: гость ещё здесь, но уже собирается —
   оранжевым, как и всё, что требует внимания сегодня. */
.stage-checkout { background: #fff1e0; color: #a35b17; }
:root[data-theme="dark"] .stage-checkout { background: #4a3418; color: #ffbe7a; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .stage-checkout { background: #4a3418; color: #ffbe7a; }
}

/* Крестик на пузыре загрузки: пока ролик ползёт вверх на телефонном
   интернете, передумать — обычное дело, а отменить было нечем. */
.local-upload { position: relative; }
.up-cancel {
  position: absolute; top: 6px; right: 6px;
  width: 30px; height: 30px; padding: 0; margin: 0;
  border: 0; border-radius: 50%;
  background: rgba(0,0,0,.45); color: #fff; font-size: 15px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.up-cancel:active { background: rgba(0,0,0,.65); }

/* Тишина по чату: значок рядом с именем и в строке списка. Не красный и не
   крупный — это состояние, а не тревога. */
.muted-mark { margin-left: 6px; font-size: 13px; opacity: .75; }
.chat .mute-mark, .chat .remind-mark, .chat .later-mark { font-size: 11px; flex-shrink: 0; opacity: .7; }

/* Голосовое: круглая кнопка, форма волны и время — как в мессенджерах.
   Системный <audio controls> занимал в сафари полпузыря и не показывал, о
   чём вообще речь: одна серая полоска на все сообщения. */
.voice {
  display: flex; align-items: center; gap: 10px;
  width: 268px; max-width: 100%; padding: 2px 0;
}
.voice .v-play {
  flex: none; width: 40px; height: 40px; border: 0; border-radius: 50%;
  background: var(--accent); cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
}
/* Треугольник и пауза рисуем рамками: две картинки ради двух состояний
   кнопки — лишние запросы на каждой переписке. */
.voice .v-play::before {
  content: ''; width: 0; height: 0; margin-left: 3px;
  border-left: 12px solid #fff;
  border-top: 8px solid transparent; border-bottom: 8px solid transparent;
}
.voice.playing .v-play::before {
  width: 12px; height: 14px; margin: 0; border: 0;
  border-left: 4px solid #fff; border-right: 4px solid #fff;
  box-sizing: border-box;
}
.voice .v-bars {
  flex: 1 1 auto; display: flex; align-items: center; gap: 2px;
  height: 26px; cursor: pointer; min-width: 0;
}
.voice .v-bars i {
  flex: 1 1 0; min-width: 2px; border-radius: 2px;
  background: var(--muted); opacity: .45;
}
.voice .v-bars i.on { background: var(--accent); opacity: 1; }
.voice .v-time {
  flex: none; font-size: 12px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Аватарка в шапке раскрывается во весь экран — по ней иногда и узнают гостя. */
#chat-avatar { cursor: zoom-in; }

/* ── Карточка брони над перепиской ──────────────────────────────────────────
   Две строки: кто с кем и деньги. Раскрывается нажатием — тогда между ними
   появляется третья: внесённое, договор, телефон. Раньше карточка занимала
   четыре строки подряд, и на телефоне первые сообщения уезжали под экран. */
.booking {
  background: var(--bubble-in); border-radius: 14px; overflow: hidden;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .06);
}
.booking.off { opacity: .55; }

.b-head {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: 2px 8px; width: 100%; padding: 7px 10px;
  border: 0; background: none; font: inherit; color: inherit;
  text-align: left; cursor: pointer;
}
/* Точка и галочка держатся первой строки: на узком экране приметы
   переносятся вниз, и по центру они оказывались напротив пустоты. */
.b-dot { width: 9px; height: 9px; border-radius: 50%;
         align-self: start; margin-top: 7px; }
.b-dot.ok { background: #34c759; }
.b-dot.wait { background: #ff9f0a; }
.b-dot.bad { background: #ff3b30; }
.b-dot.off { background: #b8b8b8; }   /* заявка площадки не оплачена — серая точка */
/* Имя и приметы в одной строке, а на узком экране приметы переезжают вниз —
   галочка раскрытия при этом остаётся на месте, справа. */
.b-title { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px;
           min-width: 0; }
.b-who { font-weight: 700; font-size: 14px; }
.b-facts { color: var(--muted); font-size: 12px; }
.b-when { white-space: nowrap; }
/* Часы заезда→выезда — сразу за датами, чуть тише, чтобы не спорить с ними. */
.b-hours { white-space: nowrap; margin-left: 5px; font-variant-numeric: tabular-nums; opacity: .85; }
.b-chev { color: var(--muted); transition: transform .15s;
          align-self: start; margin-top: 3px; }
.booking[data-open="1"] .b-chev { transform: rotate(180deg); }

/* Деньги и подробности — одной строкой, ячейки через тонкую черту. Строка
   не переносится: перенос ставил черту-разделитель в начало новой строки,
   перед первой же плашкой. Если на узком экране всё-таки не влезает, строка
   сдвигается пальцем — высота карточки от этого не скачет. */
.b-money, .b-more {
  display: flex; flex-wrap: nowrap; align-items: stretch;
  border-top: 1px solid var(--line);
  overflow-x: auto; scrollbar-width: none;
  /* Только горизонтальный жест: вертикальный с плашек уходил в страницу, а
     при клавиатуре ряды исключены из гашения touchmove (аудит 17.09.2026). */
  touch-action: pan-x;
}
.b-money::-webkit-scrollbar, .b-more::-webkit-scrollbar { display: none; }
.b-cell {
  display: flex; align-items: center; gap: 6px; flex: none;
  padding: 7px 10px; white-space: nowrap;
}
.b-cell:empty { display: none; }
.b-cell + .b-cell { border-left: 1px solid var(--line); }
.b-ic { flex: none; color: var(--muted); }
.b-ic.ok { color: #34c759; }
.b-ic.no { color: #ff3b30; }
.b-pair { display: flex; flex-direction: column; line-height: 1.15; }
.b-label { color: var(--muted); font-size: 11px; }
.b-val { font-size: 12.5px; }
.b-val.ok { color: #2e9e4f; text-decoration: none; }
.b-val.no { color: #d33a2c; }
.b-pill {
  font-size: 12px; font-weight: 600; border-radius: 8px; padding: 2px 8px;
  white-space: nowrap;
}
/* Тонкие галочка/крестик в плашках: наследуют цвет плашки. */
.b-pill .pill-ic { width: 13px; height: 13px; vertical-align: -2px; fill: none; stroke: currentColor;
                   stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.b-pill.bad { background: rgba(255, 59, 48, .13); color: #d33a2c; }
.b-pill.warn { background: rgba(255, 159, 10, .17); color: #c1741a; }
.b-pill.good { background: rgba(52, 199, 89, .16); color: #2e9e4f; }
/* Свёрнутая карточка — компактнее (владелец, 15.09.2026): второстепенные
   приметы (источник, гости, ночи) спрятаны, отступы тоньше. Строка плашек
   (оплачено · залог · договор · пропуск) остаётся целиком — владелец
   попросил не прятать зелёные. */
/* Найдена только по имени (06.10.2026): жёлтая строка под шапкой, видна и в
   свёрнутой карточке — «Верно» привязывает руками, «Не та» отвязывает. */
.b-guess {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px;
  padding: 5px 10px; border-top: 1px solid var(--line);
  background: rgba(255, 159, 10, .14); color: #a35f0e; font-size: 12px;
}
.b-guess-text { flex: 1 1 200px; }
.b-guess-acts { display: flex; gap: 6px; }
.b-guess button {
  font: inherit; font-weight: 600; border-radius: 8px; padding: 3px 10px;
  border: 1px solid currentColor; background: none; color: inherit; cursor: pointer;
}
.b-guess .b-guess-yes { background: #a35f0e; border-color: #a35f0e; color: #fff; }
.b-guess button:disabled { opacity: .5; }
.b-tab-guess { font-size: 11px; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .b-guess { color: #ffc46b; }
  :root:not([data-theme="light"]) .b-guess .b-guess-yes { background: #ffc46b; border-color: #ffc46b; color: #3a2400; }
}
:root[data-theme="dark"] .b-guess { color: #ffc46b; }
:root[data-theme="dark"] .b-guess .b-guess-yes { background: #ffc46b; border-color: #ffc46b; color: #3a2400; }
.booking:not([data-open="1"]) .b-minor { display: none; }
.booking:not([data-open="1"]) .b-head { padding: 5px 10px; }
.booking:not([data-open="1"]) .b-money .b-cell { padding: 4px 10px; }
/* Порядок скриптов: их уже три десятка, и «шаги заезда» вперемешку с
   «кодами ключей» приходилось выискивать глазами. Двигать можно стрелками
   (точный шаг, удобно с телефона) и перетаскиванием за точки (утащить через
   полсписка, не нажимая стрелку двадцать раз). */
.sc-list li { display: flex; align-items: flex-start; gap: 8px; }

/* Ручка перетаскивания: шесть точек в две колонки. Рисуем узором, а не
   символом: брайлевская «⠿» в разных шрифтах то крупнее строки, то съезжает
   по базовой линии. `touch-action: none` обязателен — без него палец вместо
   строки тащит страницу. */
.sc-grip {
  flex: none; width: 12px; height: 18px; margin-top: 2px;
  cursor: grab; touch-action: none; opacity: .55;
  background-image: radial-gradient(circle, var(--muted) 1.4px, transparent 1.5px);
  background-size: 6px 6px; background-position: 1px 1px;
}
.sc-grip:active { cursor: grabbing; opacity: 1; }
/* Строка под пальцем: бледная, чтобы сквозь неё было видно, куда встанет. */
.sc-list li.sc-dragging { opacity: .55; }

/* «Написать» в карточке пересланного контакта и логин в тексте сообщения.
   Ведут в нашу же форму «написать первым», а не наружу в телеграм: снаружи
   переписка ушла бы мимо инбокса — без истории и без сменщика. */
.c-write { display: inline-block; margin-top: 2px; font-size: 13px; }

/* Окно платежа поверх переписки. Узкое и в столбик: его открывают с телефона
   одной рукой, посреди разговора с гостем. */
/* Коробка окна поверх чата — одна на все окна (доплата, залог, внесение,
   заявка), у каждого только своя ширина. Стоит обычным ребёнком подложки,
   не fixed: на iPhone клавиатура сдвигает страницу, и fixed-коробка уезжала
   под статус-бар (см. Клавиатура в app.js). */
.form-box {
  position: relative; margin: auto;
  max-height: 100%; overflow-y: auto; overscroll-behavior: contain;
  background: var(--bg); border-radius: 16px; padding: 16px;
  display: flex; flex-direction: column; gap: 10px;
  box-shadow: 0 12px 40px rgba(0,0,0,.25);
}
/* На телефоне окно прижато к верху видимой области (см. .modal-back.form):
   по горизонтали по центру, по вертикали — не центрировать. */
@media (hover: none) and (pointer: coarse) {
  .form-box { margin: 0 auto; }
}
.form-box input, .form-box select, .form-box textarea { font-size: 16px; }
/* Крестик в шапке окна. */
.окно-закрыть { background: transparent; color: var(--muted); font-size: 18px;
                padding: 2px 6px; line-height: 1; }
#pay-box { width: min(340px, calc(100vw - 32px)); }
.pay-head { display: flex; align-items: center; justify-content: space-between;
            font-weight: 600; gap: 8px; }
.pay-row { display: flex; flex-direction: column; gap: 4px; font-size: 13px;
           color: var(--muted); }
/* Ровно 16px, не меньше: Safari на iPhone увеличивает страницу при фокусе в
   поле со шрифтом мельче 16px, и после окна доплаты чат оставался
   «приближенным». Касается всех полей окон поверх чата. */
.pay-row input, .pay-row select { font-size: 16px; }
.pay-sum { display: flex; align-items: center; gap: 6px; }
.pay-sum input { flex: 1 1 auto; }
.pay-cur { color: var(--muted); }
/* Галочка сбоку от суммы: сумма подставлена из долга, но гость мог доплатить
   больше — пусть человек посмотрит на число, прежде чем нажать. */
.pay-check { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.pay-check input { width: 18px; height: 18px; }
/* Галочка «увеличить стоимость» серая, пока сумма не больше долга. */
.pay-raise.off { opacity: .45; }
.pay-over { color: #c1741a; margin: 2px 0 0; }
/* Долг — кнопка, но выглядеть обязана как соседние плашки залога и договора.
   Шрифт наследуем только семейством: `font: inherit` целиком перебивал размер
   из .b-pill, и долг раздувался вдвое против соседей. */
button.pay-open {
  cursor: pointer; border: 0; font-family: inherit; line-height: inherit;
}
/* Заблокированная кнопка обязана выглядеть заблокированной. Синяя и живая на
   вид, но не нажимающаяся, читается как поломка — а здесь она ждёт галочку. */
#pay-save:disabled { opacity: .45; cursor: not-allowed; }

/* Окно возврата залога. Устроено как окно платежа, но выше: две суммы и
   выбор способа. */
#dep-box { width: min(360px, calc(100vw - 32px)); }
.dep-way { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.dep-way input { width: 18px; height: 18px; }
#dep-amount { background: var(--line); }
#dep-save:disabled, #depin-save:disabled { opacity: .45; cursor: not-allowed; }
button.dep-open, button.depin-open {
  cursor: pointer; border: 0; font-family: inherit; line-height: inherit;
}

/* Заявка Суточно над перепиской: как карточка брони, но со своими строками
   и кнопками действий. Отказанная — приглушена, как отменённая бронь. */
.su-card {
  margin: 8px 10px 0; padding: 10px 12px; border-radius: 12px;
  background: var(--bg); border: 1px solid var(--line); font-size: 14px;
  display: flex; flex-direction: column; gap: 8px;
}
.su-card.off { opacity: .6; }
/* Шапка — кнопка сворачивания, на вид как строка. Стрелка вниз в свёрнутом,
   вверх в раскрытом; таймер в свёрнутом виде — единственное живое место. */
.su-head {
  display: flex; align-items: center; gap: 6px 8px; flex-wrap: wrap;
  width: 100%; padding: 0; border: 0; background: transparent; color: inherit;
  font: inherit; text-align: left; cursor: pointer;
}
.su-head .b-chev { margin-left: auto; color: var(--muted); flex: none;
                   transition: transform .15s ease; }
.su-head[aria-expanded="true"] .b-chev { transform: rotate(180deg); }
.su-more { display: flex; flex-direction: column; gap: 8px; }
.su-title { font-weight: 600; }
.su-state { font-size: 12px; padding: 3px 10px; border-radius: 12px; white-space: nowrap; }
.su-state.wait { background: #fff3cd; color: #7a5a00; }
.su-state.ok { background: #e6f4ea; color: #1e6b34; }
.su-state.bad { background: #fde8e8; color: #a12626; }
.su-timer:not(:empty)::before { content: " · "; }
.su-rows { display: flex; flex-direction: column; gap: 3px; }
.su-row { display: flex; gap: 8px; line-height: 1.35; }
.su-label { color: var(--muted); flex: 0 0 82px; }
.su-flag { color: #a12626; font-weight: 600; }
.su-acts { display: flex; gap: 8px; flex-wrap: wrap; }
.su-acts button { flex: 1 1 0; padding: 9px 8px; font-size: 14px; border-radius: 12px; white-space: nowrap; }
.su-acts button.danger { background: transparent; color: #e53935; border: 1px solid var(--line); }
/* Окно действий по заявке — три вида в одном. */
#su-box { width: min(360px, calc(100vw - 32px)); }
#su-form-cost, #su-form-decline { display: flex; flex-direction: column; gap: 10px; }
#su-save:disabled { opacity: .45; cursor: not-allowed; }
#su-save.danger { background: #e53935; }

/* Окно внесения залога: как окно возврата, форма прячется, пока RC не
   ответил, внесён ли залог уже. */
#depin-box { width: min(360px, calc(100vw - 32px)); }
#depin-form { display: flex; flex-direction: column; gap: 10px; }
#depin-amount[readonly] { background: var(--line); }
#depin-link { font-size: 14px; word-break: break-all; color: var(--accent); }
#depin-copy { margin-top: 4px; }

/* Окно заявки на пропуск: как окно залога, но с многострочным полем ФИО. */
#pass-box { width: min(380px, calc(100vw - 32px)); }
/* Окно компактное — подписи 12px, отступы 8px, кнопки ниже, у заметок нет
   полей абзаца, — чтобы на iPhone над клавиатурой (~500px) помещалось как
   можно больше. Поле ФИО — пять строк и НЕ ужимается: раньше колонка flex при
   нехватке места сжимала именно его, ровно в момент, когда в нём печатают.
   Не влезло — прокручивается само окно. */
#pass-box { padding: 14px; gap: 8px; }
#pass-box .pay-row { gap: 2px; font-size: 12px; }
#pass-box input[type="date"] { padding: 8px; }
#pass-box p.note { margin: 0; font-size: 12px; line-height: 1.3; }
#pass-limit { color: var(--muted); }
.pass-dates { display: flex; gap: 10px; }
.pass-dates .pay-row { flex: 1 1 0; }
#pass-names {
  width: 100%; font: inherit; font-size: 16px; line-height: 1.4;
  padding: 10px; border-radius: 10px; resize: vertical;
  border: 1px solid var(--line); background: var(--bg); color: var(--text);
  flex: none;
}
/* Подпись предела дней приезжает вместе со списком апартаментов, чуть позже
   окна. Место под неё занято заранее, иначе поле ФИО съезжало на строку. */
#pass-limit { min-height: 1.3em; }
.pass-btns { display: flex; gap: 8px; }
.pass-btns button { flex: 1 1 0; padding: 8px 6px; font-size: 14px; }
#pass-box button.wide { margin-top: 2px; padding: 11px; }
/* История подач по брони внутри окна: компактный список, свежие сверху. */
#pass-log { display: flex; flex-direction: column; gap: 8px; }
.pass-log-title { font-size: 13px; color: var(--muted); }
.pass-log-item {
  border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px;
  display: flex; flex-direction: column; gap: 4px; font-size: 13px;
}
.pass-log-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.pass-log-where { font-weight: 600; }
.pass-log-meta { color: var(--muted); font-size: 12px; }
.pass-log-tickets { color: var(--muted); font-size: 12px; white-space: pre-line; }
#pass-bad { color: #d33a2c; white-space: pre-line; }
#pass-bad:empty, #pass-limit:empty, #pass-state:empty { display: none; }
/* Окно правки брони: жёлтые блоки раннего/позднего — как в приложении RC. */
#bk-box, #nb-box { width: min(380px, calc(100vw - 32px)); gap: 8px; }
#bk-box .pay-row, #nb-box .pay-row { gap: 2px; font-size: 12px; }
#bk-box input[type="date"], #bk-box input[type="time"], #nb-box input[type="date"], #nb-box input[type="time"] { padding: 8px; }
#bk-box p.note, #nb-box p.note { margin: 0; font-size: 12px; }
#bk-state:empty, #nb-state:empty { display: none; }
#bk-box, #nb-box { box-sizing: border-box; overflow-x: hidden; }
#bk-box .pass-dates .pay-row, #nb-box .pass-dates .pay-row { min-width: 0; flex: 1 1 0; }
/* Даты и время iOS не ужимаются ниже своей ширины, пока не снять родной
   вид — две в ряд вылезали за коробку, и окно гуляло влево-вправо. */
#bk-box .pass-dates input, #nb-box .pass-dates input { width: 100%; min-width: 0; box-sizing: border-box; -webkit-appearance: none; appearance: none; }
#bk-box input[type="date"], #bk-box input[type="time"], #nb-box input[type="date"], #nb-box input[type="time"] { display: block; }
#bk-box textarea, #nb-box textarea { font: inherit; font-size: 16px; padding: 8px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--bg); color: var(--text); resize: vertical; }
#bk-nights, #nb-nights { font-weight: 400; color: var(--muted); }
.bk-colors { display: flex; flex-wrap: wrap; gap: 6px; }
.bk-color { width: 26px; height: 26px; border-radius: 50%; border: 2px solid var(--line); padding: 0;
  cursor: pointer; box-sizing: border-box; }
.bk-color.on { border-color: var(--text); box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--text); }
.bk-color.none { background: transparent; font-size: 13px; color: var(--muted); }
.bk-reactions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.bk-react { width: 34px; height: 30px; padding: 0; font-size: 17px; border-radius: 8px;
  border: 1px solid var(--line); background: transparent; }
.bk-react.on { border-color: #1a56c4; background: #e3efff; }
.bk-react.none { font-size: 13px; color: var(--muted); }
#bk-react-own { width: 56px; font-size: 16px; padding: 4px 6px; text-align: center; }
.bk-extra { background: #fff5c2; border-radius: 12px; padding: 8px 10px; display: flex; flex-direction: column; gap: 6px; color: #3a3000; }
.bk-extra[hidden] { display: none; }
.bk-extra-head { font-size: 13px; font-weight: 600; }
.bk-extra-note { font-weight: 400; color: #7a6a00; margin-left: 4px; }
.bk-check { display: flex; align-items: center; gap: 6px; font-size: 13px; }
.bk-check input { width: 16px; height: 16px; margin: 0; }
.bk-check.off { opacity: .5; }
/* Окно «свободные варианты» (корзина RC). */

/* Файлы брони: строка с превью, именем и крестиком; снятые — зачёркнуты. */
.bk-files { margin-top: 10px; }
.bk-files-head { display: flex; align-items: center; justify-content: space-between;
                 font-size: 13px; color: var(--muted); margin-bottom: 4px; }
.bk-add-file { cursor: pointer; }
.bk-file-list { list-style: none; margin: 0; padding: 0; }
.bk-file-list li { display: flex; align-items: center; gap: 8px; padding: 5px 0;
                   border-top: 1px solid var(--line); font-size: 14px; min-width: 0; }
.bk-file-list li:first-child { border-top: 0; }
.bk-file-list .bf-pic { width: 34px; height: 34px; border-radius: 6px; object-fit: cover;
                        background: var(--bg-chat); flex: none; display: grid; place-items: center; }
.bk-file-list .bf-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
                         white-space: nowrap; text-decoration: none; color: var(--text); }
.bk-file-list .bf-x { border: 0; background: transparent; color: var(--muted); font-size: 18px;
                      padding: 0 6px; cursor: pointer; }
.bk-file-list li.gone .bf-name { text-decoration: line-through; color: var(--muted); }
.bk-file-list li.new .bf-name::after { content: ' · новый'; color: var(--accent); font-size: 12px; }
.bk-file-list li.wait .bf-name { color: var(--muted); }

/* Времена правила CRM: строки «время ✕», кнопка «+ ещё время». */
.cr-times { align-items: flex-start; }
#cr-f-times { display: flex; flex-direction: column; gap: 6px; }
.cr-time { display: flex; align-items: center; gap: 6px; }
.cr-time input { flex: 1; min-width: 0; }
.cr-time-x { border: 0; background: transparent; color: var(--muted); font-size: 16px;
             padding: 4px 6px; width: auto; height: auto; cursor: pointer; }
#cr-time-add { align-self: flex-start; margin-top: 6px; }

/* «жил · апарт 008 · 14–15 сен» — строка вместо карточки у бывшего гостя. */
.last-stay { padding: 4px 14px; font-size: 12px; color: var(--muted); background: var(--header);
             border-bottom: 1px solid var(--line); }

/* Гифка в ленте: крутится сама, без плеера; на паузе — значок GIF ярче. */
.gif-frame { display: block; position: relative; border-radius: 10px; overflow: hidden;
             background: var(--bg-chat); max-width: 100%; }
.gif-frame video { width: 100%; height: 100%; object-fit: cover; display: block; cursor: pointer; }
.gif-frame .gif-mark { position: absolute; left: 6px; top: 6px; font-size: 10px; font-weight: 700;
                       padding: 1px 5px; border-radius: 6px; background: rgba(0,0,0,.45); color: #fff;
                       opacity: .5; pointer-events: none; }
.gif-frame.paused .gif-mark { opacity: 1; }
.gif-frame.paused::after { content: '▶'; position: absolute; inset: 0; display: grid; place-items: center;
                           color: #fff; font-size: 28px; text-shadow: 0 1px 4px rgba(0,0,0,.6); pointer-events: none; }

/* «Ответить» над пузырём при наведении мышью — только там, где есть мышь. */
.msg .q-hover { display: none; }
@media (hover: hover) and (pointer: fine) {
  .msg .q-hover {
    display: block; position: absolute; top: -22px; right: 6px; z-index: 2;
    width: auto; height: auto; padding: 2px 9px; border-radius: 10px; font-size: 12px;
    background: var(--bg); color: var(--muted); border: 1px solid var(--line);
    box-shadow: 0 1px 3px rgba(0,0,0,.12); opacity: 0; pointer-events: none;
    transition: opacity .12s;
  }
  .msg.out .q-hover { right: auto; left: 6px; }
  .msg:hover .q-hover { opacity: 1; pointer-events: auto; }
  .msg .q-hover:hover { color: var(--accent); }
}

/* Двойное нажатие на пузырь — ❤️ как в Telegram: сердце всплывает над пузырём. */
.msg .dbl-heart {
  position: absolute; left: 50%; top: 40%; font-size: 34px; pointer-events: none;
  transform: translate(-50%, -50%) scale(.4); opacity: 0;
  animation: сердце .7s ease-out forwards;
}
@keyframes сердце {
  20% { opacity: 1; transform: translate(-50%, -60%) scale(1.15); }
  100% { opacity: 0; transform: translate(-50%, -140%) scale(1); }
}

/* Полоска чужого черновика нажимается: текст встаёт в поле ввода. */
.others-draft { cursor: pointer; }

/* Подсказка в окне корзины: кнопка-ссылка «сбросить автоподстановку». */
.cart-hint { margin: -4px 0 4px; font-size: 12px; }
button.linkish { background: transparent; color: var(--accent); border: 0; padding: 0; width: auto; height: auto;
                 font-size: inherit; text-decoration: underline; cursor: pointer; }

/* Выбор броней для файла из сообщения. */
.pick-bookings { list-style: none; margin: 0 0 8px; padding: 0; }
.pick-bookings li { padding: 6px 0; border-bottom: 1px solid var(--line); }
.pick-bookings label { display: flex; align-items: center; gap: 10px; font-size: 15px; cursor: pointer; }
.pick-bookings input { width: 20px; height: 20px; }
.sheet-item.all.on { background: var(--accent); color: #fff; border-color: var(--accent); }

/* Подставленное на фокусе время — серым: это подсказка, а не правка. */
#bk-box input.suggested { color: var(--muted); }
#cart-box { width: min(380px, calc(100vw - 32px)); gap: 8px; overflow-x: hidden; box-sizing: border-box; }
#cart-box .pay-row { gap: 2px; font-size: 12px; }
#cart-box .pass-dates .pay-row { min-width: 0; flex: 1 1 0; }
#cart-box .pass-dates input, #cart-box .pass-dates select { width: 100%; min-width: 0; box-sizing: border-box; -webkit-appearance: none; appearance: none; }
#cart-box input[type="date"] { display: block; padding: 8px; }
.cart-extra { display: flex; gap: 6px; }
.cart-extra input { flex: 1 1 0; min-width: 0; }
.cart-extra select { flex: 0 0 64px; }
.cart-head-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
#cart-box .pass-mini { padding: 4px 10px; font-size: 13px; border-radius: 10px; border: 1px solid var(--line); background: transparent; color: var(--accent); width: auto; }
/* flex: none обязательно. Коробка окна — flex-колонка с потолком по видимой
   области, и когда клавиатура подрезает подложку, ей надо ужаться; у обычных
   детей min-height: auto = высота содержимого, а у прокручиваемого списка —
   ноль, и всю нехватку забирал он один: строки с ценами сжимались в полоску,
   а коробке прокручивать было нечего — вписать цену с телефона нельзя
   (владелец, 15.09.2026). Не сжимается список — прокручивается коробка. */
.cart-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; max-height: 40vh; overflow-y: auto; flex: none; }
.cart-items li { display: flex; align-items: center; gap: 8px; padding: 6px 4px; border-bottom: 1px solid var(--line); font-size: 14px; }
.cart-items li.busy { opacity: .45; }
.cart-items input[type="checkbox"] { width: 18px; height: 18px; margin: 0; flex: none; }
.cart-items .ci-title { flex: 1 1 auto; min-width: 0; }
.cart-items .ci-price { font-variant-numeric: tabular-nums; color: var(--muted); font-size: 13px; white-space: nowrap; }
/* 16px обязательно: меньше — iPhone зумит страницу при фокусе (владелец, 15.09). */
.cart-items .ci-price input { width: 80px; font-size: 16px; text-align: right; padding: 3px 4px; }
#cart-box p.note { margin: 0; font-size: 12px; }
#cart-state:empty, #cart-count:empty { display: none; }
.bk-money { border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; display: flex; flex-direction: column; gap: 8px; }
.bk-money[hidden] { display: none; }
.bk-money-line { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 13px; color: var(--muted); }
.bk-money-line b { color: var(--text); font-weight: 600; }
.bk-money-line b.bad { color: #d33a2c; }
.bk-money-btns { display: flex; gap: 8px; }
#bk-box .bk-money-btns .pass-mini { flex: 1 1 0; padding: 6px 8px; font-size: 13px; border-radius: 10px;
  border: 1px solid var(--line); background: transparent; color: var(--accent); }
.bk-history { font-size: 13px; }
.bk-history[hidden] { display: none; }
.bk-history summary { cursor: pointer; color: var(--muted); }
.bk-history ul { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.bk-history li { border-left: 2px solid var(--line); padding-left: 8px; }
.bk-history .bk-h-who { color: var(--muted); font-size: 12px; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .bk-extra { background: #4a3f0a; color: #ffe9a0; }
  :root:not([data-theme="light"]) .bk-extra-note { color: #d9c46a; }
}
:root[data-theme="dark"] .bk-extra { background: #4a3f0a; color: #ffe9a0; }
:root[data-theme="dark"] .bk-extra-note { color: #d9c46a; }
.pass-auto { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); }
.pass-auto input { width: 16px; height: 16px; margin: 0; }
.pass-auto.off span { text-decoration: line-through; }
.pass-run { display: flex; gap: 8px; }
#pass-box .pass-mini { flex: 1 1 0; padding: 6px 8px; font-size: 13px; border-radius: 10px;
  border: 1px solid var(--line); background: transparent; color: var(--text); }
#pass-box .pass-mini.danger { color: #d33a2c; border-color: rgba(211,58,44,.4); }
#pass-box .pass-mini:disabled { opacity: .45; }
#pass-save:disabled { opacity: .45; cursor: not-allowed; }
button.pass-open { cursor: pointer; border: 0; font-family: inherit; line-height: inherit; }
.tg-login { text-decoration: underline; text-underline-offset: 2px; }
.sc-move { display: flex; flex-direction: column; gap: 2px; flex: none; }
.sc-move button {
  width: 28px; height: 22px; padding: 0; line-height: 1;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--bg); color: var(--muted); font-size: 13px; cursor: pointer;
}
.sc-move button:active { background: var(--line); }
.sc-body { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px;
           min-width: 0; flex: 1 1 auto; }
.sc-moved { background: rgba(51, 144, 236, .12); transition: background .4s; }

/* ---------- на компьютере — окном, а не во весь экран ----------

   Инбокс писался под телефон и на широком мониторе растягивался на всю
   ширину: строка чата в полтора метра, пузырь сообщения через весь экран,
   глаз не находит края. Поэтому на большом экране показываем ровно тот же
   интерфейс, но окном по центру — так же, как он выглядит в руке.

   Кадром служит сам body: на странице переписки он и без того колонка во всю
   высоту (.chatpage), а на списке чатов достаточно дать ему свою прокрутку —
   тогда липкая шапка липнет к верху окна, а не экрана.

   Порог 900px намеренно высокий: на планшете и узком ноутбуке окно в рамке
   только отняло бы место, там по-прежнему во всю ширину. */
@media (min-width: 900px) {
  :root {
    --окно: 480px;          /* ширина «телефона»: шире делать нельзя, вёрстка мобильная */
    --поле: 20px;           /* воздух вокруг окна */
    --вокруг: #d9dde1;      /* фон за окном */
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) { --вокруг: #0b1119; }
  }
  :root[data-theme="dark"] { --вокруг: #0b1119; }

  /* overflow: hidden на html обязателен: без него overflow-y: auto с body по
     правилам CSS переезжает на окно браузера — прокручивалась вся страница,
     содержимое настроек вылезало ниже коробки «телефона» без фона, а
     догрузка списка при поиске меряла не тот прокрутчик (15.09.2026). */
  html { background: var(--вокруг); overflow: hidden; height: 100%; }
  body {
    width: var(--окно); margin: var(--поле) auto;
    height: calc(100dvh - var(--поле) * 2);
    overflow-y: auto; overscroll-behavior: contain;
    border: 1px solid var(--line); border-radius: 14px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, .18);
  }
  /* Переписка сама держит высоту и прокручивает ленту внутри себя — своя
     прокрутка окну здесь только мешала бы, давая вторую полосу. */
  body.chatpage { height: calc(100dvh - var(--поле) * 2); overflow: hidden; }
  /* Вход занимал высоту ЭКРАНА и вылезал из окна на высоту полей. */
  .center { min-height: 100%; }

  /* Прибитое к экрану вписываем в окно вручную. Центруем полем, а не
     transform: сдвиг нужен шторке для выезда, и второй бы его перебил. */
  #side, #side-back, #scripts-pop, .modal-back {
    left: 50%; margin-left: calc(var(--окно) / -2);
  }
  #side {
    top: var(--поле); bottom: var(--поле);
    width: 300px; max-width: calc(var(--окно) - 60px);
    border-radius: 14px 0 0 14px;
  }
  #side-back, .modal-back {
    right: auto; width: var(--окно);
    top: var(--поле); bottom: var(--поле);
    border-radius: 14px;
  }
  #scripts-pop { right: auto; width: var(--окно); bottom: var(--поле); }

  /* Просмотр фото и обрезку НЕ сжимаем: картинку смотрят, а не читают, и
     большой экран здесь работает на нас. */

  /* Мерки в долях экрана считались от телефона. На мониторе 42vw — это
     восемьсот пикселей, втрое шире самого окна. */
  #account-filter { max-width: 190px; }
  #connect-qr { max-width: calc(var(--окно) - 80px); }

  /* Курсор мыши: на телефоне этого не видно, а мышью непонятно, что нажимается. */
  .chat, .side-item, .booking .b-head { cursor: pointer; }
}

/* Кнопки скрипта в карточке брони. Ряд отдельной строкой: рядом с телефоном
   и «внесено» они переносились по одной и рвали строку пополам. */
.b-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.b-act {
  border: 1px solid var(--line); background: var(--bg); color: var(--accent);
  border-radius: 14px; padding: 5px 12px; font: inherit; font-size: 13px;
  font-weight: 500; cursor: pointer; white-space: nowrap;
}
.b-act:active { background: var(--bg-chat); }
/* Недоступную кнопку не прячем: по ней видно, что код вообще бывает, и
   рядом написано, чего не хватает. */
.b-act[disabled] { color: var(--muted); cursor: default; opacity: .65; }
/* Код уже ушёл гостю (или передан лично — отметка): кнопка зелёная, в
   подсказке когда и кто (владелец, 23.09.2026). */
.b-act.key.sent { color: #2e9e4f; border-color: rgba(52, 199, 89, .45);
                  background: rgba(52, 199, 89, .12); }

/* ---------- две колонки на широком экране ----------

   От 1000px окно расширяется и делится надвое: слева список чатов, справа
   открытая переписка — как в почте. До этого порога остаётся одноколоночное
   окно 480px: на узком ноутбуке две колонки только сплющили бы обе.

   Переписка и список — по-прежнему две разные страницы, и переход по чату
   перезагружает окно целиком. Это видно глазом (список моргает), и это
   следующий шаг: подгружать правую колонку без перезагрузки. Разметка и
   стили при этом не изменятся — поменяется только способ подмены. */
.pane-list { display: block; }
.pane-chat { display: flex; flex-direction: column; flex: 1; min-height: 0; }
/* Заглушка правой колонки живёт только на широком экране. */
.pane-empty { display: none; }
/* Рамка с перепиской — только на широком экране: на телефоне переписка
   открывается обычным переходом, и рамка там лишний слой. */
.pane-frame { display: none; }
/* На телефоне страница переписки — это только переписка. */
@media (max-width: 999px) {
  .chatpage .pane-list { display: none; }
}

@media (min-width: 1000px) {
  /* Только страницы с колонками. Правило висело на голом `body`, и в ряд
     разъезжались ВСЕ страницы: в настройках заголовок уезжал в отдельный
     столбец, а карточки вставали двумя колонками рядом с ним. Переменную
     ширины тоже держим здесь, а не в :root, — иначе окно настроек
     растягивалось до 1100px без всякой на то причины. */
  body.panes { --окно: 1100px; --список: 360px; }

  /* Именно `body.chatpage`, а не просто `body`: у правила `.chatpage`
     специфичность выше, и одиночный `body` ему проигрывал — страница
     переписки оставалась колонкой, список ложился сверху, а переписка
     уезжала под него во всю ширину. */
  body.panes, body.chatpage.panes {
    width: var(--окно);
    display: flex; flex-direction: row; align-items: stretch;
    overflow: hidden;                /* прокручиваются колонки, а не окно */
  }

  .panes .pane-list {
    width: var(--список); flex: none;
    display: flex; flex-direction: column; min-height: 0;
    border-right: 1px solid var(--line);
  }
  /* Список внутри колонки прокручивается сам: иначе шапка с поиском уезжала
     бы вверх вместе с чатами. */
  .panes .pane-list #list-body { flex: 1; min-height: 0; overflow-y: auto; }
  .panes .pane-list header { position: static; }

  .panes .pane-chat { flex: 1; min-width: 0; }
  /* «Непрочитанные 24» в узкой колонке заплывало за многоточие (владелец, 15.09). */
  .panes .pane-list header h1 { font-size: 16px; }
  .panes .pane-list header #inbox-title.filtered { font-size: 15px; letter-spacing: -.2px; }
  .panes .pane-empty {
    display: flex; align-items: center; justify-content: center;
    color: var(--muted); background: var(--bg-chat);
  }
  .panes .pane-frame {
    display: block; flex: 1; min-width: 0; border: 0; background: var(--bg-chat);
  }
  /* Скрытая рамка не должна занимать место: без этого пустая правая колонка
     ужималась вдвое, а надпись «выберите переписку» уезжала влево. */
  .panes .pane-frame[hidden] { display: none; }

  /* Прибитое к экрану считаем от окна в 1100px, а не от прежних 480. */
  .panes #side, .panes #side-back, .panes .modal-back {
    margin-left: calc(var(--окно) / -2); }
  .panes #side-back, .panes .modal-back { width: var(--окно); }
  /* Список скриптов — над строкой ввода, то есть в правой колонке. */
  .panes #scripts-pop {
    margin-left: calc(var(--окно) / -2 + var(--список));
    width: calc(var(--окно) - var(--список));
  }
}

/* Закладки броней. Появляются только когда броней несколько, поэтому ряд
   ничего не занимает в обычном случае. Прокрутка вбок обязательна: при
   четырёх бронях ряд в ширину телефона уже не помещается, а переносить его
   на вторую строку — значит отдать под шапку пол-экрана. */
.b-tabs {
  display: flex; gap: 6px; padding: 6px 10px 0;
  overflow-x: auto; scrollbar-width: none; touch-action: pan-x;
}
.b-tabs::-webkit-scrollbar { display: none; }
.b-tab {
  flex: none; border: 1px solid var(--line); background: var(--bg);
  color: var(--muted); border-radius: 14px; padding: 4px 11px;
  font: inherit; font-size: 13px; white-space: nowrap; cursor: pointer;
}
.b-tab.on { color: var(--accent); border-color: var(--accent); font-weight: 600; }

/* На телефоне три условия заезда идут впритык к краю: «договор не подписан» —
   длинная плашка, и вместе с долгом и залогом ряд упирается в ширину экрана.
   Подрезаем отступы, чтобы влезало целиком, а не почти. */
@media (max-width: 480px) {
  .b-money .b-cell { padding-left: 7px; padding-right: 7px; }
  .b-money .b-pill { padding-left: 8px; padding-right: 8px; }
}

/* Строка под курсором слегка подсвечивается. На компьютере список всё время
   на виду, и без подсветки не видно, куда попадёшь нажатием, — особенно
   правой кнопкой, за которой прячутся закреп и «непрочитанное».

   Только там, где наведение настоящее: на телефоне :hover прилипает после
   касания, и строка оставалась бы подсвеченной до следующего нажатия. */
@media (hover: hover) and (pointer: fine) {
  .chat:hover { background: rgba(128, 128, 128, .07); }
  .chat.pinned:hover { background: rgba(128, 128, 128, .12); }
}

/* Открытая переписка в списке. Нужна только там, где колонки две: на
   телефоне список и переписка — разные экраны, и подсвечивать нечего. */
@media (min-width: 1000px) {
  .panes .chat.open { background: rgba(128, 128, 128, .12); }
  .panes .chat.open:hover { background: rgba(128, 128, 128, .14); }
}

/* Подпись у канала: что именно у него выключено. Без неё «почему с этого
   канала не пишется» выясняется методом тыка по меню. */
.accounts .ch-note {
  font-size: 11px; color: var(--muted); white-space: nowrap; margin-left: 6px;
}

/* Убранный канал. Он остаётся в списке — переписку по нему читают, и имя
   канала в ней должно быть откуда взять, — но это уже история, а не рабочий
   инструмент. Поэтому бледнее и без цветной точки состояния. */
.accounts li.retired { opacity: .5; }
.accounts li.retired .dot { display: none; }

/* След событий клавиатуры на «Оформлении» — мелко, но целиком, чтобы влез в скриншот. */
.screen-trace { font-size: 11px; line-height: 1.25; white-space: pre-wrap; color: var(--muted); margin: 6px 0 0; }

/* Админка причин «не забронировал»: список в стиле скриптов, архивные бледнее. */
.lr-archived { opacity: .55; }
/* Служебные сообщения CRM — админка правил. Карточки с ярлыками условий и
   переключателем; окно правки — секциями, условия — чипами. */
.cr-list { list-style: none; margin: 0; padding: 0; }
.cr-item { display: flex; align-items: flex-start; gap: 10px; padding: 12px 0;
  border-bottom: 1px solid var(--line); }
.cr-item.cr-off .cr-body { opacity: .45; }
.cr-body { flex: 1 1 auto; min-width: 0; }
.cr-head { display: flex; align-items: baseline; gap: 8px; }
.cr-name { font-size: 15px; font-weight: 600; cursor: pointer; }
.cr-when { font-size: 12px; color: var(--muted); white-space: nowrap; }
.cr-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; align-items: center; }
.cr-tag { font-size: 12px; padding: 2px 8px; border-radius: 10px; background: var(--chip, #eef1f5);
  color: var(--text, #222); }
.cr-tag.any { background: #e3efff; color: #123c73; }
.cr-tag.touch { background: #e6f6e8; color: #1e6b2e; }
.cr-tag.mute { background: transparent; color: var(--muted); border: 1px dashed var(--line); }
.cr-tag-sep { font-size: 12px; color: var(--muted); margin: 0 2px; }
.cr-text { font-size: 13px; color: var(--muted); margin-top: 5px; white-space: pre-line; }
.cr-switch { position: relative; flex-shrink: 0; width: 42px; height: 24px; margin-top: 2px; }
.cr-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.cr-knob { position: absolute; inset: 0; border-radius: 12px; background: #c9ced6; transition: background .15s; }
.cr-knob::after { content: ''; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px;
  border-radius: 50%; background: #fff; transition: transform .15s; box-shadow: 0 1px 2px rgba(0,0,0,.25); }
.cr-switch input:checked + .cr-knob { background: #34c759; }
.cr-switch input:checked + .cr-knob::after { transform: translateX(18px); }
/* Ширина — как у остальных окон (у .form-box своей нет: без неё коробка
   растягивалась по содержимому чипов шире экрана телефона). Высоту не
   переопределяем: .form-box уже ограничен видимой областью и прокручивается
   внутри; свой max-height: 92vh вылезал за низ экрана с учётом отступа
   сверху — окно казалось непрокручиваемым (владелец, 15.09 утром). */
.cr-form { width: min(440px, calc(100vw - 32px)); box-sizing: border-box; }
.cr-form .modal-title { flex: none; }
.cr-chips { min-width: 0; }
.cr-chip span { white-space: nowrap; }
.cr-section { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
.cr-section-title { font-size: 13px; font-weight: 600; margin-bottom: 6px; }
.cr-section-title small { font-weight: 400; color: var(--muted); margin-left: 4px; }
.cr-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.cr-chip { display: inline-flex; }
.cr-chip input { position: absolute; opacity: 0; width: 0; height: 0; }
.cr-chip span { font-size: 13px; padding: 5px 11px; border-radius: 14px; border: 1px solid var(--line);
  background: transparent; cursor: pointer; user-select: none; }
.cr-chip input:checked + span { background: #1a56c4; border-color: #1a56c4; color: #fff; }
.cr-chip.any input:checked + span { background: #e3efff; border-color: #1a56c4; color: #123c73; }
.cr-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 10px; }
.cr-check { flex-direction: row; align-items: center; gap: 6px; align-self: end; padding-bottom: 8px; }
#cr-f-text { font-size: 16px; width: 100%; box-sizing: border-box; }
.cr-hint { font-size: 12px; color: var(--muted); margin-top: 4px; line-height: 1.5; }
.cr-hint code { font-size: 11px; background: var(--chip, #eef1f5); padding: 1px 4px; border-radius: 4px; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .cr-tag { background: #2a2f38; color: #e6e8eb; }
  :root:not([data-theme="light"]) .cr-tag.any { background: #16304f; color: #cfe1ff; }
  :root:not([data-theme="light"]) .cr-tag.touch { background: #1f3a26; color: #93d69a; }
  :root:not([data-theme="light"]) .cr-chip.any input:checked + span { background: #16304f; color: #cfe1ff; }
  :root:not([data-theme="light"]) .cr-hint code { background: #2a2f38; }
}
:root[data-theme="dark"] .cr-tag { background: #2a2f38; color: #e6e8eb; }
:root[data-theme="dark"] .cr-tag.any { background: #16304f; color: #cfe1ff; }
:root[data-theme="dark"] .cr-tag.touch { background: #1f3a26; color: #93d69a; }
:root[data-theme="dark"] .cr-chip.any input:checked + span { background: #16304f; color: #cfe1ff; }
:root[data-theme="dark"] .cr-hint code { background: #2a2f38; }
.lr-flag { display: block; font-size: 12px; color: var(--muted); margin-top: 4px; }
.lr-flag input { vertical-align: -2px; margin-right: 4px; }
#lr-list .lr-drop { width: auto; height: auto; font-size: 12px; color: var(--muted); background: transparent; border: 1px solid var(--line); border-radius: 12px; padding: 4px 10px; flex: none; }
#lr-list li { display: flex; align-items: flex-start; gap: 8px; }
#lr-list .sc-body { flex: 1; min-width: 0; }
/* Число прямо в строке подсказки: «через [7] дней». */
.settings input.num-inline, .settings .note input.num-inline { width: 4.5em; display: inline-block; padding: 2px 6px; margin: 0 2px; font-size: 16px; vertical-align: baseline; }

/* Доска CRM: семь столбцов вбок. На телефоне — один столбец на экран, свайп с
   привязкой; на компьютере — все в ряд, каждый со своей прокруткой. Карточки —
   те же строки, что в списке чатов. */
body.boardpage { display: flex; flex-direction: column; height: 100dvh; margin: 0; }
/* Шапка под чёлкой айфона: общий `header` задаёт safe-area в padding-top, и
   сокращённый padding его стирал — шапка уезжала под часы. */
body.boardpage header {
  display: flex; align-items: center; gap: 10px; padding: 8px 12px; flex: none;
  padding-top: max(8px, env(safe-area-inset-top));
  border-bottom: 1px solid var(--line); background: var(--header);
  position: static;
}
body.boardpage header h1 { flex: 1; font-size: 18px; margin: 0; }
body.boardpage header .chip { width: auto; }
#board-tabs {
  display: flex; gap: 6px; padding: 6px 12px; overflow-x: auto; flex: none;
  scrollbar-width: none; border-bottom: 1px solid var(--line); background: var(--bg);
}
#board-tabs::-webkit-scrollbar { display: none; }
#board-tabs .tab {
  flex: none; width: auto; height: auto; padding: 4px 10px; border-radius: 14px;
  border: 1px solid var(--line); background: var(--bg-chat); color: var(--text); font-size: 13px;
}
#board-tabs .n, #board .col h3 .n { color: var(--muted); font-weight: 400; }
/* Доска и правая колонка с перепиской — рядом; на телефоне рамки нет. */
.board-body { flex: 1; min-height: 0; display: flex; }
#board {
  flex: 1; min-width: 0; min-height: 0; display: flex; gap: 10px; padding: 10px;
  padding-bottom: max(10px, env(safe-area-inset-bottom));
  overflow-x: auto; scroll-snap-type: x mandatory; background: var(--bg-chat);
}
#board-frame { display: none; }
@media (min-width: 1000px) {
  #board-frame:not([hidden]) {
    display: block; flex: 0 0 480px; border: 0; border-left: 1px solid var(--line);
    background: var(--bg-chat);
  }
}
#board .chat.open { background: var(--bg-chat); }
#board .col {
  flex: 0 0 88vw; scroll-snap-align: start; display: flex; flex-direction: column;
  background: var(--bg); border: 1px solid var(--line); border-radius: 12px; min-height: 0;
}
#board .col h3 { margin: 0; padding: 8px 12px; font-size: 14px; border-bottom: 1px solid var(--line); flex: none; }
#board .cards { overflow-y: auto; flex: 1; min-height: 0; }
#board .cards .chat { border-bottom: 1px solid var(--line); }
/* Карточки на доске компактнее строк списка: доска — обзор, в столбец
   должно влезать больше (просьба владельца 13.09). Аватарка 36px, шрифт
   на ступень мельче, отступы уже; галочка «ответ не требуется» тут не нужна. */
#board .cards .chat a { padding: 6px 10px; column-gap: 8px; }
#board .cards .av-wrap, #board .cards .avatar { width: 36px; height: 36px; font-size: 14px; }
#board .cards .chan { width: 15px; height: 15px; }
#board .cards .title { font-size: 14px; }
#board .cards .apt, #board .cards .account { font-size: 11px; }
#board .cards .preview { font-size: 13px; }
#board .cards .time { font-size: 11px; }
#board .cards .stage, #board .cards .lead { font-size: 10px; line-height: 15px; }
#board .cards .count { min-width: 18px; height: 18px; font-size: 11px; }
#board .cards .noreply { display: none; }
#board .cards .chat { content-visibility: auto; contain-intrinsic-size: 0 58px; }
#board .more {
  width: auto; height: auto; margin: 6px auto; padding: 4px 14px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--bg-chat); color: var(--text); font-size: 13px; flex: none;
}
#board .more[hidden] { display: none; }
@media (min-width: 1000px) {
  #board-tabs { display: none; }
  /* Столбцы делят ширину поровну и заполняют её до правого края; если семь
     не помещаются — вбок с видимой полосой прокрутки (на маке она иначе
     спрятана, и обрезанный столбец выглядел как поломка). */
  #board .col { flex: 1 1 300px; min-width: 300px; }
  #board { scrollbar-width: thin; scroll-snap-type: none; }
  #board::-webkit-scrollbar { height: 10px; }
  #board::-webkit-scrollbar-thumb { background: var(--line); border-radius: 5px; }
}
/* На компьютере доске нужна вся ширина: «окно телефона» 480px вмещало бы
   полтора столбца. Ширина — до 1400px, дальше столбцы просто стоят слева. */
@media (min-width: 900px) {
  body.boardpage {
    --окно: calc(100vw - var(--поле) * 2);
    width: var(--окно); height: calc(100dvh - var(--поле) * 2); overflow: hidden;
  }
}

/* ---------- экран «Заезды» ----------
   Спека 2026-09-23-checkins-board-design.md. Разметка одна: на телефоне день —
   отдельный блок в ленте (владелец: «как на компе выделено отдельное число»),
   на компьютере — колонка, как на доске; справа — та же рамка переписки. */
#ci-days {
  flex: 1; min-width: 0; min-height: 0; overflow-y: auto; padding: 10px;
  padding-bottom: max(10px, env(safe-area-inset-bottom)); background: var(--bg-chat);
}
.ci-day { background: var(--bg); border: 1px solid var(--line); border-radius: 12px;
          padding: 8px; margin-bottom: 10px; }
.ci-day.today { border: 2px solid var(--accent); }
.ci-day-head { display: flex; align-items: center; gap: 10px; width: 100%; height: auto;
               padding: 2px; background: none; border: 0; color: var(--text);
               font: inherit; text-align: left; cursor: pointer; }
.ci-date { flex: none; display: flex; flex-direction: column; align-items: center;
           justify-content: center; width: 42px; height: 42px; border-radius: 10px;
           background: var(--bg-chat); line-height: 1.1; }
.ci-date b { font-size: 17px; font-weight: 600; }
.ci-date span { font-size: 11px; color: var(--muted); }
.ci-day.today .ci-date { background: var(--accent); color: #fff; }
.ci-day.today .ci-date span { color: rgba(255, 255, 255, .85); }
.ci-sum { font-size: 13px; color: var(--muted); }
.ci-sum b { color: var(--text); font-weight: 600; }
.ci-sum .bad, .ci-out .bad { color: #d33a2c; }
.ci-day.folded .ci-card, .ci-day.folded .ci-out { display: none; }
.ci-card { border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px;
           margin-top: 8px; background: var(--bg); }
.ci-card.open { border-color: var(--accent); }
.ci-main { display: block; color: var(--text); text-decoration: none; font-size: 14px; }
.ci-req { font-size: 11px; color: #c1741a; margin-left: 6px; }
/* «Чат не найден» — красным: гостю некуда написать из инбокса (владелец,
   23.09.2026); рядом «Написать» на страницу «написать первым». */
.ci-nochat { font-size: 12px; color: #d33a2c; margin-top: 4px; }
.ci-nochat a { margin-left: 10px; color: var(--accent); font-weight: 600; text-decoration: none; }
.ci-marks { display: flex; gap: 6px; margin-top: 6px; }
.ci-mark { width: 30px; height: 28px; border-radius: 8px; border: 1px solid transparent;
           padding: 0; display: inline-flex; align-items: center; justify-content: center;
           cursor: pointer; }
.ci-mark svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.7;
               stroke-linecap: round; stroke-linejoin: round; }
.ci-mark.ok { background: rgba(52, 199, 89, .16); color: #2e9e4f; }
.ci-mark.bad { background: rgba(255, 59, 48, .13); color: #d33a2c; }
.ci-mark.warn { background: rgba(255, 159, 10, .17); color: #c1741a; }
.ci-mark.na { background: var(--bg-chat); color: var(--muted); }
.ci-mark.manual { border-color: currentColor; }
.ci-out { font-size: 12px; color: var(--muted); margin: 8px 2px 0; }
#ci-days.only-bad .ci-card.ready { display: none; }
/* Столбец «Заезд» доски: под строкой чата — те же метки, что на экране
   «Заезды», чуть мельче (владелец, 23.09.2026). Строка чата — flex-ряд, и без
   переноса ряд меток вставал в неё соседом и налезал на имя и время (ноутбук
   владельца): переносим его на свою строку во всю ширину. */
#board .cards .chat { flex-wrap: wrap; }
#board .cards .chat .ci-marks { flex: 0 0 100%; box-sizing: border-box;
                                margin: 0; padding: 0 10px 8px 54px; gap: 5px; }
#board .cards .chat .ci-mark { width: 26px; height: 24px; }
#board .cards .chat .ci-mark svg { width: 15px; height: 15px; }
#board .col[data-col="checkin"] .cards .chat { contain-intrinsic-size: 0 88px; }
#ci-only.on { background: var(--accent); color: #fff; border-color: var(--accent); }
@media (min-width: 1000px) {
  #ci-days { display: flex; gap: 10px; overflow-x: auto; overflow-y: hidden;
             align-items: flex-start; scrollbar-width: thin; }
  .ci-day { flex: 0 0 240px; margin-bottom: 0; max-height: 100%; overflow-y: auto; }
  /* Колонки не сворачиваем: свёрнутая колонка — пустой столбик. */
  .ci-day.folded .ci-card, .ci-day.folded .ci-out { display: block; }
  .ci-tail { display: none; }
}

/* Личные размеры оператора — шкала 1–10 (localStorage → --list-size-k и
   --msg-size-k на <html>, 5 = как было). Строки списка растут коэффициентом
   от базовых величин: все размеры строки считаются от него, поэтому строка
   на любой ступени пропорциональна. Доску это не трогает — --k задан только
   списку и образцу в настройках. */
#chats, .list-sample { --k: var(--list-size-k, 1); }
#chats .chat a, .list-sample .chat a {
  grid-template-columns: calc(48px * var(--k)) 1fr;
  column-gap: calc(12px * var(--k)); padding: calc(9px * var(--k)) calc(14px * var(--k));
}
#chats .av-wrap, #chats .avatar, .list-sample .av-wrap, .list-sample .avatar {
  width: calc(48px * var(--k)); height: calc(48px * var(--k)); font-size: calc(17px * var(--k));
}
#chats .chan, .list-sample .chan { width: calc(20px * var(--k)); height: calc(20px * var(--k)); }
#chats .title, .list-sample .title { font-size: calc(16px * var(--k)); }
#chats .apt, .list-sample .apt { font-size: calc(13px * var(--k)); }
#chats .account, .list-sample .account { font-size: calc(12px * var(--k)); }
#chats .preview, .list-sample .preview { font-size: calc(15px * var(--k)); }
#chats .time, .list-sample .time { font-size: calc(12px * var(--k)); }
#chats .stage, .list-sample .stage { font-size: calc(12px * var(--k)); line-height: calc(18px * var(--k)); }
#chats .lead, .list-sample .lead { font-size: calc(11px * var(--k)); line-height: calc(16px * var(--k)); }
#chats .count, .list-sample .count {
  min-width: calc(22px * var(--k)); height: calc(22px * var(--k)); font-size: calc(13px * var(--k));
}
#chats .noreply { width: calc(36px * var(--k)); height: calc(36px * var(--k)); font-size: calc(17px * var(--k)); }
#chats .chat { contain-intrinsic-size: 0 calc(76px * var(--k)); }

/* Пузыри переписки: только текст сообщений, поле ввода и шапка прежние. */
.msg { font-size: calc(16px * var(--msg-size-k, 1)); }
.msg .meta { font-size: calc(11px * var(--msg-size-k, 1)); }

/* Образцы на странице оформления: строка списка и пузырь, живут по тем же
   переменным — ползунок двигаешь, образец меняется. */
.list-sample { list-style: none; margin: 8px 0 0; padding: 0; border: 1px solid var(--line);
               border-radius: 12px; overflow: hidden; }
.list-sample .chat { content-visibility: visible; contain-intrinsic-size: auto; }
.msg-sample { margin-top: 8px; padding: 10px; border-radius: 12px; background: var(--bg-chat); }
.msg-sample .msg { max-width: 100%; }
.size-slider { display: flex; align-items: center; gap: 12px; margin-top: 6px; }
.size-slider input[type="range"] { flex: 1; min-width: 0; }
.size-slider output { min-width: 2.4em; text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }

/* ======================================================================
   Дизайн v2 (15.09.2026). Каждая часть — своим классом на <html>
   (d-bubbles, d-bg, d-card, d-list, d-anim, d-icons), классы ставит
   _head.html из настроек; выключается в «Оформлении» без выкладки.
   Полный откат — тег до-дизайна-15.09.
   ====================================================================== */

/* --- 1. Пузыри как в Telegram iOS: скругление, хвостик у последнего в
   серии, время в углу; у фото — время на плашке поверх картинки. --- */
.d-bubbles .msg {
  border-radius: 17px; padding: 6px 12px 6px 12px;
  box-shadow: 0 1px .5px rgba(0, 0, 0, .13); isolation: isolate;
}
/* Угол со стороны хвостика — прямой: хвостик растёт из самого края пузыря.
   Со скруглённым углом он торчал из-под дуги отдельным «флажком» со щелью
   (владелец, 08.10). Где хвостика нет — угол снова круглый. */
.d-bubbles .msg.in { border-bottom-left-radius: 0; }
.d-bubbles .msg.out { border-bottom-right-radius: 0; }
.d-bubbles .msg.out.failed { border-bottom-right-radius: 17px; }
.d-bubbles .msg.bare { box-shadow: none; }
/* Хвостик: псевдоэлемент цвета пузыря, вырезанный clip-path (без «заплатки»
   цветом фона — на узоре она была бы видна). Только у последнего пузыря
   серии: если следом свой же — хвоста нет. Форма как у Telegram: край
   вогнутый, уходит в острие у самого низа, кончик скруглён, низ — одна
   линия с низом пузыря. 2px заходят внутрь пузыря — без светлого шва. */
.d-bubbles .msg.in::before, .d-bubbles .msg.out::before,
.d-bubbles .msg.in::after, .d-bubbles .msg.out::after {
  content: ""; position: absolute; bottom: 0; width: 10px; height: 17px;
}
.d-bubbles .msg.in::before { z-index: -1; background: var(--bubble-in); }
.d-bubbles .msg.out::before { z-index: -1; background: var(--bubble-out); }
/* Тень хвостика — та же форма на пиксель ниже, под заливкой: box-shadow
   пузыря хвостик не обводит, и тень обрывалась бы у края. */
.d-bubbles .msg.in::after, .d-bubbles .msg.out::after {
  z-index: -2; bottom: -1px; background: rgba(0, 0, 0, .07);
}
.d-bubbles .msg.in::before, .d-bubbles .msg.in::after {
  left: -8px;
  clip-path: path("M10 0 H8 C 7.81 2.84, 7.12 5.77, 5.95 8.78 C 5.05 11.11, 3.5 13.27, 1.33 15.26 A 1 1 0 0 0 2 17 H10 Z");
}
.d-bubbles .msg.out::before, .d-bubbles .msg.out::after {
  right: -8px;
  clip-path: path("M0 0 H2 C 2.19 2.84, 2.88 5.77, 4.05 8.78 C 4.95 11.11, 6.5 13.27, 8.67 15.26 A 1 1 0 0 1 8 17 H0 Z");
}
.d-bubbles .msg.in:has(+ .msg.in)::before, .d-bubbles .msg.out:has(+ .msg.out)::before,
.d-bubbles .msg.in:has(+ .msg.in)::after, .d-bubbles .msg.out:has(+ .msg.out)::after,
.d-bubbles .msg.system::before, .d-bubbles .msg.out.failed::before,
.d-bubbles .msg.system::after, .d-bubbles .msg.out.failed::after,
.d-bubbles .msg.bare::before, .d-bubbles .msg.bare::after { display: none; }
.d-bubbles .msg.in:has(+ .msg.in) { border-bottom-left-radius: 6px; }
.d-bubbles .msg.out:has(+ .msg.out) { border-bottom-right-radius: 6px; }
.d-bubbles .msg .meta { margin: 6px 0 -1px 10px; font-size: 11px; }
/* Фото/гифка без подписи — время на тёмной плашке в углу картинки. */
.d-bubbles .msg:has(> img.media, > .gif-frame, > .video-frame):not(:has(.text)) {
  padding: 3px; background: transparent; box-shadow: none;
}
.d-bubbles .msg:has(> img.media, > .gif-frame, > .video-frame):not(:has(.text))::before,
.d-bubbles .msg:has(> img.media, > .gif-frame, > .video-frame):not(:has(.text))::after { display: none; }
.d-bubbles .msg:has(> img.media, > .gif-frame, > .video-frame):not(:has(.text)) img.media,
.d-bubbles .msg:has(> img.media, > .gif-frame, > .video-frame):not(:has(.text)) .gif-frame,
.d-bubbles .msg:has(> img.media, > .gif-frame, > .video-frame):not(:has(.text)) .video-frame { margin: 0; border-radius: 14px; }
.d-bubbles .msg:has(> img.media, > .gif-frame, > .video-frame):not(:has(.text)) .meta {
  position: absolute; right: 9px; bottom: 9px; margin: 0; padding: 2px 7px; border-radius: 10px;
  background: rgba(0, 0, 0, .45); color: #fff; z-index: 1;
}
.d-bubbles .msg:has(> img.media, > .gif-frame, > .video-frame):not(:has(.text)) .meta .ticks { color: #fff; }
.d-bubbles .msg:has(> img.media, > .gif-frame, > .video-frame):not(:has(.text)) .meta .ticks.read { color: #9fe4ad; }
.d-bubbles .msg .quote { border-radius: 8px; }
.d-bubbles .msg.system { border-radius: 12px; box-shadow: none; }

/* --- 2. Фон переписки: мятно-голубой градиент и узор «отдыха» — ключи,
   домики, чемоданы, кофе, башни (08.10.2026; до того — сетка точек на сером).
   Рисуется CSS, картинок не тянем. Узор стоит на месте, сообщения едут поверх —
   как обои в Telegram. У тёмной темы штрихи светлые и бледнее: тёмный узор на
   тёмном не виден, а светлый на светлом лезет в глаза. Цвет, «Сити» и «без
   узора» из «Оформления» меняют только переменные — ниже, у выбора фона. --- */
:root {
  --feed-doodles: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180' fill='none' stroke='rgba(30,70,70,.13)' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E %3Cg transform='rotate(-20 28 22)'%3E%3Ccircle cx='18' cy='22' r='6'/%3E%3Cpath d='M24 22h17M35 22v5M40 22v4'/%3E%3C/g%3E %3Cg transform='rotate(8 84 34)'%3E%3Cpath d='M72 36l12-11 12 11v13H72z'/%3E%3Cpath d='M81 49v-7h6v7'/%3E%3C/g%3E %3Cpath d='M150 14a12 12 0 1 0 13 17a9 9 0 0 1-13-17z'/%3E %3Cg transform='rotate(-10 30 95)'%3E%3Crect x='17' y='88' width='26' height='18' rx='3'/%3E%3Cpath d='M24 88v-4h12v4M17 96h26'/%3E%3C/g%3E %3Cpath d='M98 78l2 4.2 4.6.7-3.3 3.2.8 4.6-4.1-2.2-4.1 2.2.8-4.6-3.3-3.2 4.6-.7z'/%3E %3Cg transform='rotate(12 146 96)'%3E%3Cpath d='M135 90h20v9a8 8 0 0 1-8 8h-4a8 8 0 0 1-8-8z'/%3E%3Cpath d='M155 93h3a3.5 3.5 0 0 1 0 7h-3M141 85c-2-3 2-4 0-7M148 85c-2-3 2-4 0-7'/%3E%3C/g%3E %3Cpath d='M64 152l-9-8.5a5.2 5.2 0 0 1 9-5.3a5.2 5.2 0 0 1 9 5.3z'/%3E %3Cg transform='rotate(-6 118 148)'%3E%3Cpath d='M110 168v-32l8-9 8 9v32M114 144h8M114 152h8M114 160h8'/%3E%3C/g%3E %3Cpath d='M150 152h19a6 6 0 0 0-1.5-11.8a8.5 8.5 0 0 0-16.3-2a6.6 6.6 0 0 0-1.2 13.8z'/%3E %3Ccircle cx='56' cy='64' r='1.6'/%3E%3Ccircle cx='170' cy='60' r='1.6'/%3E%3Ccircle cx='12' cy='150' r='1.6'/%3E%3Ccircle cx='112' cy='12' r='1.6'/%3E%3Ccircle cx='86' cy='118' r='1.6'/%3E %3C/svg%3E");
  --feed-grad: linear-gradient(160deg, #dbeccd 0%, #c6e2dc 45%, #bcd3ea 100%);
  --feed-end: #bcd3ea;
  --doodle-size: 180px 180px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --feed-doodles: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180' fill='none' stroke='rgba(255,255,255,.055)' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E %3Cg transform='rotate(-20 28 22)'%3E%3Ccircle cx='18' cy='22' r='6'/%3E%3Cpath d='M24 22h17M35 22v5M40 22v4'/%3E%3C/g%3E %3Cg transform='rotate(8 84 34)'%3E%3Cpath d='M72 36l12-11 12 11v13H72z'/%3E%3Cpath d='M81 49v-7h6v7'/%3E%3C/g%3E %3Cpath d='M150 14a12 12 0 1 0 13 17a9 9 0 0 1-13-17z'/%3E %3Cg transform='rotate(-10 30 95)'%3E%3Crect x='17' y='88' width='26' height='18' rx='3'/%3E%3Cpath d='M24 88v-4h12v4M17 96h26'/%3E%3C/g%3E %3Cpath d='M98 78l2 4.2 4.6.7-3.3 3.2.8 4.6-4.1-2.2-4.1 2.2.8-4.6-3.3-3.2 4.6-.7z'/%3E %3Cg transform='rotate(12 146 96)'%3E%3Cpath d='M135 90h20v9a8 8 0 0 1-8 8h-4a8 8 0 0 1-8-8z'/%3E%3Cpath d='M155 93h3a3.5 3.5 0 0 1 0 7h-3M141 85c-2-3 2-4 0-7M148 85c-2-3 2-4 0-7'/%3E%3C/g%3E %3Cpath d='M64 152l-9-8.5a5.2 5.2 0 0 1 9-5.3a5.2 5.2 0 0 1 9 5.3z'/%3E %3Cg transform='rotate(-6 118 148)'%3E%3Cpath d='M110 168v-32l8-9 8 9v32M114 144h8M114 152h8M114 160h8'/%3E%3C/g%3E %3Cpath d='M150 152h19a6 6 0 0 0-1.5-11.8a8.5 8.5 0 0 0-16.3-2a6.6 6.6 0 0 0-1.2 13.8z'/%3E %3Ccircle cx='56' cy='64' r='1.6'/%3E%3Ccircle cx='170' cy='60' r='1.6'/%3E%3Ccircle cx='12' cy='150' r='1.6'/%3E%3Ccircle cx='112' cy='12' r='1.6'/%3E%3Ccircle cx='86' cy='118' r='1.6'/%3E %3C/svg%3E");
    --feed-grad: linear-gradient(160deg, #10202a 0%, #132836 50%, #1a2340 100%);
    --feed-end: #1a2340;
  }
}
:root[data-theme="dark"] {
  --feed-doodles: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180' fill='none' stroke='rgba(255,255,255,.055)' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E %3Cg transform='rotate(-20 28 22)'%3E%3Ccircle cx='18' cy='22' r='6'/%3E%3Cpath d='M24 22h17M35 22v5M40 22v4'/%3E%3C/g%3E %3Cg transform='rotate(8 84 34)'%3E%3Cpath d='M72 36l12-11 12 11v13H72z'/%3E%3Cpath d='M81 49v-7h6v7'/%3E%3C/g%3E %3Cpath d='M150 14a12 12 0 1 0 13 17a9 9 0 0 1-13-17z'/%3E %3Cg transform='rotate(-10 30 95)'%3E%3Crect x='17' y='88' width='26' height='18' rx='3'/%3E%3Cpath d='M24 88v-4h12v4M17 96h26'/%3E%3C/g%3E %3Cpath d='M98 78l2 4.2 4.6.7-3.3 3.2.8 4.6-4.1-2.2-4.1 2.2.8-4.6-3.3-3.2 4.6-.7z'/%3E %3Cg transform='rotate(12 146 96)'%3E%3Cpath d='M135 90h20v9a8 8 0 0 1-8 8h-4a8 8 0 0 1-8-8z'/%3E%3Cpath d='M155 93h3a3.5 3.5 0 0 1 0 7h-3M141 85c-2-3 2-4 0-7M148 85c-2-3 2-4 0-7'/%3E%3C/g%3E %3Cpath d='M64 152l-9-8.5a5.2 5.2 0 0 1 9-5.3a5.2 5.2 0 0 1 9 5.3z'/%3E %3Cg transform='rotate(-6 118 148)'%3E%3Cpath d='M110 168v-32l8-9 8 9v32M114 144h8M114 152h8M114 160h8'/%3E%3C/g%3E %3Cpath d='M150 152h19a6 6 0 0 0-1.5-11.8a8.5 8.5 0 0 0-16.3-2a6.6 6.6 0 0 0-1.2 13.8z'/%3E %3Ccircle cx='56' cy='64' r='1.6'/%3E%3Ccircle cx='170' cy='60' r='1.6'/%3E%3Ccircle cx='12' cy='150' r='1.6'/%3E%3Ccircle cx='112' cy='12' r='1.6'/%3E%3Ccircle cx='86' cy='118' r='1.6'/%3E %3C/svg%3E");
  --feed-grad: linear-gradient(160deg, #10202a 0%, #132836 50%, #1a2340 100%);
  --feed-end: #1a2340;
}
.d-bg #feed, .d-bg .bg-sample {
  background-color: var(--bg-chat);
  background-image: var(--feed-doodles), var(--feed-grad);
  background-size: var(--doodle-size), 100% 100%;
}
.d-bg .day-sep, .d-bg .msg.system { backdrop-filter: blur(2px); }

/* --- 3. Карточка брони: полоска статуса слева вместо точки, плашки одной
   высоты. --- */
.d-card .booking { border-left: 4px solid #34c759; }
.d-card .booking:has(.b-dot.wait) { border-left-color: #ff9f0a; }
.d-card .booking:has(.b-dot.bad) { border-left-color: #ff3b30; }
.d-card .booking.off { border-left-color: #b5bcc4; }
.d-card .b-dot { display: none; }
.d-card .b-head { padding-left: 8px; }
.d-card .b-pill { display: inline-flex; align-items: center; line-height: 18px; height: 22px; }

/* --- 5. Список чатов: точка непрочитанного у имени, превью в две строки,
   стадия и лид — чипы одной высоты. --- */
/* Точку непрочитанного у имени владелец убрал (15.09 вечер): счётчик
   справа и так говорит всё. Остаётся вес заголовка. */
.d-list .chat.unread .title { font-weight: 600; }
.d-list .chat .preview {
  white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  line-height: 1.25; overflow: hidden; text-overflow: ellipsis;
}
.d-list .chat .row2 { align-items: flex-start; }
.d-list .chat .count, .d-list .chat .noreply { align-self: center; }
.d-list #chats .chat { contain-intrinsic-size: 0 calc(84px * var(--k)); }
.d-list .stage, .d-list .chat .lead { border-radius: 8px; line-height: 18px; height: 18px; display: inline-flex; align-items: center; }

/* --- 6. Анимации: новый пузырь всплывает, окна и листы выезжают. Кто
   отключил анимации в системе — без них. --- */
@media (prefers-reduced-motion: no-preference) {
  .d-anim .msg.pop { animation: пузырь-появление .18s ease-out; }
  @keyframes пузырь-появление { from { opacity: 0; transform: translateY(8px) scale(.98); } }
  .d-anim .modal-back:not([hidden]) .modal,
  .d-anim .modal-back:not([hidden]) .form-box { animation: окно-выезд .2s cubic-bezier(.2, .8, .3, 1); }
  @keyframes окно-выезд { from { opacity: 0; transform: translateY(14px); } }
  .d-anim .modal-back:not([hidden]) { animation: подложка .18s ease-out; }
  @keyframes подложка { from { opacity: 0; } }
  .d-anim #gif-pop:not([hidden]), .d-anim #scripts-pop:not([hidden]) { animation: панель-снизу .2s cubic-bezier(.2, .8, .3, 1); }
  @keyframes панель-снизу { from { transform: translateY(24px); opacity: .6; } }
  .d-anim .booking .b-more { animation: пузырь-появление .16s ease-out; }
  .d-anim .b-pill, .d-anim .chat a, .d-anim .sheet-item { transition: background .12s, transform .12s; }
  .d-anim .sheet-item:active { transform: scale(.985); }
}

/* --- 7. Линейные значки вместо эмодзи (ставит JS по d-icons): общий вид. --- */
.d-icons .ic {
  width: 18px; height: 18px; vertical-align: -4px; margin-right: 8px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}
.d-icons .sheet-item { display: flex; align-items: center; }
.d-icons .sheet-item.cancel { justify-content: center; }
.d-icons #remind svg, .d-icons #mic svg { width: 22px; height: 22px; display: block; }
.d-icons #remind, .d-icons #mic { display: grid; place-items: center; }
.d-icons #plus { font-size: 0; }
.d-icons #plus svg { width: 24px; height: 24px; }
/* Значки в кругах строки ввода — ровно по центру (08.10.2026): общий отступ
   .ic справа нужен пунктам меню, а здесь сдвигал значок влево на 4px; «+»
   к тому же стоял строкой текста и уезжал вниз. */
.d-icons #composer #plus { display: grid; place-items: center; }
.d-icons #composer #plus .ic, .d-icons #composer #mic .ic { margin: 0; display: block; }

/* --- 7б. Видимость чатов (20.09.2026): замок «видят не все», лист «Кто
   видит», зажатие строки без системной плашки ссылки iOS. --- */
/* Только сенсорные экраны: правило гасит системную плашку ссылки при
   зажатии на телефоне, а на компьютере той же ценой убивало выделение
   текста имени мышью — там зажатия строки нет вовсе, а выделение нужно. */
@media (hover: none) and (pointer: coarse) {
  .chat a { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
}
.chat .lock-mark { font-size: 11px; flex-shrink: 0; opacity: .7; }
.d-icons .chat .lock-mark .ic { width: 12px; height: 12px; margin-right: 0; vertical-align: -2px; }
.sheet .access-row { display: flex; align-items: center; gap: 10px; cursor: pointer; box-sizing: border-box; }
.sheet .access-row input { width: 18px; height: 18px; margin: 0; flex: none; }
.sheet .access-row.locked { opacity: .6; }

/* --- 8. Тёмная тема: жёстко заданные цвета новых окон. --- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .bk-react.on { border-color: #6ea8ff; background: #1e3a5f; }
  :root:not([data-theme="light"]) .bk-extra { background: #3d3512; color: #f3e7a6; }
  :root:not([data-theme="light"]) .bk-extra-note { color: #d9c86a; }
  :root:not([data-theme="light"]) .cr-tag.any { background: #1e3a5f; color: #cfe2ff; }
  :root:not([data-theme="light"]) .cr-tag.touch { background: #1f3d25; color: #b8ecc2; }
  :root:not([data-theme="light"]) .cr-chip.any input:checked + span { background: #1e3a5f; color: #cfe2ff; }
  :root:not([data-theme="light"]) .cr-knob { background: #3a4550; }
  :root:not([data-theme="light"]) #gif-grid .gif .fav-tag { background: rgba(0, 0, 0, .7); color: #fff; }
  :root:not([data-theme="light"]) .gif-tab.on { box-shadow: none; }
  :root:not([data-theme="light"]) .others-draft { background: rgba(255, 255, 255, .06); }
}
:root[data-theme="dark"] .bk-react.on { border-color: #6ea8ff; background: #1e3a5f; }
:root[data-theme="dark"] .bk-extra { background: #3d3512; color: #f3e7a6; }
:root[data-theme="dark"] .bk-extra-note { color: #d9c86a; }
:root[data-theme="dark"] .cr-tag.any { background: #1e3a5f; color: #cfe2ff; }
:root[data-theme="dark"] .cr-tag.touch { background: #1f3d25; color: #b8ecc2; }
:root[data-theme="dark"] .cr-chip.any input:checked + span { background: #1e3a5f; color: #cfe2ff; }
:root[data-theme="dark"] .cr-knob { background: #3a4550; }
:root[data-theme="dark"] #gif-grid .gif .fav-tag { background: rgba(0, 0, 0, .7); color: #fff; }
:root[data-theme="dark"] .gif-tab.on { box-shadow: none; }
:root[data-theme="dark"] .others-draft { background: rgba(255, 255, 255, .06); }

/* ---------- цвет фона переписки (личный, data-feed-bg на <html>) ----------
   Переопределяем --bg-chat: от него считаются и лента, и узор дизайна v2, и
   хвостики. Тёмной теме — свои оттенки тех же цветов. */
:root[data-feed-bg="blue"] { --bg-chat: #d6e4f0; }
:root[data-feed-bg="green"] { --bg-chat: #d7e6d1; }
:root[data-feed-bg="sand"] { --bg-chat: #efe6d6; }
:root[data-feed-bg="lilac"] { --bg-chat: #e3dcef; }
:root[data-feed-bg="warm"] { --bg-chat: #e9e5e0; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"])[data-feed-bg="blue"] { --bg-chat: #0f1c2b; }
  :root:not([data-theme="light"])[data-feed-bg="green"] { --bg-chat: #0f1d16; }
  :root:not([data-theme="light"])[data-feed-bg="sand"] { --bg-chat: #221c14; }
  :root:not([data-theme="light"])[data-feed-bg="lilac"] { --bg-chat: #1a1526; }
  :root:not([data-theme="light"])[data-feed-bg="warm"] { --bg-chat: #1c1a18; }
}
:root[data-theme="dark"][data-feed-bg="blue"] { --bg-chat: #0f1c2b; }
:root[data-theme="dark"][data-feed-bg="green"] { --bg-chat: #0f1d16; }
:root[data-theme="dark"][data-feed-bg="sand"] { --bg-chat: #221c14; }
:root[data-theme="dark"][data-feed-bg="lilac"] { --bg-chat: #1a1526; }
:root[data-theme="dark"][data-feed-bg="warm"] { --bg-chat: #1c1a18; }
/* Узор дизайна v2 — на градиенте от выбранного цвета, а не от зашитого. */
:root:is([data-feed-bg="blue"], [data-feed-bg="green"], [data-feed-bg="sand"], [data-feed-bg="lilac"], [data-feed-bg="warm"]) {
  --feed-grad: linear-gradient(160deg, color-mix(in srgb, var(--bg-chat) 94%, white) 0%, color-mix(in srgb, var(--bg-chat) 94%, black) 100%);
  --feed-end: color-mix(in srgb, var(--bg-chat) 94%, black);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):is([data-feed-bg="blue"], [data-feed-bg="green"], [data-feed-bg="sand"], [data-feed-bg="lilac"], [data-feed-bg="warm"]) {
    --feed-grad: linear-gradient(160deg, color-mix(in srgb, var(--bg-chat) 92%, white) 0%, color-mix(in srgb, var(--bg-chat) 90%, black) 100%);
    --feed-end: color-mix(in srgb, var(--bg-chat) 90%, black);
  }
}
:root[data-theme="dark"]:is([data-feed-bg="blue"], [data-feed-bg="green"], [data-feed-bg="sand"], [data-feed-bg="lilac"], [data-feed-bg="warm"]) {
  --feed-grad: linear-gradient(160deg, color-mix(in srgb, var(--bg-chat) 92%, white) 0%, color-mix(in srgb, var(--bg-chat) 90%, black) 100%);
  --feed-end: color-mix(in srgb, var(--bg-chat) 90%, black);
}
/* «Нейтральный» — как было до 08.10.2026: серый градиент и мелкая сетка точек
   (дизайн v2 от 15.09). Просьба владельца — оставить и такой. */
:root[data-feed-bg="neutral"] {
  --feed-doodles: radial-gradient(rgba(0, 0, 0, .045) 1.2px, transparent 1.3px);
  --feed-grad: linear-gradient(160deg, #e3eaf0 0%, #d9e3ea 100%);
  --feed-end: #d9e3ea;
  --doodle-size: 18px 18px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"])[data-feed-bg="neutral"] {
    --feed-doodles: radial-gradient(rgba(255, 255, 255, .05) 1.2px, transparent 1.3px);
    --feed-grad: linear-gradient(160deg, #101a26 0%, #0b131c 100%);
    --feed-end: #0b131c;
  }
}
:root[data-theme="dark"][data-feed-bg="neutral"] {
  --feed-doodles: radial-gradient(rgba(255, 255, 255, .05) 1.2px, transparent 1.3px);
  --feed-grad: linear-gradient(160deg, #101a26 0%, #0b131c 100%);
  --feed-end: #0b131c;
}
/* «Без узора» — тот же градиент, без рисунка: кому узор мешает читать. */
:root[data-feed-bg="plain"] { --feed-doodles: none; }
/* «Сити» — тёплый рассвет и силуэт башен внизу ленты. Ширина силуэта не
   больше 560px: на широком экране он иначе вырастал бы во всю высоту. */
:root[data-feed-bg="city"] {
  --bg-chat: #dce6ee;
  --feed-grad: linear-gradient(180deg, #f3e9dc 0%, #dce6ee 55%, #c9d8e8 100%);
  --feed-end: #c9d8e8;
  --feed-skyline: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 140' fill='rgba(60,90,120,.13)'%3E %3Crect x='6' y='84' width='26' height='56'/%3E%3Crect x='35' y='62' width='20' height='78'/%3E %3Cpath d='M60 140V42l10-14 10 14v98z'/%3E%3Cpath d='M84 140V22l12-20 12 20v118z'/%3E%3Cpath d='M112 140V50l8-8 8 8v90z'/%3E %3Cpath d='M134 140c-4-40 10-70 4-110h22c-6 40 8 70 4 110z'/%3E%3Crect x='172' y='56' width='22' height='84'/%3E %3Cpath d='M199 140V38h12l8 10v92z'/%3E%3Crect x='224' y='72' width='24' height='68'/%3E%3Crect x='252' y='92' width='42' height='48'/%3E %3C/svg%3E");
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"])[data-feed-bg="city"] {
    --bg-chat: #152233;
    --feed-grad: linear-gradient(180deg, #0d1520 0%, #152233 60%, #1d2b40 100%);
    --feed-end: #1d2b40;
    --feed-skyline: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 140' fill='rgba(255,255,255,.05)'%3E %3Crect x='6' y='84' width='26' height='56'/%3E%3Crect x='35' y='62' width='20' height='78'/%3E %3Cpath d='M60 140V42l10-14 10 14v98z'/%3E%3Cpath d='M84 140V22l12-20 12 20v118z'/%3E%3Cpath d='M112 140V50l8-8 8 8v90z'/%3E %3Cpath d='M134 140c-4-40 10-70 4-110h22c-6 40 8 70 4 110z'/%3E%3Crect x='172' y='56' width='22' height='84'/%3E %3Cpath d='M199 140V38h12l8 10v92z'/%3E%3Crect x='224' y='72' width='24' height='68'/%3E%3Crect x='252' y='92' width='42' height='48'/%3E %3C/svg%3E");
  }
}
:root[data-theme="dark"][data-feed-bg="city"] {
  --bg-chat: #152233;
  --feed-grad: linear-gradient(180deg, #0d1520 0%, #152233 60%, #1d2b40 100%);
  --feed-end: #1d2b40;
  --feed-skyline: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 140' fill='rgba(255,255,255,.05)'%3E %3Crect x='6' y='84' width='26' height='56'/%3E%3Crect x='35' y='62' width='20' height='78'/%3E %3Cpath d='M60 140V42l10-14 10 14v98z'/%3E%3Cpath d='M84 140V22l12-20 12 20v118z'/%3E%3Cpath d='M112 140V50l8-8 8 8v90z'/%3E %3Cpath d='M134 140c-4-40 10-70 4-110h22c-6 40 8 70 4 110z'/%3E%3Crect x='172' y='56' width='22' height='84'/%3E %3Cpath d='M199 140V38h12l8 10v92z'/%3E%3Crect x='224' y='72' width='24' height='68'/%3E%3Crect x='252' y='92' width='42' height='48'/%3E %3C/svg%3E");
}
.d-bg[data-feed-bg="city"] #feed, .d-bg[data-feed-bg="city"] .bg-sample {
  background-image: var(--feed-skyline), var(--feed-grad);
  background-size: min(100%, 560px) auto, 100% 100%;
  background-position: bottom center, 0 0;
  background-repeat: no-repeat;
}
/* Выбор в настройках: кружки-образцы и живой образец пузырей на фоне. */
.bg-pick { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
.bg-swatch { display: flex; flex-direction: column; align-items: center; gap: 4px; width: auto; height: auto;
             padding: 6px; background: transparent; color: var(--muted); font-size: 11px; border-radius: 12px; }
.bg-swatch .sw { display: block; width: 34px; height: 34px; border-radius: 50%; border: 2px solid var(--line); box-sizing: border-box; }
.bg-swatch.on { color: var(--text); }
.bg-swatch.on .sw { border-color: var(--accent); box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent); }
.sw-default { background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180' fill='none' stroke='rgba(30,70,70,.2)' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E %3Cg transform='rotate(-20 28 22)'%3E%3Ccircle cx='18' cy='22' r='6'/%3E%3Cpath d='M24 22h17M35 22v5M40 22v4'/%3E%3C/g%3E %3Cg transform='rotate(8 84 34)'%3E%3Cpath d='M72 36l12-11 12 11v13H72z'/%3E%3Cpath d='M81 49v-7h6v7'/%3E%3C/g%3E %3Cpath d='M150 14a12 12 0 1 0 13 17a9 9 0 0 1-13-17z'/%3E %3Cg transform='rotate(-10 30 95)'%3E%3Crect x='17' y='88' width='26' height='18' rx='3'/%3E%3Cpath d='M24 88v-4h12v4M17 96h26'/%3E%3C/g%3E %3Cpath d='M98 78l2 4.2 4.6.7-3.3 3.2.8 4.6-4.1-2.2-4.1 2.2.8-4.6-3.3-3.2 4.6-.7z'/%3E %3Cg transform='rotate(12 146 96)'%3E%3Cpath d='M135 90h20v9a8 8 0 0 1-8 8h-4a8 8 0 0 1-8-8z'/%3E%3Cpath d='M155 93h3a3.5 3.5 0 0 1 0 7h-3M141 85c-2-3 2-4 0-7M148 85c-2-3 2-4 0-7'/%3E%3C/g%3E %3Cpath d='M64 152l-9-8.5a5.2 5.2 0 0 1 9-5.3a5.2 5.2 0 0 1 9 5.3z'/%3E %3Cg transform='rotate(-6 118 148)'%3E%3Cpath d='M110 168v-32l8-9 8 9v32M114 144h8M114 152h8M114 160h8'/%3E%3C/g%3E %3Cpath d='M150 152h19a6 6 0 0 0-1.5-11.8a8.5 8.5 0 0 0-16.3-2a6.6 6.6 0 0 0-1.2 13.8z'/%3E %3Ccircle cx='56' cy='64' r='1.6'/%3E%3Ccircle cx='170' cy='60' r='1.6'/%3E%3Ccircle cx='12' cy='150' r='1.6'/%3E%3Ccircle cx='112' cy='12' r='1.6'/%3E%3Ccircle cx='86' cy='118' r='1.6'/%3E %3C/svg%3E") 0 0/90px 90px, linear-gradient(160deg, #dbeccd, #bcd3ea); }
.sw-plain { background: linear-gradient(160deg, #dbeccd, #c6e2dc 45%, #bcd3ea); }
.sw-neutral { background: radial-gradient(rgba(0, 0, 0, .14) 1.2px, transparent 1.3px) 0 0/7px 7px, linear-gradient(160deg, #e3eaf0, #d9e3ea); }
.sw-city { background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 140' fill='rgba(60,90,120,.3)'%3E %3Crect x='6' y='84' width='26' height='56'/%3E%3Crect x='35' y='62' width='20' height='78'/%3E %3Cpath d='M60 140V42l10-14 10 14v98z'/%3E%3Cpath d='M84 140V22l12-20 12 20v118z'/%3E%3Cpath d='M112 140V50l8-8 8 8v90z'/%3E %3Cpath d='M134 140c-4-40 10-70 4-110h22c-6 40 8 70 4 110z'/%3E%3Crect x='172' y='56' width='22' height='84'/%3E %3Cpath d='M199 140V38h12l8 10v92z'/%3E%3Crect x='224' y='72' width='24' height='68'/%3E%3Crect x='252' y='92' width='42' height='48'/%3E %3C/svg%3E") bottom/100% auto no-repeat, linear-gradient(180deg, #f3e9dc, #c9d8e8); }
 .sw-blue { background: #d6e4f0; } .sw-green { background: #d7e6d1; }
.sw-sand { background: #efe6d6; } .sw-lilac { background: #e3dcef; } .sw-warm { background: #e9e5e0; }
.bg-sample { display: flex; flex-direction: column; gap: 4px; background: var(--bg-chat);
             min-height: 130px; justify-content: flex-end; }
.bg-sample .msg.out { align-self: flex-end; }

/* --- 8. «Стекло» в переписке, как в Telegram на iOS 26 (08.10.2026).
   Подложек у шапки, карточки брони и строки ввода нет: узор фона лежит на
   всей странице (на корне — тогда он есть и под часами, и под «палочкой»
   айфона, где раньше белела полоса), а кнопки, имя, карточка, поле ввода и
   плашки — одно и то же полупрозрачное стекло поверх него.
   Без backdrop-filter: под стеклом только неподвижный бледный узор, и
   размытие почти не меняло вид, зато стоило слоя и перерисовки на каждый
   элемент (их десяток) при каждом сдвиге — клавиатура, рост поля. Плотная
   заливка выглядит так же и ничего не стоит (замер 08.10.2026).
   Раскладку не трогаем: размеры и порядок прежние, код клавиатуры (15-, 55-)
   о них знает. Сообщения под стекло не заезжают — для этого пришлось бы
   перекраивать экран вокруг клавиатуры. Выключается в «Оформлении». --- */
:root {
  --glass-bg: rgba(255, 255, 255, .82);
  --glass-strong: rgba(255, 255, 255, .9);
  --glass-edge: rgba(255, 255, 255, .8);
  --glass-shadow: 0 2px 12px rgba(0, 0, 0, .10), 0 0 0 .5px rgba(0, 0, 0, .05);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --glass-bg: rgba(30, 40, 54, .78);
    --glass-strong: rgba(30, 40, 54, .88);
    --glass-edge: rgba(255, 255, 255, .10);
    --glass-shadow: 0 2px 12px rgba(0, 0, 0, .35);
  }
}
:root[data-theme="dark"] {
  --glass-bg: rgba(30, 40, 54, .78);
  --glass-strong: rgba(30, 40, 54, .88);
  --glass-edge: rgba(255, 255, 255, .10);
  --glass-shadow: 0 2px 12px rgba(0, 0, 0, .35);
}
/* Обои стекла. На телефоне их несёт корень страницы: тогда узор есть и под
   часами, и под «палочкой» айфона, где раньше белела полоса фона страницы, а
   ниже края градиента — его последний цвет (сам градиент там пошёл бы по
   новой, со швом). На широком экране инбокс — «окно» по центру (см. «на
   компьютере — окном»): там обои на самом окне, фон вокруг прежний. */
:root {
  --wall-image: var(--feed-doodles), var(--feed-grad);
  --wall-size: var(--doodle-size), 100% 100%;
  --wall-position: 0 0, 0 0;
  --wall-repeat: repeat, no-repeat;
}
:root[data-feed-bg="city"] {
  --wall-image: var(--feed-skyline), var(--feed-grad);
  --wall-size: min(100%, 560px) auto, 100% 100%;
  --wall-position: bottom center, 0 0;
  --wall-repeat: no-repeat, no-repeat;
}
@media (max-width: 899px) {
  :root.d-glass.chat-root { background: var(--bg-chat); }
  :root.d-glass.d-bg.chat-root {
    background-color: var(--feed-end); background-image: var(--wall-image);
    background-size: var(--wall-size); background-position: var(--wall-position);
    background-repeat: var(--wall-repeat);
  }
  :root.d-glass body.chatpage { background: transparent; }
}
@media (min-width: 900px) {
  :root.d-glass body.chatpage { background: var(--bg-chat); }
  :root.d-glass.d-bg body.chatpage {
    background-color: var(--feed-end); background-image: var(--wall-image);
    background-size: var(--wall-size); background-position: var(--wall-position);
    background-repeat: var(--wall-repeat);
  }
}
:root.d-glass .chatpage .pane-chat, :root.d-glass #feed { background: transparent; }
/* Без узора (дизайн v2, часть 2 выключена) обои стекла — ровный цвет ленты. */
:root:not(.d-bg) {
  --feed-end: var(--bg-chat);
  --wall-image: linear-gradient(var(--bg-chat), var(--bg-chat));
  --wall-size: 100% 100%; --wall-position: 0 0; --wall-repeat: no-repeat;
}
/* Полоса под краем страницы (~62pt у айфона в приложении, см. «Окна поверх
   чата» у .modal-back): её цвет WebKit берёт у ЦВЕТА фона body. Со стеклом body
   прозрачный — полоса цвета конца градиента, как и надо. Но пока открыто окно
   или панель, полоса должна быть их цвета: body получает этот цвет, а поверх —
   те же обои, чтобы сама страница не поменялась (скрин владельца 08.10.2026:
   светлая полоса под затемнённым окном брони). */
@media (max-width: 899px) {
  :root.d-glass.chat-root body.chatpage:is(:has(.modal-back:not([hidden])), :has(#gif-pop:not([hidden])),
      :has(#scripts-pop:not([hidden])), :has(.lightbox), :has(#crop-back:not([hidden]))) {
    background-image: var(--wall-image); background-size: var(--wall-size);
    background-position: var(--wall-position); background-repeat: var(--wall-repeat);
  }
  :root.d-glass.chat-root body.chatpage:has(.modal-back:not([hidden])) {
    background-color: color-mix(in srgb, var(--feed-end) 55%, black);
  }
  :root.d-glass.chat-root body.chatpage:is(:has(#gif-pop:not([hidden])), :has(#scripts-pop:not([hidden]))) {
    background-color: var(--bg);
  }
  :root.d-glass.chat-root body.chatpage:is(:has(.lightbox), :has(#crop-back:not([hidden]))) {
    background-color: #0b0b0b;
  }
}

/* Общий рецепт стекла. */
.d-glass .chatpage header .back, .d-glass #find-btn, .d-glass #remind, .d-glass .chatpage header .who-pill,
.d-glass .chatpage header .lead-head:not(.lead-open),
.d-glass .chatpage .booking, .d-glass .pinned-strip, .d-glass .note-strip, .d-glass .guest-card,
.d-glass .contacts-hint, .d-glass .note-add,
.d-glass #composer #text,
.d-glass #composer #plus,
.d-glass #composer #mic:not(.recording):not(.waiting):not(.cancelling),
.d-glass #composer #scroll-down,
.d-glass #composer #rec-bar,
.d-glass #quote-bar, .d-glass #attach-bar, .d-glass #schedule-bar, .d-glass .others-draft {
  background: var(--glass-bg); border: 1px solid var(--glass-edge); box-shadow: var(--glass-shadow);
}

/* Шапка: без полосы — кнопки кругами, имя плашкой, лид — своей пилюлей. */
/* Места в строке мало (назад, аватар, поиск, колокольчик, имя, лид) — круги
   36px и узкие зазоры, иначе имя обрезается уже на «Ольге Смирновой». */
.d-glass .chatpage header { background: transparent; border-bottom: 0; gap: 6px; padding-left: 10px; padding-right: 10px; }
.d-glass .chatpage header .back {
  width: 36px; height: 36px; flex: none; border-radius: 50%; padding: 0 0 3px 0;
  display: grid; place-items: center; font-size: 30px; line-height: 1;
}
.d-glass #find-btn, .d-glass #remind {
  width: 36px; height: 36px; border-radius: 50%; padding: 0;
  display: grid; place-items: center; color: var(--text);
}
.d-glass #find-btn svg, .d-glass #remind svg { display: block; }
.d-glass #remind .ic { margin: 0; }
/* Колокольчик без напоминания бледный — но бледнеет значок, а не стекло. */
.d-glass #remind { opacity: 1; }
.d-glass #remind:not(.on) > * { opacity: .55; }
.d-glass #remind.on { background-color: color-mix(in srgb, var(--accent) 20%, var(--glass-strong)); }
/* Аватар со значком канала и имя — одной плашкой рядом со стрелкой, как в
   Telegram на iOS 26 (владелец, 08.10.2026); поиск, колокольчик и лид — справа. */
.d-glass .chatpage header .who-pill {
  display: flex; align-items: center; gap: 8px; order: 1;
  /* Во всю ширину до кнопок, а не по тексту: строка под именем через 2 с
     сменяется объявлением, а у гостя бывает «печатает…» — плашка по тексту
     меняла ширину на глазах, шапка «скакала» (владелец, 08.10.2026). */
  flex: 1 1 auto; min-width: 0;
  padding: 3px 14px 3px 3px; border-radius: 24px;
}
.d-glass .chatpage header .who-pill .av-wrap, .d-glass .chatpage header .who-pill .who { order: 0; }
.d-glass .chatpage header .who-pill .av-wrap { flex: none; }
.d-glass .chatpage header .lead-head:not(.lead-open) { background-color: var(--glass-strong); }

/* Карточка брони — стеклом, с отступами, без полосы под собой. */
.d-glass .chatpage .bookings { background: transparent; border-bottom: 0; padding: 2px 8px 6px; }
.d-glass .chatpage .booking { background: var(--bubble-in); border-radius: 16px; }
/* Карточка брони — плотная, а не стеклянная, и у прошедшей брони без
   полупрозрачности: сквозь неё просвечивал узор, текст терялся («бледная,
   плохо читаемая» — владелец, 08.10.2026). Что бронь прошла — видно по
   серой полоске слева. */
.d-glass .chatpage .booking.off { opacity: 1; }
/* Полоска статуса брони слева (дизайн v2, часть 3) — главное в карточке:
   рамка стекла её перебивала, возвращаем поверх. */
.d-glass.d-card .chatpage .booking { border-left: 4px solid #34c759; }
.d-glass.d-card .chatpage .booking:has(.b-dot.wait) { border-left-color: #ff9f0a; }
.d-glass.d-card .chatpage .booking:has(.b-dot.bad) { border-left-color: #ff3b30; }
.d-glass.d-card .chatpage .booking.off { border-left-color: #b5bcc4; }
/* Полоски под шапкой (закреп, заметка, гость) — плашками, не во всю ширину. */
.d-glass .pinned-strip, .d-glass .note-strip, .d-glass .guest-card, .d-glass .contacts-hint {
  margin: 0 8px 6px; border-radius: 14px;
}
/* Метки внутри ленты — плотнее: они едут поверх узора вместе с сообщениями.
   backdrop-filter: none — снимаем размытие точек дизайна v2 (.d-bg .day-sep). */
.d-glass .day-sep, .d-glass .unread-sep, .d-glass .under-composer button, .d-glass .feed-date span {
  background: var(--glass-strong); border: 1px solid var(--glass-edge);
  /* Тень короткая: размытая на 12px перерисовывалась бы на каждой новой полосе
     прокрутки (замер 08.10: +25 % растра на ленте) — у этих меток её не видно. */
  box-shadow: 0 1px 2px rgba(0, 0, 0, .08);
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
/* Подписи на узоре — плашками, иначе их не прочитать. */
.d-glass .note-add { margin: 2px 12px 0; padding: 3px 10px; border-radius: 12px; opacity: 1; }
.d-glass .under-composer button { padding: 4px 12px; border-radius: 12px; }
.d-glass .day-sep { color: var(--muted); }
.d-glass .unread-sep { border-left: 0; border-right: 0; box-shadow: none; color: var(--accent); }

/* Строка ввода: без подложки и линии. */
.d-glass #composer { background: transparent; border-top: 0; box-shadow: none; }
.d-glass #composer #plus, .d-glass #composer #mic:not(.recording):not(.waiting):not(.cancelling) {
  color: var(--text);
}
.d-glass #composer button[type="submit"] { box-shadow: var(--glass-shadow); }
/* Знак «⌄» в шрифте нарисован низко: по рамке он по центру, а глазу — опущен. */
.d-glass #composer #scroll-down { padding: 0 0 8px; color: var(--text); }
/* Полосы над полем — плашками с отступом от краёв, а не во всю ширину. */
.d-glass #quote-bar, .d-glass #attach-bar, .d-glass #schedule-bar, .d-glass .others-draft {
  margin: 0 8px 6px; border-radius: 14px;
}


/* ---------- «Пульс смены» (спека 2026-10-08-пульс-смены-ядро) ---------- */
/* Плашка «Я на месте»: сверху, над всем, пока человек не ответил. */
.pulse-ask {
  position: sticky; top: env(safe-area-inset-top, 0px); z-index: 50;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  padding: 10px 14px; background: #fff8e1; color: #6b4f00;
  border-bottom: 1px solid #f1d27a; font-size: 15px;
}
.pulse-ask-text { flex: 1 1 160px; font-weight: 600; }
.pulse-ask button { border: 0; border-radius: 8px; padding: 7px 12px; font: inherit; cursor: pointer; }
.pulse-ask-on { background: #2e7d32; color: #fff; }
.pulse-ask-later { background: transparent; color: inherit; text-decoration: underline; }
/* Табло над лентой «Пульс»-чата: до четырёх ждущих, остальные — в разделе. */
.pulse-board { padding: 8px 12px 6px; border-bottom: 1px solid var(--line); background: var(--bg);
  font-size: 14px; flex: none; }
.pulse-board-head { display: flex; justify-content: space-between; align-items: baseline;
  font-weight: 700; margin-bottom: 2px; }
.pulse-board-head a { font-weight: 400; font-size: 13px; color: var(--accent); text-decoration: none; }
.pulse-board-row { display: flex; justify-content: space-between; gap: 8px; padding: 3px 0;
  color: inherit; text-decoration: none; }
.pulse-board-row span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pulse-min { flex: none; font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums;
  color: var(--muted); }
.pulse-board-row.m-warn .pulse-min { color: #b8860b; }
.pulse-board-row.m-bad .pulse-min { color: #c62828; }
.pulse-board-empty { color: var(--muted); }
/* Окно «Пульс»: та же шапка, что у доски и «Заездов»; плитки, карточки,
   строки ждущих с цветными минутами (серые → жёлтые с 1-й ступени →
   красные с 3-й). Ширина — колонка 760px, на телефоне во всю ширину. */
body.pulsepage { overflow-y: auto; }
body.pulsepage .pulse-body { flex: 1; overflow-y: auto; background: var(--bg-chat);
  padding: 12px; padding-bottom: max(16px, env(safe-area-inset-bottom)); }
.pulse-body > * { max-width: 760px; margin-left: auto; margin-right: auto; }
.pulse-date { font-size: 13px; font-weight: 400; color: var(--muted); margin-left: 6px; }
.pulse-me { font-size: 13px; color: #2e7d32; font-weight: 600; white-space: nowrap; }
.chip.pulse-on { background: #2e7d32; border-color: #2e7d32; color: #fff; font-weight: 600; }
.pulse-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-bottom: 10px; }
.pulse-tile { background: var(--bg); border: 1px solid var(--line); border-radius: 14px;
  padding: 10px 12px; display: flex; flex-direction: column; min-width: 0; }
.pulse-tile .pt-n { font-size: 26px; line-height: 1.1; font-weight: 700; font-variant-numeric: tabular-nums; }
.pulse-tile span { font-size: 13px; color: var(--text); }
.pulse-tile .pt-sub { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pulse-tile.alert { border-color: #e2a9a4; background: #fff4f3; }
.pulse-tile.alert .pt-n { color: #d33a2c; }
.pulse-tile.warn .pt-n { color: #c1741a; }
.pulse-card { background: var(--bg); border: 1px solid var(--line); border-radius: 14px;
  padding: 10px 12px; margin-bottom: 10px; min-width: 0; }
.pulse-card h2 { font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); margin: 2px 0 8px; }
.pulse-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 10px; }
.pulse-grid .pulse-card { margin-bottom: 0; }
.pulse-grid + .pulse-card { margin-top: 10px; }
.pulse-list { list-style: none; margin: 0; padding: 0; }
.pw { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-top: 1px solid var(--line); }
.pw:first-child { border-top: 0; }
.pw-ch { flex: none; width: 28px; height: 28px; }
.pw-ch svg { width: 28px; height: 28px; display: block; }
.pw-main { flex: 1; min-width: 0; display: flex; flex-direction: column; color: var(--text); text-decoration: none; }
.pw-title { font-size: 15px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pw-lead { font-style: normal; font-size: 11px; font-weight: 600; color: #2e7d32; border: 1px solid #2e7d32;
  border-radius: 10px; padding: 0 6px; margin-left: 6px; vertical-align: 2px; }
.pw-preview { font-size: 13px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pw-min { flex: none; font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums;
  padding: 2px 8px; border-radius: 10px; background: var(--bg-chat); color: var(--muted); }
.pw.m-warn .pw-min { background: #fff3cd; color: #8a6d1f; }
.pw.m-bad .pw-min { background: #fbe0e0; color: #c62828; }
.pw-done { flex: none; width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--line);
  background: var(--bg); color: #2e7d32; font-size: 16px; cursor: pointer; padding: 0; }
.pw-done:hover { background: #e8f5e9; border-color: #2e7d32; }
.pulse-empty { padding: 18px 0 10px; text-align: center; color: var(--muted); font-size: 15px; }
.pulse-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.pulse-chip { display: inline-flex; align-items: baseline; gap: 4px; padding: 4px 10px; border-radius: 14px;
  background: #e8f5e9; color: #2e7d32; font-weight: 600; font-size: 14px; text-decoration: none; }
.pulse-chip small { font-weight: 400; color: inherit; opacity: .8; }
.pulse-chip.link { background: var(--bg-chat); color: var(--accent); }
.pd { display: flex; align-items: baseline; gap: 8px; padding: 6px 0; border-top: 1px solid var(--line); font-size: 14px; }
.pd:first-child { border-top: 0; }
.pd-main { flex: 1; min-width: 0; color: var(--text); text-decoration: none; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.pd-sum { flex: none; font-weight: 600; color: #c1741a; font-variant-numeric: tabular-nums; }
.pulse-day { width: 100%; border-collapse: collapse; font-size: 14px; font-variant-numeric: tabular-nums; }
.pulse-day th { font-size: 11px; font-weight: 400; color: var(--muted); text-align: right; padding: 0 0 4px; }
.pulse-day td { padding: 5px 0; border-top: 1px solid var(--line); text-align: right; }
.pulse-day td:first-child, .pulse-day th:first-child { text-align: left; font-weight: 600; }
.pulse-muted-row td { color: var(--muted); font-weight: 400 !important; }
.pulse-foot { margin: 8px 0 0; font-size: 12px; color: var(--muted); }
.pulse-muted { color: var(--muted); font-size: 14px; }
.pulse-tg { margin: 10px 0 0; font-size: 14px; }
.pulse-tg-link { color: var(--accent); font-weight: 600; text-decoration: none; }
.pulse-ok { color: #2e7d32; font-weight: 600; }
.pulse-bad, .pulse-n { color: #d33a2c; }
/* «Пульс»-чат — монитор: писать в него нельзя, лид и заметка к нему не
   относятся — прячем поле ввода, «это лид» и «+ заметка». */
body[data-pulse-chat="1"] #composer, body[data-pulse-chat="1"] .under-composer,
body[data-pulse-chat="1"] #lead-mark-head, body[data-pulse-chat="1"] #lead-lost,
body[data-pulse-chat="1"] #note-add, body[data-pulse-chat="1"] #note { display: none !important; }
/* Кнопки пузыря «Пульса» — переносятся целиком, слово не рвут. */
.msg.system.pulse .crm-btns { flex-wrap: wrap; gap: 6px; }
.msg.system.pulse .crm-btn { white-space: nowrap; text-decoration: none; }
@media (max-width: 420px) {
  .pulse-tile .pt-n { font-size: 22px; }
  .pulse-tile { padding: 8px 10px; }
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pulse-ask { background: #3a2f0b; color: #f3d98b; border-color: #5c4a12; }
  :root:not([data-theme="light"]) .pulse-chip { background: #1f4020; color: #93d69a; }
  :root:not([data-theme="light"]) .pulse-chip.link { background: var(--bg-chat); color: #8fd0ff; }
  :root:not([data-theme="light"]) .pulse-tile.alert { background: #3a1b19; border-color: #6b2b27; }
  :root:not([data-theme="light"]) .pulse-tile.alert .pt-n, :root:not([data-theme="light"]) .pulse-bad { color: #ff9a9a; }
  :root:not([data-theme="light"]) .pw.m-warn .pw-min { background: #4a3c10; color: #ffd970; }
  :root:not([data-theme="light"]) .pw.m-bad .pw-min { background: #4a1f1f; color: #ff9a9a; }
  :root:not([data-theme="light"]) .pw-lead { color: #93d69a; border-color: #93d69a; }
  :root:not([data-theme="light"]) .pw-done { color: #93d69a; }
  :root:not([data-theme="light"]) .pw-done:hover { background: #1f4020; }
  :root:not([data-theme="light"]) .pulse-me, :root:not([data-theme="light"]) .pulse-ok { color: #93d69a; }
}
:root[data-theme="dark"] .pulse-ask { background: #3a2f0b; color: #f3d98b; border-color: #5c4a12; }
:root[data-theme="dark"] .pulse-chip { background: #1f4020; color: #93d69a; }
:root[data-theme="dark"] .pulse-chip.link { background: var(--bg-chat); color: #8fd0ff; }
:root[data-theme="dark"] .pulse-tile.alert { background: #3a1b19; border-color: #6b2b27; }
:root[data-theme="dark"] .pulse-tile.alert .pt-n, :root[data-theme="dark"] .pulse-bad { color: #ff9a9a; }
:root[data-theme="dark"] .pw.m-warn .pw-min { background: #4a3c10; color: #ffd970; }
:root[data-theme="dark"] .pw.m-bad .pw-min { background: #4a1f1f; color: #ff9a9a; }
:root[data-theme="dark"] .pw-lead { color: #93d69a; border-color: #93d69a; }
:root[data-theme="dark"] .pw-done { color: #93d69a; }
:root[data-theme="dark"] .pw-done:hover { background: #1f4020; }
:root[data-theme="dark"] .pulse-me, :root[data-theme="dark"] .pulse-ok { color: #93d69a; }

/* Настройки «Поддержка Авито»: варианты начала обращения, пример, причины. */
.as-variant { margin-top: 12px; }
.as-variant-head { display: flex; align-items: center; justify-content: space-between;
                   gap: 8px; font-size: 13px; color: var(--muted); margin-bottom: 4px; }
.as-actions { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.as-preview { white-space: pre-wrap; word-break: break-word; font: inherit; font-size: 14px;
              margin: 8px 0 0; padding: 10px 12px; border-radius: 10px;
              border: 1px solid var(--line); background: var(--bg-chat, var(--bg)); }
.as-reason { margin-top: 12px; }
.as-reason label { display: block; margin: 0 0 4px; }
.as-stat { padding: 8px 0; border-bottom: 1px solid var(--line); }
.as-stat.old { color: var(--muted); }
.as-stat-name { font-size: 14px; word-break: break-word; }
.as-stat-nums { font-size: 13px; color: var(--muted); margin-top: 2px; }
.as-stat-nums b { color: var(--text); }
