/* ========================================================================
   Палитра целиком взята из дизайн-системы темы: style.css (:root) и
   css/header.css. Своих оттенков блок не вводит — каждый токен ниже
   ссылается на источник в комментарии.

   Два зелёных здесь не случайность, а разведённые роли. В теме исторически
   живут оба: светлый #6da640 красит кнопки («Заказать» в блоке товара),
   тёмный #418123 — шапку. Поэтому --cta* отвечает только за кнопку покупки
   и совпадает с кнопками сайта, а --accent красит текст, иконки и активные
   состояния, где цвет обязан читаться на белом.

   Контраст с белым текстом: --cta 2.93:1, --cta-hover 4.78:1,
   --cta-active 5.30:1. Кнопка покупки в покое НЕ добирает до WCAG AA (4.5:1)
   — это осознанное решение в пользу единообразия с остальными кнопками
   сайта, которые красятся тем же #6da640. Все прочие роли AA проходят.
   ======================================================================== */
.subcat-listing {
    /* нейтрали: style.css --black/--gray/--light-gray, header.css --paper/--muted/--line */
    --ink: #343434;
    --strong: #343434;
    /* header.css --muted это #7b7b7b, но он не добирает до нормы WCAG AA:
       4.23:1 на белом и 4.06:1 на --paper. Этим цветом покрашены цена за м²
       и пересчёт в доски — данные о товаре, а не декор, поэтому берём
       ближайший серый, проходящий норму на ОБОИХ фонах: 4.95:1 на белом,
       4.58:1 на --paper. Разница с #7b7b7b на глаз не читается. */
    --muted: #707070;
    --faint: #9e9999;
    --line: #e6e6e6;
    --line-soft: #efefef;
    --paper: #f6f6f6;
    --card: #ffffff;

    /* зелёные: style.css --green (#6da640), header.css --g-800/--g-900/--lime */
    --cta: #6da640;
    --cta-hover: #418123;
    --cta-active: #3a791b;
    --accent: #3a791b;
    --lime: #70a842;
    /* свечение под главной кнопкой — то же, что тема даёт кнопкам «Заказать» */
    --cta-glow: rgba(65, 130, 40, .4);
    --cta-glow-hover: rgba(65, 130, 40, .6);
    --wash: rgba(109, 166, 64, .07);
    --wash-2: rgba(109, 166, 64, .13);
    --ok: #3a791b;
    --on-accent: #ffffff;

    /* тень одна: у тоста и мобильной панели подъём выше, чем у header.css --shadow */
    --shadow-lift: 0 18px 44px rgba(28, 36, 22, .16);
    --r: 12px;
    --r-sm: 9px;
    /* Отступ липкого заголовка таблицы. Шапка сайта (header.site-header) тоже
       sticky и при прокрутке сжимается со 119 до 61 px, z-index у неё 100.
       С top: 0 заголовок таблицы прилипал ПОД неё и был не виден вовсе —
       выглядело так, будто прилипания нет. 61 px = сжатая высота шапки,
       одинакова на всех настольных ширинах (проверено 861-1920 px). */
    --sticky-top: 61px;
}

/* Под залогиненным пользователем шапка сайта сдвинута на высоту админ-бара WP
   (32px, см. css/header.css) — заголовок таблицы обязан ехать за ней, иначе
   прилипнет ровно под бар и окажется закрыт шапкой (её z-index 100 против 3).
   Вариант с 46px не нужен: ниже 861px `thead` скрыт (display: none), а бар
   становится высоким только с 782px. */
body.admin-bar .subcat-listing {
    --sticky-top: 93px;
}

/* Тема гасит обводку глобально — `button { outline: 0 }` в style.css:551 — и
   вместе с ней исчезает единственная подсказка для клавиатуры: где фокус.
   Возвращаем её на уровне блока; специфичности класса хватает, чтобы перебить. */
.subcat-listing :focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Тема оформляет КАЖДУЮ кнопку как зелёную: своё свечение в покое и зелёный
   градиент при наведении. Внутри листинга это ломает нейтральные элементы —
   чипы фильтра и заголовки-кнопки сортировки вспыхивают зелёным, будто их
   выбрали, а под степпером висит зелёная подсветка. Гасим навязанные фон и
   тень на всех кнопках блока; там, где фон нужен, его задают наши правила. */
.subcat-listing button,
.subcat-listing button:hover,
.subcat-listing button:focus {
    background-image: none;
    box-shadow: none;
}

/* Главной кнопке свечение возвращаем: именно с ним по сайту живут «Заказать»,
   и мы сознательно равняемся на них. Селектор с .subcat-listing — иначе
   сброс выше (класс + тип) окажется специфичнее и погасит тень обратно. */
.subcat-listing .sl-buy { box-shadow: 0 10px 20px var(--cta-glow); }
/* Пустое количество — добавлять нечего, кнопка гаснет вместе со свечением. */
.sl-buy:disabled { opacity: .45; cursor: not-allowed; }
.subcat-listing .sl-buy:disabled { box-shadow: none; }
.subcat-listing .sl-buy:hover,
.subcat-listing .sl-buy:focus { box-shadow: 0 10px 20px var(--cta-glow-hover); }

/* Фон в `button:hover` тема задаёт СОКРАЩЁННОЙ записью, а она сбрасывает и
   background-color в исходное — прозрачный. Поэтому кнопкам с заливкой её
   приходится подтверждать явно: без этого чип при наведении теряет фон, а
   «Показать N» в мобильной панели превращается в белый текст на белом. */
.subcat-listing .sl-fchip:hover,
.subcat-listing .sl-fchip:focus { background-color: var(--paper); }
.subcat-listing .sl-fchip[aria-pressed="true"]:hover,
.subcat-listing .sl-fchip[aria-pressed="true"]:focus { background-color: var(--cta); }
.subcat-listing .sl-mbtn:hover,
.subcat-listing .sl-mbtn:focus { background-color: var(--card); }
.subcat-listing .sl-mapply:hover,
.subcat-listing .sl-mapply:focus { background-color: var(--accent); }

/* ========================================================================
   КОМПОНЕНТ .subcat-listing — перенесено из макета.
   Респонсив на @media (max-width: 860px): та же вёрстка отвечает на ширину
   экрана, поэтому работает и на 1360, и в рамке 390 px.
   ======================================================================== */
.subcat-listing {
    /* padding здесь не задаём: в макете отступы намеренно живут на .wr,
       а не на .subcat-listing — сохраняем это же деление и в теме */
    padding: 0;
    /* Подложки нет намеренно (решение владельца 2026-08-01), хотя в макете она
       есть (--paper). На реальной странице соседи листинга белые, и полоса
       #f6f6f6 во всю ширину читалась как пятно, а не как зона: контраст к
       белому 1,03:1 — ниже порога различимости, при этом заметнее всего серый
       был в пустых полях по краям (контент ограничен 1360 px). Отделение
       таблицы и фильтра от страницы и так делают их рамки (--line) с
       радиусами — подложка дублировала эту работу третьим слоем. */
    background: transparent;
    color: var(--ink);
    /* тот же стек, что во всей теме: 'Klimat', sans-serif (style.css, 28 объявлений).
       Свой длинный фолбэк убран — при недогруженном Klimat блок подставлял не тот
       системный шрифт, что остальная страница. */
    font-family: 'Klimat', sans-serif;
}

/* 40px снизу — как у .wrap.tovar прямо над нами (24/40). Было 8px, и блок
   с формой заявки стыковался вплотную: зазор ровно 0, форма садилась на
   таблицу. Отступы блока живут на .wr, а не на .subcat-listing — так же,
   как в макете. */
.subcat-listing .wr { max-width: 1360px; margin: 0 auto; padding: 28px 50px 40px; display: flex; flex-direction: column; gap: 20px; }

/* ---------- мобильный тулбар. На ПК обёртки растворяются (display: contents),
   поэтому .sl-filter ведёт себя как прямой ребёнок .wr и вёрстка ПК не меняется ---------- */
.sl-mtools { display: contents; }
.sl-mpanel { display: contents; }
.sl-mpanel[data-panel="sort"] { display: none; }
.sl-mbtn, .sl-mcount, .sl-mhead, .sl-mfoot, .sl-msort { display: none; }

/* ---------- фильтр над таблицей ---------- */
.sl-filter {
/* Горизонтальный зазор 20px, а не 24: на подкатегории с пятью группами
   (палубная доска) счётчик позиций не влезал в строку ровно на 1 px и
   уезжал вниз, добавляя фильтру лишние 40 px высоты. */
    display: flex; align-items: flex-end; flex-wrap: wrap; gap: 14px 20px;
    padding: 14px 18px; border: 1px solid var(--line); border-radius: var(--r); background: var(--card);
}

.sl-fgroup { display: flex; flex-direction: column; gap: 7px; }

.sl-flabel {
    font-size: 13px; font-weight: 600; letter-spacing: .14em;
    text-transform: uppercase; color: var(--muted);
}

.sl-fchips { display: flex; flex-wrap: wrap; gap: 6px; }

.sl-fchip {
    appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: 7px;
    border: 1px solid var(--line); background: var(--paper); color: var(--ink);
    border-radius: 8px; padding: 9px 13px; min-height: 40px;
    /* 14px и радиус 8 — как у .buy-btn в css/product.css, канонической кнопки сайта */
    font: 400 14px/1 'Klimat', sans-serif; font-variant-numeric: tabular-nums;
    transition: background .15s, border-color .15s, color .15s;
}

.sl-fchip:hover { border-color: var(--lime); }
.sl-fchip i { font-style: normal; font-weight: 400; font-size: 13px; color: var(--muted); }
/* нажатый чип — тот же зелёный, что у .buy-btn и кнопки покупки: заказчик
   выбрал единообразие с кнопками сайта. Контраст подписи при этом 2.93:1,
   как и у самой кнопки — то же осознанное отступление от WCAG AA. */
.sl-fchip[aria-pressed="true"] { background: var(--cta); border-color: var(--cta); color: var(--on-accent); }
/* Прозрачности здесь больше нет. На тёмном --accent .9 давало приемлемые 4.67:1,
   но заливка нажатого чипа стала светлее (--cta, как у .buy-btn), и та же .9
   уронила подсказку цены до 2.66:1 — хуже, чем подпись рядом с ней. Приглушать
   цену сильнее её же подписи незачем: роль второстепенного текста несёт размер. */
.sl-fchip[aria-pressed="true"] i { color: var(--on-accent); }

/* сброс появляется только когда есть что сбрасывать */
.sl-freset {
    appearance: none; cursor: pointer; border: 0; background: none; padding: 0 0 12px;
    font: 500 13px/1 'Klimat', sans-serif; color: var(--muted);
    text-decoration: underline; text-underline-offset: 3px;
}

.sl-freset:hover { color: var(--accent); }
.sl-freset[hidden] { display: none; }

.sl-count { margin-left: auto; padding-bottom: 11px; font-size: 13px; color: var(--muted); }
.sl-count b { color: var(--strong); font-weight: 600; font-variant-numeric: tabular-nums; }

/* ---------- таблица ---------- */
.sl-table { border: 1px solid var(--line); border-radius: var(--r); background: var(--card); overflow: clip; }
table.sl-list { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.sl-list caption { caption-side: top; }
.sl-list .is-off { display: none; }
.sl-list tbody[hidden] { display: none; }

.sl-list thead th {
    /* тема сбрасывает vertical-align: top на tr (html, body, div, table, tr,
       td, li, ul, p { vertical-align: top }), th в этот список не входит,
       но его собственный UA-дефолт vertical-align: inherit подхватывает top
       от строки — без явного middle шапка съезжает по вертикали */
    vertical-align: middle;
    position: sticky; top: var(--sticky-top, 0px); z-index: 3; background: var(--card);
    text-align: left; padding: 13px 18px; border-bottom: 1px solid var(--line);
    font-size: 13px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
}

.sl-list thead th.r { text-align: right; }

/* Ширины колонок. Свободное место распределено по трём левым колонкам, а не
   свалено в одну: «Размер» — самая длинная строка и запас на другие подкатегории,
   «Сорт» и «Наличие» — короткие статусы. Правая тройка (количество, сумма,
   кнопка) жмётся по содержимому (width: 1%), поэтому между степпером и суммой
   остаётся только padding. Содержимое «Количества» прижато вправо — иначе запас
   этой колонки лёг бы точно перед суммой. */
.sl-list thead th { white-space: nowrap; width: 1%; }
.sl-list thead th:nth-child(1) { width: 22%; }
.sl-list thead th:nth-child(2) { width: 13%; }
.sl-list thead th:nth-child(3) { width: 18%; }

/* короткие колонки-статусы центрируются: воздух распределяется по обе стороны
   и не читается как провал между колонками */
.sl-list thead th:nth-child(2), .sl-cell-grade,
.sl-list thead th:nth-child(3), .sl-cell-stock { text-align: center; }
.sl-list thead th:nth-child(4),
.sl-cell-qty { text-align: right; }
.sl-cell-qty .sl-qty { margin-left: auto; }
/* по центру колонки, а не в правый край: подпись читается как относящаяся
   к степперу над ней, а не как оторванный от него хвост */
.sl-conv { text-align: center; }

/* сортировка: заголовок — кнопка, состояние читается из aria-sort на th */
.sl-sort {
    appearance: none; border: 0; background: none; padding: 0; cursor: pointer;
    font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
    display: inline-flex; align-items: center; gap: 6px;
}

.sl-sort:hover { color: var(--accent); }
.sl-list thead th:not([aria-sort="none"]) .sl-sort { color: var(--accent); }
.sl-arrow { font-size: 13px; line-height: 1; }
.sl-list thead th[aria-sort="none"] .sl-arrow { opacity: .35; }
.sl-list thead th[aria-sort="none"] .sl-arrow::after { content: "↕"; }
.sl-list thead th[aria-sort="ascending"] .sl-arrow::after { content: "↑"; }
.sl-list thead th[aria-sort="descending"] .sl-arrow::after { content: "↓"; }
/* У каждой ячейки одинаковая структура: полоса контента 46 px (по самому
   высокому элементу — степперу) и полоса подписи 15 px. Ячейки без подписи
   добирают её псевдоэлементом, поэтому высота контента у всех колонок равна,
   и vertical-align: middle центрирует их одинаково. */
.sl-list td, .sl-list tbody th {
    padding: 8px 18px; border-bottom: 1px solid var(--line-soft); vertical-align: middle;
}

/* в этих ячейках контент инлайновый — строка задаётся line-height */
.sl-name, .sl-cell-grade, .sl-cell-stock, .sl-cell-act { line-height: 46px; }

.sl-name::after,
.sl-cell-grade::after,
.sl-cell-stock::after,
.sl-cell-act::after { content: ""; display: block; height: 15px; }
.sl-list tbody tr.on > * { background: var(--wash); }

/* линия отделяет группы текущей сортировки; ставится только между видимыми
   строками, поэтому у верхней строки её нет по построению */
.sl-list tbody tr.is-last > * { border-bottom: 0; }

.sl-name { text-align: left; font-weight: 400; }

/* Анкор товара по образцу темы: .product-card_title — её собственная ссылка на
   товар — это 16px / 500 / underline. Подчёркивание принципиально: до этого о том,
   что размер кликабелен, говорил только цвет при наведении, то есть для тач-устройств
   и для клавиатуры ссылка была неотличима от обычного текста.
   Цвет оставляем на токене --strong (#343434): в теме .product-card_title хардкодит
   `black`, хотя её же токен --black равен #343434 — берём токен, а не хардкод. */
.sl-sku {
    display: inline-flex; align-items: center; gap: 6px;
    text-decoration: underline; text-underline-offset: 2px;
    font-size: 16px; font-weight: 500; line-height: 1.2; color: var(--strong); letter-spacing: .01em;
}

.sl-sku:hover { color: var(--accent); }
.sl-stock {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: 16px; line-height: 1.2; color: var(--ok); white-space: nowrap;
}

.sl-stock::before {
    content: ""; flex: none; width: 7px; height: 7px; border-radius: 50%;
    background: currentColor; box-shadow: 0 0 0 3px var(--wash-2);
}

.sl-stock[data-s="order"] { color: var(--muted); }
.sl-stock[data-s="out"] { color: var(--faint); }

/* колонка сорта нужна, когда в таблице больше одного сорта; при выборе
   ровно одного она повторяла бы одно значение 18 раз — сорт назван в фильтре */
/* Скрываем колонку «Сорт», только когда атрибут явно говорит «off». Раньше правило
   было построено на ОТСУТСТВИИ атрибута, из-за чего колонка пропадала до исполнения
   JS и оставалась скрытой навсегда, если скрипт падал. Теперь значение печатает PHP. */
.sl-list[data-gcol="off"] [data-col="grade"] { display: none; }

.sl-gtag {
    display: inline-block; line-height: 1.25;
    font-size: 13px; font-weight: 600; letter-spacing: .04em;
    padding: 4px 9px; border-radius: 6px; background: var(--wash-2); color: var(--accent);
}

/* поле количества: число и единица стоят вместе и центрированы в поле */
/* поле тянется по колонке, но не шире 142 px: 34 + 34 на кнопки, ~72 на «N м²».
   min-width: fit-content по спецификации перебивает max-width — поэтому на
   четырёхзначном количестве или в «шт» поле подрастёт, а не обрежет кнопку «+». */
/* inline-flex — чтобы подпись «N досок» встала на ту же строку: только когда
   все ячейки однострочные, vertical-align: middle центрирует их одинаково */
.sl-qty {
    /* vertical-align: top, а не middle: при middle inline-flex высотой 46 px
       раздувает строку контента, и подпись под полем уезжает ниже подписи
       под суммой. С top строка ровно 46 px — как strut ячейки. */
    display: flex; align-items: stretch;
    width: 142px; min-width: fit-content; height: 46px;
    border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--card); overflow: clip;
}

.sl-qty button {
    /* тема задаёт всем <button> свой padding (25px 44px) и display: flex; у
       border-box паддинг не даёт боксу стать уже суммы паддингов — без явного
       сброса кнопка вместо 34×42 раздувается до ~88×50 */
    padding: 0; min-width: 0; min-height: 0;
    appearance: none; cursor: pointer; border: 0; background: transparent; color: var(--accent);
    font: 500 18px/1 'Klimat', sans-serif; width: 34px; height: 42px; flex: none;
}

.sl-qty button:hover { background: var(--wash-2); }

.sl-qty .val {
    flex: 1; display: flex; align-items: center; justify-content: center; gap: 3px;
    border-left: 1px solid var(--line); border-right: 1px solid var(--line); padding: 0 4px;
}

.sl-qty input {
    border: 0; background: transparent; color: var(--strong); text-align: center;
    /* 16px/400 — как содержимое ячеек .opistable в теме: там размер у td не задан
       вовсе и наследуется от body. Наши ячейки так и работают, поле количества было
       единственным исключением. Плюс граница 16px практическая: Safari на iOS
       зумит страницу при фокусе на поле с размером меньше 16px. */
    font: 400 16px/1 'Klimat', sans-serif; font-variant-numeric: tabular-nums;
    padding: 0; -moz-appearance: textfield;
}

.sl-qty input::-webkit-outer-spin-button,
.sl-qty input::-webkit-inner-spin-button { appearance: none; margin: 0; }
.sl-qty .u { font-size: 15px; font-style: normal; color: var(--muted); white-space: nowrap; }
.sl-conv { display: block; height: 15px; line-height: 15px; font-size: 13px; color: var(--muted); }

.sl-total { display: block; height: 46px; line-height: 46px; font-size: 18px; font-weight: 600; color: var(--strong); white-space: nowrap; letter-spacing: -.01em; }
.sl-total.zero { color: var(--muted); font-weight: 400; }
.sl-meta { display: block; height: 15px; line-height: 15px; font-size: 13px; color: var(--muted); white-space: nowrap; }

.sl-cell-sum { text-align: right; }
.sl-act { text-align: right; }

/* кнопка раскрытия существует только в мобильной вёрстке */
.sl-cell-toggle { display: none; }

.sl-buy {
    appearance: none; cursor: pointer; border: 1px solid var(--cta); background: var(--cta); color: var(--on-accent);
    /* геометрия как у .buy-btn: радиус 8, шрифт 14, содержимое по центру.
       padding: 20px и width: 100% оттуда НЕ берём — там это крупная кнопка
       блока товара, в строке таблицы она разнесла бы ряд по высоте. */
    border-radius: 8px; padding: 12px 18px; min-height: 44px; white-space: nowrap;
    display: inline-flex; align-items: center; justify-content: center;
    font: 400 14px/1 'Klimat', sans-serif;
    transition: background .15s, border-color .15s, color .15s;
}

.sl-buy:hover { background: var(--cta-hover); border-color: var(--cta-hover); }
.sl-buy:active { background: var(--cta-active); border-color: var(--cta-active); }
.sl-buy[data-in] { background: var(--wash-2); border-color: transparent; color: var(--accent); }

/* ---------- липкая панель заявки ---------- */
.sl-toast {
    position: sticky; bottom: 16px; z-index: 7; margin: 0 50px -46px; padding: 12px 16px;
    border-radius: var(--r-sm); background: var(--strong); color: var(--paper); font-size: 14px;
    box-shadow: var(--shadow-lift); opacity: 0; transform: translateY(6px);
    transition: opacity .18s, transform .18s; pointer-events: none;
}

.sl-toast[data-on] { opacity: 1; transform: none; }

/* ======================= УЗКИЙ КОНТЕЙНЕР ================================ */
@media (max-width: 860px) {
    /* ================== МОБИЛЬНАЯ ВЕРСИЯ ==================
       Управление уезжает в липкий тулбар: до правки фильтр + сортировка +
       пустая панель корзины съедали ~520 px из 760 px экрана. Панели
       выпадают ИЗ тулбара (absolute внутри sticky), поэтому не требуют
       position: fixed и не ломаются внутри прокручиваемого контейнера. */
    /* на мобильной боковых отступов нет, но нижний нужен по той же причине */
    .subcat-listing .wr { padding: 0 0 32px; gap: 0; }

    .sl-mtools {
        display: flex; align-items: center; gap: 8px;
        position: sticky; top: 0; z-index: 9;
        padding: 10px 14px;
        background: var(--paper);
        border-bottom: 1px solid var(--line);
    }

    .sl-mbtn {
        appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: 7px;
        border: 1px solid var(--line); border-radius: 10px; background: var(--card); color: var(--ink);
        font: 400 14px/1 'Klimat', sans-serif; padding: 0 13px; min-height: 44px;
        max-width: 46vw; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }

    .sl-mbtn[aria-expanded="true"] { border-color: var(--accent); color: var(--accent); }
    .sl-mbtn i { font-style: normal; font-weight: 400; color: var(--muted); font-size: 13px; }
    .sl-mbtn[aria-expanded="true"] i { color: var(--accent); }
    .sl-mico { flex: none; width: 15px; height: 15px; }

    .sl-mbtn .n {
        display: none; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 10px;
        background: var(--accent); color: var(--on-accent); font-size: 13px; font-weight: 600;
        align-items: center; justify-content: center;
    }

    .sl-mbtn .n[data-on] { display: inline-flex; }

    .sl-mcount { display: block; margin-left: auto; font-size: 13px; color: var(--muted); white-space: nowrap; }
    .sl-mcount b { color: var(--strong); font-weight: 600; font-variant-numeric: tabular-nums; }

    /* выпадающая панель: перекрывает список, а не раздвигает его.
       Селектор с [data-panel] повторён, чтобы побить правило display:none
       из ПК-блока — у контейнерных запросов своей специфичности нет. */
    .sl-mpanel,
    .sl-mpanel[data-panel="sort"] {
        display: block; position: absolute; top: 100%; left: 0; right: 0;
        max-height: 420px; overflow: auto; overscroll-behavior: contain;
        background: var(--card); border-bottom: 1px solid var(--line);
        box-shadow: var(--shadow-lift);
        padding: 4px 14px 14px;
    }

    .sl-mpanel[hidden] { display: none; }

    .sl-mhead {
        display: flex; align-items: center; justify-content: space-between;
        padding: 10px 0 6px; font-size: 15px; font-weight: 600; color: var(--strong);
    }

    .sl-mclose {
        /* та же утечка паддинга темы (button { padding: 25px 44px }), что и у
           .sl-qty button: без сброса 44×44 раздувается до размера паддингов */
        padding: 0; min-width: 0; min-height: 0;
        appearance: none; cursor: pointer; border: 0; background: none; color: var(--muted);
        font: 400 20px/1 'Klimat', sans-serif; width: 44px; height: 44px; margin-right: -12px;
    }

    .sl-mclose:hover { color: var(--accent); }

    /* фильтр внутри панели: без рамки и лишних отступов */
    .sl-filter {
        display: flex; flex-direction: column; align-items: stretch; gap: 14px;
        padding: 0; border: 0; border-radius: 0; background: none;
    }

    .sl-fchip { min-height: 44px; padding: 0 14px; }
    .sl-count, .sl-freset { display: none; }

    .sl-mfoot {
        display: flex; align-items: center; gap: 10px;
        margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line);
    }

    .sl-mreset {
        appearance: none; cursor: pointer; background: none; border: 1px solid var(--line);
        border-radius: var(--r-sm); color: var(--ink); font: 400 14px/1 'Klimat', sans-serif;
        min-height: 46px; padding: 0 16px;
    }

    .sl-mreset[hidden] { display: none; }

    .sl-mapply {
        /* та же утечка паддинга темы: без сброса вертикальный padding темы
           раздувает кнопку выше min-height: 46px */
        padding: 0; min-width: 0;
        flex: 1; appearance: none; cursor: pointer; border: 0; border-radius: var(--r-sm);
        background: var(--accent); color: var(--on-accent);
        font: 400 15px/1 'Klimat', sans-serif; min-height: 46px;
    }

    /* сортировка — список вариантов */
    .sl-msort { display: flex; flex-direction: column; }

    .sl-msort button {
        /* display и transition заданы явно из-за темы: она делает КАЖДУЮ кнопку
           inline-flex с justify-content: center, и центрирование флексом
           побеждает text-align — подпись уезжала на 115 px от левого края.
           Свой transition темы (0.4s) вдобавок не подчинялся prefers-reduced-motion. */
        display: block; transition: none;
        appearance: none; cursor: pointer; text-align: left; border: 0; background: none;
        border-bottom: 1px solid var(--line-soft); color: var(--ink);
        font: 400 15px/1.3 'Klimat', sans-serif; min-height: 50px; padding: 8px 30px 8px 0;
        position: relative;
    }

    .sl-msort button:last-child { border-bottom: 0; }
    .sl-msort button[aria-pressed="true"] { color: var(--accent); font-weight: 600; }
    .sl-msort button[aria-pressed="true"]::after { content: "✓"; position: absolute; right: 4px; top: 50%; transform: translateY(-50%); }

    /* ---------- таблица: строка становится карточкой в две строки ---------- */
    .sl-list, .sl-list tbody, .sl-list tr, .sl-list th, .sl-list td { display: block; }
    .sl-list thead { display: none; }
    .sl-table { border: 0; border-radius: 0; }

    /* Аккордеон: в свёрнутой строке — размер, сорт рядом с ним, наличие под
       ними и сумма справа. Количество и кнопка раскрываются по тапу. */
    .sl-list tbody tr {
        display: grid; grid-template-columns: auto auto 1fr auto auto;
        align-items: center; gap: 6px 10px;
        padding: 10px 6px 10px 14px; border-bottom: 1px solid var(--line-soft);
    }

    /* в карточке полосы не нужны — строка разложена по сетке */
    .sl-list tbody tr > * { height: auto; border: 0; padding: 0; line-height: 1.3; }
    .sl-name::after, .sl-cell-grade::after,
    .sl-cell-stock::after, .sl-cell-act::after { content: none; }
    .sl-total { height: auto; line-height: 1.2; }
    .sl-conv, .sl-meta { height: auto; line-height: 1.3; }
    .sl-cell-qty, .sl-conv, .sl-cell-stock, .sl-cell-grade { text-align: left; }
    .sl-cell-qty .sl-qty { margin-left: 0; }
    .sl-list tbody tr.is-last { border-bottom: 0; }

    .sl-list .sl-name { grid-area: 1 / 1; }
    .sl-list .sl-cell-grade { grid-area: 1 / 2; }
    .sl-list .sl-cell-sum { grid-area: 1 / 4; }
    .sl-list .sl-cell-toggle { grid-area: 1 / 5; display: block; }
    .sl-list .sl-cell-stock { grid-area: 2 / 1 / 2 / 4; }

    /* Раскрытая часть — одна строка: степпер слева, кнопка справа, под ними
       по центру пересчёт. Отдельный ряд под кнопку экономил бы 46 px впустую. */
    /* Разделитель — отдельный элемент строки во всю ширину: линия над
       количеством и над кнопкой физически одна и та же. */
    .sl-list tr[data-open]::after {
        content: ""; grid-area: 3 / 1 / 3 / -1; height: 0;
        border-top: 1px solid var(--line-soft); margin-top: 4px;
    }

    /* Обе ячейки занимают одну область во всю ширину и разводятся по краям.
       Полоса 1fr входит в их span — поэтому раскрытая часть не растягивает
       колонки шапки и тег сорта не уезжает вправо. */
    .sl-list .sl-cell-qty,
    .sl-list .sl-cell-act {
        grid-area: 4 / 1 / 4 / -1; display: none;
        align-self: start; width: calc(50% - 5px);
    }

    .sl-list .sl-cell-qty { justify-self: start; }
    .sl-list .sl-cell-act { justify-self: end; }

    .sl-list .sl-cell-qty .sl-qty { max-width: none; }
    /* ячейка вдвое уже строки пересчёта — пускаем её в пустое место под кнопкой,
       вместо переноса на вторую строку */
    .sl-conv { text-align: left; white-space: nowrap; }
    .sl-list tr[data-open] .sl-cell-qty,
    .sl-list tr[data-open] .sl-cell-act { display: block; }
    .sl-list tr[data-open] .sl-sku { color: var(--accent); }
    .sl-buy { width: 100%; }

    /* В карточке нет шапки таблицы, поэтому числа подписываются на месте:
       иначе непонятно, 583 ₽ — это за м², за штуку или итог за количество. */
    .sl-lbl,
    .sl-conv::before,
    .sl-cell-qty::before {
        font-size: 13px; font-weight: 600; letter-spacing: .1em;
        text-transform: uppercase; color: var(--muted);
    }

    .sl-conv::before { content: "Фактически "; margin-right: 3px; }

    .sl-cell-qty::before {
        content: "Количество"; display: block; height: 14px; line-height: 14px; margin-bottom: 7px;
    }

    /* пустая дорожка той же высоты в ячейке кнопки: без неё подпись сдвигает
       степпер вниз и кнопка перестаёт совпадать с ним по вертикали */
    .sl-list .sl-cell-act::before {
        content: ""; display: block; height: 14px; margin-bottom: 7px;
    }

    .sl-toggle {
        /* та же утечка паддинга темы: border-box не ужимает бокс меньше
           паддинга — без сброса 44×44 раздувается до размера паддингов */
        padding: 0; min-width: 0; min-height: 0;
        appearance: none; cursor: pointer; border: 0; background: none;
        width: 44px; height: 44px; display: grid; place-items: center;
    }

    .sl-toggle::before {
        content: ""; width: 9px; height: 9px;
        border-right: 1.6px solid var(--faint); border-bottom: 1.6px solid var(--faint);
        transform: rotate(45deg) translate(-2px, -2px); transition: transform .15s;
    }

    .sl-toggle[aria-expanded="true"]::before {
        border-color: var(--accent); transform: rotate(-135deg) translate(-2px, -2px);
    }

    .sl-total { display: block; font-size: 17px; }
    /* в карточке подписи возвращаются под свой элемент */
    /* .sl-list перед классом — иначе .sl-list td { display: block } выше по
       специфичности и сумма с ценой встают в обратном порядке */
    .sl-list .sl-cell-sum { text-align: right; }
    .sl-conv { margin-top: 3px; min-height: 15px; }
    .sl-gtag { padding: 3px 7px; }
    /* 44 + 44 на кнопки, ~62 на «N м²»; min-width: fit-content из базы
       по-прежнему не даёт обрезать четырёхзначное количество */
    .sl-qty { display: flex; width: 100%; max-width: 150px; }
    .sl-qty button { width: 44px; height: 44px; }
    .sl-buy { padding: 12px 14px; min-height: 46px; }

    /* ---------- панель заявки: пустая сворачивается до одной кнопки ---------- */
    .sl-toast { margin: 0 14px -46px; bottom: 16px; }
}

/* На самых узких экранах кнопка не помещается рядом со степпером — уходит
   на свою строку во всю ширину. */
@media (max-width: 345px) {
    .sl-list tbody tr { gap: 6px 8px; padding-left: 12px; }
    .sl-list .sl-cell-qty { width: auto; justify-self: stretch; }
    .sl-list .sl-cell-act { grid-area: 5 / 1 / 5 / -1; width: auto; justify-self: stretch; }
    .sl-list .sl-cell-act::before { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .sl-buy, .sl-toast, .sl-fchip, .sl-toggle::before { transition: none; }
}

.subcat-listing .vh {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
}
