/* ═════════════════ Sentos · Общая основа экранов ═════════════════
   То, что повторяется на всех экранах после входа: панели, аватары,
   круглые кнопки, поля, строки списков и нижняя навигация. Экранное —
   в sidebar.css, chat.css, composer.css, profile.css и дальше.

   Палитра и сброс живут в base.css и подключаются раньше.
   ═══════════════════════════════════════════════════════════════ */

/* ─────────────────────────── Панели ─────────────────────────── */

.panel {
  position: relative;
  min-height: 0;
  /* Свой тон панели держим переменной: тени и градиенты внутри должны
     растворяться именно в нём, а на телефоне это фон страницы. */
  --panel-bg: var(--panel);
  background: var(--panel-bg);
}

/* ─────────────────────── Каркас приложения ───────────────────────
   На компьютере три колонки: список, переписка и профиль. На телефоне
   одна: переписка выезжает поверх списка, профиль — поверх неё.
   Ширины колонок задаёт touch.css, здесь только общее устройство. */

.messenger {
  display: grid;
  grid-template-columns: 1fr;
  height: 100dvh;
  overflow: hidden;
  /* clip, а не только hidden: скрытые переписка и профиль стоят сдвинутыми
     на 28 точек вправо (смена экранов, touch.css) и выступают за край.
     hidden такое обрезает, но прокручивать себя позволяет — нажатие или
     фокус поля подтягивали приложение вбок на 20 точек. clip прокрутки
     не допускает вовсе; где он не знаком, остаётся hidden. */
  overflow: clip;
}

.panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

/* ─────────────────────────── Смена экранов ───────────────────────────
   Одно движение на все переходы между экранами: вперёд новый экран
   приходит справа с коротким сдвигом и проявляется, прежний гаснет,
   уходя влево; назад — зеркально. Сдвиг в 28 точек — подсказка
   направления, а не перелистывание страницы.

   Уход короче прихода и идёт первым: 110 мс на уход, 230 мс на приход
   после паузы в 70. Экраны почти не стоят друг на друге, и гаснущий не
   просвечивает сквозь приходящий. Те же числа — у переходов экранов
   телефона в touch.css: там экраны переключает класс, и движение
   сделано переходами, а не этими кадрами.

   Кадры задают только начало прихода и конец ухода: другой конец —
   обычный вид элемента. */
@keyframes screen-in-forward {
  from { opacity: var(--in-o, 0); transform: var(--in-t, translateX(28px)); }
}

@keyframes screen-in-back {
  from { opacity: var(--in-o, 0); transform: var(--in-t, translateX(-28px)); }
}

/* Уход начинается с того вида, в котором элемент застали (--out-*):
   недовыехавший список при частых нажатиях иначе вспыхивал до полной
   видимости — у ухода было только «куда», и «откуда» бралось обычное. */
@keyframes screen-out-forward {
  from { opacity: var(--out-o, 1); transform: var(--out-t, none); }
  to { opacity: 0; transform: translateX(-28px); }
}

@keyframes screen-out-back {
  from { opacity: var(--out-o, 1); transform: var(--out-t, none); }
  to { opacity: 0; transform: translateX(28px); }
}

/* ───────────────────────────── Загрузка ─────────────────────────────
   Пока данные идут, на месте будущего содержимого стоит скелетон —
   заливка той же формы, что строки, пузыри или плитки, с тем же
   переливом, что у картинок в ленте (media.css). Виден он становится
   через 200 мс: быстрый ответ сменит его раньше, и заглушка не мелькнёт.
   Уходит скелетон проявлением, и так же проявляется пришедшее —
   см. js/loading.js, числа там те же. */
.skeleton {
  display: flex;
  flex-direction: column;
  pointer-events: none;
  animation: skeleton-in 180ms ease 200ms backwards;
}

.skeleton[hidden] { display: none; }

.skeleton.is-leaving { animation: skeleton-out 160ms ease both; }

.skeleton-fill {
  display: block;
  background: linear-gradient(100deg,
    var(--field-strong) 20%, var(--field) 44%, var(--field-strong) 68%);
  background-size: 220% 100%;
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}

/* Строка — той же высоты и с тем же аватаром, что строка чата: когда
   придут настоящие, ничего не сдвинется. */
.skeleton-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 64px;
  padding: 9px 10px;
}

.skeleton-avatar {
  flex: none;
  width: 46px;
  height: 46px;
  border-radius: 50%;
}

.skeleton-lines {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 9px;
}

.skeleton-line {
  width: 46%;
  height: 12px;
  border-radius: 999px;
}

.skeleton-line + .skeleton-line {
  width: 72%;
  height: 10px;
}

/* Разная длина — иначе заглушка читается решёткой, а не списком. */
.skeleton-row:nth-child(3n+2) .skeleton-line { width: 34%; }
.skeleton-row:nth-child(3n+2) .skeleton-line + .skeleton-line { width: 58%; }
.skeleton-row:nth-child(3n) .skeleton-line { width: 54%; }
.skeleton-row:nth-child(3n) .skeleton-line + .skeleton-line { width: 80%; }

/* Переписка: пузыри той же высоты и скругления, свои — справа. */
.skeleton-feed { gap: 7px; }

.skeleton-bubble {
  width: 52%;
  height: 38px;
  border-radius: 18px;
}

.skeleton-bubble:nth-child(3n+2) { width: 38%; }
.skeleton-bubble:nth-child(3n) { width: 64%; }
.skeleton-bubble:nth-child(4n+3),
.skeleton-bubble:nth-child(4n) { align-self: flex-end; }

/* Вложения в профиле: плитки той же сетки. */
.skeleton.skeleton-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
}

.skeleton-tile {
  aspect-ratio: 1;
  border-radius: 18px;
}

/* Пришедшее проявляется, а не возникает рывком на месте заглушки. */
.is-arriving > :not(.skeleton) { animation: content-arrive 220ms ease backwards; }

@keyframes skeleton-in {
  from { opacity: 0; }
}

@keyframes skeleton-out {
  to { opacity: 0; }
}

@keyframes skeleton-shimmer {
  50% { background-position: 100% 0; }
}

@keyframes content-arrive {
  from { opacity: 0; }
}

/* ─────────────────────────── Аватары ─────────────────────────── */

/* overflow не режем — это требование контракта: рабочий код кладёт точку
   «в сети» прямо внутрь аватара (`<span class="avatar">Б<i
   class="online-dot"></i></span>`), и с `hidden` её срезало бы по кругу.
   Фотографию круглит её собственный радиус. */
.avatar {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  overflow: visible;
  background: var(--field-strong);
  color: var(--muted);
  font-size: 15px;
  font-weight: 600;
}

/* «Избранное»: звезда на акцентной заливке — единственный чат без лица,
   и узнают его по значку. */
.avatar.avatar-saved {
  background: var(--accent-fill);
  color: var(--accent-fill-text);
}

.avatar.avatar-saved .icon {
  width: 52%;
  height: 52%;
}

/* Фотография лежит поверх аватара, а не в его сетке. В сетке с
   place-items: center картинка не растягивается на ячейку, и её
   height: 100% не разрешается вовсе: получалось 84 px в ширину и 126 в
   высоту. Пока аватар обрезал лишнее, этого не было видно — с
   overflow: visible оно вылезло наружу. */
.avatar img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  -webkit-user-drag: none;
}

.avatar-sm { width: 34px; height: 34px; font-size: 13px; }
.avatar-md { width: 40px; height: 40px; font-size: 15px; }
.avatar-lg { width: 84px; height: 84px; font-size: 28px; }

/* Точка «в сети» лежит либо на обёртке (наша разметка), либо прямо в
   аватаре — так её рисует рабочий код. Оформление у обеих одно. */
.avatar-wrap {
  position: relative;
  flex: none;
}

.avatar-wrap > .online-dot,
.avatar > .online-dot {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--online);
  box-shadow: 0 0 0 2.5px var(--panel);
}

/* ─────────────────────── Круглые кнопки ─────────────────────── */

.icon-btn {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  flex: none;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--text-soft);
  transition:
    background-color 160ms ease,
    color 160ms ease,
    transform 180ms cubic-bezier(0.22, 1, 0.36, 1),
    filter 180ms ease;
}

.icon-btn .icon {
  display: block;
  width: 22px;
  height: 22px;
  fill: currentColor;
}

.icon-btn.is-pressed:not(:disabled) {
  transform: scale(0.9);
}

/* Стрелка «назад» на своей подложке: голая стрелка на фоне переписки
   теряется и не читается как кнопка. */
.icon-btn.on-surface {
  background: var(--field);
  color: var(--text);
}

.icon-btn.on-surface.is-pressed:not(:disabled) {
  background: var(--field-strong);
}

@media (hover: hover) {
  .icon-btn:hover {
    background: var(--field);
    color: var(--text);
  }
}

.icon-btn:focus-visible {
  outline: 0;
  background: var(--brand-50);
  color: var(--brand-700);
}

.dark .icon-btn:focus-visible {
  background: var(--brand-950);
  color: var(--brand-500);
}

/* Главная кнопка — заливка акцентом */
.accent-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 22px;
  border: 0;
  border-radius: 999px;
  background: var(--brand-work);
  color: #fff;
  font-size: 15px;
  font-weight: 500;
  transition:
    background-color 160ms ease,
    transform 180ms cubic-bezier(0.22, 1, 0.36, 1),
    filter 180ms ease;
}

.dark .accent-btn {
  background: var(--accent-fill);
  color: var(--accent-fill-text);
}

.accent-btn.is-pressed:not(:disabled) {
  transform: scale(0.97);
}

/* ─────────────────────── Поля и поиск ─────────────────────── */

.field-shell {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 0 14px;
  border-radius: 999px;
  background: var(--field);
  color: var(--muted);
  transition: background-color 160ms ease;
}

/* Никакой подсветки акцентом по фокусу: поле и так заметное, а вспышка
   оранжевым на каждое касание отвлекает — так же, как у поля ввода
   сообщения.

   Заливку меняем только для клавиатурного фокуса: обводки в проекте
   запрещены, и без неё было бы не видно, где стоит курсор при обходе по
   Tab. Класс ставит core.js — родительского селектора у нас нет. */
.field-shell.is-key-focus {
  background: var(--field-strong);
}

.field-shell .icon {
  width: 18px;
  height: 18px;
  flex: none;
  fill: currentColor;
}

.field-shell input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 15px;
}

/* Подсказка не исчезает рывком: при фокусе она растворяется, при уходе
   из пустого поля так же плавно возвращается — как в поле ввода
   сообщения. Растворяем цветом, а не прозрачностью: opacity у
   ::placeholder анимируют не все браузеры. */
.field-shell input::placeholder {
  color: var(--muted);
  transition: color 220ms ease;
}

.field-shell input:focus::placeholder {
  color: transparent;
}

/* ─────────────────────── Строки-списки ─────────────────────── */

.list-group {
  border-radius: 22px;
  overflow: hidden;
  background: var(--panel);
}

.list-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 52px;
  padding: 10px 16px;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 15px;
  text-align: left;
  text-decoration: none;
  transition:
    background-color 160ms ease,
    transform 180ms cubic-bezier(0.22, 1, 0.36, 1),
    filter 180ms ease;
}

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

   :not(:disabled) здесь не для фильтрации, а чтобы перебить общее
   правило продавливания из styles.css — оно описано как
   button.is-pressed:not(:disabled) и иначе выигрывает по важности. */
.list-row.is-pressed:not(:disabled),
.nav-item.is-pressed:not(:disabled) {
  transform: none;
  filter: none;
}

.list-row.is-pressed:not(:disabled) {
  background: var(--field-strong);
}

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

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

/* Плашка иконки круглая — квадраты спорили со скруглением строк и групп */
.list-row-icon {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: none;
  border-radius: 50%;
  color: #fff;
}

.list-row-icon .icon {
  width: 19px;
  height: 19px;
  fill: currentColor;
}

/* У «выйти» рисунок в своём квадрате сдвинут вправо — выравниваем на глаз */
.list-row.is-danger .list-row-icon .icon {
  transform: translateX(-1.5px);
}

.list-row-text {
  flex: 1;
  min-width: 0;
}

.list-row-note {
  flex: none;
  color: var(--muted);
  font-size: 13px;
}

.list-row-chevron {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--muted);
  fill: currentColor;
}

.list-caption {
  margin: 0 0 8px;
  padding: 0 18px;
  color: var(--muted);
  font-size: 12px;
}

/* ─────────────────────── Нижняя навигация ─────────────────────── */

/* Панель не приклеена к краям: небольшой отступ и скругление отделяют
   её от экрана и от нижней кромки телефона. */
.bottom-nav {
  position: relative;
  display: none;
  flex: none;
  align-items: stretch;
  gap: 2px;
  margin: 4px 10px calc(10px + env(safe-area-inset-bottom));
  padding: 4px 6px;
  /* Панель — овал целиком: скругление больше её половины высоты, и
     форма перестаёт зависеть от того, какой она высоты. */
  border-radius: 999px;
  background: var(--field);
}

/* Подсветка активного раздела — отдельная плашка, которая переезжает
   между пунктами. Так переключение читается как движение, а не как
   мигание в двух местах сразу. */
.nav-pill {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 0;
  width: 58px;
  border-radius: 999px;
  background: var(--accent-soft);
  transform: translateX(var(--pill-x, 0px));
  transition: transform 360ms cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}

/* До первой расстановки плашку не показываем, иначе она проедет из угла */
.bottom-nav:not(.is-ready) .nav-pill { opacity: 0; }

.bottom-nav a,
.bottom-nav button {
  position: relative;
  z-index: 1;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-height: 50px;
  padding: 4px 0;
  border: 0;
  /* Скругление как у самой панели: иначе пункт выглядит квадратной
     вставкой внутри овала. */
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 10px;
  text-decoration: none;
  transition:
    color 160ms ease,
    background-color 160ms ease,
    transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
}

.bottom-nav .icon {
  width: 23px;
  height: 23px;
  fill: currentColor;
}

/* Единственная подсветка — переезжающая плашка, поэтому у самих
   пунктов заливки нет ни в покое, ни при нажатии. */
.bottom-nav .active {
  color: var(--accent);
}

.bottom-nav .is-pressed {
  background: transparent;
}

/* Пункт нижней панели продавливается, как кнопка: значок с подписью
   уходят вглубь, плашка под ними — отдельная и не сжимается. Раньше
   отклика не было вовсе (общее правило .nav-item его снимало). */
.bottom-nav .nav-item.is-pressed:not(:disabled) {
  transform: scale(0.94);
  filter: none;
}

.nav-badge {
  position: absolute;
  top: 0;
  left: 50%;
  margin-left: 7px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--accent-fill);
  color: var(--accent-fill-text);
  font-size: 10px;
  line-height: 15px;
}

.nav-item {
  position: relative;
}

/* ─────────────────────── Логотип ─────────────────────── */

.brand-link {
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  gap: 8px;
  color: var(--text);
  text-decoration: none;
}

/* В шапке стоит сам знак, а не буква: круг у него свой, поэтому ни
   заливки, ни шрифтовых правил ему не нужно. На экране входа знак
   по-прежнему буквенный. */
img.brand-mark {
  background: none;
  object-fit: contain;
}

.brand-mark {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: none;
  border-radius: 9999px;
  background: var(--brand-500);
  color: #fff;
  font-family: "SF Pro Display", "SF Pro Text", sans-serif;
  font-size: 15px;
  font-weight: 600;
}

/* ─────────────────── Кнопка без заливки ───────────────────
   Ссылка по смыслу, кнопка по разметке: «Зарегистрироваться»,
   «Продолжить в браузере», «Найти человека». */

.text-btn {
  display: inline-flex;
  align-items: center;
  padding: 0 4px;
  border-radius: 9999px;
  background: transparent;
  color: var(--accent);
  font-size: 13px;
  font-weight: 500;
}

@media (hover: hover) {
  .text-btn:hover { color: var(--brand-600); }
}

.text-btn:focus-visible {
  background: var(--accent-soft);
  color: var(--accent);
}

/* Аватар на экране звонка: единственное место, где он крупнее
   карточки профиля — портрет виден во весь экран. */
.avatar-xl {
  width: 112px;
  height: 112px;
  font-size: 38px;
}
