/*
 * Шапка WildSide и переключатель панелей. Один файл на четыре домена,
 * раздаётся nginx-ом как /panels.css - см. шапку panels.js.
 *
 * Все цвета берутся из переменных дизайн-системы, но с запасным значением: у
 * панели модерации свой набор токенов, и если там что-то переименуют,
 * переключатель обязан остаться читаемым, а не раствориться в фоне.
 *
 * Префикс wsp- обязателен: файл подключается рядом с четырьмя разными
 * таблицами стилей, и короткое имя вроде .menu там уже занято.
 */

/* ======================================================================
 * ШАПКА
 *
 * ПОЧЕМУ ЗДЕСЬ, А НЕ У КАЖДОЙ ПАНЕЛИ. Шапка - единственное, что остаётся на
 * месте при переходе между панелями: по ней и переходят. Пока размеры жили в
 * четырёх таблицах стилей, они разъехались молча - капсула была 1000 в
 * кабинете, 1180 в медийке, 1320 в админке и 1400 в модерации, отступы 9 и 8,
 * карточка человека то капсулой, то прозрачной кнопкой. При каждом переходе
 * шапка прыгала, хотя это буквально одна и та же шапка.
 *
 * Ширина одна на всех - 1320. Колонки содержимого у панелей разные (у админки
 * таблицы не влезают в 1180, у модерации вьюер боёв просит 1400), и подчинять
 * шапку каждой из них значит вернуть тот же разъезд.
 *
 * Всё скоупится под .top: классы вроде .icon-btn у панели модерации живут и
 * вне шапки, и переопределять их целиком нельзя.
 * ====================================================================== */
.top {
  position: sticky;
  top: 0;
  z-index: 20;
  padding: 12px 16px 0;
  /* Панель модерации - колонка во всю высоту экрана, там шапка не должна тянуться */
  flex: none;
}
.top__in {
  max-width: 1320px;
  margin: 0 auto;
  padding: 9px 10px 9px 18px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  gap: 12px;
  background: rgba(17, 21, 29, .9);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border: 1px solid var(--line, #212734);
  /*
   * ТИПОГРАФИКА КАПСУЛЫ ЗАДАЁТСЯ ЗДЕСЬ, А НЕ НАСЛЕДУЕТСЯ ОТ ПАНЕЛИ. У панелей
   * она разная: body в кабинете, медийке и админке - 16px/normal, в модерации
   * 13.5px/1.5. Всё, что шапка не объявила сама, молча принимало чужой
   * размер, и одинаковый на вид font-size давал разную высоту строки:
   * логотип в модерации выходил 25.5px против 20px в кабинете.
   */
  font-size: 14px;
  line-height: normal;
}
.top .logo {
  font-weight: 800;
  font-size: 17px;
  /* Своя высота строки: наследованная 1.5 делала логотип выше на 5.5px */
  line-height: 1.2;
  display: inline-flex;
  align-items: center;
  letter-spacing: .04em;
  text-decoration: none;
  white-space: nowrap;
  color: var(--text, #eef1f6);
}
/* Логотип панели - это ДВА слова: марка «WS» и название самой панели (ID,
 * Media, Admin, Mod). Пробел между ними стоит в разметке, но flex-контейнер
 * схлопывает пробел между анонимным текстовым узлом и соседним тегом, и
 * «WS Media» рисовалось как «WSMedia». В исходнике вёрстки этого не видно -
 * там пробел есть, - поэтому зазор задаётся стилем и живёт здесь.
 *
 * Правило доезжает только до четырёх панелей: публичный сайт panels.css не
 * подключает, и его слитное «WILDSIDE» остаётся одним словом, каким и должно.
 */
.top .logo b,
.top .logo span {
  margin-left: 6px;
  /* Название панели - метка при марке, а не вторая половина слова: у «WildSide»
     обе половины набирались одинаково, здесь у них разные роли. */
  font-weight: 700;
  letter-spacing: .02em;
  color: var(--accent, var(--red, #e23744));
}

/* Ряд панелей и всё за ним прижаты вправо. Правило висит на узле-хозяине, а не
   на карточке человека: узел есть в разметке всегда, даже когда идти некуда и
   ряд не рисуется, - иначе карточка прилипала бы к логотипу. */
.top #switcher,
.top #panel-switch { margin-left: auto; }

/*
 * Карточка человека. Два имени на четыре панели: .top__user - див у кабинета,
 * медийки и админки, .user-chip - кнопка у модерации (она ведёт в профиль).
 * Вид общий, поведение остаётся своё.
 */
.top .top__user,
.top .user-chip {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 5px 12px 5px 6px;
  border-radius: 999px;
  border: 1px solid var(--line, #212734);
  background: var(--panel-2, #171c26);
  color: var(--muted, #9aa6b8);
  font-size: 13px;
  font-weight: 600;
  min-width: 0;
  flex: 0 1 auto;
  max-width: 220px;
  text-align: left;
  white-space: nowrap;
  box-shadow: none;
  /* У модерации это <button>: без сброса он тащит оформление от браузера */
  appearance: none;
  -webkit-appearance: none;
}
.top button.user-chip { cursor: pointer; }
.top button.user-chip:hover {
  color: var(--text, #eef1f6);
  border-color: var(--line-strong, #2b3446);
  background: var(--panel-3, #1d2330);
}

.top .avatar,
.top .user-dot {
  position: relative;
  overflow: hidden;
  width: 27px;
  height: 27px;
  flex: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  /*
   * Красный здесь литералом, а не через --accent-soft: переменная есть не у
   * всех панелей и значит у них разное (в модерации .10, у остальных .13),
   * из-за чего один и тот же кружок был бледнее ровно на одной панели.
   */
  background: rgba(226, 55, 68, .13);
  border: 1px solid rgba(226, 55, 68, .3);
  color: var(--red, #e23744);
  font-size: 12px;
  font-weight: 800;
}
.top .top__name,
.top .user-name {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 150px;
}

.top .icon-btn {
  appearance: none;
  cursor: pointer;
  width: 37px;
  height: 37px;
  flex: none;
  padding: 0;
  display: grid;
  place-items: center;
  /* Своя типографика, как у всей капсулы: класс .icon-btn есть и у панелей,
     и их размер шрифта проступал бы сквозь общий вид кнопки */
  gap: 0;
  font-size: 14px;
  font-weight: 600;
  line-height: normal;
  border-radius: 50%;
  border: 1px solid var(--line, #212734);
  background: var(--panel-2, #171c26);
  color: var(--muted, #9aa6b8);
  box-shadow: none;
  transition: color .18s ease, border-color .18s ease;
}
.top .icon-btn:not([disabled]):hover {
  color: var(--red, #e23744);
  border-color: rgba(226, 55, 68, .4);
  background: var(--panel-2, #171c26);
}
.top .icon-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.top .icon-btn svg { width: 17px; height: 17px; display: block; }
.top .icon-btn[disabled] { cursor: default; color: var(--muted-2, #5f6b7f); }

@media (max-width: 720px) {
  .top .top__name,
  .top .user-name { max-width: 96px; }
}
@media (max-width: 560px) {
  .top { padding: 9px 8px 0; }
  .top__in { padding: 7px 7px 7px 12px; gap: 7px; }
  .top .top__name,
  .top .user-name { max-width: 70px; }
  .top .top__user,
  .top .user-chip { padding: 4px 10px 4px 5px; gap: 7px; }
  .top .icon-btn { width: 34px; height: 34px; }
}

/*
 * Узел, в который панель кладёт ряд. Класс вешает сам mount: элемент на каждой
 * поверхности свой, а сжиматься обязан одинаково, иначе ряд выдавит из шапки
 * логотип и карточку человека вместо того, чтобы прокручиваться.
 */
.wsp-host {
  position: relative;
  display: flex;
  min-width: 0;
  flex: 0 1 auto;
}

/*
 * Растушёвка у края, за которым ряд продолжается. Классы вешает mount по
 * реальной прокрутке - ряд, который целиком влез, никаких краёв не рисует.
 * Живут на хозяине, а не на самом ряду: тот прокручивается, и приклеенное к
 * нему уехало бы вместе с вкладками.
 */
.wsp-host::before,
.wsp-host::after {
  content: "";
  position: absolute;
  z-index: 1;
  top: 1px;
  bottom: 1px;
  width: 26px;
  pointer-events: none;
  opacity: 0;
  border-radius: 999px;
  transition: opacity .16s ease;
}
.wsp-host::before {
  left: 1px;
  background: linear-gradient(to right, var(--panel-2, #171c26), rgba(23, 28, 38, 0));
}
.wsp-host::after {
  right: 1px;
  background: linear-gradient(to left, var(--panel-2, #171c26), rgba(23, 28, 38, 0));
}
.wsp-host--left::before { opacity: 1; }
.wsp-host--right::after { opacity: 1; }

/*
 * Ряд вкладок - «капсула в капсуле»: своя подложка внутри шапки, которая сама
 * капсула. Без подложки вкладки читались бы как случайные ссылки рядом с
 * логотипом; с ней сразу видно, что это одна группа и что внутри переключают.
 */
.wsp {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border-radius: 999px;
  border: 1px solid var(--line, #212734);
  background: var(--panel-2, #171c26);
  /* Вкладок бывает четыре, а шапку делят ещё логотип и карточка человека.
     На узком экране ряд не ломается и не режется - его прокручивают вбок. */
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
  overscroll-behavior-x: contain;
}
.wsp::-webkit-scrollbar { display: none; }

.wsp__tab {
  flex: none;
  padding: 6px 13px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.15;
  white-space: nowrap;
  text-decoration: none;
  color: var(--muted, #9aa6b8);
  transition: color .16s ease, background .16s ease;
}
a.wsp__tab:hover {
  color: var(--text, #eef1f6);
  background: var(--panel-3, #1d2330);
  /* У панелей на .top a:hover висит подъём - вкладке он не нужен, она в ряду */
  transform: none;
}
a.wsp__tab:focus-visible { outline: 2px solid #fff; outline-offset: -2px; }

/*
 * Текущая панель остаётся в ряду, но никуда не ведёт: ряд одинаков на всех
 * поверхностях, и меняется только подсветка. Заливка + тонкий контур внутрь:
 * одной заливки на тёмном фоне мало, чтобы вкладка читалась как нажатая.
 */
.wsp__tab--on {
  cursor: default;
  /* Литералы, а не --accent-soft/--accent-line: см. кружок человека выше -
     переменные есть не у всех панелей, и отметка «вы здесь» была разной */
  color: var(--red, #e23744);
  background: rgba(226, 55, 68, .13);
  box-shadow: inset 0 0 0 1px rgba(226, 55, 68, .32);
}

@media (max-width: 720px) {
  .wsp__tab { padding: 6px 10px; font-size: 12px; }
}
@media (max-width: 560px) {
  .wsp { padding: 2px; gap: 1px; }
  .wsp__tab { padding: 6px 9px; font-size: 11.5px; }
}
@media (prefers-reduced-motion: reduce) {
  .wsp__tab,
  .wsp-host::before,
  .wsp-host::after { transition-duration: .001ms; }
}

/* ======================================================================
 * РАЗДЕЛЫ СТАТИСТИКИ - ОДИН ЯЗЫК НА ВСЕ ПАНЕЛИ
 *
 * ПОЧЕМУ ЗДЕСЬ, А НЕ У КАЖДОЙ ПАНЕЛИ - ровно по той же причине, что и шапка
 * выше, и с тем же уже случившимся исходом. Числа про проект показывают и
 * админка, и панель модерации; рисовали их порознь, и разъехалось всё: раздел
 * назывался то `<h2>Название` с пояснением рядом, то КАПСОМ без пояснения;
 * пустой раздел занимал то строку, то плашку в 170 пикселей; полоса значения
 * в одном месте меряла долю от максимума, в другом - от суммы. Человек ходит
 * между панелями и читает это как разные продукты.
 *
 * Всё с префиксом ws-: файл подключается рядом с четырьмя таблицами стилей,
 * и короткие имена вроде .bar или .row там давно заняты.
 *
 * Палитра берётся у панели, но имена токенов у панелей РАЗНЫЕ (--accent против
 * --red, --line-strong против --line-hover), поэтому ниже один слой сведения.
 * Литерал в конце цепочки - не «на всякий случай», а последняя линия: без него
 * раздел на панели с другим набором токенов растворился бы в фоне.
 * ====================================================================== */
:root {
  --ws-accent: var(--accent, var(--red, #e23744));
  --ws-accent-soft: var(--accent-soft, var(--red-soft, rgba(226, 55, 68, .12)));
  --ws-line-strong: var(--line-strong, var(--line-hover, #39424f));
  --ws-mono: var(--mono, ui-monospace, 'SF Mono', Consolas, monospace);
}

/* ---------- Выбор промежутка ----------
 * ОДНОЙ строкой. Поля даты обязаны иметь фиксированную ширину: в них двадцать
 * символов, а растянутые на всю колонку они ломают строку и утаскивают кнопку
 * «Показать» вниз - так и было в админке, где колонка шире модераторской. */
.ws-range {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 9px;
  margin-bottom: 12px;
}
.ws-range input[type='datetime-local'] {
  flex: none;
  /* 200, а не «сколько поместится»: формат поля задаёт локаль браузера, и в
     en-US он длиннее русского на «, 05:26 PM». Обрезанное поле выглядит
     поломкой, лишние двадцать пикселей - ничем. */
  width: 200px;
  padding: 7px 10px;
  font: inherit;
  font-size: 12.5px;
  color: var(--text, #eef1f6);
  background: var(--panel-2, #171c26);
  border: 1px solid var(--line, #212734);
  border-radius: 9px;
  /* Иначе браузер рисует СВОЙ календарь и значок по светлой теме: белая
     иконка на тёмном поле и всплывающий белый календарь посреди панели. */
  color-scheme: dark;
}
.ws-range input[type='datetime-local']:focus {
  outline: none;
  border-color: var(--ws-line-strong);
}
.ws-range__dash { color: var(--muted-2, #6b7789); }
.ws-range__note {
  font-size: 12px;
  color: var(--muted-2, #6b7789);
}
/* Кнопка стоит В строке, а не переносится под поля: перенос и был тем самым
   «выбор промежутка в три этажа», из-за которого шапка раздела съедала экран. */
.ws-range__go {
  flex: none;
  appearance: none;
  cursor: pointer;
  padding: 7px 13px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text, #eef1f6);
  background: var(--panel-2, #171c26);
  border: 1px solid var(--line, #212734);
  border-radius: 9px;
}
.ws-range__go:hover {
  border-color: var(--ws-accent);
  color: var(--ws-accent);
}
/* Поиск прижимается вправо: он фильтрует показанное, а не выбирает его. */
.ws-range__search {
  margin-left: auto;
  width: 230px;
  padding: 7px 11px;
  font: inherit;
  font-size: 12.5px;
  color: var(--text, #eef1f6);
  background: var(--panel-2, #171c26);
  border: 1px solid var(--line, #212734);
  border-radius: 9px;
}
.ws-range__search:focus {
  outline: none;
  border-color: var(--ws-line-strong);
}

/* Поиск в одиночестве - это и есть вся полоса инструментов: прижимать его
   вправо не к чему, справа пусто. */
.ws-range__search:only-child { margin-left: 0; width: 100%; }

/* Поиск, ведущий полосу, а не замыкающий её: поле и кнопка «Найти» - это одно
   действие, и поле забирает всё, что осталось от кнопки. */
.ws-range__search--wide { margin-left: 0; flex: 1; width: auto; min-width: 180px; }

/* Полоса пресетов. Своя, а не общая .seg: у панели модерации .seg своего вида,
   и раздел статистики не должен меняться от того, на каком домене открыт. */
.ws-seg {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--panel-2, #171c26);
  border: 1px solid var(--line, #212734);
  border-radius: 10px;
}
.ws-seg button {
  appearance: none;
  cursor: pointer;
  border: 0;
  background: transparent;
  color: var(--muted, #9aa6b8);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 5px 10px;
  border-radius: 7px;
}
.ws-seg button:hover { color: var(--text, #eef1f6); }
.ws-seg button.active {
  background: var(--panel-3, #1d2330);
  color: var(--text, #eef1f6);
}
/* Пустой селектор остаётся селектором: подпись «нет данных» живёт внутри него,
   а не рядом, иначе полоса схлопывается в невидимую рамку. */
.ws-seg button:disabled {
  cursor: default;
  color: var(--muted-2, #6b7789);
  font-weight: 500;
}

/* Тот же переключатель, но в роли ВТОРОЙ ступени навигации: вкладки сверху
   говорят, чем администратор занимается, подразделы - что из этого он смотрит.
   Крупнее обычного сегмента ровно настолько, чтобы читаться навигацией, а не
   фильтром, и не настолько, чтобы спорить с вкладками. */
.ws-seg--nav {
  /* Ширина по содержимому, а не во всю строку: полоса вкладок выше занимает всю
     ширину, и вторая такая же читалась бы тем же уровнем, а не подчинённым. */
  margin-bottom: 16px;
  padding: 4px;
}

.ws-seg--nav button { font-size: 13px; padding: 7px 14px; }

/* ---------- Заголовки ----------
 * Две ступени, и только две. Группа отвечает на «о чём вообще этот кусок
 * страницы», раздел - на «что именно тут показано». Третьей ступени нет
 * намеренно: семнадцать разделов подряд одного веса читаются как один
 * бесконечный список, а четыре группы по четыре - как отчёт. */
.ws-group {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin: 30px 0 14px;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--line, #212734);
}
.ws-group:first-child { margin-top: 18px; }
.ws-group h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--text, #eef1f6);
}
.ws-group p {
  margin: 0;
  font-size: 12.5px;
  color: var(--muted-2, #6b7789);
}

/* Раздел. Пояснение стоит РЯДОМ с названием, а не отсутствует: «Recovery» и
   «Охват событий» без единой поясняющей строки не значат ничего даже тому,
   кто эти числа заказывал. */
.ws-sect {
  display: flex;
  align-items: baseline;
  gap: 9px;
  flex-wrap: wrap;
  margin: 18px 0 8px;
}
.ws-sect h3 {
  margin: 0;
  font-size: 13.5px;
  font-weight: 650;
  color: var(--text, #eef1f6);
}
.ws-sect p {
  margin: 0;
  font-size: 12px;
  color: var(--muted-2, #6b7789);
}
.ws-sect:first-child { margin-top: 0; }

.ws-group__note,
.ws-sect__note { margin-left: auto; font-size: 12px; color: var(--muted-2, #6b7789); }

/* Счётчик в заголовке раздела: число читают, а не разглядывают, поэтому
   табличные цифры и обычный цвет текста - красным тут подсвечивать нечего. */
.ws-sect__note b {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text, #eef1f6);
}

/* ---------- Контейнер содержимого ---------- */
.ws-card {
  background: var(--panel, #11151d);
  border: 1px solid var(--line, #212734);
  border-radius: 12px;
  overflow: hidden;
}
/* Карточка вокруг единственной строки «ничего нет» выглядит пустым полем ввода
   и зовёт туда что-то напечатать. Рамку убираем, строку оставляем. */
.ws-card:has(> .ws-none:only-child) {
  background: none;
  border-color: transparent;
}

/* ---------- Числа ----------
 * auto-fill + потолок ширины, а не 1fr: четыре плашки, растянутые на колонку в
 * 1280, выглядят как заглушка вёрстки. Пусть лучше справа останется воздух. */
.ws-kpi {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(164px, 212px));
  justify-content: start;
  gap: 9px;
}
.ws-kpi__i {
  padding: 12px 14px;
  background: var(--panel, #11151d);
  border: 1px solid var(--line, #212734);
  border-radius: 12px;
}
.ws-kpi__n {
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text, #eef1f6);
}
.ws-kpi__i--accent .ws-kpi__n { color: var(--ws-accent); }
/* Оттенок по СМЫСЛУ числа, а не по его величине: «ложных банов» жёлтым - это
   предупреждение, «чистых» зелёным - подтверждение, и читаются они до цифры. */
.ws-kpi__i--ok .ws-kpi__n { color: var(--ok, #35c46a); }
.ws-kpi__i--warn .ws-kpi__n { color: var(--warn, #e8b339); }
.ws-kpi__l {
  margin-top: 3px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--muted-2, #6b7789);
}
.ws-kpi__s {
  margin-top: 5px;
  font-size: 11.5px;
  color: var(--muted-2, #6b7789);
}

/* ---------- Строка с полосой ----------
 * Подпись - трек - значение, и метаданные ОТДЕЛЬНОЙ строкой под треком.
 * Раньше они лепились справа от значения и переносились в три строки по
 * девять пикселей: формально всё показано, прочитать нельзя. */
.ws-bar {
  display: grid;
  /* Четвёртая колонка - намеренный воздух. Трек во всю ширину карточки
     разносит полосу и её число на метр: глаз идёт слева направо через пустоту
     и теряет строку. Полоса упирается в потолок, число стоит сразу за ней.

     Колонка значения ШИРЕ, чем нужно двузначному числу (92, не 52): каждая
     строка - свой grid, и ширину этой колонки задаёт её собственное значение.
     С тесным минимумом список из «13» и «3.1млн» встаёт лесенкой. */
  grid-template-columns: minmax(110px, 208px) minmax(0, 520px) minmax(92px, max-content) 1fr;
  align-items: center;
  gap: 2px 14px;
  padding: 9px 14px;
  border-bottom: 1px solid var(--line, #212734);
}
.ws-bar:last-child { border-bottom: 0; }
.ws-bar__l {
  font-size: 12.5px;
  color: var(--muted, #9aa6b8);
  overflow-wrap: anywhere;
}
.ws-bar--off .ws-bar__l { color: var(--muted-2, #6b7789); }
.ws-bar__t {
  height: 8px;
  border-radius: 999px;
  background: var(--panel-3, #1d2330);
  overflow: hidden;
}
.ws-bar__f {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--ws-accent);
  min-width: 2px;
}
.ws-bar--ok .ws-bar__f { background: var(--ok, #35c46a); }
.ws-bar--warn .ws-bar__f { background: var(--warn, #e8b339); }
.ws-bar--info .ws-bar__f { background: var(--tg, #2aa8e8); }
.ws-bar--mute .ws-bar__f { background: var(--ws-line-strong); }
.ws-bar__v {
  justify-self: end;
  font-family: var(--ws-mono);
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text, #eef1f6);
}
.ws-bar--off .ws-bar__v { color: var(--muted-2, #6b7789); font-weight: 600; }
/* Метаданные: вторая строка сетки, от трека до правого края, ОДНОЙ строкой. */
.ws-bar__m {
  /* До числа включительно, не до края: иначе строка уезжает в тот самый воздух
     и снова читается как подпись к следующей полосе. */
  grid-column: 2 / 4;
  font-size: 11px;
  color: var(--muted-2, #6b7789);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- Подзаголовок ВНУТРИ карточки ----------
 * Делит длинный список на смысловые куски и подписывает, от чего считаются
 * доли («213 регистраций за промежуток»), не заводя третьей ступени заголовков
 * снаружи. Ею же держится база процента: доля без знаменателя рядом - это
 * число, которое нечем проверить. */
.ws-cat {
  display: flex;
  align-items: baseline;
  gap: 9px;
  padding: 9px 14px 8px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .03em;
  color: var(--muted-2, #6b7789);
  background: var(--panel-2, #171c26);
  border-bottom: 1px solid var(--line, #212734);
}
/* Моноширинного шрифта тут нет намеренно: справа стоит не только число, но и
   оговорка вроде «вехи независимы друг от друга», а фраза моноширинным читается
   как вывод консоли. Табличные цифры при этом остаются. */
.ws-cat__v {
  margin-left: auto;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--muted, #9aa6b8);
}

/* ---------- Строка без полосы ----------
 * Когда сравнивать нечего (список источников, переходы, причины кика) полоса
 * лишняя: она предлагает сравнить длины там, где смысл в самом перечне. */
.ws-row {
  /* Та же сетка, что у .ws-bar, и это главное в ней: список без полос и список
     с полосами стоят рядом на одной странице, и если числа в них не под одной
     вертикалью, страница читается как две разные таблицы. */
  display: grid;
  grid-template-columns: minmax(110px, 208px) minmax(0, 520px) minmax(92px, max-content) 1fr;
  align-items: baseline;
  gap: 2px 14px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--line, #212734);
  font-size: 12.5px;
  color: var(--muted, #9aa6b8);
}
.ws-row:last-child { border-bottom: 0; }
.ws-row__l { overflow-wrap: anywhere; }
.ws-row__v {
  justify-self: end;
  font-family: var(--ws-mono);
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text, #eef1f6);
  white-space: nowrap;
}
.ws-row__m {
  font-size: 11.5px;
  color: var(--muted-2, #6b7789);
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Место значения, когда там не число, а орган управления. Отдельный класс, а не
   .ws-row__v: у того моноширинный шрифт, и кнопки внутри наследуют его через
   `font: inherit`, превращаясь в подобие вывода терминала. */
.ws-row__c { justify-self: end; display: inline-flex; }

/* ---------- Строка про человека ----------
 * Списки людей есть и в аналитике (кто зарегистрировался), и в модерации
 * (мультиаккаунты) - и рисовались порознь: там аватар 32 и подпись в строке,
 * тут 24 и подпись под ником. Один человек в двух панелях выглядел двумя. */
.ws-person {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--line, #212734);
}
.ws-person:last-child { border-bottom: 0; }
/* Приглушается строка, а не только ник: твинк - это вся строка второго сорта. */
.ws-person--dim { opacity: .55; }
.ws-person__a {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  overflow: hidden;
  font-weight: 700;
  color: var(--text, #eef1f6);
  background: var(--panel-3, #1d2330);
  box-shadow: inset 0 0 0 1px var(--line, #212734);
}
.ws-person__b { min-width: 0; }
.ws-person__n {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text, #eef1f6);
}
.ws-person__m {
  margin-top: 2px;
  font-size: 11px;
  color: var(--muted-2, #6b7789);
}
.ws-person__r {
  margin-left: auto;
  text-align: right;
  font-size: 11px;
  line-height: 1.5;
  white-space: nowrap;
  color: var(--muted-2, #6b7789);
}

/* Пометка у имени, у значения или у карточки сущности. Смысл, а не оттенок:
   нейтральная, «присмотрись», «плохо», «служебное» и «идёт прямо сейчас».
   Больше состояний заводить нельзя - шестой цвет уже никто не различает.

   ЭТО ЕДИНСТВЕННЫЙ ВИД ПОМЕТКИ В ПАНЕЛЯХ. До этого рядом жил второй набор
   (`.badge`: капслок, 11.5px, рамка, скругление в кольцо), и на одной странице
   «Слабо» у пары твинков и «ЗАТРОНУТО АККАУНТОВ: 3» у бана выглядели как метки
   из разных программ. */
.ws-tag {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 7px;
  color: var(--muted, #9aa6b8);
  background: var(--panel-3, #1d2330);
}
.ws-tag--warn { color: #f0a94a; background: rgba(247, 164, 74, .16); }
.ws-tag--bad { color: #f08a97; background: rgba(224, 67, 95, .18); }
.ws-tag--info { color: #9bc8ff; background: rgba(155, 200, 255, .16); }
.ws-tag--live { color: #c39bff; background: rgba(165, 108, 240, .2); }

/* Пульсирующая точка живой записи. Своё имя у анимации, а не `pulse`: файл
   общий на четыре домена, и у каждого свои ключевые кадры под этим именем. */
.ws-tag__dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentcolor;
  box-shadow: 0 0 8px currentcolor;
  animation: ws-pulse 1.4s ease-in-out infinite;
}

@keyframes ws-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: .35; }
}

/* ---------- Пусто ----------
 * ОДНА строка, не плашка. В разделе «В игре» шесть пустых плашек по 170
 * пикселей занимали восемьдесят процентов страницы, и «данных нет» кричало
 * громче, чем единственное место, где данные были. */
.ws-none {
  padding: 10px 14px;
  font-size: 12.5px;
  color: var(--muted-2, #6b7789);
}

/* ---------- Хвост из нулей ----------
 * Не «пустое место», а ответ: до этого не дошёл никто. Поэтому строка живёт
 * внутри карточки со своей верхней линией, а не растворяется в фоне. Перечень
 * идёт мелко и в одну колонку - он для сверки, а не для чтения подряд. */
.ws-zeros {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 8px;
  padding: 9px 14px;
  border-top: 1px solid var(--line, #212734);
  font-size: 12px;
  color: var(--muted-2, #6b7789);
}
/* Пустая строка не рисует и линию: в форме ставок предпросмотр появляется
   только после того, как бандл со счётом денег доехал. */
.ws-zeros:empty { display: none; }
/* Предупреждение с новой строки во всю ширину: рядом с перечнем оно
   переносится посередине фразы и читается как часть перечня. */
.ws-zeros__w {
  flex-basis: 100%;
  color: var(--warn, #f0a94a);
}
.ws-zeros b {
  flex: none;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--muted, #8a94a6);
}
.ws-zeros__l { flex: none }
.ws-zeros__n {
  min-width: 0;
  font-size: 11.5px;
  line-height: 1.5;
  opacity: .8;
}

/* ---------- Матрица «строка × группы колонок» ----------
 * Для сущности с ДВУМЯ равноправными метриками в разных единицах. Полоса
 * показывает одну величину и ровно поэтому тут не годится: вторая уезжает в
 * подпись и перестаёт сравниваться по столбцу. */
/* Все свойства задаются явно, включая те, что «и так по умолчанию». Хост-
 * страница админки держит правила на голых `table`, `th` и `td` (это её
 * собственные таблицы аудита и текстов), и они протекают внутрь: подписи строк
 * приезжали КАПСОМ, а у первой колонки был свой фон. Общий вокабуляр не может
 * зависеть от того, какие таблицы завела у себя страница-носитель. */
.ws-tbl__scroll { overflow-x: auto }
/* Ширина по содержимому, а не во всю карточку. Растянутая на 1300px таблица
   из шести коротких чисел разносит подпись строки и её первое число на
   полтысячи пикселей пустоты, и строку приходится вести пальцем. */
.ws-tbl {
  width: auto;
  min-width: 0;
  border-collapse: collapse;
  font-size: 13px;
}
.ws-tbl th,
.ws-tbl td {
  background: transparent;
  border: 0;
  vertical-align: middle;
}
.ws-tbl thead th {
  padding: 7px 12px;
  text-align: right;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted-2, #6b7789);
  white-space: nowrap;
}
/* Шапка группы центрируется над своими колонками, подпись строки жмётся влево. */
.ws-tbl thead tr:first-child th[colspan] {
  text-align: center;
  color: var(--text, #eef1f6);
  padding-bottom: 2px;
}
.ws-tbl thead th[rowspan] { text-align: left; vertical-align: bottom; padding-right: 28px }
.ws-tbl thead tr:last-child th { border-bottom: 1px solid var(--line, #212734) }
.ws-tbl thead tr:first-child th[rowspan] { border-bottom: 1px solid var(--line, #212734) }
.ws-tbl tbody th {
  padding: 9px 12px;
  text-align: left;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  white-space: normal;
  color: var(--text, #eef1f6);
}
.ws-tbl tbody td {
  padding: 9px 12px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text, #eef1f6);
  white-space: nowrap;
}
.ws-tbl tbody tr + tr > * { border-top: 1px solid var(--line, #212734) }
.ws-tbl tbody tr:hover > * { background: var(--panel-2, #171c26) }
/* Линия между группами колонок: без неё шесть чисел в ряд читаются как одно
   поле, и глаз не находит, где кончаются новички и начинаются старожилы.
   Селектор с `.ws-tbl` впереди - ради веса: сброс рамок выше перебил бы
   одиночный класс и разделители пропали бы молча. */
.ws-tbl .ws-tbl__sep { border-left: 1px solid var(--line, #212734) }
/* Прочерк - это «такого тут не бывает», а не ноль, и звучать он должен тише. */
.ws-tbl__none { color: var(--muted-2, #6b7789) }

/* Счётчик внутри кнопки сегмента: «Бан 0» отвечает на вопрос, не заставляя
   нажимать. Нулю глушится фон - иначе пустая корзина выглядит важной. */
/* Значок без числа не рисуется вовсе. Пустой кружок читается как «ноль», а
   «ещё не знаем» и «ноль» - разные ответы: первый обязан молчать. Правило
   стоит ПЕРЕД остальными и ловит все .cnt, включая счётчики вкладок из
   style.css страницы-носителя. */
.cnt:empty { display: none }

.seg .cnt,
.ws-seg .cnt {
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  background: var(--panel-2, #171c26);
  color: var(--muted-2, #6b7789);
}

/* ---------- Распределение одной полосой ----------
 * Метрика с корзинами («сломал 0 / 1-9 / 10-99 / ...») - это ОДНА величина,
 * разложенная на доли, а не пять независимых. Пятью строками с нулями она
 * занимала пол-экрана на метрику; одной полосой с легендой читается целиком. */
.ws-split { padding: 9px 14px; border-bottom: 1px solid var(--line, #212734); }
.ws-split:last-child { border-bottom: 0; }
.ws-split__h {
  display: flex;
  align-items: baseline;
  gap: 9px;
  margin-bottom: 7px;
}
.ws-split__n { font-size: 12.5px; color: var(--text, #eef1f6); }
.ws-split__m { margin-left: auto; font-size: 11px; color: var(--muted-2, #6b7789); }
.ws-split__t {
  display: flex;
  height: 11px;
  max-width: 760px;
  border-radius: 999px;
  overflow: hidden;
  /* Фон темнее панели: на --panel-3 серый сегмент «не делал» неотличим от
     пустого трека, и полоса выглядит просто ненарисованной. */
  background: var(--bg, #0a0d12);
  box-shadow: inset 0 0 0 1px var(--line, #212734);
}
.ws-split__s { min-width: 3px; }
/* Шкала корзин: серый - «не начинал», дальше нарастающий акцент. Значения
   литеральные: у панелей нет общего токена для полутонов акцента. */
.ws-split__s--none { background: #3f4a5b; }
.ws-split__s--s1 { background: rgba(226, 55, 68, .34); }
.ws-split__s--s2 { background: rgba(226, 55, 68, .55); }
.ws-split__s--s3 { background: rgba(226, 55, 68, .78); }
.ws-split__s--s4 { background: #e23744; }
.ws-split__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  margin-top: 7px;
  font-size: 11.5px;
  color: var(--muted-2, #6b7789);
}
.ws-split__k { display: inline-flex; align-items: center; gap: 5px; }
.ws-split__k i {
  width: 9px;
  height: 9px;
  border-radius: 3px;
  flex: none;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .06);
}
.ws-split__k b {
  font-family: var(--ws-mono);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--muted, #9aa6b8);
}
/* Корзина без единого попадания не исчезает из легенды: «никто не дошёл» -
   это результат, а не отсутствие данных. Но и веса ей не даём. */
.ws-split__k--off b { color: var(--muted-2, #6b7789); }

/* ---------- Активность по часам ---------- */
.ws-hours {
  display: grid;
  grid-template-columns: repeat(24, 1fr);
  align-items: end;
  gap: 4px;
  padding: 14px;
  height: 116px;
  max-width: 820px;
}
.ws-hours__c {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  height: 100%;
  justify-content: flex-end;
}
/* Обычный час - приглушённый акцент, а не серый: серыми столбиками график
   читался как отключённый, особенно когда регистраций за сутки не было вовсе и
   выделять было нечего. Литерал - по той же причине, что и у шкалы корзин:
   общего токена для полутона акцента у панелей нет. */
.ws-hours__b {
  width: 100%;
  min-height: 2px;
  border-radius: 3px 3px 0 0;
  background: rgba(226, 55, 68, .38);
}
.ws-hours__b--hot { background: var(--ws-accent); }
/* Подписывается каждый третий час: двадцать четыре числа по девять пикселей
   подряд - это шум, по которому всё равно не читают точное время. */
.ws-hours__l { font-size: 10px; color: var(--muted-2, #6b7789); min-height: 12px; }

/* ---------- Подпись под разделом ---------- */
.ws-hint {
  margin: -4px 0 12px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--muted-2, #6b7789);
}

@media (max-width: 720px) {
  .ws-bar,
  .ws-row { grid-template-columns: 1fr minmax(52px, auto); }
  .ws-bar__t { grid-column: 1 / -1; order: 3; }
  .ws-bar__m,
  .ws-row__m { grid-column: 1 / -1; }
  .ws-kpi { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
  .ws-range__search { margin-left: 0; width: 100%; }
}
