/* ==========================================================================
   Каталог кейсов — Figma 22:4093 (320–575), 22:3611 (576–767), 22:3703
   (768–1023), 22:3795 (1024–1279), 22:3887 (1280–1920), 22:3990 (1920–max).

   Страница категории — второй набор макетов, секция 28:4345 «Cases / Identity»:
   28:4857 (320–575), 28:4346 (576–767), 28:4444 (768–1023), 28:4542
   (1024–1279), 28:4640 (1280–1920), 28:4749 (1920–max). От витрины она
   отличается тремя вещами, и все три — содержимое тех же узлов: третья крошка,
   «Identity Cases» вместо «Cases» и описание услуги под заголовком. Поэтому
   отдельного блока у неё нет — только .catalog-head__intro ниже.

   Залипшая строка фильтров — секция 28:5121 «Cases • Filter Block After
   Scroll»: 28:5809 (320–575), 28:5122 (576–767), 28:5255 (768–1023), 28:5388
   (1024–1279), 28:5521 (1280–1920), 28:5665 (1920–max). Во всех шести строка
   стоит на y = 48, то есть вплотную под прибитой шапкой.

   Три блока сверху вниз: шапка страницы (крошки + «Cases 28» + описание),
   строка фильтров и сетка. Отличий между брейкпоинтами всего два, и оба
   берутся из уже существующих переменных: шкала шрифта переключается на 1024
   (tokens.css), число колонок — на 768 и 1280 (--catalog-columns). Своих
   медиазапросов по ширине в этом файле поэтому нет вовсе.

   Высоты блоков из макета получаются сами:
     шапка   80 + (21 + 16 + 32) + 24 = 173   до 1024, витрина
             80 + (24 + 16 + 48) + 24 = 192   на 1024+, витрина
             +16 + описание                   на странице категории
     фильтры 12 + (21 + 4) + 8 = 45  /  12 + (24 + 4) + 8 = 48
   ========================================================================== */

/* --- Шапка страницы ------------------------------------------------------
   Шапка сайта прибита к верху и из потока выключена, поэтому отсчёт идёт от
   нуля страницы — тот же приём, что у hero: 80 сверху перекрывают её 48. */

.catalog-head__inner {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-lg);
  padding-block: var(--spacing-6xl) var(--spacing-xl);
}

/* Крошки — общий блок, вынесен в blocks/breadcrumbs.css: те же «Home · …»
   стоят на странице кейса и на правовых страницах, а каталог им не нужен. */

/* «Cases 28» — заголовок и счётчик по одной нижней линии (в макете 28 стоит
   на y = 11 при высоте строки 21 и заголовке 32: 11 + 21 = 32) */
.catalog-head__title-row {
  display: flex;
  align-items: flex-end;
  gap: var(--spacing-md);
}

.catalog-head__title {
  font-size: var(--font-size-3xl);
  font-weight: var(--font-weight-medium);
  line-height: var(--line-height-display);
  letter-spacing: var(--letter-spacing-uppercase);
}

.catalog-head__count {
  color: var(--color-text-subtle);
  font-size: var(--font-size-sm);
  line-height: var(--line-height-text-relaxed);
  letter-spacing: var(--letter-spacing-text);
}

/* Описание услуги — только на странице категории (Figma 28:4653). Набрано тем
   же стилем Text md, что и крошки, но приглушённым цветом; ширина — вся
   колонка контента, поэтому число строк меняется с шириной само: 7 при 425,
   5 при 576, 4 при 768, 3 при 1024–1280 и 2 при 1872 — ровно как в макете.
   На витрине /cases описания нет, и узел стоит с hidden: display: none не
   создаёт зазор во flex-колонке, поэтому шапка остаётся макетных 173 / 192. */
.catalog-head__intro {
  color: var(--color-text-subtle);
  font-size: var(--font-size-sm);
  line-height: var(--line-height-text-relaxed);
  letter-spacing: var(--letter-spacing-text);
}

/* --- Строка фильтров -----------------------------------------------------
   Линия сверху — тенью, а не рамкой: в Figma обводка идёт внутрь фрейма и
   его высоту не меняет (45 = 12 + 25 + 8), а border добавил бы 1px. Тот же
   приём, что у подчёркнутых пунктов шапки.

   Строка залипает под шапкой: в макетах 28:5121 она стоит на y = 48, то есть
   ровно на высоте прибитой шапки, а содержимое уезжает под неё. Подложка —
   непрозрачный --color-bg-base из макета (28:5622): плитки под строкой не
   просвечивают. Приглушённое содержимое в тех кадрах — способ показать, что
   оно проехало под строкой, а не эффект: полупрозрачности здесь нет.

   z-index ниже шапки (10), но выше сетки: панель меню на 1024+ висит внутри
   шапки и обязана накрывать строку, а не подныривать под неё. */

.catalog-filter {
  position: sticky;
  inset-block-start: var(--header-height);
  z-index: 5;
  background-color: var(--color-bg-base);
}

.catalog-filter__inner {
  padding-block: 12px var(--spacing-md);
  box-shadow: inset 0 1px 0 var(--color-border-subtle);
}

/* До 768 пункты в строку не помещаются (в макете 425 их суммарная ширина
   715 против контейнера 377) и уезжают за правый край экрана — ровно как в
   Figma, где фрейм с ними обрезан кадром, а не контейнером. Отсюда лишний
   слой: линия и поля остаются на контейнере, а прокручиваемая область
   выходит из полей наружу и клипается уже краем окна.

   Полосу прокрутки прячем: она добавила бы блоку высоты, и 45 из макета
   перестали бы сходиться. Пункты при этом остаются доступны — свайпом,
   колесом с Shift и клавиатурой (фокус доводит их до вида сам). */
.catalog-filter__scroller {
  margin-inline: calc(-1 * var(--spacing-xl));
  padding-inline: var(--spacing-xl);
  overflow-x: auto;
  scrollbar-width: none;
  /* Прокрутка по одной оси в CSS невозможна: overflow-x: auto подрезает и
     вертикаль, а вместе с ней рамку фокуса на пункте. Поле в 4px даёт ей
     место, а такой же отрицательный отступ возвращает блоку его высоту —
     45 из макета остаются 45. */
  margin-block: calc(-1 * var(--spacing-sm));
  padding-block: var(--spacing-sm);
  /* пункт, доведённый до вида клавиатурой, не должен вставать вплотную к краю */
  scroll-padding-inline: var(--spacing-xl);
}

.catalog-filter__scroller::-webkit-scrollbar {
  display: none;
}

/* Пока помещаются — разъезжаются по ширине контейнера (в макете 1024 шаг
   между пунктами ровно (976 − 619) / 7 = 51). Как только перестали —
   min-width: max-content уводит строку в прокрутку с зазором 24. */
.catalog-filter__list {
  display: flex;
  justify-content: space-between;
  gap: var(--spacing-xl);
  min-width: max-content;
}

.catalog-filter__item {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--spacing-md);
  white-space: nowrap;
}

/* Поле снизу — то самое, из-за которого пункт в макете 25 высотой при строке
   21: под ним проходит подчёркивание выбранного фильтра. Стоит оно и у
   счётчика — иначе он повис бы на 4px выше подписи. */
.catalog-filter__label,
.catalog-filter__count {
  padding-block-end: var(--spacing-sm);
  font-size: var(--font-size-sm);
  line-height: var(--line-height-text-relaxed);
  letter-spacing: var(--letter-spacing-text);
}

.catalog-filter__count {
  color: var(--color-text-subtle);
}

/* Подчёркнута только подпись, счётчик — нет (в макете обводка стоит на
   фрейме подписи). Линия — псевдоэлемент по нижнему краю поля в 4px, то есть
   там же, где её рисовала inset-тень: высоту пункта он не меняет, а в отличие
   от тени умеет ехать. Выбор категории переезжает с пункта на пункт за то же
   время, что и подмена содержимого, — см. «Переключение категории» ниже. */
.catalog-filter__label {
  position: relative;
}

.catalog-filter__label::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  height: 1px;
  background-color: var(--color-border-primary);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-leave) var(--ease-soft);
}

.catalog-filter__item[aria-current] .catalog-filter__label::after {
  transform: scaleX(1);
  transition-duration: var(--duration-enter);
}

/* Тег, под который в ленте нет ни одного кейса: в макете такого случая нет,
   но список услуг фиксирован, а лента — нет. Пункт остаётся на месте, чтобы
   строка не перестраивалась, но кликать в пустоту не даёт. */
.catalog-filter__item[aria-disabled="true"] {
  color: var(--color-text-subtle);
  pointer-events: none;
}

/* --- Переключение категории ----------------------------------------------
   Каждая категория — отдельный адрес (/cases/identity/), и без JS переход по
   пункту фильтра остаётся обычной загрузкой страницы. С JS он перехватывается
   и идёт на месте: js/catalog.js гасит шапку страницы и сетку, подменяет
   крошки, заголовок, описание и карточки, и проявляет обратно.

   Гаснут ровно два блока. Строка фильтров в них не входит нарочно: по ней
   только что кликнули, она залипла у верхнего края, и мигать ей незачем —
   единственное её движение — переезд подчёркивания на новый пункт.

   Движения на 8px хватает, чтобы подмена читалась как смена содержимого, а не
   как перерисовка. Уход короче прихода — по общим токенам. */

.catalog-head__inner,
.catalog__grid {
  transition: opacity var(--duration-enter) var(--ease-soft),
              translate var(--duration-enter) var(--ease-soft);
}

.page--switching .catalog-head__inner,
.page--switching .catalog__grid {
  opacity: 0;
  translate: 0 8px;
  transition-duration: var(--duration-leave);
}

/* При reduce подмена мгновенная: что категория сменилась, видно по заголовку,
   крошкам и подчёркиванию, а не по движению. */
@media (prefers-reduced-motion: reduce) {
  .catalog-head__inner,
  .catalog__grid,
  .catalog-filter__label::after {
    transition: none;
  }

  .page--switching .catalog-head__inner,
  .page--switching .catalog__grid {
    translate: none;
  }
}

/* --- Сетка ---------------------------------------------------------------
   Кладка построчная: карточки идут в порядке данных, ряд заканчивается по
   самой высокой из своих карточек, следующий начинается через 40. Это
   обычный грид, поэтому раскладку целиком держит CSS — JS только создаёт
   карточки (в отличие от ленты на главной, где колонки набираются
   round-robin и потом разъезжаются параллаксом).

   Зазоры разные по осям и оба из макета: 4 между колонками, 40 между рядами.
   Предел ширины — контейнерный: в макете 1920–max сетка замирает на 1872 и
   стоит на одном x с шапкой и фильтрами (344 при кадре 2560). Этим она
   отличается от ленты на главной, где предел с 1920 снимается вовсе. */

.catalog {
  display: flex;
  justify-content: center;
  padding-block: var(--grid-inset) var(--spacing-xl);
  /* то же, что у ленты на главной: вырез забирает край только набок */
  padding-inline:
    max(var(--grid-inset), var(--safe-inline-start))
    max(var(--grid-inset), var(--safe-inline-end));
}

.catalog__grid {
  display: grid;
  grid-template-columns: repeat(var(--catalog-columns), minmax(0, 1fr));
  align-items: start;
  column-gap: var(--grid-gap);
  row-gap: var(--spacing-3xl);
  width: 100%;
  max-width: var(--container-max);
}

.catalog__grid[data-state="loading"] {
  min-height: 50vh;
}

.catalog__message {
  grid-column: 1 / -1;
  padding-block: var(--spacing-4xl);
  color: var(--color-text-subtle);
  font-size: var(--font-size-sm);
  line-height: var(--line-height-text-md);
  text-align: center;
  text-transform: uppercase;
}

/* --- Карточка ------------------------------------------------------------
   Картинка со всем, что появляется по наведению, — общая с лентой на главной
   (blocks/cases.css, js/card.js). Своё здесь только одно: подпись стоит в
   потоке всегда, а не раскрывается, и несёт третью строку — описание.

   Высота подписи из макета: 109 до 1024 и 122 на 1024+
     (4 + 17) + 8 + 20 + 8 + 2×24 + 4 = 109
     (4 + 20) + 8 + 24 + 8 + 2×27 + 4 = 122 */

.case-card--catalog {
  gap: var(--spacing-md);
}

.case-card__note {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  /* 20 — буквально из макета: у подписи каталога поля свои, не 4, как у
     раскрывающейся подписи на главной */
  padding-inline: 20px;
  padding-block-end: var(--spacing-sm);
}

/* Название набрано Display sm (font-size/lg с высотой строки 1), а не Text xl,
   как заголовок в активном состоянии плитки на главной */
.case-card--catalog .case-card__title {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-medium);
  line-height: var(--line-height-display);
  letter-spacing: var(--letter-spacing-uppercase);
}

.case-card__excerpt {
  color: var(--color-text-primary);
  font-size: var(--font-size-md);
  line-height: var(--line-height-text-relaxed);
  letter-spacing: var(--letter-spacing-text);
}
