:root {
  --bg: #17212b;
  --panel: #232e3c;
  --sunken: #1b2431;
  --border: #101921;
  --divider: #2c3949;
  --text: #ffffff;
  --hint: #708499;
  --dim: #5a6b7d;
  --accent: #5288c1;
  /* Надпись на акцентной кнопке. Отдельно от --text: тема Telegram может
     прислать светлый акцент, и тогда наш светлый текст на нём исчезает. */
  --accent-text: #fff;
  /* Акцент как цвет ТЕКСТА на фоне страницы. Отдельно от заливки: в чужой
     теме кнопка бывает того же цвета, что и фон, и подпись на нём пропадает. */
  --accent-on-bg: #5288c1;
  --accent-soft: #2b5278;
  --link: #62bcf9;
  --green: #4dcd5e;
  --red: #e8555a;
  --orange: #e8a33d;
  --purple: #9b7ede;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, "Segoe UI", system-ui, "Helvetica Neue", sans-serif;
  -webkit-font-smoothing: antialiased;
  font-size: 15px;
  line-height: 1.45;
  /* Ширину, а не только высоту — иначе широкие таблицы/строки распирают экран вбок. */
  overflow-x: hidden;
}

a { color: var(--link); }

/* label тоже бывает кнопкой: выбор файла нельзя открыть из кода, поэтому
   «Загрузить» — это <label> поверх скрытого поля. Без него такая кнопка
   рисовалась голым текстом без подложки.

   Ссылка — тем более: переход на другой экран это <a>, а не кнопка, и без
   этой строки она получала синий текст без подложки. Замерено: рядом с
   настоящей кнопкой такая пара читается как съехавшая вёрстка, хотя
   геометрия у них совпадает до пикселя. */
button, label.btn-small, label.btn-primary, a.btn-small, a.btn-primary {
  font: inherit;
  cursor: pointer;
  border: none;
  border-radius: 11px;
  padding: 10px 16px;
  /* Не var(--panel): обычная кнопка почти всегда лежит на панели того же
     цвета и на нём просто исчезает — на sunken она остаётся видимой чипсой. */
  background: var(--sunken);
  color: var(--text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: filter 0.12s ease, transform 0.08s ease;
}
button:hover:not(:disabled) { filter: brightness(1.18); }
button:active:not(:disabled) { filter: brightness(0.88); transform: scale(0.97); }
button:disabled { opacity: 0.45; cursor: default; }
button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible {
  outline: 2px solid var(--accent-on-bg);
  outline-offset: 2px;
}

/* Селектор с тегами намеренно: базовое правило кнопок перечисляет
   a.btn-primary и label.btn-primary, а значит перебивает голый .btn-primary
   по весу. Из-за этого ссылка и label, помеченные главными, главными
   не выглядели — фон у них оставался обычным. */
button.btn-primary,
a.btn-primary,
label.btn-primary,
.btn-primary {
  background: var(--accent);
  color: var(--accent-text);
  font-weight: 600;
}
/* Кнопка удаления в покое — тихая.

   Замерено на живом экране: в редакторе команды красный ✕ повторяется до пяти
   раз на блок и оказывается самым ярким пятном — ярче текста самого сообщения.
   Глаз ведёт к уничтожению, а не к содержанию. Красный никуда не делся, он
   включается под пальцем и в окне подтверждения, где и нужен. */
.btn-danger {
  background: transparent;
  color: var(--dim);
  box-shadow: inset 0 0 0 1px var(--divider);
  transition: color .12s, box-shadow .12s;
}

.btn-danger:hover,
.btn-danger:focus-visible,
.btn-danger:active {
  color: var(--red);
  box-shadow: inset 0 0 0 1px #5c3538;
}

/* Исключение — «Опасная зона»: там красный не пятно, а подпись раздела.
   Раздел так и называется, и кнопка в нём одна. */
.btn-danger.btn-loud { color: var(--red); box-shadow: inset 0 0 0 1px #5c3538; }
.btn-small { padding: 7px 12px; font-size: 13px; border-radius: 9px; min-height: 36px; }

/* Подчёркивание и цвет ссылки кнопке не нужны — иначе каждый такой переход
   приходится глушить стилем прямо в разметке, и однажды об этом забывают. */
/* :not(.btn-primary) не придирка: у главной ссылки оба класса, вес правил
   одинаковый, и побеждает то, что ниже. Без исключения обычный цвет текста
   ложился поверх цвета надписи на заливке — и на светлом акценте надпись
   пропадала. */
a.btn-small:not(.btn-primary) { text-decoration: none; color: var(--text); }
a.btn-primary { text-decoration: none; }

input, select, textarea {
  font: inherit;
  width: 100%;
  padding: 11px 13px;
  min-height: 44px;
  border-radius: 11px;
  border: 1px solid var(--divider);
  background: var(--sunken);
  color: var(--text);
  outline: none;
  transition: border-color 0.12s ease;
}
textarea { min-height: 44px; line-height: 1.45; }
input:focus, select:focus, textarea:focus { border-color: var(--accent); }
input::placeholder, textarea::placeholder { color: var(--dim); }
input:disabled, select:disabled, textarea:disabled { opacity: 0.5; }

.app { max-width: 720px; margin: 0 auto; padding: 0 14px calc(60px + env(safe-area-inset-bottom, 0px)); }

/* ── Шапка ───────────────────────────────────────────────────────────────── */

header.top {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 0 10px;
}
/* Знак — та же мозаика, что на аватарке бота: тёмная плашка, белые плитки
   и одна акцентная. Сплошной синий квадрат спорил с синей главной кнопкой. */
.mark {
  width: 36px; height: 36px; border-radius: 10px; background: var(--sunken);
  box-shadow: inset 0 0 0 1px var(--divider);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.who { display: flex; flex-direction: column; gap: 4px; flex-grow: 1; min-width: 0; }
.who b { font-size: 17px; font-weight: 700; letter-spacing: -0.2px; }
.who span {
  font-size: 13px; color: var(--hint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
header.top .btn-small { flex-shrink: 0; }

nav.tabs { display: flex; align-items: center; gap: 8px; padding-bottom: 13px; }
nav.tabs a {
  text-decoration: none;
  background: var(--panel);
  color: var(--hint);
  font-size: 13px;
  font-weight: 600;
  padding: 9px 16px;
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  border-radius: 10px;
  transition: filter 0.12s ease;
}
nav.tabs a:active { filter: brightness(0.88); }
nav.tabs a.on { background: var(--accent); color: var(--accent-text); font-weight: 600; }

/* ── Карточки ────────────────────────────────────────────────────────────── */

.stack { display: flex; flex-direction: column; gap: 12px; }

/* Фильтр списка ботов. Кнопки те же, что у периодов в статистике:
   заводить ради этого второй вид «чипа» незачем. */
.bot-filter { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }

/* Заголовок группы ботов: каналы, группы, нигде не стоят.
   Отступ сверху больше, чем снизу, намеренно — так заголовок читается
   как начало СВОЕЙ группы, а не как подпись к предыдущей. */
.group-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin: 10px 0 -4px;
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--dim);
}
.group-head:first-child { margin-top: 0; }
.group-head span { font-variant-numeric: tabular-nums; }

/* Дублёр — под своим основным, а не рядом с ним.
   Полоска слева и отступ говорят «этот подчинён верхнему» без единого слова:
   на живых данных три бота назывались одинаково и стояли как три равных. */
.nest { padding-left: 22px; position: relative; }
.nest::before {
  content: "";
  position: absolute;
  left: 9px; top: -12px; bottom: 14px;
  border-left: 2px solid var(--divider);
  border-bottom: 2px solid var(--divider);
  width: 9px;
  border-bottom-left-radius: 8px;
}
.card.nested { background: var(--sunken); }

/* Имя бота — В ОДНУ строку.
   Замерено на снимке живого списка: «🫦You might wanna see this…» переносилось
   на вторую строку, точка состояния уезжала под имя, и карточка становилась
   выше соседних — список переставал читаться столбиком. Глобально .name
   переносить НАДО (в дереве сценария длинные названия команд читают целиком),
   поэтому правило только здесь. */
.bot-card .row { flex-wrap: nowrap; }
.bot-card .name,
.bot-card .sub {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.card {
  background: var(--panel);
  border-radius: 15px;
  padding: 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  color: inherit;
  transition: filter 0.12s ease;
}
a.card:active, a.card:hover { filter: brightness(1.1); }
.card.bad { background: #2b2732; box-shadow: inset 0 0 0 1px #5c3538; }
.card.off { background: var(--sunken); }

.ava {
  width: 44px; height: 44px; border-radius: 13px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 700; color: #17212b;
}

.grow { flex-grow: 1; min-width: 0; }
.row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; row-gap: 8px; }
.row.wrap { flex-wrap: wrap; }
/* Внутри строки текстовые/полевые элементы должны иметь право сжиматься —
   иначе длинный текст (regex-триггер, длинное имя) распирает ряд и вылезает
   за экран, даже если у ряда есть перенос. */
.row > input, .row > select, .row > textarea,
.row > span, .row > a, .row > .name, .row > .sub, .row > .mono {
  min-width: 0;
}
.name { font-size: 15px; font-weight: 600; overflow-wrap: anywhere; }
.sub { font-size: 13px; color: var(--hint); overflow: hidden; text-overflow: ellipsis; }
.dot { width: 7px; height: 7px; border-radius: 4px; flex-shrink: 0; }

/* Тумблер: показывает СОСТОЯНИЕ, а не предлагает действие. Кнопка с текстом
   «да» на его месте читалась как «нажать да», и было неясно, включено сейчас
   или включится после нажатия. */
.switch {
  width: 46px; min-height: 28px; height: 28px; padding: 3px;
  border-radius: 999px; background: var(--sunken);
  display: inline-flex; align-items: center; justify-content: flex-start;
  flex-shrink: 0; transition: background 0.15s ease;
}
.switch > span {
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--dim); transition: transform 0.15s ease, background 0.15s ease;
}
.switch.on { background: var(--accent-soft); justify-content: flex-end; }
.switch.on > span { background: var(--accent); }

/* Нижние разделы бота.

   Стоят там, куда дотягивается палец: между «Сценарием», «Рассылками» и
   «Статистикой» одного бота ходят часто, и раньше это стоило двух касаний —
   «назад» и потом плитка.

   Панель прижата к низу и не уезжает при прокрутке, поэтому содержимому
   отдаётся отступ снизу — иначе последняя кнопка экрана оказывалась
   под ней и не нажималась. */
.bottom-tabs {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  display: flex;
  background: var(--panel);
  border-top: 1px solid var(--divider);
  padding-bottom: env(safe-area-inset-bottom, 0);
  z-index: 40;
}
.bottom-tabs a {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 8px 2px 7px;
  color: var(--dim);
  text-decoration: none;
  font-size: 11px;
  /* Подпись обязана поместиться целиком: «Статистика» в две строки
     ломает высоту всей панели. */
  white-space: nowrap;
}
/* Семь вкладок вместо шести: слот сузился с 62 до 53.6 точек, и «Статистика»
   перестала помещаться — 55 против 54 доступных. Замерено на 375.

   Лечит именно шрифт: убирание боковых отступов даёт 2 точки и не спасает,
   а 10px помещает все семь подписей с запасом. Правило включается только
   когда вкладок действительно семь, — на шести подписи остаются прежними. */
.bottom-tabs:has(a:nth-child(7)) a { font-size: 10px; }

.bottom-tabs a.on { color: var(--accent-on-bg); }
body:has(.bottom-tabs) #app { padding-bottom: 78px; }

/* Стрелки порядка в списке ботов. Приглушены намеренно: порядок меняют
   раз в жизни, и спорить за внимание с самими ботами им незачем. */
.move { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; color: var(--dim); }
.move > span {
  display: flex; align-items: center; justify-content: center;
  width: 26px; height: 22px; border-radius: 6px; cursor: pointer;
}
.move > span:active { background: var(--sunken); color: var(--text); }

.panel { background: var(--panel); border-radius: 15px; padding: 16px; }
/* Отступ между соседними блоками задаётся ими самими, а не разметкой.
   Правило было только для .panel — и сетка плиток, встав следом за панелью,
   прилипала к ней вплотную: рядом две скруглённые рамки без зазора читаются
   как наезд одной на другую. */
.panel + .panel,
.panel + .tiles,
.tiles + .panel,
.tiles + .tiles,
.panel + .fold,
.fold + .panel,
.fold + .tiles,
.tiles + .fold,
.fold + .fold { margin-top: 12px; }

/* ...но внутри сетки отступ задаёт сам grid своим gap, а это правило там
   лишнее: соседи по РЯДУ получали margin-top и съезжали вниз относительно
   первой карточки. Замерено на статистике — «Подписчиков» стояла на 269,
   а «Активных за период» на 281, и ряд выглядел кривым. */
.cards > .panel { margin-top: 0; }
.panel h3 {
  margin: 0 0 12px;
  font-size: 13px; font-weight: 700; letter-spacing: 0.5px;
  color: var(--hint); text-transform: uppercase;
}

.line {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; row-gap: 8px;
  padding: 11px 0; border-bottom: 1px solid var(--divider);
}
.line:last-child { border-bottom: none; padding-bottom: 0; }
.line:first-of-type { padding-top: 0; }

.mono { font-family: ui-monospace, Menlo, Consolas, monospace; overflow-wrap: anywhere; }
.muted { color: var(--hint); font-size: 13px; }
.tiny { font-size: 13px; color: var(--dim); }

.banner {
  background: #2b2732; box-shadow: inset 0 0 0 1px #5c3538;
  color: #e8888c; border-radius: 12px; padding: 12px 14px;
  font-size: 13px; margin-bottom: 12px; overflow-wrap: anywhere;
}

.empty { text-align: center; padding: 44px 20px; color: var(--hint); }
.empty .empty-icon {
  width: 52px; height: 52px; margin: 0 auto 16px; border-radius: 16px;
  background: var(--sunken); display: flex; align-items: center; justify-content: center;
}
.empty b { display: block; font-size: 17px; color: var(--text); margin-bottom: 8px; }
.empty p { margin: 0; font-size: 13px; line-height: 1.45; max-width: 320px; margin-inline: auto; }

/* ── Плитки разделов ─────────────────────────────────────────────────────── */

/* Четыре раздела бота были четырьмя одинаковыми панелями с заголовком,
   абзацем и кнопкой — экран прокручивался, а взгляду не за что зацепиться.
   Плитки дают то же самое в четыре раза компактнее и читаются за один взгляд. */
.tiles {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.tile {
  background: var(--panel);
  border-radius: 15px;
  padding: 14px;
  text-decoration: none;
  color: inherit;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 104px;
  transition: filter 0.12s ease, transform 0.08s ease;
}
.tile:hover { filter: brightness(1.1); }
.tile:active { transform: scale(0.985); }

/* Цвет живёт на значке, а не на всей плитке: четыре цветных прямоугольника
   рядом кричат одинаково громко и перестают что-либо значить. */
.tile .tile-icon {
  width: 32px; height: 32px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.tile b { font-size: 15px; font-weight: 600; }
.tile span { font-size: 11px; color: var(--hint); line-height: 1.45; }

/* ── Предпросмотр: кнопки под сообщением ─────────────────────────────────── */

/* В телеграме кнопки под сообщением прижаты к нему и невысокие. Обычные
   .btn-small на 44px превращали четыре кнопки в полэкрана, и было не понять,
   к какому сообщению они относятся. */
.pv-buttons {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 4px;
  max-width: 85%;
}
.pv-buttons .row-line { display: flex; gap: 4px; }

.pv-btn {
  flex: 1 1 0;
  min-width: 0;
  min-height: 38px;
  padding: 8px 12px;
  border-radius: 7px;
  font-size: 13px;
  background: var(--sunken);
  box-shadow: inset 0 0 0 1px var(--divider);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--link);
  text-align: center;
  overflow-wrap: anywhere;
}
button.pv-btn:hover { filter: brightness(1.15); }

/* Ссылка в предпросмотре никуда не ведёт — она бледнее и не нажимается,
   но выглядеть должна кнопкой, иначе ряд разъезжается. */
.pv-btn.dead { pointer-events: none; color: var(--hint); }

/* ── Модалка ─────────────────────────────────────────────────────────────── */

.backdrop {
  position: fixed; inset: 0; background: rgba(0, 0, 0, 0.65);
  display: flex; align-items: center; justify-content: center; padding: 18px;
  z-index: 50;
  overflow-y: auto;
}
.modal {
  background: var(--panel); border-radius: 18px; padding: 20px;
  width: 100%; max-width: 420px;
  max-height: calc(100vh - 36px);
  max-height: calc(100dvh - 36px);
  overflow-y: auto;
  display: flex; flex-direction: column; gap: 16px;
  margin: auto;
}
.modal h2 { margin: 0; font-size: 17px; overflow-wrap: anywhere; }
.modal .field { display: flex; flex-direction: column; gap: 8px; }
.modal label { font-size: 13px; color: var(--hint); }
/* Кнопки окна прибиты к низу.

   Замерено на экране 360×620: «Новая рассылка» и «Что добавить» выше окна,
   содержимое прокручивается — и «Отмена» с «Создать» оказывались НИЖЕ края.
   Человек видел форму без единой кнопки и не понимал, чем её закончить.

   Липкая полоса решает это на все окна разом: контент прокручивается под
   ней, кнопки остаются на месте. Отрицательный отступ снизу гасит внутреннее
   поле окна, чтобы полоса доставала до самого края и под ней ничего не
   просвечивало. */
.modal .actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  position: sticky;
  bottom: -20px;
  background: var(--panel);
  padding: 12px 0 20px;
  margin-bottom: -20px;
}

/* Картинка результата внутри окна: то же сообщение, что увидит человек. */
.modal-preview {
  background: var(--sunken);
  border-radius: 12px;
  padding: 11px;
}

/* Выбор одного из нескольких.

   Строкой, а не рядом чипсов: у каждого варианта есть пояснение, и на
   телефоне читать столбик проще, чем разбирать шесть подписей вподбор. */
.pick { display: flex; flex-direction: column; gap: 8px; }

.pick-row {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  width: 100%; text-align: left; padding: 11px 13px;
  border-radius: 11px; background: var(--sunken);
}

.pick-row:hover, .pick-row:focus-visible { background: var(--accent-soft); }

/* pointer-events на подписях сняты: без этого нажатие приходит на <span>,
   а data-value лежит на кнопке, и первый же тык по подписи ничего не делал. */
.pick-label, .pick-hint { pointer-events: none; }
.pick-label { font-size: 15px; }
.pick-hint { font-size: 13px; color: var(--hint); }

/* Числовые поля — без стрелок.

   Родные стрелки браузера мелкие, лезут поверх текста и на телефоне в них
   не попасть пальцем. Толку от них нет: цену набирают с клавиатуры, а не
   щёлкают по единице за раз. inputmode подсказывает телефону сразу
   открыть цифровую клавиатуру. */
input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Строка с флажком.

   Своя, а не .pick-row: та — колонка под кнопку с подписью и пояснением,
   и флажок в ней уезжал на отдельную строку во всю ширину, читаясь как
   огромная птица посреди экрана. Здесь нужен обычный флажок «поставил
   и забыл», а не тумблер состояния. */
.check {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 11px 13px;
  border-radius: 11px; background: var(--sunken);
  font-size: 15px;
}
.check input {
  width: 18px; height: 18px; margin: 0;
  flex-shrink: 0; accent-color: var(--accent);
}

/* ── Предпросмотр сообщения рядом с правками ─────────────────────────────── */

.preview-pane { margin-bottom: 12px; padding: 12px 14px; }

.preview-toggle {
  width: 100%;
  background: none;
  padding: 0;
  border-radius: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--hint);
}

.preview-body { margin-top: 12px; }
.preview-pane.closed .preview-body { display: none; }

/* Широкий экран: предпросмотр стоит рядом и не прячется.

   Переключатель там не нужен — место есть, и лишняя кнопка только
   спрашивает о том, чего никто не хочет менять. */
@media (min-width: 900px) {
  .preview-pane {
    position: sticky;
    top: 12px;
    float: right;
    width: 320px;
    margin-left: 20px;
  }

  .preview-pane.closed .preview-body { display: block; }
  .preview-toggle { pointer-events: none; }
  .preview-toggle .tiny { display: none; }
}

/* ── Свёрнутая панель: общий приём всех настроек ─────────────────────────── */

/* Выглядит как обычная панель, но занимает место только когда её открыли.
   Одна разметка на бота, канал и чат — иначе настройки разъедутся. */
.fold {
  background: var(--panel);
  border-radius: 14px;
  padding: 14px 16px;
}

.fold > summary {
  cursor: pointer;
  /* Своя стрелка справа вместо треугольника слева: он тянет строку влево
     и ломает ряд с остальными заголовками экрана. */
  list-style: none;
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Заголовок и подпись переносятся вместе, а не спорят за одну строку. */
.fold-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  min-width: 0;
  flex: 1 1 auto;
}

.fold > summary::-webkit-details-marker { display: none; }

.fold-title {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--hint);
}

/* Строка, видная не открывая панель: сколько ссылок, кому выдан доступ.

   Без nowrap и без многоточия: обрезанная подпись рядом с перенесённым
   заголовком выглядела наездом одного текста на другой. Пусть лучше
   займёт свою строку — места это стоит одну строку, а читается целиком. */
.fold-note {
  font-size: 13px;
  color: var(--dim);
  min-width: 0;
  overflow-wrap: anywhere;
}

.fold > summary::after {
  content: "⌄";
  margin-left: auto;
  font-size: 15px;
  line-height: 1;
  color: var(--hint);
  transition: transform .15s;
  flex-shrink: 0;
}

.fold[open] > summary::after { transform: rotate(180deg); }
.fold > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }

.fold-body { margin-top: 12px; }

/* Опасное: рамка вместо заливки. Красным горит только то, что внутри. */
.fold-danger { background: none; box-shadow: inset 0 0 0 1px var(--divider); }
.fold-danger .fold-title { color: var(--red); }

/* ── Вложенная панель: линия вместо коробки ──────────────────────────────────

   Внутри карточки канала или чата панель лежит на подложке ТОГО ЖЕ цвета —
   коробки в коробке не видно, и четыре группы сливались в одно серое пятно.
   Замерено на живом экране: у вложенной и у внешней панели совпадал фон.

   Поэтому внутри карточки группы разделяются волосяной линией, как строки
   списка, а собственную заливку и скругления не получают вовсе. */
.panel > * .fold,
.panel > .fold {
  background: none;
  box-shadow: none;
  border-radius: 0;
  margin: 0;
  padding: 13px 0;
  border-top: 1px solid var(--divider);
}

/* Первая группа линии не получает: её отделяет сама шапка карточки. */
.panel > * > .fold:first-child { border-top: 0; padding-top: 4px; }

/* Опасная группа внутри карточки — тоже строкой, без рамки. */
.panel > * .fold-danger { box-shadow: none; }

/* ── Всплывашка ──────────────────────────────────────────────────────────── */

#toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(22px + env(safe-area-inset-bottom, 0px));
  background: var(--panel); box-shadow: 0 8px 28px rgba(0,0,0,0.5);
  border-radius: 12px; padding: 12px 18px; font-size: 15px;
  z-index: 100; max-width: 90vw; text-align: center;
}
#toast.err { background: #3a2529; color: #ffb4b7; }

/* Смена экрана без перехода читается как сбой отрисовки: содержимое
   мгновенно подменяется другим. Короткое проявление снизу показывает,
   что это новый экран, и не задерживает — 140 мс не ощущаются как ожидание. */
@keyframes screen-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
.screen { animation: screen-in 0.14s ease-out; }

/* Кто просил не анимировать — тому не анимируем. */
@media (prefers-reduced-motion: reduce) {
  .screen { animation: none; }
  button { transition: none; }
  .tile { transition: none; }
}

.spinner {
  width: 22px; height: 22px; margin: 60px auto;
  border: 2.5px solid var(--divider); border-top-color: var(--accent-on-bg);
  border-radius: 50%; animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Мобильная ширина (телефон в первую очередь — это Mini App) ────────────── */

@media (max-width: 480px) {
  /* Палец промахивается мимо мелких кнопок — везде на телефоне держим
     нажимаемую область не меньше 44px по высоте. */
  button, .btn-small, nav.tabs a {
    min-height: 44px;
  }

  /* Ряды из нескольких select/input, рассчитанные на широкий экран,
     на телефоне превращаются в столбик — иначе поля сжимаются до нечитаемой
     ширины или наезжают друг на друга. Целимся точечно по data-атрибутам
     редактора, логику это не трогает.
     !important — у этих полей в разметке свой инлайновый flex-basis
     (например style="flex:1 1 110px"), он в любом случае перебивает
     внешний CSS по специфичности, если его явно не перебить. */
  [data-btn="text"],
  [data-btn="url"],
  [data-btn="command"],
  [data-block="variable"],
  [data-block="expect"],
  [data-block="actionVariable"],
  [data-block="actionValue"],
  [data-cond="variable"],
  [data-cond="op"],
  [data-cond="value"],
  [data-cond="goto"] {
    flex-basis: 100% !important;
  }

  /* Кнопка удаления строки прижимается вправо и остаётся компактной.
     Растянутая во всю ширину красная полоса читается как «удалить всё»,
     хотя убирает она одну строку над собой. Ширины хватает для пальца:
     min-height 44px задан выше, ширину добираем отступами. */
  [data-act="fl-btn-del"],
  [data-act="fl-branch-del"],
  [data-act="fl-poll-del"] {
    flex: 0 0 auto !important;
    margin-left: auto;
    padding-left: 20px;
    padding-right: 20px;
  }

  .modal .actions {
    flex-direction: column;
  }
  .modal .actions button {
    width: 100%;
  }
}

/* Ход оформления канала.

   Оформление идёт десятки секунд, и раньше экран молчал: владелец решал,
   что не сработало, и жал кнопку снова — замерено, девятнадцать сообщений
   в канале вместо двух. Полоса и список шагов существуют ровно затем,
   чтобы это молчание убрать. */
.bar {
  height: 6px; border-radius: 3px;
  background: var(--sunken); overflow: hidden;
}
.bar i {
  display: block; height: 100%;
  background: var(--accent);
  transition: width .25s ease;
}
.step-now { font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
.steps {
  margin: 0; padding-left: 20px;
  max-height: 34vh; overflow-y: auto;
  /* По горизонтали не ездим: полоса прокрутки внизу окна появлялась просто
     от вертикальной полосы у списка и делала окно неопрятным. */
  overflow-x: hidden; min-width: 0;
  font-size: 13px; color: var(--hint);
  display: flex; flex-direction: column; gap: 4px;
}
.steps li { overflow-wrap: anywhere; }
.done {
  white-space: pre-wrap; font-size: 13px;
  border-left: 3px solid var(--accent); padding-left: 10px;
  overflow-wrap: anywhere;
}
.done.bad { border-left-color: var(--red); }

/* Скрытое — скрыто.

   Атрибут hidden слабее любого правила с display в нашем же файле: кнопка
   «Закрыть» с классом .btn-primary показывалась прямо во время работы, и
   окно выглядело так, будто дело уже кончилось. */
[hidden] { display: none !important; }

/* ═══════════════════════════════════════════════════════════════
   «Конвейер» — новый интерфейс.

   Цвет здесь называет РОЛЬ, а не украшает: платка дорогая и главная,
   дожимка вторая и дешевле. Оба берутся из темы Telegram, поэтому
   остаются читаемыми и на светлой подложке.
   ═══════════════════════════════════════════════════════════════ */

:root {
  --role-main: var(--orange);
  --role-warm: var(--purple);
}

/* ── Шапка и переключатель экранов ─────────────────────────── */

.head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 0 12px;
}
.head .brand {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--dim);
}
.head .worker {
  margin-left: auto;
  font-size: 11px;
  color: var(--dim);
  background: var(--panel);
  border-radius: 999px;
  padding: 4px 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 55%;
}

/* Линии — чипсами: их две-три, выпадающий список тут был бы лишним шагом. */
.lines {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding-bottom: 8px;
  scrollbar-width: none;
}
.lines::-webkit-scrollbar { display: none; }
.line-chip {
  border-radius: 999px;
  padding: 7px 13px;
  font-size: 13px;
  font-weight: 600;
  background: var(--panel);
  color: var(--dim);
  white-space: nowrap;
  flex-shrink: 0;
}
.line-chip[aria-selected="true"] { background: var(--accent); color: var(--accent-text); }

.tabs {
  display: flex;
  gap: 4px;
  background: var(--panel);
  border-radius: 12px;
  padding: 4px;
  margin-bottom: 14px;
}
.tabs button {
  flex: 1;
  background: none;
  color: var(--dim);
  font-size: 13px;
  font-weight: 600;
  padding: 8px 6px;
  border-radius: 9px;
}
.tabs button[aria-selected="true"] { background: var(--sunken); color: var(--text); }

/* ── Карточка пары ─────────────────────────────────────────── */

.pair {
  background: var(--panel);
  border-radius: 16px;
  border-left: 3px solid var(--role-main);
  overflow: hidden;
  margin-bottom: 12px;
}
.pair.warm { border-left-color: var(--role-warm); }
.pair.dead { border-left-color: var(--red); }

.pair-main { display: flex; gap: 14px; padding: 15px 15px 13px; align-items: center; }
.ring { width: 62px; height: 62px; flex-shrink: 0; }

.pair-id { flex: 1; min-width: 0; }
.role {
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--role-main);
}
.role.warm { color: var(--role-warm); }
.role.off { color: var(--dim); }
.pair-title {
  font-size: 16px;
  font-weight: 700;
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pair-price { font-size: 12.5px; color: var(--dim); margin-top: 3px; }
.livedot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--green);
  display: inline-block;
  margin-right: 5px;
  vertical-align: middle;
}

/* ── Ссылка как объект, а не поле ввода ────────────────────── */

.links { display: flex; flex-direction: column; }
.link-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--panel);
  padding: 11px 15px;
  width: 100%;
  text-align: left;
  border-radius: 0;
  border-top: 1px solid var(--divider);
}
.price-chip {
  font-size: 12px;
  font-weight: 600;
  color: var(--role-main);
  background: color-mix(in srgb, var(--role-main) 14%, transparent);
  border-radius: 6px;
  padding: 3px 7px;
  flex-shrink: 0;
}
.price-chip.warm {
  color: var(--role-warm);
  background: color-mix(in srgb, var(--role-warm) 14%, transparent);
}
.link-url {
  flex: 1;
  min-width: 0;
  font-size: 12.5px;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.link-row .copy { font-size: 11.5px; color: var(--dim); flex-shrink: 0; }

/* Спутник: дожимка живёт при платке, а не отдельной карточкой. */
.satellite {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px 15px;
  border-top: 1px solid var(--divider);
  font-size: 13px;
  color: var(--dim);
  width: 100%;
  text-align: left;
  border-radius: 0;
  background: var(--panel);
}
.satellite .bullet {
  width: 3px; height: 14px; border-radius: 2px;
  background: var(--role-warm);
  flex-shrink: 0;
}
.satellite b { color: var(--text); font-weight: 600; }
.satellite .num { margin-left: auto; white-space: nowrap; font-size: 12px; }

/* ── Итоги строкой, а не плитками ──────────────────────────── */

.totals {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  padding: 2px 4px 10px;
  font-size: 12px;
  color: var(--dim);
}
.totals b {
  display: block;
  color: var(--text);
  font-size: 16px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* ── Подсказка вместо крика ────────────────────────────────── */

.tip {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--panel);
  border-radius: 14px;
  padding: 12px 14px;
  font-size: 13px;
  color: var(--dim);
  line-height: 1.45;
  margin-bottom: 12px;
}
.tip .mark {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--role-main);
  margin-top: 6px;
  flex-shrink: 0;
}
.tip.bad .mark { background: var(--red); }
.tip b { color: var(--text); display: block; font-size: 13.5px; margin-bottom: 2px; }

/* ── Действия: одно главное, остальное тише ────────────────── */

.act {
  border-radius: 12px;
  padding: 12px 16px;
  font-size: 14px;
  font-weight: 600;
  background: var(--accent);
  color: var(--accent-text);
  width: 100%;
  justify-content: center;
}
.act.quiet { background: var(--sunken); color: var(--text); font-weight: 500; }
.acts { display: flex; gap: 8px; }
.acts .act { flex: 1; }
.acts .act.dots { flex: 0 0 46px; padding: 12px 0; }

.sec {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
  font-weight: 700;
  margin: 16px 0 8px;
}

/* ── Строка пары в списке ──────────────────────────────────── */

.row-pair {
  background: var(--panel);
  border-radius: 14px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 9px;
  border-left: 3px solid var(--role-main);
  margin-bottom: 10px;
}
.row-pair.warm { border-left-color: var(--role-warm); }
.row-pair.off { border-left-color: var(--divider); }
.row-pair.dead { border-left-color: var(--red); }

.row-head { display: flex; align-items: center; gap: 9px; }
.row-head .t {
  flex: 1; min-width: 0;
  font-weight: 600; font-size: 14.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.state {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 6px;
  flex-shrink: 0;
}
.state.live { color: var(--green); background: color-mix(in srgb, var(--green) 14%, transparent); }
.state.draft { color: var(--dim); background: var(--sunken); }
.state.full { color: var(--role-main); background: color-mix(in srgb, var(--role-main) 14%, transparent); }
.state.dead { color: var(--red); background: color-mix(in srgb, var(--red) 14%, transparent); }

.mini-bar { height: 4px; border-radius: 2px; background: var(--sunken); overflow: hidden; }
.mini-bar i { display: block; height: 100%; background: var(--role-main); }
.mini-bar.warm i { background: var(--role-warm); }

.row-foot {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 12px;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}

/* ── Редактор шаблона ──────────────────────────────────────── */

.seg {
  display: flex; gap: 4px;
  background: var(--panel);
  border-radius: 11px;
  padding: 3px;
  margin-bottom: 4px;
}
.seg button {
  flex: 1;
  background: none;
  color: var(--dim);
  font-size: 13px;
  font-weight: 600;
  padding: 8px;
  border-radius: 8px;
}
.seg button[aria-selected="true"] { background: var(--role-main); color: #17130a; }
.seg button.warm[aria-selected="true"] { background: var(--role-warm); color: #17102e; }

.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.field > label { font-size: 12px; color: var(--dim); }

/* Подсказка одна на весь интерфейс, а не только внутри поля: правило было
   вложено в .field, и та же подпись под лентой канала выходила крупной
   белой строкой — читалась как основной текст, хотя это сноска. */
.hintline { font-size: 12px; color: var(--dim); line-height: 1.4; }

/* Быстрые значения: 20 и 40 — те два числа, между которыми он выбирает. */
.quick { display: flex; gap: 6px; flex-wrap: wrap; }
.quick button { background: var(--sunken); font-size: 13px; padding: 8px 14px; border-radius: 10px; }
.quick button[aria-selected="true"] { background: var(--role-main); color: #17130a; font-weight: 700; }

.block {
  background: var(--panel);
  border-radius: 13px;
  padding: 11px 13px;
  display: flex;
  gap: 11px;
  align-items: flex-start;
  border-left: 3px solid transparent;
  margin-bottom: 8px;
  width: 100%;
  text-align: left;
}
.block.paid { border-left-color: var(--role-main); }
.block .num {
  color: var(--dim);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  padding-top: 2px;
  min-width: 14px;
}
/* Кнопка по умолчанию центрирует текст — предпросмотр блока от этого
   выглядел как заголовок, а не как начало поста. */
.block .b-body { flex: 1; min-width: 0; text-align: left; }
.b-kind {
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--dim);
}
.b-kind.paid { color: var(--role-main); }
.b-text {
  font-size: 13px;
  color: var(--text);
  margin-top: 3px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.b-text.empty { color: var(--dim); }
.b-meta { font-size: 11.5px; color: var(--dim); margin-top: 5px; font-variant-numeric: tabular-nums; }
.b-move { display: flex; flex-direction: column; gap: 4px; }
.b-move button { padding: 4px 8px; font-size: 12px; background: var(--sunken); border-radius: 7px; }

/* ── Ход оформления ────────────────────────────────────────── */

.steps {
  display: flex;
  flex-direction: column;
  gap: 9px;
  max-height: 34vh;
  overflow-y: auto;
  overflow-x: hidden;
}
.step { display: flex; gap: 10px; align-items: center; font-size: 13px; color: var(--dim); }
.step .tick {
  width: 17px; height: 17px; border-radius: 50%;
  border: 1.5px solid var(--divider);
  flex-shrink: 0;
  display: grid; place-items: center;
  font-size: 9px;
}
.step.done .tick { background: var(--green); border-color: var(--green); color: var(--bg); }
.step.now { color: var(--text); font-weight: 600; }
.step.now .tick { border-color: var(--role-main); border-style: dashed; }

/* ── Кто вошёл ─────────────────────────────────────────────── */

.buyer {
  display: flex; gap: 11px; align-items: center;
  padding: 9px 0;
  border-bottom: 1px solid var(--divider);
}
.buyer:last-child { border-bottom: none; }
.buyer.gone { opacity: 0.55; }
.ava {
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--sunken);
  display: grid; place-items: center;
  font-size: 13px; font-weight: 700; color: var(--dim);
  flex-shrink: 0;
}
.buyer .who { flex: 1; min-width: 0; }
.buyer .who b {
  font-size: 13.5px; font-weight: 600; display: block;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.buyer .who span { font-size: 11.5px; color: var(--dim); }
.buyer .till { font-size: 11.5px; color: var(--dim); text-align: right; white-space: nowrap; }

/* ── Пустой экран ──────────────────────────────────────────── */

.steps-num { display: flex; flex-direction: column; gap: 13px; }
.stepnum { display: flex; gap: 11px; align-items: flex-start; font-size: 13px; color: var(--dim); line-height: 1.45; }
.stepnum .k {
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--sunken); color: var(--text);
  display: grid; place-items: center;
  font-size: 11px; font-weight: 700;
  flex-shrink: 0;
}
.stepnum b { color: var(--text); font-weight: 600; }

/* Нажатая кнопка разметки: видно, жирный сейчас блок или нет. */
.quick-tag[aria-selected="true"] { background: var(--role-main); color: #17130a; }

/* Кнопки внутри карточки поста — мельче: их две в строке с заголовком,
   и в полный рост они перебивали сам пост. */
.block .btn-small { padding: 6px 11px; font-size: 12.5px; border-radius: 9px; }

/* Имя исполнителя нажимается: его вводят в каждый новый канал руками. */
button.worker { border: none; cursor: pointer; font: inherit; }
button.worker:active { filter: brightness(1.3); }
