/*
 * Стили витрины и кабинета покупателя: то, чего нет у второго кабинета, — мега-меню каталога, строка
 * поиска, точка доставки, сетка карточек, карточка модели, выдача с фасетами. Каркас (раскладка, карточка,
 * пустое состояние, пометка блока, метки, ряд действий, пагинатор) приходит из libs/bff-web файлом
 * css/base.css, подключённым перед этим (change 0011, design.md → «каркас двух кабинетов переезжает в
 * libs/bff-web»); тем же файлом приходит система оформления «Сталь»: переменные, шрифты, правила
 * элементов (change 0064).
 *
 * Кнопки, поля, таблицы, заголовки и ссылки здесь не описываются: их задаёт система, и повторять их значило
 * бы завести второй источник правды об оформлении (требование «Оформление кабинетов задаётся одной системой
 * в общей библиотеке»). Остаётся только своё. Цвета и тени — только переменными системы (--c-text-2 и
 * подобными), чисел цвета здесь нет: палитра — это тоже оформление, и хозяин у неё один.
 *
 * Лежит файл в статике сервиса и отдаётся с того же хоста: внешних CDN у платформы нет — стенд и прод
 * работают в закрытых сетях (ADR-0011, спека bff-market/page-shell, сценарий «Статика своя»).
 */

/*
  Ссылки, которые ведут по витрине, а не по тексту, — пункты меню, быстрые ссылки, подкатегории, значения
  фасетов — система красит цветом текста сама: они стоят в nav и перечнях (change 0064, задача 1.12). Остаётся
  название в карточке сетки: оно стоит в блоке, а не в перечне, и без правила было бы ссылочного цвета.
*/
.product-card .card-title { color: var(--c-text); text-decoration: none; }
.product-card .card-title:hover { color: var(--c-link-hover); text-decoration: underline; }
/* Имя производителя на плитке ведёт на его страницу (change 0080) и остаётся приглушённой строкой плитки. */
.product-card .card-maker a { color: inherit; text-decoration: none; }
.product-card .card-maker a:hover { color: var(--c-link-hover); text-decoration: underline; }

/* ── шапка витрины: кнопка каталога, строка поиска, точка доставки, корзина ── */

/*
  Кнопка каталога — главная кнопка шапки: графит и значок «≡» вместо стрелки раскрытия задаёт система
  (.topbar .catalog-button, change 0064, design.md → D7), она же красит незагруженную кнопку рамкой и цветом
  «внимания». Здесь — только промежуток между значком и надписью, как на макете.
*/
.topbar .catalog-button { gap: 10px; }

/*
  Подпись у знака («промышленное оборудование») — пояснение, а не название: строка шапки витрины принадлежит
  поиску, разделам и посетителю, поэтому подпись показывается только там, где строка не тесна, — на 1920
  (change 0045). У кабинетов продавца и менеджера подпись — имя кабинета, и система показывает её всегда.
*/
@media (max-width: 1919px) {
  .topbar .brand-sub { display: none; }
}

/*
  Строка поиска — единственная часть шапки, которая тянется: остальные стоят своей шириной, а лишнее место
  достаётся ей, но не больше 560 px — на 1920 поле для одного кода модели во всю шапку разбалансировало строку
  (change 0047). Пол — 260 px (change 0064, design.md → D7): при нём в поле остаётся около 150 px текста, и
  подсказка «Искать модель или код» читается до «или»; ниже она обрывалась бы на первом слове.

  Лупа стоит внутри поля слева, на отступе текста поля, а текст начинается за ней (задача 2.20); «Найти»
  приставлена к полю справа: у поля скруглена левая сторона, у кнопки — правая, общая граница — рамка кнопки.
  Высота поля и «Найти» — высота поля системы (правило ряда в base.css). Вид «Найти» — нейтральная кнопка строки
  поиска системы.
*/
.topbar .search { position: relative; display: flex; flex: 1 1 260px; min-width: 260px; max-width: 560px; margin: 0; }
.topbar .search input {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
  max-width: none;
  padding-left: calc(var(--field-pad) + 26px);
  border-right: 0;
  border-radius: var(--radius) 0 0 var(--radius);
}
.topbar .search button { flex: none; padding: 0 18px; border-radius: 0 var(--radius) var(--radius) 0; }
.topbar .search-icon {
  position: absolute;
  top: 50%;
  left: var(--field-pad);
  color: var(--c-placeholder);
  transform: translateY(-50%);
  pointer-events: none;
}

/*
  Точка доставки: справка о том, куда везут, а не базис цены карточек, — двумя строками: мелкая подпись и
  адрес с многоточием. Место в тесной строке она уступает поиску, но не ниже 120 px — «Доставка на завод»
  читается целиком — и не шире 210 px: длинный адрес завода не имеет права занимать строку (change 0045,
  change 0064, design.md → D7). Полностью адрес — в подсказке и на странице точек доставки.

  Точка открывает правую группу шапки — что покупатель набрал и куда везёт: группа прижата к правому краю
  вместе, и имя от неё не отрывается.
*/
.topbar .delivery {
  display: flex;
  flex: 0 1 auto;
  flex-direction: column;
  min-width: 120px;
  max-width: 210px;
  margin-left: auto;
  line-height: 1.3;
}
.topbar .delivery ~ .visitor { margin-left: 0; }
.delivery-label { color: var(--c-text-3); font-size: var(--fs-2xs); }
.delivery-address { overflow: hidden; font-size: var(--fs-sm); white-space: nowrap; text-overflow: ellipsis; }
/* точек нет — одна строка цветом ссылки: это приглашение завести точку, а не справка */
.topbar .delivery-add { justify-content: center; color: var(--c-link); font-size: var(--fs-sm); white-space: nowrap; }

/*
  Корзина стоит у имени посетителя кнопкой с рамкой (change 0055, требование «Шапка витрины»): значок и
  подпись. Ниже 1440 подпись скрыта глазу — на 1280 строка витрины тесна (бюджет — design.md → D7), — но
  остаётся для чтения с экрана. Корзина, когда она и есть текущая страница, выделена как текущий раздел.
*/
.topbar .cart-button { padding: 0 14px; font-weight: 500; }
.topbar .cart-button:is(.active, [aria-current="page"]) {
  border-color: var(--c-text);
  background: var(--c-subtle);
  color: var(--c-text);
  font-weight: 600;
}
@media (max-width: 1439px) {
  .topbar .cart-button { padding: 0 12px; }
  .topbar .cart-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/*
  Мега-меню: одна разметка на широкий и узкий экран (спека bff-market/catalog-menu, требование «Меню в
  разметке страницы»). Раскрытие — details/summary, без скриптов; на широком экране группы ложатся
  колонками, на узком — тем же аккордеоном в один столбец.

  Вид — панель системы (change 0064, design.md → D7, D9): белая, с рамкой и единственной тенью системы,
  скругление 4 px. Раздел уровня 1 — строка 40 px: название 15/600 и счётчик 13 px третичным цветом;
  раскрытый раздел — светлым фоном, как текущий пункт панели. Группы — колонками по 220 px: заголовок группы
  15/600, ссылки 14 px цветом текста, при наведении — цветом ссылки с чертой; «Ещё» — цветом ссылки: это
  действие, а не категория.
*/
.catalog-menu { position: relative; }
.catalog-menu > .menu-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 30;
  width: max(320px, 62vw);
  max-height: 72vh;
  overflow: auto;
  padding: 6px;
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
  box-shadow: var(--shadow-panel);
}
.menu-panel > .note { margin: 6px; }
.menu-section > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: var(--h-m);
  padding: 0 12px;
  border-radius: var(--radius-mark);
  font-weight: 600;
}
.menu-section > summary::after { margin-left: auto; color: var(--c-text-3); }
.menu-section > summary:hover,
.menu-section[open] > summary { background: var(--c-subtle); }
.menu-groups { columns: 3 220px; column-gap: 24px; padding: 12px 12px 16px 24px; }
.menu-group { break-inside: avoid; margin-bottom: 16px; }
.menu-group ul,
.menu-more ul { list-style: none; margin: 6px 0 0; padding: 0; }
.menu-group li { margin: 0; padding: 3px 0; font-size: var(--fs-sm); }
.menu-group-title { font-weight: 600; }
.menu-all { display: block; margin-bottom: 12px; font-weight: 500; }
.menu-panel a:hover { color: var(--c-link-hover); text-decoration: underline; }
.menu-count { color: var(--c-text-3); font-size: var(--fs-xs); font-weight: 400; }
.menu-deeper { margin-left: 4px; color: var(--c-text-3); }
.menu-more > summary { padding: 3px 0; color: var(--c-link); font-size: var(--fs-sm); }
.menu-more > summary::after { width: 6px; height: 6px; margin-left: 8px; }

/*
  Узкий экран: панель встаёт в поток шапки аккордеоном в один столбец, а раскрытое меню занимает строку
  шапки целиком — иначе панель сжималась бы до ширины кнопки каталога.
*/
@media (max-width: 720px) {
  .topbar .catalog-menu[open] { flex: 1 1 100%; }
  .catalog-menu > .menu-panel { position: static; width: auto; margin-top: 8px; box-shadow: none; max-height: none; }
  .menu-groups { columns: 1; }
}

/*
  Главная: строка быстрых ссылок на разделы уровня 1 и сетка карточек во всю ширину (материал
  openspec/specs/bff-market/home.md, п. 1) — пять карточек в ряд на 1280 и 1440, шесть на 1920, две на
  узком экране (change 0045).
*/
/*
  Каждый наш `nav` прижимается влево явно. Набор раскладывает голый `nav` полосой `space-between`, и это
  верно для панели навигации во всю ширину, но не для строки ссылок внутри страницы: на широком экране
  две быстрые ссылки разъезжались по разным краям, а крошки и порядок выдачи — следом за ними.
*/
/*
  Быстрые ссылки главной — разделы уровня 1 строкой 15/500 цветом текста, при наведении — цветом ссылки
  (change 0064, design.md → D9): это навигация, а не текст, и подчёркнутые оранжевые ссылки на полотне шумели.
*/
.quick-links { display: flex; flex-wrap: wrap; gap: 8px 24px; margin: 0 0 16px; font-weight: 500; }

/*
  Число колонок задают объявленные ширины, а не остаток места (change 0045, требование «Колонки сетки
  заданы точками перелома»): с auto-fill число колонок выводилось из остатка, и ни на одной ширине раскладка
  не была выверена.

  Числа «Стали» (change 0064, design.md → D8). Нижняя граница карточки — 248 px, ширина карточки на макете
  выдачи: цена одной строкой и название в две читаются целиком. Промежуток 16, фасеты 272 + 28, содержимое — окно
  минус два поля (40 от 1440, 24 ниже, 16 до 720), не больше 1680:

    ширина   без колонки      рядом с фасетами (главная и выдача)
    1920     6 × 266,7        5 × 263,2
    1440     5 × 259,2        4 × 253,0
    1280     4 × 296          3 × 300
     900     3 × 273          2 × 268
     720     2 × 336          фасеты над выдачей, 2 × 336

  Между точками раскладка тянется, но не перестраивается. Колонка фасетов объявляется по их наличию: с
  change 0079 она есть и на главной, и в каждой выдаче (блок «Производитель»), поэтому обе раскладываются
  правым столбцом таблицы — его задаёт селектор .results-body:has(> .facets), а разметка сетки одна. Левый
  столбец остался странице без колонки — главной и выдаче, на которые поиск не ответил.
  minmax(0, 1fr), а не 1fr: колонка не шире своей доли, даже если в карточке нерушимый код.
*/
.grid-cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-grid); }
@media (min-width: 900px) {
  .grid-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .results-body:has(> .facets) .grid-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1280px) {
  .grid-cards { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .results-body:has(> .facets) .grid-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1440px) {
  .grid-cards { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .results-body:has(> .facets) .grid-cards { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (min-width: 1920px) {
  .grid-cards { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .results-body:has(> .facets) .grid-cards { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}
/*
  Карточка позиции в сетке (change 0064, design.md → D9, макет buyer-catalog): белый блок без полей по краям —
  подложка фото 200 px во всю ширину, код модели белой меткой в её углу; ниже, с полями 16 и промежутком 12,
  группы: цена с базисом и сроком, название с производителем и категорией, характеристики одной строкой,
  отметка внешнего продавца и «В корзину» графитом во всю ширину — прижаты к низу, и в ряду сетки кнопки стоят
  на одной линии.
*/
.product-card {
  display: flex;
  flex-direction: column;
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
}
.grid-cards > * { min-width: 0; }
/* заглушка той же высоты, что фотография: без неё сетка разъезжается на позициях без изображения */
.card-media { position: relative; }
.product-card .thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px;
  overflow: hidden;
  background: var(--c-media);
  text-decoration: none;
}
.product-card .thumb img { max-width: 100%; max-height: 100%; object-fit: contain; }
.product-card .thumb .muted { font-size: var(--fs-xs); }
/*
  Метка кода не шире подложки: код длиннее обрезается многоточием, полностью он — на карточке позиции. Один
  нерушимый код («high-precision-nc-machine-reamers-…» legacy-каталога) не растягивает колонку сетки и не
  вылезает за край карточки (change 0045; замечание владельца 2026-09-27, задача 2.20).
*/
.product-card .card-code {
  position: absolute;
  top: 10px;
  left: 10px;
  display: block;
  max-width: calc(100% - 20px);
  padding: 3px 7px;
  overflow: hidden;
  border: 0;
  font-size: var(--fs-2xs);
  text-overflow: ellipsis;
}
.card-body { display: flex; flex: 1 1 auto; flex-direction: column; gap: 12px; padding: 16px; }
.card-body p { margin: 0; }
.product-card .card-price {
  overflow: hidden;
  font-size: var(--fs-price);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.3;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.product-card .card-price .price { font-weight: inherit; }
/*
  Цены нет — вместо неё приглашение («войдите, чтобы увидеть цену»): это подсказка, а не сумма, и кеглем
  цены оно вставало в две строки крупным серым (задача 1.12). Приглушённым мелким кеглем: в карточке сетки —
  13 px, в блоке цены карточки позиции — 14 px. Не хватило ширины — переносится своим межстрочным.
*/
.product-card .card-price > .muted { display: inline-block; font-size: var(--fs-xs); font-weight: 400; letter-spacing: 0; line-height: 1.35; white-space: normal; }
.total .sum > .muted { font-size: var(--fs-sm); font-weight: 400; }
.product-card .card-terms { margin-top: 2px; color: var(--c-text-2); font-size: var(--fs-xs); }
.card-names { display: flex; flex-direction: column; gap: 4px; }
/* название — не длиннее двух строк и всегда высотой в две: заголовки карточек ряда стоят на одной линии */
.product-card .card-title {
  display: -webkit-box;
  min-height: calc(2em * 1.35);
  overflow: hidden;
  font-weight: 600;
  line-height: 1.35;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
.product-card :is(.card-maker, .card-category) {
  overflow: hidden;
  color: var(--c-text-3);
  font-size: var(--fs-xs);
  white-space: nowrap;
  text-overflow: ellipsis;
}
/*
  Характеристики — одной строкой через запятую: единица, пробел, значение — «kg 10575, V 400, kW 66.2», как
  написал владелец (задача 2.20; прежде — табличка из трёх ячеек). Строка не переносится: не поместилась —
  многоточие, полностью имя каждой характеристики — в её подсказке, значения — на карточке позиции.
*/
.product-card .card-params {
  overflow: hidden;
  font-size: var(--fs-sm);
  font-weight: 500;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.card-foot { display: flex; flex-direction: column; gap: 12px; margin-top: auto; }
.product-card .card-seller { color: var(--c-text-2); font-size: var(--fs-2xs); }
.product-card .card-actions { margin: 0; }
.product-card .card-actions button { width: 100%; height: var(--h-m); font-size: var(--fs-sm); }
.product-card .card-choose { font-size: var(--fs-sm); font-weight: 600; }
.grid-cards .more { grid-column: 1 / -1; justify-self: center; margin-top: 8px; }

/*
  Корзина (change 0064, design.md → D9, раскладка buyer-cart-layout в цветах «Стали»): позиции и под ними
  доставка и работы — слева, итог — справа колонкой 420 px через 32; уже 1280 колонка одна. Позиции —
  таблицей в блоке: миниатюра 120 × 90, название и цена за штуку, количество, сумма 17/600 и «Убрать»;
  таблица, которой не хватило ширины, прокручивается внутри блока, а не режется его краем.
*/
.cart-layout { display: grid; grid-template-columns: minmax(0, 1fr) var(--aside-cart); gap: 32px; align-items: start; }
@media (max-width: 1279px) {
  .cart-layout { grid-template-columns: minmax(0, 1fr); }
}
.cart-main { display: flex; flex-direction: column; gap: 40px; min-width: 0; }
.cart-main > .card { margin: 0; }
.cart-lines { overflow-x: auto; }
#cart-items :is(th, td),
#cart-extras td { padding-inline: 16px; }
#cart-items tr > :first-child,
#cart-extras td:first-child { padding-left: 20px; }
#cart-items tr > :last-child,
#cart-extras td:last-child { padding-right: 20px; }
#cart-items td { vertical-align: top; }
/*
  Уменьшенное главное фото в строке корзины (change 0058): рамка постоянного размера — и под изображение, и под
  заглушку «фотографии нет», поэтому строки с фотографией и без неё одной высоты.
*/
.cart-position { display: flex; align-items: flex-start; gap: 14px; }
.cart-thumb {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 120px;
  height: 90px;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--c-media);
  font-size: var(--fs-2xs);
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
}
.cart-thumb img { max-width: 100%; max-height: 100%; object-fit: contain; }
.cart-what { display: flex; flex-direction: column; gap: 4px; min-width: 140px; }
.cart-what p { margin: 0; }
.cart-title { font-weight: 600; }
.cart-unit { color: var(--c-text-2); font-size: var(--fs-xs); }
.cart-unit .price { font-weight: 500; }
/* количество над «Обновить», одной высоты с действием строки: строка держит высоту миниатюры */
.cart-qty { display: flex; flex-direction: column; gap: 8px; width: max-content; margin: 0; }
.cart-qty .qty { height: var(--h-s); text-align: center; }
.cart-qty button { width: 100%; }
.cart-sum { font-size: var(--fs-fact); font-weight: 600; }
/* расхождение цены — строкой под позицией цветами «внимания»; линия между позицией и строкой не нужна */
#cart-items tr:has(+ .price-changed) > td { border-bottom: 0; }
#cart-items .price-changed > td { padding-top: 0; }
.price-changed [data-price-changed] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  padding: 8px 12px;
  border-radius: var(--radius);
  background: var(--c-warn-bg);
  color: var(--c-warn-ink);
  font-size: var(--fs-sm);
}
.cart-work { font-weight: 600; }
/*
  До 720 строка позиции плотнее — миниатюра 72 × 54 и сумма кеглем текста, — и таблица позиций помещается в
  ширину экрана; таблица работ узкая и растягивается на весь блок, а не встаёт по своим строкам.
*/
@media (max-width: 720px) {
  .cart-thumb { width: 72px; height: 54px; }
  .cart-what { min-width: 120px; }
  .cart-sum { font-size: var(--fs-body); }
  .cart-works table { display: table; width: 100%; }
}

/*
  Итог — белый блок секциями через линию: точка доставки (выбранная 17/600, адрес, выбор другой), сумма
  32/700 и курс, «Оформить заявку» акцентом 54 px во всю ширину и пояснение, что уйдёт в заявку.
*/
.cart-summary { border: 1px solid var(--c-border); border-radius: var(--radius); background: var(--c-surface); }
.cart-summary > section { padding: 20px 24px; border-bottom: 1px solid var(--c-line); }
.cart-summary > section:last-child { border-bottom: 0; }
.cart-summary h2 { margin: 0 0 10px; color: var(--c-text-2); font-size: var(--fs-h-narrow); }
.cart-summary p { margin: 0 0 4px; }
.cart-point-name { font-size: var(--fs-fact); font-weight: 600; }
.cart-point-choice { flex-wrap: nowrap; margin: 12px 0 0; }
.cart-point-choice select { flex: 1 1 auto; min-width: 0; max-width: none; }
.cart-total-sum { font-size: var(--fs-total); font-weight: 700; letter-spacing: -0.01em; line-height: 1.2; overflow-wrap: anywhere; }
.cart-fx { color: var(--c-text-2); font-size: var(--fs-xs); }
.cart-checkout form { margin: 0 0 12px; }
.cart-checkout button { width: 100%; height: var(--h-xl); }
.cart-checkout .muted { font-size: var(--fs-xs); }

/* ── подкатегории страницы категории: ссылки в три колонки внутри блока (design.md → D9) ── */
.tree { list-style: none; margin: 0; padding: 0; columns: 3 220px; column-gap: 24px; }
.tree li { margin: 0; padding: 4px 0; break-inside: avoid; }
.tree .muted { margin-left: 4px; }

/*
  Карточка модели: изображение слева, сводка справа (спека bff-market/catalog-pages). Нет фотографии —
  заглушка той же высоты: раскладка не должна съезжать от того, что медиа у офферинга не завели.
*/
.model-hero { display: grid; grid-template-columns: minmax(0, 1fr) var(--aside-buy); gap: 28px; align-items: start; margin: 24px 0; }
.model-side { display: flex; flex-direction: column; gap: var(--flow); min-width: 0; }
.model-hero .card { margin: 0; }
.model-image {
  height: 480px; display: flex; align-items: center; justify-content: center;
  background: var(--c-media);
  border: 1px solid var(--c-border); border-radius: var(--radius); overflow: hidden;
}
.model-image img { width: 100%; height: 100%; object-fit: contain; }

@media (max-width: 899px) {
  .model-hero { grid-template-columns: minmax(0, 1fr); }
}

/* сравнение конфигураций: подпись строки слева, по колонке на предложение */
table.compare th[scope="row"] { text-align: left; font-weight: 600; white-space: nowrap; }
table.compare td { white-space: nowrap; }

/*
  На узком экране прокручивается сама таблица сравнения, а не страница (change 0045, сценарий «Узкий
  экран»): ячейки в ней не переносятся намеренно — колонка на предложение, — и с тремя предложениями она
  шире 720 при любой вёрстке. Уезжающая страница уносит с собой и шапку, и всё остальное; уезжающая
  таблица остаётся своей бедой.
*/
@media (max-width: 720px) {
  table.compare { display: block; overflow-x: auto; }
}

/*
  Выдача витрины: фасеты колонкой слева, перечень справа (спека bff-market/catalog-pages). На узком экране
  фасеты уезжают наверх — колонка в 240 пикселей рядом с двумя карточками не помещается.

  Колонка фасетов объявляется по их наличию, а не всегда. С change 0079 она есть на каждой сложившейся
  выдаче — в ней всегда блок «Производитель», — и карточки стоят сеткой рядом. Без колонки остаётся только
  выдача, на которую индекс не ответил: перечень, оставшись единственным ребёнком, не должен вставать в
  первую колонку сетки, ту самую в 240 пикселей, — карточки выстроились бы столбиком (change 0045).
*/
.results-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; align-items: start; }
@media (min-width: 900px) {
  .results-body:has(> .facets) { grid-template-columns: var(--facets-w) minmax(0, 1fr); gap: var(--facets-gap); }
}
/*
  Фасеты — одна белая панель, фасет — её секция через линию (change 0064, design.md → D9, макет
  buyer-catalog). Значение — строка 32 px: квадрат-отметка, подпись с многоточием и число справа; длинный
  перечень прокручивается внутри секции. Квадрат рисуют стили: невыбранный — рамкой, выбранный — квадратом
  акцента с графитовой галочкой (сценарий «Выбранный фильтр отмечен»); галочка — рамками и поворотом, а не
  картинкой.
*/
.facets {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
}
.facet { padding: 16px 20px; border-bottom: 1px solid var(--c-line); }
.facet:last-child { border-bottom: 0; }
/*
  Название фасета — заголовок секции узкой колонки, 14 px системы: заголовком раздела страницы (20 px)
  «Наибольший диаметр обработки над станиной, mm» вставал в колонке в три строки (задача 1.12).
*/
.facet h2 { margin: 0 0 8px; font-size: var(--fs-h-narrow); line-height: 1.35; }
.facet-values { list-style: none; margin: 0; padding: 0; max-height: 224px; overflow: auto; }
.facet-values li { display: flex; align-items: center; gap: 10px; min-height: 32px; margin: 0; font-size: var(--fs-sm); }
.facet-values a {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  padding-left: 26px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.facet-values a::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 16px;
  height: 16px;
  margin-top: -8px;
  border: 1.5px solid var(--c-mark-off);
  border-radius: var(--radius-mark);
  background: var(--c-surface);
}
.facet-values a:hover::before { border-color: var(--c-text); }
.facet-values a.chosen::before { border-color: var(--c-accent); background: var(--c-accent); }
.facet-values a.chosen::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 5px;
  width: 6px;
  height: 10px;
  margin-top: -7px;
  border-right: 2px solid var(--c-on-accent);
  border-bottom: 2px solid var(--c-on-accent);
  transform: rotate(45deg);
}
.facet-count { flex: none; color: var(--c-text-3); font-size: var(--fs-xs); }
/* диапазон: два поля через тире и «Применить» во всю ширину — поля делят строку, а не обрезают число */
.facet-range { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 8px; margin: 0; }
.facet-range input { width: 100%; max-width: none; height: var(--h-m); padding: 0 10px; font-size: var(--fs-sm); }
.facet-range button { grid-column: 1 / -1; width: 100%; height: var(--h-m); font-size: var(--fs-sm); }

/*
  Фильтр «Производитель» по странам (change 0084, design D6): окно фиксированной высоты с прокруткой, в нём
  страны раскрытием (<details>), внутри — производители. Число стоит слева от названия. Флажки — настоящие
  поля формы: без скриптов форма уходит кнопкой, со скриптами — при отметке. Флажок производителя, отмеченного
  страной, неактивен: страна уже означает его.
*/
.maker-filter { max-height: 320px; overflow-y: auto; margin: 0 0 12px; }
.maker-country { margin: 0; border-bottom: 1px solid var(--c-line); }
.maker-country:last-child { border-bottom: 0; }
.maker-country > summary { display: flex; align-items: center; gap: 8px; min-height: 32px; cursor: pointer; font-size: var(--fs-sm); }
.maker-country > ul { list-style: none; margin: 0 0 8px; padding: 0 0 0 22px; }
.maker-country li { display: flex; align-items: center; min-height: 30px; margin: 0; font-size: var(--fs-sm); }
.maker-filter label { display: flex; align-items: center; gap: 8px; min-width: 0; margin: 0; cursor: pointer; }
.maker-filter input[type=checkbox] { flex: none; width: 16px; height: 16px; margin: 0; accent-color: var(--c-text); }
.maker-filter .facet-count { min-width: 2ch; text-align: right; }
.maker-name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.maker-filter-form button { width: 100%; height: var(--h-m); font-size: var(--fs-sm); }

/* область поиска — переключатель системы; пояснение под ним не шире строки, которую читают целиком */
.scopes { margin: 0 0 16px; }
p.note#narrow-hint { max-width: 70ch; }

.results-main { min-width: 0; }

/*
  Строка над выдачей: слева выбранный отбор метками системы (.chip) и «Сбросить всё», справа порядок
  переключателем системы (.segments). «Сбросить всё» стоит на полотне — цветом ссылки на полотне (D3: цвет
  ссылки даёт там 4,3:1). Промежуток до выдачи — 20, как на макете.
*/
.results-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 20px; }
.chosen-filters { display: flex; flex: 1 1 auto; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.chosen-filters .reset-filters { color: var(--c-link-hover); font-size: var(--fs-sm); font-weight: 500; }
.results-bar .sort { margin-left: auto; }

/*
  До 900 фасеты стоят над выдачей: секции панели ложатся в две колонки, а не столбцом во всю высоту, — на
  720 секция 344 px, и поле диапазона держит пять знаков с дробью. Линия — над секцией; у верхнего ряда её
  прячет край панели.

  Секция, оставшаяся в ряду одна, занимает всю строку (change 0079): на главной и в выдаче без фасетов
  характеристик в панели один блок «Производитель», и в половине панели он оставлял вторую половину пустой.
  То же с последней секцией при нечётном числе: пустой половины в панели нет.
*/
@media (max-width: 899px) {
  .facets { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); overflow: hidden; }
  .facet,
  .facet:last-child { margin-top: -1px; border-top: 1px solid var(--c-line); border-bottom: 0; }
  .facet:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/*
  Карточка позиции (change 0064, design.md → D9, макет buyer-product). Над заголовком — код модели меткой,
  под ним — производитель 16 px вторичным. Ниже два ряда колонок «содержимое | блок покупки 440 px» через 28:
  галерея и покупка, характеристики и модель; другие предложения — во всю ширину. Колонки держатся от 900:
  владелец смотрит на ~1000, и при одной колонке блок покупки с «В корзину» уходил под галерею, за первый экран
  (задача 1.16; прежде одна колонка — уже 1024). Уже 900 колонка одна.
*/
.product-head { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.product-head h1 { margin: 0; }
.product-head .product-maker { margin: 0; color: var(--c-text-2); font-size: var(--fs-h3); }
.product-head .product-maker:empty { display: none; }
.product-top,
.product-rows { display: grid; grid-template-columns: minmax(0, 1fr) var(--aside-buy); gap: 28px; align-items: start; }
.product-top { margin: 28px 0 var(--flow); }
.product-rows { margin: 40px 0 0; }
.product-rows > * { margin: 0; }
.product-offers { margin-top: 40px; }
@media (max-width: 899px) {
  .product-top,
  .product-rows { grid-template-columns: minmax(0, 1fr); }
}

/*
  Галерея (change 0058): крупная подложка 480 px и полоса миниатюр 88 × 66, текущая — графитовой рамкой;
  «N из M» — меткой в правом нижнем углу, когда фотографий несколько. Нет фотографии — слова на той же
  подложке: раскладка не съезжает.
*/
.product-gallery .gallery-main {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 480px;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--c-media);
}
.product-gallery .gallery-main img { max-width: 100%; max-height: 100%; object-fit: contain; }
.product-gallery .gallery-main #no-photo { margin: 0; color: var(--c-text-2); }
.gallery-count { position: absolute; right: 14px; bottom: 14px; border: 0; color: var(--c-text); }
.gallery-strip { display: flex; flex-wrap: wrap; gap: 10px; list-style: none; margin: 12px 0 0; padding: 0; }
.gallery-strip li { margin: 0; }
.gallery-strip a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 88px;
  height: 66px;
  overflow: hidden;
  border: 2px solid transparent;
  border-radius: var(--radius);
  background: var(--c-media);
}
.gallery-strip a:hover { border-color: var(--c-border); }
.gallery-strip a[aria-current="true"] { border-color: var(--c-text); }
.gallery-strip img { width: auto; max-width: 100%; max-height: 100%; object-fit: contain; }
@media (max-width: 720px) {
  .product-gallery .gallery-main { height: 360px; }
}

/*
  Блок покупки: цена 42/700 и базис под ней; факты сеткой 2 × 2 через линии — срок и условия в первой строке,
  продавец во всю вторую; одной строкой поле количества и справа от него графитовая «В корзину» — высотой поля
  системы (решение владельца 2026-09-27, задача 2.20: не акцент и не 54 px, главного действия у карточки позиции
  нет, D5), — и пояснение, что доставку и монтаж посчитает корзина. Приглашение вместо цены — 14 px: это
  подсказка, а не сумма.
*/
.buy-box { display: flex; flex-direction: column; border: 1px solid var(--c-border); border-radius: var(--radius); background: var(--c-surface); }
.buy-price { padding: 24px 24px 20px; }
.buy-price p { margin: 0; }
.buy-sum { font-size: var(--fs-price-buy); font-weight: 700; letter-spacing: -0.02em; line-height: 1.1; overflow-wrap: anywhere; }
.buy-sum .price { font-weight: inherit; white-space: normal; }
.buy-sum:has(> .muted) { font-size: var(--fs-sm); font-weight: 400; letter-spacing: 0; line-height: var(--lh-body); }
.buy-price .buy-basis { margin-top: 8px; color: var(--c-text-2); font-size: var(--fs-sm); }
.buy-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 0; border-top: 1px solid var(--c-line); }
.buy-facts > div { min-width: 0; padding: 14px 24px; border-bottom: 1px solid var(--c-line); }
.buy-facts > div:first-child:not(.wide) { border-right: 1px solid var(--c-line); }
.buy-facts > .wide { grid-column: 1 / -1; }
.buy-facts dt { color: var(--c-text-3); font-size: var(--fs-2xs); }
.buy-facts dd { margin: 2px 0 0; font-size: var(--fs-fact); font-weight: 600; }
.buy-facts .seller-mark::before { width: 7px; height: 7px; }
.buy-do { display: flex; flex-direction: column; gap: 14px; padding: 20px 24px 24px; }
.buy-do > * { margin: 0; }
.buy-actions { display: flex; flex-wrap: nowrap; align-items: center; gap: 12px; margin: 0; }
.buy-actions .qty { flex: none; width: 72px; font-weight: 600; text-align: center; }
.buy-actions button { flex: 1 1 auto; height: var(--h-field); }

/* блок модели справа от характеристик: абзац и переход контуром */
.product-model h2 { margin-bottom: 8px; }
.product-model p { color: var(--c-text-soft); }

/*
  Заявки и запросы площадке (change 0064, design.md → D9): перечни — таблицами в блоке, номер моноширинным,
  состояние меткой; карточка заявки — состояние меткой первой строкой, факты строками, позиции таблицей с итогом
  под ней, решение покупателя — «Принять» акцентом и «Отказаться» с причиной.
*/
/* блок заявки подменяется целиком; следующий за ним блок документов не прилипает к нему */
#request { margin: 0 0 var(--flow); }
.request-state-head { margin: 0 0 8px; }
#request-state .props { margin-top: 16px; }
#request-point p { margin: 0; }
.card.flush > .total { justify-content: flex-end; border-top: 1px solid var(--c-line); }
.decline input { flex: 1 1 260px; max-width: var(--field-max); }

/* документ строкой: метка формата файла, имя ссылкой и вид документа под ним (как на макете buyer-product) */
.doc { display: flex; align-items: center; gap: 12px; }
.doc-format {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: var(--radius);
  background: var(--c-subtle);
  color: var(--c-link);
  font-size: var(--fs-unit);
  font-weight: 700;
}
.doc-text { display: flex; flex-direction: column; min-width: 0; }
.doc-text a { font-weight: 500; }
.model-documents { list-style: none; }
.model-documents > .doc { min-height: 56px; margin: 0; padding: 8px 0; border-bottom: 1px solid var(--c-line); }
.model-documents > .doc:last-child { border-bottom: 0; }
.model-documents .doc-format { width: auto; min-width: 34px; padding: 0 4px; }
.doc-kind { color: var(--c-text-3); font-size: var(--fs-xs); }

/*
  Формы покупателя — запрос площадке, точка доставки — по образцу формы цены и условий продавца (change 0064,
  design.md → D9): раскладка — части системы .form-page, .form-sections, .field-row (задача 1.16), своих правил
  у витрины нет. Своё — поле ИНН при привязке юрлица: короткое, рядом с «Найти».
*/
.inn-search input { flex: 0 1 280px; }

/*
  Вход по номеру (change 0064, design.md → D9): колонка 440 px, поле 44 px, кнопка шага во всю колонку.
  Сообщение о том, почему шаг не прошёл, — пояснением цветами «внимания»; код заглушки SMS — обычным пояснением.
*/
.signin { max-width: 440px; }
.signin form button { width: 100%; }
.signin .note.note-amber { background: var(--c-warn-bg); color: var(--c-warn-ink); }
/* ссылка в колонке стоит на полотне — цветом ссылки на полотне (D3: цвет ссылки даёт там 4,3:1) */
.signin > p a:where(:not([role="button"])) { color: var(--c-link-hover); }
