/* Кабинет Rechedar — единственная таблица стилей. Волна 5.5 «Живой
   кабинет» (ADR-007): JS-слой (htmx) включён, но инлайн-стили
   по-прежнему запрещены CSP style-src 'self' — инжект стилей
   индикаторов у htmx выключен (meta htmx-config), их стили живут
   здесь. Спокойная корпоративная палитра, аккуратные таблицы,
   print-стили для отчёта кампании. */

:root {
  color-scheme: light;
  --bg: #f7f8fa;
  --panel: #ffffff;
  --ink: #1a202c;
  --muted: #5a6779; /* ≥4.5:1 на белом — контраст AA для мелкого текста */
  --line: #e2e8f0;
  --accent: #2b6cb0;
  --accent-dark: #2c5282;
  --ok: #2f855a;
  --warn: #b7791f;
  --stop: #c53030;
  --radius: 6px;
  --code-bg: #edf2f7; /* code/pre.code — «плашки» моноширинного текста */
  --ctl-bg: #ffffff;  /* поля ввода и обычные кнопки */
  --focus: #bee3f8;   /* кольцо фокуса полей */
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 15px/1.55 -apple-system, "Segoe UI", Roboto, "PT Sans", Arial, sans-serif;
  color: var(--ink);
  background: var(--bg);
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
/* Ссылки в текстовых абзацах — всегда с подчёркиванием (WCAG 1.4.1:
   отличие от текста не только цветом; находка axe в обеих темах).
   UI-ссылки в таблицах/навигации и кнопкоподобные — без. */
p > a:not(.buttonlike) { text-decoration: underline; }

code { background: var(--code-bg); border-radius: 3px; padding: 1px 4px; font-size: 0.9em; }

/* --- шапка --- */

/* На узком экране шапка переносит строки: навигация прокручивается
   вбок, имя тенанта уходит вправо — вместо срезанной вёрстки 52px. */
.topbar {
  display: flex;
  align-items: center;
  gap: 12px 24px;
  flex-wrap: wrap;
  padding: 8px 20px;
  min-height: 52px;
  /* Своя переменная, не --accent-dark: та используется и кнопками
     primary, а шапке в тёмной теме положен свой фон (обзор 02.09:
     светло-синяя полоса выбивалась из тёмной палитры). */
  background: var(--topbar-bg, var(--accent-dark));
  color: #fff;
}

.brand { color: #fff; font-weight: 700; font-size: 17px; letter-spacing: 0.3px; }
.brand:hover { text-decoration: none; }

/* Липкая шапка только на десктопе (CU-21): там она одноэтажная. На узком
   экране шапка двухэтажная — липкость съедала бы четверть экрана. */
@media (min-width: 901px) {
  .topbar {
    position: sticky;
    top: 0;
    z-index: 20;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
  }
}

.mainnav {
  display: flex;
  gap: 4px;
  flex: 1;
  overflow-x: auto;
  scrollbar-width: thin;
}
.mainnav a {
  color: #cbd5e0;
  padding: 6px 12px;
  border-radius: var(--radius);
  white-space: nowrap;
}
.mainnav a:hover { color: #fff; background: rgba(255, 255, 255, 0.08); text-decoration: none; }
.mainnav a.active { color: #fff; background: rgba(255, 255, 255, 0.15); }

.who { display: flex; align-items: center; gap: 12px; font-size: 13px; margin-left: auto; flex-shrink: 0; }
.tenant { color: #e2e8f0; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.linklike {
  background: none;
  border: none;
  color: #cbd5e0;
  font: inherit;
  cursor: pointer;
  padding: 2px 4px;
  min-height: 24px; /* WCAG 2.5.8: область касания ≥ 24px */
}
.linklike:hover { color: #fff; text-decoration: underline; }

/* Переключатель темы (CU-41): в шапке выглядит как ссылка навигации,
   на странице входа (нет шапки) — кнопка-капсула под формой: заметный
   аффорданс, а не ссылка-невидимка (обзор 02.09). */
.theme-toggle { font-size: 13px; white-space: nowrap; }
.login-card .theme-toggle {
  display: inline-block;
  margin: 16px auto 0;
  padding: 8px 16px;
  min-height: 24px;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  background: var(--ctl-bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  text-decoration: none;
}
.login-card .theme-toggle:hover { border-color: var(--accent); text-decoration: none; }

.container { max-width: 1180px; margin: 24px auto 40px; padding: 0 20px; }

.footer {
  text-align: center;
  color: var(--muted);
  font-size: 12px;
  padding: 16px 0 28px;
}

/* --- вход --- */

.login-card {
  max-width: 380px;
  margin: 8vh auto 0;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 32px;
  text-align: center;
}
.login-brand { font-weight: 700; font-size: 20px; color: var(--accent); letter-spacing: 0.5px; }
.login-card h1 { font-size: 18px; margin: 8px 0 4px; }
.login-card form { text-align: left; margin-top: 16px; }
.login-card label { display: block; margin-bottom: 6px; }

/* --- типографика страниц --- */

h1 { font-size: 22px; margin: 0 0 16px; }
h2 { font-size: 16px; margin: 0 0 12px; }
h2.mt { margin-top: 20px; }
h3 { font-size: 14px; margin: 16px 0 8px; }

.muted { color: var(--muted); }
.center { text-align: center; }

.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.page-head h1 { margin: 0; }
.head-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* --- панели/карточки --- */

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 16px;
}

.grid2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-bottom: 16px;
}
/* Широкое содержимое ячейки (таблица с nowrap, длинный UUID) не должно
   растягивать трек сетки за ширину экрана — минимальная ширина ячейки
   по умолчанию auto = min-content содержимого. */
.grid2 > * { min-width: 0; }
@media (max-width: 900px) { .grid2 { grid-template-columns: 1fr; } }

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}
.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px;
  text-align: center;
}
.card .num { font-size: 22px; font-weight: 700; }
.card .lbl { font-size: 12px; color: var(--muted); margin-top: 2px; }

/* --- таблицы --- */

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel);
  font-size: 14px;
}
.panel > table { background: none; }
th, td {
  text-align: left;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
th { color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.4px; }
tr:last-child td { border-bottom: none; }
.table-scroll { overflow-x: auto; }
.num-col { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
table.compact th, table.compact td { padding: 5px 10px; }

/* SVG-графики серверной генерации: сжимаются пропорционально узкому
   экрану (viewBox в разметке), но не растягиваются сверх замысла. */
.panel svg, .report svg { max-width: 100%; height: auto; }

/* --- статусы --- */

.status {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 12px;
  background: #edf2f7;
  white-space: nowrap;
}
.st-running, .st-active { background: #c6f6d5; color: #22543d; }
.st-paused { background: #feebc8; color: #7b341e; }
.st-stopped, .st-failed, .st-incomplete { background: #fed7d7; color: #742a2a; }
.st-completed { background: #bee3f8; color: #2a4365; }
.st-draft { background: #e2e8f0; color: #4a5568; }
.st-archived { background: #edf2f7; color: var(--muted); }

/* --- формы --- */

label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 4px; }
input[type="text"], input[type="password"], select {
  font: inherit;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--ctl-bg);
  color: var(--ink);
  min-width: 0;
}
input:focus, select:focus { outline: 2px solid var(--focus); border-color: var(--accent); }

button, .buttonlike {
  font: inherit;
  padding: 7px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--ctl-bg);
  color: var(--ink);
  cursor: pointer;
  display: inline-block;
}
button:hover, .buttonlike:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
/* Primary — и <button>, и ссылки-кнопки <a class="buttonlike primary">:
   селектор только по button оставлял ссылку с фоновой заливкой .buttonlike
   (в тёмной теме — тёмный текст #101a26 на #262d3a, контраст 1.26; поймал
   axe на CTA вертикалей M4.2). При синхронизации копии с кабинетом
   перенести и туда. */
button.primary, a.buttonlike.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
button.primary:hover, a.buttonlike.primary:hover { background: var(--accent-dark); color: #fff; }
button.small, .small.buttonlike { padding: 4px 10px; font-size: 13px; }
button.go, .buttonlike.go { background: var(--ok); border-color: var(--ok); color: #fff; }
button.go:hover, .buttonlike.go:hover { background: #276749; color: #fff; }
button.warn, .buttonlike.warn { background: #975a16; border-color: #975a16; color: #fff; }
button.warn:hover, .buttonlike.warn:hover { background: #744210; color: #fff; }
button.stop, .buttonlike.stop { background: var(--stop); border-color: var(--stop); color: #fff; }
button.stop:hover, .buttonlike.stop:hover { background: #9b2c2c; color: #fff; }

.inline { display: inline-block; margin: 0; }
.actions { white-space: nowrap; }
.actions form { margin-right: 6px; }
.actions a { margin-right: 6px; }

/* Страница подтверждения (CU-13): кнопки в один ряд с отступом от таблицы. */
.confirm-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 16px 0 8px; }

.filters {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.filters.panel { padding: 12px 16px; }
.filters label { margin-bottom: 0; }

/* Строка «Показаны X–Y из N» над таблицей звонков (CU-16). */
.count-note { margin: 0 0 8px; font-size: 13px; }

/* Кликабельные строки таблиц (обзор 02.09): JS ведёт строку в карточку
   целиком (tr[data-href]); без JS работает ссылка в ячейке. */
tr[data-href] { cursor: pointer; }
tr[data-href]:hover td { background: color-mix(in srgb, var(--accent) 6%, transparent); }
:root.theme-dark tr[data-href]:hover td { background: color-mix(in srgb, var(--accent) 10%, transparent); }

/* Значок «память об абоненте» рядом с номером: ссылка в текстовом блоке
   обязана различаться не только цветом (WCAG 1.4.1, axe link-in-text-block
   на тёмной теме — прогон 02.09). */
td .memlink { text-decoration: underline; text-underline-offset: 2px; }

/* Diff версий сценария (CU-64): знак-носитель смысла (−/+) плюс цвет,
   подчёркивание на изменённых строках — нецветовое различие (WCAG 1.4.1). */
table.diff code { white-space: pre-wrap; }
table.diff tr.diff-del td { background: rgba(197, 48, 48, 0.12); }
table.diff tr.diff-add td { background: rgba(47, 133, 90, 0.12); }
:root.theme-dark table.diff tr.diff-del td { background: rgba(229, 121, 127, 0.14); }
:root.theme-dark table.diff tr.diff-add td { background: rgba(95, 191, 143, 0.14); }
table.diff tr.diff-del .diff-sign { font-weight: 700; color: var(--stop); }
table.diff tr.diff-add .diff-sign { font-weight: 700; color: var(--ok); }
table.diff tr.diff-del td:last-child code { text-decoration: line-through; }
table.diff td.diff-sign { width: 1.6em; text-align: center; }

/* Переключалка сортировки ссылками (BR-20, «Контакты с фактами»):
   активный режим — <strong>, альтернативный — ссылка. */
.sortbar { margin: 0 0 8px; font-size: 13px; }
.sortbar strong { font-weight: 600; }

.login-form input, .import-form input, .kb-form input, .optout-form input, .settings-form input[type="email"] { width: 100%; margin-bottom: 12px; }
/* Многострочные тексты (фразы, промпты, YAML-документ) — во всю ширину:
   без правила textarea жил браузерным дефолтом ~20 символов — «крошечное
   окошко» (замечание владельца, обзор редактора 02.09). */
.kb-form textarea {
  width: 100%;
  margin-bottom: 12px;
  resize: vertical;
  min-height: 7em;
  padding: 8px;
  font: inherit;
  line-height: 1.45;
}
.kb-form textarea.code { min-height: 24em; }
/* Чекбоксы не растягиваем правилом выше (обзор 02.09: галочки шапки
   редактора уезжали в центр формы, подписи — к правому краю). */
.login-form input[type="checkbox"], .import-form input[type="checkbox"],
.kb-form input[type="checkbox"], .optout-form input[type="checkbox"] {
  width: auto; margin: 0;
}
.import-form input[type="file"], .kb-form input[type="file"] { padding: 6px; }
/* Кнопка выбора файла в стиле остальных кнопок (иначе — системная). */
input[type="file"]::file-selector-button {
  font: inherit;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--ctl-bg);
  color: var(--ink);
  cursor: pointer;
  margin-right: 10px;
}
input[type="file"]::file-selector-button:hover { border-color: var(--accent); color: var(--accent); }
.kb-form select { width: 100%; margin-bottom: 12px; }
.optout-form { display: flex; gap: 12px; align-items: end; flex-wrap: wrap; }
.optout-form input { margin-bottom: 0; }

/* --- настройки уведомлений (T-79) --- */

.settings-form fieldset.events { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 14px; margin: 0 0 12px; }
.settings-form fieldset.events legend { font-size: 13px; color: var(--muted); padding: 0 6px; }
label.check { display: flex; gap: 10px; align-items: flex-start; padding: 6px 0; font-size: 14px; cursor: pointer; }
label.check input { width: auto; margin: 4px 0 0; }
.test-form { margin-top: 8px; padding-top: 12px; border-top: 1px dashed var(--border); }

/* --- свойства (dl) --- */

dl.props { display: grid; grid-template-columns: 180px 1fr; gap: 4px 12px; margin: 0; font-size: 14px; }
dl.props dt { color: var(--muted); }
dl.props dd { margin: 0; overflow-wrap: anywhere; }
@media (max-width: 640px) {
  dl.props { grid-template-columns: 1fr; }
  dl.props dt { margin-top: 6px; }
}

/* --- служебное --- */

/* Визуально скрытый, но читаемый скринридерами текст (caption таблиц). */
.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;
}

/* Видимый фокус с клавиатуры — для навигации без мыши (a11y). */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Якорные прыжки (#node-… редактора, #rec-… записей) не должны
   приземляться под липкую шапку — WCAG 2.4.11 Focus Not Obscured
   (шапка 52px + запас). */
[id] { scroll-margin-top: 76px; }

/* --- уведомления --- */

.notice { padding: 10px 14px; border-radius: var(--radius); margin-bottom: 16px; font-size: 14px; }
.notice.ok { background: #c6f6d5; color: #22543d; }
.notice.err { background: #fed7d7; color: #742a2a; }
.notice.warn { background: #feebc8; color: #7b341e; }

/* --- пагинация --- */

.pager { display: flex; justify-content: space-between; margin-top: 12px; }

/* --- анкета кампании (BR-25) --- */

/* Переключатель «все вопросы / по версиям» — крупные табы, работают и
   без JS (обычные ссылки). */
.tabs { display: flex; gap: 4px; margin: 12px 0; }
.tab {
  display: inline-flex; align-items: center; min-height: 24px;
  padding: 6px 14px; border: 1px solid var(--line); border-radius: 8px;
  text-decoration: none; color: var(--muted);
}
.tab:hover { border-color: var(--accent); color: var(--fg); }
.tab[aria-selected="true"] { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }

/* Чипы версий сценария в режиме «по версиям». */
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 12px; }
.chip {
  display: inline-flex; align-items: center; min-height: 24px;
  padding: 4px 12px; border: 1px solid var(--line); border-radius: 999px;
  text-decoration: none; color: var(--fg); font-size: 0.92em;
}
.chip:hover { border-color: var(--accent); }
.chip.cur { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }

/* Колонка-вопрос: длинные подписи эллипсисом, полное имя узла — в title. */
table.crosstab th.q-col { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- транскрипт --- */

.transcript { display: flex; flex-direction: column; gap: 10px; }
.utter { max-width: 78%; border-radius: var(--radius); padding: 8px 12px; }
.u-user { align-self: flex-start; background: #edf2f7; }
.u-bot { align-self: flex-end; background: #bee3f8; }
/* Решение робота (вызов инструмента из llm_response, не озвучивается):
   пунктирная рамка вместо заливки — визуально «служебная» запись, не
   реплика диалога; текст моноширинный, как у кодовых плашек. */
.u-tool { align-self: flex-end; background: none; border: 1px dashed var(--line); }
.u-tool .u-text { font-family: ui-monospace, monospace; font-size: 13px; color: var(--muted); }
/* Мета реплики (время/роль): 11px на пастельных фонах реплик — цвет
   темнее muted, иначе контраст < 4.5 (находка axe, CU-44). */
.u-meta { font-size: 11px; color: #4a5568; margin-bottom: 2px; }
.u-text { white-space: pre-wrap; overflow-wrap: anywhere; }
/* Прерванная реплика бота (BR-27): хвост, не успевший прозвучать
   (перебит barge-in'ом), — приглушённый курсив; в мете — бейдж
   «перебито» с окном звучания. Реплика перестала выпадать из
   транскрипта: видно и что бот говорил, и где его оборвали. */
.u-barged .u-tail { opacity: 0.55; font-style: italic; }
.u-int { color: var(--muted); }

/* Плеер-остров (волна 5.5, CU-37): активная реплика отмечается левой
   акцентной чертой (не цветом фона — читается при любой дальтонизации);
   кликабельность реплик существует только в JS-режиме (.js на <html>). */
.js .utter[data-ts] { cursor: pointer; }
.utter.u-active { box-shadow: inset 3px 0 0 var(--accent); }
.utter:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* --- записи --- */

.rec { margin-bottom: 12px; }
.rec-name { font-size: 13px; margin-bottom: 4px; }
audio { width: 100%; }

/* Сведённый трек — основной (BR-19): чуть крупнее имя, осциллограмма
   над плеером. Клик по столбику = переход к моменту (ссылка ?t=). */
.rec-main .rec-name { font-size: 14px; font-weight: 600; }
.hint { font-size: 12px; margin: 2px 0 6px; }
svg.wave { display: block; width: 100%; height: auto; margin-bottom: 6px; }
svg.wave a { outline: none; }
/* Hover — акцентный токен, а не --accent-dark: в тёмной теме
   --accent-dark — это фон шапки (#2c5282), на тёмной панели столбик
   стал бы темнее фона и hover-фидбек пропадал (ревью этапа 5). */
svg.wave a:hover rect { fill: var(--accent); fill-opacity: 1; }
/* Прослушанная часть осциллограммы (CU-41): класс ставит waveform.go
   и JS-плеер, цвет — токен, в обеих темах акцентный. */
svg.wave .wv-done { fill: var(--accent); fill-opacity: 1; }

/* Ролевые треки свёрнуты в раскрывающийся блок. */
details.rec-details {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 8px 12px;
  margin: 10px 0 12px;
}
details.rec-details > summary { cursor: pointer; font-weight: 600; font-size: 14px; }
details.rec-details[open] > summary { margin-bottom: 10px; }

/* --- галерея шаблонов (T-87): текст YAML --- */

pre.code {
  background: var(--code-bg); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 14px; font-size: 13px; line-height: 1.45;
  max-height: 30em; overflow: auto; white-space: pre;
}

/* --- редактор сценариев (T-88) --- */

.editor-checks { display: flex; flex-direction: column; gap: 6px; margin: 10px 0; }
.editor-checks label, label.inline { display: inline-flex; align-items: center; gap: 8px; font-weight: 400; }
textarea.code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; white-space: pre; overflow-wrap: normal; }
ul.diag { list-style: none; padding-left: 0; }
ul.diag li { padding: 6px 10px; border-radius: var(--radius); margin-bottom: 6px; font-size: 14px; }
ul.diag li.d-error { background: #fed7d7; color: #742a2a; }
ul.diag li.d-warning { background: #feebc8; color: #7b341e; }

/* --- отчёт --- */

.report { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 24px 28px; }
.report-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.report-foot { margin-top: 24px; color: var(--muted); font-size: 12px; border-top: 1px solid var(--line); padding-top: 8px; }

@media print {
  body { background: #fff; font-size: 12px; }
  .topbar, .footer, .no-print, .pager { display: none !important; }
  .container { max-width: none; margin: 0; padding: 0; }
  .report { border: none; padding: 0; }
  .panel { border: none; padding: 0; }
  /* Горизонтальная прокрутка в печати не работает — таблица целиком. */
  .table-scroll { overflow: visible; }
  h1 { font-size: 18px; }
  h2 { font-size: 14px; page-break-after: avoid; }
  table { font-size: 12px; }
  tr, .panel, .grid2 { page-break-inside: avoid; }
}

/* --- волна 5.5: индикаторы и скелетоны (CU-25) ----------------------- */

/* Глобальная полоска прогресса: htmx вешает класс htmx-request на body
   при любом запросе — элемент с классом htmx-indicator проявляется.
   Стили здесь, а не инжектятся htmx: CSP style-src 'self'. */
.htmx-indicator { opacity: 0; transition: opacity 0.15s ease-in; }
body.htmx-request .htmx-indicator { opacity: 1; }
.global-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 60;
  background: var(--accent);
  background-image: linear-gradient(90deg, transparent, var(--accent), transparent);
  animation: skel-slide 1s linear infinite;
  pointer-events: none;
}

/* Приглушение списка при частичном обновлении (CU-25, тройное ревью
   этапов 0–1): hx-swap=outerHTML оставляет прежние строки видимыми до
   подмены — скелетоны не нужны, вместо них список затухает и перестаёт
   принимать клики, пока идёт запрос; глобальная полоска сверху даёт
   понять, что это ожидание, а не результат. */
#listwrap { transition: opacity 0.15s ease; }
body.htmx-request #listwrap { opacity: 0.45; pointer-events: none; }

@keyframes skel-slide { from { transform: translateX(-100%); } to { transform: translateX(100%); } }

/* Блок в состоянии фоновой догрузки (htmx ставит aria-busy сам при
   hx-indicator; вручную — на время островковых обновлений). */
[aria-busy="true"] { cursor: progress; }

/* --- волна 5.5, этап 1: пейджер с номерами, диалог, тосты, копирование --- */

/* Пейджер (CU-29): стрелки + номера страниц с гэпами «…». Прежний
   space-between растягивал две стрелки по краям — с номерами списку
   нужен единый поток с переносом на узких экранах. */
.pager { display: flex; align-items: center; flex-wrap: wrap; gap: 4px; margin-top: 12px; }
.pager a, .pager span.gap {
  min-width: 26px; padding: 3px 8px; border-radius: var(--radius);
  font-size: 13px; text-align: center; border: 1px solid transparent;
  /* inline-flex, чтобы min-height сработал: у inline-боксов высоту
     задать нельзя — WCAG 2.5.8 Target Size ≥ 24px. */
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 24px;
}
.pager a { border-color: var(--line); }
.pager a:hover { border-color: var(--accent); }
.pager a.cur { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
.pager span.gap { color: var(--muted); border-color: transparent; }

/* Диалог подтверждения (CU-28): один на страницу в лейауте, содержимое
   подставляет app.js. ::backdrop затемняет фон, showModal держит
   фокус-ловушку и Esc. */
dialog.dlg {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel); color: var(--ink);
  padding: 20px 22px 16px; max-width: 26em; box-shadow: 0 12px 40px rgba(0,0,0,0.25);
}
dialog.dlg::backdrop { background: rgba(26, 32, 44, 0.45); }
dialog.dlg p { margin: 0 0 16px; font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; }
.dlg-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* Тосты (CU-28): статус у нижнего края поверх всего, читается
   скринридером через aria-live=polite контейнера. */
.toasts {
  position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  z-index: 70; pointer-events: none; max-width: min(90vw, 30em);
}
.toast {
  background: #2d3748; color: #fff; font-size: 14px;
  padding: 9px 16px; border-radius: var(--radius);
  box-shadow: 0 6px 24px rgba(0,0,0,0.3);
  opacity: 1; transition: opacity 0.3s ease, transform 0.3s ease;
}
.toast.err { background: #9b2c2c; }
.toast.gone { opacity: 0; transform: translateY(8px); }

/* Кнопки копирования (CU-30): скрыты без JS (clipboard требует скрипта),
   с JS — компактный глиф рядом со значением. */
.copybtn {
  display: none; align-items: center; justify-content: center;
  width: 24px; height: 24px; margin-left: 6px; padding: 0;
  border: 1px solid var(--line); border-radius: 6px;
  background: transparent; color: var(--muted);
  font-size: 13px; line-height: 1; cursor: pointer; vertical-align: middle;
}
.copybtn:hover { border-color: var(--accent); color: var(--accent); }
.js .copybtn { display: inline-flex; }
.sr-only-copy { position: fixed; left: -9999px; top: 0; }

@media print { .toasts, .copybtn { display: none !important; } }

/* --- волна 5.5, этап 2: живая карточка, лента звонков, бейджи (CU-31…CU-34) --- */

/* Полоса живого блока карточки кампании (CU-32): статус, действия и
   метка автообновления в одну строку; сам блок #livecard — цель
   JS-поллинга, при замене фрагмента мигания нет (данные идут те же). */
.live-strip {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  margin: 14px 0;
}
.live-strip .status { margin-right: 4px; }
.live-hint { color: var(--muted); font-size: 12.5px; }

/* Кнопки в состоянии «действие ушло» (CU-34): гаснут и не кликабельны,
   пока оптимистичный POST не завершится (успех — reload, сбой — откат). */
a.buttonlike.busy { pointer-events: none; opacity: 0.45; }

/* Статус-бейджи звонков (CU-33): преаттентивный значок перед подписью.
   Цвет — не единственный носитель смысла: значок различается формой,
   рядом полный текст статуса. «Живые» статусы слегка пульсируют. */
.cbadge {
  display: inline-block; width: 1.35em; text-align: center;
  font-weight: 700; font-size: 13px;
}
.cb-queued { color: #718096; }
.cb-dialing, .cb-ringing, .cb-in_progress { animation: cbpulse 1.6s ease-in-out infinite; }
.cb-dialing { color: #b7791f; }
.cb-ringing { color: #2b6cb0; }
.cb-in_progress { color: #2c7a7b; }
.cb-completed { color: #276749; }
.cb-incomplete { color: #c05621; }
.cb-failed { color: #9b2c2c; }
.cb-busy { color: #6b46c1; }
.cb-no_answer { color: #4a5568; }
.cb-canceled { color: #a0aec0; }
.cb-unknown { color: #718096; }
@keyframes cbpulse { 50% { opacity: 0.45; } }

/* Значок статуса кампании (CU-43): внутри капсулы .st-*, цвет наследует. */
.campbadge { display: inline-block; width: 1.3em; text-align: center; font-weight: 700; }

/* Живая лента /calls (CU-33): бар с opt-in переключателем над таблицей;
   без JS скрыт целиком (лента требует скрипта). Активная лента —
   мигающая точка и нажатое состояние кнопки. */
.livefeed-bar { display: none; }
.js .livefeed-bar {
  display: flex; align-items: center; gap: 12px; margin: 0 0 12px;
}
.livefeed-bar button {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 14px; border: 1px solid var(--line); border-radius: 999px;
  background: transparent; font-size: 13.5px; cursor: pointer; color: inherit;
}
.livefeed-bar button:hover { border-color: var(--accent); }
.livefeed-bar button .dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: #a0aec0; flex: none;
}
.livefeed-bar button.on { border-color: var(--accent); color: var(--accent); font-weight: 600; }
.livefeed-bar button.on .dot { background: var(--accent); animation: cbpulse 1.6s ease-in-out infinite; }
.livefeed-bar .muted { font-size: 12.5px; }

/* Пульсация живых статусов и точки ленты выключается по системной
   настройке «уменьшить движение». */
@media (prefers-reduced-motion: reduce) {
  .cb-dialing, .cb-ringing, .cb-in_progress,
  .livefeed-bar button.on .dot { animation: none; }
}

@media print { .livefeed-bar, .live-hint { display: none !important; } }

/* --- Редактор сценариев: волна 5.5, этап 4 (CU-38…CU-40) ------------------- */

/* Индикатор живой сессии правки (CU-38): несохранённые правки, остаток
   сессии, время черновика. Тихая плашка; жёлтая — меньше 5 минут,
   красная — истекла. Создаётся JS-островом, без JS не существует. */
.ed-state {
  display: inline-block; padding: 4px 12px; margin-bottom: 12px;
  border-radius: 999px; background: #edf2f7; color: var(--muted);
  font-size: 12.5px;
}
.ed-state.warn { background: #feebc8; color: #7b341e; }
.ed-state.expired { background: #fed7d7; color: #742a2a; }

/* Бар восстановления черновика (CU-38): заметный, но не перекрывающий
   контент; создан JS-островом поверх класса notice warn. */
.ed-restore { display: block; }
.ed-restore button { margin-left: 6px; }

/* Подсказка валидации поля (CU-40): видна до отправки формы, создаётся
   JS-островом рядом с полем (aria-describedby). */
.field-err { color: var(--stop); font-size: 12.5px; margin: 2px 0 10px; }
input[aria-invalid="true"], textarea[aria-invalid="true"] {
  border-color: var(--stop);
}

/* Дерево узлов (CU-39): хендл перетаскивания существует только в JS-режиме
   (кнопки ↑/↓ — постоянная no-JS альтернатива, WCAG 2.5.7); переходы
   узла — компактные ссылки-стрелки. */
.drag-handle { display: none; cursor: grab; color: var(--muted); padding: 0 2px; }
.js .drag-handle { display: inline-block; }
.drag-handle:active { cursor: grabbing; }
td.ordcell { white-space: nowrap; width: 1%; }
td.ordcell form { margin-right: 2px; }
td.refs-cell .nref { display: inline-block; margin-right: 10px; white-space: nowrap; }
.sortable-ghost { opacity: 0.4; }

/* --- Тёмная тема (CU-41) ---------------------------------------------- */

/* Класс theme-dark на <html> ставит ранний theme-init.js (внешний
   скрипт в <head> — инлайн запрещён CSP): явный выбор из localStorage
   либо системная тёмная (prefers-color-scheme, matchMedia). Значения —
   те же токены, что и в светлой: компоненты выше их уже используют;
   цветные капсулы переопределены ниже парами фон/текст с контрастом AA.
   Системная тёмная БЕЗ JS не подхватывается (детект до CSS требует
   инлайн-скрипта, а дублировать палитру в @media — рассинхрон):
   без JS кабинет остаётся светлым — это презентационный слой, все
   действия работают (TestNoJSFallback). */
:root.theme-dark {
  color-scheme: dark; /* нативные контролы/скроллбары под тему */
  --bg: #141821;
  --panel: #1d232e;
  --ink: #e4e9f1;
  --muted: #9fabbf;
  --line: #333c4a;
  --accent: #7ab3e8;
  --accent-dark: #2c5282; /* кнопки primary — одинаковы в обеих темах */
  --topbar-bg: #1d2836;   /* шапка в тёмной теме — тёмная (обзор 02.09) */
  --ok: #5fbf8f;
  --warn: #d9a13f;
  --stop: #e5797f;
  --radius: 6px;
  --code-bg: #262d3a;
  --ctl-bg: #262d3a;
  --focus: #8fbcf0;
}

/* Цветные кнопки в тёмной теме несут светлую заливку — текст тёмный
   (белый на светлом акценте проваливал бы контраст). Покрыты ОБЕ
   формы кнопок: и <button>, и ссылки-кнопки .buttonlike — действия
   кампаний в таблицах рендерятся ссылками (баг поймал Lighthouse:
   белый текст на тёмном токене --ok, контраст 2.24). */
:root.theme-dark button.primary,
:root.theme-dark .buttonlike.primary,
:root.theme-dark button.go,
:root.theme-dark .buttonlike.go,
:root.theme-dark button.warn,
:root.theme-dark .buttonlike.warn,
:root.theme-dark button.stop,
:root.theme-dark .buttonlike.stop,
:root.theme-dark .pager a.cur { color: #101a26; }
/* Заливки — светлые токены темы: базовые правила кнопок выше
   переписали и тёмную ветку (#975a16 + тёмный текст = провал). */
:root.theme-dark button.go, :root.theme-dark .buttonlike.go { background: var(--ok); border-color: var(--ok); }
:root.theme-dark button.warn, :root.theme-dark .buttonlike.warn { background: var(--warn); border-color: var(--warn); }
:root.theme-dark button.stop, :root.theme-dark .buttonlike.stop { background: var(--stop); border-color: var(--stop); }
:root.theme-dark button.primary:hover,
:root.theme-dark .buttonlike.primary:hover { background: var(--accent); color: #101a26; }
:root.theme-dark button.go:hover,
:root.theme-dark .buttonlike.go:hover { background: var(--ok); color: #101a26; }
:root.theme-dark button.warn:hover,
:root.theme-dark .buttonlike.warn:hover { background: var(--warn); color: #101a26; }
:root.theme-dark button.stop:hover,
:root.theme-dark .buttonlike.stop:hover { background: var(--stop); color: #101a26; }

/* Капсулы статусов и уведомлений: те же смысловые цвета, пары
   тёмный фон / светлый текст (контраст AA). */
:root.theme-dark .status { background: #2a3240; color: var(--ink); }
:root.theme-dark .st-running, :root.theme-dark .st-active { background: #123527; color: #7fd6a8; }
:root.theme-dark .st-paused { background: #403013; color: #e6c07a; }
:root.theme-dark .st-stopped, :root.theme-dark .st-failed, :root.theme-dark .st-incomplete { background: #45201f; color: #ef9a9a; }
:root.theme-dark .st-completed { background: #16324e; color: #9cc6ec; }
:root.theme-dark .st-draft { background: #2b3442; color: #b6c0cf; }
:root.theme-dark .st-archived { background: #2a3240; color: var(--muted); }

:root.theme-dark .notice.ok { background: #123527; color: #7fd6a8; }
:root.theme-dark .notice.err { background: #45201f; color: #ef9a9a; }
:root.theme-dark .notice.warn { background: #403013; color: #e6c07a; }

/* Реплики транскрипта и диагностики редактора. */
:root.theme-dark .u-meta { color: var(--muted); }
:root.theme-dark .u-user { background: #262d3a; }
:root.theme-dark .u-bot { background: #1d3a5c; }
:root.theme-dark .u-tool { border-color: var(--line); }
:root.theme-dark .u-int { color: var(--muted); }
:root.theme-dark ul.diag li.d-error { background: #45201f; color: #ef9a9a; }
:root.theme-dark ul.diag li.d-warning { background: #403013; color: #e6c07a; }

/* Индикатор сессии редактора (CU-38). */
:root.theme-dark .ed-state { background: #2a3240; color: var(--muted); }
:root.theme-dark .ed-state.warn { background: #403013; color: #e6c07a; }
:root.theme-dark .ed-state.expired { background: #45201f; color: #ef9a9a; }

/* Значки статусов звонков (CU-33): средние по тону HEX светлой темы
   на тёмной панели теряли контраст — осветлены. */
:root.theme-dark .cb-queued { color: #9fabbf; }
:root.theme-dark .cb-dialing { color: #d9a13f; }
:root.theme-dark .cb-ringing { color: #7ab3e8; }
:root.theme-dark .cb-in_progress { color: #5fc9bd; }
:root.theme-dark .cb-completed { color: #63c790; }
:root.theme-dark .cb-incomplete { color: #e0955f; }
:root.theme-dark .cb-failed { color: #e5797f; }
:root.theme-dark .cb-busy { color: #a98fd8; }
:root.theme-dark .cb-no_answer { color: #b6c0cf; }
:root.theme-dark .cb-canceled { color: #8b98ab; }
:root.theme-dark .cb-unknown { color: #9fabbf; }

/* Тосты и фон диалога — те же тёмные плашки, добавлена кромка,
   чтобы не сливались с тёмной страницей. */
:root.theme-dark .toast { border: 1px solid #4a5568; }

/* Печать всегда светлая: тёмные поверхности на бумаге жгут тонер и
   не несут смысла — токены сбрасываются ПОСЛЕ тёмного блока, чтобы
   перебить класс (специфичность селекторов равна, решает порядок).
   Кроме токенов гасим и компонентные правила тёмной темы с литеральными
   цветами (капсулы/уведомления/бейджи): светлый текст вида #7fd6a8 на
   белом листе давал бы контраст ~1.8:1 (находка ревью этапа 5). */
@media print {
  :root, :root.theme-dark, :root.theme-light {
    color-scheme: light;
    --bg: #ffffff;
    --panel: #ffffff;
    --ink: #1a202c;
    --muted: #5a6779;
    --line: #e2e8f0;
    --code-bg: #edf2f7;
    --ctl-bg: #ffffff;
    --accent: #2b6cb0;
    --ok: #2f855a;
    --warn: #975a16;
    --stop: #c53030;
    --focus: #2b6cb0;
  }
  :root.theme-dark .status,
  :root.theme-dark .st-running, :root.theme-dark .st-active,
  :root.theme-dark .st-paused,
  :root.theme-dark .st-stopped, :root.theme-dark .st-failed, :root.theme-dark .st-incomplete,
  :root.theme-dark .st-completed,
  :root.theme-dark .st-draft,
  :root.theme-dark .st-archived,
  :root.theme-dark .notice.ok, :root.theme-dark .notice.err, :root.theme-dark .notice.warn,
  :root.theme-dark .u-user, :root.theme-dark .u-bot,
  :root.theme-dark ul.diag li.d-error, :root.theme-dark ul.diag li.d-warning,
  :root.theme-dark .ed-state,
  :root.theme-dark .ed-state.warn, :root.theme-dark .ed-state.expired {
    background: none;
    color: var(--ink);
  }
  /* Бейджи звонков (cb-*) в тёмной теме осветлены для панели — на белом
     листе гасим до чернильного: цвет статуса на бумаге не читается. */
  :root.theme-dark .cb-queued, :root.theme-dark .cb-dialing, :root.theme-dark .cb-ringing,
  :root.theme-dark .cb-in_progress, :root.theme-dark .cb-completed,
  :root.theme-dark .cb-incomplete, :root.theme-dark .cb-failed,
  :root.theme-dark .cb-busy, :root.theme-dark .cb-no_answer,
  :root.theme-dark .cb-canceled, :root.theme-dark .cb-unknown {
    color: var(--ink);
  }
}

/* --- Симулятор диалога (CU-67): панель прогона сценария текстом --- */
.sim-log {
  max-height: 380px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 6px 2px;
  margin-bottom: 12px;
}
.sim-msg { margin: 0; padding: 8px 12px; border-radius: var(--radius); max-width: 85%; font-size: 14px; }
.sim-who { display: block; font-size: 12px; opacity: .8; margin-bottom: 2px; }
.sim-options { margin: 6px 0 0; padding-left: 20px; font-size: 13px; color: var(--muted); }
.sim-form { display: flex; gap: 8px; }
.sim-form input[type="text"] { flex: 1; }

/* --- Организация и подсказки (CU-73/79, обзор 02.09) --- */
/* Единая строка хлебных крошек на вложенных экранах. */
.crumbs { margin: 0 0 10px; font-size: 13px; color: var(--muted); }
/* Подчёркивание обязательно (WCAG 1.4.1): отличие ссылки от текста
   не только цветом — axe link-in-text-block. */
.crumbs a { color: var(--accent); text-decoration: underline; }
.crumbs .crumb-sep { margin: 0 6px; opacity: .6; }
.crumbs [aria-current="page"] { color: var(--muted); }
/* Ссылки внутри определений .props (карточки кампаний/звонков) —
   с подчёркиванием: рядом есть текст, отличие не только цветом (WCAG). */
.props dd a { text-decoration: underline; }
/* Сворачиваемая подсказка: одна строка сути + «Подробнее» без JS. */
details.how { margin: 4px 0 0; }
details.how > summary {
  cursor: pointer;
  color: var(--accent);
  text-decoration: underline dotted;
  font-size: 13px;
  user-select: none;
}
details.how[open] > summary { margin-bottom: 6px; }
details.how > *:not(summary) { font-size: 14px; color: var(--ink); }
details.how.tech { margin-top: 10px; border-top: 1px solid var(--line); padding-top: 8px; }
/* fieldsets формы новой кампании (CU-82): в духе settings-form. */
.kb-form fieldset { border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 14px; margin: 4px 0 12px; }
.kb-form fieldset legend { font-size: 13px; color: var(--muted); padding: 0 6px; }
.inline-fields input { width: auto; }
/* Радио режима сценария входящей линии (BR-25.5): блоками, касание ≥24px. */
.kb-form label.radio { display: block; min-height: 24px; margin: 6px 0; }
.kb-form label.radio input { width: auto; margin-right: 6px; }
