/* Hallmark · genre: modern-minimal · design-system: DESIGN-SITE.md (system-managed)
 * macrostructure: Ledger/Schedule (услуги) + Catalogue с фильтром (техника)
 *               + Form-as-instrument (светлый бланк заявки) + Reading column (тексты)
 * nav: N9 edge-aligned (наследуется из hero.css) · footer: Ft4 dense colophon
 * enrichment: Tier C generated stills + Tier A CSS-штриховка на месте недостающих кадров
 * signature: полка с числом (выноска чертежа) — та же, что на первом экране
 * pre-emit critique: P5 H5 E4 S5 R5 V4
 *
 * Стили ШАБЛОНОВ генератора. Всё, чего нет в page.css / pages.css.
 * Правило зоны: tokens.css, hero.css и pages.css здесь только читаются,
 * ни одна их строка не переопределяется — новые классы, новые имена.
 *
 * Порядок подключения на странице:
 *   tokens.css → hero.css → pages.css → tpl.css
 *
 * Ритм страниц намеренно РАЗНЫЙ, чтобы сайт не читался одним шаблоном:
 *   услуга        — полка обещаний, полоса кадра, ведомость работ
 *   подстраница   — плотный лист без кадра, цена в первом экране
 *   каталог       — витрина плиток с фильтром на radio + :has()
 *   категория     — сравнительная таблица вместо плиток
 *   карточка      — кадр с выноской слева, панель заказа справа (как принятая)
 *   вопросы       — рейка тем + две колонки
 *   новости       — лента строками, дата на рейке
 *   статья        — узкая колонка чтения
 *   вакансии      — строки с фактами справа
 *   нормативы     — плотный список с поиском
 *   контакты      — светлый остров во всю ширину
 *   формы         — светлый бланк, поля как графы
 */

:root {
  /* Продолжение короткой шкалы из tokens.css. Значения совпадают с page.css
     намеренно: типографика сайта одна, а page.css к шаблонам не подключается. */
  --text-h3:   clamp(1.125rem, 0.5vw + 1rem, 1.5rem);
  --text-sm:   0.875rem;
  --text-price: clamp(1.25rem, 0.9vw + 0.95rem, 1.75rem);
  --sec-pad:   clamp(44px, 6.5vh, 92px);
  /* Ширина текстового листа: без ограничения на 1920 колонка тянется,
     а строка упирается в 62ch и оставляет справа пустое поле. */
  --sheet-w:   1320px;

  /* Два цвета, которых нет в tokens.css, а трогать его нельзя — это чужая
     зона. Поэтому они объявлены здесь ИМЕНАМИ, а не вписаны в правила
     значениями: система остаётся токенной, и при переносе в tokens.css
     достаточно перенести две строки.
     · поле ввода на светлом острове: белее самой поверхности, иначе граница
       поля читается только по кромке;
     · красный ошибки: в палитре сайта его нет вовсе — жёлтый по системе
       занят звонком и «не хватает данных», и подменять им ошибку нельзя. */
  --field-bg:      oklch(1 0 0);
  --danger:        oklch(0.55 0.19 27);   /* кромка невалидного поля */
  --danger-text:   oklch(0.48 0.19 27);   /* текст «заявка не ушла» на светлом: 5.1:1 */
}

/* ═════════════════════════ Служебное ══════════════════════════════════════ */

/* Видно скринридеру, не видно глазу. Нужно там, где визуальная подсказка
   есть (стрелка ↗), а словами не сказано. */
.vh {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
/* Ловушка для ботов. Не display:none — часть ботов такие поля пропускает. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Кнопка в один ряд с текстом: тот же силуэт, что у .btn, ростом пониже. */
/* 44px, а не 40: замер показал кнопки «Сбросить фильтр» и «Показать карту»
   154×40 и 142×40 при норме 44 по высоте. */
.btn--sm { min-height: 44px; padding: 0 var(--space-md); font-size: var(--text-sm); }

/* Числовая ячейка таблицы на узких экранах. pages.css ставит всем ячейкам
   overflow-wrap:anywhere ради длинных слов — но «anywhere» рвёт и неразрывный
   пробел тоже, и «от 1 700 ₽» разваливалось так, что ₽ уезжало на вторую
   строку отдельным символом (замер на 320). Для числовых ячеек перенос
   возвращаем в нормальный режим: рвётся только по обычному пробелу после «от»,
   само число с валютой остаётся целым. Селектор с элементом — иначе
   специфичность ниже, чем у правила из pages.css. */
@media (max-width: 639px) {
  .tbl td.tbl__num, .tbl td.tbl__num-2 { overflow-wrap: normal; hyphens: none; }
}

.prose p { margin: 0 0 var(--space-md); color: var(--text-2); line-height: 1.65; max-width: 68ch; }

/* Ссылка внутри текста наследует цвет строки и подчёркивается. Без этого
   браузер рисует её своим синим — чужой цвет в палитре и контраст около 2:1
   на графите. Поймано на рендере 320: «Полный прайс — на странице цены»
   в служебной строке блока. Тот же дефект уже лечили в pages.css
   у .pending__text — здесь он закрыт для всех новых текстовых блоков. */
:where(.block__note, .top__answer, .qa__a, .works__text, .figband__cap,
       .dirs__text, .dirs__meta, .vac__lead, .feed__lead, .norm__about,
       .sitemap__note, .prose, .contacts__note, .art__lead,
       .legal, .legal__list, .tbd__text) a {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--chrome-dim);
}
@media (hover: hover) and (pointer: fine) {
  :where(.block__note, .top__answer, .qa__a, .works__text, .figband__cap,
         .dirs__text, .dirs__meta, .vac__lead, .feed__lead, .norm__about,
         .sitemap__note, .prose, .contacts__note, .art__lead,
         .legal, .legal__list, .tbd__text) a:hover {
    color: var(--green-signal); text-decoration-color: var(--green-signal);
  }
}
/* На светлом острове тот же приём, но своим цветом. */
:where(.island__text, .formbox__list, .formbox__small, .check__text) a {
  color: var(--light-text);
  text-decoration: underline; text-underline-offset: 3px;
}

/* Ссылка в ячейке таблицы и в правовой строке подвала. Обе — самостоятельные
   переходы, а не слова внутри предложения, поэтому кроме цвета им нужна
   и область нажатия. Замер до правки: «Вывоз грунта» 106×20 и «Политика
   обработки персональных данных» 1235×34 при норме 44; цвет — браузерный
   синий, 2.01:1 и 1.84:1 на графите при норме 4.5. */
.tbl td a, .tbl th a, .foot__legal a {
  display: inline-flex; align-items: center; min-height: 44px;
  color: var(--text);
  text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: var(--chrome-dim);
}
.foot__legal a { color: var(--text-2); }
@media (hover: hover) and (pointer: fine) {
  .tbl td a:hover, .tbl th a:hover, .foot__legal a:hover {
    color: var(--green-signal); text-decoration-color: var(--green-signal);
  }
}

/* ═════════════════════════ Полка обещаний ═════════════════════════════════
   Три обещания первого экрана услуги. Не иконки в кружочках: полка с числом —
   производная от чертёжной выноски, того же приёма, что на кадре. */
.promises {
  list-style: none; margin: 0 0 var(--space-xl); padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: var(--space-lg);
  max-width: var(--sheet-w);
}
.promises__item {
  border-top: 2px solid var(--chrome);
  padding-top: var(--space-sm);
  min-width: 0;
}
.promises__key {
  display: block; margin-bottom: var(--space-2xs);
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .05em; text-transform: uppercase; color: var(--label);
}
.promises__val {
  display: block; color: var(--text); line-height: 1.45;
  font-size: var(--text-md); overflow-wrap: anywhere;
}

/* ═════════════════════════ Полоса кадра ═══════════════════════════════════
   Кадр во всю ширину листа. Низ уходит в графит: стык фотографии и текста
   не должен читаться швом. */
.figband {
  position: relative; margin: 0 0 var(--space-2xl);
  overflow: clip; background: var(--surface);
}
.figband img, .figband .noshot { display: block; width: 100%; height: auto; }
.figband:not(.figband--flat)::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top, var(--graphite) 0%,
              color-mix(in oklch, var(--graphite) 40%, transparent) 9%, transparent 24%);
}
.figband__cap {
  margin: var(--space-xs) 0 0;
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  line-height: 1.6; color: var(--label); max-width: 72ch;
}
/* Высота полосы ограничена: кадр 1.6:1 на 1440 занял бы 900px — целый экран
   под картинку, за которой ещё не сказано ни одной цифры. */
.figband .shotimg { max-height: clamp(220px, 38vw, 460px); object-fit: cover; }
.figband--flat .shotimg { max-height: clamp(200px, 30vw, 380px); }

/* ── Кадра нет ───────────────────────────────────────────────────────────
   Сам блок .noshot переехал в hero.css: его подключают все страницы,
   включая собранные вручную. Здесь остались только частные случаи. */

/* ═════════════════════════ Ведомость работ ════════════════════════════════
   Строки, а не карточки: разделяет хайрлайн, как графы таблицы чертежа. */
.works { list-style: none; margin: 0; padding: 0; max-width: var(--sheet-w); }
.works__row {
  display: grid; grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
  gap: var(--space-xs) clamp(var(--space-lg), 3vw, var(--space-3xl));
  padding: var(--space-lg) 0;
  border-top: var(--hair) solid var(--edge);
}
.works__row:first-child { border-top: 0; padding-top: 0; }
.works__name {
  margin: 0; grid-column: 1;
  font-family: var(--font-display); font-variation-settings: "SHRP" var(--shrp);
  font-weight: 600; font-size: var(--text-h3); line-height: 1.12;
  letter-spacing: -.02em; color: var(--text);
  overflow-wrap: anywhere; min-width: 0;
}
.works__text { margin: 0; grid-column: 2; color: var(--text-2); line-height: 1.6; max-width: 62ch; }
.works__fact {
  grid-column: 2; margin: 0;
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  color: var(--chrome); font-variant-numeric: tabular-nums;
}
@media (max-width: 899px) {
  .works__row { grid-template-columns: minmax(0, 1fr); }
  .works__name, .works__text, .works__fact { grid-column: 1; }
}

/* ═════════════════════════ Хаб услуг ══════════════════════════════════════ */
.dirs { list-style: none; margin: 0; padding: 0; max-width: var(--sheet-w); }
.dirs__row {
  display: grid;
  grid-template-columns: minmax(0, 220px) minmax(0, 1fr) max-content;
  gap: var(--space-md) clamp(var(--space-md), 2.4vw, var(--space-2xl));
  align-items: start;
  padding: var(--space-lg) 0;
  border-top: var(--hair) solid var(--edge);
}
.dirs__row:first-child { border-top: 0; padding-top: 0; }
.dirs__shot { grid-column: 1; min-width: 0; }
.dirs__shot img { display: block; width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; background: var(--surface); }
.dirs__shot .noshot { aspect-ratio: 3 / 2; }
.dirs__body { grid-column: 2; min-width: 0; }
.dirs__name {
  margin: 0 0 var(--space-2xs);
  font-family: var(--font-display); font-variation-settings: "SHRP" var(--shrp);
  font-weight: 600; font-size: var(--text-h3); line-height: 1.12; letter-spacing: -.02em;
  overflow-wrap: anywhere;
}
.dirs__name a {
  display: inline-flex; align-items: center; min-height: 44px;
  color: var(--text); text-decoration: none;
  border-bottom: var(--hair) solid var(--edge-strong);
}
.dirs__text { margin: 0; color: var(--text-2); line-height: 1.55; max-width: 62ch; }
.dirs__meta {
  margin: var(--space-xs) 0 0;
  font-family: var(--font-mono); font-size: var(--text-mono-label); color: var(--label);
}
.dirs__price { grid-column: 3; margin: 0; text-align: right; min-width: 0; }
.dirs__rate {
  display: block; white-space: nowrap;
  font-family: var(--font-mono); font-weight: 600; font-size: var(--text-price);
  line-height: 1.15; letter-spacing: -.03em; color: var(--chrome);
  font-variant-numeric: tabular-nums;
}
.dirs__rate--ask { color: var(--text-2); font-size: var(--text-md); }
.dirs__unit { font-size: var(--text-mono-label); font-weight: 400; color: var(--text-2); letter-spacing: 0; }
.dirs__for {
  display: block; margin-top: var(--space-3xs);
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  text-transform: uppercase; letter-spacing: .04em; color: var(--label);
}
@media (hover: hover) and (pointer: fine) {
  .dirs__name a:hover { color: var(--green-signal); border-bottom-color: var(--green-signal); }
}
@media (max-width: 959px) {
  .dirs__row { grid-template-columns: minmax(0, 180px) minmax(0, 1fr); }
  .dirs__price { grid-column: 2; text-align: left; }
}
@media (max-width: 639px) {
  .dirs__row { grid-template-columns: minmax(0, 1fr); }
  .dirs__shot, .dirs__body, .dirs__price { grid-column: 1; }
  .dirs__shot { order: -1; }
}

/* ═════════════════════════ Каталог техники ════════════════════════════════
   Фильтр на radio + :has(): без единой строки JavaScript. Механика та же,
   что у переключателя навесок на принятой карточке машины. */
.catalog { margin: 0 0 var(--space-2xl); border: 0; padding: 0; }
.catalog__filters {
  display: grid; gap: var(--space-lg);
  padding-bottom: var(--space-lg);
  margin-bottom: var(--space-lg);
  border-bottom: var(--hair) solid var(--edge);
}
.catalog__reset { display: flex; align-items: center; gap: var(--space-sm); }

/* Плитки. Одинаковых «иконка + заголовок + строка» здесь нет: в каждой
   реальная ставка из прайса и своя характеристика. */
/* Линии сетки даёт outline каждой плитки, а НЕ фон контейнера в просветах.
   Так было раньше, и на широком экране это вылезало: 22 плитки в четыре
   колонки оставляют в последнем ряду два пустых места, и они светились
   сплошным прямоугольником цвета кромки — на 1440 читалось дырой в каталоге.
   Outline не занимает места, соседние совпадают в зазоре 1px, а пустой хвост
   ряда остаётся графитом, как и должен. Тень для этого не годится:
   «теней нет» — DESIGN-SITE, «Макет». */
/* Зазор между плитками — не волосок. Замечание заказчика 03.09.2026: «получилось
   очень близко… они сливаются общим текстом, техника вся разная, а идёт слитно».
   На 1440 четыре кадра шириной 329px стыковались краями, и каталог читался одной
   лентой фотографий, а не восемнадцатью машинами. Обводка каждой плитки остаётся
   и при разведении работает уже как рамка своей плитки, а не как линия сетки. */
.units {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(17rem, 100%), 1fr));
  gap: var(--space-lg);
  background: none;
}
.unitc {
  background: var(--graphite); min-width: 0;
  display: flex; flex-direction: column;
  outline: var(--hair) solid var(--edge);
}
.unitc__shot { position: relative; overflow: clip; background: var(--surface); }
.unitc__shot img { display: block; width: 100%; height: auto; aspect-ratio: 1.6 / 1; object-fit: cover; }
.unitc__body {
  padding: var(--space-md) var(--space-md) var(--space-lg);
  display: grid; gap: var(--space-xs); align-content: start;
  border-top: var(--hair) solid var(--edge);
}
.unitc__cat {
  margin: 0;
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .04em; text-transform: uppercase; color: var(--label);
}
.unitc__name {
  margin: 0;
  font-family: var(--font-display); font-variation-settings: "SHRP" var(--shrp);
  font-weight: 600; font-size: 1.0625rem; line-height: 1.15; letter-spacing: -.02em;
  overflow-wrap: anywhere; min-width: 0;
}
/* Область нажатия набирается вертикальными полями, а не ростом шрифта;
   отрицательное поле гасит прирост, чтобы заголовок не отъехал от ставки. */
/* 12px полей, а не 11: с 11 замер давал 43px высоты — на пиксель ниже нормы. */
.unitc__name a {
  display: inline-block; padding-block: 12px; margin-block: -12px;
  color: var(--text); text-decoration: none;
  border-bottom: var(--hair) solid var(--edge-strong);
}
/* Полка со ставкой — тихая производная от выноски: та же полка и тот же
   моношрифт, но без выносной линии. */
.unitc__rate {
  margin: 0; display: flex; align-items: baseline; gap: var(--space-2xs);
  padding-top: var(--space-xs);
  border-top: 2px solid var(--chrome);
  width: max-content; max-width: 100%;
}
.unitc__num {
  font-family: var(--font-mono); font-weight: 600; font-size: var(--text-price);
  line-height: 1.1; letter-spacing: -.03em; color: var(--chrome);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.unitc__num--ask { font-size: var(--text-md); color: var(--text-2); letter-spacing: 0; }
.unitc__per { font-family: var(--font-mono); font-size: var(--text-mono-label); color: var(--text-2); }
.unitc__meta {
  margin: 0; font-family: var(--font-mono); font-size: var(--text-mono-label);
  line-height: 1.6; color: var(--label);
}
.unitc__meta b { color: var(--text-2); font-weight: 400; }
.unitc__link { margin: 0; font-family: var(--font-mono); font-size: var(--text-mono-label); }
.unitc__link a {
  display: inline-flex; align-items: center; min-height: 44px;
  color: var(--text-2); text-decoration: underline;
  text-underline-offset: 3px; text-decoration-color: var(--edge-strong);
}
.unitc__link a::after { content: " →"; color: var(--chrome-dim); white-space: pre; }
@media (hover: hover) and (pointer: fine) {
  .unitc__name a:hover { color: var(--green-signal); border-bottom-color: var(--green-signal); }
  .unitc__link a:hover { color: var(--green-signal); text-decoration-color: var(--green-signal); }
}

/* ── Сама фильтрация ─────────────────────────────────────────────────────
   Два независимых набора radio дают пересечение: «экскаваторы И снос».
   Правила ниже общие; пары, под которые машин нет вовсе, считаются
   на сборке и выводятся в <style> самой страницы. */
.catalog__empty { display: none; }
.catalog__empty {
  border-left: 2px solid var(--amber);
  padding: var(--space-md) var(--space-lg);
  background: var(--surface);
}
.catalog__empty-title { margin: 0 0 var(--space-2xs); font-weight: 600; color: var(--text); }
.catalog__empty-q {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .04em; text-transform: uppercase; color: var(--chrome-dim);
}
.catalog__what::after { content: "—"; color: var(--chrome); }
.catalog__empty-text { margin: 0 0 var(--space-md); color: var(--text-2); line-height: 1.6; max-width: 62ch; }
.catalog__empty-text a { color: var(--amber); text-underline-offset: 3px; white-space: nowrap; }
.catalog__empty-act { margin: 0; }

/* Скрытие плиток по выбранному фасету. Селекторы перечисляются на сборке
   в <style> страницы — здесь только то, что от данных не зависит. */
@supports selector(:has(*)) {
  .catalog__filters { display: grid; }
}
/* Там, где :has() не поддержан, фильтр выключаем целиком: неработающий
   набор кнопок хуже его отсутствия. Список машин при этом виден весь. */
@supports not selector(:has(*)) {
  .catalog__filters, .catalog__empty { display: none !important; }
}

/* ═════════════════════════ Карточка машины ════════════════════════════════
   Обобщение принятой карточки: значения по навескам лежат в разметке все
   сразу, переключатель меняет уже отрисованное (SITEMAP §4.3).
   Индексы 0…5 — потолок по навескам; больше шести у одной машины не бывает. */
.shot__stage--tpl { position: relative; aspect-ratio: 1.6 / 1; }
.shot__stage--tpl .shotimg { width: 100%; height: 100%; object-fit: cover; }
.shot__stage--tpl .noshot { position: absolute; inset: 0; aspect-ratio: auto; }
.mark--tpl { --len: clamp(28px, 4vw, 56px); }

/* Метки-прокси вверху карточки. Сам radio живёт в форме заявки внизу
   (одно поле на страницу, см. templates/machine.html), поэтому подсветку
   выбранного варианта нельзя сделать через `+ label` — соседства нет.
   Правил ровно столько, сколько бывает вариантов у машины: пять высот
   автовышки, три навески погрузчика. */
/* Радиокнопки выбора позиции стоят в СВЕТЛОМ острове формы, а базовые стили
   .hitch__label написаны под тёмную секцию карточки: замер живого DOM дал
   светло-серый текст (oklch .756) на светлом фоне — читалось плохо, а первая
   строка вообще пропадала. Здесь палитра острова: тёмный текст, тёмная
   рамка, выбранный вариант заливается графитом. */
.hitch__row--form { gap: var(--space-2xs); }
.hitch__row--form .hitch__label {
  color: color-mix(in oklch, var(--light-text) 88%, var(--light-surface));
  border-color: color-mix(in oklch, var(--light-text) 32%, transparent);
  background: transparent;
}
.hitch__row--form .hitch__opt:checked + .hitch__label {
  background: var(--graphite); border-color: var(--graphite); color: var(--light-surface);
}
.hitch__row--form .hitch__opt:focus-visible + .hitch__label {
  outline: 2px solid var(--graphite); outline-offset: 3px; box-shadow: 0 0 0 3px var(--light-surface);
}
@media (hover: hover) and (pointer: fine) {
  .hitch__row--form .hitch__label:hover { border-color: var(--light-text); color: var(--light-text); }
}
.hitchset { border: 0; margin: 0; padding: 0; }
.hitchset > .field__label { display: block; padding: 0; }

.hitch__note { margin-top: var(--space-2xs); font-family: var(--font-mono); font-size: var(--text-mono-label); color: var(--label); }
.card:has(#hitch-0:checked) .hitch__label--proxy[for="hitch-0"],
.card:has(#hitch-1:checked) .hitch__label--proxy[for="hitch-1"],
.card:has(#hitch-2:checked) .hitch__label--proxy[for="hitch-2"],
.card:has(#hitch-3:checked) .hitch__label--proxy[for="hitch-3"],
.card:has(#hitch-4:checked) .hitch__label--proxy[for="hitch-4"],
.card:has(#hitch-5:checked) .hitch__label--proxy[for="hitch-5"] {
  border-color: var(--chrome); background: var(--surface-2); color: var(--text);
}
/* Клавиатура: фокус живёт на radio в форме, кольцо рисуется на его подписи
   там же. Метка-прокси кликабельна мышью и пальцем. */

.v[data-i] { display: none; }
.v[data-i="0"] { display: inline; }
.card:has(#hitch-1:checked) .v[data-i="0"] { display: none; }
.card:has(#hitch-1:checked) .v[data-i="1"] { display: inline; }
.card:has(#hitch-2:checked) .v[data-i="0"] { display: none; }
.card:has(#hitch-2:checked) .v[data-i="2"] { display: inline; }
.card:has(#hitch-3:checked) .v[data-i="0"] { display: none; }
.card:has(#hitch-3:checked) .v[data-i="3"] { display: inline; }
.card:has(#hitch-4:checked) .v[data-i="0"] { display: none; }
.card:has(#hitch-4:checked) .v[data-i="4"] { display: inline; }
.card:has(#hitch-5:checked) .v[data-i="0"] { display: none; }
.card:has(#hitch-5:checked) .v[data-i="5"] { display: inline; }
/* Фолбэк без :has(): показываем ВСЕ значения подряд, каждое подписано
   своей навеской. Цифры не пропадают ни при каком раскладе.
   Правило .v::after и скрытие переключателя уже есть в pages.css. */
@supports not selector(:has(*)) {
  .v[data-i] { display: inline; }
  .v[data-i] + .v[data-i]::before { content: " · "; color: var(--label); }
}

/* ═════════════════════════ Оглавление тем ═════════════════════════════════ */
.toc {
  padding: var(--space-md) 0 var(--space-lg);
  border-bottom: var(--hair) solid var(--edge);
}
.toc__key {
  margin: 0 0 var(--space-sm);
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .05em; text-transform: uppercase; color: var(--label);
}
.toc__list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--space-2xs) var(--space-xs);
}
.toc__list a {
  display: inline-flex; align-items: center; gap: var(--space-xs);
  min-height: 44px; padding: 0 var(--space-md);
  border: var(--hair) solid var(--edge-strong); border-radius: var(--radius-btn);
  color: var(--text-2); text-decoration: none;
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  transition: color var(--dur-instant) var(--ease-out), border-color var(--dur-instant) var(--ease-out);
}
.toc__n { color: var(--chrome); font-variant-numeric: tabular-nums; }
@media (hover: hover) and (pointer: fine) {
  .toc__list a:hover { color: var(--text); border-color: var(--chrome); }
}

/* ═════════════════════════ Лента новостей ═════════════════════════════════ */
.feed { list-style: none; margin: 0; padding: 0; max-width: var(--sheet-w); }
.feed__row {
  display: grid; grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
  gap: var(--space-xs) clamp(var(--space-lg), 3vw, var(--space-2xl));
  padding: var(--space-lg) 0;
  border-top: var(--hair) solid var(--edge);
}
.feed__row:first-child { border-top: 0; padding-top: 0; }
.feed__meta {
  margin: 0; display: flex; flex-wrap: wrap; gap: var(--space-2xs) var(--space-sm);
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .04em; text-transform: uppercase; color: var(--label);
}
.feed__date { color: var(--chrome-dim); font-variant-numeric: tabular-nums; }
.feed__body { min-width: 0; }
.feed__title {
  margin: 0 0 var(--space-2xs);
  font-family: var(--font-display); font-variation-settings: "SHRP" var(--shrp);
  font-weight: 600; font-size: var(--text-h3); line-height: 1.15; letter-spacing: -.02em;
  overflow-wrap: anywhere;
}
.feed__title a {
  display: inline-block; padding-block: 10px; margin-block: -10px;
  color: var(--text); text-decoration: none;
  border-bottom: var(--hair) solid var(--edge-strong);
}
.feed__lead { margin: var(--space-xs) 0 0; color: var(--text-2); line-height: 1.6; max-width: 68ch; }
/* Обложка в ленте: её ставит редактор через админку, у существующих материалов
   её нет — тогда правило не применяется вовсе и строка выглядит как прежде. */
.feed__cover { display: block; margin: 0 0 var(--space-sm); max-width: min(22rem, 100%); }
.feed__cover img { display: block; width: 100%; height: auto; border-radius: 2px; }
@media (hover: hover) and (pointer: fine) {
  .feed__title a:hover { color: var(--green-signal); border-bottom-color: var(--green-signal); }
}
@media (max-width: 767px) {
  .feed__row { grid-template-columns: minmax(0, 1fr); }
}

/* ═════════════════════════ Статья ═════════════════════════════════════════
   Единственная страница сайта, где длина строки важнее плотности данных. */
.art { max-width: 46rem; padding-block: clamp(var(--space-xl), 4vw, var(--space-3xl)); }
.art__meta {
  margin: 0 0 var(--space-md);
  display: flex; flex-wrap: wrap; gap: var(--space-sm);
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .04em; text-transform: uppercase; color: var(--label);
}
.art__meta time { color: var(--chrome-dim); font-variant-numeric: tabular-nums; }
.art__title {
  margin: 0 0 var(--space-md);
  font-family: var(--font-display); font-variation-settings: "SHRP" var(--shrp);
  font-weight: 800; font-size: clamp(1.75rem, 2.4vw + 1rem, 2.75rem);
  line-height: 1.05; letter-spacing: -.035em; text-wrap: balance;
  overflow-wrap: break-word;
}
.art__lead { margin: 0 0 var(--space-xl); font-size: var(--text-lead); line-height: 1.55; color: var(--text-2); }
.art__body p { margin: 0 0 var(--space-md); color: var(--text-2); line-height: 1.7; }
.art__body a { color: var(--text); text-underline-offset: 3px; }
.art__h2 {
  margin: var(--space-2xl) 0 var(--space-sm);
  font-family: var(--font-display); font-variation-settings: "SHRP" var(--shrp);
  font-weight: 700; font-size: clamp(1.25rem, 1vw + 1rem, 1.625rem);
  line-height: 1.15; letter-spacing: -.025em; color: var(--text);
}
.art__list { margin: 0 0 var(--space-md); padding: 0; list-style: none; }
.art__list li {
  padding: var(--space-2xs) 0 var(--space-2xs) 1.4em; text-indent: -1.4em;
  color: var(--text-2); line-height: 1.6;
}
.art__list li::before { content: "— "; color: var(--chrome-dim); }
.art__note {
  margin: var(--space-lg) 0; padding: var(--space-md) var(--space-lg);
  border-left: 2px solid var(--chrome);
  background: var(--surface); color: var(--text-2); line-height: 1.6;
}
/* ── Элементы, которые может породить редактор через админку ──────────────
   Раздел новостей ведёт редактор Заказчика, и в markdown ему доступны
   подзаголовок третьего уровня, обложка и «услуги по теме». Без своих правил
   они взяли бы браузерные умолчания: h3 крупнее h2, картинка без границ.
   На существующих страницах этих классов нет — вид материалов не меняется. */
.art__h3 {
  margin: var(--space-xl) 0 var(--space-2xs);
  font-family: var(--font-display); font-variation-settings: "SHRP" var(--shrp);
  font-weight: 700; font-size: clamp(1.0625rem, .5vw + .95rem, 1.25rem);
  line-height: 1.2; letter-spacing: -.015em; color: var(--text);
}
.art__cover { margin: 0 0 var(--space-xl); }
.art__cover img { display: block; width: 100%; height: auto; border-radius: 2px; }
.art__updated { color: var(--label); }
.art__next { margin-top: var(--space-2xl); }
.art__body table {
  width: 100%; margin: 0 0 var(--space-md);
  border-collapse: collapse; font-size: var(--text-sm, .9375rem);
}
.art__body th, .art__body td {
  padding: var(--space-2xs) var(--space-sm);
  border-bottom: var(--hair) solid var(--edge); text-align: left; color: var(--text-2);
}

.art__foot { margin-top: var(--space-2xl); }
.art__foot-key {
  margin: 0 0 var(--space-sm);
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .05em; text-transform: uppercase; color: var(--label);
}

/* ═════════════════════════ Вакансии ═══════════════════════════════════════ */
.vacs { list-style: none; margin: 0; padding: 0; max-width: var(--sheet-w); }
.vac {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
  gap: var(--space-md) clamp(var(--space-lg), 3vw, var(--space-3xl));
  padding: var(--space-lg) 0;
  border-top: var(--hair) solid var(--edge);
}
.vac:first-child { border-top: 0; padding-top: 0; }
.vac__name {
  margin: 0;
  font-family: var(--font-display); font-variation-settings: "SHRP" var(--shrp);
  font-weight: 600; font-size: var(--text-h3); line-height: 1.15; letter-spacing: -.02em;
}
.vac__name a {
  display: inline-block; padding-block: 10px; margin-block: -10px;
  color: var(--text); text-decoration: none;
  border-bottom: var(--hair) solid var(--edge-strong);
}
.vac__lead { margin: var(--space-xs) 0 0; color: var(--text-2); line-height: 1.6; max-width: 60ch; }
.vac__facts { margin: 0; display: grid; gap: var(--space-2xs); align-content: start; }
.vac__facts > div {
  display: grid; grid-template-columns: minmax(0, 7.5rem) minmax(0, 1fr);
  gap: var(--space-sm);
  padding: var(--space-2xs) 0;
  border-bottom: var(--hair) solid var(--edge);
}
.vac__facts dt {
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .04em; text-transform: uppercase; color: var(--label);
}
.vac__facts dd { margin: 0; color: var(--text-2); min-width: 0; overflow-wrap: anywhere; }
@media (hover: hover) and (pointer: fine) {
  .vac__name a:hover { color: var(--green-signal); border-bottom-color: var(--green-signal); }
}
@media (max-width: 899px) { .vac { grid-template-columns: minmax(0, 1fr); } }

/* ═════════════════════════ Нормативы ══════════════════════════════════════ */
.norm-search { padding: var(--space-lg) 0; display: grid; gap: var(--space-2xs); max-width: 34rem; }
.no-js .norm-search { display: none; }   /* поле, которое ничего не делает, хуже отсутствия поля */
.norm-search__label {
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .05em; text-transform: uppercase; color: var(--label);
}
.norm-search__ctl {
  min-height: 48px; padding: 0 var(--space-md);
  background: var(--surface); color: var(--text);
  border: var(--hair) solid var(--edge-strong); border-radius: var(--radius-btn);
  font-family: var(--font-body); font-size: var(--text-md);
}
.norm-search__ctl:focus-visible {
  outline: 2px solid var(--amber); outline-offset: 2px;
  box-shadow: 0 0 0 3px var(--graphite);
}
.norm-search__hint, .norm-search__count {
  margin: 0; font-family: var(--font-mono); font-size: var(--text-mono-label); color: var(--label);
}
.norm-search__count { color: var(--green-signal); }

.norms { list-style: none; margin: 0; padding: 0; }
.norm {
  display: grid; grid-template-columns: minmax(0, 11rem) minmax(0, 1fr) max-content;
  gap: var(--space-xs) var(--space-lg);
  padding: var(--space-md) 0;
  border-top: var(--hair) solid var(--edge);
}
.norm:first-child { border-top: 0; }
.norm[hidden] { display: none; }
.norm__code {
  margin: 0; grid-column: 1;
  font-family: var(--font-mono); font-weight: 600; font-size: var(--text-sm);
  color: var(--chrome); letter-spacing: .02em;
}
.norm__year { color: var(--label); font-weight: 400; }
.norm__body { grid-column: 2; min-width: 0; }
.norm__title { margin: 0; font-size: var(--text-md); font-weight: 600; line-height: 1.35; color: var(--text); }
.norm__about { margin: var(--space-3xs) 0 0; color: var(--text-2); font-size: var(--text-sm); line-height: 1.5; max-width: 62ch; }
.norm__act { grid-column: 3; margin: 0; display: grid; gap: var(--space-3xs); justify-items: end; }
.norm__act a {
  display: inline-flex; align-items: center; min-height: 44px;
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  color: var(--text-2); text-underline-offset: 3px; white-space: nowrap;
}
.norm__dl { color: var(--chrome); }
.norm__size { color: var(--label); }
@media (hover: hover) and (pointer: fine) {
  .norm__act a:hover { color: var(--green-signal); }
}
@media (max-width: 899px) {
  .norm { grid-template-columns: minmax(0, 1fr); }
  .norm__code, .norm__body, .norm__act { grid-column: 1; }
  .norm__act { justify-items: start; grid-auto-flow: column; gap: var(--space-lg); justify-content: start; }
}
.norm-group[hidden] { display: none; }

/* ═════════════════════════ Пустые состояния ═══════════════════════════════
   Что это · почему пусто · с чего начать. Не «нет данных». */
.empty {
  border-left: 2px solid var(--amber);
  padding: var(--space-lg);
  background: var(--surface);
  max-width: 62ch;
}
.empty[hidden] { display: none; }
.empty__title { margin: 0 0 var(--space-xs); font-weight: 600; font-size: var(--text-lead); color: var(--text); }
.empty__text { margin: 0 0 var(--space-md); color: var(--text-2); line-height: 1.6; }
.empty__text a { color: var(--amber); text-underline-offset: 3px; }
.empty__act { margin: 0; display: flex; flex-wrap: wrap; gap: var(--space-xs); }

/* ═════════════════════════ Контакты ═══════════════════════════════════════
   Светлый остров во всю ширину: ровно то место, где человек читает номер
   и жмёт кнопку, а тёмный экран на улице работает зеркалом. */
.contacts {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 24rem);
  gap: clamp(var(--space-lg), 4vw, var(--space-3xl));
  align-items: start;
  padding: clamp(var(--space-xl), 4vw, var(--space-3xl)) 0;
  color: var(--light-text);
}
.contacts__kicker { color: color-mix(in oklch, var(--light-text) 72%, transparent); }
.contacts__title { color: var(--light-text); margin-bottom: var(--space-md); }
.contacts__tel {
  display: inline-flex; align-items: center; min-height: 44px;
  margin: var(--space-sm) 0 0 calc(var(--space-2xs) * -1);
  padding-inline: var(--space-2xs);
  font-family: var(--font-mono); font-weight: 600;
  font-size: clamp(1.625rem, 2.4vw + 0.9rem, 2.5rem);
  line-height: 1.1; letter-spacing: -.04em;
  color: var(--light-text); font-variant-numeric: tabular-nums;
  text-decoration: underline; text-decoration-color: var(--green-brand);
  text-decoration-thickness: 2px; text-underline-offset: 3px;
}
.contacts__note {
  margin: var(--space-xs) 0 0; max-width: 46ch; line-height: 1.55;
  color: color-mix(in oklch, var(--light-text) 82%, var(--light-surface));
}
.contacts__rows { list-style: none; margin: var(--space-lg) 0 0; padding: 0; }
.contacts__rows li {
  display: grid; grid-template-columns: minmax(0, 8.5rem) minmax(0, 1fr);
  gap: var(--space-md);
  padding: var(--space-sm) 0; border-top: var(--hair) solid var(--light-edge);
  line-height: 1.5;
}
.contacts__k {
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .04em; text-transform: uppercase;
  color: color-mix(in oklch, var(--light-text) 68%, transparent);
}
.contacts__v { min-width: 0; overflow-wrap: anywhere; }
.contacts__v a {
  display: inline-flex; align-items: center; min-height: 44px;
  padding-inline: var(--space-2xs); margin: -12px calc(var(--space-2xs) * -1);
  color: var(--light-text); text-decoration: underline; text-underline-offset: 3px;
}
.contacts__act { display: grid; gap: var(--space-sm); }
.contacts__act .btn { width: 100%; }
.contacts__small {
  margin: var(--space-2xs) 0 0;
  font-family: var(--font-mono); font-size: var(--text-mono-label); line-height: 1.6;
  color: color-mix(in oklch, var(--light-text) 74%, transparent);
}
@media (max-width: 959px) {
  .contacts { grid-template-columns: minmax(0, 1fr); }
  .contacts__act { max-width: 24rem; }
}
@media (max-width: 559px) {
  .contacts__rows li { grid-template-columns: minmax(0, 1fr); gap: var(--space-3xs); }
}
/* Фокус на светлом фоне: янтарное кольцо на белом даёт 1.8:1 и на кромке
   исчезает. Здесь кольцо графитовое — 15:1 к светлой поверхности. */
.island-wrap :where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--graphite);
  outline-offset: 2px;
  box-shadow: 0 0 0 3px var(--light-surface);
}

/* ── Карта: грузится по нажатию ────────────────────────────────────────── */
.mapbox { position: relative; aspect-ratio: 16 / 9; background: var(--surface); border: var(--hair) solid var(--edge); }
.mapbox__stub {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: center; align-items: flex-start;
  gap: var(--space-xs); padding: clamp(var(--space-md), 3vw, var(--space-2xl));
  background:
    repeating-linear-gradient(90deg, transparent 0 47px, color-mix(in oklch, var(--chrome) 8%, transparent) 47px 48px),
    repeating-linear-gradient(0deg, transparent 0 47px, color-mix(in oklch, var(--chrome) 8%, transparent) 47px 48px);
}
.mapbox__title {
  margin: 0; font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .05em; text-transform: uppercase; color: var(--chrome);
}
.mapbox__text { margin: 0; color: var(--text-2); max-width: 44ch; line-height: 1.55; }
.mapbox__act { margin: var(--space-xs) 0 0; display: flex; flex-wrap: wrap; gap: var(--space-xs); }
.mapbox iframe { display: block; width: 100%; height: 100%; border: 0; }
@media (max-width: 559px) { .mapbox { aspect-ratio: 4 / 3; } }

/* ═════════════════════════ Тексты и служебные ═════════════════════════════ */
.top--slim { grid-template-columns: minmax(0, 1fr); }
.legal { max-width: 46rem; padding-bottom: var(--space-2xl); }
.legal p { margin: 0 0 var(--space-md); color: var(--text-2); line-height: 1.7; }
.legal__h2 {
  margin: var(--space-2xl) 0 var(--space-sm);
  font-family: var(--font-display); font-variation-settings: "SHRP" var(--shrp);
  font-weight: 700; font-size: clamp(1.125rem, 0.8vw + 0.9rem, 1.375rem);
  line-height: 1.2; letter-spacing: -.02em; color: var(--text);
}
.legal__list { margin: 0 0 var(--space-md); padding: 0; list-style: none; }
.legal__list li {
  padding: var(--space-3xs) 0 var(--space-3xs) 1.4em; text-indent: -1.4em;
  color: var(--text-2); line-height: 1.6;
}
.legal__list li::before { content: "— "; color: var(--chrome-dim); }
.legal__updated {
  margin: var(--space-md) 0 0;
  font-family: var(--font-mono); font-size: var(--text-mono-label); color: var(--label);
}

/* Карта сайта */
.sitemap {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
  gap: var(--space-xl);
  padding-bottom: var(--space-2xl);
}
.sitemap__title {
  margin: 0 0 var(--space-sm); padding-bottom: var(--space-xs);
  border-bottom: var(--hair) solid var(--edge-strong);
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .05em; text-transform: uppercase; color: var(--label); font-weight: 400;
}
.sitemap__list { list-style: none; margin: 0; padding: 0; }
.sitemap__list li { border-bottom: var(--hair) solid var(--edge); }
.sitemap__list a {
  display: flex; align-items: center; min-height: 44px;
  color: var(--text-2); text-decoration: none;
}
.sitemap__note { font-family: var(--font-mono); font-size: var(--text-mono-label); color: var(--label); }
@media (hover: hover) and (pointer: fine) { .sitemap__list a:hover { color: var(--green-signal); } }

/* «Спасибо» — успех фиксируем словами и даём следующий шаг */
.done {
  max-width: 46rem; margin-bottom: var(--space-2xl);
  border-left: 2px solid var(--green-signal);
  background: var(--surface); padding: var(--space-lg);
}
.done__mark {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-mono); font-size: 1.5rem; line-height: 1; color: var(--green-signal);
}
.done__title { margin: 0 0 var(--space-xs); font-size: var(--text-lead); font-weight: 600; color: var(--text); }
/* До подтверждения заявки заголовок плашки пуст: он повторял бы заголовок
   страницы. Элемент остаётся в DOM — в него пишет скрипт после отправки. */
.done__title:empty { display: none; }
.done__text { margin: 0 0 var(--space-lg); color: var(--text-2); line-height: 1.65; }
.done__act { margin: 0; display: flex; flex-wrap: wrap; gap: var(--space-xs); }

/* 404: четыре выхода строками, а не рисунок */
.ways {
  list-style: none; margin: 0 0 var(--space-lg); padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
  gap: var(--hair);
  background: var(--edge); border: var(--hair) solid var(--edge);
}
.ways__item { background: var(--graphite); padding: var(--space-lg); min-width: 0; }
.ways__title {
  margin: 0 0 var(--space-2xs);
  font-family: var(--font-display); font-variation-settings: "SHRP" var(--shrp);
  font-weight: 600; font-size: var(--text-h3); letter-spacing: -.02em; line-height: 1.15;
}
.ways__title a {
  display: inline-block; padding-block: 10px; margin-block: -10px;
  color: var(--text); text-decoration: none;
  border-bottom: var(--hair) solid var(--edge-strong);
}
.ways__text { margin: 0; color: var(--text-2); line-height: 1.55; }
@media (hover: hover) and (pointer: fine) {
  .ways__title a:hover { color: var(--green-signal); border-bottom-color: var(--green-signal); }
}

/* ═════════════════════════ Форма заявки ═══════════════════════════════════
   Светлый бланк: поля как графы, подписи над полями, единственное
   обязательное поле названо словами. Ни одного поля «на всякий случай» —
   каждое влияет либо на расчёт, либо на разговор. */
.formbox {
  display: grid; grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
  gap: clamp(var(--space-lg), 4vw, var(--space-3xl));
  align-items: start;
  padding: clamp(var(--space-xl), 4vw, var(--space-3xl)) 0;
  color: var(--light-text);
}
.formbox--slim { grid-template-columns: minmax(0, 1fr) minmax(0, 22rem); }
.formbox .island__title { color: var(--light-text); }
.formbox .island__text { color: color-mix(in oklch, var(--light-text) 82%, var(--light-surface)); }
.formbox__facts { list-style: none; margin: var(--space-lg) 0 0; padding: 0; }
.formbox__facts li {
  display: grid; grid-template-columns: minmax(0, 7.5rem) minmax(0, 1fr);
  gap: var(--space-sm);
  padding: var(--space-xs) 0; border-top: var(--hair) solid var(--light-edge);
  line-height: 1.5;
}
.formbox__k {
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .04em; text-transform: uppercase;
  color: color-mix(in oklch, var(--light-text) 68%, transparent);
}
.formbox__v { min-width: 0; overflow-wrap: anywhere; }
.formbox__tel {
  display: inline-flex; align-items: center; min-height: 44px;
  padding-inline: var(--space-2xs); margin: -12px calc(var(--space-2xs) * -1);
  font-family: var(--font-mono); font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--light-text); text-decoration: underline;
  text-decoration-color: var(--green-brand); text-decoration-thickness: 2px;
  text-underline-offset: 3px; white-space: nowrap;
}
.formbox__ask { margin: var(--space-lg) 0 var(--space-xs); font-weight: 600; }
.formbox__list { margin: 0; padding: 0; list-style: none; }
.formbox__list li {
  padding: var(--space-2xs) 0 var(--space-2xs) 1.4em; text-indent: -1.4em;
  color: color-mix(in oklch, var(--light-text) 82%, var(--light-surface)); line-height: 1.55;
}
.formbox__list li::before { content: "— "; color: var(--green-brand); }
.formbox__ways { display: grid; gap: var(--space-sm); align-content: start; }
.formbox__ways .btn { width: 100%; }
.formbox__small {
  margin: var(--space-2xs) 0 0;
  font-family: var(--font-mono); font-size: var(--text-mono-label); line-height: 1.6;
  color: color-mix(in oklch, var(--light-text) 74%, transparent);
}
.formbox__pending { background: color-mix(in oklch, var(--light-text) 6%, transparent); }
.formbox__pending .pending__title, .formbox__pending .pending__text { color: var(--light-text); }
/* Телефон внутри светлого острова. Было 70% амбера — на светлом фоне это
   2.71:1, то есть номер, ради которого блок и существует, читался хуже
   остального текста. 55% амбера с чёрным сохраняет янтарный тон (hue 75)
   и даёт 6.26:1 — замер на рендере /uslugi/vyvoz-snega/. */
.formbox__pending .pending__text a { color: color-mix(in oklch, var(--amber) 55%, black); }

.form {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-md) var(--space-lg);
  align-content: start;
}
.field { display: grid; gap: var(--space-2xs); align-content: start; min-width: 0; }
.field--wide { grid-column: 1 / -1; }
.field__label {
  font-family: var(--font-mono); font-size: var(--text-mono-label);
  letter-spacing: .04em; text-transform: uppercase;
  color: color-mix(in oklch, var(--light-text) 74%, transparent);
}
.field__req { color: var(--green-brand); }
.field__ctl {
  width: 100%; min-height: 48px; padding: 0 var(--space-sm);
  /* 16px — не эстетика: на iOS поле с меньшим шрифтом заставляет Safari
     зумить страницу при фокусе, и человек оказывается в приближённой вёрстке. */
  font-family: var(--font-body); font-size: var(--text-md); line-height: 1.4;
  color: var(--light-text);
  background: var(--field-bg);
  border: var(--hair) solid color-mix(in oklch, var(--light-text) 32%, var(--light-surface));
  border-radius: var(--radius-btn);
}
.field__ctl--area { min-height: 96px; padding: var(--space-sm); resize: vertical; line-height: 1.5; }
.field__ctl::placeholder { color: color-mix(in oklch, var(--light-text) 52%, var(--light-surface)); }
/* Кромка поля отвечает на наведение и ввод не скачком: 140 мс — тот же
   --dur-instant, что у высокочастотных элементов системы (кнопки навески,
   строки таблицы). Анимируется только цвет кромки, толщина в базе уже задана,
   поэтому раскладка не дёргается. */
.field__ctl {
  transition: border-color var(--dur-instant) var(--ease-out);
}
.field__ctl:hover { border-color: color-mix(in oklch, var(--light-text) 52%, var(--light-surface)); }
@media (prefers-reduced-motion: reduce) { .field__ctl { transition: none; } }
/* Ошибку рисуем только после попытки отправки: подсвечивать пустое поле,
   которое человек ещё не заполнял, — значит ругать его заранее. */
.field__ctl:user-invalid { border-color: var(--danger); border-width: 2px; }
.field__hint {
  font-family: var(--font-mono); font-size: var(--text-mono-label); line-height: 1.5;
  color: color-mix(in oklch, var(--light-text) 66%, transparent);
}

.checks { display: grid; gap: var(--space-xs); }
.check {
  display: grid; grid-template-columns: 24px minmax(0, 1fr);
  gap: var(--space-sm); align-items: start;
  /* область нажатия 44px: чекбокс маленький, а промахиваться по согласию
     на телефоне человек будет постоянно */
  padding-block: 12px; cursor: pointer;
}
/* Сам квадратик 24px, но нажимается вся строка-лейбл: у .check
   вертикальные поля 12px, поэтому фактическая высота цели больше 44. */
.check__box {
  width: 24px; height: 24px; margin: 0;
  accent-color: var(--green-brand);
}
.check__text { line-height: 1.45; color: var(--light-text); min-width: 0; }
.check__text a { color: var(--light-text); text-underline-offset: 3px; }

.form__foot { display: grid; gap: var(--space-sm); justify-items: start; }
.form__foot .btn { min-width: 14rem; }
.form__status { margin: 0; font-family: var(--font-mono); font-size: var(--text-mono-label); line-height: 1.6; }
.form__status--wait { color: color-mix(in oklch, var(--light-text) 74%, transparent); }
/* Зелёный сигнальный на белом даёт 1.9:1 — как текст он нечитаем.
   Успех и ошибку набираем тёмным, а цветом только помечаем. */
.form__status--ok  { color: var(--green-brand); font-weight: 600; }
.form__status--err { color: var(--danger-text); font-weight: 600; }
.form__status--ok::before  { content: "✓ "; }
.form__status--err::before { content: "! "; }
.form__nojs {
  margin: 0; font-family: var(--font-mono); font-size: var(--text-mono-label);
  color: color-mix(in oklch, var(--light-text) 70%, transparent);
}

@media (max-width: 959px) {
  .formbox, .formbox--slim { grid-template-columns: minmax(0, 1fr); }
}
/* На 320 под значение оставалось 156px, а телефон моноширинным занимает 176 —
   номер обрезался справа на «258-06-5» (видно на рендере). Строка складывается
   в две: подпись сверху, значение под ней. Тот же приём уже применён
   к .island__rows на главной и к .contacts__rows здесь. */
@media (max-width: 559px) {
  .formbox__facts li, .vac__facts > div {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3xs);
  }
}
@media (max-width: 639px) {
  .form { grid-template-columns: minmax(0, 1fr); }
  .form__foot .btn { width: 100%; }
}

/* Ячейка без ставки. Числовые колонки набраны моноширинным и выключены
   вправо; словами набранная строка в том же кегле выглядела опечаткой,
   поэтому она мельче и тише — это подпись, а не цена. Красным или жёлтым
   не помечаем: отсутствие ставки — не ошибка и не предупреждение. */
.tbl__ask {
  font-family: var(--font-body);
  font-size: var(--text-mono-label);
  font-weight: 400;
  color: var(--text-2);
  white-space: nowrap;
}

/* ═════════════════════════ Полка действия ═════════════════════════════════
   Ставится там, где человек дочитал раздел: под таблицей цен, под первым
   экраном услуги, в конце вопросов. До неё кнопки жили только в форме внизу,
   и одиннадцать страниц подряд заканчивались текстом.

   Форма — полка с хромовой кромкой сверху, как у полки обещаний и у ставки
   в плитке каталога. Не центрированный «блок призыва»: контент прижат влево,
   центрированных блоков подряд на сайте не бывает (DESIGN-SITE, «Макет»). */
.act {
  margin: var(--space-xl) 0 0;
  padding-top: var(--space-md);
  border-top: 2px solid var(--chrome);
}
.act__note {
  margin: 0 0 var(--space-md);
  max-width: 56ch;
  font-family: var(--font-mono);
  font-size: var(--text-mono-label);
  line-height: 1.7;
  color: var(--text-2);
}
.act__row {
  display: flex; flex-wrap: wrap; gap: var(--space-sm);
  margin: 0;
}
/* Номер моноширинным: он читается как число, а не как слово, и не прыгает
   при смене цифр (тот же приём, что у ставок в таблицах). */
.act__tel { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* Первый экран услуги: полка стоит сразу под лидом, поэтому вторая кромка
   рядом с кромкой заголовка была бы лишней линией. Здесь только отступ. */
.act--top { border-top: 0; padding-top: 0; margin-top: var(--space-lg); }

/* Ниже 420 кнопки становятся полосами во всю ширину: на 375 «Рассчитать
   стоимость» и номер в строку не помещаются, вторая кнопка уезжала вниз
   узким огрызком. Тот же приём уже применён к .card__actions. */
@media (max-width: 419px) {
  .act__row { flex-direction: column; align-items: stretch; }
  .act__row .btn { width: 100%; }
}

/* ═════════════════════════ Движение ═══════════════════════════════════════
   Приём ровно один и он привязан к signature: полка со ставкой
   прочерчивается слева направо, когда блок входит в кадр — тот же жест,
   что вычерчивание выноски на первом экране. Никаких fade-up у всего подряд.

   ⚠️ 11.08.2026 — ПЕРЕПИСАНО ПОСЛЕ АВАРИИ. Прошлая версия делала родную
   кромку прозрачной (`border-top-color: transparent`), а линию рисовала
   слоем ::before из кадра `from { transform: scaleX(0) }` по
   `animation-timeline: view()` под гейтом `@supports`. В WebKit 26.5
   @supports отвечает ДА, а таймлайн не продвигается — и полка исчезала
   совсем: родная кромка прозрачна, замена застряла в нуле. Замер модели
   мёртвого таймлайна (Playwright, оба движка, 1440): каталог машин 0 полок
   из 22, обещания услуги 0 из 3, форма «заказать» 0 из 1.

   Закон, по которому переписано: видимость контента не может быть
   результатом работы чего-либо; прятать вправе только механизм, который
   в тот же момент уже умеет показать обратно. Отсюда три следствия:
   1) родная кромка НИКОГДА не прозрачна — худшее, что может случиться,
      это линия в приглушённом тоне вместо яркого хрома;
   2) прячет и приглушает только `.has-reveal` — класс ставит сторож
      в /js/reveal.js и снимает его сам, если наблюдатель не поехал;
   3) движение — обычный transition по классу `.is-in`, а не анимация
      с fill-mode: у transition нет «первого кадра», в котором можно
      застрять навсегда. */
@media (prefers-reduced-motion: no-preference) {
  /* Приглушение, а не исчезновение: если сторож почему-то не откроет блок,
     человек увидит полку тоном ниже, а не пустоту на месте линии. */
  .has-reveal .promises__item,
  .has-reveal .unitc__rate,
  .has-reveal .act:not(.act--top) { position: relative; border-top-color: var(--chrome-dim); }

  .has-reveal .promises__item::before,
  .has-reveal .unitc__rate::before,
  .has-reveal .act:not(.act--top)::before {
    content: ""; position: absolute; left: 0; right: 0; top: -2px; height: 2px;
    background: var(--chrome); transform-origin: left center; transform: scaleX(0);
    transition: transform 620ms var(--ease-out);
  }
  .has-reveal .promises__item.is-in::before,
  .has-reveal .unitc__rate.is-in::before,
  .has-reveal .act.is-in:not(.act--top)::before { transform: scaleX(1); }
}
