/* =====================================================================
   Motion Elevated — Apple-style моушн-слой для landing-страниц.
   Используется на главной (ai_pages/home_copy.html), но является
   универсальным: hero-parallax, splittext reveal, sticky-storytelling,
   magnetic CTA, mesh-gradient, marquee, cross-fade.

   Все эффекты выключаются через prefers-reduced-motion.
   ===================================================================== */

/* ---------- 1. Mesh-gradient ambient background (для hero) ---------- */
.ds-mesh-bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
.ds-mesh-bg::before,
.ds-mesh-bg::after {
  content: '';
  position: absolute;
  border-radius: 50%;
  /* PERF: blur 40px вместо 80 — экономит ×2 в GPU compositor cost (radial samples).
     Размер 40vw вместо 60vw — ещё ×2 экономии на pixel count. Drift амплитуда
     уменьшена соответственно. Визуально разница не заметна. */
  filter: blur(40px);
  opacity: 0.5;
  will-change: transform;
  animation: ds-mesh-drift 26s ease-in-out infinite alternate;
}
/* Когда .ds-mesh-bg помечена off-screen — паузим анимацию (JS ставит атрибут).
   Иначе keyframes крутятся вечно на GPU даже когда benefits в viewport.
   will-change: auto освобождает GPU layer когда секция не видна (раньше
   layer держался всегда, даже на паузе). */
.ds-mesh-bg[data-off]::before,
.ds-mesh-bg[data-off]::after {
  animation-play-state: paused;
  will-change: auto;
}
.ds-mesh-bg::before {
  /* PERF: 40vw вместо 60vw — pixel count ×0.44 */
  width: 40vw;
  height: 40vw;
  left: 0vw;
  top: -10vw;
  background: radial-gradient(circle, rgba(0, 142, 248, 0.32), transparent 70%);
}
.ds-mesh-bg::after {
  width: 35vw;
  height: 35vw;
  right: -5vw;
  top: 5vh;
  background: radial-gradient(circle, rgba(139, 92, 246, 0.22), transparent 70%);
  animation-delay: -10s;
  animation-duration: 32s;
}
@keyframes ds-mesh-drift {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  100% { transform: translate3d(-3vw, 4vh, 0) scale(1.05); }
}

/* Cursor-follow свечение. Координаты приходят из home-motion.js через
   CSS custom properties --mx, --my (значения от 0 до 1). */
.ds-mouse-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background: radial-gradient(
    600px circle at calc(var(--mx, 0.5) * 100%) calc(var(--my, 0.3) * 100%),
    rgba(0, 142, 248, 0.14),
    transparent 50%
  );
  transition: opacity 0.4s ease;
  opacity: 0;
}
/* hover: hover — на touch-устройствах после tap glow «застревал» включённым */
@media (hover: hover) {
  .ds-hero-elevated:hover .ds-mouse-glow { opacity: 1; }
}

/* ---------- 2. Hero elevated ---------- */
.ds-hero-elevated {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: linear-gradient(180deg, #ffffff 0%, #f5f8fb 100%);
  /* Подтягиваем секцию под прозрачный sticky-хедер и компенсируем падингом сверху,
     чтобы внутренний контент остался на том же визуальном расстоянии (64/80px). */
  margin-top: calc(var(--ds-header-h, 64px) * -1);
  padding-top: calc(var(--ds-header-h, 64px) + 64px);
}
@media (min-width: 768px) {
  .ds-hero-elevated {
    padding-top: calc(var(--ds-header-h, 80px) + 80px);
  }
}
.ds-hero-elevated > .container-fluid {
  position: relative;
  z-index: 2;
}

/* Eyebrow pill с пульсирующей точкой */
.ds-hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(0, 142, 248, 0.18);
  color: var(--ds-brand);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  box-shadow: 0 4px 20px rgba(0, 142, 248, 0.06);
}
.ds-hero-eyebrow__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ds-brand);
  position: relative;
}
.ds-hero-eyebrow__dot::after {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  background: var(--ds-brand);
  opacity: 0.5;
  animation: ds-pulse 2s ease-out infinite;
}
@keyframes ds-pulse {
  0%   { transform: scale(0.8); opacity: 0.6; }
  100% { transform: scale(2.5); opacity: 0; }
}

/* Display headline: больше air, чище ритм */
.ds-display-headline {
  font-family: var(--ds-font-family);
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.05;
  color: var(--ds-text-primary);
  font-size: clamp(40px, 6.5vw, 80px);
  margin: 0;
}
.ds-display-headline .ds-grad-text {
  /* Тот же градиент что у CTA-кнопки .ds-btn-magnetic--primary — brand blue
     к deeper blue. Никакого фиолетового. */
  background: var(--ds-brand-gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  display: inline-block;
}

/* Splittext: каждое слово в .ds-word, появляется снизу с blur */
.ds-word {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.45em);
  filter: blur(8px);
  transition: opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.8s cubic-bezier(0.22, 1, 0.36, 1),
              filter 0.8s cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: calc(var(--word-i, 0) * 60ms);
}
.ds-split-ready .ds-word {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
}
/* PERF: после окончания reveal-анимации JS ставит .is-done на каждое слово.
   Снимаем filter и transition — освобождаем GPU layers (5 слов = 5 stacking contexts).
   Иначе filter:blur(0px) держит layer навсегда, transition: filter ждёт изменений. */
.ds-word.is-done {
  filter: none;
  transition: none;
  transform: none;
}

.ds-subhead-elevated {
  font-size: clamp(17px, 1.6vw, 22px);
  line-height: 1.5;
  color: var(--ds-text-secondary);
  max-width: 640px;
  margin: 24px auto 36px;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.9s ease, transform 0.9s ease;
  transition-delay: 0.35s;
}
.ds-split-ready .ds-subhead-elevated { opacity: 1; transform: translateY(0); }

/* CTA group + hint */
.ds-cta-row {
  display: flex;
  flex-direction: column;
  gap: 16px;
  align-items: center;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.9s ease, transform 0.9s ease;
  transition-delay: 0.55s;
}
@media (min-width: 576px) {
  .ds-cta-row { flex-direction: row; }
}
.ds-split-ready .ds-cta-row { opacity: 1; transform: translateY(0); }

.ds-hero-hint {
  margin-top: 20px;
  font-size: 14px;
  color: var(--ds-text-muted);
  opacity: 0;
  transition: opacity 1s ease;
  transition-delay: 0.7s;
}
.ds-split-ready .ds-hero-hint { opacity: 1; }

/* .ds-btn-magnetic* стили перенесены в atoms-btn-magnetic.css —
   глобально подключаемый atoms-уровень DS. Работает на всех страницах,
   не только на главной (соответствует logic'е ds_motion JS-бандла). */

/* Hero image wrap — parallax + scale on scroll.
   Значения --p (0..1) и --s (1..1.08) приходят из JS. */
.ds-hero-stage {
  position: relative;
  margin-top: clamp(40px, 6vw, 80px);
  perspective: 1600px;
  perspective-origin: 50% 0%;
}
.ds-hero-stage-frame {
  position: relative;
  border-radius: clamp(20px, 3vw, 36px);
  overflow: hidden;
  background: #0a0f1a;
  box-shadow:
    0 50px 100px -20px rgba(15, 33, 76, 0.18),
    0 30px 60px -30px rgba(15, 33, 76, 0.28),
    0 0 0 1px rgba(15, 33, 76, 0.06);
  transform-origin: 50% 0%;
  transform:
    translate3d(0, calc(var(--p, 0) * -40px), 0)
    scale(var(--s, 1));
  transition: box-shadow 0.4s ease;
  opacity: 0;
  animation: ds-stage-rise 1.2s cubic-bezier(0.22, 1, 0.36, 1) 0.4s forwards;
}
@keyframes ds-stage-rise {
  from { opacity: 0; transform: translate3d(0, 40px, 0) scale(0.97); }
  to   { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
}
.ds-hero-stage-frame img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: inherit;
}

/* Floating chips around hero stage */
.ds-hero-chip {
  position: absolute;
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid rgba(15, 33, 76, 0.08);
  border-radius: 16px;
  padding: 12px 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ds-text-primary);
  box-shadow: 0 14px 30px rgba(15, 33, 76, 0.12);
  display: flex;
  align-items: center;
  gap: 10px;
  opacity: 0;
  transform: translateY(20px);
  animation: ds-chip-in 0.9s cubic-bezier(0.22, 1, 0.36, 1) forwards;
  z-index: 3;
}
.ds-hero-chip svg { flex-shrink: 0; }
.ds-hero-chip--tl { top: 14%; left: -4%; animation-delay: 1.0s; }
.ds-hero-chip--br { bottom: 18%; right: -3%; animation-delay: 1.2s; }
@media (max-width: 991px) {
  .ds-hero-chip { display: none; }
}
@keyframes ds-chip-in {
  to { opacity: 1; transform: translateY(0); }
}

/* ---------- 3. Section: Apple-style chapter labels ---------- */
.ds-chapter-label {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ds-brand);
  margin-bottom: 16px;
  display: inline-block;
}

.ds-section-headline {
  font-family: var(--ds-font-family);
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.15;
  font-size: clamp(28px, 3.2vw, 44px);
  color: var(--ds-text-primary);
  margin: 0 0 16px;
}
.ds-section-sub {
  font-size: 18px;
  line-height: 1.55;
  color: var(--ds-text-secondary);
  max-width: 720px;
  margin: 0;
}

/* Раньше тут жил .ds-story (sticky storytelling, ~135 строк) — отключён
   в шаблонах после редизайна benefits на highlights-carousel. Удалён
   как dead code; initStory() в home-motion.js остаётся защищённым ранним
   return'ом если [data-story] не найден. */

/* ---------- 4b. Highlights carousel (Apple "Get the highlights") ----------
   Горизонтальный snap-scroll, крупные карточки, текст внизу, peek по краям.
   Контролы: native drag/wheel + arrow buttons + dot indicators.
   Работает одинаково на mobile/desktop (responsive width карточки). */
.ds-highlights {
  position: relative;
  isolation: isolate;
  /* Контейнер для absolute-positioned controls (мы их не используем,
     но isolation страхует от z-index конфликтов). */
}

/* Wrap нужен, чтобы trek наследовал full-bleed width, а контейнер выше остался ограничен 1320px */
.ds-highlights-track-wrap {
  width: 100%;
  position: relative;
}

.ds-highlights-track {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
  /* Padding-bottom больше top: overflow-x:auto заставляет браузер клипать и
     overflow-y (нельзя visible+auto одновременно), а hover-тень карточки
     уезжает ~45px вниз. Запас 48px / 56px вмещает blur полностью. */
  padding: 24px 0 48px;
}
.ds-highlights-track::-webkit-scrollbar { display: none; }

/* Drag-to-scroll: курсор и блок text-select во время перетаскивания мышью */
.ds-highlights-track.is-dragging {
  cursor: grabbing !important;
  user-select: none;
  scroll-snap-type: none; /* во время drag snap не нужен — будет дёргать */
}
.ds-highlights-track.is-dragging .ds-highlight-card,
.ds-highlights-track.is-dragging .ds-highlight-card * {
  cursor: grabbing !important;
  pointer-events: none; /* предотвращает выделение текста при drag */
}

@media (min-width: 768px) {
  .ds-highlights-track {
    gap: 24px;
    padding: 32px 0 56px;
  }
}

/* Карточка — landscape 2:1, контент-overlay (Apple "Get the highlights") */
.ds-highlight-card {
  /* Фиксированная ширина карточки. Track full-bleed (на всю ширину viewport),
     peek соседних виден до краёв экрана. JS recalibrate ставит padding-inline
     треку чтобы первая/последняя карточка центрировались. */
  flex: 0 0 calc(100vw - 32px);
  scroll-snap-align: center;
  border-radius: 20px;
  overflow: hidden;
  position: relative;
  display: block;
  isolation: isolate;
  /* Landscape 2:1 — как у Apple */
  aspect-ratio: 2 / 1;
  /* Фон — отдельный div .ds-highlight-card__bg внутри карточки (для parallax).
     Сам article держит fallback-цвет и обрезает overflow (overflow: hidden
     уже задан выше). */
  background: #0a0f1a;
  color: #fff;
  /* Click на peek-карточку доскроллит её в центр (см. home-motion.js).
     По умолчанию указывающий курсор намекает что карточка кликабельна. */
  cursor: pointer;
  box-shadow: 0 10px 30px -10px rgba(15, 33, 76, 0.18);
  transition: transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1),
              box-shadow 0.5s cubic-bezier(0.22, 0.61, 0.36, 1);
  /* PERF: will-change только на hover, не статически. Иначе 6 GPU layers
     постоянно держатся в VRAM (M1 Max limit ~50, но дешевле не плодить). */
}
.ds-highlight-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 22px 50px -18px rgba(15, 33, 76, 0.28);
  will-change: transform;
}
/* Центральная (активная) карточка не кликабельна — peek-карточки доскроливаются,
   а центральная уже в фокусе. Сбрасываем pointer и hover-lift, чтобы курсор
   не намекал на действие, которого нет. */
.ds-highlight-card.is-active {
  cursor: default;
}
.ds-highlight-card.is-active:hover {
  transform: none;
  box-shadow: 0 10px 30px -10px rgba(15, 33, 76, 0.18);
  will-change: auto;
}

/* Mobile: aspect-ratio 2:1 даёт всего ~172px высоты на 343px ширины,
   многострочный текст (3-4 строки desc) не влезает. 1.2:1 → ~286px на
   375vw, ~330px на 414vw — текст читается без обрезания. min-height 260px
   страхует на узких экранах (iPhone SE 320vw). На tablet/desktop (≥768)
   ratio возвращается к 2:1. */
@media (max-width: 767px) {
  .ds-highlight-card {
    aspect-ratio: 1.2 / 1;
    min-height: 260px;
  }
}
@media (min-width: 768px) {
  .ds-highlight-card {
    /* Tablet: карточка ~712px (на 768 viewport — peek по 28px от края) */
    flex: 0 0 min(calc(100vw - 56px), 880px);
    border-radius: 24px;
  }
}
@media (min-width: 992px) {
  .ds-highlight-card {
    /* Desktop: фиксированная max 1088px (как раньше, до зажима в контейнер).
       На viewport ≥1216 — ровно 1088. На узких — calc вписывает. */
    flex: 0 0 min(calc(100vw - 128px), 1088px);
    border-radius: 28px;
  }
}

/* Bg layer — фон карточки в отдельном div. Чуть шире карточки (scale 1.12),
   чтобы был запас под parallax shift по горизонтали при scroll-snap.
   JS на scroll трека выставляет --px (амплитуда ±60-80px). */
.ds-highlight-card__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  /* Запас по обе стороны на parallax shift.
     PERF: 2D translate() вместо translate3d — не промотит автоматически
     в композитный layer. Layer создаётся только когда добавляется
     will-change: transform через класс .is-nearby (см. ниже).
     С translate3d все 6 карточек висели бы в GPU постоянно — динамический
     will-change был бы placebo. */
  transform: translate(var(--px, 0px), 0) scale(1.12);
}
.ds-highlight-card.is-nearby .ds-highlight-card__bg {
  /* JS добавляет .is-nearby только активной + prev + next (3 layers вместо 6).
     На .is-nearby создаётся композитный layer, бэкграунд анимируется на GPU.
     Скрытые карточки за viewport — обычный paint без GPU-promote. */
  will-change: transform;
}

/* Overlay — текст слева сверху + dark gradient для читаемости поверх фото.
   Gradient идёт от тёмного слева-сверху (где текст) к прозрачному вправо-вниз. */
.ds-highlight-card__overlay {
  position: absolute;
  inset: 0;
  padding: clamp(28px, 4vw, 56px) clamp(28px, 4vw, 64px);
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  pointer-events: none;
  background: linear-gradient(
    135deg,
    rgba(0, 0, 0, 0.55) 0%,
    rgba(0, 0, 0, 0.35) 30%,
    rgba(0, 0, 0, 0) 65%
  );
}
/* Eyebrow — категория над заголовком */
.ds-highlight-card__eyebrow {
  font-family: var(--ds-font-family);
  font-size: clamp(12px, 1.05vw, 14px);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.78);
  margin: 0 0 14px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}

/* Title — главное утверждение */
.ds-highlight-card__title {
  font-family: var(--ds-font-family);
  font-size: clamp(22px, 2.6vw, 36px);
  font-weight: 700;
  letter-spacing: -0.018em;
  line-height: 1.18;
  color: inherit;
  margin: 0 0 14px;
  max-width: min(60%, 640px);
  text-wrap: balance;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}

/* Desc — раскрывающий subtitle под заголовком */
.ds-highlight-card__desc {
  font-family: var(--ds-font-family);
  font-size: clamp(14px, 1.25vw, 17px);
  font-weight: 400;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.88);
  margin: 0;
  max-width: min(48%, 480px);
  text-wrap: pretty;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}

/* ===== Apple-style controls: pill-пагинатор + Play кнопка ===== */
.ds-highlights-controls {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
}

/* Pill с dots — серая капсула, точки внутри */
.ds-highlights-pill {
  background: rgba(15, 33, 76, 0.08);
  border-radius: 999px;
  /* Меньше padding, потому что сами кнопки-обёртки теперь 24×24
     и уже содержат свободное место вокруг визуальных точек. */
  padding: 12px 14px;
  display: flex;
  align-items: center;
  height: 48px;
}
.ds-highlights-dots {
  display: flex;
  gap: 4px; /* визуальный gap между точками задаётся padding'ом кнопок */
  align-items: center;
}

/* Button-обёртка — увеличенная hover-зона 24×24 (4× площадь визуальной точки).
   Сама точка рисуется ::before, чтобы анимировать только её, не button-бокс. */
.ds-highlights-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  background: transparent;
  border: none;
  cursor: pointer;
  flex-shrink: 0;
}

/* Визуальная точка. Принципиально border-radius: 999px на ВСЕХ состояниях —
   это всегда даёт capsule-shape (радиус = половина минорной стороны).
   При width=6, height=6 → полный круг. При width=26, height=6 → таблетка
   с круглыми концами радиусом 3px. Никаких промежуточных эллипсов в transition. */
.ds-highlights-dot::before {
  content: '';
  display: block;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: rgba(15, 33, 76, 0.32);
  transition:
    background 0.3s ease,
    width 0.45s cubic-bezier(0.22, 0.61, 0.36, 1),
    transform 0.25s cubic-bezier(0.22, 0.61, 0.36, 1);
  /* Промоутим — нет jank на переключении */
  will-change: width, transform;
}

/* Hover — точка растёт + темнеет (для неактивных) */
.ds-highlights-dot:hover::before {
  background: rgba(15, 33, 76, 0.55);
  transform: scale(1.4);
}

/* Active — capsule 26px. Hover на active не применяет scale (некрасиво). */
.ds-highlights-dot.is-active::before {
  background: rgba(15, 33, 76, 0.72);
  width: 26px;
}
.ds-highlights-dot.is-active:hover::before {
  transform: scale(1);
  background: rgba(15, 33, 76, 0.85);
}

/* Play / Pause кнопка — circular, тех же размеров что pill */
.ds-highlights-play {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: rgba(15, 33, 76, 0.08);
  border: none;
  color: rgba(15, 33, 76, 0.72);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background 0.2s ease, transform 0.2s ease;
  position: relative;
}
.ds-highlights-play:hover {
  background: rgba(15, 33, 76, 0.14);
  transform: scale(1.04);
}
.ds-highlights-play:active { transform: scale(0.96); }

.ds-highlights-play__icon {
  transition: opacity 0.2s ease;
}
.ds-highlights-play[data-state="playing"] .ds-highlights-play__icon--play,
.ds-highlights-play:not([data-state="playing"]) .ds-highlights-play__icon--pause {
  display: none;
}
.ds-highlights-play__icon--play { transform: translateX(1px); }

/* prefers-reduced-motion: убрать smooth scrolling */
@media (prefers-reduced-motion: reduce) {
  .ds-highlights-track { scroll-behavior: auto; }
  .ds-highlight-card,
  .ds-highlights-play,
  .ds-highlights-dot {
    transition: none !important;
  }
  .ds-highlight-card:hover { transform: none; }
}

/* ---------- 5. Launch steps — SVG progress timeline ---------- */
.ds-timeline {
  position: relative;
}
.ds-timeline__progress {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.ds-timeline__progress path {
  stroke: var(--ds-brand);
  stroke-width: 2;
  fill: none;
  stroke-linecap: round;
  stroke-dasharray: var(--len, 1000);
  stroke-dashoffset: calc(var(--len, 1000) * (1 - var(--prog, 0)));
  transition: stroke-dashoffset 0.3s linear;
  filter: drop-shadow(0 0 4px rgba(0, 142, 248, 0.4));
}

.ds-step-elevated {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
  /* Delay через CSS-var: шаблон передаёт style="--step-i: N" (0..3).
     Раньше :nth-child(2/3/4) считал ВСЕХ siblings включая arrow-stems
     между карточками — реальные позиции карточек 1,3,5,7, и порядок
     reveal'a ломался. Через --step-i порядок гарантирован. */
  transition-delay: calc(var(--step-i, 0) * 100ms);
}
.ds-step-elevated.is-in {
  opacity: 1;
  transform: translateY(0);
}

/* ---------- 6. Models tabs cross-fade ---------- */
.ds-tab-panel-fade {
  opacity: 0;
  transform: translateY(8px);
  filter: blur(6px);
  transition: opacity 0.4s ease, transform 0.4s ease, filter 0.4s ease;
  pointer-events: none;
}
.ds-tab-panel-fade.is-active {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
  pointer-events: auto;
}

/* ---------- 7. Marquee (feedbacks) ---------- */
.ds-marquee {
  position: relative;
  overflow: hidden;
  mask-image: linear-gradient(
    to right,
    transparent,
    #000 8%,
    #000 92%,
    transparent
  );
  -webkit-mask-image: linear-gradient(
    to right,
    transparent,
    #000 8%,
    #000 92%,
    transparent
  );
}
.ds-marquee__track {
  display: flex;
  gap: 24px;
  width: max-content;
  animation: ds-marquee-scroll var(--speed, 60s) linear infinite;
  will-change: transform;
}
.ds-marquee:hover .ds-marquee__track { animation-play-state: paused; }
/* Off-viewport pause: JS ставит [data-off] через IntersectionObserver,
   когда секция feedbacks вне экрана. Без этого marquee гонит GPU всё время
   что юзер на странице — заметный battery drain на мобиле. */
.ds-marquee[data-off] .ds-marquee__track {
  animation-play-state: paused;
  will-change: auto;
}
@keyframes ds-marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ---------- 8. Final CTA — full-bleed dark, Apple-style ---------- */
.ds-final-cta {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  /* Двухслойный фон: radial-эллипс сверху (центральный glow) +
     vertical-gradient снизу плавно сходящийся к цвету футера #27293a.
     Это убирает визуальный шов между секцией и футером. */
  background:
    linear-gradient(180deg, transparent 60%, #27293a 100%),
    radial-gradient(ellipse at top, #0d1929 0%, #060b16 70%);
  color: #fff;
  padding: clamp(80px, 14vw, 180px) 0;
  text-align: center;
  /* Negative margin поглощает .mt-5 (48px white gap) wrapper'a футера —
     белая полоса исчезает, секция стыкуется напрямую с .ds-footer-section. */
  margin-bottom: -48px;
}
/* Контент колонок final-CTA — по левому краю. Центрирование наследовалось
   от .ds-final-cta text-align: center и центрировало chapter-label, h3
   формы, subtitle. */
.ds-final-cta .col-lg-6 {
  text-align: left;
}
.ds-final-cta::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(600px circle at 30% 30%, rgba(0, 142, 248, 0.35), transparent 50%),
    radial-gradient(500px circle at 70% 70%, rgba(107, 61, 245, 0.25), transparent 55%);
  z-index: 0;
  pointer-events: none;  /* декорация — не должна красть клики у формы */
}
.ds-final-cta::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(ellipse at center, #000 0%, transparent 70%);
  -webkit-mask-image: radial-gradient(ellipse at center, #000 0%, transparent 70%);
  z-index: 0;
  opacity: 0.5;
  pointer-events: none;  /* декорация — не должна красть клики у формы */
}
/* В шаблоне используется .container-fluid (не .container) — старое правило
   не матчилось, контент шёл z-index: auto и оказывался ПОД ::before/::after. */
.ds-final-cta > .container,
.ds-final-cta > .container-fluid {
  position: relative;
  z-index: 1;
}
.ds-final-cta h2 {
  font-size: clamp(30px, 3.6vw, 52px);
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.15;
  margin: 0 0 20px;
}
.ds-final-cta h2 .ds-grad-text-light {
  /* Light-blue gradient на dark hero. var(--ds-brand-gradient) (#008ef8 →
     #006bd1) на этом фоне даёт контраст ~3.8:1 — fail WCAG AA 4.5:1 для
     normal text. #4eb6ff → #80ccff даёт ~7:1 — pass с запасом.
     WCAG 1.4.3 Contrast (AA). */
  background: linear-gradient(135deg, #4eb6ff 0%, #80ccff 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.ds-final-cta p {
  font-size: clamp(16px, 1.4vw, 20px);
  color: rgba(255, 255, 255, 0.7);
  max-width: 600px;
  margin: 0 auto 40px;
  line-height: 1.55;
}

/* Final-CTA feature list: чек-маркеры в круглых icon-фонах.
   Раньше всё было inline-стилями (5 повторяющихся li). */
.ds-final-cta__features {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.ds-final-cta__feature {
  display: flex;
  align-items: center;
  gap: 14px;
  color: rgba(255, 255, 255, 0.85);
  font-size: 16px;
}
.ds-final-cta__feature-icon {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(0, 142, 248, 0.22);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.ds-final-cta__feature-icon--purple {
  background: rgba(167, 139, 250, 0.25);
}

/* Карточка регистрации справа в final-cta. Раньше — inline 6 свойств.
   color: var(--ds-text-primary) обязателен — родитель .ds-final-cta дал
   color:#fff и React-рендеримые consent-тексты (auth_modals/AuthForm.tsx)
   без явного color наследуют белый, сливаются с белым background карточки. */
.ds-final-cta__form-card {
  background: #fff;
  color: var(--ds-text-primary);
  border-radius: 24px;
  padding: 36px 32px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.4);
  text-align: left;
}
/* Reset .ds-final-cta p (clamp font-size + white-70 color + max-width 600px +
   margin 0 auto 40px) для React-рендеримых consent-параграфов внутри карточки.
   :not([class]) — точечный таргет: subtitle/foot имеют explicit классы и должны
   сохранить свои margin'ы (24px снизу у subtitle, 18px сверху у foot). */
.ds-final-cta__form-card p:not([class]) {
  font-size: inherit;
  color: var(--ds-text-secondary);
  max-width: none;
  margin: 0;
  line-height: inherit;
}
/* Двойной class-selector (.form-card .form-subtitle и т.д.) повышает specificity
   до 0,2,0 — выше чем .ds-final-cta p (0,1,1), чтобы перекрыть его font/color/
   margin/max-width глобальные правила для левой колонки. */
.ds-final-cta__form-card .ds-final-cta__form-title {
  color: var(--ds-text-primary);
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0 0 6px;
  max-width: none;
  line-height: 1.3;
}
.ds-final-cta__form-card .ds-final-cta__form-subtitle {
  color: var(--ds-text-secondary);
  font-size: 14px;
  margin: 0 0 24px;
  max-width: none;
  line-height: 1.4;
}
.ds-final-cta__form-card .ds-final-cta__form-foot {
  text-align: center;
  font-size: 14px;
  color: var(--ds-text-secondary);
  margin: 18px 0 0;
  max-width: none;
  line-height: 1.4;
}
.ds-final-cta__form-foot a {
  color: var(--ds-brand);
  text-decoration: none;
}
.ds-final-cta__form-foot a:hover,
.ds-final-cta__form-foot a:focus-visible {
  text-decoration: underline;
  outline: none;
}

/* Eyebrow label поверх dark final-cta — синий accent вместо тёмного brand */
.ds-final-cta .ds-chapter-label { color: #4eb6ff; }

/* Heading в левой колонке final-cta — выровнен по левому краю */
.ds-final-cta__heading {
  text-align: left;
  margin-bottom: 28px;
}

/* ---------- 9. Subtle entry reveals (для всех секций) ---------- */
.ds-reveal-up {
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 0.9s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}
.ds-reveal-up.is-in { opacity: 1; transform: translateY(0); }

.ds-reveal-scale {
  opacity: 0;
  transform: scale(0.96);
  transition: opacity 0.9s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}
.ds-reveal-scale.is-in { opacity: 1; transform: scale(1); }

/* Card 3D-tilt (запускается на hover, без JS).
   PERF: убраны статические will-change и transform-style: preserve-3d —
   они держали ~10 GPU layers постоянно на feedbacks/launch-steps/trial.
   will-change на :hover не ставим: это анти-паттерн — браузер не успевает
   подготовить композитный layer (hint прилетает уже когда transition стартовал).
   Для transform: translate + rotate браузер промотит layer самостоятельно
   на время transition'а — current Chromium/Safari умеют это. */
.ds-card-tilt {
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1),
              box-shadow 0.5s ease;
}
.ds-card-tilt:hover {
  transform: translateY(-4px) perspective(1000px) rotateX(2deg);
  box-shadow: 0 24px 50px rgba(15, 33, 76, 0.12);
}

/* Spring-press для тогглов — теперь реализовано через Web Animations API
   в home-motion.js initSpring(). Composite: 'add' добавляет scale-колебание
   ПОВЕРХ inline transform от magnetic JS (а не заменяет его) — это убирает
   видимый «дёрг» при возврате к magnetic-тилту в конце анимации. CSS
   @keyframes тут больше не нужен. */

/* ---------- 9c. Launch steps — точечный фон-декорация ----------
   Раньше жил inline `<style>` в launch_steps.html, что нарушало DS-first
   принцип. */
.launch-steps-dot {
  position: relative;
}
.launch-steps-dot::before {
  content: '';
  position: absolute;
  top: 24px;
  right: 24px;
  width: 120px;
  height: 120px;
  background-image: radial-gradient(circle, #d0d0d8 1px, transparent 1px);
  background-size: 12px 12px;
  opacity: 0.5;
  pointer-events: none;
}

/* ---------- 10. Reduced motion — отключить всё ---------- */
@media (prefers-reduced-motion: reduce) {
  .ds-mesh-bg::before,
  .ds-mesh-bg::after,
  .ds-hero-eyebrow__dot::after,
  .ds-marquee__track {
    animation: none !important;
  }
  .ds-word,
  .ds-subhead-elevated,
  .ds-cta-row,
  .ds-hero-hint,
  .ds-hero-stage-frame,
  .ds-step-elevated,
  .ds-reveal-up,
  .ds-reveal-scale {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
    animation: none !important;
  }
  .ds-hero-chip {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }
  .ds-card-tilt:hover {
    transform: translateY(-2px) !important;
  }
  .ds-tab-panel-fade {
    transition: opacity 0.15s linear !important;
    filter: none !important;
    transform: none !important;
  }
  /* Spring-press теперь WAAPI — отключение в JS через matchMedia,
     CSS-override не нужен. */
  /* Кнопочные микро-анимации тоже глушим — оставляем только смену цвета.
     .ds-btn-magnetic reduce-motion перенесён в atoms-btn-magnetic.css. */
  .ds-btn-cta,
  .ds-btn-cta > span,
  .ds-btn-pill,
  .ds-faq-question::after {
    transition: background 0.15s linear, color 0.15s linear !important;
  }
  .ds-btn-cta:hover,
  .ds-btn-cta:active,
  .ds-btn-cta:hover > span,
  .ds-btn-pill:hover,
  .ds-btn-pill:active,
  .ds-faq-question[aria-expanded="true"]::after {
    transform: none !important;
    filter: none !important;
  }
}
