/*
   PVlab Landing — публичная страница «/» (Views/Landing/Index.cshtml, layout _LandingLayout).

   ── Почему у страницы отдельная палитра и отдельный namespace ────────────────────────────
   Лендинг не является экраном приложения. У него другой фон (#f4fcff против #dde3ec), другой
   основной цвет текста (#00395c против #1a1a23), другой акцент (#3da7f3 против #3DB6FF), другая
   типографика (Bounded + Golos Text) и другая сетка. Переиспользовать токены
   pvlab-glass.css значило бы либо переопределить их почти целиком, либо тянуть лендинг к
   палитре приложения вопреки макету. Поэтому здесь свой набор --lp-*, а файл не подключается
   ни к одной странице приложения (и наоборот).

   Внутренние классы носят короткий префикс lp- (landing page). Все правила живут под
   .pvlab-landing, пересечься с pvlab-* оболочки они не могут.

   Тема всегда светлая: тёмного варианта лендинга в макете нет, data-theme здесь не читается.

   Соответствие макету: Figma pharma-lab, node 1339:4584. Числовые значения (радиусы 29px,
   тень 0 4px 7px rgba(0,57,92,0.21), заливка карточек rgba(182,212,255,0.1)) взяты оттуда.
*/

/* ═══════════════════════════ Шрифты ═══════════════════════════
   Самохостинг, как Golos Text/Steppe в pvlab-glass.css: Google Fonts CDN render-blocking и
   нестабилен из РФ-сетей. Сабсеты — по тем же unicode-range, что отдаёт css2 API.

   Bounded — OFL 1.1, Vlad Churkin (github.com/churkinvlad/Bounded), латиница + кириллица.
   Golos Text — OFL 1.1, вариативный (один файл на сабсет, вес задаётся диапазоном).
   Geologica — OFL 1.1, только цифры: используется исключительно для номеров 01-05.
   Лицензии лежат рядом с файлами (wwwroot/fonts/<семейство>/OFL.txt).

   САБСЕТЫ BOUNDED — С КОНТУРАМИ TRUETYPE, и это не мелочь сборки. Исходные лежали с контурами
   CFF, и заголовок героя рисовался запасным Golos Text: браузер файл СКАЧИВАЛ (200) и молча
   отвергал — санитайзер шрифтов Chrome к таким сабсетам строже, чем инструменты, которыми их
   режут. Ни ошибки на экране, ни пустого места: просто другой шрифт. Пересобирать их обратно
   в CFF нельзя. */

@font-face {
  font-family: 'Bounded'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/fonts/Bounded/Bounded-Regular-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Bounded'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/fonts/Bounded/Bounded-Regular-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Golos Text'; font-style: normal; font-weight: 400 900; font-display: swap;
  src: url('/fonts/GolosText/GolosText-cyrillic-ext.woff2') format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Golos Text'; font-style: normal; font-weight: 400 900; font-display: swap;
  src: url('/fonts/GolosText/GolosText-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Golos Text'; font-style: normal; font-weight: 400 900; font-display: swap;
  src: url('/fonts/GolosText/GolosText-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
                 U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Golos Text'; font-style: normal; font-weight: 400 900; font-display: swap;
  src: url('/fonts/GolosText/GolosText-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Geologica'; font-style: normal; font-weight: 200; font-display: swap;
  src: url('/fonts/Geologica/Geologica-ExtraLight-digits.woff2') format('woff2');
  unicode-range: U+0030-0039;
}

/* ═══════════════════════════ Токены ═══════════════════════════ */

.pvlab-landing {
  /* Цвета сняты из макета (заливки — пипеткой по рендерам секций). */
  --lp-bg:            #f4fcff;                    /* фон всех секций */
  --lp-card:          rgba(182, 212, 255, 0.10);  /* заливка карточек: поверх --lp-bg даёт #edf8ff */
  --lp-card-hover:    rgba(182, 212, 255, 0.26);
  /* Тот же цвет, но непрозрачный. Нужен там, где карточки лежат друг на друге (колода
     «Знакомо?»): полупрозрачная заливка позволяет читать текст нижних карточек сквозь
     верхнюю, и стопка превращается в кашу. */
  --lp-card-solid:    #edf8ff;
  --lp-pill:          rgba(182, 212, 255, 0.36);  /* «таблетка» рубрики */
  --lp-header:        rgba(182, 212, 255, 0.12);  /* плашка шапки */
  --lp-header-solid:  rgba(235, 245, 255, 0.86);  /* она же после прокрутки */

  --lp-ink:           #00395c;   /* основной тёмно-синий */
  --lp-ink-dark:      #191c1e;   /* «почти чёрный» в заголовках с подсветкой и в тексте карточек */
  --lp-ink-body:      #343434;   /* вводные абзацы */
  --lp-brand:         #3da7f3;   /* акцент, подсветка, активная точка */
  --lp-brand-deep:    #2b93e0;
  --lp-footer-bg:     #151929;
  --lp-footer-ink:    #b9c0d4;

  --lp-shadow:        0 4px 7px rgba(0, 57, 92, 0.21);
  --lp-shadow-lift:   0 14px 30px rgba(0, 57, 92, 0.16);
  --lp-shadow-cta:    0 10px 28px rgba(61, 140, 255, 0.45);

  --lp-radius:        29px;
  --lp-radius-sm:     23px;
  --lp-pill-radius:   100px;

  /* Ширина контента: в макете секции занимают x 172…1268 на полотне 1440. */
  --lp-content:       1096px;
  --lp-gutter:        clamp(18px, 4.2vw, 60px);

  --lp-ease:          cubic-bezier(0.22, 0.61, 0.36, 1);
  /* Отдельная кривая для наведения: мягкий разгон и длинный выкат, из-за которого плитка
     не «щёлкает» под курсором, а всплывает. Длительность держим одинаковой у всех
     интерактивных поверхностей — вразнобой это читается как разная «тяжесть» элементов. */
  --lp-ease-hover:    cubic-bezier(0.33, 0.02, 0.18, 1);
  --lp-hover-time:    0.45s;
}

/* ═══════════════════════════ База ═══════════════════════════ */

.pvlab-landing,
.pvlab-landing *,
.pvlab-landing *::before,
.pvlab-landing *::after { box-sizing: border-box; }

.pvlab-landing {
  margin: 0;
  padding: 0;
  overflow-x: hidden;                             /* блобы героя выходят за край намеренно */
  background: var(--lp-bg);
  color: var(--lp-ink);
  font-family: 'Golos Text', 'Segoe UI', system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ── Полоса прокрутки ─────────────────────────────────────────────────────────
   Системная полоса серая и на фоне #f4fcff читается как деталь чужого интерфейса.
   Приём взят из оболочки приложения (pvlab-glass.css): прозрачный трек и
   полупрозрачный ползунок-пилюля. Цвет — от основного текста (--lp-ink), а не от
   акцента: полоса тянется во всю высоту страницы, и ярко-голубая линия рядом с
   содержимым спорила бы с настоящими акцентами вместо того, чтобы уступать им.

   Токены объявлены на :root, а не на .pvlab-landing, как остальные --lp-*: полоса
   прокрутки страницы принадлежит <html>, то есть элементу НАД body, а переменные,
   объявленные на body, вверх не наследуются.

   Селектор html без класса здесь безопасен: файл подключает только _LandingLayout,
   ни на один экран приложения он не попадает.

   Синтаксиса два, потому что их поддержка не пересекается: современные браузеры
   берут scrollbar-width/color (и тогда ::-webkit-* правила игнорируют вовсе),
   а Safari до 18.2 понимает только ::-webkit-*. */
:root {
  --lp-scroll-thumb:       rgba(0, 57, 92, 0.25);
  --lp-scroll-thumb-hover: rgba(0, 57, 92, 0.45);
}

html,
.pvlab-landing,
.pvlab-landing * {
  scrollbar-width: thin;
  scrollbar-color: var(--lp-scroll-thumb) transparent;
}

html::-webkit-scrollbar,
.pvlab-landing::-webkit-scrollbar,
.pvlab-landing *::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

/* Прозрачный трек и угол — без серых плашек по краю страницы. */
html::-webkit-scrollbar-track,
html::-webkit-scrollbar-corner,
.pvlab-landing::-webkit-scrollbar-track,
.pvlab-landing::-webkit-scrollbar-corner,
.pvlab-landing *::-webkit-scrollbar-track,
.pvlab-landing *::-webkit-scrollbar-corner {
  background: transparent;
}

html::-webkit-scrollbar-thumb,
.pvlab-landing::-webkit-scrollbar-thumb,
.pvlab-landing *::-webkit-scrollbar-thumb {
  background: var(--lp-scroll-thumb);
  border: 2px solid transparent;   /* воздух по периметру превращает ползунок в пилюлю */
  border-radius: 999px;
  background-clip: padding-box;    /* иначе фон залил бы и прозрачную рамку */
  transition: background-color 160ms ease;
}

html::-webkit-scrollbar-thumb:hover,
.pvlab-landing::-webkit-scrollbar-thumb:hover,
.pvlab-landing *::-webkit-scrollbar-thumb:hover {
  background: var(--lp-scroll-thumb-hover);
  background-clip: padding-box;
}

/* Сброс завёрнут в :where() — селектор с нулевой специфичностью. Иначе `.pvlab-landing p`
   (класс + тег) перебивал бы одноклассовые правила компонентов вроде .lp-hero__lead, и
   отступы приходилось бы возвращать !important'ами. Ровно на это налетела первая версия
   файла: у абзацев пропали margin'ы, а встроенный логотип в заголовке получил height: auto
   и вырос до натуральных 202px. */
:where(.pvlab-landing) :where(h1, h2, h3, p, ul, ol, figure) { margin: 0; }

:where(.pvlab-landing) :where(ul, ol) { padding: 0; list-style: none; }

:where(.pvlab-landing) :where(img) { max-width: 100%; height: auto; display: block; }

:where(.pvlab-landing) :where(a) { color: inherit; text-decoration: none; }

/* Единая видимая обводка фокуса: у кнопок и ссылок здесь снят outline по умолчанию.

   border-radius НЕ задаём. Раньше он тут стоял (4px) — и менял скругление самого элемента:
   поле формы с радиусом 12px при фокусе превращалось в почти прямоугольное. Современные
   браузеры и так ведут outline по собственному радиусу элемента, подсказывать не нужно. */
.pvlab-landing :focus-visible {
  outline: 2px solid var(--lp-brand);
  outline-offset: 3px;
}

.lp-container {
  width: 100%;
  max-width: calc(var(--lp-content) + var(--lp-gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--lp-gutter);
}

.lp-section { padding-block: clamp(56px, 7vw, 96px); }

/* Притягивания к блокам (scroll-snap) на странице НЕТ — прокрутка свободная.

   Пробовали: сначала мягкое, потом жёсткое «как в презентации», с остановками по границам
   секций, по подблокам длинных секций и по кадрам обеих прокручиваемых сцен. На практике
   оказалось неудобно — страница перестаёт слушаться колеса. Если решение будут переигрывать,
   помнить про две вещи, на которые ушло больше всего времени:
     • mandatory требует остановок по ВСЕЙ длине страницы: там, где их нет, браузер тянет
       к ближайшей и схлопывает промежуток рывком;
     • последняя остановка обязана быть достижимой — выравнивание по началу финальной секции
       давало точку ниже предела прокрутки, и подвал становился недосягаем.

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

/* ═══════════════════════ Типографика ═══════════════════════ */

.lp-eyebrow {
  display: inline-block;
  min-width: 190px;
  padding: 6px 20px;
  border-radius: 140px;
  background: var(--lp-pill);
  color: var(--lp-ink);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-align: center;
  text-transform: uppercase;
  margin-bottom: clamp(20px, 2.4vw, 30px);
}

.lp-h2 {
  font-size: clamp(27px, 3.35vw, 48px);
  font-weight: 400;
  line-height: 1.2;
  color: var(--lp-ink-dark);
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.lp-h2--bold {
  font-weight: 700;
  color: var(--lp-ink);
}

.lp-h2 strong { font-weight: 700; }

/* Подсветка фрагмента заголовка: белый текст на акцентном прямоугольнике, плотно по строке.
   box-decoration-break даёт одинаковые поля на каждой строке при переносе. */
.lp-mark {
  background: var(--lp-brand);
  color: #fff;
  padding: 0.04em 0.14em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* Логотип, вклеенный в строку заголовка (перед «— валидированная система»). */
.lp-inline-logo {
  display: inline-block;
  height: 0.82em;
  width: auto;
  vertical-align: -0.06em;
  margin-right: 0.06em;
}
.lp-inline-logo--lg { height: 1.05em; vertical-align: -0.22em; margin: 0 0 0 0.1em; }

/* ═══════════════════════════ Кнопки ═══════════════════════════ */

.lp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid transparent;
  border-radius: var(--lp-pill-radius);
  font-family: 'Golos Text', system-ui, sans-serif;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  transition: transform var(--lp-hover-time) var(--lp-ease-hover),
              box-shadow var(--lp-hover-time) var(--lp-ease-hover),
              background-color var(--lp-hover-time) var(--lp-ease-hover),
              color var(--lp-hover-time) var(--lp-ease-hover),
              border-color var(--lp-hover-time) var(--lp-ease-hover);
}

.lp-btn:hover { transform: translateY(-2px); }
/* Нажатие — единственное место, где отклик должен быть мгновенным: длинный переход на
   :active ощущается как залипшая кнопка. */
.lp-btn:active { transform: translateY(0); transition-duration: 0.08s; }

.lp-btn--primary {
  padding: 17px 32px;
  background: var(--lp-brand);
  color: #fff;
  font-size: 16px;
  box-shadow: var(--lp-shadow-cta);
}
.lp-btn--primary:hover { background: var(--lp-brand-deep); box-shadow: 0 16px 34px rgba(61, 140, 255, 0.5); }

.lp-btn--outline {
  padding: 8px 24px;
  border-color: var(--lp-ink);
  color: var(--lp-ink);
  font-size: 14px;
  background: transparent;
}
.lp-btn--outline:hover { background: var(--lp-ink); color: #fff; }

.lp-btn--outline-accent {
  padding: 17px 40px;
  border-color: var(--lp-brand);
  color: var(--lp-brand);
  font-size: 14px;
  background: rgba(255, 255, 255, 0.6);
}
.lp-btn--outline-accent:hover { background: var(--lp-brand); color: #fff; box-shadow: var(--lp-shadow-cta); }

.lp-btn--light {
  padding: 8px 24px;
  background: #fff;
  color: var(--lp-ink);
  font-size: 14px;
}
.lp-btn--light:hover { background: var(--lp-ink); color: #fff; }

/* ═══════════════════════════ Шапка ═══════════════════════════ */

/* Шапка висит НАД первым экраном и не занимает собственной полосы в потоке. Достигается
   нулевой высотой: «таблетка» внутри выходит за границы блока (overflow по умолчанию
   видимый), а сам блок при этом остаётся липким.

   Раньше здесь стоял margin-bottom: -102px — подгонка под высоту шапки. Реальная высота
   80px, и лишние 22px подтягивали <main> вверх: первый экран начинался выше нуля, а сцена
   героя стартовала уже на 4% своего прогресса, из-за чего снимки просвечивали до прокрутки.
   Нулевая высота убирает и подгонку, и её расхождение с действительностью. */
.lp-header {
  position: sticky;
  top: clamp(10px, 1.6vw, 22px);
  z-index: 20;
  height: 0;
  padding-inline: var(--lp-gutter);
}

.lp-header__pill {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  max-width: var(--lp-content);
  min-height: 80px;
  margin-inline: auto;
  padding: 10px clamp(16px, 2vw, 29px);
  border-radius: var(--lp-radius);
  background: var(--lp-header);
  box-shadow: var(--lp-shadow);
  transition: background-color 0.3s var(--lp-ease), box-shadow 0.3s var(--lp-ease);
}

/* Класс ставит скрипт после первых 40px прокрутки: над карточками секций полупрозрачная
   плашка теряет читаемость, поэтому она уплотняется и уходит в размытие. */
.lp-header.is-stuck .lp-header__pill {
  background: var(--lp-header-solid);
  box-shadow: var(--lp-shadow-lift);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}

.lp-header__brand img { width: 52px; height: auto; }

.lp-header__nav {
  display: flex;
  align-items: center;
  gap: clamp(14px, 2.4vw, 35px);
}

.lp-header__link {
  color: var(--lp-ink);
  font-size: 16px;
  white-space: nowrap;
  transition: color 0.2s var(--lp-ease);
}
.lp-header__link:hover { color: var(--lp-brand); }

.lp-header__link--access { font-weight: 600; }

/* ═══════════════════════════ Герой ═══════════════════════════ */

/* Базовое состояние — просто первый экран во всю высоту окна, без сцены. Именно его видит
   посетитель без JS и владелец узкого экрана. min-height, а не height: на низком окне
   содержимое должно раздвинуть героя, а не обрезаться. Две записи подряд — фолбэк: dvh
   учитывает съезжающую адресную строку мобильных браузеров, понимают его не все. */
.lp-hero { position: relative; }

.lp-hero__stage {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: 100dvh;
  overflow: hidden;
}

/* Сцена с разъездом включается только при живом JS и только там, где справа есть место
   для снимков: на одной колонке им деваться некуда. Порог тот же, что у залипания секции
   «Знакомо?», — оба приёма требуют двухколоночной раскладки и высокого окна. */
@media (min-width: 1101px) and (min-height: 640px) {
  /* Высота сцены — экран, но не больше 1000px.
     Ограничение появилось из-за провалов на стыках. Сцена ростом ровно в экран центрирует
     содержимое, поэтому над ним и под ним остаётся по половине незанятой высоты. На мониторе
     1440px эта половина — сотни пикселей, и на границе двух соседних сцен они складываются:
     замерено 563px между первым экраном и «Знакомо?» против 194px у обычных стыков.
     Перекладывать пустоту отступами бесполезно — она просто переезжает на соседний стык,
     поэтому ограничивается сама высота сцены, и лишней пустоте неоткуда взяться.

     Прокручиваемая обёртка считается ОТ ЭТОЙ величины, а не от экрана: иначе на высоком
     мониторе ход сцены удлинился бы вместе с окном, а её видимая часть — нет. */
  .lp-js .pvlab-landing,
  .lp-js .lp-hero,
  .lp-js .lp-problems__scroll { --lp-scene-h: min(100vh, 1000px); }

  .lp-js .lp-hero { height: calc(var(--lp-scene-h) * 1.65); }
  .lp-js .lp-hero__stage { position: sticky; top: 0; height: var(--lp-scene-h); min-height: 0; }
}

/* Текстовая колонка. Ширина у неё КОНЕЧНАЯ (та, что после сдвига влево), а стартовое
   положение по центру получается масштабом и сдвигом — иначе пришлось бы анимировать
   ширину и кегль, то есть пересчитывать раскладку каждый кадр.

   transform-origin: center — при масштабировании центр блока остаётся на месте, и сдвиг
   на половину собственной ширины ставит его ровно в центр сцены. */
/* Стартовое положение — РОВНО по центру сцены, и обеспечивает его раскладка (margin: auto),
   а не арифметика в transform. Прежний вариант отсчитывал сдвиг в процентах от собственной
   ширины и промахивался мимо центра на десяток пикселей; считать через 50vw тоже нельзя —
   vw включает полосу прокрутки, а раскладка нет.

   Смещение влево (--lp-hero-shift) замеряет скрипт по фактической колонке контента и
   пересчитывает при изменении размера окна. При p = 0 сдвиг нулевой, то есть центр точен
   по построению. */
.lp-hero__inner {
  position: relative;
  z-index: 2;
  flex: 0 0 auto;
  /* Ширина колонки вынесена в переменную и растёт вместе с кеглем заголовка (см. блоки
     @media шире 2K). Держать её постоянной нельзя: «Фармаконадзор» — одно слово, переносить
     его некуда, и при крупном кегле оно перестаёт помещаться. А выглядит это не как обычное
     переполнение, а как обрезка: заголовок залит градиентом через background-clip: text при
     color: transparent, поэтому часть букв за пределами блока остаётся БЕЗ ЗАЛИВКИ и просто
     пропадает. Замерено: при кегле 74px слову нужно 582px, при 82px — 645px. */
  width: min(var(--lp-hero-col, 560px), calc(100% - var(--lp-gutter) * 2));
  margin-inline: auto;
  text-align: center;
  transform: translateX(calc(var(--lp-hero-p, 0) * -1 * var(--lp-hero-shift, 0px)))
             scale(calc(1 + (1 - var(--lp-hero-p, 0)) * 0.52));
  transform-origin: center center;
}

/* Снимки системы выезжают справа по мере прокрутки сцены. Разложены веером: верхний
   впереди, остальные уходят вправо-вниз. */
/* Высота НЕ задана: её набирают сами снимки. Раньше здесь стояла фиксированная высота с
   object-fit: cover — она равняла снимки по общему окну, но обрезала их, а у трёх экранов
   системы пропорции разные (1.53, 2.22, 1.60). Теперь снимки идут колонкой с нахлёстом,
   каждый в своих пропорциях, и высота блока получается сама. Так замена скриншотов на
   другие ничего не ломает — подстраивать числа под новые пропорции не нужно. */
.lp-hero__shots {
  position: absolute;
  right: max(var(--lp-gutter), calc((100vw - var(--lp-content)) / 2));
  top: 50%;
  z-index: 1;
  display: flex;
  flex-direction: column;
  width: min(38%, 440px);
  opacity: var(--lp-hero-p, 0);
  transform: translateY(-50%) translateX(calc((1 - var(--lp-hero-p, 0)) * 70%));
  pointer-events: none;
}

.lp-hero__shot {
  position: relative;          /* нужен для z-index лесенки */
  width: 100%;
  height: auto;
  border-radius: 14px;
  box-shadow: 0 18px 44px rgba(0, 57, 92, 0.24);
}

/* Нахлёст в процентах от ШИРИНЫ блока (так считается вертикальный margin в процентах) —
   значит, он не зависит от пропорций конкретного снимка. */
.lp-hero__shot--2,
.lp-hero__shot--3 { margin-top: -14%; }

/* Сдвиги веера нарастают вместе с прогрессом: в начале снимки лежат стопкой, к концу
   расходятся. Первый — опорный, он и задаёт высоту блока. */
/* Лесенка: снимки разведены по горизонтали, чтобы перекрывать друг друга только краями.
   Второй — на переднем плане и заметно правее остальных; вправо есть куда, между колонкой
   и краем окна лежит поле страницы. */
.lp-hero__shot--1 { z-index: 2; }

.lp-hero__shot--2 {
  z-index: 3;
  transform: translateX(calc(var(--lp-hero-p, 0) * 26%));
}

.lp-hero__shot--3 {
  z-index: 1;
  transform: translateX(calc(var(--lp-hero-p, 0) * -10%));
}

/* Кегль подобран под КОНЕЧНУЮ ширину колонки (≈560px): «Фармаконадзор» должно умещаться
   в одну строку. В стартовом положении блок увеличен масштабом 1.52, то есть визуально
   заголовок читается примерно как 85px из макета. */
.lp-hero__title {
  font-family: 'Golos Text', system-ui, sans-serif;
  font-size: clamp(30px, 3.9vw, 56px);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: -0.01em;
  /* Вертикальный градиент по тексту: «Прозрачный» плотный, «Фармаконадзор» растворяется.
     Заливка одна на весь заголовок, поэтому строки нельзя разносить по элементам. */
  background: linear-gradient(180deg, var(--lp-ink) 0%, rgba(0, 57, 92, 0) 108%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Браузер без background-clip: text показал бы пустое место вместо заголовка. */
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .lp-hero__title { color: var(--lp-ink); background: none; }
}

.lp-hero__lead {
  margin-top: clamp(20px, 2.6vw, 32px);
  font-size: clamp(13px, 1.05vw, 15px);
  line-height: 1.6;
  color: var(--lp-ink);
}

.lp-hero__cta { margin-top: clamp(20px, 2.6vw, 30px); }

/* Кнопка призыва проявляется ВМЕСТЕ со снимками, а не стоит с самого начала: первый кадр
   держит только заголовок, а предложение действовать приходит тогда же, когда посетитель
   впервые видит саму систему.

   Правило живёт под .lp-js и внутри сцены — там же, где включается разъезд. Без скрипта
   переменная --lp-hero-p не появится, и единственная кнопка первого экрана осталась бы
   невидимой навсегда; вне сцены (мобильные, низкие окна) она тоже просто видна сразу.

   pointer-events снимаются классом от скрипта, а не вычисляются из прозрачности: невидимая,
   но кликабельная кнопка перехватывала бы нажатия по пустому месту. */
@media (min-width: 1101px) and (min-height: 640px) {
  .lp-js .lp-hero__cta {
    opacity: var(--lp-hero-p, 0);
    pointer-events: none;
  }

  .lp-js .lp-hero__stage.is-scene-open .lp-hero__cta { pointer-events: auto; }
}

/* ── Витающие пятна фона ────────────────────────────────────────────────
   Слой закреплён в ОКНЕ и лежит под всей страницей: пятна видны на всей длине лендинга,
   а не только на первом экране. Дрейф — чистый CSS: анимировать transform дешевле, чем
   держать на публичной странице скрипт ради декорации (в приложении для этого есть
   pvlab-blobs.js, но он завязан на его сцену и палитру).

   z-index: 0 против z-index: 1 у контента — слой обязан оказаться ПОД текстом; при
   position: fixed и порядке в DOM он иначе перекрыл бы страницу целиком. */
.lp-blobs {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

/* Контент поднимается над слоем пятен. Селектор в :where() — с нулевой специфичностью:
   обычный `.pvlab-landing > header` перебивал бы `position: sticky` у шапки (класс + тег
   против одного класса), и она переставала залипать. */
:where(.pvlab-landing) > :where(main, header, footer) { position: relative; z-index: 1; }

.lp-blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(46px);
  opacity: 0.62;
  will-change: transform;
}

.lp-blob--1 { left: 12%;  top:  8%; width: 150px; height: 150px; background: #a9d8fb; animation: lp-drift-a 19s ease-in-out infinite; }
.lp-blob--2 { left: 78%;  top: -6%; width: 320px; height: 320px; background: #bfe3fd; animation: lp-drift-b 24s ease-in-out infinite; }
.lp-blob--3 { left: 46%;  top: 38%; width: 130px; height: 130px; background: #cfeaff; animation: lp-drift-a 21s ease-in-out infinite reverse; }
.lp-blob--4 { left: 84%;  top: 62%; width: 240px; height: 240px; background: #9ed2fa; animation: lp-drift-b 27s ease-in-out infinite reverse; }
.lp-blob--5 { left: -4%;  top: 66%; width: 200px; height: 200px; background: #b6dffc; animation: lp-drift-a 23s ease-in-out infinite; }
.lp-blob--6 { left: 28%;  top: 84%; width: 165px; height: 165px; background: #c7e6fd; animation: lp-drift-b 31s ease-in-out infinite; }
.lp-blob--7 { left: 62%;  top: 16%; width: 110px; height: 110px; background: #b0dcfb; animation: lp-drift-a 26s ease-in-out infinite reverse; }

@keyframes lp-drift-a {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(26px, -22px, 0) scale(1.08); }
}
@keyframes lp-drift-b {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(-30px, 24px, 0) scale(0.93); }
}

/* ── Плашка о cookie ─────────────────────────────────────────────────── */

/* Плашка закреплена в углу ОКНА, а не в углу героя: иначе она уезжает вверх вместе с первым
   экраном, и посетитель, начавший читать со второй секции, согласия так и не увидит. */
.lp-cookie {
  position: fixed;
  right: clamp(16px, 3vw, 24px);
  bottom: clamp(16px, 3vw, 24px);
  z-index: 40;
  width: 289px;
  max-width: calc(100vw - 32px);
  padding: 24px 29px;
  border-radius: var(--lp-radius);
  background: rgba(233, 241, 255, 0.92);
  box-shadow: var(--lp-shadow);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  animation: lp-cookie-in 0.45s var(--lp-ease) both;
}

.lp-cookie[hidden] { display: none; }

.lp-cookie__title { font-size: 12px; font-weight: 700; line-height: 1.35; }
.lp-cookie__text  { margin-top: 12px; font-size: 12px; line-height: 1.35; }
.lp-cookie__accept { width: 100%; margin-top: 16px; }

@keyframes lp-cookie-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* ═══════════════════════════ Проблемы ═══════════════════════════ */

.lp-problems__grid {
  display: grid;
  grid-template-columns: minmax(0, 640px) minmax(0, 404px);
  gap: clamp(32px, 5vw, 80px);
  /* Колода по центру относительно текстовой колонки: карточка одна и вдвое ниже текста,
     прижатая к верху она оставляла под собой пустое поле в половину экрана. */
  align-items: center;
}

.lp-problems__paragraph {
  margin-top: 20px;
  font-size: clamp(16px, 1.55vw, 22px);
  font-weight: 400;
  line-height: 1.45;
  color: var(--lp-ink-body);
}
.lp-problems__text .lp-h2 + .lp-problems__paragraph { margin-top: clamp(24px, 3vw, 56px); }

/* ── Залипание секции ───────────────────────────────────────────────────
   Пока колода перелистывается, заголовок и абзацы стоят на месте. Механика штатная,
   без перехвата колеса: внешняя обёртка искусственно вытянута на несколько экранов, а
   внутренний блок держится sticky — страница прокручивается как обычно, но содержимое
   остаётся в кадре, пока обёртка проходит мимо.

   --lp-deck-step — сколько прокрутки приходится на одну карточку. Меньше ~50vh листается
   рывками, больше ~80vh воспринимается как «страница застряла». */
/* Сколько прокрутки приходится на одну карточку. 26vh — это около 230px на типовом окне,
   то есть два-три щелчка колеса. Раньше стояло 62vh (больше половины экрана на карточку):
   колесо приходилось крутить долго, и колода воспринималась как застрявшая, а не как
   листаемая. Ниже ~20vh начинается обратная беда — карточки проскакивают по две за щелчок. */
.lp-problems__scroll { position: relative; --lp-deck-step: 26vh; }

/* Залипание включаем ТОЛЬКО там, где двухколоночный блок заведомо помещается в высоту
   экрана. На узком окне колонки складываются в одну, на низком не хватает высоты — и
   пришпиленный блок ростом в экран обрезал бы собственное содержимое. В этих случаях
   секция остаётся обычной, а колода листается по мере её прохода через экран; режим
   скрипт определяет сам по вычисленному position, отдельного флага нет. */
@media (min-width: 1101px) and (min-height: 640px) {
  /* Собственные отступы секции обнуляются: залипший блок ростом в экран центрирует
     содержимое сам, и padding поверх него превращался в пустую полосу — сверху между
     первым экраном и «Знакомо?», снизу перед «Решением». */
  .lp-js .lp-problems { padding-block: 0; }

  .lp-js .lp-problems__scroll {
    height: calc(var(--lp-scene-h) + (var(--lp-cards, 5) - 1) * var(--lp-deck-step, 62vh));
  }

  .lp-js .lp-problems__sticky {
    position: sticky;
    top: 0;
    display: flex;
    align-items: center;
    height: var(--lp-scene-h);
  }

  /* Стык двух сцен подтягивается отрицательным полем.

     Откуда берётся провал. Первый экран и «Знакомо?» — залипшие блоки ростом ровно в экран,
     и каждый центрирует содержимое по вертикали. На границе встречаются НИЖНИЙ полупросвет
     первой сцены и ВЕРХНИЙ полупросвет второй, и они складываются: замерено 410px между
     последней строкой героя и словом «Знакомо?» при экране 900px, тогда как между обычными
     секциями около 190px. Обнулённый padding секции (правило выше) тут уже не помогает —
     пустоту даёт центрирование, а не отступы.

     Значения меньше самих полупросветов, поэтому подтягивание съедает только пустой фон и
     не может наехать на содержимое: у героя в запасе 150px, забираем 126, у колоды 246 —
     забираем 90. В vh, а не в px: просветы пропорциональны высоте окна, и фиксированное
     число на высоком экране оставило бы провал, а на низком — срезало бы текст.

     Вторая часть формулы — про высокие мониторы. Полупросвет равен половине незанятой
     высоты экрана, то есть растёт вместе с ним: замерено, что стык 1→2 расходится со 156px
     на экране 900px до 563px на 1440px, тогда как обычные стыки держатся около 190px на
     любой высоте. Поэтому сверх постоянной доли добавляется поправка, включающаяся только
     выше 1000px и забирающая часть каждого лишнего пикселя высоты. Коэффициент 0.65, а не 1:
     он заведомо меньше скорости роста самого просвета, и подтягивание не сможет догнать
     содержимое и наехать на него даже на очень высоком экране. */
  /* Остаток провала снимается подтягиванием соседнего блока. Доля считается от ВЫСОТЫ СЦЕНЫ,
     а не от окна: сцена ограничена сверху, и привязка к окну на большом мониторе давала пере-
     тягивание — стык 2→3 схлопывался до 18px. Обе доли заведомо меньше полупросвета сцены,
     поэтому подтягивание съедает пустой фон и не наезжает на содержимое. */
  .lp-js .lp-problems__scroll { margin-top: calc(var(--lp-scene-h) * -0.2); }
  .lp-js .lp-solution { margin-top: calc(var(--lp-scene-h) * -0.1); }
}

.lp-problems__deck { position: relative; }

.lp-deck__track { display: grid; gap: 16px; }

/* Содержимое по центру вертикали: карточки вытянуты до самой высокой, и у коротких текст
   иначе прижимался к верху, оставляя внизу пустую полосу. */
.lp-problem {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 22px 26px 26px;
  border-radius: var(--lp-radius);
  background: var(--lp-card);
  box-shadow: var(--lp-shadow);
  overflow: hidden;
}

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

   Высоту дорожки и шаг между карточками считает скрипт по самой высокой карточке
   (--lp-track-h и --lp-step): содержимое разной длины, а зашитые в CSS числа разъехались бы
   с ним на первой же правке текста. Значения ниже — только запасные, до первого замера. */
.lp-js .lp-deck__track {
  position: relative;
  display: block;
  height: var(--lp-track-h, 560px);
  gap: 0;
}

.lp-js .lp-problem {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  /* Все карточки ростом с самую высокую (значение замеряет скрипт). Разнобой был заметен
     именно в карусели: соседи стоят рядом, и короткая карточка читалась как обрезанная. */
  min-height: var(--lp-card-h, auto);
  /* Непрозрачная заливка обязательна: сквозь штатную полупрозрачную читались бы заголовки
     и номера соседних карточек. */
  background: var(--lp-card-solid);
  /* --lp-pos — позиция относительно активной СО ЗНАКОМ (-1 сверху, +1 снизу), --lp-abs —
     её модуль. Обе ставит скрипт: считать модуль средствами CSS пришлось бы через abs(),
     который поддерживается ещё не везде. */
  transform: translateY(calc(-50% + var(--lp-pos, 0) * var(--lp-step, 200px)))
             scale(calc(1 - var(--lp-abs, 0) * 0.13));
  opacity: calc(1 - var(--lp-abs, 0) * 0.55);
  z-index: calc(10 - var(--lp-abs, 0));
  transition: transform 0.6s var(--lp-ease), opacity 0.6s var(--lp-ease),
              box-shadow 0.4s var(--lp-ease);
}

/* Стартовая раскладка на случай, пока скрипт ещё не отработал: первая карточка в центре,
   вторая под ней, остальные за пределами видимости (при --lp-abs: 2 прозрачность уходит
   в ноль). Без неё между отрисовкой и DOMContentLoaded все пять стояли бы в одной точке.
   Инлайновые значения от скрипта эти правила перебивают. */
.lp-js .lp-problem { --lp-pos: 2; --lp-abs: 2; }
.lp-js .lp-problem:nth-child(1) { --lp-pos: 0; --lp-abs: 0; }
.lp-js .lp-problem:nth-child(2) { --lp-pos: 1; --lp-abs: 1; }

/* Карточки дальше соседних невидимы — и не должны перехватывать курсор. */
.lp-js .lp-problem.is-hidden { pointer-events: none; }

.lp-js .lp-problem.is-active { box-shadow: var(--lp-shadow-lift); }

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

.lp-problem__number {
  position: absolute;
  top: 14px;
  right: 22px;
  font-family: 'Geologica', 'Golos Text', system-ui, sans-serif;
  font-weight: 200;
  font-size: 111px;
  line-height: 0.876;
  letter-spacing: -0.018em;
  /* Номер растворяется книзу — тот же приём, что у заголовка героя. */
  background: linear-gradient(180deg, rgba(0, 57, 92, 0.42) 0%, rgba(50, 92, 118, 0) 76%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  pointer-events: none;
  user-select: none;
}
/* Карточки колоды одного размера. Уменьшенные 04-05 из макета («стопка уходит вдаль»)
   в карусели не нужны: там вперёд по очереди выходит каждая, и разнобой читался бы как
   ошибка вёрстки. */

.lp-problem__title {
  position: relative;
  max-width: 88%;
  font-size: clamp(19px, 1.75vw, 25px);
  font-weight: 700;
  line-height: 1.15;
  color: var(--lp-ink);
}

.lp-problem__text {
  position: relative;
  margin-top: 14px;
  font-size: 13px;
  line-height: 1.35;
  color: var(--lp-ink-dark);
}

/* ═══════════════════════════ Решение ═══════════════════════════ */

.lp-solution__title { color: var(--lp-ink); }

.lp-solution__paragraph {
  max-width: 640px;
  margin-top: 18px;
  font-size: clamp(15px, 1.25vw, 18px);
  font-weight: 400;
  line-height: 1.5;
  color: var(--lp-ink);
}
.lp-solution .lp-h2 + .lp-solution__paragraph { margin-top: clamp(24px, 3vw, 44px); }

/* ── Сетка возможностей 4 × 2 ──────────────────────────────────────── */

.lp-features {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 22px;
  margin-top: clamp(32px, 4.6vw, 62px);
}

.lp-feature {
  padding: 22px 20px 24px;
  border-radius: var(--lp-radius);
  background: var(--lp-card);
  box-shadow: var(--lp-shadow);
  transition: transform var(--lp-hover-time) var(--lp-ease-hover),
              box-shadow var(--lp-hover-time) var(--lp-ease-hover),
              background-color var(--lp-hover-time) var(--lp-ease-hover);
}
.lp-feature:hover {
  transform: translateY(-6px);
  background: var(--lp-card-hover);
  box-shadow: var(--lp-shadow-lift);
}

/* Иконка вместо прежней точки. Цвет наследуется через currentColor, поэтому у символов
   в спрайте своей заливки нет — плитка задаёт его сама. */
.lp-feature__icon {
  display: block;
  width: 26px;
  height: 26px;
  margin-bottom: 18px;
  color: var(--lp-brand-deep);
  /* Дублирует атрибуты символов в спрайте. fill и stroke — наследуемые CSS-свойства, они
     доходят до теневого дерева <use>; страховка на случай, если спрайт когда-нибудь
     пересоберут без атрибутов и иконки снова станут чёрными пятнами. */
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: color var(--lp-hover-time) var(--lp-ease-hover),
              transform var(--lp-hover-time) var(--lp-ease-hover);
}
.lp-feature:hover .lp-feature__icon { color: var(--lp-brand); transform: scale(1.12); }

.lp-feature__title { font-size: 19px; font-weight: 700; color: var(--lp-ink); }
.lp-feature__text  { margin-top: 12px; font-size: 13px; line-height: 1.35; color: var(--lp-ink-dark); }

/* ── «Сейчас» → «Станет с PV Lab.» ─────────────────────────────────── */

.lp-compare {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1.35fr);
  gap: clamp(20px, 3vw, 42px);
  align-items: center;
  margin-top: clamp(48px, 6.4vw, 92px);
}

.lp-compare__title {
  font-size: clamp(26px, 2.9vw, 42px);
  font-weight: 700;
  line-height: 1.1;
  color: var(--lp-ink);
  text-transform: uppercase;
}

.lp-compare__list { margin-top: clamp(20px, 2.6vw, 34px); }

.lp-compare__list li {
  position: relative;
  padding-left: 18px;
  font-size: clamp(14px, 1.15vw, 16px);
  line-height: 1.4;
  color: var(--lp-ink-dark);
}
.lp-compare__list li + li { margin-top: 16px; }

.lp-compare__list li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 0.55em;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--lp-ink);
}

/* Подсвеченный пункт итогового списка. Свечение сделано тенью текста, а не заливкой
   (.lp-mark): заливка читается как терминологический термин в заголовке, а здесь нужен
   акцент на последнем пункте перечисления — он должен светиться, не разрывая строй списка.

   Три тени разного радиуса вместо одной: одна широкая даёт мутное пятно, а сложенные
   дают ореол с плотным ядром у самих букв. Точка-маркер подсвечивается вместе с текстом,
   иначе она осталась бы тусклой и пункт выглядел бы наполовину выделенным. */
.lp-compare__item--glow {
  color: var(--lp-ink);
  font-weight: 700;
  text-shadow: 0 0 6px rgba(61, 167, 243, 0.55),
               0 0 16px rgba(61, 167, 243, 0.40),
               0 0 34px rgba(61, 167, 243, 0.25);
  animation: lp-glow 3.2s var(--lp-ease) infinite;
}

.lp-compare__item--glow::before {
  background: var(--lp-brand);
  box-shadow: 0 0 10px rgba(61, 167, 243, 0.9);
}

/* Медленное дыхание: пункт не мигает, а плавно наливается светом. Период намеренно
   длинный — быстрый пульс рядом с текстом мешает читать соседние строки. */
@keyframes lp-glow {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.82; }
}

.lp-compare__arrow { display: block; width: clamp(26px, 2.4vw, 34px); color: #9ec9f5; }
.lp-compare__arrow svg { width: 100%; height: auto; display: block; }

/* ═══════════════════════ Почему PV Lab ═══════════════════════ */

.lp-advantages__group + .lp-advantages__group { margin-top: clamp(48px, 6vw, 86px); }

.lp-advantages__cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(18px, 2.4vw, 32px);
  margin-top: clamp(20px, 2.6vw, 34px);
  /* Без align-items соседние карточки тянутся на всю высоту строки: тексты в паре разной
     длины (сравните «Валидированная система» и «Информационная безопасность»), и по высоте
     содержимого они получались заметно разными. */
  align-items: stretch;
}

.lp-advantage {
  padding: 22px 26px 26px;
  border-radius: var(--lp-radius);
  background: var(--lp-card);
  box-shadow: var(--lp-shadow);
  transition: transform var(--lp-hover-time) var(--lp-ease-hover),
              box-shadow var(--lp-hover-time) var(--lp-ease-hover),
              background-color var(--lp-hover-time) var(--lp-ease-hover);
}
.lp-advantage:hover {
  transform: translateY(-6px);
  background: var(--lp-card-hover);
  box-shadow: var(--lp-shadow-lift);
}

.lp-advantage__title { font-size: clamp(17px, 1.4vw, 20px); font-weight: 700; color: var(--lp-ink); }
.lp-advantage__text  { margin-top: 12px; font-size: 13px; line-height: 1.42; color: var(--lp-ink-dark); }

/* ═══════════════════════ Дорожная карта ═══════════════════════ */

.lp-roadmap__subtitle {
  max-width: 640px;
  margin-top: clamp(20px, 2.4vw, 30px);
  font-size: clamp(15px, 1.25vw, 18px);
  font-weight: 400;
  line-height: 1.5;
  color: var(--lp-ink);
}

/* Лента всегда прокручиваемая по горизонтали: восемь вех не ужимаются в узкий экран без
   потери читаемости, а сворачивать хронологию в столбик — терять саму метафору времени. */
.lp-roadmap__scroller {
  margin-top: clamp(34px, 4.4vw, 58px);
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 12px;
  /* Вид полосы задан один раз в «Базе» — здесь он не повторяется. */
}

.lp-roadmap__track {
  /* Высота строки с датой ФИКСИРОВАНА, а не auto. Иначе самая длинная подпись
     («Ноябрь-декабрь, 2026») переносится на три строки, опускает свою точку ниже соседних —
     и пунктирная ось разрывается ступенькой. */
  --lp-date-h: 42px;

  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(112px, 1fr);
  /* Ровно столько, чтобы восемь колонок (семь вех + хвост «Светлое будущее») укладывались
     в ширину контента на десктопе и полоса прокрутки не появлялась. Уже — лента едет вбок. */
  min-width: 940px;
  align-items: start;
}

.lp-milestone {
  position: relative;
  display: grid;
  grid-template-rows: var(--lp-date-h) 24px auto;
  align-items: center;
  padding-right: 10px;
}

.lp-milestone__date {
  align-self: start;
  /* nowrap: «Ноябрь-декабрь,» иначе переносится по дефису и вместе с годом требует трёх
     строк — они не влезают в фиксированную высоту строки дат. Небольшой заход на соседнюю
     колонку допустим, у соседа там короткое «Октябрь,». */
  white-space: nowrap;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.35;
  color: var(--lp-ink);
}
.lp-milestone__date br + * { font-weight: 400; }

/* Пунктирная ось проходит через ряд точек. Рисуем её на самой вехе, а не одной линией на
   всю ленту: так линия тянется ровно до последней вехи и не выступает из-под стрелки. */
.lp-milestone::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--lp-date-h) + 12px);
  height: 0;
  border-top: 1.5px dashed rgba(0, 57, 92, 0.45);
}

.lp-milestone__dot {
  position: relative;
  z-index: 1;
  justify-self: start;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--lp-brand);
  box-shadow: 0 0 0 4px var(--lp-bg);
  /* Точки проявляются по очереди, когда лента входит в экран (класс ставит скрипт). */
  transform: scale(0);
  transition: transform 0.4s var(--lp-ease) var(--lp-delay, 0ms);
}
.lp-roadmap__track.is-drawn .lp-milestone__dot { transform: scale(1); }

/* Разделитель — левая граница подписи, и он обязан прийтись РОВНО на центр точки.
   Точка прижата к началу колонки (justify-self: start) и шириной 11px, значит её центр
   на 5.5px правее края. На столько же сдвигаем блок подписи: без сдвига линия шла по
   краю колонки, то есть левее точки на её половину. */
.lp-milestone__text {
  margin-left: 5.5px;
  padding-top: 12px;
  padding-right: 10px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--lp-ink-dark);
}
.lp-milestone + .lp-milestone .lp-milestone__text {
  padding-left: 12px;
  border-left: 1px solid rgba(0, 57, 92, 0.16);
}

/* Хвост ленты: стрелка и подпись стоят рядом на самой оси, а не друг под другом — оба
   элемента кладём во вторую строку и разводим по колонкам. Без явной колонки подпись
   автоматически уезжала в первую строку (стрелка занимала вторую) и оказывалась над осью. */
.lp-milestone--future {
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: var(--lp-date-h) 24px auto;
  column-gap: 10px;
  padding-right: 0;
}
.lp-milestone--future::before { content: none; }
.lp-milestone--future .lp-milestone__text {
  grid-row: 2;
  grid-column: 2;
  align-self: center;
  border-left: 0;
  padding: 0;
  font-weight: 500;
}

.lp-milestone__arrow {
  grid-row: 2;
  grid-column: 1;
  align-self: center;
  width: 46px;
}
.lp-milestone__arrow svg { width: 100%; height: auto; display: block; }

/* Пунктир хвоста повторяет ось между вехами: тот же цвет и та же толщина. Шаг штриха
   подобран под вид CSS-границы dashed при 1.5px — точного соответствия между dasharray
   и отрисовкой border: dashed не существует, браузеры считают её по-своему. */
.lp-milestone__arrow-line {
  stroke: rgba(0, 57, 92, 0.45);
  stroke-width: 1.5;
  stroke-dasharray: 4 3.5;
}

/* Наконечник остаётся акцентным — как точки вех. */
.lp-milestone__arrow-head {
  stroke: var(--lp-brand);
  stroke-width: 2;
}

/* ═══════════════════════════ Интерфейс ═══════════════════════════ */

.lp-interface .lp-h2 { color: var(--lp-ink); max-width: 1000px; }

.lp-carousel {
  position: relative;
  margin-top: clamp(32px, 4.2vw, 56px);
  border-radius: var(--lp-radius);
  background: var(--lp-card);
  box-shadow: var(--lp-shadow);
  overflow: hidden;
}

.lp-carousel__viewport { position: relative; display: grid; }

/* Слайды лежат друг на друге в одной ячейке грида: высота карусели равна самому высокому
   слайду и не скачет при переключении. */
.lp-slide {
  grid-area: 1 / 1;
  display: grid;
  grid-template-columns: minmax(0, 0.78fr) minmax(0, 1fr);
  gap: clamp(20px, 3vw, 40px);
  align-items: center;
  padding: clamp(28px, 4vw, 54px) clamp(56px, 5vw, 72px) clamp(28px, 4vw, 54px) clamp(24px, 3vw, 34px);
  opacity: 0;
  visibility: hidden;
  transform: translateX(24px);
  transition: opacity 0.45s var(--lp-ease), transform 0.45s var(--lp-ease), visibility 0s 0.45s;
}

.lp-slide.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.45s var(--lp-ease), transform 0.45s var(--lp-ease), visibility 0s;
}

.lp-slide__title {
  font-size: clamp(22px, 2.2vw, 32px);
  font-weight: 700;
  line-height: 1.16;
  color: var(--lp-ink);
}

.lp-slide__caption {
  margin-top: 18px;
  font-size: clamp(13px, 1.05vw, 15px);
  line-height: 1.45;
  color: var(--lp-ink-dark);
}

/* Снимок показывается целиком, в своих пропорциях. Раньше здесь было общее окно с
   object-fit: cover — оно держало высоту карусели постоянной, но срезало низ каждого
   экрана. Теперь высоту карусели задаёт самый высокий слайд (все три лежат в одной ячейке
   грида), а более широкие центрируются в ней по вертикали — align-items у .lp-slide. */
.lp-slide__shot {
  width: 100%;
  height: auto;
  border-radius: 14px;
  box-shadow: 0 18px 40px rgba(0, 57, 92, 0.22);
  /* Лёгкий параллакс: скрипт двигает --lp-shift при прокрутке секции. */
  transform: translateY(var(--lp-shift, 0px));
  will-change: transform;
}

.lp-carousel__dots {
  position: absolute;
  right: 18px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.lp-dot {
  width: 11px;
  height: 11px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #b2babf;
  cursor: pointer;
  transition: background-color 0.25s var(--lp-ease), transform 0.25s var(--lp-ease);
}
.lp-dot:hover { transform: scale(1.25); }
.lp-dot.is-active { background: var(--lp-brand); }

/* ═══════════════════════════ F.A.Q. ═══════════════════════════ */

.lp-faq__list { margin-top: clamp(26px, 3.4vw, 40px); display: grid; gap: 18px; }

.lp-faq__item {
  border-radius: var(--lp-radius-sm);
  background: var(--lp-card);
  box-shadow: var(--lp-shadow);
  overflow: hidden;
  transition: background-color var(--lp-hover-time) var(--lp-ease-hover),
              box-shadow var(--lp-hover-time) var(--lp-ease-hover);
}
.lp-faq__item:hover { background: var(--lp-card-hover); }
.lp-faq__item[open] { box-shadow: var(--lp-shadow-lift); }

.lp-faq__question {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 22px clamp(22px, 2.6vw, 44px);
  font-size: clamp(14px, 1.15vw, 16px);
  font-weight: 700;
  color: var(--lp-ink);
  cursor: pointer;
  list-style: none;
}
.lp-faq__question::-webkit-details-marker { display: none; }

.lp-faq__chevron {
  flex: 0 0 auto;
  width: 22px;
  color: var(--lp-ink);
  transition: transform 0.4s var(--lp-ease);
}
.lp-faq__chevron svg { width: 100%; height: auto; display: block; }

/* Стрелка поворачивается по классу is-open, а не по [open]: при закрытии скрипт снимает
   сам атрибут только в конце анимации высоты, и стрелка дожидалась бы её окончания.
   Правило с [open] оставлено фолбэком на случай, когда скрипт не отработал.
   Порядок важен: is-closing идёт последним и перебивает [open] при равной специфичности. */
.lp-faq__item[open] .lp-faq__chevron,
.lp-faq__item.is-open .lp-faq__chevron { transform: rotate(90deg); }
.lp-faq__item.is-closing .lp-faq__chevron { transform: none; }

.lp-faq__answer {
  padding: 0 clamp(22px, 2.6vw, 44px) 24px;
  font-size: clamp(13px, 1.1vw, 15px);
  line-height: 1.5;
  color: var(--lp-ink-dark);
}

/* Раскрытие и закрытие анимирует pvlab-landing.js по высоте самого <details> (штатный
   элемент переключается мгновенно, к нему CSS-переход не приделать). Здесь — только
   подстраховка: пока идёт анимация, содержимое не должно вылезать за скруглённые углы. */
.lp-faq__item.is-animating { overflow: hidden; }

/* ═══════════════════════════ Команда ═══════════════════════════ */

.lp-team__subtitle {
  max-width: 720px;
  margin-top: clamp(18px, 2.2vw, 26px);
  font-size: clamp(14px, 1.15vw, 16px);
  line-height: 1.5;
  color: var(--lp-ink-dark);
}

.lp-team__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(18px, 2.4vw, 32px);
  margin-top: clamp(30px, 3.6vw, 46px);
  align-items: stretch;
}

.lp-team__card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 26px;
  border-radius: var(--lp-radius);
  background: var(--lp-card);
  box-shadow: var(--lp-shadow);
  transition: transform var(--lp-hover-time) var(--lp-ease-hover),
              box-shadow var(--lp-hover-time) var(--lp-ease-hover),
              background-color var(--lp-hover-time) var(--lp-ease-hover);
}
.lp-team__card:hover {
  transform: translateY(-6px);
  background: var(--lp-card-hover);
  box-shadow: var(--lp-shadow-lift);
}

.lp-team__photo {
  width: 84px;
  height: 84px;
  border-radius: 50%;
  object-fit: cover;
  margin-bottom: 18px;
}

/* Заглушка вместо снимка: инициалы на мягкой заливке. Выглядит осознанным оформлением,
   а не забытой картинкой, и подменяется на фото одной строкой в модели. */
.lp-team__photo--initials {
  display: grid;
  place-items: center;
  background: linear-gradient(140deg, #d3ecff, #a9d8fb);
  color: var(--lp-ink);
  font-size: 28px;
  font-weight: 700;
  letter-spacing: 0.02em;
  user-select: none;
}

.lp-team__name { font-size: clamp(17px, 1.4vw, 20px); font-weight: 700; color: var(--lp-ink); }
.lp-team__role { margin-top: 6px; font-size: 13px; font-weight: 600; color: var(--lp-brand-deep); }
.lp-team__about { margin-top: 12px; font-size: 13px; line-height: 1.45; color: var(--lp-ink-dark); }

/* ═══════════════════ Заявка на демонстрацию ═══════════════════ */

.lp-modal {
  /* Отступ вынесен в переменную: от него же считается отрицательное поле капчи,
     и разъехаться эти два числа не должны. */
  --lp-modal-pad: clamp(26px, 4vw, 38px);

  /* Воздух между окном и краем экрана. Своё значение вместо браузерного
     calc(100% - 6px - 2em): то оставляло под содержимое ровно 582px на экране 620px,
     это оставляет 588px. Наше ограничение мягче браузерного, поэтому на просторных
     экранах оно просто не срабатывает. */
  --lp-modal-inset: 16px;

  /* Высота растушёвки у краёв прокрутки. Ею же заданы внутренние поля прокручиваемой
     области: в крайних положениях градиент ложится на пустое поле, а не на первое или
     последнее поле формы — иначе докрученный до упора список выглядел бы выцветшим,
     то есть сломанным. Ровно на эти 20px уменьшены верхние поля первого элемента и
     кнопки, поэтому на просторном экране высота окна не изменилась ни на пиксель. */
  --lp-modal-fade: 20px;

  width: min(460px, calc(100vw - 32px));

  /* Две строки намеренно: dvh считает по видимой части экрана и не уезжает под панель
     мобильного браузера, а первая — запас для движков, которые его не знают. */
  max-height: calc(100vh - var(--lp-modal-inset) * 2);
  max-height: calc(100dvh - var(--lp-modal-inset) * 2);

  padding: 0;   /* отступы переехали в шапку, прокрутку и подвал */
  border: 0;
  border-radius: var(--lp-radius);
  background: #fff;
  box-shadow: 0 30px 70px rgba(0, 57, 92, 0.28);
  color: var(--lp-ink);

  /* Прокручивается не окно целиком, а только его середина. Раньше прокрутка была у самого
     <dialog> (браузерное overflow: auto), и на невысоком экране кнопка «Отправить заявку»
     уезжала за нижний край без единого признака, что там что-то есть, — это и читалось
     как обрезка, а не как «прокрути». */
  overflow: hidden;
}

.lp-modal::backdrop {
  background: rgba(0, 32, 54, 0.45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

/* Появление окна и подложки. Анимируем через [open]: <dialog> добавляет атрибут в момент
   показа, и отдельный класс для этого не нужен. */
/* display объявлен ЗДЕСЬ, а не в .lp-modal, и это не стилистика: авторское правило сильнее
   браузерного dialog:not([open]) { display: none } по происхождению каскада, и колонка,
   объявленная без [open], вытащила бы закрытое окно прямо на страницу. */
.lp-modal[open] {
  display: flex;
  flex-direction: column;
  animation: lp-modal-in 0.3s var(--lp-ease);
}
.lp-modal[open]::backdrop { animation: lp-backdrop-in 0.3s var(--lp-ease); }

@keyframes lp-modal-in {
  from { opacity: 0; transform: translateY(14px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}
@keyframes lp-backdrop-in { from { opacity: 0; } to { opacity: 1; } }

/* Форма — вторая ступень колонки. min-height: 0 обязателен на КАЖДОЙ ступени: по умолчанию
   флекс-элемент не сжимается ниже своего содержимого, прокрутке внутри взяться неоткуда,
   и окно снова полезет за край экрана. */
.lp-modal__body {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  padding: 0;
}

.lp-modal__close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 34px;
  height: 34px;
  padding: 7px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--lp-ink);
  cursor: pointer;
  z-index: 2;   /* поверх растушёвки шапки: она позиционирована и иначе перехватила бы клик */
  transition: background-color var(--lp-hover-time) var(--lp-ease-hover);
}
.lp-modal__close:hover { background: rgba(0, 57, 92, 0.08); }
.lp-modal__close svg { width: 100%; height: 100%; display: block; }

/* Межстрочное — втрое-с-половиной плотнее унаследованного 1.45: у двухстрочного заголовка
   окна строки расходились так, будто это абзац. 1.0 — предел, ниже которого «р» и «ц»
   из «демонстрацию» начинают задевать строку под собой. */
.lp-modal__title {
  font-size: clamp(20px, 2vw, 26px);
  font-weight: 700;
  line-height: 1;
  color: var(--lp-ink);
}
.lp-modal__subtitle { margin-top: 10px; font-size: 14px; line-height: 1.5; color: var(--lp-ink-dark); }

.lp-field { display: block; margin-top: 18px; }
.lp-field__label { display: block; margin-bottom: 6px; font-size: 13px; font-weight: 600; color: var(--lp-ink); }

.lp-field__input {
  width: 100%;
  padding: 12px 16px;
  border: 1px solid rgba(0, 57, 92, 0.18);
  border-radius: 12px;
  background: #f7fbff;
  color: var(--lp-ink);
  font-family: inherit;
  font-size: 15px;
  transition: border-color 0.25s var(--lp-ease-hover), background-color 0.25s var(--lp-ease-hover);
}
.lp-field__input::placeholder { color: #90a6b6; }
.lp-field__input:focus { outline: none; border-color: var(--lp-brand); background: #fff; }
.lp-field__input.is-invalid { border-color: #c5253a; background: #fff6f7; }

.lp-field__error { display: block; margin-top: 6px; font-size: 12px; color: #c5253a; }
.lp-field__error:empty { display: none; }

.lp-modal__error {
  margin-top: 16px;
  padding: 12px 14px;
  border-radius: 12px;
  background: #fff1f2;
  color: #a01c2e;
  font-size: 13px;
  line-height: 1.45;
}
.lp-modal__error[hidden] { display: none; }

/* Гнездо капчи. Пока библиотека не считает её нужной, сюда не приходит ничего — и блок
   не должен занимать места: :empty убирает и отступ. Виджет Яндекса приезжает своей вёрсткой,
   ширину ему не навязываем, только не даём вылезти за края окна. */
.lp-captcha { margin-top: 20px; }
.lp-captcha:empty { display: none; }
.lp-captcha > * { max-width: 100%; }

/* Виджет Яндекса имеет неснижаемую ширину 300px и в узкое окно с отступами не влезает:
   на экране 360px под содержимое остаётся 270px, и капча вылезала за края. Отдаём ей всю
   ширину окна, погасив внутренние отступы. Прокрутка — страховка для совсем узких экранов
   (уже 320px): лучше сдвинуть виджет пальцем, чем поломать раскладку страницы. */
@media (max-width: 400px) {
  .lp-captcha {
    display: flex;
    justify-content: safe center;
    margin-inline: calc(var(--lp-modal-pad) * -1);
    overflow-x: auto;
  }
}

.lp-modal__submit { width: 100%; margin-top: 22px; }
.lp-modal__submit[disabled] { opacity: 0.65; cursor: progress; }

/* Шаги формы — третья ступень колонки. Шаг с полями раскладывается на шапку, прокрутку и
   подвал; шагу «успех» делить нечего, он остаётся обычным блоком. */
.lp-modal__step { flex: 1 1 auto; min-height: 0; }
.lp-modal__step--fields { display: flex; flex-direction: column; }

/* Своя прокрутка взамен утраченной браузерной: у окна теперь overflow: hidden, и без этой
   строки длинный текст успеха на низком экране стало бы некуда докрутить. */
.lp-modal__step--success { overflow-y: auto; padding: var(--lp-modal-pad); }

.lp-modal__step[hidden] { display: none; }

/* Шапка и подвал не сжимаются: заголовок и кнопка отправки видны при любой высоте экрана,
   прокручивается только то, что между ними, — поля и капча. Именно это, а не выигранные
   отступы, и есть гарантия того, что кнопка перестанет обрезаться. */
.lp-modal__head {
  position: relative;
  flex: none;
  padding: var(--lp-modal-pad) var(--lp-modal-pad) 0;
}

.lp-modal__foot {
  position: relative;
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 16px;   /* просвет между общим сообщением об ошибке и кнопкой */
  padding: 0 var(--lp-modal-pad) var(--lp-modal-pad);
}

/* Расстояния в подвале держит gap; собственные верхние поля потомков прибавились бы к нему
   и оторвали кнопку от края. Правило намеренно узкое — одноимённой кнопки на шаге «успех»
   оно не касается, там margin-top по-прежнему нужен. */
.lp-modal__foot > * { margin-top: 0; }

/* Прокручиваемая середина. Намеренно НЕ position: relative — сразу по двум причинам:
   .lp-honeypot с left: -9999px получил бы этот блок своим содержащим блоком, а растушёвка
   шапки перестала бы его перекрывать (непозиционированный поток рисуется раньше
   позиционированных элементов, на чём и держится z-index у градиентов ниже). */
.lp-modal__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;

  /* Боковые отступы теперь здесь, а не на форме: полоса прокрутки должна вставать у самого
     края окна, а не внутри поля. Побочно это сохраняет правило полноширинной капчи из
     @media (max-width: 400px): её margin-inline считается от того же --lp-modal-pad. */
  padding: var(--lp-modal-fade) var(--lp-modal-pad);

  /* Куда браузер доводит поле, к которому пришёл фокус по Tab, и капчу, которую подводит
     скрипт: без этого элемент встаёт впритык к границе и наполовину прячется под растушёвкой. */
  scroll-padding-block: var(--lp-modal-fade);

  /* Докрутив до конца, не тянем за собой страницу под окном. */
  overscroll-behavior: contain;
}

/* Верхнее поле первого элемента снято: его роль играет padding прокрутки. Без этого правила
   и без .lp-modal__foot > * отступы сложились бы, и окно на просторном экране стало бы выше. */
.lp-modal__scroll > :first-child { margin-top: 0; }

/* Растушёвка у границ прокрутки. Содержимое не обрывается линией, а уходит под шапку и под
   кнопку: срез читается как «дальше есть ещё», а не как обрезанная вёрстка — ровно та
   претензия, с которой всё началось. pointer-events снят, иначе градиент перехватывал бы
   клик по капче под собой. */
.lp-modal__head::after,
.lp-modal__foot::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: var(--lp-modal-fade);
  pointer-events: none;
  z-index: 1;
}
.lp-modal__head::after {
  top: 100%;
  background: linear-gradient(to bottom, #fff, rgba(255, 255, 255, 0));
}
.lp-modal__foot::before {
  bottom: 100%;
  background: linear-gradient(to top, #fff, rgba(255, 255, 255, 0));
}

/* Поле-ловушка. Не display:none и не hidden: часть автозаполнялок пропускает полностью
   невидимые поля, а уведённое за границу экрана — заполняет, что нам и нужно. */
.lp-honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ═══════════════════════ Финальный призыв ═══════════════════════ */

/* Фон у секции такой же, как у всех остальных: собственного он больше не имеет.
   Были голубой градиент вправо и белое полупрозрачное пятно за заголовком — оба убраны,
   секция ничем не выделяется на фоне страницы. Элемент пятна оставлен в разметке скрытым:
   вернуть его дешевле, чем восстанавливать по истории, если решение переиграют. */
.lp-final { position: relative; }
.lp-final__glow { display: none; }

.lp-final .lp-container { position: relative; z-index: 1; }

.lp-final__title { max-width: 1031px; color: var(--lp-ink); }

.lp-final__paragraph {
  max-width: 640px;
  font-size: clamp(14px, 1.15vw, 16px);
  line-height: 1.5;
  color: var(--lp-ink);
}
.lp-final__title + .lp-final__paragraph { margin-top: clamp(26px, 3.4vw, 44px); }
.lp-final__paragraph + .lp-final__paragraph { margin-top: 18px; }

.lp-final .lp-btn { margin-top: clamp(26px, 3.4vw, 40px); }

/* ═══════════════════════════ Подвал ═══════════════════════════ */

.lp-footer { background: var(--lp-footer-bg); padding-block: 26px; }

/* Последняя остановка прокрутки — КОНЕЦ страницы, а не начало финальной секции.

   Выравнивание по началу давало точку ниже предела прокрутки: страница физически не может
   доехать до неё, и жёсткое притягивание держало бы посетителя на предыдущей остановке,
   не показывая ни призыв, ни подвал. Выравнивание по концу всегда достижимо, а призыв
   и подвал вместе (≈590px) укладываются в один экран. */
/* Разделительной линии над содержимым подвала нет: подвал и так отбит от страницы сменой
   фона на тёмный, и линия поверх этой границы читалась как лишний шов. */
.lp-footer__inner {
  display: flex;
  align-items: center;
  gap: clamp(18px, 3vw, 48px);
}

.lp-footer__logo { width: 52px; height: auto; flex: 0 0 auto; }

.lp-footer__text { font-size: 14px; color: var(--lp-footer-ink); }

.lp-footer__link {
  margin-left: 6px;
  color: var(--lp-footer-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 0.2s var(--lp-ease);
}
.lp-footer__link:hover { color: #fff; }

/* ═══════════════════ Появление при прокрутке ═══════════════════
   Начальное состояние включается только при живом JS (класс lp-js ставит layout синхронно
   в <head>). Без скрипта содержимое видно сразу и не остаётся прозрачным навсегда. */

/* Появление сделано АНИМАЦИЕЙ, а не переходом. Переход пришлось бы объявлять на самом
   [data-reveal], а он висит и на плитках — свойство transition у них переписывалось целиком,
   и собственные переходы плитки (фон, тень) при наведении пропадали: подсветка включалась
   рывком, а сдвиг ехал плавно.

   fill-mode именно backwards: во время задержки элемент держит первый кадр, а ПОСЛЕ конца
   анимации никакой заливки не остаётся — плитка возвращается к своим обычным стилям, и
   hover-трансформация работает как ни в чём не бывало. С both финальный transform: none
   от анимации перебивал бы :hover. */
.lp-js [data-reveal] { opacity: 0; }

.lp-js [data-reveal].is-visible {
  opacity: 1;
  animation: lp-reveal 0.6s var(--lp-ease) var(--lp-delay, 0ms) backwards;
}

@keyframes lp-reveal {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

/* ═════════════════════ Большие мониторы (2K и шире) ═════════════════════
   Почти вся типографика задана через clamp(min, Nvw, max), и на широком экране всё упирается
   в ВЕРХНЮЮ границу: на 2560px «3.35vw» это 85px, но clamp обрезает до 48px. В итоге текст
   перестаёт расти вместе с окном и выглядит мелким. Поднимаем потолки и заодно расширяем
   колонку контента — иначе выросший кегль просто уплотнит те же 1096px.

   Порог 1800px, а не 1920: типовой 2K-монитор в масштабе Windows 125% даёт около 2048
   логических пикселей, а 1920-й в 100% — ровно 1920, и оба должны попасть под правило. */
@media (min-width: 1800px) {
  .pvlab-landing {
    --lp-content: 1320px;
    font-size: 17px;
  }

  .lp-h2 { font-size: 56px; }
  .lp-eyebrow { font-size: 11px; }

  .lp-hero__title { font-size: 66px; }
  .lp-hero__lead { font-size: 17px; }

  .lp-problems__paragraph { font-size: 24px; }
  .lp-problem__title { font-size: 28px; }
  .lp-problem__text { font-size: 15px; }

  .lp-solution__paragraph { font-size: 20px; }
  .lp-feature__title { font-size: 21px; }
  .lp-feature__text { font-size: 15px; }
  .lp-feature__icon { width: 30px; height: 30px; }

  .lp-compare__list li { font-size: 18px; }

  .lp-advantage__title { font-size: 22px; }
  .lp-advantage__text { font-size: 15px; }

  .lp-roadmap__subtitle { font-size: 20px; }
  .lp-milestone__date { font-size: 15px; }
  .lp-milestone__text { font-size: 13px; }

  .lp-slide__title { font-size: 36px; }
  .lp-slide__caption { font-size: 17px; }

  .lp-faq__question { font-size: 18px; }
  .lp-faq__answer { font-size: 17px; }

  .lp-team__subtitle { font-size: 18px; }
  .lp-team__name { font-size: 22px; }
  .lp-team__role { font-size: 15px; }
  .lp-team__about { font-size: 15px; }
  .lp-team__photo { width: 96px; height: 96px; }

  .lp-final__paragraph { font-size: 18px; }
  .lp-footer__text { font-size: 16px; }

  .lp-header__link { font-size: 18px; }
  .lp-btn--outline { padding: 10px 28px; font-size: 16px; }
  .lp-btn--primary { padding: 19px 36px; font-size: 18px; }
  .lp-btn--outline-accent { padding: 19px 44px; font-size: 16px; }

  .lp-modal { width: min(520px, calc(100vw - 32px)); }
  .lp-field__input { font-size: 17px; padding: 14px 18px; }
  .lp-field__label { font-size: 15px; }
  .lp-modal__subtitle { font-size: 16px; }
}

/* ═══════════════ Экраны шире 2K ═══════════════
   Выше 1800px шкала обрывалась: колонка навсегда замирала на 1320px, и дальше рос только
   пустой фон по краям. Замерено: на 2560px по бокам оставалось по 560px, на 3440px — по
   1000px, то есть от 44% до 58% ширины экрана не занято ничем. Именно на это и жалуются.

   Растёт колонка, а не только кегль: пустует ШИРИНА, и увеличение шрифта в прежней колонке
   её не заполнит, а лишь удлинит строки. Кегль поднимается следом, чтобы текст не выглядел
   мелким в широком блоке.

   Верхняя ступень намеренно последняя: у абзацев есть собственные max-width, и дальше
   расширять колонку значит гнать строку за предел читаемости (после ~90 знаков глаз теряет
   начало следующей строки). За 3400px поля снова начнут расти — это осознанный предел,
   а не недосмотр. */
@media (min-width: 2200px) {
  .pvlab-landing {
    --lp-content: 1560px;
    font-size: 18px;
  }

  .lp-h2 { font-size: 62px; }

  /* Кегль и ширина колонки правятся ВМЕСТЕ: слову «Фармаконадзор» при 74px нужно 582px,
     и в прежние 560px оно не влезало — хвост уходил за блок и пропадал вместе с заливкой. */
  .lp-hero { --lp-hero-col: 660px; }
  .lp-hero__title { font-size: 74px; }
  .lp-problems__paragraph { font-size: 26px; }
  .lp-problem__title { font-size: 30px; }
  .lp-slide__title { font-size: 40px; }

  /* Вводные абзацы упёрты в 640px на всех ширинах, и на широком экране это давало провал:
     41% колонки занято, остальное пусто. Ограничение снимать нельзя — оно и держит строку
     читаемой. Но 640px рассчитаны на кегль 16px, а здесь он 18px: тех же букв в строке
     теперь помещается меньше. Поднимаем предел ровно во столько же раз (640 × 18/16),
     то есть длина строки в ЗНАКАХ не меняется, а ширина растёт вместе со шрифтом. */
  .lp-solution__paragraph,
  .lp-roadmap__subtitle,
  .lp-final__paragraph { max-width: 720px; }
}

@media (min-width: 2800px) {
  .pvlab-landing {
    --lp-content: 1760px;
    font-size: 19px;
  }

  .lp-h2 { font-size: 68px; }

  /* При 82px слову нужно 645px. */
  .lp-hero { --lp-hero-col: 740px; }
  .lp-hero__title { font-size: 82px; }

  /* Тот же пересчёт, что ступенью ниже: 640 × 19/16. */
  .lp-solution__paragraph,
  .lp-roadmap__subtitle,
  .lp-final__paragraph { max-width: 760px; }
}

/* ═══════════════════════════ Адаптив ═══════════════════════════
   Макета для узких экранов нет — раскладки ниже выведены из десктопного: сетки схлопываются
   по степеням двойки, лента роадмапа остаётся прокручиваемой. Колода «Знакомо?» работает на
   всех ширинах без правок: она и так занимает одну колонку. */

/* Сцена первого экрана отключена — герой становится обычным центрированным блоком.
   Условие ЗЕРКАЛЬНО тому, что включает сцену выше; разойдись они, колонка осталась бы
   узкой и сдвинутой, а снимки — за краем экрана. */
@media (max-width: 1100px), (max-height: 639px) {
  .lp-hero__inner {
    width: 100%;
    max-width: var(--lp-content);
    margin-inline: auto;
    padding-inline: var(--lp-gutter);
    transform: none;
  }

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

     overflow у сцены снимается: она была обрезана по 100vh ради разъезда, и в колонке
     отрезала бы снимки вместе с нижним краем. */
  .lp-hero__stage {
    flex-direction: column;
    justify-content: center;
    overflow: visible;
    padding-block: clamp(96px, 18vw, 140px) clamp(40px, 10vw, 72px);
  }

  .lp-hero__shots {
    position: static;
    width: min(340px, 78%);
    margin: clamp(30px, 8vw, 52px) auto 0;
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }

  /* Нахлёст мельче десктопного, а веер — фиксированный: раскрывать его было нечем,
     прогресса сцены здесь не существует. */
  .lp-hero__shot--2,
  .lp-hero__shot--3 { margin-top: -11%; }
  .lp-hero__shot--2 { transform: translateX(9%); }
  .lp-hero__shot--3 { transform: translateX(-7%); }

  .lp-hero__title { font-size: clamp(34px, 6.2vw, 76px); }
  .lp-hero__lead { max-width: 530px; margin-inline: auto; font-size: clamp(14px, 1.3vw, 17px); }
}

@media (max-width: 1100px) {
  .lp-problems__grid { grid-template-columns: minmax(0, 1fr); }
  .lp-features { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .lp-team__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  /* Контакты уводим в кнопку «Связаться»: телефон и почта не помещаются рядом с логотипом,
     а обрезать их многоточием хуже, чем оставить один явный призыв. */
  .lp-header__pill { min-height: 66px; }

  .lp-compare { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .lp-compare__arrow { justify-self: center; transform: rotate(90deg); }

  .lp-slide { grid-template-columns: minmax(0, 1fr); padding: 28px 24px 56px; }
  .lp-slide__text { order: 1; }
  .lp-slide__shot { order: 2; }
  .lp-carousel__dots { flex-direction: row; right: 50%; top: auto; bottom: 18px; transform: translateX(50%); }
}

@media (max-width: 700px) {
  .lp-advantages__cards { grid-template-columns: minmax(0, 1fr); }
  .lp-features { grid-template-columns: minmax(0, 1fr); }
  .lp-team__grid { grid-template-columns: minmax(0, 1fr); }

  .lp-hero__stage { padding-block: 118px 64px; }
  .lp-hero__lead { font-size: 15px; }

  /* Плашка cookie перестаёт быть «карточкой в углу» и занимает всю ширину: угол экрана на
     телефоне слишком мал, чтобы в нём поместился читаемый текст с кнопкой. */
  .lp-cookie {
    left: 12px;
    right: 12px;
    bottom: 12px;
    width: auto;
    max-width: none;
  }

  .lp-footer__inner { flex-direction: column; align-items: flex-start; gap: 16px; }
  .lp-footer__text { font-size: 13px; }
  .lp-footer__link { display: block; margin-left: 0; margin-top: 6px; }
}

@media (max-width: 480px) {
  .lp-eyebrow { min-width: 0; }
  .lp-btn--primary { padding: 15px 24px; font-size: 15px; width: 100%; }
  .lp-hero__cta { width: 100%; }
  .lp-problem__number { font-size: 84px; }
}

/* ═══════════════ Окно заявки на невысоком экране ═══════════════
   Порог 720px взят из бюджета, а не круглый: в полную величину форма занимает ~729px и
   перестаёт помещаться примерно с 761px вьюпорта, но 1440×760 обязан выглядеть ровно как
   сегодня — поэтому уплотнение начинается заведомо ниже этой границы. Сжимаем только
   воздух: отступы, зазоры и кегль служебных строк. Поле ввода остаётся, кнопка не
   трогается вовсе — она и есть то, ради чего всё затевалось.

   Блок обязан оставаться ПОСЛЕ @media (min-width: 1800px): специфичность там та же,
   и выигрывает тот, кто ниже по файлу. */
@media (max-height: 720px) {
  .lp-modal {
    --lp-modal-pad: 26px;
    --lp-modal-fade: 16px;
  }

  .lp-modal__title { font-size: 20px; }   /* нижняя граница собственного clamp(20px, 2vw, 26px) */
  .lp-modal__subtitle { margin-top: 6px; font-size: 13px; line-height: 1.4; }
  .lp-modal__foot { gap: 12px; }

  .lp-field { margin-top: 12px; }

  /* padding-block, а не padding: горизонтальные отступы поля приходят шорткодом из блока
     @media (min-width: 1800px), к высоте они отношения не имеют. */
  .lp-field__input { padding-block: 10px; }

  .lp-captcha { margin-top: 14px; }
}

/* Ниже 660px даже уплотнённая форма не показывает капчу целиком без прокрутки. Убираем
   единственную строку, которую можно убрать без потери смысла, — вводную фразу: о чём эта
   форма, уже сказано заголовком и кнопкой, с которой её открыли. Привязка к шагу
   обязательна: тем же классом на шаге «успех» набран ответ посетителю, его скрывать нельзя. */
@media (max-height: 660px) {
  .lp-modal__step--fields .lp-modal__subtitle { display: none; }
}

/* ═══════════════════ Уважение к настройке «меньше движения» ═══════════════════
   Пользователь с prefers-reduced-motion получает ту же страницу без анимаций: блоки сразу
   видимы, точки роадмапа сразу на месте, слайды переключаются без сдвига. */

@media (prefers-reduced-motion: reduce) {
  .pvlab-landing *,
  .pvlab-landing *::before,
  .pvlab-landing *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .lp-js [data-reveal] { opacity: 1; transform: none; animation: none; }
  .lp-roadmap__track .lp-milestone__dot { transform: scale(1); }
  .lp-slide { transform: none; }

  /* Колода «Знакомо?» разбирается обратно в список, а секция перестаёт залипать: и то и
     другое здесь — чистая анимация, а с обнулёнными переходами превратилось бы в рывковую
     подмену карточек внутри застрявшего экрана. */
  /* Сцена первого экрана тоже разбирается: её смысл целиком в движении. */
  .lp-js .lp-hero { height: auto; }
  .lp-js .lp-hero__stage { position: static; height: auto; min-height: 100vh; }
  .lp-hero__inner { width: 100%; max-width: var(--lp-content); margin-inline: auto;
                    padding-inline: var(--lp-gutter); transform: none; }

  /* Снимки остаются на месте и здесь: анимацию отключают, чтобы не мутило от движения,
     а не чтобы лишиться половины содержимого первого экрана. Просто встают под текстом. */
  .lp-hero__stage { flex-direction: column; justify-content: center; overflow: visible; }
  .lp-hero__shots { position: static; width: min(420px, 80%); margin: 40px auto 0;
                    opacity: 1; transform: none; }
  .lp-hero__shot--2, .lp-hero__shot--3 { margin-top: -11%; transform: none; }
  .lp-js .lp-hero__cta { opacity: 1; pointer-events: auto; }

  .lp-js .lp-problems__scroll { height: auto; }
  .lp-js .lp-problems__sticky { position: static; height: auto; display: block; }
  .lp-js .lp-deck__track { display: grid; gap: 16px; height: auto; }
  .lp-js .lp-problem {
    position: relative;
    top: auto;
    transform: none;
    opacity: 1;
    pointer-events: auto;
    background: var(--lp-card);
  }
  .lp-slide__shot { transform: none; }
  .lp-btn:hover,
  .lp-problem:hover,
  .lp-feature:hover,
  .lp-advantage:hover { transform: none; }
}
