/* Компоненты страниц сайта поверх дизайн-системы.
   Токены и базовые классы живут в design-system/, здесь — только то,
   чего в системе нет: лесенка карточек, инфографики, таблицы, форма заявки.
   Радиусы не используются: в этой системе их нет вовсе (DESIGN.md §Shapes). */

/* ── Каталог коллекций: ровная сетка ───────────────────────────────── */
/* Раньше здесь была «лесенка» со смещением каждой второй карточки. Лесенка —
   признак системы №1 (Dedon, DESIGN-MATRIX.md) и в DESIGN.md Tribù прямо
   записана как занятая. У Tribù список коллекций — лента с перетаскиванием
   (главная); на странице каталога, где 21 карточка, — ровная сетка. */
.catalog-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-40) var(--gutter-lg);
  align-items: start;
}
.collection-card__link { display: block; color: inherit; text-decoration: none; }
.collection-card__designer { display: block; margin-top: var(--sp-4); }
.collection-card__link:hover .card__title { color: var(--text-accent); }

@media (max-width: 1024px) { .catalog-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 720px) { .catalog-grid { grid-template-columns: 1fr; } }

/* ── Лента коллекций (dragRail) ─────────────────────────────────────── */
/* Поведение — design-system/js/slider.js на GSAP Draggable. Лента
   фокусируема: стрелки листают, Home и End — в начало и в конец. Трек
   держит touch-action: pan-y, поэтому вертикальный скролл страницы на
   телефоне лента не перехватывает. */
.slider__viewport:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 4px;
}
.slider__slide .collection-card { margin: 0; }

/* ── Инфографика ───────────────────────────────────────────────────── */
.infographic { margin: 0; }
.infographic__scroll { overflow-x: auto; overscroll-behavior-x: contain; padding-bottom: var(--sp-12); }

.process {
  display: grid;
  grid-template-columns: repeat(6, minmax(150px, 1fr));
  gap: var(--gutter);
  margin: 0;
  padding: 0;
  list-style: none;
}
.process__step { position: relative; padding-top: var(--sp-40); }
.process__index {
  position: absolute;
  top: 0;
  left: 0;
  font-family: var(--ff-num);
  font-size: var(--fs-h3);
  line-height: 1;
  color: var(--text-accent);
}
.process__line {
  position: absolute;
  top: calc(var(--sp-12) + 2px);
  left: var(--sp-32);
  right: calc(var(--gutter) * -1);
  height: 1px;
  background: var(--border-subtle);
}
.process__step:last-child .process__line { display: none; }
.process__title { margin: 0 0 var(--sp-4); font-family: var(--ff-label); font-size: var(--fs-label);
  letter-spacing: var(--ls-label); text-transform: uppercase; }

.layers { display: grid; gap: var(--sp-16); margin: 0; padding: 0; list-style: none; }
.layers__item { display: grid; grid-template-columns: 96px 1fr; gap: var(--sp-24); align-items: center; }
.layers__bar {
  height: 10px;
  /* Слой глубже — полоса плотнее: разрез сиденья сверху вниз */
  background: color-mix(in srgb, var(--c-olive) calc(100% - var(--layer-depth) * 18%), var(--bg-raised));
  border: 1px solid var(--border-subtle);
}
.layers__title { margin: 0; grid-column: 2; font-weight: 600; }
.layers__item p.t-small { grid-column: 2; margin: 0; }

@media (max-width: 720px) {
  .process { grid-template-columns: repeat(6, 74vw); }
  .layers__item { grid-template-columns: 56px 1fr; }
}

/* ── Таблицы ───────────────────────────────────────────────────────── */
.table-scroll { overflow-x: auto; overscroll-behavior-x: contain; }
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
.table caption { text-align: left; padding-bottom: var(--sp-16); }
.table th,
.table td { padding: var(--sp-16) var(--sp-16) var(--sp-16) 0; text-align: left; vertical-align: top;
  border-bottom: 1px solid var(--border-subtle); }
.table thead th {
  font-family: var(--ff-label);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom-color: var(--border-strong);
  white-space: nowrap;
}
.table tbody th { font-weight: 600; color: var(--text-primary); }
@media (max-width: 720px) { .table { min-width: 560px; } }

/* ── Карточка фактов на странице коллекции ─────────────────────────── */
.facts { border: 1px solid var(--border-subtle); padding: var(--sp-32); }
.facts__list { margin: 0; }
.facts__row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-16);
  padding: var(--sp-12) 0; border-bottom: 1px solid var(--border-subtle); }
.facts__row:last-child { border-bottom: none; }
.facts__row dt { margin: 0; color: var(--text-muted); }
.facts__row dd { margin: 0; }

/* ── Галерея ───────────────────────────────────────────────────────── */
.gallery { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--gutter); }
.gallery__item { margin: 0; grid-column: span 2; }
.gallery__item--wide { grid-column: span 4; }
.gallery__item img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 720px) {
  .gallery { grid-template-columns: 1fr; }
  .gallery__item,
  .gallery__item--wide { grid-column: span 1; }
}

/* ── Предметы коллекции: студийные вырезки на подложке ─────────────── */
.pieces { display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--gutter);
  margin: 0; padding: 0; list-style: none; }
/* Вырезка предмета снята на белом фоне, поэтому плитка светлая:
   на тёмном фоне страницы тёмная мебель в PNG просто пропадает. */
.pieces__item {
  display: grid;
  grid-template-rows: 1fr auto;
  gap: var(--sp-12);
  justify-items: center;
  align-content: center;
  text-align: center;
  background: var(--c-sand);
  /* --on-panel в системе нет: имя предмета наследовало светлый цвет страницы
     и на песочной плитке читалось как 1,1:1, то есть не читалось вовсе. */
  color: var(--text-inverse);
  padding: var(--sp-24) var(--sp-12);
  min-height: 220px;
}
.pieces__item .t-label { color: var(--c-warm-grey); }
.pieces__img { width: 100%; height: auto; align-self: center; }
/* Предмет без вырезки: тот же размер плитки, только имя по центру */
.pieces__item--text { align-content: center; }
.pieces__item--text .t-label { color: var(--text-inverse); }
@media (max-width: 1024px) { .pieces { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px) { .pieces { grid-template-columns: repeat(2, 1fr); } }

/* ── Форма заявки ──────────────────────────────────────────────────── */
.form__row { margin-bottom: var(--sp-24); }
.field__input {
  width: 100%;
  padding: var(--sp-12) 0;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-primary);
  font: inherit;
  /* 16px — иначе iOS зумит страницу при фокусе, §4 мобильная */
  font-size: max(16px, var(--fs-body));
  transition: border-color var(--dur-base) var(--ease-out);
}
.field__input:hover { border-bottom-color: var(--border-strong); }
.field__input:focus-visible { outline: none; border-bottom-color: var(--accent); }
.field__input::placeholder { color: var(--text-muted); }
.form__trap { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.form__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-24); margin-top: var(--sp-32); }
.form__promise { flex: 1 1 260px; margin: 0; }
.form__status { margin-top: var(--sp-16); min-height: 1.4em; }
.form__status[data-state="ok"] { color: var(--c-olive); }
.form__status[data-state="error"] { color: var(--error); }
/* Виджет капчи грузится лениво и распахивается до 65px: без запаса под него
   кнопка, подпись и весь подвал съезжали вниз — единственный заметный сдвиг
   в замере CLS (0,016-0,032 на 1440). Место держим заранее. */
.cf-turnstile { margin-top: var(--sp-24); min-height: 65px; }
@media (max-width: 720px) {
  .form__actions .btn { width: 100%; }
}

/* ── Мелочи ────────────────────────────────────────────────────────── */
.btn--sm { padding: var(--sp-8) var(--sp-16); font-size: var(--fs-label); }
.btn--block { display: block; width: 100%; text-align: center; }
.header__cta { margin-left: var(--sp-16); }
@media (max-width: 720px) { .header__cta { display: none; } }

.section--top { padding-top: calc(var(--header-h) + var(--sp-72)); }
.hero--collection .hero__content { max-width: var(--measure-display); }
.t-body { font-size: var(--fs-body); line-height: var(--lh-body); max-width: var(--measure-text); }
.designer--plain { display: block; }

.footer__cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gutter-lg);
  margin-top: var(--sp-56); }
.footer__list { list-style: none; margin: var(--sp-16) 0 0; padding: 0; display: grid; gap: var(--sp-8); }
.footer__link { color: var(--text-secondary); text-decoration: none; }
.footer__link:hover { color: var(--text-primary); }
/* Девиз антиквой: Cormorant в 17-19px на тёмной оливе читался волосяной
   линией — светлый текст на тёмном визуально тоньше. Антиква в этой системе
   только для крупного, поэтому девиз поднят до размера подзаголовка. */
.footer__tagline { font-family: var(--ff-display); font-size: clamp(1.5rem, 2.2vw, 2rem); line-height: 1.25;
  letter-spacing: var(--ls-display); }
.footer__legal { margin-top: var(--sp-56); }
@media (max-width: 720px) { .footer__cols { grid-template-columns: 1fr; gap: var(--sp-40); } }

/* ── Движение и загрузка шрифтов: техправки ───────────────────────── */

/* Капс-строки на подстановочном шрифте берут свою поправку ширины
   (см. fonts.css), иначе меню и кнопки дёргаются при подмене Montserrat. */
.skip-link, .announce, .header__desc, .nav__link, .btn, .t-label, .link,
h3, .t-h3, .feature-item__title, .process__title, .table thead th, .field__label {
  font-family: 'Montserrat', 'Montserrat Caps Fallback', ui-sans-serif, system-ui, 'Segoe UI', sans-serif;
}

/* ── Кадр не шире своего файла ─────────────────────────────────────── */
/* --maxw ставит сборка по родной ширине оригинала (build_site.existing_variants),
   и в том же числе ограничены все длины в sizes (cap_sizes). Студийная вырезка
   приходит с CDN фабрики ровно в 500px: без предела плитка предмета на ретине
   тянула её вдвое, и вырезка шла мылом — та же причина, что на Poliform 21.09.
   Полноширинный герой сюда не попадает: у интерьерных кадров native 1920. */
picture {
  display: block;
  /* width: 100% обязателен: margin-inline: auto у ребёнка grid или flex
     отменяет растяжение, и у Kettal сетка из-за этого дала горизонтальную
     прокрутку. Ширина по контейнеру, потолок — ширина файла. */
  width: 100%;
  max-width: var(--maxw, none);
  margin-inline: auto;
}

/* <picture> — блок с высотой по содержимому, и img с .cover растягивался
   только до собственной пропорции: на телефоне фото героя занимало
   полосу сверху, а маска-вайп открывала рамку 4:5 с пустым низом. */
.hero__media > picture,
.frame > picture,
.card__media > picture {
  width: 100%;
  height: 100%;
}

/* .card__media — span, то есть строчный элемент: overflow у него не работает,
   и фото при наведении вылезало из рамки на подпись. Размер рамки прежний. */
.collection-card .card__media {
  display: block;
  /* Общая рамка 3:2. С aspect-ratio: auto каждая карточка брала пропорцию
     своей обложки (1,58 / 1,78 / 1,93), и в ленте низ фото и подписи шёл
     лесенкой. 3:2 режет пейзажные обложки не больше чем на треть по ширине
     (проверка frame_fit на сборке), sizes умножены на это превышение. */
  aspect-ratio: 3 / 2;
}

/* ── Панель коллажа: фото на всю высоту панели ────────────────────── */
/* Картинка стояла в своей пропорции, и под ней оставалась пустая белая
   полоса до низа текстовой колонки. Рамка тянется по высоте текста,
   кадр заполняет её с cover. */
.split-panel__media > picture {
  position: absolute;
  inset: 0;
  height: 100%;
}

/* ── Предмет без вырезки: имя по центру плитки ────────────────────── */
/* Строк у плитки две (1fr auto), и одинокая подпись вставала в первую —
   к верхнему краю. Здесь строка одна, и тот же кегль, что у остальных. */
.pieces__item--text { grid-template-rows: 1fr; align-items: center; }
.pieces__item--text .t-label { font-size: var(--fs-label); }

/* ── Зона нажатия: настоящая коробка, а не невидимый ::before ──────── */
/* Было два изъяна сразу. Первый — всё это стояло под @media (pointer: coarse),
   то есть на мыши не работало вовсе, а C3 сети мерит зону нажатия на любом
   вводе: на 1024-1920 ссылки шапки были 40px, крошки 24px, «reveal» 28px.
   Второй — высоту добирал `::before`, а псевдоэлемент не читает ни одна
   измерялка сети (находка Meroni 25.09: 483 цели, у всех коробка 30px при
   настоящей зоне 44). Поэтому теперь высоту держит сама коробка.
   Линия ссылки нарисована ::after по нижнему краю, и чтобы она не уехала
   вниз вместе с коробкой, её низ поднят на тот же отступ. */
:root { --tap-pad: 13px; }

.nav__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.breadcrumbs a,
.link--reveal,
.table th > .link {
  padding-top: var(--tap-pad);
  padding-bottom: calc(var(--tap-pad) + var(--sp-4));
}

.link--reveal::after,
.table th > .link::after { bottom: var(--tap-pad); }

/* Имя коллекции в первой ячейке строки — главная ссылка строки, а у Kos,
   CTR, Tao и Mood она выходит 36-44px в ширину. Палец в неё не попадает,
   поэтому коробка добирается до 44 и линия ховера идёт по коробке. */
.table th > .link { min-width: 44px; }

.breadcrumbs a { display: inline-flex; align-items: center; }

/* Подвал: ссылки второстепенны, но палец у них тот же. Зазор списка убран,
   чтобы шаг между пунктами не вырос вдвое. */
.footer__link { display: inline-block; padding-block: var(--tap-pad); }
.footer__list { gap: 0; }

/* ── Классы, у которых не было ни одного правила ───────────────────── */
/* Сверка «классы в разметке против классов в CSS» (build/check_classes.py)
   нашла три таких: .hero-lead, .grid-people и .menu-close. Ни один из них
   не падал в глаза — блок просто раскладывался по умолчанию: лид героя шёл
   на 60ch поперёк центрированного текста, карточки людей брали минимум
   auto-grid в 240px, а кнопка Close в меню растягивалась на всю ширину
   первой строкой. То же самое 21.09 нашлось у Poliform. */

/* Лид под заголовком героя: текст центрированный, поэтому мера у него
   короче обычной — иначе последняя строка висит в одиночестве. */
.hero-lead {
  max-width: 46ch;
  margin-inline: auto;
}

/* Сетка людей: карточка дизайнера — имя антиквой плюс список коллекций,
   в 240px имя переносится по слогам. */
.grid-people { --min: 288px; }
.grid-people .designer {
  padding-top: var(--sp-24);
  border-top: 1px solid var(--border-subtle);
}

/* Кнопка выхода из полноэкранного меню: прижата вправо, размер пальца. */
.menu-close {
  justify-self: end;
  min-height: 44px;
  margin-bottom: var(--sp-24);
}

/* ── Капс-дисплей на телефоне ─────────────────────────────────────── */
/* Слово «COLLECTIONS» капсом в 48px с разрядкой 0,08em шире колонки 328px:
   каталог на 360 прокручивался вбок на 18px (ворота 4). Кегль тянется от
   ширины экрана, разрядка остаётся положительной — признак системы. */
@media (max-width: 480px) {
  .t-display--caps {
    font-size: clamp(2rem, 10.5vw, 3rem);
    letter-spacing: 0.05em;
  }
}

/* ── Рамка героя равна полосе, под которую вырезан файл ────────────── */
/* Было: min-height: min(94svh, 940px), то есть пропорцию рамки задавало
   окно — 0,91 на 768 и 2,27 на 1920 при обложках от 1,20 до 1,93. Одна
   рамка не совпадает с одним файлом ни при какой высоте, и A2 насчитала
   143 «чужих формы» на 31 странице. Теперь полос три, у каждой свой
   вырезанный файл (derive_hero_mobile.py и derive_hero_wide.py), и рамка
   берёт ровно её пропорцию. Пол оставлен на случай коротких заголовков:
   он ниже расчётной высоты и в пропорцию не вмешивается. */
.hero {
  min-height: 0;
  aspect-ratio: 360 / 733;
}

@media (min-width: 721px) {
  .hero { aspect-ratio: 1.6; min-height: 420px; }
}

@media (min-width: 1280px) {
  .hero { aspect-ratio: 2.1; min-height: 560px; }
}

/* ── Фотоколонка коллажа: рамка под кадр, а не под соседа ──────────── */
/* Рамка здесь тянется по высоте текстовой колонки — это и есть приём
   коллажа, но пропорция у неё тогда чужая. Ниже 1024 панель сложена, и
   кадр идёт своей полосой 3:2. От 1024 колонка близка к квадрату (449×472
   на 1440), поэтому туда режется квадратный файл — случай круга Roda:
   форму назначила система, значит режется файл. */
.split-panel__media { aspect-ratio: 3 / 2; min-height: 0; }

@media (min-width: 1024px) {
  .split-panel__media { aspect-ratio: 1; }
}

/* ── Двухстрочный логотип: боксы гарнитур не сходятся ──────────────── */
/* Находка сети 3 в её здешней форме. У .header__logo стояло line-height: 1,
   а Cormorant рисует 1.211 em (hhea 924 + 287 на 1000 upm, снято fontTools),
   Montserrat 1.219. Строчный бокс короче букв, и содержимое вордмарка
   заходило на содержимое дескриптора на 2-3px на каждой из 31 страницы и на
   всех пяти ширинах. Ù и капс снизу ничего не рисуют, поэтому глаз этого не
   ловил, — но ноль пересечений значит ноль. Ведущее поднято до чернильного
   бокса каждой гарнитуры, зазор строки убран, высота блока выросла на 7px
   при шапке в 88. Трекинг и кегль не тронуты: это признаки системы. */
/* Числа сняты не из таблиц гарнитуры, а с отрисовки: прямоугольник Range
   у Cormorant 28px выходит 34.0 (1.214 em), у Montserrat 14px — 18.0
   (1.286 em, шире чем hhea 1.219, Chrome берёт свои метрики). Ведущее
   ставится по отрисованному, иначе остаётся пиксель пересечения. */
.header__logo { gap: 0; }
.header__mark { line-height: 1.23; }
.header__desc { line-height: 1.3; }

/* ── Текст героя на фотографии: контраст посчитан по пикселям ──────── */
/* Ровная затемняющая плёнка 0,42 держала контраст, пока рамка героя была
   высокой и кадр показывал свою тёмную часть. После перехода на полосы
   2,10 и 1,60 (см. выше) под словами оказалось небо и песок, и пиксельный
   замер (build/check_contrast.js) дал 2,61:1 у h1 при пороге 3 и 2,50:1
   у лида при пороге 4,5 — на 22 и 16 страницах. Обход backgroundColor
   этого не видит вовсе: под текстом лежит кадр, а не заливка.
   Лечится не общим затемнением (оно убило бы кадр), а пятном ровно там,
   где стоит текст: контент героя центрирован, и плёнка сгущается к центру
   и сходит на нет к краям. Затемнение остаётся тёплым и почти чёрным —
   так оно описано в DESIGN.md. */
.hero__scrim {
  background:
    radial-gradient(120% 78% at 50% 52%,
      rgba(20, 24, 16, 0.64) 0%, rgba(20, 24, 16, 0.42) 58%, rgba(20, 24, 16, 0) 100%),
    linear-gradient(to bottom, var(--scrim-deep) 0%, transparent 42%, var(--scrim) 100%),
    linear-gradient(var(--scrim), var(--scrim));
}

/* Крошки стоят у верхнего края героя, куда пятно не достаёт, а олива на
   кадре давала 3,21:1 при пороге 4,5. На фотографии они набираются костью
   и песком: оливой крошки остаются везде, где под ними ровная заливка. */
.hero .breadcrumbs { color: var(--c-sand); }
.hero .breadcrumbs a { color: var(--c-bone); }

/* ── Журнал: статья и раздел (27.09) ──────────────────────────────── */
/* Схема журнала Kettal, собранная из блоков этой системы. Заголовок статьи
   в две-четыре строки стоит на герое-полосе: свой кегль и мера, иначе капс
   с разрядкой в 120px распирал рамку 1,6 на планшете, и кадр переставал
   совпадать с вырезанным под полосу файлом. Межстрочный 1,04 — не ниже
   display 1,0, прошедшего на этом сайте проверку боксов гарнитуры. */
.t-display--story {
  font-size: clamp(2rem, 3.6vw + 0.75rem, 4.25rem);
  line-height: 1.04;
  letter-spacing: 0.06em;
  max-width: 20ch;
  margin-inline: auto;
}
@media (max-width: 480px) {
  .t-display--story { font-size: clamp(1.625rem, 7.6vw, 2.25rem); letter-spacing: 0.04em; }
}

.story__row + .story__row { margin-top: var(--sp-72); }
.story__lead { color: var(--text-primary); }
.story__fig { margin: 0; }
.story__fig .frame { width: 100%; }

/* Карточка фактов со страницы коллекции, в колонке в две восьмых:
   строки в одну колонку, подпись над значением. */
.story__aside .facts { padding: var(--sp-24); }
.story__aside .facts__row { grid-template-columns: 1fr; gap: var(--sp-4); }
.story__aside dd .link { margin-right: var(--sp-16); }
@media (min-width: 1024px) {
  .story__aside { position: sticky; top: calc(var(--header-h) + var(--sp-24)); align-self: start; }
}
/* На планшете две восьмых — 150px: карточка уходит под текст, текст и
   кадр встают на шесть колонок со смещением на одну. */
@media (min-width: 768px) and (max-width: 1023px) {
  .grid > .story__text, .grid > .story__aside, .grid > .story__fig { grid-column: 2 / span 6; }
}

/* Процесс статьи: столько колонок, сколько шагов. Базовый .process держит
   шесть, и на пяти шагах шестая колонка оставалась пустой. */
.process--n { grid-template-columns: repeat(var(--n, 6), minmax(150px, 1fr)); }
@media (max-width: 720px) {
  .process--n { grid-template-columns: repeat(var(--n, 6), 74vw); }
}

/* Ссылка-заголовок в нумерованном списке: линия системы, кегль строки. */
.feature-item__title .link { font-size: inherit; letter-spacing: inherit; font-weight: inherit; }
/* Строки заголовка статьи (h1_lines) от 900 идут своими строками: мера 20ch
   рвала «patio furniture sets» посередине. Разрыв — <br> внутри одного текста,
   а не блочные span: у отдельных элементов строчные боксы Cormorant (1,214 em)
   при межстрочном 1,04 заходили друг на друга на 5-12px (B2, 27.09). */
.t-display--story .ln-br { display: none; }
@media (min-width: 900px) {
  .t-display--story { max-width: none; }
  .t-display--story .ln-br { display: inline; }
}
/* Имя коллекции в карточке фактов: «Kos» выходило 38px в ширину (C3). */
.story__aside dd .link { min-width: 44px; }
