/* ════════════════════════════════════════════════════════════════════
   Библиотека движения. Два слоя:

   1. Появление при скролле — [data-reveal], класс .is-revealed вешает
      js/modules/reveal.js. Ничего не «прыгает» до входа в кадр.
   2. Живые детали — бесконечные декоративные циклы (.ms-*), перенесённые
      из макета. Это витрина продукта: эфир должен выглядеть живым.

   Все длительности умножаются на --motion. При prefers-reduced-motion
   он равен нулю — анимации схлопываются в конечное состояние, а не
   мигают ускоренно. Одна точка выключения на весь сайт.
   ════════════════════════════════════════════════════════════════════ */

/* ── 1. Появление при скролле ──────────────────────────────────────── */

[data-reveal] {
  opacity: 0;
  transform: translate3d(var(--reveal-x, 0), var(--reveal-y, 22px), 0)
             scale(var(--reveal-s, 1));
  transition:
    opacity var(--t-slow) var(--ease-out) var(--reveal-delay, 0s),
    transform var(--t-slow) var(--ease-out) var(--reveal-delay, 0s),
    filter var(--t-slow) var(--ease-out) var(--reveal-delay, 0s);
  will-change: opacity, transform;
}

[data-reveal="left"]  { --reveal-x: -28px; --reveal-y: 0; }
[data-reveal="right"] { --reveal-x: 28px;  --reveal-y: 0; }
[data-reveal="scale"] { --reveal-y: 12px;  --reveal-s: 0.96; }
[data-reveal="fade"]  { --reveal-y: 0; }
[data-reveal="blur"]  { --reveal-y: 14px; filter: blur(10px); }

[data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  filter: none;
  will-change: auto;
}

/* Появление по буквам/словам для заголовков — элементы готовит JS. */
.reveal-word {
  display: inline-block;
  opacity: 0;
  transform: translate3d(0, 0.5em, 0);
  transition:
    opacity 0.7s var(--ease-out) var(--reveal-delay, 0s),
    transform 0.7s var(--ease-out) var(--reveal-delay, 0s);
}
.is-revealed .reveal-word { opacity: 1; transform: none; }

/* ── 2. Живые детали ───────────────────────────────────────────────── */

@keyframes ms-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
.ms-live       { animation: ms-pulse calc(1.8s * var(--motion)) ease-in-out infinite; }
.ms-pulse-slow { animation: ms-pulse calc(3.2s * var(--motion)) ease-in-out infinite; }

@keyframes ms-blink { 0%, 45% { opacity: 1; } 55%, 100% { opacity: 0.2; } }
.ms-blink { animation: ms-blink calc(1.4s * var(--motion)) steps(1, end) infinite; }

@keyframes ms-nudge {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(4px); }
}
.ms-nudge { animation: ms-nudge calc(1.6s * var(--motion)) ease-in-out infinite; }

@keyframes ms-spin { to { transform: rotate(360deg); } }
.ms-spin { animation: ms-spin calc(9s * var(--motion)) linear infinite; }

@keyframes ms-drift { from { background-position: 0 0; } to { background-position: 28px 28px; } }
.ms-drift { animation: ms-drift calc(14s * var(--motion)) linear infinite; }

@keyframes ms-breathe { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } }
.ms-breathe { animation: ms-breathe calc(7s * var(--motion)) ease-in-out infinite; }

/* Горизонтальный «пролёт» блика по поверхности. */
.ms-shine { position: relative; overflow: hidden; }
.ms-shine::after {
  content: '';
  position: absolute;
  inset: -20% auto;
  left: -30%;
  width: 26%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.45), transparent);
  transform: skewX(-20deg);
  animation: ms-shine calc(4.5s * var(--motion)) ease-in-out infinite;
  pointer-events: none;
}
@keyframes ms-shine { 0%, 60% { left: -30%; } 100% { left: 130%; } }

/* Пульсирующее кольцо вокруг точки — «сигнал пошёл». */
@keyframes ms-ping {
  0%   { transform: scale(1); opacity: 0.9; }
  100% { transform: scale(3.4); opacity: 0; }
}
.ms-ping { animation: ms-ping calc(2.4s * var(--motion)) ease-out infinite; }

@keyframes ms-pulse-ring {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--c-accent) 55%, transparent); }
  70%  { box-shadow: 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.ms-pulse-ring { animation: ms-pulse-ring calc(2.4s * var(--motion)) ease-out infinite; }

@keyframes ms-glow {
  0%, 100% {
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--c-accent) 20%, transparent),
                0 30px 60px -30px color-mix(in srgb, var(--c-accent) 30%, transparent);
  }
  50% {
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--c-accent) 50%, transparent),
                0 30px 80px -24px color-mix(in srgb, var(--c-accent) 60%, transparent);
  }
}
.ms-glow { animation: ms-glow calc(4s * var(--motion)) ease-in-out infinite; }

@keyframes ms-breathe2 {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  50%      { box-shadow: 0 0 28px -6px color-mix(in srgb, var(--c-accent-2) 45%, transparent); }
}
.ms-breathe2 { animation: ms-breathe2 calc(4s * var(--motion)) ease-in-out infinite; }

/* Пунктир, бегущий по линии связи. */
@keyframes ms-dash { to { stroke-dashoffset: -24; } }
.ms-dash { animation: ms-dash calc(1.2s * var(--motion)) linear infinite; }

/* Отрисовка галочки/линии по мере прохода кадра. */
@keyframes ms-draw {
  0%   { stroke-dashoffset: 24; opacity: 0; }
  4%   { opacity: 1; }
  22%  { stroke-dashoffset: 0; }
  88%  { stroke-dashoffset: 0; opacity: 1; }
  100% { stroke-dashoffset: 0; opacity: 0; }
}
.ms-draw { animation: ms-draw calc(6s * var(--motion)) ease-out infinite; }

/* Полоса сигнала, пробегающая слева направо и замирающая. */
@keyframes ms-signal {
  0%   { transform: translateX(-100%); }
  25%  { transform: translateX(100%); }
  100% { transform: translateX(100%); }
}
.ms-signal { animation: ms-signal calc(8s * var(--motion)) linear infinite; }

/* ── Детали внутри «телевизора» ────────────────────────────────────── */

/* Строчная развёртка и виньетка — статичные текстуры, не анимации. */
.ms-scan {
  background-image: repeating-linear-gradient(
    0deg, rgba(255, 255, 255, 0.03) 0 1px, transparent 1px 3px);
  pointer-events: none;
}
.ms-vignette {
  background: radial-gradient(ellipse 80% 70% at 50% 50%, transparent 55%, rgba(0, 0, 0, 0.55) 100%);
  pointer-events: none;
}

/* Луч сканирования и «шагающая» рамка распознавания живут в hero.css:
   в макете они заданы в пикселях под ширину 1440, а на текучем экране
   им нужны проценты и размеры конкретного кадра. Общей версии здесь
   нет намеренно — она была бы мёртвым кодом. */

/* Всплывающее окно звонка поверх эфира. */
@keyframes ms-pip {
  0%, 6%    { transform: translateY(140%); opacity: 0; }
  14%, 80%  { transform: translateY(0); opacity: 1; }
  90%, 100% { transform: translateY(140%); opacity: 0; }
}
.ms-pip { animation: ms-pip calc(12s * var(--motion)) ease-in-out infinite; }

/* Подсветка кадра в момент срабатывания детектора. */
@keyframes ms-frame {
  0%, 100% { filter: brightness(1); }
  8%, 16%  { filter: brightness(1.9); }
}
.ms-frame { animation: ms-frame calc(6s * var(--motion)) linear infinite; }

@keyframes ms-playhead { from { left: 0; } to { left: calc(100% - 2px); } }
.ms-playhead { animation: ms-playhead calc(6s * var(--motion)) linear infinite; }

/* Чип метки, вспыхивающий акцентом раз в цикл. */
@keyframes ms-chip {
  0%, 100% { border-color: var(--c-line); color: var(--c-text); }
  8%, 14%  { border-color: var(--c-accent); color: var(--c-accent); }
}
.ms-chip { animation: ms-chip calc(6s * var(--motion)) ease-in-out infinite; }

@keyframes ms-hop {
  0%, 100% { background-color: color-mix(in srgb, var(--c-accent) 8%, transparent); }
  10%, 22% { background-color: color-mix(in srgb, var(--c-accent) 48%, transparent); }
}
.ms-hop { animation: ms-hop calc(5s * var(--motion)) ease-in-out infinite; }

@keyframes ms-detect {
  0%, 100% {
    border-color: var(--c-line);
    color: var(--c-text);
    box-shadow: 0 0 0 0 transparent;
  }
  10%, 22% {
    border-color: var(--c-accent-2);
    color: var(--c-accent-2);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent-2) 18%, transparent);
  }
}
.ms-detect { animation: ms-detect calc(4s * var(--motion)) ease-in-out infinite; }

/* Набор поискового запроса и всплывающий под ним результат. */
@keyframes ms-type {
  0%   { max-width: 0; animation-timing-function: steps(22, end); }
  30%  { max-width: 190px; }
  100% { max-width: 190px; }
}
.ms-type { animation: ms-type calc(9s * var(--motion)) infinite; }

@keyframes ms-result {
  0%, 34%  { opacity: 0; transform: translateY(6px); }
  42%, 92% { opacity: 1; transform: none; }
  100%     { opacity: 0; transform: translateY(6px); }
}
.ms-result { animation: ms-result calc(9s * var(--motion)) ease-in-out infinite; }

/* Переключатель Ghost Mode: две пары «трек + ручка» в противофазе. */
@keyframes ms-track-a {
  0%, 40%   { background: var(--c-line); }
  60%, 100% { background: var(--c-accent); }
}
@keyframes ms-knob-a {
  0%, 40%   { left: 2px; background: var(--c-dim); }
  60%, 100% { left: 16px; background: var(--c-bg); }
}
@keyframes ms-track-b {
  0%, 40%   { background: var(--c-accent); }
  60%, 100% { background: var(--c-line); }
}
@keyframes ms-knob-b {
  0%, 40%   { left: 16px; background: var(--c-bg); }
  60%, 100% { left: 2px; background: var(--c-dim); }
}
@keyframes ms-lbl-a { 0%, 40% { color: var(--c-muted); } 60%, 100% { color: var(--c-text); } }
@keyframes ms-lbl-b { 0%, 40% { color: var(--c-text); } 60%, 100% { color: var(--c-muted); } }

.ms-track-a { animation: ms-track-a calc(5s * var(--motion)) ease-in-out infinite alternate; }
.ms-knob-a  { animation: ms-knob-a  calc(5s * var(--motion)) ease-in-out infinite alternate; }
.ms-track-b { animation: ms-track-b calc(5s * var(--motion)) ease-in-out infinite alternate; }
.ms-knob-b  { animation: ms-knob-b  calc(5s * var(--motion)) ease-in-out infinite alternate; }
.ms-lbl-a   { animation: ms-lbl-a   calc(5s * var(--motion)) ease-in-out infinite alternate; }
.ms-lbl-b   { animation: ms-lbl-b   calc(5s * var(--motion)) ease-in-out infinite alternate; }

/* ── Утилиты задержки ──────────────────────────────────────────────── */
/* Сдвигают фазу цикла, чтобы соседние элементы не пульсировали в такт. */
.d-1 { animation-delay: calc(0.4s * var(--motion)); }
.d-2 { animation-delay: calc(0.9s * var(--motion)); }
.d-3 { animation-delay: calc(1.5s * var(--motion)); }
.d-4 { animation-delay: calc(2.2s * var(--motion)); }
.d-5 { animation-delay: calc(3.1s * var(--motion)); }

/* ── Доступность ───────────────────────────────────────────────────── */
/* --motion: 0 схлопывает все calc()-длительности в ноль: элемент сразу
   в конечном состоянии, без мигания. transition-ы гасим отдельно —
   их длительности заданы токенами, а не через --motion. */
@media (prefers-reduced-motion: reduce) {
  :root { --motion: 0; }
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  [data-reveal] { opacity: 1; transform: none; filter: none; }
  .reveal-word  { opacity: 1; transform: none; }
}
