/* =========================================================================
   Анимации: «дорогие» переходы, появления, микровзаимодействия
   ========================================================================= */

/* ---- Появление страниц (View Transitions API) ---- */
@keyframes vt-fade-in {
  from { opacity: 0; transform: translateY(10px) scale(0.992); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes vt-fade-out {
  from { opacity: 1; transform: translateY(0) scale(1); }
  to   { opacity: 0; transform: translateY(-8px) scale(0.996); }
}

::view-transition-old(root) {
  animation: vt-fade-out var(--dur-3) var(--ease-out-quint) both;
}
::view-transition-new(root) {
  animation: vt-fade-in var(--dur-4) var(--ease-out-expo) both;
}

/* Откат, если View Transitions не поддерживается: класс на #main */
.page-enter {
  animation: pageEnter var(--dur-4) var(--ease-out-expo) both;
}
@keyframes pageEnter {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- Reveal on scroll (data-reveal) ----
   ВАЖНО для SEO/доступности: контент НЕ прячется по умолчанию. Скрываем только
   когда работает JS (класс .js на <html>) — тогда поисковые роботы и пользователи
   без JS видят весь контент сразу, а с JS получают плавное появление. */
.js [data-reveal]:not(.is-visible) {
  opacity: 0;
  transform: translateY(22px);
  will-change: opacity, transform;
}
[data-reveal] {
  transition:
    opacity var(--dur-5) var(--ease-out-expo),
    transform var(--dur-5) var(--ease-out-expo);
  transition-delay: var(--reveal-delay, 0ms);
}
.js [data-reveal="left"]:not(.is-visible)  { transform: translateX(-26px); }
.js [data-reveal="right"]:not(.is-visible) { transform: translateX(26px); }
.js [data-reveal="scale"]:not(.is-visible) { transform: scale(0.94); }
[data-reveal].is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  .page-enter { animation: none; }
}

/* ---- Универсальные keyframes ---- */
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes fadeInDown {
  from { opacity: 0; transform: translateY(-16px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes scaleIn {
  from { opacity: 0; transform: scale(0.9); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes popIn {
  0%   { opacity: 0; transform: scale(0.8); }
  60%  { transform: scale(1.04); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes slideInRight {
  from { opacity: 0; transform: translateX(40px); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes slideInLeft {
  from { opacity: 0; transform: translateX(-40px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* ---- Мерцание скелетонов ---- */
@keyframes shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

/* ---- Пульс/дыхание ---- */
@keyframes breathe {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.05); opacity: 0.85; }
}
@keyframes pulseRing {
  0%   { box-shadow: 0 0 0 0 var(--c-ring); }
  70%  { box-shadow: 0 0 0 12px rgba(46, 125, 79, 0); }
  100% { box-shadow: 0 0 0 0 rgba(46, 125, 79, 0); }
}

/* ---- Вращение (спиннер) ---- */
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- Плавающий градиентный фон героя ---- */
@keyframes meshFloat {
  0%   { transform: translate(0, 0) scale(1); }
  33%  { transform: translate(2%, -3%) scale(1.06); }
  66%  { transform: translate(-3%, 2%) scale(0.97); }
  100% { transform: translate(0, 0) scale(1); }
}

/* ---- Рост ветви дерева (анимация линий связей) ---- */
@keyframes drawLine {
  from { stroke-dashoffset: var(--len, 600); }
  to   { stroke-dashoffset: 0; }
}
/* ВАЖНО: на узлах дерева позиция задаётся SVG-атрибутом transform="translate(...)".
   CSS-анимация transform перебила бы её и собрала бы все узлы в точке (0,0),
   поэтому при появлении анимируем только прозрачность. */
@keyframes nodeGrow {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ---- Перелив градиента (для акцентного текста) ---- */
@keyframes gradientPan {
  0% { background-position: 0% center; }
  100% { background-position: -220% center; }
}

/* ---- Бегущий блик по кнопке (sheen) ---- */
@keyframes sheen {
  0%   { transform: translateX(-130%) skewX(-18deg); }
  100% { transform: translateX(360%) skewX(-18deg); }
}

/* ---- Утилитарные классы анимаций ---- */
.anim-fade-in   { animation: fadeIn var(--dur-4) var(--ease-soft) both; }
.anim-fade-up   { animation: fadeInUp var(--dur-4) var(--ease-out-expo) both; }
.anim-scale-in  { animation: scaleIn var(--dur-3) var(--ease-spring) both; }
.anim-pop       { animation: popIn var(--dur-3) var(--ease-spring) both; }
.anim-slide-r   { animation: slideInRight var(--dur-4) var(--ease-out-expo) both; }

/* Каскад (stagger) для списков: задаётся --i на элементе */
.stagger > * {
  animation: fadeInUp var(--dur-4) var(--ease-out-expo) both;
  animation-delay: calc(var(--i, 0) * 55ms);
}

@media (prefers-reduced-motion: reduce) {
  .anim-fade-in, .anim-fade-up, .anim-scale-in, .anim-pop, .anim-slide-r,
  .stagger > * { animation: none !important; }
}
