/* PF-UI-v1 — платформенный слой оформления Marketplace Platform.
 *
 * Отдаётся шлюзом (/platform/pf.css) и инжектится в </head> КАЖДОЙ страницы
 * всех 13 сервисов одной строкой sub_filter — см. gateway/nginx.conf.
 * Поэтому файл стоит в каскаде ПОСЛЕ всех <style> сервисов и может
 * перенастраивать их переменные, не трогая их шаблоны.
 *
 * Секции (порядок важен):
 *   1. tokens     — единственный источник цвета/радиуса/тени/типографики
 *   2. bridge     — старые токены сервисов → платформенные (унификация без правок)
 *   3. base       — аддитивно поверх Bootstrap, ТОЛЬКО через --bs-*
 *   4. components — новые имена pf-* (ничего чужого не переопределяется)
 *
 * Правила слоя:
 *   - класс Bootstrap никогда не переопределяется селектором, только его --bs-*;
 *   - каждый статус несёт не-цветовой канал (глиф), иначе смысл теряется при
 *     дальтонизме и в оттенках серого;
 *   - тема только светлая (решение владельца 2026-09-05), но токены готовы к
 *     light-dark(): переход = правка одного блока :root.
 *
 * Бренд подключается ОТДЕЛЬНЫМ файлом brand.css (грузится следом) — он
 * переопределяет только --pf-accent*, --pf-mp-*, --pf-brand-*.
 */

/* ═══════════════════════ 1. TOKENS ═══════════════════════ */

:root {
    color-scheme: light;

    /* --- Шкала серого (slate). Уже де-факто общая для hypothesis/supply/offline --- */
    --pf-gray-50:  #f8fafc;
    --pf-gray-100: #f1f5f9;
    --pf-gray-200: #e2e8f0;
    --pf-gray-300: #cbd5e1;
    --pf-gray-400: #94a3b8;
    --pf-gray-500: #64748b;
    --pf-gray-600: #475569;
    --pf-gray-700: #334155;
    --pf-gray-800: #1e293b;
    --pf-gray-900: #0f172a;

    /* --- Акцент. Placeholder до появления бренда FORSAL; AA 5.17:1 на белом.
           Переопределяется ТОЛЬКО в brand.css. --- */
    --pf-accent:       #2563eb;
    --pf-accent-rgb:   37, 99, 235;
    --pf-accent-hover: #1d4ed8;
    --pf-accent-soft:  #eff6ff;

    /* --- Семантика. Пары text/bg: text — для надписей на светлом (все ≥ 4.5:1),
           bg — заливка плашек, текст на ней берётся из -text того же ряда. --- */
    --pf-ok-text:   #15803d;  --pf-ok-bg:   #dcfce7;  --pf-ok-line:   #86efac;
    --pf-warn-text: #b45309;  --pf-warn-bg: #fef3c7;  --pf-warn-line: #fcd34d;
    --pf-bad-text:  #b91c1c;  --pf-bad-bg:  #fee2e2;  --pf-bad-line:  #fca5a5;
    --pf-info-text: #1d4ed8;  --pf-info-bg: #dbeafe;  --pf-info-line: #93c5fd;

    /* --- Поверхности --- */
    --pf-surface:        #ffffff;
    --pf-surface-muted:  var(--pf-gray-50);
    --pf-surface-raised: var(--pf-gray-100);
    --pf-body-bg:        var(--pf-gray-100);
    --pf-border:         var(--pf-gray-200);
    --pf-border-strong:  var(--pf-gray-300);
    --pf-text:           var(--pf-gray-800);
    /* не --pf-gray-500 (#64748b): 4.34 на сером холсте — ниже AA.
       #5b6a7d проходит на всех трёх поверхностях: 5.52 / 5.28 / 5.04 */
    --pf-text-muted:     #5b6a7d;

    /* --- Площадки. Только бейджи, легенды графиков и маркеры — не фон блоков.
           Значения подобраны так, чтобы -ink давал AA на своём -soft. --- */
    --pf-mp-wb:        #7c3aed;  --pf-mp-wb-ink:   #6d28d9;  --pf-mp-wb-soft:   #f5f3ff;
    --pf-mp-ozon:      #1d4ed8;  --pf-mp-ozon-ink: #1e40af;  --pf-mp-ozon-soft: #eff6ff;
    --pf-mp-ym:        #d92f10;  --pf-mp-ym-ink:   #b91c1c;  --pf-mp-ym-soft:   #fef2f2;
    --pf-mp-offline:   #0f766e;  --pf-mp-offline-ink: #115e59; --pf-mp-offline-soft: #f0fdfa;

    /* --- Форма. Три радиуса и три тени — вместо 28 и 98 значений вразнобой. --- */
    --pf-radius-sm: 4px;
    --pf-radius:    8px;
    --pf-radius-lg: 12px;
    --pf-radius-pill: 999px;
    --pf-shadow-1: 0 1px 2px rgba(15, 23, 42, .06);
    --pf-shadow-2: 0 1px 3px rgba(15, 23, 42, .10);
    --pf-shadow-3: 0 4px 12px rgba(15, 23, 42, .08);
    /* Слой НАД полотном: модалка, выпадающая панель, карточка входа.
       Раньше каждая такая поверхность придумывала свою тень. */
    --pf-shadow-overlay: 0 8px 24px rgba(15, 23, 42, .18);

    /* --- Ритм --- */
    --pf-space-1: 4px;  --pf-space-2: 8px;  --pf-space-3: 12px;
    --pf-space-4: 16px; --pf-space-5: 24px; --pf-space-6: 32px;

    /* --- Типографика. Шрифты self-host (см. @font-face ниже). --- */
    --pf-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif;
    --pf-font-mono: "JetBrains Mono", ui-monospace, "Cascadia Code", Consolas, monospace;
    --pf-fs-xs: .75rem;
    --pf-fs-sm: .8125rem;
    --pf-fs-md: .875rem;
    --pf-fs-lg: 1rem;
    --pf-fs-xl: 1.25rem;
    --pf-fs-2xl: 1.5rem;

    /* --- Слои. Тосты и диалоги живут в top-layer, им z-index не нужен. --- */
    --pf-z-sticky:  20;
    --pf-z-nav:   1000;
    --pf-z-overlay: 1050;
}

/* Шрифты — self-host. Google Fonts из РФ отдаёт ~700 мс на первый рендер, а
   инжектируемый слой не должен зависеть от внешней сети. Подмножества латиницы
   и кириллицы разведены через unicode-range: браузер качает только нужное
   (кириллический файл Inter — 7.7 КБ против 24 КБ латинского).
   Символы-глифы статусов (▲▼✓) в подмножества не входят и берутся из системного
   шрифта — это осознанно, они одинаковы во всех ОС. */
@font-face {
    font-family: "Inter";
    src: url("/platform/fonts/inter-cyrillic-400-normal.woff2") format("woff2");
    font-weight: 400; font-style: normal; font-display: swap;
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-family: "Inter";
    src: url("/platform/fonts/inter-latin-400-normal.woff2") format("woff2");
    font-weight: 400; font-style: normal; font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Inter";
    src: url("/platform/fonts/inter-cyrillic-500-normal.woff2") format("woff2");
    font-weight: 500; font-style: normal; font-display: swap;
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-family: "Inter";
    src: url("/platform/fonts/inter-latin-500-normal.woff2") format("woff2");
    font-weight: 500; font-style: normal; font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Inter";
    src: url("/platform/fonts/inter-cyrillic-600-normal.woff2") format("woff2");
    font-weight: 600; font-style: normal; font-display: swap;
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-family: "Inter";
    src: url("/platform/fonts/inter-latin-600-normal.woff2") format("woff2");
    font-weight: 600; font-style: normal; font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Inter";
    src: url("/platform/fonts/inter-cyrillic-700-normal.woff2") format("woff2");
    font-weight: 700; font-style: normal; font-display: swap;
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-family: "Inter";
    src: url("/platform/fonts/inter-latin-700-normal.woff2") format("woff2");
    font-weight: 700; font-style: normal; font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "JetBrains Mono";
    src: url("/platform/fonts/jbmono-cyrillic-400-normal.woff2") format("woff2");
    font-weight: 400; font-style: normal; font-display: swap;
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-family: "JetBrains Mono";
    src: url("/platform/fonts/jbmono-latin-400-normal.woff2") format("woff2");
    font-weight: 400; font-style: normal; font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "JetBrains Mono";
    src: url("/platform/fonts/jbmono-cyrillic-500-normal.woff2") format("woff2");
    font-weight: 500; font-style: normal; font-display: swap;
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-family: "JetBrains Mono";
    src: url("/platform/fonts/jbmono-latin-500-normal.woff2") format("woff2");
    font-weight: 500; font-style: normal; font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ═══════════════════════ 2. BRIDGE ═══════════════════════
 *
 * Сервисы объявляют свои токены в собственных <style>/css. Инъекция идёт
 * последней, поэтому переопределение здесь красит ВСЕ страницы разом — до
 * того, как мы дойдём до правок шаблонов волнами A–E.
 *
 * Каждая строка удаляется, когда сервис перестаёт объявлять свой токен.
 * Всё, что здесь стоит — это ровно те имена, что реально встречаются в коде
 * (hypothesis/auth base.html, supply ds.css + base.html, offline of-ds.css,
 * finmodel app.css, costing app.css).
 */

:root {
    /* -- hypothesis + auth base.html -- */
    --gray-50:  var(--pf-gray-50);
    --gray-100: var(--pf-gray-100);
    --gray-200: var(--pf-gray-200);
    --gray-300: var(--pf-gray-300);
    --gray-400: var(--pf-gray-400);
    --gray-500: var(--pf-gray-500);
    --gray-600: var(--pf-gray-600);
    --gray-700: var(--pf-gray-700);
    --gray-800: var(--pf-gray-800);
    --gray-900: var(--pf-gray-900);

    --primary:       var(--pf-accent);
    --primary-dark:  var(--pf-accent-hover);
    --primary-light: color-mix(in srgb, var(--pf-accent) 55%, #fff);
    --primary-color: var(--pf-accent);          /* stock-monitoring */
    --secondary:     var(--pf-info-text);
    --dark:          var(--pf-gray-800);

    /* Семантика: платформенные значения проходят AA на белом, дефолты сервисов — нет
       (hypothesis --success #10b981 = 2.53:1, --danger #ef4444 = 3.76:1). */
    --success: var(--pf-ok-text);
    --warning: var(--pf-warn-text);
    --danger:  var(--pf-bad-text);
    --info:    var(--pf-info-text);

    /* Градиенты → плоские поверхности. Именно эти три значения давали «ИИ-вид»
       (#667eea→#764ba2 в 13 файлах). Переменная остаётся, чтобы
       `background: var(--gradient-primary)` в шаблонах продолжал работать. */
    --gradient-primary:   var(--pf-accent);
    --gradient-secondary: var(--pf-gray-600);
    --gradient-dark:      var(--pf-gray-800);


    --bg-body:      var(--pf-body-bg);
    --bg-main:      var(--pf-surface-muted);    /* supply base.html */
    --bg-sidebar:   var(--pf-surface);
    --bg-card:      var(--pf-surface);
    --bg-hover:     var(--pf-gray-100);
    --bg-secondary: var(--pf-surface-muted);
    --text-primary:   var(--pf-text);
    --text-secondary: var(--pf-text-muted);
    --text-table:     var(--pf-gray-600);
    --border-color:   var(--pf-border);

    --accent-hypothesis: var(--pf-accent);
    --accent-secondary:  var(--pf-info-text);
    --accent-wb:   var(--pf-mp-wb);
    --accent-ozon: var(--pf-mp-ozon);
    --accent-ym:   var(--pf-mp-ym);

    /* -- supply ds.css -- */
    --ds-gray-50:  var(--pf-gray-50);
    --ds-gray-100: var(--pf-gray-100);
    --ds-gray-200: var(--pf-gray-200);
    --ds-gray-300: var(--pf-gray-300);
    --ds-gray-500: var(--pf-gray-500);
    --ds-gray-700: var(--pf-gray-700);
    --ds-gray-900: var(--pf-gray-900);
    --ds-primary:       var(--pf-accent);
    --ds-border:        var(--pf-border);
    --ds-surface:       var(--pf-surface);
    --ds-surface-muted: var(--pf-surface-muted);
    --ds-text-muted:    var(--pf-text-muted);
    --mp-wb:   var(--pf-mp-wb);
    --mp-ozon: var(--pf-mp-ozon);
    --mp-ym:   var(--pf-mp-ym);

    /* -- offline of-ds.css. Янтарный акцент сервиса уводим в платформенный:
          отдел офлайна отличается площадкой в бейджах, а не тоном всей страницы. -- */
    --of-accent:   var(--pf-accent);
    --of-accent-2: var(--pf-warn-text);
    --of-pos:  var(--pf-ok-text);
    --of-neg:  var(--pf-bad-text);
    --of-warn: var(--pf-warn-text);
    --of-info: var(--pf-info-text);
    --of-surface:        var(--pf-surface);
    --of-surface-muted:  var(--pf-surface-muted);
    --of-surface-raised: var(--pf-surface-raised);
    --of-border:         var(--pf-border);
    --of-border-strong:  var(--pf-border-strong);
    --of-text:       var(--pf-text);
    --of-text-muted: var(--pf-text-muted);
    --of-shadow:    var(--pf-shadow-2);

    /* -- finmodel app.css -- */
    --fm-teal-700: var(--pf-accent);
    --fm-teal-500: color-mix(in srgb, var(--pf-accent) 60%, #fff);
    --fm-ink:   var(--pf-text);
    --fm-muted: var(--pf-text-muted);
    --fm-neg:   var(--pf-bad-text);
    --fm-pos:   var(--pf-ok-text);
    --fm-total-bg: var(--pf-surface-muted);

    /* -- costing app.css -- */
    --cs-bg:            var(--pf-body-bg);
    --cs-surface:       var(--pf-surface);
    --cs-surface-2:     var(--pf-surface-muted);
    --cs-border:        var(--pf-border);
    --cs-border-strong: var(--pf-border-strong);
    --cs-ink:   var(--pf-text);
    --cs-ink-2: var(--pf-gray-600);
    /* Не gray-400 (#94a3b8, 2.56:1): этим «серым» в costing покрашены ЦИФРЫ
       в таблицах — 291 ячейка на двух страницах, а не декоративные подписи. */
    --cs-ink-3: var(--pf-text-muted);
    --cs-brand:     var(--pf-accent);
    --cs-brand-ink: var(--pf-accent-hover);
    --cs-good: var(--pf-ok-text); --cs-good-bg: var(--pf-ok-bg);
    --cs-warn: var(--pf-warn-text); --cs-warn-bg: var(--pf-warn-bg);
    --cs-bad:  var(--pf-bad-text);  --cs-bad-bg:  var(--pf-bad-bg);
    --cs-shadow-lg: var(--pf-shadow-3);
}

/* Точечная нейтрализация чужих правил, которые нельзя выключить переменной.
   Сюда попадает ТОЛЬКО то, что сервис объявил жёстко и что явно выбивается.
   Каждая строка снимается вместе с правкой шаблона в своей волне. */

/* hypothesis base.html: свечение кнопки под фиолетовый акцент */
.sidebar-brand-icon,
.btn-primary { box-shadow: var(--pf-shadow-1) !important; }
.btn-primary:hover { box-shadow: var(--pf-shadow-2) !important; transform: none !important; }

/* hypothesis base.html: градиентные плашки иконок статистики */
.bg-gradient-success { background: var(--pf-ok-text) !important; }
.bg-gradient-primary { background: var(--pf-accent) !important; }
.bg-gradient-warning { background: var(--pf-warn-text) !important; }
.bg-gradient-info    { background: var(--pf-info-text) !important; }

/* costing: body.cs-body (0,1,1) перебивает платформенное правило body (0,0,1) —
   единственный такой случай на платформе. Снимается в волне E вместе с --cs-*. */
body.cs-body { font-family: var(--pf-font); }

/* stock-monitoring / reviews: градиентный навбар */
.navbar.bg-gradient, .navbar[style*="linear-gradient"] { background-image: none !important; }

/* ═══════════════════════ 3. BASE (поверх Bootstrap, только --bs-*) ═══════════════════════
 *
 * Класс Bootstrap не переопределяется селектором — иначе ломаются страницы,
 * полагающиеся на дефолты. Настраиваем ровно те переменные, что задают тон.
 * НЕ трогаем: --bs-body-font-size (плотность таблиц), gutters, паддинги .btn,
 * --bs-danger/--bs-success (они служат фоном бейджей, там другой контраст).
 */

:root {
    --bs-body-font-family: var(--pf-font);
    --bs-font-monospace:   var(--pf-font-mono);
    --bs-body-color:       var(--pf-text);
    --bs-body-color-rgb:   30, 41, 59;
    /* --bs-body-bg НЕ переопределяем: у Bootstrap это цвет ПОВЕРХНОСТИ (от него
       наследуется --bs-table-bg), а не холста страницы. Подмена на серый красит
       ячейки всех таблиц и роняет контраст приглушённого текста ниже AA
       (замер 05.09: +37 нарушений на /supply/ и /hypothesis/advisor/).
       Холст страницы каждый сервис задаёт сам — через --bg-body/--bg-main
       в секции bridge выше. */
    --bs-border-color:     var(--pf-border);
    --bs-border-radius:    var(--pf-radius);
    --bs-border-radius-sm: var(--pf-radius-sm);
    --bs-border-radius-lg: var(--pf-radius-lg);
    --bs-border-radius-pill: var(--pf-radius-pill);
    --bs-link-color:       var(--pf-accent);
    --bs-link-color-rgb:   var(--pf-accent-rgb);
    --bs-link-hover-color: var(--pf-accent-hover);
    --bs-primary:          var(--pf-accent);
    --bs-primary-rgb:      var(--pf-accent-rgb);
    --bs-focus-ring-color: rgba(var(--pf-accent-rgb), .25);
    --bs-secondary-color:  var(--pf-text-muted);
}

.btn-primary {
    --bs-btn-bg: var(--pf-accent);
    --bs-btn-border-color: var(--pf-accent);
    --bs-btn-hover-bg: var(--pf-accent-hover);
    --bs-btn-hover-border-color: var(--pf-accent-hover);
    --bs-btn-active-bg: var(--pf-accent-hover);
    --bs-btn-active-border-color: var(--pf-accent-hover);
    --bs-btn-disabled-bg: var(--pf-accent);
    --bs-btn-disabled-border-color: var(--pf-accent);
}
.btn-outline-primary {
    --bs-btn-color: var(--pf-accent-hover);
    --bs-btn-border-color: var(--pf-accent);
    --bs-btn-hover-bg: var(--pf-accent);
    --bs-btn-hover-border-color: var(--pf-accent);
    --bs-btn-active-bg: var(--pf-accent-hover);
}
/* Бутстраповский #6c757d на белом даёт 4.44:1 при 14px — ниже AA */
.btn-outline-secondary {
    --bs-btn-color: var(--pf-gray-600);
    --bs-btn-border-color: var(--pf-border-strong);
    --bs-btn-hover-bg: var(--pf-gray-100);
    --bs-btn-hover-color: var(--pf-text);
    --bs-btn-hover-border-color: var(--pf-gray-400);
}
/* Активный (`.active`) вариант обеих кнопок — белый текст на светлой заливке
   давал 4.23:1; заливаем акцентом, а не серым. */
.btn-outline-secondary.active, .btn-outline-secondary:active {
    --bs-btn-active-bg: var(--pf-gray-700);
    --bs-btn-active-border-color: var(--pf-gray-700);
    --bs-btn-active-color: #fff;
}
/* Остальные контурные кнопки: их фирменные цвета на белом ниже AA
   (success 4.13:1, danger 4.28:1, warning вообще 1.8:1). */
.btn-outline-success { --bs-btn-color: var(--pf-ok-text);   --bs-btn-border-color: var(--pf-ok-line);
                       --bs-btn-hover-bg: var(--pf-ok-text); --bs-btn-hover-border-color: var(--pf-ok-text); }
.btn-outline-danger  { --bs-btn-color: var(--pf-bad-text);  --bs-btn-border-color: var(--pf-bad-line);
                       --bs-btn-hover-bg: var(--pf-bad-text); --bs-btn-hover-border-color: var(--pf-bad-text); }
.btn-outline-warning { --bs-btn-color: var(--pf-warn-text); --bs-btn-border-color: var(--pf-warn-line);
                       --bs-btn-hover-bg: var(--pf-warn-text); --bs-btn-hover-border-color: var(--pf-warn-text);
                       --bs-btn-hover-color: #fff; }
.btn-outline-info    { --bs-btn-color: var(--pf-info-text); --bs-btn-border-color: var(--pf-info-line);
                       --bs-btn-hover-bg: var(--pf-info-text); --bs-btn-hover-border-color: var(--pf-info-text);
                       --bs-btn-hover-color: #fff; }

/* Текстовые утилиты Bootstrap на светлом фоне проваливают AA, и это не мелочь:
   ими покрашены ЦИФРЫ в таблицах (у диадока 133 ячейки жёлтым 1.47:1, у P&L —
   проценты). Меняем только цвет текста; заливки `.text-bg-*` и `.bg-*` не трогаем. */
/* `<code>` Bootstrap: #d63384 на белом — 3.68:1 */
:root { --bs-code-color: #9d174d; }
.text-success { color: var(--pf-ok-text)   !important; }
.text-danger  { color: var(--pf-bad-text)  !important; }
.text-warning { color: var(--pf-warn-text) !important; }
.text-info    { color: var(--pf-info-text) !important; }
.text-muted   { color: var(--pf-text-muted) !important; }
/* На тёмной подложке эти же утилиты обязаны остаться светлыми — иначе текст
   исчезает. Bootstrap-контейнеры тёмного фона помечены явными классами. */
:is(.bg-dark, .bg-black, .navbar-dark, [data-bs-theme="dark"]) :is(.text-success, .text-danger, .text-warning, .text-info, .text-muted) {
    color: inherit !important;
}

.card {
    --bs-card-border-color: var(--pf-border);
    --bs-card-border-radius: var(--pf-radius-lg);
    --bs-card-inner-border-radius: var(--pf-radius);
    --bs-card-box-shadow: var(--pf-shadow-1);
    --bs-card-cap-bg: transparent;
}
.table {
    --bs-table-border-color: var(--pf-border);
    --bs-table-striped-bg: var(--pf-surface-muted);
    --bs-table-hover-bg: var(--pf-accent-soft);
}
.form-control, .form-select {
    --bs-border-color: var(--pf-border-strong);
}
.badge { --bs-badge-border-radius: var(--pf-radius-sm); }
.dropdown-menu {
    --bs-dropdown-border-color: var(--pf-border);
    --bs-dropdown-border-radius: var(--pf-radius);
    --bs-dropdown-link-active-bg: var(--pf-accent);
    --bs-dropdown-link-hover-bg: var(--pf-gray-100);
}
.nav-tabs { --bs-nav-tabs-link-active-color: var(--pf-accent-hover); }
.modal { --bs-modal-border-radius: var(--pf-radius-lg); }

/* Гарнитура. --bs-body-font-family не помогает там, где сервис объявил
   `body { font-family: ... }` напрямую (supply, costing, prodplan) — прямое
   свойство побеждает переменную независимо от порядка. Поэтому одна строка на
   элемент body: это не класс Bootstrap, правило слоя не нарушено, а типографика
   на платформе становится единой в тот же день. */
body { font-family: var(--pf-font); }
code, pre, kbd, samp, .mono { font-family: var(--pf-font-mono); }

/* Единая видимая обводка фокуса на всей платформе (у 4 сервисов её не было вовсе) */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--pf-accent);
    outline-offset: 2px;
    border-radius: var(--pf-radius-sm);
}

/* Ссылка «к содержимому» — вставляется pf.js первым элементом body */
.pf-skip {
    position: absolute; left: -9999px; top: 0; z-index: 2000;
    padding: .55rem .9rem; background: var(--pf-surface); color: var(--pf-accent-hover);
    border: 1px solid var(--pf-accent); border-radius: 0 0 var(--pf-radius) 0;
    font: 600 var(--pf-fs-md) var(--pf-font); text-decoration: none;
}
.pf-skip:focus { left: 0; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ═══════════════════════ 4. COMPONENTS (только новые имена pf-*) ═══════════════════════ */

/* --- Числа. Без tabular-nums колонки «пляшут» при каждом обновлении. --- */
.pf-num, .pf-kpi-value, .pf-kpi-sub, .pf-delta,
.pf-table td.num, .pf-table th.num { font-variant-numeric: tabular-nums; }

/* --- KPI-плитка ---
 * Обёртка обязательна: container-type нельзя ставить на саму сетку —
 * @container не матчит элемент, на котором объявлен (баг of-kpi-grid). */
.pf-kpi-wrap { container-type: inline-size; }
.pf-kpi-grid {
    display: grid;
    gap: var(--pf-space-3);
    grid-template-columns: repeat(2, minmax(0, 1fr));
    margin-bottom: var(--pf-space-4);
}
@container (min-width: 640px)  { .pf-kpi-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@container (min-width: 1000px) { .pf-kpi-grid { grid-template-columns: repeat(var(--pf-kpi-cols, 4), minmax(0, 1fr)); } }

.pf-kpi {
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-lg);
    box-shadow: var(--pf-shadow-1);
    padding: var(--pf-space-3) var(--pf-space-4);
    min-width: 0;
}
.pf-kpi-label {
    font-size: var(--pf-fs-xs);
    color: var(--pf-text-muted);
    text-transform: uppercase;
    letter-spacing: .04em;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pf-kpi-value {
    font-size: var(--pf-fs-2xl);
    font-weight: 700;
    color: var(--pf-text);
    line-height: 1.25;
}
.pf-kpi-sub { font-size: var(--pf-fs-sm); color: var(--pf-text-muted); }

/* Дельта: знак несут И глиф, И цвет */
.pf-delta { font-size: var(--pf-fs-sm); font-weight: 600; }
.pf-delta[data-dir="up"]   { color: var(--pf-ok-text); }
.pf-delta[data-dir="down"] { color: var(--pf-bad-text); }
.pf-delta[data-dir="flat"] { color: var(--pf-text-muted); }
.pf-delta[data-dir="up"]::before   { content: "▲ "; font-size: .7em; }
.pf-delta[data-dir="down"]::before { content: "▼ "; font-size: .7em; }
.pf-delta[data-dir="flat"]::before { content: "≈ "; font-size: .8em; }
/* Инверсия для метрик, где рост — плохо (ДРР, себестоимость, срок доставки) */
.pf-delta[data-invert][data-dir="up"]   { color: var(--pf-bad-text); }
.pf-delta[data-invert][data-dir="down"] { color: var(--pf-ok-text); }

/* --- Статус: цвет + обязательный глиф --- */
.pf-status {
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .15rem .5rem;
    border-radius: var(--pf-radius-pill);
    font-size: var(--pf-fs-xs); font-weight: 600;
    border: 1px solid transparent;
}
.pf-status[data-status="ok"]    { color: var(--pf-ok-text);   background: var(--pf-ok-bg);   border-color: var(--pf-ok-line); }
.pf-status[data-status="warn"]  { color: var(--pf-warn-text); background: var(--pf-warn-bg); border-color: var(--pf-warn-line); }
.pf-status[data-status="bad"]   { color: var(--pf-bad-text);  background: var(--pf-bad-bg);  border-color: var(--pf-bad-line); }
.pf-status[data-status="info"]  { color: var(--pf-info-text); background: var(--pf-info-bg); border-color: var(--pf-info-line); }
.pf-status[data-status="muted"] { color: var(--pf-text-muted); background: var(--pf-gray-100); border-color: var(--pf-border); }
.pf-status[data-status="ok"]::before    { content: "✓"; }
.pf-status[data-status="warn"]::before  { content: "!"; }
.pf-status[data-status="bad"]::before   { content: "✕"; }
.pf-status[data-status="info"]::before  { content: "i"; font-style: italic; }
.pf-status[data-status="muted"]::before { content: "·"; }

/* --- Бейдж площадки --- */
.pf-mp {
    display: inline-block;
    padding: .1rem .4rem;
    border-radius: var(--pf-radius-sm);
    font-size: var(--pf-fs-xs); font-weight: 700; letter-spacing: .03em;
}
.pf-mp[data-mp="wb"]      { color: var(--pf-mp-wb-ink);      background: var(--pf-mp-wb-soft); }
.pf-mp[data-mp="ozon"]    { color: var(--pf-mp-ozon-ink);    background: var(--pf-mp-ozon-soft); }
.pf-mp[data-mp="ym"]      { color: var(--pf-mp-ym-ink);      background: var(--pf-mp-ym-soft); }
.pf-mp[data-mp="offline"] { color: var(--pf-mp-offline-ink); background: var(--pf-mp-offline-soft); }

/* --- Тулбар страницы --- */
.pf-toolbar {
    position: sticky; top: 0; z-index: var(--pf-z-sticky);
    display: flex; align-items: center; gap: var(--pf-space-3); flex-wrap: wrap;
    padding: var(--pf-space-2) var(--pf-space-3);
    margin-bottom: var(--pf-space-4);
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    box-shadow: var(--pf-shadow-1);
}
.pf-toolbar .pf-title { margin: 0; font-size: var(--pf-fs-lg); font-weight: 700; text-wrap: balance; }
.pf-toolbar .pf-spacer { flex: 1 1 auto; }

/* --- Таблица данных ---
 * border-collapse: separate обязателен — при collapse липкие ячейки теряют границы. */
.pf-table-wrap {
    max-height: var(--pf-table-h, 74vh);
    overflow: auto;
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    background: var(--pf-surface);
}
.pf-table {
    width: 100%; margin: 0;
    border-collapse: separate; border-spacing: 0;
    font-size: var(--pf-fs-md);
}
.pf-table th, .pf-table td {
    padding: 6px 8px;
    border-right: 1px solid var(--pf-border);
    border-bottom: 1px solid var(--pf-border);
    background-clip: padding-box;
}
.pf-table thead th {
    position: sticky; top: 0; z-index: 10;
    background: var(--pf-gray-800); color: #fff;
    font-weight: 600; font-size: var(--pf-fs-sm);
    white-space: nowrap; padding: 9px 8px;
    text-align: left;
}
.pf-table td.num, .pf-table th.num { text-align: right; }
.pf-table .pf-sticky-col {
    position: sticky; left: 0; z-index: 5;
    background: var(--pf-surface);
    text-align: left; font-weight: 600;
    border-right: 2px solid var(--pf-gray-700);
}
.pf-table thead .pf-sticky-col { z-index: 11; background: var(--pf-gray-800); }
.pf-table tbody tr:nth-child(even) > :where(td, th):not([class*="tl-s-"]) { background: var(--pf-surface-muted); }
.pf-table tbody tr:hover > :where(td, th):not([class*="tl-s-"]) { background: var(--pf-accent-soft); }
.pf-table caption {
    caption-side: top; text-align: left;
    padding: .5rem .75rem; color: var(--pf-text-muted); font-size: var(--pf-fs-sm);
}
/* Сортировка: заголовок-кнопка. aria-sort ставится на th (на button его не пускает axe). */
.pf-sort {
    border: 0; background: none; padding: 0; font: inherit; font-weight: 600;
    color: inherit; cursor: pointer; display: inline-flex; align-items: center; gap: .25rem;
}
.pf-table th[aria-sort="ascending"]  .pf-sort::after { content: "↑"; }
.pf-table th[aria-sort="descending"] .pf-sort::after { content: "↓"; }
.pf-table th[aria-sort] .pf-sort::after { opacity: .9; }
/* Длинные списки: отложенный рендер строк вне вьюпорта (Ctrl+F продолжает работать) */
.pf-table.-long tbody tr { content-visibility: auto; contain-intrinsic-block-size: auto 2.25rem; }

/* --- Поведенческий слой для ЧУЖОЙ таблицы (`.pf-data-table`) ---
 * Не перекрашивает таблицу: добавляет только липкую шапку, липкую первую колонку
 * и ресайз колонок поверх бутстраповской (или любой другой) разметки. Нужен там,
 * где таблица шире экрана: без него при горизонтальном скролле уезжает артикул,
 * и человек читает цифры неизвестно чьей строки.
 * border-collapse: separate обязателен — при collapse липкие ячейки теряют границы;
 * Bootstrap рисует только нижнюю границу ячейки, поэтому вид не меняется. */
.pf-dt-wrap { overflow: auto; max-block-size: var(--pf-dt-h, 72vh); }
table.pf-data-table {
    border-collapse: separate; border-spacing: 0;
    /* Чужой `overflow: hidden` на самой таблице (его ставят ради скруглённых
       углов) делает её скроллпортом для липких ячеек — и они перестают липнуть,
       молча: стилей на них полный набор, а шапка уезжает (dispatch/product_select). */
    overflow: visible;
}
table.pf-data-table > thead > tr > th {
    position: sticky; inset-block-start: 0; z-index: 3;
    background: var(--pf-surface); background-clip: padding-box;
}
table.pf-data-table > thead.table-light > tr > th { background: var(--pf-gray-100); }
table.pf-data-table > :where(thead, tbody, tfoot) > tr > .pf-dt-col1 {
    position: sticky; inset-inline-start: 0; z-index: 2;
    background: var(--pf-surface); background-clip: padding-box;
}
table.pf-data-table > thead > tr > .pf-dt-col1 { z-index: 4; background: var(--pf-gray-100); }
/* Тень-подсказка «там ещё есть» появляется, только когда реально уехали */
.pf-dt-wrap.-scrolled-x table.pf-data-table .pf-dt-col1 { box-shadow: 6px 0 6px -6px rgb(0 0 0 / .25); }
.pf-dt-wrap.-scrolled-y table.pf-data-table > thead > tr > th { box-shadow: 0 6px 6px -6px rgb(0 0 0 / .25); }
/* Ручка ресайза: тонкая зона у правого края заголовка.
   Липкий th уже спозиционирован, поэтому ручке хватает absolute без relative. */
.pf-dt-grip {
    /* Полоса ЦЕЛИКОМ внутри ячейки и над её содержимым: вылезающая за край
       ручка перекрывается соседним липким заголовком, и мышь до неё не доходит
       (у синтетических событий это не видно — они летят прямо в элемент). */
    position: absolute; inset-block: 0; inset-inline-end: 0; inline-size: 10px;
    z-index: 5; cursor: col-resize; touch-action: none; user-select: none;
}
.pf-dt-grip:hover, .pf-dt-grip.-drag { background: var(--pf-accent); opacity: .35; }
.pf-dt-resizing { cursor: col-resize; user-select: none; }

/* --- Видимость колонок (`pf.table.columns`): кнопка + список чекбоксов --- */
.pf-cols { position: relative; display: inline-block; }
.pf-cols-btn.-active { border-color: var(--pf-accent); color: var(--pf-accent); }
.pf-cols-menu {
    position: absolute; right: 0; top: calc(100% + 4px); z-index: 60;
    min-width: 220px; max-height: 60vh; overflow: auto;
    background: var(--pf-surface, #fff); border: 1px solid var(--pf-border, #e2e8f0);
    border-radius: var(--pf-radius, 8px); box-shadow: var(--pf-shadow-3);
    padding: .4rem .25rem; font-size: var(--pf-fs-sm);
}
.pf-cols-item { display: flex; align-items: center; gap: .5rem; padding: .25rem .6rem; margin: 0; cursor: pointer; white-space: nowrap; }
.pf-cols-item:hover { background: var(--pf-gray-100, #f1f5f9); }
.pf-cols-item input:disabled + * , .pf-cols-item:has(input:disabled) { color: var(--pf-text-muted); cursor: default; }
.pf-cols-reset { display: block; width: 100%; text-align: left; padding: .3rem .6rem; font-size: var(--pf-fs-xs); }

/* --- Обёртка графика. Высоту задаёт ОБЁРТКА: низкий canvas ломает тик-генератор
       Chart.js (шаг ±1000 при данных ~200). В JS обязателен maintainAspectRatio:false. --- */
.pf-chart-box {
    position: relative; height: var(--pf-chart-h, 300px);
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-lg);
    box-shadow: var(--pf-shadow-1);
    padding: var(--pf-space-3);
}
.pf-chart-box--sm { --pf-chart-h: 220px; }
.pf-chart-box--lg { --pf-chart-h: 380px; }
.pf-chart-box > canvas { max-width: 100%; }

/* --- Страница инструкции (`.hp-*`) ---
 * Одни и те же классы были объявлены трижды — в auth, prodplan и finmodel, со
 * своими цветами и своими провалами контраста. Здесь общий набор на токенах;
 * сервисам остаётся только их собственная специфика (скриншоты, таблица ролей).
 * Набор ОПТ-ИН: включается классом `.pf-help` на обёртке страницы — иначе он
 * молча перекрасил бы инструкцию prodplan, которая ждёт своей очереди (B-068). */
/* класс включения ставится на ту же обёртку, что и `.hp-wrap` */
.pf-help.hp-wrap, .pf-help .hp-wrap { max-width: 1200px; margin: 0 auto; }
.pf-help .hp-toc { position: sticky; top: 1rem; font-size: var(--pf-fs-md); }
.pf-help .hp-toc a {
    display: block; padding: .3rem .75rem; color: var(--pf-text);
    text-decoration: none; border-inline-start: 3px solid transparent;
    border-radius: 0 var(--pf-radius) var(--pf-radius) 0;
}
.pf-help .hp-toc a:hover { background: var(--pf-accent-soft); color: var(--pf-accent-hover); }
.pf-help .hp-toc a:focus-visible { outline: 2px solid var(--pf-accent); outline-offset: -2px; }
/* Заголовок группы: у сервисов он был #888 (3.27:1) — ниже порога даже для
   крупного текста, а это подпись в 11 px. */
.pf-help .hp-toc-head {
    font-weight: 600; color: var(--pf-text-muted); text-transform: uppercase;
    font-size: var(--pf-fs-xs); letter-spacing: .04em; padding: .6rem .75rem .2rem;
}
.pf-help .hp-sec {
    background: var(--pf-surface); border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-lg); padding: 1.4rem 1.6rem;
    margin-bottom: 1.25rem; scroll-margin-top: 1rem;
}
.pf-help .hp-sec h4 { display: flex; align-items: center; gap: .6rem; margin-bottom: .35rem; }
.pf-help .hp-sec h4 i { color: var(--pf-accent); font-size: 1.25rem; }
.pf-help .hp-where { font-size: var(--pf-fs-sm); color: var(--pf-text-muted); margin-bottom: .9rem; }
.pf-help .hp-where .badge { font-weight: 500; }
.pf-help .hp-open { font-size: var(--pf-fs-sm); }
.pf-help .hp-steps { counter-reset: step; list-style: none; padding-inline-start: 0; margin: .75rem 0; }
.pf-help .hp-steps > li {
    counter-increment: step; position: relative;
    padding: .35rem 0 .35rem 2.6rem; margin-bottom: .35rem;
}
.pf-help .hp-steps > li::before {
    content: counter(step); position: absolute; inset-inline-start: 0; top: .3rem;
    inline-size: 1.9rem; block-size: 1.9rem; border-radius: 50%;
    background: var(--pf-accent); color: #fff; font-weight: 700;
    display: flex; align-items: center; justify-content: center; font-size: .95rem;
}
.pf-help .hp-tip, .pf-help .hp-warn {
    border-radius: var(--pf-radius); padding: .7rem .9rem;
    margin: .8rem 0; font-size: var(--pf-fs-md);
}
.pf-help .hp-tip  { background: var(--pf-info-bg); border: 1px solid var(--pf-info-line); color: var(--pf-text); }
.pf-help .hp-warn { background: var(--pf-warn-bg); border: 1px solid var(--pf-warn-line); color: var(--pf-text); }
/* Глиф иконочным шрифтом, а не эмодзи: эмодзи скринридер читает как «лампочка». */
.pf-help .hp-tip::before, .pf-help .hp-warn::before {
    font-family: bootstrap-icons; margin-inline-end: .4rem; speak: never;
}
.pf-help .hp-tip::before  { content: "\F467"; color: var(--pf-info-text); }
.pf-help .hp-warn::before { content: "\F33A"; color: var(--pf-warn-text); }
.pf-help .hp-flow { display: flex; flex-wrap: wrap; gap: .4rem; align-items: stretch; margin: .8rem 0; }
.pf-help .hp-flow .hp-node {
    background: var(--pf-surface-muted); border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius); padding: .55rem .8rem;
    font-size: var(--pf-fs-sm); flex: 1 1 160px; min-inline-size: 150px;
}
.pf-help .hp-flow .hp-node b { display: block; color: var(--pf-accent-hover); margin-bottom: .15rem; }
.pf-help .hp-flow .hp-arr { align-self: center; color: var(--pf-text-muted); font-size: 1.2rem; flex: 0 0 auto; }
.pf-help .hp-kbd {
    background: var(--pf-gray-100); border: 1px solid var(--pf-border);
    border-radius: 6px; padding: .05rem .45rem; font-size: .85em; white-space: nowrap;
    font-family: var(--pf-font-mono, ui-monospace, monospace);
}
@media (max-width: 991.98px) { .hp-toc { position: static; margin-bottom: 1rem; } }
@media print { .hp-toc-col { display: none !important; } .hp-sec { break-inside: avoid; } }

/* --- Свежесть данных --- */
.pf-fresh {
    display: inline-flex; align-items: center; gap: .35rem;
    padding: .12rem .5rem;
    border-radius: var(--pf-radius-pill);
    font-size: var(--pf-fs-xs); font-weight: 500;
    border: 1px solid var(--pf-border);
    background: var(--pf-surface-muted);
    color: var(--pf-text-muted);
    vertical-align: middle;
}
.pf-fresh::before { content: "●"; font-size: .7em; color: var(--pf-gray-400); }
.pf-fresh.-ok::before      { color: var(--pf-ok-text); }
.pf-fresh.-stale { color: var(--pf-warn-text); background: var(--pf-warn-bg); border-color: var(--pf-warn-line); }
.pf-fresh.-stale::before   { color: var(--pf-warn-text); content: "!"; }
.pf-fresh.-unknown::before { content: "?"; }

/* --- Плашка-ловушка (контекстное предупреждение о семантике данных) --- */
.pf-caveat {
    border: 1px solid var(--pf-warn-line);
    background: var(--pf-warn-bg);
    color: var(--pf-warn-text);
    border-radius: var(--pf-radius);
    padding: .5rem .75rem;
    margin-bottom: var(--pf-space-3);
    font-size: var(--pf-fs-md);
}
.pf-caveat > summary { cursor: pointer; font-weight: 600; }
.pf-caveat-body { margin-top: .4rem; color: var(--pf-text); white-space: pre-line; }
.pf-caveat.-blocker { border-color: var(--pf-bad-line); background: var(--pf-bad-bg); color: var(--pf-bad-text); }

/* --- Тултип метрики (один на страницу, top-layer) --- */
abbr[data-pf-metric] {
    text-decoration: underline dotted var(--pf-gray-400);
    text-underline-offset: .2em;
    cursor: help;
}
#pf-tip {
    margin: 0; padding: .6rem .75rem;
    max-width: 32rem;
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    background: var(--pf-surface);
    box-shadow: var(--pf-shadow-3);
    font-size: var(--pf-fs-md); color: var(--pf-text);
    position: absolute;
}
#pf-tip .pf-tip-title { font-weight: 700; margin-bottom: .2rem; }
#pf-tip .pf-tip-meta { color: var(--pf-text-muted); font-size: var(--pf-fs-xs); margin-top: .35rem; }

/* --- Пустое состояние / ошибка блока --- */
.pf-empty {
    display: grid; place-items: center; gap: .5rem;
    padding: 2.5rem 1rem; text-align: center;
    color: var(--pf-text-muted);
    background: var(--pf-surface-muted);
    border: 1px dashed var(--pf-border-strong);
    border-radius: var(--pf-radius-lg);
}
.pf-empty-title { font-weight: 600; color: var(--pf-text); text-wrap: balance; }
.pf-empty.-error { border-color: var(--pf-bad-line); background: var(--pf-bad-bg); }
.pf-empty.-error .pf-empty-title { color: var(--pf-bad-text); }

/* --- Скелетон --- */
.pf-skeleton {
    border-radius: var(--pf-radius);
    background: linear-gradient(90deg, var(--pf-surface-raised) 25%, var(--pf-border) 50%, var(--pf-surface-raised) 75%);
    background-size: 200% 100%;
    animation: pf-skeleton-wave 1.4s ease-in-out infinite;
    min-height: 1rem;
}
@keyframes pf-skeleton-wave { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* --- Спиннер (замена fa-spin) --- */
.pf-spin { display: inline-block; animation: pf-spin 1s linear infinite; }
@keyframes pf-spin { to { transform: rotate(360deg); } }

/* --- Тосты: popover="manual" — top-layer игнорирует z-index родителей --- */
.pf-toast {
    position: fixed; inset: auto 1rem 1rem auto;
    display: flex; align-items: flex-start; gap: .5rem;
    max-width: 26rem; margin: 0;
    padding: .65rem .8rem;
    border: 1px solid var(--pf-border);
    border-left: 4px solid var(--pf-info-text);
    border-radius: var(--pf-radius);
    background: var(--pf-surface);
    box-shadow: var(--pf-shadow-3);
    font-size: var(--pf-fs-md); color: var(--pf-text);
}
.pf-toast--success { border-left-color: var(--pf-ok-text); }
.pf-toast--warning { border-left-color: var(--pf-warn-text); }
.pf-toast--error   { border-left-color: var(--pf-bad-text); }
.pf-toast-title { font-weight: 700; }
.pf-toast-body  { flex: 1 1 auto; white-space: pre-line; }
.pf-toast-close, .pf-toast-action {
    border: 0; background: none; cursor: pointer; padding: 0 .2rem;
}
.pf-toast-close  { font-size: 1.1rem; line-height: 1; color: var(--pf-text-muted); }
.pf-toast-action { color: var(--pf-accent-hover); font-weight: 600; white-space: nowrap; }

/* --- Диалог --- */
.pf-dialog {
    border: 0; padding: 0;
    border-radius: var(--pf-radius-lg);
    box-shadow: 0 10px 40px rgba(15, 23, 42, .25);
    max-width: 30rem; width: calc(100% - 2rem);
    color: var(--pf-text); background: var(--pf-surface);
}
.pf-dialog::backdrop { background: rgba(15, 23, 42, .45); }
.pf-dialog-body { padding: var(--pf-space-4); }
.pf-dialog h5 { margin: 0 0 .5rem; font-size: var(--pf-fs-lg); font-weight: 700; }
.pf-dialog p  { margin: 0 0 var(--pf-space-4); color: var(--pf-text-muted); white-space: pre-line; }
.pf-dialog-actions { display: flex; justify-content: flex-end; gap: .5rem; }

/* --- Сообщить о проблеме: плавающая кнопка и диалог --- */
/* Кнопка намеренно скромная: она нужна в момент раздражения, а не как
   постоянный элемент интерфейса, поэтому приглушена и уходит за край экрана
   при печати. Каркасы страниц не меняются — это единственный добавленный
   платформой элемент поверх них. */
.pf-fab {
    position: fixed; right: 1rem; bottom: 1rem; z-index: var(--pf-z-toast, 1080);
    width: 2.25rem; height: 2.25rem; border-radius: 50%;
    border: 1px solid var(--pf-border); background: var(--pf-surface);
    color: var(--pf-text-muted); font-size: 1rem; line-height: 1;
    box-shadow: var(--pf-shadow-2); cursor: pointer; opacity: .65;
    transition: opacity .15s ease, color .15s ease;
}
.pf-fab:hover, .pf-fab:focus-visible { opacity: 1; color: var(--pf-accent); }
@media print { .pf-fab { display: none; } }
/* Заявки в поддержку (docs/tasks/support-requests): метка «есть ответ» — число, не тревога,
   поэтому акцент, а не красный; при метке кнопка не приглушена. На тач-экране цель 44 px. */
.pf-fab { bottom: var(--pf-fab-bottom, max(1rem, env(safe-area-inset-bottom))); }
.pf-fab--unread { opacity: 1; color: var(--pf-accent); border-color: var(--pf-accent); }
.pf-fab__badge {
    position: absolute; top: -.35rem; right: -.35rem; min-width: 1.15rem; height: 1.15rem;
    padding: 0 .25rem; border-radius: var(--pf-radius-pill); background: var(--pf-accent);
    color: #fff; font-size: .7rem; font-weight: 700; line-height: 1.15rem; text-align: center;
}
.pf-fab.pf-fab--hidden { display: none; }
/* 09.10: бледный кружок 36 px никто не замечал — акцентная плашка с текстом, на узком экране круг 48 px.
   Плашка большая, поэтому: резерв места внизу страницы (body.pf-has-fab), компактный круг над липкой нижней
   панелью страницы (html.pf-fab-compact, высоту ставит pf.js в --pf-fab-bottom), z-index ниже модалок. */
.pf-fab {
    width: auto; height: 2.75rem; padding: 0 1.1rem; border-radius: var(--pf-radius-pill);
    display: inline-flex; align-items: center; gap: .5rem; opacity: 1; z-index: var(--pf-z-nav, 1000);
    border: 0; background: var(--pf-accent); color: #fff; font: 600 var(--pf-fs-sm)/1 var(--pf-font);
    box-shadow: var(--pf-shadow-3);
}
.pf-fab:hover, .pf-fab:focus-visible { opacity: 1; color: #fff; background: var(--pf-accent-hover); }
.pf-fab:focus-visible { outline: 3px solid var(--pf-accent-hover); outline-offset: 3px; }
.pf-fab__q { display: none; font-size: 1.35rem; font-weight: 700; }
.pf-fab--unread { border: 0; color: #fff; }
.pf-fab__badge { background: var(--pf-surface); color: var(--pf-accent-hover); box-shadow: 0 0 0 2px var(--pf-accent); }
body.pf-has-fab { padding-bottom: 4.75rem; }
.pf-toast { bottom: calc(var(--pf-fab-bottom, 1rem) + 3.5rem); }
@media (max-width: 899.98px) {
    .pf-fab { width: 3rem; height: 3rem; padding: 0; justify-content: center; }
    .pf-fab__q { display: inline; }
    .pf-fab__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
    body.pf-has-fab { padding-bottom: 4.5rem; }
}
html.pf-fab-compact .pf-fab { width: 2.75rem; height: 2.75rem; padding: 0; justify-content: center; }
html.pf-fab-compact .pf-fab__q { display: inline; }
html.pf-fab-compact .pf-fab__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

.pf-sr-only {
    position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.pf-dialog--wide { max-width: 34rem; padding: var(--pf-space-4); }
.pf-dialog__title { margin: 0 0 var(--pf-space-3); font-size: var(--pf-fs-lg); font-weight: 700; }
.pf-dialog__note { margin: var(--pf-space-2) 0 var(--pf-space-3); font-size: var(--pf-fs-sm); color: var(--pf-text-muted); }
.pf-dialog__actions { display: flex; justify-content: flex-end; gap: .5rem; }

/* --- Страница «Инструкция»: единые hp-* (три копии в auth/prodplan/finmodel) --- */
.hp-wrap { max-width: 1100px; }
.hp-toc {
    background: var(--pf-surface); border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius); padding: var(--pf-space-3) var(--pf-space-4);
}
.hp-toc-head { font-weight: 700; color: var(--pf-text); margin-bottom: .4rem; }
.hp-sec { margin-bottom: var(--pf-space-6); scroll-margin-top: 5rem; }
.hp-sec h2 { font-size: var(--pf-fs-xl); font-weight: 700; margin-bottom: var(--pf-space-3); }
.hp-tip, .hp-warn {
    border-left: 4px solid; border-radius: var(--pf-radius);
    padding: .6rem .85rem; margin: var(--pf-space-3) 0; font-size: var(--pf-fs-md);
}
.hp-tip  { border-color: var(--pf-info-text); background: var(--pf-info-bg); color: var(--pf-text); }
.hp-warn { border-color: var(--pf-warn-text); background: var(--pf-warn-bg); color: var(--pf-text); }
.hp-steps { padding-left: 1.25rem; }
.hp-steps li { margin-bottom: .4rem; }
/* Ссылки в справке — бренд-акцент, а не бутстраповский синий */
.hp-wrap a, .hp-toc a { color: var(--pf-accent-hover); }

/* Переход на карточку товара из любой таблицы. Иконка, а не подчёркнутый
   артикул: строки этих таблиц кликабельны сами (модалка детализации), и
   ссылка-на-весь-артикул перехватывала бы привычный клик. */
.pf-card-link {
    margin-left: .35rem;
    color: var(--pf-text-muted, #5b6a7d);
    text-decoration: none;
    opacity: .55;
    transition: opacity .12s ease, color .12s ease;
}
.pf-card-link:hover,
.pf-card-link:focus-visible { opacity: 1; color: var(--pf-accent-hover, #000096); }
tr:hover .pf-card-link { opacity: .9; }

/* Точечные статусные цвета для страниц без Bootstrap (fbs-manager рисует всё
   сам): те же токены, что у платформенных плашек, а не свои green/red. */
.pf-ok  { color: var(--pf-ok-text, #15803d); }
.pf-bad { color: var(--pf-bad-text, #b42318); }

/* ─── Метаданные UI: подсказки метрик, бейдж свежести, плашка ловушек ─────── */

/* Метрика с подсказкой: пунктир вместо сплошного подчёркивания — в таблице
   на сорок столбцов сплошное превратило бы шапку в частокол. */
.pf-has-tip {
    border-bottom: 1px dashed var(--pf-gray-400, #94a3b8);
    cursor: help;
}
.pf-has-tip:focus-visible { outline: 2px solid var(--pf-accent); outline-offset: 2px; }

.pf-tip {
    position: absolute;
    z-index: 1080;
    max-width: 22rem;
    padding: .6rem .75rem;
    background: var(--pf-gray-800, #1e293b);
    color: #fff;
    border-radius: var(--pf-radius, 8px);
    box-shadow: var(--pf-shadow-2);
    font-size: .8125rem;
    line-height: 1.45;
    pointer-events: none;
}
.pf-tip strong { font-weight: 600; }
.pf-tip p { margin: .35rem 0 0; }
.pf-tip-meta { margin-top: .4rem; opacity: .75; font-size: .75rem; }
.pf-tip-caveat {
    margin-top: .45rem; padding-top: .4rem;
    border-top: 1px solid rgba(255, 255, 255, .2);
    color: #fde68a;
}

/* Бейдж свежести. Три состояния и все три — словами: «данные отстают»
   цветом не передашь. */
.pf-fresh {
    display: inline-flex; align-items: center; gap: .35rem;
    padding: .1rem .5rem; border-radius: 999px;
    font-size: .75rem; white-space: nowrap;
    border: 1px solid var(--pf-border, #e2e8f0);
    color: var(--pf-text-muted, #5b6a7d);
    background: var(--pf-surface, #fff);
}
.pf-fresh::before { content: "•"; font-size: 1rem; line-height: 0; }
.pf-fresh.-ok::before { color: var(--pf-ok-text, #15803d); }
.pf-fresh.-stale { color: var(--pf-warn-text, #92400e); background: var(--pf-warn-bg, #fef3c7); border-color: transparent; }
.pf-fresh.-stale::before { color: var(--pf-warn-text, #92400e); }
.pf-fresh.-unknown::before { color: var(--pf-gray-400, #94a3b8); }

/* Ловушки данных: свёрнуты по умолчанию — это не предупреждение об ошибке,
   а инструкция по чтению, и она нужна не при каждом заходе. */
.pf-caveat {
    margin: .75rem 0;
    border: 1px solid var(--pf-border, #e2e8f0);
    border-radius: var(--pf-radius, 8px);
    background: var(--pf-surface, #fff);
    font-size: .8125rem;
}
.pf-caveat > summary {
    padding: .5rem .75rem; cursor: pointer;
    color: var(--pf-text-muted, #5b6a7d);
}
.pf-caveat > summary::marker { color: var(--pf-gray-400, #94a3b8); }
.pf-caveat-item { padding: .5rem .75rem .6rem; border-top: 1px solid var(--pf-border, #e2e8f0); }
.pf-caveat-item.-blocker { border-left: 3px solid var(--pf-warn-text, #92400e); }
.pf-caveat-item strong { color: var(--pf-text, #1e293b); }
.pf-caveat-item p { margin: .25rem 0 0; color: var(--pf-text-muted, #5b6a7d); }

/* ── Боковая панель деталей (pf-drawer) ─────────────────────────────────────────
   Немодальная панель справа: список слева остаётся рабочим (референс Refero —
   Mercury Transactions). База — классы Bootstrap `offcanvas offcanvas-end`,
   настройка только через --bs-offcanvas-*; показ/скрытие — pf.drawer (pf.js),
   а НЕ Bootstrap JS: тот ставит aria-modal="true" и держит фокус, панель
   переставала бы быть немодальной. Разметка и API — docs/tasks/refero-hypothesis-pilot/design.md */
.pf-drawer {
    --bs-offcanvas-width: clamp(360px, 35vw, 560px);
    --bs-offcanvas-padding-x: var(--pf-space-5);
    --bs-offcanvas-padding-y: var(--pf-space-4);
    --bs-offcanvas-bg: var(--pf-surface);
    --bs-offcanvas-color: var(--pf-text);
    --bs-offcanvas-border-color: var(--pf-border);
    box-shadow: var(--pf-shadow-overlay);
}
.pf-drawer:focus { outline: none; }
.pf-drawer:focus-visible { outline: 2px solid var(--pf-accent); outline-offset: -2px; }
.pf-drawer-head {
    align-items: flex-start; gap: var(--pf-space-3);
    border-bottom: 1px solid var(--pf-border);
}
.pf-drawer-head > :first-child { flex: 1 1 auto; min-width: 0; }
.pf-drawer-tools { display: flex; align-items: center; gap: var(--pf-space-1); flex: 0 0 auto; }
.pf-drawer-note {
    margin: 0; padding: var(--pf-space-2) var(--pf-space-5);
    font-size: var(--pf-fs-sm); color: var(--pf-warn-text);
    background: var(--pf-warn-bg); border-bottom: 1px solid var(--pf-warn-line);
}
.pf-drawer-note::before { content: "! "; font-weight: 700; }
/* Сдвиг контента, чтобы панель не закрывала правую часть страницы (кнопки, колонки).
   Ширину ставит pf.drawer в --pf-drawer-push по фактической ширине панели. */
.pf-drawer-pushed { margin-inline-end: var(--pf-drawer-push, 0); transition: margin-inline-end .3s ease-in-out; }
/* Строка списка, открытая в панели: фон + полоса слева (не только цвет).
   В таблицах Bootstrap фон ячейки рисует inset-тень от --bs-table-bg-state. */
.pf-drawer-current { --bs-table-bg-state: var(--pf-accent-soft); }
.pf-drawer-current > * { background-color: var(--pf-accent-soft); }
.pf-drawer-current > :first-child { box-shadow: inset 3px 0 0 var(--pf-accent), inset 0 0 0 9999px var(--pf-accent-soft); }
@media (max-width: 991.98px) {
    .pf-drawer { --bs-offcanvas-width: 100vw; }
    .pf-drawer-pushed { margin-inline-end: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .pf-drawer-pushed { transition: none; }
}
