/* ==========================================================================
   Стекло — слой оформления
   ==========================================================================

   Отдельный файл не из прихоти, а потому что styles.css за десять
   месяцев покрыл всё подряд и правила разошлись: одна и та же кнопка
   описана в трёх местах, стекло лепят��и вручную в каждом экране, и
   правка одного угла тянула за собой весь файл.

   Здесь — одна система. Токены, стеклянные поверхности, компоненты.
   Подключается после styles.css, поэтому перекрывает его, ничего из
   старого не ломая: каждый блок ниже меняет вид, но не поведение.

   Порядок правил важен: токены → фон → поверхности → компоненты →
   частности. Каскад вниз.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Токены стекла
   -------------------------------------------------------------------------- */

:root {
  /* Толщина стекла. Чем толще слой, тем больше размытия и меньше
     прозрачности — как в iOS, где материал зависит от высоты. */
  --g-blur:   28px;
  --g-blur-2: 18px;
  --g-blur-3: 44px;
  --g-sat:    180%;

  /* Подложка под стеклом. В тёмной теме она чуть светлее фона — стекло
     должно читаться слоем над подложкой, а не дырой в темноте. */
  --g-tint:        rgba(255,255,255,.055);
  --g-tint-strong: rgba(255,255,255,.085);
  --g-tint-soft:   rgba(255,255,255,.032);

  /* Кромка стекла: у iOS она всегда светлее заливки и ловит блик
     сверху. Без неё стекло выглядит серой пятном. */
  --g-edge:      rgba(255,255,255,.14);
  --g-edge-soft: rgba(255,255,255,.08);
  --g-edge-lit:  rgba(255,255,255,.32);

  /* Тень стекла. Мягкая и широкая: стекло не лежит на поверхности,
     а висит над ней. */
  --g-sh-1: 0 2px 10px rgba(0,0,0,.28);
  --g-sh-2: 0 10px 30px rgba(0,0,0,.34);
  --g-sh-3: 0 22px 60px rgba(0,0,0,.46);

  /* Скругления: iOS держит их крупными и одинаковыми по ритму. */
  --g-r-sm: 12px;
  --g-r:    18px;
  --g-r-lg: 24px;
  --g-r-xl: 32px;

  /* Анимация. Один токен на всё движение — иначе интерфейс дёргается
     разными кривыми и собирается ощущение «склеенного». */
  --g-ease: cubic-bezier(.32,.72,0,1);
  --g-fast: .18s;
  --g-med:  .32s;
}

[data-theme="light"] {
  /* В светлой теме стекло работает наоборот: тёмная подложка под ним
     даёт глубину, а светлая кромка — блик. Поэтому здесь tint темнее,
     а край светлее. Один и тот же токен в двух темах даёт разный
     результат — это и нужно. */
  --g-tint:        rgba(255,255,255,.72);
  --g-tint-strong: rgba(255,255,255,.86);
  --g-tint-soft:   rgba(255,255,255,.55);

  --g-edge:      rgba(10,10,20,.10);
  --g-edge-soft: rgba(10,10,20,.06);
  --g-edge-lit:  rgba(255,255,255,.95);

  --g-sh-1: 0 1px 3px rgba(20,20,50,.07);
  --g-sh-2: 0 8px 24px rgba(20,20,50,.10);
  --g-sh-3: 0 20px 48px rgba(20,20,50,.16);
}

/* --------------------------------------------------------------------------
   2. Фон: живой градиент
   --------------------------------------------------------------------------

   Раньше фон был просто тёмной заливкой. Из-за этого стеклу не на
   что было преломлять свет: размывать нечего, и плашки выглядели
   серыми прямоугольниками.

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

   Один слой вместо двух: четыре пятна и виньетка — это пять
   радиальных градиентов в одной фоновой картинке. Два отдельных
   слоя требовали бы двух слоёв композитора и двойной работы при
   прокрутке, а разницы не видно.
   -------------------------------------------------------------------------- */

.app {
  position: relative;
  background: var(--bg);
  isolation: isolate;
}
.app::before {
  content: '';
  position: absolute;
  inset: -20%;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(46% 40% at 16% 6%,  rgba(124,92,255,.50) 0%, transparent 70%),
    radial-gradient(44% 40% at 88% 20%, rgba(255,77,141,.36) 0%, transparent 70%),
    radial-gradient(50% 42% at 84% 92%, rgba(37,244,238,.24) 0%, transparent 72%),
    radial-gradient(42% 38% at 6% 78%,  rgba(47,214,168,.18) 0%, transparent 70%),
    radial-gradient(130% 90% at 50% 0%, transparent 58%, rgba(0,0,0,.30) 100%);
  animation: gDrift 38s var(--g-ease) infinite alternate;
}
[data-theme="light"] .app::before {
  background:
    radial-gradient(46% 40% at 16% 6%,  rgba(124,92,255,.30) 0%, transparent 70%),
    radial-gradient(44% 40% at 88% 20%, rgba(255,77,141,.22) 0%, transparent 70%),
    radial-gradient(50% 42% at 84% 92%, rgba(37,244,238,.18) 0%, transparent 72%),
    radial-gradient(42% 38% at 6% 78%,  rgba(47,214,168,.14) 0%, transparent 70%),
    radial-gradient(130% 90% at 50% 0%, transparent 60%, rgba(20,20,50,.08) 100%);
}

@keyframes gDrift {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(3%, -2.5%, 0) scale(1.09); }
}

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

/* --------------------------------------------------------------------------
   3. Стеклянные поверхности
   -------------------------------------------------------------------------- */

/* Базовое стекло. Всё, что хочет выглядеть стеклом, берёт эти свойства
   отсюда, а не пишет backdrop-filter заново. */
.glass,
.g-surface {
  position: relative;
  background: var(--g-tint);
  -webkit-backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  border: 1px solid var(--g-edge-soft);
  border-radius: var(--g-r);
  box-shadow: var(--g-sh-2);
}

/* Блик по верхней кромке: тонкая светлая полоса в один пиксель.
   Именно она отличает стекло от полупрозрачного пластика. */
.glass::before,
.g-surface::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--g-edge-lit) 22%, var(--g-edge-lit) 78%, transparent);
  border-radius: inherit;
  pointer-events: none;
}

/* Поверхности по плотности. */
.g-surface--thin { background: var(--g-tint-soft); }
.g-surface--deep { background: var(--g-tint-strong); border-color: var(--g-edge); }

/* Стекло без backdrop-filter выглядит как серый прямоугольник —
   поэтому ему нужна непрозрачная заливка, иначе читаемость падает
   до unusable. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass, .g-surface {
    background: var(--surface-2);
    border-color: var(--g-edge);
  }
}

/* --------------------------------------------------------------------------
   4. Кнопки
   --------------------------------------------------------------------------

   Кнопка в iOS — не заливка, а капсула со стеклом и тонкой рамкой.
   Главное отличие от прежней: у неё появилась глубина (тень) и
   блик, и нажатие сжимает её мягко, а не до 97.5% — мелочь, но
   именно по ней рука узнаёт интерфейс как «живой».
   -------------------------------------------------------------------------- */

.btn {
  position: relative;
  overflow: hidden;
  height: 50px;
  border-radius: var(--g-r);
  font-weight: 700;
  letter-spacing: -.2px;
  background: var(--g-tint-strong);
  color: var(--text);
  border: 1px solid var(--g-edge);
  -webkit-backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  box-shadow: var(--g-sh-1), inset 0 1px 0 var(--g-edge-lit);
  transition: transform var(--g-fast) var(--g-ease),
              filter var(--g-fast) var(--g-ease),
              opacity var(--g-fast);
}
.btn:active { transform: scale(.97); filter: brightness(1.12); }
.btn svg { width: 19px; height: 19px; }

/* Блик, который пробегает по кнопке при нажатии: короткая вспышка
   от верхнего края. Без неё нажатие на стекле не читается. */
.btn::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, var(--g-edge-lit), transparent 60%);
  opacity: .5;
  pointer-events: none;
}

.btn--primary {
  background: var(--grad);
  border-color: transparent;
  color: #fff;
  box-shadow: 0 10px 26px rgba(124,92,255,.34), inset 0 1px 0 rgba(255,255,255,.3);
}

.btn--ghost {
  background: var(--g-tint-soft);
  border-color: var(--g-edge);
  color: var(--muted);
}
.btn--ghost::after { opacity: .35; }

.btn--soft {
  background: var(--grad-soft);
  color: #cdbdff;
  border-color: rgba(124,92,255,.34);
}

.btn--ok {
  background: rgba(47,214,168,.16);
  color: var(--ok);
  border-color: rgba(47,214,168,.34);
}

.btn--danger {
  background: rgba(255,79,94,.14);
  color: var(--danger);
  border-color: rgba(255,79,94,.32);
}

.btn--block { width: 100%; }
.btn--sm {
  height: 38px;
  padding: 0 15px;
  font-size: 13px;
  border-radius: var(--g-r-sm);
}

/* Кнопка из стекла вовсе без заливки.
   Главное действие профиля раньше красилось сплошным градиентом —
   в стеклянном интерфейсе это единственное пятно, которое
   выбивается и притягивает взгляд сильнее, чем сам профиль.
   Теперь оно отличается толщиной стекла и рамкой, а не цветом. */
.btn--glass {
  background: var(--g-tint);
  border-color: var(--g-edge);
  color: var(--text);
  -webkit-backdrop-filter: blur(var(--g-blur)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur)) saturate(var(--g-sat));
  box-shadow: var(--g-sh-2), inset 0 1px 0 var(--g-edge-lit);
}
.btn--glass::after { opacity: .6; }

/* --------------------------------------------------------------------------
   5. Поля ввода
   --------------------------------------------------------------------------

   Поле — не серый прямоугольник, а стеклянная лента, у которой при
   фокусе зажигается кромка. Раньше фокус давал только смену цвета
   рамки, и на телефоне было не видно, какое поле сейчас набирают.
   -------------------------------------------------------------------------- */

.input, .textarea, .select {
  background: var(--g-tint-soft);
  border: 1px solid var(--g-edge-soft);
  border-radius: var(--g-r-sm);
  color: var(--text);
  -webkit-backdrop-filter: blur(var(--g-blur-2));
  backdrop-filter: blur(var(--g-blur-2));
  box-shadow: inset 0 1px 2px rgba(0,0,0,.12);
  transition: border-color var(--g-fast) var(--g-ease),
              box-shadow var(--g-fast) var(--g-ease),
              background var(--g-fast) var(--g-ease);
}
.input:focus, .textarea:focus, .select:focus {
  border-color: var(--accent);
  background: var(--g-tint);
  box-shadow: 0 0 0 4px rgba(124,92,255,.16), inset 0 1px 2px rgba(0,0,0,.12);
}
[data-theme="light"] .input,
[data-theme="light"] .textarea,
[data-theme="light"] .select {
  box-shadow: inset 0 1px 2px rgba(20,20,50,.06);
}

.field__label b { letter-spacing: -.2px; }

/* --------------------------------------------------------------------------
   6. Мелкие элементы: плашки, чипы, кнопки-капсулы
   -------------------------------------------------------------------------- */

.pill {
  background: var(--g-tint-strong);
  border: 1px solid var(--g-edge-soft);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  padding: 5px 11px;
}

.chip {
  background: var(--g-tint);
  border: 1px solid var(--g-edge-soft);
  -webkit-backdrop-filter: blur(var(--g-blur-2));
  backdrop-filter: blur(var(--g-blur-2));
  transition: transform var(--g-fast) var(--g-ease),
              background var(--g-fast) var(--g-ease),
              border-color var(--g-fast) var(--g-ease),
              color var(--g-fast) var(--g-ease);
}
.chip.is-active {
  background: var(--grad-soft);
  color: #c9b8ff;
  border-color: rgba(124,92,255,.5);
  box-shadow: 0 4px 14px rgba(124,92,255,.2);
}
.chip:active { transform: scale(.95); }

.mini-btn {
  background: var(--g-tint-strong);
  border: 1px solid var(--g-edge-soft);
  -webkit-backdrop-filter: blur(var(--g-blur-2));
  backdrop-filter: blur(var(--g-blur-2));
  border-radius: 11px;
  transition: transform var(--g-fast) var(--g-ease), filter var(--g-fast);
}
.mini-btn:active { transform: scale(.95); }

/* --------------------------------------------------------------------------
   7. Иконка-кнопка
   -------------------------------------------------------------------------- */

.icon-btn {
  background: var(--g-tint-strong);
  border: 1px solid var(--g-edge-soft);
  -webkit-backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  box-shadow: var(--g-sh-1), inset 0 1px 0 var(--g-edge-lit);
  transition: transform var(--g-fast) var(--g-ease), filter var(--g-fast);
}
.icon-btn:active { transform: scale(.92); filter: brightness(1.15); }

/* --------------------------------------------------------------------------
   8. Разделы и заголовки
   -------------------------------------------------------------------------- */

.sec { padding: 4px 16px 18px; }

.sec__h { align-items: center; margin: 10px 2px 12px; }
.sec__h b { letter-spacing: -.3px; font-weight: 800; }
.sec__h--sub b { text-transform: uppercase; letter-spacing: .05em; }

/* --------------------------------------------------------------------------
   9. Карточки
   --------------------------------------------------------------------------

   Три карточки приложения — bcard (люди), my-work (свои работы),
   adm-card (модерация) — раньше отличались только цветом рамки и
   выглядели тремя разными предметами. Стекло и одинаковый ритм
   скруглений делают их одним семейством, и экран перестаёт пёстро
   мельтешить.
   -------------------------------------------------------------------------- */

.bcard,
.my-work,
.adm-card,
.chat-row {
  background: var(--g-tint);
  -webkit-backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  border: 1px solid var(--g-edge-soft);
  border-radius: var(--g-r);
  box-shadow: var(--g-sh-1), inset 0 1px 0 var(--g-edge-lit);
  transition: transform var(--g-fast) var(--g-ease),
              box-shadow var(--g-fast) var(--g-ease),
              border-color var(--g-fast) var(--g-ease);
}
.bcard:active,
.my-work:active,
.chat-row:active {
  transform: scale(.985);
  border-color: var(--g-edge);
  box-shadow: var(--g-sh-2), inset 0 1px 0 var(--g-edge-lit);
}

/* Карточка модерации — рабочий инструмент, а не витрина: она должна
   читаться плотнее и без «эффекта витрины», иначе в списке из
   тридцати работ ничего не найти. */
.adm-card {
  background: var(--g-tint);
  -webkit-backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  border-color: var(--g-edge);
  border-radius: var(--g-r);
  box-shadow: var(--g-sh-1), inset 0 1px 0 var(--g-edge-lit);
  transition: transform var(--g-fast) var(--g-ease),
              box-shadow var(--g-fast) var(--g-ease),
              border-color var(--g-fast) var(--g-ease);
}
.adm-card.is-new {
  border-color: rgba(124,92,255,.4);
  box-shadow: var(--g-sh-1), 0 0 0 3px rgba(124,92,255,.12);
}

/* --------------------------------------------------------------------------
   10. Меню настроек
   -------------------------------------------------------------------------- */

.menu {
  background: var(--g-tint);
  -webkit-backdrop-filter: blur(var(--g-blur)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur)) saturate(var(--g-sat));
  border: 1px solid var(--g-edge-soft);
  border-radius: var(--g-r);
  box-shadow: var(--g-sh-2), inset 0 1px 0 var(--g-edge-lit);
  overflow: hidden;
}

/* Разделитель между пунктами — не линия, а выемка: тонкая тень сверху
   даёт ощущение, что пункт «лежит» на стекле. */
.menu__i { border-bottom: 1px solid var(--g-edge-soft); }
.menu__i:last-child { border-bottom: 0; }
.menu__i:active { background: var(--g-tint-strong); }

.set-group {
  background: var(--g-tint);
  -webkit-backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  border: 1px solid var(--g-edge-soft);
  border-radius: var(--g-r);
  box-shadow: var(--g-sh-1), inset 0 1px 0 var(--g-edge-lit);
}

/* Заголовок группы. Раньше он начинался вплотную к верхней кромке
   и обрезался: буквы верхнего регистра упирались в рамку и строка
   читалась как «ДВИЖЕНИЕЗА СУТКИ». */
.set-group__h {
  padding: 11px 13px 7px;
  letter-spacing: .07em;
}

/* --------------------------------------------------------------------------
   11. Таб-бар
   --------------------------------------------------------------------------

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

.tabbar {
  background: var(--g-tint);
  -webkit-backdrop-filter: blur(var(--g-blur-3)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-3)) saturate(var(--g-sat));
  border-top: 1px solid var(--g-edge-soft);
  box-shadow: 0 -8px 30px rgba(0,0,0,.28);
}
[data-theme="light"] .tabbar { box-shadow: 0 -8px 30px rgba(20,20,50,.1); }

.tab.is-active { color: var(--text); }
.tab.is-active svg {
  background: var(--grad-soft);
  border-radius: 12px;
  box-shadow: inset 0 1px 0 var(--g-edge-lit);
}

/* --------------------------------------------------------------------------
   12. Пустые состояния
   -------------------------------------------------------------------------- */

.empty__ico {
  background: var(--g-tint-strong);
  border: 1px solid var(--g-edge-soft);
  -webkit-backdrop-filter: blur(var(--g-blur-2));
  backdrop-filter: blur(var(--g-blur-2));
  box-shadow: inset 0 1px 0 var(--g-edge-lit);
  color: var(--muted);
}

/* Скелет загрузки должен быть стеклянным, а не серым: на тёмном фоне
   серый скелет выглядит как грязное пятно. */
.card-skeleton, .sk {
  background: var(--g-tint-soft);
  border-color: var(--g-edge-soft);
  border-radius: var(--g-r);
}
.sk {
  background-image: linear-gradient(90deg,
    transparent 0%, var(--g-tint-strong) 45%, transparent 90%);
  background-size: 300% 100%;
  animation: gSk 1.4s infinite linear;
}
@keyframes gSk { 0% { background-position: 120% 0; } 100% { background-position: -60% 0; } }

/* --------------------------------------------------------------------------
   13. Плашки загрузки и уведомления
   -------------------------------------------------------------------------- */

.notice {
  background: var(--g-tint-strong);
  -webkit-backdrop-filter: blur(var(--g-blur-3)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-3)) saturate(var(--g-sat));
  border: 1px solid var(--g-edge);
  border-radius: var(--g-r);
  box-shadow: var(--g-sh-3), inset 0 1px 0 var(--g-edge-lit);
}

/* --------------------------------------------------------------------------
   14. Аватары
   --------------------------------------------------------------------------
   Единая рамка: аватар в карточке, в шапке и в чате должны выглядеть
   как одно и то же, иначе интерфейс читается как набор макетов.
   -------------------------------------------------------------------------- */

.avatar {
  border: 1px solid var(--g-edge);
  box-shadow: var(--g-sh-1);
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   15. Каркас: пустить пятна внутрь приложения
   --------------------------------------------------------------------------

   Собственная заливка у .app была главной причиной, по которой стекло
   не читалось: под ним была ровная заливка, размывать нечего, и все
   плашки выглядели серыми прямоугольниками. Теперь .app прозрачный,
   и под ним — живой фон из пятен, который стекло преломляет.
   -------------------------------------------------------------------------- */

.app {
  background: var(--bg);
  isolation: isolate;
}
.screen, .tabbar { z-index: 1; }

/* Стеклянная шапка, которая прилипает при прокрутке: раньше она
   заливала экран цветом фона и просто отрезала полосу фона у списка.
   Теперь она стеклянная и список уходит под неё по-настоящему. */
.screen__head--sticky {
  background: var(--g-tint-soft);
  -webkit-backdrop-filter: blur(var(--g-blur)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur)) saturate(var(--g-sat));
  border-bottom: 1px solid var(--g-edge-soft);
  box-shadow: 0 8px 24px rgba(0,0,0,.18);
}
[data-theme="light"] .screen__head--sticky { box-shadow: 0 8px 24px rgba(20,20,50,.08); }

/* Отдельного слоя под виньетку больше нет: она стала пятым
   градиентом в .app::above. Лишний слой поверх списка значил бы ещё
   одну композицию при каждой прокрутке ради эффекта, который
   заметен только на краях экрана. */
.screen, .tabbar { z-index: 1; }

/* --------------------------------------------------------------------------
   16. Анимации
   --------------------------------------------------------------------------

   Правило, которому подчинено всё остальное: анимация должна
   объяснять, что произошло, и стоить не больше 300 мс. Всё, что
   дольше, мешает жестам — палец уже отпустил, а картинка ещё едет.
   -------------------------------------------------------------------------- */

/* Появление экрана. Раньше был только fade + 6px вверх; теперь
   появление идёт снизу и с лёгким масштабом — так переход читается
   как «шаг вперёд», а не как «перерисовали». */
.screen.is-active { animation: gScreenIn var(--g-med) var(--g-ease); }
@keyframes gScreenIn {
  from { opacity: 0; transform: translateY(10px) scale(.994); }
  to   { opacity: 1; transform: none; }
}

/* Появление содержимого списка. Каждый пункт с задержкой по индексу:
   список собирается сверху вниз, и глаз сразу видит верх, а не
   середину. Задержка копится через CSS-переменную --i. */
.g-stagger > * {
  animation: gRise .42s var(--g-ease) backwards;
  animation-delay: calc(var(--i, 0) * 38ms);
}
@keyframes gRise {
  from { opacity: 0; transform: translateY(14px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* Нажатие: короткое сжатие с отдачей. Без отдачи нажатие ощущается
   как залипание, интерфейс кажется неотзывчивым. */
.g-press { transition: transform var(--g-fast) var(--g-ease); }
.g-press:active { transform: scale(.94); }

/* Пульс «звонят». Три расходящихся кольца — как в iOS, и их видно
   даже не глядя: по ритму понятно, что это звонок. */
.g-pulse { position: relative; }
.g-pulse::before,
.g-pulse::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 2px solid var(--accent);
  animation: gPulse 2.1s var(--g-ease) infinite;
  pointer-events: none;
}
.g-pulse::after { animation-delay: .7s; }
@keyframes gPulse {
  0%   { opacity: .75; transform: scale(1); }
  100% { opacity: 0;   transform: scale(1.75); }
}

/* Мерцание нового: в модерации и в ленте, где важно не пропустить
   только что появившееся. */
@keyframes gGlow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(124,92,255,.0), var(--g-sh-1); }
  50%      { box-shadow: 0 0 0 4px rgba(124,92,255,.22), var(--g-sh-1); }
}
.g-glow { animation: gGlow 2.4s var(--g-ease) infinite; }

/* Живой индикатор записи: точка дышит, пока идёт запись голоса. */
@keyframes gBreath {
  0%, 100% { opacity: .35; transform: scale(.85); }
  50%      { opacity: 1;   transform: scale(1); }
}
.g-breath { animation: gBreath 1.25s var(--g-ease) infinite; }

/* Отправка: сообщение уходит вверх и растворяется — так человек
   понимает, что действие выполнено, ещё до ответа сервера. */
@keyframes gSend {
  0%   { opacity: 1;   transform: none; }
  100% { opacity: 0;   transform: translateY(-14px) scale(.96); }
}
.g-send { animation: gSend .28s var(--g-ease) forwards; }

/* Входящее сообщение: приезжает снизу с подъёмом. */
@keyframes gIn {
  from { opacity: 0; transform: translateY(12px) scale(.98); }
  to   { opacity: 1; transform: none; }
}

/* Переход между вкладками: точка под активной иконкой едет, а не
   прыгает. Меняем --i у навигатора — точка едет одним движением. */
.g-dot {
  position: absolute;
  bottom: 4px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--grad);
  box-shadow: 0 0 10px rgba(124,92,255,.7);
  transition: transform var(--g-med) var(--g-ease);
  transform: translateX(calc(var(--i, 0) * var(--tab-step, 0px)));
}

/* --------------------------------------------------------------------------
   17. Голосовой звонок
   --------------------------------------------------------------------------

   Экран переделан под то, что в нём есть: голос. Кадра нет, поэтому
   главное — чтобы человек поверил, что связь идёт. Отсюда пульс
   аватара, таймер длительности и полоса микрофона.
   -------------------------------------------------------------------------- */

.callbox {
  text-align: center;
  padding: 8px 0 4px;
}
.callbox__ava {
  position: relative;
  width: 118px;
  height: 118px;
  margin: 0 auto 18px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 38px;
  font-weight: 800;
  color: #fff;
  background: var(--grad);
  box-shadow: 0 18px 46px rgba(124,92,255,.42), inset 0 1px 0 var(--g-edge-lit);
}
.callbox__ini { position: relative; z-index: 2; }

/* Таймер: цифры моноширинным шрифтом, иначе двоеточие «прыгает»
   каждую секунду и время невозможно прочесть. */
.callclock {
  margin-top: 14px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .12em;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* Полоса микрофона. Ширина задаётся из JS через --lv. */
.calllevel {
  width: 190px;
  height: 5px;
  margin: 12px auto 4px;
  border-radius: 999px;
  background: var(--g-tint-strong);
  overflow: hidden;
  border: 1px solid var(--g-edge-soft);
}
.calllevel > i {
  display: block;
  height: 100%;
  width: var(--lv, 0%);
  border-radius: 999px;
  background: linear-gradient(90deg, var(--ok), var(--accent) 60%, var(--accent-2));
  transition: width .1s linear;
}

/* Выключенный микрофон должен читаться сразу, без чтения подписи. */
.btn--soft.is-off {
  color: var(--danger);
  border-color: rgba(255,79,94,.4);
  background: rgba(255,79,94,.12);
}

/* --------------------------------------------------------------------------
   20. Значки ролей
   --------------------------------------------------------------------------

   Раньше «МОДЕРАЦИЯ» и «ПРОВЕРЕН» были одного калибра с именем
   человека и стояли рядом с ним же, из-за чего глаз цеплялся не за
   человека, а за плашки под ним: в списке из двадцати друзей
   строка выглядела как новогодняя гирлянда.

   Теперь роль — тихая подпись, а человек остаётся главным. Галочка
   проверки наоборот остаётся единственной яркой меткой: она и
   должна быть видна, ради неё список и читают.
   -------------------------------------------------------------------------- */

.bcard__badge {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: none;
  padding: 2px 7px;
  border-radius: 8px;
  background: var(--g-tint-strong);
  border: 1px solid var(--g-edge-soft);
  color: var(--muted);
  /* Метка не должна тянуть на себя внимание от ника. */
  opacity: .9;
}

.bcard__badge--mod {
  /* Роль сотрудника площадки — это не достижение человека, а
     должность. Раньше она светилась неоном и стояла впереди галочки
     проверки, хотя по смыслу вторична. Оставляем цвет, убираем
     свечение. */
  background: linear-gradient(135deg, rgba(232,56,79,.22), rgba(120,20,32,.22));
  color: #ff8b99;
  border-color: rgba(232,56,79,.3);
  text-shadow: none;
  animation: none;
}

.bcard__badge--ok {
  /* Проверен: тихая метка рядом с именем. Красную анимированную
     галочку ставит handleCheck — она одна и остаётся главной. */
  background: var(--g-tint-strong);
  border-color: var(--g-edge-soft);
  color: var(--muted);
}

.bcard__badge--vip {
  background: rgba(255,199,89,.14);
  color: #ffc759;
  border-color: rgba(255,199,89,.28);
}

/* --------------------------------------------------------------------------
   22. Окна: модалки и шторки
   --------------------------------------------------------------------------

   Это половина интерфейса: чат, настройки, комментарии, подтверждения,
   выбор темы. Раньше окна были сплошной заливкой цвета фона, и они
   выглядели как чужеродные плашки, наложенные на приложение: стекло
   вокруг и матовая плита внутри одного экрана.

   Теперь окно — самый толстый слой стекла в приложении: под ним
   видно то, что было под окном. Так переход «открылось окно» читается
   как приближение, а не как смена экрана.
   -------------------------------------------------------------------------- */

.overlay {
  background: rgba(0,0,0,.52);
  -webkit-backdrop-filter: blur(18px) saturate(120%);
  backdrop-filter: blur(18px) saturate(120%);
}
[data-theme="light"] .overlay { background: rgba(20,20,50,.28); }

.sheet,
.modal {
  background: var(--g-tint-strong);
  -webkit-backdrop-filter: blur(var(--g-blur-3)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-3)) saturate(var(--g-sat));
  border-color: var(--g-edge);
  box-shadow: 0 -18px 60px rgba(0,0,0,.5), inset 0 1px 0 var(--g-edge-lit);
}
[data-theme="light"] .sheet,
[data-theme="light"] .modal {
  box-shadow: 0 -18px 60px rgba(20,20,50,.18), inset 0 1px 0 rgba(255,255,255,.9);
}

.sheet {
  border-radius: var(--g-r-xl) var(--g-r-xl) 0 0;
  animation: gSheetUp .34s var(--g-ease);
}
@keyframes gSheetUp {
  from { transform: translate(-50%, 100%); }
  to   { transform: translate(-50%, 0); }
}

/* Шапка окна: стекло, которое едет вместе с содержимым.
 *
 *  В настройках шестнадцать пунктов, и прокручивать их приходится
 *  долго. Шапка уезжала наверх вместе с ними, и кнопка закрытия
 *  исчезала — чтобы вернуться, приходилось доводить список до
 *  конца и искать её внизу. Это и читалось как «настройки багуются».
 *
 *  Теперь заголовок и крестик зафиксированы и сделаны из того же
 *  стекла, что и само окно: сквозь них видно уезжающий список,
 *  и остаётся ощущение одного цельного предмета. */
.sheet__head {
  position: sticky;
  top: 0;
  z-index: 3;
  flex: none;
  padding: 8px 14px 12px;
  background: var(--g-tint-strong);
  -webkit-backdrop-filter: blur(var(--g-blur)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur)) saturate(var(--g-sat));
  box-shadow: 0 1px 0 var(--g-edge-soft);
}
.sheet__head b { flex: 1; min-width: 0; }

/* Крестик закрытия. Стоит в шапке, которая не уезжает, поэтому
   доступен на любом месте длинного списка. */
.sheet__x { flex: none; width: 34px; height: 34px; }
.sheet__x svg { width: 17px; height: 17px; }
/* Шапка теперь вне прокручиваемого тела, поэтому между ней и
   содержимым не должно быть разрыва в стекле. */
.sheet__body { padding-top: 4px; }

/* Кнопка закрытия в шапке — круглое стекло, как и остальные. */
.sheet__head .icon-btn { flex: none; }

.modal {
  border-radius: var(--g-r-xl);
  animation: gPop .28s var(--g-ease);
}
@keyframes gPop {
  from { transform: scale(.92) translateY(16px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

.sheet__grab { background: var(--g-edge-lit); }

/* --------------------------------------------------------------------------
   23. Панель модерации
   --------------------------------------------------------------------------
   Это рабочий инструмент, а не витрина: здесь важнее плотность и
   читаемость, чем эффекты. Плитки обзора — стекло, но без свечений:
   загорается только то, что требует решения прямо сейчас. */

.obz__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
.obz__tile {
  padding: 14px 12px;
  border-radius: var(--g-r);
  text-align: left;
  background: var(--g-tint);
  border: 1px solid var(--g-edge-soft);
  -webkit-backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  box-shadow: var(--g-sh-1), inset 0 1px 0 var(--g-edge-lit);
  transition: transform var(--g-fast) var(--g-ease), border-color var(--g-fast) var(--g-ease);
}
.obz__tile:active { transform: scale(.96); }
.obz__tile b {
  display: block;
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -1px;
  line-height: 1.05;
}
.obz__tile span { display: block; font-size: 11.5px; color: var(--muted); margin-top: 3px; }
.obz__tile i { display: block; font-size: 10.5px; font-style: normal; color: var(--muted-2); }

/* Зажжённая плитка: ненулевое число, которое ждёт решения. */
.obz__tile--hot {
  border-color: rgba(124,92,255,.45);
  background: var(--grad-soft);
}
.obz__tile--hot b { color: #fff; }

.obz__rows { padding: 4px 0; }
.obz__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 9px 2px;
  border-bottom: 1px solid var(--g-edge-soft);
  font-size: 13.5px;
  color: var(--muted);
}
.obz__row:last-child { border-bottom: 0; }
.obz__row b { font-size: 15px; color: var(--text); font-variant-numeric: tabular-nums; }

.obz__ok {
  padding: 14px;
  border-radius: var(--g-r);
  margin-bottom: 12px;
  font-size: 13.5px;
  color: var(--ok);
  background: rgba(47,214,168,.12);
  border: 1px solid rgba(47,214,168,.3);
}

/* Вкладки панели: прокручиваются, если их много. */
.adm-tabs {
  -webkit-backdrop-filter: blur(var(--g-blur-2));
  backdrop-filter: blur(var(--g-blur-2));
}

/* Панель массовых действий. Появляется над списком, когда есть
   что отмечать, и уходит вниз сама, как только выбор снят. */
.adm-bulk {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 14px;
  padding: 10px 12px;
  border-radius: var(--g-r);
  background: var(--g-tint);
  border: 1px solid var(--g-edge-soft);
  -webkit-backdrop-filter: blur(var(--g-blur-2));
  backdrop-filter: blur(var(--g-blur-2));
}
.adm-bulk.is-on {
  border-color: rgba(124,92,255,.4);
  background: var(--grad-soft);
}
.adm-bulk__n { font-size: 12px; color: var(--muted); }
.mini-btn.is-primary {
  background: var(--grad);
  color: #fff;
  border-color: transparent;
}
.mini-btn[disabled] { opacity: .4; pointer-events: none; }

/* Точка отметки на карточке работы. Крупная и с запасом вокруг:
   попасть пальцем в 12 пикселей можно, но неудобно. */
.adm-card { position: relative; }
.adm-card__check {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--g-tint-strong);
  border: 1px solid var(--g-edge);
  box-shadow: var(--g-sh-1);
}
.adm-card__check svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: var(--muted);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
}
.adm-card__check.is-on { background: var(--grad); border-color: transparent; }
.adm-card__check.is-on svg { stroke: #fff; opacity: 1; }
.adm-card.is-picked { border-color: rgba(124,92,255,.55); }

/* --------------------------------------------------------------------------
   24. Заставка: блик, как в iOS
   --------------------------------------------------------------------------

   Заставка и раньше была не пустой: пятна, карточки, кольцо. Но она
   выглядела статичной — тёмный фон с размытыми кругами. Главный
   приём iOS здесь один: по поверхности идёт узкая световая полоса,
   и стекло от неё вспыхивает. Именно этот блик отличает «живой»
   экран от картинки.

   Полоса едет на `left`, а не на `transform`: трансформация тут
   создавала бы отдельный слой композитора на каждой карточке, а их
   на заставке семь-пятнадцать, и телефон грелся бы зря. Полоса
   перерисовывается только у видимых карточек.
   -------------------------------------------------------------------------- */

.splash__mark {
  position: relative;
  overflow: hidden;
  -webkit-backdrop-filter: blur(var(--g-blur)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur)) saturate(var(--g-sat));
  box-shadow: var(--g-sh-3), inset 0 1px 0 var(--g-edge-lit);
}

/* Блик по знаку. Идёт справа налево, как отражённый свет. */
.splash__mark::after,
.splash__card::after,
.splash__title span::after {
  content: '';
  position: absolute;
  top: -20%;
  bottom: -20%;
  left: -70%;
  width: 42%;
  pointer-events: none;
  background: linear-gradient(100deg,
    transparent 0%,
    rgba(255,255,255,.10) 30%,
    rgba(255,255,255,.46) 50%,
    rgba(255,255,255,.10) 70%,
    transparent 100%);
  animation: gShimmer 2.6s var(--g-ease) infinite;
}
.splash__mark::after { animation-duration: 2.1s; }

@keyframes gShimmer {
  0%   { left: -70%; }
  55%  { left: 130%; }
  100% { left: 130%; }
}

/* У карточек своя фаза: если блик пойдёт у всех синхронно, заставка
   выглядит как мигающая ёлочная игрушка, а не как движение. */
.splash__card { position: relative; overflow: hidden; }
.splash__card::after {
  animation-duration: 3.4s;
  animation-delay: inherit;
}

/* Буквы названия тоже блестят — по одной, слева направо.
   Это ровно то, что делает логотип в iOS: свет проходит по
   надписи, а не по всей плашке целиком. */
.splash__title span { position: relative; overflow: hidden; display: inline-block; }
.splash__title span::after {
  animation-duration: 3s;
  width: 34%;
}
.splash__title span:nth-child(2)::after { animation-delay: 1.5s; }

@media (prefers-reduced-motion: reduce) {
  .splash__mark::after,
  .splash__card::after,
  .splash__title span::after { animation: none; display: none; }
}

/* Полоса загрузки: узкая, как в системе, с бегущим бликом. */
.splash__bar i {
  background: linear-gradient(90deg,
    var(--accent) 0%, var(--accent-2) 50%, var(--accent) 100%);
  background-size: 200% 100%;
  box-shadow: 0 0 14px rgba(124,92,255,.6);
  animation: gShimmerBar 1.4s linear infinite;
}
@keyframes gShimmerBar {
  from { background-position: 120% 0; }
  to   { background-position: -80% 0; }
}

/* --------------------------------------------------------------------------
   25. Связь
   --------------------------------------------------------------------------
   Полоса «нет связи» живёт над шапкой и ездит с прокруткой. В стекле
   она читается как системная плашка iOS, а не как ошибка приложения. */
.netbar {
  position: fixed;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  z-index: 300;
  width: 100%;
  max-width: 520px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: calc(var(--safe-t) + 8px) 16px 8px;
  font-size: 12.5px;
  font-weight: 600;
  color: #fff;
  background: rgba(255, 79, 94, .92);
  -webkit-backdrop-filter: blur(var(--g-blur-2));
  backdrop-filter: blur(var(--g-blur-2));
  box-shadow: 0 8px 24px rgba(0, 0, 0, .3);
  animation: gDrop .3s var(--g-ease);
}
.netbar__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #fff;
  flex: none;
}
@keyframes gDrop {
  from { transform: translate(-50%, -100%); opacity: 0; }
  to   { transform: translate(-50%, 0); opacity: 1; }
}

/* --------------------------------------------------------------------------
   26. Уведомления
   -------------------------------------------------------------------------- */

.toast {
  background: var(--g-tint-strong);
  -webkit-backdrop-filter: blur(var(--g-blur-3)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-3)) saturate(var(--g-sat));
  border: 1px solid var(--g-edge);
  border-radius: 15px;
  box-shadow: var(--g-sh-3), inset 0 1px 0 var(--g-edge-lit);
}

/* --------------------------------------------------------------------------
   27. Потянуть-обновить
   -------------------------------------------------------------------------- */

.ptr {
  position: fixed;
  top: 0;
  left: 50%;
  z-index: 250;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, calc(var(--pull, 0px) - 62px));
  transition: transform .22s var(--g-ease), opacity .22s var(--g-ease);
}
.ptr.is-pull { opacity: 1; }
.ptr.is-spin, .ptr.is-done {
  opacity: 1;
  transform: translate(-50%, calc(var(--pull, 0px) - 62px));
}

.ptr__ring {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--g-tint-strong);
  border: 1px solid var(--g-edge);
  -webkit-backdrop-filter: blur(var(--g-blur-2));
  backdrop-filter: blur(var(--g-blur-2));
  box-shadow: var(--g-sh-1), inset 0 1px 0 var(--g-edge-lit);
}
.ptr__ring i {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: 2px solid var(--g-edge);
  border-top-color: var(--accent);
  transition: transform .2s var(--g-ease);
}
/* Пока палец тянет, значок крутится в такт движению — видно, что
   приложение услышало жест, а не просто зависло. */
.ptr.is-pull .ptr__ring i { transform: rotate(90deg); }
.ptr.is-spin .ptr__ring i { animation: gSpin .8s linear infinite; }
@keyframes gSpin { to { transform: rotate(360deg); } }
.ptr.is-done .ptr__ring i { border-top-color: var(--ok); transform: rotate(0deg); }

.ptr__t { font-size: 11px; color: var(--muted); }

/* --------------------------------------------------------------------------
   28. Поиск по переписке
   -------------------------------------------------------------------------- */

.chatsearch {
  display: none;
  position: relative;
  padding: 8px 16px 0;
}
.chatsearch.is-open { display: block; }
.chatsearch__x {
  position: absolute;
  top: 14px;
  right: 22px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: var(--muted);
  background: var(--g-tint-strong);
  border: 1px solid var(--g-edge-soft);
}
.chatsearch__hits {
  margin-top: 8px;
  max-height: 210px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.chatsearch__none {
  padding: 14px 4px;
  font-size: 13px;
  color: var(--muted);
  text-align: center;
}
.chatsearch__hit {
  display: block;
  width: 100%;
  text-align: left;
  padding: 9px 11px;
  border-radius: var(--g-r-sm);
  background: var(--g-tint-soft);
  border: 1px solid var(--g-edge-soft);
}
.chatsearch__hit:active { background: var(--g-tint-strong); }
.chatsearch__at { display: block; font-size: 10.5px; color: var(--muted-2); }
.chatsearch__txt {
  display: block;
  font-size: 13.5px;
  color: var(--text);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chatsearch__who { display: block; font-size: 10.5px; color: var(--muted); margin-top: 2px; }

/* Подсветка найденного сообщения. Держится пару секунд и сама
   гаснет: человек видит, куда его привело, и не думает, что
   сообщение кто-то перекрасил навсегда. */
.msg.is-hit { animation: gHit 2.2s var(--g-ease); }
@keyframes gHit {
  0%, 60% { box-shadow: 0 0 0 3px rgba(124,92,255,.55); }
  100%    { box-shadow: none; }
}

/* Граница «непрочитанные». Красная по привычке почты: её ждут и
   не путают ни с чем другим. */
.msg-unread {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 14px 0 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: #ff8b99;
}
.msg-unread::before,
.msg-unread::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(232,56,79,.45));
}
.msg-unread::after { background: linear-gradient(90deg, rgba(232,56,79,.45), transparent); }

/* Закладка в карточке работы. Заполненная — заметная, пустая —
   тихая: человек должен видеть разницу с одного взгляда, иначе
   непонятно, сохранено ли уже. */
.text-btn.is-on {
  color: var(--accent);
  border-color: rgba(124, 92, 255, .5) !important;
  background: var(--grad-soft) !important;
}
.text-btn.is-on svg { fill: currentColor; }

/* --------------------------------------------------------------------------
   29. Переписка
   -------------------------------------------------------------------------- */

   Пузыри раньше были сплошной заливкой с цветом автора. На стекле
   это ломается: сплошной прямоугольник не пропускает фон, и чат
   превращается в стену. Пузырь — это самое стекло, которое чат
   себе позволяет.
   -------------------------------------------------------------------------- */

.msg { display: flex; margin-bottom: 6px; animation: gIn .3s var(--g-ease) backwards; }
.msg--me { justify-content: flex-end; }
.msg--them { justify-content: flex-start; }

.msg__bubble {
  position: relative;
  max-width: 78%;
  padding: 9px 13px 7px;
  border-radius: 18px;
  font-size: 14.5px;
  line-height: 1.45;
  word-break: break-word;
  -webkit-backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  box-shadow: var(--g-sh-1);
  border: 1px solid var(--g-edge-soft);
}
.msg--them .msg__bubble {
  border-bottom-left-radius: 6px;
  background: var(--g-tint-strong);
}
.msg--me .msg__bubble {
  border-bottom-right-radius: 6px;
  background: var(--grad-soft);
  border-color: rgba(124,92,255,.28);
}

/* Текст сообщения. Отдельный блок нужен, чтобы время внизу не
   вставало в тот же поток: иначе «отправил» и «05:48» налезают
   друг на друга в конце длинной фразы. */
.msg__text { white-space: pre-wrap; }

/* Подвал пузыря: время слева, галочка справа. Отдельной строкой
   и всегда на одном месте — глаз перестаёт искать их в конце фразы. */
.msg__foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  margin-top: 2px;
}
.msg__time {
  font-size: 10px;
  font-style: normal;
  color: var(--muted-2);
  font-variant-numeric: tabular-nums;
}
.msg__tick {
  font-style: normal;
  font-size: 10px;
  line-height: 1;
  color: var(--muted-2);
  letter-spacing: -2px;
}
.msg__tick--read { color: var(--accent); }
.msg__tick--wait { opacity: .5; }

/* Разделитель по дням. Стеклянная капсула посреди переписки:
   видно, где был вчерашний разговор, а где сегодняшний. */
.msg-day {
  position: sticky;
  top: 6px;
  z-index: 2;
  width: fit-content;
  margin: 12px auto 10px;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  background: var(--g-tint-strong);
  border: 1px solid var(--g-edge-soft);
  -webkit-backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  backdrop-filter: blur(var(--g-blur-2)) saturate(var(--g-sat));
  box-shadow: var(--g-sh-1);
}

.msg-sys {
  margin: 10px auto;
  font-size: 12px;
  color: var(--muted);
  text-align: center;
  max-width: 86%;
}

/* --------------------------------------------------------------------------
   23. Переход между вкладками
   --------------------------------------------------------------------------
   Точка под активной иконкой едет вместо прыжка: это единственная
   деталь, по которой рука понимает, что приложение «живое».
   -------------------------------------------------------------------------- */

.g-dot {
  position: absolute;
  bottom: 5px;
  left: 50%;
  width: 5px;
  height: 5px;
  margin-left: -2.5px;
  border-radius: 50%;
  background: var(--grad);
  box-shadow: 0 0 10px rgba(124,92,255,.7);
  transition: transform var(--g-med) var(--g-ease);
}

/* --------------------------------------------------------------------------
   19. Уважение к настройке «меньше движения»
   --------------------------------------------------------------------------
   Не украшение, а необходимость: анимации вызывают тошноту у части
   людей, и для них интерфейс обязан быть неподвижным.
   -------------------------------------------------------------------------- */

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