/* OWNS: .xf-dept*, .xf-l1hub* (хаб каталога, issue #362), включая
   .xf-l1hub-tile--empty (плитка подраздела без товаров); внутри
   .xf-l1hub-grid — документированные override'ы .xf-catgrid,
   .xf-cat-tile__name и .xf-cat-tile__count (только тёмная тема) */

/* Разметку под эти классы рисуют include/catalog/landing.php (корень каталога)
   и include/catalog/section.php (L1-раздел). Файл подключается последним в
   списке header.php — переопределения .xf-catgrid внутри .xf-l1hub-grid
   рассчитывают на то, что catalog.css и catsection.css уже прочитаны.

   Зачем: хаб каталога — не витрина, а развилка. Посетитель приходит уже зная,
   что ему нужно, и думает словами второго уровня («видеокарта», «SSD»,
   «роутер»), а не первого («Комплектующие для компьютеров»). Плитка-департамент
   поднимает эти слова на хаб: один экран — 17 разделов и ~70 их подразделов
   прямыми ссылками, без промежуточного клика-перевода.                       */

/* ─── Сетка департаментов (корень /catalog/) ────────────────────────────── */
.xf-dept-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}

.xf-dept {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: 16px;
  overflow: hidden;
  transition: border-color .2s, transform .2s, box-shadow .2s;
}
/* Крупнейшие разделы занимают две колонки: вес плитки следует за реальным
   объёмом раздела, а не за одинаковой сеткой. Побочно закрывает рваный
   последний ряд — 3 двойные + 14 одиночных = ровно 5 рядов по 4. */
.xf-dept--wide { grid-column: span 2; }

@media (hover: hover) {
  .xf-dept:hover {
    border-color: var(--accent-line);
    transform: translateY(calc(-2px * var(--xf-motion, 1)));
    box-shadow: var(--shadow-card);
  }
  /* [#323-урок] В тёмной теме длинная тень долетает до соседнего ряда и
     мерцает — здесь она короче и мягче, как у .xf-cat-tile. */
  html[data-theme="dark"] .xf-dept:hover {
    box-shadow: 0 8px 20px -12px oklch(0.05 0.03 280 / 0.35);
  }
}

/* Плитка обещает кликабельность всем телом: на hover она целиком
   приподнимается, светится рамкой и стрелкой. Замер живого /dev/ 2026-08-06:
   ссылкой была только шапка — 76 px из 189, — а на остальной плитке стоял
   `cursor: auto`, и попадание мимо шапки не делало ничего. Растягиваем ссылку
   шапки на всю плитку; словарь подразделов поднимаем над этим слоем, чтобы
   его собственные ссылки продолжали работать. */
.xf-dept { position: relative; }
.xf-dept__head::after { content: ''; position: absolute; inset: 0; }
/* Поднимаем над накладкой САМИ ссылки, а не список: подняв `ul`, мы вместе с
   именами подразделов подняли бы и пустоту справа от них — проверено, клик по
   середине плитки снова уходил в никуда. */
.xf-dept__link { position: relative; z-index: 1; }

/* ─── Шапка плитки: сам раздел ──────────────────────────────────────────── */
.xf-dept__head {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 18px;
  color: var(--text);
  text-decoration: none;
  min-height: 0;
}
/* Иконка раздела: нейтральная плашка (Neutral-Placeholder Rule — различие
   плиток несёт форма иконки, не цвет). */
.xf-dept__icon {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--surface-3);
  border: 1px solid var(--line-soft);
  color: var(--text-2);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .25s, border-color .25s, color .25s;
}
.xf-dept__icon svg { width: 24px; height: 24px; }
.xf-dept__icon img {
  max-width: 70%;
  max-height: 70%;
  object-fit: contain;
}
@media (hover: hover) {
  .xf-dept:hover .xf-dept__icon {
    background: var(--accent);
    border-color: transparent;
    color: #fff;
  }
}

/* Раздел без подразделов (плоский L1 — «Умный дом», «Электросамокаты»):
   шапка занимает плитку целиком и центрируется, иначе под ней зияет пустота
   в ряду, высоту которого задал сосед со списком. */
.xf-dept:not(:has(.xf-dept__links)) .xf-dept__head { flex: 1 1 auto; }

.xf-dept__label {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* Имя раздела — первое и самое весомое в плитке (и в DOM: скринридер читает
   «Комплектующие для компьютеров, 7679 товаров», а не наоборот). */
.xf-dept__name {
  margin: 0;              /* это h3 — сбрасываем браузерные поля заголовка */
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.3px;
  line-height: 1.25;
}
.xf-dept--wide .xf-dept__name { font-size: 18px; }
.xf-dept__count {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-3);
}
.xf-dept__arrow {
  flex: 0 0 auto;
  color: var(--text-3);
  display: flex;
  transition: color .2s, transform .2s;
}
@media (hover: hover) {
  .xf-dept:hover .xf-dept__arrow {
    color: var(--accent);
    transform: translate(calc(1px * var(--xf-motion, 1)), calc(-1px * var(--xf-motion, 1)));
  }
}

/* ─── Подразделы: словарь посетителя прямыми ссылками ───────────────────── */
.xf-dept__links {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  /* Разделяет расстояние, а не пунктуация. Точка-разделитель здесь пробовалась
     и проиграла: в узкой плитке каждое имя занимает свою строку, и точка
     повисает хвостом на конце каждой (а ведущая — маркером в начале). Зазор в
     16px против словесного пробела в 3-4px читается однозначно и не шумит. */
  gap: 3px 16px;
  margin: 0;
  padding: 0 18px 16px;
  list-style: none;
}
.xf-dept__link {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-2);
  text-decoration: none;
  transition: color .15s;
}
.xf-dept__link:hover { color: var(--accent-2); text-decoration: underline; }
/* «ещё N» отличается ФОРМОЙ, а не оттенком. Оттенка не хватило: в тёмной теме
   ниже мы поднимаем и счётчик, и «ещё» до --text-2 ради контраста — то есть
   ровно до цвета соседних ссылок, и в списке «Аккумуляторы для ИБП  ещё 11»
   последнее слово читалось как ещё одна категория. Подчёркивание видно в
   обеих темах и говорит «эта ссылка про другое».
   Подчёркивание СПЛОШНОЕ, а не пунктирное: в рунете пунктир — устоявшаяся
   метка «раскроется на месте / подсказка», а «ещё N» уводит на страницу
   раздела. Отличие от соседей всё равно держится — у них подчёркивания нет
   вовсе, оно появляется только на наведении. */
.xf-dept__more {
  color: var(--text-3);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Список гейтился одной шириной экрана, а планшет в портрете — это 768px:
   пальцу доставались цели высотой 17px с зазором 7.5px. Ширина не говорит
   о том, чем по экрану попадают; спрашиваем про палец напрямую и добираем
   строке высоту до 25px — это уже выше порога 24×24 (WCAG 2.5.8). */
@media (pointer: coarse) {
  .xf-dept__links { gap: 6px 16px; }
  .xf-dept__link { padding: 4px 0; }
}

/* Замерено на живой странице: --text-3 на карточке даёт 4.85:1 в светлой теме
   (AA проходит) и 4.28:1 в тёмной (не проходит для мелкого текста). Поэтому
   тише делаем только там, где это безопасно, а в тёмной поднимаем на ступень.
   Правится точечно здесь, а не в токенах: --text-3 живёт по всему шаблону,
   его сдвиг — отдельное решение, не побочный эффект правки хаба. */
html[data-theme="dark"] .xf-dept__count,
html[data-theme="dark"] .xf-dept__more { color: var(--text-2); }

/* Планшет: колонок меньше, словарь остаётся — места под него хватает.
   Двойную плитку на трёх колонках снимаем. Приём вводился, чтобы закрыть
   рваный последний ряд на четырёх колонках, а на трёх он делает ровно
   обратное: плитка шириной в две ячейки не пускает к себе в ряд вторую
   такую же, та переносится, и в первых двух рядах остаются зияющие
   третьи ячейки — плюс сирота в конце. На двух колонках (768–899px)
   span 2 — это целый ряд, дырки не возникает, поэтому там оставляем. */
@media (min-width: 900px) and (max-width: 1199px) {
  .xf-dept-grid { grid-template-columns: repeat(3, 1fr); }
  .xf-dept--wide { grid-column: auto; }
  .xf-dept--wide .xf-dept__name { font-size: 16px; }
}
@media (min-width: 768px) and (max-width: 899px) {
  .xf-dept-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ─── Телефон: словарь остаётся там, где он помещается ──────────────────
   Телефон — главная сцена покупки (PRODUCT.md), поэтому прятать на нём весь
   словарь второго уровня — значит отдать главному сценарию ровно ничего. Но и класть
   его во все 17 плиток нельзя: узкая плитка на 390 px — это 171 px, каждое
   имя заняло бы там свою строку.
   Компромисс по ширине: три крупнейших раздела и так идут во весь экран
   (356 px) — им словарь достаётся; остальные остаются компактными дверьми.
   Плата — около 120 px на страницу, и именно за товаром этих трёх разделов
   сюда чаще всего и приходят с телефона.
   Брейкпоинт 767px — тот же, на котором переключается вся сетка каталога. */
@media (max-width: 767px) {
  .xf-dept-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  .xf-dept--wide { grid-column: span 2; }
  .xf-dept:not(.xf-dept--wide) .xf-dept__links { display: none; }
  .xf-dept--wide .xf-dept__links { padding: 0 14px 14px; gap: 2px 14px; }
  .xf-dept__arrow { display: none; }
  .xf-dept__head { flex: 1 1 auto; padding: 14px; gap: 10px; }
  .xf-dept__icon { width: 36px; height: 36px; border-radius: 10px; }
  .xf-dept__icon svg { width: 20px; height: 20px; }
  .xf-dept__name { font-size: 14px; }
  /* В узкой плитке иконка и имя в одну строку не помещаются: «Видеонаблюдение»
     — одно длинное слово, оно не переносится и обрезается многоточием. Ставим
     иконку отдельной строкой — имя получает всю ширину карточки. Широкая
     плитка занимает весь ряд, там строки хватает и колонка не нужна. */
  .xf-dept:not(.xf-dept--wide) .xf-dept__head {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
  .xf-dept--wide .xf-dept__name { font-size: 15px; }
  .xf-dept__name { overflow-wrap: break-word; hyphens: auto; }
}

/* ─── L1 sub-hub (section.php): сетка подразделов без сироты ────────────
   Базовая .xf-catgrid жёстко даёт 4 колонки, поэтому пять подразделов
   раскладываются как 4 + 1 — последний ряд читается как обрыв. Число колонок
   здесь считает PHP по числу детей (--xf-l1cols) и оставляет ровные ряды.
   Это осознанный override колонок .xf-catgrid, а не случайный дубль каскада:
   класс ставит только сетка подразделов в section.php.                      */
.xf-l1hub-grid { grid-template-columns: repeat(var(--xf-l1cols, 4), 1fr); }
/* Если сирота всё же остаётся (n % колонок == 1), последняя плитка занимает
   две ячейки — ряд закрывается, а не обрывается. */
.xf-l1hub-grid--stretch-last > :last-child { grid-column: span 2; }
/* Ниже десктопа число колонок диктует ширина экрана, а не число подразделов:
   плитка с фото товара уже узкой 240px не читается. Растяжку сироты тоже
   снимаем — на 2-3 колонках она бы вернула рваный ряд. */
@media (min-width: 768px) and (max-width: 1099px) {
  .xf-l1hub-grid { grid-template-columns: repeat(3, 1fr); }
  .xf-l1hub-grid--stretch-last > :last-child { grid-column: auto; }
}
/* Тот же порог в 240px нарушала и сама пятиколоночная сетка: PHP считает
   колонки по числу подразделов и о ширине экрана не знает, поэтому на
   1100–1335px плитка падала до 193px — УЖЕ, чем она же на экране поменьше,
   где работает трёхколоночное правило выше. Пятая колонка окупается только
   с 1336px ((1336−80−4×14)/5 = 240); ниже складываемся в те же три колонки,
   что и до 1100px, и порог держится на всей ширине. */
@media (min-width: 1100px) and (max-width: 1335px) {
  .xf-l1hub-grid--five { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 767px) {
  .xf-l1hub-grid { grid-template-columns: repeat(2, 1fr); }
  .xf-l1hub-grid--stretch-last > :last-child { grid-column: auto; }
}

/* Имя подраздела резервирует две строки и на кураторской обложке (--static).
   home.css делает такой резерв только для фото-обложки (--cover), поэтому в
   ряду, где у одной плитки имя в две строки, счётчики соседей съезжали по
   вертикали вразнобой. Осознанный override внутри сетки хаба, не дубль.
   Только с 768px: ниже этой ширины `.xf-cat-tile__name` уже настроен в
   catalog.css (свой line-clamp и line-height для телефона), и правило без
   медиазапроса перебивало его по специфичности — одна и та же плитка
   получала бы разную типографику в зависимости от того, в какой она сетке. */
@media (min-width: 768px) {
  .xf-l1hub-grid .xf-cat-tile:has(.xf-cat-tile__art--static) .xf-cat-tile__name {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    line-height: 1.35;
    min-height: calc(1.35em * 2);
  }
}

/* Имя подраздела — это h3 (section.php), иначе 12 плиток сетки не видны
   навигации по заголовкам. Заголовку сбрасываем браузерные поля: базовый
   .xf-cat-tile__name гасит только margin-top, и снизу у h3 осталось бы 1em —
   плитка стала бы выше соседних. Тот же приём, что у .xf-dept__name на хабе. */
.xf-l1hub-grid h3.xf-cat-tile__name { margin: 0; }

/* Подраздел без товаров (section.php снимает с него ссылку): плитка остаётся
   на месте — пустая полка это факт, прятать его значит рисовать ассортимент
   лучше, чем он есть, — но перестаёт зазывать. Гасим обложку, а не текст:
   приглушённый текст ушёл бы ниже AA, а картинка контраста не несёт.
   Наведение тоже молчит — двигаться некуда. */
.xf-l1hub-tile--empty { cursor: default; background: var(--surface-2); }
.xf-l1hub-tile--empty .xf-cat-tile__art { opacity: .45; }
.xf-l1hub-tile--empty .xf-cat-tile__count { color: var(--text-3); }
@media (hover: hover) {
  .xf-l1hub-tile--empty:hover {
    transform: none;
    box-shadow: none;
    border-color: var(--line-soft);
  }
}

/* Счётчик на плитке подраздела: тот же случай, что у .xf-dept__count выше —
   --text-3 в тёмной теме даёт 4.27:1, для 11.5px это ниже AA. Первый заход
   поднял только счётчики хаба и пропустил счётчик самой сетки подразделов,
   хотя чинил именно её страницу. Правка живёт внутри сетки хаба, на плитки
   других страниц не распространяется. */
html[data-theme="dark"] .xf-l1hub-grid .xf-cat-tile__count { color: var(--text-2); }

/* Подпись перед полосой брендов: без неё чипы читаются как инертные теги.
   Слово рядом объясняет, что это фильтр по бренду, и не добавляет акцента
   (One-Voice Indigo). */
.xf-l1hub-chiprow {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px 10px;
  /* Отступ сверху раньше нёс сам .xf-brand-chips; обёртка забирает его себе,
     иначе подпись прилипает к лиду раздела. */
  margin-top: 12px;
}
.xf-l1hub-chiprow__label {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--text-3);
  white-space: nowrap;
}
.xf-l1hub-chiprow .xf-brand-chips,
.xf-l1hub-chiprow .xf-facet-chips { margin: 0; }
