/* Кабинет Competitive — тёмная тема из согласованного макета */

:root {
  /* Тёмная тема объявлена браузеру, а не только нарисована стилями. Без этого
     он рисует своим светлым всё, до чего стили не дотягиваются: полосы
     прокрутки и выпадающий список <select> — это нативные окна, и белая
     полоса посреди тёмной страницы читалась как сбой вёрстки. */
  color-scheme: dark;
  /* Наследуются, поэтому хватает одного объявления на всю страницу. */
  scrollbar-width: thin;
  scrollbar-color: #3a404e transparent;

  --bg: #0f1014;
  --surface: #181a20;
  --surface-2: #1b1e26;
  --line: #272b34;
  --line-soft: #22252d;
  --ink: #e8eaf0;
  --ink-2: #9aa0ad;
  --ink-3: #767c89;
  --accent: #5865f2;
  --accent-soft: #5865f226;
  --ok: #44ff88;
  --warn: #f39c12;
  --bad: #ff4444;
  /* «Нужна подписка FULL». Раньше этот значок был золотым (#c8a04a), а
     «включена, но не работает» — оранжевым (--warn): в легенде рядом два
     тёплых оттенка одного тона, и отличить их можно было только по подписи.
     Фиолетовый уводит состояние подписки в другой тон целиком; с акцентом
     (--accent, синий) он не спорит — точками состояний тот не рисуется. */
  --lock: #b07cf6;
  /* Золотой — только режим владельца. Цвет взят из макета Admin.dc.html:
     по нему сразу видно, что ты не на клиентской странице. */
  --own: #e0a32e;
  --own-soft: #e0a32e1f;
  --own-line: #e0a32e4d;
  /* Шрифты (с 11.10.2026). Сайт — IBM Plex Sans, команды и коды — IBM Plex
     Mono. Golos Text с заголовками Unbounded владелец назвал почерком ИИ:
     эта пара стоит на каждом втором сгенерированном лендинге. Примеры
     сообщений Discord рисуются шрифтом самого Discord: gg sans у кого он
     есть, иначе Noto Sans — его Discord и подставляет. */
  --font: 'IBM Plex Sans', -apple-system, 'Segoe UI', system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;
  --dc-font: 'gg sans', 'Noto Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

/* В режиме владельца акцент подменяется целиком — кнопки, меню и ссылки
   становятся золотыми, и перепутать его с кабинетом клиента нельзя. */
body.owner-mode {
  --accent: #e0a32e;
  --accent-soft: #e0a32e1f;
}
body.owner-mode a { color: #efb84e; }
body.owner-mode .btn-main { color: #1a1608; }

* { box-sizing: border-box; }

/* Запасной путь для Safari и старых Chrome, где scrollbar-color ещё не
   понимают. Прозрачная рамка у ползунка — чтобы он не касался краёв: без неё
   полоса выглядит толще, чем задумано. */
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: #3a404e; border-radius: 6px;
  border: 2px solid transparent; background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: #4a5162; background-clip: padding-box; }
::-webkit-scrollbar-corner { background: transparent; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.55;
  -webkit-text-size-adjust: 100%;
  /* Страница всегда во всю высоту окна, иначе на коротких страницах
     подвал повисает посреди экрана. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

a { color: #8b93f8; text-decoration: none; }
a:hover { color: #aab0fa; }

/* Команда не рвётся на две строки: `/капт` переносился после косой черты —
   «/» в конце строки, «капт» на следующей. В коде у нас только короткие
   команды и форматы, длинных строк, которым нужен перенос, нет. */
code {
  background: #23262f; border-radius: 5px; padding: 1px 6px;
  font-family: var(--mono); font-size: .9em;
  white-space: nowrap;
}

/* 900px оставляли поля шириной в треть экрана на обычном мониторе, и страница
   выглядела пустой. 1180 — по трём колонкам карточек функций. */
.wrap { max-width: 1180px; margin: 0 auto; padding-left: 20px; padding-right: 20px; }
.wrap-wide { max-width: 1560px; margin: 0 auto; padding-left: 22px; padding-right: 22px; }

/* ─── раскладка с боковым меню (макеты Main.dc.html / Admin.dc.html) ─── */
/* Сетка из двух колонок и двух строк. Левая колонка — меню и под ним полоса
   пользователя (нижняя строка, не ниже --footrow). Правая — содержимое на обе
   строки; подвал лежит внутри него последним блоком.

   Подвал раньше был своей клеткой в нижней строке и стоял на месте вместе с
   полосой пользователя. Это отнимало у каждого экрана 96 px, и владелец
   попросил, чтобы подвал уезжал со страницей (23.09.2026). Высота у него
   та же --footrow: в конце страницы линия над ним сходится с линией над
   полосой пользователя.

   Сетка занимает ровно окно и никогда не бывает выше него: меню и полоса
   пользователя стоят на месте, прокручивается только содержимое. Так это и
   нарисовано в макете — рама на весь экран, карточка подписки внизу меню.
   Пока высоту задавало содержимое, меню тянулось следом за ним и уезжало за
   нижний край: на «Каналах» карточка подписки оказывалась под сгибом, хотя
   до конца окна оставалась сотня свободных пикселей. */
/* Меню 296 px: при шрифте 15,5 px открытый пункт «Статистика войны семей»
   жирным ломался на две строки — сначала в 264 px с Golos Text, потом в
   280 px с IBM Plex Sans (он шире), когда у меню видна полоса прокрутки. */
:root { --footrow: 96px; --sidew: 296px; }
.shell {
  display: grid; flex: 1 0 auto; min-height: 0;
  height: 100vh; height: 100dvh;
  grid-template-columns: var(--sidew) minmax(0, 1fr);
  /* Нулевой минимум у верхней строки обязателен: без него строка выросла бы
     под содержимое и выдавила нижнюю за край окна. Прокрутка теперь живёт
     внутри клеток, обрезать им нечего. */
  grid-template-rows: minmax(0, 1fr) minmax(var(--footrow), auto);
}
.side {
  grid-area: 1 / 1;
  display: flex; flex-direction: column; min-width: 0;
  background: #131519; border-right: 1px solid #23262f;
  /* Снизу отступа нет: ниже идёт полоса пользователя, своя клетка сетки. */
  padding: 22px 16px 0;
  /* На низком окне меню прокручивается само, а не режется: до карточки
     подписки надо доходить в любом случае. */
  min-height: 0; overflow-y: auto;
}
/* Логотип живёт в меню, как в макете; шапки на этих страницах нет вовсе. */
.side-logo { padding: 0 6px 20px; }
.main {
  /* Обе строки сетки: нижняя клетка второй колонки больше не держит подвал —
     он внутри, в конце содержимого, и уезжает вместе с ним. */
  grid-area: 1 / 2 / 3 / 3; min-width: 0; display: flex; flex-direction: column;
  /* Прокручивается только эта клетка: меню и полоса пользователя стоят на
     месте. overflow-y здесь включает и горизонтальную прокрутку — широкая
     таблица поедет внутри колонки, а не потащит за собой всю страницу. */
  min-height: 0; overflow-y: auto;
}
/* 1280 оставляли справа пустую полосу в треть экрана, 1800 — то же на
   мониторе 2K/4K или при уменьшенном масштабе браузера (владелец, 09.10.2026:
   на 67% страница функции занимала две трети окна). Верхней границы нет:
   абзацы держат свою ширину сами (.lede — 62ch), карточки раскладываются
   сеткой по ширине окна. */
.main > .inner { flex: 1 0 auto; min-width: 0; padding: 30px 34px 40px; }

/* Пользователь и выход — под меню, как в макете панели владельца. Своя
   клетка сетки, а не хвост колонки: так она стоит внизу окна, сколько бы
   пунктов ни было в меню. Фон и правая граница продолжают меню — иначе
   колонка обрывалась бы на полпути. */
.side-user {
  grid-area: 2 / 1;
  display: flex; flex-direction: column; justify-content: center; gap: 10px;
  min-width: 0; padding: 0 16px;
  background: #131519; border-right: 1px solid #23262f;
  border-top: 1px solid #23262f;
}
.side-user .who { justify-content: flex-start; }
.side-user .who-name {
  flex: 1 1 auto; min-width: 0; font-size: 15.5px; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.side-user .ownerlink { justify-content: center; height: 34px; }

.ico { flex-shrink: 0; }

/* выбор сервера в шапке меню */
.srvpick {
  display: flex; align-items: center; gap: 10px; padding: 10px;
  background: #1b1e26; border: 1px solid #2a2e39; border-radius: 10px;
  margin-bottom: 18px; color: var(--ink);
}
.srvpick:hover { border-color: #3a4050; color: var(--ink); }
.srvpick-name { display: flex; flex-direction: column; gap: 1px; flex: 1 1 auto; min-width: 0; }
.srvpick-name b {
  font-size: 15.5px; font-weight: 600; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.srvpick-name span { font-size: 14px; color: var(--ink-3); }

.nav { display: flex; flex-direction: column; gap: 3px; }
/* Подзаголовок группы меню: «Сервер», «Модерация», «Участнику». */
.nav-head { margin: 14px 12px 4px; font-size: 12.5px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.nav-head:first-child { margin-top: 2px; }
.nav-item {
  display: flex; align-items: center; gap: 11px;
  padding: 10px 12px; border-radius: 9px;
  color: var(--ink-2); font-size: 15.5px;
}
.nav-item:hover { background: #1b1e26; color: var(--ink); }
.nav-item.is-on { background: var(--accent-soft); color: var(--ink); font-weight: 600; }
.nav-item.is-on .ico { color: var(--accent); }

/* Разделы внутри пункта меню (статистика ВЗП). Раскрываются, только когда ты
   в этом пункте: семь экранов в меню всегда утопили бы остальные восемь
   пунктов. Линия слева показывает вложенность там, где отступа мало. */
.nav-subs {
  display: flex; flex-direction: column; gap: 1px;
  margin: 2px 0 6px 21px; padding-left: 10px;
  border-left: 1px solid var(--line);
}
.nav-sub {
  display: block; padding: 7px 10px; border-radius: 7px;
  color: var(--ink-2); font-size: 15px;
}
.nav-sub:hover { background: #1b1e26; color: var(--ink); }
.nav-sub.is-on { background: #1b1e26; color: var(--ink); font-weight: 600; }

/* Карточка подписки прижата к низу меню. Нижний отступ её же: у колонки
   его нет, и без него карточка упиралась бы в линию. */
.side-foot { margin-top: auto; padding-top: 18px; padding-bottom: 14px; }
.subcard {
  display: flex; flex-direction: column; gap: 9px; padding: 14px;
  background: #1b1e26; border: 1px solid #2a2e39; border-radius: 11px;
}
.subcard-top { display: flex; align-items: center; gap: 8px; font-size: 15px; }
.subcard-tail { font-size: 14.5px; line-height: 1.45; color: var(--ink-2); }
.subcard .btn { height: 36px; font-size: 15px; }

.ownerbadge {
  display: flex; align-items: center; gap: 9px; margin-bottom: 18px;
  padding: 9px 12px; border-radius: 9px;
  background: var(--own-soft); border: 1px solid var(--own-line);
  color: var(--own); font-size: 15px; font-weight: 600;
}

/* шапка */
header { border-bottom: 1px solid var(--line); }
.bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 62px; }
/* На страницах с меню логотип слева в самом меню, поэтому шапка прижимает
   аватар и выход вправо. */
.bar-wide { max-width: none; padding: 0 22px; justify-content: flex-end; }
.logo { font-size: 20px; font-weight: 700; letter-spacing: -0.01em; color: var(--ink); }
.logo:hover { color: var(--ink); }
/* Ссылки рядом с логотипом («Главная» у «Моих серверов»): прижимают
   остальное вправо, к аватару. */
.bar-nav { display: flex; gap: 22px; margin-left: 6px; margin-right: auto; font-size: 15.5px; }
.bar-nav a { color: var(--ink-2); }
.bar-nav a:hover { color: var(--ink); }
.who { display: flex; align-items: center; gap: 10px; font-size: 16px; color: var(--ink-2); }
.out { font-size: 15.5px; color: var(--ink-3); }
.ava { border-radius: 50%; display: block; }
.ava-text, .gico-text {
  display: flex; align-items: center; justify-content: center;
  background: #2d3140; color: #c8cdd8; font-weight: 600;
}
.ava-text { border-radius: 50%; font-size: 15px; }
.gico { border-radius: 12px; display: block; flex-shrink: 0; }
/* display:flex обязан стоять ПОСЛЕ .gico — у классов одинаковая специфичность,
   и при обратном порядке .gico перебивает центрирование своим display:block. */
.gico-text {
  border-radius: 12px; font-size: 19px; flex-shrink: 0; line-height: 1;
  display: flex; align-items: center; justify-content: center;
}

/* Забирает всё свободное место и прижимает подвал к низу окна.
   Только для страниц без меню (вход, список серверов): там main и footer —
   прямые дети body. На страницах с меню это же правило доставалось .main
   и .foot-inner внутри сетки и ломало обе клетки: содержимому доставались
   лишние 94 px сверху и снизу (к собственным отступам .inner), отчего на
   «Каналах» появлялась прокрутка на пустом месте, а подвал из-за
   margin-top:auto переставал растягиваться на свою строку — ссылки
   сползали в последние 22 px, и линия над ними не сходилась с линией над
   полосой пользователя. */
body > main { padding-block: 34px 60px; flex: 1 0 auto; }
body > footer { margin-top: auto; }

h1 {
  font-size: clamp(24px, 4vw, 30px); font-weight: 600; line-height: 1.25;
  letter-spacing: -0.01em; margin: 0 0 10px;
}
.lede { font-size: 17px; color: var(--ink-2); margin: 0 0 18px; max-width: 62ch; text-wrap: pretty; }
.muted { font-size: 15px; color: var(--ink-3); }

/* карточки */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 14px; padding: 26px; margin-bottom: 14px;
}
.center { display: flex; justify-content: center; padding-top: 30px; }
.login { width: 100%; max-width: 440px; text-align: left; }
.hr { height: 1px; background: var(--line); margin: 20px 0; }
.perm-title { font-size: 15px; font-weight: 600; color: #c4c9d4; margin-bottom: 8px; }
.perms { margin: 0 0 14px; padding-left: 20px; color: var(--ink-2); font-size: 16px; }
.perms li { margin-bottom: 5px; }

/* кнопки */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: 46px; padding: 0 22px; border-radius: 10px;
  /* Фон обязателен. У <a class="btn"> его отсутствие незаметно, а <button>
     без него берёт системный buttonface и оказывается белым пятном —
     именно так выглядела кнопка «Создать новый канал». */
  background: var(--surface-2);
  border: 1px solid #343947; color: var(--ink);
  font-size: 16.5px; font-weight: 600;
  /* Рука — как у ссылок меню. <a class="btn"> получает её от браузера сам,
     а <button> («Оплатить», «Сохранить») без этого показывал стрелку. */
  cursor: pointer;
}
.btn:hover { color: var(--ink); border-color: #4a5060; background: #22262f; }
.btn-main { width: 100%; background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-main:hover { background: #4b57e0; border-color: #4b57e0; color: #fff; }
.btn-sm { height: 38px; padding: 0 16px; font-size: 15.5px; }
/* Кнопка своей страницы настройки (поле type=page, «Настроить карты»):
   значок с отступом от текста, а не вплотную. */
.pagebtn { gap: 8px; }
.btn-buy { border-color: #3b4568; color: #aab0fa; }
.btn-buy:hover { border-color: var(--accent); color: #c3c7fb; }
/* Ставится ПОСЛЕ .btn-main, иначе та растянет кнопку на всю ширину. */
.btn-inline { width: auto; height: 44px; cursor: pointer; font: inherit; font-weight: 600; }
/* pointer-events снимает и наведение: без него выключенная кнопка (⬆ у первой
   строки, «Да, удалить» на отсчёте) подсвечивалась как рабочая. */
.btn:disabled { opacity: .5; pointer-events: none; }

/* формы на странице функции */
.card h2 { font-size: 19px; margin: 0 0 6px; }
.chform { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; margin-top: 14px; }
/* В форме добавления у поля есть подпись сверху, и кнопка, выровненная по
   центру, вставала выше самого поля. Здесь равняем по низу — кнопка стоит
   на одной линии с вводом. */
.addform, .chform-low { align-items: flex-end; }
/* appearance: none обязателен. Без него браузер рисует <select> своим
   нативным виджетом, и заданный фон живёт только в покое: под курсором и
   нажатым поле перекрашивалось системным серым — стиль будто пропадал.
   Свою стрелку приходится рисовать самим: нативная уходит вместе с виджетом.
   Она в background-image, поэтому фоновый цвет задаётся отдельным свойством —
   сокращённое background затёрло бы её. */
.sel {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  flex: 1 1 260px; min-width: 0; height: 44px; padding: 0 34px 0 12px;
  background-color: #1f222a;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%239aa0ad' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 11px 7px;
  border: 1px solid #343947; border-radius: 9px;
  color: var(--ink); font: inherit; cursor: pointer;
}
.sel:hover { border-color: #4a5060; background-color: #22262f; }
.sel:disabled { opacity: .5; cursor: default; }
/* Сам выпадающий список рисует система, и управлять им почти нечем. Цвета
   пунктов она всё же берёт отсюда — иначе на тёмной странице открывался
   белый список. */
.sel option { background: #1f222a; color: var(--ink); }

/* поля настроек */
.fld { margin-bottom: 18px; min-width: 0; }
.flabel { font-size: 15.5px; font-weight: 600; color: #c4c9d4; margin-bottom: 7px; }
.fhint { display: block; font-size: 14.5px; font-weight: 400; color: var(--ink-3); margin-top: 2px; }

/* Поля в колонках. Четыре подряд поля «сколько минут» занимали по строке
   каждое, растягивая страницу вниз при пустой правой половине. Широким типам
   (текст панели, списки ролей, перечни) колонка всё так же отдаётся целиком —
   у них содержимое, а не одно число. */
.fldgrid {
  display: grid; gap: 4px 16px;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  /* stretch, а не start: у поля с подсказкой подпись в две строки, и при
     выравнивании по верху его ввод уезжал ниже соседних. Ячейки строки
     тянутся на одну высоту, а ввод прижимается к низу — тогда все вводы
     строки стоят на одной линии независимо от длины подписей. */
  align-items: stretch;
}
.fldgrid > .fld { display: flex; flex-direction: column; }
/* auto съедает свободное место над вводом; 7px у подписи остаются как
   минимальный зазор, когда свободного места нет. */
.fldgrid > .fld > .flabel ~ * { margin-top: auto; }
.fldgrid > .fld-wide { grid-column: 1 / -1; }
/* В узкой ячейке число занимает всю ширину: 140px внутри 230px выглядели
   обрезком, а рядом с ними оставалась пустая полоса. */
.fldgrid .inp-num { width: 100%; }

/* Знак «?» рядом с подписью: наведение объясняет настройку словами, а не
   термином. Кнопка, а не просто span, — чтобы подсказка открывалась и с
   клавиатуры, и по нажатию на телефоне, где наведения нет.
   Круг рисует сам значок (list_help.Q_ICON), а не рамка кнопки: рамка и
   значок внутри неё округлялись до пикселя каждый по-своему, и знак
   садился не по центру. */
.fq {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; margin-left: 6px; padding: 0;
  border: 0; border-radius: 50%; background: transparent;
  color: var(--ink-3); font: inherit; font-size: 13px; font-weight: 700;
  line-height: 1; cursor: help; vertical-align: middle; position: relative;
}
.fq:hover, .fq:focus-visible { color: var(--ink); outline: none; }
.fq-pop {
  position: absolute; left: 50%; bottom: calc(100% + 8px); z-index: 30;
  width: max-content; max-width: 320px; transform: translateX(-50%);
  padding: 9px 11px; border: 1px solid #343947; border-radius: 9px;
  background: #23262f; box-shadow: 0 10px 26px #00000073;
  color: var(--ink-2); font-size: 14.5px; font-weight: 400; line-height: 1.45;
  text-align: left; white-space: normal;
  /* Скрытая подсказка не должна занимать места: с visibility: hidden она
     оставалась в раскладке, и у правого края 320px вылезали за колонку —
     под страницей появлялась горизонтальная прокрутка. */
  display: none;
}
.fq:hover .fq-pop, .fq:focus-visible .fq-pop, .fq:focus .fq-pop {
  display: block;
}
/* Подсказка у самого края колонки вылезала за экран — крайние поля
   прижимают её к своей стороне. */
.fld:first-child .fq-pop, .bool-row:first-child .fq-pop {
  bottom: auto; top: calc(100% + 8px);
}
.inp {
  width: 100%; padding: 11px 12px;
  background: #1f222a; border: 1px solid #343947; border-radius: 9px;
  color: var(--ink); font: inherit; line-height: 1.5;
}
/* Однострочные поля — той же высоты, что выпадающие списки (.sel, 44px). По
   отступам они выходили 46,5px, и в строке сетки рядом со списком поле
   торчало на 3px выше: низы выровнены по ячейке, и разница вылезала сверху —
   соседний список казался меньше. Многострочные поля растут сами, а у поля
   файла своя кнопка внутри — их не трогаем. */
input.inp:not([type="file"]) { height: 44px; padding-block: 0; }
.inp:focus, .sel:focus { outline: none; border-color: var(--accent); }
.inp-num { width: 140px; }
/* Многострочные поля растут под текст (где браузер умеет field-sizing);
   уголок остаётся — для тех, где не умеет. */
textarea.inp { resize: vertical; min-height: 84px; field-sizing: content; }
.fld .sel { width: 100%; flex: none; }

/* списки ролей и категорий: галочки вместо множественного выбора —
   в <select multiple> нужен ctrl+клик, о котором люди не догадываются */
.chklist {
  max-height: 210px; overflow-y: auto;
  border: 1px solid #343947; border-radius: 9px; background: #1f222a;
  padding: 6px;
}
.chk {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 8px; border-radius: 7px; cursor: pointer; font-size: 15.5px;
}
.chk:hover { background: #262a35; }

/* Галочка рисуется своя. Системная в тёмной теме выглядит белым квадратом
   с рамкой не в стилистике — именно это и было видно в списках ролей. */
.chk input {
  appearance: none; -webkit-appearance: none;
  width: 18px; height: 18px; flex-shrink: 0; margin: 0;
  border: 1.5px solid #4a5060; border-radius: 5px; background: #23262f;
  cursor: pointer; position: relative;
  transition: background .12s ease, border-color .12s ease;
}
.chk input:hover { border-color: #69708a; }
.chk input:checked { background: var(--accent); border-color: var(--accent); }
.chk input:checked::after {
  content: ""; position: absolute; left: 5px; top: 1.5px;
  width: 4px; height: 9px; border: solid #fff;
  border-width: 0 2px 2px 0; transform: rotate(42deg);
}
.chk input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.chk input:disabled { opacity: .5; cursor: not-allowed; }

/* Роли — как в Discord: кружок цвета роли и имя тем же цветом. На сервере
   их полсотни, и по цвету роль узнают быстрее, чем по названию. */
.role { display: inline-flex; align-items: center; gap: 9px; min-width: 0; }
.role-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
.role-name {
  font-weight: 500; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.role-note { font-size: 13.5px; color: var(--ink-3); flex-shrink: 0; }

/* переключатели на странице функции */
.bool-row {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 9px 0; cursor: pointer;
}
.bool-label { font-size: 15.5px; color: var(--ink); }

/* Карточки в две колонки: на 1180px одна колонка формы оставляла половину
   экрана пустой. align-items:start — чтобы короткая карточка не растягивалась
   под высоту соседней. */
.panels {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 14px; align-items: start; margin-bottom: 14px;
}
.panels > .card { margin-bottom: 0; }
/* ─── страница настроек функции: разделы и строки ───
   Владелец, 09.10.2026: поля плиткой и карточки разной высоты в сетке
   читались кашей. Теперь раздел — карточка, настройка — строка: название и
   пояснение слева, поле справа, строки разделены линией.
   19.10.2026 (владелец, в пример — настройки на discord.com/developers):
   разделы идут одной колонкой во всю ширину, поля тянутся до правого края,
   переключатель стоит у правого края. Газетные колонки — две карточки
   рядом — давали четыре столбца «название — поле — название — поле», и
   глаза разбегались, а поля по 520 px оставляли полкарточки пустой. */
/* Без container-type: он делает карточку отдельным слоем, и выпадающий
   список (.pick-pop) из нижней строки раздела уходил под следующую карточку. */
.setsec { padding-bottom: 10px; }
.setsec > h2 { margin-bottom: 6px; }
/* Колонка названий — не доля карточки, а потолок по длинной подписи
   («Канал статистики рекрутеров ?» — около 260 px): при 38 % на широком
   экране поле уезжало от короткого названия на полкарточки (владелец,
   11.10.2026). Длиннее — подпись переносится, поля в строках стоят ровно. */
.setrow {
  display: grid; grid-template-columns: minmax(200px, 280px) minmax(0, 1fr);
  gap: 8px 24px; align-items: start;
  padding: 16px 0; border-top: 1px solid var(--line-soft);
}
.setrows > .setrow:first-child { border-top: 0; }
/* Раздел без подписки — только посмотреть (render._ro): fieldset гасит поля,
   на раскладку не влияет. Строки списков по-прежнему раскрываются. */
fieldset.ro { display: contents; }
.setrows > fieldset.ro:first-child > .setrow:first-child { border-top: 0; }
/* :where — без веса: спрятанная галочка переключателя (.tgl input,
   opacity 0) остаётся спрятанной. Подпись галочки не гасим — иначе сама
   галочка в ней тускнела бы дважды. */
fieldset.ro :where(input, select, textarea, button, .pick-btn, .tgl, .btn,
                   .delbox-open) { opacity: .55; cursor: not-allowed; }
fieldset.ro a.btn { pointer-events: none; }
/* Где часть раздела открыта, закрытое подписано, чтобы не искать, почему
   поле не меняется. */
fieldset.ro-mark .setrow-l > .flabel::after,
fieldset.ro-mark .card > h2::after,
fieldset.ro-mark .tblsub > h3::after,
fieldset.ro-mark .tblsub > summary > h3::after {
  content: "по подписке"; margin-left: 8px; padding: 1px 8px; border-radius: 999px;
  background: var(--line); color: var(--ink-2); font-size: 11px; font-weight: 600;
  vertical-align: 2px; white-space: nowrap;
}
.setrow[hidden] { display: none; }
.setrow-l { display: flex; flex-direction: column; min-width: 0; padding-top: 10px; }
.setrow-l .flabel { margin-bottom: 0; }
.setrow-c { min-width: 0; }
/* Поля — до правого края. Выпадающий список со скриптами — это .pick, он
   и так во всю ширину; без скриптов .sel сжимался бы по самому длинному
   варианту. Число (.inp-num, 140 px) остаётся коротким. */
.setrow-c > .sel { width: 100%; }
/* Галочки — сеткой во всю ширину поля, как права бота в Discord: столбик
   имён у левого края оставлял бы пустую рамку, а так без прокрутки видно
   в несколько раз больше ролей. Читаются по строкам слева направо, в
   порядке ролей сервера. Клетка от 250 px — чтобы влезали длинные имена и
   пометка «роль бота»; не влезло — многоточие, имя целиком в title. */
.setrow-c .chklist {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 0 8px; align-content: start;
}
/* Длинный текст (текст панели, ссылки) — на всю ширину под названием. */
.setrow-stack { grid-template-columns: minmax(0, 1fr); }
.setrow-stack .setrow-l { padding-top: 0; }
/* Переключатель — у правого края строки, как в настройках Discord:
   название и пояснение тянутся до него, вся строка нажимается. */
.setrow-sw { grid-template-columns: minmax(0, 1fr) auto; align-items: center; cursor: pointer; }
.setrow-sw .setrow-l { padding-top: 0; }
/* У .tgl поля нажатия шире самого тумблера — без этого он не доходил до
   правого края полей над ним на 2 px. */
.setrow-sw .tgl { margin-right: -10px; }
/* Подпункт строки над ним («Какие итоги публиковать» под «Каналом итогов»):
   без верхней черты и с чертой слева у названия — читается одной группой,
   а не отдельной обязательной настройкой. Поле остаётся в общей колонке. */
.setrow-sub { border-top: 0; padding-top: 4px; }
.setrow-sub .setrow-l { padding-left: 14px; border-left: 2px solid var(--line); }
/* Узкая карточка — название над полем: две колонки по 200 px читать
   тяжелее, чем одну. Узко на телефоне и в колонке формы рядом с
   предпросмотром панели (.editgrid: окно − меню − 460 px предпросмотра;
   ниже 1080 px предпросмотр уезжает под форму и колонка снова широкая). */
@media (max-width: 700px) {
  .setrow { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .setrow-l { padding-top: 0; }
  .setrow-sw { grid-template-columns: minmax(0, 1fr) auto; }
}
@media (min-width: 1081px) and (max-width: 1500px) {
  .editcol .setrow { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .editcol .setrow-l { padding-top: 0; }
  .editcol .setrow-sw { grid-template-columns: minmax(0, 1fr) auto; }
}
.notes { display: flex; flex-direction: column; gap: 6px; }

/* списки записей: направления заявок, направления магазина */
.rowbox {
  border: 1px solid var(--line); border-radius: 10px;
  background: #1b1e26; margin-bottom: 9px;
}
.rowbox > summary {
  padding: 12px 14px; cursor: pointer; font-size: 16px; font-weight: 600;
  list-style: none; user-select: none;
}
.rowbox > summary::-webkit-details-marker { display: none; }
.rowbox > summary::before { content: "▸ "; color: var(--ink-3); }
.rowbox[open] > summary::before { content: "▾ "; }
.rowbox > summary:hover { color: #fff; }
.rowbox > form { padding: 4px 14px 14px; border-top: 1px solid var(--line); }
.rowbox .fld { margin-top: 14px; margin-bottom: 0; }
/* Карточка-строка без раскрывашки: заявки поставок, сценарии проверки ролей,
   отработки выговоров, выдача покупок. У <details> поля дают summary и форма,
   а у простой обёртки их не было — текст лежал вплотную к рамке. Линию под
   шапкой снимаем: ниже её проводит блок кнопок, и линий выходило две. */
div.rowbox { padding: 0 14px 14px; }
div.rowbox > .chrow { border-bottom: 0; }
/* Форма внутри блока-строки: поля у блока уже есть, и собственный отступ
   формы (он для <details class="rowbox">) сдвигал кнопки «Товар выдан»,
   «Отказать» правее названия над ними. */
div.rowbox > form { padding-left: 0; padding-right: 0; }
/* Номер строки в списках, где порядок — это правило (тиры: 1 — высший). */
.rownum {
  display: inline-block; min-width: 22px; margin-right: 6px;
  color: var(--ink-3); font-weight: 700;
}
/* Кнопки порядка — узкие, рядом с «Сохранить», а не в заголовке строки:
   в <summary> клик по кнопке сворачивал бы саму строку. Это запасной путь:
   там, где перенос работает (.is-drag ставит dash.js), их не видно — два
   способа делать одно и то же в одной строке только путают. */
.btn-ord { width: auto; height: 38px; padding: 0 12px; font-size: 17px; cursor: pointer; }
.rowacts-ord { margin-right: auto; display: flex; gap: 8px; }
.is-drag .rowacts-ord { display: none; }
/* Без стрелок «Сохранить» осталось бы одно у левого края — вправо его
   прижимал их margin-right: auto. */
.is-drag .rowacts { justify-content: flex-end; }

/* ─── перенос строк мышью ───
   Порядок в списке приоритета — это настройка, и собирать его шагами ⬆⬇
   значит раскрыть каждую строку и нажать столько же раз, сколько строк.
   Здесь строка берётся за заголовок и ставится на место. */
.dragnote { margin: -4px 0 12px; font-size: 14.5px; }
.rowlist { position: relative; }
/* Пока тянут, браузер не должен ни прокручивать страницу от движения пальца,
   ни выделять текст под указателем. */
.is-drag > .rowbox > summary { touch-action: none; }
.is-dragging-any { user-select: none; }
.rowbox.is-dragging {
  border-color: var(--accent); background: #20242f;
  box-shadow: 0 10px 26px rgba(0, 0, 0, .45);
  opacity: .96;
}
/* Ручка: шесть точек слева от номера. Кнопка, а не значок, — с клавиатуры
   порядок меняется стрелками ↑ ↓ на ней. */
.grip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; padding: 0; margin-right: 4px;
  vertical-align: -5px;
  border: 0; border-radius: 6px; background: transparent;
  color: var(--ink-3); cursor: grab;
}
.grip .ico { stroke-width: 2.6; }
.grip:hover { color: var(--ink); background: #23262f; }
.grip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.is-dragging .grip, .rowbox.is-dragging summary { cursor: grabbing; }

/* Список строк ячейками (вопросы анкеты, карты, метки, ветки): ручка, номер,
   поле, счётчик знаков и крестик — в одну строку. Исходное поле формы
   скрыто скриптом, без него остаётся текст «по пункту в строке». */
.lines-ed { display: flex; flex-direction: column; gap: 8px; }
.lcells { display: flex; flex-direction: column; gap: 6px; }
.lcell {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 6px 4px 4px; border: 1px solid transparent; border-radius: 10px;
}
.lcell.is-dragging {
  border-color: var(--accent); background: #20242f;
  box-shadow: 0 10px 26px rgba(0, 0, 0, .45); user-select: none;
}
.lgrip { margin-right: 0; flex: none; touch-action: none; }
.lnum {
  flex: none; min-width: 26px; text-align: right;
  color: var(--ink-3); font-size: 15px; font-variant-numeric: tabular-nums;
}
.lin { flex: 1 1 auto; min-width: 0; }
.lcnt {
  flex: none; min-width: 46px; text-align: right;
  color: var(--ink-3); font-size: 13.5px; font-variant-numeric: tabular-nums;
}
.lcnt.is-over { color: var(--warn); font-weight: 600; }
.ldel {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0; border: 0; border-radius: 8px;
  background: transparent; color: var(--ink-3); cursor: pointer;
}
.ldel:hover, .ldel:focus-visible { color: #ff8080; background: #2a1a1e; outline: none; }
.lfoot { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; }
.ladd { width: auto; cursor: pointer; font: inherit; font-weight: 600; }
.lnote { color: var(--ink-3); font-size: 14.5px; }
.lnote.is-over { color: var(--warn); }
.lines-ed .lstd-hint, .lines-ed .lstd-note { margin-top: 8px; }
.lines-ed .lstd-hint[hidden], .lines-ed .lstd-note[hidden] { display: none; }

/* Форма добавления с несколькими полями (например «ID сервера» + «название»)
   выстраивается в строку и переносится, а не растягивает каждое поле. */
.chform .fld { margin-bottom: 0; flex: 1 1 200px; min-width: 0; }
.chform .inp-num { width: 100%; }

.rowacts {
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line);
}
.btn-danger { border-color: #5c2f36; color: #ff8080; }
.btn-danger:hover { border-color: #7a3c46; color: #ff9a9a; }

/* Удаление в два шага. Галочка «подтвердить» стояла впритык к кнопке: отметить
   и нажать — одно движение, защиты в этом нет. Теперь «Удалить» только
   раскрывает предупреждение, а кнопка внутри первые секунды не нажимается —
   их хватает, чтобы прочитать, что написано выше. Без скриптов отсчёта нет,
   но сам второй шаг остаётся: это обычный <details>. */
/* Вне строк-списков раскрывающаяся кнопка стоит ровно по левому краю
   текста над ней. Раньше отступ 14 px был общим, и в обычной карточке
   «Обнулить всем баланс», «Убрать сервер» съезжали вправо от текста. */
.delbox { margin: 12px 0 0; }
/* В строке-списке (<details class="rowbox">) поля идут с отступом 14 px —
   кнопка удаления стоит с ними вровень. */
.rowbox > .delbox { margin: 0 14px 14px; }
/* Удаление в ряду кнопок строки: слева, «Сохранить» — справа. Отдельной
   строкой под формой оно оставляло между полями и собой пустую полосу во
   всю ширину («Приоритет состава»). Раскрытое предупреждение занимает ряд
   целиком, «Сохранить» переносится под него. */
.rowacts > .delbox { margin: 0 auto 0 0; }
.rowacts > .delbox[open] { flex-basis: 100%; }
/* Без скриптов слева стоят ещё и стрелки порядка — удаление идёт сразу за
   ними, а не посреди ряда: вправо прижимает уже его собственный отступ. */
.rowacts:has(> .delbox) > .rowacts-ord { margin-right: 0; }
/* Опасное действие в строке («Действия» функции) — у правого края, как
   кнопки соседних строк; раскрытое предупреждение — на всю ширину строки. */
.chrow > .delbox { margin: 0 0 0 auto; text-align: right; }
.chrow > .delbox[open] { flex-basis: 100%; }
.chrow > .delbox .delbox-in { text-align: left; }
/* Подпись поля в строке стоит сбоку, а не над полем — нижний отступ ей не нужен. */
.chrow-form > .flabel { margin: 0; }
/* Строка без формы правки (правила проверки шпионов): разделитель и отступ
   даёт форма, а раз её нет — рисуем их здесь, иначе кнопка липнет к заголовку. */
.rowbox > summary + .delbox {
  margin-top: 0; padding-top: 14px; border-top: 1px solid var(--line);
  margin-left: 0; margin-right: 0; padding-left: 14px; padding-right: 14px;
}
.delbox > summary {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 12px; border: 1px solid #5c2f36; border-radius: 9px;
  color: #ff8080; font-size: 15.5px; font-weight: 600;
  cursor: pointer; list-style: none; user-select: none;
}
.delbox > summary::-webkit-details-marker { display: none; }
.delbox > summary:hover,
.delbox[open] > summary { border-color: #7a3c46; color: #ff9a9a; background: #2a1a1e; }
.delbox-in {
  margin-top: 10px; padding: 15px 16px;
  border: 1px solid #5c2f36; border-radius: 10px; background: #241a1e;
}
.delbox-title { display: block; font-size: 16.5px; color: var(--ink); }
.delbox-note {
  margin: 7px 0 15px; font-size: 15px; line-height: 1.5;
  color: var(--ink-2); max-width: 70ch; text-wrap: pretty;
}
.chk-danger { font-size: 14.5px; color: var(--ink-3); padding: 0; }
.chk-danger:hover { background: none; }

/* Операции над списком целиком (перенос уровней из Tier). Стоят под формой
   добавления и раскрываются, как удаление: такая кнопка затирает список,
   и одного клика для этого мало. Цвет не красный — импорт ничего не теряет
   безвозвратно, его можно повторить и переписать. */
.tableacts { margin-top: 14px; }
.actbox { margin: 0; }
.actbox > summary { border-color: var(--line); color: var(--ink-2); }
.actbox > summary:hover,
.actbox[open] > summary { border-color: #3d4350; color: var(--ink); background: #20232b; }
.actbox .delbox-in { border-color: var(--line); background: var(--surface-2); }
/* Кнопки над списком — в одном ряду с формой «Добавить» и вровень с её
   кнопкой (44 px, по нижнему краю: у поля подпись сверху). Раскрытое
   подтверждение уходит отдельной строкой на всю ширину. */
.tbladd { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; margin-top: 14px; }
.tbladd > .addform { flex: 1 1 420px; margin-top: 0; }
.tbladd > .tableacts { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 0; }
.tbladd > .tableacts:has(> .actbox[open]) { flex-basis: 100%; }
.tbladd > .tableacts > .actbox[open] { flex-basis: 100%; }
.tbladd .actbox > summary { height: 44px; padding-block: 0; }
.acthint { margin: 8px 0 0; }
/* Списки внутри карточки раздела (Table.inside): весь приоритет команды —
   выключатель, группы, «кто выше внутри группы» и итог — одной карточкой. */
.setsec.has-tables { padding-bottom: 26px; }
.tblsub { margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--line); }
.tblsub h3 { font-size: 17px; margin: 0 0 6px; }
.tblopt > summary {
  display: flex; align-items: baseline; gap: 10px;
  cursor: pointer; list-style: none; user-select: none;
}
.tblopt > summary::-webkit-details-marker { display: none; }
.tblopt > summary::before { content: "▸"; color: var(--ink-3); }
.tblopt[open] > summary::before { content: "▾"; }
.tblopt > summary h3 { margin: 0; }
.tblopt > summary:hover h3 { color: #fff; }
.tblopt-in { padding-top: 8px; }
/* «Что получится» под порядком внутри группы: итог обоих списков приоритета.
   Номер — тот же, что у строк выше (.rownum), чтобы группы узнавались. */
.outcome { margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--line); }
.outcome h3 { font-size: 16px; margin: 0 0 8px; }
.outcome-row { display: flex; align-items: baseline; padding: 4px 0; font-size: 15.5px; overflow-wrap: anywhere; }
.outcome-row > .rownum { flex: none; }
.outcome p.muted { margin: 6px 0 0; }

/* ─── страница функции — одна форма (13.10.2026) ───
   Владелец: «Назначить», «Сохранить» в строках и «Добавить» стояли далеко
   друг от друга, и было непонятно, что где применяется. Теперь всё на
   странице правится сразу, а «Сохранить изменения» внизу применяет разом. */
/* Первая кнопка формы — невидимая «сохранить»: Enter в поле браузер отдаёт
   первой кнопке, а первой видимой была бы «↑ Выше» строки списка. Не
   display: none — такую кнопку часть браузеров не считает кнопкой формы. */
.default-submit {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); border: 0; white-space: nowrap;
}
/* Поля строки списка — тем же отступом, что прежняя форма строки. */
.rowbox > .rowbody { padding: 4px 14px 14px; border-top: 1px solid var(--line); }
.rowbody > .rowacts:first-child { margin-top: 12px; padding-top: 0; border-top: 0; }
/* Удаление — отметкой: строка помечается «удалится» и уходит по «Сохранить
   изменения». Кнопка — слева в ряду, как прежнее «Удалить». */
.rowdel { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-right: auto; }
.rowdel .btn { gap: 7px; }
.rowdel .btn[hidden], .rowdel-note[hidden] { display: none; }
.rowdel-note {
  flex-basis: 100%; padding: 13px 15px;
  border: 1px solid #5c2f36; border-radius: 10px; background: #241a1e;
}
.rowdel-note .delbox-note { margin: 0 0 12px; }
.rowtag-del {
  margin-left: 10px; padding: 2px 8px; border-radius: 6px; vertical-align: 1px;
  background: #2a1a1e; color: #ff9a9a; font-size: 13.5px; font-weight: 600;
}
.rowtag-del[hidden] { display: none; }
.rowbox.is-deleted { border-color: #5c2f36; }
.rowbox.is-deleted > summary .rowtitle { text-decoration: line-through; color: var(--ink-3); }
.rowbox.is-deleted .fldgrid { opacity: .45; }
/* «Сбросить настройку кнопки» — той же отметкой, но не красной: строка не
   пропадает, а возвращается к стандартной. Стоит слева, перед «Удалить». */
.rowreset { margin-right: 0; }
.rowacts:has(> .rowreset) { justify-content: flex-start; }
.rowreset .rowdel-note { border-color: var(--line); background: #1e2230; }
.rowtag-reset { background: #1e2533; color: var(--ink-2); }
.rowbox.is-reset .fldgrid { opacity: .45; }
/* Пояснение на месте поля (type="note"): «Выдать роли» у принимающей кнопки. */
.fld-note .fnote { margin: 6px 0 0; font-size: 14.5px; color: var(--ink-2); }
/* Новые записи: пустые строки лежат наготове, «Добавить …» открывает их по
   одной. Пунктир — запись ещё не сохранена. */
.newrows { flex: 1 1 100%; display: flex; flex-direction: column; gap: 9px; }
.newrows:not(:has(> .newrow:not([hidden]))) { display: none; }
.newrow {
  padding: 10px 14px 14px; border: 1px dashed #3d4350; border-radius: 10px;
  background: #1b1e26;
}
.newrow[hidden] { display: none; }
.newrow-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px; font-size: 16px; }
.newrow-head .muted { font-size: 14.5px; }
.newrow-x {
  margin-left: auto; padding: 4px 8px; border: 0; border-radius: 6px;
  background: none; color: var(--ink-3); font: inherit; font-size: 14.5px; cursor: pointer;
}
.newrow-x[hidden] { display: none; }
.newrow-x:hover, .newrow-x:focus-visible { color: #ff9a9a; background: #2a1a1e; outline: none; }
.tbladd > .btn-add[hidden] { display: none; }
/* Текст панели: «Сейчас: стандартный текст» и «Сбросить текст» под полем. */
.txt-std { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; margin-top: 10px; }
.txt-std .up-now { flex: 0 1 auto; }
.txt-std .btn[hidden] { display: none; }
/* Предупреждение под полем с кнопкой, которая его исправляет: «Название
   семьи» не как на сайте — «Вписать как на сайте». Цвета — как у .flash-warn. */
.fwarn {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; margin-top: 10px;
  padding: 10px 12px; border: 1px solid #4a3c1c; border-radius: 10px; background: #241d10;
}
.fwarn p { flex: 1 1 240px; margin: 0; font-size: 14.5px; line-height: 1.45; color: #f0b357; }
/* Выбрано «создать новый канал» — выбор существующего не действует. */
.setrow.is-off .setrow-c { opacity: .45; }
.ch-new-note { display: block; margin-top: 8px; }
.ch-new-note[hidden] { display: none; }
/* Панели функции (магазин: витрина, отчёты, лидеры, выдача покупок) —
   свёрнутые строки, как направления. В заголовке строки её канал; строка,
   чей предпросмотр сейчас справа, отмечена полосой слева. Внутри — те же
   строки «название слева, поле справа», что у разделов. */
.pnllist { display: flex; flex-direction: column; margin-top: 12px; }
.rowbox.pnl.is-shown { border-left: 3px solid var(--accent); }
.pnl-ch {
  display: inline-block; margin-left: 10px;
  font-size: 14.5px; font-weight: 500; color: var(--ink-3);
}
.pnl-ch.is-none { color: #f0b357; }
.rowbox.pnl > .rowbody { padding-top: 0; }
.rowbox.pnl .setrows > .setrow:first-child { border-top: 0; }
.pnl-note { margin: 12px 0 0; font-size: 14.5px; }
/* Переключатель панелей (Tier: основная, дополнительные, «＋ Новая панель»).
   Вкладки переносятся на новую строку, а не уезжают за край. В надписи
   вкладки — её канал мелко. Без скриптов вкладок нет, панели идут подряд
   со своими заголовками. Списки панели («Тиры», «Направления») — внутри
   вкладки. */
.pnltabs { margin: 14px 0 4px; }
.pnltabs[hidden] { display: none; }
.pnltab {
  height: auto; min-height: 32px; padding: 5px 14px; gap: 2px 8px; flex-wrap: wrap;
  background: none; border: 0; font: inherit; font-size: 15px; cursor: pointer;
}
.pnltab:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.pnltab .pnl-ch { margin-left: 0; font-size: 13px; }
.pnltab.is-on .pnl-ch { color: var(--ink-2); }
.pnltab.is-on .pnl-ch.is-none { color: #f0b357; }
.pnlpane { margin-top: 14px; }
.pnlpane[hidden] { display: none; }
.pnlpane-title { margin: 0 0 4px; font-size: 16px; }
.is-tabbed .pnlpane-title { display: none; }
.is-tabbed .pnlpane > .pnl-note:first-of-type { margin-top: 4px; }
/* «Удалить панель» — под списками вкладки. Помеченная панель приглушена и
   зачёркнута в надписи вкладки, пока «Сохранить изменения» её не удалит. */
.pnldel { margin-top: 18px; }
.pnlpane.is-deleted > .setrows, .pnlpane.is-deleted > [data-table] { opacity: .45; }
.pnltab.is-deleted > span:first-child { text-decoration: line-through; color: var(--ink-3); }

/* список серверов */
.servers { display: flex; flex-direction: column; gap: 11px; }
.srv {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; padding: 16px 18px;
}
.srv-name { display: flex; flex-direction: column; gap: 3px; min-width: 180px; flex: 1 1 200px; }
.srv-name b { font-size: 17px; font-weight: 600; color: #f2f4f8; }
.srv-sub { font-size: 14.5px; color: var(--ink-3); }
/* ID рисуется только у серверов с одинаковыми названиями */
.srv-id {
  font-size: 13.5px; color: #5f6675; letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
}
.srv-plan { display: flex; align-items: center; gap: 8px; min-width: 190px; flex: 0 1 200px; }
.srv-plan div { display: flex; flex-direction: column; gap: 2px; }
.srv-plan b { font-size: 15.5px; font-weight: 600; }
.dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.dot-ok { background: var(--ok); }
.dot-warn { background: var(--warn); }
.dot-bad { background: var(--bad); }
.dot-none { background: #474c59; }
.srv-feat { font-size: 15px; color: #868d9a; flex: 1 1 160px; }
/* Ширина блока кнопок одна во всех строках: у сервера участника кнопка одна
   («Открыть»), у администратора две, и без общей ширины колонки подписки и
   функций у такой строки съезжали вправо. */
.srv-act {
  margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap;
  justify-content: flex-end; min-width: 236px;
}

.empty { background: #17191f; border: 1px dashed #2f333e; border-radius: 12px; padding: 20px; }
/* Отступ как у .card: «Заявок нет» прилипало к карточке под ним. */
.empty + .card, .empty + .empty { margin-top: 14px; }
.empty b { display: block; margin-bottom: 4px; color: var(--ink); }

/* «Добавить бота» под списком серверов — пунктирная карточка из макета
   Servers.dc.html. Ниже неё — серверы, где человек администратор, а бота
   нет: плитками, чтобы у админа двух десятков серверов список не тянулся
   на три экрана. */
.addbot {
  margin-top: 14px; background: #17191f; border: 1px dashed #2f333e;
  border-radius: 12px; padding: 18px 20px;
}
.addbot-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px 20px; flex-wrap: wrap;
}
.addbot-txt { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.addbot-txt b { font-size: 16px; font-weight: 600; color: var(--ink); }
.addbot-txt span { font-size: 15px; color: #868d9a; }
.addbot-head > .btn { border-color: #3a3f4d; flex-shrink: 0; }
.addbot-sub {
  margin: 18px 0 10px; padding-top: 16px; border-top: 1px solid #262a33;
  font-size: 14.5px; color: var(--ink-3);
}
/* 380 px — чтобы рядом с кнопкой помещалось обычное название сервера:
   при 280 в три колонки резалось даже «Тестовый сервер». */
.addgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); gap: 10px; }
.addrow {
  display: flex; align-items: center; gap: 12px; min-width: 0;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 10px; padding: 10px 12px;
}
/* Длинное название обрезается многоточием, а не выталкивает кнопку. */
.addrow b {
  flex: 1 1 auto; min-width: 0; font-size: 15.5px; font-weight: 600;
  color: #f2f4f8; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.addrow .btn { flex-shrink: 0; }

/* подвал */
footer { border-top: 1px solid var(--line); }
.foot-links { display: flex; flex-wrap: wrap; gap: 20px; padding-block: 20px 26px; }
/* Реквизиты уходят к правому краю той же строки, а на узком экране переносятся
   сами: отдельной строкой они прибавляли бы высоту подвалу на всех страницах,
   а он стоит в клетке сетки вместе с полосой пользователя. */
.foot-req { margin-left: auto; font-size: 15px; color: var(--ink-3); }
footer a { font-size: 15.5px; color: var(--ink-3); }
footer a:hover { color: var(--ink-2); }
/* Подвал страниц с меню — последний блок внутри .main: прокручивается вместе
   с содержимым и виден в конце страницы. Стоять на месте внизу окна, как
   раньше, ему незачем: он отнимал у каждого экрана полосу в 96 px.
   На короткой странице .inner растягивается (flex: 1 0 auto) и прижимает
   подвал к низу окна. Высота та же, что у полосы пользователя
   (--footrow), — внизу страницы линии над ними сходятся. */
.foot-inner {
  flex: 0 0 auto; display: flex; align-items: center;
  min-height: var(--footrow); border-top: 1px solid var(--line-soft);
}
.foot-inner .foot-links {
  flex: 1 1 auto; padding-inline: 34px;
  padding-block: 18px; align-items: center;
}

/* ─── страница сервера ─── */
.back { display: inline-block; font-size: 15.5px; color: var(--ink-3); margin-bottom: 16px; }
.ghead { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; margin-bottom: 16px; }
.ghead-act { margin-left: auto; }
.ghead-name { flex: 1 1 240px; min-width: 0; }
.ghead h1 { margin: 0 0 4px; }
.ghead-sub { display: flex; align-items: center; gap: 8px; font-size: 15px; color: var(--ink-2); }

/* итог сохранения */
.flash { border: 1px solid; border-radius: 12px; padding: 14px 16px; margin-bottom: 18px; }
/* Только заголовок итога — блоком. Раньше правило ловило и жирное внутри
   строк: «Обновлено каналов: **11**.» разваливалось на три строки. */
.flash > b { display: block; margin-bottom: 4px; }
.flash-ok { background: #13211a; border-color: #2a4a36; }
.flash-warn { background: #241d10; border-color: #4a3c1c; }
.flash-err { background: #241417; border-color: #4a2229; }
.flash-list { margin: 6px 0 0; padding-left: 20px; font-size: 15.5px; color: var(--ink-2); }
.flash-list li { margin-bottom: 4px; }

/* легенда состояний */
.legend { display: flex; flex-wrap: wrap; gap: 18px; margin-bottom: 16px; }
.legend span { display: flex; align-items: center; gap: 7px; font-size: 14.5px; color: var(--ink-3); }
/* Кроме цвета — своя форма: кольцо вместо заливки. По оттенку состояния
   различает не каждый, а дырка в середине видна всем. */
.dot-lock {
  background: transparent;
  box-shadow: inset 0 0 0 2.5px var(--lock);
}

/* карточки функций */
.feats {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 12px;
}
/* .feat — обычный блок: внутри и переключатель, и ссылка на настройки.
   Кнопкой его делать нельзя — ссылка внутри кнопки невалидна. */
/* Со страницы выключенной функции ведёт ссылка на её карточку — подсвечиваем,
   чтобы переключатель находился сразу. */
.feat:target { box-shadow: 0 0 0 2px var(--accent); scroll-margin-top: 24px; }
.feat {
  position: relative;
  display: flex; align-items: flex-start; gap: 12px;
  padding: 15px 16px; background: var(--surface);
  border: 1px solid var(--line); border-radius: 12px;
  transition: border-color .12s ease, background .12s ease;
}
.feat:hover { border-color: #3d4350; background: #1c1f28; }
/* Карточка-ссылка без тумблера («Опубликовать сообщение от бота»): на месте
   переключателя — значок раздела той же ширины, чтобы названия стояли ровно. */
.feat-ico { flex: 0 0 38px; display: inline-flex; justify-content: center; color: var(--ink-2); }
/* Закрытую подпиской открывают посмотреть — подсветка при наведении та же. */
.feat-locked { opacity: .75; }

/* Нажимать приходилось точно в название — это неочевидно, карточка выглядит
   кнопкой целиком. Ссылка растягивается на весь блок этим псевдоэлементом. */
.feat-title { color: var(--ink); }
.feat-title:hover { color: #fff; }
.feat-title::after { content: ""; position: absolute; inset: 0; border-radius: 12px; }
.feat-title:focus-visible::after { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Переключатель — настоящая галочка: выбор копится в браузере и уходит одной
   формой. Растянутая ссылка карточки лежит выше по стопке, поэтому
   переключателю нужен свой слой, иначе клик по нему открывал бы настройки. */
.tgl {
  position: relative; z-index: 1; display: inline-flex; flex-shrink: 0;
  /* Область нажатия больше самого переключателя: 38×22 мало для пальца.
     Отрицательный внешний отступ убирает визуальный сдвиг от padding. */
  padding: 10px; margin: -9px -8px; cursor: pointer;
}
.tgl input {
  position: absolute; inset: 0; margin: 0;
  opacity: 0; cursor: pointer; width: 100%; height: 100%;
}
.tgl-locked { cursor: not-allowed; }
.sw {
  flex-shrink: 0; width: 38px; height: 22px;
  border-radius: 11px; background: #33384a; padding: 2px;
  display: flex; transition: background .15s ease;
}
.knob { width: 18px; height: 18px; border-radius: 50%; background: #fff; transition: transform .15s ease; }
.tgl input:checked ~ .sw { background: var(--accent); }
.tgl input:checked ~ .sw .knob { transform: translateX(16px); }
.tgl input:focus-visible ~ .sw { outline: 2px solid var(--accent); outline-offset: 3px; }

.feat-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.feat-body b { font-size: 15.5px; font-weight: 600; color: var(--ink); }
.feat-state { display: flex; align-items: center; gap: 6px; font-size: 14px; color: var(--ink-2); }
.feat-desc { font-size: 14.5px; line-height: 1.45; color: #868d9a; }
.feat-hint { font-size: 14px; color: var(--ink-3); }
/* Поле, которое скрипт спрятал по data-only-if. */
.fld[hidden] { display: none; }
/* «Выбрать канал →» у включённой, но не работающей функции. */
.feat-next { font-size: 14.5px; font-weight: 600; margin-top: 2px; }
.feat-scope { color: #c8a04a; }

/* ─── ядро ───
   Работает всегда и тумблера не имеет. На месте переключателя — значок:
   пустое место читалось бы как «галочку забыли нарисовать». */
.corehead {
  margin: 18px 0 10px; font-size: 14px; font-weight: 600;
  letter-spacing: .04em; text-transform: uppercase; color: var(--ink-3);
}
.corehead:first-child { margin-top: 0; }
/* Карточка ядра стоит между двумя заголовками разделов и липла к обоим:
   «Работает всегда» читалось как её собственная подпись, а «Функции» —
   как продолжение той же группы. Отступы разведены только вокруг неё;
   верхний отступ самого заголовка не трогаем — им задано расстояние до
   вводного абзаца страницы, и оно уже верное. */
.corehead-core { margin-bottom: 20px; }
.feats-core { margin-bottom: 34px; }
.feat-core { border-color: #3a4152; background: #1b1e27; }
.core-mark {
  flex-shrink: 0; display: inline-flex; align-items: center;
  justify-content: center; width: 38px; height: 22px; color: var(--ink-3);
}

/* ─── панель «Сохранить изменения» ───
   Та же, что в настройках Discord. Со скриптами всплывает над страницей и
   трясётся при попытке уйти не сохранившись; без них остаётся обычным блоком
   внизу формы — сохранить можно в любом случае. */
.savebar { margin-top: 18px; }
.savebar-in {
  display: flex; align-items: center; flex-wrap: wrap; gap: 14px;
  background: #111214; border: 1px solid #2b2f38;
  border-radius: 10px; padding: 12px 14px;
  box-shadow: 0 8px 26px rgba(0, 0, 0, .45);
}
.savebar-txt { flex: 1 1 200px; font-size: 16px; color: #e8eaf0; }
.savebar-txt::before {
  content: "!"; display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; margin-right: 10px; vertical-align: -4px;
  border-radius: 50%; background: #f0b232; color: #111214;
  font-weight: 700; font-size: 15px;
}
.savebar-reset {
  background: none; border: 0; padding: 4px 6px; cursor: pointer;
  color: #c4c9d4; font: inherit; font-size: 15.5px;
}
.savebar-reset:hover { color: #fff; }
.savebar-save {
  height: 38px; padding: 0 16px; border: 0; border-radius: 8px; cursor: pointer;
  background: #248046; color: #fff; font: inherit; font-weight: 600; font-size: 15.5px;
}
.savebar-save:hover { background: #1f6d3b; }
.savebar-save:focus-visible, .savebar-reset:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

.js .savebar {
  position: fixed; left: 50%; bottom: 20px; z-index: 60; margin: 0;
  width: min(920px, calc(100% - 32px));
  transform: translate(-50%, 18px); opacity: 0; visibility: hidden;
  transition: opacity .16s ease, transform .16s ease, visibility .16s;
}
.js .is-dirty .savebar { transform: translate(-50%, 0); opacity: 1; visibility: visible; }

/* На страницах с меню панель стоит по центру содержимого, а не окна: иначе
   она половиной висела бы на меню. Над нижней полосой её больше не
   поднимаем — подвал теперь уезжает вместе со страницей, и под панелью
   осталось бы пустое место. */
.js .has-side .savebar {
  left: calc(50% + var(--sidew) / 2);
  bottom: 20px;
  width: min(920px, calc(100% - var(--sidew) - 32px));
}

/* Трясётся ВНУТРЕННИЙ блок: на самой панели уже висит translate(-50%),
   и анимация перебила бы центрирование. */
@keyframes savebar-shake {
  0%, 100% { transform: translateX(0); }
  15% { transform: translateX(-8px); }
  30% { transform: translateX(8px); }
  45% { transform: translateX(-6px); }
  60% { transform: translateX(6px); }
  80% { transform: translateX(-3px); }
}
.savebar-in.shake { animation: savebar-shake .55s cubic-bezier(.36, .07, .19, .97); }

@media (prefers-reduced-motion: reduce) {
  .savebar-in.shake { animation: none; }
  .js .savebar, .sw, .knob, .feat { transition: none; }
}

/* ─── страница подписки ─── */
/* Оформление — одна карточка: тариф и срок переключателями, сумма, способ
   оплаты списком и одна кнопка (макет 03.10.2026). Раньше это были две
   большие карточки тарифов с кнопками сроков и отдельный блок FunPay с
   восемью кнопками — владелец назвал это громоздким. Справа — что входит
   в выбранный тариф. Переключение сумм и списка — на :has, без скриптов;
   какие суммы показывать, задаёт <style> страницы (сроки приходят от бота). */
.paygrid { display: grid; grid-template-columns: minmax(0, 460px) minmax(0, 1fr); gap: 18px; align-items: start; }
.checkout { display: flex; flex-direction: column; gap: 16px; margin: 0; }
.co-head { display: flex; align-items: baseline; justify-content: space-between; flex-wrap: wrap; gap: 4px 12px; }
.co-head h2 { margin: 0; }
.co-head span { font-size: 14px; color: var(--ink-3); min-width: 0; overflow-wrap: anywhere; }

/* Переключатель сегментами — обычные радиокнопки. */
.seg { display: grid; gap: 4px; padding: 4px; border-radius: 11px; background: #1b1e26; border: 1px solid var(--line); }
.seg-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.seg-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.seg label { position: relative; cursor: pointer; min-width: 0; }
.seg input { position: absolute; opacity: 0; pointer-events: none; }
.seg span {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  height: 40px; padding: 0 6px; border-radius: 8px; color: var(--ink-2);
  font-weight: 600; font-size: 15px; white-space: nowrap;
}
.seg label:hover span { color: var(--ink); }
.seg input:checked + span { background: #262a34; color: var(--ink); box-shadow: 0 0 0 1px #3a404e; }
.seg input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 1px; }
.seg em { font-style: normal; font-size: 12.5px; font-weight: 500; color: var(--ink-3); }
.pdot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--ink-3); }
.pdot-full { background: var(--ok); }
.pdot-lite { background: #e0a32e; }

/* Сумма выбранного тарифа и срока. Видна одна — та, что выбрана (<style>
   страницы), без :has — подпись «Оплатить» без суммы. */
.co-total { min-height: 66px; }
.tot { display: none; flex-direction: column; gap: 2px; }
.tot-sum { font-size: 34px; font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
.tot-sum small { font-size: 21px; font-weight: 600; color: var(--ink-3); }
.tot-sub { font-size: 14.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.tot-sub b { color: var(--ok); font-weight: 600; }

/* Способ оплаты. Без скриптов — обычный список; dash.js рисует поверх него
   список со значками, а сам <select> остаётся источником значения. */
.co-label { display: block; font-size: 14px; color: var(--ink-3); margin-bottom: 6px; }
.co-method { width: 100%; }
/* Список со значками нарисован — родной прячем. Атрибута hidden мало:
   у .sel свой display, и он сильнее. */
.pm .co-method[hidden] { display: none; }
.pm { position: relative; }
.pm-btn {
  width: 100%; display: flex; align-items: center; gap: 12px; padding: 8px 12px;
  border-radius: 11px; border: 1px solid var(--line); background: #1b1e26;
  color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.pm-btn:hover { border-color: #3a404e; }
.pm-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pm-btn .pm-chev { margin-left: auto; color: var(--ink-3); transition: transform .15s; }
.pm-btn[aria-expanded="true"] .pm-chev { transform: rotate(180deg); }
.pm-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.3; }
.pm-text b { font-size: 15.5px; font-weight: 600; }
.pm-text span { font-size: 13px; color: var(--ink-3); }
.pm-ico {
  width: 36px; height: 36px; border-radius: 9px; flex-shrink: 0;
  display: grid; place-items: center;
}
.pm-sbp { background: #26243a; color: #b9a6ff; }
.pm-card { background: #1f2c3a; color: #8cc4ff; }
.pm-tpay { background: #33301c; color: #ffdd55; }
.pm-yandex { background: #3a2222; color: #ff8f80; }
.pm-abroad-card { background: #1d3328; color: #7fe0a8; }
.pm-abroad-crypto { background: #352a18; color: #f5b955; }
.pm-menu {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 20;
  margin: 0; padding: 6px; list-style: none;
  background: #1b1e26; border: 1px solid #333846; border-radius: 12px;
  box-shadow: 0 14px 34px #0009; max-height: 70vh; overflow-y: auto;
}
/* Снизу до края экрана не помещается — над кнопкой (dash.js). */
.pm-menu.is-up { top: auto; bottom: calc(100% + 6px); box-shadow: 0 -10px 30px #0009; }
.pm-menu:focus { outline: none; }  /* фокус показывает подсвеченный пункт */
.pm-group { padding: 8px 10px 4px; font-size: 12.5px; color: var(--ink-3); }
.pm-opt { display: flex; align-items: center; gap: 12px; padding: 7px 10px; border-radius: 9px; cursor: pointer; }
.pm-opt:hover, .pm-opt.is-active { background: #262a34; }

.co-pay { width: 100%; height: 50px; font-size: 16.5px; }
.pay-amt, .pay-fp, .co-note-fp { display: none; }
.co-note { margin: -6px 0 0; font-size: 14px; color: var(--ink-3); text-align: center; text-wrap: balance; }
/* FunPay: кнопка без суммы (цена там своя) и своё пояснение. */
.checkout:has(.co-method option[value^="abroad"]:checked) .pay-amt { display: none !important; }
.checkout:has(.co-method option[value^="abroad"]:checked) .pay-fp { display: inline; }
.checkout:has(.co-method option[value^="abroad"]:checked) .co-note-rub { display: none; }
.checkout:has(.co-method option[value^="abroad"]:checked) .co-note-fp { display: block; }
.checkout:has(.co-method option[value^="abroad"]:checked) .co-pay { background: #262a34; box-shadow: inset 0 0 0 1px #3a404e; }
/* Браузер без :has — суммы не переключить, кнопка просто «Оплатить». */
.pay-plain { display: none; }
@supports not selector(:has(*)) {
  .pay-plain { display: inline; }
}

/* Что входит — у выбранного тарифа (<style> страницы). */
.incl-plan { display: none; flex-direction: column; gap: 6px; }
.incl-plan h2 { margin: 0; }
@supports not selector(:has(*)) {
  .incl-plan { display: flex; }
  .incl-plan + .incl-plan { margin-top: 18px; }
}
.plan-feats { margin: 4px 0 0; padding-left: 20px; color: var(--ink-2); font-size: 15.5px; }
.plan-feats li { margin-bottom: 5px; }
/* Слева ещё сайдбар (~295 px): при окне 961 px колонке «Что входит» доставалось
   126 px — слова в столбик и горизонтальная прокрутка у <main>. В одну колонку
   переходим, пока правой не хватает ~280 px. */
@media (max-width: 1120px) {
  .paygrid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 420px) {
  .seg-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tot-sum { font-size: 30px; }
}
@media (prefers-reduced-motion: reduce) { .pm-btn .pm-chev { transition: none; } }

.ords { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.ord {
  display: flex; align-items: center; flex-wrap: wrap; gap: 14px;
  padding: 10px 12px; font-size: 15px;
  background: #1b1e26; border: 1px solid var(--line); border-radius: 9px;
}
.ord-id { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.ord-what { font-weight: 600; }
.ord-sum { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.ord-status { display: flex; align-items: center; gap: 7px; margin-left: auto; color: var(--ink-2); }
.ord-who { color: var(--ink-3); }

/* ─── предпросмотр панели ─── */
/* Слева форма, справа прилипшее сообщение: правя текст, человек видит
   результат, не сохраняя и не уходя в Discord. */
/* 460 px — ширина, при которой панель переносит строки примерно как в
   Discord: в 400 заголовок «# …» ломался на две-три строки там, где на
   сервере стоит в одну. */
.editgrid {
  display: grid; grid-template-columns: minmax(0, 1fr) 460px;
  gap: 16px; align-items: start;
}
.editcol { display: flex; flex-direction: column; min-width: 0; }
/* Выше экрана колонка прокручивается сама: у Tier под панелью ещё
   предпросмотр личного канала, и низ липкой колонки иначе не увидеть. */
.previewcol {
  position: sticky; top: 18px;
  max-height: calc(100vh - 36px); overflow-y: auto; scrollbar-width: thin;
}
.previewcol > .preview + .preview { margin-top: 16px; }
.preview { padding: 0; overflow: hidden; }
.preview-head {
  display: flex; align-items: center; gap: 9px;
  padding: 13px 16px; border-bottom: 1px solid var(--line);
  font-size: 15px; color: var(--ink-2);
}
.preview-head b { color: var(--ink); font-weight: 600; }
/* Какая панель в предпросмотре — у магазина их несколько. */
.preview-of {
  margin-left: auto; padding: 2px 9px; border-radius: 6px;
  background: #232733; color: var(--ink); font-size: 14px; font-weight: 600;
}
.preview[hidden] { display: none; }
.preview-note { padding: 0 16px 14px; margin: 0; }

/* Сообщение бота: раскладка Discord — аватар слева, всё остальное колонкой. */
.dc-msg { display: flex; gap: 14px; padding: 16px; font-family: var(--dc-font); }
.dc-ava { border-radius: 50%; flex-shrink: 0; width: 40px; height: 40px; }
.dc-ava-text {
  display: flex; align-items: center; justify-content: center;
  background: var(--accent); color: #fff; font-weight: 600;
}
.dc-body { display: flex; flex-direction: column; gap: 9px; min-width: 0; flex: 1 1 auto; }
.dc-top { display: flex; align-items: center; gap: 7px; }
.dc-name { font-size: 16px; font-weight: 600; color: #f2f4f8; }
.dc-tag {
  font-size: 12px; font-weight: 600; letter-spacing: .02em;
  background: var(--accent); color: #fff; border-radius: 4px; padding: 1px 4px;
}
/* Панель — Container из Components v2, как его рисует Discord: плашка
   светлее фона сообщения, полоса цвета модуля слева, внутри баннер, текст,
   разделители и меню. Цвет полосы присылает бот (Panel.accent). */
.dc-box {
  --dc-accent: #4e5058;
  display: flex; flex-direction: column; gap: 8px;
  background: #2b2d31; border: 1px solid #383a40;
  border-left: 4px solid var(--dc-accent); border-radius: 8px;
  padding: 14px 14px 14px 12px; min-width: 0;
}
.dc-blocks { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
/* display:flex перебивает [hidden] браузера — заголовок списка (data-preview-heading)
   выключают переключателем, и он должен пропадать. */
.dc-blocks[hidden] { display: none; }
/* Section с картинкой справа (Thumbnail) — в Discord она до 85 px. */
.dc-sec { display: flex; gap: 12px; align-items: flex-start; min-width: 0; }
.dc-sec > .dc-blocks { flex: 1; }
.dc-thumb { flex: none; width: 85px; height: 85px; border-radius: 8px; object-fit: contain; }
.dc-text {
  font-size: 15.5px; line-height: 1.375; color: #dbdee1;
  overflow-wrap: anywhere; min-width: 0;
}
.dc-empty { color: var(--ink-3); }
/* Separator между баннером, блоками текста и списком. */
.dc-sep { border: 0; border-top: 1px solid #3f4147; margin: 4px 0; width: 100%; }
.dc-sep[hidden] { display: none; }
/* Место под блок, который бот собирает сам (товары, отпуска, нарушители). */
.dc-ph {
  border: 1px dashed #4e5058; border-radius: 6px; padding: 10px 12px;
  color: #949ba4; font-size: 14px;
}
.dc-banner {
  max-width: 100%; border-radius: 6px; display: block;
  background: #1f222a; max-height: 260px; object-fit: cover;
}
.dc-banner[hidden] { display: none; }
.dc-select {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  height: 42px; padding: 0 13px; border-radius: 6px; margin-top: 2px;
  background: #1e1f22; border: 1px solid #3f4147; color: #b5bac1;
  font-size: 15px;
}
/* Подсказка меню — в одну строку с многоточием, как у меню в Discord. */
.dc-select > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dc-select > svg { flex: none; }
.dc-btn {
  display: flex; align-items: center; justify-content: center; height: 40px;
  align-self: flex-start; margin-top: 2px;
  border-radius: 6px; background: #4e5058; color: #fff;
  font-size: 15px; font-weight: 600; padding: 0 16px;
}
.dc-btn-main { background: #5865f2; }
.dc-btn-ok { background: #248046; }
.dc-btn-bad { background: #da373c; }
.dc-btn:empty { display: none; }
/* Ряд кнопок, которые не настраиваются (Panel.buttons у бота). */
.dc-btns { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2px; }
.dc-btns > .dc-btn { margin-top: 0; }
/* Кнопка панели в форме — одной строкой: значок и надпись (render._button_row). */
.btnrow { display: flex; gap: 8px; align-items: flex-start; }
.btnrow-emo { flex: 0 0 96px; }
.btnrow-lbl { flex: 1 1 auto; min-width: 0; }
/* Значок слева от надписи (Panel.field_buttons, у AFK), как в Discord. */
.dc-btn-emoji { display: inline-flex; align-items: center; margin-right: 6px; }
.dc-btn-emoji:empty { display: none; }
.dc-btn-emoji .dmd-emoji { width: 18px; height: 18px; }

/* Разметка Discord внутри панели (dashboard/dmd.py, window.DMD в dash.js).
   Размеры — как в клиенте Discord: заголовки 24/20/16, подпись мелко. */
.dc-text .dmd-p { white-space: normal; }
.dmd-h { font-weight: 700; color: #f2f3f5; line-height: 1.375; margin: 6px 0 2px; }
.dmd-h:first-child { margin-top: 0; }
.dmd-h1 { font-size: 26px; }
.dmd-h2 { font-size: 21px; }
.dmd-h3 { font-size: 17px; }
.dmd-sub { font-size: 13.5px; color: #949ba4; }
.dmd-quote {
  border-left: 4px solid #4e5058; border-radius: 4px 0 0 4px;
  padding: 0 0 0 12px; margin: 2px 0;
}
.dmd-list { margin: 2px 0; }
.dmd-li { display: flex; gap: 7px; }
.dmd-d1 { padding-left: 22px; }
.dmd-d2 { padding-left: 44px; }
.dmd-mk { flex: none; min-width: 12px; color: #dbdee1; }
/* Эмодзи — в строку текста, в размер шрифта: в заголовке крупнее, как в Discord. */
.dmd-emoji {
  width: 1.375em; height: 1.375em; object-fit: contain;
  vertical-align: bottom; display: inline-block;
}
.dmd-mention {
  background: rgba(88, 101, 242, .3); color: #dee0fc;
  border-radius: 3px; padding: 0 2px; font-weight: 500;
}
.dmd-role {
  --mc: #dee0fc; color: var(--mc);
  background: color-mix(in srgb, var(--mc) 16%, transparent);
}
.dmd-time { background: rgba(255, 255, 255, .06); border-radius: 3px; padding: 0 2px; }
.dmd-a { color: #00a8fc; }
.dmd-a:hover { color: #00a8fc; text-decoration: underline; }
.dmd-code {
  font-family: var(--mono); font-size: .85em;
  background: #1e1f22; border: 1px solid #111214; border-radius: 4px; padding: 0 3px;
}
.dmd-pre {
  margin: 4px 0; padding: 8px; border-radius: 4px; overflow-x: auto;
  background: #1e1f22; border: 1px solid #111214;
  font-family: var(--mono); font-size: 13.5px;
}
.dmd-spoiler { background: #1e1f22; color: transparent; border-radius: 3px; cursor: pointer; }
.dmd-spoiler:hover { color: inherit; background: rgba(255, 255, 255, .1); }
/* Под спойлером Discord прячет всё: у упоминания свой цвет и подложка, и
   они просвечивали сквозь плашку («Спрятать упоминание» сообщений от бота). */
.dmd-spoiler:not(:hover) * { color: transparent; background: transparent; }
.dmd-spoiler:not(:hover) img { visibility: hidden; }

/* Поле с кнопкой выбора эмодзи — смайлик в углу, как в поле ввода Discord. */
.emo-wrap { position: relative; }
.emo-wrap > .inp { padding-right: 42px; }
.emo-btn {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0; border: 0; border-radius: 6px;
  background: transparent; color: #8a909c; cursor: pointer;
}
.emo-wrap-area .emo-btn { top: 8px; transform: none; }
.emo-btn:hover, .emo-btn:focus-visible { color: #f2f3f5; background: #2b2e37; outline: none; }
.emo-btn[hidden] { display: none; }

/* Кнопки над выделением в тексте панели — как в Discord (dash.js, FMT). */
.fmt-bar {
  position: fixed; z-index: 55; display: flex; align-items: center; gap: 2px;
  padding: 4px; border-radius: 8px;
  background: #111214; border: 1px solid #2b2d31;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .45);
}
.fmt-bar[hidden] { display: none; }
.fmt-b {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0; border: 0; border-radius: 6px;
  background: transparent; color: #b5bac1; cursor: pointer;
  font: 600 16px/1 var(--font);
}
.fmt-b:hover { background: #2b2d31; color: #f2f3f5; }
/* Оформление уже стоит — кнопка подсвечена: нажатие его снимет. */
.fmt-b.is-on { background: #3f4147; color: #f2f3f5; }
.fmt-b i { font-family: Georgia, 'Times New Roman', serif; font-size: 17px; }
.fmt-sep { width: 1px; height: 20px; margin: 0 4px; background: #3f4147; }

/* Шпаргалка под текстом панели (render._MD_CHEAT): красная рамка и
   «ВНИМАНИЕ!», чтобы её не пропустили. Слева — что писать, справа — как
   покажет Discord. Со скриптами видна, только пока текст правят (is-on
   ставит dash.js) — у каждого текста на каждой странице она мозолила глаза.
   Без скриптов — всегда. */
.mdhelp {
  margin: 10px 0 0; padding: 12px 14px;
  border: 1px solid #ff444466; border-left: 4px solid var(--bad);
  border-radius: 9px; background: #ff444412;
}
.js .mdhelp:not(.is-on) { display: none; }
.js .mdhelp.is-on { animation: mdhelp-in .18s ease-out; }
@keyframes mdhelp-in {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .js .mdhelp.is-on { animation: none; }
}
.mdhelp-t { color: var(--bad); font-weight: 700; margin-bottom: 10px; }
.mdhelp-g {
  display: grid; grid-template-columns: max-content minmax(0, 1fr);
  gap: 8px 18px; align-items: center;
}
.mdhelp-c {
  justify-self: start; padding: 2px 8px; border-radius: 6px;
  background: #1f222a; border: 1px solid #343947;
  font-family: var(--mono); font-size: 13.5px; color: var(--ink);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.mdhelp .dmd-h { margin: 0; }
.mdhelp-n { margin-top: 10px; font-size: 13px; color: var(--ink-2); }
/* На телефоне — пример под кодом: в две колонки «###» не помещается. */
@media (max-width: 560px) {
  .mdhelp-g { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .mdhelp-g > .dmd-h, .mdhelp-g > div { margin-bottom: 6px; }
}

/* Само поле с эмодзи картинками (dash.js ставит его вместо textarea/input
   с data-emoji). Высота — по тексту: растёт сам, уголка нет. Пробелы и
   переводы строк — как в textarea. */
.emo-ed {
  position: relative; min-height: 84px; cursor: text;
  white-space: pre-wrap; overflow-wrap: break-word;
}
.emo-ed-i {
  width: 1.375em; height: 1.375em; object-fit: contain;
  vertical-align: bottom; display: inline-block;
}
/* Значок — одна строка, как прежнее поле: 44 px, длинное уходит вбок. */
.emo-ed-one {
  min-height: 0; height: 44px; padding-block: 0; line-height: 42px;
  white-space: pre; overflow: hidden;
}
.emo-ed-one .emo-ed-i { vertical-align: middle; }
.emo-ed.is-empty::before {
  content: attr(data-ph); position: absolute; left: 12px; top: 11px;
  color: var(--ink-3); pointer-events: none;
}
.emo-ed-one.is-empty::before { top: 0; }
.emo-ed.is-off { opacity: .6; cursor: default; }
/* Оформление не влезло в предел знаков — рамка на миг краснеет. */
.emo-ed.is-full, .emo-ed.is-full:focus { border-color: var(--bad); }

/* Окно выбора: поиск, разделы «Этот сервер» / «Эмодзи бота» / обычные,
   внизу — наведённое эмодзи крупно с именем. */
.emo-pop {
  position: fixed; z-index: 60; width: 364px; max-width: calc(100vw - 16px);
  height: 400px; max-height: calc(100vh - 16px);
  display: flex; flex-direction: column;
  background: #2b2d31; border: 1px solid #3f4147; border-radius: 10px;
  box-shadow: 0 14px 36px #0000008c; overflow: hidden;
}
.emo-pop[hidden] { display: none; }
.emo-search {
  margin: 10px 10px 6px; padding: 8px 10px; border-radius: 6px;
  border: 1px solid #3f4147; background: #1e1f22; color: var(--ink);
  font: inherit; font-size: 15px;
}
.emo-search:focus { outline: none; border-color: var(--accent); }
.emo-body { flex: 1 1 auto; overflow-y: auto; padding: 0 8px 8px; }
.emo-sec[hidden] { display: none; }
.emo-sec-t {
  position: sticky; top: 0; z-index: 1; background: #2b2d31;
  padding: 8px 4px 5px; font-size: 12.5px; font-weight: 700;
  letter-spacing: .03em; text-transform: uppercase; color: #949ba4;
}
.emo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(38px, 1fr)); gap: 2px; }
.emo-i {
  display: flex; align-items: center; justify-content: center;
  height: 38px; padding: 0; border: 0; border-radius: 6px;
  background: transparent; cursor: pointer; font-size: 24px; line-height: 1;
}
.emo-i[hidden] { display: none; }
.emo-i:hover, .emo-i:focus-visible { background: #3a3c43; outline: none; }
.emo-i img { width: 28px; height: 28px; object-fit: contain; }
.emo-foot {
  display: flex; align-items: center; gap: 10px; min-height: 48px;
  padding: 6px 12px; border-top: 1px solid #3f4147; background: #232428;
  color: #dbdee1; font-size: 14.5px; font-weight: 600;
}
.emo-face { display: inline-flex; font-size: 26px; line-height: 1; }
.emo-face img { width: 30px; height: 30px; object-fit: contain; }
.emo-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ─── каналы ─── */
.chrow {
  display: flex; align-items: center; flex-wrap: wrap; gap: 14px;
  padding: 13px 0; border-bottom: 1px solid var(--line-soft);
}
.chrow:last-child { border-bottom: 0; padding-bottom: 0; }
.chrow-name { display: flex; flex-direction: column; gap: 2px; flex: 1 1 220px; min-width: 0; }
.chrow-name b { font-size: 16px; font-weight: 600; }
.chrow-form {
  display: flex; align-items: center; gap: 10px; flex: 1 1 340px; min-width: 0;
  /* Значение и кнопка строки — у правого края: раньше они вставали в начало
     правой половины, посреди карточки, и справа оставалась пустая полоса
     («Chrome … 2240 баллы» в статистике магазина). Растущие поля (выбор
     канала) заполняют колонку сами, их это не сдвигает. */
  justify-content: flex-end; text-align: right;
}

/* Перекрытие на странице «Итоги мероприятий»: фото слева, поля справа
   одной сеткой — на узком экране фото уходит наверх. */
.grmap {
  display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start;
  padding: 14px 0; border-bottom: 1px solid var(--line-soft);
}
.grmap:last-of-type { border-bottom: 0; }
.grmap-pic { flex: 0 0 168px; display: flex; flex-direction: column; gap: 4px; }
.grmap-pic img { width: 168px; max-width: 100%; border-radius: 8px; display: block; }
.grmap-none {
  display: flex; align-items: center; justify-content: center; height: 94px;
  border: 1px dashed var(--line); border-radius: 8px; color: var(--ink-3); font-size: 14px;
}
.grmap-body { flex: 1 1 320px; min-width: 0; }
.grmap-body .fld { margin-bottom: 0; }
.grmap-marks { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.grmap.is-deleted .grmap-pic, .grmap.is-deleted .fldgrid { opacity: .45; }
.grstd { margin: 4px 0 14px; }
.grstd .fhint { margin-top: 6px; }

/* ─── плитки, вкладки, столбики ─── */
.tiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px; margin-bottom: 16px;
}
.tile {
  display: flex; flex-direction: column; gap: 6px; padding: 16px 18px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
}
/* Длинная подпись («Заблокировано») в узкой плитке из четырёх упиралась в
   край: в плитках по четыре подпись мельче, а крайний случай переносится
   по слогам, а не вылезает. */
.tile span { font-size: 14.5px; color: var(--ink-3); hyphens: auto; overflow-wrap: break-word; }
.tile { min-width: 0; }
.tiles-4 .tile span { font-size: 13.5px; }
.tile b { font-size: 28px; font-weight: 700; letter-spacing: -0.02em; color: #f2f4f8; }
.tile-sm { font-size: 18px !important; }
/* Мелкое значение в ряду с крупными числами (дата, «чаще всего») стоит в
   строке той же высоты, что число в 28 px: иначе его строка ниже, и текст
   прилипал к подписи — выше соседних чисел, а не на их уровне. */
.tile b.tile-sm { line-height: calc(28px * 1.55); }
/* Пояснение к крупному числу на той же линии: «69%  9 из 13». */
.tile-of {
  margin-left: 8px; font-size: 15px; font-weight: 500; letter-spacing: 0;
  color: var(--ink-3); white-space: nowrap;
}
.tile-ok { color: #7ee2a8 !important; }
.tile-warn { color: #f0b357 !important; }

.tabs {
  display: inline-flex; gap: 0; padding: 3px; margin-bottom: 18px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 9px;
}
.tab {
  display: flex; align-items: center; justify-content: center;
  height: 32px; padding: 0 18px; border-radius: 7px;
  font-size: 15px; color: var(--ink-2);
}
.tab:hover { color: var(--ink); }
.tab.is-on { background: #2a2e39; color: var(--ink); font-weight: 600; }

/* Ряд вкладок, который не влезает в одну строку (экраны статистики). Обычный
   .tabs — inline-flex без переноса: на телефоне он уезжал за край экрана, и
   последние вкладки было не достать. */
.tabs-wrap { display: flex; flex-wrap: wrap; gap: 2px; }

/* Действия над заявкой поставки: несколько маленьких форм подряд. Переносим
   и разделяем, иначе кнопки слипаются в одну полосу. */
.rowacts { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; }
.rowacts form { margin: 0; }

/* Заявка поставки — «защита против атаки». Раньше всё шло строками без
   подписей («40x45 · 11 111 111»), и что за числа, было не понять. Теперь
   шапка — что и сколько везут, ниже стороны лицом друг к другу, каждая со
   своими картами, а в середине — то, что сейчас решается: запись, выбор
   карт, итоговая карта и время боя. Цвет сторон не красит статус: точка
   статуса по-прежнему одна, справа в шапке. */
/* .rowbox.supcard, а не .supcard: у div.rowbox свой padding, и он сильнее. */
.rowbox.supcard { display: flex; flex-direction: column; gap: 10px; padding-top: 13px; }
.sup-head { display: flex; align-items: flex-start; flex-wrap: wrap; gap: 6px 14px; }
.sup-what { flex: 1 1 260px; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px; }
.sup-what b { font-size: 16px; font-weight: 600; }
.sup-status { display: inline-flex; align-items: center; gap: 8px; font-size: 15px; }
/* Середина фиксированной ширины: у «auto» она подстраивалась под название
   карты, и стороны соседних заявок не стояли ровной колонкой. */
.sup-vs { display: grid; grid-template-columns: minmax(0, 1fr) 190px minmax(0, 1fr); gap: 10px; }
.sup-side {
  display: flex; flex-direction: column; gap: 3px; min-width: 0;
  padding: 10px 12px; border-radius: 9px;
}
.sup-def { background: #5865f21f; border-left: 3px solid #7c86ff; }
.sup-atk { background: #f08a5d1c; border-right: 3px solid #f08a5d; text-align: right; }
.sup-who { font-size: 12.5px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; }
.sup-def .sup-who { color: #9ea6ff; }
.sup-atk .sup-who { color: #f5a682; }
.sup-side.is-won .sup-who { color: var(--ok); }
.sup-fac { font-size: 17px; font-weight: 700; overflow-wrap: anywhere; }
.sup-fac .muted { font-size: 14px; font-weight: 400; }
.sup-maps { font-size: 14px; color: var(--ink-2); }
.sup-mid {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; min-width: 0; text-align: center;
}
.sup-word { font-size: 12.5px; color: var(--ink-3); letter-spacing: .06em; text-transform: uppercase; }
.sup-pill {
  max-width: 100%; overflow-wrap: anywhere; padding: 3px 10px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--surface); font-size: 14px; font-weight: 600;
}
.sup-small, .sup-foot { font-size: 14px; color: var(--ink-3); }
/* У карточки без кнопок блок действий не рисуется — общий отступ сверху
   у него свой и под шапкой не нужен. */
.supcard > .rowacts { margin-top: 0; }
@media (max-width: 620px) {
  /* На телефоне стороны встают друг под другом, середина — между ними. */
  .sup-vs { grid-template-columns: minmax(0, 1fr); }
  .sup-atk { text-align: left; border-right: 0; border-left: 3px solid #f08a5d; }
  .sup-mid { flex-direction: row; flex-wrap: wrap; justify-content: flex-start; min-width: 0; }
}

/* Выбор карт: сетка галочек, чтобы десяток названий не уезжал в столбик. */
.mapspick { display: flex; flex-direction: column; gap: 8px; flex: 1 1 100%; }
.mapspick-head { font-size: 15px; color: var(--ink-2); }
.chkgrid { display: flex; flex-wrap: wrap; gap: 8px; }

/* Карточка периода: ряд пресетов и рядом своё поле. Отступ снизу у .tabs
   свой, поэтому внутри карточки его снимаем — иначе между рядами дыра. */
.period { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.period .tabs { margin-bottom: 0; }
/* Свой период — остаток строки после пресетов. Без этого форма сжималась до
   ширины поля, и кнопка «Показать» уезжала под него; а в 280 px не влезала
   и сама подсказка «45 или 11.05.2026-17.05.2026». */
.period .rowform { flex: 1 1 440px; flex-wrap: nowrap; }
.period .rowform .inp { flex: 0 1 420px; }

/* Строка-форма: поле и кнопка в одну линию. Поле тянется, кнопка нет. */
.rowform { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.rowform .inp { flex: 1 1 240px; }
/* Поле файлов — кнопка браузера плюс «Файл не выбран»: в 240 px надпись
   резалась до «Файл …бран». */
.rowform .inp[type="file"] { flex-basis: 300px; }
.rowform-sm .inp { flex: 0 1 280px; }

/* Карточка необратимого действия. Рамка тёплая, но не кричащая: пугать
   человека до того, как он прочитал, чем это грозит, незачем. */
.card-danger { border-color: #5c2f36; }
.card-danger h2 { color: #ff9a9a; }

/* Таблица чисел. Своя прокрутка по горизонтали: у «Игроков» десять колонок,
   и на узком экране страница иначе разъезжается целиком. */
.dtbl-wrap { overflow-x: auto; margin: 0 -4px; }
.dtbl { width: 100%; border-collapse: collapse; font-size: 15px; }
.dtbl th, .dtbl td {
  padding: 8px 10px; text-align: left; white-space: nowrap;
  border-bottom: 1px solid var(--line-soft);
}
.dtbl th {
  position: sticky; top: 0; z-index: 1;
  background: var(--surface); color: var(--ink-2);
  font-weight: 600; font-size: 14px;
}
.dtbl tbody tr:hover { background: var(--surface-2); }
.dtbl tbody tr:last-child td { border-bottom: 0; }
.dtbl td .dot { margin-right: 6px; }

.bars {
  display: flex; align-items: flex-end; gap: 3px;
  height: 150px; margin-top: 12px;
}
/* Имя намеренно НЕ .bar: так назывался контейнер шапки, и объявленный ниже
   столбик перекрашивал её в сиреневый на всю ширину окна. */
.ubar { flex: 1 1 auto; min-width: 3px; background: #7c86f5; border-radius: 3px 3px 0 0; }
.bars-axis {
  display: flex; justify-content: space-between;
  margin-top: 8px; font-size: 13.5px; color: var(--ink-3);
}

.tools { display: flex; flex-direction: column; gap: 11px; margin-top: 12px; }
.tool { display: flex; align-items: center; gap: 14px; }
/* 260 px — под «Списки: капт MajesticRP (/капт)» при шрифте 15,5 px. */
.tool-name { flex: 0 0 260px; font-size: 15.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tool-bar { flex: 1 1 auto; height: 8px; background: #23262f; border-radius: 4px; overflow: hidden; }
.tool-bar > div { height: 100%; background: #7c86f5; border-radius: 4px; }
.tool-val { flex: 0 0 60px; text-align: right; font-size: 15px; color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* ─── панель владельца ─── */
.ownsearch { display: flex; gap: 10px; margin-bottom: 14px; }
.ownsearch .inp { flex: 1 1 auto; }
.ownlist { display: flex; flex-direction: column; gap: 9px; }
.ownrow {
  display: flex; align-items: center; flex-wrap: wrap; gap: 14px;
  padding: 13px 16px; background: var(--surface);
  border: 1px solid var(--line); border-radius: 11px;
}
.ownrow-fam { display: flex; align-items: center; gap: 12px; flex: 1 1 230px; min-width: 0; }
.ownrow-fam b { display: block; font-size: 16px; font-weight: 600; }
.ownrow-plan { display: flex; align-items: center; gap: 8px; flex: 0 1 200px; }
.ownrow-plan div { display: flex; flex-direction: column; }
.ownrow-plan b { font-size: 15px; font-weight: 600; }
.ownrow-mem { font-size: 15px; color: var(--ink-3); flex: 0 0 70px; }
.ownrow-act { display: flex; align-items: center; flex-wrap: wrap; gap: 7px; margin-left: auto; }
.ownrow-act .btn { height: 32px; padding: 0 11px; font-size: 14.5px; }

/* ─── загрузка баннера ─── */
.upform { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-top: 9px; }
.upfile { flex: 1 1 200px; }
/* Поле выбора файла — у всех форм одно. Кнопку внутри рисует браузер, и без
   этого правила она была серым системным прямоугольником «Выбрать файлы»
   посреди тёмной страницы (отчёт магазина). Оформлена как .btn-sm: тот же
   фон, рамка и наведение, что у остальных кнопок кабинета. */
input[type="file"].inp {
  padding: 6px 8px; min-height: 44px; color: var(--ink-2);
  font-size: 15px; line-height: 30px; cursor: pointer;
}
input[type="file"].inp::file-selector-button {
  height: 32px; margin-right: 12px; padding: 0 14px; border-radius: 8px;
  background: var(--surface-2); border: 1px solid #343947; color: var(--ink);
  font: inherit; font-size: 14.5px; font-weight: 600; cursor: pointer;
  transition: border-color .12s ease, background-color .12s ease;
}
input[type="file"].inp:hover::file-selector-button {
  border-color: #4a5060; background: #22262f;
}
input[type="file"].inp:focus-visible { outline: none; border-color: var(--accent); }
.up-now { display: block; font-size: 14.5px; color: var(--ink-2); }
.up-heavy { color: #f0b357; }
/* Строка про вес выбранного файла: занимает всю ширину под полем,
   чтобы совет не ужимался в узкую колонку рядом с кнопкой. */
.up-pick { flex: 1 1 100%; font-size: 14.5px; line-height: 1.45; color: var(--ink-2); }
.up-pick.is-warn { color: #f0b357; }
.up-pick.is-bad { color: #ff8080; }
.up-pick[hidden] { display: none; }
/* «Стандартный баннер» под ссылкой: кнопка и строка о пустом поле в ряд.
   [hidden] — явно: .btn ставит inline-flex, и без скриптов кнопка
   показалась бы, хотя нажимать её бесполезно. */
.bn-std { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 12px; }
/* Сильнее «.flabel ~ * { margin-top: auto }» в сетке полей: тот прижимает
   ввод к низу ячейки и заодно съедал зазор между полем и кнопкой. */
.fldgrid > .fld > .bn-std, .bn-std { margin-top: 8px; }
/* Строка сжимается и переносится сама, а не уезжает целиком под кнопку. */
.bn-std .fhint { flex: 1 1 180px; margin-top: 0; }
.bn-std .btn[hidden] { display: none; }
.bn-std .up-now { flex: 0 1 auto; }
/* Строка «Баннер»: главная кнопка «Выбрать файл» с подписью в ряд, под ней
   вес выбранного файла, «или вставьте ссылку» и поле, ниже — что стоит
   сейчас и сброс. Без скриптов вместо кнопки обычное поле выбора файла. */
.bn-up { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; }
.bn-up [hidden] { display: none; }
.bn-cap { font-size: 14.5px; color: var(--ink-3); }
.bn-row .up-pick { display: block; margin-top: 8px; }
.bn-row .up-pick[hidden] { display: none; }
.bn-or { margin: 14px 0 6px; font-size: 14.5px; color: var(--ink-3); }

.ownacts-row { display: flex; align-items: center; flex-wrap: wrap; gap: 9px; margin-top: 12px; }
.pills { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.pill {
  display: inline-flex; align-items: center; height: 28px; padding: 0 12px;
  border-radius: 20px; background: #23262f; border: 1px solid var(--line);
  font-size: 14.5px; color: var(--ink-2);
}

/* ─── журнал действий ─── */
.loghead, .logrow {
  display: grid; grid-template-columns: 110px minmax(0, 1fr) 190px;
  gap: 16px; align-items: start;
}
.loghead {
  padding-bottom: 8px; border-bottom: 1px solid var(--line);
  font-size: 13.5px; letter-spacing: .03em; text-transform: uppercase;
  color: var(--ink-3);
}
.logs { display: flex; flex-direction: column; }
.logrow { padding: 12px 0; border-bottom: 1px solid var(--line-soft); font-size: 15.5px; }
.logrow:last-child { border-bottom: 0; }
.logrow-when { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.logrow-what { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.logrow-what b { font-size: 15px; font-weight: 600; }
.logrow-sum { color: var(--ink-2); overflow-wrap: anywhere; }
.logrow-who { display: flex; flex-direction: column; gap: 2px; color: var(--ink-2); }

@media (max-width: 720px) {
  .loghead { display: none; }
  .logrow { grid-template-columns: minmax(0, 1fr); gap: 4px; }
}

/* ─── аналитика коллов ─── */
.callhead, .callrow {
  display: grid; grid-template-columns: minmax(0, 1fr) 110px 120px 90px;
  gap: 14px; align-items: center;
}
.callhead {
  padding: 0 0 8px; border-bottom: 1px solid var(--line);
  font-size: 13.5px; letter-spacing: .03em; text-transform: uppercase;
  color: var(--ink-3);
}
.calls { display: flex; flex-direction: column; }
.callrow { padding: 11px 0; border-bottom: 1px solid var(--line-soft); font-size: 15.5px; }
.callrow:last-child { border-bottom: 0; }
.callrow-name { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; min-width: 0; }
.callrow-name b { font-weight: 600; }
.callrow-name .srv-sub { flex: 1 1 100%; }
.callrow-used, .callrow-win, .callrow-pct {
  color: var(--ink-2); font-variant-numeric: tabular-nums;
}

/* ─── аналитика кола: расстановки ─── */
/* Две расстановки рядом — выигранная и проигранная: их и сравнивают. На узком
   экране встают одна под другой, картинка при этом не обрезается. */
.callpics {
  display: grid; gap: 14px; margin-top: 12px;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  align-items: start;
}
.callpic { margin: 0; }
.callpic figcaption {
  margin-bottom: 8px; font-size: 15.5px; font-weight: 600; color: #c4c9d4;
}
.callpic figcaption .muted { font-weight: 400; }
.callpic img {
  display: block; width: 100%; height: auto; border-radius: 10px;
  border: 1px solid var(--line); background: #14161c;
}
.callpic a + a { margin-top: 10px; display: block; }
.callpic-win figcaption { color: #7fe0a3; }
.callpic-loss figcaption { color: #ff9a9a; }
.callnotes {
  margin: 14px 0 0; padding-left: 18px;
  font-size: 14.5px; line-height: 1.55; color: var(--ink-3);
}
.callnotes li { margin-bottom: 4px; }
.res { font-weight: 600; }
.res-win { color: #7fe0a3; }
.res-lose { color: #ff9a9a; }
.res-live { color: var(--ink-3); }

/* ─── аналитика кола: список матчей ─── */
/* Своя сетка: в списке матчей три столбца (соперник, исход, кнопка), а общая
   .callrow расчерчена на четыре — под таблицы винрейта и коллов в панели
   владельца. Ширины там подобраны под цифры, и кнопка в них не помещалась. */
.mtchrow { grid-template-columns: minmax(0, 1fr) 118px 124px; }
.callrow-act { display: flex; justify-content: flex-end; }
.callrow-act .btn { width: 100%; }
/* Своей линии сверху у блока нет: её уже проводит нижняя граница последней
   строки матча. `:last-child` ту границу не снимает — последним в списке
   стоит этот блок, — и линий выходило две, одна над другой. */
.callmore {
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px;
  padding-top: 14px;
}
.callmore .btn { width: auto; }
/* Пока догружаются матчи: нажимать второй раз незачем, а пропадать кнопке
   нельзя — список под ней прыгнул бы. */
.callmore .btn.is-busy { opacity: .6; pointer-events: none; }
/* Точка внутри территории: «The Sundae post». Своей строкой между соперником
   и временем, тоном тише — это уточнение к сопернику, а не второе имя.
   Межстрочный зазор у строки матча меньше общего: строк в ней три, и
   восьмипиксельный развёл бы их на полторы высоты кнопки. */
.mtchrow .callrow-name { row-gap: 2px; }
.mpoint { flex: 1 1 100%; color: var(--ink-2); font-size: 14.5px; }
/* «играл как Old_Nick» — ник искомого из «Играл за нас» в этом матче.
   Оранжевым, как его строка в составе на странице матча. Ник — не <b>:
   у открытого матча все <b> строки перекрашены в синий. */
.mas { flex: 1 1 100%; color: #e8b27a; font-size: 14.5px; }
.mas-nick { color: #ffb86b; font-weight: 600; }
/* Знак «?» у буквы размера карты. Подсказка привязана не к знаку, а к строке
   места: знак стоит в конце текста любой длины, и по центру над ним подсказка
   у короткой карты («М Мясо») вылезала бы за левый край, а на телефоне — за
   правый. От строки она всегда начинается с её левого края. */
.mpoint, .ghead-sub { position: relative; }
.mpoint .fq, .ghead-sub .fq { position: static; }
.mpoint .fq-pop, .ghead-sub .fq-pop {
  left: 0; transform: none; max-width: min(320px, 100%);
}
/* В шапке матча над строкой один заголовок, а выше — край прокрутки:
   подсказка открывается вниз. */
.ghead-sub .fq-pop { bottom: auto; top: calc(100% + 6px); }

/* Матч, который сейчас открыт: подсвечен и без кнопки — нажимать её значило
   бы перезагрузить ту же страницу.
   Подсветке нужны свои поля: у строки списка горизонтальных отступов нет, и
   заливка шла вплотную к тексту — слева и справа он упирался в самый край.
   Отрицательное поле возвращает колонки на общую сетку, иначе открытая строка
   встала бы уже соседних. */
.mtchrow.is-here {
  background: #1b1e26; border-radius: 10px;
  padding: 11px 12px; margin: 0 -12px;
}
.mtchrow.is-here .callrow-name b { color: #aab0fa; }
/* «Открыт» стоит на месте кнопки, поэтому и выглядеть должен как её пара, а
   не как обронённое слово: та же высота, та же форма, только не нажимается. */
.mhere {
  display: inline-flex; align-items: center; justify-content: center;
  height: 38px; padding: 0 16px; border-radius: 10px;
  border: 1px dashed #3b4568; background: transparent;
  color: #8f96a8; font-size: 14.5px; font-weight: 600; white-space: nowrap;
}
@media (max-width: 720px) {
  .mtchrow { grid-template-columns: minmax(0, 1fr) auto; }
  /* Кнопка уезжает под строку: на узком экране третий столбец сжимал бы имя
     соперника до переносов по букве. */
  .callrow-act { grid-column: 1 / -1; justify-content: flex-start; }
  .callrow-act .btn { width: auto; }
}

/* ─── отбор матчей ─── */
/* Поля в ряд и по низу: у каждого подпись сверху, и выравнивание по центру
   поднимало бы кнопку выше самих полей.
   Раскладка гибкая, а не сеткой: в сетке все колонки одной ширины, и пара
   кнопок «Показать · Сбросить» в колонку 190 px не влезала — сжаться ей
   нечем (текст кнопки не переносят), и «Сбросить» вылезала за край карточки.
   Здесь поля тянутся от 190 px, а кнопки занимают ровно свою ширину. */
.callfilters {
  display: flex; flex-wrap: wrap; gap: 12px 14px; margin-top: 14px;
  align-items: end;
}
.callfilters .fld { flex: 1 1 190px; margin-bottom: 0; min-width: 0; }
.callfilters .sel, .callfilters .inp { width: 100%; }
.callfilters-act {
  display: flex; flex: 0 0 auto; gap: 10px; align-items: end; max-width: 100%;
}
.callfilters-act .btn { flex: 0 0 auto; white-space: nowrap; }
@media (max-width: 560px) {
  /* Кнопки на своей строке: рядом с полем они сжимались до многоточия. */
  .callfilters-act { flex: 1 1 100%; }
  .callfilters-act .btn { flex: 1 1 auto; }
}

/* Даты отбора — «с — по» календарём браузера. Поле шире соседних: в нём два
   ввода, и в 190 px дата обрезалась бы до «23.09.20». */
.callfilters .fld-dates { flex: 2 1 320px; }
.dates { display: flex; align-items: center; gap: 8px; }
.dates .inp { flex: 1 1 0; min-width: 0; }
.dates-sep { flex: none; color: var(--ink-3); }
/* Значок календаря в тёмной схеме браузер рисует тёмным на тёмном — почти
   невидимым; делаем его светлее и показываем, что он нажимается. */
input[type="date"].inp::-webkit-calendar-picker-indicator {
  filter: invert(.75); opacity: .8; cursor: pointer;
}
/* «Играл за нас: нашли по статику …» — пояснение к отбору, под формой. */
.callfound { margin: -6px 0 14px; font-size: 15px; }
.callfound b { color: var(--ink-2); font-weight: 600; }

/* ─── свой выпадающий список (select[data-pick]) ───
   Нативный список рисует система: пункт в две строки в нём не сделать, а
   подсветка под курсором у него своя, ярко-синяя, и перекрасить её нельзя.
   Скрипт ставит поверх <select> кнопку и свой список; сам <select> остаётся
   в форме спрятанным — отправляется он, и без скриптов работает он же. */
.pick { position: relative; width: 100%; min-width: 0; }
/* <select> не display:none, а невидим поверх кнопки: у скрытого совсем
   браузер молча не отправлял форму с пустым обязательным полем — подсказку
   «выберите вариант» ему было не к чему привязать. */
.pick > select {
  position: absolute; left: 0; top: 0; width: 100%; height: 44px;
  opacity: 0; pointer-events: none;
}
.pick-btn {
  display: flex; align-items: center; width: 100%; height: 44px;
  padding: 0 34px 0 12px; text-align: left;
  background-color: #1f222a;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%239aa0ad' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
  background-size: 11px 7px;
  border: 1px solid #343947; border-radius: 9px;
  color: var(--ink); font: inherit; cursor: pointer;
}
.pick-btn:hover { border-color: #4a5060; background-color: #22262f; }
.pick-btn:focus-visible, .pick.is-open .pick-btn { outline: none; border-color: #5a6072; }
.pick-btn:disabled { opacity: .5; cursor: default; }
.pick.is-invalid .pick-btn { border-color: #b34a55; }
.pick-btn span {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pick-pop {
  position: absolute; z-index: 40; top: calc(100% + 6px); left: 0;
  min-width: 100%; width: max-content; max-width: min(420px, 92vw);
  padding: 6px; border: 1px solid #343947; border-radius: 12px;
  background: #1c1f27; box-shadow: 0 18px 40px #0000008c;
  /* В строке .chrow-form (text-align: right) пункты прижимались к галочке,
     а слева от них оставалась пустая полоса — список читается слева. */
  text-align: left;
}
.pick-pop[hidden] { display: none; }
/* У поля у правого края карточки список открывается влево — иначе уходил бы
   за экран на узком окне. Сторону выбирает скрипт по месту. */
.pick.is-right .pick-pop { left: auto; right: 0; }
/* У нижнего края экрана — вверх, как системный список. */
.pick.is-up .pick-pop { top: auto; bottom: calc(100% + 6px); }
.pick-find {
  width: 100%; height: 38px; margin: 0 0 6px; padding: 0 10px;
  background: #15171d; border: 1px solid #2c303b; border-radius: 8px;
  color: var(--ink); font: inherit; font-size: 15.5px;
}
.pick-find:focus { outline: none; border-color: #4a5060; }
.pick-list {
  max-height: 340px; overflow-y: auto; margin: 0; padding: 0; list-style: none;
  overscroll-behavior: contain;
}
.pick-opt {
  position: relative; display: flex; flex-direction: column; gap: 1px;
  padding: 8px 34px 8px 12px; border-radius: 8px; cursor: pointer;
}
.pick-head { color: var(--ink); font-size: 16px; font-weight: 600; line-height: 1.3; }
.pick-sub { color: var(--ink-3); font-size: 14px; line-height: 1.3; }
/* Под курсором и под стрелками — графитовая плашка в тон карточек, без
   синего: в прежнем списке пункт под курсором вспыхивал системным синим. */
.pick-opt.is-active { background: #272b35; }
.pick-opt.is-active .pick-sub { color: var(--ink-2); }
/* Выбранный — галочкой справа, тихим цветом: выбор видно, а список не
   превращается в набор подсвеченных строк. */
.pick-opt.is-sel::after {
  content: ""; position: absolute; right: 13px; top: 50%;
  width: 6px; height: 11px; margin-top: -7px;
  border: solid #aab1c0; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.pick-empty { padding: 10px 12px; color: var(--ink-3); font-size: 15px; }
/* Категория каналов — подпись группы, как в Discord; сама не выбирается. */
.pick-group {
  padding: 10px 12px 4px; color: var(--ink-3); font-size: 13px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
}
.pick-group:first-child { padding-top: 4px; }
.pick-in { padding-left: 20px; }
/* Кружок цвета роли — как в списках ролей на сайте и в Discord. */
.pick-dot {
  display: inline-block; width: 10px; height: 10px; margin-right: 8px;
  border-radius: 50%; vertical-align: 1px;
}
.pick-opt.is-off { cursor: default; opacity: .45; }
.pick-group[hidden] { display: none; }
/* Выбор категории деревом, как список каналов Discord (владелец, 12.10.2026):
   категория — выбираемый пункт заглавными, с промежутком сверху; под ней с
   отступом её каналы — тусклые, не выбираются, по ним узнают категорию. */
.pick-cat { margin-top: 8px; }
.pick-cat .pick-head {
  font-size: 13.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
}
.pick-chan, .pick-loose { padding-top: 3px; padding-bottom: 3px; }
.pick-chan { padding-left: 28px; }
.pick-chan .pick-head, .pick-loose .pick-head { font-size: 15px; font-weight: 500; }
.pick-opt.pick-chan.is-off, .pick-opt.pick-loose.is-off { opacity: .4; }
/* Отсеянные поиском пункты. Атрибут hidden сам прячет только то, у чего нет
   своего display, а у пункта он flex — без этого правила поиск не прятал
   ничего. */
.pick-opt[hidden], .pick-empty[hidden] { display: none; }

/* Плитки «Матчей»: исходы и две стороны — шесть штук. Общая сетка плиток
   ставит их по 190 px, и шестая падала одна на вторую строку. Здесь ряд
   делится ровно: шесть, три и три, два и два. */
.tiles-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
@media (max-width: 1280px) {
  .tiles-6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .tiles-6 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ─── расстановка под размытием ───
   Размывает сервер: в браузер до «Посмотреть» приходит картинка в пару
   десятков точек, растянутая обратно. Здесь её только затемняем и чуть
   увеличиваем — края размытия иначе видны светлой рамкой. */
.veil {
  position: relative; overflow: hidden; border-radius: 10px;
  border: 1px solid var(--line); background: #14161c;
}
.callpic .veil .veil-img, .callpic-one .veil .veil-img {
  display: block; width: 100%; height: auto; max-height: none; margin: 0;
  aspect-ratio: 16 / 9; object-fit: cover; border: 0; border-radius: 0;
  filter: brightness(.62) saturate(.8); transform: scale(1.06);
}
.veil-act {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 10px; padding: 16px;
  text-align: center;
}
.veil-btn {
  display: inline-flex; align-items: center; gap: 8px; width: auto;
  height: 44px; padding: 0 22px; cursor: pointer; font: inherit; font-weight: 600;
  box-shadow: 0 6px 18px #00000066;
}
.veil-note {
  max-width: 36ch; color: #d3d7e0; font-size: 14px; line-height: 1.4;
  text-shadow: 0 1px 3px #000;
}
.veil.is-busy .veil-btn { opacity: .6; pointer-events: none; }
.veil-note.is-err { color: #ffb0b0; }

/* Колл закрыт этому человеку: вместо картинки — кому он открыт. */
.lockbox {
  display: flex; gap: 14px; align-items: flex-start; padding: 14px 16px;
  border: 1px dashed #343947; border-radius: 12px; background: #17191f;
  color: var(--ink-2);
}
.lockbox .ico { flex: none; margin-top: 2px; color: var(--ink-3); }
.lockbox b { display: block; margin-bottom: 4px; color: var(--ink); }
.lockbox span { display: block; font-size: 15px; line-height: 1.5; max-width: 80ch; }

/* ─── аналитика кола: один матч ─── */
/* Расстановку не растягиваем на всю страницу. Колл читают по номерам позиций,
   и на широком мониторе картинка во всю ширину уезжает за пределы экрана по
   высоте — приходится листать, чтобы увидеть её целиком. Потолок по высоте
   держит её в одном экране, а ширина подстраивается сама. */
.callpic-one { margin: 12px 0 0; }
/* Ширину занимает всю: потолок в 68vh резал картинку по высоте, и на широком
   мониторе она вставала узкой посреди карточки — справа оставалась пустая
   полоса в треть экрана. Потолок остался, но высокий: он на случай квадратного
   снимка, который иначе не помещался бы в экран целиком. Поля по бокам равные,
   чтобы упёршаяся в потолок картинка стояла посередине, а не у левого края. */
.callpic-one img {
  display: block; width: 100%; max-width: 100%; height: auto; max-height: 86vh;
  margin: 0 auto;
  border-radius: 10px; border: 1px solid var(--line); background: #14161c;
}
.callpic-one a + a { display: block; margin-top: 10px; }
/* Картинка кликается и открывается в полный размер — поэтому курсор-лупа. */
.callpic-one a { display: inline-block; cursor: zoom-in; }
.callnote { margin: 12px 0 0; }
.backline { margin: 0 0 18px; }
.backline .btn { width: auto; }
.mres { margin-left: auto; font-size: 17px; font-weight: 700; }
.mres-win { color: #7fe0a3; }
.mres-lose { color: #ff9a9a; }
.mres-live { color: var(--ink-3); }
/* Итоги мероприятий: место (ВЗХ и свои виды) — не победа и не поражение,
   своим тоном. Фото карты — на всю ширину карточки, не выше экрана. */
.res-place, .mres-place { color: #f3c969; }
.grpic { margin: 0; }
.grpic img { display: block; max-width: 100%; max-height: 420px; border-radius: 10px; }

/* Заголовок матча: кто с кем, а под ним состав, карта и время забива.
   Соперник в одиночку не говорит, чья это война: у гильдии с двумя серверами
   семьи разные, а соперники у них встречаются одни и те же. */
.mtitle { overflow-wrap: anywhere; }
.mvs { color: var(--ink-3); font-weight: 400; }
.mwhen { margin-top: 3px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* Колл и состав идут друг под другом, каждый во всю ширину.
   Колонками они стояли ровно до тех пор, пока состав помещался в половину
   экрана: ник со статиком и «2 уб · 343 урона» переставали влезать в строку
   и переносились на вторую у каждого игрока — список становился вдвое
   длиннее и нечитаемым. Ширина здесь нужнее соседства. */

/* Две стороны рядом: их и сравнивают. На узком экране встают одна под другой. */
.rosters {
  display: grid; gap: 16px; margin-top: 14px;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  align-items: start;
}
/* Состав длинный — на широком экране он ложится в две колонки сам
   (auto-fit), а на узком встаёт одна под другой. Потолка по высоте у него
   нет намеренно: список читают целиком, а не прокручивают внутри карточки. */
.roster {
  border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px;
  background: var(--surface-2);
}
/* Своя сторона выделена рамкой: на ней стоят подписи Discord, и по ней
   взгляд ищет знакомые имена. */
.roster-ours { border-color: #3b4568; }
.roster-head {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px;
  padding-bottom: 8px; margin-bottom: 4px; border-bottom: 1px solid var(--line);
  font-size: 15.5px; color: var(--ink-2);
}
.roster-head b { color: var(--ink); font-weight: 600; }
.rmans { margin: 0; padding: 0 0 0 26px; }
.rman {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px;
  padding: 5px 0; font-size: 15.5px;
  position: relative;   /* опора для номера позиции (.rman-pos) */
}
.rman-nick { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
/* Номер позиции на колле — в левом поле списка (26 px отступа у .rmans
   маркеров не держат: у строки display:flex), столбиком, как нумерация на
   самой расстановке. Тон — тот же сиреневый, что у подписи Discord: номер
   берётся по ней. */
.rman-pos {
  position: absolute; left: -30px; top: 6px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 25px; height: 21px; border-radius: 6px;
  background: #262c45; border: 1px solid #3b4568; color: #c3c7fb;
  font-size: 12.5px; font-weight: 700; font-variant-numeric: tabular-nums;
  cursor: help;
}
/* Discord-ник — подпись к игровому, а не второе имя: он и тоном тише, и
   в скобках, чтобы строка читалась как «ник (кто это)». */
.rman-dc { margin-left: 6px; color: #aab0fa; font-size: 14.5px; }
/* Карточка участника при наведении на Discord-ник: аватарка, имя, логин, ID.
   Та же механика, что у знака «?» (.fq-pop): видимость по :hover и :focus,
   поэтому на телефоне она открывается нажатием. Ставится над ником и от его
   левого края: ник стоит в начале строки, и вправо карточке место есть в
   обеих колонках составов. */
.rman-dc[tabindex] { position: relative; cursor: default; border-radius: 4px; }
.rman-dc[tabindex]:hover, .rman-dc[tabindex]:focus-visible { color: #c3c7fb; outline: none; }
.dcpop {
  position: absolute; left: 0; bottom: calc(100% + 8px); z-index: 30;
  display: flex; align-items: center; gap: 12px;
  width: max-content; max-width: 320px; padding: 10px 14px 10px 10px;
  border: 1px solid #343947; border-radius: 10px; background: #23262f;
  box-shadow: 0 10px 26px #00000073; cursor: auto;
  opacity: 0; visibility: hidden; transition: opacity .12s ease;
}
/* Мостик под карточкой: без него курсор, идущий от ника к карточке (чтобы
   выделить ID), проваливался в зазор в 8px, и карточка закрывалась. */
.dcpop::after {
  content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 10px;
}
.rman-dc[tabindex]:hover .dcpop, .rman-dc[tabindex]:focus .dcpop,
.rman-dc[tabindex]:focus-within .dcpop { opacity: 1; visibility: visible; }
.dcpop-ava {
  width: 44px; height: 44px; flex: none; border-radius: 50%; object-fit: cover;
  background: #2d3140;
}
.dcpop-ava-text {
  display: flex; align-items: center; justify-content: center;
  color: #c8cdd8; font-size: 18px; font-weight: 600;
}
.dcpop-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.dcpop-txt b {
  color: var(--ink); font-size: 15.5px; font-weight: 600;
  overflow-wrap: anywhere;
}
.dcpop-login { color: var(--ink-2); font-size: 14px; overflow-wrap: anywhere; }
.dcpop-id { color: var(--ink-3); font-size: 13.5px; }
/* ID выделяется целиком одним нажатием — его копируют, чтобы искать
   человека в Discord. */
.dcpop-num {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums; user-select: all; color: var(--ink-2);
}
.rman-num {
  flex: 0 0 auto; color: var(--ink-3); font-size: 14px;
  font-variant-numeric: tabular-nums;
}
/* Статик персонажа. Показан открыто и тише ника: по нему сверяют вручную,
   а читают всё-таки ник. Моноширинный — чтобы номер глазом сравнивался. */
.rman-id {
  margin-left: 6px; color: var(--ink-3); font-size: 14px;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums; cursor: help;
}
.rman-foot { margin: 10px 0 0; font-size: 14.5px; color: var(--ink-3); }

.pill-new { background: #3a3327; border-color: #5a4a22; color: #f0b357; height: 22px; font-size: 13.5px; }
.schema {
  margin: 10px 0; padding: 12px; border-radius: 9px; overflow-x: auto;
  background: #14161c; border: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 14px; line-height: 1.5; color: #c4c9d4; white-space: pre;
}

.mrow { display: flex; align-items: center; gap: 14px; margin-bottom: 10px; }
.mrow-name { flex: 0 0 80px; font-size: 15px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.mrow-val { flex: 0 0 130px; text-align: right; font-size: 15.5px; font-weight: 600; }
.mrow-val span { display: block; font-size: 13.5px; font-weight: 400; color: var(--ink-3); }

.ownerlink {
  display: inline-flex; align-items: center; gap: 7px;
  height: 30px; padding: 0 11px; border-radius: 8px;
  border: 1px solid var(--own-line); background: var(--own-soft);
  color: var(--own); font-size: 14.5px; font-weight: 600;
}
.ownerlink:hover { color: #efb84e; border-color: var(--own); }
.ownerlink.is-on { background: var(--own); color: #1a1608; border-color: var(--own); }

.opt-off { color: #767c89; }

/* Предпросмотр не помещается рядом с формой — уходит под неё. */
@media (max-width: 1080px) {
  .editgrid { grid-template-columns: minmax(0, 1fr); }
  .previewcol { position: static; max-height: none; overflow: visible; }
}

/* Боковое меню на узком экране становится горизонтальной полосой сверху:
   264 px сайдбара на телефоне не оставили бы места содержимому. */
@media (max-width: 860px) {
  /* Сетки здесь нет: всё идёт одной колонкой сверху вниз. Порядок задаётся
     явно — в разметке полоса пользователя стоит после содержимого (клетка
     сетки под меню), а в полосе меню ей место сразу под навигацией. */
  /* Рамы во всю высоту окна здесь нет: на телефоне меню стоит полосой
     сверху и уезжает вместе со страницей, прокрутка снова общая. */
  .shell { display: flex; flex-direction: column; height: auto; }
  .side, .main { overflow: visible; min-height: auto; }
  .main { order: 1; }
  .side {
    width: auto; flex-direction: row; flex-wrap: wrap; align-items: center;
    gap: 10px; padding: 12px 16px;
    border-right: 0; border-bottom: 0;
  }
  .srvpick { margin-bottom: 0; flex: 1 1 200px; }
  .nav { flex-direction: row; flex-wrap: wrap; gap: 6px; }
  .nav-head { display: none; }
  .nav-item { padding: 8px 10px; font-size: 15px; }
  .side-foot { margin-top: 0; padding-top: 0; padding-bottom: 0; flex: 1 1 100%; }
  /* Меню стало горизонтальной полосой — выравнивать по подвалу больше нечего.
     Полоса пользователя дорисовывает её снизу: фон тот же, нижняя граница
     переезжает на неё, правой границы у полосы во всю ширину нет. */
  .side-user {
    flex-direction: row; align-items: center;
    padding: 12px 16px; border-right: 0;
    border-bottom: 1px solid #23262f;
  }
  .foot-inner .foot-links {
    padding-inline: 16px; padding-block: 18px 22px; height: auto;
  }
  .foot-req { margin-left: 0; }
  /* Нижней полосы под панелью «Сохранить» здесь нет — она снова по центру
     окна и у самого низа. */
  .js .has-side .savebar {
    left: 50%; bottom: 20px; width: min(920px, calc(100% - 32px));
  }
  .subcard { flex-direction: row; align-items: center; gap: 12px; }
  .subcard-tail { flex: 1 1 auto; }
  .subcard .btn { width: auto; padding: 0 16px; }
  .ownerbadge { margin-bottom: 0; }
  .main > .inner { padding: 24px 16px 60px; }
}

@media (max-width: 620px) {
  .srv { gap: 12px; }
  .srv-act { margin-left: 0; width: 100%; }
  .srv-act .btn { flex: 1 1 120px; }
  .addbot { padding: 16px; }
  .addbot-head > .btn { width: 100%; }
  .addgrid { grid-template-columns: 1fr; }
  .ghead-act { width: 100%; margin-left: 0; }
  .ord-status { margin-left: 0; width: 100%; }
  .ownrow-act { margin-left: 0; width: 100%; }
  .tool-name { flex: 0 0 120px; }
  .who-name { display: none; }
  /* Шапка «Моих серверов» у владельца бота: логотип, «Главная», панель
     владельца и аватар не влезали в 375 px и уезжали за край. На узком
     экране у панели владельца остаётся значок (подсказка — в title). */
  .bar { gap: 8px; }
  .bar .logo { font-size: 17px; }
  .bar .who { gap: 8px; }
  .bar-nav { margin-left: 0; }
  .bar .ownerlink { padding: 0 8px; }
  .bar .ownerlink span { display: none; }
}

/* ─── поиск шпионов: серверы проверки ролей ─── */
/* Заголовок карточки с кнопкой справа: «Серверы проверки ролей» ведёт в их
   настройку прямо из рабочей страницы, а не только из настроек функции. */
.cardhead {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 12px; margin-bottom: 8px;
}
.cardhead h2 { margin: 0; }
.cmpsrv { padding: 14px 0; border-bottom: 1px solid var(--line-soft); }
.cmpsrv:last-child { border-bottom: 0; }
.cmpsrv-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  flex-wrap: wrap; gap: 12px;
}
.cmpsrv-head > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cmpsrv-rules {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 12px 24px; margin: 12px 0 10px;
}
.cmproles { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 6px; }
/* Роль чужого сервера цвета не несёт — бот знает только имя, а иногда и его
   нет: тогда показывается ID, тоном тише, чтобы не спутать с названием. */
.hrole {
  display: inline-flex; align-items: center; height: 26px; padding: 0 10px;
  border-radius: 13px; background: #23262f; border: 1px solid var(--line);
  font-size: 14.5px; color: var(--ink);
}
.hrole-id { color: var(--ink-3); font-variant-numeric: tabular-nums; }
/* Роли больше нет на том сервере: правило осталось, но никого не найдёт. */
.hrole-gone { color: #c98a8a; text-decoration: line-through; border-style: dashed; }
.cmpnote { margin: 8px 0 0; font-size: 14.5px; }
.chkbox { display: flex; flex-direction: column; gap: 10px; }
.chkfind { max-width: 360px; }
.chk[hidden] { display: none; }
.reqlist { margin-top: 14px; }
/* Сервер проверки без бота и без аккаунта: правила целы, но по нему никого не
   проверяют. Тон «включено, но не работает» — как у функций (--warn). */
.srvtitle { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.pill-warn {
  height: 22px; padding: 0 9px; font-size: 13.5px;
  background: #241d10; border-color: #4a3c1c; color: var(--warn);
}
.srvoff {
  margin: 10px 0 0; padding: 12px 14px; border: 1px solid #4a3c1c;
  border-radius: 10px; background: #241d10;
}
.srvoff p { margin: 0 0 8px; }
.srvoff p:last-child { margin-bottom: 0; }
.card > .srvoff:first-child { margin-top: 0; }
.chrow > .srvoff { flex: 1 1 100%; margin-top: 0; }

/* Метки «за нас / против нас / на сервере» — меньше обычной плашки: стоят в
   строке рядом с именем и не должны её раздувать. */
.pill-ok, .pill-bad, .pill-off { height: 22px; padding: 0 9px; font-size: 13.5px; }
.pill-ok { background: #173a28; border-color: #24583b; color: #7fe0a3; }
.pill-bad { background: #3a1c1f; border-color: #5c2a30; color: #ff9a9a; }
.pill-off { color: var(--ink-3); }

/* ─── карточка участника ─── */
.mcard-head { align-items: center; gap: 16px; }
.mcard-ava {
  width: 64px; height: 64px; border-radius: 50%; flex: none;
  border: 1px solid var(--line); background: #14161c;
}
.mcard-head .pill { margin-left: 8px; vertical-align: middle; }
.rolerows { display: flex; flex-direction: column; }
.rolerow {
  display: grid; grid-template-columns: 150px minmax(0, 1fr) minmax(0, 280px);
  gap: 14px; align-items: start; padding: 10px 0;
  border-bottom: 1px solid var(--line-soft); font-size: 15.5px;
}
.rolerow:last-child { border-bottom: 0; }
.rolerow-when { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.rolerow-what { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; min-width: 0; }
.rolerow-act {
  padding: 1px 8px; border-radius: 10px; font-size: 13.5px; font-weight: 600;
}
.rolerow-act.is-add { color: #7fe0a3; background: #173a28; }
.rolerow-act.is-del { color: #ff9a9a; background: #3a1c1f; }
.rolerow-who {
  display: flex; flex-direction: column; gap: 2px; min-width: 0;
  color: var(--ink-2); overflow-wrap: anywhere;
}
@media (max-width: 720px) {
  .rolerow { grid-template-columns: minmax(0, 1fr); gap: 4px; }
}
.orgchips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.orgchip {
  display: inline-flex; align-items: center; gap: 8px; height: 30px;
  padding: 0 12px; border-radius: 15px; background: #23262f;
  border: 1px solid var(--line); font-size: 15px; color: var(--ink-2);
}
.orgchip b { color: var(--ink); font-weight: 600; }

/* Игрок, пришедший из карточки участника, — оранжевым: его ищут глазами в
   составе на 20–40 человек, и цвет должен выделяться и на своей стороне, и на
   чужой, не споря с синим Discord-ником и зелёным «за нас». */
.rman-hl {
  margin: 0 -8px; padding: 5px 8px; border-radius: 8px;
  background: #3a2610; box-shadow: inset 3px 0 0 #ff9f43;
}
.rman-hl .rman-nick { color: #ffb86b; font-weight: 700; }
.rman-hl .rman-num { color: #e8b27a; }
.hlnote { color: #ffb86b; }
/* Свой список в строке формы (выбор сервера и кнопка рядом) тянется, как
   обычное поле, а не на всю строку — иначе кнопка уезжала под него. */
.rowform .pick { flex: 1 1 260px; width: auto; min-width: 0; }

/* ─── магазин: подача отчёта ─── */
/* Поля — строками, а не одним рядом: в ряд направление, количество, файлы и
   комментарий сжимались до обрезков, и форма читалась как одна длинная
   строка. */
.repform { display: flex; flex-direction: column; gap: 14px; margin-top: 8px; }
.repform .fld { margin-bottom: 0; }
.repform [hidden] { display: none !important; }
.repform > .btn { align-self: flex-start; }
.repform-row {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 14px; align-items: start;
}
@media (max-width: 720px) {
  .repform-row { grid-template-columns: minmax(0, 1fr); }
}
/* Карточка направления: со скриптом — только выбранного, без него — все
   подряд, каждая со своим названием. */
.dirinfos { display: flex; flex-direction: column; gap: 10px; }
.dirinfo {
  padding: 14px 16px; border: 1px solid var(--line); border-radius: 12px;
  background: #17191f;
}
.js .dirinfo:not(.is-on) { display: none; }
.dirinfo-name { display: block; margin-bottom: 10px; font-size: 16px; }
.js .dirinfo-name { display: none; }
.dirinfo-facts { display: flex; flex-wrap: wrap; gap: 10px 28px; }
.dirinfo-fact { display: flex; flex-direction: column; gap: 2px; }
.dirinfo-fact span { font-size: 13.5px; color: var(--ink-3); }
.dirinfo-fact b { font-size: 16px; font-weight: 600; color: var(--ink); }
.dirinfo-hint { margin: 12px 0 0; font-size: 15.5px; line-height: 1.5; color: var(--ink-2); }
.dirinfo-hint b { color: #c4c9d4; font-weight: 600; }

/* ─── магазин: страница отчёта ─── */
/* Скриншоты — сеткой крупных превью: по ним и решают, поэтому видны сразу,
   а по нажатию открываются целиком в новой вкладке. */
.repshots {
  display: grid; gap: 12px; margin-top: 10px;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.repshot {
  display: flex; flex-direction: column; gap: 6px; color: var(--ink-3);
  font-size: 14px; cursor: zoom-in;
}
.repshot img {
  display: block; width: 100%; height: auto; max-height: 70vh; object-fit: contain;
  border-radius: 10px; border: 1px solid var(--line); background: #14161c;
}
.repshot:hover img { border-color: #4a5060; }
.repshot-sm { flex: 0 0 160px; }
.repshot-sm img { max-height: 110px; object-fit: cover; }
/* Похожие скриншоты — тёплой рамкой: это повод присмотреться, а не ошибка. */
.card-warn { border-color: #5a4a22; }
.repmatch {
  display: flex; align-items: flex-start; gap: 14px; padding: 12px 0;
  border-top: 1px solid var(--line-soft);
}
.repmatch-text { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.repmatch-text .btn { align-self: flex-start; }
@media (max-width: 620px) {
  .repmatch { flex-direction: column; }
  .repshot-sm { flex-basis: auto; width: 100%; }
}
.repdecide { display: flex; align-items: flex-start; flex-wrap: wrap; gap: 12px; }
.repdecide form { margin: 0; }
/* «Принять» и «Отклонить» — в одну линию. «Отклонить» — раскрывашка
   (.delbox), и общее правило давало ей отступ 12 px сверху: оно для кнопки
   удаления под текстом карточки, а здесь кнопка стоит в ряду и съезжала
   ниже «Принять». Высота — та же 44 px, что у .btn-inline: по отступам
   summary выходил на пару пикселей ниже соседа. */
.repdecide > .delbox { margin: 0; }
.repdecide > .delbox > summary { height: 44px; padding-block: 0; }
/* Причина и кнопка отказа — одной строкой, как в заявках (.appreject):
   столбиком поле и кнопка слипались без зазора. На узком экране кнопка
   уходит под поле сама. */
.repdecide .delbox-in form { display: flex; flex-wrap: wrap; gap: 10px; }
.repdecide .delbox-in .inp { flex: 1 1 260px; min-width: 0; width: auto; }
/* Кнопка строки («Рассмотреть», «Посмотреть») — у правого края, как в
   остальных списках, а не посреди строки. */
.chrow-act { justify-content: flex-end; }
/* Подпись и кнопка в одной ячейке: кнопка — у правого края и одинаковой
   ширины во всех строках, подпись — вплотную слева от неё. Кнопка больше
   не «плавает» от длины подписи («участников в кэше 572» и «1781 ·
   обновлён …»), а правая часть строки не пустует. */
.chrow-form > .btn, .chrow-form > form { flex: none; }
/* Портфель Tier: выбор тира, «Повысить», «Понизить» — одной линией. Раньше
   каждое стояло в своей форме: форма с выбором считала ширину по тексту
   «Tier 3», а .sel просит 260 px — кнопка уезжала под выбор, и ряд
   разъезжался на два этажа. Теперь элементы — прямые дети ряда. Ширина
   ряда — по содержимому: при общей колонке 340 px он не влезал и, прижатый
   вправо, наезжал на имя. Не хватает места — уходит под имя целиком, а на
   телефоне кнопки переносятся внутри. */
.tieracts { flex: 0 1 auto; flex-wrap: wrap; }
.tieracts > .sel { flex: 0 0 180px; }



/* ─── заявки в семью ─── */
/* Раскрытая заявка: всё внутри одного блока с полями. Раньше вопросы лежали
   прямо в <details> и прилипали к рамке, а каждая форма с кнопкой брала себе
   рамку и отступы общего правила `.rowbox > form`. */
.appbox-body { padding: 2px 16px 16px; border-top: 1px solid var(--line); }
.appqa { margin: 0; }
.appqa-row { padding: 11px 0; border-bottom: 1px solid var(--line-soft); }
.appqa dt { font-size: 15.5px; font-weight: 600; color: #c4c9d4; }
.appqa dd {
  margin: 3px 0 0; color: var(--ink); font-size: 16px; line-height: 1.5;
  white-space: pre-line; overflow-wrap: anywhere;
}
.appbox-roles { margin: 12px 0 0; }
.appacts { display: flex; flex-wrap: wrap; gap: 10px; margin: 14px 0 10px; }
.appacts form { margin: 0; }
.appreject { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 10px; }
.appreject .inp { flex: 1 1 280px; min-width: 0; }
.appbox .delbox { margin: 2px 0 0; }

/* ─── статистика рекрутёров и заблокированные ─── */
/* Четыре итога — ровно на всю ширину карточки. Общая сетка полей ставила их
   по 230 px и оставляла справа пустую полосу. */
.tiles-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 720px) {
  .tiles-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.tile-bad { color: #ff9a9a !important; }
.rtbl th:not(:first-child), .rtbl td:not(:first-child) {
  width: 14%; text-align: right; font-variant-numeric: tabular-nums;
}
.rtbl td:first-child { font-weight: 600; }

.blkbtn { gap: 8px; }
.blkava {
  width: 24px; height: 24px; border-radius: 50%; object-fit: cover;
  vertical-align: -6px; margin-right: 8px;
}
.appfacts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px 24px; margin: 14px 0 0;
}
.appfacts > div { min-width: 0; }
.appfacts-wide { grid-column: 1 / -1; }
.appfacts-sub { display: block; font-size: 14.5px; color: var(--ink-3); }
/* Последний ответ анкеты уже отчёркнут — вторая линия у раздела лишняя. */
.appqa + .appsec { border-top: 0; }
.appfacts dt { font-size: 14.5px; color: var(--ink-3); }
.appfacts dd {
  margin: 3px 0 0; color: var(--ink); font-size: 16px; line-height: 1.45;
  white-space: pre-line; overflow-wrap: anywhere;
}
.appsec {
  margin: 20px 0 2px; padding-top: 14px; border-top: 1px solid var(--line-soft);
  font-size: 16px; font-weight: 600; color: #c4c9d4;
}
.apphead { margin: 6px 0 0; }
.apphist-row {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px;
  padding: 9px 0; border-bottom: 1px solid var(--line-soft); font-size: 15.5px;
}
.apphist-row:last-child { border-bottom: 0; }
.apphist-st { margin-left: auto; color: var(--ink-2); }
.st-approved { color: #7ee2a8; }
.st-blocked { color: #ff9a9a; }

/* ─── поиск шпионов: строки предупреждений ─── */
/* Три колонки одной ширины во всех строках: кто — роли-триггеры — число и
   кнопка. Правая колонка фиксированной ширины, иначе «предупреждений 12» и
   «… 1» сдвигали бы роли и кнопку по-разному. Роли — в одну строку: лишнее
   уходит в «+N», и строка не растёт от числа предупреждений. */
.warnrow {
  display: grid; align-items: center; gap: 8px 18px;
  grid-template-columns: minmax(160px, 1fr) minmax(0, 1.5fr) 360px;
  padding: 12px 0; border-bottom: 1px solid var(--line-soft);
}
.warnrow:last-child { border-bottom: 0; padding-bottom: 0; }
.warnrow-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.warnrow-who b { font-size: 16px; font-weight: 600; overflow-wrap: anywhere; }
.warnrow-roles { display: flex; flex-wrap: nowrap; gap: 6px; min-width: 0; overflow: hidden; }
.warnrow-act { display: flex; align-items: center; justify-content: flex-end; gap: 12px; }
.warnrow-act .muted { white-space: nowrap; }
.warnrow-act .btn { flex: none; white-space: nowrap; }
.wrole {
  /* inline-block, а не flex: у флекса текст — анонимный блок, и
     многоточие на длинном названии не рисовалось, текст просто резался. */
  flex: 0 1 auto; min-width: 0; max-width: 200px; height: 26px; padding: 0 10px;
  display: inline-block; line-height: 24px; border-radius: 13px;
  background: #2a1d22; border: 1px solid #5a2f38; color: #ffb3b3;
  font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wrole-id { background: #23262f; border-color: var(--line); color: var(--ink-3);
            font-variant-numeric: tabular-nums; }
.wrole-more { flex: none; background: #23262f; border-color: var(--line); color: var(--ink-2);
              cursor: help; }
@media (max-width: 900px) {
  .warnrow { grid-template-columns: minmax(0, 1fr); }
  .warnrow-act { justify-content: space-between; }
}

/* ─── проверка ролей: серверы сценария ─── */
.scn-srvs { display: flex; flex-direction: column; gap: 3px; margin-top: 4px; font-size: 15px; }
.scn-srv b { font-weight: 600; }
.scn-ok { color: #7ee2a8; }
.scn-bad { color: #ff9a9a; }
.scn-plan { margin-top: 4px; }

/* На узком экране строка переносится: значение встаёт под названием — там
   его читают слева, как и само название. */
@media (max-width: 720px) {
  .chrow-form { justify-content: flex-start; text-align: left; }
}

/* ─── справка по командам списков (dashboard/list_help.py) ───
   Что делает каждая команда и как она выглядит в Discord. Окно поверх
   страницы открывается якорем (:target) — работает и без скриптов; со
   скриптом — классом is-open, без смены адреса и с закрытием по Esc. */
.lh-q { text-decoration: none; }
.plan-feats .lh-q { margin-left: 8px; vertical-align: -3px; }

/* Команды кнопками на карточке ядра. Растянутая ссылка карточки лежит выше
   по стопке — без своего слоя нажатие открыло бы настройки, а не справку. */
.lh-chips { position: relative; z-index: 2; display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.lh-chip {
  display: inline-flex; align-items: center; gap: 7px; min-height: 30px;
  padding: 3px 7px 3px 4px; border: 1px solid #343947; border-radius: 8px;
  background: #20232b; color: var(--ink); font-size: 14px;
}
.lh-chip:hover { border-color: var(--accent); color: var(--ink); }
.lh-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lh-chip-q {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 50%;
  color: var(--ink-3); font-size: 11px; font-weight: 700; line-height: 1;
}
.lh-chip:hover .lh-chip-q { color: var(--ink); }

/* Знак «?» — значком (list_help.Q_ICON), а не символом шрифта: символ сидел
   в круге по-разному и местами уезжал вбок и вверх. Круг — в том же значке,
   во всю его ширину; overflow — чтобы край обводки не срезался. */
.q-ico { display: block; flex: none; overflow: visible; }
.fq .q-ico { width: 18px; height: 18px; }
.lh-chip-q .q-ico { width: 16px; height: 16px; }
.q-ring { stroke: #4a5060; }
.fq:hover .q-ring, .fq:focus-visible .q-ring,
.lh-chip:hover .q-ring { stroke: var(--accent); }

/* Команда в списке «что входит» на странице оплаты: наведение показывает,
   как она выглядит в Discord, нажатие открывает окно с подробностями.
   Пунктир под командой — знак, что на неё можно навести. На устройствах без
   наведения превью не всплывает: там его покажет окно по нажатию. */
.lh-cmd { position: relative; display: inline-block; color: inherit; cursor: help; }
.lh-cmd:hover, .lh-cmd:focus-visible { color: inherit; }
.lh-cmd code { border-bottom: 1px dashed #5a6070; }
.lh-cmd:hover code, .lh-cmd:focus-visible code { border-bottom-color: var(--accent); }
.lh-cmd:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.lh-tip {
  display: none; position: absolute; left: 0; top: calc(100% + 8px); z-index: 40;
  width: min(440px, calc(100vw - 48px)); padding: 12px 14px;
  background: var(--surface); border: 1px solid #343947; border-radius: 12px;
  box-shadow: 0 16px 40px #000000a6; cursor: default; white-space: normal;
  font-size: 14.5px; line-height: 1.45; color: var(--ink-2);
}
.lh-cmd:hover .lh-tip, .lh-cmd:focus-visible .lh-tip { display: block; }
/* Мостик над окном. Между командой и окном 8 px, и курсор, переходя в окно,
   на миг уходил с команды — окно гасло, до него было не добраться. Мостик —
   часть окна (оно вложено в ссылку команды), и наведение не теряется. */
.lh-tip::before { content: ""; position: absolute; left: 0; right: 0; top: -12px; height: 12px; }
/* Со скриптом окно ставит dash.js — справа от команды и целиком в экране
   (position: fixed не удлиняет страницу); наведение по CSS тогда не нужно. */
html.lh-js .lh-tip { display: none !important; }
html.lh-js .lh-tip.is-open { display: block !important; position: fixed; overflow-y: auto; }
html.lh-js .lh-tip::before { display: none; }
@media (hover: none) {
  .lh-cmd:hover .lh-tip, .lh-cmd:focus-visible .lh-tip { display: none; }
}

/* Где работает команда. */
.lh-scope {
  display: inline-block; font-size: 12.5px; font-weight: 600; letter-spacing: .02em;
  border-radius: 20px; padding: 2px 9px; white-space: nowrap;
}
.lh-any { color: #7ee2a8; background: #7ee2a81a; border: 1px solid #7ee2a840; }
/* Цвета проектов: у GTA5RP золотисто-оранжевый, у MajesticRP малиновый
   #fc036b — его назвал владелец (04.10.2026), тот же, что на главной. */
.lh-gta { color: #f5a524; background: #f5a5241a; border: 1px solid #f5a52440; }
.lh-mj { color: #fc036b; background: #fc036b1a; border: 1px solid #fc036b40; }

/* Обзор: строка на команду, вся строка — ссылка на окно. */
.lh-ov h2 { margin-bottom: 6px; }
.lh-ov-note { margin: 0 0 14px; }
.lh-ov-rows { display: flex; flex-direction: column; gap: 8px; }
.lh-ov-row {
  display: grid; grid-template-columns: 96px minmax(0, 1fr) auto; gap: 14px;
  align-items: center; padding: 12px 14px; color: var(--ink);
  border: 1px solid var(--line); border-radius: 10px; background: #1b1e26;
}
.lh-ov-row:hover { border-color: #3d4350; background: #1f222b; color: var(--ink); }
.lh-ov-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lh-ov-what { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.lh-ov-what b { font-size: 15.5px; font-weight: 600; }
.lh-ov-what span { font-size: 14.5px; line-height: 1.45; color: var(--ink-2); }
.lh-ov-side { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.lh-ov-more { font-size: 14px; color: #8b93f8; white-space: nowrap; }
.lh-ov-row:hover .lh-ov-more { color: #aab0fa; }
@media (max-width: 720px) {
  .lh-ov-row { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .lh-ov-side { flex-direction: row; align-items: center; justify-content: space-between; }
}

/* Окно. */
.lh-dlg {
  display: none; position: fixed; inset: 0; z-index: 100;
  align-items: flex-start; justify-content: center;
  padding: 32px 16px; overflow-y: auto;
}
.lh-dlg:target, .lh-dlg.is-open { display: flex; }
/* Закрыли скриптом окно, открытое по якорю из адреса: :target держался бы,
   пока адрес не сменится, — класс его перебивает. */
.lh-dlg.is-closed:target { display: none; }
.lh-bg { position: fixed; inset: 0; background: #05060acc; cursor: default; }
.lh-card {
  position: relative; width: min(1040px, 100%);
  background: var(--surface); border: 1px solid #343947; border-radius: 14px;
  padding: 22px 24px 24px; box-shadow: 0 24px 60px #000000a6;
}
html.lh-lock, html.lh-lock body { overflow: hidden; }
.lh-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.lh-head h2 { margin: 8px 0 0; font-size: 22px; line-height: 1.3; }
.lh-head h2 code { font-size: .95em; }
.lh-x {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 9px; border: 1px solid #343947;
  color: var(--ink-2); font-size: 24px; line-height: 1;
}
.lh-x:hover { color: var(--ink); border-color: #4a5060; background: #22262f; }
.lh-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lh-lead { font-size: 16.5px; line-height: 1.5; color: var(--ink-2); margin: 12px 0 18px; max-width: 72ch; }
.lh-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 460px); gap: 22px; align-items: start; }
.lh-how h3, .lh-pv-head { margin: 0 0 10px; font-size: 15px; font-weight: 600; color: var(--ink); }
.lh-how ol { margin: 0 0 14px; padding-left: 22px; }
.lh-how li { margin-bottom: 9px; font-size: 15.5px; line-height: 1.5; color: #c4c9d4; }
.lh-how li::marker { color: var(--ink-3); font-weight: 600; }
.lh-when { margin: 0 0 8px; font-size: 15px; line-height: 1.5; color: #c4c9d4; }
.lh-who { margin: 0; font-size: 14px; line-height: 1.45; color: var(--ink-3); }
.lh-pv-note { margin: 8px 0 0; font-size: 13.5px; color: var(--ink-3); }
@media (max-width: 900px) {
  .lh-grid { grid-template-columns: minmax(0, 1fr); }
  .lh-dlg { padding: 12px 8px; }
  .lh-card { padding: 18px 14px; }
  .lh-head h2 { font-size: 19px; }
}

/* Макет чата Discord: фон канала, сообщения людей и бота. */
.lh-chat {
  display: flex; flex-direction: column; gap: 12px; font-family: var(--dc-font);
  background: #313338; border: 1px solid #3f4147; border-radius: 10px;
  padding: 14px 12px; font-size: 14.5px; color: #dbdee1;
}
.lh-msg { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.lh-row { display: flex; gap: 12px; min-width: 0; }
.lh-ava {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%; color: #fff;
  font-size: 14px; font-weight: 700;
}
.lh-ava-bot { background: var(--accent); }
.lh-body { display: flex; flex-direction: column; gap: 5px; min-width: 0; flex: 1 1 auto; }
.lh-name { display: flex; align-items: center; gap: 6px; font-size: 14.5px; font-weight: 600; color: #f2f3f5; }
.lh-eph { font-size: 12.5px; font-weight: 400; color: #949ba4; }
.lh-text { line-height: 1.4; overflow-wrap: anywhere; }
.lh-chat .dc-text { font-size: 14.5px; }
.lh-chat .dmd-h1 { font-size: 21px; }
.lh-chat .dmd-h2 { font-size: 17px; }
.lh-chat code { white-space: normal; }
.lh-box { gap: 7px; padding: 11px 11px 11px 10px; }
/* Снимок карты в макете `/капт` — та же полоса 16:5, что бот ставит в
   карточку, когда карту выбрали. Путь относительный: файл лежит рядом. */
.lh-map {
  aspect-ratio: 16 / 5; border-radius: 6px;
  background: #1f222a url("lh-kapt-map.webp") center / cover no-repeat;
}
/* У !взп своя карта — «Б Татушка» из примера (NEW_B_ELBURRO), та же
   полоса, что вкладывает бот. */
.lh-map-vzp { background-image: url("lh-vzp-map.webp"); }
.lh-chan { color: #c9cdfb; background: #5865f24d; border-radius: 3px; padding: 0 3px; }
/* «Ответ на сообщение» — полоска-стрелка над сообщением, как в Discord. */
.lh-reply {
  display: flex; align-items: center; gap: 6px; padding-left: 16px;
  font-size: 13px; color: #b5bac1; min-width: 0; white-space: nowrap; overflow: hidden;
}
.lh-reply-arm {
  flex: none; width: 26px; height: 9px; margin-top: 7px;
  border-top: 2px solid #4e5058; border-left: 2px solid #4e5058; border-top-left-radius: 6px;
}
.lh-reacts { display: flex; gap: 5px; }
.lh-react {
  display: inline-flex; align-items: center; gap: 4px; padding: 1px 7px;
  border-radius: 8px; background: #5865f226; border: 1px solid #5865f2;
  font-size: 13.5px; color: #dee0fc;
}
.lh-thread {
  display: flex; align-items: center; gap: 7px; padding: 6px 0 2px;
  border-top: 1px dashed #4e5058; font-size: 13px; color: #949ba4;
}
.lh-thread b { color: #dbdee1; font-weight: 600; }
.lh-thread-ico { font-weight: 700; color: #949ba4; }
.lh-slash { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 13px; color: #b5bac1; padding-left: 4px; }
.lh-slash-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 4px; background: #4e5058; color: #fff;
  font-size: 11px; font-weight: 700;
}
.lh-args { color: #949ba4; }
.lh-btns { display: flex; flex-wrap: wrap; gap: 6px; }
.lh-b {
  display: inline-flex; align-items: center; min-height: 30px; padding: 0 11px;
  border-radius: 5px; color: #fff; font-size: 13.5px; font-weight: 500; white-space: nowrap;
}
.lh-b-g { background: #248046; }
.lh-b-r { background: #da373c; }
.lh-b-p { background: #5865f2; }
.lh-b-s { background: #4e5058; }
.lh-chat .dc-select { height: 36px; font-size: 14px; }

/* ─────────────── Главная (render.landing_page) ───────────────
   Ссылку кидают в ЛС и ставят в профиль бота. Картинки Discord — те же
   классы, что у подсказок к спискам (.lh-chat, .dc-box, .lh-b): главная
   показывает то, что рисует бот. Полосы тянутся от края до края окна
   (main.lp), текст внутри — в .wrap.

   С 11.10.2026 без примет шаблонного лендинга: нет надписи капсом над
   заголовком, мигающей точки в «таблетке», трёх шагов с крупными цифрами,
   подсвеченного тарифа и плашки «Попробуйте» в конце. Разделы — линиями,
   а не карточками; скругления маленькие. */
body > main.lp { padding-block: 0 8px; }
.lp-nav { display: flex; gap: 22px; margin-left: 18px; margin-right: auto; font-size: 15.5px; }
.lp-nav a { color: var(--ink-2); }
.lp-nav a:hover { color: var(--ink); }
.lp-login { flex: none; }
@media (max-width: 720px) { .lp-nav { display: none; } }

.lp-hero-in {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.02fr);
  gap: clamp(28px, 4vw, 60px); align-items: start; padding-block: 52px 56px;
}
@media (max-width: 940px) {
  .lp-hero-in { grid-template-columns: minmax(0, 1fr); padding-block: 32px 40px; }
}
/* Названия проектов — своими цветами: GTA5RP золотом, Majestic RP
   малиновым #fc036b (оба цвета — просьба владельца, 04.10.2026; тот же
   малиновый у метки .lh-mj). */
.lp-gta { color: #f2bf4a; }
.lp-mj { color: #fc036b; }
.lp-h1 {
  font-weight: 600; font-size: clamp(30px, 3.5vw, 44px); line-height: 1.15;
  letter-spacing: -.01em; margin: 0 0 18px; text-wrap: balance;
}
.lp-lede { margin: 0 0 26px; max-width: 54ch; font-size: 18px; color: var(--ink-2); text-wrap: pretty; }
.lp-lede code, .lp-hcap code, .lp-faq code {
  color: var(--ink); background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 4px; padding: 0 5px; font-size: .88em;
}
.lp-cta { display: flex; flex-wrap: wrap; gap: 10px; }
/* Ставится после .btn-main: та растянула бы кнопку на всю ширину. */
.lp-btn { width: auto; height: 48px; padding: 0 20px; gap: 10px; border-radius: 6px; }
.lp-note { margin: 16px 0 0; font-size: 15.5px; color: var(--ink-3); }
/* Счётчик серверов — отдельной плашкой с зелёной точкой «в сети»
   (владелец, 12.10.2026). Кольцо вокруг точки медленно расходится. */
.lp-live {
  display: flex; align-items: center; gap: 11px; width: fit-content; max-width: 100%;
  margin: 18px 0 0; padding: 9px 16px 9px 14px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--surface); font-size: 15.5px; color: var(--ink-2);
}
.lp-live b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.lp-live-dot {
  position: relative; flex: none; width: 9px; height: 9px; border-radius: 50%;
  background: var(--ok); box-shadow: 0 0 6px #44ff8866;
}
.lp-live-dot::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  border: 2px solid var(--ok); animation: lp-live-ring 2.4s ease-out infinite;
}
@keyframes lp-live-ring {
  from { transform: scale(1); opacity: .6; }
  to { transform: scale(2.6); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .lp-live-dot::after { animation: none; opacity: 0; } }

/* Под кнопками — вкладки примеров (render._lp_hero): война семей и капты
   (`!список`, `!взп` и `/капт` — у двух последних пример доходит стрелкой до
   `!список`) и РП-мероприятия.
   Подписи и примеры стоят каждый в своей клетке друг на друге. Место подписей
   держит самая длинная — вкладки не прыгают; рамка примера берёт высоту
   текущего (dash.js), иначе над короткими стояла пустота, а место под ней
   (.lp-hslot) — по самому высокому, чтобы не прыгало то, что ниже. Без скриптов
   вкладок нет и виден только первый слайд. */
.lp-how { margin-top: 34px; padding-top: 22px; border-top: 1px solid var(--line); }
.lp-how-h { margin: 0 0 12px; font-size: 15.5px; font-weight: 600; color: var(--ink); }
.lp-htabs { display: none; flex-wrap: wrap; gap: 10px 22px; margin: 0 0 14px; }
html.js .lp-htabs { display: flex; }
.lp-hgrp { display: grid; gap: 6px; }
.lp-hgrp-h { font-size: 14px; color: var(--ink-3); }
.lp-hgrp-tabs { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.lp-hgrp .lp-stab { display: inline-flex; align-items: center; padding: 0 12px; }
.lp-hcap { margin: 0; max-width: 58ch; font-size: 16px; color: var(--ink-2); text-wrap: pretty; }
/* Стрелка от карточки `!взп` / `/капт` к ветке `!список` (шаг «flow»):
   кружок со стрелкой вниз и строка «Модератор выбирает [Создать список] в
   меню…». Пункт меню — плашкой, как кнопка Discord; строка — обычное
   предложение и переносится по словам. Рамка пунктиром — это не сообщение
   в чате, а переход от одного к другому. */
.lp-flow {
  display: flex; align-items: center; gap: 12px; margin: 2px 0;
  padding: 8px 10px 8px 3px; border-radius: 8px;
  background: #5865f214; border: 1px dashed #5865f2a6;
  font-size: 13.5px; line-height: 1.75; color: #b5bac1;
}
.lp-flow-arrow {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; margin-left: 4px; border-radius: 50%;
  background: #5865f2; color: #fff;
}
.lp-flow-txt { min-width: 0; }
.lp-flow-txt > * { vertical-align: middle; }
.lp-flow b { color: #f2f3f5; font-weight: 600; }
.lp-pick { min-height: 24px; gap: 4px; padding: 0 8px; font-size: 12.5px; margin: 0 2px; }
html:not(.js) .lp-hero .lp-slide:not(.is-on) { display: none; }
.lp-hslot { position: relative; min-width: 0; }
/* Пример со стрелкой (`!взп`, `/капт`) — карточка записи и ветка `!список`
   под ней — почти вдвое выше левой колонки. Рамка не выше 820 px, лишнее
   листается внутри, как чат Discord, и через пару секунд чат сам доезжает
   до стрелки (dash.js). Без потолка первый экран вырастал до 1 400 px, а под
   короткими примерами оставалась пустота в 700 px. Тень снизу — пока ниже
   есть что листать; её место в потоке гасят отступы (вместе с gap рамки). */
.lp-hcard {
  max-height: 820px; overflow-y: auto; overflow-anchor: none;
  scrollbar-width: thin; scrollbar-color: #4e5058 transparent;
}
/* Рамка — колонка flex: без flex: none набор сжался бы до её высоты, и
   листать было бы нечего. */
.lp-hcard > .lp-slides { flex: none; }
.lp-hcard::after {
  content: ""; position: sticky; bottom: 0; flex: none; height: 56px;
  margin: -68px -12px 0; background: linear-gradient(#31333800, #313338 85%);
  pointer-events: none; opacity: 0; transition: opacity .2s;
}
.lp-hcard.has-more::after { opacity: 1; }
/* Стрелка над низом рамки (render._lp_hero, dash.js): есть что листать —
   вниз и плавно до конца примера, внизу — наверх. Стоит в .lp-hslot, а не
   в самой рамке: иначе уезжала бы вместе с содержимым. Видна, только когда
   рамка листается, — тогда её высота и есть высота .lp-hslot. */
.lp-hmore {
  position: absolute; left: 50%; bottom: 14px; z-index: 2;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; margin-left: -20px; padding: 0; border-radius: 50%;
  border: 1px solid #ffffff2e; background: #1e1f22e6; color: #f2f3f5;
  box-shadow: 0 4px 14px #0000008c; cursor: pointer;
  transition: background .15s, border-color .15s;
}
.lp-hmore[hidden] { display: none; }
/* Место под кнопкой в конце листаемого примера; dash.js (more) берёт его
   отсюда и не считает «есть что листать». */
.lp-hcard.can-scroll > .lp-slides { margin-bottom: 52px; }
.lp-hmore:hover { background: #5865f2; border-color: #5865f2; }
.lp-hmore:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lp-hmore svg { width: 20px; height: 20px; transition: transform .25s; }
.lp-hmore.is-up svg { transform: rotate(180deg); }
/* Пока зовёт вниз — слегка покачивается, чтобы её заметили. */
.lp-hmore:not(.is-up) { animation: lp-hmore-bob 2s ease-in-out infinite; }
.lp-hmore:hover { animation-play-state: paused; }
@keyframes lp-hmore-bob { 50% { transform: translateY(4px); } }
@media (prefers-reduced-motion: reduce) { .lp-hmore { animation: none; } }
@media (max-width: 940px) { .lp-hcard { max-height: min(820px, 88vh); } }
.lp-hscene { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.lp-htabs:hover .lp-stab.is-on i, .lp-htabs:focus-within .lp-stab.is-on i,
.lp-hero-in:has(.lp-hslot:hover) .lp-stab.is-on i,
.lp-hero-in.is-away .lp-stab.is-on i { animation-play-state: paused; }
/* Сценки списков: ответ на объявление в одну строку, длинное имя ветки — с
   многоточием. */
.lh-reply .dmd-mention { flex: none; }
.lp-chat .lh-thread { white-space: nowrap; }
.lp-reply-txt, .lp-chat .lh-thread b { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lp-chat { font-size: 15px; min-width: 0; }
.lp-bot-ava { width: 40px; height: 40px; object-fit: cover; }

/* Вкладки примеров: полоска под активной отмеряет время до следующего
   (смену делает dash.js по animationend). Наведение ставит полоску на
   паузу — а с ней и смену. */
.lp-stab {
  position: relative; overflow: hidden; height: 34px; padding: 0 14px; border-radius: 6px;
  border: 1px solid var(--line); background: var(--surface-2); color: var(--ink-2);
  font: inherit; font-size: 14.5px; font-weight: 500; cursor: pointer;
}
.lp-stab:hover { color: var(--ink); }
.lp-stab.is-on { color: var(--ink); border-color: #4a5060; }
.lp-stab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lp-stab i {
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--accent);
  transform: scaleX(0); transform-origin: left;
}
.lp-stab.is-on i { animation: lp-progress var(--lp-int) linear forwards; }
[data-lp-slider].is-held .lp-stab.is-on i { animation-play-state: paused; }
@keyframes lp-progress { to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) { .lp-stab.is-on i { animation: none; transform: scaleX(1); } }
.lp-slides { display: grid; gap: 12px; }
/* Смена по очереди: старый пример гаснет, затем проявляется новый. Высоту
   контейнеру без data-lp-keep ставит dash.js — по текущему примеру. */
html.js .lp-slides { overflow: hidden; transition: height .35s ease; }
html.js .lp-slide { grid-area: 1 / 1; align-self: start; opacity: 0; visibility: hidden; transition: opacity .2s ease, visibility 0s linear .2s; }
html.js .lp-slide.is-on { opacity: 1; visibility: visible; transition: opacity .25s ease .2s, visibility 0s linear .2s; }
@media (prefers-reduced-motion: reduce) { html.js .lp-slides, html.js .lp-slide, html.js .lp-slide.is-on { transition: none; } }

/* Примеры Discord собирает бот (tools/landing_examples.py), здесь — только
   то, чего нет у подсказок к спискам: раздел с миниатюрой, классический
   embed, картинка-ответ и список участников. Цвета — как в клиенте Discord. */
.lh-b { gap: 6px; }
.lh-b .dmd-emoji { width: 18px; height: 18px; vertical-align: middle; }
.lp-b-off { opacity: .5; }
.lp-ex-section { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px; align-items: start; }
.lp-ex-thumb { width: 72px; height: 72px; border-radius: 8px; object-fit: cover; }
.lp-ex-banner { width: 100%; height: auto; }
.lp-gif-wrap { position: relative; display: block; }
.lp-gif {
  position: absolute; top: 8px; left: 8px; padding: 1px 6px; border-radius: 4px;
  background: #000000b3; color: #fff; font-size: 12px; font-weight: 700; letter-spacing: .02em;
}
.lp-ex-card { display: block; width: 100%; height: auto; border-radius: 8px; margin-top: 2px; }
.lp-em {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 14px; max-width: 520px;
  padding: 12px 14px 14px 12px; background: #2b2d31; border: 1px solid #383a40;
  border-left: 4px solid var(--em, #4e5058); border-radius: 6px;
}
.lp-em-main { display: grid; gap: 8px; min-width: 0; }
.lp-em-title { font-size: 15.5px; font-weight: 700; color: #f2f3f5; }
.lp-em-desc, .lp-em-val { font-size: 14px; line-height: 1.375; color: #dbdee1; overflow-wrap: anywhere; }
.lp-em-fields { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px 12px; }
.lp-em.has-thumb .lp-em-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.lp-em-field { grid-column: 1 / -1; min-width: 0; }
.lp-em-field.is-inline { grid-column: auto; }
.lp-em-break { grid-column: 1 / -1; height: 0; }
.lp-em-name { margin-bottom: 2px; font-size: 14px; font-weight: 600; color: #f2f3f5; overflow-wrap: anywhere; }
.lp-em-thumb { width: 80px; height: 80px; border-radius: 6px; object-fit: cover; }
.lp-em-foot { font-size: 12.5px; color: #949ba4; }
/* Телефон: на ширину сообщения остаётся меньше 250 px, и миниатюра embed
   сжимала поля до 120 px — по слову в строку. Поля встают колонкой, а
   миниатюра уходит: без неё сообщение читается целиком. */
@media (max-width: 520px) {
  .lp-em, .lp-em-fields, .lp-em.has-thumb .lp-em-fields { grid-template-columns: minmax(0, 1fr); }
  .lp-em-thumb { display: none; }
  .lp-ex-thumb { width: 48px; height: 48px; }
}
.lp-nicks { display: grid; gap: 2px; padding: 2px; }
.lp-nick-role {
  margin-bottom: 4px; font-size: 12px; font-weight: 700; letter-spacing: .02em;
  text-transform: uppercase; color: #949ba4;
}
.lp-nick { display: flex; align-items: center; gap: 10px; padding: 4px 6px; border-radius: 4px; font-weight: 500; color: #3498db; }
.lp-nick:hover { background: #35373c; }
.lp-nick-ava {
  display: flex; align-items: center; justify-content: center; flex: none;
  width: 30px; height: 30px; border-radius: 50%; background: #5865f2; color: #fff; font-size: 13px;
}

/* ряд семей */
.lp-band { border-block: 1px solid var(--line); background: var(--surface); }
.lp-trust { display: grid; gap: 16px; padding-block: 22px 26px; }
.lp-fam-h { margin: 0; font-size: 15.5px; font-weight: 600; color: var(--ink-2); }
.lp-fams {
  list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(176px, 1fr)); gap: 16px 20px;
}
.lp-fam { display: flex; align-items: center; gap: 12px; min-width: 0; }
.lp-fam > div { min-width: 0; }
.lp-fam b { display: block; font-size: 16px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lp-fam-sub { display: block; font-size: 13.5px; color: var(--ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lp-fam-ava { flex: none; width: 42px; height: 42px; border-radius: 50%; object-fit: cover; }
.lp-fam-letter {
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; font-weight: 700; color: var(--ink); background: var(--fa, #34467a);
}
.lp-fa1 { --fa: #34467a; } .lp-fa2 { --fa: #6a3f5c; } .lp-fa3 { --fa: #2f5d55; }
.lp-fa4 { --fa: #6b5532; } .lp-fa5 { --fa: #4b3a78; } .lp-fa6 { --fa: #3d5a3a; }

/* разделы */
.lp-sec { padding-top: 72px; }
.lp-sec:last-child { padding-bottom: 72px; }
.lp-h2 {
  font-weight: 600; font-size: clamp(24px, 2.4vw, 32px); line-height: 1.2;
  letter-spacing: -.01em; margin: 0 0 10px; text-wrap: balance;
}
.lp-sub { max-width: 68ch; margin: 0 0 26px; font-size: 17px; color: var(--ink-2); text-wrap: pretty; }

/* ── Что ещё умеет бот (render._lp_features) ──
   Крупные карточки с примерами Discord и ряд фишек «Также бот умеет:».
   11.10.2026 владелец вернул этот вид вместо каталога всех функций. */
.lp-feats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
@media (max-width: 860px) { .lp-feats { grid-template-columns: minmax(0, 1fr); } }
.lp-feat {
  display: grid; gap: 18px; align-content: start; min-width: 0; padding: 20px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
}
.lp-feat h3 { margin: 0; font-size: 19px; font-weight: 600; }
.lp-feat p { margin: 4px 0 0; font-size: 16px; color: var(--ink-2); }
/* Широкая карточка на всю строку: текст сбоку от примера. У заявок
   примеров два (панель и карточка), и в половину строки слайдер с
   карточкой заявки вытягивал соседа вдвое. */
.lp-feat-wide {
  grid-column: 1 / -1; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  gap: 28px; align-items: start;
}
.lp-feat-text-left > .lp-feat-txt { order: -1; }
.lp-feat-text-right { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); align-items: center; }
.lp-feat-wide .lp-feat-txt { padding-top: 6px; }
.lp-feat-wide h3 { font-size: 21px; }
@media (max-width: 860px) {
  .lp-feat-wide, .lp-feat-text-right { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .lp-feat-text-left > .lp-feat-txt { order: 0; }
}
.lp-mini { padding: 12px 10px; }
@media (max-width: 520px) {
  .lp-feat { padding: 14px; }
  .lp-mini { padding: 10px 6px; }
}
.lp-points { margin: 14px 0 0; padding: 0; list-style: none; display: grid; gap: 8px; font-size: 15.5px; color: var(--ink-2); }
.lp-points li { position: relative; padding-left: 22px; }
.lp-points li::before {
  content: ""; position: absolute; left: 2px; top: .45em; width: 9px; height: 5px;
  border-left: 2px solid #8b93f8; border-bottom: 2px solid #8b93f8; transform: rotate(-45deg);
}
/* Слайдер примеров в карточке заявок: вкладки сверху, полоска под активной
   отмеряет время до следующего примера. Без скриптов примеры стоят друг
   под другом. */
.lp-slider { display: grid; gap: 10px; min-width: 0; --lp-int: 7s; }
.lp-stabs { display: none; gap: 6px; }
html.js .lp-stabs { display: flex; flex-wrap: wrap; }
.lp-slider:hover .lp-stab.is-on i, .lp-slider:focus-within .lp-stab.is-on i,
.lp-slider.is-away .lp-stab.is-on i { animation-play-state: paused; }
.lp-cab {
  display: grid; padding: 4px 16px 16px; background: var(--bg);
  border: 1px solid var(--line); border-radius: 12px;
}
.lp-cab-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 11px 0; border-bottom: 1px solid var(--line-soft); font-size: 15px;
}
.lp-cab-row small { display: block; font-size: 13px; color: var(--ink-3); }
.lp-sw { position: relative; flex: none; width: 38px; height: 22px; border-radius: 999px; background: var(--line); }
.lp-sw::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px;
  border-radius: 50%; background: var(--ink-3);
}
.lp-sw.is-on { background: var(--accent); }
.lp-sw.is-on::after { left: 19px; background: #fff; }
.lp-cab-save {
  display: flex; align-items: center; justify-content: center; height: 40px; margin-top: 14px;
  border-radius: 9px; background: var(--accent); color: #fff; font-size: 15px; font-weight: 600;
}
.lp-more { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 26px; }
.lp-more-lead { margin-right: 4px; font-size: 15.5px; font-weight: 600; color: var(--ink-2); }
/* Фишка «Также бот умеет» — это .lh-cmd подсказок к спискам: наведение
   показывает окно с описанием и примером, нажатие — окно справки. */
.lp-chip {
  padding: 6px 12px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); font-size: 14.5px; color: var(--ink-2); white-space: nowrap;
  transition: border-color .25s ease, box-shadow .25s ease, color .25s ease;
}
.lp-chip:hover, .lp-chip:focus-visible { border-color: #4a5060; color: var(--ink); }
/* Обводка по очереди (dash.js, «Обводка фишек»): ряд появился на экране —
   фишки одна за другой загораются рамкой, видно, что это кнопки. */
.lp-chip.is-glow { border-color: var(--accent); color: var(--ink); box-shadow: 0 0 0 3px var(--accent-soft); }
@media (prefers-reduced-motion: reduce) { .lp-chip { transition: none; } }
.lp-tip { white-space: normal; }
.lp-tip-head { margin-bottom: 4px; font-size: 15.5px; font-weight: 600; color: var(--ink); }
.lp-tip-desc { margin: 0 0 10px; }
.lp-tip .lh-pv-head { margin-bottom: 6px; }
.lp-dlg { max-width: 560px; }
.lp-dlg .lh-lead { margin-bottom: 14px; }
.lp-dlg-pv { max-width: 100%; }

/* ── Поиск функций в кабинете (render._cat_search, catalog.py) ──
   Поле над карточками функций: «отчёты» находят магазин активности.
   Без скриптов поля нет, а карточки видны все. */
.cat-find { display: grid; gap: 10px; max-width: 640px; margin: 4px 0 18px; }
.cat-find[hidden] { display: none; }
.cat-q {
  width: 100%; height: 44px; padding: 0 16px 0 46px; border: 1px solid #3a404e; border-radius: 6px;
  background: var(--bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%23767c89' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E") 15px 50% no-repeat;
  color: var(--ink); font: inherit; font-size: 16px;
}
.cat-q::placeholder { color: var(--ink-3); }
.cat-q:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.cat-reset {
  padding: 0; border: 0; background: none; font: inherit; color: #8b93f8; cursor: pointer;
  text-decoration: underline; text-decoration-color: #8b93f866; text-underline-offset: 3px;
}
.cat-reset:hover { color: #aab0fa; }
.cat-status { margin: 0; font-size: 15.5px; color: var(--ink-2); }
.cat-status:not(:has(span:not([hidden]))) { display: none; }
.cat-status b { color: var(--ink); }
[data-cat-group][hidden], .feat[hidden] { display: none; }
/* Пока идёт поиск, прячутся заголовок и легенда над карточками: под ними
   могло не остаться ничего. */
.is-searching [data-cat-also] { display: none; }

/* Цены — двумя карточками, как до 11.10.2026: таблица с перечнем всех
   функций читалась простынёй (владелец вернул прежний вид). */
.lp-trial {
  max-width: 900px; margin: 0 0 20px; padding: 12px 16px; border-radius: 10px;
  background: var(--accent-soft); font-size: 16px; color: var(--ink);
}
.lp-trial b { color: #aab0fa; }
.lp-plans { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; max-width: 900px; }
@media (max-width: 700px) { .lp-plans { grid-template-columns: minmax(0, 1fr); } }
.lp-plan {
  display: grid; gap: 16px; align-content: start; padding: 24px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
}
.lp-plan-main { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.lp-plan-top { display: grid; gap: 2px; }
.lp-plan h3 { margin: 0; font-size: 22px; font-weight: 700; }
.lp-plan-top p { margin: 0; font-size: 15px; color: var(--ink-3); }
.lp-price { display: grid; gap: 2px; }
.lp-price b { font-size: 30px; font-weight: 700; letter-spacing: -.01em; font-variant-numeric: tabular-nums; }
.lp-price small { font-size: 16px; font-weight: 400; letter-spacing: 0; color: var(--ink-3); }
.lp-price span { font-size: 14.5px; color: var(--ink-2); }
.lp-plan ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; font-size: 15.5px; color: var(--ink-2); }
.lp-plan li { position: relative; padding-left: 24px; }
.lp-plan li::before {
  content: ""; position: absolute; left: 3px; top: .42em; width: 10px; height: 5px;
  border-left: 2px solid #8b93f8; border-bottom: 2px solid #8b93f8; transform: rotate(-45deg);
}
.lp-price-note { max-width: 72ch; margin: 18px 0 22px; font-size: 15px; color: var(--ink-3); }

/* Вопросы — в две колонки, как до 11.10.2026. */
.lp-faq { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 44px; margin: 0; }
@media (max-width: 860px) { .lp-faq { grid-template-columns: minmax(0, 1fr); } }
.lp-faq div { display: grid; gap: 6px; align-content: start; }
.lp-faq dt { font-size: 17px; font-weight: 600; }
.lp-faq dd { margin: 0; font-size: 16px; color: var(--ink-2); }

/* ─────────────── Семьи на главной (панель владельца) ─────────────── */
.shw { padding: 0; overflow: hidden; }
.shw-head { padding: 20px 22px 16px; border-bottom: 1px solid var(--line); }
.shw-head h2 { margin: 0 0 4px; }
.shw-head .muted { margin: 0; }
.shw > .muted { margin: 0; padding: 18px 22px; }
.shw-row {
  display: grid; grid-template-columns: 40px minmax(0, 1.1fr) minmax(0, 1.7fr) auto;
  align-items: center; gap: 16px; padding: 14px 22px; border-bottom: 1px solid var(--line-soft);
}
.shw-row:last-child { border-bottom: 0; }
.shw-ava { flex: none; display: block; border-radius: 50%; object-fit: cover; }
.shw-ava-text {
  display: inline-flex; align-items: center; justify-content: center;
  background: #2d3140; color: #c8cdd8; font-size: 14px; font-weight: 600;
}
.shw-name { display: block; min-width: 0; }
.shw-name b { display: block; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shw-name span { display: block; font-size: 14px; color: var(--ink-3); }
.shw-state { display: grid; gap: 5px; justify-items: start; min-width: 0; }
.shw-sub { font-size: 14px; color: var(--ink-3); overflow-wrap: anywhere; }
.shw-sub b { font-weight: 500; color: var(--ink-2); }
.shw-swap { display: inline-flex; align-items: center; gap: 6px; margin-right: 8px; vertical-align: middle; }
.shw-pill {
  display: inline-flex; align-items: center; gap: 7px; padding: 4px 10px; border-radius: 999px;
  font-size: 13.5px; font-weight: 500;
}
.shw-pill::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.shw-ok { background: #44ff8817; color: var(--ok); }
.shw-warn { background: #f39c121c; color: var(--warn); }
.shw-bad { background: #ff44441a; color: #ff8080; }
.shw-act { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; margin: 0; }
@media (max-width: 760px) {
  .shw-row { grid-template-columns: 40px minmax(0, 1fr); }
  .shw-state, .shw-act { grid-column: 2; }
  .shw-act { justify-content: flex-start; }
}
.shw-cand { border-bottom: 1px solid var(--line-soft); }
.shw-cand:last-child { border-bottom: 0; }
.shw-cand > summary {
  display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; align-items: center; gap: 16px;
  padding: 14px 22px; cursor: pointer; list-style: none;
}
.shw-cand > summary::-webkit-details-marker { display: none; }
.shw-cand[open] > summary .shw-add { border-color: var(--accent); color: var(--ink); }
.shw-form {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px;
  margin: 0 22px 18px; padding: 18px; border: 1px solid var(--own-line); border-radius: 12px;
  background: var(--bg);
}
@media (max-width: 640px) { .shw-form { grid-template-columns: minmax(0, 1fr); } }
.shw-field { display: grid; gap: 6px; align-content: start; min-width: 0; font-size: 15px; color: var(--ink-2); }
.shw-field .inp { width: 100%; }
.shw-field small { font-size: 13.5px; color: var(--ink-3); }
.shw-wide { grid-column: 1 / -1; margin: 0; }
.shw-copy { display: flex; align-items: center; gap: 12px; font-size: 14.5px; color: var(--ink-2); }

/* ─── аналитика владельца ─── */
.an-h { font-size: 17px; margin: 6px 0 10px; color: var(--ink-2); font-weight: 600; }
.an-delta { font-size: 13.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.an-line { margin: 4px 0 18px; }
.card .an-line { margin: 12px 0 0; }
.an-sub { font-size: 15.5px; margin: 18px 0 4px; color: var(--ink-2); }
/* Две карточки рядом; на узком экране — одна под другой. */
.an-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-bottom: 14px; }
.an-grid > .card { margin-bottom: 0; min-width: 0; }
/* Значение воронки — число и доля от прошлого шага, шире обычного. */
.an-val { flex-basis: 96px; display: flex; flex-direction: column; align-items: flex-end; line-height: 1.25; }
.an-val b { color: var(--ink); font-weight: 600; }
.an-val span { font-size: 13.5px; color: var(--ink-3); }
.an-funnel .tool-name { white-space: normal; overflow: visible; text-overflow: clip; }
/* В карточке на полширины подпись сжимается, а не выталкивает число
   за край: обычная .tool-name стоит жёстко на 260 px. */
.an-grid .tool-name, .an-funnel .tool-name { flex: 0 1 230px; min-width: 0; }
.an-grid .tool-bar { min-width: 40px; }
.an-tbl td.an-wrap { white-space: normal; min-width: 160px; }
.an-tbl td.an-why { min-width: 260px; }
.an-tbl .srv-sub { display: block; }
.an-tbl .pill { white-space: nowrap; }
.an-reasons { margin: 4px 0 0; padding-left: 18px; font-size: 14px; color: var(--ink-2); }
/* Рядом — только когда каждой карточке хватает места под подпись, полоску
   и число; уже — подписи воронок резались посреди слова. */
@media (max-width: 1200px) {
  .an-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 620px) {
  .an-funnel .tool { flex-wrap: wrap; row-gap: 6px; }
  .an-funnel .tool-name { flex-basis: 100%; }
}

/* ─── Ожидание ответа после нажатия (dash.js, «Ожидание ответа») ───
   Нажатая кнопка крутит значок сразу, остальные кнопки формы гаснут, а
   сверху появляется плашка: «Применяю…», потом — что бот перерисовал панель
   в Discord или почему не смог. Без скриптов плашка перерисовки — обычный
   блок под заголовком страницы. */
.wait {
  display: flex; align-items: flex-start; gap: 12px; max-width: 560px; margin: 0 0 16px;
  padding: 12px 12px 12px 14px; background: var(--surface-2); color: var(--ink);
  border: 1px solid #3a404e; border-radius: 8px; font-size: 15.5px; line-height: 1.45;
}
.wait[hidden] { display: none; }
html.js .wait {
  position: fixed; z-index: 90; top: 16px; left: 50%; transform: translateX(-50%);
  width: min(560px, calc(100vw - 32px)); margin: 0; box-shadow: 0 12px 32px #00000080;
}
/* На страницах с меню — по центру содержимого, а не окна. */
@media (min-width: 861px) {
  html.js body.has-side .wait { left: calc(var(--sidew) + (100vw - var(--sidew)) / 2); }
}
.wait-txt { display: grid; gap: 2px; flex: 1 1 auto; min-width: 0; }
.wait-txt b { font-weight: 600; }
.wait-txt span { font-size: 14.5px; color: var(--ink-2); }
.wait-txt span[hidden] { display: none; }
.wait-spin {
  flex: none; width: 18px; height: 18px; margin-top: 2px; border-radius: 50%;
  border: 2px solid var(--accent); border-right-color: transparent;
  animation: wait-spin .8s linear infinite;
}
.wait.is-ok { border-left: 3px solid var(--ok); }
.wait.is-err { border-left: 3px solid var(--bad); }
.wait.is-ok .wait-spin, .wait.is-err .wait-spin { display: none; }
.wait-x {
  flex: none; padding: 0 4px; border: 0; background: none; color: var(--ink-3);
  font: inherit; font-size: 20px; line-height: 1; cursor: pointer;
}
.wait-x:hover { color: var(--ink); }
html:not(.js) .wait-x { display: none; }
/* Повторное нажатие, пока ждём: плашка мигает рамкой — «я тут, жду». */
.wait.is-nudge { animation: wait-nudge .6s ease; }
@keyframes wait-nudge { 50% { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft), 0 12px 32px #00000080; } }
@keyframes wait-spin { to { transform: rotate(360deg); } }

/* Нажатая кнопка: значок перед подписью; остальные кнопки формы гаснут. */
/* Только кнопки: тем же классом помечены плашка ожидания и размытая
   расстановка, и у них нажатия отбирать нельзя. */
button.is-busy, input.is-busy { pointer-events: none; }
button.is-busy::before {
  content: ""; display: inline-block; flex: none; width: .9em; height: .9em;
  margin-right: .5em; vertical-align: -.1em; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent;
  animation: wait-spin .8s linear infinite;
}
form.is-sending button[type="submit"]:not(.is-busy),
form.is-sending input[type="submit"] { opacity: .5; pointer-events: none; }
html.is-sending body { cursor: progress; }
@media (prefers-reduced-motion: reduce) {
  .wait-spin, button.is-busy::before { animation-duration: 2.4s; }
  .wait.is-nudge { animation: none; }
}

/* ─── «Оформление бота» (render._botprofile_section) ───
   Что стоит и что на проверке — маленькими картинками рядом со строками
   состояния; справа — профиль бота, как его увидят на сервере. */
.bp-now { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.bp-figs { display: flex; gap: 12px; flex: none; }
.bp-fig { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 5px; }
.bp-fig figcaption { font-size: 13.5px; color: var(--ink-3); }
.bp-thumb { display: block; background: #2b2d31; border: 1px solid var(--line); object-fit: cover; }
.bp-thumb-avatar { width: 64px; height: 64px; border-radius: 50%; }
.bp-thumb-banner { width: 160px; height: 64px; border-radius: 8px; }
.bp-thumb-blank { background: linear-gradient(135deg, #2b2d31, #1e1f24); }
.bp-status { list-style: none; margin: 0; padding: 0; flex: 1 1 260px; min-width: 0;
  display: flex; flex-direction: column; gap: 6px; font-size: 15.5px; color: var(--ink-2); }
.bp-status li { display: flex; align-items: baseline; gap: 9px; }
.bp-status .dot { position: relative; top: -1px; }
.bp-row .bn-up { margin-top: 14px; }
/* Без этого поле сжималось до «Файл …бран» рядом с подписью. */
.bp-row .upfile { flex: 0 1 360px; }
.bp-row .up-pick { display: block; margin-top: 8px; }
.bp-row .up-pick[hidden] { display: none; }
.bp-reset { margin-top: 12px; padding-left: 0; width: max-content; max-width: 100%; }
.bp-reset:hover { background: none; }
.bp-ro { padding-top: 10px; color: var(--ink-2); overflow-wrap: anywhere; }
.bp-bio-ro { white-space: pre-wrap; }
.bp-count { text-align: right; }

/* Профиль — как всплывающая карточка Discord: баннер, аватар на его краю,
   ник с меткой BOT, «Обо мне». Баннер бот обрезает до 5:2 по центру, и
   картинка здесь режется так же (object-fit). */
.bp-pcard { position: relative; background: #232428; font-family: var(--dc-font); }
.bp-pbanner { aspect-ratio: 5 / 2; background: #5865f2; overflow: hidden; }
.bp-pbanner-img { display: block; width: 100%; height: 100%; object-fit: cover; }
.bp-pbanner-img[hidden] { display: none; }
/* Аватар на нижнем краю баннера: поднят отрицательным отступом, а не
   абсолютом, — высота баннера зависит от ширины колонки. */
.bp-pava {
  position: relative; display: block; margin: -46px 0 0 16px;
  width: 80px; height: 80px; border-radius: 50%; object-fit: cover;
  border: 6px solid #232428; background: #232428; box-sizing: content-box;
}
.bp-pbody { padding: 10px 16px 16px; display: flex; flex-direction: column; gap: 12px; }
.bp-pname { display: flex; align-items: center; gap: 7px; font-size: 20px; font-weight: 700;
  color: #f2f4f8; overflow-wrap: anywhere; }
.bp-pabout { background: #111214; border-radius: 8px; padding: 12px; }
.bp-pabout[hidden] { display: none; }
.bp-pabout-t { font-size: 12px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .02em; color: #b5bac1; margin-bottom: 6px; }
.bp-pbio { font-size: 14px; line-height: 1.4; color: #dbdee1; white-space: pre-wrap;
  overflow-wrap: anywhere; }

/* ─── «Оформление бота» в панели владельца (render.owner_botprofile_page) ───
   Карточка на сервер: что стоит → что прислали, решение рядом. Новая
   картинка размыта до нажатия, как под спойлером в Discord. */
.nav-badge {
  margin-left: auto; min-width: 22px; height: 20px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; background: var(--own); color: #1a1608;
  font-size: 12.5px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.ownerlink .nav-badge { margin-left: 2px; }
.ownerlink.is-on .nav-badge { background: #1a1608; color: var(--own); }
.bpo-h { font-size: 19px; margin: 22px 0 10px; }
.bpo-card { padding: 20px 22px; scroll-margin-top: 16px; }
.bpo-card:target { border-color: var(--own-line); }
.bpo-head { display: flex; align-items: center; flex-wrap: wrap; gap: 12px 16px; }
.bpo-name { display: flex; flex-direction: column; flex: 1 1 220px; min-width: 0; }
.bpo-name b { font-size: 17px; font-weight: 600; overflow-wrap: anywhere; }
.bpo-note { display: flex; align-items: baseline; gap: 9px; margin: 12px 0 0;
  font-size: 15px; color: var(--ink-2); overflow-wrap: anywhere; }
.bpo-texts { display: grid; gap: 8px; margin-top: 14px; padding: 12px 14px;
  background: var(--bg); border: 1px solid var(--line-soft); border-radius: 10px; }
.bpo-texts > div { display: grid; grid-template-columns: 110px minmax(0, 1fr); gap: 12px;
  font-size: 15px; color: var(--ink); }
.bpo-k { color: var(--ink-3); }
.bpo-bio { white-space: pre-wrap; overflow-wrap: anywhere; }
.bpo-standing { margin-top: 14px; flex-wrap: wrap; }
.bpo-req { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--line-soft); }
.bpo-req-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px;
  margin-bottom: 12px; font-size: 16px; }
.bpo-pics { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; }
.bpo-arrow { font-size: 22px; color: var(--ink-3); }
.bpo-thumb-avatar { width: 112px; height: 112px; border-radius: 50%; }
.bpo-thumb-banner { width: 280px; max-width: 70vw; height: auto; aspect-ratio: 5 / 2;
  border-radius: 8px; }
.bpo-veil { position: relative; display: block; cursor: pointer; overflow: hidden; }
.bpo-veil-chk { position: absolute; opacity: 0; pointer-events: none; }
.bpo-veil img { filter: blur(22px) saturate(.6); transition: filter .15s; }
.bpo-veil-cap {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  gap: 6px; font-size: 14px; font-weight: 600; color: #fff; text-shadow: 0 1px 3px #000;
}
.bpo-veil-chk:checked ~ img { filter: none; }
.bpo-veil-chk:checked ~ .bpo-veil-cap { display: none; }
.bpo-veil-chk:focus-visible ~ img { outline: 2px solid var(--accent); outline-offset: 2px; }
.bpo-veil:has(.bpo-thumb-avatar) { border-radius: 50%; }
.bpo-veil:has(.bpo-thumb-banner) { border-radius: 8px; }
.bpo-meta { margin: 12px 0 0; font-size: 15px; color: var(--ink-2); overflow-wrap: anywhere; }
.bpo-acts { display: flex; align-items: flex-start; flex-wrap: wrap; gap: 10px; margin-top: 12px; }
.bpo-acts form { margin: 0; }
.bpo-acts .btn, .bpo-gacts .btn { height: 36px; padding: 0 14px; font-size: 15px; }
.bpo-reject > summary { list-style: none; display: inline-flex; align-items: center; }
.bpo-reject > summary::-webkit-details-marker { display: none; }
.bpo-reject[open] > summary { border-color: #7a3c46; }
.bpo-reject-form { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.bpo-reject-form .inp { flex: 1 1 320px; min-width: 0; }
.bpo-gacts { display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line-soft); }
.bpo-log { display: flex; flex-direction: column; }
.bpo-log-row { display: grid; grid-template-columns: 112px minmax(0, 1fr) auto; gap: 14px;
  padding: 9px 0; border-bottom: 1px solid var(--line-soft); font-size: 15px; }
.bpo-log-row:last-child { border-bottom: 0; }
.bpo-log-when { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.bpo-log-what { color: var(--ink-2); overflow-wrap: anywhere; }
.bpo-log-what b { color: var(--ink); font-weight: 600; }
.bpo-log-who { color: var(--ink-3); text-align: right; }
@media (max-width: 760px) {
  .bpo-card { padding: 16px; }
  .bpo-texts > div { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .bpo-log-row { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .bpo-log-who { text-align: left; }
}
@media (prefers-reduced-motion: reduce) { .bpo-veil img { transition: none; } }

/* ─── Заявки на серверы в панели владельца (render.owner_spyrequests_page) ───
   Те же карточки, что у «Оформления бота»: строки «что прислали», ниже —
   выбор аккаунта пула и «Отклонить» с подтверждением. */
.sr-texts { overflow-wrap: anywhere; }
.sr-texts a { color: var(--accent); }
.sr-raw { font-family: var(--mono); font-size: 14px; }
.sr-acts { align-items: center; gap: 12px 18px; }
.sr-fulfill, .sr-reject { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.sr-fulfill { flex: 1 1 420px; min-width: 0; }
.sr-fulfill .inp { flex: 1 1 280px; min-width: 0; max-width: 560px; height: 36px; }
.sr-nopool { margin: 0; flex: 1 1 420px; }
.sr-done .bpo-texts { margin-top: 12px; }
.sr-done .bpo-meta { color: var(--ink-3); }

/* ─── Уведомления владельца (render._notice_bell, dash.js) ───
   Колокольчик рядом со ссылкой «Панель владельца» — того же золотого цвета,
   число непрочитанного — красным кружком, как в мессенджерах. Раскрытый
   список, страница /owner/notices и окна в правом нижнем углу. */
.ownerbar { display: flex; align-items: center; gap: 8px; min-width: 0; }
.side-user .ownerbar .ownerlink { flex: 1 1 auto; min-width: 0; }
.nbell {
  position: relative; flex: none; display: inline-flex; align-items: center;
  justify-content: center; width: 34px; height: 34px; border-radius: 8px;
  border: 1px solid var(--own-line); background: var(--own-soft); color: var(--own);
}
.bar .nbell { width: 30px; height: 30px; }
.nbell:hover, .nbell.is-open, body.owner-mode .nbell:hover {
  color: #efb84e; border-color: var(--own);
}
.nbell-n {
  position: absolute; top: -8px; right: -9px; min-width: 20px; height: 20px;
  padding: 0 5px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; background: #f23f43; color: #fff;
  box-shadow: 0 0 0 2px #131519;
  font-size: 11.5px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums;
}
.bar .nbell-n { box-shadow: 0 0 0 2px var(--bg); }
.nbell-n[hidden] { display: none; }

/* Раскрытый колокольчик: место и высоту ставит dash.js по колокольчику. */
.npanel {
  position: fixed; z-index: 95; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid #2f3440; border-radius: 12px;
  box-shadow: 0 16px 40px #000000a0; overflow: hidden;
}
.npanel[hidden] { display: none; }
.npanel-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 14px; border-bottom: 1px solid var(--line);
}
.npanel-head b { font-size: 16px; }
.npanel-head a { font-size: 14.5px; color: var(--own); }
.npanel-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.npanel-foot { padding: 6px; border-top: 1px solid var(--line); }
.npanel-foot[hidden] { display: none; }
.npanel-desk {
  width: 100%; padding: 8px 10px; border: 0; border-radius: 8px; background: none;
  color: var(--ink-2); font: inherit; font-size: 14.5px; text-align: left; cursor: pointer;
}
.npanel-desk:hover:not(:disabled) { background: var(--surface-2); color: var(--ink); }
.npanel-desk:disabled { cursor: default; color: var(--ink-3); }
.nempty { margin: 0; padding: 18px 14px; color: var(--ink-3); font-size: 14.5px; }

/* «Ждут решения» — от прочтения не зависит. */
.npends { padding: 10px 10px 4px; border-bottom: 1px solid var(--line); }
.card .npends { padding: 0; border-bottom: 0; }
.npends-h {
  margin: 0 4px 6px; font-size: 12.5px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}
.npend {
  display: flex; align-items: center; gap: 10px; margin-bottom: 6px; padding: 8px 10px;
  border-radius: 8px; background: var(--own-soft); border: 1px solid var(--own-line);
}
.npend, body.owner-mode a.npend, a.npend:hover { color: var(--ink); }
a.npend:hover { border-color: var(--own); }
.npend-name { display: grid; gap: 1px; flex: 1 1 auto; min-width: 0; font-size: 14.5px; }
.npend-hint { font-size: 13px; color: var(--ink-3); }
.npend b { flex: none; min-width: 24px; text-align: right; color: var(--own);
  font-variant-numeric: tabular-nums; }

/* Строки ленты: вся строка — ссылка (растянутая из заголовка), новое —
   подсвечено и с красной точкой справа. */
.card.nfeed { padding: 0; overflow: hidden; }
.nlist { display: flex; flex-direction: column; }
.nitem {
  position: relative; display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 14px; border-bottom: 1px solid var(--line-soft);
}
.nitem:last-child { border-bottom: 0; }
.nitem:hover { background: var(--surface-2); }
.nitem.is-new { background: #e0a32e0f; }
.nitem.is-new:hover { background: #e0a32e1a; }
.nitem-ico {
  flex: none; width: 34px; height: 34px; border-radius: 50%; display: inline-flex;
  align-items: center; justify-content: center; background: var(--surface-2);
  color: var(--ink-2);
}
.nk-pay.nitem-ico, .nk-pay .ntoast-ico { background: #44ff8817; color: var(--ok); }
.nk-bp.nitem-ico, .nk-bp .ntoast-ico { background: #b07cf61f; color: var(--lock); }
.nk-spy.nitem-ico, .nk-spy .ntoast-ico { background: #5865f22e; color: #8f98ff; }
.nk-show.nitem-ico, .nk-show .ntoast-ico { background: #f39c121f; color: var(--warn); }
.nitem-body { display: grid; gap: 2px; flex: 1 1 auto; min-width: 0; }
.nitem-link, body.owner-mode .nitem-link, .nitem-link:hover {
  font-size: 15px; font-weight: 600; color: var(--ink);
}
.nitem-link::after { content: ""; position: absolute; inset: 0; }
.nitem-text { font-size: 14.5px; color: var(--ink-2); overflow-wrap: anywhere; }
.nitem-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: 2px 7px;
  font-size: 13.5px; color: var(--ink-3);
}
.nitem-meta time::before { content: "·"; margin-right: 7px; }
/* Приглашение из заявки — своя ссылка поверх растянутой. */
.nitem-sub { position: relative; z-index: 1; justify-self: start; font-size: 13.5px;
  overflow-wrap: anywhere; }
.nitem-dot { flex: none; width: 9px; height: 9px; margin-top: 6px; border-radius: 50%;
  background: #f23f43; }

/* Окна в правом нижнем углу: новое, пришедшее, пока страница открыта. */
.ntoasts {
  position: fixed; z-index: 96; right: 16px; bottom: 16px; display: flex;
  flex-direction: column; gap: 10px; width: min(380px, calc(100vw - 32px));
  pointer-events: none;
}
.ntoast {
  pointer-events: auto; display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 8px 12px 12px; background: var(--surface-2);
  border: 1px solid #3a404e; border-left: 3px solid var(--own); border-radius: 10px;
  box-shadow: 0 12px 32px #00000080; animation: ntoast-in .22s ease-out;
}
.ntoast, body.owner-mode a.ntoast, .ntoast:hover { color: var(--ink); }
.ntoast:hover { border-color: #4a5160; border-left-color: var(--own); }
.ntoast.nk-pay { border-left-color: var(--ok); }
.ntoast.nk-bp { border-left-color: var(--lock); }
.ntoast.nk-spy { border-left-color: #8f98ff; }
.ntoast.nk-show { border-left-color: var(--warn); }
.ntoast.is-gone { opacity: 0; transform: translateX(16px); transition: opacity .2s, transform .2s; }
.ntoast-ico {
  flex: none; width: 32px; height: 32px; border-radius: 50%; display: inline-flex;
  align-items: center; justify-content: center; background: var(--own-soft); color: var(--own);
}
.ntoast-txt { display: grid; gap: 2px; flex: 1 1 auto; min-width: 0; }
.ntoast-txt b { font-size: 15px; font-weight: 600; }
.ntoast-txt span { font-size: 14px; color: var(--ink-2); overflow-wrap: anywhere; }
.ntoast-x {
  flex: none; padding: 0 4px; border: 0; background: none; color: var(--ink-3);
  font: inherit; font-size: 20px; line-height: 1; cursor: pointer;
}
.ntoast-x:hover { color: var(--ink); }
@keyframes ntoast-in { from { opacity: 0; transform: translateY(12px); } }
@media (prefers-reduced-motion: reduce) {
  .ntoast { animation: none; }
  .ntoast.is-gone { transition: none; }
}
@media (max-width: 620px) {
  .ntoasts { left: 16px; width: auto; }
}

/* ─── обращения: «Ошибка или идея» (21.10.2026) ─── */
/* Ссылка у имени — каждому вошедшему: тихая, чтобы не спорить с меню. */
.fblink {
  display: inline-flex; align-items: center; gap: 7px; height: 30px; padding: 0 11px;
  border-radius: 8px; border: 1px solid var(--line); color: var(--ink-2);
  font-size: 14.5px; white-space: nowrap;
}
.fblink:hover { color: var(--ink); border-color: #4a5060; }
.side-user .fblink { justify-content: center; height: 34px; }
/* В шапке ссылка стоит у имени, справа, а не посередине полосы. */
.bar-end { display: flex; align-items: center; gap: 14px; min-width: 0; }
/* На узком экране — только значок: в полосе рядом панель владельца и имя. */
@media (max-width: 700px) { .fblink span { display: none; } .fblink { padding: 0 9px; } }
.fb-text { margin-top: 12px; white-space: pre-wrap; overflow-wrap: anywhere; font-size: 15.5px;
  color: var(--ink); }
.fb-reply { margin-top: 12px; padding: 10px 12px; border-left: 3px solid var(--ok);
  background: var(--bg); border-radius: 0 8px 8px 0; }
.fb-reply .fb-text { margin-top: 4px; }
.fb-shot { display: inline-block; margin-top: 12px; }
.fb-shot img { display: block; max-width: min(520px, 100%); max-height: 360px; height: auto;
  border-radius: 8px; border: 1px solid var(--line); }
.fb-owner-form { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line-soft); }
.fb-owner-form .repform-row .fld { max-width: 260px; }
.fb-howto ol { margin: 8px 0 0; padding-left: 22px; display: grid; gap: 8px; }
.fb-tabs { margin: 18px 0 4px; }
.fb-tabs .pill:hover { color: var(--ink); }
.nk-fb.nitem-ico, .nk-fb .ntoast-ico { background: #3fa7d61f; color: #6cc3ec; }
.ntoast.nk-fb { border-left-color: #6cc3ec; }

/* ─── сообщения от бота (render.messages_page, message_page) ─── */
.bm-list { padding: 0; }
.bm-item { display: flex; flex-direction: column; gap: 4px; padding: 14px 18px; border-top: 1px solid var(--line); }
.bm-item:first-child { border-top: 0; }
.bm-item-main { display: flex; flex-direction: column; gap: 2px; color: var(--ink); text-decoration: none; min-width: 0; }
.bm-item-main:hover b { color: #fff; text-decoration: underline; }
.bm-item-snip { color: var(--ink-3); font-size: 14.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bm-item-state, .bm-state { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 14.5px; }
.bm-foot { margin-top: 12px; }
.bm-blocks { display: flex; flex-direction: column; gap: 10px; margin: 8px 0 12px; }
.bm-block { border: 1px solid var(--line); border-radius: 10px; background: #17191f; min-width: 0; }
.bm-head { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; padding: 8px 12px; border-bottom: 1px solid var(--line); }
.bm-kind { font-size: 15px; }
.bm-acts { margin-left: auto; display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.bm-acts .btn-ord { height: 32px; padding: 0 10px; }
.bm-acts [hidden], .bm-add [hidden], .bm-body [hidden] { display: none; }
/* Перенос мышью, как у тиров (.rowbox.is-dragging): блок берут за заголовок,
   стрелки ↑ ↓ тогда не нужны — их место у ручки (dash.js, .is-drag). */
.bm-head .grip { margin-right: 0; vertical-align: middle; }
.bm-head .grip[hidden] { display: none; }
.bm-blocks.is-drag [data-bm-move] { display: none; }
.bm-blocks.is-drag .bm-head { touch-action: none; cursor: grab; }
.bm-blocks.is-drag .bm-acts { cursor: default; }
.bm-block.is-dragging {
  border-color: var(--accent); background: #20242f;
  box-shadow: 0 10px 26px rgba(0, 0, 0, .45);
  opacity: .96;
}
.bm-block.is-dragging .bm-head { cursor: grabbing; }
.bm-body { display: flex; flex-direction: column; gap: 8px; padding: 12px; min-width: 0; }
/* У .sel «flex: 1 1 260px» — под ряд. В столбце блока эти 260 px ушли бы в
   высоту, и под списком вида кнопки зияла пустота (своему списку dash.js
   передаёт те же flex-свойства). */
.bm-body .sel { flex: none; }
.bm-img { display: flex; gap: 12px; align-items: flex-start; }
.bm-img-c { display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 0; }
.bm-thumb { width: 96px; height: 72px; object-fit: cover; border-radius: 6px; background: #1f222a; flex: none; }
.bm-checks { display: flex; flex-wrap: wrap; gap: 6px; }
.bm-add { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.bm-add-nojs { display: flex; flex-wrap: wrap; gap: 8px; }
.bm-count { margin: 10px 0 0; }
.bm-count.bm-over { color: #ff8080; }
.bm-color { width: 72px; height: 40px; padding: 4px; cursor: pointer; }
.bm-pub { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
/* Кто опубликовал и кто правил — строками «что · кто · когда». */
.bm-who { list-style: none; margin: 4px 0 12px; padding: 0; display: grid; gap: 4px; }
.bm-who li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; font-size: 15px; }
.bm-who-k { color: var(--ink-3); min-width: 140px; }
.bm-actrow { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-start; margin-top: 12px; }
.bm-del > summary { list-style: none; cursor: pointer; }
.bm-del > summary::-webkit-details-marker { display: none; }
.bm-del-form { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; align-items: flex-start; }
/* Без рамки блоки стоят прямо в сообщении, как в Discord. */
.dc-box.bm-noframe { background: none; border: 0; padding: 0; }
/* Сетка картинок — как раскладывает Discord (render._bm_gallery, dash.js):
   ряды в шестых долях, одна картинка — своим размером, три — крупная слева
   и две справа. Маленькую одиночную Discord не растягивает на всю рамку. */
.bm-pv-gal { display: grid; gap: 4px; grid-template-columns: repeat(6, minmax(0, 1fr));
  border-radius: 8px; overflow: hidden; }
.bm-pv-cell { position: relative; display: block; min-width: 0; }
.bm-pv-s6 { grid-column: span 6; }
.bm-pv-s3 { grid-column: span 3; }
.bm-pv-s2 { grid-column: span 2; }
.bm-pv-img { display: block; width: 100%; height: 100%; object-fit: cover; background: #1f222a; }
.bm-pv-s6 .bm-pv-img { height: 220px; }
.bm-pv-s3 .bm-pv-img { height: 170px; }
.bm-pv-s2 .bm-pv-img { height: 120px; }
.bm-pv-gal-1 { display: block; overflow: visible; }
.bm-pv-gal-1 .bm-pv-cell { display: inline-block; max-width: 100%; vertical-align: top;
  border-radius: 8px; overflow: hidden; }
.bm-pv-gal-1 .bm-pv-img { width: auto; height: auto; max-width: 100%; max-height: 350px;
  object-fit: contain; }
.bm-pv-gal-3 { grid-template-columns: 2fr 1fr; grid-template-rows: 120px 120px; }
.bm-pv-gal-3 .bm-pv-cell:first-child { grid-row: span 2; }
.bm-pv-gif {
  position: absolute; left: 6px; top: 6px; padding: 1px 5px; border-radius: 4px;
  background: rgba(0, 0, 0, .6); color: #fff; font-size: 11px; font-weight: 700;
  letter-spacing: .02em; pointer-events: none;
}
.bm-pv-noimg { display: flex; align-items: center; justify-content: center; min-height: 90px;
  color: #949ba4; font-size: 14px; border: 1px dashed #4e5058; }
.bm-pv-sep-big { margin: 12px 0; }
.bm-pv-sep-blank { border-top-color: transparent; }
.dc-btn > svg { margin-left: 6px; opacity: .8; }
.bm-o-card .bm-o-text { white-space: pre-wrap; overflow-wrap: anywhere; margin: 6px 0; color: var(--ink-2); }
.bm-o-links { margin: 6px 0; padding-left: 18px; font-size: 14.5px; overflow-wrap: anywhere; }
@media (max-width: 640px) {
  .bm-img { flex-direction: column; }
  .bm-acts { margin-left: 0; }
}

/* ─── «Новое» и «Обновлено» (whatsnew.py) ───
   Синие, а не зелёные: зелёная точка на карточке уже значит «работает».
   «Новое» залито, «Обновлено» — бледнее: новая функция заметнее правки. */
.wn {
  display: inline-block; vertical-align: 2px; margin-left: 8px;
  padding: 2px 8px; border-radius: 999px;
  font-size: 12px; font-weight: 600; line-height: 1.4; white-space: nowrap;
}
.wn-new { background: var(--accent); color: #fff; }
.wn-changed { background: var(--accent-soft); color: #aab2ff; }
.wn-card { padding: 16px 20px; }
.wn-card b { display: flex; align-items: center; gap: 8px; font-size: 15.5px; }
.wn-card .wn { margin-left: 0; vertical-align: 0; }
.wn-card ul { margin: 8px 0 0; padding-left: 20px; color: var(--ink-2); font-size: 15px; }
.wn-card li { margin-bottom: 4px; }
.wn-day { color: var(--ink-3); white-space: nowrap; }

/* ─── «Списки участников» вкладками (сменщик, 28.10.2026) ───
   «Общие · Война семей · Сборы» под заголовком; у двух последних — ряд их
   частей помельче: «Запись и состав · Статистика» и «… · Итоги мероприятий». */
.ltabs, .ltabs-sub { width: fit-content; max-width: 100%; }
.ltabs { margin-bottom: 10px; }
.ltabs-sub { margin-bottom: 18px; }
.ltabs-sub .tab { height: 28px; padding: 0 14px; font-size: 14px; }
/* Заголовок части вкладки (статистика, итоги) — с состоянием и «Выключить». */
.subhead { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; margin: 4px 0 6px; }
.subhead h2 { margin: 0; }
.subhead-act { margin: 0 0 0 auto; }
/* Карточка списков на главной: ссылки на вкладки и то, что внутри них. */
.feat-tabs { align-items: center; }
.feat-tabs-lbl { color: var(--ink-2); font-size: 14px; margin-right: 2px; }
.feat-parts { position: relative; z-index: 2; display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 8px; }
.feat-part { display: inline-flex; align-items: center; gap: 8px; color: var(--ink); font-size: 14.5px; }
.feat-part:hover { color: var(--accent); }
.feat-part .feat-state { margin: 0; }
/* Предпросмотр состава справа от настроек вкладки. */
.lpv .lpv-body { margin-top: 10px; transition: opacity .15s; }
.lpv.is-busy .lpv-body { opacity: .55; }
.lpv-anchor { font-weight: 600; }
.lpv-foot { margin-top: 10px; font-size: 13.5px; }
#prio { scroll-margin-top: 18px; }
/* Предпросмотр поставки в «Итогах мероприятий»: сторона и шаг —
   переключателями, ниже заявка в Discord поставок и то, что у семьи. */
.spv-ctl { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.spv .seg span { height: 34px; font-size: 14px; }
.spv-where { margin: 16px 0 6px; font-size: 14.5px; color: var(--ink-2); }
.spv-cap, .spv-none { margin: 0 0 8px; font-size: 13.5px; }
/* Шансы нападения: отдельная карточка для каждого вида поставки. */
.sch-fields { border: 0; padding: 0; margin: 0; min-width: 0; }
.sch-head, .sch-row { display: grid; grid-template-columns: minmax(140px, 1fr) minmax(170px, 1fr) 75px; gap: 12px; align-items: center; }
.sch-head { color: var(--ink-2); font-size: 12px; padding: 16px 0 8px; }
.sch-row { padding: 10px 0; border-top: 1px solid var(--line); }
.sch-share { text-align: right; font-variant-numeric: tabular-nums; }
.sch-bulk { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-top: 16px; }
.sch-bulk > .inp { width: auto; }
.sch-bulk > .pick { width: 210px; }
.sch-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 16px; }
.sch-tabs [aria-selected="true"] { background: var(--accent); color: #fff; }
.sch-row.is-adjusted .sch-share { color: var(--accent); font-weight: 600; }
@media (max-width: 560px) {
  .sch-head { display: none; }
  .sch-row { grid-template-columns: minmax(0, 1fr) 65px; }
  .sch-row > .chk { grid-column: 1 / -1; }
  .sch-bulk > .inp { flex: 1; min-width: 140px; }
  .sch-bulk > .pick { flex: 1; min-width: 110px; }
}
