/* ============================================================
   Слой лендинга поверх base.css.

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

   Правило одно и оно жёсткое: **цвета и размеры объявляются и правятся
   в base.css**. Отсюда их переопределять нельзя — наслоение переопределений
   обходится дороже правки исходного значения. Разбор, из-за которого правило
   появилось, — в CLAUDE.md проекта, «Визуальная система».

   Не хватает компонента — сначала искать готовый класс в base.css
   и только потом заводить новый здесь.

   Зачистка 11.08.2026: убрано 139 правил, не встречавшихся ни в разметке,
   ни в скриптах, — остатки блоков, снятых со страницы (кейсы, цены
   на карточках услуг, калькулятор-мастер). Вид страницы проверен слепком
   до и после: 4 094 свойства на двух ширинах, ни одного расхождения.
   ============================================================ */

/* ============================================================
   ГЛАВНОЕ ПРАВИЛО АДАПТАЦИИ

   В стилях макета на экранах уже 680px контейнер задан так:

       width: min(360px, calc(100% - 28px));
       margin-left: 14px; margin-right: auto;

   То есть ширина зафиксирована на 360px и прижата влево. Отсюда всё, что
   ломалось: на 500px контент занимал 360 и жался к левому краю, справа
   оставалась пустая полоса; на 430 поля были разной ширины; на 250 контейнер
   оказывался шире окна, и текст рвался посреди слов.

   Возвращаем поведение, при котором контейнер тянется за окном и стоит
   по центру с равными полями. Одно это правило чинит адаптацию по всей
   длине страницы, а не в отдельных блоках.
   ============================================================ */
@media (max-width: 680px) {
.container {
    width: min(var(--max), calc(100% - 28px));
    margin-left: auto;
    margin-right: auto;
  }
}

/* На совсем узких экранах поля меньше — иначе на контент остаётся слишком мало */
@media (max-width: 380px) {
.container {
    width: calc(100% - 20px);
  }
}

/* Страховка от «распирания».

   В сетках макета минимальная ширина колонки задана в пикселях (240–280).
   Пока окно шире — всё в порядке, но на узком экране колонка отказывается
   сжиматься, и блок вылезает за контейнер: на окне 250px карточки занимали
   304. Правило ниже говорит сеткам и карточкам, что сжиматься можно
   до нуля, а шире контейнера быть нельзя. */
@media (max-width: 680px) {
.trust-row,
.steps-row,
.documents-grid,
.about-layout,
.contact-layout,
.footer__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  
.hero__form,
.hero__title,
.trust-item,
.about-media,
.about-card,
.service-card,
.service-feature,
.step-card,
.doc-card,
.contact-card,
.contact-form,
.promo,
.review {
    min-width: 0;
    max-width: 100%;
  }

  /* поля и кнопки внутри тоже не должны задавать ширину блоку */
  .field,
  .select,
  .textarea,
  .btn {
    max-width: 100%;
  }
}

/* Длинные слова вроде «ПРОФЕССИОНАЛЬНАЯ» на узком экране не помещаются в строку.
   Браузер рвёт их посередине, и получается «ПРОФЕССИОНАЛЬН / АЯ». Разрешаем
   перенос по слогам — язык страницы задан, правила переноса известны. */
h1,
h2,
h3,
.hero__title h1,
.section h2 {
  overflow-wrap: break-word;
  hyphens: auto;
}

/* ============================================================
   Первый экран целиком помещается в окно.

   В макете он собран в три строки: форма сверху справа, распорка, заголовок
   снизу слева. Схема красивая, но требует высоты: содержимому нужно ~940px,
   а на ноутбуке под первый экран остаётся ~630 (окно 744 минус служебная
   строка 42 и шапка 71). Поэтому:

     · вычитаем реальную высоту шапки, а не приблизительную;
     · на невысоком экране форма и заголовок встают рядом — тогда высота
       блока равна не сумме, а большему из двух;
     · размеры внутри привязаны и к ширине, и к высоте окна, чтобы на любом
       ноутбуке первый экран оставался первым экраном.
   ============================================================ */

/* Высоту задают оба: и секция, и её внутренний слой. Если поправить только
   один, второй продолжает распирать блок — так и оставалось лишних 22px. */
.hero,
.hero__inner {
  /* Ровно окно минус служебная строка и шапка — без потолка в 820px:
     с ним на большом мониторе снизу оставалась пустая полоса. */
  min-height: calc(100svh - 113px);
}

/* Порог по высоте — не на глаз: схеме макета (форма сверху, заголовок снизу)
   нужно 1129px вместе со служебной строкой и шапкой. Значит переключаться
   на две колонки надо на всём, что ниже этого, включая обычный монитор 1080. */
@media (min-width: 1081px) and (max-height: 1160px) {
.hero__inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
    grid-template-rows: auto;
    align-items: center;
    gap: var(--sp-32);
    padding: var(--sp-16) 0 var(--sp-24);
  }

  .hero__title {
    grid-column: 1;
    grid-row: 1;
  }

  .hero__form {
    grid-column: 2;
    grid-row: 1;
    align-self: center;
  }

  /* распорка между строками в этой раскладке не нужна */
  .hero__inner > div:empty {
    display: none;
  }

  /* Вложенный min() автозамена не разобрала — переведено руками. */
  .hero__title h1 {
    font-size: clamp(var(--fs-28), min(3.4vw, 6.4vh), var(--fs-44));
    line-height: 1.04;
  }

  .hero__desc {
    margin-top: var(--sp-12);
    font-size: var(--fs-15);
  }

  .hero__price {
    margin: var(--sp-12) 0 var(--sp-16);
    padding: var(--sp-8) var(--sp-16);
  }

  .hero__form {
    padding: var(--sp-24);
  }

  .hero__form h2 {
    font-size: var(--fs-20);
  }
}

/* Совсем низкие окна: прячем описание под кнопками — оно повторяет то,
   что уже сказано заголовком и полосой доверия ниже. */
@media (min-width: 1081px) and (max-height: 720px) {
.hero__desc {
    display: none;
  }

  .hero__form-trust {
    display: none;
  }
}

/* Первый экран рисуется сразу, без анимации появления.
   В макете он тоже приезжает по «reveal», и это допустимо для главной страницы
   сайта. Для страницы под платный клик — нет: человек попадает сюда с рекламы
   и в первый момент видит фотографию без заголовка, цены и формы. За этот клик
   уже заплачено, второго шанса нет. Анимацию оставляем всему, что ниже. */
.hero .reveal,
.hero__form,
.hero__title,
.trust-strip .reveal {
  opacity: 1;
  transform: none;
}

/* Ценовой якорь: первый вопрос клиента — «сколько стоит».
   На тёмном первом экране, поэтому светлый текст и полупрозрачная подложка. */
.hero__price {
  display: inline-flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sp-4) var(--sp-12);
  margin: var(--sp-16) 0 var(--sp-24);
  padding: var(--sp-12) var(--sp-16);
  border-left: 3px solid var(--sky);
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(4px);
}

.hero__price b {
  font-size: var(--fs-22);
  font-weight: 800;
  color: #fff;
  letter-spacing: -0.01em;
}

.hero__price span {
  font-size: var(--fs-13);
  color: rgba(255, 255, 255, 0.72);
}

/* Ответ формы. Место под него держится всегда, чтобы при появлении текста
   кнопка не прыгала вниз. */
.form-status {
  margin: var(--sp-12) 0 0;
  min-height: 18px;
  font-size: var(--fs-13);
  line-height: 1.45;
}

.form-status--ok {
  color: var(--green);
  font-weight: 600;
}

.form-status--error {
  color: #d05555;
  font-weight: 600;
}

.footer__legal {
  margin-top: var(--sp-12);
  font-size: var(--fs-13);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.55);
}

/* Съёмка компании сделана на прозрачном фоне — люди вырезаны.
   Макет рассчитывал на кадры с фоном и обрезал их по краям (object-fit: cover),
   из-за чего от специалистов оставались одни ноги. Показываем целиком. */
.about-media {
  background: linear-gradient(180deg, var(--soft-blue) 0%, var(--soft) 100%);
  display: block;
  padding: 0;
}

/* Кадр заполняет коробку и обрезается по краям. Прежнее «показываем целиком»
   заводилось под снимки с вырезанным фоном; с обычной фотографией оно даёт
   пустую подложку на треть блока — проверено 16.08.2026 замером: коробка
   648×769, снимок 1400×932, при contain сверху оставалось 370 точек пустоты. */
.about-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* ============================================================
   Правки читаемости и удобства.

   Макет рисовался как главная страница сайта, где человек уже пришёл сам
   и готов вчитываться. На странице под платный клик условия другие: решение
   принимается за секунды, и половина заходов — с телефона. Отсюда три правила:
   текст не мельче 14px, у всего кликабельного высота от 44px, между блоками
   меньше пустоты.
   ============================================================ */

/* ---------- Карточка услуги: собрана заново по образцу референса ----------
   В макете снимок был приглушён до прозрачности 0.58 и уведён под маску —
   он читался как фактура. На референсе фотография предмета проблемы занимает
   верх карточки целиком, цена стоит в заголовке, а кнопка идёт полосой внизу.
   Так человек, искавший «тараканы», сразу видит таракана и цену. */

.service-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  /* иначе тело и кнопка получают ширину по содержимому: тело уже карточки,
     а кнопка с внутренними отступами — шире, и карточка начинает ездить вбок */
  align-items: stretch;
  min-height: 320px;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--graphite);
}

/* Специфичность намеренно повышена: в базовых стилях есть .service-card > div
   и .service-card a — они перебивали правила по одному классу, и карточка
   молча собиралась не так, как задумано. */
.service-card > .service-card__body,
.service-card > a.service-card__cta {
  width: 100%;
  max-width: 100%;
}

/* Фотография — фоном всей карточки, во всю резкость.

   Размытие в 2px здесь стояло с 06.08: снимок «задавал настроение», не споря
   с текстом. Роман снял его 16.08.2026 вместе с затемнением — карточки должны
   показывать работу, а не намёк на неё. */
.service-card::before {
  content: "";
  position: absolute;
  /* Слой ровно по карточке. Размытие делает края полупрозрачными, но под ними
     графитовая подложка карточки — стыка не видно. Запас по периметру
     (отрицательный inset или scale) давал карточке прокрутку вбок. */
  inset: 0;
  width: auto;
  background: var(--service-image) center / cover no-repeat;
  filter: saturate(1.06);
  opacity: 1;
  -webkit-mask-image: none;
  mask-image: none;
}

/* Затемняющего слоя больше нет — снят Романом 16.08.2026 вместе с размытием.

   Псевдоэлемент оставлен пустым намеренно: в базовых стилях макета он занят
   под узкую декоративную полосу (right:34%, width:34%) внутри медиазапроса.
   Убери правило целиком — полоса вернётся и ляжет поверх снимка третью
   карточки. Так что слой объявлен и обнулён.

   Белый текст держится теперь тенью по буквам, а не подложкой: тень не гасит
   фотографию, ради которой всё и затевалось. */
.service-card::after {
  content: "";
  position: absolute;
  inset: 0;
  top: 0;
  right: 0;
  bottom: 0;
  background: none;
}

.service-card > .service-card__body {
  position: relative;
  z-index: 1;
  padding: var(--sp-16) var(--sp-24) var(--sp-16);
}

.service-card > .service-card__body .chip {
  margin-bottom: var(--sp-12);
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  backdrop-filter: blur(4px);
}

.service-card > .service-card__body h3 {
  margin: 0 0 var(--sp-8);
  font-size: var(--fs-22);
  color: #fff;
}

/* Цена — отдельной строкой и крупно: её нельзя не заметить */
.service-card > .service-card__body h3 b {
  color: var(--orange);
}

.service-card > .service-card__body p {
  margin: 0;
  color: rgba(255, 255, 255, 0.8);
}

.service-card > a.service-card__cta {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--btn-h-lg);
  padding: var(--sp-12) var(--sp-16);
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(6px);
  color: #fff;
  font-weight: 700;
  font-size: var(--fs-13);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  transition: background 0.15s ease, color 0.15s ease;
}

.service-card > a.service-card__cta:hover {
  background: var(--orange);
  color: #fff;
}

/* Широкие карточки-баннеры в макете тянули снимки, которых в проекте нет
   (treatment-field и рекламное фото производителя оборудования). Правая
   половина оставалась пустой заливкой. Ставим собственную съёмку. */
.service-feature--business h3,
.service-feature--business .label {
  color: #fff;
}

.service-feature--business p {
  color: rgba(255, 255, 255, 0.78);
}

/* ---------- Скидки: конкретный оффер вместо общей фразы ----------
   Схема с референса: огромная цифра процента, короткое условие, кнопка полосой.
   Цифра работает как графика — её видно раньше, чем прочитан текст. */

/* Лента с прокруткой: офферов больше, чем помещается в ряд, и добавлять новые
   можно без перевёрстки — как на референсе. Листается пальцем, колесом
   и кнопками; на узком экране карточка занимает почти всю ширину. */
.promo-rail {
  /* Лента на flex, а не на grid-auto-columns: у сетки ширина колонки в процентах
     считается от контейнера, а он при прокрутке сам растягивается по содержимому —
     карточки схлопывались в узкие полоски. У flex ширина задаётся самой карточке
     и от контейнера не зависит. */
  display: flex;
  gap: var(--sp-16);
  overflow-x: auto;
  /* proximity, а не mandatory: жёсткая привязка подтягивает прокрутку
     к позиции карточки на каждом кадре и добавляет своё дрожание поверх
     дробных координат. Мягкая срабатывает только когда прокрутка почти
     остановилась у карточки. */
  scroll-snap-type: x proximity;
  padding-bottom: var(--sp-4);
  scrollbar-width: none;
}

.promo-rail::-webkit-scrollbar {
  display: none;
}

.rail-btn {
  width: 52px;
  height: var(--btn-h);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--white);
  color: var(--graphite);
  font-size: var(--fs-17);
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.rail-btn:hover:not(:disabled) {
  background: var(--orange);
  border-color: var(--orange);
  color: #fff;
}

.rail-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

/* Ширина карточки — целыми точками, без процентов и vw.

   Было clamp(260px, 24%, 320px): 24% от ленты в 1305 точек даёт 313,2 —
   значение попадает ВНУТРЬ диапазона, и ограничитель его не округляет.
   Каждая следующая карточка съезжала ещё на 0,188 точки, ни одна рамка
   не ложилась на пиксельную сетку, и при прокрутке линия то темнела,
   то пропадала: рамка в одну точку размазывалась по двум пикселям экрана,
   а фаза округления менялась на каждом кадре.

   Первая попытка — заменить 24% на 30%, чтобы значение упиралось в потолок, —
   лечит только широкий экран. Ниже примерно 1070 точек тридцать процентов
   снова оказываются меньше 320, процент побеждает, и дробь возвращается:
   на 1024 карточка выходила 278,688. Поэтому процентов здесь нет вовсе,
   а ширина задана ступенями. Целое число нельзя получить из процента
   от контейнера, который сам стоит на дробной координате. */
.promo {
  flex: 0 0 320px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  scroll-snap-align: start;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--white);
}

.promo--main {
  background: var(--graphite);
  border-color: var(--graphite);
}

.promo__value {
  display: block;
  padding: var(--sp-24) var(--sp-24) 0;
  font-size: var(--fs-60);
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--orange);
}

.promo__value i {
  font-style: normal;
  font-size: var(--fs-28);
}

.promo__body {
  flex: 1;
  padding: var(--sp-12) var(--sp-24) var(--sp-24);
}

.promo__body h3 {
  margin: var(--sp-8) 0 var(--sp-8);
  font-size: var(--fs-17);
  line-height: 1.25;
  color: var(--graphite);
}

.promo__body p {
  margin: 0;
  font-size: var(--fs-13);
  line-height: 1.5;
  color: var(--muted);
}

.promo--main .promo__body h3 {
  color: #fff;
}

.promo--main .promo__body p {
  color: rgba(255, 255, 255, 0.72);
}

.promo__cta {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--btn-h-lg);
  padding: var(--sp-12) var(--sp-16);
  background: var(--orange);
  color: #fff;
  font-size: var(--fs-13);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  transition: background 0.15s ease;
}

.promo__cta:hover {
  background: var(--orange-strong);
}

/* На телефоне карточка тоже целыми точками, а не 82vw: проценты от ширины
   экрана дают дробь ровно так же. Ступени подобраны так, чтобы за краем
   всегда выглядывала следующая карточка — иначе непонятно, что лента
   листается. */
@media (max-width: 760px) {
.promo {
    flex-basis: 300px;
  }
}

@media (max-width: 400px) {
.promo {
    flex-basis: 264px;
  }
}

/* ---------- Отзывы ----------
   Схема с референса: тёмная шапка с именем и звёздами, под ней услуга,
   белое тело с текстом, снизу дата и площадка. Отзывы настоящие,
   поэтому рядом стоят ссылки на площадки — их можно проверить. */

.review-rail {
  display: flex;
  gap: var(--sp-16);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: var(--sp-4);
  scrollbar-width: none;
}

.review-rail::-webkit-scrollbar {
  display: none;
}

.review {
  flex: 0 0 clamp(280px, 30%, 380px);
  display: flex;
  flex-direction: column;
  scroll-snap-align: start;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--white);
}

.review__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-12);
  padding: var(--sp-16) var(--sp-16);
  background: var(--graphite);
}

.review__name {
  display: block;
  font-size: var(--fs-20);
  text-transform: uppercase;
  letter-spacing: 0.01em;
  color: #fff;
}

.review__service {
  display: block;
  margin-top: var(--sp-4);
  font-size: var(--fs-12);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.62);
}

.review__stars {
  flex: none;
  font-size: var(--fs-15);
  letter-spacing: 2px;
  color: var(--orange);
}

.review__text {
  flex: 1;
  margin: 0;
  padding: var(--sp-16);
  font-size: var(--fs-15);
  line-height: 1.6;
  color: var(--graphite-2);
}

.review__foot {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-12);
  padding: var(--sp-12) var(--sp-16) var(--sp-16);
  font-size: var(--fs-13);
  color: var(--muted);
}

.review-sources {
  text-align: right;
}

.review-sources__label {
  display: block;
  margin-bottom: var(--sp-8);
  font-size: var(--fs-13);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

/* Обе кнопки одной ширины — по самой широкой из них.

   Флексом это не делается: там ширина берётся по содержимому, и «2ГИС»
   выходил на 14 точек уже «Яндекс Карт». Сетка с автоколонками в 1fr
   раздаёт колонкам одинаковую ширину, равную самой широкой; сам ряд
   при этом остаётся по содержимому и прижат вправо, а не растянут
   на всю строку. */
.review-sources__links {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: var(--sp-8);
  width: fit-content;
  margin-left: auto;
}

.review-sources__links a {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-4);
  min-height: var(--btn-h-lg);
  justify-content: center;
  padding: var(--sp-8) var(--sp-16);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--white);
  text-align: center;
  transition: border-color 0.15s ease;
}

.review-sources__links a:hover {
  border-color: var(--orange);
}

.review-sources__links b {
  font-size: var(--fs-15);
  color: var(--graphite);
}

.review-sources__links span {
  font-size: var(--fs-12);
  color: var(--muted);
}

@media (max-width: 760px) {
.review {
    flex-basis: 84vw;
  }

  .review-sources {
    text-align: left;
    margin-top: var(--sp-16);
  }

  /* На узком экране ряд занимает всю строку, и обе кнопки делят её поровну.
     Иначе на 320 точках пара по 141 плюс промежуток не помещается
     и выпирает за край. */
  .review-sources__links {
    width: 100%;
    margin-left: 0;
  }
}

/* ---------- Логотипы клиентов ----------
   Сетка как на референсе: ровные ячейки с тонкой линией, логотип по центру.
   Пока это места под будущие логотипы — намеренно приглушённые, чтобы пустые
   ячейки не выглядели готовым блоком. */

.logo-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}

/* Ячейка белая. Логотипы клиентов пришли вырезками на ПРОЗРАЧНОМ фоне —
   на графите сквозь них просвечивал сам графит, и тёмные марки (Альмак,
   Ёбидоёби, Балтнефть) пропадали совсем. Тёмный фон продержался ровно
   до первого взгляда Романа: «плохая читаемость». */
.logo-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 132px;
  padding: var(--sp-12) var(--sp-16);
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--white);
}

/* Пустая ячейка-заглушка: подпись на белом. */
.logo-cell span {
  font-size: var(--fs-13);
  color: var(--line-dark);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* contain, а не cover: снимки шире ячейки, и заполнение по краю резало
   логотипы — у РЖД и SPAR отрезало половину знака. Марку клиента обрезать
   нельзя, лучше поля по бокам. */
.logo-cell img {
  width: 100%;
  height: 100%;
  max-height: 104px;
  object-fit: contain;
  transition: transform 0.25s ease;
}

.logo-cell:hover img {
  transform: scale(1.04);
}

@media (max-width: 1080px) {
.logo-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

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

  .logo-cell {
    min-height: 100px;
  }
}

/* --- Читаемость: подписи в макете опускались до 11px --- */

.trust-item span,
.service-card p,
.step-card p,
.about-card p,
.doc-card__body p,
.calc-note,
.privacy {
  font-size: var(--fs-13);
  line-height: 1.5;
}

.hero__form p,
.eyebrow {
  font-size: var(--fs-15);
}

.chip {
  font-size: var(--fs-13);
}

/* --- Кликабельность: палец не попадает в кнопку высотой 29px --- */

.btn--sm,
.doc-tab,
.calc-tab,
.service-tab {
  min-height: var(--btn-h);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.service-card .btn {
  min-height: var(--btn-h);
}

.topline a,
.footer a,
.contact-popover__item {
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-8);
}

/* --- Вертикаль: блок услуг занимал три экрана --- */

.section__top {
  margin-bottom: var(--sp-32);
}

/* ============================================================
   Телефон. Макет рисовался под большой экран, и на узком многое разъезжается:
   кнопки разной ширины, ссылки вразнобой, вкладки с полосой прокрутки,
   выпадающие списки обрезают текст. Ниже — по каждому случаю.
   ============================================================ */

@media (max-width: 760px) {
.hero__price {
    margin: var(--sp-12) 0 var(--sp-16);
    padding: var(--sp-8) var(--sp-12);
  }

  .hero__price b {
    font-size: var(--fs-20);
  }

  .section {
    padding-block: var(--sp-48);
  }

  /* Кнопки одной ширины и в столбик: разноширокие рядом читаются как ошибка.

     На телефоне их не видно вовсе — решение Романа 16.08.2026: «убирай
     кнопки позвонить и оставить заявку, они не нужны, потому что внизу
     уже есть кнопки». Липкая полоса внизу предлагает то же самое и всегда
     под рукой, а здесь они съедали пол-экрана первого впечатления.

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

     Ссылка на #order отсюда была единственной на всей странице (правило 13).
     На телефоне форма первого экрана и так скрыта, и lp.js уводил такой
     переход на #contacts — теперь уводить нечего, кнопки нет. */
  .hero__bottom {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-8);
  }

  
.hero__bottom .btn,
.service-card .btn,
.calc-lead .btn {
    width: 100%;
    justify-content: center;
    min-height: var(--btn-h-lg);
  }

  /* Вкладки документов: три в ряд без горизонтальной прокрутки */
  .doc-tabs-nav {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--sp-4);
    overflow: visible;
  }

  .doc-tab {
    width: 100%;
    padding-inline: var(--sp-4);
    font-size: var(--fs-12);
    text-align: center;
  }

  /* Выпадающие списки обрезали текст на середине слова */
  .select {
    padding-right: var(--sp-32);
    font-size: var(--fs-15);
    text-overflow: ellipsis;
  }

  /* Ячейки статистики одной высоты — иначе подписи в две строки ломают ряд */
  .stats-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .stat-item {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 104px;
    padding: var(--sp-16) var(--sp-8);
    text-align: center;
  }

  .stat-label {
    min-height: 32px;
  }

  /* Место под липкую панель задаётся в base.css одной величиной --cta-space:
     она считается из состава самой панели и учитывает безопасную зону
     телефонов с вырезом. Здесь стояло своё число 84 — оно перебивало
     базовое 76, и любая правка панели их не задевала. Правило проекта:
     размеры объявляются и правятся там, где объявлены. */

  /* Первый экран на телефоне.

     Заголовок с ценой и кнопками занимает 520px, форма — 435. Вместе 955,
     а под первый экран остаётся 773 (окно 844 минус шапка 71). Уместить оба
     можно только сжав до нечитаемого, поэтому делим иначе: первый экран —
     предложение, цена и два действия ровно по высоте окна; форма начинается
     сразу за сгибом, на расстоянии одного движения пальцем. Кнопка «Оставить
     заявку» ведёт прямо к ней. Так нет ни обрезки на середине формы,
     ни мелкого текста. */
  .hero {
    min-height: 0;
    padding-bottom: 0;
  }

  .hero__inner {
    min-height: 0;
    padding: 0;
    gap: 0;
  }

  /* Содержимое прижато к низу — решение Романа 16.08.2026: «что осталось,
     вниз блока, чтобы видна была картинка хорошо». Верх экрана отдан
     фотографии; было center, и текст сидел ровно посередине кадра. */
  .hero__title {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    /* Экран минус шапка И минус липкая полоса: она лежит поверх страницы,
       и без вычитания третья строка заголовка пряталась за кнопками.
       --cta-space уже включает запас на полосу жеста «домой». */
    min-height: calc(100svh - 71px - var(--cta-space));
    /* Снизу отступ вдвое больше верхнего: под блоком стоит липкая полоса,
       и заголовок в 24 точках от неё читался как прилипший к краю экрана.
       Роман 16.08.2026. Величина проверяется замером зазора до полосы. */
    padding: var(--sp-24) 0 var(--sp-48);
  }

  /* Форма первого экрана на телефоне снята — решение Романа 10.08.2026.
     Она уезжала под заголовок и отодвигала весь экран вниз, а способов
     оставить заявку на телефоне и без неё четыре: две кнопки под первым
     экраном, нижняя панель и форма в контактах.
     На #order — её якорь — ведёт одна кнопка «Оставить заявку». Чтобы она
     не вела в никуда, lp.js на клике проверяет, видна ли форма, и если нет —
     уводит на #contacts, куда и так ведёт «Заявка» из нижней панели. */
  .hero__form {
    display: none;
  }

  /* Кегль поднят для телефона. Регистр задан отдельно, в самом конце файла:
     здесь его перебивает общий сброс для всех заголовков. */
  .hero__title h1 {
    /* 7.8vw подобрано замером: при 8.4 слово «ПРОФЕССИОНАЛЬНАЯ» прописными
       разваливалось на «ПРОФЕССИОНАЛЬНА / Я» на 375 и 390. Крупнейший кегль,
       при котором каждая строка цела: 29 на 360, 30 на 375, 31 на 390, 34 на 430. */
    font-size: clamp(var(--fs-22), 7.8vw, 34px);
    letter-spacing: -0.01em;
  }
}

/* Невысокий телефон: описание под кнопками не помещается и выталкивает
   первый экран за границу окна. Прячем — то же самое сказано заголовком
   и полосой доверия сразу под сгибом. */
@media (max-width: 760px) and (max-height: 720px) {
.hero__desc {
    display: none;
  }

  .hero__title {
    padding: var(--sp-16) 0 var(--sp-24);
  }

  /* Вкладки документов вылезали на несколько пикселей из-за просветов */
  .doc-tabs-nav {
    gap: var(--sp-4);
  }
}

/* Увеличенная подложка-снимок выходила за карточку и добавляла ей внутреннюю
   прокрутку вбок. Слой позиционируется явно, чтобы масштаб оставался внутри. */
.service-card::before {
  left: 0;
  right: 0;
  transform-origin: center;
}

.service-card,
.promo {
  contain: paint;
}

/* Знак процента приподнят как индекс и вылезал за край карточки */
.promo__value {
  overflow: hidden;
}

.promo__value i {
  display: inline-block;
  vertical-align: baseline;
  position: relative;
  top: -0.42em;
  margin-left: 0;
}

/* ============================================================
   Самые узкие экраны — правила идут последними намеренно.

   Раньше этот блок стоял выше по файлу, и его перебивал мобильный блок
   (max-width: 760px): при равной специфичности побеждает тот, что ниже.
   Из-за этого вкладки документов оставались в три колонки и вылезали.
   ============================================================ */
@media (max-width: 420px) {
/* вкладки: в столбик, и снимаем минимальную ширину из базовых стилей */
  .doc-tabs-nav {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-4);
  }

  .doc-tab {
    min-width: 0;
    width: 100%;
  }

  /* метка категории не переносилась и распирала строку заголовка панели */
  .chip {
    max-width: 100%;
    white-space: normal;
    overflow-wrap: break-word;
  }

  /* кнопки в липкой панели делят ширину поровну и сжимаются до нуля,
     иначе вторая уезжает за экран */
  .mobile-cta .btn {
    flex: 1 1 0;
    min-width: 0;
    padding-left: var(--sp-8);
    padding-right: var(--sp-8);
    font-size: var(--fs-13);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .mobile-cta {
    left: 0;
    right: 0;
    width: 100%;
    max-width: 100vw;
    box-sizing: border-box;
  }
}

/* Размеры текста на самых узких экранах — тоже в конце файла, по той же
   причине: раньше блок стоял выше мобильного и не срабатывал, заголовок
   оставался 26px при окне 250 и слово «Профессиональная» не помещалось. */
@media (max-width: 360px) {
.hero__title h1 {
    font-size: clamp(var(--fs-20), 8vw, var(--fs-22));
    line-height: 1.15;
  }

  
.section h2 {
    font-size: clamp(var(--fs-20), 7.4vw, var(--fs-22));
  }

  
.step-card h3,
.doc-card__body h3,
.service-card h3 {
    font-size: var(--fs-17);
    line-height: 1.25;
  }

  /* Длинные слова вроде «Рыбоперерабатывающее» не помещаются в строку ни при
     каком разумном размере шрифта. Переносим по слогам; если перенос почему-то
     не сработал — рвём слово, но не даём ему выпирать за карточку. */
  h1, h2, h3, p, li, .btn {
    overflow-wrap: anywhere;
    word-break: normal;
  }
}

/* Кнопка в карточке услуги растянута отрицательными полями (margin: 10px -14px),
   чтобы лечь во всю ширину карточки поверх её внутренних отступов. На узких
   экранах отступ карточки меньше 14px, и кнопка вылезала за карточку слева —
   край срезался, потому что карточка обрезает содержимое. Растягиваем обычным
   способом, без отрицательных полей. */
@media (max-width: 680px) {
.service-card > a.service-card__cta {
    margin-left: 0;
    margin-right: 0;
    width: 100%;
    box-sizing: border-box;
  }
}

/* Название услуги и цена стоят в одном заголовке: «Тараканы <b>от 2 500 ₽</b>».
   При интерлиньяже 25px на шрифте 22px строки слипались, и на телефоне
   получалась каша. Разводим их: цена — отдельной строкой с воздухом. */
.service-card > .service-card__body h3 {
  line-height: 1.22;
  margin-bottom: var(--sp-4);
}

.service-card > .service-card__body h3 b {
  display: block;
  margin-top: var(--sp-4);
  font-size: 0.94em;
}

/* Здесь стояло усиленное затемнение снизу — на светлых снимках (трава, участок)
   белый текст без него терялся. Снято 16.08.2026 вместе с основным.
   Читаемость держит тень по буквам, объявленная ниже. */

/* Перенос по слогам нужен только там, где слово иначе не помещается: на очень
   узких экранах. На обычном телефоне он даёт «продук-товых» в заголовке
   карточки — формально верно, читается плохо. Оставляем перенос словам,
   но не заголовкам, начиная с 361px. */
@media (min-width: 361px) {
h1, h2, h3,
  .hero__title h1,
  .section h2 {
    hyphens: manual;
  }
}

/* Промежуток между телефоном и планшетом: 560–680px.
   Ниже 560 всё в одну колонку — иначе карточки становятся слишком узкими.
   Выше 560 одна колонка уже смотрится пусто: карточка на 650px шириной
   с одной строкой текста. Возвращаем две колонки там, где содержимое
   это выдерживает. */
@media (min-width: 560px) and (max-width: 680px) {
.documents-grid,
.trust-row,
.footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ============================================================
   БЛОК УСЛУГ — перестроен 06.08 по правкам Романа

   Шесть направлений вместо шести вредителей: человек ищет «дезинсекцию»
   или «травят ли клопов», а не «муравьи от 2 500». Внутри карточки порядок
   от общего к частному: услуга → что за объект → что именно делаем → цена.

   Поведение снято с образца живьём, а не по памяти:
     · фотография лежит в карточке всегда, поверх неё сплошная плашка;
     · при наведении плашка уходит за полсекунды, текст становится белым;
     · на экранах до 640px плашки нет вовсе — фото видно сразу,
       потому что наводить курсор там нечем.
   ============================================================ */

/* Промо-карточка: белый градиент заменён на графит.
   Светлая подложка спорила с фотографией и с остальной страницей —
   это единственное белое пятно среди тёмных карточек. */
/* Снимок прислан Романом 13.08.2026. Точка привязки по вертикали 6%, а не
   center: карточка почти впятеро шире, чем высока, и при обрезке по центру
   от кадра оставалась полоса с коленом и полом. На 6% в кадр входят кепка
   и куртка с логотипом — то, ради чего снимок и нужен. Подобрано сравнением
   снимков: 18% отрезало кепку, center — всё выше пояса. */
.service-feature {
  background:
    linear-gradient(90deg, rgba(32, 36, 45, 0.88) 0%, rgba(32, 36, 45, 0.7) 40%, rgba(32, 36, 45, 0.45) 72%, rgba(32, 36, 45, 0.45) 100%),
    url("../images/feature-kitchen.webp") right 6% / cover no-repeat,
    var(--graphite);
  border-color: transparent;
}

.service-feature h3,
.service-feature .label {
  color: #fff;
}

.service-feature p {
  color: rgba(255, 255, 255, 0.8);
}

/* Снимок прислан Романом 13.08.2026. Бригада стоит в правой половине кадра,
   левая — пустая стена, туда и ложится текст карточки.

   Точка привязки по вертикали 14%, а не center: карточка почти впятеро шире,
   чем высока, и от кадра остаётся узкая полоса. На 30% в неё попадали одни
   торсы, на center — ноги и оборудование на полу. На 14% видны маски и лица,
   ради которых снимок и нужен. Подобрано сравнением снимков, как и у соседней
   карточки частных клиентов. */
.service-feature--business {
  background:
    linear-gradient(90deg, rgba(32, 36, 45, 0.88) 0%, rgba(32, 36, 45, 0.7) 40%, rgba(32, 36, 45, 0.45) 72%, rgba(32, 36, 45, 0.45) 100%),
    url("../images/feature-brigade.webp") right 14% / cover no-repeat,
    var(--graphite);
}

/* ---------- Лента услуг ---------- */

.services-rail {
  display: flex;
  gap: var(--sp-16);
  margin-top: var(--sp-16);
  padding-bottom: var(--sp-4);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.services-rail::-webkit-scrollbar {
  display: none;
}

.services-rail > .service-card {
  flex: 0 0 clamp(260px, 31%, 380px);
  scroll-snap-align: start;
}

/* ---------- Карточка услуги ---------- */

/* Фотография видна всегда.

   До 16.08.2026 она проявлялась по наведению — механика была взята с референса.
   Роман её снял: на телефоне наводить нечем (там снимок и так показывался
   сразу), а на десктопе лента услуг выглядела рядом одинаковых тёмных
   прямоугольников, и что за каждым стоит своя работа, узнавал только тот,
   кто провёл мышью по всем восьми. */

.services-rail > .service-card::before {
  opacity: 1;
}

.services-rail > .service-card > .service-card__body h3 {
  font-size: clamp(var(--fs-20), 2.1vw, var(--fs-28));
  line-height: 1.1;
  font-weight: 800;
  letter-spacing: -0.015em;
  color: #fff;
}

/* Объект работы — вторая строка. Голубой, потому что это указатель,
   а не текст: по нему глаз находит нужную карточку. */
.service-card__object {
  display: block;
  margin-bottom: var(--sp-8);
  font-size: var(--fs-13);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--sky);
}

.services-rail > .service-card > .service-card__body p {
  font-size: var(--fs-13);
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.82);
}

.services-rail > .service-card > a.service-card__cta {
  z-index: 2;
}

/* Кнопки прокрутки — те же, что у скидок и отзывов */
.rail-controls {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-8);
  margin-top: var(--sp-12);
}

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

/* Кнопка карточки на фотографии: плотнее подложка, иначе на светлом
   снимке надпись сливается. */
/* Кнопка светлее подложки, а не темнее. Была залита графитом с прозрачностью —
   на графитовой карточке получалось тёмное на тёмном, и от фона её отделяла
   только тонкая линия. На проявившейся фотографии светлая заливка тоже
   работает: она отделяет кнопку от снимка. */
.services-rail > .service-card > a.service-card__cta {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(6px);
  color: #fff;
}

.services-rail > .service-card > a.service-card__cta:hover {
  background: var(--sky);
  color: #fff;
}

/* ============================================================
   КАРТОЧКА УСЛУГИ — сборка заново 06.08 по замечаниям Романа

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

     · заголовки стояли на разной высоте (67, 88, 68 пикселя от верха) —
       описания разной длины толкали текст, и карточки в ряду не совпадали;
     · кнопка была сдвинута влево на 17px при ширине карточки 380 —
       её растягивали отрицательные поля из базовых стилей, рассчитанные
       на другой внутренний отступ. Отсюда «плашка кривая и не доходит
       до края»;
     · между текстом и кнопкой оставалась дыра в 14 пикселей, и в неё
       просвечивала фотография;
     · затемнение жило на теле, а тело начиналось не от верха карточки —
       выше него градиента не было вовсе, и переход выглядел оборванным.

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

.services-rail > .service-card {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

/* Текстовая зона занимает всю карточку, поэтому затемнение идёт от самого
   верха вниз, без оборванного края. Содержимое внутри прижато к низу. */
.services-rail > .service-card > .service-card__body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  margin: 0;
}

/* Заголовок в две строки у «Акарицидной обработки» и в одну у остальных —
   держим место под две, иначе соседние карточки разъезжаются по высоте. */
.services-rail > .service-card > .service-card__body h3 {
  align-items: flex-end;
  margin: 0 0 var(--sp-4);
}

/* То же для описания: три строки у одних, две у других. Место держим
   под три — тогда цена и заголовок стоят на одной линии во всём ряду. */
.services-rail > .service-card > .service-card__body p {
  margin: 0;
}

/* Кнопка: во всю ширину карточки, вплотную к тексту.
   Отрицательные поля из базовых стилей снимаются здесь для всех экранов,
   а не только для узких, как было раньше. */
.services-rail > .service-card > a.service-card__cta {
  flex: 0 0 auto;
  margin: 0;
  width: 100%;
  box-sizing: border-box;
  border-radius: 0;
}

/* Заголовки должны стоять на одной линии на ЛЮБОЙ ширине.

   Первая правка держала под описание три строки — столько оно занимает
   на широкой карточке. На узкой те же слова разворачиваются в четыре-пять
   строк, упираются в запас и снова начинают толкать заголовок вверх:
   замер показал 100, 121, 101, 100 — вторая карточка выбивалась на 21px.

   Поэтому запас задан по ширине карточки, а не одним числом. Плюс жёсткое
   ограничение по строкам: если Роман пришлёт описание длиннее, карточка
   не поедет, а обрежет лишнее многоточием. */
.services-rail > .service-card > .service-card__body p {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

@media (min-width: 1100px) {
.services-rail > .service-card > .service-card__body p {
    -webkit-line-clamp: 3;
    min-height: 4.5em;
  }
}

/* На самых узких карточках длинное название разворачивается в три строки —
   запас под две тогда не спасает. */
@media (max-width: 400px) {
.services-rail > .service-card > .service-card__body h3 {
    min-height: 2.4em;
  }
}

/* На 250px «Акарицидная обработка» и «Защита растений» разворачиваются
   в три строки, остальные держатся в двух — запас под две снова оставлял
   их выше соседей на 20px. Это последняя ширина, где заголовки не совпадали. */
@media (max-width: 300px) {
.services-rail > .service-card > .service-card__body h3 {
    min-height: 4.6em;
  }
}

/* Последнее, что выбивалось на 250–270px: подпись объекта. «Деревья
   и кустарники» там разворачивается в две строки, остальные держатся
   в одной — и одна карточка из шести уезжала вверх на 16 пикселей.
   Искал в заголовке и описании, а дело было в строке между ними:
   замер по частям карточки показал 34px против 17. */
/* Порог 340, а не 300: на 320px «Деревья и кустарники» тоже разворачивается
   в две строки. Первый раз я нашёл это на 250 и закрыл только его, а рядом
   стояла та же ширина с той же бедой. */
@media (max-width: 340px) {
.services-rail > .service-card .service-card__object {
    min-height: 2.5em;
  }
}

/* ============================================================
   КАРТОЧКА УСЛУГИ — схема с референса, правка Романа 06.08 (вторая)

   Что было не так в моей сборке и как устроено в образце.

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

     .services_pest_elem_card  — светлая подложка, overflow: hidden
       ├ __image  — absolute, начинается с 84px и уходит вниз
       └ __info   — relative, лежит СВЕРХУ: заголовок на 28px от края

   То есть текст сверху, картинка снизу, и никакого градиента вообще.
   А на их карточках с фотографией во всю площадь читаемость держит
   не градиент, а равномерная вуаль:

     .service_slide__bg::before { background: rgba(0, 0, 0, 0.28) }

   Делаем так же: заголовок наверх, градиент убран, вместо него ровная
   графитовая вуаль и лёгкое размытие снимка. Фотография остаётся видна
   целиком — она приглушена, а не съедена.
   ============================================================ */

/* Текст в левый верхний угол.

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

   Строки выравниваются между карточками: заголовку отведено место под две
   строки, подписи — под одну. Иначе описание у «Фумигации» начинается выше,
   чем у «Акарицидной обработки территории», и ряд читается рваным. */
.services-rail > .service-card > .service-card__body {
  justify-content: flex-start;
  background: none;
  padding: var(--sp-24) var(--sp-24) var(--sp-16);
}

/* Фотография плюс ровное затемнение в 10%.

   Размытия нет. Градиентной накладки нет — она снята 16.08.2026, когда Роман
   прислал снимки, сделанные с тёмным низом под текст. В тот же день он
   попросил вернуть затемнение, но другое: «затемни карточки маленькие
   в услугах на 10% по всей площади».

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

   Читаемость держится в первую очередь самим снимком, а не этой десятиной.
   Проверять не глазами: tools/contrast-cards.js меряет контраст белого
   текста по настоящим пикселям экрана, порог 3:1. Пришёл светлый кадр —
   проверка это скажет, а карточка промолчит. */
.services-rail > .service-card::before {
  background:
    linear-gradient(180deg, rgba(32, 36, 45, 0.62) 0%, rgba(32, 36, 45, 0.42) 26%, rgba(32, 36, 45, 0.45) 52%, rgba(32, 36, 45, 0.45) 100%),
    var(--service-image) center / cover no-repeat;
  filter: none;
}

/* Карточка возвращается к прежней высоте: место под фотографию сверху
   больше не нужно — теперь там текст. */
/* Высота держится минимумом, чтобы карточки стояли в ряд одинаковыми.
   Было 330px под содержимое со ссылкой «Рассчитать стоимость» внутри тела;
   ссылка снята 10.08.2026, и те же 330 оставляли под текстом 97px пустоты.
   Замер без минимума: карточке хватает 249px, воздуха при этом 16px — мало.
   290 возвращает воздух к прежним ~57px. */
.services-rail > .service-card {
  min-height: 290px;
}

/* ============================================================
   МОБИЛЬНАЯ ВЁРСТКА БЛОКОВ — правка 06.08

   Замер на 390px показал три вещи, которые на десктопе не видны:

     · заголовок секции 21px при подписи под ним 15px — иерархии нет,
       блок читается как сплошной текст (на десктопе заголовок 44px);
     · шапка секции разложена в колонку с зазором 40px — заголовок
       и лид отрывались друг от друга на треть экрана;
     · градиент промо-карточки идёт слева направо. Он рассчитан на широкую
       карточку: слева плотный графит под текст, справа открытая фотография.
       На узком экране текст попадает как раз на светлую часть и тонет.
   ============================================================ */
@media (max-width: 760px) {
.section h2 {
    font-size: clamp(var(--fs-22), 6.6vw, var(--fs-28));
    line-height: 1.12;
  }

  .section__top {
    gap: var(--sp-12);
  }

  /* Промо-карточка: затемнение сверху вниз, потому что фотография
     на узком экране лежит под всем блоком, а не сбоку от текста. */
  .service-feature,
  .service-feature--business {
    background:
      linear-gradient(180deg, rgba(32, 36, 45, 0.78) 0%, rgba(32, 36, 45, 0.6) 34%, rgba(32, 36, 45, 0.45) 66%, rgba(32, 36, 45, 0.45) 100%),
      var(--feature-image) center / cover no-repeat,
      var(--graphite);
  }

  .service-feature {
    --feature-image: url("../images/feature-kitchen.webp");
  }

  .service-feature--business {
    --feature-image: url("../images/feature-brigade.webp");
  }
}

/* На телефоне карточка занимает почти всю ширину экрана, но не всю:
   краешек следующей должен быть виден — иначе не понятно, что лента листается.
   При фиксированных 260px на экране 390 обрезок выходил в 55px и читался
   как случайно обрезанный блок, а не как продолжение. */
@media (max-width: 680px) {
.services-rail > .service-card {
    flex: 0 0 82%;
  }
}

/* Последняя правка выравнивания — обе величины в пикселях, а не в em.

   В em они считались от размера шрифта самого элемента, а он разный:
   у подтверждённой цены 17px, у заглушки «цена по объекту» — 14. Один
   и тот же запас «3,4em» давал 58 и 48 пикселей, и цены расходились на 10.
   То же с описанием: запас в em не удерживал строку, когда текст длиннее.

   Высота задана жёстко, лишнее обрезается — тогда ряд ровный при любой
   длине текста, включая те, что Роман пришлёт позже. */
.services-rail > .service-card > .service-card__body p {
  height: 84px;
  min-height: 0;
}

@media (min-width: 1100px) {
.services-rail > .service-card > .service-card__body p {
    height: 63px;
  }
}

/* Тень под текстом карточки. Вуаль приглушает снимок равномерно, но снимки
   разной светлоты: на стеллаже с препаратами и на траве голубая подпись
   всё равно читалась слабее, чем на тёмных. Тень стоит всегда — на графите
   её не видно, на фотографии она держит текст. */
.services-rail > .service-card > .service-card__body h3,
.services-rail > .service-card > .service-card__body p,
.services-rail > .service-card .service-card__object {
  text-shadow: 0 1px 12px rgba(15, 17, 21, 0.55);
}

/* ============================================================
   ТЁМНОЕ ПЯТНО НА КАРТОЧКАХ — убрано 06.08

   На проявившейся фотографии левее центра было видно тёмное пятно.
   Это остаток прежней схемы: в базовых стилях макета у карточки есть
   декоративный псевдоэлемент шириной 34% (right: 34%, width: 34%),
   а я когда-то покрасил его градиентом затемнения — тогда он служил
   подложкой под текст.

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

   Убираем совсем: читаемость держат вуаль на слое фотографии и тень
   под текстом, отдельный слой затемнения больше ни для чего не нужен.
   ============================================================ */
.service-card::after {
  display: none;
}

/* ============================================================
   ЧИТАЕМОСТЬ ШРИФТА — правка 06.08 по замечанию Романа

   Текст на всей странице читался как размазанный жирный. Причин две,
   и они усиливали друг друга.

   1. В базовых стилях стоит `-webkit-font-smoothing: antialiased`.
      На macOS это норма, а на Windows свойство ОТКЛЮЧАЕТ субпиксельное
      сглаживание (ClearType) и переводит текст на серое. Буквы теряют
      чёткость краёв и выглядят замыленными. Роман и десять человек,
      подтвердивших проблему, смотрят с Windows.

   2. Сверхжирные начертания на мелком кегле: 94 элемента весом 800–900,
      причём меню 13px весом 800, кнопка 12px весом 900, телефон 14px
      весом 900. У Inter вес 900 — это Black; на 12–14px его штрихи
      съедают просветы внутри букв, и слово превращается в пятно.

   Ниже — возврат к субпиксельному сглаживанию и разумная шкала весов:
   чем мельче текст, тем легче начертание. Крупные заголовки остаются
   жирными — там это работает.
   ============================================================ */

/* Возвращаем ClearType: на Windows это главное для чёткости */
html,
body,
body * {
  -webkit-font-smoothing: auto;
  -moz-osx-font-smoothing: auto;
}

/* --- Мелкий текст: 11–13px --- */

.label,
.eyebrow,
.doc-card__type,
.chip,
.doc-tab,
.header__cta,
.topline a,
.topline span,
.nav a,
.nav__contact-link,
.contact-popover__item,
.trust-item strong,
.stat-label {
  font-weight: 600;
}

/* --- Средний текст: 14–17px. Кнопки и вкладки заметны и без Black --- */

.btn,
.service-tab,
.calc-tab,
.faq-card summary,
.promo__cta,
.service-card__cta,
.rail-btn,
.mobile-cta .btn,
.form input,
.form select,
input,
select {
  font-weight: 700;
}

/* --- Имена в отзывах и подписи покрупнее --- */
.review__name,
.service-card__object {
  font-weight: 700;
}

/* --- Крупные заголовки: здесь тяжёлое начертание уместно --- */

.hero__title h1,
.section h2,
.stat-num,
.promo__value,
.step-num {
  font-weight: 800;
}

/* Текст абзацев — обычный вес, без утолщения */

p,
.trust-item span,
.step-card p,
.faq-card p {
  font-weight: 400;
}

/* Остатки тяжёлых начертаний на мелком тексте, найденные повторным замером:
   номер телефона, пункты под формой, ссылки на направления и текст
   промо-блока. */
[data-phone] b,
[data-phone-text],
.topline b,
.hero__form-trust span,
.hero__form-trust,
.service-feature p,
.service-feature--business p {
  font-weight: 600;
}

/* Номер телефона на кнопке — чуть плотнее, он несёт действие */
.btn [data-phone-text],
.btn b {
  font-weight: 700;
}

/* ============================================================
   БЛОК КОМАНДЫ

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

   Состав взят из базы знаний (семь человек), а не выдуман. Имена и фото
   помечены заглушками: имена сотрудников лежат в справочнике вместе
   с рабочими номерами, и выносить их на публичную страницу без решения
   Романа нельзя.
   ============================================================ */

/* Команда листается на всех экранах, а не раскладывается сеткой.
   Людей в блоке будет семеро и, вероятно, больше: при любой сетке последний
   ряд остаётся неполным — одна-две карточки с пустотой справа. Лента этим
   не страдает и уже используется на странице для услуг, скидок и отзывов. */
.team-grid {
  display: flex;
  gap: var(--sp-16);
  margin-top: var(--sp-24);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding-bottom: var(--sp-4);
}

.team-grid::-webkit-scrollbar {
  display: none;
}

.team-grid > .team-card {
  flex: 0 0 clamp(230px, 24%, 300px);
  scroll-snap-align: start;
}

.team-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
}

/* Место под портрет. Пропорция 4:5 — вертикальный кадр, в который человек
   вписывается по пояс. Ровно эта же пропорция указана в ТЗ на съёмку. */
.team-card__photo {
  position: relative;
  aspect-ratio: 4 / 5;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--soft);
  border-bottom: 1px solid var(--line);
}

.team-card__photo span {
  font-size: var(--fs-12);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--line-dark);
}

.team-card__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.team-card__body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  padding: var(--sp-16) var(--sp-16) var(--sp-16);
}

.team-card__body h3 {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-17);
  font-weight: 700;
  line-height: 1.25;
  color: var(--graphite);
}

.team-card__role {
  margin-bottom: var(--sp-8);
  font-size: var(--fs-12);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--sky);
}

.team-card__body p {
  margin: 0;
  font-size: var(--fs-13);
  font-weight: 400;
  line-height: 1.5;
  color: var(--muted);
}

@media (max-width: 560px) {
.team-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-12);
  }

  /* На телефоне вертикальный портрет занимает пол-экрана — делаем кадр шире */
  .team-card__photo {
    aspect-ratio: 16 / 10;
  }

}

/* Принцип специалиста — короткая цитата под описанием.
   Прижата к низу карточки, чтобы у соседних карточек цитаты стояли
   на одной линии независимо от длины описания. */
.team-card__quote {
  margin: var(--sp-12) 0 0;
  padding: var(--sp-8) 0 0;
  border-top: 1px solid var(--line);
  font-size: var(--fs-13);
  font-style: italic;
  font-weight: 400;
  line-height: 1.5;
  color: var(--graphite);
}

/* Кавычки стоят прямо в тексте цитаты, а не в псевдоэлементах.
   Псевдоэлементами они были до 07.08, и когда цитате понадобился
   display:flex для выравнивания по нижнему краю, ::before и ::after
   превратились в отдельные элементы строки: открывающая кавычка уехала
   в начало второй строки, закрывающая — к правому краю. */

/* Описание тянется, цитата остаётся внизу */
.team-card__body p {
  flex: 1 1 auto;
}

/* На телефоне команда листается вбок, а не тянется столбиком.

   Четыре карточки с портретами вертикально — это четыре экрана прокрутки
   подряд, и до следующего блока человек чаще всего не доходит. Лента
   компактна и уже используется на странице для услуг, скидок и отзывов —
   значит, жест знаком. Правка Романа 07.08. */
/* На узких экранах карточка занимает почти всю ширину: краешек следующей
   виден, значит понятно, что лента листается. */
@media (max-width: 680px) {
.team-grid > .team-card {
    flex: 0 0 78%;
    max-width: 320px;
  }
}

/* Цитаты у всех разной длины: у Руслана три строки, у остальных две.
   Выровнены они были по низу карточки, но верхняя граница расходилась
   на 20 пикселей и линия отчёркивания шла уступом. Держим место под три
   строки — тогда и черта, и текст встают ровно во всём ряду.
   Величина в пикселях, а не в em: em считается от размера шрифта самого
   элемента, и на этом я уже обжигался с ценами в карточках услуг. */
/* Цитата и должность держат постоянную высоту, иначе черта отчёркивания
   идёт уступом: «Менеджер по работе с клиентами» занимает две строки против
   одной у «Дезинфектор 3-го разряда», а цитаты у всех разной длины.
   Высота ступенчатая: чем уже карточка, тем больше строк занимает тот же текст. */
.team-card__role {
  display: flex;
  align-items: flex-end;
  min-height: 2.6em;
}

/* Высота цитаты не фиксируется. Была попытка выровнять черту отчёркивания,
   задав ей постоянную высоту, — и текст стал обрезаться: у длинных принципов
   пропадали первые строки, а на 768px не влезала ни одна цитата из шести.
   Ровная линия не стоит съеденных слов; карточки в ленте и так выравниваются
   по высоте самой высокой. */
.team-card__quote {
  display: block;
}

/* Должность «Менеджер по работе с клиентами» на узкой карточке разворачивается
   в три строки против одной-двух у дезинфекторов. Ширина карточки зависит
   не от экрана напрямую, а от того, сколько их помещается в ленту, поэтому
   запас увеличен ровно в двух диапазонах, где замер показал три строки:
   на самых узких телефонах и на планшетах, где карточка сжимается до 230px. */
@media (max-width: 340px), (min-width: 700px) and (max-width: 1180px) {
.team-card__role {
    min-height: 3.9em;
  }
}

/* Имя тоже держит две строки: «Владимир Зиновьевич» на узкой карточке
   переносится, «Сергей Юрьевич» — нет, и всё, что ниже, съезжало на строку.
   Замер это показал не сразу: я сначала грешил на должность, потому что
   у менеджера она длиннее всех, а расходилось из-за имени. */
.team-card__body h3 {
  display: flex;
  align-items: flex-end;
  min-height: 2.5em;
}

/* Байт — единственный в ленте, кто не человек. Отличие сдержанное: фирменная
   рамка вместо серой. Ставить рядом с живыми людьми что-то кричащее незачем —
   он и сам предупреждает об этом первой строкой описания. */
.team-card--byte {
  border-color: var(--sky);
}

/* Панель параметров растёт по содержимому.

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

/* Телефон: калькулятор ужат по мелочам, но без фокусов.

   Попытка уложить его целиком в один экран — фиксированные высоты с прокруткой
   внутри плюс форма заявки, спрятанная за кнопку, — откатана 08.08: получились
   вложенные прокрутки и три кнопки подряд. Осталось то, что не мешает: убран
   повтор подзаголовка, заголовок мельче, разделу оставлено место под нижнюю
   полосу «Звонок · Заявка». */
@media (max-width: 860px) {
/* Внизу лендинга висит полоса «Звонок · Заявка» — она перекрывала низ
     калькулятора. Оставляем ей место, иначе кнопка расчёта уходит под неё.

     В шкалу не переводится намеренно (исключение Романа): это не отступ
     ради воздуха, а высота чужого элемента плюс запас. Ближайшая ступень
     64px меньше самой полосы. */
  .calculator {
    padding-bottom: 84px;
  }

  .calc-note {
    font-size: var(--fs-12);
    line-height: 1.35;
  }

  .calculator .section__top h2 {
    font-size: var(--fs-28);
    line-height: 1.1;
  }

  /* Отступ до калькулятора был поджат до 12px, когда над ним стояли и заголовок,
     и подзаголовок раздела, и подпись в правой панели — втроём они съедали экран.
     Подзаголовки сняты 10.08.2026, повод исчез: раздел встаёт в общий ритм 32px,
     как все остальные. */
}

/* Длинная строка выбранного («Дезинсекция, Дератизация, …») не должна
   распирать свою колонку. У колонок сетки и у флекс-детей минимальная ширина
   по умолчанию равна содержимому, и многоточие не срабатывает — строка
   раздвигала левую панель, а правая сжималась в щепку с рваным текстом.
   min-width: 0 разрешает им ужиматься, и многоточие начинает работать. */
/* ============================================================
   КВИЗ И ФОРМА — два блока на компьютере, один на телефоне.

   Требование Романа: «квиз и форма для ПК, для мобилки один блок»,
   и размеры блоков — общие для страницы, а не свои. Сетка взята у блока
   контактов: 0.85fr / 1.15fr, промежуток 22. Здесь колонки зеркальны —
   вопросам места нужно больше, чем форме из двух полей.

   Рамка квиза постоянного размера, шаги меняются внутри. Это единственный
   способ сделать блок железно неподвижным: прежние попытки — фиксированная
   высота с прокруткой внутри — дали три прокрутки друг в друге и были
   откатаны. Прокрутки нет, потому что один шаг всегда меньше рамки.
   ============================================================ */

.calc-shell > * {
  min-width: 0;
}

/* ── ТЕЛЕФОН: ОДИН БЛОК ───────────────────────────────────────────────────
   Рамка переезжает на обёртку, у детей её нет — два блока читаются как один.
   Формы в нём нет вовсе (указание Романа по образцу):
   расчёт виден сразу, а «Вызвать специалиста» открывает всплывающее окно. */
@media (max-width: 860px) {
.calc-shell {
    grid-template-columns: 1fr;
    gap: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: #fff;
    overflow: hidden;
  }
}

/* Всплывающее окно с заявкой. */
.calc-modal {
  position: fixed;
  inset: 0;
  /* Выше всего, что приклеено к экрану: шапка сайта — 80, нижняя полоса
     «Звонок · Заявка» — 90, всплывашка контактов — 120. Со слоем 60 шапка
     рисовалась поверх окна и срезала ему заголовок: выглядело так, будто
     карточка криво сидит на экране. */
  z-index: 130;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-16);
  background: rgba(35, 39, 45, 0.6);
}

.calc-modal[hidden] {
  display: none;
}

.calc-modal__box {
  position: relative;
  width: min(420px, 100%);
  max-height: 90svh;
  overflow-y: auto;
  padding: var(--sp-24);
  border-radius: var(--radius);
  background: #fff;
}

.calc-modal__close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 34px;
  height: 34px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: #fff;
  color: var(--graphite);
  font-size: var(--fs-20);
  line-height: 1;
  cursor: pointer;
}

.calc-modal__close:hover {
  border-color: var(--sky);
  color: var(--sky);
}

/* Место под крестик: он лежит поверх, в правом верхнем углу — 34 точки
   шириной плюс 12 отступа. Без запаса длинный заголовок уезжал под него. */
.calc-modal__title {
  display: block;
  padding-right: calc(var(--sp-48) + var(--sp-8));
  font-size: var(--fs-22);
  text-transform: uppercase;
}

.calc-modal__lead {
  margin: var(--sp-8) 0 0;
  color: var(--muted);
  font-size: var(--fs-13);
  line-height: 1.4;
}

.calc-lead--modal {
  background: transparent;
  padding: var(--sp-16) 0 0;
  display: grid;
  gap: var(--sp-12);
}

.calc-lead--modal .field {
  border: 1px solid var(--line);
}

.calc-lead--modal .privacy {
  color: var(--muted);
}

@media (max-width: 860px) {
.calc-modal {
    padding: var(--sp-12);
    align-items: flex-end;
  }

  .calc-modal__box {
    padding: var(--sp-16);
  }
}

/* Скрытое обязано быть скрытым.

   У кнопок и у сетки собственный display, и он сильнее признака hidden:
   без этого правила «Назад» на первом шаге и «Вызвать специалиста» до расчёта
   остаются на экране. Правило уже стояло однажды и было потеряно при уборке
   стилей второй панели — поэтому оно теперь живёт отдельным блоком. */
[hidden] {
  display: none !important;
}

/* ============================================================
   ЗАГОЛОВКИ БЕЗ КАПСА — правка Романа 09.08.2026

   Капс остаётся ровно в трёх местах: логотип (он набран заглавными
   в самой разметке, стилями его никто не переводит), мелкие
   подписи-надзаголовки .label и .eyebrow, и кнопки .btn.

   Всё остальное читается обычным регистром. Капс в длинном заголовке
   съедает скорость чтения: буквы одинаковой высоты, глазу не за что
   зацепиться, и «ОБРАБОТКА ОТ НАСЕКОМЫХ И ГРЫЗУНОВ ПОД КЛЮЧ»
   разбирается по буквам вместо того, чтобы схватываться целиком.

   Правится здесь, а не в base.css: тот не редактируется по правилу
   проекта. Селекторы повторяют базовые один в один — при равном весе
   побеждает файл ниже, а lp.css подключён после base.css.
   ============================================================ */

h1,
h2,
h3,
h4,
.hero h1,
.section h2,
.hero__form h2,
.service-feature h3,
.service-card h3,
.services-rail > .service-card > .service-card__body h3,
.doc-business-text h3,
.step-card h3,
.footer h3,
.footer h4,
/* Абзац под заголовком hero-формы: это обычный текст в три строки,
капсом он читался как крик и мешал самому заголовку. */
.hero__form p {
  text-transform: none;
}

/* Строчные буквы читаются мельче заглавных при том же кегле: у капса
   вся строка ростом с заглавную, у обычного текста — со строчную.
   Возвращаем разницу размером. Только широкие экраны: ниже 1180
   и ниже 680 в base.css своя лестница размеров, она уже подобрана
   под ширину и трогать её незачем. */
@media (min-width: 1181px) {
.hero h1 {
    font-size: clamp(var(--fs-44), 4.7vw, var(--fs-60));
  }

  
.section h2 {
    font-size: var(--fs-60);
  }

  .service-feature h3 {
    font-size: clamp(var(--fs-28), 4.4vw, var(--fs-60));
  }

  .doc-business-text h3 {
    font-size: var(--fs-28);
  }

  .hero__form h2 {
    font-size: var(--fs-22);
  }

  .service-card h3 {
    font-size: var(--fs-22);
  }

  .step-card h3 {
    font-size: var(--fs-22);
  }

  .services-rail > .service-card > .service-card__body h3 {
    font-size: clamp(var(--fs-22), 2.2vw, var(--fs-28));
  }
}

/* ============================================================
   РЯДЫ КНОПОК ОДНОЙ ШИРИНЫ — правка Романа 09.08.2026

   Флекс раздаёт ширину по содержимому, и ряд получается рваным:
   у ссылок направлений разброс был 112 точек («Акарицидная обработка»
   вдвое длиннее «Озонации»), у пары кнопок под вопросами — 56.

   Лечится не флексом, а сеткой: у автоколонок 1fr ширина одна на всех
   и равна самой широкой ячейке. Ряд при этом не растягивается на всю
   строку — остаётся по содержимому.

   .hero__bottom намеренно не трогаем: там разная ширина работает как
   иерархия, главная кнопка с номером обязана быть заметнее второй. */

/* ============================================================
   Ленты тянутся мышью — правка 10.08.2026

   Класс `is-draggable` ставит скрипт и только тогда, когда содержимое
   действительно шире ленты: рука на неподвижном блоке — враньё.
   `is-dragging` живёт ровно от порога в 5px до отпускания.
   ============================================================ */

.is-draggable {
  cursor: grab;
}

/* Горизонтальные ленты не должны получать вторую ось прокрутки из-за
   дробного переполнения содержимого по высоте. */
.promo-rail,
.review-rail,
.services-rail,
.team-grid,
.kit-rail,
.doc-tabs-nav {
  overflow-y: hidden;
}

.is-dragging {
  cursor: grabbing;
  user-select: none;
}

/* Пока тянут — ничто внутри не перехватывает курсор на себя: ни ссылка
   с «указателем», ни картинка со своим перетаскиванием. */
.is-dragging * {
  cursor: grabbing !important;
  user-select: none;
}

/* ============================================================
   Оборудование — 10.08.2026

   Карточки прислал Роман готовыми композициями 1448×1086 с набранным
   текстом внутри. Целиком их на страницу не поставить: окно под снимок
   427px, текст под ширину 1448 сжимается втрое и не читается. Поэтому
   от композиции берётся левая квадратная часть — сам прибор на фирменном
   фоне, — а текст живёт в разметке.

   Приборов семь, поэтому лента, а не сетка: 3+3+1 в ряду смотрится обрубком.
   ============================================================ */

.kit-rail {
  display: flex;
  gap: var(--sp-16);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding-bottom: var(--sp-4);
}

.kit-rail::-webkit-scrollbar {
  display: none;
}

.kit-card {
  flex: 0 0 320px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
}

.kit-card__photo {
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--soft);
}

.kit-card__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.kit-card__body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  padding: var(--sp-24) var(--sp-24) var(--sp-16);
}

.kit-card__body h3 {
  font-size: var(--fs-20);
  line-height: 1.15;
}

.kit-card__type {
  display: block;
  margin-top: var(--sp-4);
  color: var(--sky-dark);
  font-size: var(--fs-13);
  font-weight: 700;
}

.kit-card__body p {
  margin-top: var(--sp-12);
  color: var(--muted);
  font-size: var(--fs-15);
  line-height: 1.55;
}

@media (max-width: 760px) {
.kit-card {
    flex-basis: 300px;
  }
}

@media (max-width: 400px) {
.kit-card {
    flex-basis: 264px;
  }
}

/* Кнопки-переключатели вместо выпадающих списков на два-три варианта. */
.calc-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
}

.calc-chip {
  padding: var(--sp-8) var(--sp-12);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #fff;
  color: var(--ink);
  font-size: var(--fs-13);
  font-weight: 600;
  cursor: pointer;
}

.calc-chip:hover {
  border-color: var(--sky-btn);
}

.calc-chip.is-on {
  border-color: var(--sky-btn);
  background: var(--sky-btn);
  color: #fff;
}

/* Поле размера: число и единица в одну строку. Класс новый — прежний
   калькулятор рисовал число иначе, и стилей у него не было. */
/* ============================================================
   КАЛЬКУЛЯТОР — по образцу, выбранному Романом, 10.08.2026

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

   Системный <select> здесь не годится принципиально: ширину его списка
   задаёт самая длинная опция, и на телефоне он вылезал за края экрана.
   У образца ровно поэтому свой виджет.
   ============================================================ */

.calc-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--sp-24);
  align-items: stretch;
}

/* Высота постоянная — требование Романа 10.08.2026: ни форма, ни картинка
   не меняют размер ни при каких раскладах. Раньше блок дышал: пусто — 484,
   выбрана категория — 553, дальше больше, и страница под ним прыгала.

   660 взято замером самого высокого состояния: заказчик, категория, тип
   помещения и площадь — четыре строки, больше полей не бывает ни у частных,
   ни у бизнеса. Прокрутки внутри нет: содержимое помещается. */
.calc-form {
  display: flex;
  flex-direction: column;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  overflow: hidden;
}

/* Высота по содержимому — правка Романа 10.08.2026. Раньше блок резервировал
   место под ещё не показанные поля, и между «Категорией услуг» и «Итого»
   зияла пустота. Прыжки при выборе — плата за это, и она принята осознанно. */

/* ---------- шапка ---------- */

.calc-form__top {
  padding: var(--sp-16) var(--sp-24);
  background: var(--graphite);
}

.calc-form__title {
  color: #fff;
  font-size: var(--fs-13);
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ---------- строки ---------- */

/* Все строки — дети одной сетки: колонка подписи получает ширину самой
   длинной подписи и одинакова во всех строках. Была фиксированная 128px,
   и у коротких подписей вроде «Заказчик» половина колонки пустовала. */
.calc-form__content {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-16);
  flex: 1 1 auto;
  padding: var(--sp-24);
}

.calc-form__fields,
.calc-form__line {
  display: contents;
}

.calc-form__caption {
  color: var(--muted);
  font-size: var(--fs-13);
  font-weight: 600;
}

.calc-form__hint {
  grid-column: 2;
  margin: calc(var(--sp-8) * -1) 0 0;
  color: var(--sky-dark);
  font-size: var(--fs-12);
  font-weight: 600;
}

/* ---------- выбор из двух: заказчик и подуслуга ----------

   Подчёркивание — язык вкладок, а не выбора. Здесь выбирают одно из двух,
   поэтому вид взят у вкладок «Частным / Бизнесу» в блоке направлений услуг:
   два равных сегмента во всю ширину, активный залит графитом. */

.calc-form .calc-tabs,
.calc-form .calc-chips {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  overflow: hidden;
}

.calc-form .calc-tab,
.calc-form .calc-chip {
  min-height: var(--btn-h);
  padding: var(--sp-8) var(--sp-12);
  border: 0;
  border-right: 1px solid var(--line);
  border-radius: 0;
  background: #fff;
  color: var(--muted);
  font-size: var(--fs-13);
  font-weight: 800;
  line-height: 1.2;
  cursor: pointer;
}

.calc-form .calc-tab:last-child,
.calc-form .calc-chip:last-child {
  border-right: 0;
}

.calc-form .calc-tab.is-active,
.calc-form .calc-chip.is-on {
  background: var(--graphite);
  color: #fff;
}

/* ---------- свой выпадающий список ---------- */

.calc-select {
  position: relative;
  min-width: 0;
}

.calc-select__field {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  width: 100%;
  min-height: 50px;
  padding: var(--sp-8) var(--sp-12);
  border: 1px solid var(--line-dark);
  border-radius: var(--radius);
  background: #fff;
  text-align: left;
  cursor: pointer;
}

.calc-select.is-open .calc-select__field {
  border-color: var(--sky-btn);
}

.calc-select__value {
  flex: 1 1 auto;
  min-width: 0;
}

.calc-select__value strong {
  display: block;
  font-size: var(--fs-15);
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.calc-select__value--empty strong {
  color: var(--muted);
  font-weight: 600;
}

/* Пояснение живёт второй строкой и обрезается многоточием: длинное
   «Тараканы, клопы, блохи, муравьи, моль и др.» не должно тянуть поле. */
.calc-select__term {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--fs-12);
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.calc-select__arrow {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  margin-right: 4px;
  border-right: 2px solid var(--ink);
  border-bottom: 2px solid var(--ink);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 0.15s ease;
}

.calc-select.is-open .calc-select__arrow {
  transform: rotate(-135deg) translate(-3px, -3px);
}

/* Меню шириной ровно в поле — за края экрана не выходит никогда. */
.calc-select__menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  display: none;
  max-height: 264px;
  overflow-y: auto;
  padding: var(--sp-4);
  border: 1px solid var(--line-dark);
  border-radius: var(--radius);
  background: #fff;
  box-shadow: 0 18px 40px rgba(20, 24, 30, 0.16);
}

.calc-select.is-open .calc-select__menu {
  display: block;
}

.calc-select__item {
  display: block;
  width: 100%;
  padding: var(--sp-8) var(--sp-12);
  border: 0;
  border-radius: 8px;
  background: none;
  text-align: left;
  cursor: pointer;
}

.calc-select__item:hover,
.calc-select__item.is-on {
  background: var(--soft);
}

.calc-select__item strong {
  display: block;
  font-size: var(--fs-15);
  line-height: 1.25;
}

.calc-select__item-term {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--fs-12);
  line-height: 1.3;
}

/* ---------- число ---------- */

.calc-num {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  min-width: 0;
}

.calc-num .field {
  flex: 1 1 auto;
  min-width: 0;
}

.calc-num__unit {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: var(--fs-13);
  font-weight: 600;
  white-space: nowrap;
}

/* ---------- ошибка, итог, кнопки ---------- */

.calc-form__error {
  margin: 0 var(--sp-24) var(--sp-12);
  color: #c0392b;
  font-size: var(--fs-12);
  font-weight: 700;
}

.calc-form__result {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-16);
  margin-top: auto;
  padding: var(--sp-16) var(--sp-24) var(--sp-8);
}

/* Сумма и перечёркнутая цена до скидки стоят в одной строке справа.

   Когда вместе с подписью они не помещаются — сумма уходит на свою строку
   целиком, а не ломается внутри. Ломать число нельзя: «от 18 198 ₽»
   в три строки не читается как цена вовсе. Разрешаем перенос строке
   результата и запрещаем внутри самой суммы. */
.calc-form__result {
  flex-wrap: wrap;
}

.calc-form__result-sum {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: var(--sp-8);
  min-width: 0;
  margin-left: auto;
}

/* Только когда это сумма. Фраза «Подготовим коммерческое предложение»
   стоит в том же месте и переноситься обязана. */
.calc-form__result-sum.is-sum,
.calc-form__result-sum.is-sum .calc-form__result-value,
.calc-form__result-sum.is-sum .calc-form__result-old {
  white-space: nowrap;
  overflow-wrap: normal;
}

.calc-form__result-sum:not(.is-sum) {
  max-width: 70%;
}

/* Цена до скидки. Мелко и приглушённо: она здесь не ради себя, а чтобы
   было видно, что скидка уже снята с суммы рядом. */
.calc-form__result-old {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: var(--fs-15);
  font-weight: 500;
  text-decoration-thickness: 1px;
  white-space: nowrap;
}

/* Главное число блока — крупное и голубое, правка Романа 11.08.2026:
   до неё сумма была набрана как служебная строка и терялась.

   Голубой взят не фирменный. `--sky` на белом даёт 2,67:1 при пороге 3:1
   даже для крупного текста — замерено. `--sky-strong` даёт 4,65:1, проходит
   и для мелкого, и остаётся голубым. Цена — то самое место, где читаемость
   важнее оттенка.

   Значением бывает и фраза «Подготовим коммерческое предложение»: она
   набирается тем же кеглем, но обычным цветом — не сумма, а сообщение. */
.calc-form__result-value {
  min-width: 0;
  color: var(--sky-strong);
  font-size: var(--fs-28);
  font-weight: 800;
  line-height: 1.1;
  text-align: right;
  overflow-wrap: anywhere;
}

.calc-form__result-sum:not(.is-sum) .calc-form__result-value {
  color: var(--muted);
  font-size: var(--fs-17);
  font-weight: 400;
  line-height: 1.25;
}

/* Пояснение под «Итого». Кегль поднят с 12 до 13: на двенадцати мелкий
   серый текст даёт цветную кайму от сглаживания и читается как ссылка.
   Никакого подчёркивания у него нет и не было — проверено замером. */
.calc-form__note {
  padding: 0 var(--sp-24) var(--sp-16);
  color: var(--muted);
  font-size: var(--fs-13);
  line-height: 1.5;
  text-decoration: none;
}

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

   Вид взят у плашки скидки — та же светлая подложка и полоса слева, — но
   без кружка с процентом: он говорил бы о скидке, а речь о другом. */
.calc-caution {
  margin-top: var(--sp-12);
  padding: var(--sp-12);
  border-left: 3px solid var(--sky);
  border-radius: 6px;
  background: rgba(70, 189, 240, 0.1);
  color: var(--graphite);
  font-size: var(--fs-13);
  line-height: 1.35;
}

/* Ширина колонок задана подписями, а не красотой.

   Сначала главному действию отдавалось больше места: обведённая кнопка
   читается крупнее залитой. После переименования второй в «Заказать
   со скидкой 10%» (правка Романа 11.08.2026) ей стало не хватать двадцати
   точек, подпись переносилась на две строки и тянула вверх обе кнопки —
   66 вместо 54. Перенос уродливее лёгкого перевеса, поэтому место отдано
   той, которой оно нужно: замерено, требуется 293 против 268 у первой.

   Если подписи снова изменятся, это поймает прогон калькулятора: он
   сравнивает нужную ширину с наличной и валится на переносе. */
/* ============================================================
   ПОСТОЯННАЯ ВЫСОТА БЛОКА — требование Романа 11.08.2026

   «Я больше не хочу видеть эти скачущие по размеру формы блоков.»
   Замерено до правки: высота гуляла на 273 точки — поля появлялись по мере
   заполнения, плашка и расчёт возникали только после нажатия, и страница
   под калькулятором дёргалась на каждый выбор.

   Держится это тремя вещами, и убрать можно только все три сразу:
     · строки полей рисуются всегда, недоступные — закрытыми (calc.js);
     · места под сумму, строку скидки и счётчики закреплены снизу здесь;
     · плашка стоит всегда, а не появляется после расчёта.
   ============================================================ */

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

.calc-form__line > .calc-select .calc-select__field,
.calc-form__line > .calc-tabs,
.calc-form__line > .calc-chips,
.calc-form__line > .calc-num .field {
  min-height: var(--calc-field-h);
}

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

   Высота задана здесь, а не на .calc-form__fields: у той display: contents,
   коробки у неё нет вовсе, и min-height на ней ничего не делает. */
.calc-form__content {
  min-height: calc(var(--calc-field-h) * 3 + var(--sp-16) * 4);
}

/* Высота держится одной величиной на всю форму, а не запасами у каждой
   части по отдельности. Части всё равно дышат: сумма то есть, то нет;
   строка под ней то в одну строку, то в две; полей у бизнеса на одно
   меньше. Гнаться за каждой — бесконечная работа.

   Поэтому высота задана форме целиком, а середина с полями объявлена
   растягивающейся (flex: 1 1 auto выше) и добирает разницу на себя.
   Что бы ни происходило внутри, снаружи блок неподвижен. */
/* Закреплённая высота блока. В базовых стилях макета она 730 — это на сорок
   точек больше, чем блоку нужно в самом высоком состоянии. Разницу забирала
   середина с полями (она растягивается), и получалась пустота между последним
   полем и ценой. Роман 16.08.2026: «предлагаю сжать немного блок, чтобы её
   не было».

   692 = 682 (самое высокое состояние — бизнес на ширинах 1100–1280, где
   плашка разворачивается в две строки) плюс десять точек запаса. Меньше
   ставить нельзя: содержимое полезет поверх соседей. Замеряется прогоном
   высоты калькулятора с ключом «авто» — не на глаз.

   Правится здесь, а не в base.css: файл макета проект не трогает. */
:root {
  --calc-form-h: 692px;
}

.calc-form {
  height: var(--calc-form-h);
}

/* Место под сумму: до расчёта оно пустое, после — занято числом в 28 кегля. */
.calc-form__result-sum {
  min-height: calc(var(--fs-28) * 1.1);
}

/* Строка под суммой: до расчёта в ней подзаголовок, после расчёта —
   причина, если она есть. Место под две строки резервируется, чтобы блок
   не дёргался, когда текст меняет длину. */
.calc-form__note {
  min-height: calc(var(--fs-13) * 1.5 * 2);
}

/* А если после расчёта в ней пусто — место не резервируется вовсе.

   Строка «Скидка 10% уже учтена» убрана Романом 13.08.2026, и с тех пор
   в обычном расчёте сюда не попадает ничего: пояснения в модели нет,
   причина у посчитанной услуги пустая. Две зарезервированные строки
   оставались пустыми — 39 точек между ценой и плашкой ни за чем.
   Роман назвал это первым, что бросается в глаза: «между ценой и описанием
   расчёта пустота бесполезная».

   Высота блока закреплена сверху, поэтому схлопывание пустой строки блок
   не дёргает: освободившееся место забирает середина с полями. */
.calc-form__note:empty {
  min-height: 0;
  padding-bottom: 0;
}

/* Значок калькулятора нужен только на телефоне — там кнопка сжимается
   до квадрата. На большом экране места хватает на подпись, и значок рядом
   с ней был бы украшением. */
.calc-btn__icon {
  display: none;
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
}

.calc-form__bottom {
  display: grid;
  grid-template-columns: 1fr 1.1fr;
  gap: var(--sp-12);
  padding: 0 var(--sp-24) var(--sp-24);
}

/* ---------- картинка ---------- */

/* Высоту строки задаёт форма, а не снимок. Снимок вертикальный, и пока он
   участвовал в расчёте высоты, форма растягивалась под него: между полями
   и «Итого» зияла пустота на полтысячи точек. Картинка выведена из потока
   и просто заполняет ту высоту, которая получилась у формы. */
.calc-banner {
  position: relative;
  align-self: stretch;
  min-height: 320px;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--soft);
}

.calc-banner img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center;
}

/* ---------- узкие экраны ---------- */

@media (max-width: 960px) {
.calc-shell {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Картинка уходит: она украшение, а форма — работа. Так же и у образца. */
  .calc-banner {
    display: none;
  }
}

@media (max-width: 680px) {
.calc-form__top,
  .calc-form__content,
  .calc-form__result,
  .calc-form__note,
  .calc-form__bottom {
    padding-left: var(--sp-16);
    padding-right: var(--sp-16);
  }

  .calc-form__error {
    margin-left: var(--sp-16);
    margin-right: var(--sp-16);
  }

  /* Подпись встаёт над полем: колонку под неё в 360 точек не выделить.
     Правило смотрит на сетку .calc-form__content, а не на строку: строки
     теперь display: contents и своей сетки не имеют. */
  /* Между парами «подпись + поле» нужен воздух, иначе всё слипается
     в один столбец без ритма. Отбиваем поля, а не подписи. */
  .calc-form__content > .calc-select,
  .calc-form__content > .calc-num,
  .calc-form__content > .calc-tabs,
  .calc-form__content > .calc-chips,
  .calc-form__content > .textarea {
    margin-bottom: var(--sp-12);
  }

  .calc-form__hint {
    grid-column: 1;
    margin-top: 0;
  }

  .calc-form .calc-tabs {
    gap: var(--sp-16);
  }

  .calc-form__result {
    padding-top: var(--sp-12);
  }

  .calc-form__result-value {
    font-size: var(--fs-17);
  }

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

     Заказ здесь залит, хотя в разметке у него класс светлой кнопки: вид
     задаётся местом, а не классом. Прежде он был текстовой ссылкой внизу
     и терялся. */
  .calc-form__bottom {
    grid-template-columns: var(--btn-h-lg) minmax(0, 1fr);
    gap: var(--sp-8);
    align-items: stretch;
  }

  /* Квадрат со значком — светлый, как в образце. Залей его тем же голубым,
     что и заказ, и две кнопки слились бы в одно пятно: главным должно быть
     одно действие, а пересчёт рядом — вспомогательным. */
  .calc-form__bottom .btn:first-child {
    padding: 0;
    border-color: var(--line);
    background: var(--soft);
    color: var(--graphite);
  }

  .calc-btn__icon {
    display: block;
  }

  .calc-btn__text {
    /* Спрятано от глаз, но не от экранных дикторов: у кнопки есть
       aria-label, а текст остаётся в разметке. */
    display: none;
  }

  .calc-form__bottom .btn--light {
    border-color: var(--sky-btn);
    background: var(--sky-btn);
    color: #fff;
  }
}

/* ============================================================
   КАЛЬКУЛЯТОР НА ТЕЛЕФОНЕ — один экран целиком

   Требование Романа 11.08.2026: «весь калькулятор должен поместиться
   на один экран». Замерено до правки: блок 995 при экране 844, из которых
   свободны 702 — шапка сайта липкая (71) и нижняя полоса (71) съедают
   остальное. Резать пришлось 293 точки, и по мелочи их не набрать.

   Что ужато и почему именно это:
     · тёмная шапка «ПАРАМЕТРЫ» убрана целиком — над блоком уже стоит
       заголовок секции, и второй раз называть его незачем;
     · поля с 50 до 44, подписи с 13 до 11 кегля;
     · плашка с 13 до 12 кегля и с плотной строкой;
     · отступы формы с 24 до 16.

   Кегль ниже двенадцати не опускаем даже ради места: мелкий серый текст
   на телефоне не читается, а не «читается хуже».
   ============================================================ */

@media (max-width: 680px) {
:root {
    --calc-field-h: 44px;
    /* Чуть выше самого высокого состояния: закрепи меньше — содержимое полезет
       поверх соседей, и итог наедет на поля. Проверяется прогоном
       `node tools/calc-height.js 390 844 авто`. Замер 13.08.2026 — 640
       (было 647; строка «Заказчик» лишилась подписи и стала ниже). Значение
       не опускаю: запас в десять точек дешевле, чем правка при первом же
       новом поле. */
    --calc-form-h: 650px;
  }

  /* Заголовок блока стоит выше, в шапке секции. */
  .calc-form__top {
    display: none;
  }

  /* Подписи стоят в строку с полями, как на компьютере, а не над ними.
     Столбиком каждая строка стоила лишних двадцати точек — на четырёх
     это восемьдесят, ровно та разница, из-за которой блок не влезал
     в экран. Ширину колонки задаёт самая длинная подпись. */
  .calc-form__content {
    grid-template-columns: max-content minmax(0, 1fr);
    align-items: center;
    gap: var(--sp-8) var(--sp-12);
    padding: var(--sp-16);
    min-height: 0;
  }

  .calc-form__caption {
    margin-bottom: 0;
    font-size: var(--fs-12);
    line-height: 1.15;
  }

  /* Заказчик: подпись убрана, вкладки во всю ширину блока — правка Романа
     13.08.2026. Слово «Заказчик» ничего не объясняло: «Частному лицу»
     и «Бизнесу» говорят сами за себя, а колонку подписей занимали и без него
     три оставшиеся строки, так что сетка от этого не поехала.

     Строки — display: contents, своей сетки у них нет, и растягивать надо
     сами вкладки по колонкам родителя, а не строку. */
  .calc-form__line--audience > .calc-form__caption {
    display: none;
  }

  .calc-form__line--audience > .calc-tabs {
    grid-column: 1 / -1;
  }

  .calc-select__field {
    padding: var(--sp-8) var(--sp-12);
  }

  .calc-select__value strong {
    font-size: var(--fs-15);
  }

  /* Термин виден в списке при выборе, а в закрытом поле второй строкой
     не показывается: человек только что его прочитал, а строка стоит
     шестнадцать точек — на телефоне это заметная доля экрана. */
  .calc-select__field .calc-select__term {
    display: none;
  }

  .calc-form__result {
    padding: var(--sp-8) var(--sp-16) var(--sp-4);
  }

  .calc-form__note {
    padding: 0 var(--sp-16) var(--sp-8);
    min-height: calc(var(--fs-12) * 1.4 * 2);
    font-size: var(--fs-12);
  }

  .calc-caution {
    margin: 0 var(--sp-16) var(--sp-12);
    padding: var(--sp-8) var(--sp-12);
    font-size: var(--fs-12);
    line-height: 1.3;
  }

  .calc-form__bottom {
    padding: 0 var(--sp-16) var(--sp-16);
  }
}

@media (max-width: 680px) {
/* Кегль вернулся к шкале — 13, как у прочих вкладок страницы.

     Стояло 11 в порядке исключения: колонку подписей задавала самая длинная
     («Категория услуг»), вкладкам оставалось около ста точек на каждую,
     и «Частному лицу» переносилось на две строки. С 13.08.2026 подписи
     у этой строки нет, вкладки во всю ширину блока — по 154 точки на кнопке
     при экране 390, — и повода для исключения не осталось. Замерено:
     обе кнопки в одну строку.

     Перенос запрещён по-прежнему: он тут не спасает, а ломает — вторая
     строка растит кнопку, а с ней и весь блок, высота которого закреплена. */
  .calc-form .calc-tab {
    padding: var(--sp-8) var(--sp-4);
    white-space: nowrap;
  }
}

/* ============================================================
   ССЫЛКА «ПОДРОБНЕЕ» И ОКНО С УСТРОЙСТВОМ ЦЕНЫ

   Указание Романа 11.08.2026: в плашке одна строка, подробности —
   во всплывающем окне. Пять строк под расчётом перетягивали внимание
   с самой цены, а выбросить их было нельзя: без объяснения расчёт
   читается как цена-приманка.

   Ссылка сделана кнопкой, а не тегом ссылки: она никуда не ведёт,
   а открывает окно. Ссылка без адреса ломает навигацию с клавиатуры
   и обещает переход, которого не будет.
   ============================================================ */

.calc-caution__more {
  padding: 0;
  border: 0;
  background: none;
  color: var(--sky-dark);
  font: inherit;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.calc-caution__more:hover {
  color: var(--sky-strong);
}

/* Окно подробностей шире формы заявки: в нём читают, а не заполняют,
   и строка в 420 точек для длинного текста слишком узкая — глаз устаёт
   на переносах. Ширина задана через `width`, а не `max-width`: у базового
   правила стоит `width: min(420px, 100%)`, и максимум её не перебивает. */
.calc-modal__box--info {
  width: min(640px, 100%);
}

.calc-info {
  display: grid;
  gap: var(--sp-16);
  margin-top: var(--sp-16);
}

.calc-info__text {
  margin: 0;
  color: var(--muted);
  font-size: var(--fs-13);
  line-height: 1.5;
}

@media (max-width: 680px) {
  .calc-modal__box--info {
    max-height: 84vh;
  }

  .calc-info {
    gap: var(--sp-12);
  }
}

/* ============================================================
   ОКНО «КАК РАССЧИТЫВАЕТСЯ СТОИМОСТЬ» — оформление длинного текста

   Текст Романа 12.08.2026, целиком. Он длинный намеренно: человек, который
   открыл «Подробнее», хочет разобраться, а не прочитать ещё одну отписку.
   Задача оформления — сделать его читаемым, а не сократить.
   ============================================================ */

/* Разделы окна — карточки-раскладушки, как в блоке вопросов на странице.
   Просьба Романа 12.08.2026. Класс faq-card взят готовый: тот же вид,
   то же поведение от браузера, и правка вида в одном месте меняет оба места.
   Здесь только то, чем окно отличается от страницы. */
.calc-info__card + .calc-info__card {
  margin-top: var(--sp-8);
}

/* В окне карточки теснее, чем на странице: там вокруг них воздух секции,
   здесь — узкая колонка, и отступ в 24 съедал бы четверть строки. */
.calc-info__card summary {
  padding: var(--sp-12) var(--sp-48) var(--sp-12) var(--sp-16);
  font-size: var(--fs-13);
}

.calc-info__card .faq-icon {
  right: var(--sp-12);
  width: 22px;
  height: 22px;
}

.calc-info__card > *:not(summary) {
  padding: 0 var(--sp-16) var(--sp-16);
}

.calc-info__card .calc-info__text {
  padding-bottom: 0;
}

.calc-info__card > .calc-info__text:last-child {
  padding-bottom: var(--sp-16);
}

/* Вступление стоит до карточек и карточкой не является: сворачивать в нём
   нечего. */
.calc-info__intro {
  display: grid;
  gap: var(--sp-8);
  margin-bottom: var(--sp-16);
}

.calc-info__text + .calc-info__text {
  margin-top: var(--sp-8);
}

/* Итог раздела: он подводит черту под сказанным выше, поэтому отделён
   и набран цветом заголовков — иначе теряется в потоке. */
.calc-info__text--after {
  margin-top: var(--sp-12);
  color: var(--ink);
  font-weight: 600;
}

/* Четыре фактора внутри карточки. Полоса слева вместо отступа: на телефоне
   отступ съедает и без того узкую строку. */
.calc-info__sub {
  margin-top: var(--sp-12);
  padding-left: var(--sp-12);
  border-left: 2px solid var(--line);
}

.calc-info__subhead {
  display: block;
  margin-bottom: var(--sp-4);
  color: var(--ink);
  font-size: var(--fs-13);
  font-weight: 800;
}

.calc-info__steps {
  margin: var(--sp-12) 0 0;
  padding-left: var(--sp-24);
  display: grid;
  gap: var(--sp-4);
  color: var(--muted);
  font-size: var(--fs-13);
  line-height: 1.5;
}

.calc-info__steps li::marker {
  color: var(--sky-dark);
  font-weight: 800;
}

/* ============================================================
   ШАПКИ ОТЗЫВОВ НА ТЕЛЕФОНЕ — правка 16.08.2026

   Роман: «шапки прыгающие, не адаптирован заголовок отзыва, и получаются
   они скачут по размерам». Замер подтвердил: на 390 точках тёмные шапки
   выходили 75, 90, 99 и 114 — разброс 39 точек. Карточки в ленте одной
   высоты, поэтому белый текст под шапками начинался на разных уровнях,
   и лента выглядела рваной.

   Причина — имя в 20 кегле прописными и подпись услуги рядом со звёздами:
   на узкой карточке «НАТАЛЬЯ КУЗНЕЦОВА» разворачивается в две строки,
   «Дезинсекция, выезд в субботу» — тоже, а «МАРИЯ» остаётся в одной.

   Лечим двумя вещами сразу: кегль ниже, чтобы большинство имён легло
   в строку, и место резервируется под две строки имени и одну под услугу.
   Резерв, а не обрезка: имя человека многоточием не режут. Что длиннее
   двух строк — подрезается, но таких в списке нет, и проверка это меряет.
   ============================================================ */

@media (max-width: 680px) {
  .review__name {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-height: calc(var(--fs-17) * 1.15 * 2);
    font-size: var(--fs-17);
    line-height: 1.15;
  }

  .review__service {
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-height: calc(var(--fs-12) * 1.3);
    font-size: var(--fs-12);
    line-height: 1.3;
  }

  /* Звёзды прижаты к верху, чтобы не тянуть шапку вниз вслед за именем. */
  .review__stars {
    align-self: flex-start;
    font-size: var(--fs-13);
    letter-spacing: 1px;
  }
}

/* ============================================================
   СВОДКА РАСЧЁТА В ОКНЕ ЗАЯВКИ — 16.08.2026

   Человек нажал «Вызвать специалиста» после расчёта и должен видеть,
   о чём заявка: тот же объект, услуга, объём и та же сумма, что были
   на экране. Числа берутся из ответа движка, страница ничего не считает.
   ============================================================ */

.calc-modal__summary {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  margin: var(--sp-16) 0;
  padding: var(--sp-12) var(--sp-16);
  border-left: 3px solid var(--sky);
  border-radius: 4px;
  background: var(--soft);
  text-align: left;
}

/* Каждый факт — своей строкой. Без этого куски встают в одну:
   span по умолчанию строчный, и «Квартира или дом» слипается
   с «Дезинсекция» и с суммой. */
.calc-modal__summary > * {
  display: block;
}

.calc-modal__summary-label {
  margin-bottom: var(--sp-4);
  font-size: var(--fs-12);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.calc-modal__summary-row {
  font-size: var(--fs-15);
  line-height: 1.4;
  color: var(--ink);
}

/* Сумма крупнее остального: за ней человек сюда и пришёл. */
.calc-modal__summary-price {
  margin-top: var(--sp-4);
  font-size: var(--fs-20);
  font-weight: 800;
  line-height: 1.2;
  color: var(--sky-dark);
}

/* Поле свободного сообщения в окне: по умолчанию textarea тянется
   пользователем вбок и вылезает за окно. Разрешаем только по высоте. */
.calc-lead--modal .textarea {
  resize: vertical;
  min-height: 84px;
}

/* ============================================================
   НИЖНЯЯ ПОЛОСА НА ТЕЛЕФОНЕ — правка 16.08.2026

   Роман: «нам лучше звонки». Отсюда два решения:

   · кнопка звонка стоит справа — под большой палец правой руки, и она
     единственная залита цветом. Вторая живёт обводкой;
   · трубка на ней качается раз в несколько секунд. Не бесконечно и не часто:
     непрерывное движение на липкой панели раздражает и читается как баннер.

   Список способов написать открывается ВВЕРХ, над полосой: вниз некуда,
   полоса и так стоит у нижнего края.
   ============================================================ */

.mobile-cta__write {
  position: relative;
  display: flex;
  min-width: 0;
}

.mobile-cta__write > .btn {
  width: 100%;
}

.mobile-cta__ways {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + var(--sp-8));
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-8);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  box-shadow: 0 12px 32px rgba(15, 18, 23, 0.18);
}

.mobile-cta__ways a {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  min-height: var(--btn-h);
  padding: 0 var(--sp-12);
  border-radius: 4px;
  font-size: var(--fs-15);
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
}

.mobile-cta__ways a:active {
  background: var(--soft);
}

.mobile-cta__ways img {
  width: 20px;
  height: 20px;
}

/* Трубка качается: два коротких взмаха, потом длинная пауза.
   Вся анимация занимает шесть секунд, из них движение — меньше секунды.

   prefers-reduced-motion выключает её целиком: для части людей дрожащие
   элементы — не «привлекает внимание», а физически неприятно. */
@keyframes трубка-звонит {
  0%, 74%, 100% { transform: rotate(0deg); }
  76% { transform: rotate(-14deg); }
  79% { transform: rotate(12deg); }
  82% { transform: rotate(-10deg); }
  85% { transform: rotate(8deg); }
  88% { transform: rotate(-5deg); }
  91% { transform: rotate(0deg); }
}

.mobile-cta__ring {
  transform-origin: 50% 60%;
  animation: трубка-звонит 6s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .mobile-cta__ring {
    animation: none;
  }
}

/* Первый экран на телефоне: пара кнопок под заголовком не показывается —
   внизу стоит липкая полоса с теми же действиями. Решение Романа 16.08.2026.
   Порог 680 — ровно тот, на котором появляется нижняя полоса. Не 760, где
   прячется форма первого экрана: между 681 и 760 формы уже нет, а полосы
   ещё нет, и эти две кнопки там — единственный быстрый путь к звонку. */
@media (max-width: 680px) {
  .hero__bottom {
    display: none;
  }
}

/* ============================================================
   ПЕРВЫЙ ЭКРАН НА ТЕЛЕФОНЕ — правка 16.08.2026

   Роман: «убрал бы „Узнайте стоимость“ и нижнее описание, а что осталось —
   вниз блока, чтобы видна была картинка».

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

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

   Высота задана: без неё блок сжимается по содержимому, и «прижать к низу»
   становится не к чему. 70svh — экран минус шапка и нижняя полоса,
   с запасом на адресную строку браузера, которая на телефоне то есть,
   то нет.
   ============================================================ */

@media (max-width: 680px) {
  .hero__price,
  .hero__desc {
    display: none;
  }

}

/* Выравнивание строк в маленьких карточках. Заголовки бывают в одну строку
   («Фумигация») и в две («Акарицидная обработка территории»), подписи —
   тоже. Резервируем место, а не обрезаем: название услуги многоточием
   не режут. Величины проверяются замером, а не на глаз. */
.services-rail > .service-card > .service-card__body h3 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 2.2em;
}

.services-rail > .service-card .service-card__object {
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 1.2em;
}

/* ============================================================
   ЗАГОЛОВОК ПЕРВОГО ЭКРАНА НА ТЕЛЕФОНЕ — ПРОПИСНЫМИ

   Решение Романа 16.08.2026: «здесь шрифт сделал бы капсом и увеличил его».

   Стоит в конце файла намеренно. Выше объявлен общий сброс регистра для
   всех заголовков (`h1, h2, h3, h4, .hero h1, …`) — правило без медиазапроса
   и с той же специфичностью, что `.hero__title h1`. Кто ниже, тот и прав:
   первая попытка стояла в мобильном блоке выше по файлу, кегль применился,
   а регистр молча нет. Переносить сюда, а не наращивать специфичность:
   наслоение весов — та самая беда, из-за которой в правилах проекта
   записано «правка значения там, где оно объявлено».
   ============================================================ */

@media (max-width: 760px) {
  .hero__title h1 {
    text-transform: uppercase;
  }
}

/* Голубая точка и галочка перед надписью над заголовком сняты 16.08.2026:
   «эти два мелких голубых элемента убери вообще, как колхоз смотрится».
   Точка рисовалась псевдоэлементом, галочка — значком в разметке.
   Значок оставлен в разметке и спрятан: он ничего не сообщает экранным
   дикторам (aria-hidden), но удаление из шаблона тронуло бы вёрстку
   всех блоков с надписью, а просят про первый экран. */
.hero .eyebrow::before {
  display: none;
}

.hero .eyebrow svg {
  display: none;
}

/* ============================================================
   ДОКУМЕНТЫ: ЛЕНТА И ВСПЛЫВАЮЩАЯ КАРТОЧКА — 16.08.2026

   Роман: «сделай так, чтобы их скролом листать можно было, а ещё при
   открытии документа должна всплывающая карточка быть, а не открытие
   новой страницы».

   Лента устроена как у услуг и отзывов: та же прокрутка, те же прилипания,
   та же тяга мышью (её включает bindDragScroll по признаку data-rail).
   Второй механики заводить не стал — одна на все ленты страницы.
   ============================================================ */

.documents-grid {
  display: flex;
  gap: var(--sp-16);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding-bottom: var(--sp-4);
}

.documents-grid::-webkit-scrollbar {
  display: none;
}

/* Ширина карточки целым числом, а не процентом: процент от контейнера
   на нечётной ширине окна даёт дробную координату, и рамка в одну точку
   размазывается по двум пикселям — линия мерцает при прокрутке. Так уже
   было в ленте акций, правило записано в CLAUDE.md. */
.documents-grid > .doc-card {
  scroll-snap-align: start;
}

/* --- Всплывающая карточка документа --- */

/* Показ и скрытие делает UIkit (`uk-modal` в разметке), вид — эти правила.
   Разделение не косметическое: у UIkit ловушка фокуса и возврат фокуса
   на карточку при закрытии, а руками это пишется мучительно и обычно
   с ошибками.

   Ниже намеренно НЕТ `display` в самом `.doc-modal`: скрытым его держит
   правило UIkit `.uk-modal { display: none }`. Поставишь здесь `display: flex` —
   наш файл грузится ниже, перебьёт его, и окно будет висеть на странице
   всегда. Показ описан отдельным правилом на `.uk-open`. */
.doc-modal {
  position: fixed;
  inset: 0;
  z-index: 130;
  padding: var(--sp-16);
  background: rgba(15, 18, 23, 0.72);
}

/* `!important` здесь обязателен, и это единственная причина, по которой он
   тут стоит: открывая окно, UIkit ставит `display: block` СТРОЧНЫМ стилем,
   а строчный стиль сильнее любого правила из файла — кроме правила
   с `!important`. Это тот самый случай, ради которого он в CSS и существует.

   Уберёшь — окно вернётся к `display: block`, и коробка перестанет стоять
   по центру: замерено 21.08.2026 на экране 790 — с флексом 32 точки сверху
   и 32 снизу, без него 16 и 47, верх документа срезан. */
.doc-modal.uk-open {
  display: flex !important;
  align-items: center;
  justify-content: center;
}

.doc-modal__box {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-12);
  width: min(760px, 100%);
  max-height: 92svh;
  padding: var(--sp-24);
  border-radius: var(--radius);
  background: #fff;
}

.doc-modal__close {
  position: absolute;
  top: var(--sp-8);
  right: var(--sp-8);
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 50%;
  background: var(--soft);
  color: var(--ink);
  font-size: var(--fs-22);
  line-height: 1;
  cursor: pointer;
}

.doc-modal__title {
  padding-right: 48px;
  font-size: var(--fs-17);
  font-weight: 800;
  color: var(--ink);
}

/* Лист прокручивается внутри окна: документ выше экрана почти всегда,
   а окно за край экрана уходить не должно. */
.doc-modal__sheet {
  flex: 1 1 auto;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--soft);
}

.doc-modal__sheet img {
  display: block;
  width: 100%;
  height: auto;
}

.doc-modal__box .btn {
  align-self: flex-start;
}

/* ============================================================
   КАРТОЧКА ДОКУМЕНТА: РАЗМЕРЫ — 16.08.2026

   Ширина карточки равна ширине одной вкладки: вкладок три, они делят
   контейнер поровну. Первая карточка встаёт ровно под первой кнопкой,
   вторая под второй — этого Роман и просил.

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

   Превью показывает верх листа, а не лист целиком: у А4 пропорция 1:1,41,
   и карточка получалась длиной в два экрана. Половина листа — это 1,41:1,
   и её хватает, чтобы узнать документ; целиком он открывается нажатием.
   ============================================================ */

.documents-grid > .doc-card {
  flex: 0 0 calc(100% / 3);
}

.doc-card__preview {
  aspect-ratio: 1.414 / 1;
}

/* Виден верх листа — там шапка и номер, по ним документ и узнаётся.
   По умолчанию cover берёт середину, а у свидетельства там мелкий текст. */
.doc-card__preview img {
  object-position: top center;
}

/* На телефоне вкладки стоят столбиком во всю ширину, и карточка во всю
   ширину повторила бы их — но тогда лента перестаёт читаться как лента:
   соседней карточки не видно, и что её можно листать, никак не понять.
   Оставляем край следующей видимым. */
@media (max-width: 680px) {
  .documents-grid > .doc-card {
    flex: 0 0 min(300px, 84%);
  }
}

/* ============================================================
   СТРОКА О СОГЛАСИИ ПОД КНОПКОЙ — 16.08.2026

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

   Ссылка подчёркнута намеренно. Без подчёркивания серый текст на сером
   не читается как ссылка вовсе, а по закону человек должен иметь
   возможность прочитать документ до отправки.
   ============================================================ */

.form-legal {
  margin: var(--sp-8) 0 0;
  font-size: var(--fs-12);
  line-height: 1.35;
  text-align: center;
  color: var(--muted);
}

.form-legal a {
  color: inherit;
  text-decoration: underline;
}