/**
 * Назначение: ядро паттернов интерфейса TMS — «паттерн = класс»: готовые элементы, из которых собирается любая новая
 *   страница, вместо переписывания вёрстки заново (план «Дизайн-система», шаг 2).
 * Что делает: даёт классы с префиксом .ui-, каждый — с комментарием «что это, где эталон»: миниатюра товара .ui-thumb и ячейка
 *   «Товар» .ui-product; размеры миниатюры S / M / L — токен --ui-thumb-size, модификаторы .ui-thumb-m и .ui-thumb-l, атрибут
 *   [data-ui-thumb-size] на контейнере страницы, переключатель [data-ui-thumb-switch] с кнопками [data-ui-thumb-size-btn], столбцы
 *   .ui-col-thumb, .ui-col-thumb-switch (шире, под переключатель в шапке; сам переключатель в шапке — .ui-segments-th) и .ui-col-product,
 *   ячейка «Товар» с фото сверху .ui-product-stack; поле поиска в заголовке столбца .ui-th-search (лупа .ui-th-search-icon, поле
 *   .ui-th-search-input, крестик .ui-th-search-clear, фильтр включён — .is-active); копирование столбца .ui-th-copy (значение
 *   [data-ui-copy] или столбец живой таблицы [data-ui-copy-col] + [data-ui-copy-table], значение ячейки [data-ui-copy-value]);
 *   прилипающая шапка .ui-sticky-head (шапка из двух строк — с .ui-sticky-head-rows) и шапка таблицы шире экрана полосой под меню
 *   .ui-sticky-band (скрипт UiCore.stickyBand; живой режим {live: true} — в полосе настоящая строка, в таблице её невидимая копия
 *   .ui-sticky-band-placeholder); сегментный переключатель .ui-segments (плотный .ui-segments-sm; сегмент-ссылка a.ui-segment); бейдж количества «×N» .ui-qty (крупный
 *   при N>1 — .ui-qty-multi, растёт с размером миниатюры; строка позиции N>1 — .ui-qty-row); плитки итогов .ui-stat-tile
 *   (плотная сетка .ui-stat-tiles-compact); кликабельные карточки-фильтры .ui-filter-card (сетка .ui-filter-cards, тоны .ui-filter-card-warn/-bad/-ok/-zero,
 *   выбранная .is-selected; части .ui-filter-card-value/-label/-caption); инфо-плашка с пилюлями .ui-pills (тона сегментов ценообразования
 *   .ui-pill-segment-special/-base/-reduced); точка статуса .ui-status-dot; тихая кнопка-значок .ui-icon-btn; вкладки-«папки»
 *   .ui-folder-tabs (контейнер) и .ui-folder-tabs-bar (полоса без тела); строка-группа таблицы .ui-group-row и вложенная строка группы .ui-group-child; срезы одного числа в ячейке .ui-slices (строка .ui-slices-row на источник с подписью «значок и слово» .ui-slices-label и числами .ui-slices-value, название столбца и подписи чисел в шапке .ui-slices-head, тон расхождения .ui-slices-row-warn); доля с кольцом .ui-share (кольцо 40 px и процент, тона -ok / -warn / -bad, галочка у 100 %; скрипт UiCore.share); всплывающая карточка .ui-pop (одна на все подсказки: справка ⓘ .ui-hint и состав числа) и формула .ui-formula (деление дробью);
 *   чекбокс 20×20 .ui-check с подписью .ui-check-label; две кнопки над списком галочек «Выделить все» / «Сбросить все» .ui-check-actions (кнопка .ui-check-action);
 *   окно поверх страницы .ui-modal (оболочка: подложка, коробка, заголовок, тело, кнопки; содержимое правки значения .ui-modal-product,
 *   .ui-edit-*, .ui-modal-error, .ui-modal-note, .ui-modal-help); прогресс-бар .ui-progress со счётчиком; прогресс по площадкам .ui-progress-platforms (строка площадки .ui-progress-platform с бейджем, «N из M» и счётчиками,
 *   под ними общий итог .ui-progress-total — окно «Проверка статусов на площадках», зона check-modal); янтарная плашка настройки .ui-note-warn (пояснение .ui-note-warn-hint); загрузка данных: болванки .ui-skeleton (формы .ui-skeleton-tile, -line, -line-short, -row;
 *   группы .ui-skeleton-tiles и .ui-skeleton-rows), блок ожидания .ui-load с подписью .ui-load-text и значками .ui-load-bars (столбики), .ui-load-dots (точки площадок),
 *   .ui-load-ring (кольцо; крупное .ui-load-ring-lg), перезагрузка показанных данных .ui-busy с оверлеем .ui-busy-overlay (скрипты UiCore.loader / skeleton / busy). Цвета и размеры — токены
 *   --ui-* на :root (цвета, поверхность --ui-surface, рамка --ui-border, размеры шрифта --ui-text-xs…xl, цвета прогресс-бара, размеры значков загрузки --ui-load-*, цвет пояснения янтарной плашки --ui-warn-hint; значения повторяют --chart-* страниц аналитики и токены --table-* из site.css, но не зависят от корня
 *   страницы .analytics-page, поэтому работают где угодно). Пустое состояние — .ui-empty.
 * Запрещённые имена: jQuery UI (yii\jui\JuiAsset на карточке товара, assets/ProductAsset.php) занимает префикс ui-, поэтому в ядро
 *   нельзя заводить .ui-tabs, .ui-button, .ui-dialog, .ui-progressbar, .ui-menu, .ui-tooltip, .ui-icon, .ui-widget, .ui-state-*,
 *   .ui-sortable*, .ui-draggable*, .ui-helper-*, .ui-front, а также .ui-spinner и .ui-loader (jQuery Mobile). Вкладки, прогресс-бар, окно и ожидание в ядре называются .ui-folder-tabs,
 *   .ui-progress, .ui-modal и .ui-load*.
 * Как использовать: подключается базовым AppAsset после site.css на каждой странице; интерактив (копирование, справка ⓘ,
 *   сворачивание групп, окна, полоса шапки) — js/ui-core.js на атрибутах data-ui-* и вызовах UiCore.*. Страничный CSS ядро не дублирует: нужен другой размер или
 *   цвет — страница переопределяет токен или добавляет модификатор, а не копирует класс. Живые примеры и стандарты — витрина
 *   /ui-kit (только владельцу) и хаб TMS-vault/1 Разработка/Стандарты/0 Дизайн.md.
 */

:root {
    --ui-ink: #333;
    --ui-ink-secondary: #555;
    --ui-ink-muted: #8b8577;
    --ui-accent: #3c8dbc;
    --ui-accent-ink: #2a6a8e;
    --ui-accent-strong: #327aa3;
    --ui-accent-soft: rgba(60, 141, 188, 0.14);
    --ui-segments-bg: #eef1f4;
    --ui-ok-bg: #f0fdf4;
    --ui-ok-line: #bbf7d0;
    --ui-ok-ink: #15803d;
    --ui-warn-bg: #fffbeb;
    --ui-warn-line: #fde68a;
    --ui-warn-ink: #92400e;
    --ui-warn-hint: #a16207;
    --ui-bad-bg: #fef2f2;
    --ui-bad-line: #fecaca;
    --ui-bad-ink: #b91c1c;
    --ui-info-ink: #25607f;
    --ui-surface: #fff;
    --ui-border: #dee2e6;
    --ui-text-xs: 12.5px;
    --ui-text-sm: 13px;
    --ui-text-md: 16px;
    --ui-text-lg: 18px;
    --ui-text-xl: 28px;
    --ui-progress-track: #e9ecef;
    --ui-progress-from: #5686e6;
    --ui-progress-to: #16a34a;
    --ui-load-ring-size: 16px;
    --ui-load-ring-width: 2px;
    --ui-load-icon-size: 32px;
    --ui-load-height: 160px;
    --ui-skeleton-tile-height: 96px;
    --ui-skeleton-row-height: 36px;
}

/* ---------- Миниатюра товара и ячейка «Товар» ----------
   Миниатюра 64×64 везде (решение владельца 2026-10-06): фото целиком (contain), рамка токена таблиц, клик открывает
   крупное фото в Fancybox. Размер — токен --ui-thumb-size (по умолчанию 64 px); страницам с переключателем «S / M / L»
   (Подтверждение сборки, Заказы Авито) размеры 150 и 320 даёт блок «зона assembly» в конце файла. Разметка: <a class="ui-thumb" href="крупное фото" data-fancybox><img src="превью" alt=""></a>.
   Источник картинок — только ImageHelper (thumb_url и image_url), класс задаёт вид. Эталон — «Выкуп и доход по артикулам»
   (ячейка «Товар», pb-item) и «Проверка приёмки площадками». */
.ui-thumb {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: var(--ui-thumb-size, 64px);
    height: var(--ui-thumb-size, 64px);
    border: 1px solid var(--table-border, #d1d5db);
    border-radius: var(--btn-border-radius, 8px);
    background: var(--ui-surface);
    overflow: hidden;
}

.ui-thumb:hover,
.ui-thumb:focus-visible {
    border-color: var(--ui-accent);
    outline: 0;
}

.ui-thumb img {
    display: block;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* Заглушка без фото: тот же квадрат 64×64, значок приглушённым серым. */
.ui-thumb-empty {
    color: #bbb;
    font-size: calc(var(--ui-thumb-size, 64px) / 3);
}

/* Ширина столбца с миниатюрой — классом на col или th, не style; растёт вместе с --ui-thumb-size (64 → 86 px). */
.ui-col-thumb {
    width: calc(var(--ui-thumb-size, 64px) + 22px);
}

/* Ячейка «Товар» (фото + артикул-ссылка на карточку + название в две строки) — одна ячейка вместо трёх столбцов.
   Разметка: <div class="ui-product"><a class="ui-thumb">…</a><div class="ui-product-body"><a class="ui-product-sku" href="карточка">816202</a>
   <div class="ui-product-name">Название</div></div></div>. Эталон — pb-item, pb-sku-link, pb-name в «Выкуп и доход». */
.ui-product {
    display: flex;
    align-items: center;
    gap: 10px;
    max-width: 380px;
}

.ui-product-body {
    flex: 1;
    min-width: 0;
}

.ui-product-sku {
    display: inline-block;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1.25;
    white-space: nowrap;
}

.ui-product-name {
    display: -webkit-box;
    overflow: hidden;
    color: var(--ui-ink-secondary);
    line-height: 1.3;
    white-space: normal;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
}

/* ---------- Копирование столбца в заголовке ----------
   Заголовок столбца и рядом кнопка fa-clone в одну линию; клик по [data-ui-copy] кладёт значение атрибута в буфер
   (строки через перевод строки), кнопка на 1,6 с становится зелёной с галочкой (js/ui-core.js). Разметка:
   <th><div class="ui-th-copy"><span>Номер заказа</span><button type="button" class="btn btn-default btn-xs ui-th-copy-btn"
   data-ui-copy="1&#10;2" aria-label="Скопировать столбец"><i class="fa fa-clone"></i></button></div></th>.
   Режим «столбец живой таблицы» — вместо data-ui-copy кнопка несёт data-ui-copy-col="индекс столбца с нуля" и data-ui-copy-table="id таблицы":
   скрипт сам берёт текст ячеек видимых строк (ячейка с data-ui-copy-value отдаёт это значение, а не свой текст); нужен, когда строки
   рисует скрипт страницы или их скрывает фильтр.
   Эталон — «Проверка приёмки площадками» (столбец «Номер заказа»), «Подтверждение сборки» и «Склад». */
.ui-th-copy {
    display: flex;
    align-items: center;
    gap: 6px;
}

.ui-th-copy-btn {
    flex-shrink: 0;
    padding: 1px 5px;
}

.ui-th-copy-btn.is-done,
.ui-icon-btn.is-done {
    border-color: var(--ui-ok-line);
    background: var(--ui-ok-bg);
    color: var(--ui-ok-ink);
}

/* ---------- Поле поиска в заголовке столбца (.ui-th-search) ----------
   Поиск по строкам таблицы живёт в шапке своего столбца, а не отдельной строкой фильтров над таблицей: лупа слева, крестик справа —
   только когда запрос задан. Запрос задан — корню ставится .is-active: акцентная обводка и лупа, фильтр виден и без фокуса. Корень
   растягивается на свободное место строки шапки (flex: 1 1 auto), предел ширины ставит страница. Разметка:
   <th><span>📦 Товар</span><div class="ui-th-search is-active"><i class="fa fa-search ui-th-search-icon" aria-hidden="true"></i>
   <input type="text" class="ui-th-search-input" placeholder="Артикул или название" aria-label="Поиск по артикулу и названию">
   <button type="button" class="ui-th-search-clear" aria-label="Очистить поиск"><i class="fa fa-times"></i></button></div></th>.
   При перерисовке шапки страница создаёт поле один раз и переносит тот же узел в новую шапку, а фокус и положение курсора
   возвращает сама (при переносе узла браузер сбрасывает фокус). Эталон — «Выкуп и доход по артикулам» (столбец «Товар») и
   «Аналитика выплат» (лента продаж). */
.ui-th-search {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
}

.ui-th-search-input {
    width: 100%;
    height: 28px;
    padding: 2px 26px 2px 30px;
    border: 1px solid var(--ui-border);
    border-radius: 6px;
    background: var(--ui-surface);
    color: var(--ui-ink);
    font: inherit;
    font-size: 13px;
    font-weight: 400;
}

.ui-th-search-input:focus {
    border-color: var(--ui-accent);
    outline: none;
    box-shadow: 0 0 0 3px rgba(60, 141, 188, 0.22);
}

.ui-th-search.is-active .ui-th-search-input {
    border: 2px solid var(--ui-accent);
}

.ui-th-search.is-active .ui-th-search-icon {
    color: var(--ui-accent);
}

.ui-th-search-icon {
    position: absolute;
    top: 7px;
    left: 9px;
    color: var(--ui-ink-muted);
    font-size: 14px;
    pointer-events: none;
}

.ui-th-search-clear {
    position: absolute;
    top: 0;
    right: 0;
    width: 26px;
    height: 28px;
    border: 0;
    background: transparent;
    color: var(--ui-ink-muted);
    font-size: 13px;
    cursor: pointer;
}

.ui-th-search:not(.is-active) .ui-th-search-clear {
    display: none;
}

.ui-th-search-clear:hover,
.ui-th-search-clear:focus-visible {
    color: var(--ui-accent-ink);
}

/* ---------- Прилипающая шапка таблицы ----------
   Класс на .list-table-card (или на самой таблице): шапка столбцов остаётся под строкой верхнего меню при прокрутке.
   Смещение — переменная --ui-sticky-top (по умолчанию высота липкой строки меню --tn-bar-h из topnav.css; страница с
   дополнительной липкой панелью задаёт своё). Вместо горизонтальной прокрутки карточки у таблицы с этим классом
   прокручивается страница: sticky не работает у предка с overflow, поэтому overflow карточки и цепочки предков снят
   (тот же приём, что у «Склада» и «Ценообразования ЯМ»). Только для таблицы, помещающейся в ширину: у таблицы шире экрана
   шапка полосой — .ui-sticky-band ниже. Сплошной фон шапки и линия box-shadow — иначе строки просвечивают
   сквозь шапку, а обычная нижняя граница под sticky уезжает. */
.content-wrapper:has(.ui-sticky-head),
.content:has(.ui-sticky-head) {
    overflow: visible;
}

.list-table-card.ui-sticky-head,
.list-table-card:has(.ui-sticky-head) {
    overflow: visible !important;
}

.ui-sticky-head thead th {
    position: sticky;
    top: var(--ui-sticky-top, var(--tn-bar-h, 42px));
    z-index: 4;
    border-bottom: 0;
    background-color: var(--table-header-bg, var(--ui-segments-bg));
    background-clip: padding-box;
    box-shadow: 0 2px 0 var(--table-border, #d1d5db);
}

/* Без overflow карточка не обрезает углы: скругляем крайние ячейки шапки и последней строки под радиус карточки. */
.ui-sticky-head thead > tr:first-child > th:first-child {
    border-top-left-radius: var(--table-radius, 8px);
}

.ui-sticky-head thead > tr:first-child > th:last-child {
    border-top-right-radius: var(--table-radius, 8px);
}

.ui-sticky-head tbody:last-of-type > tr:last-child > td:first-child {
    border-bottom-left-radius: var(--table-radius, 8px);
}

.ui-sticky-head tbody:last-of-type > tr:last-child > td:last-child {
    border-bottom-right-radius: var(--table-radius, 8px);
}

/* ---------- Шапка таблицы шире экрана — полосой под меню ----------
   Таблица шире экрана лежит в карточке .list-table-card с горизонтальной прокруткой, а position: sticky у предка с overflow не
   работает — .ui-sticky-head здесь не годится. Вместо него скрипт UiCore.stickyBand(table, {top}) (или атрибут data-ui-sticky-band
   на <table>) при прокрутке страницы показывает полосу .ui-sticky-band: копию <thead>, закреплённую под верхним меню, с теми же
   ширинами столбцов и той же горизонтальной прокруткой; полоса скрыта, пока шапка таблицы на месте или таблица вне экрана.
   Копия живая для клика (галочка «все», копирование, справка ⓘ), но не для клавиатуры и экранных дикторов: настоящая шапка осталась
   в таблице. Полосу рисует скрипт: <div class="list-table-card ui-sticky-band"><table class="table ui-sticky-band-table" data-ui-band-clone>; классы страницы
   таблица в полосе не получает (вид ячеек шапки скрипт берёт у настоящих th), страница ничего не размечает, кроме атрибута.
   Эталон — «Выкуп и доход по артикулам» (своя копия того же приёма) и «Проверка приёмки площадками». */
.list-table-card.ui-sticky-band {
    position: fixed;
    z-index: 1020; /* ниже строки меню (1030) и окон, выше строк таблицы */
    overflow: hidden;
    margin: 0;
    border-top: 0;
    border-radius: 0;
    background: var(--ui-surface);
    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.08);
}

.list-table-card.ui-sticky-band[hidden] {
    display: none;
}

.ui-sticky-band > .table {
    margin: 0;
    table-layout: fixed;
}

.ui-sticky-band > .table > thead > tr > th {
    box-sizing: border-box; /* ширины столбцов скрипт берёт у настоящей шапки как полные (с рамкой и отступами) */
    background-color: var(--table-header-bg, var(--ui-segments-bg));
    background-clip: padding-box;
}

/* ---------- Сегментный переключатель ----------
   Серая полоса, активный сегмент — белая карточка с лёгкой тенью, без рамок (вид «10/10» владельца 2026-10-06). Сегмент —
   <button class="ui-segment [is-active]"> или <label class="ui-segment"><input type="radio" name="…"><span>Текст</span></label>
   (радио скрыт, активным считается отмеченный). Плотный вариант — .ui-segments-sm (padding 4×10).
   Эталон — «Все / Едут / Выкуплено / Не выкуплено» («Статусы заказов») и режимы «Топ по доходу…» в «Выкуп и доход». */
.ui-segments {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 2px;
    padding: 2px;
    border-radius: 8px;
    background: var(--ui-segments-bg);
    vertical-align: middle;
}

.ui-segment {
    position: relative;
    margin: 0;
    padding: 6px 12px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--ui-ink-secondary);
    font-family: inherit;
    font-size: var(--ui-text-sm);
    font-weight: 600;
    line-height: 1.43;
    white-space: nowrap;
    cursor: pointer;
}

.ui-segment:hover {
    color: var(--ui-ink);
}

.ui-segment input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.ui-segment.is-active,
.ui-segment:has(input:checked) {
    background: var(--ui-surface);
    color: var(--ui-ink);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}

.ui-segment:focus-visible,
.ui-segment:has(input:focus-visible) {
    outline: 2px solid var(--ui-accent);
    outline-offset: 1px;
}

/* ---------- Плитки итогов ----------
   Плитка с цветной полосой слева 6 px: подпись, крупное число, мелкая строка под ним. Цвет полосы — переменная
   --ui-tile-accent или готовый тон-класс .ui-tile-blue и соседи. Сетка плиток — .ui-stat-tiles (auto-fit от 170 px; у .ui-stat-tiles-compact от 150 px).
   Эмодзи в подписи — по правилу владельца «значки эмодзи везде, где уместны». Эталон — «Выкуп и доход по артикулам»
   и «График продаж». */
.ui-stat-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: 10px;
}

.ui-stat-tile {
    position: relative;
    overflow: hidden;
    padding: 12px 14px 12px 20px;
    border: 1px solid #dee2e6;
    border-radius: var(--table-radius, 8px);
    background: var(--ui-surface);
}

.ui-stat-tile::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 6px;
    background: var(--ui-tile-accent, var(--ui-ink-muted));
}

.ui-tile-blue { --ui-tile-accent: #3b82d6; }
.ui-tile-green { --ui-tile-accent: #2f9e5f; }
.ui-tile-navy { --ui-tile-accent: #1e56a8; }
.ui-tile-orange { --ui-tile-accent: #e0913c; }
.ui-tile-purple { --ui-tile-accent: #8a6bbf; }
.ui-tile-red { --ui-tile-accent: #c9483a; }

.ui-stat-tile-label {
    margin-bottom: 4px;
    color: var(--ui-ink-muted);
    font-size: var(--ui-text-sm);
    font-weight: 700;
}

.ui-stat-tile-value {
    color: var(--ui-ink);
    font-size: 22px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.ui-stat-tile-sub {
    margin-top: 2px;
    color: var(--ui-ink-secondary);
    font-size: var(--ui-text-sm);
}

/* ---------- Инфо-плашка со сводкой в пилюлях ----------
   Светло-синяя плашка (как .info-block из site.css) с подписью и цветными пилюлями: сводка состава в одну строку, не для таблиц.
   Разметка: <div class="ui-pills"><span class="ui-pills-caption">Дата отгрузки …</span><span class="ui-pill ui-pill-info">
   На сборке: <strong>511</strong></span>…</div>. Тон пилюли — смысл: info — в работе, ok — готово, warn — внимание,
   bad — потери, muted — нейтрально. Эталон — плашка «Подтверждение сборки» (ca-stat-pill) и сводка сегментов в «Ценообразование ЯМ»
   (.ym-assortment-segments). */
.ui-pills {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 10px;
    margin-bottom: 14px;
    padding: 12px 16px;
    border: 1px solid #bfdbfe;
    border-radius: 12px;
    background: #eff6ff;
    color: var(--ui-ink);
    line-height: 1.5;
}

.ui-pills-caption {
    font-size: 0.95em;
}

.ui-pill {
    display: inline-block;
    padding: 4px 12px;
    border-radius: 20px;
    font-size: 1.05em;
    line-height: 1.3;
}

.ui-pill strong {
    font-weight: 700;
}

.ui-pill-info { background: #dbeafe; color: #1e4a8a; }
.ui-pill-ok { background: #dcfce7; color: #15602c; }
.ui-pill-warn { background: #fef3c7; color: #92400e; }
.ui-pill-bad { background: #fee2e2; color: #991b1b; }
.ui-pill-muted { background: #e5e7eb; color: #444; }

/* ---------- Точка статуса ----------
   Круглая точка 8 px цвета состояния и подпись рядом, без подложки: <span class="ui-status-dot ui-status-dot-ok"></span>Собран.
   Тоны те же, что у пилюль. Эталон — «Сборка у нас» в «Проверке приёмки площадками». */
.ui-status-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 6px;
    border-radius: 50%;
    background: #c0c4cc;
    vertical-align: 1px;
}

.ui-status-dot-info { background: #3b82d6; }
.ui-status-dot-ok { background: #22c55e; }
.ui-status-dot-warn { background: #f59e0b; }
.ui-status-dot-bad { background: #ef4444; }
.ui-status-dot-muted { background: #6b7280; }

/* ---------- Тихая кнопка-значок ----------
   Значок без рамки и подложки (копировать, правка, ссылка): серый, при наведении темнее, после действия .is-done — зелёный.
   Разметка: <button type="button" class="ui-icon-btn" aria-label="…"><i class="fa fa-clone"></i></button>. Для главных действий
   строки — обычные btn-default, не этот класс. */
.ui-icon-btn {
    padding: 2px 6px;
    border: 1px solid transparent;
    border-radius: var(--btn-border-radius, 8px);
    background: none;
    color: var(--ui-ink-muted);
    line-height: 1.4;
    cursor: pointer;
    transition: color 0.15s;
}

.ui-icon-btn:hover,
.ui-icon-btn:focus-visible {
    color: var(--ui-ink);
    outline: 0;
}

/* ---------- Строка-группа в таблице ----------
   Магазин, площадка, этап — строка-заголовок группы на фоне --table-stripe, под ней строки группы. Группа — свой tbody
   с классом .ui-group (раскрыта — ещё .is-open), шапка столбцов у таблицы одна; клик по строке сворачивает и раскрывает
   (js/ui-core.js), свёрнутая группа прячет всё, кроме строки-группы. Внутри строки: .ui-group-toggle (кнопка с названием)
   с .ui-chevron (шеврон поворачивается у .is-open — и у кнопки-разворота вне таблицы: .is-open > .ui-chevron), .ui-group-line — подписи в строку с переносом. Таблица — с .no-stripe:
   зебра и строки-группы вместе читаются хуже. Строка-группа может быть обычной строкой таблицы из нескольких ячеек (мастер-строка: название и числа
   группы по столбцам таблицы) — класс .ui-group-row на tr и клик по всей строке те же. Эталон — магазины в «Проверке приёмки площадками»;
   мастер-строка с вложенными заказами — лента «Аналитики выплат» в виде «По товарам». */
.list-table-card > .table > tbody > tr.ui-group-row > td,
.list-table-card > .table:not(.no-stripe) > tbody > tr.ui-group-row > td {
    background: var(--table-stripe, #fafbfc);
    cursor: pointer;
}

.ui-group:not(.is-open) > tr:not(.ui-group-row) {
    display: none;
}

/* Вложенная строка группы: заказы под строкой-артикулом, записи под основанием. Класс ставится на tr рядом с остальными строками
   группы (прячет и показывает их то же правило, что выше): первая ячейка с отступом и приглушённой левой кромкой — видно, что строка
   принадлежит группе над ней. Примечание в конце группы («показаны первые 200 из N», «не удалось загрузить») — тоже строка
   .ui-group-child, на всю ширину таблицы. Эталон — «Лента продаж» в виде «По товарам» («Аналитика выплат»). */
.list-table-card > .table > tbody > tr.ui-group-child > td:first-child {
    padding-left: 24px;
    box-shadow: inset 3px 0 0 var(--ui-border);
}

.ui-group-line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 14px;
    white-space: normal;
}

.ui-group-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
}

.ui-group-toggle:focus-visible {
    outline: 2px solid var(--ui-accent);
    outline-offset: 2px;
}

.ui-chevron {
    width: 10px;
    color: var(--ui-ink-muted);
    font-size: 11px;
    transition: transform 0.15s ease;
}

.ui-group.is-open .ui-chevron,
.is-open > .ui-chevron {
    transform: rotate(90deg);
}

/* ---------- Всплывающая карточка: одна на все подсказки ----------
   Решение владельца 2026-10-08 («не хочется рандома»): всё, что всплывает при наведении, — одна светлая карточка .ui-pop,
   как подсказка графика продаж: справка ⓘ (что это, формула, пункты) и состав числа в ячейке (пары «ключ — значение»)
   отличаются содержанием, не видом. Тёмных плашек и подсказок Bootstrap нет. Разметка: <div class="ui-pop" role="tooltip">
   <div class="ui-pop-title">Заголовок</div> … </div>; пары — .ui-pop-row > .ui-pop-key + .ui-pop-value, черта перед итогом —
   .ui-pop-sep. Положение (position: fixed по координатам якоря) ставит JS: справку ⓘ — ядро, свою подсказку — страница. */
.ui-pop {
    position: fixed;
    z-index: 1100;
    display: flex;
    flex-direction: column;
    max-width: 380px;
    padding: 12px 16px;
    border: 1px solid var(--ui-border);
    border-radius: 8px;
    background: var(--ui-surface);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
    color: var(--ui-ink);
    font-size: var(--ui-text-sm);
    line-height: 18px;
    font-variant-numeric: tabular-nums;
    white-space: normal;
    pointer-events: none;
}

.ui-pop[hidden] {
    display: none;
}

.ui-pop-title {
    margin-bottom: 8px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--ui-border);
    font-weight: 700;
}

.ui-pop-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 3px 0;
}

.ui-pop-key {
    color: var(--ui-ink-secondary);
}

.ui-pop-value {
    font-weight: 700;
}

.ui-pop-sep {
    margin: 6px 0;
    border-top: 1px solid var(--ui-border);
}

/* Тело карточки из блоков (строка «что это», формула, пункты, пример) — с ровным шагом между ними. */
.ui-pop-body {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* ---------- Формула ----------
   Формула в справке и в подсказке-расчёте: термины плашками (.ui-formula-term), знаки (.ui-formula-op), деление — только
   дробью .ui-formula-frac (числитель .ui-formula-num над чертой, знаменатель .ui-formula-den), знак ÷ не пишется (замечание
   владельца 2026-10-08). Знак с соседним термином — .ui-formula-pair без переноса внутри. .ui-formula-plain — та же формула
   числами, без плашек и подложки (значения .ui-formula-val, итог — .ui-formula-result). Собирает UiCore.formula(parts,
   {plain}), parts — строки (знаки = + − × ( ) и термины) и {frac: [числитель, знаменатель]}. */
/* Формула по ширине содержимого, не на всю карточку; переносов внутри не бывает — формула пишется так, чтобы влезть в строку. */
.ui-formula {
    display: flex;
    flex-wrap: wrap;
    align-self: flex-start;
    align-items: center;
    gap: 4px 5px;
    padding: 6px 8px;
    border-radius: 6px;
    background: var(--ui-segments-bg);
}

.ui-formula-plain {
    padding: 0;
    background: none;
}

.ui-formula-term {
    padding: 1px 6px;
    border: 1px solid var(--ui-border);
    border-radius: 4px;
    background: var(--ui-surface);
    font-weight: 600;
    white-space: nowrap;
}

.ui-formula-val {
    white-space: nowrap;
}

.ui-formula-result {
    font-weight: 700;
}

.ui-formula-op {
    color: var(--ui-ink-muted);
    font-weight: 600;
}

.ui-formula-pair,
.ui-formula-num,
.ui-formula-den {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    white-space: nowrap;
}

.ui-formula-frac {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    vertical-align: middle;
}

.ui-formula-num {
    padding: 0 2px 3px;
}

.ui-formula-den {
    padding: 3px 2px 0;
    border-top: 1px solid var(--ui-ink-muted); /* черта приглушённая: не перетягивает взгляд с терминов (замечание владельца 2026-10-08) */
}

/* ---------- Справка ⓘ у заголовка ----------
   Тихий значок fa-info-circle рядом с названием столбца или поля; справка — карточка .ui-pop (заголовок над чертой + текст)
   при наведении, фокусе и нажатии (js/ui-core.js рисует её в body, position: fixed: прокручиваемая таблица её не обрежет).
   Разметка: <button type="button" class="ui-hint" data-ui-hint-title="Остаток" data-ui-hint="Что значит число"
   aria-label="Справка: Остаток"><i class="fa fa-info-circle"></i></button>. Вместо системного title (его не видно сразу и
   не стилизовать). Перенос строки в data-ui-hint (\n, в HTML-атрибуте &#10;) — новая строка. Справка, где больше двух фраз
   или есть формула, — разметкой (замечание владельца 2026-10-08: сплошной абзац не читается): <template class="ui-hint-content">
   внутри кнопки с .ui-hint-lead (что это), .ui-formula (формула), .ui-hint-list (пункты), .ui-hint-example (пример),
   .ui-hint-warn (оговорка); из кода — UiCore.hint(title, spec). Эталон — «Проверка приёмки площадками», разметка —
   «Выкуп и доход по артикулам»; состав числа в ячейке — стандарт «UI — всплывающие подсказки». */
.ui-hint {
    display: inline-block;
    margin-left: 5px;
    padding: 0 2px;
    border: 0;
    background: none;
    color: var(--ui-ink-muted);
    font-size: var(--ui-text-sm);
    line-height: 1;
    vertical-align: baseline;
    cursor: help;
    transition: color 0.15s;
}

.ui-hint:hover,
.ui-hint:focus-visible {
    color: var(--ui-accent);
}

.ui-hint:focus-visible {
    outline: 2px solid var(--ui-accent);
    outline-offset: 1px;
    border-radius: 50%;
}

.ui-hint-text {
    white-space: pre-line;
}


.ui-hint-list {
    margin: 0;
    padding-left: 16px;
}

.ui-hint-list li + li {
    margin-top: 2px;
}

.ui-hint-example {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 5px;
    color: var(--ui-ink-secondary);
}

.ui-hint-warn {
    padding-top: 8px;
    border-top: 1px solid var(--ui-border);
}

/* ---------- Пустое состояние ----------
   Нет данных за выбор: одна строка приглушённым текстом под фильтрами, без картинок и рамок. Разметка: <p class="ui-empty">Заказов нет.</p>.
   Эталон — «Проверка приёмки площадками». */
/* Отступы сверху и снизу равные: внутри карточки или блока строка стоит по центру (замечание владельца 2026-10-06). */
.ui-empty {
    margin: 12px 0;
    color: var(--ui-ink-muted);
}

/* ---------- Чекбокс 20×20 ----------
   Стандарт интерфейса (AGENTS §8): все чекбоксы выбора в таблицах и формах — 20×20 px, по центру строки. Эталон — выбор
   заказов для печати этикеток в «Проверке приёмки площадками». */
.ui-check {
    width: 20px;
    height: 20px;
    margin: 0;
    vertical-align: middle;
    cursor: pointer;
}

.ui-check:disabled {
    cursor: not-allowed;
}

/* Чекбокс с подписью — одной строкой по центру: подпись .ui-check-label (и любой label, в котором чекбокс стоит первым)
   выравнивает квадрат и текст по середине, без «подпрыгивания» текста (замечание владельца 2026-10-06: частая проблема). */
.ui-check-label,
label:has(> .ui-check) {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    font-weight: 600;
    line-height: 20px;
    cursor: pointer;
}

.ui-check-label:has(> .ui-check:disabled),
label:has(> .ui-check:disabled) {
    color: var(--ui-ink-muted, #8a8f98);
    cursor: not-allowed;
}

/* ---------- Действия над списком галочек ----------
   Над списком галочек (поставщики, магазины, любой выбор из многих) — две тихие кнопки в одну строку, поровну на всю ширину блока:
   «Выделить все» и «Сбросить все». Белая кнопка с рамкой ядра, мелкий шрифт; при наведении рамка и подпись — акцентом. Кнопка,
   которой нечего делать (все уже отмечены / все сняты), недоступна. Пояснение к списку стоит под ним, не над кнопками.
   Разметка: <div class="ui-check-actions"><button type="button" class="btn btn-default ui-check-action">Выделить все</button>
   <button type="button" class="btn btn-default ui-check-action">Сбросить все</button></div>, затем список. Эталон — блок «Поставщики»
   на «Аналитике выплат» (компонент AnalyticsSuppliers, js/analytics-filters.js). */
.ui-check-actions {
    display: flex;
    gap: 8px;
    margin: 0 0 8px;
}

.ui-check-actions .ui-check-action {
    flex: 1 1 0;
    min-width: 0;
    padding: 4px 10px;
    border: 1px solid var(--ui-border);
    border-radius: var(--btn-border-radius, 8px);
    background: var(--ui-surface);
    color: var(--ui-ink-secondary);
    font-size: var(--ui-text-xs);
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
    transition: color 0.15s, border-color 0.15s, background-color 0.15s;
}

.ui-check-actions .ui-check-action:hover:not(:disabled),
.ui-check-actions .ui-check-action:focus-visible:not(:disabled) {
    border-color: var(--ui-accent);
    background: var(--ui-accent-soft);
    color: var(--ui-accent-ink);
    outline: 0;
}

.ui-check-actions .ui-check-action:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* ---------- Окно поверх страницы (.ui-modal) ----------
   Общая оболочка окон: затемнение на весь экран, белая коробка по центру сверху, заголовок, тело, кнопки «Отмена / Подтвердить».
   Закрывают Esc, щелчок по затемнению и любой [data-ui-modal-close]; фокус уходит в поле (UiCore.modal.open) и возвращается на
   кнопку, открывшую окно. Окно с data-ui-modal-static не закрывается ни Esc, ни затемнением — для операции, которую нельзя прервать
   случайно (прогресс). Ширина — переменная --ui-modal-width (520 px по умолчанию). Разметка:
   <div class="ui-modal" id="…" role="dialog" aria-modal="true" aria-labelledby="…-title" hidden><div class="ui-modal-box">
   <button type="button" class="ui-modal-close" data-ui-modal-close aria-label="Закрыть">&times;</button>
   <h4 class="ui-modal-title" id="…-title">Заголовок</h4><div class="ui-modal-body">…</div>
   <div class="ui-modal-footer"><button class="btn btn-default" data-ui-modal-close>Отмена</button><button class="btn btn-primary">Подтвердить</button></div></div></div>.
   Открыть и закрыть из кода — UiCore.modal.open(el, {focus}) и UiCore.modal.close(el); событие ui:modal-close всплывает от окна.
   Эталон вида — «Подтверждение сборки» (#ca-stock-edit-modal, на Bootstrap-модалке; на .ui-modal он не переведён) и
   «Проверка приёмки площадками». */
.ui-modal {
    position: fixed;
    inset: 0;
    z-index: 1050;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 80px 16px 16px;
    background: rgba(0, 0, 0, 0.45);
    overflow-y: auto;
}

.ui-modal[hidden] {
    display: none;
}

.ui-modal-box {
    position: relative;
    width: 100%;
    max-width: var(--ui-modal-width, 520px);
    padding: 20px 24px 18px;
    border-radius: 6px;
    background: var(--ui-surface);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25);
    color: var(--ui-ink);
}

.ui-modal-title {
    margin: 0 28px 16px 0;
    font-size: var(--ui-text-lg);
    font-weight: 600;
}

.ui-modal-close {
    position: absolute;
    top: 12px;
    right: 14px;
    border: 0;
    background: none;
    color: var(--ui-ink-muted);
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
}

.ui-modal-close:hover {
    color: var(--ui-ink);
}

.ui-modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 18px;
}

/* Содержимое окна «Правка значения»: товар (миниатюра .ui-thumb 64 + артикул крупно и название), «сейчас → новое» крупно,
   ошибка, поясняющая строка. Разметка полей — в витрине /ui-kit, раздел «Окно правки значения». */
.ui-modal-product {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 16px;
}

.ui-modal-product-info {
    min-width: 0;
}

.ui-modal-product-sku {
    margin-bottom: 4px;
    font-size: 22px;
    font-weight: 700;
    line-height: 1.1;
}

.ui-modal-product-name {
    color: var(--ui-ink-secondary);
    font-size: var(--ui-text-sm);
    line-height: 1.35;
}

.ui-edit-compare {
    display: flex;
    align-items: flex-end;
    gap: 16px;
}

.ui-edit-label {
    display: block;
    margin-bottom: 4px;
    color: var(--ui-ink-muted);
    font-size: var(--ui-text-xs);
    font-weight: 600;
    text-transform: uppercase;
}

.ui-edit-current-box {
    flex: 0 0 auto;
}

.ui-edit-current {
    font-size: var(--ui-text-xl);
    font-weight: 700;
    line-height: 46px;
}

.ui-edit-arrow {
    flex: 0 0 auto;
    color: var(--ui-ink-muted);
    font-size: 24px;
    line-height: 46px;
}

.ui-edit-new-box {
    flex: 1 1 auto;
}

.ui-edit-input {
    height: 46px;
    font-size: 22px;
    font-weight: 700;
}

.ui-modal-error {
    margin-top: 12px;
    padding: 8px 12px;
    border: 1px solid var(--ui-bad-line);
    border-radius: 4px;
    background: var(--ui-bad-bg);
    color: var(--ui-bad-ink);
    font-size: var(--ui-text-sm);
}

.ui-modal-error[hidden],
.ui-modal-note[hidden] {
    display: none;
}

/* Плашка-предупреждение в окне (правка не того, что на экране): янтарная, одна крупная строка и мелкая подпись. */
.ui-modal-note {
    margin: 0 0 14px;
    padding: 10px 12px;
    border-left: 4px solid var(--ui-warn-ink);
    background: var(--ui-warn-bg);
    color: var(--ui-warn-ink);
    line-height: 1.35;
}

.ui-modal-note small {
    display: block;
    margin-top: 4px;
    font-size: var(--ui-text-xs);
}

.ui-modal-help {
    margin: 10px 0 0;
    color: var(--ui-ink-muted);
    font-size: var(--ui-text-xs);
}

/* ---------- Прогресс-бар (.ui-progress) ----------
   Стандарт «UI — прогресс-бары и ожидание»: обёртка высотой 6 px на сером фоне, внутри полоса с градиентом синий → зелёный и
   плавной шириной; без полосок и бегущей анимации. Счётчик («Проверено 50 из 240») — рядом с полосой, не внутри. Общая полоса над
   подчинёнными — .ui-progress-master (12 px). Ширину ставит UiCore.setProgress(el, процент) или атрибут data-ui-progress="62".
   Разметка: <div class="ui-progress-line"><div class="ui-progress" role="progressbar" aria-valuemin="0" aria-valuemax="100"
   data-ui-progress="62"><div class="ui-progress-bar"></div></div><span class="ui-progress-count">Проверено 31 из 50</span></div>.
   Отступ 10 px над полосой — правило ниже. Эталон — «Парсинг заказов» и окно проверки в «Проверке приёмки площадками»; страницы, где идёт долгая операция, берут эти классы. */
.ui-progress-line {
    display: flex;
    align-items: center;
    gap: 12px;
}

.ui-progress-line .ui-progress {
    flex: 1 1 auto;
}

.ui-progress-count {
    flex: 0 0 auto;
    color: var(--ui-ink-secondary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.ui-progress {
    height: 6px;
    border-radius: 3px;
    background: var(--ui-progress-track);
    overflow: hidden;
}

.ui-progress-bar {
    width: 0;
    height: 100%;
    border-radius: 3px;
    background: linear-gradient(90deg, var(--ui-progress-from), var(--ui-progress-to));
    transition: width 0.4s ease;
}

.ui-progress-master {
    height: 12px;
    border-radius: 6px;
}

.ui-progress-master .ui-progress-bar {
    border-radius: 6px;
}

/* Отступ: полоса или строка «полоса + счётчик» ниже счётчика, сводки или другой полосы отступает на 10 px; сама полоса в строке с
   подписью (.ui-progress-line, первый потомок) — без отступа. */
.ui-progress:not(:first-child),
.ui-progress-line:not(:first-child) {
    margin-top: 10px;
}

/* ---------- Загрузка данных (.ui-skeleton, .ui-load, .ui-busy) ----------
   Что показывать, пока данных ещё нет или они перезагружаются; выбор по ситуации. Первая загрузка таблицы или плиток, форма блока известна
   заранее, — болванки .ui-skeleton (пульсирующие серые плитки и строки на месте будущих). Графики и диаграммы — столбики .ui-load-bars,
   ожидание ответа площадок — точки .ui-load-dots цветов площадок, кнопка, ячейка или строка — кольцо .ui-load-ring. Смена фильтра или периода
   при уже показанных данных — .ui-busy на том же блоке: данные приглушены, поверх по центру оверлей .ui-busy-overlay со значком этого блока
   (графики — столбики, таблицы и плитки — кольцо); при первой загрузке пустого блока оверлей несёт подпись (UiCore.busy(el, true, kind, подпись)). Разметку строят
   UiCore.loader(el, 'bars'|'dots'|'ring', подпись), UiCore.skeleton(el, {tiles, rows}) и UiCore.busy(el, on, kind, подпись) — страница своей вёрстки не пишет. Руками: <div class="ui-load"><span class="ui-load-bars"><i></i><i></i><i></i><i></i><i></i></span>
   <div class="ui-load-text">Считаем продажи…</div></div>; кольцо в кнопке: <button class="btn btn-default"><span class="ui-load-ring"></span> Обновляю</button>.
   Размеры — токены --ui-load-* (кольцо --ui-load-ring-size и --ui-load-ring-width, высота значков, минимальная высота блока ожидания, высота болванок плитки и
   строки); цвета — токены ядра и цвета площадок --mp-*. Имена .ui-spinner и .ui-loader заняты jQuery UI и jQuery Mobile — не использовать.
   При prefers-reduced-motion анимации выключены: болванки, столбики, точки и кольцо стоят на месте. Эталон — «График продаж» (аналитика). */
@keyframes ui-skeleton-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

@keyframes ui-load-grow {
    0%, 100% { transform: scaleY(0.25); }
    50% { transform: scaleY(1); }
}

@keyframes ui-load-bounce {
    0%, 60%, 100% { transform: translateY(0); }
    30% { transform: translateY(-12px); }
}

@keyframes ui-load-spin {
    to { transform: rotate(360deg); }
}

/* Болванка: нейтральная заливка с пульсом; соседние болванки пульсируют волной (задержка по порядку, шаг 0,15 с, цикл из шести). */
.ui-skeleton {
    display: block;
    border-radius: 4px;
    background: var(--ui-progress-track);
    animation: ui-skeleton-pulse 1.4s ease-in-out infinite;
}

.ui-skeleton:nth-child(6n + 2) { animation-delay: 0.15s; }
.ui-skeleton:nth-child(6n + 3) { animation-delay: 0.3s; }
.ui-skeleton:nth-child(6n + 4) { animation-delay: 0.45s; }
.ui-skeleton:nth-child(6n + 5) { animation-delay: 0.6s; }
.ui-skeleton:nth-child(6n + 6) { animation-delay: 0.75s; }

.ui-skeleton-tile {
    height: var(--ui-skeleton-tile-height);
}

.ui-skeleton-line {
    height: 10px;
}

.ui-skeleton-line + .ui-skeleton-line {
    margin-top: 8px;
}

.ui-skeleton-line-short {
    width: 40%;
}

.ui-skeleton-row {
    height: var(--ui-skeleton-row-height);
}

/* Группы болванок: плитки — сеткой .ui-stat-tiles (класс сетки добавляет скрипт), строки — столбцом. */
.ui-skeleton-tiles:not(:last-child) {
    margin-bottom: 14px;
}

.ui-skeleton-rows {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* Строки-болванки внутри карточки таблицы (.list-table-card, site.css) не липнут к её рамке. */
.list-table-card > .ui-skeleton-rows {
    padding: 10px 12px;
}

/* Блок, который сам сетка плиток (.ui-stat-tiles): строки-болванки занимают всю ширину под плитками. */
.ui-stat-tiles > .ui-skeleton-rows {
    grid-column: 1 / -1;
}

/* Блок ожидания: значок над подписью по центру места будущих данных. */
.ui-load {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    min-height: var(--ui-load-height);
    padding: 16px;
    box-sizing: border-box;
}

.ui-load-text {
    color: var(--ui-ink-muted);
    font-size: var(--ui-text-sm);
    text-align: center;
}

/* Столбики для графиков: пять столбиков растут волной от низа, три первых акцентные, два последних зелёные (как конец прогресс-бара). */
.ui-load-bars {
    display: inline-flex;
    align-items: flex-end;
    gap: 4px;
    height: var(--ui-load-icon-size);
}

.ui-load-bars i {
    display: block;
    width: 6px;
    height: 100%;
    border-radius: 2px;
    background: var(--ui-accent);
    transform: scaleY(0.25);
    transform-origin: bottom;
    animation: ui-load-grow 1.1s ease-in-out infinite;
}

.ui-load-bars i:nth-child(n + 4) { background: var(--ui-progress-to); }
.ui-load-bars i:nth-child(2) { animation-delay: 0.12s; }
.ui-load-bars i:nth-child(3) { animation-delay: 0.24s; }
.ui-load-bars i:nth-child(4) { animation-delay: 0.36s; }
.ui-load-bars i:nth-child(5) { animation-delay: 0.48s; }

/* Точки площадок: пять точек цветов Ozon, Wildberries, Яндекс Маркета, Авито и Temu прыгают волной; запас сверху держит место под прыжок. */
.ui-load-dots {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding-top: 12px;
}

.ui-load-dots i {
    display: block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--ui-accent);
    animation: ui-load-bounce 1.2s ease-in-out infinite;
}

.ui-load-dots i:nth-child(1) { background: var(--mp-ozon-bg, var(--ui-progress-from)); }
.ui-load-dots i:nth-child(2) { background: var(--mp-wb-bg, var(--ui-accent)); animation-delay: 0.15s; }
.ui-load-dots i:nth-child(3) { background: var(--mp-ym-bg, var(--ui-accent)); animation-delay: 0.3s; }
.ui-load-dots i:nth-child(4) { background: var(--mp-avito-bg, var(--ui-accent)); animation-delay: 0.45s; }
.ui-load-dots i:nth-child(5) { background: var(--mp-temu-bg, var(--ui-accent)); animation-delay: 0.6s; }

/* Кольцо: встаёт в строку текста (кнопка, ячейка, строка); размер и толщину задают токены, крупное — .ui-load-ring-lg. */
.ui-load-ring {
    display: inline-block;
    vertical-align: middle;
    box-sizing: border-box;
    width: var(--ui-load-ring-size);
    height: var(--ui-load-ring-size);
    border: var(--ui-load-ring-width) solid var(--ui-progress-track);
    border-top-color: var(--ui-accent);
    border-radius: 50%;
    animation: ui-load-spin 0.8s linear infinite;
}

.ui-load-ring-lg {
    --ui-load-ring-size: 28px;
    --ui-load-ring-width: 3px;
}

/* Кольцо в кнопке: на цветной кнопке (синяя, зелёная, красная) акцентный верх сливается с фоном — кольцо берёт цвет текста кнопки
   с полупрозрачной дорожкой; в мелкой кнопке .btn-xs кольцо меньше, чтобы кнопка не меняла высоту. Разметка — кольцо, пробел, текст
   («<span class="ui-load-ring"></span> Проверяю…»): отступ 3 px вместе с пробелом дают ~6 px до первой буквы. */
.btn .ui-load-ring {
    margin-right: 3px;
}

.btn-primary .ui-load-ring,
.btn-info .ui-load-ring,
.btn-success .ui-load-ring,
.btn-danger .ui-load-ring,
.btn-warning .ui-load-ring {
    border-color: rgba(255, 255, 255, 0.35);
    border-top-color: currentColor;
}

.btn-xs .ui-load-ring {
    --ui-load-ring-size: 12px;
}

/* Перезагрузка показанных данных: содержимое приглушено и не кликается, оверлей со значком сам не приглушается. Оверлей занимает не выше
   480 px блока и центрирует значок в этой части, чтобы у длинной таблицы значок не уезжал за экран. */
.ui-busy {
    position: relative;
}

.ui-busy > :not(.ui-busy-overlay) {
    opacity: 0.45;
    pointer-events: none;
    transition: opacity 0.15s ease;
}

.ui-busy-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 100%;
    max-height: 480px;
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .ui-skeleton { animation: none; opacity: 0.7; }
    .ui-load-bars i { animation: none; transform: scaleY(0.6); }
    .ui-load-dots i { animation: none; }
    .ui-load-ring { animation: none; }
    .ui-busy > :not(.ui-busy-overlay) { transition: none; }
}

/* ===== зона stock-core ===== */

/* ---------- Прилипающая шапка из нескольких строк (.ui-sticky-head-rows) ----------
   Модификатор к .ui-sticky-head: в <thead> две и более строки (заголовки и строка фильтров с полями ввода). Прилипает не каждая
   ячейка, а весь <thead> одним блоком, иначе строка фильтров уезжает из-под заголовков. Последняя строка шапки — белая, с чёткой
   нижней линией; нижняя линия заголовков — тенью (обычная граница под sticky уезжает). Класс ставится вместе с .ui-sticky-head на
   карточку или таблицу. Эталон — «Склад». */
.ui-sticky-head.ui-sticky-head-rows thead {
    position: sticky;
    top: var(--ui-sticky-top, var(--tn-bar-h, 42px));
    z-index: 4;
}

.ui-sticky-head.ui-sticky-head-rows thead th {
    position: static;
}

.ui-sticky-head.ui-sticky-head-rows thead > tr:not(:last-child) > th {
    box-shadow: 0 2px 0 var(--table-border, #d1d5db);
}

.ui-sticky-head.ui-sticky-head-rows thead > tr:last-child > th,
.ui-sticky-head.ui-sticky-head-rows thead > tr:last-child > td {
    background-color: var(--ui-surface);
    background-clip: padding-box;
    box-shadow: inset 0 -1px 0 var(--table-border, #d1d5db);
}

/* Нижняя граница шапки у таблицы в карточке .list-table-card: правило site.css (.list-table-card > .table > thead > tr > th) специфичнее
   базового .ui-sticky-head, а обычная граница под sticky уезжает — гасим её, линию рисует тень. */
.list-table-card.ui-sticky-head > .table > thead > tr > th,
.list-table-card > .table.ui-sticky-head > thead > tr > th {
    border-bottom: 0;
}

/* ---------- Янтарная плашка настройки (.ui-note-warn) ----------
   Блок «внимание: это меняет поведение запуска» с галочкой и пояснением: «Тестовый режим», «Только парсинг». Янтарный фон и рамка
   токенов предупреждения, скругление 12 px, заголовок-галочка — .ui-check-label (20×20, одной строкой по центру), пояснение
   .ui-note-warn-hint ниже мелким шрифтом. Несколько плашек подряд — каждая в своём блоке. Разметка:
   <div class="ui-note-warn"><label class="ui-check-label"><input type="checkbox" class="ui-check" name="dry_run" value="1">
   <span>Тестовый режим</span></label><p class="ui-note-warn-hint">Что изменится, когда галочка стоит.</p></div>.
   Эталон — «Парсинг заказов» и «Обновление маркетплейсов». */
.ui-note-warn {
    margin-bottom: 14px;
    padding: 10px 14px;
    border: 1px solid var(--ui-warn-line);
    border-radius: 12px;
    background: var(--ui-warn-bg);
    color: var(--ui-warn-ink);
}

.ui-note-warn .ui-check-label {
    color: var(--ui-warn-ink);
}

.ui-note-warn-hint {
    margin: 6px 0 0;
    font-size: 0.85em;
    color: var(--ui-warn-hint);
}

/* ===== зона assembly ===== */

/* ---------- Размеры миниатюры S / M / L ----------
   Базовый размер 64 px (S) — решение владельца 2026-10-06. Страницы, где оператору иногда нужно рассмотреть фото крупнее
   («Подтверждение сборки», «Заказы Авито»), дают переключатель S / M / L: M = 150 px, L = 320 px. Размер задаёт токен
   --ui-thumb-size, свой CSS странице не нужен. Два способа:
   - модификатор на самой миниатюре: <a class="ui-thumb ui-thumb-m"> (150) или <a class="ui-thumb ui-thumb-l"> (320);
   - атрибут на контейнере страницы: <div data-ui-thumb-size="m"> — размер получают все .ui-thumb внутри (токен наследуется),
     в том числе столбцы .ui-col-thumb и .ui-col-product. Атрибут ставит переключатель (js/ui-core.js, [data-ui-thumb-switch]);
     без атрибута размер 64. Окно .ui-modal стоит вне контейнера страницы и остаётся с миниатюрой 64: второй размер в окне —
     дефект (чеклист «Дизайн», пункт 11).
   Ячейка «Товар» .ui-product при L ставит фото над текстом (рядом 320 px оставили бы тексту узкую полоску); тот же вид без
   атрибута контейнера даёт модификатор .ui-product-stack на самой ячейке (вместе с .ui-thumb-l). Эталон — «Подтверждение
   сборки» (/order-processing/orders/confirm-assembly) и «Заказы Авито» (/avito/orders).
   Переключатель живёт в шапке столбца «Фото» / «Товар» (реестр хаба «Дизайн», строка «Миниатюра товара»). В узком столбце «Фото»
   (тут миниатюра 64 px и столбец .ui-col-thumb 86 px) три сегмента в строку не помещаются: столбцу даётся .ui-col-thumb-switch
   (не уже 100 px), переключателю — .ui-segments-th (под подписью, по центру, плотнее .ui-segments-sm). Таблиц на странице
   несколько (по дням) — переключатель в шапке каждой с одним data-ui-thumb-key, выбор подсвечивается во всех. */
.ui-thumb-m,
[data-ui-thumb-size="m"] {
    --ui-thumb-size: 150px;
}

.ui-thumb-l,
[data-ui-thumb-size="l"] {
    --ui-thumb-size: 320px;
}

/* Столбец «Фото» с переключателем S / M / L в шапке: как .ui-col-thumb (миниатюра + 22 px), но не уже 100 px — в 86 px переключатель
   перенёсся бы на вторую строку. Вместо .ui-col-thumb, не вместе с ним: <col class="ui-col-thumb-switch">. */
.ui-col-thumb-switch {
    width: calc(max(var(--ui-thumb-size, 64px), 78px) + 22px);
}

/* Переключатель размера в шапке узкого столбца: на своей строке под подписью «Фото», по центру, плотный (padding 2×8, 12 px). */
.ui-segments-th {
    display: flex;
    width: fit-content;
    margin: 4px auto 0;
}

.ui-segments-th .ui-segment {
    padding: 2px 8px;
    font-size: 12px;
}

/* Столбец ячейки «Товар»: ширина = миниатюра + место под артикул и две строки названия; при L (фото над текстом) — миниатюра + отступы. */
.ui-col-product {
    width: calc(var(--ui-thumb-size, 64px) + 250px);
}

[data-ui-thumb-size="l"] .ui-col-product {
    width: calc(var(--ui-thumb-size) + 40px);
}

.ui-product-stack,
[data-ui-thumb-size="l"] .ui-product {
    flex-direction: column;
    align-items: flex-start;
    max-width: none;
}

/* Кнопка копирования, когда копировать нечего (фильтр скрыл все строки): на 1,6 с жёлтая с значком «нельзя» (js/ui-core.js). */
.ui-th-copy-btn.is-empty,
.ui-icon-btn.is-empty {
    border-color: var(--ui-warn-line);
    background: var(--ui-warn-bg);
    color: var(--ui-warn-ink);
}

/* Переключатель размера — .ui-segments из сегментов-кнопок: <div class="ui-segments" data-ui-thumb-switch=".страница"
   data-ui-thumb-key="ключСохранения"><button type="button" class="ui-segment is-active" data-ui-thumb-size-btn="s">S</button>…</div>.
   Выбор запоминается в localStorage под ключом из data-ui-thumb-key. */

/* ===== зона analytics-pricing ===== */

/* Плитки итогов: плотная сетка от 150 px (график продаж с плитками площадок). */
.ui-stat-tiles-compact {
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}

/* Сегментный переключатель: плотный вариант (переключатель в шапке блока, «Все / Едут / Выкуплено / Не выкуплено»). */
.ui-segments-sm .ui-segment {
    padding: 4px 10px;
}

/* Тона пилюль для тарифных сегментов ценообразования: цвет несёт смысл сегмента, а не площадки (токены --pricing-segment-* из
   site.css, стандарт «UI — цвета сегментов ценообразования»). special — спецтариф / «без скидки на доставку», base — базовый
   тариф, reduced — спецтариф со снижением дохода (приглушённый оранжевый). Ошибка расчёта («Нерентабельно») — обычный .ui-pill-bad. */
.ui-pill-segment-special {
    background: var(--pricing-segment-special-bg, #FFCC00);
    color: var(--pricing-segment-special-text, #222);
}

.ui-pill-segment-base {
    background: var(--pricing-segment-base-bg, #e5e7eb);
    color: var(--pricing-segment-base-text, #444);
}

.ui-pill-segment-reduced {
    background: var(--pricing-segment-reduced-bg, #ffedd5);
    color: var(--pricing-segment-reduced-text, #9a3412);
}

/* ---------- Вкладки-«папки» ----------
   Подразделы одного уровня (профили, поставщики, режимы таблицы, папки фото): активная вкладка врастает в тело под ней, как
   выступ папки. Разметка — контейнер .ui-folder-tabs с Bootstrap-вкладками и телом:
   <div class="ui-folder-tabs"><ul class="nav nav-tabs"><li class="active"><a href="#a" data-toggle="tab">Вкладка</a></li>…</ul>
   <div class="tab-content"><div class="tab-pane active" id="a">…</div></div></div>. Полоса вкладок без тела (шапка блока, тело
   лежит отдельно) — .ui-folder-tabs-bar на самом <ul class="nav nav-tabs">. Имя .ui-tabs занято jQuery UI, поэтому .ui-folder-tabs.
   Как «папка» бесшовно втекает в тело: полоса несёт единственный шов — border-bottom; каждый <li> опущен на шов
   (margin-bottom: -1px, на <li>, не на <a>: иначе шов «плавает» на дробном зуме); активная <a> перекрывает шов цветом тела
   (рамка сверху и по бокам, низ — цвет тела, margin-top: -1px, поверх шва); ::after — брусок 3 px цвета тела поверх шва, чтобы
   на дробном DPR (1,25) субпиксель не показал линию под активной вкладкой. !important на геометрии — чтобы перебить AdminLTE
   (.nav-tabs-custom) и Bootstrap; вид настраивается токенами на контейнере, не копией правил:
   --ui-folder-body (цвет тела), --ui-folder-line (рамка и шов), --ui-folder-ink / --ui-folder-ink-active (текст вкладки и
   активной), --ui-folder-radius (скругление вкладки), --ui-folder-gap (зазор между вкладками), --ui-folder-weight (насыщенность
   неактивной). Тело и отступы внутри — страница (модификаторы вида .xxx-modes-tabs), саму «папку» не переписывает.
   Эталон — «Ценообразование Яндекс Маркет» (профили, поставщики, режимы) и карточка товара (разделы и папки фото). */
.ui-folder-tabs,
.ui-folder-tabs-bar {
    --ui-folder-body: var(--ui-surface);
    --ui-folder-line: var(--table-border, #d1d5db);
    --ui-folder-ink: #666;
    --ui-folder-ink-active: #222;
    --ui-folder-radius: 8px;
    --ui-folder-gap: 4px;
    --ui-folder-weight: 500;
}

.ui-folder-tabs {
    margin-bottom: 18px;
    border-radius: 12px;
}

.ui-folder-tabs > .nav-tabs,
.ui-folder-tabs-bar {
    display: flex !important;
    align-items: stretch !important;
    margin: 0;
    padding: 0;
    border-bottom: 1px solid var(--ui-folder-line) !important; /* шов полоса ↔ тело */
    list-style: none;
}

.ui-folder-tabs > .nav-tabs > li,
.ui-folder-tabs-bar > li {
    display: flex;
    align-items: stretch;
    float: none;
    margin-right: var(--ui-folder-gap);
    margin-bottom: -1px !important; /* опускаем на шов: на <li>, не на <a> */
}

.ui-folder-tabs > .nav-tabs > li > a,
.ui-folder-tabs-bar > li > a {
    display: flex !important;
    align-items: center;
    position: relative;
    box-sizing: border-box;
    padding: 8px 18px;
    border: 1px solid transparent !important;
    border-bottom: none !important;
    border-radius: var(--ui-folder-radius) var(--ui-folder-radius) 0 0 !important;
    background: transparent;
    color: var(--ui-folder-ink);
    font-weight: var(--ui-folder-weight);
    text-decoration: none;
    transition: color 0.12s ease, background 0.12s ease;
}

.ui-folder-tabs > .nav-tabs > li > a:hover,
.ui-folder-tabs-bar > li > a:hover {
    border-color: transparent !important;
    background: rgba(0, 0, 0, 0.04);
    color: var(--ui-folder-ink-active);
}

.ui-folder-tabs > .nav-tabs > li.active > a,
.ui-folder-tabs > .nav-tabs > li.active > a:hover,
.ui-folder-tabs > .nav-tabs > li.active > a:focus,
.ui-folder-tabs-bar > li.active > a,
.ui-folder-tabs-bar > li.active > a:hover,
.ui-folder-tabs-bar > li.active > a:focus {
    z-index: 2 !important;
    margin-top: -1px !important;
    border: 1px solid var(--ui-folder-line) !important;
    border-bottom-color: var(--ui-folder-body) !important;
    background: var(--ui-folder-body) !important;
    color: var(--ui-folder-ink-active) !important;
    font-weight: 700;
}

.ui-folder-tabs > .nav-tabs > li:first-child.active > a,
.ui-folder-tabs-bar > li:first-child.active > a {
    margin-left: -1px !important; /* левая рамка вкладки — на рамку контейнера, одной линией */
}

.ui-folder-tabs > .nav-tabs > li.active > a::after,
.ui-folder-tabs-bar > li.active > a::after {
    content: "";
    position: absolute;
    z-index: 3;
    right: 1px;
    bottom: -2px;
    left: 1px;
    height: 3px;
    background: var(--ui-folder-body);
}

.ui-folder-tabs > .tab-content {
    position: relative;
    z-index: 1; /* тело чуть позади активной вкладки */
    padding: 18px;
    border: 1px solid var(--ui-folder-line);
    border-top: none;
    border-bottom-right-radius: 12px;
    border-bottom-left-radius: 12px;
    background: var(--ui-folder-body);
}

/* Шапка таблицы, закреплённая полосой в «живом» режиме (UiCore.stickyBand(table, {live: true})): в таблице вместо настоящей
   строки заголовков остаётся её невидимая копия — держит ширины столбцов, пока настоящая строка (с полями, кнопками, сортировкой)
   стоит в полосе. */
.ui-sticky-band-placeholder {
    visibility: hidden;
}

/* ===== зона check-modal ===== */

/* ---------- Прогресс по площадкам (.ui-progress-platforms) ----------
   Содержимое окна «Проверка статусов на площадках» — одно на «Подтверждение сборки» и «Проверку приёмки площадками»: порционная
   проверка идёт независимой цепочкой на каждую площадку, окно показывает каждую отдельно и сверху общий итог. Строка площадки
   (.ui-progress-platform): голова — название площадки бейджем .mp-badge (site.css) слева и «N из M» справа, полоса .ui-progress,
   под ней строка счётчиков мелким приглушённым текстом («отменено: 0, ошибок: 0»). Под строками — общий итог (.ui-progress-total):
   полоса .ui-progress-master в строке .ui-progress-line с текстом «⟳ Проверено N из M» (спиннер крутится, пока идёт проверка) и общие
   счётчики. Разметку строит UiCore.progressPlatforms(контейнер, площадки) — страница её не пишет; по ходу страница зовёт update(площадка,
   {done, total, counters}) и total(done, total, counters), в конце finish(). Окно вокруг — обычное .ui-modal, текст-подсказка под
   блоком — .ui-modal-help. Эталон — «Подтверждение сборки» и «Проверка приёмки площадками» (одна разметка окна, одно поведение). */
.ui-progress-platforms {
    color: var(--ui-ink);
}

.ui-progress-platform + .ui-progress-platform {
    margin-top: 12px;
}

.ui-progress-platform-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.ui-progress-platform-count {
    color: var(--ui-ink-secondary);
    font-size: var(--ui-text-sm);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.ui-progress-platform .ui-progress {
    margin-top: 6px;
}

.ui-progress-platform-counters {
    margin-top: 4px;
    color: var(--ui-ink-muted);
    font-size: var(--ui-text-xs);
}

.ui-progress-total {
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--ui-progress-track);
}

.ui-progress-total .ui-progress-count {
    font-weight: 600;
}

.ui-progress-total-counters {
    margin-top: 8px;
    color: var(--ui-ink-secondary);
    font-size: var(--ui-text-sm);
}

.ui-progress-spinner {
    margin-right: 6px;
}

.ui-progress-platforms.is-done .ui-progress-spinner {
    display: none;
}

/* ---------- Карточки-фильтры (.ui-filter-cards) ----------
   Полоса кликабельных счётчиков по этапам: в карточке число и название этапа в одну строку (число крупнее, название жирно),
   под ними мелкая подпись. Карточка-ссылка отбирает этап как фильтр; проблема больше нуля подсвечена тоном, ноль приглушён и
   не ссылка (div). Тон — модификатор: .ui-filter-card-warn (жёлтый — ожидание), .ui-filter-card-bad (красный — просрочка и
   потери), .ui-filter-card-ok (зелёное число — принято), без тона — обычная карточка (нужны действия у нас),
   .ui-filter-card-zero (ноль: без заливки, приглушённые число и название). Выбранная — .is-selected (рамка акцентом).
   Разметка: <div class="ui-filter-cards"><a class="ui-filter-card ui-filter-card-bad is-selected" href="…"><span class="ui-filter-card-value">2</span>
   <span class="ui-filter-card-label">⏰ Не собран</span><span class="ui-filter-card-caption">подпись</span></a>…</div>.
   Применять к счётчикам, по которым кликают как по фильтру. Справочные числа без клика (итоги над таблицей) — плитки итогов
   .ui-stat-tile с цветной полосой, не эти карточки: интерактивным свой язык, заливка тоном (решение владельца 2026-10-06).
   Сетка — auto-fit от 200 px, на экране до 575 px две колонки. Эталон — «Проверка приёмки площадками». */
.ui-filter-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px;
    margin-bottom: 20px;
}

.ui-filter-card {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 10px;
    padding: 14px 16px;
    border: 1px solid var(--table-border, #d1d5db);
    border-radius: var(--table-radius, 8px);
    background: var(--ui-surface);
    color: var(--ui-ink);
}

a.ui-filter-card:hover,
a.ui-filter-card:focus {
    color: var(--ui-ink);
    text-decoration: none;
}

a.ui-filter-card:hover,
a.ui-filter-card:focus-visible {
    border-color: var(--ui-accent);
}

.ui-filter-card-value {
    font-size: var(--ui-text-xl);
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.ui-filter-card-label {
    font-size: var(--ui-text-md);
    font-weight: 700;
    white-space: nowrap;
    line-height: 1.1;
}

.ui-filter-card-caption {
    flex-basis: 100%;
    color: var(--ui-ink-muted);
    font-size: var(--ui-text-xs);
    line-height: 1.3;
}

.ui-filter-card-warn {
    border-color: var(--ui-warn-line);
    background: var(--ui-warn-bg);
}

.ui-filter-card-warn .ui-filter-card-value {
    color: var(--ui-warn-ink);
}

.ui-filter-card-bad {
    border-color: var(--ui-bad-line);
    background: var(--ui-bad-bg);
}

.ui-filter-card-bad .ui-filter-card-value {
    color: var(--ui-bad-ink);
}

.ui-filter-card-ok .ui-filter-card-value {
    color: var(--ui-ok-ink);
}

.ui-filter-card-zero {
    background: transparent;
}

.ui-filter-card-zero .ui-filter-card-value,
.ui-filter-card-zero .ui-filter-card-label {
    color: var(--ui-ink-muted);
}

.ui-filter-card.is-selected {
    border-color: var(--ui-accent);
    box-shadow: 0 0 0 2px var(--ui-accent);
}

@media (max-width: 575px) {
    .ui-filter-cards {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* ===== зона amazon-orders ===== */

/* ---------- Сегменты-ссылки ----------
   Переключатель, который открывает адрес (группировка и фильтр статуса на странице заказов), — те же .ui-segments, а сегмент
   <a class="ui-segment [is-active]" href="…" aria-current="true">. Ссылка не подчёркивается и не меняет цвет при наведении и
   фокусе (иначе её красит общий стиль ссылок); активный сегмент помечает страница классом is-active. Эталон — «Заказы Amazon»
   (/amazon/orders). */
a.ui-segment:hover,
a.ui-segment:focus {
    color: var(--ui-ink);
    text-decoration: none;
}

/* ---------- Количество «×N» ----------
   Бейдж «сколько штук в позиции» в таблице заказов: один товар — спокойная серая плашка .ui-qty, больше одного — крупная
   оранжевая .ui-qty-multi поверх базового класса (решение владельца 2026-09-11: упаковщик дважды собрал не то количество,
   узкий серый бейдж не бросался в глаза). Крупный бейдж растёт вместе с миниатюрой: 18 px, при S / M / L контейнера
   ([data-ui-thumb-size] — переключатель размера фото страницы) 18 / 28 / 40 px, при нём столбцу нужно 80 px. Разметка:
   <td class="…-col-qty"><span class="ui-qty">×1</span></td> и <span class="ui-qty ui-qty-multi">×2</span>; столбец стоит
   сразу за «Фото», текст в ячейке по центру. Эталон — «Заказы Amazon» (/amazon/orders) и «Заказы Авито» (/avito/orders). */
.ui-qty {
    display: inline-block;
    min-width: 28px;
    padding: 2px 8px;
    border-radius: 8px;
    background: #e5e7eb;
    color: #444;
    font-size: 0.95em;
    font-weight: 700;
    text-align: center;
}

.ui-qty-multi {
    padding: 4px 12px;
    border-radius: 10px;
    background: #f59e0b;
    color: #fff;
    font-size: 18px;
    white-space: nowrap;
}

[data-ui-thumb-size="m"] .ui-qty-multi {
    font-size: 28px;
}

[data-ui-thumb-size="l"] .ui-qty-multi {
    font-size: 40px;
}

/* Строка позиции с количеством больше одного — тёплая подложка на всю строку (как у «Авито — Заказы», решение владельца
   2026-09-11): упаковщик видит ×N не только по бейджу. Ставится на <tr> позиции рядом с .ui-qty-multi в ячейке. */
.ui-qty-row td {
    background-color: #fff4e0;
}

/* ===== зона payouts-v2 ===== */

/* ---------- Срезы одного числа (.ui-slices) ----------
   Несколько версий одного показателя в одной ячейке: источник на строку (прогноз, данные площадки, отчёт). Строка начинается от
   левого края ячейки подписью источника «значок и слово» (.ui-slices-label: «🔮 Прогноз», «🔌 API», «📄 Отчёт»), справа одно или
   несколько чисел; нет данных — прочерк (.is-empty, приглушённый). Сколько чисел в строке — модификатор .ui-slices-2 / .ui-slices-3
   на контейнере (без него одно число). Блок занимает ровно ширину своей сетки (width: max-content) и стоит у левого края ячейки:
   пустого поля до подписей нет. Колонка подписи и колонки чисел одной ширины (токены --ui-slices-label-w и --ui-slices-value-w),
   поэтому подписи и числа разных строк и подписи в шапке стоят друг под другом. Подписи чисел («удерж.», «доход») — один раз в
   шапке столбца: строка .ui-slices-head в той же сетке, а не в каждой строке; в её первой ячейке — название столбца со справкой ⓘ
   (над колонкой подписей). Состав числа — карточка .ui-pop на самом числе (страница строит содержимое, класс .has-pop даёт
   подсветку числа при наведении). Строка, чьи данные расходятся с другой, — тон .ui-slices-row-warn (токены --ui-warn-*).
   Легенда источников — справкой ⓘ в заголовке столбца (UiCore.hint), не рядом с числами. Разметка:
   <div class="ui-slices ui-slices-2"><div class="ui-slices-row"><span class="ui-slices-label">🔮 Прогноз</span><span class="ui-slices-value">−240 ₽</span>
   <span class="ui-slices-value has-pop">160 ₽</span></div><div class="ui-slices-row ui-slices-row-warn">…</div></div>; в шапке —
   <div class="ui-slices ui-slices-2"><div class="ui-slices-head"><span class="ui-slices-label">Срезы</span><span class="ui-slices-value">удерж.</span>
   <span class="ui-slices-value">доход</span></div></div>. Эталон — «Аналитика выплат» (/analytics/payouts, лента продаж). */
.ui-slices {
    --ui-slices-label-w: 92px;
    --ui-slices-value-w: 84px;
    --ui-slices-cols: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    width: max-content;
}

.ui-slices-2 {
    --ui-slices-cols: 2;
}

.ui-slices-3 {
    --ui-slices-cols: 3;
}

.ui-slices-row,
.ui-slices-head {
    display: grid;
    grid-template-columns: var(--ui-slices-label-w) repeat(var(--ui-slices-cols), minmax(var(--ui-slices-value-w), max-content));
    column-gap: 8px;
    align-items: baseline;
    margin: 0 -4px;
    padding: 1px 4px;
    border-radius: 4px;
    white-space: nowrap;
}

.ui-slices-head {
    align-items: center;
}

.ui-slices-label {
    text-align: left;
}

.ui-slices-head .ui-slices-value {
    color: var(--ui-ink-muted);
    font-size: var(--ui-text-xs);
    font-weight: 400;
    line-height: 1.3;
}

.ui-slices-value {
    border-radius: 3px;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.ui-slices-value.is-empty {
    color: var(--ui-ink-muted);
}

.ui-slices-value.has-pop:hover {
    background: var(--table-stripe, #f4f6f8);
}

.ui-slices-row-warn {
    background: var(--ui-warn-bg);
    box-shadow: inset 0 0 0 1px var(--ui-warn-line);
    color: var(--ui-warn-ink);
}

.ui-slices-row-warn .ui-slices-value.is-empty {
    color: var(--ui-warn-hint);
}

.ui-slices-row-warn .ui-slices-value.has-pop:hover {
    background: var(--ui-warn-line);
}

/* ===== зона v3-feed ===== */

/* ---------- Доля с кольцом (.ui-share) ----------
   Какая часть набора выполнена или обеспечена данными, одним взглядом: кольцо 40 px с долей, рядом процент крупно и под ним серым
   мелко «N из M» (сколько в целом — не главное). Тон по доле: 100 % — .ui-share-ok и круглая зелёная галочка вместо кольца,
   75–99 % — .ui-share-warn (оранжевое кольцо, значок ⏳ у процента), меньше 75 % — .ui-share-bad (красное кольцо, ⏳): «данные неполные».
   Тон считает страница (скрипт UiCore.share делает это сам и собирает разметку); процент не округляется вверх: 11 969 из 11 970 —
   «99 %», галочка только у полного набора. Кольцо — два круга одного радиуса с pathLength="100": длину дуги задаёт атрибут
   stroke-dasharray="доля 100" (CSS её не трогает). Разметка: <span class="ui-share ui-share-warn"><svg class="ui-share-ring"
   viewBox="0 0 40 40"><g transform="rotate(-90 20 20)"><circle class="ui-share-track" cx="20" cy="20" r="16" pathLength="100"/><circle
   class="ui-share-arc" cx="20" cy="20" r="16" pathLength="100" stroke-dasharray="83 100"/></g></svg><span class="ui-share-text">
   <span class="ui-share-value">83 % ⏳</span><span class="ui-share-caption">830 из 1 000</span></span></span>; у полного набора вместо
   кольца <svg class="ui-share-ring"><circle class="ui-share-check-bg" cx="20" cy="20" r="18"/><path class="ui-share-check-mark" d="M12 20.5l6
   6 10-12"/></svg>. Эталон — «Аналитика выплат» (/analytics/payouts, сводка срезов, столбец «Данные»). */
.ui-share {
    --ui-share-color: #c0c4cc;
    --ui-share-ink: var(--ui-ink);
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
}

.ui-share-ok {
    --ui-share-color: #22c55e;
    --ui-share-ink: var(--ui-ok-ink);
}

.ui-share-warn {
    --ui-share-color: #f59e0b;
    --ui-share-ink: var(--ui-warn-ink);
}

.ui-share-bad {
    --ui-share-color: #ef4444;
    --ui-share-ink: var(--ui-bad-ink);
}

.ui-share-ring {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
}

.ui-share-track,
.ui-share-arc {
    fill: none;
    stroke-width: 5;
}

.ui-share-track {
    stroke: var(--ui-progress-track);
}

.ui-share-arc {
    stroke: var(--ui-share-color);
}

.ui-share-check-bg {
    fill: var(--ui-share-color);
}

.ui-share-check-mark {
    fill: none;
    stroke: var(--ui-surface);
    stroke-width: 3.5;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.ui-share-text {
    display: flex;
    flex-direction: column;
    line-height: 1.2;
}

.ui-share-value {
    color: var(--ui-share-ink);
    font-size: var(--ui-text-md);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.ui-share-caption {
    color: var(--ui-ink-muted);
    font-size: var(--ui-text-xs);
    font-variant-numeric: tabular-nums;
}

.ui-share-empty {
    color: var(--ui-ink-muted);
}
