/* ═══════════════════════════════════════════════════════════════════════
   Панель «Мои Небеса». Оформление.

   🔴 НИ ОДНОЙ СТРОЧКИ JAVASCRIPT В РАЗМЕТКЕ. Заголовок безопасности, который
   панель ставит сама (app/main.py, SECURITY_HEADERS), запрещает встроенные
   скрипты (script-src 'self'), и отказ у него тихий: обработчик просто не
   выполняется, ошибки нигде нет. Всё, что здесь выглядит интерактивным,
   сделано на CSS и <details>.

   🔴 И НИ ОДНОГО АТРИБУТА style= В ШАБЛОНАХ: `style-src 'self'` идёт без
   'unsafe-inline'. Всякое оформление — сюда, классом по смыслу; послабление
   в политике четыре атрибута однажды уже держали на всю панель.

   Имена классов сохранены все до единого — разметка не переписывалась,
   переписано оформление.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Токены ──────────────────────────────────────────────────────────── */
:root {
  color-scheme: light dark;

  /* Шкала отступов кратна 4 — так вертикальный ритм не расползается. */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px;

  --r-sm: 6px; --r-md: 10px; --r-lg: 14px; --r-full: 999px;

  --bg:        #f6f7f9;
  --bg-sunken: #eef0f4;
  --card:      #ffffff;
  --text:      #16181d;
  --text-soft: #4a5160;
  --muted:     #6d7482;
  --border:    #e3e6eb;
  --border-strong: #cdd2da;

  --accent:      #2f5fe0;
  --accent-soft: #eaf0ff;
  --accent-ink:  #1b3fa8;

  --ok:      #17864a;   --ok-soft:     #e4f6ec;
  --danger:  #c8322b;   --danger-soft: #fdeceb;
  --warn:    #a8650a;   --warn-soft:   #fdf3e3;
  --info:    #3b5bb5;   --info-soft:   #eaeffb;

  --shadow-1: 0 1px 2px rgba(16, 20, 30, .05);
  --shadow-2: 0 2px 8px rgba(16, 20, 30, .07);
  --shadow-3: 0 8px 28px rgba(16, 20, 30, .12);

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
          "Liberation Mono", monospace;
}

/* Тёмная тема появляется сама по настройке системы. Отдельного
   переключателя нет намеренно: он потребовал бы скрипта. */
@media (prefers-color-scheme: dark) {
  :root {
    --bg:        #0f1216;
    --bg-sunken: #0a0c0f;
    --card:      #171b21;
    --text:      #e8eaee;
    --text-soft: #b3b9c4;
    --muted:     #8b93a1;
    --border:    #262c35;
    --border-strong: #39414d;

    --accent:      #6f95ff;
    --accent-soft: #1b2436;
    --accent-ink:  #a8c0ff;

    --ok:      #4cc47f;   --ok-soft:     #12291d;
    --danger:  #f2756c;   --danger-soft: #2c1614;
    --warn:    #e0a34a;   --warn-soft:   #2a2113;
    --info:    #8aa6ea;   --info-soft:   #171e2e;

    --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-2: 0 2px 8px rgba(0, 0, 0, .45);
    --shadow-3: 0 8px 28px rgba(0, 0, 0, .55);
  }
}

/* ── Основа ──────────────────────────────────────────────────────────── */
* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.55 var(--font);
  font-variant-numeric: tabular-nums;   /* колонки чисел не пляшут */
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }

h1 { font-size: 26px; line-height: 1.2; letter-spacing: -.02em; margin: 0 0 var(--s4); }
h2 { font-size: 18px; line-height: 1.3; letter-spacing: -.01em; margin: var(--s6) 0 var(--s3); }
h3 { font-size: 15px; margin: 0 0 var(--s2); }

code, pre, .mono { font-family: var(--mono); font-size: .92em; }
code {
  background: var(--bg-sunken); border: 1px solid var(--border);
  padding: 1px 6px; border-radius: var(--r-sm);
}

.muted { color: var(--muted); font-weight: 400; }
.inline { display: inline-flex; align-items: center; gap: var(--s2); margin: 0; }
.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Видно только скринридеру — для подписей, которые глазами читаются
   из контекста, а на слух нет. */
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-sm); }

/* ── Верхняя панель ──────────────────────────────────────────────────── */
.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: var(--s5);
  padding: var(--s3) var(--s5);
  background: color-mix(in srgb, var(--card) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(10px);
  border-bottom: 1px solid var(--border);
}
.topbar .logo {
  font-weight: 650; letter-spacing: -.02em; color: var(--text);
  display: inline-flex; align-items: center; gap: var(--s2); white-space: nowrap;
}
.topbar .logo::before {
  content: ""; width: 10px; height: 10px; border-radius: 3px;
  background: linear-gradient(140deg, var(--accent), #7aa2ff);
}
.topbar nav {
  display: flex; align-items: center; gap: var(--s1);
  flex: 1; flex-wrap: wrap;
}
.topbar .nav-link {
  color: var(--text-soft); padding: 6px 12px; border-radius: var(--r-full);
  font-size: 14px; font-weight: 500; white-space: nowrap;
}
.topbar .nav-link:hover { background: var(--bg-sunken); color: var(--text); text-decoration: none; }
.topbar .nav-link[aria-current="page"] {
  background: var(--accent-soft); color: var(--accent-ink); font-weight: 600;
}
.topbar .nav-link.muted { color: var(--muted); }
/* Переключатель проектов. Отделён чертой от разделов намеренно: «в каком я
   проекте» и «в каком я разделе» — разные вопросы, и слипшись в одну строку
   они отвечались бы на глаз одинаково. Цена ошибки тут — деньги. */
.topbar .projects {
  flex: 0 0 auto; gap: var(--s1);
  padding-right: var(--s4); border-right: 1px solid var(--border);
}
.topbar .projects .project-current {
  background: var(--accent-soft); color: var(--accent-ink); font-weight: 650;
}
/* Всё, что после этого разделителя, прижимается вправо. */
.topbar .spacer { flex: 1; }
.user { display: inline-flex; align-items: center; gap: var(--s2); font-size: 14px; color: var(--text-soft); }
.user .role { color: var(--muted); font-size: 12px; }

/* Действие в ряду таблицы или в строке сведений. Раньше это был голый
   текст без границ: щёлкать было некуда, и от обычной ссылки такая кнопка
   не отличалась ничем. Теперь это тихая кнопка — форма есть, вес малый. */
.link {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 1px solid transparent; border-radius: var(--r-sm);
  color: var(--accent); cursor: pointer;
  padding: 3px 8px; margin: -3px -8px;
  font: inherit; font-size: 13px; line-height: 1.3; text-align: left;
  transition: background .12s, border-color .12s, color .12s;
}
.link:hover {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 24%, transparent);
  text-decoration: none; color: var(--accent-ink);
}
.link:active { transform: translateY(1px); }
button.link[disabled] {
  color: var(--muted); cursor: not-allowed; background: none; border-color: transparent;
}

/* ── Каркас ──────────────────────────────────────────────────────────── */
/* Полоса широкая: главное на этих страницах — таблицы в десять-двенадцать
   столбцов, и каждый отнятый пиксель они отыгрывают горизонтальной
   прокруткой. Тексту это не вредит: у него своя мера, .prose ограничивает
   строку 68 знаками независимо от полосы. */
main { max-width: 1560px; margin: var(--s5) auto var(--s7); padding: 0 var(--s5); }
@media (min-width: 1700px) { main { padding: 0 var(--s6); } }
.breadcrumb { color: var(--muted); font-size: 13px; margin: 0 0 var(--s3); }
.section { margin-bottom: var(--s6); }
.section h2 { margin-top: 0; }
.section-header {
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: var(--s2); margin-bottom: var(--s3);
}
.section-header h2 { margin: 0; }

/* ── Кнопки ──────────────────────────────────────────────────────────── */
/* 🔴 Базовый вид задан самому button, а не только особым классам. Прежде
   стиль получали лишь кнопки внутри .create-form и .login-card, а
   остальные — например, «Обновить кампании» — доставались браузеру как
   есть и выглядели чужеродно на своей же странице. */
button {
  font: inherit; font-size: 14px; line-height: 1.2;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  padding: 8px 14px; border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); background: var(--card); color: var(--text);
  cursor: pointer; transition: background .12s, border-color .12s, transform .12s;
}
button:hover:not([disabled]) { background: var(--bg-sunken); border-color: var(--muted); }
button:active:not([disabled]) { transform: translateY(1px); }
button[disabled] { opacity: .5; cursor: not-allowed; }

/* Видимый фокус нужен не только с клавиатуры: без него непонятно, какая
   кнопка сработает по Enter. */
button:focus-visible, a:focus-visible, summary:focus-visible,
input:focus-visible, select:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.btn-primary, .create-form button, .login-card button {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  padding: 9px 18px; border: 1px solid transparent; border-radius: var(--r-sm);
  background: var(--accent); color: #fff; font-weight: 550; cursor: pointer;
  box-shadow: var(--shadow-1); transition: background .12s, transform .12s;
}
.btn-primary:hover:not([disabled]),
.create-form button:hover, .login-card button:hover {
  background: var(--accent-ink); text-decoration: none;
}
.btn-primary:active:not([disabled]) { transform: translateY(1px); }
.btn-primary[disabled] { opacity: .5; cursor: not-allowed; box-shadow: none; }

.actions { margin-top: var(--s5); display: flex; gap: var(--s3); align-items: center; flex-wrap: wrap; }
.actions form, .actions details { margin: 0; }
.actions button, .section-header button, .bulk-bar button, .template-card button, .filters button {
  padding: 8px 14px; border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--card); color: var(--text); cursor: pointer; font-size: 14px;
  transition: background .12s, border-color .12s;
}
.actions button:hover, .section-header button:hover,
.bulk-bar button:hover, .template-card button:hover { background: var(--bg-sunken); }
.actions button.danger, button.danger {
  color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, transparent);
  background: var(--danger-soft);
}
.actions button[disabled], .section-header button[disabled],
.bulk-bar button[disabled], .template-card button[disabled] { opacity: .5; cursor: not-allowed; }

/* ── Сообщения ───────────────────────────────────────────────────────── */
/* Отдельной строкой badge превращается в полосу-сообщение: разметка их
   не различает, а смысл разный. */
p.badge {
  display: block; padding: var(--s3) var(--s4); border-radius: var(--r-md);
  font-size: 14px; font-weight: 450; line-height: 1.5; margin: 0 0 var(--s4);
  border: 1px solid var(--border);
}
p.badge.ok      { background: var(--ok-soft);     color: var(--ok);     border-color: color-mix(in srgb, var(--ok) 30%, transparent); }
p.badge.error   { background: var(--danger-soft); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 30%, transparent); }
p.badge.pending { background: var(--warn-soft);   color: var(--warn);   border-color: color-mix(in srgb, var(--warn) 30%, transparent); }
.warn {
  color: var(--warn); background: var(--warn-soft);
  border: 1px solid color-mix(in srgb, var(--warn) 30%, transparent);
  border-radius: var(--r-md); padding: var(--s3) var(--s4);
}
/* Предупреждения пробного прогона: стоят сразу под таблицей изменений, и
   отступ отделяет «что произойдёт» от «чем это грозит». Без него блок
   читается как последняя строка таблицы. */
.dry-run-warnings { margin-top: var(--s4); }

.error { color: var(--danger); margin: 0 0 var(--s3); }
.hint { color: var(--muted); font-size: 13px; margin: 0; }
.hint.busy { color: var(--warn); }

/* ── Метки состояния ─────────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: var(--r-full);
  font-size: 12px; font-weight: 550; line-height: 1.6;
  background: var(--bg-sunken); color: var(--text-soft);
  border: 1px solid var(--border);
}
.badge::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; opacity: .75; flex: none;
}
.badge.active, .badge.ok   { background: var(--ok-soft);     color: var(--ok); border-color: transparent; }
.badge.error               { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
.badge.creating            { background: var(--warn-soft);   color: var(--warn); border-color: transparent; }
.badge.pending             { background: var(--warn-soft);   color: var(--warn); border-color: transparent; }
.badge.draft               { background: var(--info-soft);   color: var(--info); border-color: transparent; }
.badge.deleted, .badge.skipped { background: var(--bg-sunken); color: var(--muted); }
p.badge::before { display: none; }


/* ── Иконки ──────────────────────────────────────────────────────────── */
/* Были текстовые значки — ▸ ▾ ★ ⏱ ⏳ ▶ ↑. Каждый рисуется своим шрифтом,
   в разных системах выглядит по-разному, не выравнивается по строке и
   меняет размер вместе с начертанием. Заменены на маски: форма задана
   SVG, цвет берётся у текста, размер — от кегля.
   data: в масках разрешён политикой безопасности (img-src 'self' data:),
   а вот встроенный скрипт — нет, поэтому никакой библиотеки иконок. */
.ic {
  display: inline-block; width: 1em; height: 1em; flex: none;
  vertical-align: -0.125em; background: currentColor;
  -webkit-mask: var(--ic) center / contain no-repeat;
          mask: var(--ic) center / contain no-repeat;
}
.ic-chevron { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 5l7 7-7 7'/%3E%3C/svg%3E"); }
.ic-star { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Cpath d='M12 2.6l2.9 5.9 6.5.95-4.7 4.58 1.11 6.47L12 17.45l-5.81 3.05 1.11-6.47-4.7-4.58 6.5-.95z'/%3E%3C/svg%3E"); }
.ic-clock { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5l3.5 2'/%3E%3C/svg%3E"); }
.ic-arrow-right { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12h15M13 6l6 6-6 6'/%3E%3C/svg%3E"); }
.ic-arrow-up { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20V5M6 11l6-6 6 6'/%3E%3C/svg%3E"); }
.ic-external { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 4h6v6'/%3E%3Cpath d='M20 4l-8.5 8.5'/%3E%3Cpath d='M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5'/%3E%3C/svg%3E"); }
.ic-play { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Cpath d='M7 4.5l13 7.5-13 7.5z'/%3E%3C/svg%3E"); }
.ic-check { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12.5l5 5 10-11'/%3E%3C/svg%3E"); }
.ic-alert { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5l9.5 16.5h-19z'/%3E%3Cpath d='M12 10v4M12 17.2v.1'/%3E%3C/svg%3E"); }

/* Значок состояния в плашке: точка ничего не говорила, галочка и
   восклицание говорят. Нейтральная плашка остаётся с точкой. */
.badge.ok::before, .badge.active::before {
  width: 12px; height: 12px; border-radius: 0; opacity: 1;
  -webkit-mask: var(--ic-check) center / contain no-repeat;
          mask: var(--ic-check) center / contain no-repeat;
}
.badge.error::before {
  width: 12px; height: 12px; border-radius: 0; opacity: 1;
  -webkit-mask: var(--ic-alert) center / contain no-repeat;
          mask: var(--ic-alert) center / contain no-repeat;
}
.badge.pending::before, .badge.creating::before {
  width: 12px; height: 12px; border-radius: 0; opacity: 1;
  -webkit-mask: var(--ic-clock) center / contain no-repeat;
          mask: var(--ic-clock) center / contain no-repeat;
}
:root {
  --ic-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 5l7 7-7 7'/%3E%3C/svg%3E");
  --ic-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12.5l5 5 10-11'/%3E%3C/svg%3E");
  --ic-alert: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5l9.5 16.5h-19z'/%3E%3Cpath d='M12 10v4M12 17.2v.1'/%3E%3C/svg%3E");
  --ic-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5l3.5 2'/%3E%3C/svg%3E");
}

/* ── Таблицы ─────────────────────────────────────────────────────────── */
/* Широкие таблицы прокручиваются внутри себя, а не растягивают страницу. */
.table-wrap {
  overflow-x: auto; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--card); box-shadow: var(--shadow-1);
}
.table-wrap > table { border: none; border-radius: 0; box-shadow: none; margin: 0; }

table.subs, table.steps, .data-table {
  width: 100%; border-collapse: collapse; background: var(--card);
  border: 1px solid var(--border); border-radius: var(--r-md);
  overflow: hidden; box-shadow: var(--shadow-1); font-size: 14px;
}
table.subs th, table.subs td,
table.steps th, table.steps td,
.data-table th, .data-table td {
  padding: 11px var(--s3); text-align: left; vertical-align: top;
  border-bottom: 1px solid var(--border);
}
table.subs th, table.steps th, .data-table th {
  position: sticky; top: 0; z-index: 1;
  background: var(--bg-sunken); color: var(--muted);
  font-size: 11px; font-weight: 650; letter-spacing: .05em; text-transform: uppercase;
  white-space: nowrap; vertical-align: bottom;
}
table.subs th .muted, .data-table th .muted { text-transform: none; letter-spacing: 0; font-weight: 500; }
table.subs tbody tr:hover, .data-table tbody tr:hover { background: color-mix(in srgb, var(--accent) 4%, transparent); }
table.subs tbody tr:last-child td, .data-table tbody tr:last-child td { border-bottom: none; }
.data-table.compact th, .data-table.compact td { padding: 7px 10px; font-size: 13px; }
/* Колонка денег. Цифры моноширинные, чтобы суммы читались столбиком, а не
   плясали; сумма не переносится посреди числа. */
td.balance { white-space: nowrap; }
td.balance b { font-size: 15px; font-variant-numeric: tabular-nums; }
td.balance .muted { white-space: normal; }
table.steps pre {
  margin: 0; font: 12px/1.45 var(--mono); white-space: pre-wrap;
  word-break: break-word; max-width: 520px; color: var(--text-soft);
}

/* ── Плитки чисел ────────────────────────────────────────────────────── */
.kpi-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--s3); margin-bottom: var(--s4);
}
.kpi {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--s4); display: flex; flex-direction: column; gap: var(--s1);
  box-shadow: var(--shadow-1);
}
.kpi-value { font-size: 28px; font-weight: 640; line-height: 1.1; letter-spacing: -.02em; }
.kpi-label { font-size: 13px; color: var(--muted); }
.kpi-trend { font-size: 12px; color: var(--muted); }
.kpi-trend.up { color: var(--ok); }
.kpi-trend.down { color: var(--danger); }

/* ── Переключатель периода ───────────────────────────────────────────── */
/* Ссылки, а не кнопки: без скрипта переключение возможно только переходом,
   и это честно отражено разметкой. */
/* Строка выбора периода целиком: «Период», сам переключатель и даты. Зазор
   шире обычного (--s2 у .inline), потому что здесь стоят рядом три разные
   вещи, а не части одной. */
.period-picker { gap: var(--s3); }
.segmented {
  display: inline-flex; padding: 3px; gap: 2px;
  background: var(--bg-sunken); border: 1px solid var(--border);
  border-radius: var(--r-full);
}
.segmented > a, .segmented > strong {
  padding: 5px 14px; border-radius: var(--r-full);
  font-size: 13px; font-weight: 550; color: var(--text-soft);
}
.segmented > a:hover { background: var(--card); text-decoration: none; color: var(--text); }
.segmented > strong { background: var(--card); color: var(--text); box-shadow: var(--shadow-1); }

/* ── Карточки и формы ────────────────────────────────────────────────── */
.card, .create-block, .login-card, .error-card, .api-panel {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-1);
}
.card { padding: var(--s4); }
.card h3 { margin: 0 0 var(--s3); }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--s4); }

/* Карточка проекта на корне: четыре числа парами «подпись — значение». */
.project-card h3 { font-size: 19px; }
.project-numbers { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); margin: var(--s4) 0 0; }
.project-numbers > div { display: flex; flex-direction: column; gap: 2px; }
.project-numbers dt { font-size: 13px; color: var(--muted); }
.project-numbers dd { margin: 0; font-size: 22px; font-weight: 620; letter-spacing: -.02em; }
.project-numbers dd .badge { font-size: 13px; font-weight: 550; }

/* Жалобы на профили, чьи секреты не прочитались. Отдельно от списка самих
   профилей: битый файл больше не прячет рабочие. */
.broken-profiles { margin: 0 0 var(--s4); padding-left: 20px; color: var(--danger); }
.broken-profiles li { margin-bottom: var(--s1); }
.create-block { padding: var(--s5); margin-bottom: var(--s5); }
.create-block h2 { margin-top: 0; }

.create-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s3); margin: var(--s3) 0; }
.create-form label { display: block; flex: 1 1 260px; margin: 0; }
.create-form label span { display: block; font-size: 13px; color: var(--text-soft); margin-bottom: 5px; }
.create-form input, .filters input, .filters select,
.toolbar-actions input, .toolbar-actions select,
.direct-controls input, .direct-controls select, select {
  width: 100%; padding: 9px 11px; font: inherit; font-size: 14px;
  color: var(--text); background: var(--card);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  transition: border-color .12s, box-shadow .12s;
}
.create-form input:focus, select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
  outline: none;
}
.create-form button { flex: none; }
table select { min-width: 190px; padding: 6px 9px; font-size: 13px; }

/* ── Вход ────────────────────────────────────────────────────────────── */
.login-page { display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: var(--s4); }
.login-card { width: 380px; max-width: 100%; padding: var(--s6); box-shadow: var(--shadow-3); }
.login-card h1 { text-align: center; margin: 0 0 var(--s5); font-size: 22px; }
.login-card label { display: block; margin-bottom: var(--s3); }
.login-card label span { display: block; font-size: 13px; color: var(--text-soft); margin-bottom: 5px; }
.login-card input[type=text], .login-card input[type=password] {
  width: 100%; padding: 10px 12px; font: inherit;
  color: var(--text); background: var(--card);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
}
.login-card button { width: 100%; margin-top: var(--s3); padding: 11px; }

/* ── Города ──────────────────────────────────────────────────────────── */
.city-list {
  list-style: none; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--s4);
}
.city-tile {
  display: block; background: var(--card); padding: var(--s5); border-radius: var(--r-lg);
  border: 1px solid var(--border); box-shadow: var(--shadow-1);
  transition: box-shadow .15s, transform .15s, border-color .15s;
}
.city-tile:hover {
  box-shadow: var(--shadow-2); transform: translateY(-2px);
  border-color: var(--border-strong); text-decoration: none;
}
.city-tile strong { display: block; font-size: 17px; margin-bottom: 2px; }
.city-tile span { color: var(--muted); font-size: 13px; }

/* ── Раскрывающиеся блоки ────────────────────────────────────────────── */
/* Заменяют собой окошки подтверждения: confirm() без скрипта не работает. */
details { margin: 0; }
details > summary {
  cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 5px;
  color: var(--accent); font-size: 14px;
}
details > summary::-webkit-details-marker { display: none; }
details > summary::before {
  content: ""; display: inline-block; width: .8em; height: .8em;
  background: currentColor; transition: transform .12s;
  -webkit-mask: var(--ic-chevron) center / contain no-repeat;
          mask: var(--ic-chevron) center / contain no-repeat;
}
details[open] > summary::before { transform: rotate(90deg); }
details > summary:hover { text-decoration: underline; text-underline-offset: 2px; }

/* Заголовок, живущий внутри <summary>: он обязан стоять В СТРОКУ со
   значком-стрелкой, а не переносить её на отдельную строку, как это делает
   блочный <h2>. */
.disclosure-heading { display: inline-block; }

.instructions {
  background: var(--warn-soft); border: 1px solid color-mix(in srgb, var(--warn) 28%, transparent);
  border-radius: var(--r-md); padding: var(--s3) var(--s4); margin: var(--s3) 0 var(--s5);
}
.instructions > summary { color: var(--warn); font-weight: 550; }
.instructions ol { margin: var(--s3) 0 var(--s1); padding-left: 22px; }
.instructions ol > li { margin-bottom: var(--s3); }
.instructions ul { margin: var(--s1) 0 0; padding-left: 20px; }
.instructions p { margin: var(--s2) 0; }
.instructions code { background: color-mix(in srgb, var(--warn) 12%, transparent); border-color: transparent; }
.instructions a { color: var(--warn); font-weight: 550; }

/* ── Свойства объекта ────────────────────────────────────────────────── */
dl.kv {
  display: grid; grid-template-columns: minmax(140px, 220px) 1fr; gap: var(--s2) var(--s4);
  background: var(--card); padding: var(--s4) var(--s5);
  border: 1px solid var(--border); border-radius: var(--r-md); box-shadow: var(--shadow-1);
}
dl.kv dt { color: var(--muted); font-size: 14px; }
dl.kv dd { margin: 0; }
dl.kv dd.error { color: var(--danger); }
.open-link { margin: var(--s3) 0 var(--s4); font-weight: 500; }

/* ── Ожидание ────────────────────────────────────────────────────────── */
.spinner {
  display: inline-block; width: 14px; height: 14px;
  border: 2px solid var(--border); border-top-color: var(--accent);
  border-radius: 50%; animation: spin .9s linear infinite;
  vertical-align: middle; margin-left: var(--s2);
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 3s; }
  * { transition-duration: .01ms !important; }
}

/* ── Витрина API (страница /direct) ──────────────────────────────────── */
/* Подпись второй метрики графика — заявок. Цвет тот же, каким нарисована
   линия заявок в самом рисунке (stroke="#16a34a"), и выписан значением, а не
   взят из --ok: легенда, покрашенная не как линия, читалась бы как подпись к
   другой метрике. */
.legend-conversions { color: #16a34a; }

.direct-layout { display: grid; grid-template-columns: 230px 1fr; gap: var(--s5); margin: 0 calc(-1 * var(--s5)); }
.direct-sidebar {
  background: var(--card); border-right: 1px solid var(--border);
  padding: var(--s5) 0; min-height: calc(100vh - 80px);
  position: sticky; top: 64px; align-self: start; border-radius: var(--r-md) 0 0 var(--r-md);
}
.direct-sidebar .sidebar-header { padding: 0 var(--s5) var(--s4); border-bottom: 1px solid var(--border); }
.direct-sidebar h3 { margin: 0 0 var(--s1); }
.sidebar-nav { padding: var(--s3) 0; display: flex; flex-direction: column; gap: 2px; }
.sidebar-nav a {
  padding: 8px var(--s5); color: var(--text-soft); display: flex;
  justify-content: space-between; align-items: center; font-size: 14px;
}
.sidebar-nav a:hover { background: var(--bg-sunken); text-decoration: none; color: var(--text); }
.sidebar-nav a.active {
  background: var(--accent-soft); color: var(--accent-ink);
  border-left: 3px solid var(--accent); padding-left: 21px; font-weight: 600;
}
.sidebar-nav .count { background: var(--bg-sunken); border-radius: var(--r-full); font-size: 12px; padding: 1px 9px; }
.sidebar-nav a.muted { color: var(--muted); }
.sidebar-footer { padding: var(--s3) var(--s5); border-top: 1px solid var(--border); font-size: 12px; }
.sidebar-footer p { margin: var(--s1) 0; }
.direct-main { padding: 0 var(--s5) var(--s7); min-width: 0; }
.direct-toolbar {
  display: flex; justify-content: space-between; align-items: center;
  padding: var(--s4) 0 var(--s5); border-bottom: 1px solid var(--border);
  margin-bottom: var(--s5); flex-wrap: wrap; gap: var(--s4);
}
.direct-toolbar h1 { margin: 0 0 2px; font-size: 22px; }
.toolbar-actions { display: flex; gap: var(--s2); align-items: center; flex-wrap: wrap; }
.toolbar-actions input, .toolbar-actions select { width: auto; }
.toolbar-actions input[type=search] { min-width: 240px; }
.filters { display: flex; gap: var(--s2); flex-wrap: wrap; }
.filters input, .filters select { width: auto; }
.bulk-bar {
  background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--s2) var(--s3); display: flex; gap: 6px; align-items: center;
  flex-wrap: wrap; margin: var(--s3) 0;
}
.bulk-bar > .muted { margin-right: var(--s3); font-size: 14px; }
.template-card { display: flex; flex-direction: column; gap: var(--s2); }
.template-card button { align-self: flex-start; margin-top: var(--s2); }
.rules { list-style: none; padding: 0; margin: 0 0 var(--s3); }
.rules li {
  padding: var(--s3) 0; border-bottom: 1px solid var(--border);
  display: grid; grid-template-columns: 1fr auto; gap: var(--s1) var(--s3);
}
.rules li:last-child { border-bottom: none; }
.rules li > .muted { grid-column: 1 / 2; font-size: 13px; }
.rules li > .link { grid-column: 2 / 3; grid-row: 1 / 3; align-self: center; }
.chart { width: 100%; height: auto; background: var(--bg-sunken); border-radius: var(--r-sm); }
.direct-controls {
  background: var(--bg-sunken); padding: var(--s3) var(--s4);
  border: 1px solid var(--border); border-radius: var(--r-md);
  display: flex; gap: var(--s3); align-items: end; flex-wrap: wrap; margin: var(--s4) 0;
}
.direct-controls label { display: flex; flex-direction: column; gap: var(--s1); min-width: 200px; flex: 1; }
.direct-controls label span { font-size: 12px; color: var(--muted); }
.direct-controls button { padding: 9px 16px; background: var(--accent); color: #fff; border: none; border-radius: var(--r-sm); cursor: pointer; }
.api-panel { padding: var(--s3) var(--s4); margin-bottom: var(--s2); }
.api-panel h3 { display: flex; align-items: center; gap: var(--s2); margin: 0 0 var(--s2); font-size: 14px; }
.api-raw {
  background: var(--bg-sunken); padding: var(--s2); border-radius: var(--r-sm);
  font: 12px/1.45 var(--mono); overflow-x: auto; max-height: 220px; margin: var(--s1) 0;
}
.api-raw.error { background: var(--danger-soft); color: var(--danger); }

/* ── Ошибка ──────────────────────────────────────────────────────────── */
.error-card { max-width: 620px; margin: var(--s7) auto; padding: var(--s6); }
.error-card pre { background: var(--bg-sunken); padding: var(--s3); border-radius: var(--r-sm); overflow-x: auto; }

/* ── Узкий экран ─────────────────────────────────────────────────────── */
@media (max-width: 860px) {
  main { padding: 0 var(--s4); margin-top: var(--s4); }
  .topbar { padding: var(--s2) var(--s4); gap: var(--s3); }
  .topbar nav { gap: 0; }
  .topbar .nav-link { padding: 5px 9px; font-size: 13px; }
  .user { display: none; }         /* имя пользователя на узком экране — шум */
  h1 { font-size: 22px; }
  .direct-layout { grid-template-columns: 1fr; margin: 0; }
  .direct-sidebar { position: static; min-height: 0; border-right: none; border-bottom: 1px solid var(--border); }
  .direct-main { padding: 0; }
  dl.kv { grid-template-columns: 1fr; gap: 2px var(--s3); }
  dl.kv dt { margin-top: var(--s2); }
}

/* ── Печать ──────────────────────────────────────────────────────────── */
@media print {
  .topbar, .actions, form, .segmented { display: none; }
  body { background: #fff; }
  .table-wrap, table.subs { box-shadow: none; overflow: visible; }
}

/* ── Страница кампаний ───────────────────────────────────────────────── */
/* Было: заголовок, период, две кнопки и три абзаца пояснений подряд — всё
   одного веса, и глазу не за что зацепиться. Разложено по слоям:
   что это → чем управлять → сколько получилось → подробности. */

.page-head {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: var(--s3); margin-bottom: var(--s4);
}
.page-head h1 { margin: 0; }

.toolbar {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s4);
  padding: var(--s3) var(--s4); margin-bottom: var(--s3);
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-1);
}
.toolbar-group { display: flex; align-items: center; gap: var(--s3); }
.toolbar-right { margin-left: auto; }
.toolbar-label { font-size: 13px; color: var(--muted); }

/* ── Читаемый текст ──────────────────────────────────────────────────── */
/* Пояснений на страницах много, и это правильно: они объясняют, почему
   число такое. Но сплошной серой стеной их не читают. Мера строки, воздух
   между абзацами и выделенный зачин делают ту же длину проходимой. */
.prose { max-width: 68ch; }
.prose p { margin: 0 0 var(--s3); line-height: 1.65; font-size: 14px; }
.prose p:last-child { margin-bottom: 0; }
.prose p > strong:first-child {
  color: var(--text); font-weight: 600;
}
.prose .muted { color: var(--text-soft); }

details.note { margin-bottom: var(--s5); }
details.note > summary {
  cursor: pointer; font-size: 13px; color: var(--muted);
  padding: var(--s2) 0; list-style: none;
}
details.note > summary::-webkit-details-marker { display: none; }
details.note > summary::before {
  content: ""; display: inline-block; width: .85em; height: .85em;
  margin-right: 6px; vertical-align: -0.05em; background: currentColor;
  transition: transform .12s;
  -webkit-mask: var(--ic-chevron) center / contain no-repeat;
          mask: var(--ic-chevron) center / contain no-repeat;
}
details.note[open] > summary::before { transform: rotate(90deg); }
details.note > summary:hover { color: var(--text); }
details.note > .prose {
  padding: var(--s3) var(--s4); margin-top: var(--s2);
  background: var(--bg-sunken); border-radius: var(--r-md);
  border: 1px solid var(--border);
}

/* ── Аккаунт как складная карточка ───────────────────────────────────── */
/* 🔴 Аккаунтов восемь, и раскрытыми они сливались в одну ленту: чтобы
   понять, у кого что, приходилось листать. Свёрнутая карточка обязана
   говорить главное сама — логин, поддомен, цена заявки, расход и сколько
   кампаний работает. Иначе сворачивание прячет, а не упорядочивает. */
details.account {
  margin-bottom: var(--s4); background: var(--card);
  border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--shadow-1);
}
details.account[open] { border-color: var(--border-strong); }
details.account > summary {
  cursor: pointer; list-style: none; padding: var(--s4);
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s3);
  border-radius: var(--r-md);
}
details.account > summary::-webkit-details-marker { display: none; }
details.account > summary:hover { background: var(--bg-sunken); }
details.account[open] > summary {
  border-bottom: 1px solid var(--border);
  border-radius: var(--r-md) var(--r-md) 0 0;
}
.acc-caret {
  color: var(--muted); width: 14px; height: 14px; flex: none;
  background: currentColor; transition: transform .12s;
  -webkit-mask: var(--ic-chevron) center / contain no-repeat;
          mask: var(--ic-chevron) center / contain no-repeat;
}
details.account[open] .acc-caret { transform: rotate(90deg); }

.acc-id { display: flex; align-items: baseline; gap: var(--s2); flex-wrap: wrap; }
.acc-id code { font-size: 14px; font-weight: 600; background: none; border: none; padding: 0; }
.acc-domain { font-size: 13px; color: var(--muted); }
.acc-badges { display: flex; gap: var(--s2); flex-wrap: wrap; }
.acc-stats {
  margin-left: auto; display: flex; align-items: baseline; gap: var(--s4);
  font-size: 13px; color: var(--muted); white-space: nowrap;
}
.acc-stats b {
  font-size: 15px; color: var(--text); font-weight: 640;
  font-variant-numeric: tabular-nums;
}
.acc-stats .bad { color: var(--danger); }
.account-body { padding: var(--s4); }
.account-actions {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s3);
  margin-bottom: var(--s4);
}
.meta-line { font-size: 12px; margin: var(--s3) 0 0; }

/* Верхняя строка шапки объединяет столбцы по смыслу: где кончается
   «что это» и начинается «сколько стоило». */
table.campaigns thead tr.group-row th {
  position: static; padding-bottom: 3px; padding-top: var(--s2);
  border-bottom: none; color: var(--text-soft); font-size: 10px;
}
table.campaigns thead tr.group-row th[colspan] {
  border-left: 1px solid var(--border);
}
table.campaigns thead tr.group-row th:first-child { border-left: none; }
table.campaigns thead tr:last-child th { top: 0; }
table.campaigns td { vertical-align: top; }
table.campaigns .cell-name { min-width: 200px; }
table.campaigns .cell-clarify { max-width: 190px; white-space: normal; line-height: 1.4; }
table.campaigns .cell-strategy { font-size: 12px; max-width: 210px; line-height: 1.5; }
table.campaigns .cell-target { max-width: 210px; font-size: 13px; line-height: 1.45; }
table.campaigns .side { display: inline-block; min-width: 38px; color: var(--muted); }
/* За что кампания платит. Отделено чертой от стратегии: это не её параметр,
   а следствие, и путать их не надо. */
table.campaigns .pay {
  margin-top: 5px; padding-top: 5px; border-top: 1px dashed var(--border);
  display: flex; align-items: flex-start; gap: 5px;
}
table.campaigns .pay.ok { color: var(--ok); }
table.campaigns .pay.warn { color: var(--danger); font-weight: 500; }
table.campaigns .pay .ic { flex: none; margin-top: 2px; }

details.x30 > summary { cursor: pointer; list-style: none; }
details.x30 > summary::-webkit-details-marker { display: none; }
details.x30 ul {
  margin: var(--s2) 0 0; padding-left: 16px; font-size: 12px;
  max-width: 320px; white-space: normal; line-height: 1.5;
}
details.x30 li { margin-bottom: 4px; }
details.x30 li.error { color: var(--danger); }

@media (max-width: 860px) {
  .toolbar-right { margin-left: 0; }
  .acc-stats { margin-left: 0; width: 100%; white-space: normal; }
}

/* ── Микрографики ────────────────────────────────────────────────────── */
/* Рисуются на сервере готовым SVG: CSP панели (script-src 'self') не даёт
   ни одной библиотеке графиков работать, а SVG — не скрипт. */
.spark { margin: 0; display: flex; flex-direction: column; gap: 2px; }
.spark figcaption { font-size: 11px; color: var(--muted); white-space: nowrap; }
.spark figcaption b { color: var(--text); font-variant-numeric: tabular-nums; }
.spark svg { display: block; overflow: visible; }
.spark rect { fill: var(--accent); }
.spark .spark-base { fill: var(--border-strong); }
.spark-peak { font-size: 10px; color: var(--muted); white-space: nowrap; }

/* Цвет по смыслу: показы приглушены, заявки — главное число страницы. */
.spark-impressions rect { fill: color-mix(in srgb, var(--accent) 45%, transparent); }
.spark-clicks rect { fill: var(--accent); }
.spark-conversions rect { fill: var(--ok); }

.spark-row { display: flex; gap: var(--s4); flex-wrap: wrap; margin-top: var(--s3); }

/* В строке таблицы график вспомогательный: подписи мельче, пик не нужен. */
.spark-mini { display: flex; gap: 10px; margin-top: 6px; justify-content: flex-end; }
.spark-mini .spark-peak { display: none; }
.spark-mini figcaption { font-size: 10px; }
/* 🔴 Здесь НЕ задаётся высота. Задать её поверх SVG с viewBox значит
   заставить браузер вписать рисунок с сохранением пропорций — он ужмётся и
   по ширине. Геометрия компактного графика приходит с сервера уже своя. */

/* Подсказка на графике — без единой строчки скрипта: прозрачная зона
   наведения во всю высоту столбца и подпись, которую показывает :hover.
   Родной <title> не годится: он появляется через секунду и выглядит
   системным окошком, а по столбику в три пикселя ещё надо попасть. */
/* 🔴 Селектор с типом элемента, а не просто класс: правило `.spark rect`
   выше весит столько же и красило бы зону наведения цветом метрики во всю
   высоту — график превращался в сплошную заливку, за которой не видно
   столбиков. */
.spark rect.spark-hit { fill: transparent; }
.spark-col:hover rect.spark-hit { fill: color-mix(in srgb, var(--accent) 12%, transparent); }
.spark-tip {
  display: none; font-size: 10px; font-family: var(--font);
  fill: var(--text); text-anchor: middle;
  /* Обводка цветом карточки вместо подложки: ширину текста на сервере не
     измерить, а прямоугольник нужного размера без этого не нарисовать. */
  stroke: var(--card); stroke-width: 3px; paint-order: stroke fill;
}
.spark-col:hover .spark-tip { display: block; }
/* Место для подписи над графиком — иначе она уедет под заголовок. */
.spark svg { margin-top: 12px; }

/* Сеть целиком — заголовок страницы, а не ещё одна карточка в ряду.
   Поэтому отдельная плашка над списком кабинетов. */
.network {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-1);
  padding: var(--s4) var(--s5); margin-bottom: var(--s5);
}
.network .section-header { margin-bottom: var(--s3); }
.network .kpi-grid { margin-bottom: var(--s3); }
.spark-row-big { gap: var(--s6); }
.spark-row-big figcaption { font-size: 13px; }
