/* ==========================================================================
   KOPYTKO — _motion.css
   Мотион-слой. D22 (сдержанный мотион, без 3D/WebGL/canvas/частиц),
   D29 (облик эталона неприкосновенен), D28 п.2 (no-js-гард).
   Анимируются ТОЛЬКО opacity и transform.

   Подключается ПОСЛЕДНИМ в каскаде (inc/assets.php): блок
   prefers-reduced-motion внизу файла должен перебивать компоненты.
   Ни одного цветового литерала и ни одного font-family в этом файле.
   Источник: animation-motion-map.md §3 и §7.2 + performance-accessibility-map.md §8.2.
   ========================================================================== */

/* --------------------------------------------------------------------------
   3.1. Токены длительностей и кривых. Значения взяты из эталона,
   а не назначены заново.
   -------------------------------------------------------------------------- */
:root {
  --mo-fast:  200ms;                          /* эталон: .btn            */
  --mo-base:  250ms;                          /* эталон: .card/.sys-cell */
  --mo-slow:  700ms;                          /* эталон: .reveal         */
  --mo-wipe:  900ms;                          /* мотив «7 радикалов»     */
  --mo-count: 1200ms;                         /* счётчики, D22 «≤1,2 с»  */
  --mo-step:  60ms;                           /* шаг stagger             */
  --mo-ease:  ease;                           /* эталон                  */
  --mo-out:   cubic-bezier(.22, .61, .36, 1); /* затухание без пружины   */
}

/* --------------------------------------------------------------------------
   3.2. M-01 — reveal + 🔴 no-js-гард (D28 п.2).
   Базовое состояние — ВИДИМОЕ. Скрытие включается только когда JS
   подтвердил работу классом .js на <html>. Без JS страница читаема целиком.
   -------------------------------------------------------------------------- */
.reveal {
  opacity: 1;
  transform: none;
}

.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity   var(--mo-slow) var(--mo-ease),
    transform var(--mo-slow) var(--mo-ease);
}

.js .reveal.in {
  opacity: 1;
  transform: none;
}

/* ⛔ will-change на .reveal НЕ ставится намеренно: 19 элементов на главной
   получили бы 19 композиторских слоёв заранее. Переходы opacity/transform
   промоутируются автоматически на время самого перехода. */

/* --------------------------------------------------------------------------
   3.3. M-02 / M-11 — stagger внутри группы.
   Индекс печатает PHP в атрибут style: style="--rv-i:3".
   Потолок 7 шагов => максимум 420 мс. Стоимость JS — 0 байт.
   -------------------------------------------------------------------------- */
.js [data-reveal-group] > .reveal,
.js [data-reveal-group] .reveal {
  transition-delay: calc(min(var(--rv-i, 0), 7) * var(--mo-step));
}

.js [data-reveal-group] .reveal:not(.in) {
  transition-delay: calc(min(var(--rv-i, 0), 7) * var(--mo-step));
}

/* --------------------------------------------------------------------------
   3.4. M-12 — номер радикала проступает на 120 мс позже своей ячейки.
   Цвет номера НЕ трогаем (D29): «подсветка» = появление, а не смена оттенка.
   -------------------------------------------------------------------------- */
.js .sys-cell .n {
  opacity: 0;
  transition: opacity var(--mo-slow) var(--mo-ease);
  transition-delay: calc(min(var(--rv-i, 0), 7) * var(--mo-step) + 120ms);
}

.js .sys-cell.in .n {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   3.5. M-03 — подчёркивание в меню.
   Облик 1:1 с эталоном: линия 1.5px растёт слева направо. Отличие только
   в анимируемом свойстве: width -> transform:scaleX (композитор вместо layout).
   -------------------------------------------------------------------------- */
.menu a::after {
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--mo-base) var(--mo-ease);
}

.menu a:hover::after,
.menu a:focus-visible::after {
  width: 100%;
  transform: scaleX(1);
}

/* --------------------------------------------------------------------------
   3.6. M-04 / M-07 — сужение списка анимируемых свойств.
   В эталоне стоит `transition: .25s ease`, то есть `all`. Облик не меняется —
   меняется список кандидатов на анимацию.
   -------------------------------------------------------------------------- */
.card {
  transition:
    transform    var(--mo-base) var(--mo-ease),
    border-color var(--mo-base) var(--mo-ease);
}

.btn {
  transition:
    background-color var(--mo-fast) var(--mo-ease),
    border-color     var(--mo-fast) var(--mo-ease),
    color            var(--mo-fast) var(--mo-ease);
}

/* Клавиатурный паритет: что работает по наведению — работает и по фокусу. */
.card:focus-within {
  transform: translateY(-3px);
}

/* --------------------------------------------------------------------------
   3.7. M-08 — счётчики. Ширину резервирует JS; тут только контейнер.
   ⛔ font-variant-numeric: tabular-nums НЕ применяется: меняет рисунок цифр (D29).
   -------------------------------------------------------------------------- */
.stat-num {
  display: inline-block;
  text-align: left;
}

/* --------------------------------------------------------------------------
   3.8. M-09 — параллакс фона цитаты. Смещение задаёт JS inline-transform.
   Запас по высоте обязателен: без него сдвинутый фон обнажит край секции.
   -------------------------------------------------------------------------- */
.js [data-parallax] .quote-bg {
  will-change: transform;
  height: 112%;          /* 100% + 2 x 6% хода */
  top: -6%;
}

/* --------------------------------------------------------------------------
   3.9. M-10 — мотив «7 радикалов»: прорисовка заслонкой.
   Ассет растровый, поэтому stroke-dasharray неприменим.
   ⛔ Ни canvas, ни WebGL, ни частиц (D22).
   -------------------------------------------------------------------------- */
.motif {
  position: relative;
  overflow: hidden;
}

.motif img {
  display: block;
  width: 100%;
  height: auto;
}

/* Без JS заслонки не существует вовсе — картинка видна сразу. */
.motif__shutter {
  display: none;
}

.js .motif__shutter {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 1;
  transform: translateX(0);
  transition: transform var(--mo-wipe) var(--mo-out);
  pointer-events: none;
}

.js .motif.is-drawn .motif__shutter {
  transform: translateX(101%);
}

/* Цвет заслонки = цвет секции. Только существующие токены эталона (D29). */
.motif--on-green      .motif__shutter { background: var(--green); }
.motif--on-green-deep .motif__shutter { background: var(--green-deep); }
.motif--on-paper      .motif__shutter { background: var(--paper); }
.motif--on-paper-2    .motif__shutter { background: var(--paper-2); }

/* --------------------------------------------------------------------------
   3.10. M-13 — анти-движение выключенной кнопки.
   Реакция на наведение = обещание. Выключенная кнопка ничего не обещает.
   -------------------------------------------------------------------------- */
.btn.is-disabled {
  transition: none;
}

.btn.is-disabled:hover,
.btn.is-disabled:focus,
.btn.is-disabled:focus-visible,
.btn.is-disabled:active {
  transform: none;
}

.card.is-disabled:hover,
.card.is-disabled:focus-within {
  transform: none;
}

/* ==========================================================================
   7.2. prefers-reduced-motion — обязателен (D22).
   Покрывает весь каталог движений. Ставится ПОСЛЕДНИМ во всей цепочке.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {

  /* 1. Глобальный предохранитель + плавная прокрутка.
        0.01ms, а не 0s, — чтобы transitionend/animationend всё-таки
        выстрелили и код, который их ждёт, не завис навсегда. */
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
  }

  html { scroll-behavior: auto !important; }

  /* 2. M-01 reveal. КРИТИЧНО: без этого правила пользователь с включённым
        reduce и «залипшим» JS остаётся на пустой странице. */
  .reveal,
  .reveal.in,
  .js .reveal,
  .js .reveal.in {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }

  /* 3. M-02 / M-11 — каскад: все элементы группы появляются одновременно. */
  .js [data-reveal-group] > .reveal,
  .js [data-reveal-group] .reveal,
  .js .sys-cell,
  .js .radical {
    transition-delay: 0s !important;
  }

  /* 4. M-08 счётчики: контейнер не резервирует ширину и не считает.
        Финальное число уже стоит в разметке. */
  .stat-num {
    min-width: 0 !important;
  }

  /* 5. M-04 карточка: убираем СМЕЩЕНИЕ, оставляем цветовую обратную связь. */
  .card,
  .card:hover,
  .card:focus-within {
    transform: none !important;
  }

  .card:hover { border-color: var(--brass); }

  /* 6. M-03 подчёркивание меню: появляется сразу, без роста слева направо. */
  .menu a::after {
    transition: none !important;
  }
  .menu a:hover::after,
  .menu a:focus-visible::after {
    transform: scaleX(1) !important;
  }

  /* 7. M-09 параллакс: фон стоит на месте. Дублирует ранний выход в JS. */
  .quote-bg,
  .js [data-parallax] .quote-bg {
    transform: none !important;
    will-change: auto !important;
  }

  /* 8. M-10 мотив: заслонка мгновенно уходит, мотив виден целиком. */
  .js .motif__shutter {
    transform: translateX(101%) !important;
    transition: none !important;
  }

  /* 9. M-12 номера радикалов: видны сразу. */
  .js .sys-cell .n,
  .js .sys-cell.in .n {
    opacity: 1 !important;
    transition: none !important;
  }

  /* 10. Мобильное меню — без выезда. */
  .mobile-nav { transition: none !important; }

  /* 11. 🔴 M-14 ФОКУС НЕ ТРОГАЕМ НИКОГДА.
         Явно возвращаем ему право на мгновенную отрисовку, чтобы
         предохранитель из п. 1 его не задел. Цвет — токен эталона. */
  :focus-visible {
    outline: 3px solid var(--brass) !important;
    outline-offset: 3px !important;
    transition: none !important;
  }
  .hero :focus-visible,
  .system :focus-visible,
  .quote :focus-visible,
  .final :focus-visible,
  .site-footer :focus-visible {
    outline-color: var(--brass-soft) !important;
  }
}
