/* ═════ Sentos · Боковая панель: список чатов, журнал звонков, поиск, меню и нижняя навигация ═════
   Перенесено из прототипа newfront/chats.css.
   Палитра и общие примитивы — в base.css и app.css. */

/* ─────────────────────── Боковая панель ─────────────────────── */

.sidebar {
  grid-area: sidebar;
  min-width: 0;
}

.brand-row {
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 14px 14px 6px 18px;
}

.brand-name {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* Заголовок лежит внутри списка: так он уходит и приходит вместе с
   ним одним кадром, а раздел настроек закрывает его собой. */
.sidebar-head {
  position: relative;
  display: flex;
  flex: none;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: calc(10px + env(safe-area-inset-top)) 10px 6px 18px;
}

/* ─────────────── Строка связи ───────────────
   «Ожидание сети… / Соединение… / Обновление…» — как у Telegram. По
   центру шапки, поверх неё: раскладку не трогает, нажатия проходят к
   названию и кнопке. Строки лежат друг на друге: новая падает сверху на
   20 точек с проявлением, прежняя уходит вниз, гаснув, — 220 мс
   (js/netline.js). */
.net-status {
  position: absolute;
  top: calc(10px + env(safe-area-inset-top));
  left: 0;
  right: 0;
  display: grid;
  place-items: center;
  height: 42px;
  color: var(--text);
  font-size: 15px;
  font-weight: 500;
  pointer-events: none;
}

.net-status > .net-line,
.net-host > .net-line,
.net-slot > * {
  grid-area: 1 / 1;
}

.net-host {
  display: inline-grid;
  justify-items: start;
}

.net-slot {
  display: inline-grid;
  justify-items: start;
  min-width: 0;
}

.net-line {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  animation: net-in 220ms ease both;
}

/* Крутилка перед надписью — дуга в четверть круга, оборот за секунду,
   как у Telegram (ProxyDrawable): под ней бледное кольцо. */
.net-spin {
  width: 0.9em;
  height: 0.9em;
  margin-right: 6px;
  flex: none;
  border: 0.13em solid color-mix(in srgb, currentColor 18%, transparent);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: net-spin 1s linear infinite;
}

@keyframes net-spin {
  to { transform: rotate(360deg); }
}

.net-line.is-leaving {
  animation: net-out 220ms ease both;
}

/* Присутствие в шапке переписки уходит тем же движением, что строка
   связи, и тем же возвращается. */
#currentStatus {
  transition: opacity 220ms ease, transform 220ms ease;
}

#currentStatus.is-away {
  opacity: 0;
  transform: translateY(20px);
}

@keyframes net-in {
  from { opacity: 0; transform: translateY(-20px); }
}

@keyframes net-out {
  to { opacity: 0; transform: translateY(20px); }
}

/* Три точки: проявляются по очереди через 150 мс, каждая за 300, с
   тысячной гаснут все вместе за 400, пауза 300 — круг 1,7 с. Меняется
   только прозрачность: место под точками есть всегда. */
.net-dots i {
  font-style: normal;
  opacity: 0;
  animation: net-dot-1 1700ms linear infinite;
}

.net-dots i:nth-child(2) { animation-name: net-dot-2; }
.net-dots i:nth-child(3) { animation-name: net-dot-3; }

@keyframes net-dot-1 {
  0% { opacity: 0; }
  17.6% { opacity: 1; }
  58.8% { opacity: 1; }
  82.4%, 100% { opacity: 0; }
}

@keyframes net-dot-2 {
  0%, 8.8% { opacity: 0; }
  26.5% { opacity: 1; }
  58.8% { opacity: 1; }
  82.4%, 100% { opacity: 0; }
}

@keyframes net-dot-3 {
  0%, 17.6% { opacity: 0; }
  35.3% { opacity: 1; }
  58.8% { opacity: 1; }
  82.4%, 100% { opacity: 0; }
}

.sidebar-search {
  padding: 4px 14px 8px;
}

.filters {
  display: flex;
  gap: 8px;
  padding: 2px 14px 8px;
}

/* Отборы лежат в самом списке чатов (index.html): при смене раздела
   они уходят вместе с ним, и соседние разделы не съезжают на их
   высоту. Раньше они стояли над всеми списками и сворачивались —
   приходящие чаты ехали по диагонали, влево и вниз. Липкие: при
   прокрутке остаются наверху, на фоне панели. Поля списка (8 по бокам)
   гасим отрицательными, чтобы пилюли стояли в 14 от края, как было. */
.chat-list > .filters {
  position: sticky;
  top: 0;
  z-index: 2;
  margin: 0 -8px;
  background: var(--panel-bg, var(--panel));
}

/* Заглушка первой загрузки ложится под отборы, а не на них. */
.sidebar-lists > #chatsLoading { padding-top: 42px; }

.filter {
  min-height: 32px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  background: var(--field);
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  transition:
    background-color 160ms ease,
    color 160ms ease,
    transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
}

.filter.active {
  background: var(--accent-fill);
  color: var(--accent-fill-text);
}

.filter.is-pressed { transform: scale(0.96); }

/* ─────────────── Сворачивание полос (ui.js, fold) ───────────────
   Отборы и полосы над списком приходят и уходят не кадром: место под
   ними растёт и схлопывается, а сами они приходят масштабом от 0,96 с
   проявлением. Приход — высота 260 мс общей кривой, прозрачность 200;
   уход короче: прозрачность 140, масштаб 160, высота 220. */
.fold {
  overflow: hidden;
  transform-origin: 50% 0;
  transition:
    max-height 260ms cubic-bezier(0.22, 1, 0.36, 1),
    margin 260ms cubic-bezier(0.22, 1, 0.36, 1),
    padding 260ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 200ms ease,
    transform 260ms cubic-bezier(0.22, 1, 0.36, 1);
}

.fold.is-folded {
  margin-top: 0;
  margin-bottom: 0;
  padding-top: 0;
  padding-bottom: 0;
  opacity: 0;
  transform: scale(0.96);
  transition:
    max-height 220ms cubic-bezier(0.22, 1, 0.36, 1),
    margin 220ms cubic-bezier(0.22, 1, 0.36, 1),
    padding 220ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 140ms ease,
    transform 160ms ease;
}

/* Отбор прячет строки, не подходящие под него (chat.js, bindChatFilters). */
.chat-list[data-filter="unread"] .chat-row:not(.unread),
.chat-list[data-filter="groups"] .chat-row:not(.is-group) {
  display: none;
}

/* Полоса про уведомления */
.notify-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 14px 8px;
  padding: 10px 8px 10px 14px;
  border-radius: 18px;
  background: var(--brand-50);
  color: var(--brand-700);
  font-size: 12px;
  line-height: 1.35;
}

.dark .notify-bar {
  background: #2a1a16;
  color: #f0937d;
}

.notify-bar > .icon {
  width: 20px;
  height: 20px;
  flex: none;
  fill: currentColor;
}

.notify-bar span {
  flex: 1;
  min-width: 0;
}

.notify-accept {
  flex: none;
  min-height: 32px;
  padding: 0 12px;
  border: 0;
  border-radius: 999px;
  background: var(--accent-fill);
  color: var(--accent-fill-text);
  font: inherit;
  font-size: 12px;
  transition: transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
}

.notify-accept.is-pressed { transform: scale(0.96); }

.notify-close {
  width: 32px;
  height: 32px;
  color: inherit;
}

.notify-close .icon { width: 18px; height: 18px; }

.pull-refresh {
  padding: 6px 0;
  color: var(--muted);
  font-size: 12px;
  text-align: center;
}

/* ─────────────── Меню боковой панели ───────────────

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

   Бургер стоит на своей круглой подложке — как стрелки «назад»: голая
   иконка рядом с логотипом не читается как кнопка. Размер чуть меньше
   обычных круглых кнопок (36 против 42), чтобы не спорить с логотипом. */

.sidebar-burger {
  width: 36px;
  height: 36px;
}

.burger-icons {
  width: 20px;
  height: 20px;
}

/* Крестик приходит на место бургера тем же движением, что микрофон в
   звонке: уходящая иконка сжимается, приходящая вырастает. */
.burger-icons .icon-close {
  opacity: 0;
  transform: scale(0.5);
}

.sidebar-burger.is-open .burger-icons .icon-menu {
  opacity: 0;
  transform: scale(0.5);
}

.sidebar-burger.is-open .burger-icons .icon-close {
  opacity: 1;
  transform: none;
}

/* Логотип держится за бургер, кнопка нового чата остаётся у края */
.brand-link { margin-right: auto; }

/* Меню выезжает из-за левого края поверх списка, а список под ним
   гаснет; закрывается — уезжает обратно влево. Поэтому оба вида лежат
   друг на друге в общей обёртке и занимают одно место.

   Прячем через visibility, а не display: с display перехода не будет
   вовсе. Само скрытие отложено на длительность движения — иначе вид
   исчезает раньше, чем успевает уехать. */
.sidebar-views {
  position: relative;
  flex: 1;
  min-height: 0;
}

.sidebar-body,
.sidebar-menu {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  transition:
    opacity 220ms ease,
    transform 300ms cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0s linear 300ms;
}

.sidebar-body {
  opacity: 1;
  visibility: visible;
  transition-delay: 0s, 0s, 0s;
}

.sidebar-menu {
  opacity: 0;
  visibility: hidden;
  transform: translateX(-100%);
}

.messenger.menu-open .sidebar-body {
  opacity: 0;
  visibility: hidden;
  transition-delay: 0s, 0s, 300ms;
}

.messenger.menu-open .sidebar-menu {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s, 0s, 0s;
}

.sidebar-menu-scroll {
  flex: 1;
  min-height: 0;
  padding: 2px 14px 10px;
}

.menu-me {
  gap: 10px;
  margin-bottom: 10px;
  padding: 8px 12px;
  border-radius: 22px;
  background: var(--field);
}

.menu-me .avatar {
  width: 38px;
  height: 38px;
  font-size: 15px;
}

.menu-me-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  flex: 1;
  min-width: 0;
}

.menu-me-name {
  overflow: hidden;
  font-size: 15px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu-me-note {
  color: var(--muted);
  font-size: 12px;
}

.menu-group {
  margin-bottom: 10px;
  border-radius: 22px;
  overflow: hidden;
  background: var(--field);
}

/* Строки меню плотнее обычных списков: разделов немного, и с высотой
   строки настроек меню занимало пол-экрана пустотой. */
.menu-group .list-row {
  gap: 10px;
  min-height: 46px;
  padding: 5px 12px;
  border-radius: 0;
  font-size: 15px;
}

/* Заливка группы уже занята полем, поэтому отклик строки — тон темнее */
.menu-group .list-row.is-pressed:not(:disabled) {
  background: var(--field-strong);
}

@media (hover: hover) {
  .menu-group .list-row:hover { background: var(--field-strong); }
}

.menu-icon {
  width: 28px;
  height: 28px;
  background: var(--field-strong);
  color: var(--text-soft);
}

.menu-icon .icon {
  width: 17px;
  height: 17px;
}

.light .menu-icon {
  background: #e2e2e6;
  color: #4b4b52;
}

/* Текущий раздел отмечен не только цветом текста: плашка иконки тоже
   меняется, поэтому выбор виден и без различения оттенков. */
.menu-group .list-row.active { color: var(--accent); }

.menu-group .list-row.active .menu-icon {
  background: var(--brand-50);
  color: var(--brand-700);
}

.dark .menu-group .list-row.active .menu-icon {
  background: #2a1a16;
  color: var(--accent);
}

/* Переключатель. Флажок настоящий, но невидимый: строка целиком служит
   ему подписью, поэтому работает и нажатие в любом месте строки, и
   пробел с клавиатуры. */
.switch-row {
  cursor: default;
}

.ui-switch {
  position: relative;
  flex: none;
  width: 42px;
  height: 24px;
  border-radius: 999px;
  background: var(--field-strong);
  transition: background-color 200ms ease;
}

.light .ui-switch { background: #d9d9de; }

.ui-switch-dot {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  transition: transform 240ms cubic-bezier(0.22, 1, 0.36, 1);
}

.switch-row input:checked ~ .ui-switch {
  background: var(--accent-fill);
}

.switch-row input:checked ~ .ui-switch .ui-switch-dot {
  transform: translateX(18px);
}

.switch-row input:focus-visible ~ .ui-switch {
  background: var(--brand-500);
}

.sidebar-menu-version {
  margin: 0;
  padding: 4px 18px calc(14px + env(safe-area-inset-bottom));
  color: var(--muted);
  font-size: 12px;
  text-align: center;
}

/* ─────────────── Режим поиска ───────────────

   Пока в поле что-то введено, список чатов уступает место находкам.
   Поиск лежит поверх списка, поэтому оба живут в общей обёртке и
   занимают одно место; уходящий список гаснет, приходящий поиск
   проявляется — та же смена кадра, что между списком и перепиской. */

.sidebar-lists {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.search-results {
  position: absolute;
  inset: 0;
  padding: 0 8px 10px;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 110ms ease,
    visibility 0s linear 110ms;
}

.sidebar-body.is-searching .search-results {
  opacity: 1;
  visibility: visible;
  transition-delay: 90ms, 0s;
}

/* Список во время поиска не прячем совсем: он гаснет на месте, чтобы
   возврат к нему был таким же плавным, как уход. */
.sidebar-body.is-searching .chat-list,
.sidebar-body.is-searching .calls-panel {
  opacity: 0;
  visibility: hidden;
  transition: opacity 90ms ease, visibility 0s linear 90ms;
}

.chat-list,
.calls-panel {
  transition: opacity 110ms ease 90ms;
}

/* Списки разделов лежат друг на друге, как и поиск: во время смены
   кадра уходящий и приходящий не должны двигать друг друга. Без этого
   оба на мгновение оказывались в потоке и делили высоту пополам. */
.sidebar-lists > .chat-list,
.sidebar-lists > .calls-panel,
.sidebar-lists > .list-state,
.sidebar-lists > .skeleton {
  position: absolute;
  inset: 0;
}

/* Скелетон стоит там же, где встанут строки, — с полями самого списка. */
.sidebar-lists > .skeleton { padding: 0 8px 10px; }

/* Смена раздела — смена кадра: 110 мс гаснет уходящий, следом за
   150 мс приходит новый, с коротким подъёмом. Заголовок панели меняется
   вместе со списком, иначе название успевало смениться раньше самого
   раздела и переход читался рывком.

   Заполнение у прихода — backwards, а не both: с both анимация навсегда
   закрепила бы непрозрачность, и погасить список на время поиска стало
   бы нечем. */
.sidebar-lists > .chat-list:not([hidden]),
.sidebar-lists > .calls-panel:not([hidden]) {
  animation: section-in 150ms cubic-bezier(0.22, 1, 0.36, 1) 110ms backwards;
}

.sidebar-lists > .chat-list.is-closing,
.sidebar-lists > .calls-panel.is-closing {
  pointer-events: none;
  animation: section-out 110ms ease both;
}

.sidebar-head .screen-title.is-swapping {
  animation: section-in 150ms cubic-bezier(0.22, 1, 0.36, 1) 110ms backwards;
}

/* Переключение разделов нижней панели — общее движение смены экранов
   (app.css). Направление — по порядку кнопок: контакты, звонки, чаты,
   настройки; его кладёт showSection() в data-motion. При запуске
   отметки нет, и список появляется прежним подъёмом, а не выезжает. */
.sidebar-body[data-motion="forward"] .sidebar-lists > .chat-list:not([hidden]),
.sidebar-body[data-motion="forward"] .sidebar-lists > .calls-panel:not([hidden]),
.sidebar-body[data-motion="forward"] .sidebar-head .screen-title.is-swapping {
  animation: screen-in-forward 230ms cubic-bezier(0.22, 1, 0.36, 1) 70ms backwards;
}

.sidebar-body[data-motion="back"] .sidebar-lists > .chat-list:not([hidden]),
.sidebar-body[data-motion="back"] .sidebar-lists > .calls-panel:not([hidden]),
.sidebar-body[data-motion="back"] .sidebar-head .screen-title.is-swapping {
  animation: screen-in-back 230ms cubic-bezier(0.22, 1, 0.36, 1) 70ms backwards;
}

/* Уход — после прихода и с той же силой селектора: иначе правило
   прихода перебило бы его, пока у уходящего ещё нет hidden. */
.sidebar-body[data-motion="forward"] .sidebar-lists > .chat-list.is-closing,
.sidebar-body[data-motion="forward"] .sidebar-lists > .calls-panel.is-closing {
  animation: screen-out-forward 110ms cubic-bezier(0.4, 0, 1, 1) both;
}

.sidebar-body[data-motion="back"] .sidebar-lists > .chat-list.is-closing,
.sidebar-body[data-motion="back"] .sidebar-lists > .calls-panel.is-closing {
  animation: screen-out-back 110ms cubic-bezier(0.4, 0, 1, 1) both;
}

@keyframes section-in {
  from { opacity: 0; transform: translateY(7px); }
  to { opacity: 1; transform: none; }
}

@keyframes section-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

/* Раздел от раздела отделяет подпись и тонкая полоса. Полоса — не рамка
   вокруг блока, а тональная черта между списками: без неё «человек» и
   «сообщения» слипались в один поток строк. */
.search-section + .search-section {
  position: relative;
  margin-top: 6px;
  padding-top: 10px;
}

.search-section + .search-section::before {
  content: "";
  position: absolute;
  top: 0;
  left: 16px;
  right: 16px;
  height: 1px;
  background: var(--field-strong);
}

.search-results .list-caption {
  padding: 8px 16px 6px;
}

.search-row {
  gap: 12px;
  padding: 8px 12px;
  border-radius: 20px;
}

.search-row-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
}

.search-row-name {
  overflow: hidden;
  font-size: 15px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.search-row-note {
  overflow: hidden;
  color: var(--muted);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.search-row-date {
  flex: none;
  align-self: flex-start;
  color: var(--muted);
  font-size: 11px;
}

/* Человек, которому ещё не писали: отметка объясняет, почему у него нет
   переписки, — иначе кажется, что строка ведёт в пустоту. */
.search-row-tag {
  flex: none;
  padding: 2px 9px 3px;
  border-radius: 999px;
  background: var(--field);
  color: var(--muted);
  font-size: 11px;
}

/* Совпавшая часть подсвечена: видно, почему строка нашлась — по имени,
   логину или номеру. */
.search-hit {
  background: transparent;
  color: var(--accent);
  font-weight: 600;
}

.search-results .list-state {
  padding: 28px 16px;
  text-align: center;
}

/* ─────────────────────── Список чатов ─────────────────────── */

.chat-list,
.calls-list {
  flex: 1;
  min-height: 0;
  padding: 0 8px 10px;
}

.chat-row,
.call-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 9px 10px;
  border: 0;
  border-radius: 18px;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  transition:
    background-color 160ms ease,
    transform 180ms cubic-bezier(0.22, 1, 0.36, 1),
    filter 180ms ease;
}

/* ─────────────── Черта между строками ───────────────
   Расстояния между строками мало: превью в две строки сливается со
   следующим соседом, и список читается сплошным полотном. Черта еле
   видна и делит строки, а не режет экран линиями — осознанное
   отступление от «никаких рамок» ради плотного списка.

   Живёт черта на нижней строке пары (`+`), а не на верхней: тогда под
   последней строкой её нет и без счёта детей — список дорисовывается
   на ходу, и `:last-child` там врал бы.

   Слева черта начинается там же, где имя: поля строки + аватар + зазор.
   В журнале звонков и в контактах аватар меньше, поэтому отступ свой. */
.chat-row,
.call-row {
  position: relative;
  --row-rule: 68px;
}

.call-row,
.chat-row:has(.avatar-md) { --row-rule: 62px; }

.chat-row + .chat-row::before,
.call-row + .call-row::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: var(--row-rule);
  height: 1px;
  background: var(--hairline);
}

/* У залитой строки черты нет ни сверху, ни снизу: заливка скруглена,
   и черта резала бы ей угол. */
.chat-row.is-active::before,
.chat-row.is-active + .chat-row::before,
.chat-row.is-pressed::before,
.chat-row.is-pressed + .chat-row::before,
.call-row.is-pressed::before,
.call-row.is-pressed + .call-row::before { display: none; }

@media (hover: hover) {
  .chat-row:hover::before,
  .chat-row:hover + .chat-row::before,
  .call-row:hover::before,
  .call-row:hover + .call-row::before { display: none; }
}

/* Строки чатов и звонков продавливаются, как обычные кнопки: список
   разрежённый, соседям это не мешает, а открытие чата ощущается нажатием.
   Плотное меню настроек — другой случай, там масштаб убран. */
.chat-row.is-pressed,
.call-row.is-pressed {
  background: var(--field-strong);
}

.chat-peer.is-pressed:not(:disabled) {
  transform: none;
  filter: none;
  background: var(--field-strong);
}

@media (hover: hover) {
  .chat-row:hover,
  .call-row:hover {
    background: var(--field);
  }
}

.chat-row:focus-visible,
.call-row:focus-visible {
  outline: 0;
  background: var(--field-strong);
}

.chat-main,
.call-row-body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1;
  min-width: 0;
}

.chat-line {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.chat-line-end {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
}

.chat-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.date-chip {
  flex: none;
  color: var(--muted);
  font-size: 11px;
}

.preview {
  display: flex;
  align-items: center;
  gap: 5px;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: 13px;
}

.preview b {
  font-weight: 500;
  color: var(--text-soft);
}

.preview-icon,
.checks {
  width: 15px;
  height: 15px;
  flex: none;
  fill: currentColor;
}

.checks { color: var(--accent); }

/* Цвет и переливание строки «печатает…» описаны ниже, вместе с волной */

.mute-icon {
  width: 15px;
  height: 15px;
  color: var(--muted);
  fill: currentColor;
}

.badge {
  flex: none;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--accent-fill);
  color: var(--accent-fill-text);
  font-size: 11px;
  line-height: 20px;
  text-align: center;
}

.muted .badge {
  background: var(--field-strong);
  color: var(--muted);
}

/* Закреплённый чат: булавка на месте счётчика. Пришли непрочитанные —
   счётчик важнее, булавку он вытесняет. */
.pin-mark {
  flex: none;
  width: 15px;
  height: 15px;
  color: var(--muted);
}

.pin-mark .icon {
  display: block;
  width: 15px;
  height: 15px;
  fill: currentColor;
}

/* Меню строки чата — то же, что у сообщения, но поверх всего приложения:
   на телефоне список занимает весь экран, на компьютере меню может
   выйти за колонку. Ниже экрана звонка (90). Селекторы двойные:
   chat.css подключается позже и при равном весе вернул бы absolute. */
.message-dim.chat-row-dim,
.message-menu.chat-row-menu { position: fixed; }

.message-dim.chat-row-dim { z-index: 70; }
.message-menu.chat-row-menu { z-index: 71; }

.list-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 40px 24px;
  color: var(--muted);
  font-size: 13px;
  text-align: center;
}

.list-state strong {
  color: var(--text);
  font-size: 15px;
}

.list-state .accent-btn { margin-top: 10px; }

/* Журнал звонков */
.calls-panel {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

/* Пока в разделе пусто, подпись стоит сверху, а не прижимается к низу:
   список внутри панели растянут на всю высоту, и без этого «Пока
   никого» оказывалось под ним, у самого края экрана. */
.calls-panel:has(> .list-state:not([hidden])) > .calls-list,
.calls-panel > .calls-list:empty {
  flex: none;
}

.call-row-note {
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--muted);
  font-size: 13px;
}

.call-row.missed .call-row-note { color: var(--accent); }

.call-row-time {
  flex: none;
  color: var(--muted);
  font-size: 11px;
}

/* Чат без сообщений: строка есть, а показывать в ней нечего. */
.preview-empty {
  color: var(--muted);
  font-style: italic;
}
