/* Carlito вендорен локально (дизайн-код 0.28.0) — без внешнего CDN (закрытый
 * контур). OFL 1.1, метрика Calibri, полная кириллица. Carlito — НЕ variable:
 * два начертания, 400 (Regular) и 700 (Bold); промежуточных весов нет, поэтому
 * font-weight:500 матчится в 400, 600 — в 700. font-display: swap — текст виден
 * сразу на фолбэке, подменяется по загрузке (без FOIT). Mono — системный
 * ui-monospace-стек (--font-mono), своего @font-face не требует. */
@font-face {
    font-family: 'Carlito';
    src: url('fonts/Carlito-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Carlito';
    src: url('fonts/Carlito-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* 0.19.49 systemic fix: HTML атрибут `hidden` означает «скрыть совсем»,
 * но UA-стиль `[hidden] { display: none }` идёт БЕЗ !important и
 * перебивается любым author-правилом с `display: flex/grid/block/…`.
 * Это привело к visible-пустым `.banner` (0.19.47) и
 * `.batch-active-actions` (всегда был, заметили 0.19.48).
 *
 * 37 элементов в HTML используют `hidden`. Чтобы не добавлять
 * `.X[hidden] { display: none }` к каждому классу с custom `display:`,
 * выставляем глобально с !important — `hidden` теперь inviolable,
 * как и подразумевал автор HTML-атрибута. JS `el.hidden = true` /
 * `el.removeAttribute('hidden')` продолжают работать как обычно. */
[hidden] { display: none !important; }

:root {
    /* ─── Pastel palette (Notion/Miro-inspired) ──────────── */
    /* sage — success / pass */
    --sage-50:  #F3F7EF;
    --sage-100: #E7EEDE;
    --sage-500: #87A878;
    --sage-700: #4A6B3E;

    /* clay — error / fail */
    --clay-50:  #FAF0EB;
    --clay-100: #F4E0D6;
    --clay-500: #C98976;
    --clay-700: #8A4B3C;

    /* sand — warning */
    --sand-50:  #FBF4DF;
    --sand-100: #F6E9C2;
    --sand-500: #D4A95B;
    --sand-700: #7A5A1A;

    /* steel — accent / primary (дизайн-код 0.28.0, было iris) */
    --steel-50:  #EDF0F5;
    --steel-100: #D6DEEA;
    --steel-500: #32527B;
    --steel-700: #223A5A;

    /* Legacy alias iris → steel (DEPRECATED, новый код использует --steel-*).
     * 200+ ссылок var(--iris-*) авто-обновляются через алиас — тот же
     * паттерн, что для --card-bg и др. в 0.19.60. Массовый rename не нужен. */
    --iris-50:  var(--steel-50);
    --iris-100: var(--steel-100);
    --iris-500: var(--steel-500);
    --iris-700: var(--steel-700);

    /* ─── File-format icon hues (дизайн-код: цветной бейдж формата) ──────
     * Отдельная от статус-палитры семантика: цвет кодирует ФОРМАТ файла
     * (IFC / IDS / …), а НЕ pass/fail. -glyph = контур документа (тон 500),
     * -ink = подпись расширения (тон 700, контрастнее на белом). IFC
     * совпадает со steel — акцент системы; остальные — родственные пастельные
     * тона того же регистра, что sage / sand / clay. Единый источник цвета для
     * примитива FileTypeIcon (uploaded-file-chip.js). */
    --fmt-ifc-glyph:    #32527B;  --fmt-ifc-ink:    #223A5A;
    --fmt-ifczip-glyph: #2E6E62;  --fmt-ifczip-ink: #1E4A42;
    --fmt-trm-glyph:    #B98F3E;  --fmt-trm-ink:    #7A5A1A;
    --fmt-ids-glyph:    #6E9160;  --fmt-ids-ink:    #4A6B3E;
    --fmt-xml-glyph:    #7A5B93;  --fmt-xml-ink:    #50406A;

    /* ─── Neutrals — warm off-white base ───────────────────────
     * Modern (canonical) tokens:
     *   --bg          холст за карточками
     *   --bg-subtle   приглушённые группированные секции
     *   --bg-surface  карточки (white)
     *   --ink-primary  основной текст
     *   --ink-secondary  второстепенный текст / icon
     *   --ink-tertiary   приглушённый / placeholder
     *   --border-subtle  светлая граница (тонкая)
     *   --border-default обычная граница (карточки)
     *
     * Legacy aliases — оставлены для существующего CSS (старые правила
     * используют `--card-bg`, `--text`, `--text-muted`, `--text-secondary`,
     * `--border`, `--border-light`). 0.19.60: значения теперь — РЕФЕРЕНСЫ
     * на canonical токены, не literal hex. Изменишь canonical — обновятся
     * legacy aliases. Mass-replace `--card-bg` → `--bg-surface` теперь
     * визуальный no-op, можно делать постепенно (см. docs/conventions.md §3).
     */
    --bg:            #FAF9F6;
    --bg-subtle:     #F4F2ED;
    --bg-surface:    #FFFFFF;
    --ink-primary:   #1F2421;
    --ink-secondary: #4F5852;
    --ink-tertiary:  #8A8F8A;
    --border-subtle: #EFEDE5;
    --border-default:#E6E3DB;

    /* Legacy aliases (DEPRECATED, не использовать в новом коде). */
    --card-bg:        var(--bg-surface);
    --text:           var(--ink-primary);
    --text-secondary: var(--ink-secondary);
    --text-muted:     var(--ink-tertiary);
    --border:         var(--border-default);
    --border-light:   var(--border-subtle);

    /* ─── Semantic status tokens (map to pastel) ─────────── */
    --pass:      var(--sage-500);
    --pass-bg:   var(--sage-50);
    --pass-text: var(--sage-700);
    --fail:      var(--clay-500);
    --fail-bg:   var(--clay-50);
    --fail-text: var(--clay-700);
    --warn:      var(--sand-500);
    --warn-bg:   var(--sand-50);
    --warn-text: var(--sand-700);
    /* Бордер-тон статус-чипов (--*-100) — раньше сырые rgba-тинты яркой
     * до-пастельной палитры (emerald / red / amber). */
    --pass-border: var(--sage-100);
    --fail-border: var(--clay-100);
    --warn-border: var(--sand-100);

    /* ─── Info (применимость / прогресс) ─────────────────────
     * Отдельный приглушённый сине-стальной тон, ОТЛИЧИМЫЙ от акцента steel
     * (info ≠ действие). Раньше — сырой tailwind-синий (var(--info-500)/var(--info-100)/…). */
    --info-50:   #EBF2FA;
    --info-100:  #D3E2F2;
    --info-500:  #3E6FA6;
    --info-700:  #294E79;
    --info-border: var(--info-100);

    /* ─── Accent (steel) ─────────────────────────────────── */
    --primary:       var(--steel-500);
    --primary-hover: var(--steel-700);
    --primary-light: var(--steel-50);

    /* ─── Radius + shadows + geometry ──────────────────────
     * Canonical: --r-lg / --r-md / --r-sm. Legacy aliases на референсы. */
    --r-lg:        14px;
    --r-md:        10px;
    --r-sm:         8px;
    /* Legacy aliases (DEPRECATED). */
    --radius:      var(--r-lg);
    --radius-sm:   var(--r-md);
    --radius-xs:   var(--r-sm);

    /* Тёплые тени дизайн-кода (0.28.0) — заметнее, с отрицательным spread. */
    --shadow:    0 1px 2px rgba(31, 36, 33, 0.06);
    --shadow-md: 0 6px 16px -4px rgba(31, 36, 33, 0.12);
    --shadow-lg: 0 16px 40px -8px rgba(31, 36, 33, 0.20);

    --sidebar-width: 232px;
    --sidebar-collapsed: 72px;
    --header-height: 64px;
    --top-tabs-height: 0px;
    --transition: 0.2s ease;
    --transition-slow: 0.3s ease;

    /* typography */
    --font-ui:   'Carlito', 'Segoe UI', system-ui, -apple-system, BlinkMacSystemFont, Roboto, sans-serif;
    --font-mono: ui-monospace, 'SF Mono', 'Cascadia Code', Menlo, 'Consolas', monospace;

    /* ─── Section title scale (0.19.50) ───────────────────────
     * До 0.19.50: одно и то же — «заголовок секции / шага»
     * SPA — было 4 разных размера (1.25 / 1.05 / 1 / 0.95rem) и
     * 2 разных weight (700/600) на разных страницах. Единый scale
     * фиксирует визуальный rhythm — пользователь не видит разной
     * «весомости» заголовков при переключении между модулями.
     *
     * Уровни (от больше к меньше):
     *   --section-title-lg     — заголовок «страницы внутри SPA»
     *                            (Обзор результатов / Что исправить).
     *   --section-title-size   — заголовок «карточки/шага» (IFC-модель /
     *                            Правила ТЭП / Загрузите файлы).
     *   --section-title-sm     — компактный sub-section.
     *
     * Использование: `.section-title` (default) /
     * `.section-title--lg` / `.section-title--sm`.
     */
    /* Шкала заголовков дизайн-кода (0.28.0): base 20 / lg 30 / sm 16 px. */
    --section-title-lg:     30px;
    --section-title-size:   20px;
    --section-title-sm:     16px;
    --section-title-weight: 700;

    /* ─── Spacing scale (0.19.52) ──────────────────────────────
     * 4-step base (Tailwind-like). До этого в style.css использовалось
     * 26 разных raw-px значений без системы. Цель — единый rhythm
     * через CSS variables.
     *
     * НЕ batch-миграция: эти vars обязательны для НОВОГО CSS,
     * старые `padding: 16px` мигрируются постепенно (когда касаемся
     * правила для другой причины).
     *
     * Покрытие audit'а (топ значения):
     *   --space-1  4px  — tight inline (border-spacing, small gap)
     *   --space-2  8px  — small (icon gap, micro padding)
     *   --space-3  12px — default (card inner gap, button padding-y)
     *   --space-4  16px — standard (card padding, section margin)
     *   --space-5  24px — large (section separator, page header)
     *   --space-6  32px — XL (hero, page-level separation)
     *   --space-7  48px — rare (modal-style padding)
     */
    --space-1:  4px;
    --space-2:  8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --space-7: 48px;
}

/* Utility — заголовок section/card/step. Применяется к h1-h6
 * безотносительно semantic level (h-level выбирается по структуре
 * документа для accessibility, .section-title унифицирует visual). */
.section-title {
    font-size: var(--section-title-size);
    font-weight: var(--section-title-weight);
    color: var(--text);
    margin: 0;
    line-height: 1.3;
}
.section-title--lg {
    font-size: var(--section-title-lg);
}
.section-title--sm {
    font-size: var(--section-title-sm);
    font-weight: 600;
}
/* Co-located icon — typical pattern in page headers (icon + text). */
.section-title svg {
    width: 20px;
    height: 20px;
    color: var(--primary);
    vertical-align: -3px;
    margin-right: 6px;
}
.section-title--lg svg {
    width: 26px;
    height: 26px;
}

body {
    font-family: var(--font-ui);
    background: var(--bg);
    color: var(--text);
    line-height: 1.5;
    overflow: hidden;
    height: 100vh;
    font-feature-settings: "ss01", "cv11";
}

/* ─── Header ──────────────────────────────────────────── */
.app-header {
    height: var(--header-height);
    background: var(--card-bg);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 24px;
    position: fixed;
    top: var(--top-tabs-height);
    left: 0;
    right: 0;
    z-index: 50;
}

.header-left {
    display: flex;
    align-items: center;
    gap: 12px;
}

.app-logo {
    width: 36px;
    height: 36px;
    background: var(--primary-light);
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--primary);
}
.app-logo svg { width: 20px; height: 20px; }

.header-title {
    display: flex;
    align-items: baseline;
    gap: 10px;
}
.header-title h1 {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--text);
}
.version-badge {
    font-size: 0.7rem;
    color: var(--text-muted);
    background: var(--border-light);
    padding: 2px 8px;
    border-radius: 10px;
    font-family: var(--font-mono);
    font-weight: 500;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 12px;
}

.btn-export-header {
    min-width: 104px;
    justify-content: center;
}
/* 0.19.56 cleanup: .btn-clear-session legacy hex palette (red #b91c1c)
 * полностью перекрыта modern clay-палитрой (line ~4582). Удалена. */

/* ─── Layout ──────────────────────────────────────────── */
.app-layout {
    display: flex;
    height: calc(100vh - var(--top-tabs-height) - var(--header-height));
    margin-top: calc(var(--top-tabs-height) + var(--header-height));
}

/* На страницах с .body--page-scroll (/tep, /xml-check, /agr, /stats) скроллится
 * вся страница, а не
 * .main-content — иначе колёсико не докручивает контент, когда курсор висит
 * над фиксированной шапкой или табами. Но при auto-высоте у .app-layout
 * сайдбар «обрывается» внизу видимой области: его высота наследуется от
 * собственного контента, а главный блок уезжает вниз вместе с документом.
 *
 * Фикс — sticky-сайдбар, прилипающий под шапкой и тянущийся ровно до низа
 * вьюпорта; .app-layout при этом перестаёт ограничивать высоту, чтобы main
 * мог быть длиннее экрана. */
body.body--page-scroll .app-layout {
    height: auto;
    min-height: calc(100vh - var(--top-tabs-height) - var(--header-height));
}
body.body--page-scroll .sidebar {
    position: sticky;
    top: calc(var(--top-tabs-height) + var(--header-height));
    height: calc(100vh - var(--top-tabs-height) - var(--header-height));
    align-self: flex-start;
}

/* Сегментированный переключатель подстраниц /tep */
.tep-segments {
    position: sticky;
    top: calc(var(--top-tabs-height) + var(--header-height));
    z-index: 5;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px;
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: 999px;
    align-self: center;
    box-shadow: var(--shadow);
}
.tep-segment {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 18px;
    border: 1px solid transparent;
    border-radius: 999px;
    background: transparent;
    color: var(--ink-tertiary);
    cursor: pointer;
    font-size: 0.9rem;
    font-weight: 600;
    transition: background var(--transition), color var(--transition);
}
.tep-segment svg {
    width: 16px;
    height: 16px;
}
.tep-segment:hover:not(.is-disabled):not(.is-active) {
    background: var(--bg-subtle);
    color: var(--ink-primary);
}
.tep-segment.is-active {
    background: var(--iris-500);
    color: #fff;
    cursor: default;
}
.tep-segment.is-active svg { color: #fff; }
.tep-segment.is-disabled {
    opacity: 0.45;
    cursor: not-allowed;
}
.tep-segment__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.25);
    color: inherit;
    font-size: 0.72rem;
    font-weight: 700;
}
.tep-segment:not(.is-active) .tep-segment__badge {
    background: var(--iris-50);
    color: var(--iris-700);
}
.tep-segment__badge[hidden] { display: none; }

/* Подстраницы — простой show/hide; стилизация лежит на дочерних .fixer-step */
.tep-subpage {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;   /* чтобы широкая таблица скроллилась внутри, а не раздувала */
}
.tep-subpage[hidden] { display: none; }

/* =========================================================================
 * Wizard — пошаговая «Настройка» с состояниями locked/active/completed.
 * ========================================================================= */

.wizard-step {
    background: var(--card-bg, #fff);
    border: 1px solid var(--border-subtle, var(--border));
    border-radius: var(--r-lg, 14px);
    transition: border-color var(--transition), box-shadow var(--transition);
    overflow: hidden;
}
/* 0.19.85: убрана синяя обводка active-шага — на flat-layout (single
 * step) она визуально пугала пользователя. Если wizard вернётся с
 * настоящей нумерацией шагов, можно вернуть локально. */
.wizard-step[data-step-state="active"] {
    /* no special border — выглядит как обычная карточка */
}
/* 0.19.83: locked-шаги полностью скрываем — последовательность строгая,
 * не показываем заголовки шагов, до которых юзер ещё не дошёл. Активный +
 * completed остаются видимы, чтобы юзер мог вернуться через «Изменить». */
.wizard-step[data-step-state="locked"] {
    display: none;
}

.wizard-step__head {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 18px 22px;
}

.wizard-step__num {
    width: 36px;
    height: 36px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    background: var(--border-light, rgba(0,0,0,0.06));
    color: var(--text-muted);
    font-weight: 700;
    font-size: 0.95rem;
    transition: background var(--transition), color var(--transition);
}
.wizard-step__num-check {
    display: none;
    width: 18px;
    height: 18px;
}
.wizard-step[data-step-state="active"] .wizard-step__num {
    background: var(--primary, #32527B);
    color: #fff;
}
.wizard-step[data-step-state="completed"] .wizard-step__num {
    background: var(--pass-bg);
    color: var(--pass-text);
}
.wizard-step[data-step-state="completed"] .wizard-step__num-digit { display: none; }
.wizard-step[data-step-state="completed"] .wizard-step__num-check { display: inline-block; }

.wizard-step__title-block {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.wizard-step__title {
    /* 0.19.50: было локальное 1.05rem/700 — теперь через --section-title-size
     * (тот же 1.05rem) и --section-title-weight. У .fixer-step такая же шкала. */
    margin: 0;
    font-size: var(--section-title-size);
    font-weight: var(--section-title-weight);
    color: var(--text);
}
.wizard-step__subtitle {
    margin: 0;
    font-size: 0.85rem;
    color: var(--text-muted);
}
.wizard-step[data-step-state="active"] .wizard-step__subtitle {
    color: var(--primary, #32527B);
}
.wizard-step[data-step-state="completed"] .wizard-step__subtitle {
    color: var(--pass-text);
}

.wizard-step .wizard-step__edit {
    display: none;
}
.wizard-step[data-step-state="completed"] .wizard-step__edit {
    display: inline-flex;
}

/* Body виден только в active-состоянии */
.wizard-step__body {
    display: none;
    padding: 0 22px 22px;
    flex-direction: column;
    gap: 14px;
}
.wizard-step[data-step-state="active"] .wizard-step__body {
    display: flex;
}

/* Footer (nav buttons) — две колонки: слева Назад, справа Далее/Запустить */
.wizard-step__footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding-top: 8px;
    border-top: 1px solid var(--border-subtle, var(--border));
    margin-top: 6px;
}
.wizard-step__footer-left {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Inline-toggle (Показать дерево правил) */
.wizard-step__inline-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: transparent;
    border: none;
    padding: 6px 0;
    color: var(--primary, #32527B);
    font-size: 0.88rem;
    font-weight: 600;
    cursor: pointer;
    align-self: flex-start;
}
.wizard-step__inline-toggle[hidden] { display: none; }
.wizard-step__inline-toggle:hover { text-decoration: underline; }
.wizard-step__inline-toggle svg {
    width: 14px;
    height: 14px;
    transition: transform var(--transition);
}
.wizard-step__inline-toggle.is-open svg {
    transform: rotate(90deg);
}

.wizard-step__reveal {
    align-self: flex-start;
}
.wizard-step__reveal[hidden] { display: none; }

/* Опасный вариант segment-badge — для подвкладки «Ошибки» */
.tep-segment__badge--danger {
    background: rgba(239, 68, 68, 0.18) !important;
    color: rgb(185, 28, 28) !important;
}
.tep-segment.is-active .tep-segment__badge--danger {
    background: rgba(255, 255, 255, 0.3) !important;
    color: #fff !important;
}

/* =========================================================================
 * Подвкладка «Ошибки» — аккордион по файлам.
 * ========================================================================= */
.tep-issues-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
/* 0.19.57: .tep-issues-empty / .tep-results-empty / .fx-empty /
 * .ids-radio-empty / .panel-loading удалены — мигрировано на
 * .empty-state utility (см. ~line 1779). */

.tep-issue-file {
    border: 1px solid var(--border-subtle, var(--border));
    border-left-width: 4px;
    border-radius: var(--r-md, 8px);
    background: var(--card-bg, #fff);
    overflow: hidden;
}
.tep-issue-file--critical { border-left-color: var(--fail); }
.tep-issue-file--warning  { border-left-color: var(--warn); }
.tep-issue-file--info     { border-left-color: var(--steel-500); }

.tep-issue-file__summary {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    cursor: pointer;
    list-style: none;
    user-select: none;
}
.tep-issue-file__summary::-webkit-details-marker { display: none; }
.tep-issue-file__summary::marker { content: ""; }
.tep-issue-file__summary:hover { background: rgba(0, 0, 0, 0.02); }

.tep-issue-file__icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}
.tep-issue-file--critical .tep-issue-file__icon { color: var(--fail); }
.tep-issue-file--warning  .tep-issue-file__icon { color: var(--warn); }
.tep-issue-file--info     .tep-issue-file__icon { color: var(--steel-500); }

.tep-issue-file__name {
    flex: 1;
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-mono);
    font-size: 0.88rem;
}
.tep-issue-file__count {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--steel-700);
    padding: 3px 11px;
    background: var(--steel-50);
    border: 1px solid var(--steel-100);
    border-radius: 999px;
    flex-shrink: 0;
}
.tep-issue-file__count::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--steel-500);
}

.tep-issue-file__list {
    list-style: none;
    margin: 0;
    padding: 0 16px 16px 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* 0.28.x: замечания рендерятся как .banner (renderIssues) — .tep-issue-item
 * удалён. Ниже — новые элементы панели «Ошибки» под дизайн-код. */

/* Сводка → stat-пилюли */
.tep-issue-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 4px;
}
.tep-stat {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    padding: 5px 12px;
    background: var(--bg-subtle);
    border: 1px solid var(--border-subtle);
    border-radius: 999px;
    font-size: 0.82rem;
}
.tep-stat__label { color: var(--ink-secondary); }
.tep-stat__val {
    font-weight: 700;
    color: var(--ink-primary);
    font-variant-numeric: tabular-nums;
}
.tep-stat__val.is-zero { color: var(--ink-tertiary); font-weight: 600; }

/* Баннер замечания внутри файла — свой gap у списка, margin не нужен */
.tep-issue-file__list .banner { margin-bottom: 0; }
.tep-issue-text { margin: 0; }

/* Code-чипы показателей */
.tep-metric-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
}
.tep-metric-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 5px 12px 5px 6px;
    background: var(--bg-surface);
    border: 1px solid var(--steel-100);
    border-radius: var(--r-sm);
    font-size: 0.82rem;
    color: var(--ink-secondary);
}
.tep-metric-chip__code {
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: 0.8rem;
    color: var(--steel-700);
    background: var(--steel-50);
    padding: 2px 7px;
    border-radius: 6px;
}

/* 0.19.57: см. ~line 1779 — .empty-state.empty-state--lg */

/* ─── Sidebar ─────────────────────────────────────────── */
.sidebar {
    width: var(--sidebar-width);
    min-width: var(--sidebar-width);
    background: var(--card-bg);
    border-right: 1px solid var(--border);
    padding: 16px 12px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    transition: width var(--transition-slow), min-width var(--transition-slow);
    overflow: hidden;
}

.sidebar-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    transition: all var(--transition);
    white-space: nowrap;
    user-select: none;
}
.sidebar-item svg { width: 20px; height: 20px; flex-shrink: 0; }
.sidebar-item:hover:not(.disabled) {
    background: var(--border-light);
    color: var(--text);
}
.sidebar-item.active {
    background: var(--primary-light);
    color: var(--primary);
    font-weight: 600;
}
.sidebar-item.disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.sidebar-footer {
    margin-top: auto;
    padding: 12px 14px;
    text-align: center;
}
.sidebar-author {
    font-size: 0.68rem;
    font-weight: 600;
    color: var(--text-muted);
    letter-spacing: 0.05em;
    opacity: 0.6;
    white-space: nowrap;
}

/* ─── Main Content ────────────────────────────────────── */
.main-content {
    flex: 1;
    overflow-y: auto;
    padding: 28px 32px 64px;
    min-width: 0;
}

/* ─── Pages & Transitions ─────────────────────────────── */
.page {
    display: none;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity var(--transition-slow), transform var(--transition-slow);
}
.page.page-active {
    display: block;
    opacity: 1;
    transform: translateY(0);
}

.page-header {
    margin-bottom: 24px;
}
.page-header h2 {
    /* 0.19.50: использует --section-title-lg (30px) — единая шкала. */
    font-size: var(--section-title-lg);
    font-weight: var(--section-title-weight);
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 10px;
}
.page-header h2 svg { width: 26px; height: 26px; color: var(--primary); }

/* ─── Cards ───────────────────────────────────────────── */
/* 0.19.53 cleanup: было 2 rule блока (line 812 + 4746). Modern palette
 * (Notion/Miro warmer) wins для bg/border/radius/shadow, legacy для
 * padding/transition. Сейчас — один canonical .card с final-state. */
.card {
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    padding: 24px;
    transition: box-shadow var(--transition);
}
.card:hover {
    box-shadow: var(--shadow-md);
}

/* 0.19.53: `.surface` — utility-класс для container'ов которые хотят
 * визуал .card без padding (когда внутри свой layout определяет paddings).
 * Готов к использованию в новом коде; existing ad-hoc card-классы
 * (action-card, fix-summary-card, ...) будут converging postepenno. */
.surface {
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
}

/* ─── File Selection ──────────────────────────────────── */
.file-selection {
    margin-bottom: 24px;
}
.file-selection--unified {
    padding: 28px;
}
.file-selection-intro {
    margin-bottom: 22px;
}
.file-selection-intro h3 {
    font-size: var(--section-title-size);
    font-weight: var(--section-title-weight);
    color: var(--text);
    margin-bottom: 4px;
}
.file-selection-intro p {
    color: var(--text-secondary);
    font-size: 0.92rem;
}
.file-panes {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
}
.file-pane {
    padding: 20px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: linear-gradient(180deg, #fff, #fbfcff);
}

.file-card-header {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 16px;
}
.file-card-header svg { width: 20px; height: 20px; color: var(--primary); }
.file-card-header h3 { font-size: 1rem; font-weight: 600; }

.file-card select {
    width: 100%;
    padding: 10px 12px;
    border: 1.5px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: 0.9rem;
    font-family: inherit;
    background: var(--card-bg);
    color: var(--text);
    cursor: pointer;
    transition: border-color var(--transition);
    outline: none;
}
.file-card select:focus { border-color: var(--primary); }

.drop-zone {
    margin-top: 12px;
    border: 2px dashed var(--border);
    border-radius: var(--radius-sm);
    padding: 24px;
    text-align: center;
    transition: all var(--transition);
}
.drop-zone.dragover {
    border-color: var(--primary);
    background: var(--primary-light);
}
.drop-icon { color: var(--text-muted); margin-bottom: 8px; }
.drop-zone p { color: var(--text-muted); font-size: 0.85rem; margin-bottom: 10px; }

.ifc-prepare-status {
    margin-top: 12px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: linear-gradient(180deg, #fff, var(--border-light));
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.7);
}
.ifc-prepare-status--loading {
    max-width: 520px;
    margin: 16px auto 0;
    text-align: left;
}
.ifc-prepare-status__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}
.ifc-prepare-status__title {
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--text);
    letter-spacing: 0.01em;
}
.ifc-prepare-status__badge {
    font-size: 0.74rem;
    font-weight: 700;
    color: var(--text-secondary);
    background: var(--border-light);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 4px 9px;
    white-space: nowrap;
}
.ifc-prepare-status__bar {
    height: 10px;
    border-radius: 999px;
    overflow: hidden;
    background: #e9eef5;
    border: 1px solid var(--border);
}
.ifc-prepare-status__fill {
    height: 100%;
    width: 0;
    opacity: 1;
    border-radius: inherit;
    transition: width 0.24s ease, background 0.2s ease;
    background: linear-gradient(90deg, #cbd5e1 0%, #94a3b8 100%);
}
.ifc-prepare-status__meta {
    margin-top: 8px;
    font-size: 0.76rem;
    color: var(--text-muted);
    line-height: 1.4;
    min-height: 1.1em;
}
.ifc-prepare-status.is-waiting {
    border-color: var(--border);
    background: linear-gradient(180deg, #fff, var(--border-light));
}
.ifc-prepare-status.is-waiting .ifc-prepare-status__badge {
    color: var(--text-secondary);
    background: var(--border-light);
    border-color: var(--border);
}
.ifc-prepare-status.is-uploading {
    border-color: #c7d2fe;
    background: linear-gradient(180deg, #fafbff, #eef2ff);
}
.ifc-prepare-status.is-uploading .ifc-prepare-status__badge {
    color: var(--primary);
    background: rgba(50, 82, 123, 0.10);
    border-color: rgba(50, 82, 123, 0.22);
}
.ifc-prepare-status.is-uploading .ifc-prepare-status__fill {
    background: linear-gradient(90deg, #5A7BA8 0%, var(--primary) 100%);
}
.ifc-prepare-status.is-parsing {
    border-color: var(--info-border);
    background: var(--info-50);
}
.ifc-prepare-status.is-parsing .ifc-prepare-status__badge {
    color: var(--info-500);
    background: var(--info-50);
    border-color: var(--info-border);
}
.ifc-prepare-status.is-parsing .ifc-prepare-status__fill {
    background: linear-gradient(90deg, var(--info-100) 0%, var(--info-500) 100%);
}
.ifc-prepare-status.is-ready {
    border-color: #a7f3d0;
    background: linear-gradient(180deg, #f7fffb, var(--pass-bg));
}
.ifc-prepare-status.is-ready .ifc-prepare-status__badge {
    color: var(--pass-text);
    background: var(--pass-bg);
    border-color: var(--pass-border);
}
.ifc-prepare-status.is-ready .ifc-prepare-status__fill {
    background: linear-gradient(90deg, #34d399 0%, var(--pass) 100%);
}
.ifc-prepare-status.is-error {
    border-color: #fecaca;
    background: linear-gradient(180deg, #fffafa, var(--fail-bg));
}
.ifc-prepare-status.is-error .ifc-prepare-status__badge {
    color: var(--fail-text);
    background: var(--fail-bg);
    border-color: var(--fail-border);
}
.ifc-prepare-status.is-error .ifc-prepare-status__fill {
    background: linear-gradient(90deg, #f87171 0%, var(--fail) 100%);
}

.upload-status {
    margin-top: 10px;
    font-size: 0.85rem;
    color: var(--primary);
    font-weight: 500;
    min-height: 1.3em;
    /* Длинные имена файлов (в т.ч. без пробелов) не должны вылезать за карточку. */
    overflow-wrap: anywhere;
    word-break: break-word;
}
.upload-status.is-loading {
    color: var(--text-muted);
}
.upload-status.is-error {
    color: var(--fail);
}
.upload-status.is-ready {
    color: var(--pass);
}
/* ─── Buttons ─────────────────────────────────────────── */
.btn-primary {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--primary);
    color: #fff;
    border: none;
    padding: 12px 28px;
    border-radius: var(--radius-sm);
    font-size: 0.95rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: all var(--transition);
}
.btn-primary svg { width: 18px; height: 18px; }
.btn-primary:hover { background: var(--primary-hover); transform: translateY(-1px); box-shadow: var(--shadow-md); }
.btn-primary:active { transform: translateY(0); }
.btn-primary:disabled { background: var(--text-muted); cursor: not-allowed; transform: none; box-shadow: none; }

/* 0.19.56 cleanup: было 2 правила (это + override line ~4948). Modern
 * палитра выигрывала для bg/color/border/radius/font-weight. Слиты —
 * final values здесь. svg-size и :hover остаются. */
.btn-secondary {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--bg-surface);
    color: var(--ink-secondary);
    border: 1px solid var(--border-default);
    padding: 6px 16px;
    border-radius: var(--r-md);
    font-size: 0.85rem;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    transition: all var(--transition);
}
.btn-secondary svg { width: 16px; height: 16px; }
/* Disabled-вид: у .btn-primary он есть (line ~1051), у secondary не было —
 * поэтому «Добавить файлы» во время скана был disabled по факту (JS ставит
 * .disabled), но выглядел активным. Серый + not-allowed, как у остальных
 * disabled-контролов проекта. */
.btn-secondary:disabled { opacity: 0.45; cursor: not-allowed; }
/* :hover теперь только в modern override (line ~4948) — :not(:disabled)
 * дает чуть выше specificity и охватывает disabled state. */

.controls {
    display: flex;
    align-items: center;
    gap: 20px;
    margin-bottom: 24px;
}
.controls--inside {
    margin-top: 24px;
    margin-bottom: 0;
    padding-top: 20px;
    border-top: 1px solid var(--border);
    flex-wrap: wrap;
}
.controls--inside .btn-primary {
    margin-left: auto;
}
.checkbox-label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.9rem;
    cursor: pointer;
    color: var(--text-secondary);
}
/* 0.19.55: размер уже 18px (стандарт), accent-color мигрирован
 * с --primary (зелёный) на --iris-500 (синий) — совпадает с focus halo
 * .input-search / .input-select. Единый interaction-feedback color. */
.checkbox-label input[type="checkbox"] {
    width: 18px;
    height: 18px;
    accent-color: var(--iris-500);
    cursor: pointer;
}

/* ─── Loading ─────────────────────────────────────────── */
/* Модальный оверлей подготовки/проверки — тот же слой, что .fx-modal-backdrop
   (вынесен на уровень body, т.к. у .page transform ломает position:fixed). */
.loading {
    position: fixed;
    inset: 0;
    z-index: 1000;
    background: rgba(15, 17, 26, 0.55);
    backdrop-filter: blur(2px);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.loading__card {
    width: 100%;
    max-width: 560px;
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    padding: 32px 36px;
    text-align: center;
}
.loading p {
    color: var(--text-secondary);
    font-weight: 500;
}
.spinner {
    width: 40px; height: 40px;
    border: 3px solid var(--border);
    border-top-color: var(--primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    margin: 0 auto 14px;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ─── Banner — единый visual для status-сообщений ─────────────────────────
 *
 * Замена 3 отдельных классов (.error-banner / .unrouted-banner /
 * .cov-skip-banner) которые делали примерно одно и то же, но с
 * разными paddings / borders / margins. 4 модификатора по цвету:
 *
 *     <div class="banner banner--error">Plain text message</div>
 *     <div class="banner banner--warn">
 *         <i data-lucide="alert-triangle" class="banner__icon"></i>
 *         <div class="banner__body">Message <strong>with</strong> markup</div>
 *     </div>
 *
 * Icon slot опциональный — flex с одним child тоже корректно отображается.
 * 0.19.47: первый шаг визуальной унификации.
 */
.banner {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 16px;
    border-radius: var(--radius-sm);
    margin-bottom: 16px;
    font-size: 0.88rem;
    line-height: 1.5;
    border: 1px solid transparent;
}
/* 0.19.49: специфичное `.banner[hidden]` правило больше не нужно —
 * глобальное `[hidden] { display: none !important }` сверху файла
 * закрывает этот класс багов для ВСЕХ элементов сразу. */
.banner__icon {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    margin-top: 1px;
}
.banner__body {
    flex: 1;
    min-width: 0;
}
.banner code {
    background: rgba(0,0,0,0.06);
    padding: 1px 5px;
    border-radius: 3px;
    font-size: 0.82em;
}
.banner--error {
    background: var(--fail-bg);
    color: var(--fail-text);
    border-color: rgba(220,38,38,0.20);
}
.banner--warn {
    background: var(--warn-bg);
    color: var(--warn-text);
    border-color: rgba(217,119,6,0.20);
}
.banner--warn .banner__icon { color: var(--warn); }
.banner--info {
    background: var(--iris-50);
    color: var(--iris-700);
    border-color: var(--iris-100);
}
.banner--success {
    background: var(--sage-50);
    color: var(--sage-700);
    border-color: var(--sage-100);
}

/* Строгая проверка «Назначение здания» (RUS_FNO) — список зданий в баннере. */
.bp-message { margin-top: 4px; }
.bp-list {
    list-style: none;
    margin: 8px 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.bp-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.85rem;
}
.bp-row__mark { width: 15px; height: 15px; flex-shrink: 0; }
.bp-row--fail .bp-row__mark { color: var(--fail); }
.bp-row--ok .bp-row__mark { color: var(--pass); }
.bp-row__name { font-weight: 600; }
.bp-row__value { color: inherit; opacity: 0.85; margin-left: auto; }

/* Проверка кодов помещений в квартирах — блоки «квартира → помещения» в
   «Деталях»: сворачиваемые группы движка (.subgroup), по умолчанию свёрнуты. */
.apartment-blocks { padding: 0 20px 16px; }
.apartment-block { margin-top: 8px; }
/* Строки найденных ошибок под заголовком группы-квартиры («Детали» и «Что
   исправить») — видны в свёрнутом состоянии, по строке на правило. */
.subgroup-sublines {
    margin-top: 2px;
    font-size: 0.8rem;
    font-weight: 400;
    line-height: 1.35;
    color: var(--fail-text);
}

/* ─── Progress overlay (0.19.58) ──────────────────────────────────────────
 * Единый компонент для loading / progress UI. До 0.19.58 были отдельные
 * реализации (.loading + .ifc-prepare-status на главной). Все рендерили
 * одно — spinner + phase text + detail text + progress bar — но с разной
 * DOM-разметкой и разными именами классов.
 *
 * Использование: см. progress.js → ProgressOverlay.show/update/hide.
 *
 * Variants:
 *   --overlay   full-screen overlay (z-index 20, backdrop blur)
 *   --inline    card-в-потоке (max-width 520px, центрирован margin: auto)
 *
 * Tones (через class on root):
 *   --idle / --loading / --parsing / --ready / --error
 *
 * Indeterminate (когда percent === null): root получает --indeterminate,
 * .progress__bar-fill анимируется через @keyframes progressSlide.
 */
.progress {
    display: flex;
    align-items: center;
    justify-content: center;
}
.progress--overlay {
    position: absolute;
    inset: 0;
    background: rgba(248, 250, 253, 0.82);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    z-index: 20;
    animation: fadeIn 0.18s ease-out;
}

/* Модалка загрузки при переключении вкладок главной (Детали/Что исправить/
   Схема): на весь вьюпорт (fixed) поверх сайдбара и шапки. Переопределяет
   absolute — внутри скроллящегося .main-content absolute-оверлей «уезжает»
   при прокрутке, fixed держится на месте. */
#page-loading-overlay.progress--overlay {
    position: fixed;
    z-index: 9000;
}
.progress--inline {
    display: block;
    margin: var(--space-4) auto;
    max-width: 520px;
}
.progress__card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 28px 36px;
    background: var(--bg-surface, #fff);
    border: 1px solid var(--border-default, var(--border-subtle));
    border-radius: var(--r-lg, 18px);
    box-shadow: var(--shadow-lg);
    min-width: 320px;
    max-width: 480px;
}
.progress__spinner {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--iris-50);
}
.progress__spinner svg {
    width: 32px;
    height: 32px;
    color: var(--iris-500);
}
.progress__spinner .spin {
    animation: spin 1s linear infinite;
}
.progress__texts {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    text-align: center;
}
.progress__phase {
    font-size: 15px;
    font-weight: 600;
    color: var(--ink-primary);
}
.progress__phase:empty {
    display: none;
}
.progress__detail {
    font-size: 13px;
    color: var(--ink-tertiary);
    min-height: 16px;
    max-width: 360px;
    word-break: break-word;
}
.progress__bar {
    width: 240px;
    height: 4px;
    background: rgba(0, 0, 0, 0.06);
    border-radius: 999px;
    overflow: hidden;
    position: relative;
}
.progress__bar-fill {
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    background: var(--iris-500);
    border-radius: 999px;
    transition: width 0.24s ease-out;
}
.progress--indeterminate .progress__bar-fill {
    left: -40%;
    width: 40%;
    animation: progressSlide 1.4s ease-in-out infinite;
}
@keyframes progressSlide {
    0%   { left: -40%; }
    100% { left: 100%; }
}
/* Tone overrides: на главной разные стадии красятся разным акцентом.
 * Пока заготовка — будут активированы когда main мигрирует на ProgressOverlay. */
.progress--ready .progress__bar-fill { background: var(--sage-500, var(--pass)); }
.progress--error .progress__bar-fill { background: var(--clay-500, var(--fail)); }
.progress--error .progress__spinner { background: var(--clay-50); }
.progress--error .progress__spinner svg { color: var(--clay-700); }

/* ─── Confirm modal (0.19.61) ─────────────────────────────────────────────
 * Замена UA-default window.confirm() на кастомный modal. Используется
 * в sidebar.js (nav-guard при cross-module переходе) и потенциально
 * везде где нужно «вы уверены?».
 *
 * Layout: full-screen overlay (rgba dim) + центрированная card.
 * Анимация: overlay fade-in (opacity), card scale-up (transform).
 * Стилевая палитра — canonical tokens (bg-surface / ink-primary / r-lg).
 */
.confirm-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 10001;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(31, 36, 33, 0.42);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    opacity: 0;
    transition: opacity 180ms ease-out;
    padding: 16px;
}
.confirm-modal-overlay.is-open {
    opacity: 1;
}
.confirm-modal-card {
    background: var(--bg-surface);
    border: 1px solid var(--border-default);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    padding: 24px;
    max-width: 440px;
    width: 100%;
    transform: scale(0.96);
    transition: transform 180ms cubic-bezier(0.16, 1, 0.3, 1);
}
.confirm-modal-overlay.is-open .confirm-modal-card {
    transform: scale(1);
}
.confirm-modal-title {
    margin: 0 0 8px;
    font-size: var(--section-title-size);
    font-weight: var(--section-title-weight);
    color: var(--ink-primary);
}
.confirm-modal-message {
    margin: 0 0 20px;
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--ink-secondary);
    white-space: pre-line;
}
.confirm-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}
.confirm-modal-actions .btn-secondary,
.confirm-modal-actions .btn-primary {
    min-width: 88px;
    justify-content: center;
}
/* Danger вариант — confirm-кнопка красная (для деструктивных действий).
 * btn-primary--danger переопределяет background/border на clay-палитру. */
.btn-primary--danger {
    background: var(--clay-500) !important;
    border-color: var(--clay-500) !important;
}
.btn-primary--danger:hover:not(:disabled) {
    background: var(--clay-700) !important;
    border-color: var(--clay-700) !important;
}

/* ─── Tooltip (0.19.60) ───────────────────────────────────────────────────
 * Кастомный tooltip — замена UA-default `title="..."` (медленный,
 * нестилизуемый, недоступен с клавиатуры). Управляется через
 * data-tooltip="..." атрибут + tooltip.js (event delegation).
 *
 * Position: fixed — рендерится в координатах viewport, чтобы overflow
 * родительских контейнеров (карточки, modals) не клипал tooltip.
 *
 * Цветовая палитра: ink-primary (тёмный) на bg-surface (светлый), чтобы
 * читалось поверх любого фона. Тень глубокая (shadow-lg) — visual lift.
 */
.tooltip {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 10000;
    max-width: 320px;
    padding: 6px 10px;
    background: #1f2937;
    color: #f9fafb;
    border-radius: var(--r-sm, 6px);
    font-size: 0.78rem;
    line-height: 1.4;
    box-shadow: var(--shadow-lg);
    pointer-events: none;
    opacity: 0;
    transform: translateY(2px);
    transition: opacity 150ms ease-out, transform 150ms ease-out;
    word-break: break-word;
    white-space: pre-line;
}
.tooltip--visible {
    opacity: 1;
    transform: translateY(0);
}
/* Стрелочка-указатель — pseudo-element. Позиция зависит от placement. */
.tooltip::after {
    content: '';
    position: absolute;
    width: 0;
    height: 0;
    border: 5px solid transparent;
}
.tooltip[data-placement="top"]::after {
    bottom: -10px;
    left: 50%;
    margin-left: -5px;
    border-top-color: #1f2937;
}
.tooltip[data-placement="bottom"]::after {
    top: -10px;
    left: 50%;
    margin-left: -5px;
    border-bottom-color: #1f2937;
}
.tooltip[data-placement="left"]::after {
    right: -10px;
    top: 50%;
    margin-top: -5px;
    border-left-color: #1f2937;
}
.tooltip[data-placement="right"]::after {
    left: -10px;
    top: 50%;
    margin-top: -5px;
    border-right-color: #1f2937;
}

/* ─── Toast (0.19.57) ─────────────────────────────────────────────────────
 * Ephemeral notifications в правом верхнем углу. Стек снизу вверх,
 * новые сверху. Auto-dismiss после Toast.show({duration}). Прозрачные
 * для cursor — pointer-events на индивидуальных toast'ах (чтобы можно
 * было кликнуть UI под пустым местом контейнера).
 *
 * Tone-палитра: совпадает с .banner (sage/clay/honey/iris), но более
 * "взрослые" тени и более компактный padding — toast визуально легче,
 * это «временное» сообщение, а banner — «постоянное».
 */
.toast-container {
    position: fixed;
    top: 16px;
    right: 16px;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    gap: 8px;
    pointer-events: none;
    max-width: 380px;
    width: calc(100vw - 32px);
}
.toast {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 10px 12px 10px 14px;
    border-radius: var(--r-md);
    border: 1px solid var(--border-default);
    background: var(--bg-surface);
    box-shadow: var(--shadow-lg);
    font-size: 0.88rem;
    line-height: 1.4;
    color: var(--ink-primary);
    pointer-events: auto;
    animation: toastIn 200ms cubic-bezier(0.16, 1, 0.3, 1);
}
.toast--leaving {
    animation: toastOut 200ms ease-in forwards;
}
.toast__message {
    flex: 1;
    min-width: 0;
    word-break: break-word;
}
.toast__close {
    flex-shrink: 0;
    background: transparent;
    border: none;
    color: inherit;
    font-size: 1.2rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 2px;
    opacity: 0.5;
    transition: opacity var(--transition);
}
.toast__close:hover {
    opacity: 1;
}
.toast--success {
    background: var(--sage-50);
    color: var(--sage-700);
    border-color: var(--sage-100);
}
.toast--error {
    background: var(--clay-50);
    color: var(--clay-700);
    border-color: var(--clay-100);
}
.toast--warn {
    background: var(--honey-50, var(--warn-bg));
    color: var(--honey-700, var(--warn-text));
    border-color: var(--honey-100, rgba(217,119,6,0.20));
}
.toast--info {
    background: var(--iris-50);
    color: var(--iris-700);
    border-color: var(--iris-100);
}
@keyframes toastIn {
    from { opacity: 0; transform: translateX(20px); }
    to   { opacity: 1; transform: translateX(0); }
}
@keyframes toastOut {
    from { opacity: 1; transform: translateX(0); }
    to   { opacity: 0; transform: translateX(20px); }
}

/* DEPRECATED 0.19.47: переехало в .banner / .banner--error / --warn.
 * Оставлены как aliases чтобы старые внешние скрипты / закладки не
 * сломались, и для постепенной миграции если что-то пропустим.
 * Удалить вместе со следующим CSS-cleanup-эпиком. */
.error-banner {
    background: var(--fail-bg);
    color: var(--fail-text);
    padding: 14px 20px;
    border-radius: var(--radius-sm);
    margin-bottom: 20px;
    font-weight: 500;
    border: 1px solid var(--fail-border);
}

/* ─── Stats Row ───────────────────────────────────────── */
.stats-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 16px;
    margin-bottom: 20px;
}

/* 0.19.53 cleanup: было 3 rule блока (line 1204 + 4754 + 5062) каждый
 * частично перебивал другой. Теперь — один canonical .stat-card с
 * final-state значениями (modern palette wins). status-tint overrides
 * остались отдельно (.stat-pass, .stat-fail, ...). */
.stat-card {
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    min-height: 108px;
    transition: all var(--transition);
}
.stat-card:hover { box-shadow: var(--shadow-md); }

.stat-icon {
    width: 48px; height: 48px;
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.stat-icon svg { width: 24px; height: 24px; }

.stat-pass .stat-icon { background: var(--pass-bg); color: var(--pass); }
.stat-fail .stat-icon { background: var(--fail-bg); color: var(--fail); }
.stat-warn .stat-icon { background: var(--warn-bg); color: var(--warn); }
.stat-coverage .stat-icon { background: var(--primary-light); color: var(--primary); }
.stat-skip .stat-icon { background: #FFF7ED; color: #C2410C; }

.stat-number { font-size: 2rem; font-weight: 700; line-height: 1; }
.stat-pass .stat-number { color: var(--pass); }
.stat-fail .stat-number { color: var(--fail); }
.stat-warn .stat-number { color: var(--warn); }
.stat-coverage .stat-number { color: var(--primary); font-size: 1.5rem; }
.stat-skip .stat-number { color: #C2410C; }
.stat-label { font-size: 0.85rem; color: var(--text-muted); margin-top: 2px; }

/* ─── Report Meta ─────────────────────────────────────── */
.report-meta {
    font-size: 0.85rem;
    color: var(--text-muted);
    margin-bottom: 16px;
    display: flex;
    gap: 20px;
    flex-wrap: wrap;
}
.report-meta span { display: inline-flex; align-items: center; gap: 4px; }

/* ─── Overall Status ──────────────────────────────────── */
.overall-status {
    padding: 14px 24px;
    border-radius: var(--radius);
    font-size: 1rem;
    font-weight: 600;
    text-align: center;
    margin-bottom: 24px;
    transition: all var(--transition);
}
.status-pass { background: var(--pass-bg); color: var(--pass-text); border: 1px solid var(--pass-border); }
.status-fail { background: var(--fail-bg); color: var(--fail-text); border: 1px solid var(--fail-border); }
.status-warn { background: var(--warn-bg); color: var(--warn-text); border: 1px solid var(--warn-border); }

/* ─── Absent Categories ───────────────────────────────── */
/* Отступ между панелями Обзора (нераспознанные / отсутствующие / назначение),
   чтобы они не прилипали друг к другу. Скрытые (hidden) не занимают места. */
#unrouted-overview-panel,
#absent-panel,
#storey-naming-panel,
#building-purpose-panel,
#apartment-rooms-panel { margin-bottom: 20px; }

.absent-panel-content {
    display: flex;
    gap: 14px;
    align-items: flex-start;
    padding: 14px 18px;
    border-radius: var(--radius);
}
.absent-excluded {
    background: var(--info-50);
    border: 1px solid var(--info-border);
}
.absent-excluded .absent-panel-icon { color: var(--info-500); }
.absent-excluded .absent-panel-title { color: var(--info-700); }
.absent-excluded .absent-panel-text { color: var(--info-700); }
.absent-excluded .absent-spec-tag { background: var(--info-100); color: var(--info-700); }
.absent-excluded .absent-action-btn {
    border-color: var(--info-border);
    color: var(--info-700);
}
.absent-excluded .absent-action-btn:hover { background: var(--info-100); }

.absent-included {
    background: var(--warn-bg);
    border: 1px solid rgba(217,119,6,0.25);
}
.absent-included .absent-panel-icon { color: var(--warn); }
.absent-included .absent-panel-title { color: var(--warn-text); }
.absent-included .absent-panel-text { color: var(--warn-text); opacity: 0.85; }
.absent-included .absent-spec-tag { background: rgba(217,119,6,0.12); color: var(--warn-text); }
.absent-included .absent-action-btn {
    border-color: rgba(217,119,6,0.4);
    color: var(--warn-text);
}
.absent-included .absent-action-btn:hover { background: rgba(217,119,6,0.1); }

/* Красный вариант — нераспознанные IfcSpace в Обзоре (ошибка, а не warn). */
.absent-error {
    background: var(--fail-bg);
    border: 1px solid var(--fail-border);
}
.absent-error .absent-panel-icon { color: var(--fail); }
.absent-error .absent-panel-title { color: var(--fail-text); }
.absent-error .absent-panel-text { color: var(--fail-text); opacity: 0.85; }
.absent-error .absent-spec-tag { background: var(--clay-100); color: var(--fail-text); }

/* Amber-вариант — предупреждение (WARN), напр. нейминг уровней в Обзоре. */
.absent-warn {
    background: var(--warn-bg);
    border: 1px solid var(--warn-border);
}
.absent-warn .absent-panel-icon { color: var(--warn); }
.absent-warn .absent-panel-title { color: var(--warn-text); }
.absent-warn .absent-panel-text { color: var(--warn-text); opacity: 0.85; }
.absent-warn .absent-spec-tag { background: var(--sand-100); color: var(--warn-text); }

.absent-panel-icon { flex-shrink: 0; margin-top: 2px; }
.absent-panel-icon svg { width: 18px; height: 18px; }
.absent-panel-body { flex: 1; min-width: 0; }

.absent-panel-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 4px;
}
.absent-panel-title { font-weight: 600; font-size: 0.875rem; }
.absent-panel-text { font-size: 0.82rem; margin-bottom: 10px; }

.absent-action-btn {
    flex-shrink: 0;
    padding: 4px 12px;
    border-radius: var(--radius-xs);
    border: 1px solid;
    background: transparent;
    font-size: 0.78rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--transition);
}

.absent-spec-tags { display: flex; flex-wrap: wrap; gap: 6px; }
/* Тихая недопроверка: класс «отсутствует», но подтипы в модели есть (0.37.0) */
.absent-subtype-hints {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-top: var(--space-3);
}
.absent-subtype-hint {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--r-sm);
    background: var(--sand-50);
    color: var(--sand-700);
    font-size: 0.82rem;
    line-height: 1.45;
}
.absent-subtype-hint i {
    flex-shrink: 0;
    width: 15px;
    height: 15px;
    margin-top: 2px;
}
.absent-spec-tag {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 20px;
    font-size: 0.78rem;
    font-weight: 500;
}

/* ─── Unrouted IfcSpace Section ──────────────────────── */
.section-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 28px 0 14px;
    color: var(--text-secondary);
    font-size: 0.85rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.section-divider::before,
.section-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--border);
}
.section-divider-label {
    display: flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}
.section-divider-label svg { width: 15px; height: 15px; }

/* 0.19.47: .unrouted-banner удалён — заменён на .banner.banner--warn
 * (см. вверху файла). HTML/JS использования уже мигрированы. */

/* ─── Dashboard Tabs ──────────────────────────────────── */
.dash-tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 0;
    border-bottom: 1.5px solid var(--border);
    padding-bottom: 0;
}
.dash-tab {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 10px 18px;
    border: none;
    background: none;
    font-size: 0.88rem;
    font-weight: 500;
    font-family: inherit;
    color: var(--text-muted);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1.5px;
    transition: all var(--transition);
}
.dash-tab svg { width: 16px; height: 16px; }
.dash-tab:hover { color: var(--text); }
.dash-tab.active {
    color: var(--primary);
    border-bottom-color: var(--primary);
    font-weight: 600;
}
.dash-panel {
    padding-top: 20px;
    animation: fadeIn 0.3s ease;
}
.dash-card-inner { padding: 24px; }

.skip-insights {
    background: linear-gradient(135deg, #FFF7ED 0%, #FFFFFF 100%);
    border: 1px solid rgba(217,119,6,0.18);
    border-radius: var(--radius);
    padding: 14px 16px;
    margin-bottom: 16px;
}
.skip-insights.simple {
    padding: 12px 14px;
}
.skip-insights-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 14px;
}
.skip-insights-title {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--warn-text);
    margin-bottom: 2px;
}
.skip-insights-text {
    font-size: 0.82rem;
    color: var(--text-secondary);
    line-height: 1.4;
}
.skip-insights.simple .skip-insights-title {
    margin-bottom: 4px;
}
.skip-insights.simple .skip-insights-text {
    max-width: 860px;
}
.skip-spec-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 12px;
}
.skip-spec-card {
    background: rgba(255,255,255,0.82);
    border: 1px solid rgba(217,119,6,0.12);
    border-radius: var(--radius-sm);
    padding: 12px 14px;
}
.skip-spec-title {
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 4px;
    line-height: 1.3;
}
.skip-spec-meta {
    font-size: 0.78rem;
    color: var(--text-secondary);
    margin-bottom: 8px;
}
.skip-issue-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.skip-issue-line {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.skip-issue-line.compact {
    gap: 0;
}
.skip-issue-name {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text);
    line-height: 1.35;
}
.skip-issue-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.skip-issue-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.72rem;
    font-weight: 700;
    border-radius: 999px;
    padding: 4px 8px;
    white-space: nowrap;
}
.skip-issue-badge.missing {
    background: var(--fail-bg);
    color: var(--fail-text);
}
.skip-issue-badge.empty {
    background: #FFF7ED;
    color: #C2410C;
}
.skip-issue-badge.mismatch {
    background: var(--info-50);
    color: var(--info-700);
}
.skip-issue-values {
    font-size: 0.78rem;
    color: var(--text-muted);
    line-height: 1.45;
}

/* ─── Charts ──────────────────────────────────────────── */
.charts-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    margin-bottom: 20px;
}
.chart-card { text-align: center; }
.chart-card h3 { font-size: 0.95rem; margin-bottom: 16px; font-weight: 600; }
.chart-card canvas { margin: 0 auto; display: block; }
.chart-legend {
    margin-top: 14px;
    display: flex;
    justify-content: center;
    gap: 20px;
    font-size: 0.82rem;
}
.legend-item { display: flex; align-items: center; gap: 6px; }
.legend-dot {
    width: 10px; height: 10px;
    border-radius: 50%;
    display: inline-block;
}

#model-stats { text-align: left; }
#model-stats .muted { color: var(--text-muted); }
.entity-list { list-style: none; max-height: 260px; overflow-y: auto; }
.entity-list li {
    display: flex;
    justify-content: space-between;
    padding: 6px 0;
    border-bottom: 1px solid var(--border-light);
    font-size: 0.88rem;
}
.entity-list li:last-child { border-bottom: none; }
.entity-count { font-weight: 600; color: var(--primary); }

/* ─── Class Bar Chart ─────────────────────────────────── */
.class-bar-legend {
    display: flex; gap: 16px; font-size: 0.82rem;
    color: var(--text-muted); margin-bottom: 12px;
}
.cls-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 4px; }
.class-bar-list { display: flex; flex-direction: column; gap: 6px; }
.class-bar-row { display: flex; align-items: center; gap: 10px; }
.class-bar-label { width: 140px; flex-shrink: 0; font-size: 0.82rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.class-bar-track {
    flex: 1; height: 20px; display: flex;
    border-radius: var(--radius-xs); overflow: hidden;
    background: var(--border-light); max-width: 100%;
}
.class-bar-seg { height: 100%; transition: width var(--transition-slow); }
.seg-pass { background: var(--pass); }
.seg-warn { background: var(--warn); }
.seg-fail { background: var(--fail); }
.class-bar-counts { display: flex; gap: 6px; font-size: 0.8rem; font-weight: 600; width: 80px; flex-shrink: 0; }

/* ─── Heatmap ─────────────────────────────────────────── */
.heatmap-table { border-collapse: collapse; font-size: 0.82rem; min-width: 400px; }
.heatmap-table th {
    text-align: center; padding: 8px 10px;
    background: var(--border-light); border: 1px solid var(--border);
    font-size: 0.78rem; font-weight: 600; color: var(--text-muted);
}
.hm-label { padding: 8px 12px; border: 1px solid var(--border); font-size: 0.82rem; white-space: nowrap; }
.hm-cell { text-align: center; padding: 8px 10px; border: 1px solid var(--border); font-weight: 600; font-size: 0.82rem; cursor: default; border-radius: 0; }
.hm-empty { text-align: center; padding: 8px 10px; border: 1px solid var(--border); color: var(--border); font-size: 0.75rem; }

/* ─── Coverage Dashboard ──────────────────────────────── */
.coverage-summary { display: flex; gap: 24px; align-items: center; margin-bottom: 16px; }
.cov-card { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.cov-circle {
    width: 80px; height: 80px; border-radius: 50%;
    background: conic-gradient(var(--pass) calc(var(--pct) * 1%), var(--border) 0);
    display: flex; align-items: center; justify-content: center;
    font-size: 1rem; font-weight: 700; color: var(--text);
    position: relative;
}
.cov-circle::before {
    content: ''; position: absolute; inset: 10px;
    background: var(--card-bg); border-radius: 50%;
}
.cov-circle span { position: relative; z-index: 1; }
.cov-stat-list { display: flex; flex-direction: column; gap: 4px; font-size: 0.9rem; }
.cov-bar-wrap { width: 140px; height: 8px; background: var(--border); border-radius: 4px; overflow: hidden; }
.cov-bar { height: 100%; border-radius: 4px; transition: width var(--transition-slow); }

/* 0.19.47: .cov-skip-banner удалён — заменён на .banner.banner--warn
 * (см. вверху файла). JS dashboard.js уже мигрирован. */
.cov-skip-badge {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 600;
    background: var(--warn-bg);
    color: var(--warn-text);
    padding: 1px 6px;
    border-radius: 10px;
    margin-left: 4px;
    white-space: nowrap;
}
.cov-row-warn td { background: var(--warn-bg) !important; }

/* ─── View Toggle ─────────────────────────────────────── */
.view-toggle {
    display: flex;
    gap: 4px;
    margin-bottom: 16px;
}
.view-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 18px;
    border: 1.5px solid var(--border);
    border-radius: 20px;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.88rem;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    transition: all var(--transition);
}
.view-btn svg { width: 16px; height: 16px; }
.view-btn:hover { border-color: var(--primary); color: var(--primary); }
.view-btn.active { background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 600; }

/* ─── Filter Bar ──────────────────────────────────────── */
.filter-bar {
    background: var(--card-bg);
    border-radius: var(--radius);
    border: 1px solid var(--border);
    padding: 14px 20px;
    margin-bottom: 16px;
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
}
.filter-label {
    font-size: 0.72rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
}
.filter-group {
    display: flex;
    align-items: center;
    gap: 8px;
}
.filter-btns { display: flex; gap: 4px; }
.filter-btn {
    padding: 5px 13px;
    border-radius: var(--radius-xs);
    font-size: 0.78rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    border: 1.5px solid transparent;
    background: var(--border-light);
    color: var(--text-muted);
    transition: all var(--transition);
    letter-spacing: 0.03em;
}
.filter-btn:hover:not(.active) { background: var(--border); color: var(--text); }
.filter-btn.active { background: var(--primary); color: #fff; border-color: var(--primary); }
.filter-btn.fail.active { background: var(--fail); border-color: var(--fail); color: #fff; }
.filter-btn.warn.active { background: var(--warn); border-color: var(--warn); color: #fff; }
.filter-btn.pass.active { background: var(--pass); border-color: var(--pass); color: #fff; }
.filter-btn.action-applicability.active { background: var(--info-500); border-color: var(--info-500); color: #fff; }

.filter-search-group {
    flex: 1;
    min-width: 220px;
    position: relative;
}
.search-icon {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    color: var(--text-muted);
    pointer-events: none;
}
/* ─── Search inputs (0.19.51) ─────────────────────────────────────────────
 *
 * До: 5 разных search/text inputs на 4 страницах — 2 имели локальный CSS
 * (#search-input / .fx-search, с разным padding/border/focus), 3 были
 * unstyled (только browser defaults). Заменены на единый .input-search.
 *
 * Использование:
 *     <input type="search" class="input-search" placeholder="…">
 *     <!-- with overlay icon (icon в .filter-search-group или similar): -->
 *     <input type="search" class="input-search input-search--with-icon">
 *
 * Focus ring (3px halo) — взят от .fx-search, теперь работает везде.
 */
.input-search {
    width: 100%;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card-bg);
    color: var(--text);
    font-family: inherit;
    font-size: 0.88rem;
    outline: none;
    transition: border-color var(--transition), box-shadow var(--transition);
}
.input-search::placeholder {
    color: var(--text-muted);
}
.input-search:focus {
    border-color: var(--iris-500);
    box-shadow: 0 0 0 3px var(--iris-50);
}
/* Padding-left для overlay-иконки внутри .filter-search-group / wrappers. */
.input-search--with-icon {
    padding-left: 34px;
}
/* 0.19.56: WebKit-style ✕ button (появляется при набранном тексте у
 * type="search"). UA default — серое X пиксельно квадратное, выпадает
 * из эстетики. Кастомизируем под наш iris-палитру. */
.input-search::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238088C7' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M4 4l8 8M12 4l-8 8'/%3E%3C/svg%3E");
    background-size: contain;
    cursor: pointer;
    opacity: 0.6;
    transition: opacity var(--transition);
}
.input-search::-webkit-search-cancel-button:hover {
    opacity: 1;
}

/* ─── Empty state (0.19.57) ───────────────────────────────────────────────
 * Единый utility для «пустого» экрана: «нет данных», «загружается»,
 * «ничего не найдено». До 0.19.57 было 6 отдельных классов с почти
 * одинаковой структурой (.tep-issues-empty / .tep-results-empty /
 * .fx-empty / .ids-radio-empty / .panel-loading и др.) — все
 * центрировали content по обеим осям + svg + h2 + p. Теперь единый
 * .empty-state + модификаторы для размера / inline-style / тона.
 *
 * Modifiers:
 *  --lg       большой padding + крупная svg (пустой экран на всю область)
 *  --inline   subtle bg + dashed border + компактный padding (внутри списка / dropdown)
 *  --ok       зелёный тон (success: «всё хорошо, проблем нет»)
 *  --error    clay тон (ошибка загрузки данных)
 */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    padding: var(--space-5) var(--space-4);
    text-align: center;
    color: var(--ink-tertiary);
}
.empty-state > svg {
    width: 48px;
    height: 48px;
    opacity: 0.5;
}
.empty-state > h2 {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    color: var(--ink-primary);
}
.empty-state > p {
    margin: 0;
    font-size: 0.95rem;
    max-width: 360px;
    line-height: 1.5;
}
.empty-state--lg {
    padding: 56px 24px;
}
.empty-state--lg > svg {
    width: 64px;
    height: 64px;
}
.empty-state--inline {
    padding: 18px;
    font-size: 0.86rem;
    background: var(--bg-subtle);
    border: 1px dashed var(--border-subtle);
    border-radius: var(--r-md);
    gap: 0;
}
.empty-state--ok {
    color: var(--pass-text);
}
.empty-state--ok > svg {
    opacity: 0.6;
}
.empty-state--error {
    color: var(--clay-700);
    border-color: var(--clay-100);
    background: var(--clay-50);
}

/* ─── Select (0.19.55) ────────────────────────────────────────────────────
 * До: у каждого селекта своё правило — разный border (1.5px vs 1px),
 * font-size (0.85 vs 0.82), background.
 * Сейчас: одно правило, та же шкала и focus-halo что у .input-search. */
.input-select {
    padding: 6px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card-bg);
    color: var(--text);
    font-family: inherit;
    font-size: 0.86rem;
    cursor: pointer;
    outline: none;
    transition: border-color var(--transition), box-shadow var(--transition);
}
.input-select:focus {
    border-color: var(--iris-500);
    box-shadow: 0 0 0 3px var(--iris-50);
}

/* ─── Checkbox (0.19.55) ──────────────────────────────────────────────────
 * До: .checkbox-label input (18px, accent --primary) vs .fx-checkbox input
 * (14px, accent --iris-500) — разные размеры и цвета.
 * Сейчас: единый 18px + accent --iris-500 (matches focus halo от
 * .input-search / .input-select). */
.input-checkbox {
    width: 18px;
    height: 18px;
    accent-color: var(--iris-500);
    cursor: pointer;
}

/* DEPRECATED 0.19.51: #search-input + .fx-search заменены на .input-search.
 * Selector оставлен для обратной совместимости (вдруг где-то ещё ссылается),
 * но новые input'ы должны использовать .input-search. */
#search-input {
    /* По cascade .input-search wins если есть оба класса. Без них —
     * сохраняем старый look чтобы переход был bisectable. */
    width: 100%;
    padding: 7px 12px 7px 34px;
    border: 1.5px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: 0.88rem;
    font-family: inherit;
    outline: none;
    transition: border-color var(--transition);
    background: var(--card-bg);
    color: var(--text);
}
#search-input:focus { border-color: var(--primary); }

/* 0.19.55: #group-by мигрирован на .input-select (см. вверху файла).
 * Здесь оставили alias — старый #id-selector выше по specificity, без
 * него .input-select не победила бы. Когда удалим #id selectors в
 * HTML (заменим на classes), эту секцию можно полностью убрать. */
#group-by,
.input-select {
    padding: 6px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card-bg);
    color: var(--text);
    font-family: inherit;
    font-size: 0.86rem;
    cursor: pointer;
    outline: none;
    transition: border-color var(--transition), box-shadow var(--transition);
}
#group-by:focus,
.input-select:focus {
    border-color: var(--iris-500);
    box-shadow: 0 0 0 3px var(--iris-50);
}

.filter-count {
    font-size: 0.82rem;
    color: var(--text-muted);
    white-space: nowrap;
    margin-left: auto;
    font-style: italic;
}

.btn-csv {
    padding: 5px 12px;
    font-size: 0.8rem;
    white-space: nowrap;
}

/* ─── Specification Cards ─────────────────────────────── */
/* 0.19.54: мигрирована на modern palette (--bg-surface / --border-subtle
 * / --r-lg + subtle box-shadow). Унифицирована с .card / .stat-card /
 * .file-split-card / .ids-radio-card. */
.spec-card {
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    margin-bottom: 10px;
    overflow: hidden;
    transition: box-shadow var(--transition);
}
.spec-card:hover { box-shadow: var(--shadow-md); }

.spec-header {
    padding: 14px 20px;
    display: flex;
    align-items: center;
    gap: 12px;
    cursor: pointer;
    user-select: none;
    transition: background var(--transition);
}
.spec-header:hover { background: var(--border-light); }

.badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 3px 10px;
    border-radius: 20px;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    flex-shrink: 0;
    letter-spacing: 0.03em;
}
.badge-pass { background: var(--pass-bg); color: var(--pass-text); }
.badge-fail { background: var(--fail-bg); color: var(--fail-text); }
.badge-warn { background: var(--warn-bg); color: var(--warn-text); }
.badge-applicability { background: var(--info-100); color: var(--info-700); }

.spec-info { flex: 1; min-width: 0; }
.spec-name { font-weight: 600; font-size: 0.95rem; }
/* Бейдж источника спеки — режим «по разделам»: показывает, из какой IDS пришла
 * карточка (при слиянии нескольких IDS набора). В обычной проверке пусто. */
.spec-source {
    display: inline-flex;
    align-items: center;
    padding: 1px 7px;
    margin-left: 6px;
    border-radius: 999px;
    background: var(--iris-50);
    border: 1px solid var(--iris-100);
    color: var(--iris-700);
    font-size: 0.7rem;
    font-weight: 600;
    vertical-align: middle;
}
.spec-meta { font-size: 0.82rem; color: var(--text-muted); margin-top: 2px; }
/* Группировка карточек проверок по исходной IDS (мульти-IDS: «Общий» ≥2 и «По
 * разделам»): сворачиваемая белая плашка с шапкой (название IDS + счётчик +
 * шеврон), внутри — spec-карточки. «Общие требования» — группа без IDS-источника. */
.spec-group {
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    margin-bottom: var(--space-4);
    overflow: hidden;
}
.spec-group__header {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 12px 16px;
    cursor: pointer;
    border-left: 3px solid var(--iris-500);
    transition: background var(--transition);
}
.spec-group__header:hover { background: var(--bg-subtle); }
.spec-group--general .spec-group__header { border-left-color: var(--sage-500, var(--pass)); }
.spec-group--general .spec-group__icon { color: var(--sage-500, var(--pass)); }
.spec-group__icon { width: 18px; height: 18px; color: var(--iris-500); flex-shrink: 0; }
.spec-group__title { font-weight: 700; font-size: 0.98rem; color: var(--ink-primary); }
.spec-group__count {
    margin-left: auto;
    font-size: 0.8rem;
    color: var(--ink-tertiary);
    font-variant-numeric: tabular-nums;
}
.spec-group__toggle {
    margin-left: var(--space-3);
    color: var(--ink-tertiary);
    font-size: 0.85rem;
    flex-shrink: 0;
}
.spec-group__body { padding: var(--space-3) var(--space-4) 2px; }
.spec-group.is-collapsed .spec-group__body { display: none; }
/* Второй уровень группировки «Что исправить» — лёгкий заголовок-строка + карточки. */
.action-subgroup { margin-bottom: var(--space-3); }
.action-subgroup__header {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 4px 2px;
    margin-bottom: var(--space-2);
    font-weight: 600;
    font-size: 0.86rem;
    color: var(--ink-secondary);
    border-bottom: 1px solid var(--border-subtle);
}
.action-subgroup__count {
    margin-left: auto;
    font-size: 0.76rem;
    font-weight: 500;
    color: var(--ink-tertiary);
    font-variant-numeric: tabular-nums;
}
/* Карточки внутри плашки — без своей тени (плоские), плашка сама даёт глубину. */
.spec-group__body .spec-card { box-shadow: none; }
.spec-counts { font-size: 0.82rem; color: var(--text-muted); white-space: nowrap; }
.spec-toggle {
    font-size: 0.82rem;
    color: var(--primary);
    white-space: nowrap;
    font-weight: 500;
}

.spec-details { display: none; padding: 0; overflow-x: auto; }
.spec-details.open { display: block; animation: fadeIn 0.25s ease; }
.spec-details > .results-table { margin: 0 20px 20px; width: calc(100% - 40px); min-width: 600px; }

/* Нераспознанные IfcSpace — FAIL-карточка наверху: тонкая clay-граница-акцент;
   пояснение-баннер отступает от краёв (у .spec-details padding:0). */
.spec-card--unrouted { border-color: var(--fail-border); }
.spec-card--unrouted .banner { margin: 16px 20px 0; }

/* Карточки-дубли плашек «Обзора» в «Деталях»: RUS_FNO пройдено — зелёная
   (PASS), отсутствующие категории — amber (WARN), как в «Обзоре». */
.spec-card--pass-info { border-color: var(--pass-border); }
.spec-card--warn-info { border-color: var(--warn-border); }
.absent-spec-tags--details { padding: 12px 20px 16px; }

/* ─── Results Table ───────────────────────────────────── */
.results-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.84rem;
    table-layout: auto;
    word-break: break-word;
}
.results-table th {
    text-align: left;
    padding: 10px 12px;
    background: var(--border-light);
    border-bottom: 1.5px solid var(--border);
    font-weight: 600;
    color: var(--text-muted);
    white-space: nowrap;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.results-table td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--border-light);
    vertical-align: top;
    white-space: normal;
}
.results-table tbody tr:nth-child(even) td { background: var(--bg); }
.results-table td.col-message { min-width: 200px; white-space: normal; }
.results-table td.col-elem { min-width: 180px; }
.results-table tr:last-child td { border-bottom: none; }

/* Таблица проверки IFC схемы (дубликаты наборов свойств) — подвкладка «Схема». */
.schema-card { padding: 0; overflow-x: auto; }
.schema-table { min-width: 560px; }
.schema-table .col-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cell-pass { color: var(--pass); font-weight: 600; }
.cell-fail { color: var(--fail); font-weight: 600; }
.cell-warn { color: var(--warn); font-weight: 600; }
.cell-skip { color: var(--info-500); font-weight: 700; }
.muted { color: var(--text-muted); }

/* ─── Subgroups ───────────────────────────────────────── */
.subgroup-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 20px 16px;
}
.subgroup {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.subgroup-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    cursor: pointer;
    background: var(--border-light);
    transition: background var(--transition);
    user-select: none;
}
.subgroup-header:hover { background: var(--border); }
.subgroup-title {
    flex: 1;
    font-weight: 600;
    font-size: 0.88rem;
    color: var(--text);
}
/* Реальное (техническое) имя параметра рядом с человеческим в заголовке группы
 * «Что исправить» — мельче и бледнее, обычным весом. */
.param-real {
    font-size: 0.82em;
    font-weight: 400;
    color: var(--ink-tertiary);
    margin-left: 6px;
}
.subgroup-counts {
    font-size: 0.8rem;
    color: var(--text-muted);
    white-space: nowrap;
}
.subgroup-toggle {
    font-size: 0.8rem;
    color: var(--primary);
    width: 16px;
    text-align: center;
}
.subgroup-body { display: none; }
.subgroup-body.open { display: block; animation: fadeIn 0.2s ease; }
.subgroup-body .results-table { margin: 0; border-top: 1px solid var(--border); }
/* Вложенный (2-й уровень) аккордеон — лёгкий отступ для иерархии. */
.subgroup .subgroup-list { margin-left: 12px; }

/* Кнопка «+» второго уровня группировки. */
.group-add-btn {
    border: 1px solid var(--border-default);
    background: var(--bg-surface);
    color: var(--ink-secondary);
    border-radius: var(--r-sm);
    width: 30px;
    height: 30px;
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    flex-shrink: 0;
    transition: var(--transition);
}
.group-add-btn:hover { border-color: var(--info-500); color: var(--info-500); }

/* ─── Element Cell ────────────────────────────────────── */
.elem-cell { display: flex; flex-direction: column; gap: 4px; }
.elem-primary { line-height: 1.35; }
.elem-meta-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}
.guid-tag {
    font-size: 0.72rem;
    font-family: var(--font-mono);
    color: var(--text-muted);
    background: var(--border-light);
    padding: 2px 7px;
    border-radius: 4px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    letter-spacing: 0.02em;
    cursor: pointer;
    max-width: fit-content;
    user-select: none;
    transition: all var(--transition);
    position: relative;
}
.guid-tag:hover { background: var(--border); color: var(--text); }
.guid-tag.copied { background: var(--pass-bg); color: var(--pass-text); }
.guid-copy-icon { font-size: 0.65rem; opacity: 0.5; }
.guid-tag:hover .guid-copy-icon { opacity: 1; }

.revit-id-chip,
.copy-field {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}
.revit-id-chip {
    background: var(--primary-light);
    border: 1px solid rgba(50, 82, 123,0.15);
    border-radius: var(--radius-xs);
    padding: 2px 7px;
    max-width: fit-content;
}
.revit-id-label {
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--primary);
}
.revit-id-value,
.copy-field-value {
    font-size: 0.72rem;
    font-family: var(--font-mono);
    color: var(--text);
}
.copy-field-value {
    background: var(--border-light);
    padding: 2px 7px;
    border-radius: 4px;
}
.copy-inline-btn {
    appearance: none;
    border: 1px solid var(--border);
    background: var(--card-bg);
    color: var(--text-muted);
    border-radius: 999px;
    padding: 2px 8px;
    font-size: 0.68rem;
    font-weight: 700;
    font-family: inherit;
    line-height: 1.25;
    cursor: pointer;
    transition: all var(--transition);
}
.copy-inline-btn:hover {
    background: var(--border-light);
    color: var(--text);
    border-color: var(--text-muted);
}
.copy-inline-btn.copied {
    background: var(--pass-bg);
    color: var(--pass-text);
    border-color: var(--pass);
}

/* ─── Subtype Badges ──────────────────────────────────── */
.subtype-badge {
    font-size: 0.68rem; font-weight: 600; padding: 1px 6px;
    border-radius: 10px; white-space: nowrap;
}
.subtype-room { background: var(--border-light); color: var(--text-secondary); }
.subtype-zone { background: var(--info-100); color: var(--info-700); }
.subtype-area { background: var(--warn-bg); color: var(--warn-text); }

.spec-name-cell {
    font-size: 0.8rem;
    color: var(--text-muted);
    max-width: 160px;
    word-break: break-word;
    line-height: 1.3;
}

/* ─── Show-more pagination ────────────────────────────── */
.show-more-wrap { padding: 12px 20px; }

/* ─── Clickable rows ──────────────────────────────────── */
.result-row.clickable { cursor: pointer; }
.result-row.clickable:hover td { background: var(--primary-light) !important; }

.skip-reason-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 220px;
}
.skip-reason-item {
    display: flex;
    flex-direction: column;
    gap: 3px;
}
.skip-reason-prop {
    font-size: 0.78rem;
    font-family: var(--font-mono);
    color: var(--text);
}
.skip-reason-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
}
.skip-reason-pill {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1.2;
}
.skip-reason-pill.reason-missing {
    background: var(--info-100);
    color: var(--info-700);
}
.skip-reason-pill.reason-empty {
    background: #FEF3C7;
    color: #B45309;
}
.skip-reason-pill.reason-mismatch {
    background: #FEE2E2;
    color: #B91C1C;
}
.skip-reason-extra {
    font-size: 0.74rem;
    color: var(--text-muted);
    line-height: 1.35;
}

/* ─── Action List ─────────────────────────────────────── */
.fix-summary {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
    margin-bottom: 16px;
}
/* 0.19.54: мигрирована на modern palette. tone-* modifiers ниже остались
 * чтобы перебивать border на цветной (status hint). */
.fix-summary-card {
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    padding: 16px 18px;
}
/* Тон плиток сводки = приоритет: Обязательные → красный, Второстепенные →
   жёлтый, Рекомендации → стальной (совпадает с бейджами/кнопками). */
.fix-summary-card.tone-applicability {
    border-color: var(--fail-border);
    background: var(--fail-bg);
}
.fix-summary-card.tone-required {
    border-color: var(--warn-border);
    background: var(--warn-bg);
}
.fix-summary-card.tone-recommended {
    border-color: var(--steel-100);
    background: var(--steel-50);
}
.fix-summary-title {
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 8px;
}
.fix-summary-value {
    font-size: 1.9rem;
    font-weight: 700;
    line-height: 1;
}
.fix-summary-label {
    font-size: 0.88rem;
    font-weight: 600;
    margin-top: 6px;
}
.fix-summary-meta {
    margin-top: 4px;
    font-size: 0.8rem;
    color: var(--text-muted);
}
.fix-section {
    margin-bottom: 20px;
}
.fix-section-header {
    margin-bottom: 12px;
}
.fix-section-title {
    font-size: 1rem;
    font-weight: 700;
    color: var(--text);
}
.action-help-inline {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    margin-left: 6px;
    border-radius: 50%;
    background: var(--info-100);
    color: var(--info-700);
    font-size: 0.72rem;
    font-weight: 700;
    cursor: help;
    vertical-align: middle;
}
.fix-section-text {
    font-size: 0.88rem;
    color: var(--text-muted);
    line-height: 1.5;
    margin-top: 4px;
}
.fix-card-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
/* 0.19.54: мигрирована на modern palette. tone-* остались — переопределяют
 * border-color на цветной (status hint). */
.action-card {
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    margin-bottom: 10px;
    overflow: hidden;
    transition: box-shadow var(--transition);
}
.action-card.tone-applicability { border-color: var(--info-border); }
.action-card.tone-required { border-color: var(--fail-border); }
.action-card.tone-unrouted { border-color: var(--fail-border); }  /* нераспознанные IfcSpace — ошибка */
.action-card.tone-recommended { border-color: var(--warn-border); }
.action-card:hover { box-shadow: var(--shadow-md); }
.action-header {
    display: flex; align-items: center; gap: 12px;
    padding: 14px 20px; cursor: pointer;
    user-select: none; transition: background var(--transition);
}
.action-header:hover { background: var(--border-light); }
.action-main { flex: 1; min-width: 0; }
.action-kicker {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 4px;
}
.action-title {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--text);
}
.action-subtitle {
    font-size: 0.82rem;
    color: var(--text-muted);
    margin-top: 2px;
}
.action-toggle { color: var(--primary); font-size: 0.8rem; }
.action-body { display: none; padding: 12px 20px 16px; border-top: 1px solid var(--border); }
.action-body.open { display: block; animation: fadeIn 0.2s ease; }
.copy-all-btn { margin-bottom: 10px; }
.action-guide-grid {
    display: grid;
    gap: 8px;
    margin-bottom: 12px;
}
.action-guide-row {
    display: grid;
    grid-template-columns: 120px minmax(0, 1fr);
    gap: 12px;
    align-items: start;
}
.action-guide-label {
    font-size: 0.76rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
}
.action-guide-text {
    font-size: 0.88rem;
    color: var(--text);
    line-height: 1.5;
}
.action-elem-list { display: flex; flex-direction: column; gap: 4px; max-height: 320px; overflow-y: auto; }
.action-elem-row {
    display: flex; align-items: center; gap: 10px;
    padding: 6px 8px; border-radius: var(--radius-xs); font-size: 0.84rem;
}
.action-elem-row.clickable { cursor: pointer; }
.action-elem-row.clickable:hover { background: var(--primary-light); }
.action-elem-main {
    flex: 1;
    min-width: 0;
}
.action-elem-title {
    font-size: 0.84rem;
    color: var(--text);
    line-height: 1.35;
}
.action-elem-note {
    font-size: 0.76rem;
    color: var(--text-muted);
    margin-top: 2px;
    line-height: 1.4;
}
.action-elem-tools {
    display: flex;
    align-items: center;
    gap: 6px;
    justify-content: flex-end;
    flex-wrap: wrap;
}

/* ─── Element Detail Panel ────────────────────────────── */
.element-panel-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.25);
    backdrop-filter: blur(2px);
    z-index: 100; display: none;
    transition: opacity var(--transition);
}
.element-panel-overlay.open { display: block; animation: fadeIn 0.2s ease; }

.element-panel {
    position: fixed;
    right: 0; top: 0; bottom: 0;
    width: 460px;
    max-width: 100vw;
    background: var(--card-bg);
    z-index: 101;
    overflow-y: auto;
    box-shadow: -4px 0 24px rgba(0,0,0,0.12);
    transform: translateX(100%);
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    display: flex;
    flex-direction: column;
}
.element-panel.open { transform: translateX(0); }

.panel-header {
    position: sticky; top: 0;
    background: var(--primary);
    color: #fff;
    padding: 16px 20px;
    display: flex; align-items: center; gap: 12px;
    z-index: 1; flex-shrink: 0;
}
.panel-header h3 { flex: 1; font-size: 0.95rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.panel-close {
    background: none; border: none; color: rgba(255,255,255,0.8);
    font-size: 1rem; cursor: pointer; line-height: 1;
    padding: 4px 8px; border-radius: 4px; flex-shrink: 0;
    transition: all var(--transition);
}
.panel-close:hover { background: rgba(255,255,255,0.15); color: #fff; }
.panel-close svg { width: 20px; height: 20px; }

.panel-section {
    padding: 16px 20px;
    border-bottom: 1px solid var(--border-light);
}
.panel-section h4 {
    font-size: 0.72rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.07em; color: var(--text-muted); margin-bottom: 10px;
}
.panel-table { width: 100%; border-collapse: collapse; font-size: 0.84rem; }
.panel-table td { padding: 5px 6px; vertical-align: top; border-bottom: 1px solid var(--border-light); }
.panel-table tr:last-child td { border-bottom: none; }
.panel-table td.panel-key { color: var(--text-muted); width: 120px; white-space: nowrap; font-size: 0.8rem; }

.spatial-path {
    font-size: 0.88rem; color: var(--text);
    background: var(--border-light); padding: 8px 12px;
    border-radius: var(--radius-xs);
}

.pset-details { margin-bottom: 6px; border: 1px solid var(--border); border-radius: var(--radius-xs); overflow: hidden; }
.pset-details summary {
    cursor: pointer; font-size: 0.85rem;
    padding: 8px 12px; user-select: none;
    background: var(--border-light); list-style: none;
    display: flex; align-items: center; gap: 6px;
    transition: background var(--transition);
}
.pset-details summary:hover { background: var(--border); }
.pset-details summary::-webkit-details-marker { display: none; }
.pset-details summary::before { content: '\25B6'; font-size: 0.6rem; color: var(--primary); transition: transform var(--transition); }
.pset-details[open] summary::before { transform: rotate(90deg); }
.pset-table { font-size: 0.82rem; width: 100%; }
.pset-table td { padding: 4px 12px; border-bottom: 1px solid var(--border-light); }
.pset-table tr:last-child td { border-bottom: none; }

.ids-result-item {
    display: flex; gap: 10px; align-items: flex-start;
    padding: 8px 0; border-bottom: 1px solid var(--border-light);
}
.ids-result-item:last-child { border-bottom: none; }
.ids-status-badge { font-weight: 700; font-size: 0.78rem; min-width: 38px; padding-top: 2px; }
.ids-result-body { flex: 1; font-size: 0.82rem; }
.ids-result-spec { font-weight: 600; margin-bottom: 2px; }
.ids-result-prop { color: var(--text-muted); font-family: var(--font-mono); font-size: 0.78rem; margin-bottom: 2px; }
.ids-result-msg  { color: var(--text); line-height: 1.4; }
.panel-section .skip-reason-list { margin-top: 8px; }

/* 0.19.57: .panel-loading удалён — используем .empty-state в JS (element-detail.js). */

/* ─── Animations ──────────────────────────────────────── */
@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes slideUp {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: translateY(0); }
}

.stat-card { animation: slideUp 0.4s ease backwards; }
.stat-card:nth-child(1) { animation-delay: 0.05s; }
.stat-card:nth-child(2) { animation-delay: 0.1s; }
.stat-card:nth-child(3) { animation-delay: 0.15s; }
.stat-card:nth-child(4) { animation-delay: 0.2s; }
.stat-card:nth-child(5) { animation-delay: 0.25s; }

/* ─── File Split Cards ────────────────────────────────── */
.file-cards-grid {
    display: grid;
    /* Боксы IFC + IDS — в одну строку; стек только на узких экранах (<~720px),
       чтобы не листать на обычных мониторах. */
    grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
    gap: 20px;
    margin-bottom: 16px;
}
.file-split-card {
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.file-split-card__header {
    display: flex;
    align-items: center;
    gap: 10px;
}
.file-split-card__header svg { width: 20px; height: 20px; color: var(--primary); }
.file-split-card__header h3 { font-size: 1rem; font-weight: 600; }

.drop-zone--large {
    flex: 1;
    min-height: 160px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    margin-top: 0;
    padding: 32px 20px;
}
.drop-zone[hidden] { display: none; }

.ids-field-label {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.file-select {
    width: 100%;
    padding: 10px 12px;
    border: 1.5px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card-bg);
    color: var(--text);
    font-size: 0.9rem;
    font-family: inherit;
    cursor: pointer;
    transition: border-color var(--transition);
    outline: none;
}
.file-select:focus { border-color: var(--primary); }

.ids-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--text-muted);
    font-size: 0.8rem;
}
.ids-divider::before,
.ids-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--border);
}

/* 0.19.56 cleanup: objединено из 2 правил (этот + line ~5502).
 * Final values: dashed border-default 1.5px, ink-secondary, font 0.85rem,
 * radius r-md. hover/has-file modifier живут отдельно (ниже + во второй
 * секции). */
.btn-upload-ids {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    padding: 10px 16px;
    border: 1.5px dashed var(--border-default);
    border-radius: var(--r-md);
    background: transparent;
    color: var(--ink-secondary);
    font-size: 0.85rem;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    transition: all var(--transition);
}
.btn-upload-ids svg { width: 16px; height: 16px; }
/* 0.19.56 cleanup: .btn-upload-ids:hover/.has-file (pass palette) был
 * полностью перекрыт modern (sage palette) — см. line ~5502. Удалён. */

/* ─── Run Controls Card ───────────────────────────────── */
.controls--run {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 14px;
    padding: 22px;
}
/* Кнопка запуска прижата к низу колонки (третий бокс в одной строке с IFC/IDS). */
.controls--run .btn-primary { margin-top: auto; }

/* ─── IDS Upload Modal ────────────────────────────────── */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 200;
    animation: fadeIn 0.15s ease;
}
.modal {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: var(--card-bg);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    width: min(480px, 90vw);
    z-index: 201;
    animation: slideUp 0.2s ease;
}
.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20px 24px 16px;
    border-bottom: 1px solid var(--border);
}
.modal-header__title {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--text);
}
.modal-header__title svg { width: 20px; height: 20px; color: var(--primary); }
.modal-header__title h3 { font-size: var(--section-title-size); font-weight: var(--section-title-weight); }
.modal-close {
    width: 32px;
    height: 32px;
    border: none;
    background: transparent;
    border-radius: var(--radius-xs);
    cursor: pointer;
    color: var(--text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all var(--transition);
}
.modal-close:hover { background: var(--border-light); color: var(--text); }
.modal-close svg { width: 18px; height: 18px; }
.modal-body { padding: 24px; }
.modal-hint {
    font-size: 0.875rem;
    color: var(--text-secondary);
    margin-bottom: 16px;
}

/* ─── Responsive Desktop ──────────────────────────────── */
@media (max-width: 1200px) {
    /* Боковое меню модулей НЕ сворачивается по ширине окна — только вручную
       (кнопка-тумблер). Состояние держит .sidebar.is-collapsed, не вьюпорт. */
    .charts-row { grid-template-columns: 1fr; }
    .skip-insights-header { flex-direction: column; }
    .coverage-summary { flex-direction: column; align-items: flex-start; }
    .fix-summary { grid-template-columns: 1fr; }
    .action-guide-row { grid-template-columns: 1fr; gap: 4px; }
    .action-elem-row { align-items: flex-start; }
    .action-elem-tools { justify-content: flex-start; }
    .file-panes { grid-template-columns: 1fr; }
    .controls--inside .btn-primary { margin-left: 0; }
    .controls--run .btn-primary { margin-left: 0; }
}

@media (min-width: 1600px) {
    .file-panes { gap: 24px; }
    .stats-row { gap: 20px; }
    .charts-row { gap: 24px; }
}

/* ─── Scrollbar ───────────────────────────────────────── */
.main-content::-webkit-scrollbar { width: 6px; }
.main-content::-webkit-scrollbar-track { background: transparent; }
.main-content::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.main-content::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

/* History (unused but keep for compat) */
.history-section { margin-top: 32px; }
.clickable { cursor: pointer; user-select: none; }
.clickable:hover { color: var(--primary); }

/* ─── Top-level tab switcher ──────────────────────────── */
.top-tabs {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--top-tabs-height);
    background: linear-gradient(180deg, #0F172A 0%, #1E293B 100%);
    display: flex;
    align-items: stretch;
    padding: 0 24px;
    gap: 4px;
    z-index: 60;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}

.top-tab {
    background: transparent;
    border: none;
    color: rgba(255, 255, 255, 0.65);
    cursor: pointer;
    padding: 0 20px;
    font-size: 0.9rem;
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 8px;
    transition: color var(--transition), background var(--transition);
    border-bottom: 2px solid transparent;
    font-family: inherit;
}

.top-tab:hover {
    color: #fff;
    background: rgba(255, 255, 255, 0.05);
}

.top-tab--active {
    color: #fff;
    border-bottom-color: var(--primary);
    background: rgba(255, 255, 255, 0.04);
}

.top-tab i { width: 16px; height: 16px; }
/* Top-nav is now <a> anchors (since 0.6.3: per-page routing), not buttons.
 * Kill the default underline and anchor colors. */
a.top-tab { text-decoration: none; }
a.top-tab:visited { color: rgba(255, 255, 255, 0.65); }
a.top-tab.top-tab--active { color: #fff; }

/* ─── Fixer workspace ─────────────────────────────────── */
.fixer-header {
    height: var(--header-height);
    background: var(--card-bg);
    border-bottom: 1px solid var(--border);
    padding: 0 32px;
    display: flex;
    align-items: center;
    position: fixed;
    top: var(--top-tabs-height);
    left: 0;
    right: 0;
    z-index: 50;
}

.fixer-header__title {
    display: flex;
    align-items: center;
    gap: 12px;
}

.fixer-header__title > i {
    width: 28px;
    height: 28px;
    color: var(--primary);
}

.fixer-header__title h1 {
    font-size: 1.1rem;
    font-weight: 600;
    margin: 0;
}

.fixer-header__subtitle {
    font-size: 0.78rem;
    color: var(--text-secondary);
    margin: 0;
}

.fixer-header__subtitle code {
    background: var(--primary-light);
    color: var(--primary-hover);
    padding: 1px 6px;
    border-radius: var(--radius-xs);
    font-size: 0.72rem;
}

.fixer-main {
    padding: 28px 16px 64px;
    /* .app-layout уже сдвинут вниз на --header-height (margin-top) под фикс-
     * шапку — прибавлять --header-height ещё и здесь НЕЛЬЗЯ: это давало двойной
     * отступ и большой зазор под шапкой на /agr, /stats (tep/xml-check
     * раньше маскировали это костылём body--tep). Остаётся только «дыхание». */
    padding-top: calc(var(--top-tabs-height) + 24px);
    /* Единая ширина для /tep, /agr (0.20.16: 1320 → 1440px,
       padding 32→16). Без min(100vw) — пусть просто упирается в окно
       минус padding. На больших экранах (>1472px) центрируется. */
    max-width: 1440px;
    width: 100%;
    /* min-width:0 обязателен: .fixer-main — flex-элемент .app-layout. Без него
     * min-width:auto не даёт ужаться под ширину широкой таблицы результатов —
     * та раздувает контент и скроллится ВСЯ страница вместо .tep-results-wrap. */
    min-width: 0;
    margin-left: auto;
    margin-right: auto;
    display: flex;
    flex-direction: column;
    gap: 18px;
}

/* Режим скролла всей страницы — включается при переключении на вкладку
 * «Правка параметров». Иначе колёсико не докручивает список, когда курсор
 * висит над фиксированной шапкой или табами. */
body.body--page-scroll {
    overflow: auto;
    height: auto;
}

.fixer-step {
    padding: 22px;
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: none;
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;   /* flex-элемент: даёт .tep-results-wrap скроллиться внутри */
    animation: fixer-step-in 0.25s ease-out both;
}

.fixer-step[hidden] {
    display: none;
}

/* Боксы ввода в одну строку (главные input-секции страницы), чтобы не листать.
   Скрытые секции ([hidden] → display:none) выпадают из грида. align-items:stretch —
   боксы одной высоты (тянутся до самого высокого), чтобы низкая дропзона не
   выглядела «обрезанной» рядом с высоким боксом параметров. /agr и /tep. */
.input-row-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 18px;
    align-items: stretch;
}

/* /agr: порядок колонок — Модели IFC | IDS-спецификации | Параметры объекта.
   order действует только на видимые секции грида. */
#agr-files-section { order: 1; }
#agr-ids-library-section { order: 2; }
#agr-options-section { order: 3; }

/* Неактивная секция (IDS до включения «Проверка по IDS»): видна всегда, но
   серая и некликабельная — пока галочка снята.
   animation: none — у .fixer-step есть entry-анимация fixer-step-in с
   fill:both, чей финальный кадр opacity:1 перебивает наше opacity:0.5
   (анимации в каскаде выше обычных правил). Гасим её, иначе серый не применится. */
.fixer-step--inactive {
    animation: none;
    opacity: 0.5;
    pointer-events: none;
    user-select: none;
}

/* Кнопки «Выбрать все» / «Сбросить» в шапке IDS — иконки: текст не влезал в
   узкий бокс при 3-колоночной раскладке и вылезал за край. Квадратные,
   иконка по центру (подпись — в тултипе). */
#agr-ids-library-section .fixer-step__header-right .btn-secondary--sm {
    min-width: 0;
    padding: 6px;
    justify-content: center;
}
#agr-ids-library-section .fixer-step__header-right .btn-secondary--sm svg {
    width: 16px;
    height: 16px;
}

/* --cols3 (ТЭП): ровно 3 равные колонки боксов в один ряд (не auto-fit, чтобы
   ничего не переносилось на вторую строку) и одинаковая высота — все боксы
   тянутся до самого высокого (align-items: stretch вместо start).
   minmax(0,1fr) не даёт контенту распирать колонку. На узких экранах — стек. */
.input-row-grid--cols3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: stretch;
}
@media (max-width: 768px) {
    .input-row-grid--cols3 {
        grid-template-columns: 1fr;
    }
}

@keyframes fixer-step-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

.fixer-step__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 0;
}

.fixer-step__title {
    display: flex;
    align-items: center;
    gap: 10px;
}

.fixer-step__title svg {
    width: 18px;
    height: 18px;
    color: var(--iris-700);
}

.fixer-step__header h2 {
    /* 0.19.50: было 0.95rem/600 — приравняли к --section-title-size
     * (1.05rem/700), чтобы шаги всех страниц выглядели одинаково
     * (одна visual rhythm для wizard-flows). letter-spacing оставлен. */
    font-size: var(--section-title-size);
    font-weight: var(--section-title-weight);
    color: var(--ink-primary);
    letter-spacing: -0.005em;
    margin: 0;
}

.step-badge--ok {
    background: var(--sage-50);
    color: var(--sage-700);
    border-color: var(--sage-100);
}

.fixer-hint {
    color: var(--ink-secondary);
    margin: 0;
    font-size: 0.88rem;
    line-height: 1.5;
}

.fixer-actions {
    display: flex;
    gap: 10px;
    margin-top: 4px;
    flex-wrap: wrap;
}
.fixer-actions--end {
    justify-content: flex-end;
}

.drop-zone--compact {
    padding: 20px;
    min-height: auto;
}

.fx-prop-name {
    font-weight: 600;
    color: var(--iris-700);
}

/* --- Шапка и тело шага .fixer-step (/tep, /agr, /xml-check) -------------- */

.fixer-step__header-right {
    display: flex;
    align-items: center;
    gap: 10px;
}
.fixer-step__summary {
    font-size: 0.85rem;
    color: var(--ink-secondary);
    font-weight: 500;
}

.fixer-step__body[hidden] {
    display: none !important;
}

@keyframes fx-indeterminate {
    0% { background-position: 100% 0; }
    100% { background-position: -100% 0; }
}

/* Apply Progress Modal — показывается при «Применить (для активного / ко
 * всем)». Полупрозрачный backdrop + центрированная карточка с списком
 * файлов и их статусом по ходу обработки. */
.fx-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(15, 17, 26, 0.55);
    backdrop-filter: blur(2px);
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.fx-modal-backdrop[hidden] { display: none !important; }
body.fx-modal-open { overflow: hidden; }

.fx-modal {
    background: var(--bg-surface);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    width: 100%;
    max-width: 560px;
    max-height: 80vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.fx-modal--narrow { max-width: 420px; }

/* ===========================================================================
 * Changelog modal — «что нового» по клику на версию в шапке сайдбара.
 * Базируется на .fx-modal-backdrop / .fx-modal.
 * ========================================================================= */
.version-badge--clickable {
    cursor: pointer;
    transition: var(--transition);
}
.version-badge--clickable:hover {
    color: var(--iris-500);
    text-decoration: underline;
}
/* Версия ядра (движка): рядом с версией приложения, со знаком Strata (малый
 * знак для мелких размеров, img/strata/README.md); warn — движок несовместим. */
.version-badge--engine {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: 4px;
    font-family: var(--font-ui);
    font-size: 0.74rem;
    color: var(--ink-secondary);
}
.version-badge--engine::before {
    content: "";
    flex: none;
    width: 14px;
    height: 14px;
    background: url('img/strata/strata-mark-small.svg') center / contain no-repeat;
}
.version-badge--warn {
    color: var(--clay-700);
    background: var(--clay-50);
    border-color: var(--clay-100);
}
.version-badge--clickable:focus-visible {
    outline: 2px solid var(--iris-500);
    outline-offset: 2px;
    border-radius: var(--r-sm);
}

.changelog-modal { max-width: 620px; }

.changelog-modal__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 18px 22px;
    border-bottom: 1px solid var(--border-subtle);
}
.changelog-modal__header h2 {
    margin: 0;
    font-size: 1.15rem;
    color: var(--ink-primary);
}
.changelog-modal__close {
    border: none;
    background: transparent;
    font-size: 1.1rem;
    line-height: 1;
    color: var(--ink-tertiary);
    cursor: pointer;
    padding: 4px 8px;
    border-radius: var(--r-sm);
    transition: var(--transition);
}
.changelog-modal__close:hover {
    background: var(--bg-subtle);
    color: var(--ink-primary);
}

.changelog-modal__content {
    padding: 8px 22px 22px;
    overflow-y: auto;
}

/* Подпись автора переехала из сайдбара сюда (0.28.x). */
.changelog-modal__footer {
    padding: 12px 22px;
    border-top: 1px solid var(--border-subtle);
    text-align: right;
}
.changelog-author {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    color: var(--ink-tertiary);
    letter-spacing: 0.02em;
}

.changelog-entry {
    padding: 16px 0;
    border-bottom: 1px solid var(--border-subtle);
}
.changelog-entry:last-child { border-bottom: none; }

.changelog-entry__head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 6px;
}
.changelog-version {
    font-weight: 700;
    font-size: 1.05rem;
    color: var(--iris-500);
}
.changelog-date {
    font-size: 0.82rem;
    color: var(--ink-tertiary);
}

.changelog-entry__body { color: var(--ink-secondary); font-size: 0.9rem; }
.changelog-entry__body p { margin: 6px 0; line-height: 1.5; }
.changelog-section {
    margin: 12px 0 4px;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--ink-primary);
}
.changelog-list { margin: 4px 0 4px 18px; padding: 0; }
.changelog-list li { margin: 3px 0; line-height: 1.45; }
.changelog-entry__body code {
    background: var(--bg-subtle);
    padding: 1px 5px;
    border-radius: var(--r-sm);
    font-size: 0.85em;
}
.changelog-empty {
    color: var(--ink-tertiary);
    text-align: center;
    padding: 24px 0;
}

/* TEP «Набор правил» radio choice — default / custom. */
.tep-rules-choice {
    margin-top: 8px;
}
/* flat-variant — без фона/границы, для использования внутри fixer-step. */
.tep-rules-choice--flat {
    margin-top: 0;
    padding: 0;
    background: transparent;
    border: none;
}
.tep-rules-choice__head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
}
.tep-rules-choice__title {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--ink-primary);
}
.tep-rules-choice__status {
    margin-left: auto;
    font-size: 0.82rem;
    color: var(--ink-secondary);
}

/* Per-file прогресс в карточке pending. */
.tep-file-card__progress {
    margin-top: 8px;
    width: 100%;
}
.tep-file-card__progress-label {
    display: flex;
    justify-content: space-between;
    font-size: 0.78rem;
    color: var(--ink-secondary);
    margin-bottom: 4px;
}
.tep-file-card--pending {
    flex-wrap: wrap;
}
.tep-radio {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 8px 4px;
    cursor: pointer;
}
.tep-radio input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.tep-radio__dot {
    width: 18px;
    height: 18px;
    border: 2px solid var(--border-default, var(--border));
    border-radius: 50%;
    flex-shrink: 0;
    margin-top: 2px;
    position: relative;
    background: var(--bg-surface);
    transition: border-color var(--transition);
}
.tep-radio input[type="radio"]:checked + .tep-radio__dot {
    border-color: var(--iris-500, var(--primary));
}
.tep-radio input[type="radio"]:checked + .tep-radio__dot::after {
    content: "";
    position: absolute;
    inset: 3px;
    border-radius: 50%;
    background: var(--iris-500, var(--primary));
}
.tep-radio__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.tep-radio__label {
    font-weight: 600;
    color: var(--ink-primary);
    font-size: 0.9rem;
}
.tep-radio__sub {
    color: var(--ink-secondary);
    font-size: 0.82rem;
}

.fx-modal__hint {
    margin: 12px 0 0;
    font-size: 0.82rem;
    color: var(--ink-tertiary);
    line-height: 1.4;
}
.fx-modal__header {
    padding: 20px 24px 12px;
    border-bottom: 1px solid var(--border-subtle);
}
.fx-modal__header h2 {
    margin: 0 0 4px;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--ink-primary);
}
.fx-modal__sub {
    margin: 0;
    font-size: 0.85rem;
    color: var(--ink-secondary);
}
.fx-modal__body {
    padding: 12px 24px;
    overflow-y: auto;
    flex: 1;
}
.fx-modal__footer {
    padding: 12px 24px 16px;
    border-top: 1px solid var(--border-subtle);
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    background: var(--bg-subtle);
}

.fx-apply-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.fx-apply-item {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px 4px;
    border-bottom: 1px dashed var(--border-subtle);
    font-size: 0.9rem;
}
.fx-apply-item:last-child { border-bottom: none; }

.fx-apply-item__progress-bar {
    height: 4px;
    background: var(--border-subtle);
    border-radius: 2px;
    overflow: hidden;
}
.fx-apply-item__progress-fill {
    height: 100%;
    background: var(--iris-500, var(--primary));
    transition: width 0.15s ease-out;
}
.fx-apply-item__progress-fill.is-indeterminate {
    background: linear-gradient(
        90deg,
        var(--iris-50) 0%,
        var(--iris-500, var(--primary)) 50%,
        var(--iris-50) 100%
    );
    background-size: 200% 100%;
    animation: fx-indeterminate 1.4s linear infinite;
}

.fx-apply-item__icon {
    display: inline-flex;
    width: 18px;
    height: 18px;
    align-items: center;
    justify-content: center;
    color: var(--ink-tertiary);
    flex-shrink: 0;
}
.fx-apply-item__icon svg { width: 18px; height: 18px; }

.fx-apply-item.is-done .fx-apply-item__icon { color: var(--pass, var(--sage-500)); }
.fx-apply-item.is-error .fx-apply-item__icon { color: var(--fail, var(--clay-500)); }
.fx-apply-item__name {
    flex: 1;
    color: var(--ink-primary);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fx-apply-item__status {
    color: var(--ink-secondary);
    font-size: 0.82rem;
    flex-shrink: 0;
}
.fx-apply-item.is-done .fx-apply-item__status { color: var(--pass, var(--sage-700)); }
.fx-apply-item.is-error .fx-apply-item__status { color: var(--fail, var(--clay-700)); }

/* spinner для loader-2 svg внутри modal — переиспользуем existing @spin
 * keyframes (строка 1113). transform-origin важен — без него svg крутится
 * вокруг top-left, а не центра. */
.fx-apply-item__icon .spin {
    animation: spin 1s linear infinite;
    transform-origin: center;
}

/* Иконка-подсказка «?». Используется рядом с заголовками секций — клик
 * (на тач) или hover (на десктопе) показывает tooltip с пояснением.
 * Заменяет длинные .fixer-hint простыни под title. */
.hint-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin-left: 4px;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--ink-tertiary);
    cursor: help;
    border-radius: 50%;
    transition: color var(--transition), background var(--transition);
}
.hint-icon:hover,
.hint-icon:focus-visible {
    color: var(--iris-500, var(--primary));
    background: var(--iris-50, rgba(50, 82, 123, 0.08));
    outline: none;
}
.hint-icon svg {
    width: 16px;
    height: 16px;
}

.fx-q-status--queued {
    background: var(--bg-subtle);
    color: var(--ink-secondary);
    border-color: var(--border-default);
}

.fx-q-status--scanning,
.fx-q-status--applying {
    background: var(--iris-50);
    color: var(--iris-700, #223A5A);
    border-color: var(--iris-100, #DDDAF4);
}

.fx-q-status--scanned {
    background: var(--sage-50);
    color: var(--sage-700);
    border-color: var(--sage-100);
}

.fx-q-status--no-issues {
    background: var(--sand-50);
    color: var(--sand-700);
    border-color: var(--sand-100, #F2D996);
}

.fx-q-status--applied {
    background: var(--sage-50);
    color: var(--sage-700);
    border-color: var(--sage-100);
}

.fx-q-status--error {
    background: var(--clay-50);
    color: var(--clay-700);
    border-color: var(--clay-100);
}

/* -------------------------------------------------------------------------
   Shared: compact drop-zone
   ------------------------------------------------------------------------- */

.drop-zone--compact {
    padding: 16px 14px;
    border-radius: 10px;
    border: 1.5px dashed rgba(255,255,255,0.12);
    background: rgba(255,255,255,0.02);
    text-align: center;
    transition: background 0.2s ease, border-color 0.2s ease;
}

.drop-zone--compact .drop-icon {
    width: 24px;
    height: 24px;
    color: #74b9ff;
    margin-bottom: 6px;
}

.drop-zone--compact .drop-zone__label {
    font-size: 12px;
    margin: 0 0 8px;
    color: #93a5b8;
}

.drop-zone--compact .btn-secondary {
    padding: 6px 14px;
    font-size: 12px;
}

.drop-zone--compact.dragover {
    border-color: rgba(116,185,255,0.55);
    background: rgba(116,185,255,0.08);
}

/* =========================================================
   REDESIGN 2026 — Notion/Miro-minimal pastel system
   Loaded last to override legacy styles without edits above.
   ========================================================= */

/* ─── Hide legacy top-tabs (navigation moved to sidebar) ── */
.top-tabs { display: none !important; }
body { background: var(--bg); }

/* ─── App header v2 ──────────────────────────────────────── */
.app-header {
    height: var(--header-height);
    top: 0;
    background: var(--bg-surface);
    border-bottom: 1px solid var(--border-subtle);
    padding: 0 24px;
    box-shadow: none;
}

.app-logo {
    width: 34px;
    height: 34px;
    /* Нейтральная иконка-логотип в шапке — без цветной заливки (дизайн-код:
     * тихая шапка, акцент не в логотипе). */
    background: var(--bg-subtle);
    color: var(--ink-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: 10px;
}
.app-logo svg { width: 18px; height: 18px; }

.header-title { gap: 8px; align-items: baseline; }
.header-title h1 {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--ink-primary);
    letter-spacing: -0.005em;
}
.header-sub {
    font-size: 0.75rem;
    color: var(--ink-tertiary);
    line-height: 1;
    margin-top: 2px;
    font-weight: 400;
}
.header-title--stack {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
}

.version-badge {
    font-family: var(--font-mono);
    font-size: 0.68rem;
    color: var(--ink-tertiary);
    background: var(--bg-subtle);
    border: 1px solid var(--border-subtle);
    padding: 1px 7px;
    border-radius: 999px;
    font-weight: 500;
}

/* Header actions — soft buttons */
.btn-clear-session {
    background: var(--clay-50);
    border-color: var(--clay-100);
    color: var(--clay-700);
}
.btn-clear-session:not(:disabled):hover {
    background: #F4D9CD;
    border-color: var(--clay-500);
    color: var(--clay-700);
}

/* ─── Layout v2: sidebar + main, no top-tabs ─────────────── */
.app-layout {
    height: calc(100vh - var(--header-height));
    margin-top: var(--header-height);
}

/* ─── Sidebar v2 — tree of services ──────────────────────── */
.sidebar {
    width: var(--sidebar-width);
    min-width: var(--sidebar-width);
    background: var(--bg-surface);
    border-right: 1px solid var(--border-subtle);
    padding: 14px 10px 10px;
    gap: 2px;
}

.tree-section-label {
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-tertiary);
    padding: 4px 10px 6px;
}

.tree { display: flex; flex-direction: column; gap: 2px; }

.tree-service {
    border-radius: 10px;
    position: relative;
}

.tree-service__head {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 8px 10px;
    border-radius: 10px;
    color: var(--ink-secondary);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 500;
    cursor: pointer;
    user-select: none;
    transition: background var(--transition), color var(--transition);
}
.tree-service__head svg { width: 15px; height: 15px; flex-shrink: 0; }
.tree-service__head:hover { background: var(--bg-subtle); color: var(--ink-primary); }

.tree-service__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.tree-chevron {
    width: 12px !important;
    height: 12px !important;
    color: var(--ink-tertiary);
    transition: transform var(--transition);
}
.tree-service.is-open > .tree-service__head .tree-chevron { transform: rotate(180deg); }

/* Active service: pastel fill + accent bar */
.tree-service.is-active > .tree-service__head {
    background: var(--bg-subtle);
    color: var(--ink-primary);
    font-weight: 600;
}
.tree-service.is-active::before {
    content: "";
    position: absolute;
    left: 0;
    top: 8px;
    bottom: 8px;
    width: 3px;
    background: var(--iris-500);
    border-radius: 0 2px 2px 0;
}

/* Tree children — ASCII-tree aesthetic */
.tree-children {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 2px 0 4px;
}
.tree-service:not(.is-open) > .tree-children { display: none; }

.tree-child {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px 6px 6px;
    border-radius: 8px;
    color: var(--ink-secondary);
    font-size: 0.82rem;
    font-weight: 400;
    text-decoration: none;
    cursor: pointer;
    transition: background var(--transition), color var(--transition);
    white-space: nowrap;
}
.tree-child svg { width: 13px; height: 13px; flex-shrink: 0; color: var(--ink-tertiary); }
.tree-child .sidebar-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.tree-glyph {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    color: var(--ink-tertiary);
    letter-spacing: -0.02em;
    width: 22px;
    flex-shrink: 0;
    line-height: 1;
}

.tree-child:hover:not(.disabled) {
    background: var(--bg-subtle);
    color: var(--ink-primary);
}
.tree-child.active {
    background: var(--iris-50);
    color: var(--iris-700);
    font-weight: 600;
}
.tree-child.active svg { color: var(--iris-500); }
.tree-child.active .tree-glyph { color: var(--iris-500); }

.tree-child.disabled {
    opacity: 0.42;
    cursor: not-allowed;
    pointer-events: none;
}

.tree-count {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    font-weight: 500;
    color: var(--ink-tertiary);
    background: var(--bg-subtle);
    border: 1px solid var(--border-subtle);
    padding: 1px 6px;
    border-radius: 999px;
    margin-left: auto;
}
.tree-child.active .tree-count {
    color: var(--iris-700);
    background: var(--iris-50);
    border-color: var(--iris-100);
}
.tree-count--fail { color: var(--clay-700); background: var(--clay-50); border-color: var(--clay-100); }
.tree-count--warn { color: var(--sand-700); background: var(--sand-50); border-color: var(--sand-100); }

/* Sidebar footer — keep the credit line subtle */
.sidebar-footer {
    margin-top: auto;
    padding: 10px 12px 4px;
    border-top: 1px solid var(--border-subtle);
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.7rem;
    color: var(--ink-tertiary);
}
.sidebar-footer::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--sage-500);
    flex-shrink: 0;
}

/* ─── Sidebar collapsed mode (icons only) ────────────────── */
.sidebar {
    transition: width var(--transition), min-width var(--transition);
}

/* Кнопка переключения — над «Сервисы» */
.sidebar-toggle {
    align-self: flex-end;
    margin: -4px -4px 4px;
    width: 28px;
    height: 28px;
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    background: transparent;
    color: var(--ink-tertiary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.sidebar-toggle:hover {
    background: var(--bg-subtle);
    color: var(--ink-primary);
    border-color: var(--border-strong, var(--border-subtle));
}
.sidebar-toggle svg { width: 16px; height: 16px; }
.sidebar-toggle__open  { display: none; }
.sidebar-toggle__close { display: inline-block; }
.sidebar.is-collapsed .sidebar-toggle__open  { display: inline-block; }
.sidebar.is-collapsed .sidebar-toggle__close { display: none; }
.sidebar.is-collapsed .sidebar-toggle {
    align-self: center;
    margin: 0 0 6px;
}

/* Свёрнутый сайдбар — только иконки */
.sidebar.is-collapsed {
    width: 56px;
    min-width: 56px;
    padding: 10px 6px;
}
.sidebar.is-collapsed .tree-section-label,
.sidebar.is-collapsed .tree-service__label,
.sidebar.is-collapsed .sidebar-label,
.sidebar.is-collapsed .tree-children,
.sidebar.is-collapsed .tree-chevron,
.sidebar.is-collapsed .tree-count,
.sidebar.is-collapsed .tree-glyph,
.sidebar.is-collapsed .sidebar-author,
.sidebar.is-collapsed .sidebar-footer span {
    display: none;
}
.sidebar.is-collapsed .tree-service__head,
.sidebar.is-collapsed .sidebar-item {
    justify-content: center;
    padding: 9px 6px;
    gap: 0;
}
/* В свёрнутом рейле остаются только иконки — укрупняем их (в развёрнутом
   виде 15/13px нормальны рядом с подписью, но по центру узкой 56px-полосы
   мелкие иконки «теряются» и выглядят уменьшенными). */
.sidebar.is-collapsed .tree-service__head svg,
.sidebar.is-collapsed .sidebar-item svg {
    width: 20px;
    height: 20px;
}
.sidebar.is-collapsed .tree-service.is-active::before {
    /* Активный индикатор остаётся, но укорочен */
    top: 6px;
    bottom: 6px;
    width: 2px;
}
.sidebar.is-collapsed .sidebar-footer {
    padding: 8px 6px;
    border-top: 1px solid var(--border-subtle);
    justify-content: center;
}
.sidebar.is-collapsed .sidebar-footer::before {
    margin: 0 auto;
}

/* ─── Cards — warmer ─────────────────────────────────────── */
/* 0.19.53 cleanup: .card палитра (bg/border/radius/shadow) объединена
 * в основном правиле line ~812. Здесь оставлены только локальные
 * tweaks (если будут) для разделов ниже. */

/* ─── Stat cards — pastel status tint ────────────────────── */
/* 0.19.53 cleanup: base .stat-card палитра (bg/border/radius/shadow)
 * объединена в основном правиле line ~1204. Здесь остались только
 * status-modifier overrides (.stat-pass, .stat-fail, ...). */
.stat-card.stat-pass {
    background: var(--sage-50);
    border-color: var(--sage-100);
}
.stat-card.stat-pass .stat-number,
.stat-card.stat-pass .stat-icon { color: var(--sage-700); }
.stat-card.stat-pass .stat-icon { background: var(--sage-100); }

.stat-card.stat-fail {
    background: var(--clay-50);
    border-color: var(--clay-100);
}
.stat-card.stat-fail .stat-number,
.stat-card.stat-fail .stat-icon { color: var(--clay-700); }
.stat-card.stat-fail .stat-icon { background: var(--clay-100); }

.stat-card.stat-warn {
    background: var(--sand-50);
    border-color: var(--sand-100);
}
.stat-card.stat-warn .stat-number,
.stat-card.stat-warn .stat-icon { color: var(--sand-700); }
.stat-card.stat-warn .stat-icon { background: var(--sand-100); }

.stat-card.stat-coverage {
    background: var(--iris-50);
    border-color: var(--iris-100);
}
.stat-card.stat-coverage .stat-number,
.stat-card.stat-coverage .stat-icon { color: var(--iris-700); }
.stat-card.stat-coverage .stat-icon { background: var(--iris-100); }

.stat-card.stat-skip {
    background: var(--bg-subtle);
    border-color: var(--border-subtle);
}
.stat-card.stat-skip .stat-number { color: var(--ink-secondary); }
.stat-card.stat-skip .stat-icon { color: var(--ink-tertiary); background: var(--bg-surface); }

/* Дубли наборов свойств (нарушение схемы) — sand-тон, как у предупреждений. */
.stat-card.stat-dup {
    background: var(--sand-50);
    border-color: var(--sand-100);
}
.stat-card.stat-dup .stat-number,
.stat-card.stat-dup .stat-icon { color: var(--sand-700); }
.stat-card.stat-dup .stat-icon { background: var(--sand-100); }

/* Карточка «Квартиры с ошибками»: зелёная — ошибок нет, красная — есть; без
   тона — проверка не применима (здание не жилое). Тона как у «Осей». */
.stat-card.stat-apartments--ok {
    background: var(--sage-50);
    border-color: var(--sage-100);
}
.stat-card.stat-apartments--ok .stat-number,
.stat-card.stat-apartments--ok .stat-icon { color: var(--sage-700); }
.stat-card.stat-apartments--ok .stat-icon { background: var(--sage-100); }
.stat-card.stat-apartments--fail {
    background: var(--clay-50);
    border-color: var(--clay-100);
}
.stat-card.stat-apartments--fail .stat-number,
.stat-card.stat-apartments--fail .stat-icon { color: var(--clay-700); }
.stat-card.stat-apartments--fail .stat-icon { background: var(--clay-100); }

/* Карточка «Оси (IfcGrid)»: зелёная — оси есть, красная — нет.
   Пастельные тона, идентичные карточкам PASS/FAIL: «Нет» — ровно как «Ошибки»
   (clay-50 фон + clay-100 рамка), «есть оси» — как «Успешно» (sage). */
.stat-card.stat-axes--ok {
    background: var(--sage-50);
    border-color: var(--sage-100);
}
.stat-card.stat-axes--ok .stat-number,
.stat-card.stat-axes--ok .stat-icon { color: var(--sage-700); }
.stat-card.stat-axes--ok .stat-icon { background: var(--sage-100); }
.stat-card.stat-axes--missing {
    background: var(--clay-50);
    border-color: var(--clay-100);
}
.stat-card.stat-axes--missing .stat-number,
.stat-card.stat-axes--missing .stat-icon { color: var(--clay-700); }
.stat-card.stat-axes--missing .stat-icon { background: var(--clay-100); }

.stat-number {
    font-family: var(--font-mono);
    font-weight: 600;
    letter-spacing: -0.01em;
}

/* ─── Filter buttons — soft pills ────────────────────────── */
.filter-btn {
    border-radius: 999px;
    border: 1px solid var(--border-subtle);
    background: var(--bg-surface);
    color: var(--ink-secondary);
    font-weight: 500;
    transition: all var(--transition);
}
.filter-btn:hover:not(.active) { background: var(--bg-subtle); }
.filter-btn.active { background: var(--ink-primary); color: var(--bg-surface); border-color: var(--ink-primary); }
.filter-btn.fail.active   { background: var(--clay-500); border-color: var(--clay-500); color: #fff; }
.filter-btn.warn.active   { background: var(--sand-500); border-color: var(--sand-500); color: #fff; }
.filter-btn.pass.active   { background: var(--sage-500); border-color: var(--sage-500); color: #fff; }
.filter-btn.steel.active  { background: var(--steel-500); border-color: var(--steel-500); color: #fff; }
.filter-btn.active-tone   { background: var(--iris-50); border-color: var(--iris-100); color: var(--iris-700); }
.filter-btn.action-applicability.active-tone { background: var(--iris-100); }

/* ─── Badges / Chips ─────────────────────────────────────── */
.badge, .badge-pass, .badge-fail, .badge-warn {
    font-family: var(--font-mono);
    font-weight: 500;
    letter-spacing: 0;
    border-radius: 999px;
}
.badge-pass { background: var(--sage-50); color: var(--sage-700); border: 1px solid var(--sage-100); }
.badge-fail { background: var(--clay-50); color: var(--clay-700); border: 1px solid var(--clay-100); }
.badge-warn { background: var(--sand-50); color: var(--sand-700); border: 1px solid var(--sand-100); }
/* Стальной бейдж — «Рекомендации» в «Что исправить» (низший приоритет). */
.badge-steel { background: var(--steel-50); color: var(--steel-700); border: 1px solid var(--steel-100); }

/* ─── Monospace for GUIDs, IFC classes, file names ──────── */
code, .mono, .guid, .ifc-class, .file-name-mono,
.ids-result-prop, [class*="mono"] {
    font-family: var(--font-mono);
}

/* ─── Primary button — soft iris ─────────────────────────── */
.btn-primary {
    background: var(--iris-500);
    border-color: var(--iris-500);
    color: #fff;
    border-radius: var(--r-md);
    font-weight: 500;
}
.btn-primary:hover:not(:disabled) {
    background: var(--iris-700);
    border-color: var(--iris-700);
}
/* 0.19.56 cleanup: .btn-secondary был partial-override (rule line 1062 +
 * этот). Объединено в основном rule (см. line 1062). Здесь оставлен
 * только hover state (имеет :not(:disabled) что отличается от старого
 * `.btn-secondary:hover`). */
.btn-secondary:hover:not(:disabled) {
    background: var(--bg-subtle);
    color: var(--ink-primary);
    border-color: var(--border-default);
}

/* ─── Fixer header ───────────────────────────────────────── */
.fixer-header {
    background: var(--bg-surface);
    border-bottom: 1px solid var(--border-subtle);
}
.fixer-header__title h1 {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--ink-primary);
}
.fixer-header__subtitle { color: var(--ink-secondary); }

/* ─── Dashboard tabs — cleaner underline ─────────────────── */
.dash-tab {
    border-radius: var(--r-md);
    color: var(--ink-secondary);
    font-weight: 500;
}
.dash-tab.active {
    background: var(--bg-subtle);
    color: var(--ink-primary);
    font-weight: 600;
}

/* ─── Version badge in sidebar footer ────────────────────── */
.sidebar-author { font-family: var(--font-mono); }

/* ─── Drop-zones — warmer tones ──────────────────────────── */
.drop-zone {
    border-radius: var(--r-lg);
    background: var(--bg-subtle);
    border: 1.5px dashed var(--border-default);
}
.drop-zone:hover, .drop-zone.drag-over {
    background: var(--iris-50);
    border-color: var(--iris-500);
}

/* Header — keep subtitle on one line, truncate */
.header-title--stack { min-width: 0; max-width: 100%; }
.header-title--stack h1 { white-space: nowrap; }
.header-sub {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 48ch;
}

/* ─── Overview (Dashboard) v2 ────────────────────────────── */
.overview-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 16px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border-subtle);
}
.overview-header__text h2 {
    /* Page-level заголовок — одна шкала с .page-header h2 (30px). */
    font-size: var(--section-title-lg);
    font-weight: var(--section-title-weight);
    color: var(--ink-primary);
    letter-spacing: -0.01em;
    margin: 0;
    display: flex;
    align-items: center;
    gap: 10px;
}
.overview-header__text h2 svg { display: none; }
.overview-header__sub {
    font-size: 0.82rem;
    color: var(--ink-tertiary);
    margin: 4px 0 0;
}

/* Report meta — chip row */
.report-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    font-size: 0.8rem;
    margin-bottom: 18px;
}
.report-meta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.report-meta span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 11px;
    border: 1px solid var(--border-subtle);
    background: var(--bg-surface);
    border-radius: 999px;
    color: var(--ink-secondary);
}
.report-meta span b {
    color: var(--ink-primary);
    font-weight: 500;
    font-family: var(--font-mono);
    font-size: 0.78rem;
}

/* Stat cards v2 — label on top, number below */
.stats-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 12px;
    margin-bottom: 20px;
}
/* 0.19.53 cleanup: .stat-card layout properties объединены в основном
 * правиле line ~1204 (см. ниже). !important убраны — больше нет
 * competing rules. */
.stat-card__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}
.stat-label {
    font-size: 0.78rem;
    font-weight: 500;
    color: var(--ink-secondary);
    letter-spacing: 0;
    text-transform: none;
    margin: 0;
    line-height: 1.3;
}
.stat-icon {
    width: 28px !important;
    height: 28px !important;
    border-radius: 8px;
    flex-shrink: 0;
}
.stat-icon svg { width: 15px !important; height: 15px !important; }
.stat-number {
    font-size: 1.9rem !important;
    font-weight: 600 !important;
    line-height: 1 !important;
    color: var(--ink-primary);
    letter-spacing: -0.02em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.stat-number--fraction { font-size: 1.35rem !important; }

/* Overall status — soft inline badge */
.overall-status {
    padding: 12px 18px !important;
    border-radius: var(--r-md) !important;
    font-size: 0.9rem !important;
    font-weight: 500 !important;
    text-align: left !important;
    margin-bottom: 20px !important;
    display: flex;
    align-items: center;
    gap: 10px;
}
.overall-status.status-pass {
    background: var(--sage-50);
    border: 1px solid var(--sage-100);
    color: var(--sage-700);
}
.overall-status.status-fail {
    background: var(--clay-50);
    border: 1px solid var(--clay-100);
    color: var(--clay-700);
}
.overall-status.status-warn {
    background: var(--sand-50);
    border: 1px solid var(--sand-100);
    color: var(--sand-700);
}

/* Dashboard tabs — pill group in a soft container */
.dash-tabs {
    display: inline-flex !important;
    gap: 2px !important;
    padding: 4px !important;
    background: var(--bg-subtle);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md) !important;
    margin-bottom: 18px;
    border-bottom: 1px solid var(--border-subtle) !important;
    width: auto;
}
.dash-tab {
    padding: 7px 14px !important;
    border-radius: 8px !important;
    border: none !important;
    margin: 0 !important;
    font-size: 0.82rem !important;
    font-weight: 500 !important;
    color: var(--ink-secondary) !important;
    background: transparent !important;
}
.dash-tab:hover:not(.active) {
    background: var(--bg-surface) !important;
    color: var(--ink-primary) !important;
}
.dash-tab.active {
    background: var(--bg-surface) !important;
    color: var(--ink-primary) !important;
    border-bottom: none !important;
    box-shadow: 0 1px 2px rgba(31, 36, 33, 0.05);
    font-weight: 600 !important;
}
.dash-tab svg { width: 14px !important; height: 14px !important; }

/* Chart cards — cleaner */
.charts-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
.chart-card { padding: 20px !important; text-align: left !important; }
.chart-card h3 {
    font-size: 0.85rem !important;
    font-weight: 600 !important;
    color: var(--ink-primary);
    margin: 0 0 14px !important;
    text-align: left !important;
}
.chart-card canvas { margin: 0 auto !important; }
.dash-card-inner { padding: 20px !important; }

/* ─── Files page v2 — two-card step layout ──────────────── */
.file-cards-grid {
    gap: 18px;
    margin-bottom: 18px;
}
.file-split-card {
    padding: 22px;
    border-radius: var(--r-lg);
    gap: 14px;
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    box-shadow: none;
}
.file-split-card__header {
    justify-content: space-between;
    align-items: center;
}
/* Подпись-пояснение под заголовком карточки (напр. «Параметры проверки»). */
.controls-box__hint {
    margin: 4px 0 12px;
    font-size: 0.82rem;
    color: var(--ink-tertiary);
    line-height: 1.5;
}
.file-split-card__title {
    display: flex;
    align-items: center;
    gap: 10px;
}
.file-split-card__title svg {
    width: 18px;
    height: 18px;
    color: var(--iris-700);
}
.file-split-card__title h3 {
    /* Единый ритм заголовков секций со всеми пошаговыми страницами
     * (.fixer-step__header h2 на /tep /agr): было 0.95rem/600 —
     * выбивалось мельче/легче. Теперь 1.05rem/700 через section-title-токены. */
    font-size: var(--section-title-size);
    font-weight: var(--section-title-weight);
    color: var(--ink-primary);
    letter-spacing: -0.005em;
    margin: 0;
}
.step-badge {
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--iris-700);
    background: var(--iris-50);
    border: 1px solid var(--iris-100);
    padding: 3px 9px;
    border-radius: 999px;
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.drop-zone--tinted {
    background: var(--sage-50);
    border: 1.5px dashed var(--sage-100);
    color: var(--ink-secondary);
}
.drop-zone--tinted:hover,
.drop-zone--tinted.drag-over {
    background: var(--iris-50);
    border-color: var(--iris-500);
}
.drop-zone--tinted .drop-icon {
    color: var(--sage-700);
}
.drop-zone--tinted:hover .drop-icon,
.drop-zone--tinted.drag-over .drop-icon {
    color: var(--iris-700);
}
.drop-zone__label {
    font-size: 0.92rem;
    color: var(--ink-primary);
    margin: 0;
}
.drop-zone__label b { font-weight: 600; color: var(--ink-primary); }
.drop-zone__hint {
    font-size: 0.78rem;
    color: var(--ink-tertiary);
    margin: 2px 0 14px;
}
.drop-zone--tinted .btn-secondary {
    background: var(--bg-surface);
    border: 1px solid var(--border-default);
}
.drop-zone--tinted .btn-secondary svg {
    width: 15px;
    height: 15px;
}

/* Вся карточка IFC — drop-зона (как корзины на /agr): при перетаскивании
   файла подсвечивается весь бокс, а не только пунктирный квадрат. Класс
   is-drop-target вешает UploadDropzone на #ifc-card. */
.file-split-card {
    transition: border-color var(--transition), box-shadow var(--transition);
}
.file-split-card.is-drop-target {
    border-color: var(--iris-500);
    box-shadow: 0 0 0 3px var(--iris-100);
}
.file-split-card.is-drop-target .drop-zone--tinted {
    border-color: var(--iris-500);
    background: var(--iris-50);
}
.file-split-card.is-drop-target .drop-zone--tinted .drop-icon {
    color: var(--iris-700);
}

.ids-field-label {
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--ink-tertiary);
    letter-spacing: 0.04em;
}

.ids-radio-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    /* ≈ 7 карточек — все действующие спецификации видны без прокрутки. */
    max-height: 30rem;
    overflow-y: auto;
    padding-right: 4px;
}
/* Длинный список (с архивными) затухает снизу, пока не долистан: на маке полосы
 * прокрутки скрыты, и карточка под краем незаметна. Маска — только в анимации
 * по прокрутке: без прокрутки или без поддержки (Firefox) её просто нет. */
@keyframes ids-list-more-below {
    from, 95% {
        -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 32px), transparent);
        mask-image: linear-gradient(to bottom, #000 calc(100% - 32px), transparent);
    }
    to {
        -webkit-mask-image: none;
        mask-image: none;
    }
}
@supports (animation-timeline: scroll()) {
    .ids-radio-list {
        animation: ids-list-more-below linear both;
        animation-timeline: scroll(self);
    }
}
/* 0.19.57: .ids-radio-empty / .is-error удалены — мигрировано на
 * .empty-state.empty-state--inline + --error модификатор (см. ~line 1779). */

.ids-radio-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 14px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
    background: var(--bg-surface);
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition);
}
.ids-radio-card:hover {
    border-color: var(--iris-100);
    background: var(--iris-50);
}
.ids-radio-card input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.ids-radio-card__dot {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 1.5px solid var(--border-default);
    background: var(--bg-surface);
    flex-shrink: 0;
    position: relative;
    transition: border-color var(--transition), background var(--transition);
}
.ids-radio-card__dot::after {
    content: '';
    position: absolute;
    inset: 3px;
    border-radius: 50%;
    background: var(--iris-500);
    transform: scale(0);
    transition: transform var(--transition);
}
.ids-radio-card input[type="radio"]:checked + .ids-radio-card__dot {
    border-color: var(--iris-500);
}
.ids-radio-card input[type="radio"]:checked + .ids-radio-card__dot::after {
    transform: scale(1);
}
.ids-radio-card:has(input[type="radio"]:checked) {
    border-color: var(--iris-500);
    background: var(--iris-50);
}
.ids-radio-card__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1;
}
.ids-radio-card__name {
    font-size: 0.88rem;
    font-weight: 500;
    color: var(--ink-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.ids-radio-card__meta {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    color: var(--ink-tertiary);
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.ids-radio-card__badge {
    display: inline-flex;
    align-items: center;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--bg-subtle);
    border: 1px solid var(--border-subtle);
    color: var(--ink-secondary);
    font-family: var(--font-sans, inherit);
    font-size: 0.68rem;
    letter-spacing: 0.02em;
}
.ids-radio-card.is-archived .ids-radio-card__name {
    color: var(--ink-secondary);
    font-style: italic;
}

.ids-field-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 4px;
}
.ids-archive-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.74rem;
    color: var(--ink-secondary);
    cursor: pointer;
    user-select: none;
}
.ids-archive-toggle input[type="checkbox"] {
    margin: 0;
    cursor: pointer;
}

.ids-divider {
    color: var(--ink-tertiary);
    font-size: 0.74rem;
    margin: 4px 0;
}
.ids-divider::before,
.ids-divider::after { background: var(--border-subtle); }

/* 0.19.56 cleanup: .btn-upload-ids был partial-override (rule line 2549
 * + этот override). Объединено в основном rule line ~2549 (см. выше).
 * Здесь оставлены только status modifiers (hover/has-file с iris+sage
 * палитрой) и has-file (success state). */
.btn-upload-ids:hover {
    border-color: var(--iris-500);
    color: var(--iris-700);
    background: var(--iris-50);
}
.btn-upload-ids.has-file {
    border-color: var(--sage-500);
    background: var(--sage-50);
    color: var(--sage-700);
}

/* Run-controls card — no heavy border */
.controls--run {
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: none;
}

/* ============================================================
   ТЭП module (/tep)
   ============================================================ */

.drop-zone.is-dragover {
    border-color: var(--primary);
    background: rgba(50, 82, 123, 0.06);
}

/* Rules preview ─────────────────────────────────────────── */
.tep-rules-preview {
    margin-top: 16px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--bg-surface);
    overflow: hidden;
}
.tep-default-badge {
    display: inline-block;
    margin-left: 8px;
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(50, 82, 123, 0.12);
    color: var(--primary);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: lowercase;
    letter-spacing: 0.02em;
}
.fixer-hint--muted {
    color: var(--text-muted);
    font-size: 0.82rem;
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: -8px;
    margin-bottom: 12px;
}
.fixer-hint--muted svg { width: 14px; height: 14px; flex: none; }
.tep-rules-preview__header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 16px;
    background: var(--surface-alt, rgba(50, 82, 123,0.04));
    border-bottom: 1px solid var(--border);
    font-weight: 600;
    color: var(--text);
    font-size: 0.92rem;
}
.tep-rules-preview__header svg { width: 18px; height: 18px; color: var(--primary); }
.tep-rules-preview__tree-wrap {
    max-height: 480px;
    overflow-y: auto;
    padding: 8px 12px 12px;
}
.tep-rules-tree,
.tep-rules-tree ul.tep-tree-children {
    list-style: none;
    margin: 0;
    padding: 0;
}
.tep-rules-tree ul.tep-tree-children {
    padding-left: 22px;
    border-left: 1px dashed rgba(50, 82, 123,0.18);
    margin-left: 9px;
}
.tep-tree-node { margin: 1px 0; }
.tep-tree-node details > summary {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px;
    border-radius: 6px;
    cursor: pointer;
    user-select: none;
    list-style: none;
    color: var(--text);
    font-weight: 600;
    font-size: 0.9rem;
}
.tep-tree-node details > summary::-webkit-details-marker { display: none; }
.tep-tree-node details > summary:hover { background: rgba(50, 82, 123,0.06); }
.tep-tree-chevron {
    width: 14px; height: 14px;
    color: var(--text-muted);
    transition: transform 0.15s ease;
    flex: none;
}
.tep-tree-node details[open] > summary > .tep-tree-chevron {
    transform: rotate(90deg);
}
.tep-tree-icon { width: 16px; height: 16px; flex: none; }
.tep-tree-icon--folder { color: #f59e0b; }
.tep-tree-icon--rule { color: var(--primary); }
.tep-tree-name {
    color: var(--text);
    font-weight: inherit;
    overflow: hidden;
    text-overflow: ellipsis;
}
.tep-tree-rule {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 3px 6px 3px 20px;
    font-size: 0.88rem;
    border-radius: 6px;
}
.tep-tree-rule:hover { background: rgba(50, 82, 123,0.04); }
.tep-tree-rule .tep-tree-name { flex: 1; font-weight: 500; }
.tep-tree-code {
    background: rgba(50, 82, 123,0.1);
    padding: 1px 6px;
    border-radius: 4px;
    font-family: var(--font-mono);
    font-size: 0.78rem;
    color: var(--primary);
}
.tep-tree-class {
    background: rgba(0,0,0,0.04);
    padding: 1px 6px;
    border-radius: 4px;
    font-family: var(--font-mono);
    font-size: 0.78rem;
    color: var(--text-muted);
}
.tep-tree-cond {
    min-width: 22px;
    text-align: center;
    background: rgba(50, 82, 123,0.08);
    padding: 1px 6px;
    border-radius: 999px;
    font-size: 0.75rem;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* Files list ────────────────────────────────────────────── */
.tep-files-list {
    margin-top: 14px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* 0.19.54: мигрирована на modern palette. Был --surface (не существует
 * как var!) — fallback на UA default цвет; raw 10px → --r-lg.
 * Compact padding оставлен (file-row, не самостоятельная карточка). */
.tep-file-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
.tep-file-card:hover {
    border-color: var(--primary);
    box-shadow: var(--shadow-md);
}
/* Drag-reorder загруженных файлов (порядок → столбцы ТЭП). */
.tep-file-card__grip {
    width: 16px;
    height: 16px;
    flex: none;
    color: var(--ink-tertiary);
    cursor: grab;
}
.tep-file-card--loaded { cursor: grab; }
.tep-file-card--loaded:active { cursor: grabbing; }
.tep-file-card--dragging {
    opacity: 0.55;
    border-color: var(--primary);
    box-shadow: var(--shadow-lg);
    transform: scale(1.01);
}
.tep-file-card__main {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1;
    min-width: 0;
}
.tep-file-card__main svg { width: 18px; height: 18px; color: var(--primary); flex: none; }
.tep-file-card__name {
    font-weight: 500;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.tep-file-card__status {
    font-size: 0.82rem;
    color: var(--text-muted);
}
.tep-file-card--pending { background: rgba(50, 82, 123,0.04); }
.tep-file-card--pending .tep-file-card__spin {
    animation: tep-spin 1s linear infinite;
}
.tep-file-card--error {
    border-color: var(--fail);
    background: rgba(239,68,68,0.04);
}
.tep-file-card--error .tep-file-card__main svg { color: var(--fail); }
.tep-file-card__remove {
    background: transparent;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: 4px;
    border-radius: 6px;
    display: inline-flex;
    transition: background 0.15s ease, color 0.15s ease;
}
.tep-file-card__remove:hover { background: rgba(239,68,68,0.12); color: var(--fail); }
.tep-file-card__remove svg { width: 16px; height: 16px; }

@keyframes tep-spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

/* RUS_FNO badge ─────────────────────────────────────────── */
.tep-fno-badge {
    font-size: 0.75rem;
    font-weight: 600;
    padding: 3px 9px;
    border-radius: 999px;
    letter-spacing: 0.01em;
    white-space: nowrap;
}
.tep-fno-badge--res {
    background: var(--sage-50);
    color: var(--sage-700);
}
/* «Нежилое» — жёлтый (sand), в цвет бейджа на «Проверке XML»: одна сущность
   должна выглядеть одинаково на обеих вкладках (0.38.1, было steel). */
.tep-fno-badge--non {
    background: var(--sand-50);
    color: var(--sand-700);
}
/* Нераспознанный RUS_FNO — нейтральный серый: жёлтый теперь занят «Нежилым». */
.tep-fno-badge--unknown {
    background: var(--bg-subtle);
    color: var(--ink-tertiary);
}

/* Export buttons ────────────────────────────────────────── */
.tep-export-buttons {
    display: flex;
    gap: 8px;
}
.btn-secondary--sm,
.btn-primary--sm {
    padding: 6px 12px;
    font-size: 0.85rem;
}

/* Единая кнопка «Сбросить всё» в шапке (рендерит sidebar.js на всех страницах).
   База — .btn-secondary--sm; на hover лёгкий «опасный» (clay) оттенок, т.к.
   действие удаляет загруженные в вкладку файлы. Показ/disabled — из sidebar.js. */
.btn-reset-all:hover:not(:disabled) {
    border-color: var(--clay-500);
    color: var(--clay-700);
    background: var(--clay-50);
}
.btn-reset-all:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Results table ─────────────────────────────────────────── */
.tep-results-wrap {
    margin-top: 12px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--bg-surface);
    /* Единственный горизонтальный скролл — здесь: широкая таблица прокручивается
     * ВНУТРИ этого контейнера (файловые колонки), а Показатель/Ед./Σ остаются
     * закреплёнными. overflow:auto даёт flex-min-size 0; min-width:0 — страховка. */
    overflow: auto;
    max-width: 100%;
    min-width: 0;
}
/* Прокрутка зажатием ЛКМ (drag-scroll, wireResultsPan) — курсор-«ладонь»
 * при наличии скролла; во время перетаскивания — «сжатая ладонь». */
.tep-results-wrap.has-overflow { cursor: grab; }
.tep-results-wrap.is-panning { cursor: grabbing; user-select: none; }
.tep-results-table {
    border-collapse: collapse;
    font-size: 0.9rem;
    /* table-layout: fixed нужен для пользовательского ресайза колонок —
     * иначе браузер игнорирует inline-width и подгоняет под контент.
     * При сужении заголовок ячейки переносится на 2 строки (white-space: normal),
     * данные обрезаются ellipsis.
     * Ширина таблицы выставляется JS-ом (сумма ширин колонок) для предсказуемого
     * горизонтального скролла. */
    table-layout: fixed;
}
.tep-results-table th,
.tep-results-table td {
    box-sizing: border-box;
}
.tep-results-table thead th {
    position: sticky;
    top: 0;
    background: var(--bg-surface);
    border-bottom: 2px solid var(--border);
    padding: 10px 12px;
    text-align: right;
    font-weight: 600;
    color: var(--text-muted);
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: normal;       /* перенос на узкой колонке */
    overflow-wrap: anywhere;
    line-height: 1.3;
    vertical-align: bottom;
}
.tep-results-table thead th small {
    color: var(--text-muted);
    font-weight: 500;
    text-transform: none;
    letter-spacing: normal;
}
.tep-results-table thead th:first-child,
.tep-results-table thead th:nth-child(2) {
    text-align: left;
    /* «Показатель» / «Ед.» — одна строка, тогда как заголовки файлов идут в
     * две строки (имя + бейдж ФНО). Центрируем их по вертикали, иначе
     * подпись висит у нижнего края на фоне высокой строки заголовков. */
    vertical-align: middle;
}
.tep-results-table tbody td {
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-soft, rgba(0,0,0,0.04));
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.tep-results-table tbody tr:last-child td { border-bottom: none; }
.tep-results-table tbody tr:hover { background: rgba(50, 82, 123,0.03); }
.tep-results-table__code,
.tep-results-table tbody td.tep-results-table__code {
    text-align: left;
}
/* Sticky-колонка «Показатель» — независимо от горизонтального скролла.
 * Фон обязательно непрозрачный — иначе прокручиваемые ячейки будут просвечивать. */
.tep-results-table thead th:first-child,
.tep-results-table tbody td.tep-results-table__code {
    position: sticky;
    left: 0;
    /* Сплошной непрозрачный белый — прокручиваемые ячейки не просвечивают. */
    background: var(--bg-surface);
    z-index: 2;
    box-shadow: 1px 0 0 var(--border);
}
.tep-results-table thead th:first-child { z-index: 3; }
/* «Ед.» (2-я колонка) тоже sticky — прилипает сразу за «Показатель».
 * left = ширина 1-й колонки (CSS-переменная --tep-col0-w, её ставит JS
 * и обновляет при ресайзе колонки «Показатель»). */
.tep-results-table thead th:nth-child(2),
.tep-results-table tbody td.tep-results-table__unit {
    position: sticky;
    left: var(--tep-col0-w, 360px);
    background: var(--bg-surface);
    z-index: 2;
    /* Явная тень на границе фикс-колонок и прокручиваемой части. */
    box-shadow: 7px 0 9px -7px rgba(31, 36, 33, 0.20);
}
.tep-results-table thead th:nth-child(2) { z-index: 3; }
.tep-results-table tbody tr.tep-results-row--folder td {
    position: static;
    box-shadow: none;
}
.tep-results-table tbody tr:hover td.tep-results-table__code,
.tep-results-table tbody tr:hover td.tep-results-table__unit {
    background: linear-gradient(rgba(50, 82, 123,0.03), rgba(50, 82, 123,0.03)), var(--card-bg, #fff);
}

/* Badge в заголовке файла, если в этом файле N значений были разобраны
 * из «грязной» строки (например, «108,5 м²» вместо числа). */
.tep-dirty-badge {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--sand-100);
    color: var(--sand-700);
    font-size: 0.7rem;
    font-weight: 600;
    cursor: help;
    text-transform: none;
    letter-spacing: 0;
}

/* Имя файла в шапке колонки. Усечённое (общий префикс/суффикс вырезаны),
 * с ellipsis если всё ещё длинное и колонка узкая. Полное имя — в title. */
.tep-th-filename {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
    cursor: help;
}
.tep-th-filename:hover {
    text-decoration: underline dotted;
}

/* Лаконичная шапка колонки файла: имя сверху, под ним — один центрированный
 * ряд бейджей (ФНО + предупреждения), без хаотичного переноса вперемешку. */
.tep-th-col {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    width: 100%;
}
.tep-th-col .tep-th-filename { max-width: 100%; }
.tep-th-badges {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 4px;
    text-transform: none;
    letter-spacing: normal;
}
/* Раскладку держит flex gap — сбрасываем индивидуальные left-margin'ы бейджей. */
.tep-th-badges > * { margin-left: 0; }
.tep-th-badges .tep-fno-badge {
    text-transform: none;
    letter-spacing: normal;
    font-size: 0.72rem;
    padding: 2px 8px;
}

/* Бейдж при не-каноничном RUS_FNO (отличается от «Жилое здание»/«Нежилое здание») */
.tep-fno-warn-badge {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--clay-50);
    color: var(--clay-700);
    font-size: 0.7rem;
    font-weight: 600;
    cursor: help;
    text-transform: none;
    letter-spacing: 0;
}

/* Resize-handle на правом краю каждой <th>. По умолчанию — тонкая видимая
 * вертикальная линия, чтобы пользователь понимал куда хвататься. На hover/active
 * становится толще и подсвечивается primary-цветом. */
.tep-resize-handle {
    position: absolute;
    top: 0;
    right: -4px;
    bottom: 0;
    width: 8px;
    cursor: col-resize;
    user-select: none;
    z-index: 4;
    transition: background 0.12s ease;
}
.tep-resize-handle::before {
    content: "";
    position: absolute;
    top: 18%;
    bottom: 18%;
    left: 50%;
    transform: translateX(-50%);
    width: 1px;
    background: rgba(0, 0, 0, 0.22);
    transition: background 0.12s ease, width 0.12s ease;
}
.tep-resize-handle:hover::before,
.tep-resize-handle.is-active::before {
    background: var(--primary, #32527B);
    width: 2px;
}
.tep-resize-handle:hover,
.tep-resize-handle.is-active {
    background: rgba(50, 82, 123, 0.12);
}

/* Drag-to-pan: пользователь схватил таблицу и тащит её по горизонтали.
 * Курсор-руку показываем только когда есть горизонтальный оверфлоу. */
.tep-results-wrap.has-overflow { cursor: grab; }
.tep-results-wrap.is-panning {
    cursor: grabbing;
    user-select: none;
}
.tep-results-wrap .tep-resize-handle,
.tep-results-wrap button,
.tep-results-wrap a { cursor: pointer; }
.tep-results-wrap .tep-resize-handle { cursor: col-resize; }
.tep-results-table__code code {
    background: rgba(50, 82, 123,0.08);
    padding: 1px 6px;
    border-radius: 4px;
    font-family: var(--font-mono);
    font-size: 0.82rem;
}
/* Подпункт разбивки по зонам ГПЗУ («5.2.1 БКТ») — сдвиг вправо задаётся
 * инлайн-отступом при рендере, здесь только приглушённая подпись.
 * НЕ задавать таким строкам position: оно перебьёт sticky у колонки
 * «Показатель», и при горизонтальном скролле подписи подпунктов уезжают,
 * пока пункты остаются на месте. */
.tep-results-table tbody tr.tep-results-row--sub .tep-results-table__title {
    color: var(--ink-secondary, var(--text-secondary));
}
.tep-results-table__title {
    /* Бейдж-код перед названием убран — title теперь основная подпись строки,
     * поэтому основной цвет текста, без левого отступа и с запасом по ширине
     * под расширенную колонку «Показатель». */
    color: var(--ink-primary, var(--text));
    font-size: 0.85rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-block;
    max-width: 320px;
    vertical-align: middle;
}
.tep-results-table__sum {
    font-weight: 700;
    /* Сплошной непрозрачный белый (как Показатель/Ед) — прокручиваемые ячейки
     * не просвечивают сквозь закреплённую Σ. */
    background: var(--bg-surface);
}
/* «Σ по всем» — заголовок по центру по вертикали, как «Показатель»
 * (а не по низу, как двустрочные заголовки файлов). */
.tep-results-table thead th.tep-results-table__sum {
    vertical-align: middle;
}
/* Σ закреплена справа — итог всегда виден при скролле файловых колонок.
 * Только при наличии скролла (.has-overflow): иначе на узкой таблице right:0
 * «отклеил» бы Σ к правому краю контейнера с зазором. */
.tep-results-wrap.has-overflow .tep-results-table__sum {
    position: sticky;
    right: 0;
    z-index: 2;
    box-shadow: -7px 0 9px -7px rgba(31, 36, 33, 0.20);
}
.tep-results-wrap.has-overflow .tep-results-table thead th.tep-results-table__sum {
    z-index: 3;
}
/* Строки-папки делают все td static (7032) — возвращаем sticky-right именно
 * для Σ-ячейки папки; фон непрозрачный в тон папке (steel-тинт по глубине). */
.tep-results-wrap.has-overflow .tep-results-table tbody tr.tep-results-row--folder td.tep-results-table__sum {
    position: sticky;
    right: 0;
    z-index: 2;
    box-shadow: -7px 0 9px -7px rgba(31, 36, 33, 0.20);
}
.tep-results-table tbody tr.tep-results-row--folder td.tep-results-table__sum {
    background: linear-gradient(rgba(50, 82, 123, 0.06), rgba(50, 82, 123, 0.06)), var(--bg-surface);
}
.tep-results-table tbody tr.tep-results-row--folder[data-depth="1"] td.tep-results-table__sum {
    background: linear-gradient(rgba(50, 82, 123, 0.04), rgba(50, 82, 123, 0.04)), var(--bg-surface);
}
.tep-results-table tbody tr.tep-results-row--folder[data-depth="2"] td.tep-results-table__sum {
    background: linear-gradient(rgba(50, 82, 123, 0.025), rgba(50, 82, 123, 0.025)), var(--bg-surface);
}
.tep-cell-skipped, .tep-cell-empty {
    color: var(--text-muted);
    opacity: 0.6;
}
.tep-cell-skipped { cursor: help; }
.tep-cell-err { color: var(--fail); margin-left: 4px; }
/* Вторая строка value-ячейки: мелкое полупрозрачное «N эл.» под числом —
 * сколько элементов стоит за значением (у сумм, подытогов и общей суммы). */
.tep-cell-count {
    display: block;
    margin-top: 1px;
    font-family: var(--font-ui, inherit);
    font-size: 0.7rem;
    font-weight: 400;
    line-height: 1.2;
    color: var(--text-secondary);
    opacity: 0.65;
}
/* Пояснение под нулём: правило отработало, но подходящих элементов не нашлось.
 * Мельче и бледнее счётчика — это подпись, а не цифра отчёта. */
.tep-cell-notfound {
    display: block;
    margin-top: 1px;
    font-family: var(--font-ui, inherit);
    font-size: 0.66rem;
    font-weight: 400;
    line-height: 1.2;
    color: var(--ink-tertiary, var(--text-muted));
    opacity: 0.8;
    white-space: nowrap;
}
/* Пункт 1 расходится с суммой зон участка (папка «1А»): строка красным, как
 * строка расхождения в Проверке XML. Фон — на ячейках: у «Показателя» и Σ
 * свой непрозрачный фон (sticky), фон строки они бы перекрыли. */
.tep-results-table tbody tr.tep-results-row--mismatch td,
.tep-results-table tbody tr.tep-results-row--mismatch td.tep-results-table__code,
.tep-results-table tbody tr.tep-results-row--mismatch td.tep-results-table__sum {
    background: var(--clay-50);
}
.tep-results-table tbody tr.tep-results-row--mismatch .tep-results-table__title,
.tep-results-table tbody tr.tep-results-row--mismatch td.tep-cell-value,
.tep-results-table tbody tr.tep-results-row--mismatch td.tep-results-table__sum {
    color: var(--clay-700);
}

/* Hierarchical results: folder header row spans all columns,
   rule rows below them get left-padding equal to their depth. */
.tep-results-table tbody tr.tep-results-row--folder td {
    background: rgba(50, 82, 123, 0.06);
    border-bottom: 1px solid var(--border-subtle);
    padding: 6px 12px;
    text-align: left !important;
    font-weight: 600;
    color: var(--ink-primary);
    font-size: 0.85rem;
    white-space: nowrap;
    /* Снимаем overflow: hidden (унаследовано от обычных td) — иначе
     * sticky-`<span>` внутри клиппится и не «прилипает» к левому краю. */
    overflow: visible;
}
.tep-results-row--folder[data-depth="1"] td {
    background: rgba(50, 82, 123, 0.04);
}
.tep-results-row--folder[data-depth="2"] td {
    background: rgba(50, 82, 123, 0.025);
}
.tep-results-folder {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--ink-primary);
}
.tep-results-folder-icon {
    width: 15px;
    height: 15px;
    color: var(--steel-500);
    flex-shrink: 0;
}
/* Первая ячейка строки-папки прилипает к левому краю — как sticky-колонка
 * «Показатель» у обычных строк, чтобы название папки не уезжало при
 * горизонтальном скролле. Фон обязательно непрозрачный (steel-тинт
 * поверх surface), иначе сквозь него просвечивают прокручиваемые ячейки. */
.tep-results-table tbody tr.tep-results-row--folder td.tep-results-folder-cell {
    position: sticky;
    left: 0;
    z-index: 2;
    box-shadow: 7px 0 9px -7px rgba(31, 36, 33, 0.20);
    background:
        linear-gradient(rgba(50, 82, 123, 0.06), rgba(50, 82, 123, 0.06)),
        var(--bg-surface);
}
.tep-results-row--folder[data-depth="1"] td.tep-results-folder-cell {
    background:
        linear-gradient(rgba(50, 82, 123, 0.04), rgba(50, 82, 123, 0.04)),
        var(--bg-surface);
}
.tep-results-row--folder[data-depth="2"] td.tep-results-folder-cell {
    background:
        linear-gradient(rgba(50, 82, 123, 0.025), rgba(50, 82, 123, 0.025)),
        var(--bg-surface);
}
/* Subtotal-ячейки в строке-папке: тот же steel-тинт фон что и заголовок,
 * но цифра выровнена по правому краю (как обычные value-cells). Число —
 * steel-700, чтобы подытог визуально отличался от обычных значений. */
.tep-results-table tbody tr.tep-results-row--folder td.tep-cell-folder-sub {
    text-align: right !important;
    font-weight: 600;
    color: var(--steel-700);
    font-variant-numeric: tabular-nums;
}

/* «Предварительные расчёты» — опции до запуска (Фаза 2). */
.tep-options {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.tep-option {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    user-select: none;
    color: var(--ink-primary, var(--text));
    font-size: 0.95rem;
}
.tep-option__label {
    line-height: 1.4;
}

/* ===========================================================================
 * Batch validation UI — multi-file IFC check with per-model subtabs.
 * Activated only when the user picks >1 IFC; single-file flow uses
 * existing styles unchanged.
 * ========================================================================= */

/* Chips list right under the IFC drop-zone, one per selected IFC.
   Сетка авто-колонок (а не flex-wrap в одну колонку): чипы плотно
   упаковываются по 2-3 в ряд, чтобы много файлов уместилось без скролла. */
.batch-files-chips {
    margin-top: 10px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 6px;
}
.batch-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px 4px 12px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--border-light);
    font-size: 0.82rem;
    color: var(--text-secondary);
    max-width: 280px;
}
.batch-chip__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.batch-chip__remove {
    border: none;
    background: transparent;
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    color: var(--text-muted);
    cursor: pointer;
}
.batch-chip__remove:hover {
    background: rgba(0, 0, 0, 0.06);
    color: var(--text);
}
.batch-chip__remove svg { width: 14px; height: 14px; }

/* Top progress bar shown above the dashboard while a batch is running. */
.batch-bar {
    margin-bottom: 16px;
    padding: 14px 16px;
    background: linear-gradient(180deg, #fff, var(--border-light));
    border: 1px solid var(--border);
    border-radius: 12px;
}
.batch-bar__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}
.batch-bar__title {
    font-weight: 600;
    color: var(--text);
}
.batch-bar__cancel {
    padding: 4px 10px;
    font-size: 0.84rem;
}
.batch-bar__cancel svg { width: 14px; height: 14px; }
.batch-bar__progress {
    height: 10px;
    border-radius: 999px;
    overflow: hidden;
    background: #e9eef5;
    border: 1px solid var(--border);
}
.batch-bar__fill {
    height: 100%;
    width: 0;
    border-radius: inherit;
    transition: width 0.24s ease, background 0.2s ease;
    background: linear-gradient(90deg, #5A7BA8 0%, var(--primary) 100%);
}
.batch-bar.is-done .batch-bar__fill {
    background: linear-gradient(90deg, #34d399 0%, var(--pass) 100%);
}
.batch-bar.is-cancelled .batch-bar__fill {
    background: linear-gradient(90deg, #d1d5db 0%, #9ca3af 100%);
}
.batch-bar__meta {
    margin-top: 8px;
    font-size: 0.78rem;
    color: var(--text-muted);
    line-height: 1.4;
    min-height: 1.1em;
}

/* Во время выполнения batch (нет .is-done/.is-cancelled) — тот же модальный
   оверлей, что и у одиночной проверки (#loading): единый вид прогресса.
   Когда готово/отменено — обычный инлайновый блок-навигатор над результатами. */
.batch-bar:not(.is-done):not(.is-cancelled) {
    position: fixed;
    inset: 0;
    z-index: 1000;
    margin: 0;
    padding: 20px;
    border: none;
    border-radius: 0;
    background: rgba(15, 17, 26, 0.55);
    backdrop-filter: blur(2px);
    display: flex;
    align-items: center;
    justify-content: center;
}
.batch-bar:not(.is-done):not(.is-cancelled) .batch-bar__inner {
    width: 100%;
    max-width: 560px;
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    padding: 28px 32px;
}
/* Когда проверка завершена/отменена — никакого «хода работы» вне модалки:
   полоса прогресса прячется, навигация по моделям остаётся в подвкладках. */
.batch-bar.is-done,
.batch-bar.is-cancelled {
    display: none;
}

/* Per-model subtabs row. Horizontal scroll on overflow — better than wrapping
 * because long IFC names would create tall stacked rows. */
.batch-subtabs {
    display: flex;
    /* Таблетки моделей переносятся в несколько рядов по ширине экрана, а не
       уезжают в горизонтальный скролл — все модели видны сразу, без прокрутки. */
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 16px;
}
.batch-subtab {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: #fff;
    color: var(--text-secondary);
    font-size: 0.86rem;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
    max-width: 240px;
}
.batch-subtab:hover {
    background: var(--border-light);
    color: var(--text);
}
.batch-subtab.is-active {
    background: var(--primary);
    color: #fff;
    border-color: var(--primary);
}
.batch-subtab__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.batch-subtab__icon { width: 14px; height: 14px; flex: 0 0 14px; }
.batch-subtab--done .batch-subtab__icon { color: var(--pass); }
.batch-subtab--failed .batch-subtab__icon { color: var(--fail); }
.batch-subtab--running .batch-subtab__icon,
.batch-subtab--queued .batch-subtab__icon { color: var(--text-muted); }
.batch-subtab.is-active.batch-subtab--done .batch-subtab__icon,
.batch-subtab.is-active.batch-subtab--failed .batch-subtab__icon,
.batch-subtab.is-active.batch-subtab--running .batch-subtab__icon,
.batch-subtab.is-active.batch-subtab--queued .batch-subtab__icon { color: #fff; }

@media (max-width: 768px) {
    .batch-subtab { max-width: 160px; }
}

/* Batch summary table (rendered into #page-overview when 'summary' subtab
 * is selected). Reuses existing card styles, only adds a couple of helpers. */
.batch-summary-table {
    width: 100%;
    border-collapse: collapse;
}
.batch-summary-table th,
.batch-summary-table td {
    padding: 10px 12px;
    text-align: left;
    border-bottom: 1px solid var(--border);
    font-size: 0.88rem;
}
.batch-summary-table th {
    background: var(--border-light);
    font-weight: 600;
    color: var(--text-secondary);
}
.batch-summary-table tr:hover td { background: rgba(50, 82, 123, 0.04); }
.batch-summary-table .num { text-align: right; font-variant-numeric: tabular-nums; }
/* Подсветка ячеек FAIL/WARN/PASS в сводке по моделям (как на «Обзоре») — сразу
   видно, какие модели не прошли. Идёт ПОСЛЕ tr:hover, чтобы держаться и при
   наведении. Срабатывает только когда значение не ноль (класс ставит JS). */
.batch-summary-table td.cell-fail { background: var(--fail-bg); color: var(--fail-text); font-weight: 700; }
.batch-summary-table td.cell-warn { background: var(--warn-bg); color: var(--warn-text); font-weight: 700; }
.batch-summary-table td.cell-pass { color: var(--pass-text); font-weight: 600; }
.batch-summary-table .file-link {
    background: none;
    border: none;
    color: var(--primary);
    cursor: pointer;
    padding: 0;
    text-align: left;
    font: inherit;
}
.batch-summary-table .file-link:hover { text-decoration: underline; }

.batch-summary-block { padding: 16px; }
.batch-summary-block__title {
    margin: 0 0 12px;
    font-size: 1rem;
    color: var(--text);
}

/* Сводный дашборд batch-«Сводки» (вкладка «Детали» → «Сводка»): донат + плитки
 * + «По классам» (агрегат по всем моделям). Детальнее — по подвкладкам файлов. */
.batch-overview-charts { margin: 0 0 16px; }
.batch-overview-tiles-card .asd-tiles { margin: 0; }
.batch-overview-classes { margin: 0 0 20px; }
#batch-details-summary { margin-top: 4px; }

/* When the batch-summary subtab is active, hide the per-file dashboard slots —
 * the summary table replaces them entirely. */
.page.is-batch-summary .report-meta,
.page.is-batch-summary .stats-row,
.page.is-batch-summary .overall-status,
.page.is-batch-summary #absent-panel,
/* Per-model панели относятся к конкретной модели, не к агрегату — в сводке
 * прячем их наравне с #absent-panel, иначе висит устаревшая плашка с одной
 * модели (напр. RUS_FNO), которая «стухает» после захода в per-file отчёт. */
.page.is-batch-summary #unrouted-overview-panel,
.page.is-batch-summary #storey-naming-panel,
.page.is-batch-summary #building-purpose-panel,
.page.is-batch-summary #apartment-rooms-panel,
.page.is-batch-summary .dash-tabs,
.page.is-batch-summary .dash-panel { display: none !important; }

/* Same idea for Actions / Details pages — in summary mode, hide the per-file
 * dashboard widgets; сводка показывает свой агрегат (Actions — дашборд оценки,
 * Details — донат/плитки/классы). Details-виджеты конкретной модели
 * (#specifications и спутники) прячем, иначе под дашбордом висела бы stale-
 * таблица последней открытой модели. */
.page.is-batch-summary #action-summary,
.page.is-batch-summary .action-filter-bar,
.page.is-batch-summary #action-list,
.page.is-batch-summary .filter-bar,
.page.is-batch-summary #summary-cards,
.page.is-batch-summary .results-table-section,
.page.is-batch-summary #specifications,
.page.is-batch-summary #unrouted-section,
.page.is-batch-summary #building-purpose-section,
.page.is-batch-summary #apartment-rooms-section,
.page.is-batch-summary #absent-details-section,
.page.is-batch-summary #skipped-section,
/* «Схема»: в сводке показываем таблицу по всем моделям, а таблицу дублей
 * последней открытой модели прячем — иначе она висит под сводкой как чужая. */
.page.is-batch-summary #schema-check-content,
.page.is-batch-summary #skipped-summary { display: none !important; }

.batch-stub {
    padding: 18px 20px;
    margin-bottom: 16px;
    border-left: 4px solid var(--primary);
}
.batch-stub h3 { color: var(--text); }

/* Context strip that says "Open model: X · [Выгрузить отчёт]": per-model
 * actions for the model that is open right now. */
.batch-active-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    margin-bottom: 16px;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 10px;
    flex-wrap: wrap;
}
.batch-active-actions__label {
    color: var(--text-secondary);
    font-size: 0.88rem;
}
.batch-active-actions__label strong {
    color: var(--text);
    margin-left: 4px;
}
.batch-active-actions__buttons {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}
.batch-active-actions__buttons .btn-secondary {
    padding: 6px 12px;
    font-size: 0.84rem;
}
.batch-active-actions__buttons .btn-secondary svg { width: 14px; height: 14px; }
.batch-active-actions--summary {
    background: var(--border-light);
    border-style: dashed;
}

/* Unified upload progress strip — sticky directly under the global header,
 * positioned to the RIGHT of the sidebar (i.e. only over the main content
 * column, never over user-zone or sidebar navigation). Same component
 * used by both single and batch flows. */
.global-upload {
    position: fixed;
    top: var(--header-height);
    left: var(--sidebar-width);
    right: 0;
    z-index: 9999;
    background: rgba(255, 255, 255, 0.98);
    border-bottom: 1px solid var(--border);
    padding: 8px 18px 10px;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
    backdrop-filter: blur(6px);
}
.global-upload__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 6px;
    font-size: 0.85rem;
}
.global-upload__text {
    color: var(--text);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1 1 auto;
}
.global-upload__percent {
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    flex: 0 0 auto;
}
.global-upload__track {
    height: 3px;
    background: #e9eef5;
    border-radius: 2px;
    overflow: hidden;
}
.global-upload__fill {
    height: 100%;
    width: 0;
    background: linear-gradient(90deg, #5A7BA8 0%, var(--primary) 100%);
    transition: width 0.2s ease;
    border-radius: inherit;
}

/* User zone in the global header — populated by auth.js. Two states:
 *   anonymous → single [Войти] button
 *   logged in → "alice@example.com  [Выйти]"
 * Visible only after auth.js runs (hidden by default to avoid layout
 * shift while Keycloak state is being established). */
.user-zone {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-size: 0.86rem;
}
.user-zone__label {
    color: var(--text-secondary);
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Блок пользователя в шапке: аватар + выпадающая плашка профиля.
 *    Один компонент для обоих продов — фото (jpegPhoto/picture из /userinfo
 *    на контуре Speech) или инициалы (прод Niko). auth.js рендерит. ── */
.user-session {
    position: relative;
    display: flex;
    align-items: center;
    margin-left: 8px;
    padding-left: 8px;
    border-left: 1px solid var(--border-default);
}
.user-avatar {
    width: 38px;
    height: 38px;
    padding: 0;
    border-radius: 50%;
    border: 2px solid #fff;
    box-shadow: 0 0 0 1px var(--border-default);
    background: var(--steel-500);
    color: #fff;
    cursor: pointer;
    overflow: hidden;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    font-weight: 700;
    transition: box-shadow var(--transition);
}
.user-avatar:hover,
.user-avatar[aria-expanded="true"] {
    box-shadow: 0 0 0 2px var(--steel-500);
}
.user-avatar__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.user-avatar__initial { line-height: 1; }

.user-menu {
    position: absolute;
    top: calc(100% + 9px);
    right: 0;
    z-index: 30;
    width: 260px;
    padding: 18px;
    background: var(--bg-surface);
    border: 1px solid var(--border-default);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}
.user-menu__avatar {
    width: 58px;
    height: 58px;
    border-radius: 50%;
    overflow: hidden;
    border: 2px solid #fff;
    box-shadow: 0 0 0 1px var(--border-default);
    background: var(--steel-500);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 22px;
    font-weight: 700;
    margin-bottom: 12px;
}
.user-menu__name {
    font-size: 14px;
    font-weight: 700;
    color: var(--ink-primary);
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.user-menu__email {
    font-size: 12px;
    color: var(--ink-tertiary);
    margin-top: 2px;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.user-menu__logout {
    margin-top: 14px;
    width: 100%;
    padding: 8px 12px;
    background: var(--bg-subtle);
    border: 1px solid var(--border-default);
    border-radius: var(--r-md);
    color: var(--ink-secondary);
    font-size: 13px;
    cursor: pointer;
    transition: var(--transition);
}
.user-menu__logout:hover {
    border-color: var(--steel-500);
    color: var(--steel-700);
}
.user-menu__logout:disabled {
    opacity: 0.6;
    cursor: default;
}

.btn-link {
    background: none;
    border: none;
    color: var(--primary);
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 6px;
    font-size: 0.86rem;
    font-weight: 500;
}
.btn-link:hover {
    background: rgba(50, 82, 123, 0.08);
}

/* Heatmap by-property: имя PSet — отдельная header-row через colspan,
 * чтобы группа явно отделялась от своих свойств. */
.heatmap-table--by-property tr.hm-pset-header td {
    background: var(--bg-subtle, var(--border-light));
    font-weight: 700;
    color: var(--ink-primary, var(--text));
    font-size: 0.85rem;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-left: 3px solid var(--iris-500, var(--primary));
    text-align: left;
}
.heatmap-table--by-property .hm-prop-name {
    color: var(--text-secondary);
    font-size: 0.82rem;
    padding-left: 14px;
}
.heatmap-table--by-property .hm-label {
    min-width: 220px;
    max-width: 320px;
    vertical-align: middle;
}





/* ============================================================
 * G2 step 2: UploadedFileChip — единая карточка загруженного файла
 * ============================================================
 *
 * Используется во всех 4 модулях через uploaded-file-chip.js.
 * Модули различаются `extra` слотом (TEP — RUS_FNO бэйдж и т.д.) —
 * основной layout общий.
 */

/* ── Иконка формата файла — единый примитив FileTypeIcon (вариант C дизайн-
 *    кода): контур документа в цвете формата + подпись расширения. Один вид
 *    во всех модулях (chip загрузки, ТЭП-карточка, АГР). Цвет —
 *    через data-source-kind → токены --fmt-*. Glyph = inline-SVG (не lucide),
 *    поэтому не зависит от lucide.createIcons() и работает в любой разметке. */
.ftype {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    flex-shrink: 0;
    line-height: 1;
}
.ftype__glyph {
    width: 22px;
    height: 22px;
    display: block;
    color: var(--ink-tertiary);   /* fallback до per-kind ниже */
}
.ftype__ext {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.3px;
    white-space: nowrap;
    color: var(--ink-secondary);  /* fallback */
}
.ftype[data-source-kind="ifc"]    .ftype__glyph { color: var(--fmt-ifc-glyph); }
.ftype[data-source-kind="ifc"]    .ftype__ext   { color: var(--fmt-ifc-ink); }
.ftype[data-source-kind="ifczip"] .ftype__glyph { color: var(--fmt-ifczip-glyph); }
.ftype[data-source-kind="ifczip"] .ftype__ext   { color: var(--fmt-ifczip-ink); }
.ftype[data-source-kind="trm"]    .ftype__glyph { color: var(--fmt-trm-glyph); }
.ftype[data-source-kind="trm"]    .ftype__ext   { color: var(--fmt-trm-ink); }
.ftype[data-source-kind="ids"]    .ftype__glyph { color: var(--fmt-ids-glyph); }
.ftype[data-source-kind="ids"]    .ftype__ext   { color: var(--fmt-ids-ink); }
.ftype[data-source-kind="xml"]    .ftype__glyph { color: var(--fmt-xml-glyph); }
.ftype[data-source-kind="xml"]    .ftype__ext   { color: var(--fmt-xml-ink); }

.upl-chip {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border: 1px solid var(--border-default);
    border-radius: var(--r-md);
    /* Плоская плашка — без градиента и inset-глянца (дизайн-код: тихие
     * поверхности, тонкие границы). */
    background: var(--bg-surface);
    margin: 4px 4px 4px 0;
    max-width: 100%;
}
.upl-chip__icon {
    font-size: 1.15rem;
    flex-shrink: 0;
}
.upl-chip__meta {
    display: flex;
    flex-direction: column;
    line-height: 1.2;
    min-width: 0;        /* для truncate */
    flex: 1 1 auto;
}
.upl-chip__name {
    font-weight: 500;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.upl-chip__sub {
    font-size: 0.78rem;
    color: var(--text-muted);
    margin-top: 2px;
}
.upl-chip__kind {
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.upl-chip__size {
    /* nothing — inherits from .upl-chip__sub */
}
.upl-chip__extra {
    /* Метрики = .tep-fno-badge: бейджи ФНО на чипах («Проверка XML») и в
       списках ТЭП — одна сущность, шрифт и размер должны совпадать (0.38.1). */
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    background: var(--border-light);
    color: var(--text-muted);
    white-space: nowrap;
    flex-shrink: 0;
}
.upl-chip__extra.badge-ok {
    background: var(--sage-50);
    color: var(--sage-700);
}
.upl-chip__extra.badge-warn {
    background: var(--sand-50);
    color: var(--sand-700);
}
.upl-chip__remove {
    background: transparent;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 0.95rem;
    padding: 4px 6px;
    border-radius: 4px;
    transition: background var(--transition);
    flex-shrink: 0;
}
.upl-chip__remove:hover {
    background: var(--clay-50);
    color: var(--clay-700);
}

/* Компактный однострочный чип — имя и «тип · размер» в одну строку,
   меньше паддинги. Для batch-списка на главной (много файлов без скролла). */
.upl-chip--compact {
    gap: 8px;
    padding: 5px 9px;
    margin: 0;
}
.upl-chip--compact .upl-chip__icon {
    font-size: 1rem;
}
/* Компактный чип (batch-список): бейдж формата чуть меньше, чтобы строки
   оставались плотными при многих файлах. */
.upl-chip--compact .ftype__glyph { width: 18px; height: 18px; }
.upl-chip--compact .ftype__ext   { font-size: 9px; }
.upl-chip--compact .upl-chip__meta {
    flex-direction: row;
    align-items: baseline;
    gap: 6px;
}
/* Имя занимает свободное место и обрезается многоточием; «тип · размер»
   не сжимается, чтобы остаться целиком на той же строке. */
.upl-chip--compact .upl-chip__name {
    flex: 1 1 auto;
    min-width: 0;
}
.upl-chip--compact .upl-chip__sub {
    margin-top: 0;
    flex-shrink: 0;
    white-space: nowrap;
}
.upl-chip--compact .upl-chip__remove {
    font-size: 0.85rem;
    padding: 2px 4px;
}

/* 0.19.32 sidebar-clear-session removed in v0.19.33 — заменено
 * navigation guard'ом в sidebar.js (intercept перехода между модулями
 * → confirm если файлы загружены → DELETE /api/session → переход). */

/* ============================================================
 * Top loading bar (v0.19.33) — тонкая полоска сверху при переключении
 * вкладок. Дает пользователю мгновенный feedback что click сработал.
 * Управляется sidebar.js → showTopLoadingBar(); auto-hide через 350ms.
 * ============================================================ */
.top-loading-bar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: linear-gradient(
        90deg,
        transparent 0%,
        var(--primary) 25%,
        var(--primary) 75%,
        transparent 100%
    );
    background-size: 200% 100%;
    background-position: 100% 0;
    opacity: 0;
    pointer-events: none;
    z-index: 9999;
    transition: opacity 120ms ease;
}
.top-loading-bar.is-active {
    opacity: 1;
    animation: top-loading-shimmer 800ms linear infinite;
}
@keyframes top-loading-shimmer {
    from { background-position: 100% 0; }
    to   { background-position: -100% 0; }
}

/* ============================================================
 * AGR Автокласс (0.19.110) — стили для /agr
 * ============================================================ */

/* Список pending-файлов (до отправки) */
.agr-files-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.agr-file-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    background: var(--bg-subtle);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
}
/* Файл неподходящей версии схемы IFC (IFC2X3) — красная подсветка строки. */
.agr-file-row--error {
    background: var(--fail-bg);
    border-color: var(--fail);
}
.agr-file-row__main { flex: 1; min-width: 0; }
.agr-file-row__name {
    font-weight: 500;
    color: var(--ink-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.agr-file-row__meta {
    font-size: 12px;
    color: var(--ink-tertiary);
}

/* Inline form-row для формы R3 */
.form-row--inline {
    display: flex;
    gap: var(--space-4);
    flex-wrap: wrap;
    align-items: flex-start;
}
.form-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 160px;
}
.form-field__label {
    font-size: 13px;
    font-weight: 500;
    color: var(--ink-secondary);
}
.form-field__hint {
    font-size: 12px;
    color: var(--ink-tertiary);
}
.form-field--checkbox {
    flex-direction: row;
    align-items: center;
    gap: var(--space-2);
}
.form-field--checkbox .form-field__label { margin-bottom: 0; }
.input-text {
    padding: 8px 12px;
    border: 1px solid var(--border-default);
    border-radius: var(--r-sm);
    background: var(--bg-surface);
    color: var(--ink-primary);
    font-family: inherit;
    font-size: 14px;
}
.input-text:focus {
    outline: none;
    border-color: var(--iris-500);
    box-shadow: 0 0 0 3px var(--iris-50);
}

/* Результаты — карточки файлов */
.agr-results-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-top: var(--space-3);
}
.agr-file-result {
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
    padding: var(--space-3);
    background: var(--bg-surface);
}
.agr-file-result--done   { border-left: 3px solid var(--sage-500); }
.agr-file-result--failed { border-left: 3px solid var(--clay-500); }
.agr-file-result--running { border-left: 3px solid var(--iris-500); }
.agr-file-result--cancelled { border-left: 3px solid var(--ink-tertiary); }

.agr-file-result__header {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
.agr-file-result__main { flex: 1; min-width: 0; }
.agr-file-result__name {
    font-weight: 600;
    color: var(--ink-primary);
}

.agr-progress {
    margin-top: 4px;
    height: 3px;
    background: var(--bg-subtle);
    border-radius: 2px;
    overflow: hidden;
}
.agr-progress__bar {
    height: 100%;
    background: var(--iris-500);
    transition: width 0.2s;
}
.agr-progress__bar.is-indeterminate {
    width: 33% !important;
    animation: agr-indeterminate 1.4s linear infinite;
}
@keyframes agr-indeterminate {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(400%); }
}

.agr-result-summary {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
    font-size: 13px;
    color: var(--ink-secondary);
    align-items: center;
}
.agr-icon-ok    { color: var(--sage-500); }
.agr-icon-fail  { color: var(--clay-500); }
.agr-r44-warn {
    width: 14px;
    height: 14px;
    color: var(--warn-text);
    vertical-align: -2px;
    cursor: help;
}
.agr-error-msg {
    margin-top: var(--space-2);
    padding: var(--space-2);
    background: var(--clay-50);
    color: var(--clay-700);
    border-radius: var(--r-sm);
    font-family: var(--font-mono, monospace);
    font-size: 12px;
}

.agr-artifacts {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-3);
}
.agr-artifact {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    background: var(--bg-subtle);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-sm);
    text-decoration: none;
    color: var(--ink-primary);
    font-size: 13px;
    transition: background var(--transition);
}
.agr-artifact:hover {
    background: var(--iris-50);
    border-color: var(--iris-500);
}

/* Status badges */
.status-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 500;
}
.status-badge--queued   { background: var(--bg-subtle); color: var(--ink-secondary); }
.status-badge--running  { background: var(--iris-50); color: var(--iris-700); }
.status-badge--done     { background: var(--sage-50); color: var(--sage-700); }
.status-badge--failed   { background: var(--clay-50); color: var(--clay-700); }
.status-badge--cancelled{ background: var(--bg-subtle); color: var(--ink-tertiary); }

/* Spinner */
.animate-spin {
    animation: agr-spin 1s linear infinite;
}
@keyframes agr-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

/* AGR Автокласс — модал прогресса: status-классы для fx-apply-item.
   Использует общие fx-modal стили + переопределяет цвета per status. */
.fx-apply-item.is-queued .fx-apply-item__icon { color: var(--ink-tertiary); }
.fx-apply-item.is-running .fx-apply-item__icon {
    color: var(--iris-500);
    animation: agr-spin 1s linear infinite;
}
.fx-apply-item.is-failed .fx-apply-item__icon { color: var(--clay-500); }
.fx-apply-item.is-cancelled .fx-apply-item__icon { color: var(--ink-tertiary); }
.fx-apply-item.is-queued .fx-apply-item__status { color: var(--ink-tertiary); }
.fx-apply-item.is-running .fx-apply-item__status { color: var(--iris-700); }
.fx-apply-item.is-failed .fx-apply-item__status { color: var(--clay-700); }

/* AGR IDS-library — общий picker для AGR/IFC проверка (0.20.8) */
.agr-ids-library {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: var(--space-3);
}
.agr-ids-group-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--ink-tertiary);
    margin: var(--space-2) 0 4px;
}
.agr-ids-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 6px var(--space-2);
    background: var(--bg-subtle);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-sm);
    font-size: 13px;
}
.agr-ids-row__icon { color: var(--ink-tertiary); }
.agr-ids-row__name { flex: 1; color: var(--ink-primary); }
.agr-ids-row__meta { color: var(--ink-tertiary); font-size: 12px; }
.agr-ids-row__badge {
    font-size: 11px;
    background: var(--iris-50);
    color: var(--iris-700);
    padding: 2px 6px;
    border-radius: 4px;
}

/* AGR Параметры объекта — опции в столбик (0.20.10) */
.agr-options {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-top: var(--space-3);
}
.agr-option {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 6px 0;
    cursor: pointer;
    color: var(--ink-primary);
    /* Единый размер метки с .tep-option / опциями на / (было 14px). */
    font-size: 0.95rem;
}
.agr-option input[type="checkbox"] {
    flex-shrink: 0;
    /* Единый размер чекбокса с .input-checkbox (18px, было 16px). */
    width: 18px;
    height: 18px;
    accent-color: var(--iris-500);
}
/* Опция недоступна (напр. R44 при снятой разметке): тускнеет, курсор-запрет. */
.agr-option--disabled {
    opacity: 0.5;
    cursor: not-allowed;
}
.agr-option--disabled input[type="checkbox"] {
    cursor: not-allowed;
}
.agr-option__label {
    flex: 1;
    user-select: none;
}
.agr-option .hint-icon {
    flex-shrink: 0;
    margin-left: auto;
}

/* === AGR режим загрузки «По корпусам» (корзины) === */
.agr-mode-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    flex-wrap: wrap;
}
.agr-mode-hint {
    font-size: 0.85rem;
    color: var(--ink-tertiary);
}
/* Тумблер режима — не sticky (в отличие от внутри-страничных .tep-segments). */
.agr-mode-row .tep-segments {
    position: static;
    align-self: auto;
    top: auto;
}
.agr-baskets {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.agr-basket {
    border: 1px solid var(--border-default);
    border-radius: var(--r-md);
    background: var(--bg-subtle);
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    transition: border-color var(--transition), background var(--transition);
}
/* Подсветка корзины-цели при перетаскивании файла-чипа. */
.agr-basket.is-drag-over {
    border-color: var(--iris-500);
    background: var(--iris-50);
}
.agr-basket__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}
.agr-basket__title {
    font-weight: 600;
    color: var(--ink-primary);
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}
.agr-basket__count {
    font-size: 0.8rem;
    color: var(--ink-tertiary);
    font-weight: 400;
}
.agr-basket__del {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-sm);
    background: var(--bg-surface);
    color: var(--ink-tertiary);
    cursor: pointer;
    transition: all var(--transition);
}
.agr-basket__del:hover {
    border-color: var(--clay-500);
    color: var(--clay-700);
    background: var(--clay-50);
}
.agr-basket__del svg { width: 16px; height: 16px; }
.agr-basket__files {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}
.agr-basket__empty {
    font-size: 0.85rem;
    color: var(--ink-tertiary);
    padding: var(--space-2) 0;
}
/* Компактная строка докидывания файлов в непустую корзину (вместо большой
 * дропзоны — вся карточка остаётся drop-целью). */
.agr-basket__add {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}
.agr-basket__add-hint {
    font-size: 0.8rem;
    color: var(--ink-tertiary);
}
/* Корпус/Секция подставлены из имени файла — пометка у подписи поля. */
.agr-name-auto {
    color: var(--sage-700);
    font-weight: 600;
}
/* Файлы разных корпусов в одной корзине: значение не подставлено. */
.agr-basket__name-hint {
    margin: 0;
    font-size: 0.82rem;
    line-height: 1.4;
    color: var(--warn-text);
}
.agr-file-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-sm);
    background: var(--bg-surface);
    font-size: 0.85rem;
    color: var(--ink-primary);
    cursor: grab;
    max-width: 100%;
}
.agr-file-chip--error {
    background: var(--fail-bg);
    border-color: var(--fail);
}
.agr-file-chip:active { cursor: grabbing; }
.agr-file-chip.is-dragging { opacity: 0.4; }
.agr-file-chip svg { width: 14px; height: 14px; flex-shrink: 0; color: var(--ink-tertiary); }
.agr-file-chip__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 220px;
}
.agr-file-chip__remove {
    display: inline-flex;
    border: none;
    background: transparent;
    color: var(--ink-tertiary);
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
}
.agr-file-chip__remove:hover { color: var(--clay-700); }

/* AGR IDS-cards (0.20.11): нативный <input type="checkbox"> прячется,
   стилизованный __dot становится квадратиком с галочкой (вместо
   круглой radio-точки). Это для multi-select варианта на /agr. */
.ids-radio-card input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
/* Квадратный «чекбокс» вместо круглой radio-точки, если внутри input — checkbox */
.ids-radio-card:has(input[type="checkbox"]) .ids-radio-card__dot {
    border-radius: 4px;
}
.ids-radio-card:has(input[type="checkbox"]) .ids-radio-card__dot::after {
    /* Галочка ✓ через clip-path вместо круглого fill */
    inset: 0;
    background: transparent;
    border-radius: 0;
    /* SVG-галочка как маска */
    background-color: var(--iris-500);
    -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3 8l3.5 3.5L13 4.5' stroke='black' stroke-width='2.2' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / 100% no-repeat;
            mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3 8l3.5 3.5L13 4.5' stroke='black' stroke-width='2.2' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / 100% no-repeat;
    transform: scale(0);
}
.ids-radio-card input[type="checkbox"]:checked + .ids-radio-card__dot {
    border-color: var(--iris-500);
    background: var(--iris-500);
}
.ids-radio-card input[type="checkbox"]:checked + .ids-radio-card__dot::after {
    transform: scale(1);
    background-color: var(--bg-surface);  /* белая галочка на синем фоне */
}
.ids-radio-card:has(input[type="checkbox"]:checked) {
    border-color: var(--iris-500);
    background: var(--iris-50);
}

/* AGR Rules modal (0.20.12) — широкая модалка со скроллом + таблица правил */
.modal--wide { max-width: 880px; width: 90vw; }
.modal-body--scroll {
    max-height: calc(90vh - 100px);
    overflow-y: auto;
}
.agr-rules-group { margin-bottom: var(--space-5); }
.agr-rules-group:last-child { margin-bottom: 0; }
.agr-rules-group__title {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-2);
    padding-bottom: 8px;
    border-bottom: 2px solid var(--iris-50);
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--ink-primary);
}
.agr-rules-group__title svg { width: 16px; height: 16px; color: var(--iris-500); }

.agr-rules-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}
.agr-rules-table td {
    padding: 8px 10px;
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: top;
}
.agr-rules-table tr:last-child td { border-bottom: none; }
.agr-rules-table__code {
    width: 70px;
    font-family: var(--font-mono, monospace);
    font-weight: 600;
    color: var(--iris-700);
    white-space: nowrap;
}
.agr-rules-table__text { color: var(--ink-primary); line-height: 1.5; }
.agr-rules-table__text b { color: var(--clay-700); }

/* =========================================================================
   Статистика использования (/stats)
   ========================================================================= */

/* Переключатель периода */
.stats-range { display: flex; gap: var(--space-1); flex-wrap: wrap; }
.stats-range__btn {
    border: 1px solid var(--border-default);
    background: var(--bg-surface);
    color: var(--ink-secondary);
    border-radius: var(--r-sm);
    padding: var(--space-1) var(--space-3);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: var(--transition);
}
.stats-range__btn:hover { border-color: var(--iris-500); color: var(--ink-primary); }
.stats-range__btn.is-active {
    background: var(--iris-500);
    border-color: var(--iris-500);
    color: #fff;
}
/* Активный период (ДД.ММ.ГГ — ДД.ММ.ГГ): слева от плашек, а сам блок
   «даты + плашки» прижат вправо (margin-left:auto). */
.stats-period-range {
    align-self: center;
    margin-left: auto;
    font-size: 0.82rem;
    color: var(--ink-tertiary);
    white-space: nowrap;
}

/* KPI-карточки */
.stats-kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}
.stats-kpi {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    padding: var(--space-4);
    box-shadow: var(--shadow);
}
.stats-kpi__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--r-md);
    background: var(--iris-50);
    color: var(--iris-700);
    flex-shrink: 0;
}
.stats-kpi__icon i { width: 20px; height: 20px; }
.stats-kpi__value { font-size: 22px; font-weight: 700; color: var(--ink-primary); line-height: 1.1; }
.stats-kpi__label { font-size: 12px; color: var(--ink-tertiary); margin-top: 2px; }

/* Горизонтальные бары (по типам) */
.stats-bars { display: flex; flex-direction: column; gap: var(--space-2); }
.stats-bar { display: grid; grid-template-columns: 160px 1fr 56px; align-items: center; gap: var(--space-3); }
.stats-bar__label { font-size: 13px; color: var(--ink-secondary); }
.stats-bar__track { background: var(--bg-subtle); border-radius: var(--r-sm); height: 10px; overflow: hidden; }
.stats-bar__fill { height: 100%; background: var(--iris-500); border-radius: var(--r-sm); transition: width var(--transition); }
.stats-bar__value { font-size: 13px; font-weight: 600; color: var(--ink-primary); text-align: right; }
/* «Статистика → Сервер»: уровень заполнения по порогам 70 / 90 %. */
.stats-bar__fill--ok { background: var(--sage-500); }
.stats-bar__fill--warn { background: var(--sand-500); }
.stats-bar__fill--danger { background: var(--clay-500); }
.stats-server-meter { min-width: 140px; }
.stats-server-note { font-size: 12px; color: var(--ink-tertiary); margin: var(--space-2) 2px 0; }

/* Heatmap */
.stats-heatmap { overflow-x: auto; }
.stats-heatmap__grid {
    display: grid;
    grid-template-columns: 32px repeat(24, 1fr);
    gap: 3px;
    min-width: 640px;
}
.stats-heatmap__hour { font-size: 10px; color: var(--ink-tertiary); text-align: center; }
.stats-heatmap__day { font-size: 11px; color: var(--ink-secondary); display: flex; align-items: center; }
.stats-heatmap__cell {
    /* Высота не фиксирована: ячейки тянутся по строкам грида, чтобы heatmap
       заполнял высоту карточки вровень с боксом «Доп. показатели» справа. */
    min-height: 18px;
    border-radius: 3px;
    background: var(--bg-subtle);
    border: 1px solid var(--border-subtle);
}

/* Активность: heatmap (слева) + бокс «Доп. показатели» (справа) — одна строка,
   две равновысокие карточки (align-items: stretch у grid-строки). */
.stats-activity-row {
    display: grid;
    /* «Доп. показатели» чуть шире (значение + дельта тренда в одну строку). */
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: var(--space-4);
    align-items: stretch;
}
@media (max-width: 1024px) { .stats-activity-row { grid-template-columns: 1fr; } }

/* heatmap тянется на всю высоту карточки (карточка — flex-колонка),
   строки грида делят высоту поровну → ячейки крупные, место заполнено. */
.stats-activity-row .stats-heatmap { flex: 1 1 auto; min-height: 0; }
.stats-activity-row .stats-heatmap__grid {
    height: 100%;
    grid-template-rows: auto repeat(7, minmax(26px, 1fr));
}

.stats-summary { display: flex; flex-direction: column; gap: var(--space-4); }
.stats-summary__group { display: flex; flex-direction: column; gap: var(--space-2); }
.stats-summary__title {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ink-tertiary);
}
.stats-summary__row {
    display: grid;
    grid-template-columns: 40px 1fr auto;
    align-items: center;
    gap: var(--space-2);
}
.stats-summary__label { font-size: 12px; color: var(--ink-secondary); font-variant-numeric: tabular-nums; }
.stats-summary__track { background: var(--bg-subtle); border-radius: var(--r-sm); height: 8px; overflow: hidden; }
.stats-summary__fill { display: block; height: 100%; background: var(--iris-500); border-radius: var(--r-sm); }
.stats-summary__val {
    font-size: 12px;
    font-weight: 600;
    color: var(--ink-primary);
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.stats-summary__fact {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--space-2);
    font-size: 12px;
}
.stats-summary__fact-k { color: var(--ink-tertiary); white-space: nowrap; }
.stats-summary__fact-v {
    color: var(--ink-primary);
    font-weight: 600;
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;   /* значение + дельта в одну строку (бокс шире) */
}
/* Дневная дельта тренда рядом со значением: ↑ зелёным / ↓ красным. */
.stats-summary__delta {
    margin-left: var(--space-1);
    font-weight: 600;
    font-size: 11px;
}
.stats-summary__delta--up { color: var(--sage-500); }
.stats-summary__delta--down { color: var(--clay-500); }
.stats-summary__delta--flat { color: var(--ink-tertiary); }

/* Timeline (вертикальные бары по дням) */
.stats-timeline__chart { display: flex; gap: var(--space-2); }
/* Ось Y: подписи max / середина / 0, прижатые к линиям сетки (та же высота). */
.stats-timeline__yaxis {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: flex-end;
    height: 180px;
    font-size: 10px;
    line-height: 1;
    color: var(--ink-tertiary);
    font-variant-numeric: tabular-nums;
}
/* min-width: 0 — позволяет колонкам сжиматься: бары всегда влезают в ширину
   блока, горизонтального скролла нет независимо от числа дней. */
.stats-timeline__plotwrap { flex: 1 1 auto; min-width: 0; }
.stats-timeline__plot { position: relative; height: 180px; }
/* Пунктирные линии сетки — максимально прозрачные, это фон, не акцент. */
.stats-timeline__grid {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    pointer-events: none;
}
.stats-timeline__grid i {
    display: block;
    height: 0;
    border-top: 1px dashed var(--iris-500);
    opacity: 0.12;
}
.stats-timeline__bars { position: relative; display: flex; align-items: flex-end; gap: 2px; height: 100%; }
.stats-timeline__col { flex: 1 1 0; min-width: 0; height: 100%; display: flex; align-items: flex-end; }
.stats-timeline__bar { width: 100%; min-height: 2px; background: var(--iris-500); border-radius: 2px 2px 0 0; }
/* Подписи под барами — те же flex-колонки, ровно под столбцами. Прорежены в
   JS (~12), горизонтальные: влезают без поворота и без скролла. */
.stats-timeline__ticks { display: flex; gap: 2px; margin-top: 4px; }
.stats-timeline__tick {
    flex: 1 1 0;
    min-width: 0;
    font-size: 9px;
    color: var(--ink-tertiary);
    text-align: center;
    white-space: nowrap;
    overflow: visible;
    font-variant-numeric: tabular-nums;
}

/* Отступ между блоками статистики (иначе .fixer-step идут впритык) */
.body--stats .fixer-step,
.body--stats .stats-two-col { margin-bottom: var(--space-4); }

/* Две таблицы рядом */
.stats-two-col { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
@media (max-width: 1024px) { .stats-two-col { grid-template-columns: 1fr; } }

.stats-table-wrap { overflow-x: auto; }
/* Прокрутка внутри блока, когда строк много (по пользователям / проектам).
   Шапка залипает сверху при скролле. */
.stats-table-wrap--scroll { max-height: 420px; overflow-y: auto; }
.stats-table-wrap--scroll thead th {
    position: sticky;
    top: 0;
    background: var(--bg-surface);
    z-index: 1;
}
.stats-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.stats-table th {
    text-align: left;
    font-weight: 600;
    color: var(--ink-tertiary);
    border-bottom: 1px solid var(--border-default);
    padding: var(--space-2);
    white-space: nowrap;
}
.stats-table td {
    padding: var(--space-2);
    border-bottom: 1px solid var(--border-subtle);
    color: var(--ink-primary);
}
.stats-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.stats-empty { color: var(--ink-tertiary); font-size: 13px; padding: var(--space-3); text-align: center; }

/* ---- Drill-down: воркеры, сегменты, фильтры, события, модалка ---- */

/* Виджет воркеров */
.stats-workers {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}
.stats-workers__item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
    padding: var(--space-2) var(--space-3);
    font-size: 13px;
    color: var(--ink-secondary);
}
.stats-workers__item i { width: 16px; height: 16px; }
.stats-workers__item b { color: var(--ink-primary); }
.stats-workers__item--ok { border-color: var(--sage-500); }
.stats-workers__item--busy { border-color: var(--iris-500); }
.stats-workers__item--warn { border-color: var(--sand-500); }
.stats-workers__item--off { color: var(--ink-tertiary); }
.stats-workers__item--job { border-color: var(--iris-500); }
/* Прогресс живой задачи в модалке очереди (/stats). */
.stats-progress { min-width: 200px; }
.stats-progress__bar { height: 6px; border-radius: 3px; background: var(--bg-subtle); overflow: hidden; }
.stats-progress__fill { height: 100%; background: var(--iris-500); transition: width var(--transition); }
.stats-progress__meta { font-size: 12px; color: var(--ink-secondary); margin-top: 4px; }
.stats-progress__meta b { color: var(--ink-primary); }
.stats-progress__age { font-size: 11px; color: var(--ink-tertiary); }
.stats-progress--stale .stats-progress__fill { background: var(--sand-500); }
.stats-progress--stale .stats-progress__age { color: var(--sand-700); }
.stats-progress--none { color: var(--ink-tertiary); }

/* Тулбар: сегменты + период */
.stats-toolbar {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}
.stats-segments { display: flex; gap: var(--space-1); }
.stats-segment {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    border: 1px solid var(--border-default);
    background: var(--bg-surface);
    color: var(--ink-secondary);
    border-radius: var(--r-sm);
    padding: var(--space-2) var(--space-4);
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: var(--transition);
}
.stats-segment i { width: 16px; height: 16px; }
.stats-segment:hover { color: var(--ink-primary); }
.stats-segment.is-active {
    background: var(--iris-50);
    border-color: var(--iris-500);
    color: var(--iris-700);
}

/* Фильтр-бар */
.stats-filterbar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
}
.stats-filterbar .input-select,
.stats-filterbar .input-search { min-width: 180px; }

/* Бейджи статуса событий (на базе .badge + status-токены) */
.badge--ok { background: var(--pass-bg); color: var(--pass-text); }
.badge--fail { background: var(--fail-bg); color: var(--fail-text); }
.badge--warn { background: var(--warn-bg); color: var(--warn-text); }
.badge--error { background: var(--clay-500); color: #fff; }

/* Кликабельные строки таблиц */
.stats-table--hover tbody tr { cursor: pointer; }
.stats-row--click { cursor: pointer; }
.stats-row--click:hover { background: var(--bg-subtle); }
.stats-row--error { background: var(--clay-50); }
.stats-err {
    color: var(--clay-700);
    font-size: 12px;
    max-width: 320px;
    display: inline-block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}

/* Пагинация */
.stats-pager { display: flex; gap: var(--space-2); justify-content: flex-end; margin-top: var(--space-3); }

/* Модалка детали события */
.fx-modal--wide { max-width: 900px; width: 92vw; }
.stats-event-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    font-size: 13px;
    color: var(--ink-secondary);
    margin-bottom: var(--space-4);
}
.stats-event-meta b { color: var(--ink-tertiary); font-weight: 600; }
.stats-samples { display: flex; flex-wrap: wrap; gap: 4px; }
.guid-chip {
    font-family: var(--font-mono, monospace);
    font-size: 11px;
    background: var(--bg-subtle);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-sm);
    padding: 1px 6px;
    cursor: pointer;
    color: var(--ink-secondary);
}
.guid-chip:hover { border-color: var(--iris-500); color: var(--iris-700); }

/* «N файлов» с подсказкой при наведении */
.stats-multifile { border-bottom: 1px dashed var(--border-default); cursor: help; }

/* Плашка воркеров — кликабельная (модалка с деталями задач) */
.stats-workers { cursor: pointer; }
.stats-workers__item { transition: var(--transition); }
.stats-workers:hover .stats-workers__item { border-color: var(--iris-500); }

/* Заголовки секций в модалке очереди */
.stats-modal-h { margin: var(--space-4) 0 var(--space-2); font-size: 14px; font-weight: 600; color: var(--ink-secondary); }
.stats-modal-h:first-child { margin-top: 0; }
.stats-worker-list { list-style: none; padding: 0; margin: 0; font-size: 13px; }
.stats-worker-list li { padding: 4px 0; border-bottom: 1px solid var(--border-subtle); color: var(--ink-primary); }
.stats-worker-list li:last-child { border-bottom: none; }
.stats-modal-live { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink-tertiary); margin: 0 0 var(--space-3); }
.stats-live-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--sage-500); animation: statsLivePulse 1.4s ease-in-out infinite; }
.stats-job-actions { text-align: right; white-space: nowrap; }
.stats-badge { display: inline-block; padding: 2px 8px; border-radius: var(--r-sm); font-size: 12px; }
.stats-badge--cancel { background: var(--sand-50); color: var(--sand-700); }
@keyframes statsLivePulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }

/* ===========================================================================
 * Режим «По разделам» на главной (sections-ui.js): тумблер, «Параметры
 * проверки» на всю ширину (3 колонки), карточки наборов (IFC | IDS-чекбоксы),
 * бейдж набора в сводке.
 * =========================================================================== */

/* Тумблер режима — тот же паттерн, что .agr-mode-row (не sticky). */
.check-mode-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    flex-wrap: wrap;
}
.check-mode-row .tep-segments {
    position: static;
    align-self: auto;
    top: auto;
}
.check-mode-hint {
    font-size: 0.85rem;
    color: var(--ink-tertiary);
}

/* «Параметры проверки» на всю ширину + 3 колонки чекбоксов (общие для наборов). */
.controls-box--wide {
    margin-bottom: var(--space-4);
    padding: var(--space-5);
}
.controls-box__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-2) var(--space-5);
    margin-top: var(--space-2);
}
@media (max-width: 768px) {
    .controls-box__grid { grid-template-columns: 1fr; }
}
/* «Выбрать все» — справа в шапке блока: подчинённая заголовку подпись. */
.controls-box__select-all {
    font-size: 0.82rem;
    color: var(--ink-tertiary);
    gap: var(--space-2);
    white-space: nowrap;
}

/* Карточка набора — подложка как .agr-basket, внутри 2 колонки IFC | IDS. */
.sections-block { margin-bottom: var(--space-2); }
/* Карточка набора — на белой подложке, как боксы в «Общем» (.file-split-card):
 * bg-surface + border-subtle + r-lg. */
.section-card {
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-lg);
    background: var(--bg-surface);
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.section-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}
.section-card__title {
    font-weight: 600;
    color: var(--ink-primary);
}
.section-card__del {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-sm);
    background: var(--bg-surface);
    color: var(--ink-tertiary);
    cursor: pointer;
    transition: all var(--transition);
}
.section-card__del:hover:not(:disabled) {
    border-color: var(--clay-500);
    color: var(--clay-700);
    background: var(--clay-50);
}
.section-card__del:disabled { opacity: 0.4; cursor: not-allowed; }
.section-card__del svg { width: 16px; height: 16px; }
.section-card__body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-4);
    /* stretch: обе колонки одной высоты → дроп-зона слева тянется под правую
     * IDS-панель (симметрия, как в «Общем»). */
    align-items: stretch;
}
@media (max-width: 768px) {
    .section-card__body { grid-template-columns: 1fr; }
}
.section-card__ifc,
.section-card__ids {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
}
/* Дроп-зона занимает всю высоту левой колонки (которая растянута под правую). */
.section-card__ifc .drop-zone {
    flex: 1;
    min-height: 150px;
}
.section-card__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}
.section-card__upload { align-self: flex-start; }
/* Список IDS набора растёт по содержимому — без внутреннего скролла (карточка
 * набора и так на всю ширину/высоту). Перекрывает max-height/overflow базового
 * .ids-radio-list. */
.section-card__ids-list {
    max-height: none;
    overflow: visible;
}

/* Чекбокс-вариант карты IDS (мульти-выбор на набор): зеркалит .ids-radio-card,
 * но с квадратным чек-боксом вместо радио-точки. */
.ids-check-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 12px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
    background: var(--bg-surface);
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition);
}
.ids-check-card:hover {
    border-color: var(--iris-100);
    background: var(--iris-50);
}
.ids-check-card input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.ids-check-card__box {
    width: 16px;
    height: 16px;
    border-radius: 4px;
    border: 1.5px solid var(--border-default);
    background: var(--bg-surface);
    flex-shrink: 0;
    position: relative;
    transition: border-color var(--transition), background var(--transition);
}
.ids-check-card__box::after {
    content: '';
    position: absolute;
    left: 4px;
    top: 1px;
    width: 5px;
    height: 9px;
    border: solid #fff;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg) scale(0);
    transition: transform var(--transition);
}
.ids-check-card input[type="checkbox"]:checked + .ids-check-card__box {
    border-color: var(--iris-500);
    background: var(--iris-500);
}
.ids-check-card input[type="checkbox"]:checked + .ids-check-card__box::after {
    transform: rotate(45deg) scale(1);
}
.ids-check-card:has(input[type="checkbox"]:checked) {
    border-color: var(--iris-500);
    background: var(--iris-50);
}
.ids-check-card__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1;
}
.ids-check-card__name {
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--ink-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.ids-check-card__meta {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    color: var(--ink-tertiary);
    display: flex;
    align-items: center;
    gap: 8px;
}
.ids-check-card__badge {
    display: inline-flex;
    align-items: center;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--iris-50);
    border: 1px solid var(--iris-100);
    color: var(--iris-700);
    font-family: var(--font-sans, inherit);
    font-size: 0.68rem;
}

/* Бейдж набора в сводке batch-таблицы («по разделам»). */
.set-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--iris-50);
    border: 1px solid var(--iris-100);
    color: var(--iris-700);
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}

/* ===========================================================================
 * Дашборд оценки в batch-«Сводке» на вкладке «Что исправить»
 * (renderActionBatchSummary): общая оценка + плитки + таблица по моделям.
 * =========================================================================== */
#action-batch-summary { margin-bottom: var(--space-4); }
.asd {
    display: flex;
    gap: var(--space-4);
    flex-wrap: wrap;
    align-items: stretch;
    margin-bottom: var(--space-4);
}
.asd-score {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-width: 150px;
    padding: var(--space-4) var(--space-5);
    border-radius: var(--r-lg);
    border: 1px solid var(--border-subtle);
    background: var(--bg-surface);
}
.asd-score__value { font-size: 2.6rem; font-weight: 800; line-height: 1; }
.asd-score__label { font-size: 0.8rem; color: var(--ink-tertiary); margin-top: 6px; }
.asd-score--ok   .asd-score__value { color: var(--pass-text); }
.asd-score--warn .asd-score__value { color: var(--warn-text); }
.asd-score--fail .asd-score__value { color: var(--fail-text); }
.asd-tiles {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-3);
    flex: 1;
    min-width: 260px;
}
@media (max-width: 768px) { .asd-tiles { grid-template-columns: repeat(2, 1fr); } }
.asd-tile {
    padding: var(--space-4);
    border-radius: var(--r-md);
    border: 1px solid var(--border-subtle);
    background: var(--bg-surface);
    display: flex;
    flex-direction: column;
    justify-content: center;
}
.asd-tile__v { font-size: 1.6rem; font-weight: 700; color: var(--ink-primary); }
.asd-tile__l { font-size: 0.78rem; color: var(--ink-tertiary); margin-top: 4px; }
.asd-tile--ok   .asd-tile__v { color: var(--pass-text); }
.asd-tile--fail .asd-tile__v { color: var(--fail-text); }
.asd-tile--warn .asd-tile__v { color: var(--warn-text); }
.asd-models-title { font-size: 1rem; font-weight: 700; margin: 0 0 var(--space-2); color: var(--ink-primary); }
.asd-chip {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-weight: 700;
    font-size: 0.8rem;
}
.asd-chip--ok   { background: var(--pass-bg); color: var(--pass-text); }
.asd-chip--warn { background: var(--warn-bg); color: var(--warn-text); }
.asd-chip--fail { background: var(--fail-bg); color: var(--fail-text); }

/* ─── Выгрузка отчёта «Что исправить» (0.36.0) ─────────────────────────────
 * Три блока: (1) шапка страницы с кнопкой выгрузки — на живой странице;
 * (2) .report-export* — шапка и обёртка САМОГО выгруженного HTML (правила
 * дремлют на главной, активны в офлайн-файле, куда style.css инлайнится);
 * (3) .rex-modal* — модалка формирования (показывается на живой странице). */

/* (1) Шапка «Что исправить» с кнопкой справа. */
.page-header--with-action {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}

/* (2) Обёртка и шапка выгруженного документа. */
body.report-export {
    padding: 0;
    background: var(--bg);
    color: var(--ink-primary);
    /* Базовый body — app-shell: overflow:hidden + height:100vh, скроллится
     * .main-content. В выгрузке .main-content-скроллера нет, поэтому content
     * ниже экрана был недоступен. Возвращаем обычный документный скролл. */
    overflow: auto;
    height: auto;
}
.report-export__header {
    padding: var(--space-5) var(--space-6);
    border-bottom: 1px solid var(--border-default);
    background: var(--bg-surface);
}
.report-export__brand {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}
.report-export__title {
    font-size: var(--section-title-lg);
    font-weight: var(--section-title-weight);
    color: var(--ink-primary);
}
.report-export__company {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--iris-500);
    letter-spacing: 0.04em;
}
.report-export__subject {
    margin-top: var(--space-2);
    font-size: 0.95rem;
    color: var(--ink-secondary);
}
.report-export__madeby {
    margin-top: var(--space-2);
    font-size: 0.78rem;
    color: var(--ink-tertiary);
}
.report-export__body {
    padding: var(--space-5) var(--space-6);
    max-width: 1400px;
    margin: 0 auto;
}
/* Секцию #page-actions в выгрузке НЕ анимируем и не смещаем — она вне
 * .main-content, transform/opacity из .page здесь не нужны. */
.report-export .page.report-export__page {
    opacity: 1;
    transform: none;
    transition: none;
}
/* Строки результатов кликабельны только в веб-приложении (openElementPanel там
 * тянет PSets с сервера). В офлайн-файле клик даёт лишь тост — не рекламируем
 * интеракцию: убираем pointer-курсор и hover-подсветку. */
body.report-export .result-row.clickable { cursor: default; }
body.report-export .result-row.clickable:hover td { background: inherit; }

/* (3) Модалка формирования отчёта. */
.rex-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: blur(2px);
    padding: var(--space-4);
}
.rex-modal__card {
    width: min(460px, 100%);
    background: var(--bg-surface);
    border: 1px solid var(--border-default);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-5);
}
.rex-modal__title {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--ink-primary);
    margin-bottom: var(--space-4);
}
.rex-modal__track {
    height: 8px;
    border-radius: 999px;
    background: var(--bg-subtle);
    overflow: hidden;
}
.rex-modal__fill {
    height: 100%;
    width: 0;
    border-radius: 999px;
    background: var(--iris-500);
    transition: width var(--transition);
}
.rex-modal.is-done .rex-modal__fill,
.rex-modal-overlay.is-done .rex-modal__fill { background: var(--sage-500); }
.rex-modal-overlay.is-error .rex-modal__fill { background: var(--clay-500); }
.rex-modal__status {
    margin-top: var(--space-3);
    font-size: 0.85rem;
    color: var(--ink-secondary);
    min-height: 1.2em;
    word-break: break-word;
}
.rex-modal__actions {
    margin-top: var(--space-4);
    display: flex;
    gap: var(--space-3);
    justify-content: flex-end;
}

/* Дата редакции IDS («от 07.09.2026») — мелко и приглушённо рядом с именем спеки */
.ids-check-card__date,
.ids-radio-card__date {
    white-space: nowrap;
    font-family: var(--font-sans, inherit);
    font-size: 0.68rem;
    color: var(--ink-tertiary);
}
.report-ids-date,
.spec-group__date {
    font-size: 0.78em;
    font-weight: 400;
    color: var(--ink-tertiary);
    white-space: nowrap;
}
