/* Живой интерфейс (правка 502, паспорт docs/design/motion.md). Только токены длительностей и кривых из tokens.css,
   все движения 0,1–0,4 с. Скрытое начальное состояние (проявление блоков урока) включает motion.js классом m-on на <html>:
   без скрипта ничего не скрыто. ?anim=off (data-anim="off") и prefers-reduced-motion — движения нет, всё сразу видно. */

/* 1. Наведение — только на устройствах с мышью: приподнимается, тень, указатель. */
@media (hover: hover) and (pointer: fine) {
  .btn, .home-card, .hub-card, .guide-option, .oge-tile, .ex-num, .o19-options button, .chip-link, .guide-card[id^="guide-card-"],
  .guide-nav > button, .lesson-list a, .fb-chip {
    transition: transform var(--dur-hover) var(--ease-out), box-shadow var(--dur-hover) var(--ease-out), border-color var(--dur-hover) var(--ease-out),
      background-color var(--dur-hover) var(--ease-out);
  }
  .btn:not(:disabled):hover, a.home-card:hover, .hub-card:hover, .guide-option:not(:disabled):hover, .oge-tile:not([data-kind="none"]):hover,
  .ex-num:hover, .o19-options button:not(:disabled):hover, .lesson-list a:hover, .fb-chip:hover {
    transform: translateY(var(--lift)); box-shadow: var(--shadow-lift); cursor: pointer;
  }
  .chip-link:hover { transform: translateY(var(--lift)); }
}

/* 2. Нажатие — везде, и на телефоне: «вдавливается» и отпускается. */
.btn:not(:disabled):active, a.home-card:active, .hub-card:active, .guide-option:not(:disabled):active, .oge-tile:not([data-kind="none"]):active,
.ex-num:active, .o19-options button:not(:disabled):active, .guide-nav > button:active, .fb-chip:active, .fb-toggle:active {
  transform: translateY(1px) scale(var(--press-scale)); box-shadow: none; transition-duration: var(--dur-press);
}

/* 3. Блоки урока при прокрутке: проявляются и чуть поднимаются, один раз (motion.js). */
.m-on .m-reveal { opacity: 0; transform: translateY(12px); }
.m-on .m-reveal:has(input, textarea, select) { transform: none; }  /* 716: блок с полем ввода проявляется без сдвига — как в уроке алгебры (681) */
.m-on .m-reveal.m-in { opacity: 1; transform: none; transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out); }
.m-on .m-reveal.m-now { transition: none; }  /* переход по полосе блоков — сразу на месте (motion.js settle) */

/* 4. Реакции на ответ: верно — лёгкий отскок карточки; неверно — поле коротко вздрагивает (2–3 колебания). */
.m-bounce { animation: m-bounce var(--dur-base) var(--ease-back); }
.m-shake { animation: m-shake var(--dur-max) var(--ease-in-out); }
@keyframes m-bounce { 0% { transform: scale(1); } 45% { transform: scale(1.018); } 100% { transform: scale(1); } }
@keyframes m-shake { 0%, 100% { transform: translateX(0); } 20% { transform: translateX(-6px); } 40% { transform: translateX(5px); }
  60% { transform: translateX(-4px); } 80% { transform: translateX(2px); } }
/* Пифа меняет эмоцию: прежняя картинка растворяется поверх новой (motion.js кладёт её слоем m-fade-out). */
.hero-figure { position: relative; }
.m-fade-out { position: absolute; inset: 0; pointer-events: none; animation: m-fade-out var(--dur-base) var(--ease-out) forwards; }
@keyframes m-fade-out { to { opacity: 0; } }

/* 5. «Урок пройден» (правка 505): лёгкие частицы из середины итога разлетаются и гаснут за 1,2 с; не ловят касания. */
.guide-finish { position: relative; }
.m-party { position: absolute; left: 50%; top: 40%; width: 0; height: 0; pointer-events: none; }
.m-party i { position: absolute; left: -4px; top: -4px; width: 8px; height: 8px; border-radius: 2px; background: var(--accent); opacity: 0;
  --delay: 0s; animation: m-party var(--dur-party) var(--ease-out) var(--delay) forwards; }
.m-party i:nth-child(4n+1) { background: var(--sketch-hot); border-radius: 50%; }
.m-party i:nth-child(4n+2) { background: var(--sketch-ref); }
.m-party i:nth-child(4n+3) { background: var(--sketch-given); border-radius: 50%; }
.m-hop { animation: m-hop var(--dur-max) var(--ease-back) 2; }
@keyframes m-hop { 0%, 100% { transform: translateY(0); } 45% { transform: translateY(-10px); } }
@keyframes m-party { 0% { opacity: 1; transform: translate(0, 0) scale(0.6) rotate(0); }
  70% { opacity: 1; } 100% { opacity: 0; transform: translate(var(--dx), calc(var(--dy) + 30px)) scale(1) rotate(200deg); } }

/* 6. Правка 630: страница не грузится «плашмя» — блоки мягко появляются при открытии (--dur-base, следующие — с маленьким
   шагом), Пифа проявляется. Скрытое начальное состояние — только с классом m-js на <html> (его ставит theme.js в <head>, кроме
   «уменьшить движение» и ?anim=off): без скрипта всё видно. backwards — после появления действуют обычные стили (наведение). */
/* 716: появление блоков страницы (карточки, плашки, списки) ведёт набор приёмов по паспорту (web/motion/kit.js) — прежнего появления
   правилами CSS больше нет: два появления на одном блоке мешали друг другу и сдвигали блоки с полями ввода. */
.m-js .home-pifa .hero-figure { animation: m-appear var(--dur-base) var(--ease-out) backwards; }  /* Пифа главной появляется мягко (у .hero — своё появление, hero.css) */
@keyframes m-appear { from { opacity: 0; } }

/* Ручки: ?anim=off и «уменьшить движение» — никакого движения, всё видно сразу. */
html[data-anim="off"] *, html[data-anim="off"] *::before, html[data-anim="off"] *::after {
  animation: none !important; transition: none !important;
}
html[data-anim="off"] .m-reveal { opacity: 1 !important; transform: none !important; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .m-reveal { opacity: 1 !important; transform: none !important; }
}

/* Чертёж по шагам (правка 503, web/draw_steps.js): пока не пришёл GSAP, элементы шагов не видны (класс ставит скрипт,
   через 2,5 с без GSAP снимает); кнопки «▶ Проиграть ещё раз» и «Показать сразу» — 44 px. */
.ds-pending [data-step] { opacity: 0; }
.ds-controls { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-2) 0 0; }
.ds-controls .btn { min-height: var(--control-h); }
/* Движения (правка 504): пунктир между точкой и её образом — в конце движения. */
.mv-link { fill: none; stroke: var(--stage-muted); stroke-width: 1.5; stroke-dasharray: 5 5; }
/* Правки 713–715: блоки паспорта движения ждут своего появления прозрачными — пока на <html> стоит mp-wait (ставит
   web/motion_wait.js до первого кадра, снимает паспорт или страховка через 1,5 с). Здесь — блоки, которые есть в разметке
   с самого начала (главная и страница предмета); блоки, пришедшие с данными, набор прячет сам в кадр их появления. */
html.mp-wait #home-sl1 :is(.home-kicker, .home-h1, .home-lead, .home-cta, .home-fig), html.mp-wait #top .home-stab,
html.mp-wait #home .home-h2, html.mp-wait #subject-list .home-card, html.mp-wait #benefits .home-ben, html.mp-wait #how .home-example,
html.mp-wait #card-branches .card-title, html.mp-wait .subj-head h1, html.mp-wait .subj-tiles .subj-tile,
html.mp-wait .gdz-pifa, html.mp-wait .gdz-say, html.mp-wait .gdz-steps-list li, html.mp-wait main h1, html.mp-wait main .card-title, html.mp-wait main .card:not(:has(input, textarea, select)):not([data-motion=still]) { opacity: 0; }  /* 716: общие блоки остальных страниц; блок с полем ввода не прячется и не двигается */

/* Правка 714: набор приёмов (web/motion/kit.js). Слово заголовка — в маске: выезжает снизу, не вылезая за строку. */
.mk-w { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: .08em; margin-bottom: -.08em; }
.mk-w > i { display: inline-block; font-style: inherit; }
.mk-run { transition: none !important; }  /* блок двигает набор — свой переход (наведение) на это время выключен */
.mk-n { font: inherit; font-variant-numeric: tabular-nums; }
/* Полоса прокрутки: тонкая линия сверху, растёт вместе с прокруткой (приём progress). Без движения — не показывается. */
.mk-progress { position: fixed; left: 0; top: 0; z-index: 60; width: 100%; height: 3px; transform: scaleX(0); transform-origin: 0 50%; background: var(--accent); pointer-events: none; }
html[data-anim="off"] .mk-progress { display: none; }
@media (prefers-reduced-motion: reduce) { .mk-progress { display: none; } }
/* 3D-наклон с бликом (приём tilt, только мышь): блик идёт за курсором по --mx, --my. */
.mk-tilt { position: relative; transform-style: preserve-3d; }
.mk-tilt::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; transition: opacity var(--dur-base);
  background: radial-gradient(400px circle at var(--mx, 50%) var(--my, 50%), var(--mk-shine), transparent 40%); }
.mk-tilt:hover::after { opacity: 1; }
