/*
   FilterSync
   Developer / Разработчик: IEVGENII OKHRYMENKO (https://github.com/okhko)
   © MIRIDON. Proprietary software - see LICENSE. Проприетарное ПО - см. LICENSE.
*/
/* Планировщик обслуживания — стили. Светлая и тёмная темы на CSS-переменных:
   тема переключается атрибутом data-theme на <html> (см. app.js). */
* { box-sizing: border-box; }

:root {
  color-scheme: light;
  /* Нейтральная шкала — zinc (в духе дизайн-системы shadcn/ui «New York»):
     истинно-серые тона вместо прежнего синеватого оттенка фона/границ/текста.
     Акцент/ссылка/--text/--strong-bg — фирменные цвета MIRIDON (брендбук
     2026-08-05): PÕHIVÄRV SININE #0057B7 (PANTONE 2935 C) и PÕHIVÄRV MUST
     #212322 (PANTONE 419 C). Семантические --ok/--err/бейджи намеренно НЕ
     тронуты — это функциональные статусы (успех/ошибка), не бренд-decor. */
  --bg: #fafafa;             /* фон страницы (zinc-50) */
  --panel: #fff;             /* карточки/панели */
  --text: #212322;           /* основной текст — фирменный чёрный PANTONE 419 C */
  --muted: #71717a;          /* приглушённый текст (zinc-500) */
  --border: #e4e4e7;         /* границы полей (zinc-200) */
  --border-light: #f4f4f5;   /* тонкие разделители (zinc-100) */
  --hover: #f4f4f5;          /* фон при наведении (zinc-100) */
  --active-bg: #e5f2ff;      /* выбранный элемент списка (тон фирменного синего) */
  --active-border: #80bcff;
  --chip-bg: #f4f4f5;        /* чипы, code, мелкие кнопки (zinc-100) */
  --chip-hover: #e4e4e7;     /* zinc-200 */
  --input-bg: #fff;
  --th-bg: #fafafa;          /* шапка таблиц (zinc-50) */
  --row-hover: #fafafa;
  --map-bg: #dde3ec;
  --strong-bg: #212322;     /* тёмные акценты: актив. подвкладка, тост — фирменный чёрный */
  --strong-fg: #fff;
  --accent: #0057B7;        /* фирменный синий PANTONE 2935 C */
  --accent-hover: #00448e;
  --link: #0057B7;
  --brand-mint: #5DD39E;     /* lisavärv mint, PANTONE 346 C — только декоративные акценты */
  --brand-green: #BCE784;    /* lisavärv roheline, PANTONE 366 C — только декоративные акценты */
  --ok: #17803d;
  --err: #b42318;
  --warn-bg: #fff6e6; --warn-border: #f2c94c; --warn-text: #7a5200;
  --shadow: 0 1px 2px rgba(16,24,40,.05);
  --shadow-lg: 0 4px 16px rgba(16,24,40,.09);
  --best-bg: #f6fbf7;       /* лучший кандидат диспетчера */
  /* Токены, которые раньше жили ТОЛЬКО как var(--x, fallback) — сам --x нигде
     не был определён, поэтому реально всегда рендерился fallback (де-факто
     хардкод под синтаксисом переменной). Определяем явно и переиспользуем уже
     существующие семантические токены вместо близких, но самостоятельных
     копий — единообразие вместо разрозненных оттенков (аудит дизайн-системы
     2026-08-04). */
  --accent-soft: rgba(0, 87, 183, .12);  /* rgb-канал --accent */
  --ok-bg: var(--badge-ok-bg); --ok-text: var(--badge-ok-fg);
  --err-bg: var(--badge-err-bg); --err-text: var(--badge-err-fg);
  --warn: var(--warn-text);
  --danger: var(--err);
  --panel-2: rgba(127, 127, 127, .12);   /* нейтральна к теме — не переопределяется в dark */
  /* Семантическая палитра бейджей: источник записи, важность/срочность/приоритет
     события, легенда телеметрии. Единый набор пар «фон/текст» вместо
     разбросанных литералов. Значения едины для светлой и тёмной темы — бейджи
     цветные и не зависят от темы (в dark-блоке не переопределяются). */
  --badge-info-bg: #e7edf7;   --badge-info-fg: #1f4e8c;    /* инфо / ручной ввод */
  --badge-warn-bg: #fdf3d7;   --badge-warn-fg: #8a6100;    /* важность «обычная» */
  --badge-urgent-bg: #fdeede; --badge-urgent-fg: #b25e09;  /* срочно / симулятор */
  --badge-err-bg: #fde4e1;    --badge-err-fg: #b3261e;     /* ошибка / критично */
  --badge-err-rgb: 179, 38, 30;  /* тот же красный для полупрозрачных подложек */
  --badge-ok-bg: #e6f4ea;     --badge-ok-fg: #1a7f37;      /* устройство / успех */
  --badge-import-bg: #efe7f7; --badge-import-fg: #6b3fa0;  /* импорт */
  /* Шрифт бренда — Gotham (платный, встроить нельзя, см. static/vendor/poppins/);
     Poppins геометрически близок и покрывает те же 4 начертания
     Light/Book/Medium/Bold → 300/400/500/700. Системный sans — резерв на
     время загрузки/для кириллицы (Poppins её не содержит, как и сам Gotham). */
  --font-sans: "Poppins", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* Дизайн-токены: единые отступы, радиусы, типографика, переходы. */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px;
  --r-xs: 4px; --r-sm: 6px; --r-md: 8px; --r-lg: 10px; --r-xl: 12px; --r-pill: 999px;
  --fs-2xs: 11px; --fs-xs: 12px; --fs-sm: 13px; --fs-md: 14px; --fs-lg: 16px;
  --t-fast: .15s;
  --ctrl-h: 32px;          /* единая высота полей и кнопок-действий */
}
html[data-theme="dark"] {
  color-scheme: dark;
  /* Та же нейтральная шкала zinc, тёмная сторона — см. комментарий в :root. */
  --bg: #09090b;             /* zinc-950 */
  --panel: #18181b;          /* zinc-900 */
  --text: #fafafa;           /* zinc-50 */
  --muted: #a1a1aa;          /* zinc-400 */
  --border: #3f3f46;         /* zinc-700 */
  --border-light: #27272a;   /* zinc-800 */
  --hover: #27272a;          /* zinc-800 */
  --active-bg: #24344f;
  --active-border: #3e5578;
  --chip-bg: #27272a;        /* zinc-800 */
  --chip-hover: #3f3f46;     /* zinc-700 */
  --input-bg: #09090b;       /* на тон темнее панели — «утопленное» поле */
  --th-bg: #27272a;          /* zinc-800 */
  --row-hover: #27272a;
  --map-bg: #1c2536;
  --strong-bg: #3b4c68;
  --strong-fg: #fff;
  --accent: #1e89ff;         /* фирменный синий, осветлён для контраста на тёмном фоне */
  --accent-hover: #479eff;
  --link: #65aeff;
  --ok: #4ade80;
  --err: #f87171;
  --warn-bg: #33290f; --warn-border: #7a5200; --warn-text: #f2c94c;
  --shadow: 0 1px 3px rgba(0,0,0,.4);
  --shadow-lg: 0 6px 24px rgba(0,0,0,.5);
  --best-bg: #1c2c22;
  --accent-soft: rgba(30, 137, 255, .16);  /* rgb-канал --accent тёмной темы */
}

html, body { height: 100%; }
body {
  margin: 0;
  font: 14px/1.45 var(--font-sans);
  color: var(--text);
  background: var(--bg);
}
/* Единая вторичная кнопка действий. Ссылки/вкладки/иконочные кнопки
   сбрасывают оформление ниже (сохраняют свой компактный вид). */
button { font: inherit; cursor: pointer; color: var(--text);
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: 6px 12px; min-height: var(--ctrl-h);
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast); }
button:hover { background: var(--hover); }
/* Спец-кнопки без «коробки»: своя высота/паддинги. */
.tabs .tab, .theme-toggle, .qhelp, .link, .mon-sbtn, .zone-bar button,
.ctl button, .stop-row .ctl button, .pager button, .mon-hist-btns button {
  min-height: 0; }
.theme-toggle, .qhelp, .link, .ctl button, .stop-row .ctl button { padding: 0; }
input, select, textarea { font: inherit; padding: 5px 8px; min-height: var(--ctrl-h);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--input-bg); color: var(--text); transition: border-color var(--t-fast); }
input.mini, input.mini[type], .worker-item select, select.visit-sel { min-height: 0; }
/* Единая клавиатурная фокус-обводка (доступность). */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
button:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, a:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
input:focus, select:focus, textarea:focus { border-color: var(--accent); outline: none; }
label { display: block; margin: 6px 0; }
h3 { margin: 0 0 8px; font-size: var(--fs-md); }

/* Шапка всегда в одну строку (ТЗ §2.1): при нехватке места вкладки
   прокручиваются по горизонтали, а не переносятся — иначе высота шапки
   «плавает» и ломает расчёт высоты рабочей области (100vh - 48px). */
/* Шапка — грид из трёх колонок 1fr auto 1fr: бренд слева, меню в центральной
   колонке (ровно по центру СТРАНИЦЫ, а не между брендом и правым блоком),
   пользовательский блок справа. Так верхнее меню и ряд под-вкладок (тоже
   центрированный по странице) выровнены по одной оси — эстетично (§2.2). */
.topbar {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  gap: 8px; min-height: 48px;
  padding: 8px 16px; color: #fff;
  /* Фирменный чёрный → затемнённый фирменный синий (та же светлота, что
     раньше у произвольной тёмно-синей пары). */
  background: linear-gradient(90deg, #212322 0%, #002957 100%);
  box-shadow: 0 1px 4px rgba(16,24,40,.12);
}
.tabs { display: flex; flex-wrap: nowrap; overflow-x: auto;
  scrollbar-width: thin; min-width: 0; justify-self: center; justify-content: center; }
.tabs .tab { white-space: nowrap; flex: none; }
.brand { font-weight: 600; display: flex; align-items: center; gap: 8px;
  white-space: nowrap; justify-self: start; min-width: 0; }
.userbox { justify-self: end; }
/* Клик по бренду → главная (§4). Ссылка выглядит как часть шапки, но явно
   кликабельна: курсор-рука, подсветка при наведении, фокус с клавиатуры. */
.brand-home { display: flex; align-items: center; gap: 8px; cursor: pointer;
  text-decoration: none; color: inherit; padding: 3px 6px;
  border-radius: var(--r-sm); transition: background var(--t-fast); }
.brand-home:hover { background: rgba(255, 255, 255, .12); }
.brand-home:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }
.brand-logo { height: 30px; max-width: 160px; object-fit: contain;
  background: #fff; border-radius: var(--r-sm); padding: 2px 4px; }
.logo-preview { height: 44px; max-width: 160px; object-fit: contain;
  border: 1px solid var(--border); border-radius: var(--r-sm); padding: 3px; background: var(--panel); }
.version { opacity: .6; font-weight: 400; font-size: var(--fs-xs); margin-left: 6px; }
.tabs .tab {
  background: none; border: none; color: #b9c4d4;
  padding: 8px 14px; border-radius: var(--r-md);
}
/* Активная вкладка/селект роли в шапке — фирменный синий (было захардкожено
   отдельным литералом #2c3e57, не связанным с --accent, поэтому не
   подхватило смену палитры на брендбук). */
.tabs .tab.active { background: var(--accent); color: #fff; }
.userbox { display: flex; align-items: center; gap: 10px; }
.userbox select { padding: 3px 6px; background: var(--accent); color: #fff; border-color: var(--accent); }
.theme-toggle { background: none; border: none; font-size: var(--fs-lg); padding: 2px 4px;
  display: inline-flex; align-items: center; justify-content: center; }
/* Иконки lucide (ISC) — см. static/vendor/lucide/lucide.js. inline-block +
   vertical-align вместо display:block — убирает паразитный зазор снизу от
   инлайновых SVG (baseline gap), но не ломает обтекание текстом соседних
   узлов в кнопках «иконка + подпись» (в flex-контейнерах вроде .theme-toggle
   display иконки всё равно переопределяется форматированием флекс-контекста,
   так что вложенность туда работает без изменений). Цвет наследуется от
   текста кнопки (stroke=currentColor), поэтому тема/hover/disabled работают
   без отдельных правил на каждую иконку. */
.lucide-ico { display: inline-block; vertical-align: middle; flex: none; }
code { background: var(--chip-bg); padding: 1px 5px; border-radius: var(--r-sm); font-size: var(--fs-xs); word-break: break-all; }

/* Мобильная адаптация шапки (v2.0.1): базовый 3-колоночный grid
   (бренд | вкладки | userbox) не помещался на узких экранах — панель
   кнопок userbox переполняла свою ячейку и наезжала на бренд и вкладки.
   На телефоне разносим по строкам: бренд (слева) и панель кнопок (справа,
   с переносом) — первой строкой, вкладки — отдельной прокручиваемой строкой
   ниже во всю ширину. Версия и имя пользователя скрыты ради места
   (имя дублируется кнопкой «Выйти»; версия видна в «О программе»). */
@media (max-width: 720px) {
  .topbar {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "brand user"
      "tabs  tabs";
    row-gap: 8px;
    padding: 8px 12px;
  }
  .brand { grid-area: brand; }
  .userbox { grid-area: user; flex-wrap: wrap; justify-content: flex-end; gap: 6px; }
  .tabs { grid-area: tabs; justify-self: stretch; justify-content: flex-start; }
  .version, #userName { display: none; }
  /* Презентационный режим и конструктор раскладки — десктоп-функции
     (полноэкранная витрина, drag-перетаскивание); на телефоне прячем,
     чтобы панель кнопок помещалась и не громоздилась. */
  #presentBtn, #layoutBtn { display: none; }
  .userbox select { max-width: 110px; }
}

.tab-page { display: none; }
.tab-page.active { display: block; }

/* Диспетчер: три под-вкладки (Готовые маршруты / Планирование / Специалисты).
   Занимает всю рабочую высоту; активная под-вкладка заполняет остаток под
   панелью под-вкладок. Планировщик (#dsub-plan) — та же грид-раскладка
   «сайдбар + карта + маршруты», что была у отдельной вкладки «Планирование»:
   ширины боковых панелей перетаскиваемые (§10), между колонками — .col-resizer. */
main#tab-ops.active { display: flex; flex-direction: column; height: calc(100vh - 48px); }
.disp-subtabs { flex: none; padding: 8px 10px 0; margin: 0; }
#tab-ops .dsub { display: none; flex: 1 1 auto; min-height: 0; }
#tab-ops #dsub-suggest.active,
#tab-ops #dsub-techs.active,
#tab-ops #dsub-queue.active { display: block; overflow-y: auto; }
/* «Мониторинг» и «Планирование» — одинаковая грид-раскладка (сайдбар + карта +
   правая панель); ширины боковых колонок перетаскиваемые (§10). */
#tab-ops #dsub-monitor.active,
#tab-ops #dsub-plan.active {
  display: grid;
  grid-template-columns: var(--layout-left, 330px) 6px minmax(0, 1fr) 6px var(--layout-right, 400px);
  gap: 6px; padding: 10px; min-height: 0;
}
/* Разделитель колонок: тонкая перетаскиваемая полоса. */
.col-resizer { cursor: col-resize; border-radius: var(--r-xs); background: var(--border-light);
  transition: background .15s; touch-action: none; }
.col-resizer:hover, .col-resizer.dragging { background: var(--accent, #0057B7); }
.sidebar { overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }
.panel { background: var(--panel); border-radius: var(--r-lg); padding: 12px; box-shadow: var(--shadow); }
.panel.narrow { max-width: 480px; margin: 16px; }
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 4px 0; }
.row.right { justify-content: flex-end; }
/* Блоки фильтров/управления в боковых панелях — по центру (единый вид по всему
   проекту). Ряды с растягивающимся контролом (flex:1) остаются на всю ширину —
   центрирование на них не влияет. */
.sidebar .panel .row { justify-content: center; }
/* Кнопки действий выровнены по центру и по отношению друг к другу — одинаковой
   ширины, ровные края. .act-col — вертикальная колонка (панель планирования),
   .act-row — горизонтальный ряд (футер модалок и т.п.). */
.act-col { display: flex; flex-direction: column; align-items: center; gap: 6px; margin-top: 8px; }
.act-col > button { width: 100%; max-width: 260px; }
.act-row { display: flex; justify-content: center; gap: 10px; flex-wrap: wrap; margin-top: 10px; }
.act-row > button { min-width: 130px; }
.list { max-height: 300px; overflow-y: auto; margin-top: 6px; }

/* Сводка шага 4 «Проверка и запуск»: живые чипы с выбранными работами,
   специалистами, транспортом, периодом и режимом оптимизации. */
.plan-summary { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 10px; }
.plan-summary .sum-chip {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 6px 10px; border-radius: var(--r-pill);
  background: var(--chip-bg); border: 1px solid var(--border);
  font-size: var(--fs-sm); line-height: 1.2;
}
.plan-summary .sum-chip b { font-weight: 600; font-variant-numeric: tabular-nums; }
.plan-summary .sum-chip .sum-label { color: var(--muted); }
.plan-summary .sum-empty { color: var(--muted); font-size: var(--fs-sm); }

/* Сводка критической ситуации в «Планировании»: при входе сразу видно, что
   обслуживать в первую очередь. Тревожный вариант — акцентная рамка + чипы,
   спокойный — зелёная точка «критических ситуаций нет». */
.plan-critical { padding: 10px 12px; }
.plan-critical-body.alert { border-left: 3px solid #e11d48; padding-left: 9px; }
.plan-critical-body.ok    { border-left: 3px solid #17803d; padding-left: 9px; }
.plan-critical-body .pc-head {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-bottom: 6px;
}
.plan-critical-body .pc-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
}
.plan-critical-body .pc-dot.alert { background: #e11d48; animation: pcPulse 1.6s ease-in-out infinite; }
.plan-critical-body .pc-dot.ok    { background: #17803d; }
@keyframes pcPulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }
.plan-critical-body .pc-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; }
.plan-critical-body .pc-chip {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 4px 9px; border-radius: var(--r-pill);
  font-size: var(--fs-sm); line-height: 1.2; border: 1px solid var(--border);
}
.plan-critical-body .pc-chip b { font-weight: 700; font-variant-numeric: tabular-nums; }
/* «В первую очередь»: одно крупное действенное число (размер объединения =
   что отберёт кнопка), разбивка ниже как «в том числе» (не суммируется). */
.plan-critical-body .pc-hero { display: flex; align-items: baseline; gap: 8px; margin: 6px 0 2px; }
.plan-critical-body .pc-num { font-size: 32px; font-weight: 800; line-height: 1; color: #e11d48; font-variant-numeric: tabular-nums; }
.plan-critical-body .pc-num-label { font-size: var(--fs-sm); }
.plan-critical-body .pc-incl { margin: 2px 0 0; }
.plan-critical-body .pc-overlap { margin: 1px 0 6px; font-size: var(--fs-xs); opacity: .85; }
.plan-critical-body .pc-chip.crit  { background: rgba(225,29,72,.12);  border-color: rgba(225,29,72,.4); }
.plan-critical-body .pc-chip.high  { background: rgba(249,115,22,.12); border-color: rgba(249,115,22,.4); }
.plan-critical-body .pc-chip.emerg { background: rgba(234,88,12,.10);  border-color: rgba(234,88,12,.35); }
.plan-critical-body button.primary { width: 100%; margin-top: 4px; }

/* Быстрый план по зоне (зона → сразу «Сформировать план»): выделенная панель
   сверху, крупная главная кнопка; детали — в сворачиваемом «Уточнить план». */
.plan-quick { border: 1px solid var(--accent, #0057B7); }
.primary.big { font-size: var(--fs-md); padding: 10px 14px; font-weight: 600; }
.plan-refine { border: 1px solid var(--border-light); border-radius: var(--r-md);
  background: var(--panel); padding: 0 8px; }
.plan-refine > summary { cursor: pointer; padding: 8px; font-weight: 600;
  color: var(--muted); list-style-position: inside; }
.plan-refine[open] > summary { border-bottom: 1px solid var(--border-light);
  margin-bottom: 6px; }
.plan-refine > .panel { border: none; padding-left: 0; padding-right: 0; }

/* Режимы планирования (ТЗ 1.0 §8.1): сегментированный переключатель. */
.plan-modes { display: flex; gap: 4px; margin: 2px 0 4px; }
.plan-modes .plan-mode {
  flex: 1; border: 1px solid var(--border); background: var(--panel);
  color: var(--text); border-radius: var(--r-sm); padding: 5px 6px;
  font-size: var(--fs-xs); cursor: pointer; white-space: nowrap;
}
.plan-modes .plan-mode.active {
  background: var(--accent, #0057B7); color: #fff; border-color: transparent;
}

/* Раздел «Телеметрия» (ТЗ «Сбор телеметрии» §8): две панели настройки +
   панель визуализации на всю ширину под ними. */
.telemetry-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 12px; align-items: start;
}
.telemetry-grid .telemetry-view { grid-column: 1 / -1; }
.tel-subhead { margin: 12px 0 4px; font-size: var(--fs-md); }
.tel-chart {
  width: 100%; min-height: 140px; margin: 6px 0;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--panel); overflow: hidden;
}
.tel-chart svg { display: block; width: 100%; height: 160px; }
.tel-chart .tel-empty { color: var(--muted); font-size: var(--fs-sm); padding: 12px; }
/* Бейдж источника записи (реальные / синтетика / ручной / импорт) — §9. */
.src-badge {
  display: inline-block; padding: 1px 7px; border-radius: var(--r-pill);
  font-size: var(--fs-2xs); font-weight: 600;
}
.src-device { background: var(--badge-ok-bg); color: var(--badge-ok-fg); }
.src-simulator { background: var(--badge-urgent-bg); color: var(--badge-urgent-fg); }
.src-manual { background: var(--badge-info-bg); color: var(--badge-info-fg); }
.src-import { background: var(--badge-import-bg); color: var(--badge-import-fg); }
/* Бейдж важности события — §6. */
.sev-badge {
  display: inline-block; padding: 1px 7px; border-radius: var(--r-pill);
  font-size: var(--fs-2xs); font-weight: 600;
}
.sev-info { background: var(--badge-info-bg); color: var(--badge-info-fg); }
.sev-warning { background: var(--badge-warn-bg); color: var(--badge-warn-fg); }
.sev-error { background: var(--badge-err-bg); color: var(--badge-err-fg); }
.sev-critical { background: var(--badge-err-fg); color: #fff; }
.tel-row-anom { background: rgba(var(--badge-err-rgb), .08); }
/* Легенда графика телеметрии (§8): основной ряд, сравнение, аномалии. */
.tel-legend { display: flex; flex-wrap: wrap; gap: 12px; margin: 2px 0 6px; font-size: var(--fs-xs); }
.tel-legend .lg-main { color: var(--badge-info-fg); font-weight: 600; }
.tel-legend .lg-cmp { color: var(--badge-urgent-fg); font-weight: 600; }
.tel-legend .lg-anom { color: var(--badge-err-fg); font-weight: 600; }

/* Интерактивная лента событий мониторинга (ТЗ §36–51, Этап E2). */
.qfilters { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
.qfilter {
  border: 1px solid var(--border); background: var(--panel); color: var(--text);
  border-radius: var(--r-pill); padding: 3px 10px; font-size: var(--fs-xs);
  cursor: pointer;
}
.qfilter.active { background: var(--accent, #0057B7); color: #fff; border-color: transparent; }
.mev-filters { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; margin-bottom: 6px; }
.mev-filters select { font-size: var(--fs-xs); padding: 2px 4px; }
.mev-filters .link.active { font-weight: 600; }
.mev-batch { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 6px; }
/* Чипы-пресеты, ряд фильтров и групповые действия ленты событий — по центру. */
.qfilters, .mev-filters, .mev-batch { justify-content: center; }
.mev-batch button.small, .ev-card button.small { font-size: var(--fs-xs); padding: 3px 8px; }
.ev-badge {
  display: inline-block; padding: 0 6px; border-radius: var(--r-pill);
  font-size: var(--fs-2xs); font-weight: 600; vertical-align: middle;
}
.u-critical, .p-critical { background: var(--badge-err-fg); color: #fff; }
.u-urgent, .p-high { background: var(--badge-urgent-bg); color: var(--badge-urgent-fg); }
.u-normal, .p-medium { background: var(--badge-warn-bg); color: var(--badge-warn-fg); }
.u-info, .p-low { background: var(--badge-info-bg); color: var(--badge-info-fg); }
.ev-flag { font-size: var(--fs-xs); }
.mon-event .ev-check { margin-right: 4px; }
/* Просмотренные/обработанные события визуально приглушены (§38). */
.mon-event.ev-viewed { opacity: .72; }
.mon-event.ev-queued, .mon-event.ev-order_created { border-left: 3px solid var(--accent, #0057B7); }
.mon-event.ev-closed, .mon-event.ev-done { opacity: .5; }
.ev-card { border: 1px solid var(--accent, #0057B7); }
/* Подсказка «что делать дальше» на карточке события — заметная, но не кричащая. */
.ev-next { margin-top: 6px; padding: 6px 8px; border-radius: var(--r-sm);
  background: var(--row-hover); border-left: 3px solid var(--accent, #2dd4bf); }
/* Подсветка выбранного объекта на карте — пульсирующее кольцо (§36.4). */
.mon-hl { background: transparent; border: none; }
.mon-pulse {
  display: block; width: 44px; height: 44px; border-radius: 50%;
  border: 3px solid #1f6fe0; box-sizing: border-box;
  animation: monPulse 1.4s ease-out infinite;
}
@keyframes monPulse {
  0% { transform: scale(.35); opacity: 1; }
  100% { transform: scale(1); opacity: 0; }
}

/* --- Пульсирующее свечение устройства на карте (docs/40) --- */
/* Цвет свечения (--glow) — по каналу связи; частота пульса — по активности
   передачи; сбой связи/передатчика — красное резкое мигание. Свечение
   рисуется как drop-shadow вокруг SVG-маркера (circleMarker). */
.mon-glow { --glow: #94a3b8; animation: monGlowPulse 2.4s ease-in-out infinite; }
@keyframes monGlowPulse {
  0%, 100% { filter: drop-shadow(0 0 1px var(--glow)); }
  50%      { filter: drop-shadow(0 0 7px var(--glow)); }
}
/* Цвет свечения по каналу связи (легко различимые цвета). */
.mon-ch-bluetooth { --glow: #2b7cff; }   /* Bluetooth — синий */
.mon-ch-wifi      { --glow: #14b8a6; }   /* Wi-Fi — бирюзовый */
.mon-ch-mobile    { --glow: #a855f7; }   /* мобильная сеть — фиолетовый */
.mon-ch-lora      { --glow: #f59e0b; }   /* LoRa — янтарный */
.mon-ch-ethernet  { --glow: #475569; }   /* проводной — тёмно-серый */
.mon-ch-none      { --glow: #94a3b8; }   /* канал не задан — нейтральный */
/* Частота пульса по активности передачи: недавно передавал — быстро,
   длительная пауза — очень медленно. */
.mon-act-active { animation-duration: .9s; }
.mon-act-idle   { animation-duration: 2.4s; }
.mon-act-quiet  { animation-duration: 5s; }
/* Фактическая передача сигнала — кратковременно ярче и быстрее. */
.mon-live { animation-duration: .5s !important; }
.mon-live { filter: drop-shadow(0 0 9px var(--glow)); }
/* Сбой (нет связи / проблема передатчика) — красное резкое мигание, поверх
   любого канала/активности. */
.mon-fail { animation: monFailBlink .5s steps(1) infinite !important; }
@keyframes monFailBlink {
  0%, 49%   { filter: drop-shadow(0 0 6px #ff2d2d); opacity: 1; }
  50%, 100% { filter: none; opacity: .4; }
}

/* Легенда свечения (канал связи + сбой) в углу карты. */
.glow-legend {
  position: absolute; left: 8px; bottom: 8px; z-index: 500;
  display: flex; flex-wrap: wrap; gap: 4px 10px; max-width: 70%;
  padding: 6px 8px; border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .88); font-size: var(--fs-xs);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .2);
}
.glow-item { display: inline-flex; align-items: center; gap: 4px; }
.glow-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--glow, #94a3b8); box-shadow: 0 0 6px var(--glow, #94a3b8);
}
.glow-fail .glow-dot { --glow: #ff2d2d; }
/* Тёмная тема переключается атрибутом data-theme на <html> (см. app.js) —
   раньше эта единственная панель следовала системной prefers-color-scheme и
   рассинхронизировалась с ручным переключателем темы в приложении (аудит
   дизайн-системы 2026-08-04). */
html[data-theme="dark"] .glow-legend { background: rgba(20, 24, 33, .88); color: #e5e7eb; }

/* Очередь работ (ТЗ §40, Этап E3). */
.queue-badge {
  display: inline-block; min-width: 16px; padding: 0 5px; border-radius: var(--r-pill);
  background: var(--badge-err-fg); color: #fff; font-size: var(--fs-2xs); font-weight: 600;
  line-height: 16px; text-align: center;
}
.queue-list { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.queue-item {
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 8px 10px; background: var(--panel);
}
.queue-item.q-crit { border-left: 3px solid var(--badge-err-fg); }
.queue-item-head { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.queue-locate { cursor: pointer; text-decoration: underline dotted; }
.queue-actions { margin-top: 6px; gap: 8px; align-items: center; }
.queue-actions select { font-size: var(--fs-xs); padding: 2px 4px; }

/* Подбор специалиста из мониторинга (ТЗ §42, Этап E4). */
.match-card { max-width: 560px; }
#matchBody { max-height: 60vh; overflow-y: auto; }
.match-cand {
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 8px 10px; margin: 6px 0;
}
.match-cand.match-top { border-color: var(--accent, #0057B7); background: rgba(0, 87, 183, .05); }
.match-cand .dispatch-score { font-weight: 700; font-size: var(--fs-md); }
.match-excluded { margin-top: 8px; }
.match-excluded ul { margin: 4px 0 0; padding-left: 18px; }
.match-excluded summary { cursor: pointer; }

/* Сохранённые представления (ТЗ §44–45) и realtime-баннеры (§47). */
.fs-panel {
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 8px; margin-top: 6px; background: var(--chip-bg);
}
.fs-actions { display: flex; flex-wrap: wrap; gap: 6px 12px; margin-top: 6px; }
.fs-actions .link { font-size: var(--fs-sm); }
.mon-session-bar, .mon-rt-bar {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  padding: 6px 8px; margin: 4px 0; border-radius: var(--r-sm);
  font-size: var(--fs-sm);
}
.mon-session-bar { background: var(--badge-warn-bg); color: var(--badge-warn-fg); }
.mon-rt-bar { background: var(--badge-err-bg); color: var(--badge-err-fg); font-weight: 600; }

.order-item, .worker-item {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 6px; border-radius: var(--r-sm);
}
.order-item:hover, .worker-item:hover { background: var(--hover); }
.order-item .title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.worker-item select { max-width: 140px; }

.badge { font-size: var(--fs-2xs); padding: 1px 7px; border-radius: var(--r-lg); white-space: nowrap; }
.badge.emergency { background: #fde2e2; color: #b42318; }
.badge.planned { background: var(--active-bg); color: var(--accent); }
.badge.daily { background: #e5f4e9; color: #17803d; }
.badge.p4 { background: #7f1d1d; color: #fff; }
.badge.p3 { background: #b42318; color: #fff; }
.badge.p2 { background: #f79009; color: #fff; }
.badge.p1 { background: #98a2b3; color: #fff; }
.badge.p0 { background: #d0d5dd; color: #344054; }
.badge.repeat { background: #fef0c7; color: #b54708; }
.badge.warranty { background: #ede9fe; color: #6941c6; }
/* Статус визита (§18): цветная точка-индикатор + компактный select в строке. */
.visit-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  margin-right: 6px; vertical-align: middle; }
select.visit-sel { font-size: var(--fs-xs); padding: 2px 4px; max-width: 140px;
  vertical-align: middle; }
.pending-item { display: flex; align-items: center; gap: 8px; padding: 4px 0;
  border-top: 1px dashed var(--border-light); }
.pending-item .title { flex: 1; }
.auth-switch { margin-top: 10px; text-align: center; }
/* Авторство и лицензия (MIRIDON) на странице входа — см. LICENSE. */
.auth-credit { margin-top: 14px; text-align: center; opacity: .8; }

.map-wrap { position: relative; border-radius: var(--r-lg); overflow: hidden; background: var(--map-bg); }
#map { position: absolute; inset: 0; }
/* left:52px — правее кнопок зума Leaflet (+/−), чтобы панель их не
   перекрывала; flex-wrap + max-width — перенос на узкой карте вместо
   вылезания за правый край. */
/* left: 62px — гарантированный зазор от элемента масштаба Leaflet (+/−, слева),
   чтобы панель зоны его не касалась/не перекрывала на любой ширине. */
.zone-bar { position: absolute; top: 8px; left: 62px; z-index: 1000;
  display: flex; gap: 6px; align-items: center; flex-wrap: wrap;
  max-width: calc(100% - 72px); background: var(--panel);
  padding: 4px 8px; border-radius: var(--r-md); box-shadow: 0 1px 4px rgba(16,24,40,.2); }
.zone-bar button { font-size: var(--fs-xs); padding: 3px 8px; border: 1px solid var(--border);
  border-radius: var(--r-sm); background: var(--panel); color: var(--text); cursor: pointer; }
.zone-bar button.active { background: var(--accent); color: #fff; border-color: var(--accent); }
#mapFallback { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 24px; text-align: center; color: var(--muted); }
/* Тёмная тема: приглушаем светлые тайлы OSM инверсией. */
html[data-theme="dark"] .leaflet-tile { filter: brightness(.6) invert(1) contrast(3.2) hue-rotate(200deg) saturate(.35) brightness(.75); }
html[data-theme="dark"] .leaflet-container { background: var(--map-bg); }

.routes-panel { overflow-y: auto; }
.route-card { background: var(--panel); border-radius: var(--r-lg); padding: 10px 12px; margin-bottom: 10px; box-shadow: var(--shadow); border-left: 5px solid #888; }
.route-card .head { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.route-card .head select { max-width: 150px; }
.metrics { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.chip { background: var(--chip-bg); border-radius: var(--r-md); padding: 2px 8px; font-size: var(--fs-xs); }
/* Метрики маршрута: сетка «подпись → значение» (подпись видна сразу, без
   наведения — вместо облака иконок-чипов). */
.route-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 12px; margin: 8px 0; }
.mgroup { background: var(--chip-bg); border-radius: var(--r-md); padding: 6px 8px; min-width: 0; }
.mgroup-title { font-size: var(--fs-xs); font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .03em; margin-bottom: 4px; }
.mrow { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; font-size: var(--fs-sm); line-height: 1.5; }
.mrow .mlabel { color: var(--muted); white-space: nowrap; }
.mrow .mval { font-weight: 600; text-align: right; }
.mrow.total { border-top: 1px dashed var(--border); margin-top: 2px; padding-top: 3px; }
.mrow.total .mval { color: var(--link); }
@media (max-width: 720px) { .route-metrics { grid-template-columns: 1fr; } }
input.mini { width: 60px; padding: 2px 5px; font-size: var(--fs-xs); }
.stop-row .name.done { text-decoration: line-through; color: var(--muted); }
details.fact { margin-top: 6px; }
details.fact summary { cursor: pointer; }
details.checklist { margin-top: 6px; }
details.checklist summary { cursor: pointer; }
.chk-body { margin-top: 6px; }
.chk-items { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-bottom: 6px; }
.chk-item { display: flex; align-items: center; gap: 4px; font-size: var(--fs-xs); cursor: pointer; }
.chk-mat, .chk-ready { font-size: var(--fs-xs); margin: 3px 0; }
.chk-mat.ok, .chk-ready.ok { color: var(--ok); }
.chk-mat.bad { color: var(--err); }
.chk-ready { color: var(--muted); }
#analyticsBox { margin: 4px 0 8px; }
.warn { background: var(--warn-bg); border: 1px solid var(--warn-border); color: var(--warn-text); border-radius: var(--r-md); padding: 4px 8px; font-size: var(--fs-xs); margin: 4px 0; }

.stop-row { display: flex; align-items: center; gap: 6px; padding: 4px 0; border-top: 1px dashed var(--border-light); }
.stop-row .num { width: 22px; height: 22px; border-radius: 50%; color: #fff; font-size: var(--fs-2xs); display: flex; align-items: center; justify-content: center; flex: none; }
.stop-row .info { flex: 1; min-width: 0; }
.stop-row .info .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stop-row .ctl { display: flex; gap: 2px; }
.stop-row .ctl button { border: none; background: var(--chip-bg); color: var(--text); border-radius: var(--r-sm); width: 24px; height: 24px; }
.stop-row .ctl button:hover { background: var(--chip-hover); }
.add-stop { margin-top: 6px; }

.unassigned-item { padding: 6px 8px; background: var(--panel); border-radius: var(--r-md); margin-bottom: 6px; border-left: 4px solid #f04438; }

/* Данные */
main#tab-data.active { padding: 12px 16px; max-width: 1800px; margin: 0 auto; }
/* Ряды внутренних вкладок — по центру (§3.1), единый стиль активного
   состояния для всех разделов. */
.subtabs { display: flex; justify-content: center; flex-wrap: wrap;
  margin-bottom: 8px; }
/* Ряд под-вкладок «легче»: неактивные — тихий текст без рамки (в «Данных» их
   13, в «Аналитике» 11 — сплошные рамки перегружали), активная — мягкий синий
   вместо почти-чёрного. Тон совпадает с выделением элементов списка. */
.subtab { border: 1px solid transparent; background: transparent; color: var(--muted);
  padding: 6px 14px; border-radius: var(--r-md); margin-right: 6px;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast); }
.subtab:hover { background: var(--hover); color: var(--text); }
.subtab.active { background: var(--active-bg); color: var(--link);
  border-color: var(--active-border); font-weight: 600; }
/* Группировка под-вкладок (v1.0.35): тематические кластеры «Данные»/«Аналитика».
   Кластер — inline-flex со своей подписью; между кластерами — тонкий разделитель.
   Каждый кластер = свой data-reorder-group, перетаскивание работает внутри него. */
.subtabs.grouped { gap: 4px 8px; }
.subtab-group { display: inline-flex; align-items: center; flex-wrap: wrap;
  gap: 4px; padding: 0 4px; }
.subtab-group + .subtab-group { border-left: 1px solid var(--border-light);
  padding-left: 10px; margin-left: 4px; }
.subtab-group-label { font-size: var(--fs-2xs); color: var(--muted);
  text-transform: uppercase; letter-spacing: .04em; margin-right: 2px;
  white-space: nowrap; user-select: none; }
.data-toolbar { margin: 0 0 10px 0; }
table.data { width: 100%; border-collapse: collapse; background: var(--panel); border-radius: var(--r-lg); overflow: hidden; }
table.data th, table.data td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--border-light); font-size: var(--fs-sm); }
table.data th { background: var(--th-bg); font-weight: 600; }
table.data tr:hover td { background: var(--row-hover); }
table.data .ctl button { border: none; background: none; font-size: var(--fs-md); }
/* Таблицы «Данных» (v1.0.80): не растягиваем по контейнеру — при
   малом числе колонок width:100% давал огромные пустые разрывы между
   ячейками (напр. Офисы: 7 колонок на 1800px). Ширина — по содержимому,
   но не уже половины контейнера; для колоночных таблиц (Контроллеры и
   т.п.) auto-раскладка сама займёт нужное место. Других мест использования
   table.data (Аналитика, импорт, журналы — уже во вложенных .panel) не
   касается. */
#tab-data table.data { width: auto; min-width: 60%; }

/* Документы по заявке (платформа): предпросмотр акта/счёта в модале. */
.doc-preview { border: 1px solid var(--border-light); border-radius: var(--r-lg); padding: 14px 16px; background: var(--panel); }
.doc-preview .doc-h1 { font-size: var(--fs-lg); margin: 0 0 2px; }
.doc-preview .doc-parties { display: flex; flex-wrap: wrap; gap: 28px; margin: 12px 0; }
.doc-preview .doc-party { font-size: var(--fs-sm); line-height: 1.5; }
.doc-preview .doc-table { width: 100%; border-collapse: collapse; margin-top: 10px; }
.doc-preview .doc-table th, .doc-preview .doc-table td { border: 1px solid var(--border-light); padding: 6px 8px; font-size: var(--fs-sm); }
.doc-preview .doc-total { text-align: right; font-weight: 600; font-size: var(--fs-md); margin-top: 10px; }

/* Импорт (под-вкладка «Данных») / настройки */
.import-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; max-width: 1100px; }
/* Настройки (ТЗ доп. §8, разделы — v1.0.79): карточки раскладываются
   колонками по ширине экрана (1–3), а не одной длинной вертикальной
   колонкой. break-inside не даёт карточке разорваться между колонками.
   Разделы (subtabs) сузили каждую сетку до 3–5 тематических карточек —
   потолок ширины поднят (было 1500 — много пустого поля по краям на
   широких мониторах), а 3-я колонка включается раньше, т.к. в разделе
   меньше карточек и им просторнее. */
.settings-subtabs { margin-bottom: 10px; }
.settings-grid { columns: 2; column-gap: 12px; max-width: 1800px;
  margin: 0 auto; padding: 10px; }
.settings-grid .panel { break-inside: avoid; margin-bottom: 12px; }
@media (max-width: 1000px) { .settings-grid { columns: 1; } }
@media (min-width: 1400px) { .settings-grid { columns: 3; } }
.small { font-size: var(--fs-xs); }
.muted { color: var(--muted); }
.hidden { display: none !important; }
.link { background: none; border: none; color: var(--link); text-decoration: underline; padding: 0; font-size: var(--fs-sm); }
.link.danger { color: var(--err); }
.primary { background: var(--accent); border: none; color: #fff; border-radius: var(--r-md); padding: 7px 14px; }
.primary:hover { background: var(--accent-hover); }
button:disabled { opacity: .5; cursor: default; }

.ok { color: var(--ok); }
.err { color: var(--err); }

/* Мини-график тренда здоровья парка (спарклайн + дельта за период) */
.hlt-trend { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 10px; }
.hlt-spark { color: var(--accent); flex: 0 0 auto; }
.hlt-delta { font-variant-numeric: tabular-nums; }
.hlt-delta.ok { color: var(--ok); }
.hlt-delta.bad { color: var(--err); }

/* Командная палитра (Ctrl/Cmd+K) — быстрый глобальный поиск */
.cmd-overlay { position: fixed; inset: 0; background: rgba(10,15,25,.45); display: flex; align-items: flex-start; justify-content: center; z-index: 1200; padding-top: 12vh; }
.cmd-box { background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-lg, 12px); width: min(560px, 92vw); max-height: 70vh; display: flex; flex-direction: column; overflow: hidden; box-shadow: 0 18px 60px rgba(0,0,0,.35); }
.cmd-box > #cmdInput { border: 0; border-bottom: 1px solid var(--border); border-radius: 0; padding: 14px 16px; font-size: var(--fs-lg); background: transparent; color: var(--text); outline: none; }
.cmd-results { overflow-y: auto; }
.cmd-item { display: flex; align-items: center; gap: 10px; padding: 9px 14px; cursor: pointer; border-bottom: 1px solid var(--border); }
.cmd-item.active, .cmd-item:hover { background: var(--accent-soft, rgba(80,120,255,.12)); }
.cmd-ico { width: 22px; text-align: center; flex: 0 0 auto; }
.cmd-main { min-width: 0; }
.cmd-label { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmd-sub { color: var(--muted); font-size: var(--fs-sm); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmd-kind { margin-left: auto; color: var(--muted); font-size: var(--fs-sm); flex: 0 0 auto; }
.cmd-empty { padding: 16px; color: var(--muted); text-align: center; }
.cmd-recent-head { display: flex; align-items: center; justify-content: space-between; padding: 8px 14px 2px; text-transform: uppercase; letter-spacing: .04em; }
.cmd-recent-clear { background: none; border: none; color: var(--muted); cursor: pointer; font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: .04em; padding: 2px 6px; border-radius: var(--r-sm); }
.cmd-recent-clear:hover { text-decoration: underline; }
.cmd-foot { padding: 8px 14px; border-top: 1px solid var(--border); }

/* Подсветка строки, к которой перешли из палитры (кратковременная вспышка) */
@keyframes rowFlash { from { background: rgba(80,120,255,.28); } to { background: transparent; } }
.data tbody tr.row-flash { animation: rowFlash 1.6s ease-out; }

/* Модалка */
.modal { position: fixed; inset: 0; background: rgba(10,15,25,.45); display: flex; align-items: center; justify-content: center; z-index: 1000; }
.modal-card { background: var(--panel); border-radius: var(--r-xl); padding: 16px 18px; width: 460px; max-height: 85vh; overflow-y: auto; }
.modal-card label { font-size: var(--fs-sm); }
.modal-card input, .modal-card select { width: 100%; }
/* Поля обязательной смены пароля (admin / admin). */
.pw-field { display: block; margin: 8px 0; }
.pw-field span { display: block; margin-bottom: 2px; color: var(--muted); }

.toast { position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%); background: var(--strong-bg); color: var(--strong-fg); padding: 9px 16px; border-radius: var(--r-lg); z-index: 1200; max-width: 70vw; }

/* Страница входа / регистрации */
.auth-page {
  position: fixed; inset: 0; z-index: 1100;
  display: flex; align-items: center; justify-content: center; padding: 20px;
  /* Фирменные цвета MIRIDON: чёрный → синий → мятный (единственное место,
     где решили показать все три «tunnusvärvid + lisavärv» вместе —
     декоративный фон, не несёт смысловой нагрузки статуса). */
  background: linear-gradient(135deg, #212322 0%, #0057B7 65%, #5DD39E 100%);
}
.auth-card {
  background: var(--panel); border-radius: var(--r-xl); padding: 28px 26px; width: 380px;
  max-width: 100%; box-shadow: 0 18px 50px rgba(8,15,30,.45);
}
.auth-brand { text-align: center; margin-bottom: 14px; }
.auth-logo { max-height: 72px; max-width: 220px; object-fit: contain; }
.auth-emoji { font-size: 46px; line-height: 1; }
.auth-company { font-size: 20px; font-weight: 700; margin-top: 8px; color: var(--text); }
.auth-card h3 { margin: 6px 0 4px; }
.auth-card form { margin-top: 10px; }
.auth-card label { font-size: var(--fs-sm); }
.auth-card input { width: 100%; padding: 9px 10px; }
.auth-card .primary { width: 100%; padding: 10px; margin-top: 4px; }

@media (max-width: 1200px) {
  .import-grid { grid-template-columns: 1fr; }
}

/* ---------- Мониторинг контроллеров (под-вкладка «Операции») ---------- */
/* Грид-раскладка мониторинга задана выше вместе с планировщиком
   (#tab-ops #dsub-monitor.active). Здесь — только панель «По городам». */
/* «По городам» — последняя панель сайдбара тянется до низа экрана, а список
   городов прокручивается внутри неё. Иначе список упирался в max-height:300px,
   и под панелью оставалась пустота до низа окна. */
#tab-ops #dsub-monitor.active #monCityPanel {
  display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
}
#tab-ops #dsub-monitor.active #monCityPanel #monCities {
  flex: 1 1 auto; max-height: none; min-height: 0;
}

/* Адаптивность (ТЗ §2.1): ни одна панель не исчезает при масштабе браузера
   80–200% и на планшетах. До 1200px — две колонки: сайдбар на обе строки,
   карта сверху, лента событий/маршрутов ПОД картой со своим скроллом —
   всё остаётся на одном экране. ВАЖНО: блок стоит ПОСЛЕ базовых правил
   main#tab-*, иначе базовые перекрывают медиа-правила (одинаковая
   специфичность решается порядком в файле). */
@media (max-width: 1200px) {
  main#tab-ops.active #dsub-plan.active,
  main#tab-ops.active #dsub-monitor.active {
    grid-template-columns: 250px minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) minmax(140px, 34vh);
    height: calc(100vh - 48px);
  }
  main#tab-ops.active #dsub-plan.active .sidebar,
  main#tab-ops.active #dsub-monitor.active .sidebar { grid-row: 1 / -1; }
  .routes-panel { grid-column: 2; grid-row: 2; }
  /* На узких экранах колонки не тянутся — разделители убираем из потока. */
  .col-resizer { display: none; }
}
/* Телефоны: одна колонка, страница прокручивается целиком. */
@media (max-width: 560px) {
  main#tab-ops.active { height: auto; }
  main#tab-ops.active #dsub-plan.active,
  main#tab-ops.active #dsub-monitor.active { display: flex; flex-direction: column; height: auto; }
  .map-wrap { min-height: 45vh; }
  .routes-panel { max-height: 60vh; }
  .sidebar { overflow-y: visible; }
  /* На телефоне сайдбар без фиксированной высоты — возвращаем список городам
     собственный скролл, иначе он растянется на весь список. */
  main#tab-ops.active #dsub-monitor.active #monCityPanel { flex: none; }
  main#tab-ops.active #dsub-monitor.active #monCityPanel #monCities { flex: none; max-height: 320px; }
}

#monMap { position: absolute; inset: 0; }
/* Понятное сообщение вместо пустой карты (ТЗ доп. §5): объектов в области
   нет или фильтр не дал результатов. Не мешает работе с картой. */
/* top: 56px — под строкой поиска (справа вверху) + ограничение ширины, чтобы
   баннер не налезал на поле поиска и кнопки по краям карты. */
.map-empty { position: absolute; left: 50%; top: 56px;
  transform: translateX(-50%); z-index: 900; pointer-events: none;
  max-width: min(64%, 460px); text-align: center;
  background: var(--panel); color: var(--text); font-size: var(--fs-sm);
  padding: 6px 14px; border-radius: var(--r-xl);
  box-shadow: 0 2px 8px rgba(16,24,40,.25); }
/* Поиск адреса/объекта в карте (ТЗ доп3 §2.2): правый верхний угол. */
.map-search { position: absolute; top: 10px; right: 10px; z-index: 1000;
  width: min(320px, calc(100% - 70px)); }
.map-search input { width: 100%; padding: 8px 12px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--panel); color: var(--text);
  box-shadow: 0 2px 8px rgba(16,24,40,.2); }
.map-search-results { margin-top: 4px; background: var(--panel);
  border: 1px solid var(--border-light); border-radius: var(--r-md);
  box-shadow: 0 4px 14px rgba(16,24,40,.25); max-height: 320px; overflow-y: auto; }
.ms-item { padding: 6px 10px; cursor: pointer; border-bottom: 1px solid var(--border-light); }
.ms-item:last-child { border-bottom: none; }
.ms-item:hover { background: var(--hover); }
.ms-info { padding: 8px 10px; }

/* Индикатор потери связи (ТЗ §2.2): данные остаются, сверху — предупреждение. */
.map-conn { position: absolute; left: 50%; top: 14px; transform: translateX(-50%);
  z-index: 950; pointer-events: none; font-size: var(--fs-sm); padding: 6px 14px;
  border-radius: var(--r-xl); background: #fef3c7; color: #92400e;
  border: 1px solid #f59e0b; box-shadow: 0 2px 8px rgba(16,24,40,.25); }
#monMapFallback { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 24px; text-align: center; color: var(--muted); }

/* Редактор объектов на карте (ТЗ FilterSync): кнопка-переключатель и подсказка. */
/* top: 80px — ниже элемента масштаба Leaflet (+/−, слева вверху), чтобы кнопка
   не перекрывала его (запрос владельца). Справа вверху — поиск, слева внизу —
   легенда свечения; поэтому опускаем кнопку под масштаб, а не сдвигаем вбок. */
.map-edit-btn {
  position: absolute; left: 10px; top: 80px; z-index: 1000;
  padding: 6px 12px; border-radius: var(--r-md); cursor: pointer;
  border: 1px solid var(--border); background: var(--panel); color: var(--text);
  font-size: var(--fs-sm); font-weight: 600; box-shadow: var(--shadow);
}
.map-edit-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); }
/* Кнопка «Весь парк» — под кнопкой редактирования; заметка о кластерах — ниже. */
.map-all-btn { top: 122px; }
.map-all-note {
  position: absolute; left: 10px; top: 162px; z-index: 1000; max-width: 260px;
  padding: 6px 10px; border-radius: var(--r-md); background: var(--panel);
  color: var(--text); font-size: var(--fs-xs); box-shadow: var(--shadow);
  border: 1px solid var(--border);
}
.map-edit-hint {
  position: absolute; left: 50%; top: 10px; transform: translateX(-50%);
  z-index: 1000; max-width: 70%; padding: 6px 14px; border-radius: var(--r-xl);
  background: var(--accent); color: #fff; font-size: var(--fs-xs);
  box-shadow: 0 2px 8px rgba(16,24,40,.25); text-align: center;
}
/* Курсор-перекрестье, когда включён режим редактирования карты. */
#monMap.mon-edit { cursor: crosshair; }
#monMap.mon-edit .leaflet-interactive { cursor: move; }

/* Сворачивание/разворачивание панелей сайдбара мониторинга: свернуть ненужные
   окна, оставить нужные — чтобы освободить место (запрос владельца). */
.panel-collapse {
  background: none; border: none; cursor: pointer; color: var(--muted);
  font-size: var(--fs-sm); line-height: 1; padding: 0 6px 0 0;
}
.panel-collapse::before { content: "▾"; }
.panel-collapsed > h3 .panel-collapse::before,
.head-collapsed > .panel-collapse::before { content: "▸"; }
.panel-collapsed > :not(h3) { display: none !important; }
.panel-collapsed { padding-bottom: 8px; }

.mon-stats { display: flex; flex-direction: column; gap: 5px; margin-top: 6px; }
.mon-stat {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 6px 8px; border: 1px solid var(--border-light); border-radius: var(--r-md);
  background: var(--panel); color: var(--text); cursor: pointer; text-align: left; font-size: var(--fs-sm);
}
.mon-stat:hover { background: var(--hover); }
.mon-stat.active { background: var(--active-bg); border-color: var(--active-border); }
.mon-stat-label { flex: 1; }
.mon-stat-count { font-weight: 700; }
.mon-dot { width: 11px; height: 11px; border-radius: 50%; flex: none; display: inline-block; }
/* Иконка статуса (ТЗ доп3 §2.4) — статус читается без цвета. */
.mon-stat-ico { flex: none; width: 18px; text-align: center; font-size: var(--fs-sm); }
.mon-event-ico { flex: none; width: 18px; text-align: center; font-size: var(--fs-md); margin-top: 2px; }

.mon-city { padding: 6px; border-radius: var(--r-sm); cursor: pointer; }
.mon-city:hover { background: var(--hover); }
.mon-city.active { background: var(--active-bg); }
.mon-city-head { display: flex; align-items: center; gap: 6px; font-size: var(--fs-sm); }
.mon-city-total { margin-left: auto; font-weight: 700; }
.mon-city-dots { font-size: var(--fs-2xs); display: flex; gap: 8px; flex-wrap: wrap; margin-top: 2px; }
.mon-citydot { font-weight: 600; }

.mon-event, .mon-hist { display: flex; gap: 8px; padding: 6px 4px; border-bottom: 1px solid var(--border-light); }
/* Кнопки правки/удаления заметки (§3.1) — прижаты вправо. */
.mon-hist-btns { margin-left: auto; white-space: nowrap; display: flex; gap: 4px; }
.mon-hist-btns button { font-size: var(--fs-xs); }
.mon-event { cursor: pointer; }
.mon-event:hover { background: var(--hover); }
.mon-event .mon-dot { margin-top: 4px; }
.mon-event-top { display: flex; gap: 6px; align-items: baseline; }

.mon-card { background: var(--panel); border: 1px solid var(--border-light); border-radius: var(--r-lg); padding: 10px; margin-bottom: 10px; }
.mon-card-head { display: flex; align-items: center; gap: 8px; }
.mon-card-head .link { margin-left: auto; }
.mon-sbtns { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.mon-sbtn {
  padding: 4px 9px; border: 1.5px solid var(--border); border-radius: var(--r-xl);
  background: var(--panel); color: var(--text); cursor: pointer; font-size: var(--fs-xs);
}
.mon-sbtn:hover { background: var(--hover); }
.mon-sbtn.active { background: var(--strong-bg); color: var(--strong-fg); border-color: var(--strong-bg); }
.mon-histlist { max-height: 260px; overflow-y: auto; }

/* ---------- Диспетчер: подбор специалиста ---------- */
/* Единая ширина «страницы-контента» (v1.0.80): используется на всех
   разделах-списках/формах (Диспетчер, Аналитика, Симулятор), совпадает с
   шириной .settings-grid — один лаконичный стиль вместо разнобоя узких/
   растянутых страниц. Мониторинг и Планирование — сознательное исключение
   (полноэкранный layout с боковыми панелями), их не трогаем. */
.dispatch-wrap { padding: 10px; display: flex; flex-direction: column; gap: 10px;
  max-width: 1800px; margin: 0 auto; }
.dispatch-cols { display: grid; grid-template-columns: 1.4fr 1fr; gap: 10px; }
.dispatch-card { border: 1px solid var(--border-light); border-left: 4px solid #98a2b3;
  border-radius: var(--r-lg); padding: 8px 10px; margin-bottom: 8px; }
.dispatch-card.best { border-left-color: var(--ok); background: var(--best-bg); }
.dispatch-card-head { display: flex; align-items: center; gap: 8px; }
.dispatch-rank { width: 22px; height: 22px; border-radius: 50%; background: var(--strong-bg);
  color: var(--strong-fg); font: 12px/22px system-ui; text-align: center; flex: none; }
.dispatch-score { margin-left: auto; font-weight: 700; font-size: var(--fs-lg); color: var(--text); }
.dispatch-excl { padding: 4px 2px; border-bottom: 1px solid var(--border-light); font-size: var(--fs-sm); }
@media (max-width: 900px) { .dispatch-cols { grid-template-columns: 1fr; } }

/* Карточка проблемы (ТЗ 2026-07-13 §3.2): слева чекбокс, в центре объект и
   детали, справа рекомендованный специалист и кнопка «Спланировать». */
.dsp-card { display: flex; gap: 10px; align-items: flex-start;
  background: var(--panel); border: 1px solid var(--border-light);
  border-left: 4px solid #98a2b3; border-radius: var(--r-lg);
  padding: 8px 10px; margin-bottom: 8px; box-shadow: var(--shadow); }
.dsp-card .dsp-main { flex: 1; min-width: 0; }
.dsp-card .dsp-cands { width: 250px; flex: none; font-size: var(--fs-sm); }
.dsp-check { padding-top: 2px; }
.dsp-name { cursor: pointer; }
.dsp-name:hover { text-decoration: underline; }
@media (max-width: 900px) {
  .dsp-card { flex-wrap: wrap; }
  .dsp-card .dsp-cands { width: 100%; }
}

/* Расписание дня (ТЗ доп. §5.1): таймлайн по специалистам. */
#schedBox { background: var(--panel); border-radius: var(--r-lg); padding: 8px 12px;
  margin-bottom: 10px; box-shadow: var(--shadow); }
#schedBox summary { cursor: pointer; }
.sched-scale { position: relative; height: 14px; margin: 8px 0 2px; min-width: 360px; }
.sched-hour { position: absolute; font-size: var(--fs-2xs); color: var(--muted);
  transform: translateX(-50%); }
.sched-row { margin-bottom: 8px; min-width: 360px; }
.sched-name { font-size: var(--fs-xs); margin-bottom: 2px; }
.sched-track { position: relative; height: 18px; background: var(--chip-bg);
  border-radius: var(--r-sm); }
.sched-drive { position: absolute; top: 6px; height: 6px; background: #98a2b3;
  opacity: .55; border-radius: var(--r-xs); }
.sched-stop { position: absolute; top: 0; height: 18px; border-radius: var(--r-xs);
  color: #fff; font: 10px/18px system-ui; text-align: center; min-width: 12px;
  overflow: hidden; }

/* Результаты геокодирования (ТЗ §6) — кликабельные варианты адреса. */
.geo-item { padding: 4px 6px; border-radius: var(--r-sm); cursor: pointer; }
.geo-item:hover { background: var(--hover); }

/* Карточки специалистов (ТЗ доп. §2) — компактная сетка. */
.tech-grid { display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); }
/* Панель фильтров специалистов (v2.0.2): поиск растягивается, селекты
   ограничены по ширине и переносятся на узких экранах. */
.tech-filters { gap: 6px 8px; align-items: center; }
.tech-flt-search { flex: 1 1 200px; min-width: 160px; }
.tech-filters select { max-width: 180px; }
/* Карточка техника — тот же карточный «язык», что и остальные плитки
   (v1.0.82: добавлен фон-панель, раньше карточка была прозрачной с одной
   рамкой и выпадала из общего белого-карточного стиля). */
.tech-card { border: 1px solid var(--border-light); border-radius: var(--r-lg);
  padding: 8px 10px; background: var(--panel); }
/* Расшифровка формул аналитики (§9): построчно «формула = подстановка». */
.formulas { border: 1px dashed var(--border-light); border-radius: var(--r-md);
  padding: 6px 10px; margin-top: 6px; font-size: var(--fs-xs); }
.formula-row { padding: 2px 0; }
.formula-row + .formula-row { border-top: 1px solid var(--border-light); }

/* Варианты маршрутов (§5): компактная таблица со сравнением режимов. */
.variants-table { width: 100%; border-collapse: collapse; font-size: var(--fs-xs); }
.variants-table th, .variants-table td { padding: 4px 6px; text-align: right;
  border-bottom: 1px solid var(--border-light); white-space: nowrap; }
.variants-table th:first-child, .variants-table td:first-child { text-align: left; }
.variant-row { cursor: pointer; }
.variant-row:hover { background: var(--warn-bg); }
.variant-row.rec { font-weight: 600; }
/* Активный день многодневного плана — подсвечен, чтобы было видно, чей маршрут
   сейчас показан ниже (запрос владельца: каждый день выделен отдельно). */
.mday-row.active { background: var(--accent, #0057B7); color: #fff; font-weight: 600; }
.mday-row.active td { color: #fff; }

/* Навыки с уровнем квалификации (§4.5): чип «навык ★★☆». */
.skill-chip { display: inline-block; margin: 1px 3px 1px 0; padding: 0 4px;
  border-radius: var(--r-xs); background: var(--border-light); white-space: nowrap; }
.skill-stars { color: #d98a00; letter-spacing: -1px; }

/* Загрузка специалиста (§4.3): полоса + подпись. */
.tech-load { margin: 4px 0; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tech-load-bar { flex: none; width: 90px; height: 7px; border-radius: var(--r-xs);
  background: var(--border-light); overflow: hidden; }
.tech-load-bar span { display: block; height: 100%; background: var(--ok, #2e8b57); }
.tech-load-bar span.high { background: #d98a00; }
.tech-load-bar span.over { background: #c0392b; }
/* Предложение системы: применить одним нажатием. */
.sugg-card { align-items: center; }
.sugg-card .dsp-cands { width: auto; }
/* Готовые маршруты: карта слева, список маршрутов справа. */
.sugg-layout { display: flex; gap: 12px; align-items: stretch; }
.sugg-map { flex: 1 1 55%; min-width: 280px; min-height: 460px;
  border-radius: var(--r-md); overflow: hidden; }
.sugg-list { flex: 1 1 45%; min-width: 280px; max-height: 640px;
  overflow-y: auto; }
/* Активная (выбранная) карточка маршрута — подсветка рамкой акцентом. */
.sugg-card.route-active { outline: 2px solid var(--accent);
  outline-offset: -2px; }
@media (max-width: 900px) {
  .sugg-layout { flex-direction: column; }
  .sugg-map { min-height: 320px; }
}

/* ---------- Сводка руководителя ---------- */
/* Карточки центрируются по горизонтали: каждая строка выравнивается по
   центральной оси сама по себе (flex-wrap + justify-content), поэтому неполная
   последняя строка не «прижимается» влево, а стоит по центру — композиция
   «перевёрнутая пирамида». Карточки не растягиваются (grow 0), фиксированная
   основа 230px с возможностью ужаться на узких экранах. */
.sum-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.sum-card { flex: 0 1 230px; min-width: 200px;
  border: 1px solid var(--border-light); border-radius: var(--r-lg); padding: 10px 12px; }
.sum-card.warn-card { border-color: var(--warn-border); background: var(--warn-bg); }
.sum-title { font-size: var(--fs-xs); color: var(--muted); }
.sum-big { font-size: 26px; font-weight: 700; margin: 2px 0; }
.sum-sub b { font-weight: 700; }

/* ---------- Профиль сотрудника (§47) ---------- */
.eff-row { cursor: pointer; }
.prof-comp { display: flex; align-items: center; gap: 8px; margin: 5px 0; font-size: var(--fs-sm); }
.prof-comp-name { flex: 0 0 180px; }
.prof-bar { flex: 1; height: 8px; background: var(--chip-bg); border-radius: var(--r-sm); overflow: hidden; }
.prof-bar-fill { display: block; height: 100%; background: var(--accent); }

/* ---------- Помощь и документация ---------- */
.help-wrap { display: grid; grid-template-columns: 280px 1fr; gap: 10px;
  padding: 10px; max-width: 1200px; margin: 0 auto; align-items: start; }
.help-side { position: sticky; top: 10px; }
/* Блок «О программе»: авторство и лицензия (MIRIDON) — см. LICENSE. */
.about-box { margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--border-light);
  line-height: 1.5; }
.about-box b { color: var(--text); }
.help-side input { width: 100%; margin: 6px 0; }
.help-nav { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; }
.help-nav-item { text-align: left; border: none; background: none; color: var(--text);
  padding: 7px 10px; border-radius: var(--r-md); font-size: var(--fs-sm); }
.help-nav-item:hover { background: var(--hover); }
.help-nav-item.active { background: var(--active-bg); font-weight: 600; }
.help-main { min-height: 300px; }
.help-item { border-bottom: 1px solid var(--border-light); padding: 4px 0; }
.help-item summary { cursor: pointer; padding: 7px 4px; font-weight: 600; font-size: var(--fs-sm); }
.help-item summary:hover { color: var(--link); }
.help-body { padding: 2px 8px 10px; font-size: var(--fs-sm); }
.help-body h4 { margin: 10px 0 4px; font-size: var(--fs-xs); color: var(--muted);
  text-transform: uppercase; letter-spacing: .03em; }
.help-body ul, .help-body ol { margin: 4px 0; padding-left: 20px; }
.help-body li { margin: 3px 0; }
.help-group { margin: 14px 0 4px; font-size: var(--fs-sm); color: var(--muted); }
@media (max-width: 900px) { .help-wrap { grid-template-columns: 1fr; } .help-side { position: static; } }

/* Контекстные подсказки «?» */
.qhelp { width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--border);
  background: var(--chip-bg); color: var(--muted); font-size: var(--fs-2xs); line-height: 1;
  padding: 0; vertical-align: middle; margin-left: 2px; }
.qhelp:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
.tip-pop { position: absolute; z-index: 1300; background: var(--strong-bg); color: var(--strong-fg);
  border-radius: var(--r-md); padding: 8px 10px; font-size: var(--fs-xs); line-height: 1.45;
  box-shadow: 0 4px 16px rgba(0,0,0,.35); }

/* Разъяснение ошибки в тосте */
.toast-hint { font-size: var(--fs-xs); opacity: .85; margin-top: 4px; }

/* ---------- Перепланирование: дифф план→план ---------- */
.replan-box { border: 1px solid var(--active-border); background: var(--active-bg); border-radius: var(--r-lg);
  padding: 8px 10px; margin-bottom: 8px; }
#replanBtn { background: #0e7490; color: #fff; }

/* Пейджер серверной таблицы «Данных» (§17) */
.pager { display: flex; gap: 10px; align-items: center; margin: 8px 0; }
.pager button { min-width: 34px; }

/* Уведомления (§25): бейдж на колокольчике и выпадающая панель */
.notif-badge { position: absolute; top: -4px; right: -6px; background: #b42318;
  color: #fff; border-radius: var(--r-lg); font-size: var(--fs-2xs); line-height: 1;
  padding: 2px 5px; }
.notif-panel { position: fixed; top: 52px; right: 12px; width: 360px;
  max-height: 60vh; overflow-y: auto; background: var(--panel, #fff);
  border: 1px solid rgba(128,128,128,.35); border-radius: var(--r-md);
  box-shadow: 0 8px 24px rgba(0,0,0,.18); z-index: 1200; padding: 6px; }
.notif-item { padding: 6px 8px; border-bottom: 1px solid rgba(128,128,128,.15);
  font-size: var(--fs-sm); }
.notif-item.unread { font-weight: 600; }
.notif-item .muted { font-weight: 400; }
.notif-item.clickable { cursor: pointer; }
.notif-item.clickable:hover { background: var(--row-hover); }
.notif-go { color: var(--accent, #2dd4bf); font-weight: 700; }

/* Сортируемые заголовки таблиц «Данных» (клик — сортировка по колонке). */
.data th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.data th.sortable:hover { background: var(--chip-hover); }

/* Список галочек в формах (навыки/модели техника из справочника). */
.chk-list { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 4px;
  max-height: 190px; overflow-y: auto; border: 1px solid var(--border-light);
  border-radius: var(--r-sm); padding: 6px 8px; background: var(--input-bg); }
.chk-item { display: inline-flex; align-items: center; gap: 5px; margin: 0;
  font-weight: 400; white-space: nowrap; cursor: pointer; }
.chk-item input { min-height: 0; width: auto; }

/* Статистика пользования (Аналитика → Использование) */
.seg { display: inline-flex; border: 1px solid var(--border); border-radius: var(--r-md);
  overflow: hidden; }
.seg button { border: none; background: var(--panel); color: var(--text);
  padding: 5px 12px; cursor: pointer; }
.seg button.active { background: var(--strong-bg); color: var(--strong-fg); }
.usage-cards { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; margin-top: 10px; }
.usage-card { flex: 0 1 160px; min-width: 140px; border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 12px 14px; background: var(--panel); }
.uc-val { font-size: 26px; font-weight: 700; }
.uc-lbl { margin-top: 2px; }
.usage-timeline { display: flex; align-items: flex-end; gap: 2px; height: 80px;
  border-bottom: 1px solid var(--border); padding-top: 4px; }
.ut-bar { flex: 1 1 auto; min-width: 3px; background: var(--strong-bg);
  border-radius: var(--r-xs) var(--r-xs) 0 0; }
.ubar-row { display: flex; align-items: center; gap: 8px; margin: 3px 0; }
.ubar-lbl { flex: 0 0 170px; font-size: var(--fs-sm); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.ubar-track { flex: 1 1 auto; height: 12px; background: var(--border-light);
  border-radius: var(--r-sm); overflow: hidden; }
.ubar-fill { display: block; height: 100%; background: var(--strong-bg); }
.ubar-num { flex: 0 0 46px; text-align: right; font-variant-numeric: tabular-nums; }

/* --- Impersonation «войти как пользователь» (ТЗ FilterSync Этап 1) --- */
/* Заметный, «не скрытый» баннер: админ всегда видит, что работает от имени. */
.imp-banner {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  background: var(--warn-bg); color: var(--warn-text);
  border-bottom: 2px solid var(--warn-border);
  font-size: var(--fs-sm); font-weight: 600;
}
.imp-banner .imp-ico { font-size: var(--fs-lg); }
.imp-banner #impBannerText { flex: 1 1 auto; }
.imp-banner .btn {
  border: 1px solid var(--warn-border); background: transparent;
  color: var(--warn-text); border-radius: var(--r-sm);
  padding: 4px 10px; cursor: pointer; font-weight: 600;
}
.imp-banner .btn:hover { background: var(--warn-border); color: #1c2430; }
/* Тонкая рамка страницы во время impersonation — постоянное напоминание. */
body.imp-active { box-shadow: inset 0 0 0 3px var(--warn-border); }

/* --- Подписка и оплата доступа (ТЗ FilterSync Этап 7) --- */
/* Баннер закрытой подписки — как imp-banner, но «денежный» акцент. */
.sub-banner {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  background: var(--warn-bg); color: var(--warn-text);
  border-bottom: 2px solid var(--warn-border);
  font-size: var(--fs-sm); font-weight: 600;
}
.sub-banner .imp-ico { font-size: var(--fs-lg); }
.sub-banner #subBannerText { flex: 1 1 auto; }
.sub-banner .btn {
  border: 1px solid var(--warn-border); background: transparent;
  color: var(--warn-text); border-radius: var(--r-sm);
  padding: 4px 10px; cursor: pointer; font-weight: 600;
}
.sub-banner .btn:hover { background: var(--warn-border); color: #1c2430; }
/* Карточки тарифов в разделе биллинга. */
.billing-plans {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.plan-card {
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--sp-3); cursor: pointer; background: var(--th-bg);
  display: flex; flex-direction: column; gap: 2px;
}
.plan-card:hover { border-color: var(--accent); }
.plan-card.selected {
  border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent) inset;
}
.plan-card .plan-name { font-weight: 700; }
.plan-card .plan-price { font-size: var(--fs-lg); font-weight: 700; }
.plan-card .plan-limits { color: var(--muted); font-size: var(--fs-xs); }
.sub-badge {
  display: inline-block; padding: 1px 8px; border-radius: var(--r-pill);
  font-size: var(--fs-xs); font-weight: 700;
}
.sub-badge.ok { background: var(--ok-bg, #e6f5ea); color: var(--ok-text, #1c6b34); }
.sub-badge.warn { background: var(--warn-bg); color: var(--warn-text); }
.sub-badge.bad { background: var(--err-bg, #fbe6e6); color: var(--err-text, #a12020); }
.imp-flags {
  margin-top: var(--sp-3); padding: var(--sp-3);
  border: 1px dashed var(--border); border-radius: var(--r-md);
  background: var(--th-bg);
}
.imp-flags-title { font-weight: 600; margin-bottom: var(--sp-2);
  font-size: var(--fs-sm); }
.imp-flags .check { display: flex; align-items: center; gap: var(--sp-2);
  margin: var(--sp-1) 0; font-weight: 400; }
.imp-flags .check input { width: auto; }

/* --- Доступ и видимость разделов (ТЗ FilterSync Этап 2) --- */
/* Гейт видимости: скрытый по правилам доступа раздел (отдельно от .hidden,
   чтобы не конфликтовать с admin-only/platform-only). */
.acc-hidden { display: none !important; }
/* Двухколоночный конструктор: слева субъект, справа матрица разделы×действия. */
.access-cols { display: flex; gap: var(--sp-4); flex-wrap: wrap;
  align-items: flex-start; }
.access-subject { flex: 0 0 220px; display: flex; flex-direction: column;
  gap: var(--sp-2); }
.access-grid-wrap { flex: 1 1 420px; min-width: 0; }
.access-matrix th, .access-matrix td { white-space: nowrap; }
.access-matrix tr.acc-top > td:first-child { font-weight: 600; }
.access-matrix select.acc-cell { min-width: 48px; padding: 2px 4px; }

/* --- Шаблоны интерфейса (ТЗ FilterSync Этап 3) --- */
.access-templates { margin-top: var(--sp-4); padding-top: var(--sp-3);
  border-top: 1px solid var(--border-light); }
.access-templates h4 { margin: 0 0 var(--sp-1); font-size: var(--fs-md); }
.access-templates .row { flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.tpl-item { display: flex; justify-content: space-between; align-items: center;
  gap: var(--sp-2); padding: 2px 0; border-bottom: 1px solid var(--border-light); }

/* --- Презентационный режим (ТЗ FilterSync Этап 4, §7) --- */
.present-bar {
  position: sticky; top: 0; z-index: 60;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  background: var(--strong-bg); color: var(--strong-fg);
}
.present-bar .present-brand { font-weight: 700; font-size: var(--fs-lg); }
.present-bar .present-clock { font-variant-numeric: tabular-nums; opacity: .85; }
.present-bar .present-actions { margin-left: auto; display: flex; gap: var(--sp-2); }
.present-bar .btn {
  border: 1px solid rgba(255, 255, 255, .35); background: transparent;
  color: var(--strong-fg); border-radius: var(--r-sm); padding: 4px 10px;
  cursor: pointer; font-weight: 600;
}
.present-bar .btn:hover { background: rgba(255, 255, 255, .15); }
.present-bar .btn.present-exit { border-color: var(--warn-border); }
.present-bar #presentRotateBtn.active { background: rgba(255, 255, 255, .22); }
/* Витрина: прячем служебную обвязку и элементы редактирования. Это режим
   ОТОБРАЖЕНИЯ (удобство показа), а не граница безопасности — та в Этапе 2. */
body.presentation .userbox,
body.presentation .tab[data-tab="settings"],
body.presentation .tab[data-tab="help"],
body.presentation .qhelp,
body.presentation .admin-only,
body.presentation .platform-only,
body.presentation .ctl button { display: none !important; }

/* --- Симулятор реальной работы (docs/39) --- */
.sim-grid {
  display: grid; gap: var(--sp-3); margin-top: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
.sim-grid label { display: flex; flex-direction: column; gap: 4px; }
.sim-types { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: 4px; }
.sim-type { display: inline-flex; align-items: center; gap: 4px; }
/* Микшер причин отказов сценария (этап 3b): подпись причины + числовой вес. */
.sim-causes-wrap { margin-top: 8px; }
.sim-causes { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: 4px; }
.sim-cause {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px; border: 1px solid var(--border); border-radius: var(--r-pill);
  font-size: var(--fs-sm);
}
.sim-cause input { text-align: center; }
/* История и сравнение запусков (этап 5). */
.sim-runs { display: flex; flex-direction: column; gap: 4px; }
.sim-run {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 8px; border: 1px solid var(--border); border-radius: var(--r-sm);
  font-size: var(--fs-sm);
}
.sim-run .sim-run-main { flex: 1 1 auto; min-width: 0; }
.sim-run-del { margin-left: auto; color: var(--muted); }
.sim-compare { margin-top: 10px; }
.sim-compare-title { font-weight: 600; margin-bottom: 6px; }
.sim-compare-tbl { border-collapse: collapse; width: 100%; font-size: var(--fs-sm); }
.sim-compare-tbl th, .sim-compare-tbl td {
  border: 1px solid var(--border); padding: 4px 8px; text-align: left;
  font-variant-numeric: tabular-nums;
}
.sim-compare-tbl th { background: var(--chip-bg); }
/* Прогресс фоновой массовой генерации (этап 6). */
.sim-job { margin-top: 10px; }
.sim-job-label { margin-bottom: 4px; font-size: var(--fs-sm); }
.sim-job-track {
  height: 8px; border-radius: var(--r-pill); background: var(--chip-bg);
  border: 1px solid var(--border); overflow: hidden;
}
.sim-job-fill {
  height: 100%; background: var(--accent, #0057B7);
  transition: width .3s ease;
}
/* Серверный движок таймлайна (этап 3c): отдельный блок под клиентскими кнопками. */
.sim-srv {
  margin-top: 10px; padding-top: 8px; border-top: 1px dashed var(--border);
}
.sim-estimate {
  margin-top: var(--sp-3); padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm); border: 1px solid var(--border, #e5e7eb);
}
.sim-est-ok { border-color: var(--ok, #16a34a); }
.sim-est-warn { border-color: var(--warn, #d97706); }
.sim-est-block { border-color: var(--danger, #dc2626); }

/* --- Редактор раскладки (ТЗ FilterSync Этап 5, §13) --- */
.layout-bar {
  position: sticky; top: 0; z-index: 60;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  background: var(--accent); color: #fff;
}
.layout-bar .layout-actions { margin-left: auto; display: flex; gap: var(--sp-2); }
/* Раскладка по умолчанию на роль (только админ): подпись + выбор роли + кнопка. */
.layout-bar .layout-role { display: flex; align-items: center; gap: var(--sp-2); }
.layout-bar .layout-role select {
  border: 1px solid rgba(255, 255, 255, .5); background: transparent; color: #fff;
  border-radius: var(--r-sm); padding: 4px 8px; font-weight: 600;
}
.layout-bar .layout-role select option { color: var(--text); }
.layout-bar .layout-role.hidden { display: none; }
.layout-bar .btn {
  border: 1px solid rgba(255, 255, 255, .5); background: transparent; color: #fff;
  border-radius: var(--r-sm); padding: 4px 10px; cursor: pointer; font-weight: 600;
}
.layout-bar .btn:hover { background: rgba(255, 255, 255, .18); }
/* Режим перетаскивания: помеченные панели «хватаемы» (пунктир + курсор + ручка). */
body.layout-edit [data-reorder-group] > [data-reorder-id] {
  cursor: move; outline: 2px dashed var(--accent); outline-offset: 3px;
  position: relative;
}
body.layout-edit [data-reorder-group] > [data-reorder-id] > h3::after {
  content: " ⠿"; opacity: .5;
}
[data-reorder-id].dragging { opacity: .45; }

/* Конструктор интерфейса (Odoo-стиль): скрытие/показ элементов. Скрытый
   элемент не виден в обычном режиме; в режиме редактирования показывается
   тускло, чтобы его можно было вернуть. */
.lay-hidden { display: none !important; }
body.layout-edit .lay-hidden {
  display: revert !important; opacity: .4;
  outline-style: dotted !important;
}
/* Кнопка «скрыть/показать» на каждом настраиваемом элементе — только в режиме
   редактирования. */
.lay-hide-btn { display: none; }
body.layout-edit [data-reorder-id] > .lay-hide-btn {
  display: inline-flex; align-items: center; justify-content: center;
  position: absolute; top: -8px; right: -8px; z-index: 5;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--accent); color: #fff; font-size: var(--fs-xs); line-height: 1;
  cursor: pointer; box-shadow: 0 1px 3px rgba(0,0,0,.4);
}
body.layout-edit [data-reorder-id] > .lay-hide-btn::before { content: "×"; }
body.layout-edit .lay-hidden > .lay-hide-btn { background: var(--ok, #16a34a); }
body.layout-edit .lay-hidden > .lay-hide-btn::before { content: "↺"; }

/* --- QR приглашения / тестовый кабинет (ТЗ FilterSync Этап 6, §14) --- */
.qr-box { display: inline-block; background: #fff; padding: 12px;
  border-radius: var(--r-md); }
.qr-box svg { display: block; width: 240px; height: 240px; }
label.inline { display: inline-flex; align-items: center; gap: 6px;
  white-space: nowrap; }
label.inline input { width: 70px; }

/* --- Двухфакторная аутентификация (2FA) — коды восстановления --- */
.twofa-codes { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--fs-md); line-height: 1.7; letter-spacing: 1px;
  white-space: pre; margin: 6px 0; padding: var(--sp-2);
  border-radius: var(--r-sm); background: var(--panel-2, rgba(127,127,127,.12));
  user-select: all; overflow-x: auto; }
#twofaQr svg { display: block; width: 200px; height: 200px; }

/* Версия в футере страницы входа (год и версия подставляются скриптом) */
.auth-version { opacity: .85; white-space: nowrap; }
