/* ═══════════════════════════════════════════════════════════════════════════
   GOLDJAXE Scribe · admin.css — общий слой страниц под топбаром.

   Сюда вынесены правила, которые были дословно скопированы в inline <style>
   сразу нескольких шаблонов (admin_list · admin_org · admin_edit · my_reports).
   Дубли расходились при правках: у одной страницы .btn.ghost краснел на золото
   через --gold, у другой через --c-gold-strong, и «одинаковые» кнопки вели себя
   по-разному. Уникальные для страницы правила остались в самих шаблонах, в
   блоке page_css.

   Подключать ПОСЛЕ tokens.css и components.css. Прежние страничные стили
   переопределяют этот файл — он идёт раньше inline <style> наследника.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── База страницы ─────────────────────────────────────────────────────────── */
.app-shell *{ box-sizing: border-box; }
body{
  margin: 0;
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--ink);
  line-height: 1.55;
}

/* Рабочая колонка. max-width страницы отличается (760 у формы организации,
   1200 у списков) — задаётся на месте, здесь только общая механика. */
.wrap{ max-width: 1200px; margin: 0 auto; padding: 24px 22px 80px; }
@media (max-width: 767px){
  .wrap{ padding: 20px 14px 72px; }
}

/* ── Заголовки ─────────────────────────────────────────────────────────────── */
h1{ font-size: 22px; margin: 0; letter-spacing: -.2px; }
.sub{ color: var(--muted); font-size: 14px; margin-top: 3px; }

/* Заголовок секции — моноширинный капс, общий для /admin и страницы организации.
   Строка-флекс, а не просто текст: рядом с заголовком живут значок справки и
   действие секции («+ Новый проект»), и без общей оси они разъезжались по
   базовой линии на пиксель-два — заметно ровно настолько, чтобы выглядеть
   небрежностью.

   Переехало из <style> admin_list.html 10.08.2026 (GOL-358): разделы надзора
   разошлись по четырём страницам, и копия правил в четырёх шаблонах разошлась бы
   при первой правке — та же болезнь, которую здесь уже лечили дважды. */
.sec-h{
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 32px;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 700;
  margin: 30px 4px 12px;
}
/* Действие секции прижимается вправо: заголовок и кнопка — одна строка. */
.sec-h .sec-cta{ margin-left: auto; }
/* gap:8px уже даёт отступ — гасим собственный margin значка справки. */
.sec-h .help-q{ margin-left: -3px; }

/* «Показать ещё» под свёрнутым списком. Во всю ширину и 48px высотой: это
   мобильный сценарий (на десктопе свёртки нет), а там кнопка во всю строку
   попадается пальцем без прицеливания. */
.dtable-more{ margin-block-start: 12px; }
.dtable-more .btn{
  width: 100%;
  min-height: 48px;
  justify-content: center;
}

/* Подпись под заголовком секции — говорит о срезе списка («показаны 200 из
   1340»). Обычным текстом, не предупреждением: это норма работы страницы, а не
   ошибка, и красная плашка здесь пугала бы на ровном месте. */
.sec-note{
  margin: -6px 4px 12px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--c-ink-3);
}

/* ── Выбор людей: список с поиском (.upick) ────────────────────────────────── */
/* Переехало из <style> шаблона admin_edit.html 11.08.2026 (GOL-359): тем же
   компонентом выбирают администраторов на странице «Пользователи», а стили,
   запертые в одном шаблоне, второй странице не достаются.
   Заодно .owner-chk переименован в .upick-item: компонент выбирает людей вообще,
   а не только «ответственных за проект», и имя обязано это отражать.

   ЗАЧЕМ КОМПОНЕНТ. Плоский перечень чекбоксов читается, пока людей пять. На
   двадцати он превращается в простыню на пол-экрана, по которой нельзя искать:
   глазами по неотсортированным адресам почты. Свёрнутый список занимает одну
   строку и открывается с полем поиска. */
.upick{ position: relative; }
.upick-trigger{
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%;
  padding: 10px 13px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--c-surface-2);
  color: var(--ink);
  font: inherit; font-size: 13.5px;
  cursor: pointer; text-align: left;
  transition: border-color .14s;
}
.upick-trigger:hover{ border-color: var(--gold-line); }
.upick-trigger[aria-expanded="true"]{ border-color: var(--gold); }
.upick-trigger .muted{ color: var(--faint); }
.upick-caret{ color: var(--faint); flex: none; transition: transform .15s; }
.upick-trigger[aria-expanded="true"] .upick-caret{ transform: rotate(180deg); }
.upick-panel{
  position: absolute; z-index: 60;
  top: calc(100% + 4px); left: 0; right: 0;
  background: var(--c-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-2);
  padding: 8px;
}
.upick-panel[hidden]{ display: none; }
.upick-search{ width: 100%; margin-bottom: 6px; }
.upick-list{ max-height: 190px; overflow: auto; display: flex; flex-direction: column; gap: 2px; }
.upick-empty{ padding: 10px 6px; font-size: 13px; color: var(--faint); }
.upick-item{
  display: flex; align-items: center; gap: 8px;
  font-size: 13.5px; font-weight: 400; cursor: pointer;
  padding: 6px 8px; border-radius: var(--radius-sm);
}
/* Скрытие строки поиском. Обязательно ЯВНО: браузерное правило [hidden] задаёт
   display:none с той же силой, что и любой селектор по классу, и объявленный
   выше display:flex его перебивает — строка остаётся на экране, хотя скрипт
   честно проставил hidden. Дефект был не виден на пяти пользователях (совпадали
   почти все) и вылез на двадцати четырёх: поиск «находил» 4 адреса, а список
   продолжал показывать все. */
.upick-item[hidden]{ display: none; }
.upick-item:hover{ background: var(--c-surface-2); }
.upick-item input{ width: 16px; height: 16px; accent-color: var(--gold); flex: none; }
/* Запертая строка — админ из настроек сервера: снять права здесь нельзя, и
   курсор с цветом обязаны сказать это раньше, чем человек кликнет. */
.upick-item.locked{ color: var(--muted); cursor: default; }
.upick-item.locked input{ cursor: default; }
.upick-item svg{ width: 13px; height: 13px; color: var(--faint); flex: none; }

@media (max-width: 767px){
  /* Тач-цель: строка списка — то, по чему целятся пальцем. */
  .upick-item{ min-height: 44px; }
  .upick-list{ max-height: 260px; }
}

/* ── Карточка проекта и её сетка ───────────────────────────────────────────── */
/* Переехало из <style> шаблона admin_list.html 10.08.2026 (GOL-356): проекты
   теперь рисуются на ДВУХ страницах — списком холдинга на /admin и списком
   организации на карточке арендатора. Стили, живущие в одном шаблоне, второй
   странице не достаются: карточки там разваливались в столбик голого текста.
   Правило то же, что для элементов каркаса, — общий элемент живёт в общем CSS. */
.grid{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
.pcard{
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 18px 20px;
  box-shadow: var(--elev-1);
  transition: border-color .15s, box-shadow .15s;
}
.pcard:hover{ border-color: var(--c-line-strong); box-shadow: var(--elev-2); }
.pcard h3{ margin: 0 0 4px; font-size: 16px; display: flex; align-items: center; gap: 8px; }
/* Ключ проекта — компактный моно-чип по контенту (не full-width плашка-«инпут») */
.k{
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--muted);
  background: var(--c-surface-2);
  padding: 2px 8px;
  border-radius: var(--radius-xs);
}
.tags{ display: flex; gap: 6px; flex-wrap: wrap; margin: 10px 0 14px; }
/* Теги — мягкий прямоугольник (не капсула): согласовано с угловатым брендом.
   Монохром: цветом ничего не кодируем. */
.t{
  font-size: 13px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: var(--radius-sm);
  background: var(--c-surface-3);
  color: var(--ink-soft);
}
.t.lock{ display: inline-flex; align-items: center; gap: 4px; }
.pactions{ display: flex; gap: 8px; flex-wrap: wrap; }
/* Кнопки действий в карточке — обычный Inter, БЕЗ капса и моно: рутинные действия
   не должны кричать. Капс-моно оставлен за главным CTA («Новый проект») и
   sec-заголовками. */
.pactions .btn{
  padding: 8px 14px;
  font-size: 13px;
  font-family: var(--font-sans);
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
}

@media (max-width: 767px){
  .grid{ grid-template-columns: 1fr; }
  .pcard{ padding: 14px 15px; }
  .pcard h3{ font-size: 15px; }
  /* Действия проекта — с ПОДПИСЯМИ, в строку по содержимому. Правило по ПРЯМЫМ
     детям: кнопка удаления обёрнута в <form>, и элемент flex-строки — форма. */
  .pactions{ flex-wrap: wrap; gap: 8px; }
  .pactions > *{ flex: 0 0 auto; }
  .pactions .btn{ justify-content: center; min-height: 48px; padding: 0 14px; width: auto; }
}

/* ── Текст личной инструкции под раскрытием (/admin/prompts) ───────────────── */
/* Раскрытие, а не строка таблицы: содержание чужого промта — то, ради чего в
   раздел заходят, и оно же то, что не должно попадаться на глаза мимоходом.
   pre с переносом — инструкции пишут абзацами, и nowrap растянул бы таблицу. */
.prompt-body{ margin-top: 6px; }
.prompt-body > summary{
  cursor: pointer;
  font-size: 12px;
  color: var(--c-ink-3);
}
.prompt-body > summary:hover{ color: var(--c-ink-2); }
.prompt-body__pre{
  margin: 6px 0 0;
  padding: 8px 10px;
  max-height: 240px;
  overflow: auto;
  border: 1px solid var(--c-line);
  border-radius: 6px;
  background: var(--c-surface-2);
  font-size: 12px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
}

/* ── Кнопки страниц админки ────────────────────────────────────────────────── */
/* Исторический набор .btn (не путать с компонентным .sc-btn из components.css).
   Новые экраны пишутся на .sc-btn; этот блок держит уже существующие. */
.btn{
  border: 0;
  border-radius: var(--radius-md);
  padding: 11px 20px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: background .15s, border-color .15s, color .15s;
}
.btn.save{
  background: var(--gold);
  color: var(--c-gold-contrast);
  border-color: var(--gold);
  box-shadow: var(--elev-1);
}
.btn.save:hover{ background: var(--c-gold-strong); }
/* Главное действие раздела («+ Новый проект», «Сохранить доступ»). Переехало из
   <style> admin_list.html (GOL-358): класс `btn gold` уже стоял в admin_org.html и
   team.html, но правило жило в одном шаблоне — на других страницах кнопка молча
   рисовалась бесцветной. Ровно тот случай, ради которого этот файл и завели. */
.btn.gold{
  background: var(--gold);
  color: var(--c-gold-contrast);
  border: 1px solid var(--gold);
  border-radius: var(--radius-sm);
  padding: 10px 16px;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
}
.btn.gold:hover{ background: var(--c-gold-mid); }
.btn.ghost{ background: var(--surface); color: var(--ink); border: 1px solid var(--line); }
.btn.ghost:hover{ border-color: var(--gold); color: var(--c-gold-strong); }
/* Разрушающее действие приглушено по умолчанию и краснеет при наведении:
   в списке из десяти строк красная кнопка в каждой притягивает взгляд зря. */
.btn.danger{ background: var(--card); color: var(--muted); border: 1px solid var(--line); }
.btn.danger:hover{
  background: var(--c-danger-bg);
  color: var(--c-danger);
  border-color: var(--c-danger-line);
}
@media (max-width: 767px){
  .btn{ justify-content: center; min-height: 48px; padding: 13px 20px; width: 100%; }
}

/* ── Формы (страница проекта и страница организации) ───────────────────────── */
.fld{ margin-bottom: 18px; }
label{ display: block; font-size: 13px; font-weight: 700; margin-bottom: 6px; }
label .hint{ font-weight: 400; color: var(--faint); font-size: 13px; }
.fld-help{ font-size: 13.5px; color: var(--muted); margin-top: 6px; line-height: 1.45; }
.fld-help b{ color: var(--ink-soft); font-weight: 600; }
/* Счётчик затронутых встреч (GS-328) — тот же кегль, что у подсказки поля, но
   с меткой: это не пояснение к полю, а следствие выбора, и человек обязан
   отличить их взглядом. Стиль дублируется в modal.css: карточку проекта рисуют
   ДВА набора (страница и окно), и правка одного молча не доедет до другого. */
.fld-help--count{ margin-top: 4px; color: var(--ink-soft); font-weight: 600; }


/* Предупреждение у политики «Открыто всем» (GS-304). Заметность нужна ровно
   такая, чтобы выбор был осознанным, — не пугать, а остановить на секунду.
   Цвет — var(--c-gold-strong): он объявлен во ВСЕХ трёх темах с проверенным
   контрастом (светлая 4.9, ночь 10.3). Красным здесь нельзя: crimson на тёмной
   теме даёт 1.77 и читается как погасший текст.
   Значок + текст, а не только цвет: состояние не имеет права держаться на
   одном цветовом признаке. */
.ap-warn{
  display: flex; align-items: flex-start; gap: 8px;
  font-size: 13.5px; line-height: 1.45; margin-top: 8px;
  padding: 9px 12px;
  color: var(--c-gold-strong);
  background: var(--c-surface-2);
  border: 1px solid var(--c-gold-strong);
  border-radius: var(--radius-sm);
}
.ap-warn svg{ flex: none; margin-top: 2px; }
/* hidden обязан победить display:flex — иначе скрытый блок остаётся на экране
   (известный дефект css-display-beats-hidden-attribute). */
.ap-warn[hidden]{ display: none; }
.keybox{
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--muted);
  background: var(--c-surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
}
.two{ display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.bar{ display: flex; gap: 10px; align-items: center; margin-top: 24px; }
@media (max-width: 767px){
  .two{ grid-template-columns: 1fr; }
  .bar{ flex-direction: column; align-items: stretch; gap: 10px; }
}

/* ── Возврат на уровень выше ──────────────────────────────────────────────── */
.backlink{
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--muted);
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 14px;
}
.backlink:hover{ color: var(--gold); }
/* Возврат — единственный выход со страницы вверх по иерархии, а был 20px по
   высоте (GS-225). Растим высоту, не трогая кегль: подпись намеренно мелкая,
   это служебный ряд, а не орган первого плана. Тот же приём уже применён к
   .sc-manage .backlink в components.css — здесь он доезжает до остальных
   страниц каркаса. */
@media (pointer: coarse){
  .backlink{ min-block-size: 48px; margin-bottom: 8px; }

  /* Ссылка в пустом состоянии («Это делается на странице Загрузка») — 17px по
     высоте. Это ПЕРВЫЙ экран новичка и его единственный следующий шаг: список
     пуст, и уйти с него больше некуда. Зона нажатия псевдоэлементом, а не
     высотой: ссылка стоит ВНУТРИ предложения, и рост высоты разорвал бы
     строку. Ширину не трогаем — растёт только вертикаль. */
  .empty-big a{ position: relative; }
  .empty-big a::after{
    content: ""; position: absolute;
    top: 50%; left: 0; right: 0; height: 44px;
    transform: translateY(-50%);
  }
}

/* ── Таблицы отчётов: общее для /admin и «Мои отчёты» ─────────────────────── */
.ic-sm{ width: 13px; height: 13px; }
/* Перебиваем глобальный .dtable a (золото): название отчёта — нейтральным
   цветом, иначе вся колонка светится и перестаёт читаться как список. */
.dtable a.title-link{ color: var(--ink); font-weight: 500; }
.dtable a.title-link:hover{ color: var(--ink); text-decoration: underline; }
/* Первая ячейка — флекс-строка: значок автора (.who) и название встречи стоят на
   одной оси. Без этого значок садится на базовую линию текста и «подпрыгивает». */
.dtable__primary{ display: flex; align-items: center; }
.views-cell{ color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.views-cell svg{
  width: 13px; height: 13px;
  color: var(--faint);
  vertical-align: -2px;
  margin-right: 3px;
}

/* ── Списки встреч: без прокрутки вбок ───────────────────────────────────────
   Правило общее для НАДЗОРА (/admin/reports) и «Моих отчётов» (/my): таблицы
   одного строения — «Встреча · Проект · Дата · Просмотры · Действия» — и с
   одинаково длинными названиями встреч.

   Компонент .dtable держит nowrap во ВСЕХ ячейках — это верно для коротких
   значений (дата, счётчик), но название встречи здесь бывает длиной в
   предложение («Постановка задачи системе по делу о сбыте (ст. 222 ч. 6 УК РФ)
   — анализ показаний свидетелей и прогноз приговора»). Одна такая строка
   требовала колонке 855px при доступных 1133px, и вся таблица уезжала за
   контейнер: горизонтальная полоса внизу, скрытые колонки «Просмотры» и
   действия, читать список можно было только качая его вбок.

   Лечим не отключением overflow (это спрятало бы данные), а тем, что снимаем
   nowrap с колонки названия — единственной, где текст может переноситься без
   потери смысла. Остальные колонки узкие и фиксированной формы, им nowrap
   нужен: дата и счётчик, разорванные пополам, читаются хуже длинного названия
   в две строки.

   table-layout: fixed нужен, чтобы браузер РАСПРЕДЕЛЯЛ ширину по заданным
   долям, а не подгонял её под самое длинное слово: при auto колонка названия
   всё равно тянула бы таблицу за край. Доли заданы под остальные колонки, а
   название забирает остаток — ему всегда достаётся больше всех.

   Одно правило на две страницы, а не копия под каждый ключ: копии расходятся
   при первой же правке ширины (ровно так разошлись .btn.ghost до этого файла).
   Расходится только колонка «Проект» — см. ниже, у неё разное содержимое.
   ───────────────────────────────────────────────────────────────────────────── */
[data-dtable="admin:reports"] .dtable,
[data-dtable="my:all"] .dtable{ table-layout: fixed; }
/* Проект. В надзоре это технический ключ («team-sync»), в «Моих отчётах» —
   человеческое имя проекта («Клиентские звонки») либо ссылка на его настройку,
   поэтому там колонке нужно заметно больше места. */
[data-dtable="admin:reports"] .dtable th:nth-child(2),
[data-dtable="admin:reports"] .dtable td:nth-child(2){ width: 130px; }
[data-dtable="my:all"] .dtable th:nth-child(2),
[data-dtable="my:all"] .dtable td:nth-child(2){ width: 200px; }
[data-dtable="admin:reports"] .dtable th:nth-child(3),
[data-dtable="admin:reports"] .dtable td:nth-child(3),
[data-dtable="my:all"] .dtable th:nth-child(3),
[data-dtable="my:all"] .dtable td:nth-child(3){ width: 160px; }          /* Дата */
/* 🔴 ДАЛЬШЕ НУМЕРАЦИЯ У ДВУХ СТРАНИЦ РАСХОДИТСЯ. В «Моих отчётах» между датой
   и просмотрами стоит своя колонка «Длительность» (23.08.2026), в надзоре её
   нет. Одним правилом на обе страницы это больше не описать: общий селектор
   на nth-child(4) выдал бы «Длительности» ширину просмотров, а всё, что за
   ней, сдвинул бы на колонку влево. Так и вышло при первой правке —
   выровненный вправо столбец уехал на середину карточки. */
[data-dtable="my:all"] .dtable th:nth-child(4),
[data-dtable="my:all"] .dtable td:nth-child(4){ width: 120px; }          /* Длительность */
[data-dtable="admin:reports"] .dtable th:nth-child(4),
[data-dtable="admin:reports"] .dtable td:nth-child(4),
[data-dtable="my:all"] .dtable th:nth-child(5),
[data-dtable="my:all"] .dtable td:nth-child(5){ width: 128px; }          /* Просмотры */
/* Действия: в надзоре две кнопки (доступ, удаление), в «Моих отчётах» одна и
   только у тех, кто вправе управлять встречей, — колонка уже. */
[data-dtable="admin:reports"] .dtable th:nth-child(5),
[data-dtable="admin:reports"] .dtable td:nth-child(5){ width: 96px; }
[data-dtable="my:all"] .dtable th:nth-child(6),
[data-dtable="my:all"] .dtable td:nth-child(6){ width: 64px; }
/* 🔴 В КАРТОЧКЕ ДОЛЕЙ НЕТ. Ниже 720px таблица разбирается на карточки
   (components.css): строка становится блоком, ячейка — строкой «подпись —
   значение» с space-between. Ширины колонок при этом ПРОДОЛЖАЮТ действовать,
   и ячейка держала свои 64-160px вместо ширины карточки: подпись и значение
   жались друг к другу посреди пустой строки, а не расходились по краям.
   Правило живёт здесь, а не в components.css: доли заданы тут, и отменять их
   должен тот же файл — иначе отмену пришлось бы усиливать !important
   (admin.css подключается последним).

   Ячейка действий исключена: она уходит в absolute в правый-верхний угол
   карточки, и полная ширина растянула бы её на всю строку под кнопкой. */
@media (max-width: 720px){
  [data-dtable="admin:reports"] .dtable tbody td:not(.dtable__cell-actions),
  [data-dtable="my:all"] .dtable tbody td:not(.dtable__cell-actions){ width: 100%; }
}
/* Ключ переноса. Ячейка перестаёт быть флекс-строкой и становится обычным
   текстовым блоком: тогда название, значок автора и флаги (замок, срок) — один
   поток, и при переносе флаг встаёт сразу за последним словом. Во флекс-версии
   он оставался отдельной колонкой и на двухстрочном названии отрывался к
   правому краю, читаясь как флаг соседней колонки.
   overflow-wrap ломает слово, только если оно само длиннее строки (ссылка,
   склейка без пробелов) — обычный текст переносится по словам. */
[data-dtable="admin:reports"] .dtable td.dtable__primary,
[data-dtable="my:all"] .dtable td.dtable__primary{
  display: block;
  white-space: normal;
  overflow-wrap: anywhere;
}
/* Название проекта не рвём посреди слова: колонка узкая, но это короткий текст,
   и «Клиентс/кие звонки» читается хуже, чем перенос по словам. Капсула .t
   остаётся цельным блоком (inline-block), иначе на переносе её фон рвётся на
   два куска и она перестаёт читаться как одна метка. */
[data-dtable="my:all"] .dtable td:nth-child(2){ white-space: normal; }
[data-dtable="my:all"] .dtable td:nth-child(2) .t{
  display: inline-block;
  white-space: normal;
}
/* Значок способа — инлайновым, на одной оси с первой строкой названия. Правило
   одно на обе таблицы: метка живёт и в надзоре, и в «Отчётах» (GS-345), а копия
   под каждый ключ разошлась бы при первой правке — как разошлись .btn.ghost. */
[data-dtable="admin:reports"] .dtable td.dtable__primary .who,
[data-dtable="my:all"] .dtable td.dtable__primary .who{
  display: inline-flex;
  vertical-align: -3px;
  margin-inline-end: 8px;
}
/* Ссылка внутри — inline, иначе inline-flex из .dtable a делает её единым
   неразрывным блоком и перенос не срабатывает. */
[data-dtable="admin:reports"] .dtable td.dtable__primary a.title-link,
[data-dtable="my:all"] .dtable td.dtable__primary a.title-link{
  display: inline;
}

/* ── Поиск по странице ──────────────────────────────────────────────────────
   База переехала сюда из inline-стиля admin_list: тем же полем пользуется
   реестр арендаторов, а вторая копия правил разошлась бы при первой правке
   (ровно как разошлись .btn.ghost до этого файла). admin_list свою копию
   переопределяет тождественно и потому безвреден. */
/* 🔴 ПОИСК И ОТБОР — ОДНОЙ СТРОКОЙ (GS-382, 12.09.2026). Замер на 1440px:
   поле поиска 420px, а список организаций под ним — 1152px во всю рабочую
   ширину. Два органа ОДНОГО назначения (сузить список) выглядели как разные
   системы: один аккуратная строка, второй полоса через весь экран. Снаружи это
   и читается как «элементы несогласованные, всё вразнобой».

   Флекс с переносом: на десктопе оба встают в ряд, на телефоне список уходит
   под поле и растягивается на всю ширину — там она и нужна. */
.searchbar{
  margin: 0 2px 20px; position: relative;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
}
/* Список организаций не тянется за свободным местом: его ширина задаётся
   содержимым и ограничена — иначе он снова съедал бы строку целиком.
   Высота — ровно как у поля поиска (замер: 35 против 41, разнобой в 6px виден
   глазом на соседних органах). Задаём на самом <select>, а не на обёртке:
   .sc-select--sm — общий мелкий размер, и менять его для всего продукта ради
   одной строки нельзя. */
.searchbar .sc-select{ flex: 0 1 auto; max-width: 280px; }
.searchbar .sc-select__el{ min-height: 41px; }
.searchbar input{
  width: 100%;
  max-width: 420px;
  /* flex-basis вместе с min-width: 0 — иначе длинный placeholder распирал бы
     поле и выталкивал список на вторую строку раньше времени. */
  flex: 1 1 260px; min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 11px 38px 11px 13px;
  font-size: 14px;
  font-family: inherit;
  background: var(--c-surface-2);
  color: var(--ink);
}
.searchbar input::placeholder{ color: var(--faint); }
/* Счётчик найденного рядом с полем: пустой результат не должен читаться
   как «все данные пропали». */
.searchbar .found{
  display: none;
  margin-left: 12px;
  font-size: 13px;
  color: var(--muted);
  white-space: nowrap;
}
.searchbar.is-active .found{ display: inline; }
/* Заглушка секции, где поиск ничего не нашёл. */
.nores{ display: none; color: var(--muted); font-size: 14px; padding: 14px 2px; }

.searchbar input:focus{
  outline: none;
  border-color: var(--gold);
  background: var(--surface);
  box-shadow: var(--focus-ring);
}
/* 16px на узких экранах: ниже порога iOS Safari зумит страницу при фокусе на
   поле и обратно не отъезжает. На десктопе остаётся 14px. */
@media (max-width: 767px){
  .searchbar input{ max-width: none; font-size: 16px; }
  .searchbar .found{ display: block; margin: 8px 0 0; }
}

/* ── Плашка «от лица супер-админа» ────────────────────────────────────────── */
/* Идёт под шапкой (та BRAND-IMMUTABLE и тёмная во всех темах). Намеренно
   заметная: цена забытого контекста — правка чужой организации. */
.imp-bar{
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: 10px var(--sp-4);
  background: var(--c-danger-bg);
  border-bottom: 2px solid var(--c-danger);
  color: var(--c-danger);
  font-size: 13.5px;
  line-height: 1.45;
}
.imp-bar__ic{ display: inline-flex; flex: none; }
.imp-bar__ic svg{ width: 16px; height: 16px; }
.imp-bar__text{ flex: 1 1 auto; min-width: 0; }
.imp-bar__text b{ font-weight: 700; }
.imp-bar__form{ margin: 0; flex: none; }
.imp-bar__btn{
  min-height: 32px;
  padding: 0 14px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--c-danger);
  background: transparent;
  border: 1px solid var(--c-danger);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background .15s, color .15s;
}
.imp-bar__btn:hover{ background: var(--c-danger); color: var(--c-bg); }
.imp-bar__btn:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
@media (max-width: 560px){
  /* На телефоне кнопка уезжает на свою строку во всю ширину: в 375px три
     элемента в строку не помещаются, а текст важнее сжатия. */
  .imp-bar{ gap: var(--sp-2); }
  .imp-bar__form{ width: 100%; }
  .imp-bar__btn{ width: 100%; min-height: 44px; }
}

/* Название организации в шапке живёт в components.css рядом с остальной шапкой:
   admin.css грузится не на всех страницах (index.html подменяет блок stylesheets
   на style.css), и здесь правило просто не доезжало — на «Загрузке» название
   оставалось вовсе без стилей и красилось браузерным дефолтом ссылки в синий. */

/* ═══════════════════════════════════════════════════════════════════════════
   Раздел «Организация» (/team) — админка организации для клиента.

   Страница плотная намеренно: владелец заходит сюда за конкретным ответом
   («до какого числа оплачено», «сколько записей осталось», «кто в команде»),
   а не читать. Поэтому воздух здесь меньше, чем на «Загрузке», и ближе к
   плотности списков надзорной админки.

   Все цвета — только токены. Скругления — только --radius-xs/sm: остальные
   в брутал-каноне обнулены, и прибитый гвоздём border-radius сломал бы
   переключатель .ui-square.
   ═══════════════════════════════════════════════════════════════════════════ */

.team{ max-width: 1080px; }

/* ── Шапка раздела ─────────────────────────────────────────────────────────── */
.team-head{
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-3);
  margin: 6px 2px var(--sp-4);
}
.team-head h1{ margin: 0; font-size: 22px; line-height: 1.25; word-break: break-word; }
.team-head__main{ min-width: 0; }
.team-head__state{ flex: none; padding-top: 4px; }
.team-error{ margin: 0 2px var(--sp-3); }

/* Вкладки прижаты к шапке: полоса вкладок и есть навигация раздела. */
.team-tabs{ margin-top: var(--sp-2); }
.team-tabs > .sc-tabpanel{ padding-top: var(--sp-4); }

/* Заголовок секции внутри вкладки — тот же .sec-h, что в надзорной админке,
   но первый в панели не должен отбивать лишние 34px: панель уже отступила. */
.sec-h.first{ margin-top: 0; }
.sec-h__n{ font-weight: 600; opacity: .75; }

/* ── Плашка тарифа ─────────────────────────────────────────────────────────
   Главный элемент вкладки «Обзор»: ради ответа «до какого числа оплачено»
   сюда и заходят. Золотой торец в покое; при приближении срока — бронза,
   после срока — красный. Тон ставит скрипт (см. team.html), а не сервер. */
.plan{
  padding: 12px 15px;
  margin: 0 0 var(--sp-3);
  background: var(--c-surface-2);
  border: 1px solid var(--c-line);
  border-left: 2px solid var(--c-gold-line);
  border-radius: var(--radius-sm);
}
.plan__row{ display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.plan__ic{ display: inline-flex; color: var(--c-gold-strong); flex: none; }
.plan__label{
  font-family: var(--font-mono);
  font-size: 12px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--c-ink-3);
}
.plan__value{
  margin-left: auto;
  font-size: 14px; font-weight: 700;
  color: var(--c-ink);
  word-break: break-word;
}
.plan__term{ margin-top: 7px; font-size: 13.5px; line-height: 1.5; color: var(--c-ink-2); }
.plan__term b{ color: var(--c-ink); font-weight: 700; }
.plan__left{ white-space: nowrap; }
.plan__cta{ margin-top: 10px; }
.plan__cta[hidden]{ display: none; }

/* Срок на исходе — предупреждение, но не ошибка: человек ничего не сломал. */
.plan.is-soon{
  background: var(--c-warn-bg);
  border-color: color-mix(in srgb, var(--c-warn) 35%, transparent);
  border-left-color: var(--c-warn);
}
.plan.is-soon .plan__ic{ color: var(--c-warn); }

/* Срок прошёл — обработка новых записей закрыта, это уже препятствие. */
.plan.is-expired{
  background: var(--c-danger-bg);
  border-color: var(--c-danger-line);
  border-left-color: var(--c-danger);
}
.plan.is-expired .plan__ic{ color: var(--c-danger); }
.plan.is-expired .plan__term b{ color: var(--c-danger); }

/* ── Квота записей ─────────────────────────────────────────────────────────
   Полоса и счётчик повторяют .quota-note с «Загрузки» (style.css): цифра
   должна выглядеть одинаково во всём сервисе. Дубль сознательный — style.css
   на страницах под топбаром не подключён, тянуть его сюда ради одного блока
   дороже, чем повторить тридцать строк. */
.quota-note{
  margin: 0 0 var(--sp-3);
  padding: 11px 14px;
  background: var(--c-surface-2);
  border: 1px solid var(--c-line);
  border-left: 2px solid var(--c-gold-line);
  border-radius: var(--radius-sm);
}
.quota-note__row{ display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 9px; }
.quota-note__ic{ display: inline-flex; align-self: center; color: var(--c-gold-strong); flex: none; }
.quota-note__title{
  font-family: var(--font-mono);
  font-size: 12px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--c-ink-3);
}
.quota-note__count{ font-size: 13.5px; color: var(--c-ink-2); margin-left: auto; }
.quota-note__count b{ font-weight: 700; color: var(--c-ink); font-variant-numeric: tabular-nums; }
.quota-note__bar{
  height: 3px;
  margin-top: 9px;
  background: var(--c-surface-3);
  border-radius: var(--radius-xs);
  overflow: hidden;
}
.quota-note__bar > span{ display: block; height: 100%; background: var(--c-gold); transition: width .3s ease; }
.quota-note__hint{ margin-top: 7px; font-size: 12.5px; line-height: 1.45; color: var(--c-ink-3); }
.quota-note.is-out{
  background: var(--c-warn-bg);
  border-color: color-mix(in srgb, var(--c-warn) 35%, transparent);
  border-left-color: var(--c-warn);
}
.quota-note.is-out .quota-note__bar > span{ background: var(--c-warn); }

/* ── Пределы обработки ─────────────────────────────────────────────────────
   Два числа в ряд: длительность записи и срок хранения. На узком экране —
   столбиком (два числа рядом на 375px превращались в кашу). */
/* Приглашение другой компании (GS-228): ссылка и кнопка «копировать» в строку.
   Поле readonly, но выглядит обычным — из него копируют, и «выключенный» вид
   заставил бы думать, что ссылка ещё не готова. */
.ref{ display: flex; gap: var(--sp-2); align-items: stretch; margin: 0 0 var(--sp-2); }
.ref__lead{ margin: 0 0 var(--sp-3); font-size: 13px; line-height: 1.5; color: var(--c-ink-3); }
.ref__link{
  flex: 1 1 auto; min-width: 0;
  /* Ссылка длинная: моноширинный кегль читается точнее, когда её сверяют
     глазами перед отправкой. */
  font-family: var(--font-mono, monospace); font-size: 12.5px;
}
.ref__copy{ flex: none; }
.ref__count{ margin: 0; font-size: 12px; color: var(--c-ink-4); }

.lim{ display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.lim__cell{
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: 11px 14px;
  background: var(--c-surface-2);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-sm);
}
.lim__ic{ display: inline-flex; color: var(--c-ink-4); flex: none; margin-top: 2px; }
/* Кегль 12px — пол шкалы холдинга (было 11). Подпись предела — то, ради чего
   человек смотрит на плитку: «длительность записи», «хранение расшифровок». */
.lim__label{
  font-family: var(--font-mono);
  font-size: 12px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase;
  color: var(--c-ink-3);
}
.lim__value{ margin-top: 3px; font-size: 14px; font-weight: 600; color: var(--c-ink); }

/* ── Каналы доставки ───────────────────────────────────────────────────────
   Список каналов организации. Управление (добавить / выключить / удалить) с
   17.08.2026 доступно и владельцу организации: канал — его адресат, и писать
   нам письмо ради второй почты в рассылке он больше не должен. Форма —
   общий партиал _channel_form.html, стили её полей ниже (.chf). */
/* Каналов нет — одна строка вместо карточки пустого состояния (03.09.2026).
   Рамку и вертикальный воздух .dtable-empty здесь не рисуем намеренно: пустой
   блок занимал пол-экрана телефона рассказом о том, чего на этой странице уже
   нет (каналы переехали в проект, GS-220). Механика — под «i» у заголовка. */
.chan-none{
  margin: 0;
  color: var(--c-ink-3);
  font-size: 13.5px;
  line-height: 1.5;
}
/* Канонический токен, не легаси-алиас: --accent объявлен один раз и застывает
   на светлой теме — ссылка потерялась бы в тёмной. */
.chan-none a{ color: var(--c-gold-strong); white-space: nowrap; }

.chan{
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-1);
  overflow: hidden;
}
/* 🔴 СЕТКА, А НЕ flex-wrap (GS-189, правка 01.09.2026).

   Раньше строка была flex с flex-wrap и тянущимся адресатом. Раскладка при этом
   следовала из СОСТАВА строки, а состав у видов канала разный: у telegram и
   webhook есть «.chan__secret», у email его нет вовсе. Из-за этого перенос
   случался в разных местах, и на телефоне каждый вид выглядел по-своему —
   у email кнопки в ряд, у telegram корзина уезжала под ярлык «включён», ярлык
   оказывался то слева, то справа. Владелец прочитал это как «всё поехало, единой
   структуры нет» — и был прав: правила раскладки не существовало, был побочный
   эффект переноса.

   Теперь позиции заданы именами областей. Место секрета в сетке есть всегда:
   у email оно просто пустое, а остальные элементы стоят там же, где у telegram.
   Это и есть «одинаково расставить»: структура задана правилом, а не тем, какие
   элементы прислал шаблон.

   🔴 ПЕРВАЯ КОЛОНКА — auto, НЕ 1fr. Вид канала («TELEGRAM») — нерастяжимая
   метка: при 1fr колонка сжималась до 51px, и слово вылезало под ярлык
   состояния. Тянется вторая колонка (адресат), потому что растягиваться должно
   то, что длинное, а не то, что короткое. Наложение видно только глазами:
   прямоугольники при этом НЕ пересекаются, замер geometry его не находит. */
.chan__row{
  display: grid;
  grid-template-areas:
    "kind   state acts"
    "target target acts"
    "secret secret acts";
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 2px var(--sp-3);
  padding: 10px 14px;
  font-size: 13.5px;
}
.chan__row:not(:last-child){ border-bottom: 1px solid var(--c-line); }
.chan__row.is-off{ color: var(--c-ink-4); }
.chan__kind{
  grid-area: kind;
  display: inline-flex; align-items: center; gap: 6px;
  /* 🔴 min-width: 0 здесь НЕЛЬЗЯ. Колонка сжимается по содержимому строки, а
     вид канала — короткая нерастяжимая метка («TELEGRAM» просит 82px). При
     обнулённом минимуме сетка выдавала ей 51px, и слово вылезало ПОД ярлык
     состояния: overflow у элемента visible, поэтому обрезки не видно — видно
     наложение. Замером это не ловится (прямоугольники не пересекаются,
     scrollWidth > clientWidth), только глазами по экрану.
     min-content — ровно ширина слова, ни пикселем больше. */
  min-width: min-content;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: 12px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase;
  color: var(--c-ink-3);
}
/* Адресат переносится по символам: почта и адрес webhook — одно «слово», и без
   этого длинный адрес распирал бы колонку (тот же приём, что у заголовка
   отчёта на телефоне). */
.chan__target{ grid-area: target; min-width: 0; color: var(--c-ink); word-break: break-all; }
/* Привязка канала к проекту (GS-199): приглушённая подпись внутри области
   target — сетку строки не трогает. Используется и на «Команде», и в карточке
   организации (там своя строка, но подпись общая). */
.chan__proj{ color: var(--c-ink-3); font-weight: 400; word-break: normal; }
.chan__secret{
  grid-area: secret;
  display: inline-flex; align-items: center; gap: 5px;
  min-width: 0;
  font-family: var(--font-mono); font-size: 12px;
  color: var(--c-ink-4);
}
/* Ярлык стоит СРАЗУ ЗА видом канала, а не у правого края: он относится к
   каналу, и на узком экране, прижатый вправо, читался как подпись к кнопкам. */
.chan__state{ grid-area: state; justify-self: start; }
/* Действия (выключить / удалить) — столбцом у правого края, на всю высоту
   строки: у всех видов канала они на одном месте, сколько бы строк ни занял
   адресат. */
.chan__act{
  grid-area: acts;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
}

/* ── Форма канала (_channel_form.html) ─────────────────────────────────────
   Одна разметка на два экрана: надзорную карточку организации и клиентский
   раздел «Организация». Отличает их только .chf--compact — клиентская манера
   полей (.sc-input / .sc-select) против надзорной сетки.

   Ряд — две колонки, на телефоне одна: поля «Куда» и «Секрет» длинные, рядом
   на 390px они нечитаемы. Когда поле секрета скрыто (вид канала — email), ряд
   секрета прячется целиком (GS-220: галочки «Приём» рядом больше нет). */
.chf__row{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-3);
}
.chf__row[hidden]{ display: none; }
.chf__fld{ min-width: 0; }
.chf__fld[hidden]{ display: none; }
.chf__label{
  display: block;
  margin-bottom: 6px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--c-ink);
}
.chf__label .hint{ font-weight: 400; color: var(--c-ink-4); }
.chf__bar{ display: flex; gap: var(--sp-2); flex-wrap: wrap; }
/* Поля формы канала в клиентской манере тянутся на всю колонку: .sc-input
   по умолчанию ужимается по содержимому, и адрес вебхука не помещался. */
.chf--compact .sc-input,
.chf--compact .sc-select{ width: 100%; }

@media (max-width: 767px){
  .chf__row{ grid-template-columns: 1fr; }
  .chf__bar .sc-btn,
  .chf__bar .btn{ width: 100%; justify-content: center; min-height: 48px; }
}

/* ── Полоса «управление выключено» ─────────────────────────────────────────
   Два разных повода, один вид: под просмотром от лица (действия скрыты) и на
   пробе (действия видны, но выключены). Оба — не ошибка пользователя, поэтому
   тон нейтральный/бронзовый, а не красный. */
.team-lock{
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-4);
  padding: 9px 13px;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--c-ink-2);
  background: var(--c-surface-3);
  border: 1px solid var(--c-line);
  border-left: 2px solid var(--c-line-strong);
  border-radius: var(--radius-sm);
}
.team-lock svg{ flex: none; color: var(--c-ink-4); }
.team-lock.is-trial{
  background: var(--c-gold-bg);
  border-color: var(--c-gold-line);
  border-left-color: var(--c-gold);
}
.team-lock.is-trial svg{ color: var(--c-gold-strong); }

/* Значок замка рядом с выключенным органом. Тач-цель 24px хватает: это
   не кнопка, а подсказка (текст живёт в data-tip). */
.lockmark{
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;
  flex: none;
  color: var(--c-gold-strong);
  cursor: help;
}

/* Выключенное действие в строке таблицы. В components.css у .dtable__row-del/act
   состояния disabled нет — кнопка выглядела рабочей и на пробе обещала действие,
   которого не будет. Гасим и снимаем hover-подсветку. */
.dtable__row-del:disabled,
.dtable__row-act:disabled{
  opacity: .40;
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Строка участника ──────────────────────────────────────────────────────── */
.mem{ display: inline-flex; align-items: center; gap: 7px; flex-wrap: wrap; min-width: 0; }
.mem__mail{ word-break: break-word; }

/* 🔴 В КАРТОЧКЕ ПОЧТА И ЧИПЫ — РАЗНЫМИ СТРОКАМИ (GS-382, 12.09.2026).
   На широком экране `inline-flex` с переносом верен: адрес короткий, чип встаёт
   рядом. В карточке телефона ширины не хватает, и место чипа начинало зависеть
   от ДЛИНЫ АДРЕСА: у владельца «elchako@yandex.ru» + «Владелец» умещались, а
   «Это вы» переносилось вниз — два одинаковых по смыслу ярлыка вставали на
   разных уровнях. Снимок владельца 12.09.2026: «чипсы владелец потом это вы
   они переносятся».

   Лечим не переносом, а раскладкой: адрес занимает свою строку целиком, чипы —
   свою, слева. Место элементов больше не зависит от данных, и карточка
   читается одинаково у любого адреса. Это тот же приём, что у .chrow с
   именованными областями: состав строки меняется, а места фиксированы. */
@media (max-width: 720px){
  /* Сетка, а не колонка флексов: адрес обязан занять ВСЮ строку (flex-basis
     100%), а чипы — встать в ряд под ним. Колонка ставила бы каждый чип на
     свою строку, и карточка вытянулась бы ещё сильнее. */
  .mem{ display: flex; flex-wrap: wrap; align-items: center; gap: 6px; width: 100%; }
  .mem__mail{
    flex: 0 0 100%;
    /* Адрес рвём по любому символу: длинные ящики на поддомене («a.very.long.
       address.for.check@subdomain.example.org») не имеют пробелов вовсе, и
       word-break:break-word оставлял бы их одной непереносимой строкой,
       вылезающей за карточку. */
    word-break: break-all;
  }
}

/* Смена роли прямо в строке: select + кнопка-дублёр (её прячет JS, она нужна
   только когда скриптов нет). */
.rolef{ display: inline-flex; align-items: center; gap: var(--sp-2); margin: 0; }
.rolef .sc-select{ min-width: 132px; }
.rolef__go[hidden]{ display: none; }
/* Пока запрос в пути — селект приглушён. Без этого смена роли выглядит как
   «ничего не произошло»: ответ приходит через десятки миллисекунд, но на
   медленной сети пауза заметна, а страница больше не перезагружается и сама
   по себе о работе не сигналит. */
.rolef.is-busy{ opacity: .55; }

/* ── Формы в окнах раздела «Организация» (GS-219) ─────────────────────────
   «Новый проект», «Пригласить человека», канал в карточке проекта — столбиком
   во всю ширину окна; кнопка — в футере окна. Заголовок окна несёт «i» с
   тем, что раньше стояло строкой под формой. */
.team-modal-form .sc-field{ margin-bottom: var(--sp-3); }
.team-modal-form .sc-input,
.team-modal-form .sc-select{ width: 100%; }
.team-modal-form .sc-modal-foot{ padding-left: 0; padding-right: 0; padding-bottom: 0; margin-top: var(--sp-2); }
.team-modal-form.is-locked .sc-input,
.team-modal-form.is-locked .sc-select__el{ background: var(--c-surface-3); }
.sc-modal-title .help-q{ vertical-align: middle; }
/* Общий контекст организации (GS-97): .sc-field не несёт отступа к соседу вне
   себя, а кнопка шла сразу за textarea без единого пикселя зазора — «Сохранить
   контекст» визуально прилипала к полю (замечание владельца 03.09.2026). */
.team-context-form .sc-field{ margin-bottom: var(--sp-3); }
/* Окно канала внутри карточки проекта (GS-220): форма партиала уже compact,
   ряды сетки на ширине окна — одной колонкой. */
#channelModal .chf__row{ grid-template-columns: 1fr; }
/* Ссылка-крестик окна (без JS ведёт на якорь секции) — как кнопка. */
a.sc-modal-x{ text-decoration: none; }

/* ── Форма приглашения (устаревшая раскладка в строку) ─────────────────────
   Оставлена для .invf в других местах; на «Организации» форма живёт в окне. */
.invf{
  display: flex;
  align-items: flex-end;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: 14px 15px;
  background: var(--c-surface-2);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-sm);
}
.invf__mail{ flex: 1 1 240px; min-width: 0; }
.invf__role{ flex: 0 0 auto; min-width: 150px; }
.invf__go{ flex: none; }
.invf__go .sc-btn{ min-height: 36px; }
/* Поля внутри формы — на ступень ВЫШЕ её подложки. Базовый .sc-input залит
   --c-surface-2, и на этом же тоне лежит сама .invf: поле сливалось с блоком и
   читалось как подпись, а не как место для ввода. Тот же --c-surface контрол
   уже получает в фокусе (components.css) — здесь он просто действует сразу, а
   не после клика. Токеном, а не белым цветом: в тёмных темах «белый фон поля»
   означает не #FFF, а свою ступень поверхности. */
.invf .sc-input,
.invf .sc-select__el{ background: var(--c-surface); }
/* Выключенная форма (проба) остаётся видимой, но явно нерабочей: приглушаем
   блок целиком, чтобы не читался как активный. Прятать нельзя — человек
   должен видеть, что он получит за деньги. Поля возвращаются на общий тон:
   поднимать нерабочий ввод незачем. */
.invf.is-locked{ background: var(--c-surface-3); border-style: dashed; }
.invf.is-locked .sc-input,
.invf.is-locked .sc-select__el{ background: var(--c-surface-2); }
.invf.is-locked .sc-label{ color: var(--c-ink-4); }

/* ── Мобильный ────────────────────────────────────────────────────────────── */
@media (max-width: 720px){
  .team-head{ flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-3); }
  .team-head__state{ padding-top: 0; }
  .team-head h1{ font-size: 19px; }

  .lim{ grid-template-columns: 1fr; gap: var(--sp-2); }

  /* Ссылка приглашения — столбиком: поле и кнопка рядом на 375px оставляют
     полю треть ширины, и от ссылки видно «https://goldj…». */
  .ref{ flex-direction: column; align-items: stretch; }
  .ref__copy{ min-height: 44px; justify-content: center; }

  /* Форма приглашения — столбиком, кнопка во всю ширину с тач-целью 48px. */
  .invf{ flex-direction: column; align-items: stretch; gap: var(--sp-3); }
  .invf__mail,
  .invf__role,
  .invf__go{ flex: 1 1 auto; min-width: 0; }
  .invf__go .sc-btn{ width: 100%; justify-content: center; min-height: 48px; }
  /* 16px в поле — ниже порога iOS Safari зумит страницу при фокусе. */
  .invf .sc-input{ font-size: 16px; }

  /* В карточке-строке (dtable ≤720px) селект роли занимает всю ширину:
     inline-flex рядом с подписью «РОЛЬ» на 375px не помещался. */
  .rolef{ display: flex; width: 100%; justify-content: flex-end; }
  .rolef .sc-select{ flex: 1 1 auto; min-width: 0; }
  /* 🔴 Высоту здесь НЕ занижаем (GS-225). Строка задавала 40px и тем перебивала
     общие 48px из components.css (@media pointer: coarse): смена роли человека —
     орган управления, а не подпись, и промах по нему меняет чужой доступ. Ширину
     правило выше уже решило растяжкой, к высоте она отношения не имеет.
     min-height, а не фиксированная: длинная подпись роли вправе занять две строки. */
  .rolef .sc-select__el{ min-height: 44px; }

  /* Действия строки — крупнее: тач-цель 44px канона холдинга. */
  .dtable__cell-actions .dtable__row-del,
  .dtable__cell-actions .dtable__row-act{ min-width: 44px; min-height: 44px; }

  /* Строка канала на телефоне. Правила выравнивания под прежний flex
     (align-items: flex-start и сброс margin-left у ярлыка) убраны — они правили
     раскладку, которой больше нет; сетка задаёт места сама.

     🔴 ЯРЛЫК СОСТОЯНИЯ — РЯДОМ С ВИДОМ КАНАЛА, в одном ярусе. Пока кнопка несла
     подпись «Выключить» (130px из 364), втроём они в ярус не помещались, и ярлык
     наезжал то на «TELEGRAM», то на кнопку; тогда он временно жил на своём ярусе.
     После сжатия кнопок до значков место появилось, и ярлык вернулся к тому, что
     описывает, — вид канала и его состояние читаются одной строкой.

     Действия остаются СТОЛБЦОМ справа. Отдельная строка под них уже была
     опробована и отвергнута замером: добавляла ещё ярус и разводила высоты по
     видам (127 · 146 · 167px вместо ровных).

     44px под палец (канон холдинга) — на КОРЗИНЕ, у неё своей ширины нет;
     подпись «Выключить» и так шире порога. */
  .chan__row{
    align-items: start;
    grid-template-areas:
      "kind   state  acts"
      "target target acts"
      "secret secret acts";
    grid-template-columns: auto minmax(0, 1fr) auto;
  }
  /* align-self: start прижимает столбец действий к верху строки: без него сетка
     растягивает его на всю высоту, и корзина уезжала вниз, повисая в пустоте
     под кнопкой (видно на 390px у webhook, где адресат занимает два яруса). */
  /* Действия — рядом, значками. Подпись «Выключить» на 390px забирала 130px из
     364, и адресату оставалось 132px: собственная почта клиента рвалась посреди
     слова («elchakox@gmail.co / m»). Значок несёт то же действие, а смысл
     держат aria-label и title — доступное имя от скрытия подписи не страдает. */
  .chan__act{ align-self: start; align-items: center; gap: 2px; }
  .chan__act-label{ display: none; }
  /* Рамку у кнопки снимаем вместе с подписью: пустая коробка со значком внутри
     читается как поле ввода, а не как действие, — рядом стоит корзина без
     рамки, и два действия одной строки выглядели разными по природе. */
  .chan__act .sc-btn{
    min-width: 44px; min-height: 44px;
    justify-content: center; padding-inline: 0;
    border-color: transparent; background: transparent;
  }
  .chan__act .dtable__row-del{ min-width: 44px; min-height: 44px; justify-content: center; }
}

@media (max-width: 400px){
  /* Полоса вкладок на самом узком экране: счётчики скрываем, иначе три
     вкладки не влезают и полоса уезжает в скролл при первом взгляде. */
  .team-tabs .sc-tab{ padding-left: 10px; padding-right: 10px; }
}

/* Ссылка «Организации (N) →» в шапке /admin — то, что осталось от переехавшей
   секции. Не .btn: это переход в соседний раздел, а не действие, и кричать
   золотом ему незачем. */
.orglink{
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: none;
  min-height: 44px;
  padding: 0 14px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--c-ink-2);
  text-decoration: none;
  background: var(--c-surface-2);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-sm);
  transition: border-color .15s ease, color .15s ease;
}
.orglink:hover{ border-color: var(--c-gold); color: var(--c-gold-strong); }
.orglink:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
.orglink svg{ width: 15px; height: 15px; flex: none; color: var(--c-ink-4); }
.orglink:hover svg{ color: var(--c-gold-strong); }   /* заливочное золото на белом даёт 2.2 — для значка норма 3 */
/* --c-ink-3, а не --c-ink-4: стрелка — единственный указатель, что плашка
   кликабельна, а блёклый токен давал 4.08 при норме 4.5 (замер WCAG 2.1). */
.orglink__go{ color: var(--c-ink-3); font-weight: 700; }
.orglink:hover .orglink__go{ color: var(--c-gold-strong); }
/* Плитка бота — та же плашка, но с состоянием службы. Молчащая служба красится
   предупреждающим: «не отвечает» набранное тем же тоном, что «2 встречи»,
   читается как обычная строка и пропускается глазом — а это единственное, ради
   чего плитку и завели. */
.botlink.is-down{ color: var(--c-warn); border-color: color-mix(in srgb, var(--c-warn) 40%, transparent); }
.botlink.is-down svg{ color: var(--c-warn); }
.botlink.is-down .orglink__go{ color: var(--c-warn); }
@media (max-width: 767px){
  /* В шапке на телефоне ссылка идёт во всю ширину под заголовком: рядом с
     h1 она отжимала заголовок в две строки. */
  .orglink{ width: 100%; justify-content: center; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   РЕЕСТР АРЕНДАТОРОВ · /admin/orgs (admin_orgs.html)

   Надзорный экран: девять колонок и сводка. Всё, что здесь есть, работает на
   плотность — каждый лишний отступ стоит строки таблицы, которая иначе
   уехала бы за нижний край без прокрутки.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Страница шире общей: девять колонок в 1200px жмутся, «Доступ до» начинает
   переноситься по слогам. С боковой колонкой (232px) 1400 — рабочий предел. */
.orgreg{ max-width: 1400px; }
.orgreg__head{ margin-bottom: var(--sp-4); }

/* ── Сводка ─────────────────────────────────────────────────────────────────
   Строка плашек, а не карточки: это подпись к таблице. Плашки равной ширины
   через grid — при разной длине подписей («всего» / «квота исчерпана») flex
   давал бы рваный ряд. */
.orgsum{
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--sp-2);
  margin: 0 2px var(--sp-4);
}
.orgsum__cell{
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 12px;
  background: var(--c-surface-2);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-sm);
  /* Левая метка цветом — состояние строки читается до чтения цифры. */
  border-left: 3px solid var(--c-line-strong);
}
.orgsum__n{
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 700;
  line-height: 1.1;
  color: var(--c-ink);
  font-variant-numeric: tabular-nums;
}
.orgsum__l{
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--c-ink-3);
}
/* «Активных» и «на пробе» — норма, а не сигнал: цветной торец у них стоял
   ВСЕГДА, и рядом с «доступ истёк» (тот красится только при ненулевом значении)
   тревожная карточка терялась среди зелёной и синей. Норму рисуем нейтрально —
   цвет остаётся тому, что требует реакции. */
.orgsum__cell.is-ok,
.orgsum__cell.is-trial{ border-left-color: var(--c-line-strong); }
/* Тревожные плашки красятся ТОЛЬКО когда в них есть что показать: ноль
   просроченных, выкрашенный красным, приучает не замечать красный вовсе. */
.orgsum__cell.is-warn{ border-left-color: var(--c-warn); }
.orgsum__cell.is-warn .orgsum__n{ color: var(--c-warn); }
.orgsum__cell.is-bad{ border-left-color: var(--c-danger); background: var(--c-danger-bg); }
.orgsum__cell.is-bad .orgsum__n{ color: var(--c-danger); }

/* ── Таблица ──────────────────────────────────────────────────────────────── */
/* Название + ключ в одной ячейке: ключ ищут не реже названия (он в письмах и
   логах), но он служебный — поэтому мельче и приглушён. */
.orgcell{ display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.orgcell__name{ font-weight: 600; }
.orgcell__key{
  font-family: var(--font-mono);
  font-size: 12px;          /* пол шкалы: ниже 12px в интерфейсе не опускаемся */
  color: var(--c-ink-4);
  word-break: break-all;
}
.orgplan{
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--c-ink-2);
}

/* Доступ до. Дата моноширинная с tabular-nums — колонка дат должна
   сравниваться взглядом по вертикали, а не читаться построчно. */
.orgtill{ white-space: nowrap; }
.orgtill__d{ font-variant-numeric: tabular-nums; }
.orgtill__inf{ color: var(--c-ink-4); }
.orgtill.is-over .orgtill__d{ color: var(--c-danger); font-weight: 700; }
.orgtill__over{
  display: block;
  font-size: 12px;          /* пол шкалы */
  font-weight: 700;
  color: var(--c-danger);
  letter-spacing: .02em;
}

/* Записи: расход из квоты. Исчерпанная — единственная цифра в таблице,
   которой позволено кричать: она означает «новые записи не принимаются». */
.orgquota{ white-space: nowrap; font-variant-numeric: tabular-nums; }
.orgquota__v{ display: inline-flex; align-items: baseline; gap: 5px; }
.orgquota b{ font-weight: 700; color: var(--c-ink); }
.orgquota__of{ color: var(--c-ink-4); font-size: 12.5px; }
.orgquota.is-out b{ color: var(--c-danger); }
.orgquota.is-out .orgquota__of{ color: var(--c-danger); }

/* Люди + приглашения. Значок «+N» прижат к числу, а не к краю ячейки:
   читается как «столько же плюс столько на подходе». */
.orgppl{ display: inline-flex; align-items: center; gap: 6px; justify-content: flex-end; }
.orgppl__n{ font-variant-numeric: tabular-nums; }
.orgppl__inv{ font-size: 12px; padding: 1px 6px; letter-spacing: .03em; }  /* пол шкалы */

/* Сброс кнопочной плашки браузера для <button class="dtable__row-act"> живёт
   в самом компоненте (components.css) — та же беда была и на /team, где кнопка
   «выслать снова» рисовалась серым квадратом. Частного правила здесь больше
   нет: чинить общий класс в двух местах порознь — как раз то, из-за чего
   дефект и уцелел на второй странице. */

/* Значки в строке живут парой — выравниваем по одной линии. */
.orgtable .dtable__cell-actions{ white-space: nowrap; }

/* 🔴 Колонка действий ПРИЛИПАЕТ к правому краю на широких экранах.
   Замер 15.08.2026: при вьюпорте 1440 таблица занимает 1542px, и за краем
   оказываются «Отчёты» (4px) и вся колонка действий (102px). Прокрутка вбок
   есть (.dtable-wrap → overflow:auto), но её не видно: человек смотрит на
   строку организации и не догадывается, что справа спрятаны «открыть» и
   «удалить» — кнопок для него просто нет.
   Прилипание, а не сжатие колонок: имя организации бывает длинным («Акционерное
   общество „Научно-производственное объединение“»), и резать его многоточием
   ради двух значков — обмен худший. Остальные колонки по-прежнему доезжают
   прокруткой, а действия доступны всегда.
   Только там, где карточного режима ещё нет (>720px): в карточке действия
   стоят в углу плитки и прилипать им не к чему. */
@media (min-width: 721px){
  .orgtable th:last-child,
  .orgtable td.dtable__cell-actions{
    position: sticky;
    inset-inline-end: 0;
    z-index: 1;
    background: var(--c-surface);
    /* Тень слева — признак, что под колонкой что-то проезжает. Без неё
       прилипшая колонка читается как часть строки, и обрыв соседней колонки
       выглядит дефектом вёрстки. */
    box-shadow: -8px 0 8px -8px rgba(0,0,0,.28);
  }
  .orgtable th:last-child{ z-index: 3; }   /* выше липкого заголовка */
  .orgtable tbody tr:hover td.dtable__cell-actions{ background: var(--c-surface-2); }
}

/* ── Планшет ──────────────────────────────────────────────────────────────── */
@media (max-width: 1100px){
  /* Пять плашек в ряд на планшете дают цифру в 40px шириной — переносим
     в две строки, лучше две строки, чем усечённая подпись. */
  .orgsum{ grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ── Телефон (таблица → карточки, ≤720px из components.css) ───────────────── */
@media (max-width: 720px){
  .orgsum{ grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin-bottom: var(--sp-3); }
  .orgsum__n{ font-size: 17px; }
  .orgsum__l{ font-size: 12px; }   /* пол шкалы — и на телефоне тоже */

  /* В карточке название и ключ идут в столбик во всю ширину — flex-строка
     из components.css прижала бы ключ вправо, и он читался бы как значение
     чужой подписи. */
  .orgcell{ width: 100%; }

  /* Значения в карточке выравниваются вправо (space-between): у «Доступ до»
     просрочка обязана оставаться под датой, а не уезжать в отдельную строку. */
  .orgtill__over{ text-align: end; }

  /* Люди и приглашения тоже держатся вместе — обёртка .orgppl уже flex. */
  .orgppl{ justify-content: flex-end; }

  /* Действий два (карточка + вход от лица) — им нужна тач-цель 44px канона
     холдинга. Селектор повторяет специфичность общего правила из
     components.css (.dtable td.dtable__cell-actions …), которое ставит 40px:
     иначе оно выигрывает и промах пальцем уводит в чужую организацию.
     Логическими свойствами — теми же, что в переопределяемом правиле, иначе
     min-width проиграет min-inline-size при равной специфичности. */
  .dtable td.dtable__cell-actions .dtable__row-act,
  .dtable td.dtable__cell-actions .dtable__row-del{
    min-inline-size: 44px;
    min-block-size: 44px;
  }
  /* Под два значка по 44px нужно больше места, чем закладывает общее правило
     (90px под 40px-значки), иначе название заезжает под них. */
  .orgtable tbody tr:has(.dtable__cell-actions .dtable__row-act + form)
    td.dtable__primary{ padding-inline-end: 98px; }
}

@media (max-width: 380px){
  /* На самом узком экране сводка — один столбец: две плашки рядом дают
     подпись «квота исчерпана» в две строки и ломают ритм. */
  .orgsum{ grid-template-columns: 1fr; }
  .orgsum__cell{ flex-direction: row; align-items: baseline; gap: var(--sp-2); }
}

/* ── Карточка организации · блок «Люди организации» ─────────────────────────
   Панель строк по образцу каналов доставки на той же странице: подпись слева,
   значение справа. Отдельная таблица ради двух чисел была бы тяжелее данных,
   которые она несёт. */
.orgppl-panel{
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--elev-1);
  padding: 4px 16px 14px;
  margin-bottom: 18px;
}
.orgppl-panel__row{
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  flex-wrap: wrap;
  padding: 10px 0;
  font-size: 13.5px;
}
.orgppl-panel__row + .orgppl-panel__row{ border-top: 1px solid var(--c-line); }
.orgppl-panel__ic{ display: inline-flex; align-self: center; flex: none; color: var(--c-ink-4); }
.orgppl-panel__label{ color: var(--c-ink-2); }
/* Значение прижато вправо: два числа под одним краем сравниваются взглядом. */
.orgppl-panel__val{
  margin-left: auto;
  font-weight: 700;
  color: var(--c-ink);
  font-variant-numeric: tabular-nums;
  word-break: break-all;
  text-align: end;
}
.orgppl-panel__none{ color: var(--c-ink-4); font-weight: 500; }
/* .orgppl-panel__hint удалён (GOL-358): пояснение про первичный контакт переехало
   под «i» к подписи самого поля, носителя у класса не осталось. */
.orgppl-panel__go{ margin: 14px 0 0; }

@media (max-width: 480px){
  /* Адрес почты во всю ширину под подписью — иначе длинный адрес рвётся
     посреди домена в узкой правой колонке. */
  .orgppl-panel__val{ margin-left: 0; width: 100%; text-align: start; }
  .orgppl-panel__go .sc-btn{ width: 100%; justify-content: center; min-height: 48px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   СТРАНИЦЫ НАДЗОРА (/admin/projects · /admin/reports · /admin/users ·
   /admin/audit) — общий слой.

   ПОЧЕМУ ЗДЕСЬ, А НЕ В page_css КАЖДОЙ СТРАНИЦЫ. До 10.08.2026 все четыре
   раздела жили одной страницей admin_list.html с вкладками, и весь набор правил
   ниже стоял в её единственном <style>. Владелец снял вкладки (GOL-358): каждый
   раздел получил свой адрес, а дублирование навигации — вкладки поверх бокового
   меню — ушло. Разложить тот же <style> копией в четыре шаблона значило бы
   завести четыре копии, которые разойдутся при первой правке: ровно та болезнь,
   от которой в этом файле уже лечили .btn.ghost и .searchbar.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Шапка страницы: заголовок слева, вход в реестр организаций справа. flex-wrap —
   чтобы на узком экране ссылка уходила ПОД заголовок, а не сжимала h1 до
   переноса по слогам. */
.row1{
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 6px 2px 16px;
  gap: 12px;
  flex-wrap: wrap;
}

/* Пустое состояние секции — компактная плашка в пунктирной рамке, а не «дыра» в
   макете: пустой список и сломанный список должны выглядеть по-разному. */
.empty{
  color: var(--muted);
  padding: 22px 16px;
  text-align: center;
  font-size: 13.5px;
  border: 1px dashed var(--c-line-strong);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

/* 🔴 ОТКАЗ — НЕ ПУСТОТА (GS-287, тема 5). Карточка прогона рисовала «не удалось
   загрузить» тем же серым пунктиром, что и «здесь ничего нет»: дежурный читал
   поломку как штатное отсутствие данных и шёл дальше, вместо того чтобы
   обновить или пойти разбираться.

   Сплошная рамка вместо пунктира — пунктир означает «место под будущее
   содержимое», а здесь содержимое есть, его не удалось получить. Цвет и
   подложка из danger-токенов, у которых контраст выверен в обеих тёмных темах
   (см. комментарий у --c-danger в tokens.css). */
.empty--fail{
  color: var(--c-danger);
  border-style: solid;
  border-color: var(--c-danger-line);
  background: var(--c-danger-bg);
}

/* Способ появления записи в списке встреч: инициал — ручная загрузка, значок
   бота — запись бота, микрофон — автозапись площадки (только старые записи,
   путь закрыт в GS-243). Значок, а не слово: колонка узкая, а различать способ
   нужно взглядом. Разметка одна на надзор и «Отчёты» — templates/_source_badge.html. */
.who{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 20px;
  height: 20px;
  margin-right: 9px;
  border-radius: var(--radius-xs);
  vertical-align: -5px;
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase;
  background: var(--c-surface-3);
  color: var(--ink-soft);
  cursor: default;
}
.who--auto{ color: var(--faint); }
/* Бот — золотом на золотой подложке: способ живой и частый, и в списке его
   отличают от инициала человека прежде, чем прочитают подсказку. Оба токена
   переопределены в каждой теме, на графите и ночи значок не гаснет. */
.who--bot{ background: var(--gold-bg); color: var(--gold-strong); }
.who svg{ width: 12px; height: 12px; }

/* ── Пользователи (/admin/users) ───────────────────────────────────────────── */
.users-panel{
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--elev-1);
  overflow: hidden;
}
.urow{ display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 10px 16px; }
.urow:not(:last-child){ border-bottom: 1px solid var(--line); }
.uemail{ font-weight: 600; font-size: 13.5px; flex: 1; min-width: 190px; }
.ubadges{ display: flex; gap: 6px; flex-wrap: wrap; }
.ub{
  font-size: 13px;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: var(--radius-sm);
  background: var(--c-surface-3);
  color: var(--ink-soft);
}
.useen{ font-size: 13px; color: var(--faint); white-space: nowrap; }
/* Отозванный пользователь — единственный цветной бейдж в панели: состояние
   «доступ закрыт» должно бросаться в глаза, иначе его не заметить в списке. */
.ub.revoked{
  background: var(--c-danger-bg);
  color: var(--c-danger);
  border: 1px solid var(--c-danger-line);
}
.uactions{ margin-left: auto; display: flex; gap: 8px; }
/* Кнопка в строке пользователя — как действия в карточке: без капса и моно,
   рутинное действие не кричит. */
.uactions .btn{
  padding: 6px 12px;
  font-size: 13px;
  font-family: var(--font-sans);
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
}

/* Форма «Доступ к админке» — орган управления, а не список: своя карточка. */
.admins-form{
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 18px 20px;
  box-shadow: var(--elev-1);
}
/* .admins-hint удалён (GOL-358): объяснение прав администратора переехало под
   значок «i» у заголовка секции, и правило осталось бы висеть без разметки. */
/* .admins-grid и .admin-chk удалены (GOL-359): плоский набор чекбоксов заменён
   общим списком с поиском (.upick выше), и правила остались бы висеть без
   разметки. Отступ, который давал .admins-grid, теперь на самом компоненте. */
.admins-form .upick{ margin-bottom: 14px; }
.admins-bar{ display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.admins-bar input{
  flex: 1;
  min-width: 220px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  font-size: 13.5px;
  font-family: inherit;
  background: var(--c-surface-2);
  color: var(--ink);
}
.admins-bar input:focus{
  outline: none;
  border-color: var(--gold);
  background: var(--surface);
  box-shadow: var(--focus-ring);
}

/* ── Журнал (/admin/audit): действия · почта · лог сервера ────────────────── */
/* Всё на токенах, без единого [data-theme]-селектора: три темы (светлая, графит,
   ночь) получаются сами. Жёсткий цвет здесь означал бы моноширинный блок,
   проваливающийся в светлой теме, — самая частая поломка таких экранов. */

/* Полоса вкладок: ссылки, а не кнопки (у каждой вкладки свой адрес), поэтому
   снимаем подчёркивание, которое .sc-tab не ожидает от <a>. */
.jtabs{ margin-top: var(--sp-2); }
.jtabs .sc-tab{ text-decoration: none; }
.jtabs > .sc-tabpanel{ padding-top: var(--sp-4); }

/* Панель отбора. Полем формы, а не пилюлями: условий пять, и каждое сужает
   выборку независимо. */
.jfilter, .logbar{
  display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end;
  margin: 0 2px 14px; padding: 12px 14px;
  background: var(--c-surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.jfilter__grow{ flex: 1 1 210px; min-width: 180px; }
.jfilter .sc-field, .logbar .sc-field{ flex: 0 1 168px; }
.jfilter__act{ display: flex; gap: 8px; margin-left: auto; }
/* Подпись поля — в одну строку. Двухстрочная («Поиск по людям и объектам»)
   поднимала своё поле выше соседних: у флекса выравнивание идёт по низу
   блока, и вся полоса отбора съезжала ступенькой. */
.jfilter .sc-label, .logbar .sc-label{ white-space: nowrap; }
/* Имя файла лога длиннее поля: «app.log · 96.6 КБ · 13.08.2026, 14:20». Даём
   ему расти, иначе размер и дата обрезаются ровно посередине. */
.logbar .sc-field:first-child{ flex: 2 1 320px; }

/* Лента событий. Значок · время · фраза · машинный код — сетка, а не flex:
   время и код обязаны стоять столбцом, иначе взгляд при прокрутке не цепляется. */
.jpanel{
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--elev-1);
  overflow: hidden;
}
.jrow{
  display: grid;
  grid-template-columns: 22px 128px 1fr auto;
  gap: 12px; align-items: baseline;
  padding: 10px 16px; font-size: 13.5px;
}
.jrow:not(:last-child){ border-bottom: 1px solid var(--line); }
.jrow:hover{ background: var(--c-surface-2); }
.jrow__ic{ align-self: center; color: var(--c-ink-4); display: flex; }
/* Тон — на строке целиком: при прокрутке ищут пятно, а не иконку. */
.jrow.is-danger .jrow__ic{ color: var(--c-danger); }
.jrow.is-watch .jrow__ic{ color: var(--c-warn); }
.jrow__time{
  color: var(--faint); white-space: nowrap;
  font-variant-numeric: tabular-nums; font-size: 12.5px;
}
.jrow__text{ color: var(--c-ink-2); word-break: break-word; }
.jrow__text b{ color: var(--ink); font-weight: 600; }
.jrow__text .obj{ color: var(--ink); font-weight: 600; }
.jrow__text code{ font-family: var(--font-mono); font-size: 12px; color: var(--c-gold-strong); }
.jrow__det{ display: block; margin-top: 2px; color: var(--faint); font-size: 12.5px; }
/* Машинный код действия: нужен для поиска в логе сервера, но не должен
   перетягивать внимание с фразы. */
.jrow__code{
  font-family: var(--font-mono); font-size: 11px; color: var(--c-ink-4);
  white-space: nowrap; padding: 2px 6px;
  background: var(--c-surface-3); border-radius: var(--radius-xs);
}

/* Страницы */
.pager{
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin: 16px 2px 0; flex-wrap: wrap;
}
.pager__info{ color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
.pager__nav{ display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.pager a, .pager .pg{
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; height: 34px; padding: 0 9px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--c-surface); color: var(--c-ink-2);
  text-decoration: none; font-size: 13px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  transition: border-color .15s, color .15s;
}
.pager a:hover{ border-color: var(--c-gold); color: var(--ink); }
.pager a:focus-visible{ outline: none; box-shadow: var(--focus-ring); border-color: var(--c-gold); }
.pager .is-current{ background: var(--c-gold-bg); border-color: var(--c-gold-line); color: var(--c-gold-strong); }
.pager .is-disabled{ opacity: .4; }
.pager .gap{ border: 0; background: transparent; min-width: 14px; color: var(--faint); }

/* ── Вкладка «Почта» ──────────────────────────────────────────────────────── */
/* Отбор переехал на общий компонент .jfilter (GS-132) — тот же, что во вкладке
   «Действия». Было шесть кнопок-пилюль в строку: на телефоне полоса ломалась в
   три ряда и съедала экран раньше списка писем. Своих правил раскладки здесь
   больше нет намеренно — иначе мобильное поведение чинилось бы в двух местах.

   Три уточнения к общему компоненту — все из замеров на живой странице.

   ШИРИНА СОСТОЯНИЯ. Подписи с числом («Отказ получателя · 9») длиннее, чем у
   отборов в «Действиях», и на общих 168px обрезались бы ровно на счётчике,
   ради которого экран и заведён.

   РОСТ ПОЛЯ ПОИСКА. `.jfilter .sc-field` (0,2,0) перебивает `.jfilter__grow`
   (0,1,0), и поле оставалось на 168px вместо того, чтобы занять свободное
   место. В «Действиях» это незаметно — там пять полей и свободного места нет;
   здесь полей два, и поиск съёживался до 180px рядом с пустой полосой.

   РОВНАЯ ЛИНИЯ ПОДПИСЕЙ. .sc-input высотой 42px против .sc-select--sm в 35px:
   при выравнивании по низу подписи «Поиск» и «Состояние» вставали на разной
   высоте (замер: 226px против 234px). Уравниваем высоту контролов, а не
   выравнивание полосы — иначе разъедутся сами поля. */
.jfilter .mfilter__state{ flex: 0 1 240px; }
.jfilter .jfilter__grow{ flex: 1 1 260px; }
.jfilter .mfilter__state .sc-select__el{ min-height: 42px; font-size: 14px; }

.mrow{
  /* Последняя колонка — max-content, а не фиксированные 96px: подписи состояний
     стали длиннее («передано провайдеру», «отказ получателя» против прежнего
     «доставлено»), и на фиксированной ширине они уезжали за правый край строки
     — при том что .mstate запрещает перенос. Ширину теперь задаёт самая длинная
     подпись, а тянется средняя колонка с адресом. */
  display: grid; grid-template-columns: 128px 92px minmax(0, 1fr) max-content;
  gap: 12px; padding: 11px 16px; font-size: 13.5px; align-items: start;
}
.mrow:not(:last-child){ border-bottom: 1px solid var(--line); }
.mtime{ color: var(--faint); font-variant-numeric: tabular-nums; white-space: nowrap; font-size: 12.5px; }
.mkind{ color: var(--muted); }
.mtarget{ color: var(--ink); word-break: break-all; }
.mnotice{ color: var(--muted); font-size: 12.5px; margin-top: 2px; }
/* Ответ сервера — красным и целиком: он отличает «адреса нет» от «не смогли
   подключиться», и ради него экран существует. */
.merr{ color: var(--c-danger); font-size: 12.5px; margin-top: 3px; word-break: break-word; }
.mstate{
  justify-self: end; font-size: 12px; font-weight: 600; white-space: nowrap;
  padding: 3px 9px; border-radius: var(--radius-pill);
  background: var(--c-surface-3); color: var(--muted);
}
/* Зелёное — ТОЛЬКО у delivered. «Передано провайдеру» (sent) держим нейтральным
   намеренно: письмо сдано релею, но получатель его ещё не видел, и зелёная
   пометка на этом состоянии ровно и создавала картину «104 доставлено, 0 не
   доставлено» в момент, когда mail.ru письма отбивал (GS-101). Цвет здесь —
   утверждение о судьбе письма, и делать его раньше времени нельзя. */
.mstate.delivered{ color: var(--c-success); background: var(--c-success-bg); }
.mstate.sent{ color: var(--muted); background: var(--c-surface-3); }
.mstate.bounced, .mstate.failed{ color: var(--c-danger); background: var(--c-danger-bg); }
.mstate.pending, .mstate.sending{ color: var(--c-warn); background: var(--c-warn-bg); }
.mattempts{ text-align: end; color: var(--faint); font-size: 12px; margin-top: 3px; }
/* Чей это отказ. Тот же текст «550 …» под нашей ошибкой SMTP и под отказом
   чужого сервера значит разное, а разбор идёт в разные стороны. */
.mhint{ color: var(--muted); font-size: 12px; margin-top: 3px; }

/* ── Вкладка «Лог сервера» ────────────────────────────────────────────────── */
.loghint{ color: var(--muted); font-size: 13px; margin: 0 4px 10px; font-variant-numeric: tabular-nums; }
.logview{
  margin: 0; padding: 14px 16px;
  max-height: 56vh; overflow: auto;
  background: var(--c-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--elev-1);
  font-family: var(--font-mono); font-size: 12.5px; line-height: 1.55;
  /* Переносим строки, а не прокручиваем вбок: горизонтальная прокрутка внутри
     страницы — верный способ потерять конец длинной строки с ошибкой. */
  white-space: pre-wrap; word-break: break-word;
  color: var(--c-ink-2);
}
.logline{ display: block; }
.logline.l-DEBUG{ color: var(--c-ink-4); }
.logline.l-INFO{ color: var(--c-ink-2); }
.logline.l-WARNING{ color: var(--c-warn); }
.logline.l-ERROR, .logline.l-CRITICAL{ color: var(--c-danger); font-weight: 600; }

/* ── Телефон ──────────────────────────────────────────────────────────────── */
@media (max-width: 767px){
  /* «Доступ к админке» на телефоне: поле ввода и кнопка — во всю ширину (раньше
     min-width выпихивал форму за экран). Сам список людей теперь .upick — его
     мобильные правила стоят рядом с компонентом, а не здесь. */
  .admins-bar{ flex-direction: column; align-items: stretch; }
  .admins-bar input{ min-width: 0; width: 100%; }
  .admins-bar .btn{ width: 100%; justify-content: center; min-height: 48px; }
  /* Заголовок секции и её кнопка — в две строки: margin-left:auto прижимал кнопку
     вправо в ОДНУ строку, и «+ Новый проект» наезжал на «ПРОЕКТЫ (4)». */
  .sec-h{ flex-wrap: wrap; }
  .sec-h .sec-cta{ margin-left: 0; flex-basis: 100%; justify-content: center; min-height: 44px; }
}

/* ── Журнал на телефоне ───────────────────────────────────────────────────── */
/* Порог 760px, а не 767: сетка строки ломается раньше, чем остальная админка —
   у неё четыре колонки, и последняя (машинный код) первой уезжает за экран. */
@media (max-width: 760px){
  /* Строка события складывается: значок остаётся столбиком слева, всё
     остальное — под ним. Время над фразой, код под ней: порядок чтения
     сохраняется, горизонтальной прокрутки не возникает. */
  .jrow{ grid-template-columns: 20px 1fr; gap: 4px 10px; padding: 12px 14px; }
  .jrow__ic{ grid-row: 1 / span 3; align-self: start; margin-top: 2px; }
  .jrow__time, .jrow__text, .jrow__code{ grid-column: 2; }
  .jrow__code{ justify-self: start; }

  .mrow{ grid-template-columns: 1fr; gap: 4px; }
  .mstate{ justify-self: start; }
  .mattempts{ text-align: start; }

  /* Поля отбора во всю ширину: подбирать их пальцем в четыре колонки нельзя. */
  .jfilter, .logbar{ padding: 12px; }
  .jfilter .sc-field, .logbar .sc-field,
  .jfilter__grow{ flex: 1 1 100%; min-width: 0; }
  .jfilter__act{ margin-left: 0; flex: 1 1 100%; }
  .jfilter__act .btn{ flex: 1 1 0; justify-content: center; min-height: 44px; }
  /* 16px — иначе iOS Safari масштабирует страницу при фокусе на поле. */
  .jfilter .sc-input, .logbar .sc-input,
  .jfilter .sc-select__el, .logbar .sc-select__el{ font-size: 16px; }

  .pager{ justify-content: center; }
  .pager__info{ flex: 1 1 100%; text-align: center; }
  /* 40px по высоте — попадание пальцем без прицеливания. */
  .pager a, .pager .pg{ min-width: 40px; height: 40px; }

  .logview{ max-height: 60vh; font-size: 12px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ДИСПЕТЧЕРСКАЯ КОНВЕЙЕРОВ (/admin/pipelines, GS-34)

   Перенос прототипа qa/proto-orchestrator.html на боевые страницы. Классы и
   структура те же — прототип снимался на этих же токенах, чтобы «как на
   картинке» означало «так и будет».

   🔴 РАЗМЕРЫ ПРИВЕДЕНЫ К ПАСПОРТУ. В прототипе местами стояли 11px и 12px
   (подписи узлов схемы, значок шага). В приложении их нет вовсе: основной
   текст 14px, плотное и интерактивное — 13px w600. Мелкий кегль в служебном
   экране читается хуже всего именно тогда, когда нужен: при разборе аварии в
   три часа ночи.

   Ни одного жёсткого цвета: только токены. Тёмная тема получается сама —
   значения токенов подменяются на уровне :root[data-theme].
   ═══════════════════════════════════════════════════════════════════════════ */

/* Живая точка и бегущая заливка — единственные две анимации раздела.
   Обе выключаются при prefers-reduced-motion (ниже): пульсация на весь экран
   у человека с вестибулярной чувствительностью — не украшение, а барьер. */
@keyframes orc-pulse { 0%, 100% { opacity: 1 } 50% { opacity: .35 } }

/* Предупреждение «воркер выключен». Не toast: состояние постоянное, а не
   событие, и обязано быть видно каждому, кто открыл экран, а не только тому,
   кто застал всплывающее сообщение. */
.orc-warn{
  display: flex; align-items: center; gap: var(--sp-2);
  margin: 0 2px 14px; padding: 10px 12px;
  font-size: 14px; color: var(--c-warn);
  background: var(--c-warn-bg);
  border: 1px solid var(--c-gold-line);
  border-radius: var(--radius-sm);
}
.orc-warn .ic{ flex: none; }

/* ── Полоса состояний ──────────────────────────────────────────────────── */
.orc-stats{ display: flex; gap: 10px; flex-wrap: wrap; margin: 0 2px 16px; }
.orc-stat{
  border: 1px solid var(--c-line); border-radius: var(--radius-sm);
  padding: 9px 13px; min-width: 96px; background: var(--c-surface);
}
.orc-stat__n{
  font-family: var(--font-mono); font-size: 19px; font-weight: 700;
  color: var(--c-ink); line-height: 1.1;
}
.orc-stat__l{
  font-family: var(--font-mono); font-size: 13px; letter-spacing: .05em;
  text-transform: uppercase; color: var(--c-ink-4); margin-top: 3px;
}
.orc-stat--run .orc-stat__n{ color: var(--c-gold-strong); }
.orc-stat--err .orc-stat__n{ color: var(--c-danger); }

/* ── Состояние живой связи ─────────────────────────────────────────────── */
/* Подписано СЛОВАМИ, а не одной точкой: «поток упал, обновляю опросом»
   человек обязан прочитать, а не вывести из оттенка кружка. */
.orc-live{
  display: inline-flex; align-items: center; gap: 6px; margin-left: auto;
  font-family: var(--font-mono); font-size: 13px; color: var(--c-ink-4);
  padding-inline: var(--sp-2);
}
.orc-live i{
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--c-success);
  animation: orc-pulse 1.6s ease-in-out infinite;
}
.orc-live[data-mode="poll"] i{ background: var(--c-warn-base); }
.orc-live[data-mode="off"] i{ background: var(--c-ink-4); animation: none; }

/* ── Реестр прогонов ───────────────────────────────────────────────────── */
/* Обёртка со скроллом: широкая таблица на узком экране уезжает вбок, а не
   ломает макет (ниже 720px она перестраивается в карточки). */
.orc-tablewrap{ overflow-x: auto; }
.runs{ width: 100%; border-collapse: collapse; }
.runs th{
  text-align: start; font-family: var(--font-mono); font-size: 13px;
  letter-spacing: .05em; text-transform: uppercase; color: var(--c-ink-4);
  font-weight: 400; padding: 0 10px 8px; border-bottom: 1px solid var(--c-line);
  white-space: nowrap;
}
.runs td{
  padding: 11px 10px; border-bottom: 1px solid var(--c-line);
  font-size: 14px; color: var(--c-ink-2); vertical-align: middle;
}
.runs__row{ cursor: pointer; }
.runs__row:hover td{ background: var(--c-gold-bg); }
.runs__row:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
.runs__row[aria-expanded="true"] td{ background: var(--c-gold-bg); }
.runs__name{ font-weight: 500; color: var(--c-ink); }
.runs__sub{
  font-family: var(--font-mono); font-size: 13px; color: var(--c-ink-4);
  margin-top: 2px;
}
/* Колонка «Кто»: почта инициатора и его организация. Почта бывает длинной
   (имя.фамилия@длинный-домен.ru) — разрешаем перенос ПО СИМВОЛАМ, иначе она
   распирает колонку и уводит таблицу в горизонтальный скролл. */
.runs__who-mail{
  font-family: var(--font-mono); font-size: 13px; color: var(--c-ink-2);
  overflow-wrap: anywhere;
}

.runs__det > td{ padding: 0; background: var(--c-surface-2); }

/* Мини-конвейер прямо в строке: видно, НА КАКОМ шаге стоит, без раскрытия
   карточки. Иначе «где встало» стоило бы клика на каждой строке. */
.mini{ display: flex; align-items: center; }
.mini__s{
  width: 20px; height: 5px; border-radius: 2px; flex: none;
  background: var(--c-line-strong);
}
.mini__s + .mini__s{ margin-inline-start: 3px; }
.mini__s--ok{ background: var(--c-success); opacity: .55; }
.mini__s--running{ background: var(--c-gold); animation: orc-pulse 1.6s ease-in-out infinite; }
.mini__s--failed{ background: var(--c-danger); }
.mini__s--skipped{ background: var(--c-line-strong); opacity: .5; }

/* Словарь состояний — общий на всю диспетчерскую (строка, карточка, лента). */
.st{
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--font-mono); font-size: 13px; font-weight: 600;
  letter-spacing: .03em; white-space: nowrap;
}
.st::before{ content: ""; width: 7px; height: 7px; border-radius: 50%; flex: none; }
.st--running::before{ background: var(--c-gold); animation: orc-pulse 1.6s ease-in-out infinite; }
.st--ok::before{ background: var(--c-success); }
.st--failed::before{ background: var(--c-danger); }
.st--queued::before, .st--cancelled::before{ background: var(--c-ink-4); }
.st--running{ color: var(--c-gold-strong); }
.st--failed{ color: var(--c-danger); }
.st--ok{ color: var(--c-ink-3); }
.st--queued, .st--cancelled{ color: var(--c-ink-4); }

.mono{ font-family: var(--font-mono); font-size: 13px; }
.dim{ color: var(--c-ink-4); }

/* Визуально скрытое, но доступное озвучке (по образцу .sc-switch__input):
   мини-конвейер нарисован цветом, и читалке нужна словесная замена. */
.sr-only{
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── Карточка прогона ──────────────────────────────────────────────────── */
.det{ padding: 16px; border-top: 1px solid var(--c-line-strong); }
.det__h{
  display: flex; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; align-items: baseline; margin-bottom: 14px;
}
.det__n{ font-size: 15px; font-weight: 600; color: var(--c-ink); }
.det__act{ display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-top: 14px; }

.steps{ display: flex; flex-direction: column; }
.step{
  display: grid; grid-template-columns: 22px 1fr auto; gap: 12px;
  align-items: center; padding: 9px 0;
  border-bottom: 1px solid var(--c-line); cursor: pointer;
}
.step:last-of-type{ border-bottom: 0; }
.step:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
.step__i{
  width: 20px; height: 20px; border-radius: 50%; flex: none;
  border: 1.5px solid var(--c-line-strong);
  display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 13px; color: var(--c-ink-4);
}
/* Значок внутри кружка — SVG из общего набора (16.08.2026, вместо текстовых
   «✓ ! ◆»: галочка бралась из шрифта и выглядела кривой). 11px при кружке 20 —
   глиф не касается обводки. */
.step__i svg{ width: 11px; height: 11px; display: block; }
.step--ok .step__i{ border-color: var(--c-success); color: var(--c-success); }
.step--running .step__i{ border-color: var(--c-gold); color: var(--c-gold-strong);
                         animation: orc-pulse 1.6s ease-in-out infinite; }
.step--failed .step__i{ border-color: var(--c-danger); color: var(--c-danger); }
.step__n{ font-size: 14px; color: var(--c-ink-2); }
.step--running .step__n{ color: var(--c-ink); font-weight: 500; }
.step__d{ font-family: var(--font-mono); font-size: 13px; color: var(--c-ink-4); }
/* Причина сбоя — в самой строке шага, до всякого раскрытия. При разборе аварии
   первый вопрос «почему», и ответ на него не должен стоить клика. */
.step__err{
  font-family: var(--font-mono); font-size: 13px; font-weight: 600;
  color: var(--c-danger); margin-top: 3px; word-break: break-word;
}

/* Раскрытие шага (уровень 2): причина сразу, полный журнал по ссылке.
   Открывается НА МЕСТЕ — при разборе сбоя важно видеть соседние шаги и их
   тайминг, а не уходить на другую страницу. */
.steplog{
  display: none;
  margin: 0 0 10px 34px; padding: 10px 12px;
  border-inline-start: 2px solid var(--c-line-strong);
  background: var(--c-gold-bg);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.steplog.open{ display: block; }
.steplog--err{ border-inline-start-color: var(--c-danger); }
.steplog__h{
  display: flex; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; align-items: baseline; margin-bottom: 7px;
}
.steplog__lnk{ color: var(--c-gold-strong); text-decoration: none; border-bottom: 1px solid currentColor; }
.steplog__lnk:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
.steplog__err{
  font-family: var(--font-mono); font-size: 13px; font-weight: 700;
  color: var(--c-danger); margin-bottom: 6px;
}
.steplog__out{
  font-family: var(--font-mono); font-size: 13px; line-height: 1.5;
  color: var(--c-ink-3); margin: 0; white-space: pre-wrap; word-break: break-word;
  max-height: 170px; overflow: auto;
}
.steplog__note{ margin-top: 6px; }
.steplog__act{ margin-top: 8px; }

/* ── Карта: время шагов ────────────────────────────────────────────────── */
.orc-maphead{ margin: 0 2px 14px; }
.orc-maphead__t{ font-size: 15px; font-weight: 600; color: var(--c-ink); }
.orc-maphead__s{ font-size: 14px; color: var(--c-ink-4); margin-top: 4px; line-height: 1.5; }
/* Полоса от САМОГО ДОЛГОГО шага: сравнивать шаги имеет смысл между собой, а не
   с абстрактной шкалой. Узкое место видно мгновенно — у него полоса во всю ширину. */
.orc-bar{
  height: 6px; background: var(--c-surface-3); border-radius: 2px;
  overflow: hidden; min-width: 60px;
}
.orc-bar > i{ display: block; height: 100%; background: var(--c-gold); border-radius: 2px; }
.orc-bar__v{ margin-top: 4px; }

/* ── Лента событий ─────────────────────────────────────────────────────── */
.feed{ border-inline-start: 2px solid var(--c-line); margin-inline-start: 6px; }
.feed__i{ position: relative; padding: 9px 0 9px 20px; }
.feed__i::before{
  content: ""; position: absolute; inset-inline-start: -5px; top: 15px;
  width: 8px; height: 8px; border-radius: 50%; background: var(--c-line-strong);
}
.feed__i--warn::before{ background: var(--c-warn-base); }
.feed__i--error::before{ background: var(--c-danger); }
.feed__t{ font-family: var(--font-mono); font-size: 13px; color: var(--c-ink-4); }
.feed__run{ color: var(--c-gold-strong); text-decoration: none; }
.feed__run:hover{ text-decoration: underline; }
.feed__run:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
.feed__m{ font-size: 14px; color: var(--c-ink-2); margin-top: 2px; }
.feed__m b{ color: var(--c-ink); font-weight: 600; font-family: var(--font-mono); font-size: 13px; }

/* ── Узкий экран ───────────────────────────────────────────────────────── */
@media (max-width: 720px){
  /* Таблица → карточки: шесть колонок на 390px не помещаются ни при какой
     верстке, а горизонтальная прокрутка на главном экране дежурного — это
     потеря половины данных за краем.
     🔴 Правило на ВСЕ строки таблицы, а не только на .runs__row: у вкладки
     «Модели» строки обычные, и без этого они оставались таблицей — колонки
     сжимались, состояние обрезалось до «выключе…», кнопки действий не
     помещались вовсе. Поймано визуальной проверкой на 390. */
  .runs thead{ display: none; }
  .runs tbody tr{ display: block; padding: 12px 2px; border-bottom: 1px solid var(--c-line); }
  /* 🔴 СКРЫТИЕ ВОЗВРАЩАЕМ ЯВНО, иначе карточка не сворачивается (GS-262).
     Строка выше перебивает браузерное [hidden]{display:none}: у того сила
     селектора по классу, и объявленный display:block его отменяет. Скрипт при
     этом отрабатывает верно — hidden снимается и ставится, aria-expanded
     переключается, не меняется только картинка. Отсюда обманчивый симптом:
     первое нажатие «работает» (карточка появляется), второе будто не нажалось.
     Ровно та же ловушка, что у .upick-item[hidden] в начале файла. */
  .runs tbody tr[hidden]{ display: none; }
  .runs tbody td{ display: block; border: 0; padding: 3px 0; }
  .runs__row{ padding: 12px 2px; }
  /* Раскрытая карточка — не карточка-строка: у неё своё содержимое во всю
     ширину, и общие отступы строки ей только мешают. */
  .runs tbody tr.runs__det{ padding: 0; }
  .runs__det > td{ padding: 0; }
  .det{ padding: 12px 2px; }
  .steplog{ margin-inline-start: 0; }
  .step{ grid-template-columns: 22px 1fr; row-gap: 4px; }
  .step__d{ grid-column: 2; }
  /* Тач-цель: строка и шаг раскрываются пальцем, а не прицеливанием. */
  .runs__row, .step{ min-height: 44px; }
  .orc-stat{ flex: 1 1 calc(50% - 5px); min-width: 0; }
  /* Подпись живой связи уходит ПОД вкладки отдельной строкой. В одной полосе с
     тремя вкладками она на 390px обрезалась до «живое обнов…» — то есть
     единственное сообщение о состоянии связи становилось нечитаемым ровно там,
     где экран и так тесный. */
  .orc-live{
    margin-inline-start: 0; width: 100%; order: 10;
    padding: 6px 0 0; white-space: nowrap;
  }
  .sc-tabs__list{ flex-wrap: wrap; }
}

/* Уважаем системную настройку «меньше движения»: пульсация на служебном экране
   не несёт смысла сверх цвета и подписи, и убрать её ничего не ломает. */
@media (prefers-reduced-motion: reduce){
  .orc-live i, .mini__s--running, .st--running::before, .step--running .step__i{
    animation: none;
  }
}

/* ── Вкладка «Модели»: цепочка провайдеров и резерв (GS-38) ────────────────── */
/* Кнопки строки — в одну линию с переносом: их пять, и на узком экране они
   обязаны переноситься, а не выдавливать таблицу горизонтальной прокруткой.
   Стрелки порядка стоят рядом парой, остальные — следом.

   🔴 НЕ `display: contents` у формы. Он выглядит логично (кнопка становится
   прямым ребёнком flex-строки), но каждая форма при этом остаётся отдельным
   переносимым блоком неизвестной ширины, и пять кнопок раскладывались в ТРИ
   ряда, раздувая строку таблицы вдвое. Поймано на визуальной проверке.
   Здесь формы сами становятся flex-элементами фиксированного содержания. */
.orc-llm__act{ display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.orc-llm__act form{ display: inline-flex; margin: 0; }
/* Стрелки — узкие квадраты: это не подписи, а направление. */
.orc-llm__act form .sc-btn[aria-label]{ padding-inline: 9px; }
.orc-llm__when{ margin-top: 3px; }
/* Ответ проверки связи — под кнопками той же строки: вопрос «жив ли этот
   провайдер» задают глядя на список, и ответ обязан появиться там же. */
.orc-llm__res{ margin-top: 6px; font-size: 13px; min-height: 0; }
.orc-llm__res--ok{ color: var(--c-success); }
.orc-llm__res--err{ color: var(--c-danger); word-break: break-word; }
.orc-llm__add{ margin-top: 18px; }
.orc-llm__note{
  margin: 12px 2px 0; font-size: 14px; line-height: 1.55; color: var(--c-ink-4);
}

@media (max-width: 720px){
  /* Кнопки во всю ширину строки: пять целей по 44px в ряд на телефоне не
     помещаются, а промах по «Удалить» дороже лишнего переноса. */
  .orc-llm__act .sc-btn{ min-height: 44px; }
}

/* Прошлые заходы прогона (GS-34, правка 13.08.2026) — свёрнутый блок под
   текущими шагами. Не прячем совсем: это материал разбора «почему пришлось
   перезапускать». Но и не мешаем с текущим состоянием — вперемешку успешный
   прогон читался как проваленный. */
.det__past{ margin-top: 14px; border-top: 1px solid var(--c-line); padding-top: 10px; }
.det__past-btn{
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
  padding: 0; font-family: var(--font-mono); font-size: 13px;
  color: var(--c-ink-4); background: none; border: 0; cursor: pointer;
}
.det__past-btn:hover{ color: var(--c-ink-2); }
.det__past-btn:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
.det__past-body{ display: none; }
.det__past.is-open .det__past-body{ display: block; }
/* Прошлое подаётся приглушённо: это уже не состояние, а история. */
.det__past-body .step{ opacity: .72; cursor: default; }

/* ═══════════════ Телефон: рамки не съедают ширину ═══════════════ */
/* ─────────────────────────────────────────────────────────────────────────────
   🔴 Ревизия 16.08.2026 (замер _frames_audit.py на 390px). Экраны админки
   строятся вложением «рамка в рамке», и каждый уровень добавляет свой отступ:

     карточка организации  .wrap(28) → .orgform(50) → .keybox(26)  = 104px (27%)
     пользователи          .wrap(28) → .admins-form(42)            =  70px (18%)
     организация           .wrap(28) → .dtable-empty(50)           =  78px (20%)
     реестр                .wrap(28) → .orgsum__cell(30)           =  58px (15%)
     журнал                .wrap(28) → .jrow(28)                   =  58px (15%)
     диспетчерская         .wrap(28) → .orc-stat(28)               =  56px (14%)

   На десктопе это воздух, на телефоне — потерянные строки текста: длинные
   названия организаций и адреса почты рвутся посреди слова. Рамки НЕ убираем
   (карточка обязана читаться как карточка), убираем ДУБЛИРОВАНИЕ отступа:
   внешний контейнер уже отделил содержимое от края экрана.
   ───────────────────────────────────────────────────────────────────────────── */
@media (max-width: 767px){
  .wrap{ padding-inline: 12px; }
  .admins-form{ padding: 14px 12px; }
  .orgsum__cell{ padding: 9px 8px; }
  .orc-stat{ padding: 9px 10px; }
  .jrow{ padding: 10px 12px; }
  .keybox{ padding: 9px 10px; }
  /* Пустое состояние: вертикальный воздух оставляем (он тут и есть сообщение),
     срезаем только боковой — текст в нём переносился по три слова в строку. */
  .dtable-empty{ padding-inline: var(--sp-3); }
}

/* ── Журнал помощника (GS-61): вкладка «Помощник» ───────────────────────────
   Строки — <details>: вопросы читаются списком, ответ разворачивается по
   клику. Тон строки («без ответа» — жёлтая полоса, «плохая оценка» —
   красная) — слева, по тому же правилу, что is-danger у jrow: при прокрутке
   ищут пятно, а не текст. */
/* Переключатель вида внутри вкладки «Помощник» — ряд sc-tab (см. шаблон),
   отделённый от ленты воздухом. Своих цветов не заводит: вид берётся от
   sc-tab, иначе два ряда вкладок на одном экране разъехались бы. */
.aviews{ margin-bottom: 12px; }
.arow{ border-bottom: 1px solid var(--line); }
.arow:last-child{ border-bottom: 0; }

/* Строка — ВЕРТИКАЛЬНЫЙ стек «шапка → вопрос», а не три колонки в ряд.
   Колонками вопрос зажимался между неразрывным временем и метками, и на
   узком экране ему доставалось несколько знаков ширины — текст ломался по
   букве в строку (замечание принципала 19.08.2026). В стеке вопрос всегда
   получает всю ширину, а метки живут своей строкой и переносятся целиком. */
.arow__sum{
  display: flex; flex-direction: column; gap: 4px;
  padding: 10px 12px; cursor: pointer; list-style: none;
}
.arow__sum::-webkit-details-marker{ display: none; }
.arow__sum:hover, .arow[open] > .arow__sum{ background: var(--c-surface-2); }
.arow.is-gap{ box-shadow: inset 3px 0 0 var(--c-warn); }
.arow.is-bad{ box-shadow: inset 3px 0 0 var(--c-danger); }
/* Шапка строки: время слева, признаки справа. flex-wrap, а не nowrap —
   организация с длинным именем на телефоне обязана переноситься, а не
   выдавливать соседей за край. */
.arow__meta{
  display: flex; flex-wrap: wrap; gap: 4px 10px;
  align-items: center; justify-content: space-between;
}
.arow__time{
  color: var(--faint); font-size: 12.5px; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.arow__count{
  font-family: var(--font-mono); font-weight: 600;
  color: var(--c-gold-strong); white-space: nowrap;
}
/* overflow-wrap вместо word-break: длинные слова (адрес, «ВКонтакте?»)
   переносятся только когда иначе не влезают, а обычный текст рвётся по
   пробелам. word-break: break-word рубил по букве в любой тесноте. */
.arow__q{
  color: var(--ink); font-weight: 500;
  overflow-wrap: anywhere; hyphens: auto;
}
.arow__side{ display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.arow__org{ color: var(--c-ink-2); font-size: 12.5px; }
.arow__flag{
  font-size: 11.5px; padding: 1px 7px; border-radius: 999px;
  border: 1px solid var(--c-warn); color: var(--c-warn);
  white-space: nowrap;
}
.arow__rate{ display: flex; }
.arow__rate.is-up{ color: var(--c-gold-strong); }
.arow__rate.is-down{ color: var(--c-danger); }
.arow__body{ padding: 2px 12px 12px; }
/* Ответ приходит уже разметкой (фильтр |md), поэтому pre-wrap здесь не
   нужен — переносы делают сами <p>/<ul>. Предел строки в 72ch — читаемая
   длина; на узком экране его перебивает ширина самого экрана. */
.arow__answer{
  color: var(--c-ink-2); overflow-wrap: anywhere;
  max-width: 72ch; line-height: 1.55;
}
.arow__answer p{ margin: 0 0 8px; }
.arow__answer p:last-child{ margin-bottom: 0; }
.arow__answer ul{ margin: 0 0 8px; padding-left: 20px; }
.arow__answer li{ margin: 2px 0; }
.arow__answer strong{ color: var(--ink); font-weight: 600; }
.arow__answer code{
  font-family: var(--font-mono); font-size: 12.5px;
  color: var(--c-gold-strong);
}
.arow__facts{
  margin-top: 8px; color: var(--faint); font-size: 12.5px;
  font-family: var(--font-mono); overflow-wrap: anywhere;
}
.arow__samples{ margin: 0; padding-left: 18px; color: var(--c-ink-2); }
.arow__samples li{ margin: 2px 0; }

/* ── Вкладка «Оплаты» (GS-363): платёж строкой, стадии под раскрытием ─────── */
/* Строка — сетка из четырёх смысловых блоков: когда · кто · за что · сколько.
   Именно сетка, а не flex-ряд: суммы сравнивают глазами по столбцу, и
   плавающая колонка это сравнение ломает. На узкой ширине сетка складывается
   в стек (медиазапрос ниже), где столбец теряет смысл, но появляется место.

   🔴 КОЛОНОК РОВНО ЧЕТЫРЕ — ПО ЧИСЛУ БЛОКОВ. На трёх колонках сумма
   переносилась во вторую строку сетки и вставала под временем, у левого края:
   колонка сумм переставала существовать ровно там, ради чего заведена
   (замер в браузере 10.09.2026 — .prow__sum-v уезжал на y+48 и в x=659). */
.prow{ border-bottom: 1px solid var(--line); }
.prow:last-child{ border-bottom: 0; }
.prow__sum{
  display: grid; gap: 4px 14px; align-items: center;
  grid-template-columns: minmax(0, auto) minmax(0, 1.2fr) minmax(0, auto) auto;
  padding: 10px 12px; cursor: pointer; list-style: none;
}
.prow__sum::-webkit-details-marker{ display: none; }
.prow__sum:hover, .prow[open] > .prow__sum{ background: var(--c-surface-2); }
/* Зависший заказ — полосой слева, как «пробел» у помощника. Цвет не
   единственный признак: в самой строке стоит «!» перед состоянием, а над
   списком — объяснение словами. */
.prow.is-stuck{ box-shadow: inset 3px 0 0 var(--c-warn); }
.prow__meta{ display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.prow__time{
  color: var(--faint); font-size: 12.5px; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* Состояние — словом, а не только цветом: на телефоне и при дальтонизме
   оттенок не читается (правило холдинга, канон П13). */
.prow__state{
  font-size: 11.5px; padding: 1px 8px; border-radius: 999px;
  align-self: flex-start; white-space: nowrap;
}
/* 🔴 ЗЕЛЁНЫЙ ЗДЕСЬ СВОЙ, А НЕ --c-success. Замер в браузере (10.09.2026):
   #16A34A на своей же подложке даёт контраст 3.02 при норме 4.5 — состояние
   «Оплачен» читалось бы хуже прочих ровно на светлой теме, самой ходовой.
   #166534 на том же фоне даёт 6.53.

   Общий --c-success не трогаем намеренно: он стоит на десятке экранов (та же
   беда у «доставлено» во вкладке «Почта»), и правка токена — отдельное
   решение с проверкой всех мест, а не побочный эффект новой вкладки.
   На тёмных темах фон другой, и штатный токен там проходит с запасом. */
.prow__state.paid{ color: #166534; background: var(--c-success-bg); }
:root[data-theme="dark"] .prow__state.paid,
:root[data-theme="night"] .prow__state.paid{ color: var(--c-success); }
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .prow__state.paid{ color: var(--c-success); }
}
.prow__state.pending{ color: var(--c-warn); background: var(--c-warn-bg); }
.prow__state.failed{ color: var(--c-danger); background: var(--c-danger-bg); }
.prow__who{ display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* min-width:0 у ячеек сетки обязателен вместе с overflow-wrap: без него
   длинная почта плательщика распирает колонку и выдавливает сумму за край. */
.prow__org{ color: var(--ink); font-weight: 500; overflow-wrap: anywhere; }
.prow__payer{
  color: var(--c-ink-3); font-size: 12.5px; overflow-wrap: anywhere;
}
.prow__what{
  display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: center;
  min-width: 0;
}
.prow__plan{ color: var(--c-ink-2); font-size: 13px; }
.prow__promo{
  font-size: 11.5px; padding: 1px 7px; border-radius: 999px;
  border: 1px solid var(--c-line); color: var(--c-gold-strong);
  font-family: var(--font-mono); white-space: nowrap;
}
/* tabular-nums — ради того же сравнения по столбцу: пропорциональные цифры
   дают разную ширину у 1 и 8, и колонка сумм перестаёт читаться рядами. */
.prow__sum-v{
  font-family: var(--font-mono); font-weight: 600; color: var(--ink);
  white-space: nowrap; font-variant-numeric: tabular-nums;
  justify-self: end;
}
/* Полная цена до скидки (GS-370): второй строкой под уплаченной суммой,
   зачёркнутая и приглушённая. Именно вторым уровнем, а не рядом: уплаченное —
   главный факт строки, и две цифры в одну линию спорили бы за внимание. */
.prow__sum-was{
  display: block; font-size: 11.5px; font-weight: 400;
  color: var(--muted); text-decoration: line-through;
  text-decoration-thickness: 1px; white-space: nowrap;
}
.prow__body{ padding: 2px 12px 12px; }

/* Цепочка стадий: заказ → зачисление → письмо. Список, а не таблица: стадий
   три, у каждой два поля, и таблица дала бы шапку длиннее содержимого. */
.pchain{
  list-style: none; margin: 0 0 10px; padding: 0;
  display: flex; flex-wrap: wrap; gap: 8px 18px;
}
.pchain__i{
  display: flex; flex-direction: column; gap: 2px;
  padding-left: 14px; position: relative; min-width: 0;
}
/* Точка стадии: пустая — не случилось, залитая — состоялось. Рядом всегда
   стоит время либо слово («ожидается», «неизвестно»), поэтому кружок только
   помогает взгляду, а не несёт факт в одиночку. */
.pchain__i::before{
  content: ""; position: absolute; left: 0; top: 5px;
  width: 8px; height: 8px; border-radius: 50%;
  border: 1.5px solid var(--c-line); background: transparent;
}
.pchain__i.is-done::before{
  background: var(--c-success); border-color: var(--c-success);
}
.pchain__i.is-unknown::before{ border-style: dashed; }
.pchain__k{ color: var(--c-ink-2); font-size: 12.5px; }
.pchain__at{
  color: var(--ink); font-size: 13px; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.pchain__at.is-muted{ color: var(--c-ink-4); font-style: italic; }

.prow__facts{
  display: flex; flex-wrap: wrap; gap: 4px 16px;
  color: var(--faint); font-size: 12.5px; overflow-wrap: anywhere;
}
.prow__facts code{
  font-family: var(--font-mono); color: var(--c-ink-2);
  overflow-wrap: anywhere;
}
.prow__facts .is-muted{ color: var(--c-ink-4); }
.prow__hint{
  margin-top: 8px; font-size: 12.5px; color: var(--c-warn);
  line-height: 1.5;
}

/* Заметка о зависших над списком и счётчик на самом корешке вкладки. */
.sec-note.is-warn{ color: var(--c-warn); }
.sc-tab__count.is-warn{
  background: var(--c-warn-bg); color: var(--c-warn);
}
.sc-tab[aria-selected="true"] .sc-tab__count.is-warn{
  background: var(--c-warn-bg); color: var(--c-warn);
}

@media (max-width: 640px){
  /* Отбор в одну колонку: на телефоне поля по 168px становились узкими
     парами, и подписи над ними переносились. */
  .jfilter .sc-field, .jfilter__grow{ flex: 1 1 100%; min-width: 0; }
  .jfilter__act{ margin-left: 0; width: 100%; }
  .jfilter__act .btn{ flex: 1 1 auto; }
  /* Тач-цель строки: 44px по правилу касания — раскрытие ответа это
     основное действие в разделе, и промахиваться по нему нельзя. */
  .arow__sum{ padding: 12px; min-height: 44px; }
  /* Две вкладки вида делят ширину поровну: так у каждой честная тач-цель, а
     ряд не сползает в прокрутку из-за счётчика у «Пробелов». */
  .aviews{ display: flex; }
  .aviews .sc-tab{ flex: 1 1 0; justify-content: center; }
  /* Платёж: сетка складывается в стек. Столбец сумм на 360px всё равно не
     собрать — три колонки там дают по 90px, где почта плательщика ломается
     по букве. Сумма уходит в шапку строки, к состоянию: это пара «сколько и
     чем кончилось», за которой в список и смотрят. */
  .prow__sum{ grid-template-columns: 1fr auto; padding: 12px; min-height: 44px; }
  .prow__meta{ grid-column: 1; grid-row: 1; }
  .prow__sum-v{ grid-column: 2; grid-row: 1; align-self: start; }
  .prow__who{ grid-column: 1 / -1; grid-row: 2; }
  .prow__what{ grid-column: 1 / -1; grid-row: 3; }
  /* Стадии в столбец: три штуки в ряд на телефоне переносились по одной и
     давали рваную лесенку с разной высотой строк. */
  .pchain{ flex-direction: column; gap: 8px; }
}

/* ── «Боты сейчас»: узлы и встречи (GS-314) ────────────────────────────────── */
/* Карточки узлов ПЕРЕД таблицей, а не вместо неё: главный вопрос экрана —
   «что идёт сейчас» (таблица), загрузка узлов — второй (решение владельца
   07.09.2026). Число узлов нигде не задано: сколько пришло, столько и лежит. */
.bnodes{
  display: flex; gap: 10px; flex-wrap: wrap; margin: 0 2px 16px;
}
.bnode{
  border: 1px solid var(--c-line); border-radius: var(--radius-sm);
  padding: 10px 13px; min-width: 190px; background: var(--c-surface);
  flex: 0 1 auto;
}
.bnode__top{ display: flex; align-items: center; gap: 7px; }
/* 🔴 ЦВЕТ НЕ ЕДИНСТВЕННЫЙ ПРИЗНАК: под точкой всегда стоит слово состояния
   (.bnode__state). На телефоне и при дальтонизме оттенок не читается. */
.bnode__dot{
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--c-success);
}
.bnode--warn .bnode__dot{ background: var(--c-warn-base); }
.bnode--down .bnode__dot{ background: var(--c-danger); }
.bnode__url{
  font-family: var(--font-mono); font-size: 13px; color: var(--c-ink-2);
  overflow-wrap: anywhere;
}
.bnode__state{ font-size: 13px; color: var(--c-ink-3); margin-top: 4px; }
.bnode--down .bnode__state{ color: var(--c-danger); }
.bnode__slots{
  margin-top: 4px; font-size: 13px; color: var(--c-ink-4);
  display: flex; gap: 6px; align-items: baseline;
}

/* Отбор экрана — тот же компонент, что в журнале (.jfilter), но без кнопки
   «Применить»: условия действуют сразу, потому что отбор идёт в браузере и
   перезагрузка страницы рвала бы живой поток. */
.bfilter{ margin-bottom: 12px; }

/* Состояния встречи бота. Своих восемь — словарь диспетчерской (.st--running,
   .st--ok) описывает состояния ПРОГОНА и с этими не совпадает ни одним именем.
   🔴 НЕ crimson: контраст 1.77 на тёмной теме — невидимая строка. Только токены
   продукта, они переопределены во всех трёх темах. */
.st--recording::before{ background: var(--c-danger); animation: orc-pulse 1.6s ease-in-out infinite; }
.st--recording{ color: var(--c-danger); }
.st--joining::before,
.st--uploading::before{ background: var(--c-gold); animation: orc-pulse 1.6s ease-in-out infinite; }
.st--joining, .st--uploading{ color: var(--c-gold-strong); }
.st--done::before{ background: var(--c-success); }
.st--done{ color: var(--c-ink-3); }
/* «Связь потеряна» — предупреждение, а не отказ: встреча может идти, а мы про
   неё не знаем. Отличать от failed обязательно, иначе живую встречу читают как
   упавшую. */
.st--unknown::before{ background: var(--c-warn-base); }
.st--unknown{ color: var(--c-warn); }

/* Комната бывает длинной ссылкой — переносим по символам, иначе строка распирает
   колонку и уводит таблицу в горизонтальную прокрутку. */
.bots__room{ overflow-wrap: anywhere; }
/* Чужая встреча (другой экземпляр Scribe на общем узле) — приглушена, но НЕ
   спрятана: молчание о ней читалось бы как потеря встречи. */
.bots__row--foreign td{ background: var(--c-surface-2); }

/* След встречи — раскрытием строки. Моноширинный, потому что читается как
   лента событий: взгляд идёт по левому краю времени. */
.bots__trailrow > td{ padding: 0; background: var(--c-surface-2); }
/* Отступы держат ВНУТРЕННИЕ блоки (.bfacts, .btrail__h, .btrail__steps), а не
   сам контейнер: иначе они складывались бы с его собственными и карточка
   уезжала бы вправо вдвое (GS-322). */
.btrail{ padding: 4px 0 8px; display: flex; flex-direction: column; gap: 0; }
.btrail__i{
  display: flex; gap: 10px; align-items: baseline; font-size: 13px;
  color: var(--c-ink-2);
}
.btrail__t{ color: var(--c-ink-4); flex: none; min-width: 52px; }
.btrail__e{ color: var(--c-ink); }
.btrail__d{ overflow-wrap: anywhere; }

/* Своя запись о встрече в карточке (GS-322): то, чего узел не знает —
   кто позвал, сколько шла, чем кончилась, где отчёт. Стоит ПЕРЕД ходом
   встречи: это ответ на «что это была за встреча», а ход — на «что с ней
   происходило». */
.bfacts{
  display: flex; flex-wrap: wrap; gap: 4px 22px;
  padding: 10px 12px 2px;
}
.bfacts__i{ display: flex; gap: 7px; align-items: baseline; font-size: 13px; }
.bfacts__l{ color: var(--c-ink-4); flex: none; }
.bfacts__v{ color: var(--c-ink-2); overflow-wrap: anywhere; }
a.bfacts__v{ color: var(--c-gold-strong); }

/* Заголовок ленты шагов — отделяет своё описание встречи от её хода. */
.btrail__h{
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .05em;
  text-transform: uppercase; color: var(--c-ink-4);
  padding: 8px 12px 4px;
}
.btrail__steps{ display: flex; flex-direction: column; gap: 4px; padding-bottom: 4px; }
.btrail__steps .btrail__i{ padding-inline: 12px; }
.btrail__steps .btrail__d{ padding-inline: 12px; }

@media (max-width: 720px){
  /* Узел на телефоне — во всю ширину: две карточки в ряд дают по 170px, и
     адрес узла в них переносится по три строки. */
  .bnode{ flex: 1 1 100%; min-width: 0; }
  /* Своя запись на телефоне — в столбик: пары «подпись: значение» в ряд
     сжимаются до нечитаемых колонок. */
  .bfacts{ flex-direction: column; gap: 4px; }
  /* След внутри карточки-строки: общие отступы строки ему мешают (та же
     правка, что у .runs__det выше). */
  .runs tbody tr.bots__trailrow{ padding: 0; }
  .btrail__i{ flex-wrap: wrap; gap: 2px 10px; }
}
