/* ============================================================
   shop-storefront — компоненты витрины. Дизайн-язык = канон
   лендинг-визарда (W7): токены tokens.css (--accent от палитры,
   нейтрали --bg/--bg-soft/--card/--text/--muted/--border/--shadow),
   ВСЁ в rem (масштаб несёт корень: от 768px html{font-size:100vw/90},
   с 1440px — фикс 16px), карточки 12px с hairline-бордером и мягкой
   тенью, кнопки/инпуты 10px, фокус = outline 2px var(--accent).

   ПОЛИТИКА ГОРИЗОНТАЛЬНЫХ ЛИНИЙ (W7 → B1, жёстко): в этом файле
   ровно ТРИ hairline — border-bottom шапки (.shop-header),
   border-top футера (.shop-footer) и border-bottom тулбара каталога
   (.cat-tools; выбор владельца — мокап В3 «Одна строка», B1 D1).
   Все прочие горизонтальные разделители запрещены: вместо них воздух
   (rem) и --bg-soft-подложки (смоук-проба w7-canon ловит регрессию
   grep'ом).

   МОБИЛЬНЫЙ-ФЁРСТ: база = телефон (320: одна колонка, тап-таргеты
   2.75rem, инпуты 1rem — iOS не зумит). Один ГЛАВНЫЙ брейкпоинт
   48rem (=768px канона: десктопная шапка/тулбар/сплиты); у грида
   каталога свои микрошаги колонок 30rem (1→2) и 62rem (2→4) —
   контентная логика W6 №19, не «планшетная перестройка». Ни одного
   max-width-медиазапроса и px-ширин.

   Анти-card-soup (W1..W6, сохранено): карточный грид — только
   каталог/категория и «Похожие»; корзина/checkout/статусы —
   типографика; тинты вместо заливок; font-mono — только номер заказа.
   ============================================================ */

/* ── База ───────────────────────────────────────────────────── */
* { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* B1 (D5, WCAG 2.4.11 Focus Not Obscured): цель в фокусе не должна
     прятаться под sticky-шапкой и sticky-тулбаром */
  scroll-padding-top: calc(var(--header-h) + var(--tools-h) + 0.75rem);
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
  margin: 0;
  /* Футер прижат к низу на ЛЮБОЙ высоте контента: страница — колонка на весь
     экран, main растёт (короткие страницы — 404, пустая корзина, кабинет —
     не оставляют футер посреди вьюпорта). dvh, а не vh: на мобилке адресная
     строка браузера не раздувает высоту; 100vh выше — фолбэк старых браузеров. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  font-family: var(--font-sans);
  font-size: var(--text-md);
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  font-synthesis-weight: none;
}
main { flex: 1 0 auto; } /* контент растёт, шапка и футер остаются по краям */
h1, h2, h3 {
  margin: 0 0 var(--shop-space-2);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.02em;
  overflow-wrap: break-word; /* длинное слово не распирает узкую колонку 320 */
}
p { margin: 0 0 var(--shop-space-4); overflow-wrap: break-word; }
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-strong); }
img, svg { max-width: 100%; height: auto; display: block; }
::selection { background: color-mix(in srgb, var(--accent) 20%, transparent); }
/* A11y канона лендинга: видимая фокус-обводка акцентом */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* Скип-линк канона лендинга (B1 D5): первый таб-стоп страницы, до <main> */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--accent); color: var(--on-accent);
  padding: .6rem var(--shop-space-4); border-radius: 0 0 8px 0; font-weight: 600;
}
.skip-link:focus { left: 0; }

/* Контейнер: канон .wrap — гаттер 1.25rem на любой ширине */
.shop-container { max-width: var(--container); margin: 0 auto; padding: 0 var(--gutter); }
.shop-prose { max-width: var(--container-prose); }
/* Вертикальный ритм секций: на телефоне на треть компактней */
.section-y { padding-top: calc(var(--section-y) * 0.67); padding-bottom: calc(var(--section-y) * 0.67); }

.text-3 { color: var(--muted); }
.mono { font-family: var(--font-mono); }

/* ── Шапка: sticky, сплошной фон ─────────────────────────────
   Одна строка на любой ширине: лого | nav (≥48rem) | действия
   (корзина, тема, burger). Member-ссылки (Кабинет/Выйти, Войти/
   Регистрация) на мобиле живут в burger-details (нативный паттерн
   лендинга) — в строке остаются только иконки 2.75rem, слипаться
   нечему (разнос владельца «шапка в кашу», W7).
   B1-v2 (джанк-фиск): blur + полупрозрачный фон УДАЛЕНЫ —
   backdrop-filter перерисовывает подложку каждый кадр скролла;
   сплошной var(--bg) стоит ноль и над прокручиваемым контентом
   читается так же (hairline уже отделяет шапку). */
.shop-header {
  position: sticky; top: 0; z-index: 50;
  background: var(--bg);
  /* hairline 1 из 2 разрешённых (политика линий W7) */
  border-bottom: 1px solid var(--border);
}
.shop-header-inner {
  display: flex; flex-wrap: wrap; align-items: center;
  /* W9 (F2.3): компактный зазор — на 320 лого + иконки помещаются В ОДНУ
     строку (~272px из 280); на десктопе плотность не вредит (группа
     действий прижата margin-left: auto). */ gap: var(--shop-space-2);
  min-height: var(--header-h);
}
.shop-logo {
  min-width: 0;
  font-size: 1.06rem; font-weight: 800; letter-spacing: -0.01em;
  color: var(--text);
  overflow-wrap: break-word;
}
.shop-logo:hover { text-decoration: none; color: var(--accent); }
/* headerfix: auth-ссылки правого кластера (.header-auth — первый ребёнок
   .header-actions, до корзины/темы). Стиль тихой текстовой ссылки — канон
   бывшего .site-nav (кнопкой НЕ выглядит, hover — bg-soft); разрядку пары
   ведёт собственный gap, дистанцию до корзины/темы — gap .header-actions
   (0.5rem, как между иконками). На мобиле кластер скрыт: строка шапки —
   только иконки (канон W7, влезание в 320), ссылки живут в .nav-burger-panel
   (свои стили, классом header-auth не помечены — каскадной встречи нет);
   ≥48rem — кластер возвращается в строку справа. */
.header-auth { display: none; }
.header-auth a, .header-auth .nav-logout-btn {
  color: var(--muted); font-size: 0.92rem; font-weight: 500;
  padding: 0.4rem 0.6rem; border-radius: 6px;
}
.header-auth a:hover, .header-auth .nav-logout-btn:hover { color: var(--text); background: var(--bg-soft); text-decoration: none; }
.header-actions { display: flex; align-items: center; gap: 0.5rem; margin-left: auto; }

/* burger-details (канон лендинга, без JS): иконка-кнопка 2.75rem,
   панель во всю ширину шапки — ссылки крупными строками с воздухом */
.nav-burger summary {
  list-style: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--shop-touch); height: var(--shop-touch); /* W9 F2.3 + P2: 44px-пол на любой ширине */
  border: 1px solid var(--border); border-radius: var(--radius-btn); color: var(--muted);
}
.nav-burger summary::-webkit-details-marker { display: none; }
.nav-burger[open] summary, .nav-burger summary:hover { color: var(--text); border-color: var(--accent); }
.nav-burger-panel {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 40;
  background: var(--card);
  padding: var(--shop-space-2) var(--gutter) var(--shop-space-4);
  display: grid; gap: 0.25rem;
  box-shadow: var(--shop-shadow-pop);
}
.nav-burger-panel a, .nav-burger-panel .nav-logout-btn {
  padding: 0.6rem 0.4rem; border-radius: 6px;
  color: var(--text); font-weight: 500; text-align: left;
}
.nav-burger-panel a:hover, .nav-burger-panel .nav-logout-btn:hover { background: var(--bg-soft); text-decoration: none; }
.nav-logout { display: inline-flex; }
.nav-logout-btn { border: 0; background: none; font: inherit; cursor: pointer; }

/* Корзина-счётчик: пилюля в тинте акцента; пустая — тихая */
.cart-counter {
  position: relative; display: inline-flex; align-items: center; gap: 0.375rem;
  min-height: var(--shop-touch); padding: 0.375rem var(--shop-space-2); border-radius: var(--radius-pill); /* W9 (F2.3)+P2: 44px-пол */
  font-size: var(--text-sm); font-weight: 600;
  background: var(--accent-tint); color: var(--accent);
}
.cart-counter:hover { text-decoration: none; color: var(--accent-strong); }
.cart-counter[data-empty="1"] { background: transparent; color: var(--muted); }
.cart-counter svg { width: 1.1rem; height: 1.1rem; }

/* Иконка-кнопка (тумблер темы): база 2.5rem — W9 (F2.3): на 320 шапка с
   пилюлей корзины помещается в ОДНУ строку только с 40px-иконками
   (лого ~112 + корзина ~47 + 2×40 + зазоры = ~263 < 280); десктоп всё
   равно пересаживает тумблер на 2.25rem канона (≥48rem). Тап-таргет 40px
   — осознанный компромисс D31 для самой узкой базы. */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--shop-touch); height: var(--shop-touch);
  border: 1px solid var(--border); border-radius: var(--radius-btn);
  background: transparent; color: var(--muted); cursor: pointer;
}
.icon-btn:hover { color: var(--text); border-color: var(--accent); }

/* ── Тумблер темы: SVG-морф солнце→луна (W6 №23, web.dev-паттерн) ──
   Одна иконка: светлая — солнце с лучами; тёмная — вырезка-маска съезжает
   на диск (затмение → серп), лучи разлетаются и гасят opacity. Анимация
   гейтится prefers-reduced-motion; тап-таргет остаётся 2.75rem. */
.theme-toggle .theme-mask-hole { transform: translate(0, 0); }
.theme-toggle .theme-rays { opacity: 1; transform: scale(1); transform-origin: 12px 12px; }
[data-theme="dynamica-dark"] .theme-toggle .theme-mask-hole { transform: translate(-19px, 8px); }
[data-theme="dynamica-dark"] .theme-toggle .theme-rays { opacity: 0; transform: scale(1.75); }
@media (prefers-reduced-motion: no-preference) {
  .theme-toggle .theme-mask-hole,
  .theme-toggle .theme-rays { transition: transform 300ms var(--ease), opacity 300ms var(--ease); }
}

/* ── Подвал: hairline 2 из 2 разрешённых (политика линий W7) ── */
.shop-footer { border-top: 1px solid var(--border); margin-top: var(--section-y); }
/* W9 (F1): .shop-footer-inner живёт на .shop-container — его `padding: var(--shop-space-7) 0` перебивал горизонтальный гаттер контейнера, текст прилипал к краям. Гаттер возвращён явно (padding-inline), вертикальный ритм прежний. */ .shop-footer-inner { padding: var(--shop-space-7) var(--gutter); font-size: 0.9rem; color: var(--muted); }
.footer-grid { display: grid; gap: 1.25rem; }
.footer-brand { margin: 0 0 var(--shop-space-2); font-weight: 600; color: var(--text); }
.footer-line { margin: 0 0 var(--shop-space-1); overflow-wrap: break-word; }
.footer-link { color: var(--muted); }
.footer-link:hover { color: var(--accent); }
.footer-legal { margin: 0; font-size: var(--text-xs); color: var(--muted); white-space: pre-line; }
/* без hairline: воздух + приглушение (политика линий W7).
   B1 (D5): opacity снята — muted на bg и так AA, .75 ронял контраст
   мелкой строки ниже 4.5:1 */
.footer-powered { margin: var(--shop-space-6) 0 0; font-size: var(--text-xs); color: var(--muted); }

/* ── Hero каталога/категории (канон hero лендинга, W7) ────────
   Центрированный, фон — градиент тинта акцента; kicker-пилюля,
   крупный H1 по clamp-формуле канона; счётчик товаров — ОТДЕЛЬНОЙ
   строкой под H1 (разнос владельца «H1 слипся со счётчиком»);
   описание — lead. Крошки — тихой строкой сверху слева. */
.cat-hero {
  padding: var(--shop-space-8) 0 var(--shop-space-7);
  text-align: center;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 9%, var(--bg)), var(--bg) 78%);
}
.cat-hero .shop-container > .breadcrumbs { text-align: left; }
.kicker {
  display: inline-flex; align-items: center;
  margin: 0 0 0.9rem; padding: 0.2rem 0.7rem; border-radius: var(--radius-pill);
  background: var(--accent-tint); color: var(--accent);
  font-size: 0.8125rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
}
.cat-title {
  margin: 0;
  font-size: clamp(2rem, 1.4rem + 2.6vw, 3.25rem);
  line-height: 1.12; letter-spacing: -0.02em; font-weight: 700;
}
/* счётчик товаров — W9 (F4): тихая строка НАД гридом слева (из hero убран:
   одинокая строка под H1 выглядела непонятным элементом) */
.cat-count { margin: 0 0 0.9rem; color: var(--muted); font-size: 0.9rem; }
.cat-desc { margin: var(--shop-space-4) auto 0; max-width: 38rem; color: var(--muted); font-size: 1.05em; }
/* короткое описание сверху: 2 строки + «Ещё» (состояние ведёт скрипт каталога) */
.cat-desc[data-clamp="1"] {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
}
.desc-toggle {
  display: none; margin: 0.4rem auto 0; padding: var(--shop-space-3) var(--shop-space-4); border: 0; background: none;
  color: var(--accent); font-size: var(--text-sm); font-family: inherit;
  cursor: pointer; text-decoration: underline; text-underline-offset: 3px;
  /* B1 (D5, WCAG 2.5.8 + P2): тач-цель «Ещё» = 44px-пол на любой ширине */
  min-height: var(--shop-touch);
}
.desc-toggle[data-visible="1"] { display: inline-block; }
/* полное SEO-описание — под гридом, перед футером */
.cat-desc-full {
  margin: var(--section-y) 0 0; max-width: var(--container-prose);
  color: var(--muted); font-size: var(--text-sm);
}

/* ── Хлебные крошки (D26, W6 №2-4) — тихая строка ─────────────
   Разделитель — CSS ::before (не DOM-текст: скринридеры его не
   читают); последний элемент — span[aria-current] без ссылки.
   Мобайл: одна строка nowrap + overflow-x + фейд справа; JS
   автоскроллит к текущему (partial крошек несёт свой скрипт). */
.breadcrumbs { margin-bottom: var(--gutter); }
.crumb-list {
  display: flex; flex-wrap: nowrap; align-items: center;
  gap: 0; margin: 0; padding: 0; list-style: none;
  font-size: 0.8125rem; color: var(--muted);
  overflow-x: auto; overflow-y: hidden; white-space: nowrap;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent);
}
.crumb-list::-webkit-scrollbar { display: none; }
.crumb-item { display: inline-flex; align-items: center; flex: 0 0 auto; }
.crumb-item + .crumb-item::before {
  content: "/"; margin: 0 0.375rem; color: var(--muted); opacity: 0.6;
}
.crumb {
  display: inline-flex; align-items: center; min-height: var(--shop-touch);
  padding: 0 var(--shop-space-1); color: var(--muted); text-decoration: none;
}
.crumb:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.crumb-current {
  display: inline-flex; align-items: center; min-height: var(--shop-touch);
  color: var(--text); font-weight: 500;
}

/* ── Тулбар каталога — В3 «Одна строка» (B1 D1, выбор владельца) ─
   Мобайл (база): одна sticky-строка под шапкой — «Фильтры» (бейдж)
   + «Сортировка: <текущая>» (нижние листы), чипы ниже переносятся
   строками (D2, без обрезки). ≥48rem — ОДНА строка мокапа В3:
   поиск (растёт) · дропдаун сортировки · «Найти» · вертикальный
   hairline-разделитель · чипы категорий (первые N + «Ещё N») ·
   счётчик справа. Sticky сохранён: фон --bg; отделение от контента
   несёт hairline №3 (border-bottom — решение владельца в В3),
   тени и скруглений кластера НЕТ («не меню-панель»). */
.cat-tools {
  position: sticky; top: var(--header-h); z-index: 30;
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0.25rem 0.625rem;
  margin: 0 calc(var(--gutter) * -1) var(--shop-space-6); padding: var(--shop-space-1) var(--gutter) 0.625rem;
  background: var(--bg);
  /* hairline 3 из 3 разрешённых (политика линий B1 — мокап В3) */
  border-bottom: 1px solid var(--border);
  /* находка владельца B1: после hairline нужен воздух до грида (24px),
     иначе hairline прилипает к карточкам */
}
.toolbar-mobile {
  display: flex; flex: 1 1 100%; align-items: center; justify-content: space-between; gap: 0.625rem;
  /* W9 (F2.1): min-width сбит — flex-элемент по умолчанию не сжимается ниже
     min-content суммы кнопок («Сортировка: Сначала новые» ~204px), из-за чего
     тулбар распирал контейнер до 325px и выталкивал documentElement в
     горизонтальный скролл на 320. С min-width: 0 ряд сжимается, подпись
     сортировки ужимается в ellipsis (правило .toolbar-btn ниже). */
  min-width: 0;
}
/* «Фильтры» — по содержимому, «Сортировка: …» — на остальную ширину
   (подпись с ellipsis, тулбар одной строкой ~44px — находка критика W7) */
.toolbar-mobile .toolbar-btn:first-child { flex: 0 0 auto; }
.toolbar-mobile .toolbar-btn + .toolbar-btn { flex: 1 1 auto; justify-content: center; min-width: 0; }
.toolbar-btn {
  display: inline-flex; align-items: center; gap: 0.5rem;
  min-height: var(--shop-touch); padding: 0.375rem 0.875rem; /* 44px-пол на любой ширине, D31+P2 */
  border: 1px solid var(--border); border-radius: var(--radius-btn);
  background: var(--card); color: var(--text);
  font-size: var(--text-sm); font-family: inherit; cursor: pointer;
  transition: border-color 200ms var(--ease), background-color 200ms var(--ease);
  /* находка критика W7: подпись сортировки не переносится на 2-ю строку
     (<480px) — тулбар держит одну строку ~44px, хвост подписи — ellipsis */
  min-width: 0; white-space: nowrap;
}
.toolbar-btn > span { overflow: hidden; text-overflow: ellipsis; }
.toolbar-btn:hover { border-color: var(--accent); color: var(--accent); }
.toolbar-btn svg { width: 1rem; height: 1rem; color: var(--muted); }
.toolbar-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.25rem; height: 1.25rem; padding: 0 0.375rem;
  border-radius: var(--radius-pill);
  background: var(--accent); color: var(--on-accent);
  font-size: var(--text-xs); font-weight: 600;
}
/* десктопная форма в базе скрыта (мобайл — кнопки-листы) */
.search-box, .tools-right, .tools-sep, .tools-count { display: none; }
.search-box { position: relative; min-width: 0; }
.search-icon {
  position: absolute; left: 0.75rem; top: 50%; transform: translateY(-50%);
  width: 1rem; height: 1rem; color: var(--muted); opacity: 0.7; pointer-events: none;
}
.field-input.search-input { padding-left: 2.375rem; min-height: var(--shop-touch); }
/* лейбл сортировки — только скринридерам (видимый лейбл раздувал тулбар) */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; /* px-допустимо: канонический sr-only паттерн */
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.sort-box { position: relative; min-width: 0; width: 100%; }

/* ── Кастомный дропдаун (B1 D3) — APG Select-Only Combobox ────
   Нативный select остаётся в форме источником значения (no-JS
   фоллбек), dropdown.js строит поверх него кнопку+listbox и прячет
   селект (.dd-source). Появление списка — fade + 2px сдвиг 160ms,
   гейт prefers-reduced-motion; шеврон крутится на 180° (канон
   «rotating chevron»); варианты — тач-цели 2.75rem в базе. */
.dd { position: relative; min-width: 0; }
.dd-source { display: none !important; }
.dd-btn {
  width: 100%;
  display: inline-flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  text-align: left; cursor: pointer;
}
.dd-btn .dd-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-chevron {
  flex: 0 0 auto; width: 0.875rem; height: 0.875rem; color: var(--muted);
  transition: transform 200ms var(--ease);
}
.dd[data-open="1"] .dd-chevron { transform: rotate(180deg); }
.dd-list {
  position: absolute; left: 0; right: 0; top: calc(100% + 0.25rem); z-index: 60;
  margin: 0; padding: var(--shop-space-1); list-style: none;
  background: var(--card);
  border: 1px solid var(--border); border-radius: var(--radius-input);
  box-shadow: var(--shop-shadow-pop);
  max-height: 20rem; overflow-y: auto;
}
@media (prefers-reduced-motion: no-preference) {
  .dd-list { animation: dd-in 160ms var(--ease); }
  @keyframes dd-in {
    from { opacity: 0; transform: translateY(-2px); }
    to { opacity: 1; transform: translateY(0); }
  }
}
.dd-opt {
  display: flex; align-items: center;
  min-height: var(--shop-touch); padding: 0.375rem 0.625rem; /* тач-цель 44px-пол, D31+P2 */
  border-radius: 8px; cursor: pointer; color: var(--text);
  font-size: var(--text-sm);
}
.dd-opt[data-active="1"] { background: var(--bg-soft); }
.dd-opt[aria-selected="true"] { color: var(--accent); font-weight: 600; background: var(--accent-tint); }
.search-submit { flex: 0 0 auto; }

/* ── Применённые фильтры — чипы с крестиком (W6 №9) ───────────
   Одна скролл-строка (как чипы категорий): мобайл — под тулбаром;
   на десктопе ряд живёт ВНУТРИ тулбара (между поиском и сортировкой).
   Чип = ссылка «вычесть этот фильтр из URL», × декоративный. */
.applied-row {
  display: flex; flex-wrap: nowrap; gap: 0.5rem;
  align-items: center; min-width: 0;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 1rem), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 1rem), transparent);
}
.applied-row::-webkit-scrollbar { display: none; }
.applied-row-mobile { margin: 0.625rem 0 0; }
.applied-row-desktop { display: none; flex: 1 1 auto; }
.applied-chip {
  display: inline-flex; align-items: center; gap: 0.375rem;
  flex: 0 0 auto; scroll-snap-align: start;
  min-height: var(--shop-touch); padding: var(--shop-space-1) var(--shop-space-3); border-radius: var(--radius-pill); /* 44px-пол, D31+P2 */
  background: var(--accent-tint); color: var(--accent);
  font-size: var(--text-sm); font-weight: 500; text-decoration: none;
  transition: background-color 200ms var(--ease), color 200ms var(--ease);
}
.applied-chip:hover { background: var(--accent-tint-strong); color: var(--accent-strong); text-decoration: none; }
.applied-chip .applied-x { font-size: var(--text-md); line-height: 1; }
.applied-reset {
  flex: 0 0 auto; min-height: var(--shop-touch); padding: var(--shop-space-1) var(--shop-space-2); border: 0; background: none; /* 44px-пол, D31+P2 */
  color: var(--muted); font-size: var(--text-sm); font-family: inherit;
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.applied-reset:hover { color: var(--err); }

/* ── Чипы категорий (B1 D2 → uxfix2 B — одна скролл-строка на мобиле) ──
   МОБАЙЛ (uxfix2, канон): ряд = «Все» + «В наличии» + первые слоты +
   «Ещё категории (K)» в ОДНОЙ горризонтальной скролл-строке БЕЗ
   переноса (overflow-x: auto, nowrap); обрезка чипа ПОПОЛАМ внутри
   ряда по-прежнему запрещена — чип не сжимается (flex: 0 0 auto) и
   не переносит текст (min-width: max-content), никаких ellipsis.
   ДЕСКТОП (≥48rem): чипы живут В строке тулбара (мокап В3);
   свёрнуто — первые N (лишние .chip-extra спрятаны), развернуто
   ([data-chips-open="1"]) — чипы переносятся строками под кластером.
   Активная категория видна всегда (.chip-extra[data-pinned="1"]). */
.chip-row {
  display: flex; flex-wrap: nowrap;
  gap: 0.5rem;
  margin: 0.875rem 0 var(--shop-space-1);
  min-width: 0;
  overflow-x: auto; scrollbar-width: none;
  /* мобайл: чипы — одной скролл-строкой под кнопками-листами */
  flex: 1 1 100%;
}
.chip-row::-webkit-scrollbar { display: none; }
.chip {
  display: inline-flex; align-items: center; gap: 0.375rem;
  flex: 0 0 auto; min-width: max-content;
  min-height: var(--shop-touch); padding: 0.375rem var(--shop-space-4); border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--card);
  font-size: var(--text-sm); color: var(--muted); cursor: pointer;
  transition: border-color 200ms var(--ease), color 200ms var(--ease);
}
.chip:hover { color: var(--text); border-color: var(--accent); text-decoration: none; }
.chip[aria-current="true"] {
  background: var(--accent-tint); color: var(--accent); border-color: transparent;
}
/* Кнопки «Ещё»: десктоп — «Ещё N» (.chip-more, первые filters_visible),
   мобайл — «Ещё категории (K)» (.chip-more-m, первые 3 слота; чипы —
   навигация, в дравер «Фильтры» не прячем). Скрытие лишних чипов:
   .chip-extra — десктопный лимит, .chip-extra-m — мобильный (классы
   независимы: чип №4 при N=5 скрыт на мобиле и виден на десктопе). */
.chip-more, .chip-extra-m { display: none; }
.chip-more-m { display: inline-flex; }
.chip-extra-m[data-pinned-m="1"] { display: inline-flex; }
.cat-tools[data-chips-open="1"] .chip-extra-m { display: inline-flex; }
/* счётчик товаров в чипе (D27); chip-child — второй уровень дерева (D18):
   иерархию несёт ПОРЯДОК (потомки сразу за родителем), отступ-«дыра»
   margin-left ликвидирована — чипы ровным рядом (v1.6.1) */
.chip-count {
  display: inline-flex; align-items: center; min-height: 1.25rem;
  padding: 0 var(--shop-space-2); border-radius: var(--radius-pill);
  background: var(--bg-soft); color: var(--muted);
  font-size: var(--text-xs);
}
.chip[aria-current="true"] .chip-count {
  background: var(--accent-tint-strong); color: var(--accent);
}

/* ── Нижние листы: фильтры и сортировка (W6 №7-8, №11) ────────
   fixed снизу, translateY-анимация, safe-area-inset-bottom; оверлей —
   клик закрывает; Esc закрывает (скрипт); футер листа — sticky кнопка
   «Показать N» (N — живой счётчик по черновику формы).
   Без внутренних hairline (политика W7): шапка/подвал листа —
   воздух и --bg-soft-подложка. */
.sheet-overlay {
  position: fixed; inset: 0; z-index: 90;
  background: color-mix(in srgb, var(--text) 40%, transparent);
  opacity: 0; visibility: hidden;
  transition: opacity 200ms var(--ease), visibility 0s linear 200ms;
}
.sheet-overlay[data-open="1"] {
  opacity: 1; visibility: visible;
  transition: opacity 200ms var(--ease);
}
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 100;
  display: flex; flex-direction: column;
  max-height: 85dvh;
  background: var(--card);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--shop-shadow-pop);
  transform: translateY(100%); visibility: hidden;
  transition: transform 260ms var(--ease), visibility 0s linear 260ms;
  padding-bottom: env(safe-area-inset-bottom);
}
.sheet[data-open="1"] {
  transform: translateY(0); visibility: visible;
  transition: transform 260ms var(--ease);
}
.sheet-head {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.9rem var(--shop-space-5) var(--shop-space-2);
}
.sheet-title { font-weight: 600; font-size: var(--text-md); }
.sheet-reset {
  margin-left: auto; padding: var(--shop-space-2) 0; border: 0; background: none;
  color: var(--muted); font-size: var(--text-sm); font-family: inherit;
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.sheet-reset:hover { color: var(--accent); }
.sheet-close {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--shop-touch); height: var(--shop-touch); margin-right: -0.5rem;
  border: 0; border-radius: var(--radius-pill);
  background: none; color: var(--muted); cursor: pointer;
  font-size: var(--text-lg); line-height: 1;
}
.sheet-close:hover { background: var(--bg-soft); color: var(--text); }
.sheet-body { overflow-y: auto; padding: var(--shop-space-4) var(--shop-space-5); display: grid; gap: 1.25rem; }
.sheet-group { border: 0; padding: 0; margin: 0; min-width: 0; }
.sheet-legend, .sheet-label {
  display: block; margin: 0 0 var(--shop-space-2); padding: 0;
  font-size: var(--text-sm); font-weight: 600; color: var(--text);
}
.sheet-option {
  display: flex; align-items: center; gap: 0.625rem;
  min-height: var(--shop-touch); cursor: pointer; color: var(--text);
}
.sheet-option input { width: 1.125rem; height: 1.125rem; accent-color: var(--accent); flex: 0 0 auto; }
.sheet-count { margin-left: auto; color: var(--muted); font-size: var(--text-sm); }
.sheet-foot {
  position: sticky; bottom: 0;
  padding: var(--shop-space-3) var(--shop-space-5);
  background: var(--bg-soft); /* подложка вместо hairline (политика W7) */
}
.sheet-apply { width: 100%; }
.sheet-apply .sheet-n { font-weight: 700; }
/* лок скролла страницы при открытом листе (вешает скрипт каталога) */
html[data-sheet-open="1"] { overflow: hidden; }

/* ── Карточный грид (ЕДИНСТВЕННЫЙ: каталог + «Похожие») ──────
   Мобильный-фёрст: 1 колонка (база, воздух 1.1rem — канон cards-grid;
   разнос владельца «карточки сливаются в ленту») → 2 (30rem) →
   4 (62rem). minmax(0, 1fr) — колонка не распирается длинным словом. */
.product-grid,
.rel-grid {
  display: grid; gap: 1.1rem;
  grid-template-columns: minmax(0, 1fr);
}
/* B2 (владелец 2026-10-09): content-visibility/contain-intrinsic-size на
   «Похожих» СНЯТЫ. Paint-containment от content-visibility клипает наружные
   тени крайних карточек к padding-box грида (рваный стиль против каталога;
   живой замер: полосы слева/справа/снизу были чистым белым 255, после
   content-visibility:visible тень возвращается). Цена отказа мала — фото в
   карточках и так loading="lazy". */
/* ── Карточка товара (W6 №20-22 → канон-карточка W7) ──────────
   Канон: border var(--border), radius 12px, тень --shadow.
   Фото — ЕДИНЫЙ аспект 3:4, object-fit: cover, лениво, width/height
   против CLS. Hover — свап на второе фото (на таче не активен).
   Название — 2 строки clamp; цена semibold; «Нет в наличии» —
   оверлей на фото (единственное место дубля: бейдж в теле при
   stock=0 не рендерится — W7 снял дублирование). */
.product-card {
  display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: var(--radius-card);
  background: var(--card);
  /* B1 (находка владельца, 320): на телефоне карточка плоская — hairline
     без blur-тени (нативный мобильный паттерн «карточки вплотную»; сумма
     «гуттер + мягкая тень» читалась толстым полем от края экрана) */
  color: inherit;
  /* B1-v2 глитч-хант (коррекция диагноза: системное «двоение при скролле» —
     старые растровые тайлы изолированных слоёв показываются в новой позиции
     кадра): с карточки СНЯТА изоляция слоёв целиком — ни contain (клауз
     B1 D4: CLS и так держат width/height фото), ни overflow:hidden
     (клип-остров). Скругление фото теперь клипует сам .product-card-photo
     (радиус верхних углов + свой overflow:hidden на маленьком боксе фото);
     фон/бордер карточки округляются нативно по border-radius. Карточка
     перестаёт быть дорогим комбайном «box-shadow + radius + overflow + contain»
     на каждый кадр скролла. */
}
/* B1-v2 глитч-фиск: во время прокрутки (JS вешает is-scrolling на <html>
   на scroll, снятие через 100ms idle — theme.js) hover-переходы карточки
   и кросс-фейд её фото выключены: пересечение курсором карточек при
   скролле не порождает repaint вообще. transition:none схлопывает
   переход к целевому значению мгновенно — застреваний не бывает.
   Против СИСТЕМНОГО двоения гард бесполезен (курсор не при чём), но
   снимает вопрос стационарного курсора на других машинах. */
html.is-scrolling .product-card,
html.is-scrolling .product-card-photo img { transition: none !important; }
@media (min-width: 48rem) { .product-card { box-shadow: var(--shop-shadow-card); } }
/* B1-v2 (находка владельца «дёрганье картинок при скролле»): у карточки
   НЕТ анимированной тени. Hover = ТОЛЬКО border-color с переходом 80ms
   (ниже порога заметности — пролёт курсора над гридом при прокрутке
   не пульсирует) + кросс-фейд второго фото (отдельно ниже). Теневой
   transition удалён: тень покоя постоянна (светлая тема), на тёмной
   теней нет вовсе (токены). Высота карточки при hover не меняется;
   на таче/скролле hover-правила не действуют (media-гейт). */
@media (hover: hover) and (pointer: fine) {
  .product-card { transition: border-color 80ms linear; }
  .product-card:hover {
    border-color: var(--shop-border-hover);
    text-decoration: none;
  }
}
.product-card-photo {
  position: relative;
  aspect-ratio: 3 / 4; width: 100%;
  /* B1-v2 глитч-хант: клип фото переехал с карточки сюда — радиус верхних
     углов = радиус карточки минус её бордер (снизу — ноль: там тело
     карточки); свой overflow:hidden клипает img на МАЛЕНЬКОМ боксе фото.
     Фон-подложка тоже округлена — без карточного overflow угол не светит
     квадратом на фоне страницы. */
  border-radius: calc(var(--radius-card) - 1px) calc(var(--radius-card) - 1px) 0 0;
  overflow: hidden;
  background: var(--bg-soft); color: var(--muted);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--text-sm);
}
.product-card-photo img {
  width: 100%; height: 100%; object-fit: cover;
  transition: opacity 200ms var(--ease);
}
.product-card-photo .card-img-alt { position: absolute; inset: 0; opacity: 0; }
@media (hover: hover) and (pointer: fine) {
  .product-card:hover .card-img-alt { opacity: 1; }
}
/* W9 (F10): кросс-фейды (hover-второе-фото карточки и галерея) гейтятся:
   reduce — анимация выключена, смена кадра мгновенная */
@media (prefers-reduced-motion: reduce) {
  .product-card-photo img { transition: none; }
}
.card-overlay {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; align-items: center; justify-content: center;
  min-height: 2.25rem; padding: var(--shop-space-1) var(--shop-space-3);
  /* B1 (находка владельца): тихий текст без фоновой пилюли; читаемость
     над произвольным фото — мягкий ореол цвета ФОНА ТЕМЫ под буквами
     (в обеих темах ореол = var(--bg), на нём --err держит ≥4.5:1) */
  background: transparent;
  color: var(--err); font-size: var(--text-sm); font-weight: 600;
  text-shadow: 0 1px 3px color-mix(in srgb, var(--bg) 90%, transparent), 0 0 8px color-mix(in srgb, var(--bg) 90%, transparent);
}
.product-card-body { display: flex; flex-direction: column; gap: 0.5rem; padding: var(--shop-space-4) var(--shop-space-5) var(--shop-space-5); }
.product-card-title {
  margin: 0; font-size: var(--text-sm); font-weight: 600;
  line-height: 1.35; color: var(--text);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
  /* резерв высоты 2 строк — карточки в ряду равной высоты */
  min-height: calc(1.35em * 2);
}
.product-card-price { font-size: var(--text-lg); font-weight: 600; }
.product-card-price .rub { color: var(--muted); font-weight: 400; margin-left: var(--shop-space-1); }
.product-card-stock { margin-top: auto; display: flex; }

/* ── salewave: цена распродажи — тихая зачёркнутая старая + новая + ──
   tint-бейдж «−N%» (акцентный тинт, НЕ semantic-красный: скидка —
   витринное событие, а не ошибка; цвет едет за палитрой магазина).
   Зачёркивание — обычный <s> с приглушённым цветом и нормальной
   насыщенностью: старая цена читается, новую не перекрикивает. */
.price-old {
  color: var(--muted);
  font-weight: 400;
  font-size: 0.875em;
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  margin-right: 0.375rem;
}
.price-now { font-variant-numeric: lining-nums; }
.badge-sale { background: var(--accent-tint); color: var(--accent-strong); }
.product-price .badge-sale { margin-left: var(--shop-space-2); vertical-align: 0.2em; }

/* ── B2c: избранное — сердечко (F1: JS-гидратация) ───────────
   Кнопка-СОСЕД ссылки карточки (вложенный интерактив в <a> невалиден):
   обёртка — grid-айтем вместо карточки, карточка растягивается на всю
   высоту ряда. Сердечко — абсолют поверх фото (правый верхний угол):
   пустое = контурная штрих-иконка токен-цвета, залитое = accent (F1).
   Переключение МГНОВЕННОЕ: transition НЕТ (reduce-гейт не нужен —
   анимации нет вовсе, канон B2c). Тач-цель ≥44px (--shop-touch). */
.product-card-wrap { position: relative; display: flex; }
.product-card-wrap .product-card { flex: 1 1 auto; }
.fav-btn {
  position: absolute; top: var(--shop-space-2); right: var(--shop-space-2);
  z-index: 2;
  width: var(--shop-touch); height: var(--shop-touch);
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--radius-pill);
  background: transparent; color: var(--muted);
  cursor: pointer; padding: 0;
}
.fav-btn:hover, .fav-btn:focus-visible { color: var(--text); }
.fav-btn[aria-pressed="true"] { color: var(--accent); }
.fav-btn[aria-pressed="true"] .fav-heart { fill: var(--accent); stroke: var(--accent); }
/* Страница товара: сердечко в правом верхнем углу фото галереи
   (viewport не ссылка — позиционирование от него). */
.fav-btn-page { top: var(--shop-space-2); right: var(--shop-space-2); color: var(--text); }
/* Контраст контура над произвольным фото — мягкий ореол цвета фона темы
   (паттерн card-overlay: читаемость на любом снимке, обе темы). */
.fav-btn-page svg { filter: drop-shadow(0 1px 3px color-mix(in srgb, var(--bg) 90%, transparent)); }

/* ── B2c: страница «Избранное» ─────────────────────────────── */
.fav-empty { max-width: var(--container-prose); }
.fav-empty-title { font-size: var(--text-lg); font-weight: 600; margin: var(--shop-space-5) 0 0; }
.fav-empty-text { color: var(--muted); margin: var(--shop-space-2) 0 var(--shop-space-5); }

/* ── B2c: отзывы на карточке товара ──────────────────────────
   Только published (модерация статусом в админке); поля анонима
   эскейпятся шаблоном (B-1). Форма — нативный POST (no-JS).
   v1.7.3 — дизайн A «Ряд» (мокапы review-A-*): шапка со средней
   крупно + SVG-звёзды + счётчиком и CTA справа; карточки —
   инициал-аватар (accent-tint), имя, дата справа, мелкие звёзды,
   текст. SVG-звёзды — инлайн-спрайт шаблона (#shop-star), честная
   графика вместо глифа ★: трек (muted 25%) + заливка-обрезка по
   ширине (половина = 50%). Цвет звёзд — токен --warn (семантика
   рейтинга, не бренда; dark-автосветление токеном). Переменные
   звёзд скоупятся секцией (.reviews) — tokens.css не трогают. */
.reviews {
  --star-fill: var(--warn);
  --star-track: color-mix(in srgb, var(--muted) 25%, transparent);
  margin-top: calc(var(--section-y) * 0.75); max-width: var(--container-prose);
}
.reviews-head { display: flex; align-items: center; gap: var(--shop-space-3); flex-wrap: wrap; }
.reviews-title { margin: 0; font-size: var(--text-lg); font-weight: 600; }
.reviews-avg { color: var(--text); font-size: 1.75rem; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.reviews-count { color: var(--muted); font-size: var(--text-sm); }
.reviews-cta { margin-left: auto; font-weight: 600; }
.reviews-meta { margin: 0; color: var(--muted); font-size: var(--text-sm); }
.review-sprite { position: absolute; width: 1px; height: 1px; overflow: hidden; }
.stars { display: inline-flex; gap: 0.125rem; vertical-align: -0.1875rem; }
.star { position: relative; width: 1.125rem; height: 1.125rem; }
.stars-lg .star, .stars-lg .star svg { width: 1.375rem; height: 1.375rem; }
.stars-sm .star, .stars-sm .star svg { width: 0.875rem; height: 0.875rem; }
.star svg { display: block; }
.star .star-track { color: var(--star-track); }
.star .star-fill { position: absolute; top: 0; left: 0; height: 100%; overflow: hidden; color: var(--star-fill); }
.review-list { list-style: none; margin: var(--shop-space-5) 0 0; padding: 0; display: grid; gap: var(--shop-space-3); }
.review-card {
  display: flex; gap: var(--shop-space-3);
  padding: var(--shop-space-4) var(--shop-space-5);
  border: 1px solid var(--border); border-radius: var(--radius-card); background: var(--card);
}
/* тень карточки — только в светло теме (токен --shop-shadow-card в dark = none,
   канон «тёмная без теней»); паттерн карточки каталога */
@media (min-width: 48rem) { .review-card { box-shadow: var(--shop-shadow-card); } }
.review-avatar {
  flex: 0 0 auto; width: 2.5rem; height: 2.5rem; border-radius: var(--radius-pill);
  background: var(--accent-tint-strong); color: var(--accent-strong);
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: var(--text-md);
}
.review-main { min-width: 0; flex: 1; }
.review-head { display: flex; align-items: baseline; gap: var(--shop-space-2) var(--shop-space-3); flex-wrap: wrap; }
.review-author { font-weight: 600; }
.review-verified {
  display: inline-flex; align-items: center; gap: var(--shop-space-1);
  padding: 0 var(--shop-space-2); border-radius: var(--radius-pill);
  background: var(--ok-tint); color: var(--ok);
  font-size: var(--text-xs); font-weight: 600;
}
.review-date { margin-left: auto; color: var(--muted); font-size: var(--text-sm); white-space: nowrap; }
.review-stars-row { margin-top: var(--shop-space-1); }
.review-body { margin: var(--shop-space-2) 0 0; white-space: pre-line; }
.form-ok {
  margin: var(--shop-space-4) 0 0; padding: var(--shop-space-3) var(--shop-space-4);
  border-radius: var(--radius-btn); background: var(--ok-tint); color: var(--ok);
}
.review-form { display: grid; gap: var(--shop-space-2); margin-top: var(--shop-space-4); max-width: var(--container-prose); }
.review-form-title { margin: var(--shop-space-4) 0 0; font-size: var(--text-md); font-weight: 600; }
.review-label { font-weight: 600; font-size: 0.92rem; margin-top: var(--shop-space-1); }
.review-form .btn { justify-self: start; margin-top: var(--shop-space-2); }
/* Отзывы-вход (v1.7.1): тихий CTA вместо формы для гостя — строка-подсказка
   в тон мета-текста отзывов, ссылки акцентом, но не кнопка (не кричит). */
.review-login { margin: var(--shop-space-4) 0 0; color: var(--muted); font-size: var(--text-sm); }
.review-login a { color: var(--accent); font-weight: 600; }
.account-links { margin: var(--shop-space-2) 0 0; }
.account-fav-link { color: var(--accent); font-weight: 600; }

/* ── Бейджи статусов — тинты, не заливки (модель канона) ────── */
.badge {
  display: inline-flex; align-items: center; gap: 0.375rem;
  padding: 0.125rem 0.625rem; border-radius: var(--radius-pill);
  font-size: var(--text-xs); font-weight: 600;
}
.badge-success { background: var(--ok-tint); color: var(--ok); }
.badge-warning { background: var(--warn-tint); color: var(--warn); }
.badge-error   { background: var(--err-tint); color: var(--err); }

/* ── Страница товара ─────────────────────────────────────────
   База: фото над текстом (одна колонка), CTA «В корзину» — на всю
   ширину строки покупки (канон мобильного e-commerce). 48rem —
   галерея слева, инфо справа (пропорция 2:3 — едет за корнем). */
.product-page-cols { display: grid; gap: calc(var(--section-y) * 0.67); grid-template-columns: minmax(0, 1fr); }
.product-gallery { display: grid; gap: 0.75rem; align-content: start; }
/* ── Галерея v2 (B1-v2): нативная scroll-snap карусель ───────
   Решение по кандидатам (Splide ~30KB / Glide / scroll-snap) — в отчёте
   b1-v2.md: свайп = нативный скролл с инерцией (композитор, ноль JS в
   кадре — «красиво и не тормозно» по замеру CPU×4), переключение
   стрелками/миниатюрами — smooth scrollTo, клавиатура — нативные
   стрелки скроллера + полоса миниатюр. Фиксированный аспект 4/5 у
   слайда + object-fit: cover — пропорции снимков любые, прыжков нет.
   Скрытый скроллбар: позицию показывают миниатюры (is-active). */
.gallery-viewport {
  position: relative; border-radius: var(--radius-lg);
  background: var(--bg-soft); color: var(--muted);
  overflow: hidden;
}
.gallery-track {
  display: flex; overflow-x: auto;
  scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none; /* позицию показывает is-active миниатюры */
}
.gallery-track::-webkit-scrollbar { display: none; }
.gallery-slide {
  flex: 0 0 100%; width: 100%;
  scroll-snap-align: start; scroll-snap-stop: always;
  aspect-ratio: 4 / 5;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--text-sm);
}
.gallery-slide img { width: 100%; height: 100%; object-fit: cover; }
/* ── Вариантные фото (v1.7.2): кросс-фейд подмены слайдов ────
   Выбор варианта → трек гасится (data-swap → opacity 0), контент
   заменяется, трек проявляется обратно (скрипт галереи v3).
   prefers-reduced-motion — подмена мгновенная (перехода нет; общий
   гейт анимаций витрины ниже трек не берёт — свой). Правило [hidden] —
   явкой: класс с display перебил бы UA-стиль скрытия. */
.gallery-track { transition: opacity var(--theme-fade); }
.gallery-track[data-swap="1"] { opacity: 0; }
.gallery-nav[hidden], .gallery-thumbs[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) {
  .gallery-track { transition: none !important; }
  .gallery-track[data-swap="1"] { opacity: 1; }
}
/* стрелки галереи — поверх фото, тап-таргет 2.75rem; подложка карточная */
.gallery-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--shop-touch); height: var(--shop-touch); border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--card) 85%, transparent);
  color: var(--text); font-size: var(--text-lg); line-height: 1;
  cursor: pointer; transition: background-color var(--theme-fade);
}
.gallery-nav:hover { background: var(--card); }
.gallery-prev { left: 0.5rem; }
.gallery-next { right: 0.5rem; }
/* миниатюры — свайп-полоса (scroll-snap), активная в рамке акцента */
.gallery-thumbs {
  display: flex; gap: 0.5rem; overflow-x: auto;
  scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
  padding-bottom: var(--shop-space-1);
}
.gallery-thumb {
  flex: 0 0 auto; width: 4rem; height: 5rem; padding: 0;
  border: 1px solid var(--border); border-radius: var(--radius-btn);
  background: var(--bg-soft); overflow: hidden; cursor: pointer;
  scroll-snap-align: start;
  /* B1-v2: только бордер, 80ms (кольцо is-active появляется мгновенно —
     это клик-состояние, не hover-пульс; box-shadow из transition убран) */
  transition: border-color 80ms linear;
}
.gallery-thumb img { width: 100%; height: 100%; object-fit: cover; }
.gallery-thumb:hover { border-color: var(--accent); }
.gallery-thumb.is-active {
  border-color: var(--accent);
  box-shadow: 0 0 0 0.125rem var(--accent-tint); /* кольцо активной миниатюры — rem, не px */
}
.product-title {
  font-size: clamp(1.5rem, 1.25rem + 1.1vw, 2rem);
  line-height: 1.2; letter-spacing: -0.015em;
}
.product-price { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em; }
.product-price .rub { font-weight: 400; color: var(--muted); margin-left: var(--shop-space-1); }
.product-desc { color: var(--muted); white-space: pre-line; }
.buy-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; margin: var(--shop-space-5) 0; }
.buy-row > .btn { flex: 1 1 100%; }
/* ── Пикер вариантов A «WB-универсал» (v1.7.3, мокапы mock-A-*) ────
   Строка на измерение; значения одного измерения — ОДИН вид: фото-свотчи
   48px (кроп, radius 10, выбран = accent-кольцо 0.125rem — rem-аналог
   кольца активной миниатюры галереи), цветная заливка по карте значения
   (hex живёт в шаблоне — это ДАННЫЕ товара, не тема; shop.css без hex,
   канон W7 №3) или текстовые пилюли (тап ≥ 44px, gap --shop-space-2).
   Недоступная комбинация (сток 0) — приглушена, aria-disabled, клик не
   выбирает (WB-автоперескок — js/picker.js). Токены, без теней; переходы
   гейтятся общим reduce-блоком ниже (пикер добавлен в его список). */
.variant-picker {
  flex: 1 1 100%; display: flex; flex-direction: column;
  gap: var(--shop-space-4); margin: 0; padding: 0; border: 0;
}
.pv-status {
  margin: 0; color: var(--muted);
  font-size: var(--text-sm); font-variant-numeric: tabular-nums;
}
.pv-status b { color: var(--text); font-weight: 600; }
.pv-status-off { color: var(--err); }
.pv-dim { min-width: 0; }
.pv-dim-label {
  display: block; margin-bottom: var(--shop-space-2);
  font-size: var(--text-sm); font-weight: 600; color: var(--text);
}
.pv-dim-val { color: var(--muted); font-weight: 400; }
.pv-values { display: flex; flex-wrap: wrap; gap: var(--shop-space-2); margin: 0; padding: 0; }
.pv-btn {
  min-width: 0; padding: 0; overflow: hidden;
  font-family: inherit; cursor: pointer; background: var(--card); color: var(--text);
}
.pv-values[data-pv-mode="swatch"] .pv-btn,
.pv-values[data-pv-mode="fill"] .pv-btn {
  width: 48px; height: 48px;
  position: relative;
  border-radius: var(--radius-btn); border: 1px solid var(--border);
  transition: border-color var(--theme-fade), box-shadow var(--theme-fade);
}
.pv-values[data-pv-mode="pill"] .pv-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--shop-touch); min-width: var(--shop-touch); padding: 0 var(--shop-space-4);
  border-radius: var(--radius-pill); border: 1px solid var(--border);
  font-size: var(--text-sm); font-weight: 600;
  transition: border-color var(--theme-fade), background-color var(--theme-fade);
}
.pv-values .pv-btn img, .pv-values .pv-fill { width: 100%; height: 100%; object-fit: cover; display: block; }
.pv-values[data-pv-mode="pill"] .pv-btn:hover { border-color: var(--shop-border-hover); }
.pv-values[data-pv-mode="pill"] .pv-btn[aria-checked="true"] {
  border-color: var(--accent); background: var(--accent-tint); color: var(--accent-strong);
}
.pv-values[data-pv-mode="swatch"] .pv-btn:hover,
.pv-values[data-pv-mode="fill"] .pv-btn:hover { border-color: var(--shop-border-hover); }
.pv-values[data-pv-mode="swatch"] .pv-btn[aria-checked="true"],
.pv-values[data-pv-mode="fill"] .pv-btn[aria-checked="true"] {
  border-color: var(--accent); box-shadow: 0 0 0 0.125rem var(--accent);
}
.pv-values[data-pv-mode="swatch"] .pv-btn[aria-checked="true"]:hover,
.pv-values[data-pv-mode="fill"] .pv-btn[aria-checked="true"]:hover { border-color: var(--accent); }
.pv-btn[aria-disabled="true"] {
  opacity: 0.45; cursor: not-allowed; text-decoration: line-through;
}
.pv-values[data-pv-mode="pill"] .pv-btn[aria-disabled="true"]:hover {
  border-color: var(--border); background: var(--card);
}
.pv-values[data-pv-mode="swatch"] .pv-btn[aria-disabled="true"]:hover,
.pv-values[data-pv-mode="fill"] .pv-btn[aria-disabled="true"]:hover {
  border-color: var(--border); box-shadow: none;
}
/* ── Степпер количества (W7, разнос владельца): ОДНА визуальная группа ──
   Нативные спиннеры number-инпута скрыты по всей витрине (дублировали
   кнопки «−/+»); контрол сцеплен: кнопка − | инпут | кнопка + с общими
   границами и радиусами только по краям группы (канон ghost-кнопки:
   border var(--border), radius 10px). Тап-таргеты 2.75rem. */
input[type="number"] { appearance: textfield; -moz-appearance: textfield; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty-stepper { display: inline-flex; align-items: stretch; }
.qty-stepper .qty-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--shop-touch); height: var(--shop-touch); padding: 0;
  border: 1px solid var(--border); background: var(--card); color: var(--muted);
  font-size: var(--text-lg); line-height: 1; cursor: pointer;
  transition: color var(--theme-fade), border-color var(--theme-fade), background-color var(--theme-fade);
}
.qty-stepper .qty-btn:first-child { border-radius: var(--radius-btn) 0 0 var(--radius-btn); }
.qty-stepper .qty-btn:last-child { border-radius: 0 var(--radius-btn) var(--radius-btn) 0; }
.qty-stepper .qty-btn:hover { color: var(--text); border-color: var(--accent); }
.qty-stepper .qty-btn:active { background: var(--bg-soft); }
/* инпут между кнопками: ширина 3ch, центр, высота группы; границы кнопок
   накрывают двойную линию стыка (margin −1px), фокус виден (outline) */
.qty-stepper .qty-input {
  width: 3rem; min-width: 3ch; height: var(--shop-touch); text-align: center;
  border: 1px solid var(--border); border-radius: 0;
  background: var(--card); color: var(--text);
  font-size: var(--text-md); font-family: inherit;
  margin: 0 -1px; /* px-допустимо: шов 1px — кнопки степпера накрывают двойную линию стыка */
}
.qty-stepper .qty-input:focus { outline: 2px solid var(--accent); outline-offset: -2px; border-color: var(--accent); }
/* Характеристики товара (features string[]) — тихий список с тире */
.features-heading { margin: var(--shop-space-5) 0 0.625rem; font-size: var(--text-lg); }
.feature-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 0.375rem; }
.feature-item { position: relative; padding-left: var(--shop-space-5); color: var(--muted); }
.feature-item::before { content: "—"; position: absolute; left: 0; color: var(--muted); opacity: 0.6; }

/* ── Кнопки — канон лендинга ──────────────────────────────────
   radius 10px, weight 600, padding .65rem 1.25rem; primary —
   акцент, secondary — ghost с бордером (hover — акцент). */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  padding: 0.65rem var(--shop-space-5); min-height: var(--shop-touch); border-radius: var(--radius-btn);
  border: 1px solid transparent; cursor: pointer;
  font: inherit; font-size: 0.95rem; font-weight: 600;
  transition: background-color 150ms ease, color 150ms ease, border-color 150ms ease;
  text-align: center;
}
.btn-primary { background: var(--accent); color: var(--on-accent); }
.btn-primary:hover { background: var(--accent-strong); color: var(--on-accent); text-decoration: none; }
.btn-secondary {
  background: transparent; color: var(--text);
  border-color: var(--border);
}
.btn-secondary:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
.btn-lg { padding: 0.875rem var(--shop-space-7); font-size: var(--text-md); }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
/* uxfix D2: неактивная «В корзину» (нулевой сток/все варианты скрыты) —
   muted через opacity канона; hover не подсвечивает disabled-кнопку. */
.btn-primary[disabled]:hover { background: var(--accent); }

/* ── Пагинация — каноническое окно (uxfix2 A2/A3): края «1»/«LAST»
   всегда, разрывы-многоточия по обе стороны, активная в тинте.
   МОБАЙЛ: окно уже (c−1 c c+1 + края — промежуточные .page-x спрятаны,
   разрывы .page-gap-m), одна строка без переноса, влезает в 320px
   (≤9 клеток × 1.75rem; тап-цель 28px — сознательный размен: 44px-пол
   девяти клеток в 280px контента не помещается, основные действия —
   ‹/› и крупные края). ДЕСКТОП (≥48rem): полное окно, клетки 36px. ── */
.pagination {
  display: flex; flex-wrap: nowrap; gap: 0.25rem;
  margin-top: var(--section-y);
  overflow-x: auto; scrollbar-width: none;
}
.pagination::-webkit-scrollbar { display: none; }
.page-link {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
  min-width: 1.75rem; height: 1.75rem; padding: 0 var(--shop-space-1);
  border-radius: var(--radius-btn); font-size: var(--text-sm);
  color: var(--muted);
}
.page-link:hover { background: var(--bg-soft); text-decoration: none; color: var(--text); }
.page-link[aria-current="true"] { background: var(--accent-tint); color: var(--accent); }
.page-link[aria-disabled="true"] { opacity: 0.45; cursor: default; }
.page-link[aria-disabled="true"]:hover { background: transparent; color: var(--muted); }
/* ПОРЯДОК ВАЖЕН (та же каскадная ловушка, что .chip-extra-m в блоке
   ≥48rem): селектор .page-gap матчает и элемент с двумя классами —
   мобильное многоточие «возвращается» правилом НИЖЕ. */
.page-gap { display: none; }
.page-gap-m {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto; min-width: 1.25rem; height: 1.75rem;
  color: var(--muted); user-select: none;
}
.page-x { display: none; }

/* ── Checkout: двухколоночная типографика, ноль карточек ─────
   База: одна колонка (заказ → форма → итог); 48rem — заказ+форма
   слева, «Итого» справа. Строки корзины — воздух вместо hairline
   (политика W7); итог — --bg-soft-подложка.
   W9 (F3): строка заказа — полноценная: миниатюра 3.5rem + название-
   ссылка + разбивка «цена × кол-во», степпер и сумма во втором ряду,
   «×» прижат к строке справа (тап-таргет 2.75rem). W9 (F6б): строка с
   перебором остатка — warning-тинт (.cart-line-over). W9 (F3): ритм
   секций чекаута ужат (rel-heading канона давал гигантские пустоты). */
.checkout-grid { display: grid; gap: calc(var(--section-y) * 0.67); grid-template-columns: minmax(0, 1fr); }
.checkout-main { max-width: none; }
.checkout-heading { margin-top: 0; }
.checkout-grid .rel-heading { margin: var(--shop-space-6) 0 var(--shop-space-4); }
.cart-lines { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.25rem; }
.cart-line {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "thumb info  remove"
    "thumb ctrl  ctrl";
  gap: 0.4rem 0.75rem;
  align-items: start;
  padding: var(--shop-space-3) 0;
  border-radius: var(--radius-card);
}
/* перебор остатка: warning-тинт вместо заливки (модель канона) */
.cart-line-over { background: var(--warn-tint); padding-left: 0.6rem; padding-right: 0.6rem; }
/* миниатюра: квадрат 3.5rem, радиус карточки; пустая photos → плейсхолдер */
.cart-line-thumb {
  grid-area: thumb; display: block; align-self: start;
  width: 3.5rem; height: 3.5rem; border-radius: var(--radius-card);
  overflow: hidden; background: var(--bg-soft);
}
.cart-line-thumb img { width: 100%; height: 100%; object-fit: cover; }
.cart-line-thumb-empty { display: block; }
.cart-line-info { grid-area: info; display: grid; gap: 0.2rem; justify-items: start; min-width: 0; }
.cart-line-name {
  color: var(--text); font-weight: 600; line-height: 1.35;
  overflow-wrap: break-word;
}
.cart-line-name:hover { color: var(--accent); text-decoration: none; }
.cart-line-price { color: var(--muted); font-size: var(--text-sm); }
/* B2a: label варианта в строке чекаута (под названием товара) */
.cart-line-variant { color: var(--muted); font-size: var(--text-xs); }
.cart-line-controls { grid-area: ctrl; display: flex; align-items: center; gap: 0.75rem; width: 100%; }
/* степпер строки чекаута (D23): − qty + одной рамкой; тап-таргеты 2.75rem */
.cart-line-stepper {
  display: inline-flex; align-items: center; align-self: center;
  border: 1px solid var(--border); border-radius: var(--radius-btn);
  background: var(--card); overflow: hidden;
}
.cart-line-stepper .qty-btn {
  width: var(--shop-touch); height: var(--shop-touch);
  border: 0; border-radius: 0; background: transparent;
}
.cart-line-stepper .qty-btn:active { background: var(--bg-soft); }
.cart-line-qty { min-width: 2rem; text-align: center; color: var(--text); font-weight: 600; }
.cart-line-sum { margin-left: auto; font-weight: 600; white-space: nowrap; }
/* «×» у позиции и «Очистить корзину»: тихие действия, не конкурирующие с CTA */
.cart-line-remove {
  grid-area: remove; justify-self: end;
  width: var(--shop-touch); height: var(--shop-touch); line-height: 1;
  border: 1px solid var(--border); border-radius: var(--radius-btn);
  background: var(--card); color: var(--muted);
  font-size: var(--text-md); cursor: pointer;
  transition: color var(--theme-fade), border-color var(--theme-fade);
}
.cart-line-remove:hover { color: var(--err); border-color: color-mix(in srgb, var(--err) 50%, transparent); }
/* W9 (F6a): живой регион предупреждений корзины (clamp остатка, неудача записи) */
.cart-note { display: none; margin: var(--shop-space-2) 0 0; color: var(--warn); font-size: var(--text-sm); }
.cart-note[data-visible="1"] { display: block; }
.cart-clear {
  margin-top: var(--shop-space-3); padding: 0; border: 0; background: none;
  color: var(--muted); font-size: var(--text-xs); font-family: inherit;
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
  transition: color var(--theme-fade);
}
.cart-clear:hover { color: var(--err); }
.cart-total-row {
  display: flex; justify-content: space-between; padding: var(--shop-space-4) 0 0;
  font-size: var(--text-lg); font-weight: 600;
}
.field { margin-bottom: var(--shop-space-4); }
.field-label { display: block; margin-bottom: 0.35rem; font-size: 0.92rem; font-weight: 600; }
/* Инпуты — канон: radius 10px, focus = outline 2px accent.
   На телефоне 1rem (16px): Safari iOS с фокусом на поле мельче
   16px зумит страницу. */
.field-input, .field-textarea {
  width: 100%; padding: 0.65rem 0.85rem;
  border: 1px solid var(--border); border-radius: var(--radius-input);
  background: var(--card); color: var(--text);
  font-size: var(--text-md); font-family: inherit;
}
.field-input::placeholder, .field-textarea::placeholder { color: var(--muted); /* B1 (D5): без opacity — muted и так AA (5.7:1), .7 ронял до ~3.4:1 */ }
.field-input:focus, .field-textarea:focus {
  outline: 2px solid var(--accent); outline-offset: 0; border-color: var(--accent);
}
.field-hint { margin-top: var(--shop-space-1); font-size: var(--text-xs); color: var(--muted); }
.hp-field { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; } /* honeypot */
.form-error {
  display: none; margin: 0 0 var(--shop-space-4); padding: 0.625rem 0.875rem;
  border-radius: var(--radius-input);
  background: var(--err-tint); color: var(--err);
  font-size: var(--text-sm);
}
.form-error[data-visible="1"] { display: block; }
.summary-row { display: flex; justify-content: space-between; gap: 0.75rem; padding: 0.375rem 0; font-size: var(--text-sm); color: var(--muted); }
/* итог — мягкая подложка вместо border-top (политика W7) */
.summary-total {
  display: flex; justify-content: space-between; gap: 0.75rem;
  margin-top: var(--shop-space-3); padding: var(--shop-space-4) var(--shop-space-5);
  background: var(--bg-soft); border-radius: var(--radius-card);
  font-weight: 600; color: var(--text);
}
.summary-note { margin-top: var(--shop-space-4); }
/* строка скидки (B2b): placeholder «применится при оформлении» — без цифры,
   финальную сумму со скидкой даёт только сервер (k_calc) */
.summary-discount span:last-child { color: var(--muted); font-size: var(--text-xs); }

/* ── Доставка на чекауте (B2b): radio-строки способов ──────────────
   Тот же паттерн, что пикер вариантов B2a: строка = тап ≥ 44px
   (--shop-touch), выбранное состояние — акцент-бордер + подложка
   (токены, без теней); описание способа — вторая строка muted. */
.delivery-list {
  display: flex; flex-direction: column;
  gap: var(--shop-space-2); margin: 0 0 var(--shop-space-4);
  padding: 0; border: 0;
}
.delivery-option {
  display: flex; align-items: center; gap: var(--shop-space-3);
  min-height: var(--shop-touch);
  padding: var(--shop-space-2) var(--shop-space-3);
  border: 1px solid var(--border); border-radius: var(--radius-btn);
  background: var(--card); cursor: pointer;
  transition: border-color var(--theme-fade), background-color var(--theme-fade);
}
.delivery-option:hover { border-color: var(--accent); }
.delivery-option:has(input:checked) { border-color: var(--accent); background: var(--bg-soft); }
.delivery-option:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.delivery-option input { accent-color: var(--accent); width: var(--shop-touch); height: var(--shop-touch); margin: 0; flex: 0 0 auto; }
.delivery-option-main { display: flex; flex-direction: column; gap: var(--shop-space-1); min-width: 0; }
.delivery-option-title { font-weight: 600; font-size: var(--text-md); overflow-wrap: break-word; }
.delivery-option-desc { color: var(--muted); font-size: var(--text-xs); overflow-wrap: break-word; }
.delivery-option-price { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ── Status-screen (заказ, 404) — чистая типографика, 36rem ── */
.status-screen {
  max-width: var(--container-narrow); margin: 0 auto;
  padding: calc(var(--section-y) * 0.75) var(--gutter);
  text-align: center;
}
.status-badge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 3.5rem; height: 3.5rem; border-radius: var(--radius-pill);
  font-size: var(--text-lg); margin-bottom: var(--shop-space-5);
}
.status-badge.success { background: var(--ok-tint); color: var(--ok); }
.status-badge.brand { background: var(--accent-tint); color: var(--accent); }
.status-badge.error { background: var(--err-tint); color: var(--err); }
.status-title {
  font-size: clamp(1.5rem, 1.25rem + 1.1vw, 2rem);
  font-weight: 700; letter-spacing: -0.015em; text-wrap: balance;
}
.status-text { margin-top: var(--shop-space-3); color: var(--muted); }
.status-order-no { margin-top: var(--shop-space-2); font-family: var(--font-mono); font-size: var(--text-sm); color: var(--muted); }
.status-actions { margin-top: 1.75rem; }
.status-help { margin-top: var(--shop-space-4); font-size: var(--text-xs); color: var(--muted); }

/* ── «Похожие» — грид ≤4 ────────────────────────────────────── */
.rel-heading { margin: calc(var(--section-y) * 1.25) 0 var(--shop-space-5); font-size: clamp(1.5rem, 1.25rem + 1.1vw, 2rem); }

/* ── Документные страницы (legal-md): оферта/политика из legal-doc ──
   Узкая проза-колонка канона (--container-prose); тело — результат
   платформенного фильтра markdown (goldmark): заголовки/списки/таблицы
   в rem-шкале, цвета — токены тем (тёмная тема подхватывается сама). */
.doc-page { max-width: var(--container-prose); }
.doc-updated { margin: 0 0 var(--shop-space-5); color: var(--muted); font-size: var(--text-sm); }
.doc-note { color: var(--muted); }
.md-body { font-size: var(--text-md); line-height: 1.65; overflow-wrap: break-word; }
.md-body h1, .md-body h2, .md-body h3, .md-body h4 { line-height: 1.3; margin: var(--shop-space-7) 0 var(--shop-space-4); }
.md-body > :first-child { margin-top: 0; }
.md-body h2 { font-size: 1.25rem; }
.md-body h3 { font-size: 1.0625rem; }
.md-body h4 { font-size: var(--text-md); }
.md-body p { margin: 0 0 var(--shop-space-4); }
.md-body ul, .md-body ol { margin: 0 0 var(--shop-space-4); padding-left: 1.375rem; }
.md-body li + li { margin-top: var(--shop-space-2); }
.md-body a { color: var(--accent); text-decoration: underline; text-underline-offset: 0.125rem; }
.md-body strong { font-weight: 600; }
.md-body blockquote { margin: 0 0 var(--shop-space-4); padding-left: var(--shop-space-4); border-left: 2px solid var(--border); color: var(--muted); }
.md-body code { font-family: var(--font-mono, monospace); font-size: 0.9375em; background: var(--bg-soft); border-radius: 0.25rem; padding: 0.0625rem 0.25rem; }
/* hr — подложка, не hairline: политика линий B1 держит border-top/bottom
   только для шапки/футера/тулбара каталога (w7-canon) */
.md-body hr { border: 0; height: 0.125rem; background: var(--bg-soft); margin: var(--shop-space-6) 0; }
/* Таблица шире колонки на 320px не рвёт страницу: скролл внутри таблицы */
.md-body table { display: block; width: max-content; max-width: 100%; overflow-x: auto; border-collapse: collapse; margin: 0 0 var(--shop-space-5); }
.md-body th, .md-body td { border: 1px solid var(--border); padding: var(--shop-space-2) var(--shop-space-3); text-align: left; vertical-align: top; }
.md-body th { background: var(--bg-soft); font-weight: 600; }
@media print {
  .shop-header, .shop-footer, .cart-note { display: none !important; }
  body { min-height: 0; }
}

/* Пустые состояния — строка текста, не карточка */
.empty-note { padding: calc(var(--section-y) * 0.75) 0; color: var(--muted); text-align: center; }

/* ── ЛК: узкая колонка форм входа/регистрации, заказы — карточки канона ── */
.auth-narrow { max-width: 26rem; margin-inline: auto; }
.auth-form { display: grid; gap: 0.875rem; margin-top: var(--shop-space-5); text-align: left; }
.auth-form .btn { justify-self: stretch; }
.account-orders { list-style: none; margin: var(--shop-space-6) 0 0; padding: 0; display: grid; gap: 1.1rem; }
.account-order {
  padding: var(--shop-space-5) var(--shop-space-6);
  border: 1px solid var(--border); border-radius: var(--radius-card);
  background: var(--card); box-shadow: var(--shop-shadow-card);
}
.account-order-main { display: flex; align-items: center; gap: 0.625rem; flex-wrap: wrap; }
.account-order-link { font-weight: 600; color: var(--text); }
.account-order-link:hover { color: var(--accent); }
.account-order-date { color: var(--muted); font-size: var(--text-sm); }
.account-order-summary { margin: 0.375rem 0 0; color: var(--muted); font-size: var(--text-sm); }
.account-order-amount { margin: 0.375rem 0 0; font-weight: 600; }

/* ── B1 (D5): prefers-reduced-motion — единый гейт анимаций витрины ──
   Фейд фото и кросс-фейды гейтятся у себя (F10); здесь — драверы,
   дропдаун, hover-подъём карточки, чипы-раскрытие: reduce = смена
   состояния мгновенная. */
@media (prefers-reduced-motion: reduce) {
  .sheet, .sheet-overlay, .product-card, .product-card-photo img,
  .dd-list, .dd-chevron, .chip, .gallery-nav, .qty-btn,
  .pv-values .pv-btn { transition: none !important; animation: none !important; }
}

/* ============================================================
   УЛУЧШЕНИЯ — только min-width (мобильный-фёрст).
   30rem — грид 1→2; 48rem (=768px, ЕДИНСТВЕННЫЙ ГЛАВНЫЙ брейкпоинт
   канона) — десктопная шапка/тулбар/сплиты; 62rem — грид 2→4.
   Дальше раскладку пропорционально масштабирует корень.
   ============================================================ */

/* ≥ 30rem (480): две колонки каталога/«Похожих». Тулбар с W6 живёт
   кнопками-листами до 48rem (дравер), десктопная форма — с 48rem. */
@media (min-width: 30rem) {
  .product-grid, .rel-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.1rem; }
}

/* ≥ 48rem (=768px — канон лендинга): десктоп одной строкой.
   Body фикс вместо clamp: плавность несёт корень (канон). */
@media (min-width: 48rem) {
  body { font-size: 1.0625rem; }
  .section-y { padding-top: var(--section-y); padding-bottom: var(--section-y); }
  /* канон hero лендинга; нижний отступ 2rem — воздух над тулбаром ≈ воздуху
     под ним (ритм «hero — тулбар — грид» ровный, находка владельца B1) */
  .cat-hero { padding: var(--shop-space-9) 0 var(--shop-space-7); }
  /* шапка (headerfix): auth-кластер выходит в строку справа (до корзины/темы),
     burger прячется; слева остаётся только логотип */
  .header-auth { display: flex; gap: 0.25rem; align-items: center; }
  .nav-burger { display: none; }
  .shop-header-inner { flex-wrap: nowrap; }
  /* тулбар: десктопная форма, мобильные кнопки скрыты */
  .toolbar-mobile { display: none; }
  .search-box { display: block; flex: 1 1 13rem; min-width: 9rem; max-width: 15rem; }
  .applied-row-desktop { display: flex; }
  .applied-row-mobile { display: none; }
  .tools-right { display: flex; flex: 0 0 auto; margin-left: auto; gap: 0.5rem; }
  .sort-box { flex: 0 1 11.5rem; min-width: 9rem; max-width: 11.5rem; width: auto; }
  /* В3: вертикальный hairline-разделитель «Найти | чипы»; когда ряд чипов
     не влез и ушёл блоком под контролы (data-chips-wrapped вешает скрипт)
     — разделитель прячется, «Найти |» без чипов не висит */
  .tools-sep {
    display: block; flex: 0 0 auto; align-self: stretch;
    width: 1px; background: var(--border); margin: 0.125rem var(--shop-space-1);
  }
  .cat-tools[data-chips-wrapped="1"] .tools-sep { display: none; }
  /* счётчик справа (мокап В3); строка над гридом на десктопе скрыта */
  .tools-count { display: inline-block; flex: 0 0 auto; margin-left: auto; color: var(--muted); font-size: var(--text-sm); white-space: nowrap; }
  .cat-count { display: none; }
  /* чипы в строке тулбара: свёрнуто — первые N; лишние прячет .chip-extra.
     min-width: min-content — когда строка тесна, ряд чипов целиком
     переносится на свою строку (не сжимается и не режется) */
  .chip-row {
    flex: 1 1 auto; min-width: min-content;
    flex-wrap: nowrap; margin: 0 0 0 var(--shop-space-1);
    gap: 0.375rem;
  }
  .chip { min-height: max(1.5rem, 24px); padding: var(--shop-space-1) var(--shop-space-3); } /* P2: пол 24px */
  .chip-extra { display: none; }
  /* активная категория ВСЕГДА видна, даже за пределами первых N (D2) */
  .chip-extra[data-pinned="1"] { display: inline-flex; }
  /* «Ещё N»: раскрытие → чипы переносятся строками ПОД кластером (D2);
     count-пилюля на кнопке в раскрытом состоянии не нужна («Свернуть») */
  .chip-more { display: inline-flex; }
  .chip-more-m { display: none; }
  /* uxfix2 B: мобильный лимит снимается ТОЛЬКО у чипов вне десктопного —
     прежде .chip-extra-m { inline-flex } каскадно «воскрешал» чипы с
     ОБОИМИ классами (`.chip-extra` спрятан строкой выше, эта — ниже и
     побеждала): ряд игнорировал filters_visible, «Ещё N» раскрывало
     пустоту. :not(.chip-extra) возвращает независимость классов. */
  .chip-extra-m:not(.chip-extra) { display: inline-flex; }
  .cat-tools[data-chips-open="1"] .chip-row { flex: 1 1 100%; order: 20; flex-wrap: wrap; margin-top: 0.375rem; }
  .cat-tools[data-chips-open="1"] .chip-extra { display: inline-flex; }
  .chip-more[data-open="1"] .chip-count { display: none; }
  /* компактные контролы десктопа (крупность несёт корень).
     В3 (P3 прошлого критика): поиск, дропдаун и «Найти» — ОДНА высота
     пиксель-в-пиксель: жёсткая height 2.5rem на всех трёх */
  .icon-btn { width: max(2.25rem, 24px); height: max(2.25rem, 24px); } /* канон .theme-toggle + P2 пол */
  .toolbar-btn, .applied-chip, .applied-reset { min-height: max(2.25rem, 24px); } /* P2: пол 24px на бэнде 768–863 */
  .page-link { min-width: max(2.25rem, 24px); height: max(2.25rem, 24px); } /* P2 */
  /* uxfix2 A3: десктопу — полное окно (промежуточные номера и десктопные
     многоточия возвращаются; мобильные .page-gap-m уходят) */
  .pagination { flex-wrap: wrap; gap: 0.375rem; overflow-x: visible; scrollbar-width: auto; }
  .pagination::-webkit-scrollbar { display: block; }
  .page-gap { display: inline-flex; min-width: max(2.25rem, 24px); height: max(2.25rem, 24px); }
  .page-gap-m { display: none; }
  .page-x { display: inline-flex; }
  .field-input.search-input, .dd-btn.field-input { height: var(--shop-control-h); min-height: 0; padding-top: 0; padding-bottom: 0; }
  .dd-opt { min-height: max(2.25rem, 24px); } /* P2 */
  .btn { min-height: 0; }
  .btn.search-submit { height: var(--shop-control-h); min-height: 0; padding-top: 0; padding-bottom: 0; }
  .field-input, .field-textarea, .qty-input { font-size: var(--text-sm); }
  .crumb-list {
    -webkit-mask-image: none; mask-image: none;
    flex-wrap: wrap; white-space: normal; overflow: visible;
  }
  /* сплиты: пропорции едут за корнем */
  .product-page-cols { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: var(--section-y); align-items: start; }
  .checkout-grid { grid-template-columns: minmax(0, 1.8fr) minmax(0, 1fr); gap: var(--section-y); }
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* строки корзины — обратно в ОДНУ строку (W9 F3): миниатюра | название +
     разбивка | степпер | сумма | «×»; controls распаковывается display:
     contents, дети становятся элементами грида строки. Степпер строки НЕ
     компактнеет: одна высота контрола везде (W8 — 2.75rem/44px) */
  .cart-line {
    grid-template-columns: auto minmax(0, 1fr) auto auto auto;
    grid-template-areas: "thumb info stepper sum remove";
    gap: 0.75rem;
    align-items: center;
  }
  .cart-line-controls { display: contents; }
  .cart-line-stepper { grid-area: stepper; }
  .cart-line-sum { grid-area: sum; margin-left: 0; }
  .cart-line-remove { width: 1.75rem; height: 1.75rem; }
  .buy-row > .btn { flex: 0 0 auto; }
  .status-screen { padding: calc(var(--section-y) * 1.5) var(--gutter); }
}

/* ≥ 62rem (992): каталог/«Похожие» — 4 колонки (W6 №19), воздух 1.25rem */
@media (min-width: 62rem) {
  .product-grid, .rel-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.25rem; }
}
