/* Лендинг «Лабиринт» — вёрстка по макету Figma 2276:4055 (iPhone Air, 420×6491).
   Вся геометрия считается от макетной ширины 420: --k — цена одной макетной
   единицы в пикселях, поэтому страница масштабируется целиком и остаётся
   пропорциональной на любой ширине экрана. Размеры пишем как calc(N * var(--k)),
   где N — значение прямо из макета. */

/* ---------- шрифты ---------- */
/* Фирменные VK Sans лежат локально (assets/fonts/vk-sans → public/fonts):
   внешние CDN из РФ нестабильны, а без своего шрифта макет разъезжается. */
@font-face {
  font-family: 'VK Sans Display';
  src: url('fonts/vk-sans-display-regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'VK Sans Display';
  src: url('fonts/vk-sans-display-medium.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'VK Sans Display';
  src: url('fonts/vk-sans-display-demibold.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'VK Sans Display';
  src: url('fonts/vk-sans-display-bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'VK Sans Display Condensed';
  src: url('fonts/vk-sans-display-condensed-bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'VK Sans Display Condensed';
  src: url('fonts/vk-sans-display-condensed-extrabold.woff2') format('woff2');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'VK Sans Display Condensed';
  src: url('fonts/vk-sans-display-condensed-black-italic.woff2') format('woff2');
  font-weight: 900;
  font-style: italic;
  font-display: swap;
}

/* ---------- переменные ---------- */

:root {
  --design-w: 420;
  --page-max: 520px;

  --blue: #0077ff;
  --blue-deep: #2e8cf8;
  --ice: #e6f3ff;       /* светлый текст на синем */
  --ice-dim: #e9f3fc;   /* текст внутри карточки сезона */
  --snow: #ebf4f9;      /* подложка светлых секций */
  --cyan: #7cedf8;
  --ink: #000;
  --muted: #818c99;

  --font-ui: 'VK Sans Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-display: 'VK Sans Display Condensed', 'VK Sans Display', sans-serif;
}

* { box-sizing: border-box; }

html {
  background: #d7e6f4;
  scroll-padding-top: calc(56px + env(safe-area-inset-top, 0px)); /* якоря не уходят под шапку */
}

/* Ширину считаем от body, а не от 100vw: vw не учитывает полосу прокрутки,
   и на десктопе колонка вылезала за экран на её ширину. */
body {
  margin: 0;
  container-type: inline-size;
  background: #fff;
  color: var(--ink);
  font-family: var(--font-ui);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Без overflow-x: при containment (container-type) body перестаёт отдавать
     overflow вьюпорту и сам становится scroll-контейнером — тогда липкая сцена
     сезонов прилипает к нему, а не к экрану. Лишнее по горизонтали режет .page. */
}

/* Макет мобильный: на широком экране держим его колонкой по центру. */
.page {
  --page-w: min(100cqw, var(--page-max));
  --k: calc(var(--page-w) / var(--design-w));
  /* Радиус больших скруглений (секции, сезоны, уголки шапки) —
     одно число в макетных единицах. */
  --r-xl: 56;
  --radius-xl: calc(var(--r-xl) * var(--k));

  position: relative;
  width: var(--page-w);
  margin-inline: auto;
  background: #fff;
  /* clip, а не hidden: hidden делает колонку scroll-контейнером, и липкая
     сцена сезонов перестаёт прилипать к экрану. */
  overflow: clip;
}

img { display: block; max-width: 100%; }

h1, h2, h3, h4, p, ol, ul { margin: 0; padding: 0; }

/* Картинка направления в карточке сезона — только для широкого экрана
   (landing-desktop.css): на телефоне карточка и так во весь экран. */
.season__art { display: none; }
/* Элементы только для широкого экрана (landing-desktop.css). */
.d-only { display: none !important; }
ol, ul { list-style: none; }

/* Крупные акцидентные заголовки макета — один стиль на всю страницу. */
.display {
  font-family: var(--font-display);
  font-weight: 900;
  font-style: italic;
  text-transform: uppercase;
  line-height: 1.02;
}

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

/* Шапка закреплена на всю страницу: sticky внутри колонки (ширина и центровка
   — её) и отрицательный отступ снизу — лежит поверх контента и ничего не сдвигает. Сверху — запас под «чёлку».

   Фон есть всегда, с первого экрана. Снизу — «перевёрнутые» уголки: контент под шапкой выглядит
   карточкой со скруглёнными верхними углами. */
.page {
  /* 60, а не 52 из макета: воздух вокруг логотипа (правки заказчика 2026-10-28). */
  --header-h: calc(60 * var(--k) + env(safe-area-inset-top, 0px));
  /* уголок той же iOS-формы и радиуса, что у секций (--r-xl, сглаживание 100%):
     заходит на 2r вдоль стороны — контент под шапкой выглядит такой же карточкой */
  --header-ear: calc(var(--r-xl) * 2 * var(--k));
}

.topbar {
  position: sticky;
  z-index: 50;
  top: 0;
  height: var(--header-h);
  margin-bottom: calc(-1 * var(--header-h));
  padding: env(safe-area-inset-top, 0px) calc(20 * var(--k)) 0 calc(24 * var(--k));
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Шапка всегда на плашке (комментарий заказчика 2026-10-27: «шапка должна
     быть визуально выделена»): и на первом экране, поверх анимации, тоже. */
  background-color: var(--snow);
  transition: background-color 0.25s ease;
}

/* «Ушки» — квадрат минус угловая плитка той же iOS-формы, что у остальных
   скруглений: цвет шапки снаружи скругления. */
.topbar::before,
.topbar::after {
  content: '';
  position: absolute;
  top: 100%;
  width: var(--header-ear);
  height: var(--header-ear);
  background: var(--snow);
  pointer-events: none;
}
/* Маска — готовое «ушко» (квадрат минус плитка в одном векторе, scripts/build-squircle-masks.mjs):
   вычитание через mask-composite оставляло волосяную рамку по внутренним краям квадрата. */
.topbar::before {
  left: 0;
  -webkit-mask: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 200 200%22 preserveAspectRatio=%22none%22%3E%3Cpath fill-rule=%22evenodd%22 d=%22M0 0H200V200H0ZM0 0c94.2809 0 141.4214 0 170.7107 29.2893a100 100 0 0 1 0 0c29.2893 29.2893 29.2893 76.4298 29.2893 170.7107L0 200Z%22 transform=%22translate(200 0) scale(-1 1)%22/%3E%3C/svg%3E') 0 0 / 100% 100% no-repeat;
          mask: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 200 200%22 preserveAspectRatio=%22none%22%3E%3Cpath fill-rule=%22evenodd%22 d=%22M0 0H200V200H0ZM0 0c94.2809 0 141.4214 0 170.7107 29.2893a100 100 0 0 1 0 0c29.2893 29.2893 29.2893 76.4298 29.2893 170.7107L0 200Z%22 transform=%22translate(200 0) scale(-1 1)%22/%3E%3C/svg%3E') 0 0 / 100% 100% no-repeat;
}
.topbar::after {
  right: 0;
  -webkit-mask: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 200 200%22 preserveAspectRatio=%22none%22%3E%3Cpath fill-rule=%22evenodd%22 d=%22M0 0H200V200H0ZM0 0c94.2809 0 141.4214 0 170.7107 29.2893a100 100 0 0 1 0 0c29.2893 29.2893 29.2893 76.4298 29.2893 170.7107L0 200Z%22/%3E%3C/svg%3E') 0 0 / 100% 100% no-repeat;
          mask: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 200 200%22 preserveAspectRatio=%22none%22%3E%3Cpath fill-rule=%22evenodd%22 d=%22M0 0H200V200H0ZM0 0c94.2809 0 141.4214 0 170.7107 29.2893a100 100 0 0 1 0 0c29.2893 29.2893 29.2893 76.4298 29.2893 170.7107L0 200Z%22/%3E%3C/svg%3E') 0 0 / 100% 100% no-repeat;
}

.topbar__logo img { width: calc(136 * var(--k)); height: auto; }

/* Вместо меню — кнопка «Начать учиться» (правки заказчика 2026-10-28: «меню скроем,
   так лучше с точки зрения конверсии в регистрацию»). Стиль — как у остальных кнопок. */
.topbar__menu,
.topnav { display: none; }
.topbar__cta {
  display: flex;
  align-items: center;
  height: calc(38 * var(--k));
  padding: calc(1 * var(--k)) calc(18 * var(--k)) 0;
  border-radius: 100px;
  background: var(--blue);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 900;
  font-style: italic;
  font-size: calc(18 * var(--k));
  line-height: 1;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}
.topbar__cta:active { background: #0066dd; }

/* Обёртки заголовка карты вузов и маршрута нужны только десктопной раскладке;
   на телефоне их как будто нет. */
.campus__head,
.outcome__art { display: contents; }

.topbar__menu {
  appearance: none;
  border: 0;
  padding: 0;
  background: none;
  cursor: pointer;
  line-height: 0;
}
.topbar__menu img { width: calc(28 * var(--k)); height: calc(28 * var(--k)); }

/* Меню — один и тот же список на всех ширинах. На телефоне оно свёрнуто за
   кнопкой и выезжает панелью из-под шапки (класс is-menu вешает landing.js),
   на широком экране стоит строкой в шапке (landing-desktop.css). */
.topnav {
  position: absolute;
  z-index: 1;
  top: calc(var(--header-h) - 6 * var(--k));
  right: calc(17 * var(--k));
  display: grid;
  gap: calc(14 * var(--k));
  padding: calc(18 * var(--k)) calc(26 * var(--k));
  border-radius: calc(20 * var(--k));
  background: var(--snow);
  box-shadow: 0 calc(16 * var(--k)) calc(36 * var(--k)) rgb(8 36 86 / 0.16);
  text-align: right;
  opacity: 0;
  translate: 0 calc(-10 * var(--k));
  visibility: hidden;
  transition: opacity 0.2s ease, translate 0.2s ease, visibility 0.2s;
}
.topnav a {
  font-weight: 500;
  font-size: calc(19 * var(--k));
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
}
.is-menu .topnav {
  opacity: 1;
  translate: 0 0;
  visibility: visible;
}

/* ---------- герой ---------- */

/* ---------- первый экран ----------
   Экран липкий и равен окну браузера. Сначала прокрутка отматывает анимацию
   (кадры на canvas, landing.js) — экран стоит; потом на него наезжает сериал.

   Три размера:
   --screen-h — окно при свёрнутых панелях Safari (lvh): экран всегда закрывает окно;
   --safe-h   — часть, видимая всегда, даже с развёрнутыми панелями (svh):
                к её низу прижаты заголовок и подзаголовок;
   --scrub-h  — путь прокрутки, за который проигрывается анимация.
   Где lvh/svh не поддерживаются — обычный vh, разницы панелей там нет. */
.page {
  --screen-h: 100vh;
  --safe-h: 100vh;
  --scrub-h: 140vh;
  /* пауза перед наездом сериала (сейчас без паузы, см. .series) */
  --hold: 0px;
}
@supports (height: 100lvh) {
  .page {
    --screen-h: 100lvh;
    --safe-h: 100svh;
    --scrub-h: 140svh;
  }
}
/* Страница сверки (?static): размеры макета, без хода прокрутки. */
.static-layout .page {
  --screen-h: calc(855 * var(--k));
  --safe-h: calc(855 * var(--k));
  --scrub-h: 0px;
  --hold: 0px;
}

/* Высота героя: экран + путь анимации + ещё экран, пока на видео наезжает сериал. */
.hero {
  position: relative;
  height: calc(var(--screen-h) * 2 + var(--scrub-h) + var(--hold));
  background: #2c8eff;
}

.hero__screen {
  position: sticky;
  z-index: 0;
  top: 0;
  height: var(--screen-h);
  overflow: hidden;
  background: #2c8eff;
}

/* Кадр прижат к верху: на низких экранах срезается низ (он под текстом и
   синим градиентом), бейджи и шарик остаются в кадре. */
.hero__poster,
.hero__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}
.hero__canvas { opacity: 0; transition: opacity 0.2s ease; }
.hero__canvas.is-ready { opacity: 1; }

.hero__scrub { height: var(--scrub-h); }

/* Слой заголовка: липкий, как экран с видео, но только на путь анимации —
   дорожка длиной «экран + путь анимации». Анимация доиграла — дорожка кончилась,
   заголовок с градиентом уезжает вверх, а следом сразу наезжает сериал
   (он начинается ровно там, где кончается дорожка). Видео стоит дальше. */
.hero__front {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  right: 0;
  height: calc(var(--screen-h) + var(--scrub-h));
  pointer-events: none;
}
.hero__front-screen {
  position: sticky;
  top: 0;
  height: var(--screen-h);
}
.hero__front .hero__copy { pointer-events: auto; }

/* Под текстом кадр растворяется в синем — привязано к низу видимой части окна. */
.hero__veil {
  position: absolute;
  left: 0;
  right: 0;
  /* Короткая растяжка (300): длинная (460) закрывала шарик и плашку AI в финальном кадре. */
  top: calc(var(--safe-h) - 300 * var(--k));
  /* Ниже экрана синева ещё 160 и растворяется: этот хвост лежит под верхом
     сериала (он идёт сразу за заголовком), поэтому между синевой и сериалом нет
     резкой границы с видео. */
  bottom: calc(-160 * var(--k));
  background: linear-gradient(180deg,
    rgba(44, 142, 255, 0) 0,
    rgba(44, 142, 255, 0.86) calc(190 * var(--k)),
    #2c8eff calc(300 * var(--k)),
    #2c8eff calc(100% - 160 * var(--k)),
    rgba(44, 142, 255, 0) 100%);
}

/* Заголовок и подзаголовок прижаты к низу видимой части: снизу — зазор из
   макета (26), полоска «домой» на iPhone и разница между окном с развёрнутыми
   и свёрнутыми панелями Safari. Так текст виден при любой высоте экрана. */
.hero__copy {
  position: absolute;
  z-index: 1;
  left: calc(18 * var(--k));
  right: calc(18 * var(--k));
  bottom: calc(var(--screen-h) - var(--safe-h) + 26 * var(--k) + env(safe-area-inset-bottom, 0px));
}

.hero__title {
  /* Оба слова одним кеглем (правки заказчика 2026-10-28) — самым крупным, при котором
     «возможностей» встаёт в ширину колонки. */
  font-size: calc(54 * var(--k));
  line-height: 0.88; /* комментарий заказчика: интерлиньяж сильно меньше */
  letter-spacing: -0.01em;
  color: #fff;
}
.hero__title i {
  display: block;
  font-style: inherit;
}

.hero__lead {
  margin-top: calc(10 * var(--k));
  margin-left: calc(4 * var(--k));
  font-size: calc(18 * var(--k));
  line-height: calc(20 * var(--k));
  color: #fff; /* комментарий заказчика: текст белый */
}
.hero__lead b { font-weight: 400; color: #fff; }

/* ---------- сериал ---------- */

/* Сериал и сезоны в одной обёртке: внутри неё сериал липкий (см. index.html). */
.series-stack {
  position: relative;
  z-index: 2; /* выше заголовка первого экрана */
  /* Страховка: всё, что вылезло за обёртку, срезаем — иначе липкий сериал,
     остановившись у её нижней границы, может достать до блока «на выходе ты
     получишь». Именно clip, а не hidden: hidden сделал бы обёртку
     scroll-контейнером, и липкость сериала и сцены сезонов сломалась бы
     (как в .page). */
  overflow: clip;
  /* Сериал начинается сразу за путём анимации: заголовок с синим градиентом
     уезжает вверх, а сериал следом наезжает на стоящее видео своими скруглёнными
     углами (хвост градиента ложится под его верх). Герой кончается ещё через экран. */
  margin-top: calc(-1 * var(--screen-h) - var(--hold));
}

/* Долистав обёртку, сериал останавливается у её низа и стоит там до конца —
   ровно за нижним краем сезонов. Сезоны закрывают его своей заливкой, но их
   нижние углы скруглены, и в вырезах углов проступал синий. Подкладываем под
   сезоны фон страницы: он выше сериала и ниже сезонов, поэтому виден только
   в этих вырезах. Высота — глубина скругления (угловая плитка squircle — 2r). */
.series-stack::after {
  content: '';
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  bottom: 0;
  height: calc(2 * var(--radius-xl) + 2px);
  background: #fff;
}

/* Доехав до шапки, сериал занимает весь экран под ней и стоит. Высота — по
   окну при свёрнутых панелях Safari (lvh): экран закрыт всегда; текст прижат
   к низу всегда видимой части, как на первом экране. */
.series {
  /* Нижние углы не скругляем, а сам блок уходит за низ окна с запасом: в iOS 26
     панель Safari плавающая, и под ней тоже должно быть видео, а не край блока
     со скруглением. Текст поднят на этот запас (.series__copy). */
  --series-overscan: 160px;

  position: sticky;
  top: var(--header-h);
  height: calc(var(--screen-h) - var(--header-h) + var(--series-overscan));
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  background: #0a4fc4;
  /* Без overflow и без маски: скругление — у самих слоёв (border-radius: inherit
     в .series__media). Маска или обрезка на предке играющего видео заставляли
     Safari пересчитывать её на каждом кадре ролика — видео тормозило. */
}

/* Здесь была пауза перед наездом сезонов: сериал прилипал на --hold выше нужного
   места, а обратно вниз его возвращала анимация по прокрутке (view timeline).
   Конструкция оказалась хрупкой: правильное положение зависело от того,
   отработала ли анимация. Там, где она не срабатывала, сериал так и оставался
   на --hold выше — его верхний край с кнопками звука и полного экрана уходил
   за край окна, и выглядело это как «иконки пропали при прокрутке».
   Поэтому паузы больше нет: --hold остаётся 0, сериал просто прилипает под
   шапку (см. .series выше), и его верх всегда на виду. */

/* Видео 16:9 в вертикальном кадре. Сверху — само видео, обрезанное по высоте
   (cover) на 515 из макета; ниже — размытый кадр ролика (готовая картинка
   series-blur.webp), поэтому кадр заполнен без пустых полей.
   Для Safari важно: на видео и его предках нет ни маски, ни фильтра, ни
   backdrop-filter — иначе каждый кадр ролика проходит через них заново. Переход
   от видео к размытию делает картинка, лежащая поверх видео: маска стоит у неё,
   а она статична — Safari считает её один раз. */
.series__media {
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.series__video {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: calc(515 * var(--k));
  object-fit: cover;
  border-radius: inherit;
  background: #0a4fc4;
}
/* Тизер на весь экран: в блоке не виден; в полноэкранном режиме — целиком, на чёрном
   (на iPhone его показывает системный плеер, CSS там не действует). */
.series__teaser {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.series__teaser:fullscreen { width: 100%; height: 100%; opacity: 1; object-fit: contain; background: #000; }
.series__teaser:-webkit-full-screen { width: 100%; height: 100%; opacity: 1; object-fit: contain; background: #000; }
.series__blur {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
  /* видно только ниже видео; вверх растворяется в нём на 150 */
  -webkit-mask: linear-gradient(180deg, transparent calc(365 * var(--k)), #000 calc(515 * var(--k)));
          mask: linear-gradient(180deg, transparent calc(365 * var(--k)), #000 calc(515 * var(--k)));
  pointer-events: none;
}
/* Затемнение снизу и синий градиент под текстом — как в макете. */
.series__shade {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(0, 119, 255, 0) 0, rgba(0, 119, 255, 0) calc(347 * var(--k)), rgba(0, 119, 255, 0.79) 100%),
    linear-gradient(0deg, rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.2) 37%, rgba(0, 0, 0, 0) 100%);
  pointer-events: none;
}

.series__ico {
  appearance: none;
  position: absolute;
  z-index: 1;
  padding: calc(8 * var(--k));
  margin: calc(-8 * var(--k));
  border: 0;
  background: none;
  cursor: pointer;
  line-height: 0;
}
.series__ico img { width: calc(28 * var(--k)); height: calc(28 * var(--k)); }
.series__ico--sound { left: calc(29 * var(--k)); top: calc(28 * var(--k)); }
.series__ico--sound[aria-pressed="false"] img { opacity: 0.75; }
.series__ico--expand { left: calc(362 * var(--k)); top: calc(23 * var(--k)); }

.series__copy {
  position: absolute;
  left: calc(23 * var(--k));
  width: calc(373 * var(--k));
  bottom: calc(var(--series-overscan) + var(--screen-h) - var(--safe-h) + 40 * var(--k) + env(safe-area-inset-bottom, 0px));
}

.series__title {
  font-size: calc(45.91 * var(--k));
  color: #fff;
}
/* Плашка над заголовком: «в формате сериала». Как на десктопе (правки заказчика
   2026-10-30): плоский яркий стикер маджентой бейджа DEV, ровно, без стекла, тени и наклона. */
.series__tag {
  display: inline-block;
  margin-bottom: calc(14 * var(--k));
  padding: calc(10 * var(--k)) calc(20 * var(--k)) calc(9 * var(--k));
  border-radius: 100px;
  background: #f8309c;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: calc(19 * var(--k));
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #fff;
}

.series__text {
  margin: calc(11 * var(--k)) 0 0 calc(2 * var(--k));
  width: calc(366 * var(--k));
  font-size: calc(18 * var(--k));
  line-height: calc(20 * var(--k));
  color: #fff;
}

/* ---------- сезоны ---------- */

.seasons {
  --season-step: 55svh;                      /* сколько листать на один сезон */
  --season-ease: cubic-bezier(0.4, 0, 0.2, 1);
  --season-time: 0.45s;

  position: relative;
  z-index: 3; /* выше сериала */
  /* Пауза: сериал во весь экран стоит, пока листаем этот отступ, потом сезоны
     наезжают на него снизу. */
  margin-top: calc(45svh + var(--hold));
  border-radius: var(--radius-xl);
  background: var(--snow);
}
/* Ход прокрутки добавляем только при работающем скрипте: без JS секция
   остаётся обычной и не заставляет листать пустое место. Именно распоркой,
   а не padding-bottom: липкий элемент ездит только внутри content-box
   родителя, в padding он не заходит. */
/* По шагу на каждый сезон, включая последний: «Продукт» тоже успевает постоять. */
.seasons.is-scrolly::after {
  content: '';
  display: block;
  height: calc(3 * var(--season-step));
}

/* Липкая сцена — всегда под шапкой, за шапку не заходит. Размеры текста
   подобраны так, чтобы сцена помещалась в экран телефона. */
.seasons__stage {
  padding-top: calc(32 * var(--k));
}
.seasons.is-scrolly .seasons__stage {
  position: sticky;
  top: var(--header-h);
}

.seasons__title {
  font-size: calc(45.91 * var(--k)); /* как заголовок сериала */
  text-align: center;
  color: var(--ink);
}
.seasons__title i { font-style: italic; color: var(--blue); }

.seasons__list { margin-top: calc(16 * var(--k)); }

/* Переключение анимируется так, что сумма высот постоянна: одна панель
   растёт ровно с той же скоростью, с какой сворачивается другая (одинаковые
   длительность и кривая). */
.season {
  border-radius: var(--radius-xl);
  background-color: #fff;
  transition: background-color var(--season-time) var(--season-ease);
}
.season.is-open { background-color: var(--blue); }

.season__head {
  appearance: none;
  position: relative;
  display: block;
  width: 100%;
  border: 0;
  cursor: pointer;
  /* Отступы свёрнутой и раскрытой шапки (раскрытая чуть ниже, текст ближе к
     панели); при прокрутке плавно перетекают по --o. */
  padding: calc(15 * var(--k)) 0 calc(14 * var(--k));
  border-radius: var(--radius-xl);
  background: none;
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 900;
  font-style: italic;
  text-transform: uppercase;
  font-size: calc(45.91 * var(--k)); /* как заголовок сериала */
  line-height: 1.02;
  text-align: center;
  /* padding не анимируем: он в единицах --k, а --k считается от container
     query и в первый кадр меняется — шапки «доезжали» бы при загрузке. Отступы
     89↔93 переключаются сразу у обеих шапок, сумма высот остаётся прежней. */
  transition: color var(--season-time) var(--season-ease);
}
.season__head span { position: relative; }
.season.is-open .season__head {
  color: var(--ice);
  padding: calc(16 * var(--k)) 0 calc(9 * var(--k));
}
/* Шапка сразу под раскрытой карточкой перетекает из синего в белый.
   Градиент не анимируется, поэтому он на отдельном слое с opacity. */
.season__head::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(180deg, #aad2ff 0%, #fff 92%);
  opacity: 0;
  transition: opacity var(--season-time) var(--season-ease);
  pointer-events: none;
}
.season.is-open + .season .season__head::before { opacity: 1; }

/* Шапка и панель раскрытого сезона — один блок: сверху (под названием) ровный
   фирменный синий, ниже по панели плавно светлеет. Своих верхних скруглений у
   панели нет — форму всему сезону задаёт маска карточки. */
.season__panel {
  display: grid;
  grid-template-rows: 0fr;
  border-radius: 0 0 var(--radius-xl) var(--radius-xl);
  background: linear-gradient(180deg, var(--blue) 0%, #6bb0fc 100%);
  transition: grid-template-rows var(--season-time) var(--season-ease);
}
.season.is-open .season__panel { grid-template-rows: 1fr; }

.season__inner {
  min-height: 0;
  overflow: hidden;
}

.steps {
  padding: calc(26 * var(--k)) calc(24 * var(--k)) calc(28 * var(--k)) calc(26 * var(--k));
  opacity: 0;
  transition: opacity var(--season-time) var(--season-ease);
}
.season.is-open .steps { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .seasons { --season-time: 0s; }
}

/* Раскрытие по прокрутке (landing.js): у каждого сезона --o — насколько он
   раскрыт (0…1), у следующего за ним --prev-o. Высоту панели скрипт пишет
   в пикселях (доля от высоты содержимого), всё остальное — от --o.
   Анимаций по времени нет: движение даёт сама прокрутка, и в любой момент
   сцена ровно там, куда долистал пользователь. */
.seasons.is-scrolly .season {
  --o: 0;
  transition: none;
  background-color: color-mix(in srgb, var(--blue) calc(var(--o) * 100%), #fff);
}
/* Цвет надписи не смешиваем (посередине вышел бы серый): он переключается
   с короткой анимацией, когда фон уже достаточно синий (.is-lit, от 70%). */
.seasons.is-scrolly .season__head {
  color: var(--ink);
  transition: color 0.2s ease;
  padding: calc((15 + 1 * var(--o)) * var(--k)) 0 calc((14 - 5 * var(--o)) * var(--k));
}
.seasons.is-scrolly .season.is-lit .season__head { color: var(--ice); }
.seasons.is-scrolly .season__head::before {
  transition: none;
  /* гаснет, пока сезон сам раскрывается: под названием ровный синий */
  opacity: calc(var(--prev-o, 0) * (1 - var(--o)));
}
/* Высоту панели в пикселях пишет скрипт (доля от высоты содержимого). */
.seasons.is-scrolly .season__panel {
  /* градиент проявляется вместе с фоном сезона — без шва на стыке с шапкой */
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--blue) calc(var(--o) * 100%), #fff) 0%,
    color-mix(in srgb, #6bb0fc calc(var(--o) * 100%), #fff) 100%);
  display: block;
  overflow: hidden;
  transition: none;
}
.seasons.is-scrolly .steps {
  transition: none;
  opacity: calc(var(--o) * 2 - 0.5); /* текст выезжает вместе с панелью и проявляется к концу */
}

.step { padding-block: calc(18 * var(--k)); }
.step:first-child { padding-top: 0; }
.step:last-child { padding-bottom: 0; }
.step + .step { border-top: 1px solid rgba(255, 255, 255, 0.4); }

.step__num {
  float: left;
  width: calc(30 * var(--k));
  height: calc(30 * var(--k));
  margin-right: calc(11 * var(--k));
  border: calc(2.14 * var(--k)) solid #fff;
  border-radius: 50%;
  /* Без backdrop-filter: карточки сезонов едут поверх играющего видео сериала,
     и размытие фона у девяти кружков Safari пересчитывал на каждом кадре. */
  /* Цифра той же толщины, что обводка (правки 2026-10-28: «цифра тонкая»). */
  color: #fff;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: calc(17 * var(--k));
  line-height: calc(25.7 * var(--k));
  text-align: center;
}

.step__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(24.54 * var(--k));
  line-height: calc(30 * var(--k));
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: #fff; /* белый на синем, а не голубой (правки 2026-10-28) */
}

/* Текст крупнее (правки 2026-10-28: «очень-очень мелкий»): 18 вместо 16.68. Если сцена
   с ним не влезает под шапку, landing.js уменьшает её целиком (fit). */
.step__text {
  clear: both;
  padding-top: calc(10 * var(--k));
  font-size: calc(18 * var(--k));
  line-height: calc(21 * var(--k));
  color: #fff;
}

/* ---------- что получится на выходе ---------- */

.outcome {
  /* position — ниже, в разделе про наезд секций: блок липкий. */
  padding-top: calc(38 * var(--k));
}

.outcome__text {
  width: calc(359 * var(--k));
  margin-inline: auto;
  font-weight: 500;
  font-size: calc(18 * var(--k));
  line-height: 1.2;
  text-align: center;
}
.outcome__text b { font-weight: 500; color: var(--blue); }

/* Маршрут между направлениями: цельная стеклянная стенка одним SVG, лежит под бейджами. */
.route {
  position: relative;
  height: calc(212 * var(--k));
  margin-top: calc(19 * var(--k));
}


.route__dot {
  position: absolute;
  width: calc(95 * var(--k));
  height: calc(95 * var(--k));
}

.route__dot img {
  position: relative;
  width: 100%;
  height: 100%;
}

.route__dot--ai { left: calc(19 * var(--k)); top: 0; }
.route__dot--dev { left: calc(159 * var(--k)); top: calc(101 * var(--k)); }
.route__dot--product { left: calc(289 * var(--k)); top: 0; }

/* ---------- цельный маршрут: стеклянная стенка ---------- */
/* Маршрут «На выходе» и на карте вузов — один SVG-путь (grooveSvg в
   scripts/lib/planks.mjs): цельная стеклянная стенка, как лабиринт первого экрана, VK Blue.
   Путь с pathLength=1, поэтому прочерчивание — это stroke-dashoffset от --mp
   (0…1, пишет landing.js). Без скрипта --mp не задан — путь целиком. */
.groove {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.groove__reveal {
  stroke-dasharray: 1 2;
  stroke-dashoffset: calc(1 - var(--mp, 1));
}
/* «На выходе»: ещё не пройденный участок — бледно-голубой (то же стекло, полупрозрачное),
   пройденный — синий. Без grayscale: Safari фильтр на SVG-группе не применял, и линия там
   и так была голубой, а в Chrome — серой; теперь одинаково. */
.groove__base { opacity: 0.4; }

/* ---------- маршрут по прокрутке ---------- */
/* Класс вешает landing.js — без скрипта, при prefers-reduced-motion и на
   странице сверки маршрут сразу цветной и целый.
   Пока прокрутка до участка не дошла, он бледно-голубой: и линия, и бейджи. Доля
   маршрута до каждого из них посчитана генератором (--t), общий прогресс
   лежит в --mp, так что краска идёт слева направо и бейдж оживает ровно
   тогда, когда до него доходит цветная дощечка. */
/* Неактивный бейдж — бледный сине-сиреневый, в тон непройденной линии (просьба заказчика
   2026-10-27, было серым). Голубая копия — готовая картинка badge-<id>-idle.webp
   (scripts/build-badge-idle.mjs): все три в оттенке AI и с его яркостью. CSS-фильтром
   красить нельзя — его итог зависит от яркости картинки, и светлые DEV и PRODUCT уходили
   в бирюзу. Копия лежит под бейджем (::before), цветной проявляется поверх: анимируется
   только прозрачность. */
.route.is-scrolly .route__dot {
  --o: clamp(0, (var(--mp, 1) - var(--t) + 0.09) / 0.09, 1);
}
.route.is-scrolly .route__dot::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--badge-idle) center / contain no-repeat;
  /* гаснет быстрее, чем проявляется цветной: на переходе цвета не смешиваются */
  opacity: calc(0.5 * (1 - var(--o)) * (1 - var(--o)));
}
.route.is-scrolly .route__dot img { opacity: var(--o); }
.route__dot--ai { --badge-idle: url(img/v2/badge-ai-idle.webp); }
.route__dot--dev { --badge-idle: url(img/v2/badge-dev-idle.webp); }
.route__dot--product { --badge-idle: url(img/v2/badge-product-idle.webp); }

/* Все кнопки — в одной стилистике с белой кнопкой-карточкой «Начать учиться»
   и кнопкой в шапке: акцидентный шрифт капсом (правки 2026-10-28: «текст в кнопке
   выглядит меньше обычного текста, кнопки привести к одной стилистике и сделать крупнее»). */
.btn {
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(62 * var(--k));
  padding: calc(2 * var(--k)) calc(12 * var(--k)) 0;
  border: 0;
  border-radius: 100px;
  background: var(--blue);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 900;
  font-style: italic;
  font-size: calc(23 * var(--k));
  line-height: 1;
  text-transform: uppercase;
  text-align: center;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
}
.btn:active { background: #0066dd; }

.outcome .btn {
  position: relative; /* кнопка перекрывает хвост линии маршрута */
  margin: 0 calc(24 * var(--k));
}

/* ---------- наезд секций в хвосте страницы ---------- */
/* Та же лесенка, что у сериала и сезонов: блок доезжает до места, замирает, и
   следующая секция наезжает на него снизу своими скруглёнными углами.
   Карта вузов выше экрана, поэтому прилипает низом (bottom): пока она
   длиннее окна, листается как обычно, а дойдя низом до края — встаёт, и её
   накрывает midsprint.
   «На выходе» больше не прилипает и карта на него не наезжает (правки заказчика
   2026-10-28: «наслаивающиеся формы блоков дёргаются — сделать плавнее или
   отказаться от части анимации»): он листается обычным потоком, маршрут красится,
   пока блок проезжает экран. Заодно ушёл артефакт — синяя кнопка прилипшего блока
   проглядывала в скруглённых углах midsprint. */
.outcome-stack,
.campus-stack { position: relative; }

.outcome { position: relative; }

/* Страница сверки (?static) — раскладка как в Figma, без ходов прокрутки. */
.static-layout .outcome,
.static-layout .campus { position: static; }
.static-layout .campus { margin-top: calc(42 * var(--k)); }

.campus {
  position: sticky;
  bottom: 0;
  margin-top: calc(42 * var(--k));
  /* Снизу запас: на него наезжает белая карточка midsprint. */
  padding: calc(41 * var(--k)) 0 calc(368 * var(--k));
  border-radius: var(--radius-xl);
  background: var(--snow);
  /* clip, а не hidden: hidden делает блок scroll-контейнером, и липкое окно
     карты прилипало бы к нему, а не к экрану. */
  overflow: clip;
}

/* По прокрутке (.is-scrolly — landing.js). Карта вузов не листается целиком,
   а встаёт в окно на весь экран: трек = окно + ход по перегонам + хвост + пауза,
   шарик ведёт прокрутка, карта панорамируется за ним (--pan). Доехав до МГТУ,
   карта ещё немного едет вниз — показывает уходящую дальше линию (--campus-tail),
   и только потом, в паузе, на неё наезжает midsprint. */
.campus.is-scrolly {
  --view-h: calc(100svh - var(--header-h));
  position: relative;
  bottom: auto;
  padding-bottom: 0;
}
.campus.is-scrolly .campus-track {
  height: calc(var(--view-h) + var(--campus-steps, 6) * var(--campus-step) + var(--campus-tail) + var(--campus-hold));
  margin-top: calc(40 * var(--k));
}
.campus.is-scrolly .campus-view {
  position: sticky;
  top: var(--header-h);
  height: var(--view-h);
  overflow: hidden;
}
.campus.is-scrolly .campus-map {
  margin-top: 0;
  transform: translateY(var(--pan, 0px));
  will-change: transform;
}
.campus.is-scrolly + .midsprint { margin-top: calc(-1 * var(--campus-hold)); }

.campus__title {
  margin-left: calc(31 * var(--k));
  font-size: calc(45.91 * var(--k));
  color: var(--blue);
}

.campus__text {
  display: grid;
  gap: calc(13 * var(--k));
  width: calc(363 * var(--k));
  margin: calc(8 * var(--k)) 0 0 calc(31 * var(--k));
  font-size: calc(16 * var(--k));
  line-height: 1.2;
}
.campus__text b { font-weight: 400; color: var(--blue); }

/* ---------- карта вузов ---------- */
/* Станции (здание + карточка) и маршрут собирает scripts/build-campus-map.mjs:
   координаты — в макетных единицах, здесь только переводим их в --k. */
.campus-map {
  position: relative;
  height: calc(var(--map-h) * var(--k));
  margin-top: calc(40 * var(--k));
}

/* Траектория шарика: тот же путь, которым выложены дощечки, но без обводки —
   он нужен только скрипту (getPointAtLength), видимой линии не рисует.
   SVG растянут preserveAspectRatio: none, но масштаб по обеим осям одинаков
   (--k), поэтому единица пути равна макетной единице. */
.campus-map__track {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  fill: none;
  stroke: none;
  pointer-events: none;
}

/* Маршрут — стеклянная стенка обычной картинкой (scripts/build-campus-map.mjs обрезает
   рендер по концу пути). Без SVG-маски «прочерчивания»: маска с размытием на каждом
   кадре прокрутки тормозила в Safari и рисовала светлое пятно с ровным срезом справа
   (assets/references/feedback-2026-10-27/). Лежит под зданиями: у платформ свой z-index. */
.campus-route { position: absolute; inset: 0; }
.campus-route__img {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  max-width: none;
  height: calc(var(--glass-h) * var(--k));
}

/* Шарик из лабиринта катится по маршруту: положение пишет landing.js в
   макетных единицах, взяв точку на пути. Своего z-index нет — ныряет под
   платформы вузов, как линия. */
/* Двигается transform, а не left/top: те пересчитывали раскладку на каждом кадре. */
.campus-map__ball {
  position: absolute;
  left: 0;
  top: 0;
  width: calc(26 * var(--k));
  height: auto;
  margin: calc(-13 * var(--k)) 0 0 calc(-13 * var(--k));
  transform: translate(calc(var(--ball-x, 0) * var(--k)), calc(var(--ball-y, 0) * var(--k)));
  will-change: transform;
  filter: drop-shadow(0 calc(3 * var(--k)) calc(5 * var(--k)) rgba(20, 60, 140, 0.35));
  opacity: 0; /* без скрипта шарика нет: он показывает прогресс прокрутки */
}
.campus-map.is-scrolly .campus-map__ball { opacity: 1; }

.campus-map__list { position: absolute; inset: 0; }

/* Станция — точка отсчёта в начале карты: и здание, и карточка позиционируются
   от неё по координатам из генератора. */
.station { position: absolute; left: 0; top: 0; }

/* ---------- карта по прокрутке ---------- */
/* Класс вешает landing.js — без скрипта, при prefers-reduced-motion и на
   странице сверки карта остаётся обычной: маршрут нарисован целиком, все вузы
   на месте. Движения по времени нет: --mp (прогресс шарика по маршруту) и --o
   (насколько вуз «открыт») пишет прокрутка, поэтому сцена всегда ровно там,
   куда долистал пользователь, и останавливается вместе с пальцем. */
/* Доля маршрута до каждой дощечки и до каждого вуза посчитана генератором
   (--t), прогресс шарика лежит в --mp на карте — так что «насколько эта
   штука уже появилась» CSS считает сам, и скрипту в кадре остаётся записать
   только --mp и координаты шарика. */


/* Вуз всплывает, когда шарик до него доезжает: сначала здание, следом карточка. */
.campus-map.is-scrolly .station {
  --o: clamp(0, (var(--mp, 1) - var(--t) + 0.06) / 0.06, 1);
  --o-bld: clamp(0, var(--o) / 0.6, 1);
  --o-card: clamp(0, (var(--o) - 0.4) / 0.6, 1);
}
.campus-map.is-scrolly .station__img {
  opacity: var(--o-bld);
  transform: translateY(calc((1 - var(--o-bld)) * 26 * var(--k)));
}
.campus-map.is-scrolly .station__card {
  opacity: var(--o-card);
  transform: translateY(calc((1 - var(--o-card)) * 14 * var(--k)));
}

.station__img {
  position: absolute;
  z-index: 1;
  left: calc(var(--bld-x) * var(--k));
  top: calc(var(--bld-y) * var(--k));
  width: calc(var(--bld-w) * var(--k));
  max-width: none;
  height: auto;
}

.station__card {
  --card-bg: #fff;
  --card-ink: var(--ink);
  --card-muted: #55657d;
  --card-accent: var(--blue);

  position: absolute;
  z-index: 2;
  left: calc(var(--card-x) * var(--k));
  top: calc(var(--card-y) * var(--k));
  width: calc(252 * var(--k));
  padding: calc(16 * var(--k)) calc(18 * var(--k)) calc(17 * var(--k));
  border-radius: calc(22 * var(--k));
  background: var(--card-bg);
  box-shadow: 0 calc(8 * var(--k)) calc(24 * var(--k)) rgba(30, 70, 140, 0.08);
}
/* Хвостик карточки — смотрит вниз, на здание. */
.station__card::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: calc(-9 * var(--k));
  width: calc(18 * var(--k));
  height: calc(10 * var(--k));
  margin-left: calc(-9 * var(--k));
  background: var(--card-bg);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
}

/* Ближайшая площадка подсвечена (выбирает landing.js по сегодняшней дате). */
.station.is-next .station__card {
  --card-bg: #2f75f5;
  --card-ink: #fff;
  --card-muted: #fff;
  --card-accent: #fff;
}

.station__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: calc(10 * var(--k));
}
/* Длинное название (МГУ им. М. В. Ломоносова) — своей строкой, дата под ним
   (карточку поднимает scripts/build-campus-map.mjs). */
.station.is-long .station__name { flex-basis: auto; }
.station.is-long .station__date { flex-basis: 100%; }

.station__name {
  padding: calc(3 * var(--k)) calc(12 * var(--k)) calc(4 * var(--k));
  border: calc(2 * var(--k)) solid var(--card-accent);
  border-radius: calc(40 * var(--k));
  color: var(--card-accent);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(17 * var(--k));
  line-height: 1.1;
  text-transform: uppercase;
  white-space: nowrap;
}

.station__date {
  color: var(--card-ink);
  font-family: var(--font-display);
  font-weight: 900;
  font-style: italic;
  font-size: calc(26 * var(--k));
  line-height: 1;
  white-space: nowrap;
}

.station__address {
  margin-top: calc(11 * var(--k));
  color: var(--card-muted);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(14 * var(--k));
  line-height: 1.15;
  text-transform: uppercase;
}

/* ---------- midsprint ---------- */

.midsprint {
  position: relative;
  z-index: 1;
  margin-top: calc(-341 * var(--k)); /* белая карточка накрывает низ карты вузов */
  padding: calc(44 * var(--k)) calc(24 * var(--k)) calc(20 * var(--k));
  border-radius: var(--radius-xl);
  background: #fff;
}

/* Врезка между картой вузов и стажировкой: одна фраза крупнее основного текста,
   отбита линией — пауза перед следующим блоком. */
.pullout {
  margin-bottom: calc(40 * var(--k));
  padding-bottom: calc(32 * var(--k));
  border-bottom: 1px solid rgb(0 119 255 / 0.18);
  font-size: calc(24 * var(--k));
  line-height: 1.22;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.pullout b { font-weight: 400; color: var(--blue); }

.midsprint__title {
  margin-left: calc(-1 * var(--k));
  font-size: calc(45.91 * var(--k));
  color: var(--ink);
}
.midsprint__title i { font-style: italic; color: var(--blue); }

.midsprint__text {
  width: calc(363 * var(--k));
  margin-top: calc(8 * var(--k));
  font-size: calc(16 * var(--k));
  line-height: 1.2;
}

/* Пропуск VK MidSprint со стикерами — та же картинка, что на широком экране
   (scripts/build-midsprint-pass.mjs: светлая карточка уже в ней, низ пропуска выступает
   за карточку). Здесь — во всю ширину колонки, между текстом и шкалой. */
.midsprint__art {
  width: 100%;
  height: auto;
  margin: calc(20 * var(--k)) 0 calc(8 * var(--k));
}

/* Прогресс. --p (0…1) — доля отмеченных пунктов. Регистрируем её как число,
   чтобы браузер умел её анимировать: тогда шарик, заливка и поворот шарика
   считаются из одного значения на каждом кадре и не расходятся. */
@property --p {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}

.progress {
  --ball: calc(28 * var(--k));
  --roll-time: 0.8s;

  display: flex;
  align-items: center;
  gap: calc(6 * var(--k));
  margin-top: calc(17 * var(--k));
  padding-inline: calc(2 * var(--k));
  transition: --p var(--roll-time) cubic-bezier(0.25, 0.8, 0.3, 1);
}

.progress__cap {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: calc(18.55 * var(--k));
  line-height: 1.02;
  text-transform: uppercase;
  transition: color 0.3s ease;
}
/* Дошли до конца — «мидл» загорается фирменным синим. */
.progress.is-done .progress__cap--goal { color: var(--blue); }

/* Трек нарочно не контейнер: --k наследуется формулой, и единицы контейнера
   внутри него считались бы от трека. */
.progress__track {
  position: relative;
  flex: 1;
  height: calc(19 * var(--k));
  border-radius: calc(27 * var(--k));
  background: var(--snow);
}

/* Путь левого края шарика: от 0 до (ширина трека − шарик). Проценты здесь —
   от ширины трека, у абсолютно спозиционированных детей так и считается. */
.progress__fill,
.progress__ball {
  --x: calc(var(--p) * (100% - var(--ball)));
}

/* Заливка заканчивается чуть дальше центра шарика — под ним, без зазора. */
.progress__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--x) + var(--ball) / 2 + 6 * var(--k));
  border-radius: inherit;
  background: var(--blue);
}

/* Тот же шарик, что катится по лабиринту. Поворот = путь / радиус (в радианах):
   полный путь по макету — 218 при радиусе 14, то есть 15.57 рад. Пропорция
   не зависит от ширины экрана, поэтому качение честное на любом размере. */
.progress__ball {
  position: absolute;
  left: var(--x);
  top: 50%;
  width: var(--ball);
  height: var(--ball);
  max-width: none;
  margin-top: calc(var(--ball) / -2);
  transform: rotate(calc(var(--p) * 15.57rad));
}

.perks {
  display: grid;
  gap: calc(12 * var(--k));
  margin-top: calc(34 * var(--k));
}

.perk {
  appearance: none;
  display: flex;
  align-items: center;
  gap: calc(10 * var(--k));
  width: 100%;
  padding: calc(14 * var(--k)) calc(12 * var(--k));  /* строка 56 — как в макете */
  border: 0;
  border-radius: calc(51 * var(--k));
  background: var(--snow);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.3s ease, color 0.3s ease, transform 0.15s ease;
}
.perk:active { transform: scale(0.98); }
.perk:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }

.perk[aria-pressed='true'] {
  background: var(--blue);
  color: #fff;
}

/* Иконки одноцветные: красим маской в currentColor — синие в обычной строке,
   белые в выбранной. */
.perk__ico,
.perk__mark {
  flex: none;
  width: calc(28 * var(--k));
  height: calc(28 * var(--k));
  background-color: currentColor;
  -webkit-mask: var(--icon) center / contain no-repeat;
          mask: var(--icon) center / contain no-repeat;
}
.perk__ico { color: var(--blue); transition: color 0.3s ease; }
.perk[aria-pressed='true'] .perk__ico { color: #fff; }

.perk__mark {
  --icon: url('data:image/svg+xml,%3Csvg width=%2228%22 height=%2228%22 viewBox=%220 0 28 28%22 fill=%22none%22 xmlns=%22http://www.w3.org/2000/svg%22%3E %3Cpath d=%22M14 2C20.627 2 26 7.373 26 14C26 20.627 20.627 26 14 26C7.373 26 2 20.627 2 14C2 7.373 7.373 2 14 2ZM14 4C8.477 4 4 8.477 4 14C4 19.523 8.477 24 14 24C19.523 24 24 19.523 24 14C24 8.477 19.523 4 14 4Z%22 fill=%22%230077FF%22/%3E %3C/svg%3E');
  margin-left: auto;
  color: var(--blue);
  transition: color 0.3s ease;
}
.perk[aria-pressed='true'] .perk__mark {
  --icon: url('data:image/svg+xml,%3Csvg width=%2228%22 height=%2228%22 viewBox=%220 0 28 28%22 fill=%22none%22 xmlns=%22http://www.w3.org/2000/svg%22%3E %3Cpath fill-rule=%22evenodd%22 clip-rule=%22evenodd%22 d=%22M14 26C20.627 26 26 20.627 26 14C26 7.373 20.627 2 14 2C7.373 2 2 7.373 2 14C2 20.627 7.373 26 14 26ZM20.207 11.207C20.3892 11.0184 20.49 10.7658 20.4877 10.5036C20.4854 10.2414 20.3802 9.99059 20.1948 9.80518C20.0094 9.61977 19.7586 9.5146 19.4964 9.51233C19.2342 9.51005 18.9816 9.61084 18.793 9.793L12 16.586L9.207 13.793C9.0184 13.6108 8.7658 13.51 8.5036 13.5123C8.2414 13.5146 7.99059 13.6198 7.80518 13.8052C7.61977 13.9906 7.5146 14.2414 7.51233 14.5036C7.51005 14.7658 7.61084 15.0184 7.793 15.207L11.293 18.707C11.4805 18.8945 11.7348 18.9998 12 18.9998C12.2652 18.9998 12.5195 18.8945 12.707 18.707L20.207 11.207Z%22 fill=%22white%22/%3E %3C/svg%3E');
  color: #fff;
}

.perk__label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(24.54 * var(--k));
  line-height: 1;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

@media (prefers-reduced-motion: reduce) {
  .progress { --roll-time: 0s; }
}

/* Отступ от пунктов: выбранные синие пункты сливались с синей кнопкой (правки 2026-10-28). */
.midsprint .btn { margin-top: calc(36 * var(--k)); }

/* ---------- подвал ---------- */

/* Без overflow и без маски iOS-скругления: картинки внутри покачиваются, а обрезку или маску
   над тем, что движется, Safari пересчитывает на каждом кадре. Обрезать и нечего — картинки
   целиком внутри блока, в скруглённые углы не заходят. */
.promo {
  position: relative;
  margin-top: calc(23 * var(--k));
  /* Снизу запас: на него наезжает светлый блок с вопросами, и без запаса он
     врезался в кнопки «ВКонтакте» и MAX (правки 2026-10-28). */
  padding-bottom: calc(64 * var(--k));
  border-radius: var(--radius-xl);
  background: var(--blue);
}

/* Сверху блока — вместо фото лабиринта 3D-ассеты из маркетингового макета, как на широком
   экране (scripts/build-promo-art.mjs): связка стеклянных бейджей AI, DEV, PRODUCT в той же
   раскладке, что на постере, или хромированный шар со стикерами (html[data-promo="ball"],
   ?promo=ball). Слегка покачиваются — только transform. */
.promo__art {
  position: relative;
  height: calc(345 * var(--k));
}
.promo__art img {
  position: absolute;
  max-width: none;
  height: auto;
}
.promo__badge--ai { left: calc(10 * var(--k)); top: calc(52 * var(--k)); width: calc(182 * var(--k)); }
.promo__badge--dev { left: calc(215 * var(--k)); top: calc(10 * var(--k)); width: calc(187 * var(--k)); }
.promo__badge--product { left: calc(140 * var(--k)); top: calc(145 * var(--k)); width: calc(207 * var(--k)); }
.promo__ball { display: none; left: calc(45 * var(--k)); top: calc(8 * var(--k)); width: calc(330 * var(--k)); }
[data-promo="ball"] .promo__badge { display: none; }
[data-promo="ball"] .promo__ball { display: block; }

@keyframes promo-float {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50% { transform: translateY(calc(-8 * var(--k))) rotate(var(--tilt, 0deg)); }
}
@media (prefers-reduced-motion: no-preference) {
  .promo__art img { animation: promo-float 7s ease-in-out infinite; }
  .is-away .promo__art img { animation-play-state: paused; } /* вдали от окна (landing.js) */
  .promo__badge--ai { --tilt: -2deg; animation-duration: 7.5s; }
  .promo__badge--dev { --tilt: 2deg; animation-duration: 6.4s; animation-delay: -2.1s; }
  .promo__badge--product { --tilt: 1.5deg; animation-duration: 8.2s; animation-delay: -4.6s; }
  .promo__ball { animation-duration: 9s; }
}

.promo__title {
  margin: calc(13 * var(--k)) 0 0 calc(23 * var(--k));
  font-size: calc(45.91 * var(--k));
  color: #fff;
}

.promo__text {
  display: grid;
  gap: calc(14 * var(--k));
  width: calc(370 * var(--k));
  margin: calc(23 * var(--k)) 0 0 calc(23 * var(--k));
  font-size: calc(18 * var(--k));
  line-height: calc(20 * var(--k));
  color: #fff;
}

.cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: calc(93 * var(--k));
  margin: calc(17 * var(--k)) calc(24 * var(--k)) 0 calc(23 * var(--k));
  padding: 0 calc(24 * var(--k)) 0 calc(27 * var(--k));
  border-radius: calc(38 * var(--k));
  background: #fff;
  text-decoration: none;
}

.cta__label {
  font-size: calc(27.33 * var(--k));
  color: var(--ink);
}

.cta__arrow { width: calc(40 * var(--k)); height: calc(40 * var(--k)); }

.socials {
  display: flex;
  gap: calc(12 * var(--k));
  margin: calc(12 * var(--k)) calc(24 * var(--k)) 0 calc(23 * var(--k));
}

/* Плашка-таблетка: полноценный логотип (знак + надпись) слева, стрелка справа — как в
   референсе заказчика (правки 2026-10-29). Ширина — по логотипу, «вконтакте» длиннее. */
.social {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  justify-content: space-between;
  gap: calc(10 * var(--k));
  height: calc(62 * var(--k));
  padding: 0 calc(16 * var(--k)) 0 calc(18 * var(--k));
  border-radius: 100px;
  background: rgba(255, 255, 255, 0.14);
  text-decoration: none;
}
.social__logo { width: auto; height: calc(21 * var(--k)); }
.social__arrow {
  flex: none;
  width: calc(24 * var(--k));
  height: calc(24 * var(--k));
}

/* ---------- ход прокрутки анимаций ---------- */
/* Все анимации по прокрутке устроены как первый экран: блок прилипает, и
   прокрутка проигрывает анимацию за свой ход. Ходы — здесь, в одном месте,
   чтобы темп по всему лендингу был одинаковым (герой — --scrub-h, сезоны —
   --season-step). Классы .is-scrolly ставит landing.js: без скрипта, при
   prefers-reduced-motion и на странице сверки (?static) ходов нет. */
.page {
  --campus-step: 55svh;   /* карта вузов: на перегон между соседними вузами, как на сезон */
  --campus-tail: 40svh;   /* шарик у МГТУ, карта доезжает вниз до конца линии — midsprint ещё не виден */
  --campus-hold: 60svh;   /* карта стоит собранной, пока на неё наезжает midsprint */
  --logo-scrub: 140svh;   /* логотип из шариков — как первый экран */
}

/* ---------- логотип из шариков ---------- */
/* Фон — у всего блока: тот же #DFEBFB, на котором отрендерен ролик
   (scripts/lib/vk-layout.mjs), поэтому квадратный кадр сливается с секцией и
   шарики летают по ней целиком, без видимой рамки кадра. Форма — как у
   остальных секций (iOS-скругление, маска ниже).
   Трек = окно + ход; окно внутри липкое, кадр — по центру окна. */
/* Светлый блок с вопросами и ответами и логотипом из шариков. Идёт за синим
   «VK Education» обычным потоком: раньше тот прилипал и этот блок на него наезжал,
   но наезд убран (правки заказчика 2026-10-28: формы блоков при прокрутке дёргались,
   а прилипший синий блок проглядывал в нижних скруглённых углах этого). */
.promo-stack { position: relative; }

.logo-scene {
  --view-h: calc(100svh - var(--header-h));
  position: relative;
  z-index: 1;
  margin-top: calc(23 * var(--k));
  border-radius: var(--radius-xl);
  /* цвет светлых секций — фон кадров и постера перекрашен в него
     (scripts/build-logo-frames.mjs); с кадрами landing.js подставляет точный цвет из кадра */
  background: var(--snow);
}
/* Сверху в блоке — вопросы и ответы (обычный поток), под ними трек анимации. */
.logo-scene.is-scrolly .logo-scene__track { height: calc(var(--view-h) + var(--logo-scrub)); }

.logo-scene__view {
  display: grid;
  place-items: center;
  overflow: hidden;
}
.logo-scene.is-scrolly .logo-scene__view {
  position: sticky;
  top: var(--header-h);
  height: var(--view-h);
}

/* Кадр квадратный: по ширине блока, но не выше окна. Края кадра растворены
   маской — даже при сдвиге оттенка (постер-jpg, другой экран) рамки не видно. */
.logo-scene__card {
  position: relative;
  width: min(100%, var(--view-h));
  aspect-ratio: 1;
  -webkit-mask:
    linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent),
    linear-gradient(180deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-composite: source-in;
          mask:
    linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent),
    linear-gradient(180deg, transparent, #000 8%, #000 92%, transparent);
          mask-composite: intersect;
}
.logo-scene__poster,
.logo-scene__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.logo-scene__canvas { opacity: 0; }
.logo-scene__canvas.is-ready { opacity: 1; }

/* ---------- вопросы и ответы ---------- */
/* Вопросы — <details>: раскрываются и без JS. Раскрытый вопрос синий, как
   раскрытый сезон. Плавное раскрытие — через ::details-content и
   interpolate-size (Chrome 131+); где их нет, ответ появляется сразу. */
.faq {
  interpolate-size: allow-keywords;
  /* лежит в начале светлого блока с логотипом из шариков — фон у блока */
  padding: calc(44 * var(--k)) calc(24 * var(--k)) calc(12 * var(--k));
}

.faq__title {
  margin-left: calc(-1 * var(--k));
  font-size: calc(45.91 * var(--k));
  color: var(--ink);
}
.faq__title i { font-style: italic; color: var(--blue); }

.faq__list {
  display: grid;
  gap: calc(10 * var(--k));
  margin-top: calc(20 * var(--k));
}

.faq__item {
  border-radius: calc(31 * var(--k));
  background: #fff; /* на светло-голубом блоке --snow почти не отличался бы от фона */
  color: var(--ink);
  transition: background-color 0.3s ease, color 0.3s ease;
}
.faq__item[open] { background: var(--blue); color: #fff; }

.faq__item::details-content {
  block-size: 0;
  overflow: hidden;
  transition: block-size 0.35s ease, content-visibility 0.35s allow-discrete;
}
.faq__item[open]::details-content { block-size: auto; }

.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(12 * var(--k));
  padding: calc(20 * var(--k)) calc(20 * var(--k)) calc(20 * var(--k)) calc(22 * var(--k));
  font-weight: 500;
  font-size: calc(18 * var(--k));
  line-height: calc(22 * var(--k));
  letter-spacing: -0.02em;
  list-style: none;
  cursor: pointer;
}
.faq__q::-webkit-details-marker { display: none; }

.faq__plus {
  flex: none;
  width: calc(22 * var(--k));
  height: calc(22 * var(--k));
  transition: transform 0.3s ease, filter 0.3s ease;
}
.faq__item[open] .faq__plus { transform: rotate(45deg); filter: invert(1); }

.faq__a {
  padding: 0 calc(22 * var(--k)) calc(22 * var(--k));
  font-size: calc(16 * var(--k));
  line-height: 1.3;
  color: var(--ice);
}

/* ---------- подвал: меню и правовое ---------- */
/* Светлый подвал под блоком с логотипом: лого, продублированное меню, соцсети
   и правовая строка. */
.footer {
  padding: calc(28 * var(--k)) calc(24 * var(--k)) calc(27 * var(--k) + env(safe-area-inset-bottom, 0px)) calc(23 * var(--k));
  background: #fff;
}

.footer-logo {
  display: block;
  margin-bottom: calc(24 * var(--k));
}
.footer-logo img { width: calc(148.5 * var(--k)); height: auto; }

.footer-nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(12 * var(--k));
}

.footer-socials {
  display: flex;
  gap: calc(20 * var(--k));
  margin-top: calc(18 * var(--k));
}
.footer-socials img { display: inline-block; vertical-align: -0.2em; width: 1.1em; height: 1.1em; margin-left: 0.15em; }
.footer-socials a {
  font-size: calc(17 * var(--k));
  line-height: calc(22 * var(--k));
  letter-spacing: -0.02em;
  color: var(--muted);
  text-decoration: none;
}
.footer-nav a {
  font-weight: 500;
  font-size: calc(17 * var(--k));
  line-height: calc(22 * var(--k));
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
}

.footer-legal {
  display: flex;
  justify-content: space-between;
  gap: calc(12 * var(--k));
  margin-top: calc(26 * var(--k));
  padding-top: calc(16 * var(--k));
  border-top: 1px solid rgba(0, 0, 0, 0.1);
  font-size: calc(14 * var(--k));
  line-height: calc(18 * var(--k));
  color: var(--muted);
}
.footer-legal a { color: inherit; }

/* ---------- iOS-скругление (corner smoothing 100% из Figma) ---------- */
/* Нативный corner-shape есть не везде, поэтому форма — CSS-маска: четыре угловые
   плитки (scripts/build-squircle-masks.mjs) и две полосы между ними. От размера
   элемента не зависит, JS не нужен, работает в Chrome/Android, Safari/iOS и Firefox.
   Полосы на 3px с каждой стороны заходят под плитки — иначе на стыке из-за
   субпиксельного округления видна волосяная щель.
   border-radius оставлен как запасной вариант: squircle целиком лежит внутри
   обычного скругления того же радиуса, так что он ничего не срезает.
   Плитки встроены data:-адресами (2026-11-02), а не файлами img/squircle/*.svg: маски браузер
   грузит с проверкой CORS, и при открытии index.html с диска (file://) или при неверном
   Content-Type у SVG на сервере плитки не грузились — от элемента оставался «крест» из
   двух полос. Пересобрали плитки (scripts/build-squircle-masks.mjs) — обновить и здесь. */
.seasons::before,
.midsprint,
.season.is-open.is-settled,
.cta,
.logo-scene {
  --sq-tl: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 200 200%22 preserveAspectRatio=%22none%22%3E%3Cpath d=%22M0 0c94.2809 0 141.4214 0 170.7107 29.2893a100 100 0 0 1 0 0c29.2893 29.2893 29.2893 76.4298 29.2893 170.7107L0 200Z%22 transform=%22translate(200 0) scale(-1 1)%22/%3E%3C/svg%3E');
  --sq-tr: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 200 200%22 preserveAspectRatio=%22none%22%3E%3Cpath d=%22M0 0c94.2809 0 141.4214 0 170.7107 29.2893a100 100 0 0 1 0 0c29.2893 29.2893 29.2893 76.4298 29.2893 170.7107L0 200Z%22/%3E%3C/svg%3E');
  --sq-bl: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 200 200%22 preserveAspectRatio=%22none%22%3E%3Cpath d=%22M0 0c94.2809 0 141.4214 0 170.7107 29.2893a100 100 0 0 1 0 0c29.2893 29.2893 29.2893 76.4298 29.2893 170.7107L0 200Z%22 transform=%22translate(200 200) scale(-1 -1)%22/%3E%3C/svg%3E');
  --sq-br: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 200 200%22 preserveAspectRatio=%22none%22%3E%3Cpath d=%22M0 0c94.2809 0 141.4214 0 170.7107 29.2893a100 100 0 0 1 0 0c29.2893 29.2893 29.2893 76.4298 29.2893 170.7107L0 200Z%22 transform=%22translate(0 200) scale(1 -1)%22/%3E%3C/svg%3E');
  --sq-p: calc(var(--sq-r, var(--r-xl)) * 2 * var(--k)); /* полное сглаживание: угол заходит на 2r */

  -webkit-mask:
    var(--sq-tl) left top / var(--sq-p) var(--sq-p) no-repeat,
    var(--sq-tr) right top / var(--sq-p) var(--sq-p) no-repeat,
    var(--sq-bl) left bottom / var(--sq-p) var(--sq-p) no-repeat,
    var(--sq-br) right bottom / var(--sq-p) var(--sq-p) no-repeat,
    linear-gradient(#000 0 0) center / calc(100% - 2 * var(--sq-p) + 6px) 100% no-repeat,
    linear-gradient(#000 0 0) center / 100% calc(100% - 2 * var(--sq-p) + 6px) no-repeat;
          mask:
    var(--sq-tl) left top / var(--sq-p) var(--sq-p) no-repeat,
    var(--sq-tr) right top / var(--sq-p) var(--sq-p) no-repeat,
    var(--sq-bl) left bottom / var(--sq-p) var(--sq-p) no-repeat,
    var(--sq-br) right bottom / var(--sq-p) var(--sq-p) no-repeat,
    linear-gradient(#000 0 0) center / calc(100% - 2 * var(--sq-p) + 6px) 100% no-repeat,
    linear-gradient(#000 0 0) center / 100% calc(100% - 2 * var(--sq-p) + 6px) no-repeat;
}

/* Низкие элементы: на полное сглаживание места нет, Figma его урезает. */
.cta {
  --sq-tl: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 46.5 46.5%22 preserveAspectRatio=%22none%22%3E%3Cpath d=%22M0 0c7.8977 0 11.8466 0 15.1416 0.5849a38 38 0 0 1 30.7735 30.7735c0.5849 3.295 0.5849 7.2439 0.5849 15.1416L0 46.5Z%22 transform=%22translate(46.5 0) scale(-1 1)%22/%3E%3C/svg%3E');
  --sq-tr: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 46.5 46.5%22 preserveAspectRatio=%22none%22%3E%3Cpath d=%22M0 0c7.8977 0 11.8466 0 15.1416 0.5849a38 38 0 0 1 30.7735 30.7735c0.5849 3.295 0.5849 7.2439 0.5849 15.1416L0 46.5Z%22/%3E%3C/svg%3E');
  --sq-bl: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 46.5 46.5%22 preserveAspectRatio=%22none%22%3E%3Cpath d=%22M0 0c7.8977 0 11.8466 0 15.1416 0.5849a38 38 0 0 1 30.7735 30.7735c0.5849 3.295 0.5849 7.2439 0.5849 15.1416L0 46.5Z%22 transform=%22translate(46.5 46.5) scale(-1 -1)%22/%3E%3C/svg%3E');
  --sq-br: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 46.5 46.5%22 preserveAspectRatio=%22none%22%3E%3Cpath d=%22M0 0c7.8977 0 11.8466 0 15.1416 0.5849a38 38 0 0 1 30.7735 30.7735c0.5849 3.295 0.5849 7.2439 0.5849 15.1416L0 46.5Z%22 transform=%22translate(0 46.5) scale(1 -1)%22/%3E%3C/svg%3E');
  --sq-p: calc(46.5 * var(--k));
}
/* Плашки соцсетей — таблетки (правки 2026-10-29), им хватает border-radius. */

/* «3 сезона»: маской режем только фон. Внутри липкая сцена и анимация —
   маска на всём блоке заставляла бы перерисовывать его на каждом кадре прокрутки. */
.seasons { background: none; }
.seasons::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: var(--radius-xl);
  background: var(--snow);
}

/* Карточки вузов: фон и тень — в слое ::before, обычный border-radius и box-shadow.
   Раньше здесь были маска iOS-скругления и filter: drop-shadow — карточки появляются
   по прокрутке, и Safari пересчитывал фильтр на каждом кадре. */
.station__card {
  background: none;
  box-shadow: none;
}
.station__card::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--card-bg);
  box-shadow: 0 calc(8 * var(--k)) calc(24 * var(--k)) rgba(30, 70, 140, 0.1);
}


/* ---------- кнопки: прямой Condensed ---------- */
/* Правки заказчика 2026-10-29: «на всех кнопках не италик, а обычное начертание Condensed,
   италик оставить только в заголовках и датах». Одно правило на все кнопки, в конце файла —
   перебивает и .display у подписи кнопки. */
.btn,
.topbar__cta,
.cta .cta__label {
  font-family: var(--font-display);
  font-weight: 800;
  font-style: normal;
}

/* ---------- заголовки секций: плотнее ---------- */
/* Правки заказчика 2026-10-29: «интерлиньяж меньше в заголовках» — по референсу (синий
   «Лабиринт возможностей», assets/references/feedback-2026-10-29/image1.png) просвет между
   строками ≈ треть высоты прописной; у VK Sans Display Condensed это line-height ≈ 0.92
   (было 1.02 от .display). Заголовок первого экрана уже плотнее — его не трогаем. */
.series__title,
.seasons__title,
.campus__title,
.midsprint__title,
.promo__title,
.faq__title { line-height: 0.92; }
