/* Стили шапки и подвала сайта для журнала. Собрано конвейером переноса. */
:root{
  /* Нейтральные. Сняты с himsostav.ru: #1b1b1b чернила, #fbfbfb полотно, #f0f0f0 подложка */
  --gray-0:#FFFFFF;
  --gray-25:#FBFBFB;
  --gray-50:#F0F0F0;
  --gray-100:#E4E4E4;
  --gray-200:#D2D2D2;
  --gray-300:#B6B6B6;
  --gray-400:#8F8F8F;
  --gray-500:#6B6B6B;
  --gray-600:#4A4A4A;
  --gray-700:#333333;
  --gray-800:#252525;
  --gray-900:#1B1B1B;
  --gray-950:#000000;

  /* Бренд. Красный знака-молекулы: #cf313b основной, #e12332 подсветка */
  --red-50:#FBECEE;
  --red-100:#F6D3D6;
  --red-200:#EDA6AC;
  --red-300:#E4767F;
  --red-400:#E8464F;
  --red-500:#CF313B;
  --red-600:#B0272F;
  --red-700:#8C1F26;
  --red-800:#63161B;

  /* Бренд, вторичный. Тёмная бирюза с сайта: #102d39 и #225f78 */
  --teal-50:#EAF0F3;
  --teal-100:#CDDCE3;
  --teal-200:#9BB9C6;
  --teal-300:#5E8EA1;
  --teal-400:#2F6F8A;
  --teal-500:#225F78;
  --teal-600:#1A4A5E;
  --teal-700:#153A4A;
  --teal-800:#102D39;

  /* Тёплые нейтральные с сайта: подложки отзывов и сертификатов */
  --sand-50:#F2F0EC;
  --sand-200:#C9C5BE;
  --sand-500:#8A8580;
  --sand-700:#4A4744;

  /* Журнальный слой. Сняты с постера «1.4 Плашка» - обложка «Журнала огнезащиты».
     Отдельная палитра для печатных и редакционных материалов, не для интерфейсов. */
  --paper-500:#E0D6C8;   /* бумага: основной фон обложки */
  --paper-300:#EDE7DD;   /* бумага светлее: подложки внутри */
  --paper-700:#C7BCAB;   /* бумага темнее: заливки блоков */
  --paper-rule:#ACA69A;  /* линейки и диагональная штриховка */
  --paper-ink:#121411;   /* чернила: марка и заголовки, темнее интерфейсных */
  --paper-muted:#69695D;  /* служебный текст: надрубрики, подписи, футер */
  --paper-red:#D21D27;   /* плашка. Плотнее интерфейсного --red-500 */
  --paper-green:#006D3F;  /* контурный статус «СВОБОДНО» */

  /* Шкала предела огнестойкости. Семь ступеней: R 15 / 30 / 45 / 60 / 90 / 120 / 150,
     диапазон заявлен на himsostav.ru. Бирюза - красный. Использовать дискретно. */
  --rating-1:#225F78;
  --rating-2:#2F6F8A;
  --rating-3:#5E8EA1;
  --rating-4:#8A8580;
  --rating-5:#E4767F;
  --rating-6:#CF313B;
  --rating-7:#8C1F26;

  /* Служебные статусы */
  --green-500:#1E7A4B;
  --green-50:#E8F4ED;
  --amber-500:#C87A00;
  --amber-600:#8A5500;
  --amber-50:#FBF1DE;
  --danger-500:#CF313B;
  --danger-50:#FBECEE;
  --blue-500:#225F78;
  --blue-50:#EAF0F3;
}

:root{--font-poster:'Onder','Arial Black',system-ui,sans-serif;--font-poster-text:'Gros Ventre','Helvetica Neue',system-ui,sans-serif;--font-poster-mono:'mononoki',ui-monospace,Menlo,monospace}
/* Состояния :hover, вынесенные из атрибутов style-hover выложенной версии.
   Файл собирается автоматически — правки сюда вносить бессмысленно. */
@media (hover:hover){
.hv1:hover{color:var(--paper-red-text) !important;border-bottom:2px solid var(--paper-red) !important}
.hv2:hover{background:var(--paper-ink) !important;border:1px solid var(--paper-500) !important;color:var(--paper-500) !important}
.hv3:hover{background:var(--paper-bg) !important;border:1px solid var(--paper-500) !important;color:var(--paper-text) !important}
.hv4:hover{color:var(--paper-red-text) !important}
.hv5:hover{background:var(--paper-ink) !important;box-shadow:inset 0 0 0 1px var(--paper-500) !important}
.hv6:hover{background:var(--paper-red) !important;border:1px solid var(--paper-red) !important;color:var(--paper-300) !important}
.hv7:hover{background:var(--paper-red) !important}
.hv8:hover{background:var(--paper-ink) !important;color:var(--paper-500) !important}
.hv9:hover{background:var(--paper-bg) !important;color:var(--paper-text) !important}
.hv10:hover{background:var(--paper-ink) !important;color:var(--paper-300) !important}
.hv11:hover{border:1px solid var(--paper-text) !important}
.hv12:hover{background:var(--paper-bg2) !important}
.hv13:hover{background:var(--paper-bg2) !important;color:var(--paper-text) !important}
.hv14:hover{border:1px solid var(--paper-500) !important}
.hv15:hover{border:1px solid var(--paper-text) !important;color:var(--paper-text) !important}
.hv16:hover{background:var(--paper-ink) !important}
.hv17:hover{background:var(--paper-bg2) !important;border:1px solid var(--paper-text) !important}
.hv18:hover{border:1px solid var(--paper-text) !important;background:var(--paper-bg) !important}
.hv19:hover{border:1px solid var(--paper-500) !important;background:var(--paper-bg) !important;color:var(--paper-text) !important}
.hv20:hover{border:1px solid var(--paper-500) !important;color:var(--paper-500) !important}
}

/* ============================================================
   МЕХАНИКА ПЕРЕНОСА
   Правила, заменяющие то, что в выложенной версии делал javascript:
   масштаб страницы, выбор между десктопной и мобильной вёрсткой,
   выпадающие панели меню. Ничего оформительского здесь нет.
   ============================================================ */

/* Масштаб страницы — единица везде.

   В исходнике обработчик изменения окна ужимал страницу до 0,9 на обычном
   десктопе (и оставлял единицу на узких и на очень широких экранах). Отсюда
   расхождение между заданными в вёрстке величинами и тем, что видно на
   экране: кегли, отступы и поля читались на девять процентов мельче
   написанного, а поля страницы вместо 63 px давали 57. Снято 15.09 по
   просьбе заказчика — вёрстка показывается в своём размере.

   Переменные оставлены: на них ссылается обёртка страницы, собранная
   конвейером. Вернуть прежнее поведение — вернуть сюда 0.9. */
:root { --zoom: 1; --minh: 100vh; }

/* ── Тёмная тема ──────────────────────────────────────────

   Весь сайт покрашен восемью токенами `--paper-*`, и роли у них парные:
   где `--paper-ink` фон, там текст `--paper-500` или `--paper-300`, и
   наоборот. Поэтому тёмная тема — это не отдельный набор правил, а другие
   значения тех же восьми переменных: шапка и подвал светлеют, полотно
   темнеет, и контраст сохраняется в обе стороны сам собой.

   Красный на тёмном взят светлее плашечного: на чернильном фоне #D21D27
   гаснет, а по нему ещё идёт тёмный текст кнопок. */
:root {
  /* Полотно и краска по нему. Разведены по ролям сборкой — см. комментарий
     в `build.mjs`. В светлой теме значения те же, что были у макета. */
  --paper-bg: #E0D6C8;        /* основное полотно */
  --paper-bg2: #EDE7DD;       /* подложки внутри */
  --paper-bg3: #C7BCAB;       /* заливки блоков */
  --paper-text: #121411;      /* заголовки и текст по полотну */
  --paper-red-text: #D21D27;  /* красным по полотну */
}

:root[data-theme='dark'] {
  --paper-bg: #15170F;
  --paper-bg2: #1C1F19;
  --paper-bg3: #262A23;
  --paper-text: #ECE7DD;
  --paper-rule: #3A3F36;
  --paper-muted: #9C9A8E;
  /* Красным по тёмному — фирменная подсветка #E12332 (она названа в палитре
     рядом с основным #CF313B). Осветлять сильнее нельзя: краска уходит
     в розовый и перестаёт быть красным марки. */
  --paper-red-text: #E12332;
  /* Шкала пределов огнестойкости красится интерфейсными серыми: активная
     подпись — `--gray-900`, остальные — `--gray-500`. На тёмном полотне
     они обе тонули, поэтому переворачиваем и их. */
  --gray-900: #ECE7DD;
  --gray-500: #9C9A8E;
}

/* Базовые краски — те же роли, что и у инлайновых стилей.

   `site-base.css` — дословная копия стилей выложенной версии, и трогать её
   нельзя: в ней вся адаптивная логика, и любая правка разойдётся с
   оригиналом при следующем переносе. Поэтому три её правила переопределяем
   здесь — файл подключается следом.

   Без этого на тёмной теме проваливалась половина страниц: текст и ссылки
   наследовали чернильный цвет от `body`, и на тёмном полотне их не было
   видно вовсе — например, весь перечень на карте сайта. */
body { background: var(--paper-bg2); color: var(--paper-text); }
a { color: var(--paper-text); }
a:hover { color: var(--paper-red-text); }

/* Знаки заказчиков на тёмной теме — светлым оттиском, без подложки.

   Сначала знак клали на бумажную плашку: цвета сохранялись, но полоса
   доверия превращалась в четырнадцать белых прямоугольников на чернилах.
   Подложку сняли по просьбе заказчика.

   Без неё знаки, нарисованные чёрным по прозрачному (Kerama Marazzi, РЖД,
   ГУОВ, «Инсистемс»), на чернильном полотне пропадали. Поэтому знак
   печатается в один тон: `grayscale(1)` снимает цвет, `invert(1)`
   переворачивает светлоту — тёмный оттиск становится светлым. Это не
   перекраска в другой цвет (её как раз даёт инверсия без обесцвечивания:
   синяя «Роснефть» уходила в оранжевый, красный РЖД — в бирюзу), а
   одноцветная печать, ровно та, какой знаки ставят на тёмной стороне бланка.
   Прозрачный фон при этом остаётся прозрачным.

   Обесцвечивание сохраняет полутона, и гербы — ГУОВ, Минобороны,
   «Спецстрой» — остаются с рисунком: плоский силуэт (`brightness(0)`)
   слепил бы их в кляксу. Небольшая добавка яркости вытягивает те из них,
   что в оригинале нарисованы серым. */
:root[data-theme='dark'] [data-logo-zakazchika] {
  filter: grayscale(1) invert(1) brightness(1.2);
  opacity: 0.92;
  transition: opacity 260ms cubic-bezier(.2, 0, .2, 1);
}

:root[data-theme='dark'] [data-client-card]:hover [data-logo-zakazchika] { opacity: 1; }

/* Полоса доверия: восемь знаков в ряд, как в макете.

   Ненадолго было шесть - при восьми колонках знак получал 130 px, и это
   казалось мелким. После того как у файлов срезали прозрачные поля, знак
   занимает плитку целиком, и восьми колонок хватает: тринадцать знаков
   ложатся в два ряда (8 + 5) вместо трёх. Плитка приглашения снята вместе
   с записью в данных (см. `data.mjs`). */

/* Колонки выпадающего меню стоят встык, и правую сдвигаем на пиксель влево:
   иначе на стыке встречаются рамки двух пунктов и дают двойную линию - ровно
   то, что между пунктами по вертикали уже схлопнуто. */
.submenu [style*="grid-template-columns:repeat(2"] > div + div { margin-left: -1px; }

/* Первая строка заголовка первого экрана переносится по мягкому переносу.

   Заголовок набран в одну строку (`white-space:nowrap`), поэтому на узком
   экране длинное слово из него выходило за край - в макете для этого лежала
   вторая, заранее разбитая версия. Она же давала дубль слова в тексте `h1`,
   поэтому осталась одна строка, а перенос делает браузер: `normal` разрешает
   разрыв, `manual` - только в местах мягкого переноса, а не где придётся. */
@media (max-width: 640px) {
  /* Макет на этой ширине прятал цельную версию и показывал разбитую -
     ту самую, что снята из разметки. Без этого правила первое слово
     заголовка на телефоне пропадало вовсе: «огнезащита без грунта без
     финиша» вместо «антикоррозионная огнезащита…». */
  h1 [data-hero-full] { display: block !important; white-space: normal; hyphens: manual; }
}

/* Знак марки занимает ровно половину строки шапки — за вычетом промежутка
   между ним и меню. Тогда первый пункт меню («Продукция») встаёт на середину
   строки: на ту же вертикаль, что левый край кадра в развороте под шапкой.

   Только на широком экране: на узком знак делит строку с кнопкой «Меню»,
   и половина ему там ни к чему.

   Половина — желаемая ширина, а не жёсткая. Меню с кнопками справа
   помещается в оставшуюся половину только с ~1540 px, а на обычных
   ноутбуках (1280, 1366, 1440) правый край шапки уезжал за экран: красной
   кнопки звонка не было видно совсем или торчала полоска. Теперь при
   нехватке места ужимается знак (до своей естественной ширины), а меню
   не сжимается никогда. На широком экране выравнивание по середине
   прежнее. */
@media (min-width: 1025px) {
  header [data-znak] { flex: 0 1 calc(50% - clamp(16px, 3vw, 48px)); }
  header nav { flex-shrink: 0; }
}

/* Две ветки вёрстки — десктопная и мобильная. В исходнике рисовалась одна,
   по ширине окна. Статическая страница несёт обе, и лишнюю убирает
   медиазапрос по той же границе 1024px.

   `display:contents` обязателен: обёртка не должна участвовать в раскладке,
   иначе флексы шапки разъедутся — там `nav` прижат к правому краю
   через `margin-left:auto`, и лишний слой это ломает. */
[data-only] { display: contents; }
@media (max-width: 1024px) { [data-only='desktop'] { display: none; } }
@media (min-width: 1025px) { [data-only='mobile'], [data-only='menuOpen'] { display: none; } }

/* Выпадающая панель меню. Открывается наведением на пункт и фокусом внутри
   панели — с клавиатуры тоже. Скрипт лишь ставит атрибут `data-open`;
   без него панели просто не видны, а ссылки в них остаются в разметке
   и в индексе. */
.submenu {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  opacity: 0;
  visibility: hidden;
  transition: opacity 140ms ease;
}
.submenu[data-open] { opacity: 1; visibility: visible; }
@media (max-width: 1024px) { .submenu { display: none; } }

/* Мобильное меню собрано в разметке раскрытым — иначе его содержимого
   в статике не было бы вовсе. Закрыто по умолчанию, открывает скрипт. */
[data-only='menuOpen'] { display: none; }
@media (max-width: 1024px) {
  [data-only='menuOpen'][data-open] { display: contents; }
}

/* Свёрнутое содержимое: ответы на вопросы, раскрывающиеся строки и карточки.
   Разметка лежит всегда — так текст попадает в индекс, — а видимость даёт
   атрибут `data-open`, который ставит скрипт. Без скрипта блок остаётся
   свёрнутым, но текст на странице есть. */
/* Раскрытие плавное: обёртка — сетка, строка которой растёт с нуля до высоты
   содержимого. Высоту заранее знать не нужно — в отличие от `max-height`, где
   пришлось бы задавать потолок наугад и на длинных ответах получать рывок.
   Лишнее срезается по строке, поэтому тело завёрнуто в один блок (`data-telo`).

   `visibility` меняется вместе с раскрытием: свёрнутый текст остаётся в
   разметке (ради поиска), но читалке экрана и клавиатуре не достаётся —
   иначе Tab уводил бы фокус в невидимое. */
[data-only='row.open'],
[data-only='p.open'],
[data-only='q.open'],
[data-only='f.open'] {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
  transition: grid-template-rows 280ms cubic-bezier(.2, 0, .2, 1), visibility 280ms;
}
[data-only='row.open'] > [data-telo],
[data-only='p.open'] > [data-telo],
[data-only='q.open'] > [data-telo],
[data-only='f.open'] > [data-telo] { overflow: hidden; min-height: 0; }
[data-only='row.open'][data-open],
[data-only='p.open'][data-open],
[data-only='q.open'][data-open],
[data-only='f.open'][data-open] { grid-template-rows: 1fr; visibility: visible; }

/* Кому движение мешает — раскрываем сразу. */
@media (prefers-reduced-motion: reduce) {
  [data-only='row.open'],
  [data-only='p.open'],
  [data-only='q.open'],
  [data-only='f.open'] { transition: none; }
}

/* Ссылки не подчёркиваются.

   В базовых стилях дизайн-системы у `a` стоит нижняя граница цветом ссылки
   (`base.css`), и она рисуется всегда, а не при наведении. В выложенной
   версии это было незаметно: переходы делались кликаемыми `div`, и правило
   их не касалось. Как только переходы стали настоящими ссылками, под каждой
   появилась тонкая красная черта — в шапке, в подвале, в карточках. В макете
   её нет, поэтому снимаем. Там, где подчёркивание задумано (ссылка на
   политику под формами), оно задано в разметке отдельным свойством
   `text-decoration` и не страдает. */
a { border-bottom: 0; }

/* Служебные накладки: плашка cookie и кнопка «Наверх». Показывает скрипт —
   плашка только тем, кто ещё не ответил, кнопка только после прокрутки. */
[data-only='cookieShown'],
[data-only='showTop'] { display: none; }
[data-only='cookieShown'][data-open],
[data-only='showTop'][data-open] { display: contents; }

/* Пункт меню, ставший кнопкой для клавиатуры, должен показывать фокус. */
[data-menu]:focus-visible,
[data-action]:focus-visible { outline: 2px solid var(--paper-red); outline-offset: 2px; }

/* Модальные окна и просмотр документа. В разметке лежат всегда — так их
   содержимое остаётся в исходном коде страницы, — показывает скрипт. */
[data-modal],
[data-lightbox] { display: none; }
[data-modal][data-open],
[data-lightbox][data-open] { display: block; }

/* ── Место под кадр, пока кадр не пришёл ───────────────────────────────

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

   Слот со снимком рисует мягкое мерцание подложки, а сам снимок остаётся
   непрозрачным и лежит поверх неё: когда файл дошёл, `perenos.js` ставит
   `data-gotov`, мерцание гаснет за треть секунды, и кадр проступает сквозь
   уходящую подложку. Гасить при этом сам снимок нельзя: страница с картинкой
   на `opacity: 0` пуста для всего, что смотрит на неё без выполнения
   скриптов, — для превью ссылки, для поискового робота, для читателя,
   у которого скрипт не отработал. */
[data-mesto-kadra]::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--paper-bg2);
  animation: kadrMercanie 1.6s ease-in-out infinite;
  transition: opacity 320ms ease;
  pointer-events: none;
}
[data-mesto-kadra][data-gotov]::before { opacity: 0; animation: none; }

@keyframes kadrMercanie {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 0.85; }
}

/* Кому движение мешает — тем ровная подложка, гаснущая без мерцания. */
@media (prefers-reduced-motion: reduce) {
  [data-mesto-kadra]::before { animation: none; transition: none; }
}

/* ── Инфографика раздела объектов ──────────────────────────────────────

   Четыре панели: шкала требуемых пределов, поставка на квадратный метр,
   след партии и порядок работ. По умолчанию одна колонка — так раздел
   читается на телефоне сверху вниз, в порядке рассуждения.

   С 900 px композиция раскрывается: полоса пределов и лента работ идут во
   всю ширину, потому что обе устроены как горизонтальная шкала и в половине
   ширины теряют разрешение; расход и след партии встают рядом — они короткие
   и сравниваются глазом. Четыре одинаковых плитки эту разницу бы стёрли. */
[data-info-setka] { grid-template-columns: minmax(0, 1fr); }

@media (min-width: 900px) {
  [data-info-setka] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  [data-info-setka] [data-panel='predel'],
  [data-info-setka] [data-panel='grafik'] { grid-column: 1 / -1; }
}

/* На узком экране семь подписей шкалы не помещаются: оставляем края и две
   верхние ступени — те, вокруг которых стоит весь раздел. */
@media (max-width: 480px) {
  [data-shkala-podpisi] [data-shkala-podpis='1'],
  [data-shkala-podpisi] [data-shkala-podpis='2'],
  [data-shkala-podpisi] [data-shkala-podpis='3'] { visibility: hidden; }
}

/* ── Путь от ТЗ до нанесения: лента процесса вместо четырёх полос ───────

   В макете четыре шага лежали строками во всю ширину, и каждая строка
   держала квадратный кадр высотой почти в треть экрана: раздел из четырёх
   коротких абзацев занимал полторы тысячи пикселей и не помещался в экран
   целиком. Прочесть его как последовательность было нельзя — шаги не видны
   одновременно, а именно это в нём главное.

   Теперь шаг устроен одинаково на любой ширине: квадрат со знаком в углу,
   под ним ось с номером, заголовком и описанием. Меняется только число
   колонок — четыре на десктопе, две на планшете, одна на телефоне. Рамка
   и подложка сняты: четыре обведённые плитки читались бы как четыре
   отдельные карточки, а это один процесс, и ось держит его непрерывным.

   Правила идут с `!important`, потому что перебивают инлайновые стили
   макета и его же мобильные переопределения из `site-base.css`. */
[data-steps-grid] {
  grid-template-columns: minmax(0, 1fr) !important;
  gap: clamp(22px, 2.4vw, 36px) !important;
}

[data-step-card] {
  display: grid !important;
  grid-template-columns: minmax(0, 1fr) !important;
  /* Знак, номер с осью, текст. Последняя строка забирает остаток высоты:
     карточки в ряду тянутся до высоты самой длинной, и при трёх `auto`
     излишек уходил бы в строку знака — он оставался бы прежним, а ось
     и текст под ним съезжали в каждой колонке по-своему. */
  grid-template-rows: auto auto 1fr !important;
  align-items: start !important;
  gap: clamp(12px, 1.2vw, 18px) 0 !important;
  padding: 0 !important;
  border: 0 !important;
  background: transparent !important;
  aspect-ratio: auto !important;
  min-height: 0 !important;
  transition: none !important;
}

/* Порядок в карточке: номер, ось, знак, текст.

   Сначала знак стоял над номером, но читалось это задом наперёд: карточка
   начиналась с картинки, а чем является шаг — узнавалось строкой ниже.
   Номер поднят наверх (правка 17.09), знак ушёл под ось. Ось при этом
   осталась на месте: линия принадлежит теперь полосе знака и по-прежнему
   идёт во всю ширину карточки, а знак сидит под ней квадратом 54 px.

   Раньше здесь стоял кадр 16:9 во всю ширину, и четыре снимка подряд
   съедали первый экран блока: карточка показывала фотографию раньше, чем
   говорила, о каком шаге речь. */
[data-step-img] {
  display: block !important;
  position: static !important;
  grid-column: 1 !important;
  grid-row: 2 !important;
  width: 100% !important;
  aspect-ratio: auto !important;
  border: 0 !important;
  border-top: 2px solid var(--paper-text) !important;
  padding-top: clamp(12px, 1.2vw, 18px) !important;
  transition: border-color 260ms cubic-bezier(.2, 0, .2, 1) !important;
}

[data-step-znak] {
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(44px, 3.4vw, 54px);
  aspect-ratio: 1 / 1;
  border: 1px solid var(--paper-rule);
  color: var(--paper-text);
  transition: border-color 260ms cubic-bezier(.2, 0, .2, 1);
}

[data-step-znak] svg {
  display: block;
  width: 54%;
  height: 54%;
}

/* Номер — первой строкой карточки, над осью и знаком. */
[data-step-n] {
  grid-column: 1 !important;
  grid-row: 1 !important;
  padding: 0 !important;
  border-top: 0 !important;
  font-size: clamp(15px, 1.15vw, 19px) !important;
  line-height: 1 !important;
}

[data-step-body] {
  grid-column: 1 !important;
  grid-row: 3 !important;
  padding-top: 0 !important;
  border-top: 0 !important;
  gap: clamp(6px, 0.7vw, 10px) !important;
}

[data-step-t] { font-size: clamp(15px, 1.15vw, 19px) !important; line-height: 1.15 !important; }

/* Описание выключено по формату — по обоим краям колонки, как в макете.
   В узкой колонке выключка без переносов рвала бы строку пробелами,
   поэтому включены автоматические переносы: страница помечена `lang="ru"`,
   и словарь переносов у браузера свой. */
[data-step-body] > span:last-child {
  text-align: justify !important;
  hyphens: auto !important;
  -webkit-hyphens: auto !important;
}

/* Заголовки шагов занимают от двух до трёх строк, и описания под ними
   начинались на разной высоте — четыре шага рядом читались как сбитый ряд.
   Держим место под три строки: описания встают на одну линию во всех
   колонках. На телефоне шаги идут друг под другом, и выравнивать нечего. */
@media (min-width: 641px) {
  [data-step-t] { min-height: calc(3 * 1.15em) !important; }
}

/* Наведение подсвечивает ось шага и рамку знака. */
[data-step-card]:hover [data-step-img] { border-top-color: var(--paper-red-text) !important; }
[data-step-card]:hover [data-step-znak] { border-color: var(--paper-red-text) !important; }

/* Кнопка под лентой шагов: в макете она прижата к сетке отступом в 2 px и
   выглядела продолжением последней строки текста. Отбиваем её от ленты —
   это отдельное действие, а не часть четвёртого шага. */
[data-steps-cta] { margin-top: clamp(28px, 3.2vw, 48px) !important; }

@media (min-width: 1025px) {
  [data-steps-grid] { grid-template-columns: repeat(4, minmax(0, 1fr)) !important; }
}

@media (min-width: 641px) and (max-width: 1024px) {
  [data-steps-grid] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
}

/* Лента порядка работ: на узком экране доля интервала уже своей подписи,
   и «интервал» вылезал за свою полосу. Штриховка читается паузой и без
   слова — оставляем подписи только у рабочих окон. */
@media (max-width: 640px) {
  [data-panel='grafik'] [data-lenta-podpis='pauza'] { visibility: hidden; }
}

/* Третий шаг в макете был залит красным во всю полосу: «производим и
   отгружаем» — момент, где обещание становится материалом, и макет его
   выделял. В ленте заливка не работает: колонка без полей прижимает текст
   к краю красного поля, а светлая краска, которую макет ставил поверх
   заливки, на бумаге исчезла бы. Акцент переезжает на ось — красная линия
   и красный номер там, где у остальных шагов чернила. */
[data-step-card]:nth-child(3),
[data-step-card]:nth-child(3):hover {
  background: transparent !important;
  border-color: transparent !important;
}
[data-step-card]:nth-child(3) span { color: var(--paper-text) !important; }
[data-step-card]:nth-child(3) [data-step-n] {
  color: var(--paper-red-text) !important;
  border-top-color: var(--paper-red-text) !important;
}
[data-step-card]:nth-child(3) [data-step-body] { border-top-color: var(--paper-red-text) !important; }

/* Номера остальных шагов держат ось чернилами: четыре красные засечки
   подряд стёрли бы акцент третьего. */
[data-step-card]:not(:nth-child(3)) [data-step-n] { color: var(--paper-text) !important; }

/* На чернилах приглушённые ступени шкалы тонут: холодные цвета ступеней
   рассчитаны на бумагу. Поднимаем их, сохраняя разницу с двумя верхними —
   теми, вокруг которых стоит весь раздел. */
:root[data-theme='dark'] { --stupen-tusklo: 0.62; }

/* Диаграмма пределов: на узком экране имя объекта и поле шкалы не помещаются
   рядом — поле уходит под имя, оставаясь той же семиступенчатой сеткой. */
@media (max-width: 720px) {
  [data-ryad-shkaly] { grid-template-columns: minmax(0, 1fr) !important; gap: 8px !important; }
}

/* ── Текст карточки объекта: журнальная полоса ─────────────────────────

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

   `break-inside: avoid` на блоках задан в разметке: без него подзаголовок
   уезжает в одну колонку, а его абзац в следующую. */
[data-kase-kolonki] {
  column-count: 1;
  column-gap: clamp(20px, 2.2vw, 36px);
}

@media (min-width: 640px) {
  [data-kase-kolonki] { column-count: 2; }
}

@media (min-width: 1000px) {
  [data-kase-kolonki] { column-count: 3; }
}

/* Четыре колонки - только там, где колонка остаётся шире сорока знаков.
   Ниже этой ширины строка рвётся так часто, что текст перестаёт читаться
   абзацем и превращается в столбик обрывков. */
@media (min-width: 1280px) {
  [data-kase-kolonki] { column-count: 4; }
}

/* Правило колонок: тонкая линейка вместо пустого промежутка — та же
   графика, что делит разделы страницы. */
@media (min-width: 640px) {
  [data-kase-kolonki] { column-rule: 1px solid var(--paper-rule); }
}

/* Сводка параметров объекта — строкой под текстом.

   Внутри колонок плашки вставали в случайные места: то в начало колонки,
   то в разрыв абзаца, и три цифры одного объекта оказывались на разной
   высоте. Здесь они выровнены между собой и читаются как сводка: предел,
   площадь, объём. На узком экране складываются в столбик. */
[data-kase-parametry] {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: 2px;
  margin-top: clamp(14px, 1.6vw, 22px);
  padding-top: clamp(18px, 2vw, 28px);
  border-top: 2px solid var(--paper-rule);
}

/* Раздел отзывов набирается той же полосой, что карточки объектов, но в две
   колонки: пунктов разбора там два. Четыре колонки оставили бы половину
   строки пустой. */
@media (min-width: 640px) {
  [data-kase-kolonki='2'] { column-count: 2 !important; }
}

/* О компании: текст и шаги выпуска — один разворот в две колонки.
   На узком экране колонки складываются, шаги идут под текстом. */
[data-o-kompanii-setka] { grid-template-columns: minmax(0, 1fr); }

@media (min-width: 900px) {
  [data-o-kompanii-setka] { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); }
}

/* Реквизиты: таблица и кнопка рядом, на узком — друг под другом. */
[data-rekvizity-setka] { grid-template-columns: minmax(0, 1fr); }

@media (min-width: 900px) {
  [data-rekvizity-setka] { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); }
}

/* Каталог: разбор линейки в три колонки — по числу пунктов разбора. */
@media (min-width: 1000px) {
  [data-kase-kolonki='3'] { column-count: 3 !important; }
}

/* Призыв на странице услуги: заголовок и кнопка рядом, на узком — столбиком. */
[data-prizyv-setka] { grid-template-columns: minmax(0, 1fr); }

@media (min-width: 900px) {
  [data-prizyv-setka] { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); }
}

/* ── «Почему мы»: кладка в одной раме ──────────────────────────────────

   Шесть кирпичей лежали свободно: два во всю ширину, третий и шестой
   сдвинуты к середине. Смещение — приём макета, оно даёт кладке ритм, но
   без общего контура крайние карточки читались как выпавшие из ряда, а под
   нижним кирпичом оставалась пустая полоса высотой с целую карточку.

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

   Поля в 2 px повторяют зазор между карточками: рамка рамы и рамки
   кирпичей не сливаются в двойную линию. */
[data-why-grid] {
  border: 1px solid var(--paper-muted);
  padding: 2px;
}

[data-why-card]:nth-child(7) { grid-column: 1 / -1 !important; }

/* ── «4 задачи в 1 составе»: кадр посередине разворота ─────────────────

   В макете четыре карточки стояли плотным квадратом слева, а всю правую
   половину занимало место под кадр с плашкой гарантии под ним. Задачи
   читались как таблица сбоку от картинки, хотя главный смысл блока в том,
   что все четыре решает один состав.

   Теперь кадр стоит между ними: 01 и 03 слева, 02 и 04 справа, снимок
   нанесения посередине. `display: contents` у сетки карточек нужен, чтобы
   карточки стали прямыми детьми разворота и их можно было развести по
   колонкам; сама сетка в макете остаётся - она держит стаггер появления.

   На узком экране всё складывается обратно в столбец: карточки парами,
   кадр под ними (`order`), иначе средняя колонка сжимается до полосы. */
@media (min-width: 1025px) {
  [data-sol-wrap] {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr) minmax(0, 1fr) !important;
    align-items: stretch !important;
  }

  [data-sol-grid] { display: contents !important; }

  /* Пары читаются сверху вниз по колонке: 01 и 02 слева, 03 и 04 справа.
     По рядам («01 слева — 02 справа») взгляд перескакивал через кадр
     и терял порядок. */
  [data-sol-card]:nth-child(1) { grid-column: 1; grid-row: 1; }
  [data-sol-card]:nth-child(2) { grid-column: 1; grid-row: 2; }
  [data-sol-card]:nth-child(3) { grid-column: 3; grid-row: 1; }
  [data-sol-card]:nth-child(4) { grid-column: 3; grid-row: 2; }

  /* Колонка кадра — второй ребёнок разворота после сетки карточек.
     Кадр квадратный: в кадре банки, и вытянутая по вертикали рамка
     срезала им края. */
  [data-sol-wrap] > div:last-child { grid-column: 2; grid-row: 1 / span 2; aspect-ratio: 1 / 1; }
  [data-sol-wrap] > div:last-child > div:first-child { flex: 1 1 auto; min-height: 0; }
}

/* Номер держится верха карточки, слово и пояснение — низа: между ними
   пустое поле, по которому карточка и читается как плитка, а не как
   абзац. */
[data-sol-card] { justify-content: flex-start !important; }
[data-sol-card] > span:first-child { margin-bottom: auto; }

/* Кадр квадратный на любой ширине: на узком экране колонка кадра лежала
   под карточками полосой в 120 px, и в ней от снимка оставалась середина. */
[data-sol-wrap] > div:last-child { aspect-ratio: 1 / 1; }

/* На планшете и телефоне макет держал карточку задачи строго квадратной
   и прятал всё, что не помещается (`overflow: hidden`). С появлением
   пояснения в карточке это срезало бы текст — высоту отдаём содержимому. */
@media (max-width: 1024px) {
  [data-sol-card] {
    aspect-ratio: auto !important;
    min-height: 0 !important;
    overflow: visible !important;
  }

  /* Мобильные правила макета уменьшали слово задачи, целясь в него как
     в последний `span` карточки. С появлением пояснения последним стал он,
     и слово осталось в 20 px — «огнезащита» вылезала за рамку плитки.
     Возвращаем кегль слову по его настоящему месту, второму. */
  [data-sol-card] > span:nth-child(2) {
    font-size: clamp(14px, 3.6vw, 18px) !important;
    line-height: 1.06 !important;
    overflow-wrap: anywhere !important;
  }

  /* Пояснению `anywhere` не нужен: он рвал «атмосферостойкость» посреди
     слога. Обычные правила переноса плюс словарь языка. Селектор длинный
     нарочно: у мобильного правила макета (`[data-sol-card] span:last-child`)
     специфичность выше, и коротким его не перебить. */
  [data-sol-card] span[data-sol-x]:last-child {
    font-size: clamp(12px, 3.2vw, 14px) !important;
    line-height: 1.45 !important;
    overflow-wrap: normal !important;
    hyphens: auto !important;
    -webkit-hyphens: auto !important;
  }
}

/* Крупная строка кирпича набирается Onder с отрицательной разрядкой, и в
   колонке шириной 260 px она спотыкалась дважды: «влагостойкость» рвалось
   посреди слога («ВЛАГОСТОЙКОС/ТЬ»), а пробел в «атмосферостойкого слоя»
   съедался разрядкой — два слова читались как одно.

   Переносы по слогам берут на себя первый случай (разрыв уходит на
   стык морфем), просвет между словами — второй. */
[data-why-big] {
  hyphens: auto;
  -webkit-hyphens: auto;
  word-spacing: 0.12em;
}

/* ── Кадр объекта в блоке «проекты СПЕКТР» ─────────────────────────────

   В макете у кадра задана только минимальная высота, а колонка тянется по
   соседней — с названием объекта, таблицей параметров и абзацем. На широком
   экране это давало полосу 2,4:1: от снимка площадки оставалась средняя
   лента, где не читается ни масштаб объекта, ни конструкции.

   Ставим 16:9 — ту же пропорцию, что у плиток видов конструкций, карточек
   объектов и зон применения. Логика прежняя: рамку задаёт кадр, а не соседний
   текст. Было 4:3; приведено к общему виду 20.09, когда 16:9 стало основной
   пропорцией снимков на сайте. */
[data-proj-kadr] {
  aspect-ratio: 16 / 9;
  min-height: 0 !important;
  align-self: start;
}

/* Короткие подписи кнопок листания («Пред», «След») лежат в разметке
   рядом с полными и показываются только на телефоне. */
[data-korotkaya] { display: none; }

/* Мобильная версия строки «Поехали» лежит в разметке рядом с десктопной
   и по умолчанию скрыта — показывает её медиазапрос ниже. */
[data-go-word-mob] { display: none; }

/* ══ Мобильная вёрстка: правки 17.09 ═══════════════════════════════════

   Десктопная раскладка заморожена — всё ниже действует только на телефоне
   (≤ 640 px). Правила идут с `!important`, потому что перебивают мобильные
   переопределения макета из `site-base.css`. */

@media (max-width: 640px) {
  /* Задачи состава — в одну колонку: в двух карточка шириной 185 px
     держала по два слова в строке, и пояснение рассыпалось на обрывки. */
  [data-sol-grid] { grid-template-columns: minmax(0, 1fr) !important; }

  /* Кладка «почему мы»: крайние кирпичи во всю ширину — первый открывает
     блок, последний его закрывает, и обоим сдвиг не нужен. Влагостойкость
     уходит вправо: без неё в середине шли три кирпича подряд по левому
     краю, и кладка теряла переплёт. */
  [data-why-card]:nth-child(1),
  [data-why-card]:nth-child(7) { width: 100% !important; margin-left: 0 !important; }

  [data-why-card]:nth-child(4) { margin-left: auto !important; }

  /* Полоса заказчиков: три колонки, считая от ширины экрана. У макета
     здесь `1fr 1fr 1fr` без `minmax(0, …)`, и знаки шириной 149 px не
     давали сетке сжаться — полоса вылезала за правый край страницы. */
  [data-clients-grid] { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }

  /* Плитке знака макет задаёт на телефоне минимальную высоту в 84 px, а
     пропорция 16:9 пересчитывает её в ширину 149 px — шире колонки, и
     плитки наезжали друг на друга, вылезая за правый край. Минимум
     снимаем, пропорцию берём ближе к квадрату: при ширине колонки 122 px
     это даёт 92 px высоты, знаку хватает. */
  [data-client-card] {
    min-height: 0 !important;
    aspect-ratio: 4 / 3 !important;
    padding: 8px 10px !important;
  }

  /* Строка действий в меню не должна заезжать под кнопку «Наверх»:
     она фиксирована в правом нижнем углу и перекрывала бы её край. */
  [data-menu-deystviya] { padding-right: 76px !important; }

  /* Слово «Поехали» — во всю ширину поля: на телефоне оно единственное
     на экране и работает вывеской, поля по краям ему не нужны. */
  [data-go-word-desk] { display: none; }
  [data-go-word-mob] { display: block; }

  /* ── Шапка раздела: две строки вместо одной ──────────────────────────

     В макете шапка — одна строка: название раздела, линейка на весь
     остаток, справа счётчик и подсказка листания. На телефоне это не
     помещалось: подсказка переносилась под название и рвала линейку.

     Делаем сетку: первая строка — название и линейка (тот же рисунок, что
     у разделов без правых меток), вторая — метки. Если метка одна, она
     занимает обе колонки и читается подзаголовком; если их две, счётчик
     слева, подсказка справа. */
  [data-nadrubrika] {
    display: grid !important;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: 8px 12px !important;
  }

  [data-nadrubrika] > :nth-child(1) { grid-column: 1; grid-row: 1; }
  [data-nadrubrika] > :nth-child(2) { grid-column: 2; grid-row: 1; }
  [data-nadrubrika] > :nth-child(3) { grid-row: 2; }
  [data-nadrubrika] > :nth-child(3):last-child {
    grid-column: 1 / -1;
    justify-self: start;
    margin-left: 0 !important;
    white-space: normal;
  }
  [data-nadrubrika] > :nth-child(3):not(:last-child) { grid-column: 1; }
  [data-nadrubrika] > :nth-child(4) { grid-column: 2; grid-row: 2; justify-self: end; }

  /* ── Номер раздела: префиксом, а не плашкой ──────────────────────────

     `PosterHeading` ставит номер кеглем 26 px слева от заголовка. На
     телефоне из-за этого заголовок жался в остаток строки и рассыпался
     на три строки по два слова. Номер уменьшается до кегля служебной
     метки, встаёт в строку с линейкой, заголовок идёт под ним. */
  [data-ph] > div > div:first-child {
    display: grid !important;
    /* Колонка номера фиксированная: при `auto` заголовок, растянутый на обе
       колонки, распирал её своей минимальной шириной — номер уезжал вправо,
       а заголовок вставал рядом с ним, а не под ним. */
    grid-template-columns: 3.4em minmax(0, 1fr);
    align-items: center;
    gap: 10px 10px !important;
  }

  [data-ph-num] {
    grid-area: 1 / 1;
    font-size: 11px !important;
    letter-spacing: 0.18em !important;
  }

  /* Линейка после номера — тем же приёмом, что у шапок разделов. */
  [data-ph] > div > div:first-child::after {
    content: '';
    grid-area: 1 / 2;
    height: 1px;
    background: var(--paper-rule);
  }

  [data-ph] h2 {
    grid-area: 2 / 1 / 3 / 3;
    min-width: 0;
    font-size: 20px !important;
    line-height: 1.08 !important;
  }

  /* Правая метка `PosterHeading` (если она есть) — следующей строкой. */
  [data-ph] > div > div:first-child > span[style*='margin-left:auto'] {
    grid-area: 3 / 1 / 4 / 3;
    margin-left: 0 !important;
  }

  /* Длинные слова в заголовках («металлоконструкций», «влагостойкость»)
     на узкой колонке рвались посреди слога: в макете стоит
     `overflow-wrap: break-word`, а он делит слово где придётся и без
     дефиса. Включаем словарные переносы — у страницы `lang="ru"`. */
  h1, h2, h3, [data-step-t], [data-why-big], [data-sol-card] > span:nth-child(2) {
    hyphens: auto;
    -webkit-hyphens: auto;
  }

  /* ── Кнопки услуги: одна строка ──────────────────────────────────────

     Было три строки подряд: «Заказать проект» во всю ширину, под ней две
     кнопки листания по половине. Подписи сокращаются до «Пред» и «След»,
     и весь ряд собирается в одну строку — как у карточки состава. */
  [data-serv-btns] {
    flex-wrap: nowrap !important;
    gap: 2px !important;
  }

  [data-serv-btns] > button:first-child,
  [data-serv-btns] > a:first-child {
    flex: 1 1 auto !important;
    padding: 0 12px !important;
  }

  [data-serv-btns] > button:not(:first-child),
  [data-serv-btns] > a:not(:first-child) {
    flex: 0 0 72px !important;
    padding: 0 !important;
    font-size: 10px !important;
    letter-spacing: 0.08em !important;
  }

  [data-serv-btns] [data-dlinnaya] { display: none !important; }
  [data-serv-btns] [data-korotkaya] { display: inline !important; }

  /* ── Кнопки карточки состава ─────────────────────────────────────────

     Мобильные правила макета целились в `button`, а первая кнопка после
     переноса стала ссылкой (`a` с адресом окна заявки) — и правило её не
     доставало: красная кнопка занимала половину строки, рядом жалась
     «Запросить расчёт». Целимся по месту в ряду, а не по тегу.

     Первая — во всю ширину, под ней строкой: расчёт и стрелки листания.
     Кегли в этой строке выравниваем: у «Запросить расчёт» он был 11 px,
     у стрелок 9 px, и строка выглядела собранной из разных кнопок. */
  [data-item-btns] > :first-child {
    flex: 1 0 100% !important;
    display: flex !important;
    align-items: center;
    justify-content: center;
  }

  [data-item-btns] > :nth-child(2) {
    flex: 1 1 auto !important;
    font-size: 10px !important;
    letter-spacing: 0.08em !important;
  }

  [data-item-btns] > [data-item-nav] {
    font-size: 10px !important;
    letter-spacing: 0.08em !important;
    display: flex !important;
    align-items: center;
    justify-content: center;
  }

  /* Запрос документов по составу: четыре плитки квадратом 2 × 2.
     В одну колонку они занимали экран целиком, хотя в каждой по два
     слова и ссылка «запросить». */
  [data-tp-docs] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }

  [data-tp-docs] > * {
    aspect-ratio: 1 / 1;
    min-height: 0 !important;
    gap: 10px !important;
    padding: 14px !important;
  }

  [data-tp-docs] > * > span:first-child { font-size: 14px !important; line-height: 1.25 !important; }

  /* ── Заголовки в блоках, собранных конвейером ────────────────────────

     Журнальные полосы (карточки объектов, каталог, документы, услуги),
     разворот «о компании», реквизиты и призыв набраны теми же кеглями,
     что и на десктопе: `clamp` упирается в нижнюю границу, а она мерялась
     под колонку в 300 px, не под телефон. Сбавляем: заголовок раздела —
     19 px, подзаголовок пункта — 16 px. */
  [data-polosa] h2,
  [data-kase-tekst] h2,
  [data-o-kompanii] h2,
  [data-prizyv-setka] h2,
  [data-uslugi-razdely] h2 { font-size: 19px !important; line-height: 1.06 !important; }

  [data-polosa] h3,
  [data-kase-tekst] h3,
  [data-o-kompanii] h3,
  [data-uslugi-razdely] h3 { font-size: 16px !important; line-height: 1.16 !important; }

  /* Разделы внутри раскрытого документа — ещё мельче: это подзаголовки
     внутри сплошного текста, а не заголовки блоков. */
  [data-polosa] [data-telo] h3 { font-size: 14px !important; letter-spacing: 0.02em !important; }
}

/* ── Слайдеры на телефоне: индикатор, категории, письма ────────────────

   Всё, что ниже, ставит и переключает скрипт (`perenos.js`); на широком
   экране этих узлов либо нет, либо они скрыты. */

[data-indikator] { display: none; }

@media (max-width: 640px) {
  /* Полоски под слайдером: одна на позицию, текущая красная. Без них на
     телефоне в окне ровно одна карточка, и не видно ни того, что есть
     следующая, ни сколько их всего. */
  [data-indikator] {
    display: flex;
    gap: 6px;
    margin-top: 16px;
  }

  [data-indikator] > span {
    flex: 1 1 auto;
    max-width: 56px;
    height: 3px;
    background: var(--paper-rule);
    transition: background 200ms cubic-bezier(.2, 0, .2, 1);
  }

  [data-indikator] > span[data-tek] { background: var(--paper-red-text); }

  /* ── Кнопки в баннерах расчёта ───────────────────────────────────────

     В строку они не помещались: «заказать расчёт объекта» занимала 233 px
     из 372, звонку и трубке оставалась половина строки, и ряд разъезжался
     на две неровные строки. Собираем: сверху звонок с трубкой, под ними
     расчёт во всю ширину.

     Расчёт берёт чернильную заливку вместо бумажной: на красном поле две
     светлые кнопки подряд читались как одна плашка, а чернила отделяют
     главное действие от второстепенного. */
  [data-ryad-knopok] {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 2px !important;
    width: 100%;
  }

  [data-ryad-knopok] > :nth-child(1) {
    order: 2;
    flex: 1 0 100% !important;
    justify-content: center;
    background: var(--paper-text) !important;
    border-color: var(--paper-text) !important;
    color: var(--paper-bg) !important;
  }

  [data-ryad-knopok] > :nth-child(2) {
    order: 1;
    flex: 1 1 auto !important;
    justify-content: center;
  }

  [data-ryad-knopok] > :nth-child(3) {
    order: 1;
    flex: 0 0 58px !important;
    justify-content: center;
    padding: 0 !important;
  }

  /* Кадр объекта — над заголовком. В макете он стоит второй колонкой
     разворота, и на телефоне уезжал под таблицу параметров: карточка
     начиналась строкой «объект 01» и названием, а сам объект показывался
     в конце, после всех цифр. */
  [data-proj-kadr] { order: -1; }

  /* ── Ленты, которые не листались вовсе ───────────────────────────────

     Карточки объектов и проектов лежат в блоке с `overflow: hidden`, а
     двигал их в макете `transform: translateX(…)` — состояние React.
     В статике состояния нет: прокрутки у ленты не было (`scrollLeft` не
     менялся), карточки просто обрезались краем блока, и палец ничего не
     листал. Возвращаем ленте собственную прокрутку и снимаем сдвиг. */
  [data-obj-lane] { overflow: visible !important; }

  [data-obj-grid],
  [data-proj-lane] {
    overflow-x: auto !important;
    touch-action: pan-x pan-y !important;
    transform: none !important;
    scrollbar-width: none;
  }

  [data-obj-grid]::-webkit-scrollbar,
  [data-proj-lane]::-webkit-scrollbar { display: none; }

  [data-obj-grid] > * { flex: 0 0 100% !important; }

  /* У полосы проектов карточки лежат ещё глубже — в треке, который двигал
     `translateX`. Трек растворяем (`display: contents`): карточки
     становятся прямыми детьми полосы, и она наконец получает ширину по
     содержимому, а не по экрану. */
  [data-proj-lane] {
    display: flex !important;
    align-items: stretch;
  }

  [data-proj-lane] > div {
    display: contents !important;
    transform: none !important;
  }

  [data-proj-lane] > div > * {
    flex: 0 0 100% !important;
    scroll-snap-align: start;
  }

  /* Полоса, у которой появился индикатор, листается по карточке: без
     привязки палец останавливал её посередине, и в окне оказывались
     половинки соседних карточек — именно это читалось как «не свайпается». */
  [data-s-indikatorom] {
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
  }

  [data-s-indikatorom] > * { scroll-snap-align: start; }

  /* Кнопка, за которой сложены типы объектов. Рисунок тот же, что у
     раскрытий видов конструкций: строка с подписью и знаком «+». */
  [data-cats-knopka] {
    width: 100%;
    min-height: 50px;
    padding: 0 18px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    border: 1px solid var(--paper-text);
    background: var(--paper-text);
    color: var(--paper-bg);
    font-family: var(--font-poster-mono);
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    text-align: left;
  }

  [data-cats-knopka]::after {
    content: '+';
    font-size: 16px;
    line-height: 1;
  }

  [data-cats-knopka][aria-expanded='true']::after { content: '−'; }

  [data-obj-cats][data-akkordeon] { display: none !important; }

  [data-obj-cats][data-akkordeon][data-otkryt] {
    display: flex !important;
    flex-wrap: wrap !important;
    overflow: visible !important;
    margin-top: 2px;
  }

  /* Раскрытый список — в одну колонку: в двух «промышленные» и «военные»
     стояли по половине строки, и счётчик рядом с названием не помещался. */
  [data-obj-cats][data-akkordeon][data-otkryt] > * { flex: 1 1 100% !important; }

  /* Бланк письма — по кнопке. На телефоне он занимал больше экрана, и до
     текста отзыва приходилось прокручивать пять раз. */
  [data-skan][data-s-knopkoy] > div:first-child { display: none !important; }

  [data-skan][data-s-knopkoy][data-pismo-otkryto] > div:first-child { display: block !important; }

  [data-pismo-knopka] {
    margin-top: 12px;
    width: 100%;
    height: 46px;
    border: 1px solid var(--paper-text);
    background: transparent;
    color: var(--paper-text);
    font-family: var(--font-poster-mono);
    font-size: 10px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
  }
}


/* ── Правки узких экранов — 21.09 ──────────────────────────────────────

   Всё ниже переопределяет файл дизайн-системы: он подключается раньше,
   поэтому здесь хватает той же специфичности. */

/* Портрет Гагарина и флаг — 4:3, как на широком экране.

   В дизайн-системе кадру «поехали» задано `flex:1` и `min-height:360px`:
   он растягивался по высоте колонки и на телефоне выходил вытянутым
   портретом вместо кадра 4:3, под который снимок и готовили. */
@media (max-width: 1024px) {
  [data-go-img] > div {
    aspect-ratio: 4 / 3 !important;
    flex: none !important;
    min-height: 0 !important;
  }
}

/* Флаг на телефоне — под заголовком «российский производитель», до карточек.

   В дизайн-системе он спрятан на всех узких экранах (`display:none`).
   Возвращаем только на телефоне и поднимаем первым в сетке: в разметке
   кадр лежит после карточек, а по смыслу должен идти сразу за заголовком.
   На планшете оставляем скрытым — там карточки и так занимают две колонки. */
@media (max-width: 640px) {
  [data-why-img] {
    display: block !important;
    order: -1;
    aspect-ratio: 4 / 3;
    min-height: 0 !important;
    margin-bottom: 18px;
  }
}

/* Плитка вида конструкций: кадр выше текста и целиком.

   Было: кадр стоял под описанием и кнопкой, высотой 110 px с обрезкой
   по `cover` — от рендера оставалась средняя полоса. Ставим 16:9 и
   `contain`: снимки ровно 16:9, так что вписывание ничего не срежет,
   а на случай другого исходника обрезки всё равно не будет. */
@media (max-width: 640px) {
  [data-type-img] {
    order: -1;
    aspect-ratio: 16 / 9 !important;
    height: auto !important;
  }

  [data-type-img] img {
    object-fit: contain !important;
  }
}

/* Зоны применения: карточка во всю ширину окна.

   В дизайн-системе правило написано как `[data-zones-grid] > div`, а
   карточки зон — ссылки `<a>`: селектор не совпадал никогда, и карточки
   сжимались по содержимому. Отсюда обрезанные заголовки вроде
   «огнезащита оцинкованных». Прилипание при листании там уже задано,
   индикатор навешивает `perenos.js` — полоса добавлена в его список. */
@media (max-width: 640px) {
  [data-zones-grid] > a {
    flex: 0 0 100% !important;
    scroll-snap-align: start;
  }
}

/* ── Полоса тары «пробной партии» ──────────────────────────────────────

   Место рассчитано под кадр целиком, без обрезки, поэтому его пропорция
   подгоняется под пропорцию снимка, а не наоборот.

   На настольном экране стоит широкий кадр с пятью вёдрами, 3200×1037 —
   это 3.085:1, а не 32:9, как было задано в макете. Задаём точное
   отношение сторон исходника: тогда `contain` ничего не оставляет пустым
   и ничего не режет.

   На телефоне и планшете тот же кадр выродился бы в полоску высотой
   чуть больше сотни точек, поэтому там второй снимок — три ведра, 16:9 —
   и место 4:3, как просил заказчик. Разница по высоте уходит в поля
   сверху и снизу: это лучше, чем срезать крайние вёдра.

   `min-height` снимаем: в разметке у места стоит 200 px, и на узких
   экранах высота упиралась бы в него, ломая пропорцию. */

[data-trial-img] {
  aspect-ratio: 3200 / 1037 !important;
  min-height: 0 !important;
}

[data-trial-uzkiy] { display: none; }
[data-trial-shirokiy] { display: block; }

@media (max-width: 1024px) {
  [data-trial-img] {
    aspect-ratio: 4 / 3 !important;
  }

  [data-trial-shirokiy] { display: none; }
  [data-trial-uzkiy] { display: block; }
}

/* ── Тара линейки: карточка товара и страница вида конструкций ─────────

   Оба места в макете были «резиновыми»: они тянулись по высоте соседней
   колонки, потому что под штриховку сойдёт любая высота. Под снимок —
   нет. Кадры тары 1920×1080, и место приводится к их пропорции, а не
   наоборот: иначе `contain` оставил бы широкие пустые поля сверху и
   снизу, а `cover` срезал бы ведру крышку или дно.

   Плитку каталога тоже приходится придерживать. Пропорция 1:1 у неё
   в разметке уже стоит и совпадает с кадром, но плитка — ячейка сетки
   с `align-items:stretch`, и высота ползёт по самой длинной колонке
   строки: замер дал 402, 333 и 317 точек у соседних плиток при одной
   и той же ширине 317. Ведро от этого меняло размер от плитки к плитке.

   `min-height` и `height` снимаем обязательно. В разметке у карточки
   товара стоит `height:100%;min-height:540px`, у правого блока вида —
   `flex:1 1 auto` с минимумом до 320 px; и то и другое пересилило бы
   `aspect-ratio` и вернуло растянутое место.

   Одного этого мало. Место в карточке товара — ячейка сетки с
   `align-items:stretch`, и `height:auto` там разворачивается в высоту
   соседней колонки: замер показал 635×540 вместо 635×357. Поэтому
   `align-self:start` — она же прижимает кадр к верху, как у остальных
   мест на сайте. У правого блока вида та же история в терминах флексбокса,
   её снимает `flex:none`. */

[data-cat-img] {
  align-self: start;
}

[data-item-img] {
  align-self: start;
  height: auto !important;
  min-height: 0 !important;
  /* `!important` не для красоты: в дизайн-системе на планшете и телефоне
     у этого места задан квадрат — он был рассчитан на кадр 1:1. Кадр тары
     широкий, и в квадрате `contain` оставлял бы полторы сотни точек пустоты
     под ведром. Порядок (`order:-1`, кадр выше описания) из системы
     оставляем: он верный. */
  aspect-ratio: 16 / 9 !important;
}

/* Плашка «толщина за один проход» уходит под кадр.

   В макете она стояла над штриховкой — над пустым местом что угодно
   выглядит подписью сверху. Теперь сверху снимок тары, и плашка читается
   как подпись к нему, а не как заголовок пустоты. Дизайн-система ровно это
   и делает на планшете с телефоном (`column-reverse` в её медиазапросах) —
   распространяем на широкий экран, чтобы порядок был один на всех ширинах.

   `!important` обязателен: направление колонки задано в самой разметке
   инлайном (`style="display:flex;flex-direction:column"`), а инлайн
   сильнее любого правила из файла. */
[data-tp-prodside] {
  flex-direction: column-reverse !important;
}

/* Сама плашка — красная.

   Чернильная она была потому, что закрывала собой верх пустой колонки:
   тёмный прямоугольник над штриховкой держал угол. Теперь угол держит
   снимок, а плашка стала подписью под ним — и красная подпись у главного
   числа страницы работает так же, как красная плашка на обложке.

   Текст на красном по всему сайту один и тот же — `--paper-300`; чернила
   и служебный серый на `#D21D27` не читаются. Надрубрике оставляем
   приглушение прозрачностью, иначе она спорит с числом.

   Целимся в первый элемент по разметке, а не по виду: `column-reverse`
   переставляет их только на экране, в дереве плашка по-прежнему первая. */
[data-tp-prodside] > div:first-child:not([data-mesto-kadra]) {
  background: var(--paper-red) !important;
}

[data-tp-prodside] > div:first-child:not([data-mesto-kadra]) span {
  color: var(--paper-300) !important;
}

[data-tp-prodside] > div:first-child:not([data-mesto-kadra]) span:first-child {
  opacity: 0.72;
}

[data-tp-prodside] > [data-mesto-kadra] {
  flex: none !important;
  min-height: 0 !important;
  aspect-ratio: 16 / 9;
}

/* ── Карточка объекта как ссылка ───────────────────────────────────────

   На странице вида конструкций три карточки объектов, и до 21.09 ни одна
   не открывалась: снимок, название, заказчик, объём — и тупик. Теперь
   карточка целиком ведёт на страницу объекта (`kartochkiObjektov()`
   в сборщике), и наведение должно это показывать — иначе ссылка есть,
   а выглядит как справка.

   Рамка карточки задана в разметке инлайном, поэтому перекрашиваем
   только цвет рамки и добавляем сдвиг: цвет говорит «сюда можно»,
   сдвиг подтверждает нажатием. Обводку фокуса не трогаем — она общая
   по сайту и уже красная.

   `text-decoration` снят в самой разметке: подчёркивать карточку целиком
   незачем, подчёркивание тут ничего не разметило бы. */

[data-obj-ssylka] {
  transition: border-color 160ms ease, transform 160ms ease;
}

[data-obj-ssylka]:hover {
  border-color: var(--paper-text) !important;
  transform: translateY(-2px);
}

@media (prefers-reduced-motion: reduce) {
  [data-obj-ssylka] { transition: none }
  [data-obj-ssylka]:hover { transform: none }
}

/* ── Полоса первого экрана ─────────────────────────────────────────────

   Два кадра на одно место, как у полосы пробной партии: широкий 3200×900
   (32:9) для настольного экрана и узкий 1600×900 (16:9) для планшета
   с телефоном. Сюжет у них разный — семь предметов против трёх, — потому
   что семь на телефоне слились бы в чёрную полоску.

   Пропорцию места переключать не нужно: 32:9 задано в разметке, а 16:9
   на узких экранах ставит сама дизайн-система. Здесь остаётся только
   решить, какой из двух кадров показывать; порог тот же, что у пробной
   партии, — 1024. */

[data-hero-uzkiy] { display: none; }
[data-hero-shirokiy] { display: block; }

@media (max-width: 1024px) {
  [data-hero-shirokiy] { display: none; }
  [data-hero-uzkiy] { display: block; }
}

/* ── Кадр в первом экране услуги и на странице 404 ─────────────────────

   Пропорция у места своя на каждой странице и стоит прямо в разметке:
   16:9 на `/404`, 4:3 на `/proekt` и `/shefmontaj`. Но место — ячейка
   сетки с растяжкой, и она тянет его по высоте соседней колонки: замер
   на 404 дал 635×402 вместо 635×357. Под штриховку это было безразлично,
   под снимок — нет.

   Лечится тем же, чем плитка каталога и первый экран карточки товара:
   `align-self:start`. Заодно кадр встаёт по верху колонки, как везде. */

[data-serv-img] {
  align-self: start;
}

/* Кадр 404 остаётся 16:9 и на узком экране.

   Общее правило дизайн-системы переводит место услуги в 4:3 — оно писано
   под кадр услуги, тот вертикальнее. Кадр 404 широкий, и в 4:3 под ним
   висело бы полсотни пустых точек. Метку `data-serv-shirokiy` ставит
   сборщик и только на этой странице. */

@media (max-width: 1024px) {
  [data-serv-shirokiy] {
    aspect-ratio: 16 / 9 !important;
  }
}

/* «Спасибо» (06.10): ряд соцсетей с логотипами + «На главную», ниже —
   блок Дзена во всю ширину. Наведение — своё: классы hvN пересобираются
   конвейером и на разных страницах значат разное. */
[data-spasibo-set]:hover { background: var(--paper-ink) !important; color: var(--paper-300) !important; }
[data-spasibo-domoy]:hover { background: var(--paper-red) !important; color: #fff !important; }
[data-spasibo-dzen-glavnaya]:hover { background: var(--paper-ink) !important; }

/* На компьютере блок соцсетей прижат к низу колонки — по нижнему краю
   кадра слева. Отступ от текста держит padding: margin занят под auto. */
@media (min-width: 1025px) {
  [data-spasibo-soc] { margin-top: auto !important; padding-top: clamp(22px, 2.4vw, 34px); }
  /* Кадр — на всю высоту ряда: когда текст выше 16:9, низ кадра всё
     равно совпадает с низом кнопок. Не ниже 16:9 его держит ::after
     (::before занят мерцанием подложки), снимок обрезается по cover. */
  [data-spasibo-kadr] { align-self: stretch !important; aspect-ratio: auto !important; }
  [data-spasibo-kadr]::after { content: ''; display: block; padding-top: 56.25%; }
  [data-spasibo-kadr] img { object-fit: cover !important; }
}

/* Телефон: соцсети — квадратами-логотипами в один ряд поровну, подпись
   прячется (в строку с подписями они не помещаются); «На главную» и
   кнопки Дзена — во всю ширину. */
@media (max-width: 640px) {
  [data-spasibo-knopki] > [data-spasibo-set] { flex: 1 1 0; padding: 0; }
  [data-spasibo-nadpis] { display: none; }
  [data-spasibo-knopki] > [data-spasibo-domoy],
  [data-spasibo-dzen-knopki] > a { flex: 1 1 100%; }
}

/* Якорь реквизитов на «Информации» (`#dokymenty`, ссылки со старого сайта):
   без отступа начало списка уходило под закреплённую шапку. */
#dokymenty { scroll-margin-top: 96px; }

/* Документы: три сертификата и пояснение (09.10). На планшете полоса
   бланков — лента (правила макета), здесь бланки по трети ряда, а
   пояснение скрыто: тот же смысл страница говорит во вступлении и в
   разделе ТДС ниже. */
@media (min-width: 641px) and (max-width: 1024px) {
  [data-certs-desk] > div { flex-basis: calc((100% - 4px) / 3) !important; }
  [data-certs-note] { display: none; }
}

/* ── Первый экран главной: объект и форма (с 08.10) ────────────

   Вариант 08 из восьми черновиков. Слева листаются объекты, справа
   красная панель с заголовком и формой, банка стоит на стыке половин.
   Обе половины держат свои краски в любой теме: снимок остаётся снимком,
   красная плашка — плашкой, поэтому токены темы здесь не участвуют.
   Разметку собирает `geroyObjekt()` в `build.mjs`, листание — `initGeroy()`. */
[data-geroy] {
  --g-pad: clamp(20px, 4.4vw, 72px);
  /* Просвет у стыка: на столько текст панели отступает вправо от стыка и на
     столько же подпись объекта не доходит до него слева. В этом просвете,
     и только в нём, стоит банка. */
  --g-prosvet: clamp(120px, 10.5vw, 200px);
  --g-svet: #F6F1EA;
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: calc(100svh - 76px);
}
[data-geroy] *, [data-geroy] *::before, [data-geroy] *::after { box-sizing: border-box; }

[data-geroy-foto] { position: relative; overflow: hidden; background: var(--paper-ink); min-height: 360px; }
[data-geroy-kadr] {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transform: scale(1.06); transition: opacity .9s, transform 7s linear;
}
[data-geroy-kadr][data-on] { opacity: 1; transform: scale(1); }
[data-geroy-foto]::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to top, rgba(18,20,17,.9) 0, rgba(18,20,17,.35) 38%, transparent 60%);
}
[data-geroy-podpis] {
  position: absolute; z-index: 2; left: var(--g-pad); right: var(--g-prosvet); bottom: clamp(24px, 3vw, 44px);
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px; color: #EDE7DD;
}
[data-geroy-nomer] {
  font-family: var(--font-poster-mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  color: rgba(237,231,221,.7);
}
/* Переносы: «металлоконструкций» длиннее рамки подписи и без них вылезало
   за стык, под банку. */
a[data-geroy-imya] {
  max-width: 100%; hyphens: auto; -webkit-hyphens: auto; overflow-wrap: break-word;
  font-family: var(--font-poster); font-weight: 900; font-size: clamp(24px, 2.3vw, 42px); line-height: .95;
  letter-spacing: -.02em; word-spacing: .1em; text-transform: uppercase; color: #EDE7DD; text-decoration: none;
}
a[data-geroy-imya]:hover { color: #fff; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 6px; }
[data-geroy-stroka] {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  font-family: var(--font-poster-mono); font-size: 12px; letter-spacing: .06em;
}
[data-geroy-r] { font-style: normal; padding: 4px 8px; background: #D21D27; color: #fff; }
[data-geroy-tochki] { display: flex; gap: 6px; margin-top: 4px; }
[data-geroy-tochki] button { position: relative; width: 36px; height: 18px; padding: 0; border: 0; background: none; cursor: pointer; }
[data-geroy-tochki] button::before { content: ''; position: absolute; left: 0; right: 0; top: 8px; height: 3px; background: rgba(237,231,221,.35); }
[data-geroy-tochki] button[aria-current]::before { background: #EDE7DD; }

[data-geroy-panel] {
  position: relative; display: flex; flex-direction: column; justify-content: center;
  padding: clamp(28px, 3.2vw, 56px) var(--g-pad) clamp(28px, 3.2vw, 56px) var(--g-prosvet);
  background: #D21D27; color: var(--g-svet);
}
[data-geroy-blok] { position: relative; display: flex; flex-direction: column; gap: clamp(14px, 1.6vw, 22px); }
[data-geroy-liniya] {
  display: flex; align-items: center; gap: 14px; min-width: 0;
  font-family: var(--font-poster-mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  color: rgba(246,241,234,.75); white-space: nowrap;
}
[data-geroy-liniya] span:nth-child(2) { flex: 1; min-width: 24px; height: 1px; background: rgba(246,241,234,.45); }
[data-geroy] h1 {
  margin: 0; font-family: var(--font-poster); font-weight: 900; font-size: clamp(36px, 3.6vw, 68px);
  line-height: .94; letter-spacing: -.03em; word-spacing: .1em; text-transform: uppercase;
  color: var(--g-svet); text-wrap: balance; hyphens: manual;
}
[data-geroy-nw] { white-space: nowrap; }
[data-geroy-chern] { color: var(--paper-ink); }
[data-geroy-lid] {
  margin: 0; max-width: 46ch; font-family: var(--font-poster-text); font-weight: 300;
  font-size: clamp(16px, 1.15vw, 19px); line-height: 1.5; color: var(--g-svet);
}

[data-geroy-forma] { display: grid; gap: 2px; }
[data-geroy-forma] input[data-pole] {
  height: 54px; width: 100%; min-width: 0; padding: 0 16px; border: 1px solid rgba(246,241,234,.55); border-radius: 0;
  background: transparent; color: var(--g-svet); font-family: var(--font-poster-text); font-size: 15px; outline: none;
  -webkit-appearance: none; appearance: none; transition: border-color .15s, background .15s;
}
[data-geroy-forma] input[data-pole]::placeholder { color: rgba(246,241,234,.78); opacity: 1; }
[data-geroy-forma] input[data-pole]:focus { border-color: var(--g-svet); background: rgba(18,20,17,.12); }
[data-geroy-forma] label {
  display: flex; gap: 10px; align-items: flex-start; padding: 10px 2px 8px; cursor: pointer;
  font-family: var(--font-poster-text); font-size: 12px; line-height: 1.45; color: rgba(246,241,234,.78);
}
[data-geroy-forma] label input { flex: none; width: 16px; height: 16px; margin: 1px 0 0; accent-color: var(--paper-ink); }
[data-geroy-forma] label a { color: inherit; text-decoration: underline; }
[data-geroy-forma] button {
  height: 56px; padding: 0 28px; border: 0; border-radius: 0; background: var(--paper-ink); color: var(--g-svet);
  font-family: var(--font-poster-mono); font-size: 12px; letter-spacing: .14em; text-transform: uppercase;
  cursor: pointer; transition: background .2s;
}
[data-geroy-forma] button:hover { background: #2A2D27; }
[data-geroy-forma] button:disabled { opacity: .7; cursor: default; }

/* Банка — отдельный слой поверх обеих половин, на раскладку не влияет.
   Серединой на стыке и по центру блока «заголовок и форма» по высоте.

   Размер — по просвету у стыка: банка помещается между подписью объекта
   и текстом панели с полем 16 px с каждой стороны и не заходит ни на то,
   ни на другое (08.10: ростом с блок она закрывала название объекта на
   ноутбуках). Видимая ширина банки — 74,83% кадра, отсюда делитель. Выше
   блока банка не бывает: на больших экранах её держит его высота.

   Середина банки в кадре — на 53,17% ширины (ручка справа длиннее), её и
   ставим на линию стыка; по высоте банка занимает кадр почти целиком. */
[data-geroy-banka] {
  position: absolute; z-index: 1; top: 50%; left: calc(-1 * var(--g-prosvet));
  height: min(100%, (2 * var(--g-prosvet) - 32px) / .7483); width: auto;
  transform: translate(-53.17%, -50%);
  filter: drop-shadow(0 30px 30px rgba(0,0,0,.45)); pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  [data-geroy-kadr] { transition: none; transform: none; }
}

@media (max-width: 1024px) {
  /* На планшете и телефоне половины друг под другом. Банка стоит на стыке
     справа, большей частью на снимке: ростом с блок она заняла бы экран,
     поэтому размер — от ширины экрана, 150–220 px (08.10: было 116–140,
     попросили крупнее). Низ банки — на `--g-banka-niz` ниже стыка, над
     верхней линейкой панели. Подпись объекта отступает справа на ширину
     банки (видимая её часть — 84,25% кадра от правого края) и 12 px. */
  [data-geroy] { grid-template-columns: minmax(0, 1fr); min-height: 0; --g-banka: clamp(150px, 24vw, 220px); --g-banka-niz: 35px; }
  [data-geroy-foto] { min-height: 0; aspect-ratio: 4 / 3; }
  [data-geroy-podpis] { right: calc(var(--g-pad) + .8425 * var(--g-banka) + 12px); }
  [data-geroy-panel] { padding: 40px var(--g-pad) 36px; }
  [data-geroy-blok] { position: static; }
  [data-geroy-banka] {
    z-index: 3; left: auto; right: var(--g-pad); top: 0; height: auto; width: var(--g-banka);
    transform: translateY(calc(-100% + var(--g-banka-niz)));
  }
}

@media (max-width: 640px) {
  [data-geroy] { --g-banka-niz: 27px; }
  [data-geroy] h1 { font-size: clamp(26px, 7.4vw, 38px); }
  [data-geroy-liniya] span:last-child { display: none; }
  [data-geroy-podpis] { left: 16px; bottom: 18px; }
}

/* ── Блок «4 задачи в 1 составе» (с 08.10) ─────────────────────

   По образцу черновика 04: выноски слева и справа, линии сходятся на таре
   в центре, тара листается. Разметку собирает `blokZadachi()` в
   `build.mjs`. */
[data-zadachi] {
  --z-pad: clamp(20px, 4.4vw, 72px);
  /* Ширина тары и насколько линия выноски заходит на неё: на 14% кадра
     слева это маленькая банка, справа — ведро. */
  --z-tara: min(34vw, 520px);
  --z-zahod: calc(var(--z-tara) * .14);
  padding: clamp(48px, 6vw, 104px) var(--z-pad);
  color: var(--paper-text);
}
[data-zadachi] *, [data-zadachi] *::before, [data-zadachi] *::after { box-sizing: border-box; }
[data-zadachi-liniya-verh] {
  display: flex; align-items: center; gap: 16px;
  font-family: var(--font-poster-mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--paper-muted);
}
[data-zadachi-liniya-verh] span:first-child { color: var(--paper-red-text); }
[data-zadachi-liniya-verh] span:nth-child(2) { flex: 1; height: 2px; background: var(--paper-red); }
[data-zadachi-zag] {
  margin: clamp(22px, 2.6vw, 40px) 0 0; text-align: center;
  font-family: var(--font-poster); font-weight: 900; font-size: clamp(36px, 5.6vw, 104px);
  line-height: .94; letter-spacing: -.03em; word-spacing: .1em; text-transform: uppercase; color: var(--paper-text);
}
[data-zadachi-zag] span { color: var(--paper-red-text); }

[data-zadachi-scena] {
  display: grid; grid-template-columns: minmax(0, 1fr) var(--z-tara) minmax(0, 1fr);
  /* Пары выносок — в общих строках, поэтому линии слева и справа всегда на
     одной высоте, какой бы длины ни был заголовок. Третья строка забирает
     остаток высоты тары. */
  grid-template-rows: auto auto 1fr; margin-top: clamp(16px, 2.4vw, 36px);
}
[data-zadachi-centr] { grid-column: 2; grid-row: 1 / 4; display: flex; flex-direction: column; align-items: center; gap: 14px; }
/* Выноски: нечётные слева, чётные справа. Линия верхней пары — на трети
   высоты тары (пояс банки слева, корпус ведра справа), нижняя — под ней. */
[data-zadachi-vynoska] { position: relative; z-index: 2; display: flex; align-items: flex-start; align-self: start; }
[data-zadachi-vynoska="lev"] { grid-column: 1; }
[data-zadachi-vynoska="prav"] { grid-column: 3; flex-direction: row-reverse; }
[data-zadachi-vynoska]:nth-child(-n+2) { grid-row: 1; margin-top: calc(var(--z-tara) * .34 - 34px); }
[data-zadachi-vynoska]:nth-child(n+3) { grid-row: 2; margin-top: clamp(16px, 2vw, 32px); }
[data-zadachi-tekst] { flex: 0 1 320px; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
[data-zadachi-vynoska="lev"] [data-zadachi-tekst] { align-items: flex-end; text-align: right; }
[data-zadachi-tekst] b { font-family: var(--font-poster-mono); font-size: 12px; font-weight: 400; color: var(--paper-red-text); }
[data-zadachi-tekst] strong {
  font-family: var(--font-poster); font-weight: 900; font-size: clamp(20px, 1.9vw, 34px); line-height: .95;
  letter-spacing: -.02em; word-spacing: .1em; text-transform: uppercase;
}
[data-zadachi-tekst] span { max-width: 30ch; font-family: var(--font-poster-text); font-size: 15px; line-height: 1.5; color: var(--paper-muted); }
[data-zadachi-liniya] {
  /* Снаружи тары линия всегда не короче 40 px — иначе на узком ноутбуке
     она целиком уходила под картинку и выноска теряла направление. */
  position: relative; flex: 1 1 auto; min-width: calc(var(--z-zahod) + 40px); height: 1px; margin-top: 34px; background: var(--paper-text);
}
[data-zadachi-vynoska="lev"] [data-zadachi-liniya] { margin-left: 18px; margin-right: calc(-1 * var(--z-zahod)); }
[data-zadachi-vynoska="prav"] [data-zadachi-liniya] { margin-right: 18px; margin-left: calc(-1 * var(--z-zahod)); }
[data-zadachi-liniya]::after {
  content: ''; position: absolute; top: -5px; width: 11px; height: 11px; background: var(--paper-red);
  outline: 4px solid rgba(210,29,39,.22);
}
[data-zadachi-vynoska="lev"] [data-zadachi-liniya]::after { right: -5px; }
[data-zadachi-vynoska="prav"] [data-zadachi-liniya]::after { left: -5px; }

a[data-zadachi-tara] { display: block; width: 100%; aspect-ratio: 1 / 1; }
a[data-zadachi-tara] img { width: 100%; height: 100%; object-fit: contain; display: block; filter: drop-shadow(0 26px 26px rgba(18,20,17,.28)); }

/* Цифры ТДС и кнопка в каталог — одной строкой под тарой. */
[data-zadachi-niz] {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: stretch; gap: 6px;
  margin-top: clamp(20px, 2.4vw, 34px);
}
[data-zadachi-niz] > span {
  display: flex; align-items: center; padding: 12px 16px; border: 1px solid var(--paper-rule);
  font-family: var(--font-poster-mono); font-size: 12px; letter-spacing: .06em; white-space: nowrap;
}
a[data-zadachi-knopka] {
  display: flex; align-items: center; justify-content: center; padding: 12px 28px;
  background: var(--paper-ink); color: var(--paper-300); text-decoration: none; white-space: nowrap;
  font-family: var(--font-poster-mono); font-size: 12px; letter-spacing: .14em; text-transform: uppercase;
  transition: background .2s;
}
a[data-zadachi-knopka]:hover { background: var(--paper-red); color: var(--paper-300); }
:root[data-theme='dark'] a[data-zadachi-knopka] { background: var(--paper-red); color: #F6F1EA; }
:root[data-theme='dark'] a[data-zadachi-knopka]:hover { background: #A8161F; }

@media (max-width: 1024px) {
  [data-zadachi] { --z-tara: min(62vw, 420px); }
  [data-zadachi-zag] { text-align: left; }
  [data-zadachi-scena] { grid-template-columns: 1fr 1fr; grid-template-rows: none; gap: 22px 28px; }
  [data-zadachi-centr] { grid-column: 1 / -1; grid-row: 1; }
  a[data-zadachi-tara] { width: var(--z-tara); }
  [data-zadachi-vynoska],
  [data-zadachi-vynoska]:nth-child(-n+2),
  [data-zadachi-vynoska]:nth-child(n+3) { grid-row: auto; grid-column: auto; align-self: start; margin: 0; flex-direction: row; }
  [data-zadachi-vynoska="lev"] [data-zadachi-tekst] { align-items: flex-start; text-align: left; }
  [data-zadachi-tekst] { flex: 1 1 auto; }
  [data-zadachi-liniya] { display: none; }
}

@media (max-width: 640px) {
  [data-zadachi] { --z-tara: min(88vw, 400px); }
  [data-zadachi-liniya-verh] span:last-child { display: none; }
  [data-zadachi-zag] { font-size: clamp(32px, 10vw, 48px); }
  [data-zadachi-scena] { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  [data-zadachi-tekst] strong { font-size: 22px; }
  [data-zadachi-niz] > span { flex: 1 1 auto; justify-content: center; }
  a[data-zadachi-knopka] { flex: 1 1 100%; min-height: 54px; }
}

/* Документы: четыре карточки разделов в ряд (09.10). Кегль заголовка из
   макета рассчитан на три колонки — в четырёх «документация» рвалась
   посередине слова. */
@media (min-width: 1025px) {
  [data-docs-grid] > * > div:nth-child(2) { font-size: clamp(17px, 1.3vw, 22px) !important; }
}

/* Объекты по отраслям (09.10): компактные карточки на телефоне — заголовок
   карточки мельче общего правила блоков конвейера (16 px): карточек сотня,
   и крупный кегль растягивал каждую на экран. */
@media (max-width: 640px) {
  [data-obj-mini] h3 { font-size: 14px !important; line-height: 1.2 !important; }
}

/* ── Страницы видов: объекты по этому типу (10.10) ─────────────────────
   Карточки здесь — ссылки (`a`), а правила полосы в макете написаны для
   `div`: без своих правил на планшете и телефоне карточка не занимала
   ширину окна полосы. Плитка «все объекты» на широком экране добирает
   последний ряд (`span`), в полосе она — обычная карточка. */
@media (min-width: 641px) and (max-width: 1024px) {
  [data-tp-objs] > a { flex: 0 0 calc(50% - 1px) !important; scroll-snap-align: start; }
}
@media (max-width: 640px) {
  [data-tp-objs] > a { flex: 0 0 100% !important; scroll-snap-align: start; }
}
@media (max-width: 1024px) {
  [data-tp-vse] { grid-column: auto !important; min-height: 0 !important; }
}

/* ── Хлебные крошки в красной полосе (10.10) ───────────────────────────
   Ссылки приглушены, текущая страница — в полную силу; наведение
   проявляет ссылку и подчёркивает её. На телефоне путь из четырёх звеньев
   не помещается в одну строку: полоса растёт по содержимому вместо
   жёсткой высоты, крошки переносятся по звеньям. */
[data-kroshki] a:hover { opacity: 1 !important; text-decoration: underline !important; text-underline-offset: 4px; }
@media (max-width: 640px) {
  [data-polosa-kroshki] { height: auto !important; min-height: 96px; padding-top: 22px !important; padding-bottom: 22px !important; }
  [data-kroshki] { font-size: 10px !important; letter-spacing: 0.14em !important; }
  [data-polosa-kroshki] [data-kroshki] { max-width: calc(100% - 76px) !important; }
}

/* Страницы видов конструкций: крошки на месте надписи «Тип конструкций»
   в строке над заголовком. На планшете колонка узкая, и путь шёл в три
   строки рядом с меткой справа — здесь путь берёт всю строку, а линия
   с меткой («ЛСТК · профлист») уходят строкой ниже. */
@media (min-width: 641px) and (max-width: 1024px) {
  [data-nadrubrika]:has([data-kroshki]) { flex-wrap: wrap; row-gap: 6px; }
  [data-nadrubrika] [data-kroshki] { flex: 1 1 100% !important; }
}

/* Заголовок первого экрана вида конструкций (10.10): на планшете колонка
   узкая, и «оцинкованных» рвалось посреди слова («ОЦИНКОВАНН / ЫХ»).
   Перенос по слогам — язык страницы русский (`lang="ru"`); разрыв по
   букве остаётся запасным, если словаря переносов у браузера нет. */
[data-nadrubrika] + h1 { hyphens: auto; -webkit-hyphens: auto; }

/* Страницы объектов: фото и видео с площадки (11.10). На телефоне ролик
   и сетка снимков — друг под другом, а не в две колонны. */
@media (max-width: 640px) {
  [data-galereya] { grid-template-columns: 1fr !important; }
}
[data-galereya] button[data-skan] img { transition: transform 200ms ease; }
[data-galereya] button[data-skan]:hover img { transform: scale(1.02); }

/* Слайдер — общий для сайта (11.10, `slayder.mjs`): три карточки на широком
   экране, две на планшете, на телефоне одна с краем следующей — видно, что
   лента листается. Карточки с проявлением при прокрутке (`data-reveal`) в
   ленте видны сразу: правее окна их наблюдатель не увидел бы до листания. */
[data-slayder-lenta]::-webkit-scrollbar { display: none; }
[data-slayder-lenta] > * { scroll-snap-align: start; min-width: 0; }
[data-slayder-lenta] > [data-reveal] { opacity: 1 !important; transform: none !important; }
@media (max-width: 1024px) {
  [data-slayder-lenta] { grid-auto-columns: calc((100% - var(--sg)) / 2) !important; }
}
@media (max-width: 640px) {
  [data-slayder-lenta] { grid-auto-columns: 86% !important; }
  [data-slayder-podskazka] { display: none; }
}
