/* ══════════════════════════════════════════════════════════════════════════
   catalog.css — только то, чего нет в общем словаре: крошки, шапка раздела,
   боковое дерево категорий, панель поиска и сортировки, карточка товара,
   пагинация и пустое состояние категории.

   Всё, что уже объявлено в base / layout / components, переиспользуется как
   есть: сетка карточек — .grid-products из layout.css (числа колонок 4/3/2/1
   заданы там явными медиазапросами), кнопки — .btn, фото-слот — .photo-slot,
   контейнер и ритм — .container.

   Ни одного литерала цвета, размера шрифта, отступа и радиуса: всё приходит
   из tokens.css. Это исполняется механически — tools/audit-tokens.py.

   Про цвет отдельно: страница НЕ вводит ни одной новой пары «текст на фоне».
   Каждое сочетание ниже уже объявлено в блоке @contrast-pairs файла
   tokens.css и посчитано планом 01-02. Разделы каталога при этом не
   различаются цветом вовсе (D-05) — различают их иконка и фотография.
   ══════════════════════════════════════════════════════════════════════════ */

/* ══ ХЛЕБНЫЕ КРОШКИ ═══════════════════════════════════════════════════════
   Имя класса — .breadcrumbs, одно на весь проект. До Фазы 3 этот файл звал
   блок .crumbs, а forms.css и content.css — .breadcrumbs; расхождение
   безвредно в статичных макетах и стало бы дефектом в Twig, где частичный
   шаблон partials/breadcrumbs.html.twig один на все страницы и печатает ОДНО
   имя класса. Переименован селектор, а не оформление: собственные значения
   блока (верхний отступ, приглушённый цвет текущего пункта) сохранены —
   catalog.css и forms.css никогда не подключаются к одной странице. */

.breadcrumbs{ padding-top:var(--space-5); }

/* Крошки переносятся на несколько строк: на узком экране «Главная → Каталог →
   Мототехника» в одну строку не помещается, и обрезать её нельзя — это
   единственный путь наверх. */
.breadcrumbs ol{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:var(--space-2);
  font-size:var(--text-label);
}
.breadcrumbs li{ display:flex; align-items:center; gap:var(--space-2); }

/* Разделитель — генерируемое содержимое, а не элемент разметки: он
   декоративен и не должен читаться вспомогательными технологиями как
   отдельный пункт списка. */
.breadcrumbs li + li::before{ content:"/"; color:var(--color-text-muted); }

.breadcrumbs a{ text-decoration:none; }
.breadcrumbs a:hover{ text-decoration:underline; }
.breadcrumbs [aria-current]{ color:var(--color-text-muted); }


/* ══ ШАПКА РАЗДЕЛА ════════════════════════════════════════════════════════
   Слот логотипа суббренда живёт ровно здесь и только на разделе
   мототехники (D-06). На обычной категории элемента нет вовсе — сравните
   с catalog-empty.html. */

.cat-head{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:var(--space-5);
  padding:var(--space-5) 0 var(--space-6);
}
.cat-head__logo{ width:180px; height:auto; flex:none; }
.cat-head__text{ flex:1 1 320px; min-width:0; }
.cat-head__lead{
  margin-top:var(--space-2);
  max-width:70ch;
  color:var(--color-text-muted);
}


/* ══ РАСКЛАДКА СТРАНИЦЫ ═══════════════════════════════════════════════════
   Ниже 992px — одна колонка: дерево категорий сверху свёрнутым аккордеоном,
   под ним панель и сетка. От 992px — боковая колонка фиксированной ширины
   плюс резиновая область списка. */

.catalog-layout{
  display:grid;
  grid-template-columns:1fr;
  gap:var(--space-6);
  align-items:start;
  padding-bottom:var(--space-7);
}
@media (min-width:992px){
  .catalog-layout{ grid-template-columns:280px 1fr; gap:var(--space-7); }
}

/* Область списка — минимальная ширина ноль, иначе длинное название товара
   растянет колонку сетки и сломает раскладку. */
.catalog-main{ min-width:0; }


/* ══ ДЕРЕВО КАТЕГОРИЙ ═════════════════════════════════════════════════════
   Аккордеон построен на нативном <details> и не требует ни строчки скрипта:
   раскрытие работает даже если main.js не выполнился.

   Разделы НЕ кодируются цветом (D-05): единый фирменный тёмно-синий на всех,
   различают их иконка и фотография товара. Активный раздел обозначен
   подложкой и начертанием 700, а не акцентным синим — акцент зарезервирован
   под CTA, ссылки, активный пункт навигации, счётчик и кольцо фокуса. */

.cat-tree{
  border:1px solid var(--color-hairline);
  border-radius:var(--radius-card);
  background:var(--color-surface);
}

.cat-tree__toggle{
  display:flex;
  align-items:center;
  gap:var(--space-3);
  min-height:var(--tap-min);
  padding:var(--space-3) var(--space-4);
  font-weight:var(--weight-bold);
  cursor:pointer;
  list-style:none;
}
.cat-tree__toggle::-webkit-details-marker{ display:none; }
.cat-tree__chev{ margin-left:auto; transition:transform .18s; }
.cat-tree[open] .cat-tree__chev{ transform:rotate(180deg); }

.cat-tree__list{ padding:0 var(--space-2) var(--space-2); }
.cat-tree__list a{
  display:flex;
  align-items:center;
  gap:var(--space-3);
  min-height:var(--tap-min);
  padding:var(--space-2) var(--space-3);
  border-radius:var(--radius-sm);
  color:var(--color-text);
  text-decoration:none;
}
.cat-tree__list a:hover{ background:var(--color-surface-alt); }
.cat-tree__list a[aria-current]{
  background:var(--color-surface-alt);
  font-weight:var(--weight-bold);
}
.cat-tree__ic{ display:flex; flex:none; color:var(--color-text-muted); }

/* Название переносится внутри своей колонки: «Молочное оборудование» в одну
   строку боковой колонки не влезает, и обрезать его нечем. */
.cat-tree__name{ flex:1 1 auto; min-width:0; }
.cat-tree__count{
  flex:none;
  margin-left:auto;
  padding-left:var(--space-2);
  font-size:var(--text-label);
  color:var(--color-text-muted);
}

/* От 992px дерево перестаёт быть аккордеоном и становится обычной боковой
   колонкой. Раскрытие выполняется таблицей стилей, без скрипта и без
   атрибута open в разметке — поэтому на mobile аккордеон остаётся СВЁРНУТЫМ
   по умолчанию, ради чего он и заведён.

   Записей две, и это не дублирование: браузеры прячут содержимое <details>
   двумя разными способами, и покрыть нужно оба.
     • ::details-content — механизм действующей спецификации;
     • прямой потомок    — то, как это исторически сделано в UA-таблицах.
   Неизвестный селектор гасит только своё правило, поэтому обе записи
   безопасны в любом браузере. */
@media (min-width:992px){
  .cat-tree__toggle{ display:none; }
  .cat-tree::details-content{ display:block; content-visibility:visible; }
  .cat-tree > *:not(summary){ display:block; }
}


/* ══ ПАНЕЛЬ УПРАВЛЕНИЯ СПИСКОМ ════════════════════════════════════════════
   Поиск и сортировка — обычная GET-форма. Клиентского состояния у неё нет:
   страница рендерится сервером целиком, поэтому ни индикатора загрузки, ни
   клиентской ошибки здесь не проектируется. Безрезультатный поиск приводит
   к тому же пустому состоянию, что и пустая категория. */

.list-bar{
  display:grid;
  grid-template-columns:1fr;
  gap:var(--space-4);
  margin-bottom:var(--space-5);
}
@media (min-width:768px){
  .list-bar{ grid-template-columns:1fr auto auto; align-items:end; }
}

.list-bar__field{
  display:flex;
  flex-direction:column;
  gap:var(--space-1);
  min-width:0;
}
.list-bar__field label{
  font-size:var(--text-label);
  color:var(--color-text-muted);
}

/* Ширину поля задаёт колонка сетки, а не его содержимое: min-width:0 снимает
   автоматический минимум grid-элемента, и длинный запрос прокручивается
   ВНУТРИ поля вместо того, чтобы растягивать панель. */
.list-bar input,
.list-bar select{
  width:100%;
  min-width:0;
  min-height:var(--tap-min);
  padding:var(--space-2) var(--space-3);
  border:1px solid var(--color-hairline);
  border-radius:var(--radius-sm);
  background:var(--color-surface);
  color:var(--color-text);
}

.list-meta{
  margin-bottom:var(--space-4);
  font-size:var(--text-label);
  color:var(--color-text-muted);
}


/* ══ КАРТОЧКА ТОВАРА ══════════════════════════════════════════════════════
   Высоты карточек в строке выравнивает сетка: карточка — flex-колонка, а
   цена прижата margin-top:auto, поэтому кнопки стоят на одной линии
   независимо от длины названия.

   ВСЯ КАРТОЧКА — ОДНА ССЫЛКА. Нажатие на фотографию, на пустую площадь и на
   название открывает страницу товара, а ссылка в разметке остаётся РОВНО
   ОДНА: растянут её псевдоэлемент (правило .card-product__title a::after
   ниже, там же и причина выбора приёма).

   position:relative здесь НЕ УКРАШЕНИЕ И НЕ НАСЛЕДСТВО: карточка служит
   содержащим блоком этого накрытия. Снять объявление — значит отсчитать
   inset:0 от предка выше по дереву и увести накрытие с карточки. */

.card-product{
  position:relative;
  display:flex;
  flex-direction:column;
  overflow:hidden;
  border:1px solid var(--color-hairline);
  border-radius:var(--radius-card);
  background:var(--color-surface);
  transition:transform .18s, box-shadow .18s;
}
.card-product:hover{ transform:translateY(-4px); box-shadow:var(--shadow-lg); }

/* Пропорция фиксирована, кадрирование заполняющее — карточки в ряду не
   разъезжаются по высоте из-за разных исходных снимков. */
.card-product__media{
  position:relative;
  aspect-ratio:16/10;
  overflow:hidden;
  background:var(--color-surface-alt);
}
.card-product__media img{ width:100%; height:100%; object-fit:cover; }
.card-product__media .photo-slot{ height:100%; }

.card-product__body{
  display:flex;
  flex:1;
  flex-direction:column;
  gap:var(--space-2);
  padding:var(--space-4);
}
/* Подъём над накрытием карточки: под ним артикул не выделить мышью, а его
   как раз и переписывают в заявку. width:fit-content обязателен ВМЕСТЕ с
   подъёмом: поднятая коробка во всю ширину карточки стала бы полосой,
   которая никуда не ведёт, — то есть тем самым дефектом, ради которого
   накрытие и появилось. Сужённая отдаёт под выделение ровно буквы. */
.card-product__sku{
  position:relative;
  z-index:1;
  width:fit-content;
  font-size:var(--text-caption);
  letter-spacing:.08em;
  text-transform:uppercase;
  color:var(--color-text-muted);
}

/* Кламп в две строки. Стандартное свойство написано рядом с префиксным:
   -webkit-line-clamp не Baseline, а line-clamp из CSS Overflow 4 новее его.
   Контейнер терпит третью строку — браузер без поддержки даёт некрасиво,
   но не сломано. */
.card-product__title{
  display:-webkit-box;
  -webkit-box-orient:vertical;
  -webkit-line-clamp:2;
  line-clamp:2;
  overflow:hidden;
  font-size:var(--text-body);
  font-weight:var(--weight-semibold);
  line-height:1.4;
}
.card-product__title a{ color:inherit; text-decoration:none; }
.card-product__title a:hover{ color:var(--color-accent); }

/* НАКРЫТИЕ — им и кликается вся карточка.

   Псевдоэлемент ЕДИНСТВЕННОЙ ссылки карточки растянут на всю её площадь.
   Приём известный (Bootstrap зовёт его .stretched-link) и в проекте уже
   применяется: .hero::after в components.css собран тем же рисунком слоёв.
   Выбран он ради одного свойства — кликается всё, а ссылка в разметке
   остаётся одна, и экранный диктор не читает один товар дважды. Обёртка
   <a> вокруг карточки дала бы вторую ссылку, да ещё и с недопустимой
   вложенностью формы «В корзину» внутрь ссылки.

   У приёма две платы, и обе оплачены рядом, а не забыты:

   1. КНОПКА. Накрытие легло бы поверх кнопки «В корзину», и заявку не
      оформил бы никто — при совершенно исправном виде. Кнопка поднята,
      см. .card-product .btn ниже.
   2. ТЕКСТ. Текст под накрытием не выделяется мышью. Артикул и цена
      подняты и сужены по содержимому, см. их правила. Название поднимать
      не надо и нельзя: оно и есть ссылка, а текст ссылки мышью не
      выделялся никогда — перетаскивание по нему начинает перенос ссылки.

   Заголовок карточки клампится (-webkit-box + overflow:hidden), и накрытие
   он не обрезает: абсолютно позиционированный потомок обрезается только
   предком из своей цепочки содержащих блоков, а заголовок не позиционирован.
   Поставь кто-нибудь position на .card-product__title или на
   .card-product__body — накрытие съёжится до него, фотография перестанет
   кликаться, и НИЧТО об этом не сообщит. Это стережёт проверка
   tests/Integration/ProductCardClickTest.php. */
.card-product__title a::after{
  content:"";
  position:absolute;
  inset:0;
}

/* Цена есть в КАЖДОЙ карточке без исключения (CAT-02). Размер — Body,
   начертание 700: так задано контрактом типографики для сетки каталога,
   крупный размер зарезервирован за карточкой товара.
   Неразрывность добавлена вместе со знаком рубля: перенос строки между
   суммой и знаком оставил бы «Б» одиноко висеть на следующей строке —
   в сетке карточек это читается как обрыв, а не как цена.
   Подъём над накрытием и сужение по содержимому — по той же причине, что у
   артикула: цену переписывают в заявку, и выделяться она обязана. */
.card-product__price{
  position:relative;
  z-index:1;
  width:fit-content;
  margin-top:auto;
  padding-top:var(--space-2);
  font-size:var(--text-body);
  font-weight:var(--weight-bold);
  white-space:nowrap;
}
/* Тот же вариант «по запросу» в сетке списка (D-07). Правило повторено, а
   не вынесено в общий слой: catalog.css и product.css к одной странице не
   подключаются, а общего файла у них нет. Значения обязаны совпадать —
   расхождение будет означать, что цена в списке и в карточке выглядит
   по-разному у одного и того же товара. */
.card-product__price--on-request{
  font-weight:var(--weight-regular);
  white-space:normal;
  color:var(--color-text);
}

/* Кнопка «В корзину» ПОВЕРХ накрытия карточки — это единственный путь к
   заявке из списка, и под накрытием он был бы закрыт наглухо при исправном
   виде кнопки. Поднимается КНОПКА, а не форма: форма — блок с инлайн-блочной
   кнопкой внутри, её коробка выше кнопки на строчный бокс, и подъём формы
   отдал бы под мёртвую полоску несколько пикселей над кнопкой. Этот же
   селектор поднимает <a class="btn"> в макете design/catalog.html, где
   кнопка ссылкой, а не формой. */
.card-product .btn{
  position:relative;
  z-index:1;
  width:100%;
}


/* ══ ПАГИНАЦИЯ ════════════════════════════════════════════════════════════
   Текущая страница помечена атрибутом состояния aria-current, а не одним
   лишь цветом: подложка и начертание 700 идут вместе с ним, а не вместо. */

.pager{ margin-top:var(--space-6); }
.pager ul{
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:var(--space-2);
}
.pager a,
.pager span{
  display:flex;
  align-items:center;
  justify-content:center;
  min-width:var(--tap-min);
  min-height:var(--tap-min);
  padding:0 var(--space-3);
  border:1px solid var(--color-hairline);
  border-radius:var(--radius-sm);
  text-decoration:none;
}
.pager a:hover{ background:var(--color-accent-surface); }
.pager [aria-current]{
  background:var(--color-surface-brand);
  border-color:transparent;
  color:var(--color-text-on-brand);
  font-weight:var(--weight-bold);
}
.pager__gap{ border-color:transparent; color:var(--color-text-muted); }


/* ══ ПУСТОЕ СОСТОЯНИЕ КАТЕГОРИИ ═══════════════════════════════════════════
   Пустая категория остаётся навигируемой страницей, а не тупиком: дерево,
   крошки, поиск и сортировка остаются на месте, а здесь стоит ссылка
   следующего шага. Пагинация в этом состоянии не выводится. */

.cat-empty{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:var(--space-4);
  padding:var(--space-7) var(--space-5);
  border:1px solid var(--color-hairline);
  border-radius:var(--radius-card);
  background:var(--color-surface);
  text-align:center;
}
.cat-empty__ic{
  display:flex;
  align-items:center;
  justify-content:center;
  width:var(--icon-tile);
  height:var(--icon-tile);
  border-radius:var(--radius-pill);
  background:var(--color-surface-alt);
  color:var(--color-text-muted);
}
.cat-empty p{ max-width:52ch; color:var(--color-text-muted); }
