/* Айдентика ГК «ОДА»: фирменная палитра и Golos Text — те же, что в портале
   группы. Шрифт лежит своими woff2-подмножествами в assets/fonts, а не тянется
   с fonts.gstatic.com: портал должен одинаково выглядеть на Railway и локально
   без интернета. Подмножество latin-ext обязательно — в нём знак рубля (U+20BD). */

@font-face {
  font-family: 'Golos Text'; font-style: normal; font-weight: 400 900; font-display: swap;
  src: url('/assets/fonts/golos-text-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Golos Text'; font-style: normal; font-weight: 400 900; font-display: swap;
  src: url('/assets/fonts/golos-text-cyrillic-ext.woff2') format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Golos Text'; font-style: normal; font-weight: 400 900; font-display: swap;
  src: url('/assets/fonts/golos-text-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Golos Text'; font-style: normal; font-weight: 400 900; font-display: swap;
  src: url('/assets/fonts/golos-text-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --oda-green: #69a74c;
  --oda-green-deep: #4e8c3a;
  --oda-blue-deep: #3e7fc4;
  --oda-mist: #c2d1cf;
  --oda-slate: #5a6666;

  --bg: #f4f6f5;
  --surface: #ffffff;
  --side: #f9faf9;
  --line: #e2e7e5;
  --ink: #23302c;
  --muted: #6d7b76;
  --warn: #b5651d;
  --warn-soft: #f6ecdf;
  --ok-soft: #e8f1e2;
  --bad: #a2372c;
}

* { box-sizing: border-box; }

/* Атрибут hidden должен побеждать любой display из наших правил. Без этого
   элемент со своим `display: flex` остаётся на экране, хотя код его спрятал, —
   так полоса «Слепок» висела над живыми данными кабинета «Рекламодатель». */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.6 "Golos Text", system-ui, -apple-system, "Segoe UI", sans-serif;
}

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

.top {
  background: var(--surface);
  border-bottom: 3px solid var(--oda-green);
  position: sticky;
  top: 0;
  z-index: 10;
}

.top-inner {
  display: flex;
  align-items: center;
  gap: 28px;
  padding: 12px 24px;
  flex-wrap: wrap;
}

.brand { display: flex; align-items: center; gap: 11px; }
.brand-mark { width: 34px; height: 34px; flex: none; }
.brand-text { display: flex; flex-direction: column; line-height: 1.2; }
.brand-name { font-size: 19px; font-weight: 700; color: var(--oda-green-deep); letter-spacing: -0.01em; }
.brand-sub { font-size: 12px; color: var(--muted); }

.cabinets { display: flex; gap: 4px; flex: 1; }

.cab {
  border: 1px solid transparent;
  background: none;
  font: inherit;
  font-size: 14px;
  color: var(--oda-slate);
  padding: 7px 14px;
  border-radius: 6px;
  cursor: pointer;
}
.cab:hover { background: var(--bg); }
.cab.is-active { background: var(--ok-soft); color: var(--oda-green-deep); font-weight: 600; }
.cab:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 2px; }

.top-right { display: flex; align-items: center; gap: 14px; margin-left: auto; }
.viewer { font-size: 13px; color: var(--muted); }

.back {
  color: var(--oda-blue-deep);
  text-decoration: none;
  font-size: 13.5px;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  white-space: nowrap;
}
.back:hover { border-color: var(--oda-blue-deep); }

/* ---------- раскладка ---------- */

.layout { display: grid; grid-template-columns: 260px 1fr; align-items: start; }

.side {
  background: var(--side);
  border-right: 1px solid var(--line);
  min-height: calc(100vh - 64px);
  padding: 20px 0 40px;
}

.cabinet-note {
  margin: 0 20px 18px;
  font-size: 13px;
  color: var(--muted);
}

.group-title {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 18px 20px 6px;
}

.side a {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  padding: 7px 20px;
  color: var(--ink);
  text-decoration: none;
  font-size: 14px;
  border-left: 3px solid transparent;
}
.side a:hover { background: #eef2f0; }
.side a.is-active { background: var(--ok-soft); border-left-color: var(--oda-green); font-weight: 600; }
.side a:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: -2px; }

.dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }
.dot.need { background: var(--warn); }
.dot.ready { background: var(--oda-green); }

/* ---------- контент ---------- */

/* Пузырь подсказки «?» шире кружка, у которого он висит, и в узком
   заголовке вылезает за правый край страницы. Absolute-потомок при этом
   расширяет область прокрутки — страница получала боковую полосу на
   26 пикселей, которую нечем прокручивать и незачем. `clip` обрезает,
   но, в отличие от hidden и auto, не делает из колонки прокручиваемый
   ящик: липкие шапки таблиц и выпадающие списки фильтров живут дальше. */
.content { padding: 32px 36px 64px; max-width: 900px; min-width: 0; overflow-x: clip; }

h1 { font-size: 25px; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 8px; }
h2 { font-size: 17px; font-weight: 600; margin: 0 0 8px; }
.note { color: var(--oda-slate); margin: 0; max-width: 62ch; }

.section-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 20px; margin-bottom: 24px; }
.crumb { font-size: 12px; color: var(--muted); margin-bottom: 4px; letter-spacing: 0.02em; }

.badge {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 5px 10px;
  border-radius: 3px;
  white-space: nowrap;
}
.badge.need { background: var(--warn-soft); color: var(--warn); }
.badge.ready { background: var(--ok-soft); color: var(--oda-green-deep); }
.badge.tiny { padding: 1px 6px; font-size: 10px; }

.placeholder {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 28px 30px;
}
.placeholder p { color: var(--oda-slate); margin: 0 0 20px; max-width: 62ch; }

.meta { display: grid; grid-template-columns: 170px 1fr; gap: 8px 16px; margin: 0; font-size: 14px; }
.meta dt { color: var(--muted); }
.meta dd { margin: 0; font-family: ui-monospace, Consolas, monospace; font-size: 13px; }

/* ---------- обзор ---------- */

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin: 24px 0 28px; }

.tile {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 16px 18px;
}
.tile b { display: block; font-size: 27px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.tile span { font-size: 13px; color: var(--muted); }
.tile.need b { color: var(--warn); }
.tile.ready b { color: var(--oda-green-deep); }

.notice {
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 4px solid var(--warn);
  border-radius: 6px;
  padding: 18px 22px;
  margin-bottom: 28px;
}
.notice p { margin: 0; color: var(--oda-slate); max-width: 64ch; font-size: 14.5px; }
.notice ul { margin: 8px 0 0; padding-left: 20px; color: var(--oda-slate); max-width: 64ch; font-size: 14.5px; }
.notice li + li { margin-top: 4px; }

.services { display: flex; flex-direction: column; gap: 10px; }

.check {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 13px 18px;
  display: grid;
  grid-template-columns: 10px 1fr auto;
  gap: 4px 14px;
  align-items: center;
}
.check .lamp { width: 10px; height: 10px; border-radius: 50%; background: var(--oda-mist); }
.check.ok .lamp { background: var(--oda-green); }
.check.fail .lamp { background: var(--bad); }
.check b { font-weight: 600; font-size: 14.5px; }
.check .ms { font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }
.check .why { grid-column: 2 / -1; font-size: 13px; color: var(--bad); }

/* ---------- живой раздел статистики ---------- */

.stat-toolbar {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 22px;
}
.stat-toolbar .spacer { flex: 1; }
.field { display: flex; flex-direction: column; gap: 4px; }
.field label { font-size: 12px; color: var(--muted); }
.field input,
.field select {
  font: inherit;
  font-size: 14px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
}
.field input:focus-visible,
.field select:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 1px; }
.field select { min-width: 200px; }

.btn {
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  padding: 8px 18px;
  border: none;
  border-radius: 6px;
  background: var(--oda-green);
  color: #fff;
  cursor: pointer;
}
.btn:hover { background: var(--oda-green-deep); }
.btn:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 2px; }

.stat-hint { font-size: 12.5px; color: var(--muted); margin: 0 0 6px; }
.stat-period { font-size: 13.5px; color: var(--muted); margin: 0 0 18px; }
.stat-period b { color: var(--ink); font-weight: 600; }

/* Полоса «Требует внимания». Карточка — это дело, а не число: заголовок
   называет, что не так, список показывает где именно, кнопка ведёт туда, где
   это чинится. Цветная полоса слева — цена ошибки: красная деньги, жёлтая
   закон и метки, синяя настройка. */
.signals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px;
  margin-bottom: 14px;
}
.signal {
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--muted);
  border-radius: 10px;
  padding: 14px 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.signal.bad { border-left-color: var(--bad); }
.signal.warn { border-left-color: #c98a12; }
.signal.info { border-left-color: var(--oda-blue-deep, #2f6fb0); }
.signal.calm { border-left-color: var(--oda-green); grid-column: 1 / -1; }
.signal-head b { font-size: 14.5px; line-height: 1.3; }
.signal-detail { margin: 0; font-size: 12.5px; color: var(--muted); line-height: 1.45; }
.signal-items {
  margin: 2px 0 0;
  padding-left: 16px;
  font-size: 12.5px;
  line-height: 1.55;
  font-variant-numeric: tabular-nums;
}
.signal-items li { color: var(--ink); }
.signal-go { align-self: flex-start; margin-top: 4px; }

.kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px;
  margin-bottom: 14px;
}
.kpi {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 16px 18px;
}
.kpi.primary {
  border-color: var(--oda-green);
  background: linear-gradient(180deg, var(--ok-soft), var(--surface) 70%);
}
.kpi .k-title {
  font-size: 12px;
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 6px;
}
.kpi .k-value {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.kpi.primary .k-value { color: var(--oda-green-deep); }
.kpi .k-hint { font-size: 11.5px; color: var(--muted); margin-top: 4px; }

/* Вторая линия обзора: объём потока и производные от него. Те же числа, что
   были плитками, но весом мельче — на них смотрят при разборе, а не первым
   взглядом. Занимает всю ширину сетки, поэтому плиток наверху ровно четыре. */
.kpi-more {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 26px;
  padding: 11px 18px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--side);
}
.kpi-min { display: flex; align-items: baseline; gap: 8px; }
.kpi-min .k-title {
  font-size: 12px;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.kpi-min .k-value { font-size: 15.5px; font-weight: 600; font-variant-numeric: tabular-nums; }
.kpi-min .k-delta { margin-top: 0; font-size: 11.5px; }

/* Подсказка с формулой метрики. Кнопка, а не span с title: атрибут title не
   открывается с клавиатуры и не существует на планшете, а формула — это то,
   ради чего метрике вообще можно верить. Всплывает по наведению и по фокусу. */
.hintmark {
  position: relative;
  width: 14px; height: 14px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--muted);
  background: none;
  font: inherit;
  color: var(--muted);
  font-size: 9px;
  line-height: 12px;
  text-align: center;
  cursor: help;
  flex: none;
}
.hintmark:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 2px; }

/* Пузырь подсказки — ОДИН на страницу, лежит в <body> и позиционируется от
   окна. Псевдоэлементом внутри кружка он быть не может: в шапке таблицы кружок
   стоит внутри .stat-table-wrap с overflow: auto, и подсказку там срезало до
   чёрного прямоугольника без текста. Координаты считает adv.js. */
.hint-bubble {
  position: fixed;
  z-index: 60;
  max-width: 320px;
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--ink);
  color: #fff;
  font-size: 12px;
  line-height: 1.45;
  text-align: left;
  white-space: normal;
  box-shadow: 0 6px 20px rgba(15, 23, 42, .22);
  pointer-events: none;
}
.hintmark.on { border-color: var(--oda-green); color: var(--oda-green); }
/* В шапке таблицы и в заголовке карточки кружок не должен ломать выравнивание
   и подпирать соседнюю колонку. */
th .hintmark { vertical-align: middle; margin-left: 3px; }
.card-head h3 .hintmark { vertical-align: middle; margin-left: 4px; }
.field-label .hintmark, .field label .hintmark { vertical-align: middle; }

/* Таблица прокручивается ВНУТРИ своей карточки, а не вместе со страницей.
   Колонка 1fr в .layout по умолчанию не сжимается ниже содержимого (min-width:
   auto), поэтому широкая таблица раздвигала весь макет: горизонтальная полоса
   появлялась у страницы целиком, вместе с шапкой и фильтрами. min-width: 0 на
   контентной колонке и карточках возвращает прокрутку туда, где ей место.

   Высоту ограничиваем, чтобы работала липкая шапка: при overflow-x браузер
   делает прокручиваемыми обе оси, и sticky у th считается от этого же бокса —
   без своей высоты ему не от чего залипать. Пролистав срез на сотню строк,
   человек должен видеть, где какая колонка. */
/* Своя вертикальная прокрутка внутри страницы, которая и так прокручивается,
   раздражает сильнее, чем длинная страница. Потолок поднят: обычная таблица
   на 25–30 строк помещается целиком, и полоса появляется только там, где
   строк действительно сотня — ради липкой шапки, которая без своего
   прокручиваемого предка работать перестанет. */
.stat-table-wrap {
  overflow: auto;
  max-height: min(92vh, 1400px);
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  margin-top: 20px;
}
table.stat thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--surface);
  box-shadow: inset 0 -1px 0 var(--line);
}
/* Первая колонка — что именно за строка. Уехав вправо за метриками, без неё
   человек читает числа неизвестно про кого. */
table.stat tbody td:first-child, table.stat thead th:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--surface);
}
table.stat thead th:first-child { z-index: 3; }
table.stat tr.clickable:hover td:first-child { background: var(--ok-soft); }
table.stat { border-collapse: collapse; width: 100%; }
/* Тринадцать колонок метрик: по 16 пикселей с каждой стороны набегает почти
   полтысячи только на воздух между числами — из-за них таблица и не влезала
   в экран. 13 читается так же, а места отдаёт заметно больше. */
table.stat th, table.stat td { padding: 11px 13px; text-align: left; font-size: 14px; border-bottom: 1px solid var(--line); }
table.stat th { font-size: 12px; letter-spacing: 0.03em; text-transform: uppercase; color: var(--muted); font-weight: 600; }
table.stat td.num, table.stat th.num { text-align: right; font-variant-numeric: tabular-nums; }
/* Числа не переносим: «14 326.26 р» в три строки читается как три значения.
   Таблица разреза шире экрана — её прокручивает .stat-table-wrap. */
table.stat td.num, table.stat th.num { white-space: nowrap; }
/* Строка «Итого» стоит в шапке: она не часть страницы данных, а сумма за весь период. */
table.stat tr.totals td { font-weight: 600; background: var(--surface-2, rgba(0,0,0,.03)); border-bottom: 2px solid var(--line); }
table.stat tr:last-child td { border-bottom: none; }

/* Таблица статистики на главной вебмастера — короткая и без сортировки,
   по центру читается опрятнее, чем общий левый/правый расклад table.stat
   (тот держим как есть — на нём завязаны разделы с сортировкой и залипающей
   первой колонкой в других экранах). */
.wm-stat-table th, .wm-stat-table td { text-align: center; }

/* ---------- расширенная статистика: строки × колонки ---------- */
/* Клеток здесь на порядок больше, чем в обычной таблице (25 строк × 30 дней),
   поэтому отступы меньше, а числа выровнены вправо: колонку сравнивают
   сверху вниз, и разряды должны стоять друг под другом. */

/* Селекторы записаны через `table.stat.pivot-table`, а не просто
   `.pivot-table`: у общего правила `table.stat th, table.stat td` вес выше
   (класс + два элемента против класса и одного), и оно перебивало и отступы, и
   выравнивание. Числа в клетках оставались прижатыми ВЛЕВО, тогда как шапка —
   вправо: колонки таблицы разъезжались с их же заголовками. */
table.stat.pivot-table th, table.stat.pivot-table td { padding: 7px 10px; font-size: 13px; }
table.stat.pivot-table td { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Название строки — тоже th, поэтому липкость первой колонки задаётся отдельно:
   правило для td:first-child до него не достаёт. */
.pivot-table tbody th.pivot-head {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--surface);
  text-transform: none;
  letter-spacing: 0;
  font-size: 13px;
  color: var(--ink);
  font-weight: 500;
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pivot-table thead th.pivot-head { z-index: 3; left: 0; position: sticky; background: var(--surface); }
.pivot-table thead th { white-space: nowrap; text-align: right; }
.pivot-table thead th.pivot-head { text-align: left; }
/* Итог по строке прижат к правому краю таблицы и выделен: он и есть ответ,
   а колонки — его разложение. */
.pivot-table .pivot-total { font-weight: 600; background: var(--side); }
.pivot-table .pivot-empty { color: var(--muted); }
.pivot-table tr.totals th, .pivot-table tr.totals td { font-weight: 600; background: var(--ok-soft); }

/* Таблицы «Пользователи»/«Сайты»/«Виджеты» в кабинете менеджера — просили
   жёстко чёрную шапку с белым текстом и белые строки, а не тему сайта (в
   тёмной теме var(--ink) на var(--surface) читался бы наоборот, поэтому оба
   цвета заданы явно, а не через переменные). Позднее правило перебивает и
   залипающий фон шапки (table.stat thead th), и белый фон первой залипающей
   колонки. */
table.stat.mgr-table thead th {
  background: #000;
  color: #fff;
}
table.stat.mgr-table th.sortable:hover { color: #8fd3ff; }
table.stat.mgr-table tbody td {
  background: #fff;
  color: #111;
}
/* Колонка «Действия» на Пользователях/Сайтах/Виджетах — несколько кнопок
   в одной ячейке, без этого они слипались бы вплотную друг к другу. */
table.stat.mgr-table td.mgr-row-actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.mgr-status-actions { display: inline-flex; align-items: center; }
.mgr-status-actions .pill { min-width: 90px; text-align: center; }
/* Пилюля-статус — теперь ещё и кнопка: клик по ней раскрывает Принять/Отклонить.
   Сброс браузерных стилей кнопки, чтобы она выглядела как обычная пилюля, а не
   как элемент управления. */
.mgr-status-toggle { border: 0; font: inherit; cursor: pointer; }
/* Попап, а не блок в потоке — иначе раскрытие сдвигало бы высоту строки и
   «дёргало» всю таблицу под курсором. position: fixed, а не absolute: строка
   лежит внутри .stat-table-wrap с overflow: auto (см. комментарий там же про
   .hint-bubble) — absolute обрезало бы попап у нижних строк рамкой прокрутки.
   Левый/верхний край считает JS от positionом toggle-кнопки (getBoundingClientRect). */
.mgr-status-btns {
  position: fixed; z-index: 60;
  display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; white-space: nowrap;
  padding: 8px; border: 1px solid var(--line); border-radius: 7px;
  background: var(--surface); box-shadow: 0 8px 22px rgba(20, 40, 30, .13);
}

/* Форма «Выпустить виджет по шаблону» — раньше max-width:480px висел
   инлайном на .card, а сама .card блочная (не flex), поэтому промежутки
   между полями держал .stat-toolbar, переиспользованный не по назначению.
   Отдельный класс со своим flex-раскладом читается понятнее и не зависит от
   того, что рядом с ним придумают для .stat-toolbar. */
.mgr-issue-card { max-width: 460px; display: flex; flex-direction: column; gap: 14px; }
.mgr-issue-card .field select,
.mgr-issue-card .field input,
.mgr-issue-card .fm-pick,
.mgr-issue-card .fm-pick-input,
.mgr-issue-card .fm-pick-q { width: 100%; box-sizing: border-box; }
.mgr-issue-card > .btn { width: 100%; }

/* Раскладка «показатели в колонках»: два признака слева, дальше числа.
   Вторая колонка липкой не делается — она узкая, а два липких столбца на
   узком экране съедают половину видимой таблицы. */
.pivot-flat th.pivot-second {
  text-transform: none;
  letter-spacing: 0;
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  white-space: nowrap;
}
.pivot-flat thead th.pivot-second { text-align: left; }
.pivot-flat tr.pivot-subtotal td, .pivot-flat tr.pivot-subtotal th { background: var(--side); font-weight: 600; }
.pivot-flat tr.pivot-subtotal th.pivot-second { color: var(--ink); }
.pivot-table tr.pivot-other th, .pivot-table tr.pivot-other td { color: var(--muted); }
.pivot-x { color: var(--muted); font-size: 13px; }

.pager {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 16px;
  font-size: 13.5px;
  color: var(--muted);
}
.btn.ghost {
  background: var(--surface);
  color: var(--oda-blue-deep);
  border: 1px solid var(--line);
}
.btn.ghost:hover:not(:disabled) { border-color: var(--oda-blue-deep); background: var(--surface); }
.btn.ghost:disabled { opacity: 0.45; cursor: default; }

.stat-error {
  background: var(--warn-soft);
  border: 1px solid var(--warn);
  border-radius: 8px;
  padding: 16px 20px;
  color: var(--warn);
}
.stat-loading { color: var(--muted); padding: 20px 0; }
.stat-empty {
  background: var(--surface);
  border: 1px dashed var(--line);
  border-radius: 8px;
  padding: 28px 22px;
  color: var(--muted);
  text-align: center;
}

/* v2-форма только для чтения */
.form-note {
  background: var(--warn-soft);
  border-left: 3px solid var(--warn);
  padding: 10px 14px;
  border-radius: 4px;
  font-size: 13.5px;
  color: var(--oda-slate);
  margin: 0 0 14px;
}
.form-table td { padding: 11px 16px; }
.form-label { color: var(--muted); width: 40%; }
.form-value { font-weight: 500; }
/* Только внутри карточек формы (.fm-field) — не трогает form-value в табличном
   просмотре формы (renderForm(), <td class="form-value">), там своя вёрстка.
   Читаемое поле выглядит как рамка на месте инпута, а не голый текст. */
.fm-field .form-value {
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  font-weight: 400;
}
.muted-dash { color: var(--line); }

/* История начислений: знак решён на сервере (списание уже отрицательное),
   здесь только цвет — начисление зелёным, списание бордовым. */
.tx-plus { color: var(--oda-green-deep); font-weight: 600; }
.tx-minus { color: var(--bad); font-weight: 600; }
.form-readonly { font-size: 12.5px; color: var(--muted); margin-top: 12px; }

/* Код виджета для вставки на сайт */
.code-block-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.code-block-head .form-note { margin: 0; flex: 1; }
.code-block {
  background: var(--oda-slate, #1f2733);
  color: #dfe6ee;
  border-radius: 8px;
  padding: 12px 14px;
  font-size: 12.5px;
  line-height: 1.5;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-all;
  margin: 0 0 14px;
}

/* Переключатель вкладок (реферальная система: RevShare/CPA) */
.pill-tabs {
  display: flex;
  gap: 4px;
  padding: 4px;
  margin: 0 0 18px;
  background: var(--side);
  border: 1px solid var(--line);
  border-radius: 10px;
}
.pill-tabs button {
  flex: 1;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  padding: 9px 16px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--oda-slate);
  cursor: pointer;
}
.pill-tabs button.active { background: var(--oda-green); color: #fff; }
.pill-tabs button:not(.active):hover { background: rgba(0, 0, 0, .04); }

/* Строка баннера в реферальной системе: превью картинки рядом с её кодом для вставки */
.banner-row {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: 18px;
  align-items: start;
  margin: 0 0 16px;
}
.banner-preview { text-align: center; }
.banner-preview img { max-width: 100%; border-radius: 8px; border: 1px solid var(--line); display: block; }
.banner-size { margin: 8px 0 0; font-size: 13px; font-weight: 600; color: var(--ink); }
@media (max-width: 520px) {
  .banner-row { grid-template-columns: 1fr; }
}

/* Готовый HTML-блок из админки: приводим таблицы к общему виду */
.legacy-html { overflow-x: auto; font-size: 14px; }
.legacy-html table { border-collapse: collapse; width: 100%; background: var(--surface); border: 1px solid var(--line); border-radius: 8px; }
.legacy-html th, .legacy-html td { padding: 9px 14px; border-bottom: 1px solid var(--line); text-align: left; }
.legacy-html th { color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; }
.legacy-html tr:last-child td { border-bottom: none; }
.legacy-html a { color: var(--oda-blue-deep); }

@media (max-width: 820px) {
  .layout { grid-template-columns: 1fr; }
  .side { min-height: 0; border-right: none; border-bottom: 1px solid var(--line); }
  .content { padding: 24px 20px 48px; }
  .top-right { width: 100%; }
}

/* Полоса режима данных: портал на слепке. Заметная, но не тревожная —
   это рабочий режим этапа, а не авария. */
.mode-strip {
  display: flex;
  gap: 10px;
  align-items: baseline;
  flex-wrap: wrap;
  margin-bottom: 20px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--oda-blue-deep, #2f6fb0);
  border-radius: 8px;
  background: var(--surface);
  font-size: 13px;
  color: var(--muted);
}
.mode-strip b { color: var(--ink); letter-spacing: 0.03em; text-transform: uppercase; font-size: 12px; }
.mode-strip code { font-size: 12px; padding: 1px 5px; border-radius: 4px; background: rgba(0,0,0,.05); }

/* ==========================================================================
   Кабинет «Рекламодатель»: дашборд открутки DSP
   ==========================================================================
   Отдельный блок, потому что это единственный экран портала с графиками и
   плотными таблицами метрик. Палитра рядов объявлена переменными: её читают и
   стили, и charts.js — один источник правды у темы и у графика. */

:root {
  --grid: #eaefed;
  --s1: #69a74c;   /* фирменный зелёный — первый ряд всегда он */
  --s2: #3e7fc4;
  --s3: #c07a22;
  --s4: #7b6cb0;
  --s5: #2f9c9c;
  --s6: #a2372c;
  /* Оливковый и серо-зелёный стояли рядом с фирменным зелёным первого ряда:
     на графике из шести кампаний седьмая и восьмая линии от него не
     отличались. Заменены на розовый и грифельный — единственные два тона,
     которых в наборе ещё не было. */
  --s7: #d4517f;
  --s8: #4a5a66;
}

/* Восемь колонок метрик в 900 пикселей не помещаются. А на широком экране
   упираться в 1320 незачем: свободное место рядом с таблицей всё равно
   пустует, а таблица из-за него получает собственную боковую прокрутку —
   вторую на странице поверх её же. Потолок остаётся, но по месту экрана. */
.content.wide { max-width: min(1920px, 100%); }

/* ---------- панель фильтров ---------- */

.adv-bar {
  display: flex;
  align-items: flex-end;
  gap: 12px 14px;
  flex-wrap: wrap;
  padding: 14px 16px;
  margin-bottom: 18px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
}
.field .field-label { font-size: 12px; color: var(--muted); }

.presets { display: flex; gap: 4px; }
.presets button {
  font: inherit;
  font-size: 13px;
  padding: 7px 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--oda-slate);
  cursor: pointer;
}
.presets button:hover { border-color: var(--oda-green); }
.presets button.is-active { background: var(--ok-soft); border-color: var(--oda-green); color: var(--oda-green-deep); font-weight: 600; }

/* «Обновить» и время последнего пересчёта — одним блоком: без времени кнопка
   не отвечает на вопрос, ради которого её нажимают («а сейчас-то сколько?»). */
.adv-fresh { display: flex; align-items: center; gap: 8px; }
.adv-fresh .hint { font-size: 12px; color: var(--muted); white-space: nowrap; }
#adv-refresh.is-busy { opacity: .6; pointer-events: none; }

/* ---------- мультиселект ---------- */

.ms { position: relative; }
.ms-trigger {
  display: flex;
  align-items: center;
  gap: 6px;
  font: inherit;
  font-size: 14px;
  padding: 7px 10px;
  min-width: 150px;
  max-width: 220px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  text-align: left;
}
.ms-trigger:hover { border-color: var(--oda-green); }
.ms-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
.ms-count {
  font-size: 11px;
  font-weight: 700;
  background: var(--ok-soft);
  color: var(--oda-green-deep);
  border-radius: 10px;
  padding: 1px 7px;
}
/* Мультиселект в шапке карточки: рядом с обычными select'ами, поэтому у него
   их размер, а панель раскрывается ВЛЕВО — справа у карточки уже край. */
.ms-inline .ms-trigger { min-width: 0; max-width: 190px; font-size: 13.5px; padding: 6px 9px; }
.ms-inline .ms-panel { left: auto; right: 0; }

.ms-panel {
  display: none;
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  width: 280px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 10px 26px rgba(35, 48, 44, .12);
  padding: 8px;
}
.ms.open .ms-panel { display: block; }
.ms-panel input[type="search"] {
  width: 100%;
  font: inherit;
  font-size: 13.5px;
  padding: 6px 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  margin-bottom: 6px;
}
.ms-options { max-height: 260px; overflow-y: auto; }
.ms-options label {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 6px;
  border-radius: 5px;
  font-size: 13.5px;
  cursor: pointer;
}
.ms-options label:hover { background: var(--bg); }
.ms-options span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ms-empty { padding: 10px 6px; color: var(--muted); font-size: 13px; }
.ms-foot { display: flex; justify-content: space-between; gap: 8px; margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--line); }

/* ---------- карточки и сетка ---------- */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 16px 18px 18px;
  margin-bottom: 18px;
  /* Иначе карточка растягивается под ширину таблицы внутри, а не наоборот. */
  min-width: 0;
}
/* Уведомления с вывода средств — ГОТОВЫЙ HTML из блейда admin
   (public.profile.withdraw_messages, см. withdrawNoticesBlock() в app.js).
   Разметка там на классах Bootstrap, которого в oda-pro нет, поэтому эти
   классы одеваются здесь — не переписывая сам HTML на стороне admin. */
.admin-notices { padding: 0; overflow: hidden; }
.admin-notices .alert { margin: 0; padding: 14px 18px; font-size: 13.5px; line-height: 1.6; }
.admin-notices .alert + .alert { border-top: 1px solid var(--line); }
.admin-notices .alert-warning { background: var(--warn-soft); border-left: 3px solid var(--warn); color: var(--oda-slate); }
.admin-notices .alert-info { background: var(--side); border-left: 3px solid var(--oda-blue-deep); color: var(--oda-slate); }
.admin-notices .alert-heading { margin: 0 0 8px; font-size: 15px; font-weight: 600; color: var(--ink); }
.admin-notices .alert p { margin: 0 0 8px; }
.admin-notices .alert p:last-child { margin-bottom: 0; }
.admin-notices .table { border-collapse: collapse; width: auto; margin: 6px 0 10px; background: var(--surface); }
.admin-notices .table th, .admin-notices .table td { border: 1px solid var(--line); padding: 5px 12px; text-align: left; font-size: 13px; }
.admin-notices .table thead th { background: var(--bg); font-weight: 600; }

/* Реквизиты выплат: «Основной способ» — чекбокс в правом верхнем углу карточки
   способа оплаты (renderCabinetPayments() в app.js). Нативный input не спрятан
   через display:none (нужен для клавиатуры и скринридеров), а сведён в точку
   opacity/размером — стандартный приём для кастомного чекбокса поверх него. */
.card.payment-card { position: relative; padding-top: 42px; }
.main-pin {
  position: absolute;
  top: 12px;
  right: 14px;
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  user-select: none;
}
.main-pin input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  margin: 0;
}
.main-pin-box {
  width: 18px;
  height: 18px;
  flex: none;
  border: 1.5px solid var(--line);
  border-radius: 5px;
  background: var(--surface);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background .15s, border-color .15s;
}
.main-pin-box::after {
  content: "";
  width: 9px;
  height: 5px;
  border-left: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(-45deg) translateY(-1px);
  opacity: 0;
  transition: opacity .1s;
}
.main-pin input:checked + .main-pin-box { background: var(--oda-green); border-color: var(--oda-green); }
.main-pin input:checked + .main-pin-box::after { opacity: 1; }
.main-pin input:hover:not(:disabled) + .main-pin-box { border-color: var(--oda-green); }
.main-pin input:focus-visible + .main-pin-box { outline: 2px solid var(--oda-green); outline-offset: 2px; }
.main-pin input:disabled + .main-pin-box { opacity: .5; }
.main-pin input:disabled ~ * { cursor: not-allowed; }
.main-pin-text { font-size: 12px; color: var(--muted); font-weight: 500; }
.main-pin input:checked ~ .main-pin-text { color: var(--oda-green-deep); font-weight: 600; }
/* Раздел «Вывод средств»: настройка автовывода свёрнута по умолчанию, как остальные <details> в интерфейсе. */
details.card { padding-top: 12px; }
details.card > summary { cursor: pointer; font-size: 15px; font-weight: 600; list-style: none; }
details.card > summary::-webkit-details-marker { display: none; }
details.card > summary::before { content: "▸"; color: var(--muted); margin-right: 6px; }
details.card[open] > summary::before { content: "▾"; }
details.card[open] > summary { margin-bottom: 12px; }
.card-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.card-head h3 { font-size: 15px; font-weight: 600; margin: 0; }
.card-head .hint { font-size: 12.5px; color: var(--muted); }
.card-head .spacer { flex: 1; }
.card-head select,
.card-head input[type="search"] {
  font: inherit;
  font-size: 13.5px;
  padding: 6px 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
}
.card-head input[type="search"] { min-width: 190px; }
.check { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--oda-slate); }

.card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 18px; }
.card-grid .card { margin-bottom: 0; }

/* Смена пароля (renderPasswordCard() в app.js) — три поля общего .fm-grid
   (repeat(auto-fit, minmax(220px,1fr))) растягивались на всю ширину карточки
   в ряд, получались три раздутых инпута вместо аккуратной формы. Здесь она
   уже, поля в столбик. */
.password-card { max-width: 380px; }
.password-card .fm-grid { grid-template-columns: 1fr; }

.btn.tiny { font-size: 13px; padding: 6px 12px; }

/* Плитка со сравнением: без него «12 400 отыгрышей» не говорит ничего. */
.k-delta { font-size: 12px; margin-top: 6px; color: var(--muted); }
.k-delta span { color: var(--muted); }
.k-delta.up { color: var(--oda-green-deep); }
.k-delta.down { color: var(--bad); }
.k-delta.flat { color: var(--muted); }

/* ---------- графики ---------- */

.chart-box { min-height: 260px; }
.chart { display: block; overflow: visible; }
.chart .ax { font-size: 11px; fill: var(--muted); }
.donut-box { display: flex; justify-content: center; padding: 6px 0 2px; }
.donut .arc { cursor: pointer; }
.donut .donut-total { font-size: 15px; font-weight: 700; fill: var(--ink); }
.chart-empty {
  padding: 34px 0;
  text-align: center;
  color: var(--muted);
  font-size: 13.5px;
}

.chart-tip {
  position: fixed;
  z-index: 60;
  pointer-events: none;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 22px rgba(35, 48, 44, .16);
  padding: 8px 10px;
  font-size: 13px;
  max-width: 280px;
}
.tip-title { font-weight: 600; margin-bottom: 4px; }
.tip-row { display: flex; align-items: center; gap: 6px; }
.tip-row b { margin-left: auto; font-variant-numeric: tabular-nums; }
.swatch { width: 9px; height: 9px; border-radius: 2px; flex: none; }

.legend { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 10px; }
.legend button {
  display: flex;
  align-items: center;
  gap: 6px;
  font: inherit;
  font-size: 12.5px;
  color: var(--oda-slate);
  background: none;
  border: none;
  padding: 2px 0;
  cursor: pointer;
}
.legend button.is-off { opacity: 0.4; text-decoration: line-through; }

/* Горизонтальные полосы — разметкой, а не SVG: подпись домена бывает длинной,
   и обрезать её пикселями пришлось бы вручную. */
.bars { display: flex; flex-direction: column; gap: 7px; }
.bar-row { display: grid; grid-template-columns: minmax(90px, 34%) 1fr auto; align-items: center; gap: 10px; }
.bar-label {
  font-size: 13px;
  color: var(--oda-slate);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bar-track { background: var(--bg); border-radius: 4px; height: 14px; overflow: hidden; }
.bar-fill { display: block; height: 100%; border-radius: 4px; }
.bar-value { font-size: 12.5px; font-variant-numeric: tabular-nums; color: var(--ink); white-space: nowrap; }

/* ---------- таблицы кабинета ---------- */

table.stat th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
table.stat th.sortable:hover { color: var(--oda-green-deep); }
table.stat th .arrow { margin-left: 3px; }
table.stat tr.clickable { cursor: pointer; }
table.stat tr.clickable:hover td { background: var(--ok-soft); }

/* Полоса в ячейке показывает вклад строки, не мешая читать само число. */
.cell-bar { position: relative; }
.cell-bar-fill {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  background: var(--oda-green);
  opacity: 0.55;
}

.name-cell { display: flex; flex-direction: column; gap: 2px; min-width: 180px; }
.name-cell .sub { font-size: 11.5px; color: var(--muted); }
.linklike {
  font: inherit;
  font-weight: 600;
  color: var(--oda-blue-deep);
  background: none;
  border: none;
  padding: 0;
  text-align: left;
  cursor: pointer;
}
.linklike:hover { text-decoration: underline; }

.pill {
  display: inline-block;
  font-size: 11.5px;
  padding: 3px 9px;
  border-radius: 11px;
  white-space: nowrap;
}
.pill.ok { background: var(--ok-soft); color: var(--oda-green-deep); }
.pill.warn { background: var(--warn-soft); color: var(--warn); }
.pill.muted { background: var(--bg); color: var(--muted); }
.pill.bad { background: color-mix(in srgb, var(--bad) 13%, transparent); color: var(--bad); font-weight: 600; }

/* ---------- превью креативов ---------- */

.thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  width: 68px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  overflow: hidden;
  cursor: pointer;
  color: var(--muted);
}
.thumb.empty { cursor: default; font-size: 13px; }
.thumb.broken { background: var(--warn-soft); }
.thumb.broken .thumb-media { display: none; }
.thumb-media { max-width: 100%; max-height: 100%; object-fit: contain; }
.thumb-play {
  position: absolute;
  right: 3px;
  bottom: 2px;
  font-size: 10px;
  color: #fff;
  background: rgba(0, 0, 0, .55);
  border-radius: 3px;
  padding: 0 4px;
}

.lightbox {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 70;
  background: rgba(20, 28, 25, .6);
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.lightbox.open { display: flex; }
.lightbox-body {
  background: var(--surface);
  border-radius: 10px;
  padding: 14px;
  max-width: min(90vw, 900px);
  max-height: 90vh;
  overflow: auto;
}
.lightbox-head { display: flex; align-items: center; gap: 14px; margin-bottom: 10px; }
.lightbox-title { font-weight: 600; }
.lightbox-head .btn { margin-left: auto; }
.lightbox-stage img,
.lightbox-stage video { max-width: 100%; max-height: 70vh; display: block; margin: 0 auto; }
.lightbox-link { display: inline-block; margin-top: 10px; font-size: 13px; color: var(--oda-blue-deep); }
.code-modal-body { width: min(70vw, 640px); }
.site-edit-body { width: min(90vw, 560px); }
/* :last-child метит именно обёртку, а не сам <pre> — он теперь последний
   внутри СВОЕЙ обёртки в любом случае (заголовок + кнопка «Копировать» перед
   ним), и без уточнения правило снимало бы отступ у обоих блоков разом. */
.code-modal-body .code-block-wrap:last-child .code-block { margin-bottom: 0; }

/* Блок «Включить АВ тест» под кодом вставки — renderAbTestBlock() в app.js. */
.code-modal-abtest { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }
.code-modal-abtest .abtest-fields { margin-top: 12px; display: flex; flex-direction: column; gap: 12px; }
.code-modal-abtest .abtest-percent { display: flex; gap: 14px; flex-wrap: wrap; }
.code-modal-abtest textarea {
  font: inherit;
  font-size: 13.5px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  resize: vertical;
}
.code-modal-abtest .abtest-actions { margin-top: 12px; display: flex; align-items: center; gap: 10px; }
.code-modal-abtest .abtest-status { margin: 0; }

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

/* Рабочая зона раскрывается ПОД строкой таблицы, а не поверх экрана.
   Попап на полэкрана прятал ту самую таблицу, из-за которой его открыли, —
   а решение почти всегда принимается сравнением строки с соседними.
   Подкрашенный фон и зелёная полоса слева показывают, где у зоны края и
   к какой строке она относится. */
.drawer { display: block; }
.drawer[hidden] { display: none; }
.drawer-body {
  background: var(--side);
  border: 1px solid var(--line);
  border-left: 3px solid var(--oda-green);
  border-radius: 0 8px 8px 0;
  padding: 20px 22px 24px;
  margin: 2px 0 10px;
}

/* Ячейка-хозяин своих отступов не добавляет: зона рисует их сама. */
tr.row-host > td,
tr.row-host:hover > td { padding: 0; background: none; }
/* Раскрытая строка остаётся подсвеченной — видно, что именно открыто. */
tr.row-open > td { background: var(--ok-soft); }
tr.row-open > td:first-child { box-shadow: inset 3px 0 0 var(--oda-green); }
.drawer-head { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 18px; }
.drawer-head h2 { margin: 0 0 4px; font-size: 19px; }
.drawer-head .sub { font-size: 13px; color: var(--muted); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.drawer-head .btn { margin-left: auto; }
/* Органы управления шапкой — одной группой у правого края.
   Без неё каждая кнопка получала своё margin-left:auto, и свободное место
   делилось МЕЖДУ ними: «Колонки», «архив», «Добавить креатив» и «Закрыть»
   расползались по всей ширине и читались как четыре не связанные вещи. */
.drawer-head .drawer-acts {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
  margin-left: auto;
}
.drawer-head .drawer-acts .btn { margin-left: 0; }

.kv { display: grid; grid-template-columns: auto 1fr; gap: 6px 16px; margin: 0; font-size: 13.5px; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; font-variant-numeric: tabular-nums; }

.json {
  margin: 0;
  padding: 12px 14px;
  background: var(--bg);
  border-radius: 8px;
  font-family: ui-monospace, Consolas, monospace;
  font-size: 12.5px;
  overflow-x: auto;
  max-height: 320px;
}

/* Пока идёт запрос, экран гасится — но остаётся читаемым: подменять таблицу
   спиннером значит терять то, на что человек уже смотрит. */
#adv-view.is-loading { opacity: 0.65; transition: opacity .12s; }

/* ==========================================================================
   Ожидание ответа базы
   ==========================================================================
   Разрез по боевой базе считается секундами, а на широком периоде — десятками.
   Пустая панель всё это время читается как поломка, а не как «идёт счёт»:
   человек успевает второй раз щёлкнуть фильтр или уйти со страницы. Поэтому
   три знака: полоса сверху, скелет вместо будущих блоков и, если ждём долго,
   строка о том, почему долго. */

.adv-progress {
  height: 2px;
  margin: -6px 0 14px;
  background: var(--line);
  border-radius: 2px;
  overflow: hidden;
}
.adv-progress span {
  display: block;
  height: 100%;
  width: 30%;
  background: var(--oda-green);
  animation: adv-slide 1.1s ease-in-out infinite;
}
@keyframes adv-slide {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(333%); }
}

.adv-wait { margin: 0 0 14px; font-size: 13px; color: var(--muted); }

.skeleton {
  border-radius: 8px;
  background: linear-gradient(90deg, var(--line) 25%, rgba(255,255,255,.65) 37%, var(--line) 63%);
  background-size: 400% 100%;
  animation: adv-shimmer 1.4s ease-in-out infinite;
}
@keyframes adv-shimmer {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}

/* Движение отключаем тем, кто просил его не показывать: мигающий скелет —
   именно то, от чего prefers-reduced-motion защищает. */
@media (prefers-reduced-motion: reduce) {
  .adv-progress span, .skeleton { animation: none; }
}

/* Подпись креатива: наверху то, что различается (тип, размер, номер), внизу —
   имя файла с рекламного сервера. Оно длинное и часто повторяется, поэтому
   ужимаем в одну строку; полное значение — в подсказке. */
/* Заголовок строки и метка ОРД держатся одной строкой: перенос метки вниз
   стоил бы по лишней строке каждому креативу — у кампании их бывает под
   тридцать, и это полэкрана прокрутки на ровном месте. */
.cr-title { display: flex; align-items: center; gap: 6px; white-space: nowrap; font-weight: 600; }
.cr-file {
  display: inline-block;
  max-width: 28ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
  font-family: ui-monospace, Consolas, monospace;
  font-size: 12px;
}

/* Исходный JSON таргетинга — под катом: он нужен, когда расходятся показания
   портала и админки, но на экране рекламодателя это шум. */
.raw-json { margin-top: 12px; }
.raw-json summary { cursor: pointer; font-size: 13px; color: var(--muted); }
.raw-json summary:hover { color: var(--oda-green-deep); }
.raw-json .json { margin-top: 8px; }

/* Пояснение под графиком про незакончившийся отрезок. */
.chart-note { margin: 6px 0 0; font-size: 12.5px; color: var(--muted); }

/* ==========================================================================
   Формы кабинета: заведение и правка кампаний и креативов
   ==========================================================================
   Единственное место портала, которое пишет в базу рекламной сети. Отсюда
   заметная кнопка сохранения и предупреждение рядом с ней: правка доезжает до
   открутки за минуту, и человек должен об этом знать до нажатия, а не после. */

.fm { display: block; }
.fm-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px 18px;
}
.fm-field { display: flex; flex-direction: column; gap: 4px; }
/* Обёртка вокруг цены цели: её показывают и прячут переключателем цели, поэтому
   поле лежит в отдельном контейнере, а не прямо в сетке. Ведёт себя как ячейка
   сетки — иначе поле внутри неё теряет ширину колонки. */
.fm-goal-price { display: flex; flex-direction: column; min-width: 0; }
.fm-goal-price > .fm-field { flex: 1; }
.fm-label { font-size: 12px; color: var(--muted); }
.fm-hint { font-size: 12px; color: var(--muted); }

/* Метка «необязательно» у подписи поля */
.fm-optional { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--oda-green-deep); background: var(--ok-soft); border-radius: 10px; padding: 1px 6px; margin-left: 5px; }
/* Целевая цена клика + кнопка «Подсказать» в одну строку */
.fm-ecpc-row { display: flex; gap: 8px; align-items: stretch; }
.fm-ecpc-row input { flex: 1; }
.fm-ecpc-row .btn.tiny { white-space: nowrap; padding: 6px 12px; font-size: 12.5px; }

/* Автоматика: две карточки-тумблера рядом (Автоставка + Умный показ) */
.fm-auto-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 6px; }
@media (max-width: 640px) { .fm-auto-2 { grid-template-columns: 1fr; } }
.fm-auto-card { border: 1px solid var(--line, #d9e0dc); border-radius: 12px; padding: 12px 13px;
  background: var(--surface, #fff); transition: border-color .15s, background .15s; }
.fm-auto-card.on { border-color: var(--oda-green); background: var(--ok-soft); }
.fm-auto-toggle { align-items: flex-start; }
.fm-auto-name b { font-weight: 620; }
.fm-auto-name i { font-style: normal; font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted); margin: 0 4px; }
.fm-auto-card .fm-hint { margin-top: 7px; display: block; }

/* Поле, которым завладела автоматика: блюр + плашка «ведёт …» (текст из data-lock) */
.fm-locked { position: relative; }
.fm-locked > *:not(.fm-lock-badge) { filter: blur(2px) grayscale(.35); opacity: .7;
  pointer-events: none; user-select: none; transition: filter .2s, opacity .2s; }
.fm-locked::after { content: "🔒 " attr(data-lock); position: absolute; inset: 0; margin: auto;
  width: -moz-fit-content; width: fit-content; height: -moz-fit-content; height: fit-content;
  padding: 6px 13px; background: var(--ink, #17202b); color: #fff; font-size: 12px; font-weight: 600;
  border-radius: 20px; box-shadow: 0 4px 14px rgba(0,0,0,.28); z-index: 3; white-space: nowrap; }
.fm-note {
  margin: 14px 0 0;
  font-size: 13px;
  color: var(--muted);
  border-left: 3px solid var(--line);
  padding-left: 10px;
}

.fm input[type="text"], .fm input[type="number"], .fm input[type="date"],
.fm input[type="password"],
.fm select, .fm textarea {
  font: inherit;
  font-size: 14px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  width: 100%;
}
.fm textarea { resize: vertical; font-size: 13px; }
.fm input:focus-visible, .fm select:focus-visible, .fm textarea:focus-visible {
  outline: 2px solid var(--oda-blue-deep);
  outline-offset: 1px;
}
.fm input:disabled { background: var(--bg); color: var(--muted); }
/* Поле, на которое пожаловался сервер. Красная рамка держится до следующей
   отправки: если убирать её по первому касанию, человек теряет из виду, что
   именно было не так. */
.fm .is-bad { border-color: var(--bad); background: #fdf6f5; }

/* ---------- выбор значений таргетинга ---------- */
/* Чипы вместо строк в textarea: выбранное видно целиком, а лишнее снимается
   одним крестиком. Список под полем — то, что реально видела статистика. */

.fm-pick { display: flex; flex-direction: column; gap: 6px; }
.fm-pick-chips { display: flex; flex-wrap: wrap; gap: 5px; min-height: 22px; align-items: center; }
.fm-pick-empty { font-size: 12.5px; color: var(--muted); }
.fm-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 4px 2px 8px;
  border: 1px solid var(--line);
  border-radius: 20px;
  background: var(--bg);
  font-size: 12.5px;
  max-width: 100%;
}
/* Значение, которого не было в статистике: не ошибка (новый домен выглядит
   так же), но повод перечитать написание — сверка у сети точная. */
.fm-chip.unknown { border-style: dashed; border-color: var(--warn); }
.fm-chip-x {
  border: 0; background: none; cursor: pointer;
  color: var(--muted); font: inherit; font-size: 14px; line-height: 1;
  padding: 0 3px;
}
.fm-chip-x:hover { color: var(--bad); }

.fm-pick-input { position: relative; }
.fm-pick-menu {
  position: absolute; z-index: 6; left: 0; right: 0; top: calc(100% + 3px);
  max-height: 230px; overflow-y: auto;
  border: 1px solid var(--line); border-radius: 7px;
  background: var(--surface);
  box-shadow: 0 8px 22px rgba(20, 40, 30, .13);
}
.fm-pick-menu button {
  display: block; width: 100%; text-align: left;
  padding: 6px 10px; border: 0; background: none;
  font: inherit; font-size: 13px; cursor: pointer;
}
.fm-pick-menu button:hover { background: var(--ok-soft); }
.fm-pick-own { color: var(--warn); border-top: 1px solid var(--line) !important; }
/* Ответ справочного поля на «такого нет»: не кнопка, а объяснение. Значение
   там — строка справочника сети, и вписать своё нельзя не из строгости. */
.fm-pick-none {
  display: block; padding: 6px 10px; font-size: 13px; color: var(--muted);
  border-top: 1px solid var(--line);
}

/* ---------- расписание показа ---------- */
/* 168 клеток вместо семи строк текста: «работает ли кампания в субботу
   вечером» становится вопросом взгляда, а не разбора строк в уме. */

.fm-time { margin-top: 18px; display: flex; flex-direction: column; gap: 8px; }
.fm-time-acts { display: flex; flex-wrap: wrap; gap: 6px; }
.fm-time-scroll { overflow-x: auto; }
.fm-time-grid { border-collapse: collapse; }
.fm-time-grid th { padding: 0; font-weight: 400; }
.fm-time-grid td { padding: 0; }
.fm-time-h, .fm-time-d {
  border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 10px; color: var(--muted); padding: 2px 3px;
}
.fm-time-h:hover, .fm-time-d:hover { color: var(--oda-green-deep); }
.fm-time-d { font-size: 11.5px; padding-right: 6px; }
.fm-cell {
  display: block;
  width: 17px; height: 17px;
  margin: 1px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 3px;
  /* Заливка — объём показов из тепловой карты; без карты клетка пустая. */
  background: rgba(105, 167, 76, calc(var(--heat, 0) * .3));
  cursor: pointer;
}
.fm-cell.hot { border-color: var(--oda-green); }
.fm-cell.on { background: var(--oda-green); border-color: var(--oda-green-deep); }
.fm-cell:hover { outline: 1px solid var(--oda-blue-deep); }
.fm-time-say { margin: 0; }

.fm-heat { border-top: 1px solid var(--line); padding-top: 10px; margin-top: 2px; }
.fm-heat-head { display: flex; flex-direction: column; gap: 2px; margin-bottom: 8px; }
.fm-heat-rec { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.fm-heat-rec p { margin: 0; font-size: 13px; }

/* ---------- деньги кампании ---------- */

.fm-money { margin-top: 14px; }
.fm-money-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 8px; }
.fm-money-tile {
  border: 1px solid var(--line); border-radius: 7px;
  background: var(--bg); padding: 9px 11px;
  display: flex; flex-direction: column; gap: 2px;
}
.fm-money-tile span { font-size: 11.5px; color: var(--muted); display: flex; align-items: center; gap: 3px; }
.fm-money-tile b { font-size: 17px; font-variant-numeric: tabular-nums; }
.fm-money-tile.bad b { color: var(--bad); }

/* Порядок цен: он один на три настройки, поэтому и написан один раз сверху. */
.fm-price-order code { font-family: ui-monospace, Consolas, monospace; font-size: 12px; }
.fm-rules-raw > summary { cursor: pointer; font-size: 12.5px; color: var(--muted); padding: 4px 0; }
.fm-rules-raw[open] > summary { color: var(--ink); }

.fm-error {
  border: 1px solid var(--bad);
  border-left: 3px solid var(--bad);
  border-radius: 6px;
  background: #fdf6f5;
  color: var(--bad);
  padding: 12px 14px;
  margin-bottom: 16px;
  font-size: 14px;
}
.fm-error ul { margin: 6px 0 0; padding-left: 18px; }

.fm-actions, .card-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 18px;
}
.fm-warn { font-size: 12.5px; color: var(--warn); }

/* ---- панель «Студия» ---- */

.studio-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.studio-head h4 { margin: 0 0 3px; font-size: 17px; }
.studio-head .sub { color: var(--muted); font-size: 13px; }

/* Деньги — самое важное на экране, поэтому идут сразу под шапкой и крупно. */
.studio-money {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px;
  margin: 16px 0;
}
.studio-tile {
  border: 1px solid var(--line);
  border-left: 3px solid var(--oda-mist);
  border-radius: 6px;
  padding: 12px 14px;
  background: var(--surface);
}
.studio-tile.ok { border-left-color: var(--oda-green); }
.studio-tile.warn { border-left-color: var(--warn); background: var(--warn-soft); }
.studio-tile.bad { border-left-color: var(--bad); }
.studio-tile.muted { border-left-color: var(--line); }
.studio-tile-label { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.studio-tile-value { font-size: 22px; font-weight: 600; margin: 4px 0 2px; font-variant-numeric: tabular-nums; }
.studio-tile.bad .studio-tile-value { color: var(--bad); }
.studio-tile.warn .studio-tile-value { color: var(--warn); }
.studio-tile-note { font-size: 12px; color: var(--muted); }

.studio-pace {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  font-size: 13px;
  color: var(--muted);
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
}
.studio-pace b { color: var(--ink); font-variant-numeric: tabular-nums; }

.studio-creatives { margin-top: 16px; }
.studio-creatives .card-head { padding: 0 0 10px; }

/* ---- генератор креативов в «Студии» ----
   Окно шаговое, и под каждым полем стоит подсказка. Подсказки набраны так,
   чтобы их было видно, но они не спорили с полем: тот же кегль, что у мелкого
   текста панели, приглушённый цвет и отступ ровно под контролом. */

.gen {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  margin: 18px 0;
}
.gen > summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 13px 16px;
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.gen > summary::-webkit-details-marker { display: none; }
.gen > summary::before {
  content: "▸";
  color: var(--muted);
  margin-right: 6px;
  transition: transform .15s;
}
.gen[open] > summary::before { content: "▾"; }
.gen-sum-note { font-weight: 400; font-size: 13px; color: var(--muted); }

.gen-step { padding: 16px; border-top: 1px solid var(--line); }
.gen-step-h {
  display: flex;
  align-items: center;
  gap: 9px;
  font-weight: 600;
  margin-bottom: 12px;
}
.gen-step-h b {
  display: inline-grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--oda-green);
  color: #fff;
  font-size: 12px;
}

.gen-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; }
.gen-field { margin-bottom: 14px; }
.gen-field > label:not(.gen-drop):not(.gen-check) {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: 5px;
}
.gen-field input[type="text"],
.gen-field input[type="url"],
.gen-field input[type="number"],
.gen-field select,
.gen-field textarea {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
}
.gen-field textarea { resize: vertical; line-height: 1.45; }
.gen-inline { display: flex; gap: 8px; }
.gen-inline select { flex: 1; }
.gen-inline input[type="number"] { width: 74px; }
.gen-check { display: flex; align-items: center; gap: 7px; font-size: 13px; margin-top: 9px; }
.gen-static {
  padding: 8px 10px;
  border: 1px dashed var(--line);
  border-radius: 6px;
  font-size: 14px;
  word-break: break-all;
}
.gen-static.mono { font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; font-size: 12.5px; }

/* Подсказка — не украшение: половина из них объясняет ограничение, о которое
   иначе спотыкаешься уже после того, как потратил кредиты. */
.gen-hint {
  margin: 6px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
}
.gen-hint code {
  font-family: ui-monospace, Consolas, monospace;
  font-size: 11.5px;
  background: var(--bg);
  padding: 1px 4px;
  border-radius: 3px;
}
.gen-hint b { color: var(--ink); font-weight: 600; }

.gen-services { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; }
.gen-svc {
  display: grid;
  gap: 2px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
}
.gen-svc.on { border-color: var(--oda-green); background: var(--ok-soft); }
.gen-svc input { display: none; }
.gen-svc span { color: var(--muted); font-size: 12px; }

.gen-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 10px; }

.gen-drop {
  display: grid;
  place-items: center;
  padding: 18px;
  border: 1px dashed var(--line);
  border-radius: 8px;
  background: var(--bg);
  color: var(--muted);
  font-size: 13px;
  cursor: pointer;
  margin: 10px 0;
}
.gen-drop.over { border-color: var(--oda-green); background: var(--ok-soft); }

.gen-specs { list-style: none; margin: 0; padding: 0; font-size: 13px; }
.gen-specs li {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  padding: 7px 0;
  border-bottom: 1px solid var(--line);
}
.gen-specs li:last-child { border-bottom: 0; }
/* Маркер — псевдоэлемент, то есть третий элемент флекса: без flex:1 на
   названии space-between растаскивает строку и загоняет подпись в центр. */
.gen-specs li > span:first-of-type { flex: 1; }
.gen-specs li > span:last-child { color: var(--muted); text-align: right; }
.gen-specs li::before { content: "•"; color: var(--muted); margin-right: 8px; }
.gen-specs li.ok::before { content: "✓"; color: var(--oda-green); }
.gen-specs li.bad::before { content: "✕"; color: var(--bad); }
.gen-specs li.bad > span:last-child { color: var(--bad); font-weight: 600; }

.gen-actions { display: flex; flex-wrap: wrap; gap: 9px; padding: 16px 16px 0; }
.gen-ord-note { padding: 0 16px 16px; }
#gen-out {
  margin: 0 16px 16px;
  padding: 12px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 12px;
  overflow-x: auto;
  white-space: pre;
}

.gen-stats { margin: 18px 0; }

/* История генераций свёрнута по умолчанию: развёрнутой она тянет портянку в
   полэкрана. Оформлена как генератор рядом — тот же складывающийся блок,
   поэтому и правила повторяют .gen: свои, а не общие, потому что у генератора
   внутри шаги с рамками, а здесь таблица. */
.gen-runs {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  overflow: hidden;
}
.gen-runs > summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 13px 16px;
  cursor: pointer;
  list-style: none;
}
.gen-runs > summary::-webkit-details-marker { display: none; }
.gen-runs > summary::before { content: "▸"; color: var(--muted); margin-right: 6px; }
.gen-runs[open] > summary::before { content: "▾"; }
/* Маркер — псевдоэлемент, то есть третий элемент флекса: без flex:1 на
   названии space-between растаскивает строку и уводит заголовок в центр.
   Правило общее с генератором — блоки стоят один над другим. */
.gen > summary > span:first-of-type,
.gen-runs > summary > span:first-of-type { flex: 1; }
.gen-runs > .gen-hint { padding: 0 16px 14px; }

.gen-runs-t td { vertical-align: top; }
.gen-runs-t .muted { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
/* 96 px и contain, а не 64 и cover: к истории вопрос ровно один — «что там
   было нарисовано», а баннер, обрезанный до квадрата в 64 px, на него не
   отвечает. Крупнее не делаем — строк много, а клик открывает файл целиком. */
.gen-run-thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 96px;
  height: 96px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  background: var(--bg);
  cursor: pointer;
}
.gen-run-thumb:hover { border-color: var(--oda-green); }
/* Не загрузилась — это факт, а не пустая рамка: файла может не быть у
   поставщика, и человек должен видеть разницу с «ещё грузится». */
.gen-run-thumb.broken { background: var(--warn-soft); }
.gen-run-thumb.broken .thumb-media { display: none; }
.gen-svc-left { color: var(--muted); font-size: 11.5px; }

.gen-stats-t { width: 100%; border-collapse: collapse; font-size: 13px; }
.gen-stats-t th {
  text-align: left;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--muted);
  padding: 6px 10px;
  border-bottom: 1px solid var(--line);
}
.gen-stats-t td { padding: 9px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
.gen-stats-t td.num { text-align: right; font-variant-numeric: tabular-nums; }
.gen-stats-t .muted { font-size: 12px; color: var(--muted); }

/* Подсказка под «?»: кнопка стоит в строке с названием поля, текст
   разворачивается под контролом. Развёрнутыми все сразу они забивали экран,
   а нужны обычно один раз — пока человек разбирается, что это за поле. */
.q {
  display: inline-grid;
  place-items: center;
  width: 16px;
  height: 16px;
  margin-left: 5px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--bg);
  color: var(--muted);
  font: 600 10px/1 inherit;
  cursor: pointer;
  vertical-align: middle;
}
.q:hover { border-color: var(--oda-green); color: var(--oda-green); }
.q.on { background: var(--oda-green); border-color: var(--oda-green); color: #fff; }
/* Подсказка лежит внутри label рядом с «?», но разворачивается блоком под
   названием поля — так она не растягивает строку заголовка. */
.gen-hint[id^="gen-h"] {
  display: block;
  margin: 6px 0 4px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
}
.gen-hint[id^="gen-h"][hidden] { display: none; }
.gen-step-h .gen-hint[id^="gen-h"] { flex-basis: 100%; }

.gen-x { align-self: center; color: var(--muted); }
.gen-custom { margin-top: 8px; }
.gen-custom input { width: 92px; }

.gen-auto { margin-bottom: 10px; }
.gen-auto-box {
  border: 1px solid var(--oda-green);
  background: var(--ok-soft);
  border-radius: 6px;
  padding: 11px 13px;
  font-size: 13.5px;
}
.gen-auto-box p { margin: 5px 0 0; color: var(--ink); font-size: 12.5px; line-height: 1.5; }
.gen-svc-note { margin-bottom: 12px; }
.gen-remind { color: var(--warn); }

.gen-drop.small { padding: 12px; margin: 0 0 10px; }
.gen-refs { display: flex; flex-wrap: wrap; gap: 10px; }
.gen-ref {
  position: relative;
  margin: 0;
  width: 122px;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  background: var(--surface);
}
.gen-ref img { display: block; width: 100%; height: 96px; object-fit: cover; }
.gen-ref figcaption { padding: 6px 7px; font-size: 11px; line-height: 1.35; word-break: break-all; }
.gen-ref-x {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 20px;
  height: 20px;
  border: 0;
  border-radius: 50%;
  background: rgba(35, 48, 44, .72);
  color: #fff;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}
.gen-stats-t td.num.low b { color: var(--bad); }

/* Редактор «CPM по доменам»: строка на домен вместо текстового поля,
   в котором надо было помнить синтаксис «домен = цена». */
.fm-dcpm-wrap .fm-count,
.fm-rules-wrap .fm-count {
  font-weight: 400;
  color: var(--muted);
  text-transform: none;
  letter-spacing: 0;
  margin-left: 6px;
}
.fm-dcpm { display: grid; gap: 6px; margin-bottom: 8px; }
.fm-dcpm-row { display: flex; align-items: center; gap: 6px; }
.fm-dcpm-row .fm-dcpm-d { flex: 1 1 auto; min-width: 0; }
.fm-dcpm-row .fm-dcpm-v { width: 96px; flex: none; text-align: right; }
.fm-dcpm-row input {
  padding: 7px 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
}
.fm-dcpm-cur { color: var(--muted); font-size: 13px; }
.fm-dcpm-x {
  width: 24px; height: 24px;
  flex: none;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: none;
  color: var(--muted);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}
.fm-dcpm-x:hover { border-color: var(--bad); color: var(--bad); }
/* Зона прилипает к левому краю прокрутки таблицы: иначе на широкой таблице
   она уезжает вбок вместе с колонками.
   ЛИПНЕТ ИМЕННО ЗОНА, А НЕ ЯЧЕЙКА. Ячейка растянута на все колонки, то есть
   ровно на ширину строки, — а sticky двигает элемент только внутри его
   контейнера, и такой ячейке двигаться некуда: она уезжала вбок вместе с
   таблицей, и у панели срезало левый край вместе с заголовком. Зона внутри
   ячейки узкая (её ширину ставит mountDrawer по видимой части), поэтому ей
   есть где прилипнуть. */
tr.row-host > td { position: relative; padding: 0; }
tr.row-host .drawer { position: sticky; left: 0; max-width: 100%; }
/* Пока раскрыта рабочая зона, таблица не ограничивает свою высоту: карточку
   неудобно читать в окне со своей прокруткой внутри страницы. */
.stat-table-wrap.row-expanded { max-height: none; }

/* Значки действий в строке кампании. Приглушены, пока на строку не навели:
   таблица читается числами, а не кнопками. */
.name-cell .name-top { display: flex; align-items: center; gap: 6px; }
.row-acts { display: inline-flex; gap: 2px; opacity: .35; transition: opacity .12s; }
tr:hover .row-acts, .row-acts:focus-within { opacity: 1; }
.row-act {
  display: inline-grid;
  place-items: center;
  width: 24px; height: 24px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 6px;
  background: none;
  color: var(--muted);
  cursor: pointer;
}
.row-act:hover { border-color: var(--line); background: var(--surface); color: var(--oda-green); }
.row-act:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 1px; }

/* «CPM по доменам»: правило .fm input[type="number"] сильнее по весу, поэтому
   ширину полей задаём селектором с тем же .fm внутри. */
.fm .fm-dcpm-row .fm-dcpm-d { flex: 1 1 auto; width: auto; min-width: 0; }
.fm .fm-dcpm-row .fm-dcpm-v { flex: 0 0 110px; width: 110px; text-align: right; }

/* Название кампании в списке — просто текст: карточку по клику там убрали,
   а вид ссылки обещал бы переход, которого больше нет. */
.name-plain { font-weight: 600; }

/* Студия внутри формы креатива: полоса готовых генераций, из которой картинка
   попадает в поле адреса одним кликом. */
.fm-studio { margin: 14px 0 10px; }
.fm-studio-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.fm-studio-list {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 8px; margin-top: 10px;
}
.fm-run {
  display: flex; flex-direction: column; gap: 4px; padding: 6px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--surface);
  cursor: pointer; text-align: left; font: inherit; color: inherit;
}
.fm-run:hover { border-color: var(--oda-green); }
/* Выбранную обводим заметно: после клика поле адреса уезжает вниз, и без
   отметки непонятно, какая именно картинка туда попала. */
.fm-run.picked { border-color: var(--oda-green); box-shadow: 0 0 0 2px var(--ok-soft); }
.fm-run img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 5px; display: block; }
.fm-run span { font-size: 11px; color: var(--muted); }
.fm-run.offline { opacity: .5; cursor: not-allowed; }
.fm-run-note { grid-column: 1 / -1; margin: 2px 0 0; }

/* Показатели галочками над графиками: их выбирают несколько сразу, и
   выпадающий список для этого не годится. */
.metric-picks { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 0 0 12px; }
.metric-pick {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; color: var(--ink); cursor: pointer; white-space: nowrap;
}
/* Панель на показатель: у каждого своя шкала, поэтому и своё полотно. */
.chart-panel + .chart-panel { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
.chart-panel-head { font-size: 12px; color: var(--muted); margin-bottom: 2px; }

/* Панель показателя задаёт высоту сама — общий min-height в 260px оставлял
   под каждым графиком пустую полосу, и три показателя не помещались на экран. */
.chart-panel .chart-box { min-height: 0; }

/* Higgsfield в «Студии». Своих правил ровно три: остальное берётся у
   генератора креативов рядом — сетка полей, кнопки и превью там уже есть,
   и второй набор тех же классов разъехался бы с первым при первой правке. */
.hf-result { display: flex; gap: 12px; align-items: flex-start; padding: 0 16px 8px; font-size: 13px; }
/* Ролик через себя не гоняем — вместо превью подпись в той же рамке. */
.hf-thumb-v { display: flex; align-items: center; justify-content: center; font-size: 11px; color: var(--muted); }

/* Правка креатива прямо в списке: строки раздвигаются, форма встаёт под своей
   строкой. Тот же приём, что у карточки кампании (tr.row-host), только этажом
   ниже — внутри ящика креативов. */
tr.row-form > td,
tr.row-form:hover > td { padding: 0; background: none; position: sticky; left: 0; }
.row-form .fm {
  max-width: 100%;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--oda-green);
  border-radius: 0 8px 8px 0;
  padding: 18px 20px 20px;
  margin: 2px 0 10px;
}
/* Форма стоит вплотную под своей строкой — шапке формы верхний отступ не нужен. */
.row-form .fm .drawer-head { margin-bottom: 14px; }
/* Правимая строка подсвечена: видно, к какому креативу относится форма. */
tr.row-editing > td { background: var(--ok-soft); }
tr.row-editing > td:first-child { box-shadow: inset 3px 0 0 var(--oda-green); }

/* Адрес перехода правится в шаге 1 «Студии»: моноширинный, как и было
   в статичной подписи — в ссылке важен каждый символ. */
.gen-field input.mono { font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; font-size: 12.5px; }

/* Подрядчик и запуск — один шаг генератора. Карточка сервиса говорит не только
   цену, но и то, запускается ли он отсюда: выбор, за которым не следует
   действие, должен выглядеть иначе, чем рабочий. */
.gen-svc-run { font-size: 11.5px; color: var(--oda-green-deep); }
.gen-svc-off { opacity: .72; }
.gen-svc-off .gen-svc-run { color: var(--muted); }
.gen-run-state { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.gen-run-state .pill { flex: none; }
.gen-run-fail { color: var(--bad); }
.gen-run-out { margin-top: 12px; }
.gen-run-out .hf-result { flex-wrap: wrap; padding-left: 0; }

/* «Что здесь бесплатно» — свёрнуто под сметой: вопрос возникает один раз,
   а место занимал бы всегда. */
.gen-free { margin-top: 12px; font-size: 13px; color: var(--oda-slate); }
.gen-free summary { cursor: pointer; color: var(--oda-green-deep); }
.gen-free ul { margin: 8px 0 0; padding-left: 20px; }
.gen-free li + li { margin-top: 4px; }
.gen-free p { margin: 10px 0 0; }

/* Смета захода — под кнопкой запуска: сколько спишется и что останется.
   Вопрос задаётся ровно в этот момент, значит и ответ должен быть здесь. */
.gen-spend { margin-top: 10px; font-weight: 600; color: var(--oda-slate); }
.gen-plan-note { margin-top: 6px; }

/* Отбор готовых вариантов в истории: галка в строке и полоса со счётчиком. */
.gen-pick-c { width: 32px; text-align: center; }
.gen-pick-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 16px; border-bottom: 1px solid var(--line);
  background: var(--side); font-size: 13px;
}
.gen-pick-note { color: var(--oda-green-deep); }

/* Ставки по признакам — JSON, и читается он моноширинным: в правиле важна
   каждая скобка. */
.fm-mono { font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; font-size: 12.5px; }
.fm-check { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.fm-check input { width: auto; margin: 0; }
.fm-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 10px; }

/* Конструктор «Ставок по признакам».
   Карточка правила читается сверху вниз как фраза: «если … и … то платим …»,
   а последней строкой сама себя пересказывает по-русски — без этого пересказа
   набор рамочек остаётся такой же головоломкой, как поле для JSON. */
.fm-rules { display: grid; gap: 10px; margin: 8px 0; }
.fm-rules-acts { display: flex; gap: 8px; flex-wrap: wrap; }
.fm-rule {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px;
  background: var(--surface);
  display: grid;
  gap: 8px;
}
.fm-rule-head { display: flex; align-items: center; gap: 6px; }
.fm-rule-head .fm-rule-name { flex: 1 1 auto; min-width: 0; }
.fm-rule-head button,
.fm-cond-x {
  width: 26px; height: 26px;
  flex: none;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: none;
  color: var(--muted);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}
.fm-rule-head button:hover, .fm-cond-x:hover { color: var(--ink); border-color: var(--ink); }
.fm-rule-head .fm-rule-x:hover, .fm-cond-x:hover { border-color: var(--bad); color: var(--bad); }
.fm-rule-conds { display: grid; gap: 6px; }
.fm-rule .fm-cond-add { justify-self: start; }
.fm-cond, .fm-rule-then { display: flex; align-items: center; gap: 6px; }
.fm-cond-lead, .fm-rule-lead {
  flex: 0 0 58px;
  white-space: nowrap;
  color: var(--muted);
  font-size: 13px;
  text-align: right;
}
.fm .fm-cond .fm-cond-k, .fm .fm-rule-then .fm-rule-mode { flex: 0 0 auto; width: auto; }
.fm .fm-cond .fm-cond-v { flex: 1 1 auto; min-width: 0; width: auto; }
.fm .fm-rule-then .fm-rule-val { flex: 0 0 110px; width: 110px; text-align: right; }
.fm-rule-unit { color: var(--muted); font-size: 13px; }
.fm-rule-say {
  margin: 0;
  padding-left: 64px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.45;
}
.fm-rules-text { margin-top: 8px; display: grid; gap: 6px; }

/* Автоставка: предупреждение о переезде ручных цен и то, что автомат держит. */
.fm-auto-note {
  margin-top: 10px;
  padding: 8px 10px;
  border-radius: 0 6px 6px 0;
  border-left: 3px solid var(--warn);
  background: var(--warn-soft);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.45;
}
.fm-auto-slices { margin-top: 10px; }
.fm-auto-slices summary { cursor: pointer; font-size: 13px; color: var(--muted); }
.fm-auto-rows { display: grid; gap: 3px; margin: 8px 0; max-height: 240px; overflow-y: auto; }
.fm-auto-row {
  display: grid;
  grid-template-columns: 1fr auto 74px;
  gap: 8px;
  align-items: baseline;
  font-size: 13px;
}
.fm-auto-row i { color: var(--muted); font-style: normal; font-size: 12px; }
.fm-auto-row b { text-align: right; font-variant-numeric: tabular-nums; }

/* Строка среза, которую нечем раскрыть («Итого», «Прочее», сам разрез по дате):
   рука над ней обещала бы раскрытие, которого не будет. */
table.stat tr.clickable.row-flat { cursor: default; }
table.stat tr.clickable.row-flat:hover td,
table.stat tr.clickable.row-flat:hover td:first-child { background: none; }

/* Стрелка темпа рядом с числом: как идёт сегодня против вчерашнего дня к
   этому же часу. Приглушена по умолчанию и загорается только на ухудшении —
   девять цветных стрелок в строке перестают что-либо значить. */
.delta {
  display: inline-block;
  position: relative;
  margin-left: 5px;
  width: 11px;
  color: var(--mist, #b9c4c1);
  font-size: 12px;
  line-height: 1;
  cursor: help;
  vertical-align: baseline;
}
.delta-bad { color: var(--bad); font-weight: 600; }
.delta::after {
  content: attr(data-hint);
  position: absolute;
  right: 0;
  bottom: calc(100% + 8px);
  width: max-content;
  max-width: 320px;
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--ink);
  color: #fff;
  font-size: 12px;
  line-height: 1.5;
  font-weight: 400;
  text-align: left;
  white-space: pre-line;
  opacity: 0;
  visibility: hidden;
  transition: opacity .12s;
  z-index: 5;
  pointer-events: none;
}
.delta:hover::after, .delta:focus-visible::after { opacity: 1; visibility: visible; }

/* ---------- меню колонок ---------- */
/* Тринадцать колонок метрик не влезают ни в один экран. Ненужные снимаются
   галочкой, порядок меняется перетаскиванием, выбор помнит браузер. */
.colpick { position: relative; display: inline-block; }
.colpick-panel {
  display: none;
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 6;
  min-width: 250px;
  max-height: 340px;
  overflow-y: auto;
  padding: 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .12);
}
.colpick.open .colpick-panel { display: block; }
.colpick-panel label {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 6px;
  border-radius: 6px;
  font-size: 13px;
  cursor: pointer;
}
.colpick-panel label:hover { background: var(--side); }
.colpick-panel input { width: auto; margin: 0; }
.colpick-foot {
  display: flex;
  gap: 6px;
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--line);
}
/* Подпись сверху, а не подсказка в углу: за ручку не потянут, если не сказать,
   что она ручка. Один раз прочитают — дальше она не мешает. */
.colpick-tip {
  margin: 0 0 6px;
  padding: 0 6px;
  color: var(--muted);
  font-size: 11px;
  line-height: 1.4;
}
.colpick-list { margin: 0; padding: 0; list-style: none; }
.colpick-item {
  display: flex;
  align-items: center;
  gap: 2px;
  border-radius: 6px;
}
.colpick-item label { flex: 1; min-width: 0; }
.colpick-item label span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Ручка перетаскивания. cursor: grab обещает ровно то, что произойдёт. */
.colpick-grip {
  padding: 0 2px 0 4px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1;
  cursor: grab;
  user-select: none;
}
.colpick-item.dragging { opacity: .45; }
.colpick-item.dragging .colpick-grip { cursor: grabbing; }
/* Стрелки — для клавиатуры и планшета, где перетаскивания нет. В покое они
   бледные, чтобы не спорить с названиями колонок. */
.colpick-move { display: flex; gap: 2px; }
.colpick-arrow {
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--muted);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
}
.colpick-arrow:hover:not(:disabled) { background: var(--side); color: var(--ink); }
.colpick-arrow:disabled { opacity: .3; cursor: default; }
/* Сколько креативов в каждом состоянии — у правого края пункта: «Остановленные»
   без числа не отвечают на вопрос, стоит ли туда заглядывать. */
.colpick-count { margin-left: auto; color: var(--muted); font-style: normal; font-size: 12px; }

/* ---------- управление креативом в строке ---------- */
.drawer-tools { display: inline-flex; align-items: center; gap: 8px; }
.cr-name {
  width: 100%;
  max-width: 260px;
  padding: 3px 6px;
  border: 1px solid transparent;
  border-radius: 5px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 12px;
}
.cr-name:hover { border-color: var(--line); }
.cr-name:focus { border-color: var(--oda-blue-deep); background: var(--surface); color: var(--ink); outline: none; }
.cr-weight { display: inline-flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.cr-weight input {
  width: 62px;
  padding: 4px 6px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  text-align: right;
}
.cr-weight i { color: var(--muted); font-style: normal; font-size: 11px; white-space: nowrap; }
.cr-weight i:empty { display: none; }
/* Кнопка-таблетка: тот же вид, что у метки статуса, но её видно как кнопку. */
.pill-act { border: 1px solid transparent; cursor: pointer; font: inherit; }
.pill-act:hover { border-color: currentColor; }
/* Статус кампании и кнопки перехода рядом: запуск, пауза, завершение. */
.camp-status { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; }
.camp-moves { display: inline-flex; gap: 4px; }
.camp-move { white-space: nowrap; }
.camp-move-active { color: var(--oda-green); border-color: currentColor; }
.camp-move-finished { color: var(--bad); }
/* Короткий ответ поля: сохранилось или нет. */
td.cr-saved { box-shadow: inset 0 0 0 2px var(--oda-green, #4a9d5f); transition: box-shadow .2s; }
td.cr-failed { box-shadow: inset 0 0 0 2px var(--bad); }
/* Архивная строка приглушена, но читаема: её открывают, чтобы вернуть. */
tr.row-archived td { opacity: .6; }
tr.row-archived:hover td { opacity: 1; }

/* Ссылка перехода правится в строке — третьей линией ячейки, а не своей
   колонкой: адрес в сто символов добавил бы боковую прокрутку, а места в
   высоту у строки хватает. */
.cr-link { display: flex; align-items: center; gap: 4px; min-width: 0; }
.cr-href { display: inline-flex; align-items: center; gap: 4px; width: 100%; min-width: 0; }
.cr-href input {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 300px;
  padding: 3px 6px;
  border: 1px solid transparent;
  border-radius: 5px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 12px;
}
.cr-href input:hover { border-color: var(--line); }
.cr-href input:focus { border-color: var(--oda-blue-deep); background: var(--surface); color: var(--ink); outline: none; }
.cr-open { flex: 0 0 auto; text-decoration: none; font-size: 13px; line-height: 1; }

/* Галочка выбора строки. Колонка узкая: в ней ничего, кроме галочки, нет. */
.stat td .cr-pick, .stat th [data-cr-pick-all] { margin: 0; cursor: pointer; }

/* Полоса действий над пачкой строк. Появляется, только когда что-то выбрано,
   и стоит НАД таблицей: выбирают сверху вниз, и уехавшая вниз полоса была бы
   за краем экрана ровно тогда, когда она нужна. */
.bulkbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 10px;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
}
.bulk-count { font-weight: 600; margin-right: 4px; }
.bulk-note { color: var(--muted); font-size: 12px; }
/* Колонка с галочкой — самая узкая в таблице: в ней ничего, кроме галочки,
   нет, и общие отступы ячейки тратили бы на неё место боковой прокрутки. */
.stat th:first-child:has([data-cr-pick-all]), .stat td:first-child:has(.cr-pick) {
  width: 1%;
  padding-left: 10px;
  padding-right: 2px;
}

/* ==========================================================================
   Узкий экран: кабинет на телефоне и планшете
   ==========================================================================
   Таблицы метрик на телефон не влезут никогда — их прокручивает
   .stat-table-wrap, и это правильно. А вот всё вокруг них влезать обязано:
   шапка рабочей зоны, кнопки и меню. Раньше шапка оставалась одной строкой,
   и кнопки «Добавить креатив» и «Закрыть» уезжали за правый край — то есть
   закрыть панель на телефоне было нечем. */
@media (max-width: 820px) {
  .drawer-head { flex-wrap: wrap; gap: 10px; }
  .drawer-head .drawer-acts { width: 100%; justify-content: flex-start; margin-left: 0; }
  .drawer-head h2 { font-size: 17px; }
  /* Отступы в ячейках вдвое меньше: на 13 колонках только воздух между
     числами съедает пол-экрана прокрутки. */
  table.stat th, table.stat td { padding: 9px 8px; font-size: 13px; }
  table.stat th { font-size: 11px; }
  /* Меню колонок и состояний открывается от своего края, а не от правого:
     у левой кнопки панель с right:0 вылезала за экран. */
  .colpick-panel { min-width: min(260px, calc(100vw - 48px)); }
  .cr-weight input { width: 52px; }
}

/* Створка графиков в шапке карточки. Подпись меняется словом, а не значком:
   стрелка вниз без текста одинаково читается и как «свернуть», и как
   «показать ещё», а слово не оставляет выбора. */
.fold-toggle { min-width: 92px; }

/* Журнал автомата в форме кампании. Створка, а не отдельный экран: вопрос
   «как он настроен» задают там же, где его включают, и уходить за ответом
   значит потерять несохранённую форму. */
.fm-auto-log { margin: 10px 0 4px; }
.fm-auto-log > summary { cursor: pointer; font-size: 13px; color: var(--oda-green-deep); }
.fm-auto-log-body { margin-top: 8px; }
.fm-auto-log-head {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  font-size: 13px;
  color: var(--muted);
}
.fm-auto-log-head b { color: var(--ink); }
/* Ручные правила над автоматом — не украшение: на этих срезах его решение до
   открутки не доходит, и без предупреждения журнал читается как враньё. */
.fm-auto-log-warn { color: var(--bad); width: 100%; }
.fm-auto-log-list { margin: 8px 0 0; padding: 0; list-style: none; font-size: 13px; }
.fm-auto-log-list li {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr) 130px minmax(0, 1.4fr);
  gap: 10px;
  padding: 5px 0;
  border-bottom: 1px solid var(--line);
}
.fm-auto-log-list li:last-child { border-bottom: none; }
.fm-auto-log-when, .fm-auto-log-why { color: var(--muted); }
.fm-auto-log-move { font-variant-numeric: tabular-nums; }
@media (max-width: 820px) {
  .fm-auto-log-list li { grid-template-columns: 1fr; gap: 2px; }
}

/* ==================== Финансы: «Очередь выплат» ==================== */

/* Плашка «Остатки на счетах» над очередью. */
.fin-accounts { margin-bottom: 16px; }
.fin-acc-head { font-size: 13px; color: var(--muted); margin-bottom: 8px; }
.fin-acc-head .hint { font-size: 11px; }
.fin-acc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 10px; }
.fin-acc {
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  padding: 12px 14px; border-left: 4px solid var(--oda-green);
}
.fin-acc-name { font-weight: 600; font-size: 14px; margin-bottom: 6px; }
.fin-acc-out { font-size: 18px; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; display: flex; flex-direction: column; }
.fin-acc-cap { font-size: 11px; font-weight: 400; color: var(--muted); margin-top: 2px; }
.fin-acc-q { font-size: 12px; color: var(--muted); margin-top: 6px; }
/* MadeTask — единственный счёт с живым остатком: выделен рамкой и крупной суммой. */
.fin-acc-primary { border-left-color: var(--oda-green-deep, var(--oda-green)); }
.fin-acc-bal {
  font-size: 22px; font-weight: 800; color: var(--ink);
  font-variant-numeric: tabular-nums; display: flex; flex-direction: column; margin-bottom: 6px;
}
.fin-acc-bal-off { color: var(--muted); font-weight: 700; }
.fin-acc-out-sm { font-size: 14px; font-weight: 600; }

/* Вкладки очереди с числом заявок. */
.fin-tabs { display: flex; gap: 6px; margin-bottom: 10px; flex-wrap: wrap; }
.fin-tab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 14px; border: 1px solid var(--line); background: var(--surface);
  border-radius: 999px; cursor: pointer; font-size: 13px; color: var(--muted);
}
.fin-tab:hover { background: var(--bg); }
.fin-tab.active { background: var(--ok-soft); color: var(--oda-green-deep); border-color: var(--oda-green); font-weight: 600; }
.fin-tab-n {
  font-variant-numeric: tabular-nums; font-size: 12px; font-weight: 600;
  background: var(--bg); border-radius: 999px; padding: 0 8px; min-width: 22px; text-align: center;
}
.fin-tab.active .fin-tab-n { background: #fff; }

/* Фильтр по способам оплаты: пилюли-переключатели, можно отметить несколько. */
.fin-payto { display: flex; gap: 6px; margin-bottom: 10px; flex-wrap: wrap; }
.fin-payto:empty { display: none; }
.fin-payto-pill {
  display: inline-flex; align-items: center;
  padding: 5px 12px; border: 1px solid var(--line); background: var(--surface);
  border-radius: 999px; cursor: pointer; font-size: 12.5px; color: var(--muted);
}
.fin-payto-pill:hover { background: var(--bg); }
.fin-payto-pill.active { background: var(--oda-green-deep); color: #fff; border-color: var(--oda-green-deep); font-weight: 600; }
.fin-payto-pill.fin-payto-clear { color: var(--bad); border-style: dashed; }

/* Полоса массового выбора. */
.fin-bulkbar {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--ok-soft); border: 1px solid var(--oda-green);
  border-radius: 10px; padding: 10px 14px; margin-bottom: 10px;
}
.fin-bulkbar #fin-bulk-summary { font-size: 14px; }

/* «Светофор»: точки-замечания в ячейке проверок. */
.fin-lights { white-space: normal; max-width: 260px; }
.fin-dot {
  display: inline-block; font-size: 11px; line-height: 1.5;
  padding: 1px 7px; border-radius: 999px; margin: 1px 2px 1px 0; white-space: nowrap;
}
.fin-dot.ok { background: var(--ok-soft); color: var(--oda-green-deep); font-weight: 700; }
.fin-dot.red { background: #f6e2df; color: var(--bad); }
.fin-dot.yellow { background: var(--warn-soft); color: var(--warn); }

/* Строки очереди: отмеченная и заблокированная (есть красное замечание). */
.fin-queue tr.picked > td { background: var(--ok-soft); }
.fin-queue tr.blocked > td:not(.fin-pick-cell) { opacity: 0.85; }
.fin-pick-cell { width: 34px; text-align: center; }
.fin-check, #fin-check-all { width: 16px; height: 16px; cursor: pointer; }

/* ---- «Очередь выплат»: работа со строкой, а не только просмотр ---- */

.fin-tools { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.fin-tools .hint { margin-left: auto; }

/* Полоса сообщений. В старой панели ошибки оплаты теряются молча, здесь у
   каждой попытки есть видимый исход — успех или объяснение отказа. */
.fin-note {
  border: 1px solid var(--line); border-left-width: 3px; border-radius: 6px;
  padding: 9px 12px; margin-bottom: 12px; font-size: 13px; line-height: 1.5;
}
.fin-note.ok { border-left-color: var(--oda-green); background: var(--ok-soft); }
.fin-note.warn { border-left-color: var(--warn); background: var(--warn-soft); }
.fin-note.err { border-left-color: var(--bad); background: #f6e2df; }

.fin-overdue { color: var(--bad); }
.fin-queue tr.fin-row { cursor: pointer; }
.fin-queue tr.fin-row:hover > td { background: var(--bg); }
.fin-queue tr.fin-row.row-open > td { background: var(--surface); box-shadow: inset 3px 0 0 var(--oda-blue-deep, var(--oda-green)); }
.fin-queue tr.fin-row.overdue > td:nth-child(4) { color: var(--bad); font-weight: 600; }
.fin-queue tr.fin-host > td { padding: 0; background: var(--surface); }

/* Переключатель «Рубли / USDT»: два списка, не фильтр внутри одного. */
.fin-cur {
  display: inline-flex; margin-bottom: 10px; max-width: 100%;
  border: 1px solid var(--line); border-radius: 10px; overflow: hidden;
}
.fin-cur button {
  display: inline-flex; align-items: center; gap: 7px;
  border: 0; background: var(--surface); padding: 8px 16px;
  font: inherit; font-size: 14px; cursor: pointer; color: var(--muted);
}
.fin-cur button + button { border-left: 1px solid var(--line); }
.fin-cur button:hover { background: var(--bg); }
.fin-cur button.active { background: var(--oda-green-deep); color: #fff; font-weight: 600; }
.fin-cur button.active .fin-tab-n { background: #fff; color: var(--oda-green-deep); }

/* Курс USDT на сегодня над списком. Жёлтая, если специальный курс не задан. */
.fin-rate {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px;
  border: 1px solid var(--line); border-left-width: 3px; border-left-color: var(--oda-green);
  border-radius: 6px; padding: 9px 12px; margin-bottom: 10px; font-size: 13px;
}
.fin-rate.warn { border-left-color: var(--warn); background: var(--warn-soft); }
.fin-rate b { font-size: 15px; font-variant-numeric: tabular-nums; }
.fin-rate form { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.fin-rate > .btn { margin-left: auto; }  /* «Обновить с BestChange» — к правому краю плашки */
.fin-rate input { width: 110px; }

/* Разделы очереди: срочно сегодня / просрочено / позже. */
.fin-queue tr.fin-group > td {
  background: var(--bg); font-weight: 600; font-size: 13px;
  padding-top: 12px; border-top: 2px solid var(--line);
}
.fin-queue tr.fin-group.urgent > td { color: var(--oda-green-deep); }
.fin-queue tr.fin-group.overdue > td { color: var(--bad); }
.fin-queue tr.fin-group .hint { font-weight: 400; margin-left: 8px; }
.fin-queue tr.fin-group { cursor: pointer; }
.fin-queue tr.fin-group:hover > td { background: var(--surface); }
.fin-group-toggle {
  border: none; background: none; padding: 0; margin: 0; font: inherit; color: inherit;
  cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
}
.fin-group-caret { display: inline-block; width: 10px; font-size: 11px; }
.fin-queue tr.fin-group.collapsed > td { border-top-color: var(--line); }

/* Подтверждение оплаты: что уйдёт в платёжную систему и код на всю пачку. */
.fin-paybox {
  border: 1px solid var(--line); border-radius: 8px; background: var(--surface);
  padding: 14px 16px; margin-bottom: 14px;
}
.fin-paybox-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 10px; }
.fin-paybox-head span { color: var(--muted); font-size: 13px; }
.fin-paybox-foot { display: flex; align-items: flex-end; gap: 12px; margin-top: 12px; flex-wrap: wrap; }
.fin-paybox-foot .field { margin: 0; }
.fin-paybox-foot input { width: 130px; }
.fin-batch-line { font-size: 11px; color: var(--muted); word-break: break-all; }
.fin-batch-line code { font-size: 11px; }

/* Карточка заявки: справка и решения на одном экране со списком. */
.fin-card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 20px; }
.fin-card-col h5 { margin: 0 0 6px; font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.fin-card-col h5:not(:first-child) { margin-top: 16px; }
.fin-card-col > div { margin-bottom: 3px; font-size: 14px; }
.fin-card-req { font-size: 15px; word-break: break-all; }
.fin-card-req .hint { display: block; font-size: 11px; }
.fin-req-copy {
  border: none; background: none; padding: 0; margin: 0; font: inherit; font-weight: 700;
  color: inherit; text-align: left; word-break: break-all; cursor: pointer;
  border-bottom: 1px dashed var(--line);
}
.fin-req-copy:hover { color: var(--oda-green-deep); border-bottom-color: var(--oda-green); }
.fin-req-copy.copied { color: var(--oda-green-deep); border-bottom-color: var(--oda-green); }
.fin-card-add { font-size: 12px; color: var(--muted); margin-top: 4px; }
.fin-card-warn { color: var(--bad); }
.fin-card-issues { margin-top: 12px; font-size: 12px; line-height: 1.9; }
.fin-card-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 18px; }
.fin-card-payto { display: flex; align-items: center; gap: 8px; margin-top: 12px; flex-wrap: wrap; font-size: 13px; }
.fin-card-payto select { max-width: 260px; }
.fin-card-more { margin-top: 14px; }
.fin-card-more summary { cursor: pointer; font-size: 13px; color: var(--muted); }
.fin-card-more .stat.tight { margin-top: 8px; }
.stat.tight td, .stat.tight th { padding: 4px 8px; font-size: 12px; }
.fin-log-diff { font-size: 11px; word-break: break-word; }

/* Отказ — единственное действие, которое не отменить: деньги вернутся, а
   заявку обратно не поднять. Отличается видом, а не только текстом. */
.btn.danger { border-color: var(--bad); color: var(--bad); background: transparent; }
.btn.danger:hover:not(:disabled) { background: #f6e2df; }

/* ---- «Перевыпуск плейсментов» (rerelease.js) ---- */

.badge.bad { background: #f6e2df; color: var(--bad); }
.rr-rules { margin: 0 0 14px; }
.rr-form { display: grid; gap: 12px; }
.rr-set { border: 1px solid var(--line); border-radius: 8px; padding: 8px 12px 10px; margin: 0; display: flex; flex-wrap: wrap; gap: 6px 16px; align-items: center; }
.rr-set legend { font-size: 13px; font-weight: 600; padding: 0 4px; }
.rr-set legend .hint { font-weight: 400; color: var(--muted); }
.rr-set .stat-hint { flex-basis: 100%; margin: 0; }
.rr-nets { display: flex; flex-wrap: wrap; gap: 4px 14px; }
.rr-net.off { color: var(--muted); }
.rr-warn { color: var(--bad) !important; font-weight: 600; }
.rr-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.rr-actions .hint { font-size: 12.5px; color: var(--muted); }
.rr-runs td { vertical-align: top; }
.rr-runs tr.row-open > td { background: var(--surface); box-shadow: inset 3px 0 0 var(--oda-green); }
.rr-progress { min-width: 140px; font-size: 12.5px; }
.rr-bar { height: 6px; border-radius: 3px; background: var(--line); overflow: hidden; margin-bottom: 3px; }
.rr-bar span { display: block; height: 100%; background: var(--oda-green); }
.rr-counters { font-size: 12.5px; max-width: 360px; }
.rr-count { display: inline-block; margin: 0 8px 2px 0; white-space: nowrap; color: var(--oda-slate); }
.rr-err { font-size: 12px; color: var(--bad); margin-top: 3px; max-width: 260px; }
.rr-acts { white-space: nowrap; }
.rr-block { margin-top: 18px; }
.rr-block h4 { font-size: 14.5px; margin: 0 0 8px; display: inline; }
.rr-block > h4 { display: block; }
.rr-block summary { cursor: pointer; margin-bottom: 8px; }
.rr-head-n { font-weight: 400; color: var(--muted); font-size: 13px; margin-left: 6px; }
.rr-block-tools { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.rr-block-tools .spacer { flex: 1; }
.rr-block-tools .hint { font-size: 12.5px; color: var(--muted); }
.rr-actions .btn:disabled { opacity: 0.45; cursor: default; }

/* ---- «Здоровье площадки» (врезка под строкой сайта в кабинете вебмастера) ---- */

.nowrap { white-space: nowrap; }
.site-health-row > td { background: var(--side); padding: 14px 16px 18px; }
.site-health { max-width: 1100px; }
.sh-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
.sh-head h4 { margin: 0; font-size: 15px; }
.sh-when { font-size: 12px; color: var(--muted); }
.sh-kpis { margin-bottom: 14px; }

/* Плашка порога. Это предложение, а не ошибка, — поэтому тёплая, а не красная. */
.gate-note {
  border: 1px solid var(--oda-mist); background: var(--surface);
  border-left: 3px solid var(--oda-green);
  border-radius: 8px; padding: 10px 14px; margin-bottom: 14px; font-size: 13.5px;
}

/* Закрытые значения. Под размытием НЕТ настоящих данных: сервер их не
   присылает (см. site-health.js) — это заглушка, чтобы форма панели читалась
   целиком и было видно, чего человек не видит. */
.blurred { filter: blur(4px); user-select: none; color: var(--muted); }
.kpi.locked { opacity: 0.8; }
.kpi.locked .k-value { color: var(--muted); }
.sh-table tr.locked td { color: var(--muted); }

/* Светофор */
.dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 7px; vertical-align: baseline; }
.dot.ok { background: var(--oda-green); }
.dot.warn { background: #d9a13b; }
.dot.bad { background: var(--bad); }
.dot.unknown { background: var(--oda-mist); }

.sh-summary { font-size: 13.5px; margin-bottom: 8px; }
.sh-table td { vertical-align: top; }
.sh-table td:first-child { font-weight: 600; width: 27%; }
.sh-table td:nth-child(2) { width: 17%; white-space: nowrap; }
.sh-value { font-weight: 400; color: var(--muted); font-size: 12.5px; margin-top: 2px; word-break: break-word; }
.sh-group-head th { background: var(--bg); font-size: 12.5px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--oda-slate); }
.sh-actions { margin-top: 14px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.sh-report { margin-top: 14px; }
.sh-report-body { background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 14px 18px; }
.sh-report-body h2 { font-size: 16px; margin: 18px 0 8px; }
.sh-report-body h3 { font-size: 14.5px; margin: 14px 0 6px; }
.sh-report-body h2:first-child { margin-top: 0; }
.sh-report-body p, .sh-report-body li { font-size: 14px; }
.sh-report-body ul, .sh-report-body ol { margin: 6px 0 10px; padding-left: 22px; }
.md-table td { font-size: 13px; }
.md-box { color: var(--oda-green-deep); }
/* Полоска вместо закрытого значения: под ней нет текста вовсе. */
.bar { display: inline-block; height: 9px; border-radius: 4px; background: linear-gradient(90deg, var(--line), var(--oda-mist)); vertical-align: middle; opacity: 0.7; }
.bar-s { width: 92px; }
.bar-l { width: 240px; max-width: 60%; }

/* ---- «Видимость в поиске» (keys.so) ---- */

.sh-seen { margin: 4px 0 16px; }
.sh-seen h5 { font-size: 14px; margin: 0 0 8px; display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.sh-seen-when { font-size: 11.5px; font-weight: 400; color: var(--muted); }
.sh-seen-empty { font-size: 13.5px; color: var(--oda-slate); margin: 0; }
.sh-seen-trend { font-size: 13.5px; margin: 8px 0 0; }
.sh-seen-trend.up { color: var(--oda-green-deep); }
.sh-seen-trend.down { color: var(--bad); }
.sh-seen-rivals { font-size: 12.5px; color: var(--oda-slate); margin: 8px 0 0; }
.sh-seen-rivals .muted { color: var(--muted); }
.sh-spark { margin-top: 10px; max-width: 560px; }
.sh-spark svg { width: 100%; height: 70px; display: block; }
.spark-line { fill: none; stroke: var(--oda-green); stroke-width: 2; vector-effect: non-scaling-stroke; }
.spark-area { fill: var(--ok-soft); stroke: none; }
.sh-spark-axis { display: flex; justify-content: space-between; font-size: 11.5px; color: var(--muted); margin-top: 2px; }

/* ---------- страница входа (public/login.html, с 2026-09-25) ---------- */

.login-wrap {
  display: flex;
  justify-content: center;
  padding: 56px 16px;
}
.login-card {
  width: 100%;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 24px 24px 26px;
}
.login-card h1 { margin: 0; font-size: 22px; }
.login-card .field input { width: 100%; box-sizing: border-box; }
.login-card .stat-error { margin: 0; padding: 10px 14px; }

/* ---- Главная кабинета вебмастера: «Сформировать отчёт» (ТЗ 27.09.2026) ---- */

.wm-account { overflow-wrap: anywhere; }
.wm-toolbar { margin-bottom: 10px; }
.wm-toolbar .field { flex: 1 1 160px; min-width: 0; }
.wm-toolbar .field select,
.wm-toolbar .field input { width: 100%; min-width: 0; box-sizing: border-box; }
.wm-toolbar .wm-field-sites { flex: 2 1 220px; }
.wm-toolbar .btn { white-space: nowrap; }
.wm-toolbar .btn:disabled { opacity: 0.45; cursor: default; }

.wm-presets { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 22px; }
.wm-presets .chip {
  font: inherit; font-size: 13px; padding: 5px 12px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 999px; background: var(--surface); color: var(--ink);
}
.wm-presets .chip:hover { border-color: var(--oda-green); }
.wm-presets .chip:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 2px; }
.wm-range-error { font-size: 13px; color: var(--bad); }

.kpi .k-wait { color: var(--muted); font-weight: 400; }

.wm-notice {
  margin: 0 0 22px; padding: 12px 16px; border-radius: 8px;
  background: #fff6d6; border: 1px solid #f0d77a; border-left: 4px solid #e0b400;
  color: #4a3b00; font-size: 14px; line-height: 1.45;
}

table.stat tfoot td { font-weight: 700; border-top: 2px solid var(--line); border-bottom: none; }

/* Мультиселект «Сайт»: кнопка как поле формы, под ней список с галочками. */
.msel { position: relative; }
.msel-btn {
  width: 100%; box-sizing: border-box; text-align: left; cursor: pointer;
  font: inherit; font-size: 14px; padding: 7px 30px 7px 10px;
  border: 1px solid var(--line); border-radius: 6px; background: var(--surface); color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; position: relative;
}
.msel-btn::after {
  content: ''; position: absolute; right: 12px; top: 50%; width: 7px; height: 7px; margin-top: -5px;
  border-right: 1.5px solid var(--muted); border-bottom: 1.5px solid var(--muted); transform: rotate(45deg);
}
.msel-btn:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 1px; }
.msel-pop {
  position: absolute; z-index: 30; left: 0; top: calc(100% + 4px); width: max(100%, 280px); max-width: calc(100vw - 32px);
  background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(35, 48, 44, 0.14); padding: 8px; box-sizing: border-box;
}
.msel-search {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 14px; padding: 7px 10px; margin-bottom: 6px;
  border: 1px solid var(--line); border-radius: 6px;
}
.msel-all, .msel-item { display: flex; align-items: center; gap: 8px; padding: 7px 6px; border-radius: 6px; cursor: pointer; font-size: 14px; }
.msel-all { font-weight: 600; border-bottom: 1px solid var(--line); border-radius: 6px 6px 0 0; margin-bottom: 4px; }
.msel-item:hover, .msel-all:hover { background: var(--ok-soft); }
.msel-item span { overflow-wrap: anywhere; }
.msel-item[hidden] { display: none; }
.msel-list { max-height: 280px; overflow-y: auto; }
.msel-empty { margin: 6px; color: var(--muted); font-size: 13px; }
.msel-foot { display: flex; justify-content: flex-end; padding-top: 6px; border-top: 1px solid var(--line); margin-top: 4px; }
.msel input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--oda-green); flex: none; }

/* «Ваш менеджер» в шапке: контакты при наведении, фокусе и касании. */
.mgr { position: relative; display: inline-block; }
.mgr-btn {
  font: inherit; font-size: 13px; color: var(--oda-blue-deep); background: none; border: none; padding: 0;
  cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px;
}
.mgr-btn:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 2px; }
.mgr-pop {
  display: none; position: absolute; right: 0; top: 100%; z-index: 40; min-width: 240px; margin-top: 6px;
  flex-direction: column; gap: 6px; padding: 12px 14px; text-align: left;
  background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(35, 48, 44, 0.14); color: var(--ink); font-size: 13.5px;
}
.mgr-pop::before { content: ''; position: absolute; left: 0; right: 0; top: -8px; height: 8px; }
.mgr-pop a { color: var(--oda-blue-deep); overflow-wrap: anywhere; }
.mgr:hover .mgr-pop, .mgr:focus-within .mgr-pop, .mgr.open .mgr-pop { display: flex; }

/* «Площадки»: статус цветом, «Здоровье» — заметная зелёная кнопка. */
.site-status { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 13px; font-weight: 600; white-space: nowrap; }
.site-status.ok { color: #2f6b1f; background: var(--ok-soft); }
.site-status.bad { color: #9b2c22; background: #fbe6e3; }
.site-status.wait { color: #7a5a00; background: #fff3c4; }
.btn.btn-health { display: inline-block; text-decoration: none; background: #3f9a2d; color: #fff; }
.btn.btn-health:hover { background: #2f7d20; }

@media (max-width: 520px) {
  .wm-toolbar .field, .wm-toolbar .wm-field-sites { flex: 1 1 100%; }
  .wm-toolbar .btn { flex: 1 1 auto; }
  .mgr-pop { right: auto; left: 50%; transform: translateX(-50%); max-width: calc(100vw - 32px); }
}
.wm-presets .spacer { flex: 1; }
.wm-presets .btn:disabled { opacity: 0.45; cursor: default; }
@media (max-width: 520px) { .wm-presets #wm-xlsx { flex: 1 1 100%; } }

/* ---- Главная вебмастера: колонки виджетов и «Динамика» (правки 28.09.2026) ---- */

.wm-stat-table .wm-widget-name { min-width: 220px; overflow-wrap: anywhere; }

.wm-trend { margin-bottom: 22px; }
.wm-trend-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
.wm-trend-head h3 { margin: 0; }
.wm-trend-sub { margin: 4px 0 0; font-size: 13px; color: var(--muted); }
.wm-seg { display: flex; gap: 6px; flex-wrap: wrap; }
.wm-seg .chip {
  font: inherit; font-size: 13px; padding: 5px 12px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 999px; background: var(--surface); color: var(--ink);
}
.wm-seg .chip.is-on { background: var(--ok-soft); border-color: var(--oda-green); color: var(--oda-green-deep); font-weight: 600; }
.wm-seg .chip:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 2px; }

.wm-metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 14px; }
.wm-metric {
  display: flex; flex-direction: column; gap: 3px; text-align: left; cursor: pointer;
  font: inherit; padding: 10px 12px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink);
}
.wm-metric:hover { border-color: var(--oda-green); }
.wm-metric.is-on { border-color: var(--oda-green); box-shadow: inset 0 0 0 1px var(--oda-green); background: var(--ok-soft); }
.wm-metric:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 2px; }
.wm-metric-label { font-size: 12px; color: var(--muted); }
.wm-metric-hint { font-size: 11px; opacity: 0.8; }
.wm-metric-value { font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; }
.wm-delta { font-size: 12px; font-variant-numeric: tabular-nums; }
.wm-delta.up { color: #2f6b1f; }
.wm-delta.down { color: #9b2c22; }
.wm-delta.flat { color: var(--muted); }

.wm-trend-legend { display: flex; flex-wrap: wrap; gap: 16px; font-size: 13px; color: var(--muted); margin-bottom: 6px; min-height: 18px; }
.wm-leg { display: inline-flex; align-items: center; gap: 6px; }
.wm-leg-sw { width: 14px; height: 3px; border-radius: 2px; display: inline-block; }
.wm-leg-sw.cur { background: var(--s1); }
.wm-leg-sw.prev { background: var(--muted); }
.wm-trend-chart { min-height: 280px; }
.wm-trend-facts { margin: 10px 0 0; font-size: 13.5px; color: var(--muted); }
.wm-trend-facts b { color: var(--ink); }

@media (max-width: 520px) {
  .wm-metrics { grid-template-columns: 1fr 1fr; }
  .wm-metric-value { font-size: 16px; }
}
.wm-leg-note { margin-left: auto; font-size: 12px; }
@media (max-width: 520px) { .wm-leg-note { margin-left: 0; flex-basis: 100%; } }

/* «Динамика» свёрнута по умолчанию: заголовок карточки — кнопка раскрытия. */
.wm-trend-toggle {
  display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 12px;
  font: inherit; text-align: left; cursor: pointer; background: none; border: none; padding: 0; color: var(--ink);
}
.wm-trend-toggle:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 4px; border-radius: 6px; }
.wm-trend-title { display: block; font-size: 16px; font-weight: 700; }
.wm-trend-toggle .wm-trend-sub { display: block; margin-top: 4px; }
.wm-trend-caret {
  flex: none; font-size: 13.5px; font-weight: 600; color: var(--oda-green-deep);
  padding: 7px 14px; border: 1px solid var(--oda-green); border-radius: 6px; background: var(--ok-soft);
}
.wm-trend-caret::after { content: ' ▾'; }
.wm-trend-toggle[aria-expanded="true"] .wm-trend-caret::after { content: ' ▴'; }
.wm-trend-toggle:hover .wm-trend-caret { background: #dcebd3; }
#wm-trend-body { margin-top: 14px; }
#wm-trend-body .wm-seg { margin-bottom: 14px; }
@media (max-width: 520px) {
  .wm-trend-toggle { flex-wrap: wrap; }
  .wm-trend-caret { width: 100%; text-align: center; }
}

/* =====================================================================
   Кабинет вебмастера — единый стиль (28.09.2026, итоговые варианты разбора
   главной и «Здоровья площадки»). Правила:
   — одна главная цифра на экране и сравнение у каждой цифры;
   — состояние словом в метке (tag), а не только цветом;
   — числа справа и моноширинными цифрами, деньги с запятой;
   — сначала «что сделать», потом подробности.
   ===================================================================== */

.tag {
  display: inline-block; padding: 2px 9px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600; line-height: 1.5; white-space: nowrap;
}
.tag.ok { color: #2f6b1f; background: var(--ok-soft); }
.tag.wait { color: #7a5a00; background: #fff3c4; }
.tag.bad { color: #9b2c22; background: #fbe6e3; }
.tag.muted { color: var(--muted); background: #eef1f0; }

.wm-card-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 12px; margin-bottom: 12px; }
.wm-card-head h3 { margin: 0; font-size: 16px; font-weight: 700; }
.wm-card-head .wm-trend-sub { margin: 0; }
.wm-link { color: var(--oda-blue-deep); font-size: 13.5px; font-weight: 600; text-decoration: none; white-space: nowrap; }
.wm-link:hover { text-decoration: underline; }

/* ---- главная: шапка и четыре плитки ---- */
.wm-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 12px 24px; margin-bottom: 18px; }
.wm-head h1 { margin: 0 0 2px; }
.wm-head .wm-account { margin: 0; }
.wm-fresh { margin: 4px 0 0; font-size: 13.5px; color: var(--muted); max-width: 70ch; }

.wm-kpis { display: grid; grid-template-columns: 1fr 1.15fr 1fr 1.3fr; gap: 12px; margin-bottom: 14px; }
.wm-k { display: flex; flex-direction: column; justify-content: flex-start; min-width: 0; }
.wm-k .k-value { overflow-wrap: anywhere; }
.wm-k-hero { border-color: var(--oda-green); box-shadow: inset 0 0 0 1px var(--oda-green); }
.wm-k-hero .k-value { font-size: 30px; color: var(--oda-green-deep); }
.wm-k-balance { background: var(--ink); border-color: var(--ink); color: #fff; flex-direction: row; align-items: center; justify-content: space-between; gap: 12px; }
.wm-k-balance .k-title, .wm-k-balance .k-hint { color: #b9c7c1; }
.wm-k-balance .btn { flex: none; text-decoration: none; }
.wm-progress { height: 7px; border-radius: 4px; background: var(--ok-soft); margin-top: 8px; overflow: hidden; }
.wm-progress i { display: block; height: 100%; background: var(--oda-green); border-radius: 4px; }

/* ---- что важно сегодня ---- */
.wm-hints { padding-bottom: 14px; }
.wm-hint-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px 16px; }
.wm-hint { border-left: 4px solid var(--oda-green); padding: 2px 0 2px 12px; min-width: 0; }
.wm-hint.bad { border-color: var(--bad); }
.wm-hint.wait { border-color: #e0b400; }
.wm-hint b { display: block; font-size: 14px; overflow-wrap: anywhere; }
.wm-hint p { margin: 3px 0 6px; font-size: 13px; color: var(--oda-slate); line-height: 1.45; }
.wm-hint a { font-size: 13.5px; font-weight: 600; color: var(--oda-blue-deep); }
.wm-calm { margin: 0; font-size: 14px; color: var(--oda-slate); }
.wm-calm .tag { margin-right: 6px; }

/* ---- площадки и форматы ---- */
.wm-split { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; }
.wm-split .card { margin-bottom: 18px; }
.wm-sites .stat-table-wrap { margin-top: 0; }
.wm-sites-table td, .wm-sites-table th { padding: 9px 11px; }
.wm-site-name { min-width: 150px; max-width: 320px; overflow-wrap: break-word; word-break: normal; font-weight: 600; }
.wm-more { margin-top: 10px; }

.wm-fmt-bar { display: flex; height: 14px; border-radius: 7px; overflow: hidden; background: #eef1f0; gap: 2px; margin: 4px 0 14px; }
.wm-fmt-bar i { display: block; height: 100%; }
.wm-fmt-bar i.static, .wm-fmt-sw.static { background: var(--oda-green); }
.wm-fmt-bar i.sticker, .wm-fmt-sw.sticker { background: var(--oda-blue-deep); }
.wm-fmt-bar i.other, .wm-fmt-sw.other { background: #98a5a0; }
.wm-fmt-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px 28px; }
.wm-fmt-list li { display: grid; grid-template-columns: 12px 1fr auto; gap: 2px 10px; align-items: baseline; font-size: 14px; }
.wm-fmt-sw { width: 12px; height: 12px; border-radius: 3px; align-self: center; }
.wm-fmt-name { font-weight: 600; }
.wm-fmt-share { font-variant-numeric: tabular-nums; color: var(--muted); }
.wm-fmt-sum { grid-column: 2; font-variant-numeric: tabular-nums; }
.wm-fmt-rpm { grid-column: 2 / 4; font-size: 12.5px; color: var(--muted); }

/* ---- отчёт ---- */
.wm-report .stat-toolbar { margin-top: 0; }
.wm-totals { display: flex; flex-wrap: wrap; gap: 6px 22px; font-size: 13.5px; color: var(--muted); min-height: 20px; }
.wm-totals b { color: var(--ink); font-variant-numeric: tabular-nums; }
.wm-table-title { margin: 16px 0 0; font-size: 14px; font-weight: 600; }
.wm-report .stat-table-wrap { margin-top: 10px; }

@media (max-width: 1180px) {
  .wm-kpis { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .wm-kpis { grid-template-columns: minmax(0, 1fr); }
  .wm-k-balance { flex-wrap: wrap; }
  .wm-k-balance .btn { width: 100%; text-align: center; }
  .wm-head .wm-seg { width: 100%; }
}

/* ---- «Здоровье площадки»: итоговый вариант (28.09.2026) ---- */
.sh2 { display: block; }
.sh-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 20px; margin-bottom: 14px; }
.sh-verdict { display: flex; align-items: center; gap: 12px; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: 10px 16px; }
.sh-verdict b { display: block; font-size: 17px; }
.sh-verdict span:not(.sh-dot) { display: block; font-size: 12.5px; color: var(--muted); }
.sh-dot { width: 14px; height: 14px; border-radius: 50%; flex: none; background: var(--oda-green); }
.sh-verdict.wait .sh-dot { background: #e0b400; }
.sh-verdict.bad .sh-dot { background: var(--bad); }
.sh-verdict.muted .sh-dot { background: #98a5a0; }
.sh-switch { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); min-width: 0; }
.sh-switch select { font: inherit; font-size: 14px; padding: 6px 8px; width: 300px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); color: var(--ink); max-width: 100%; }
.sh-kpis { margin-bottom: 6px; }
.sh-loads { margin: 0 0 16px; font-size: 13px; color: var(--muted); }

.sh-todo-list { list-style: none; margin: 0; padding: 0; counter-reset: todo; }
.sh-todo-list li { counter-increment: todo; display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; gap: 4px 12px; align-items: center; padding: 10px 0; border-top: 1px solid var(--line); }
.sh-todo-list li:first-child { border-top: 0; padding-top: 0; }
.sh-todo-list li::before { content: counter(todo); width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; color: #fff; font-weight: 700; font-size: 13px; background: #e0b400; }
.sh-todo-list li.bad::before { background: var(--bad); }
.sh-todo-main b { display: block; font-size: 14.5px; }
.sh-todo-main p { margin: 2px 0 0; font-size: 13px; color: var(--oda-slate); overflow-wrap: anywhere; }
.sh-todo-cost { text-align: right; font-size: 12.5px; color: var(--muted); }
.sh-todo-cost b { color: var(--bad); font-size: 14px; font-variant-numeric: tabular-nums; }
.sh-todo-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }

.sh-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 0 18px; align-items: start; }
.sh-line { position: relative; height: 74px; margin: 6px 12px 4px 4px; }
.sh-line-track { position: absolute; left: 0; right: 0; top: 10px; height: 4px; background: var(--line); border-radius: 2px; }
.sh-line-mark { position: absolute; top: 3px; transform: translateX(-50%); text-align: center; font-size: 12px; line-height: 1.35; white-space: nowrap; }
.sh-line-mark.now { transform: none; text-align: left; }
.sh-line-mark i { display: block; width: 18px; height: 18px; border-radius: 50%; border: 3px solid var(--surface); background: var(--oda-green); margin: 0 auto 4px; box-shadow: 0 0 0 1px var(--line); }
.sh-line-mark.now i { background: var(--ink); margin: 0 0 4px; }
.sh-line-mark.warn i { background: #e0b400; }
.sh-line-mark.bad i { background: var(--bad); }
.sh-line-mark.bad b { color: var(--bad); }
.sh-dates-note { margin: 4px 0 0; font-size: 12.5px; color: var(--muted); }

.sh-seen-main { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 10px 18px; font-size: 14px; }
.sh-seen-big { font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; }
.sh-seen .sh-spark { width: 200px; max-width: 100%; }

.sh-groups { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 8px; }
.sh-group {
  text-align: left; font: inherit; cursor: pointer; color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-top: 4px solid var(--oda-green); border-radius: 8px; padding: 9px 11px;
}
.sh-group.warn { border-top-color: #e0b400; }
.sh-group.bad { border-top-color: var(--bad); }
.sh-group.unknown { border-top-color: #98a5a0; }
.sh-group[aria-expanded="true"] { background: var(--bg); box-shadow: inset 0 0 0 1px var(--oda-green); }
.sh-group:focus-visible { outline: 2px solid var(--oda-blue-deep); outline-offset: 2px; }
.sh-group b { display: block; font-size: 13.5px; }
.sh-group span { font-size: 12.5px; color: var(--muted); }
.sh-group em { font-style: normal; font-weight: 600; }
.sh-group em.bad { color: var(--bad); }
.sh-group em.warn { color: #7a5a00; }
.sh-group-rows { margin-top: 10px; }
.sh-group-rows td { vertical-align: top; font-size: 13.5px; }
.sh-unknown { margin: 12px 0 4px; font-size: 13px; color: var(--muted); }
.nowrap { white-space: nowrap; }

@media (max-width: 560px) {
  .sh-todo-list li { grid-template-columns: 28px minmax(0, 1fr); }
  .sh-todo-cost { grid-column: 2; text-align: left; }
  .sh-pair { grid-template-columns: minmax(0, 1fr); }
  .sh-switch { width: 100%; flex-wrap: wrap; }
  .sh-switch select { width: 100%; }
}

/* Разделы кабинета вебмастера (кроме главной и «Здоровья» — там .wide). */
.content.wm-section:not(.wide) { max-width: 1180px; }
.wm-section table.stat td.nowrap { white-space: nowrap; }
