/**
 * Оформление движения: начальные состояния анимируемых блоков и всё, что
 * появилось на сайте вместе с плавным скроллом.
 *
 * Файл подключается рядом со style.css, но живёт отдельно намеренно: style.css
 * описывает страницу, которая обязана работать всегда, а здесь — только то,
 * что имеет смысл при включённом движении. Каждое правило, которое что-то
 * прячет, стоит под .has-motion: класс ставит скрипт в <head>, и он же снимает
 * его, если анимационный слой не доехал за две с половиной секунды. Нет
 * класса — нет ни одного спрятанного блока.
 */

/* --- служебное для Lenis ---------------------------------------------------
   Библиотека сама двигает страницу трансформацией, поэтому нативный плавный
   скролл обязан быть выключен: два механизма на одном событии дают рывок.
   height:auto нужен, чтобы длина страницы считалась по содержимому, а не по
   100% высоты экрана. */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
/* Внутренние прокручиваемые области (таблицы, длинные списки) помечаются
   data-lenis-prevent и крутятся нативно. */
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }
/* Пока страница едет, iframe не должен перехватывать колесо. */
.lenis.lenis-smooth iframe { pointer-events: none; }

/* --- появление блоков ------------------------------------------------------
   Прячем ДО запуска скрипта: иначе блок успевает отрисоваться, а потом
   исчезнуть — это заметно и выглядит как ошибка загрузки.
   will-change не ставим: элементов с data-anim на главной под сотню, и
   постоянный слой композитинга на каждом дороже самой анимации. */
.has-motion [data-anim] { opacity: 0; }
.has-motion [data-anim-group] { opacity: 1; }
.has-motion [data-anim-group] > * { opacity: 0; }
.has-motion [data-anim-group].anim-ready { opacity: 1; }

/* Запасной путь: GSAP не доехал, блоки выводит IntersectionObserver. */
.has-motion [data-anim].anim-in,
.has-motion [data-anim-group].anim-in,
.has-motion [data-anim].anim-in > *,
.has-motion [data-anim-group].anim-in > * {
  opacity: 1;
  transform: none;
  transition: opacity .6s var(--ease), transform .6s var(--ease);
}

/* --- заголовок по словам ---------------------------------------------------
   Слово едет из-под собственной строки, поэтому обёртке нужен обрез.

   Класс продублирован в селекторе (.sp-w.sp-w) намеренно — это поднимает вес
   правила выше «.lp-hero-tx h1 span { display: block }» из style.css. Без
   этого КАЖДОЕ слово заголовка становилось блоком и уезжало на свою строку.

   И правила НЕ под .has-motion: разметку разбил скрипт, и обратно он её не
   собирает. Если слой движения потом отключится страховкой, обёртки останутся
   в разметке — вести себя они обязаны как обычные слова. */
.sp-w.sp-w { display: inline-block; overflow: hidden; vertical-align: top; }
.sp-i.sp-i { display: inline-block; will-change: transform; }

/* --- полоса прочитанного ---------------------------------------------------
   Тонкая, поверх всего, но ниже модальных окон. Растягиваем трансформацией —
   ширина пересчитывала бы раскладку на каждый пиксель скролла. */
.mo-progress {
  position: fixed; inset: 0 0 auto 0; height: 2px; z-index: 60;
  transform: scaleX(0); transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--brand), var(--brand-2));
  box-shadow: 0 0 14px rgba(245,197,24,.5);
  pointer-events: none;
}

/* --- кнопка «наверх» ------------------------------------------------------- */
.mo-up {
  position: fixed; right: 18px; bottom: 18px; z-index: 55;
  width: 46px; height: 46px; display: grid; place-items: center;
  border-radius: 50%; cursor: pointer;
  color: var(--brand); background: rgba(21,25,34,.82);
  border: 1px solid var(--brand-line);
  backdrop-filter: blur(8px);
  opacity: 0; transform: translateY(14px) scale(.9); pointer-events: none;
  transition: opacity var(--dur-3) var(--ease), transform var(--dur-3) var(--ease),
              background var(--dur-2) var(--ease);
}
.mo-up.is-on { opacity: 1; transform: none; pointer-events: auto; }
.mo-up:hover { background: var(--brand); color: var(--brand-ink); }
.mo-up:focus-visible { outline: 2px solid var(--brand-2); outline-offset: 3px; }

/* --- шапка -----------------------------------------------------------------
   У самого верха шапка растворена в первом экране, ниже — уплотняется до
   тёмной полосы со стеклом. Уезжает при движении вниз и возвращается при
   движении вверх: на телефоне это отдаёт содержимому целую строку. */
.lp-top {
  transition: transform var(--dur-3) var(--ease), background var(--dur-3) var(--ease),
              border-color var(--dur-3) var(--ease), box-shadow var(--dur-3) var(--ease);
}
.has-motion .lp-top:not(.is-solid) {
  background: transparent; border-bottom-color: transparent; box-shadow: none;
}
.lp-top.is-solid {
  background: rgba(11,13,18,.78);
  backdrop-filter: blur(14px) saturate(1.3);
  box-shadow: 0 10px 30px -18px rgba(0,0,0,.9);
}
.lp-top.is-hidden { transform: translateY(-100%); }

/* Подчёркивание пунктов меню — растёт от левого края, а не проявляется. */
.lp-nav a { position: relative; }
.lp-nav a::after {
  content: ''; position: absolute; left: 12px; right: 12px; bottom: 10px;
  height: 2px; border-radius: 2px; background: var(--brand);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform var(--dur-2) var(--ease);
}
.lp-nav a:hover::after, .lp-nav a:focus-visible::after { transform: scaleX(1); }

/* --- наклон карточек -------------------------------------------------------
   Наклон делает GSAP, здесь — только сцена под него и блик, который ходит за
   курсором двумя переменными. */
.has-motion [data-tilt] {
  transform-style: preserve-3d;
  position: relative;
  will-change: transform;
}
.has-motion [data-tilt]::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 0%),
              rgba(245,197,24,.13), transparent 60%);
  opacity: 0; transition: opacity var(--dur-3) var(--ease);
  pointer-events: none;
}
.has-motion [data-tilt]:hover::before { opacity: 1; }

/* --- трёхмерная сцена первого экрана --------------------------------------- */
#lp-3d {
  /* Сцена растянута на весь первый экран, а машина внутри неё сдвинута в
     нижнюю полосу (см. hero3d.js): справа сверху стоит форма заявки, слева —
     заголовок, и единственное свободное место — низ. Правый нижний угол, где
     раньше жил силуэт-SVG, не подошёл: форма закрывает его наполовину.
     Без z-index намеренно: тогда сцена рисуется в порядке разметки, ПОД
     .lp-hero-shade, и затемнение гасит её слева, под заголовком. */
  position: absolute; inset: 0;
  opacity: 0; transition: opacity 1.2s var(--ease);
  pointer-events: none;                 /* сцена декоративна, клики идут сквозь */
}
#lp-3d.is-on { opacity: 1; }

/* Телефон: первый экран здесь — одна высокая колонка (заголовок, кнопки,
   форма), и она длиннее экрана. Если оставить сцену на всю её высоту, машина
   окажется на середине колонки — то есть за нижним краем экрана, и человек
   увидит пустой фон. Поэтому на узких экранах сцена занимает ровно видимый
   экран и работает фактурой за текстом. */
@media (max-width: 980px) {
  /* Сцена занимает ровно видимый экран, а не весь первый экран целиком: тот
     на телефоне длиннее окна (в него уходит форма заявки), и машина при
     растяжке оказывалась ниже края.

     Свободного места на телефоне нет вовсе — форма начинается сразу под
     кнопками, — поэтому машина здесь работает водяным знаком за текстом:
     приглушена маской, но видна между строк и оживает при наклоне корпуса. */
  #lp-3d { inset: 0 0 auto 0; height: 100svh; }
}
#lp-3d canvas { display: block; width: 100%; height: 100%; }
/* Сцена запустилась — статичный силуэт уходит совсем: два одинаковых контура
   друг на друге читаются как двоение, а не как глубина. Пока сцена не готова,
   на экране остаётся обычный SVG, и первый экран не выглядит пустым. */
.lp-hero-bg:has(#lp-3d.is-on) .lp-hero-svg { opacity: 0; }
.lp-hero-svg { transition: opacity 1.2s var(--ease); }

/* --- усиленная косметика --------------------------------------------------- */
/* Карточки: подсветка рамки и подъём. Раньше поднимались только демо-карточки,
   теперь — всё, что человек может принять за кликабельное. */
.lp-card, .lp-case, .lp-tariff, .lp-sv, .lp-demo {
  transition: transform var(--dur-3) var(--ease), border-color var(--dur-2) var(--ease),
              box-shadow var(--dur-3) var(--ease);
}
.lp-card:hover, .lp-case:hover, .lp-tariff:hover {
  transform: translateY(-4px);
  border-color: var(--line-2);
  box-shadow: 0 20px 40px -28px rgba(0,0,0,.9);
}
.lp-featured:hover { border-color: var(--brand-line);
  box-shadow: 0 24px 50px -28px rgba(245,197,24,.35); }

/* Иконка в карточке слегка оживает вместе с ней. */
.lp-card .lp-ico, .lp-sv .lp-ico {
  transition: transform var(--dur-3) var(--ease), background var(--dur-3) var(--ease);
}
.lp-card:hover .lp-ico, .lp-sv:hover .lp-ico {
  transform: translateY(-2px) rotate(-4deg) scale(1.06);
  background: var(--brand-soft);
}

/* Кнопки: мягкий блик, пробегающий слева направо при наведении. */
.btn-primary { position: relative; overflow: hidden; }
.btn-primary::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 45%;
  left: -60%; transform: skewX(-18deg);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.35), transparent);
  transition: left .55s var(--ease);
  pointer-events: none;
}
.btn-primary:hover::after { left: 130%; }

/* Полосы-разделители между разделами: тонкая градиентная линия вместо
   сплошной — на тёмном фоне она читается как свет, а не как шов. */
.lp-sec + .lp-sec-alt, .lp-sec-alt + .lp-sec { position: relative; }
.lp-sec + .lp-sec-alt::before, .lp-sec-alt + .lp-sec::before {
  content: ''; position: absolute; inset: -1px 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--brand-line) 30%,
              var(--brand-line) 70%, transparent);
}

/* Цифры в полосе «сколько осмотров» — с фирменным свечением. */
.lp-band-n b, .lp-stats-in b {
  text-shadow: 0 0 40px rgba(245,197,24,.28);
  font-variant-numeric: tabular-nums;   /* при счёте цифры не должны прыгать */
}

/* Аккордеон вопросов: стрелка поворачивается плавно. */
.lp-faq details summary::marker { color: var(--brand); }
.lp-faq details[open] summary { color: var(--brand-2); }

/* --- покой -----------------------------------------------------------------
   Системная настройка «уменьшить движение» уже не даёт поставить .has-motion,
   но правила ниже страхуют то, что живёт в чистом CSS. */
@media (prefers-reduced-motion: reduce) {
  .mo-progress, .mo-up { display: none; }
  .btn-primary::after { display: none; }
  .lp-card:hover, .lp-case:hover, .lp-tariff:hover { transform: none; }
  .lp-card:hover .lp-ico, .lp-sv:hover .lp-ico { transform: none; }
  .lp-top.is-hidden { transform: none; }
  #lp-3d { display: none; }
  .fx-grid::after, .lp-chk-car::after, #count::after,
  .lp-steps::before, .lp-steps::after { display: none; }
}

/* --- фон разделов ниже первого экрана ---------------------------------------
   Общее правило для всего, что ниже: фон — фактура, а не картинка. Текст на
   этой странице продаёт услугу, и любой эффект, из-за которого его труднее
   читать, здесь не нужен ни при какой красоте.

   Разделам, у которых появляется фоновый слой, нужны две вещи: своя система
   координат (position: relative) и обрез, чтобы слой не вылезал наружу.
   isolation отделяет смешивание внутри раздела от остальной страницы. */
.lp-sec-alt.fx-grid,
#checks, #how, #count { position: relative; isolation: isolate; overflow: hidden; }
.lp-sec-alt.fx-grid > .lp-wrap,
#checks > .lp-wrap, #how > .lp-wrap, #count > .lp-wrap { position: relative; z-index: 1; }

/* Измерительная сетка за карточками. Шаг 48px — крупнее, чем кажется нужным,
   намеренно: на мелкой сетке при плавной прокрутке на дробном devicePixelRatio
   идёт муар. Цвет — линия интерфейса, не бренд: это разметка, а не украшение.
   Овальная маска гасит сетку у краёв, поэтому заголовок и подводка стоят на
   чистом фоне. */
/* Именно ::after, а не ::before: ::before у этих разделов уже занят тонкой
   градиентной линией-разделителем (см. выше), и та задаёт высоту в один
   пиксель — сетка от неё наследовала бы полоску вместо полотна. */
.has-motion .fx-grid::after {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    repeating-linear-gradient(90deg, rgba(78,92,120,.20) 0 1px, transparent 1px 48px),
    repeating-linear-gradient(0deg,  rgba(78,92,120,.20) 0 1px, transparent 1px 48px);
  /* Гасим только у границ раздела, чтобы сетка не обрывалась ступенькой. По
     центру она идёт свободно: карточки непрозрачны и перекрывают её сами, а
     в зазорах между ними миллиметровка как раз и должна проглядывать. */
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
          mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
}

/* Луч по схеме кузова. Проезжает по чертежу один раз за проход раздела мимо
   экрана — ровно тот же жест, что полоса сканирования на первом экране.
   ЦВЕТ СПЕЦИАЛЬНО НЕЙТРАЛЬНЫЙ, почти белый: на схеме кузова жёлтый, красный,
   зелёный и синий уже заняты — это статусы деталей в отчёте, и подсвечивать
   зону фирменным жёлтым значит сказать клиенту «здесь шпатлёвка». */
.lp-chk-car { position: relative; overflow: hidden; }
.has-motion .lp-chk-car::after {
  content: ''; position: absolute; top: -10%; bottom: -10%;
  left: 0; width: 16%;
  background: linear-gradient(100deg, transparent,
              rgba(255,255,255,.05) 42%, rgba(255,255,255,.16) 50%,
              rgba(255,255,255,.05) 58%, transparent);
  transform: translateX(var(--fx-shift, -140%));
  pointer-events: none; opacity: 0;
}
.has-motion .lp-chk-car.fx-scan::after { opacity: 1; }

/* Линия хода осмотра по четырём шагам. Дорожка лежит всегда, заливка растёт по
   мере прохода раздела. Обе линии — псевдоэлементы списка, поэтому в разметке
   ничего не прибавилось. */
.lp-steps { position: relative; }
/* Линия лежит ПОД карточками шагов и видна только в зазорах между ними —
   как протянутая между столбами. Поверх карточек она перечёркивала бы их
   заголовки. */
.has-motion .lp-steps::before,
.has-motion .lp-steps::after {
  content: ''; position: absolute; left: 0; right: 0; top: 30px; height: 2px;
  border-radius: 2px; pointer-events: none; z-index: 0;
}
.lp-steps li { z-index: 1; }
.has-motion .lp-steps::before { background: var(--line); }
.has-motion .lp-steps::after {
  background: linear-gradient(90deg, var(--brand), var(--brand-2));
  box-shadow: 0 0 12px rgba(245,197,24,.45);
  transform: scaleX(var(--fx-run, 0)); transform-origin: 0 50%;
}
/* Номер шага загорается, когда линия до него дошла. */
.lp-steps li::before { transition: background var(--dur-3) var(--ease),
                                   color var(--dur-3) var(--ease),
                                   box-shadow var(--dur-3) var(--ease); }
.has-motion .lp-steps li.fx-lit::before {
  background: var(--brand); color: var(--brand-ink);
  box-shadow: 0 0 0 4px rgba(245,197,24,.14);
}
/* В одну колонку линия шла бы поперёк текста — там её просто нет. */
@media (max-width: 860px) {
  .has-motion .lp-steps::before, .has-motion .lp-steps::after { display: none; }
}

/* Полоса доверия: один проход света при появлении. Один раз — не мерцание:
   рядом с настоящим числом осмотров вечная анимация выглядит как реклама. */
.has-motion #count::after {
  content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 42%;
  z-index: 0; pointer-events: none;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.09), transparent);
  transform: translateX(var(--fx-sweep, -120%)) skewX(-14deg);
}

/* --- печать -----------------------------------------------------------------
   Отчёт печатают на бумаге, и служебные накладки на ней не нужны: полоса
   прочитанного и кнопка «наверх» на листе бессмысленны. Наклоны и подъёмы
   карточек тоже снимаем — принтер их всё равно не покажет, а тень съест
   тонер. */
@media print {
  .mo-progress, .mo-up { display: none !important; }
  .fx-grid::after, .lp-chk-car::after, #count::after,
  .lp-steps::before, .lp-steps::after { display: none !important; }
  .lp-card, .lp-case, .lp-tariff { transform: none !important; box-shadow: none !important; }
  [data-anim], [data-anim-group] > * { opacity: 1 !important; transform: none !important; }
}
