/* ==========================================================================
   ДНК — дополнительный слой анимаций.
   Отбор эффектов по видео-референсу IMG_3944.MP4 (см. claude/animation-reference.md).

   ВАЖНО: файл ничего не переопределяет в css/styles.css «вслепую» — он только
   ДОБАВЛЯЕТ свойства поверх. Подключается ПОСЛЕ styles.css.

   ОТКАТ: удалить в index.html две строки —
     <link rel="stylesheet" href="css/animations.css">
     <script src="js/animations.js" defer></script>
   Вёрстка вернётся в исходное состояние, других правок в проекте нет.
   Полные копии исходных файлов лежат в _backup/2026-07-27-before-anim/.

   Что внутри:
     1. Счётчик 90/10/5 от нуля
     2. Прорисовка мазка-перечёркивания «ДОСТАЕТСЯ» слева направо
     3. Световой блик (light sweep) по панели формы — один прогон
     4. «Дыхание» молекул: медленный scale ±2.5 %, только пока элемент во вьюпорте
     5. Ховеры карточек статистики и пунктов аккордеона
   ========================================================================== */

/* Все эффекты включаются только при наличии JS (класс .js на <html>) */

/* =========================================================================
   1. СТАТИСТИКА — счётчик
   ========================================================================= */
/* Последовательная подсветка карточек лаймом (как в референсе) была здесь,
   но снята по решению заказчика 2026-07-27: остаётся только счёт от нуля. */
/* Карточке нужен собственный transition — в styles.css его нет.
   ВАЖНО: transition — шорткат, он затирает правило `.js .reveal`, поэтому
   opacity/transform обязаны быть перечислены здесь с ИСХОДНЫМИ .7s ease,
   иначе появление карточек поедет по таймингу. Подъём на ховере вынесен
   в отдельное свойство translate — чтобы не трогать transform у reveal. */
.js .stats__card{
  transition:opacity .7s ease, transform .7s ease,
             box-shadow .3s ease,
             translate .3s cubic-bezier(.4,0,.2,1);
}

/* JS разбивает «> 90» на префикс и число. Ширину числа резервируем по финальному
   значению, иначе пока счётчик идёт от 0 к 90 карточка «дышит» по ширине. */
.js .stats__num-val{
  display:inline-block;text-align:left;
  font-variant-numeric:tabular-nums;
}

/* =========================================================================
   2. МАЗОК «ДОСТАЕТСЯ» — прорисовка слева направо
   ========================================================================= */
/* Сам мазок (background-image на ::after) уже описан в styles.css.
   Здесь только прячем его по ширине и открываем, когда заголовок появился.
   Задержка .25s — чтобы мазок шёл ПОСЛЕ выезда самого заголовка (reveal .7s). */
.js .genetics__title .is-strike::after{
  clip-path:inset(0 100% 0 0);
  transition:clip-path .65s cubic-bezier(.22,.61,.36,1) .3s;
}
.js .genetics__title.is-visible .is-strike::after{
  clip-path:inset(0 0 0 0);
}

/* =========================================================================
   3. СВЕТОВОЙ БЛИК ПО ПАНЕЛИ ФОРМЫ
   ========================================================================= */
/* Элемент .fx-sweep создаётся из js/animations.js — в разметке его нет.
   z-index:1 и позиция сразу после .panel-bg в DOM: блик выше фона панели,
   но ниже шапки формы и самой формы (они идут позже и имеют z-index 1/2). */
.fx-sweep{
  position:absolute;inset:0;z-index:1;
  overflow:hidden;pointer-events:none;
  opacity:0;
  border-radius:inherit;   /* на мобилке панель — обычный скруглённый div */
}
/* Выше 900px панель — Subtract-форма с вырезом (SVG .panel-bg), поэтому блик
   обрезаем ровно по её контуру: иначе полоса засветит прозрачный вырез
   сверху-справа и будет виден прямоугольный край. Путь пересчитан из
   viewBox 1680x726 в доли бокса (clipPathUnits="objectBoundingBox"). */
@media (min-width:901px){
  .fx-sweep{clip-path:url(#dnkFormPanelClip);}
}
.fx-sweep::before{
  content:"";position:absolute;
  top:-60%;left:0;width:38%;height:220%;
  background:linear-gradient(90deg,
    rgba(255,255,255,0) 0%,
    rgba(255,255,255,.14) 38%,
    rgba(187,208,67,.26) 55%,
    rgba(255,255,255,0) 100%);
  filter:blur(22px);
  transform:rotate(16deg) translateX(-160%);
}
.fx-sweep.is-run{opacity:1;}
.fx-sweep.is-run::before{
  animation:dnk-sweep 1.35s cubic-bezier(.33,0,.2,1) forwards;
}
@keyframes dnk-sweep{
  from{transform:rotate(16deg) translateX(-160%);}
  to  {transform:rotate(16deg) translateX(420%);}
}

/* =========================================================================
   4. «ДЫХАНИЕ» МОЛЕКУЛ
   ========================================================================= */
/* Дешёвая замена морфингу блобов из референса. Анимируем отдельное свойство
   scale — оно не конфликтует ни с translate (параллакс), ни с transform:rotate()
   у большой гантели. Класс is-breathing вешает JS по IntersectionObserver,
   чтобы за кадром анимация не крутилась вхолостую. */
@keyframes dnk-breathe{
  0%,100%{scale:1;}
  50%    {scale:1.025;}
}
.js .mol.is-breathing{
  animation:dnk-breathe 17s ease-in-out infinite;
}
/* Разводим фазы, иначе все молекулы «дышат» синхронно и это заметно */
.js .mol--black-top.is-breathing    {animation-duration:21s;animation-delay:-2s;}
.js .mol--green-big.is-breathing    {animation-duration:15s;animation-delay:-7s;}
.js .mol--green-sm.is-breathing     {animation-duration:13s;animation-delay:-4s;}
.js .mol--black-left.is-breathing   {animation-duration:19s;animation-delay:-11s;}
.js .mol--ch-green.is-breathing     {animation-duration:16s;animation-delay:-5s;}
.js .mol--ch-black.is-breathing     {animation-duration:22s;animation-delay:-9s;}
.js .mol--gen-green.is-breathing    {animation-duration:18s;animation-delay:-3s;}
.js .mol--gen-black.is-breathing    {animation-duration:14s;animation-delay:-8s;}
/* У гантели амплитуда меньше: она самая крупная, на ней 2.5 % читаются грубо */
@keyframes dnk-breathe-soft{
  0%,100%{scale:1;}
  50%    {scale:1.012;}
}
.js .mol--gen-dumbbell.is-breathing{
  animation-name:dnk-breathe-soft;animation-duration:24s;animation-delay:-6s;
}

/* =========================================================================
   5. ХОВЕРЫ
   ========================================================================= */
/* Аккордеон: те же соображения, что и у карточек статистики. Плюс попутно
   чинится существующий нюанс — правило `.change__item{transition:...}`
   (специфичность 0,1,0) проигрывало `.js .reveal` (0,2,0), поэтому подсветка
   рамки на ховере срабатывала рывком. Здесь всё перечислено явно. */
.js .change__item{
  transition:opacity .7s ease, transform .7s ease,
             border-color .25s ease, background .25s ease,
             box-shadow .3s ease, translate .3s cubic-bezier(.4,0,.2,1);
}

/* Только для устройств с настоящим курсором: на тач-экранах :hover «залипает» */
@media (hover:hover) and (pointer:fine){
  .js .stats__card.reveal.is-visible:hover{
    translate:0 -6px;
    box-shadow:0 18px 44px rgba(0,0,0,.45), inset 0 0 0 1px rgba(187,208,67,.35);
  }
  .js .change__item.reveal.is-visible:hover{
    translate:0 -3px;
    box-shadow:0 0 34px rgba(187,208,67,.16);
  }
}

/* =========================================================================
   ДОСТУПНОСТЬ
   ========================================================================= */
@media (prefers-reduced-motion:reduce){
  .js .stats__card,
  .js .change__item{transition:none;}
  .js .genetics__title .is-strike::after{clip-path:none;transition:none;}
  .fx-sweep{display:none;}
  .js .mol.is-breathing{animation:none;scale:1;}
  @media (hover:hover) and (pointer:fine){
    .js .stats__card.reveal.is-visible:hover,
    .js .change__item.reveal.is-visible:hover{translate:none;}
  }
}
