/* ==========================================================================
   Слой премиум-эффектов поверх styles-v2.css
   --------------------------------------------------------------------------
   НЕ переопределяет токены и не трогает существующие правила styles-v2.css -
   только использует его переменные (--accent, --amber-soft, --bg-deep,
   --ink и т.д., они уже объявлены в :root и body.home) и точечно дополняет
   существующие классы (.btn, .card, .cta, .turn, .next-read a и т.п.).

   Подключается на странице ПОСЛЕ styles-v2.css:
       <link rel="stylesheet" href="/assets/effects.css?v=1">
       <script src="/assets/effects.js?v=1" defer></script>

   Элементы .effects-grain / .ef-count создаёт JS (assets/effects.js),
   здесь только стили. Классы .effects-spotlight и .effects-spotlight--active
   тоже навешивает JS - без JS эти правила просто не находят получателя.
   ========================================================================== */

/* ── 1. Film-grain оверлей: тонкая киношная зернистость, статична ── */
.effects-grain {
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: .035;
  mix-blend-mode: overlay;
  background-repeat: repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='ef-grain'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23ef-grain)'/%3E%3C/svg%3E");
}
/* JS уже не создаёт этот элемент при экономии трафика (saveData),
   но если он вдруг оказался в DOM - на всякий случай гасим и по медиа-фиче */
@media (prefers-reduced-data: reduce) {
  .effects-grain { display: none; }
}

/* ── 1b. Магическая пыль: жёлтые частицы дрейфуют по ВСЕЙ странице (главная,
   body.home), закреплены к окну (position:fixed) - продолжают лететь при
   прокрутке, не привязаны к одной секции (создаёт JS - assets/effects.js,
   addMagicDust). Чистый CSS-transform/opacity, компоузится на GPU - дёшево
   даже на слабом телефоне. Два направления (вверх/вниз) вперемешку. ── */
.dust {
  position: fixed; inset: 0; z-index: 30;
  pointer-events: none; overflow: hidden;
}
.dust span {
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle, #FFEFC4 0%, #F5C87A 55%, transparent 76%);
  box-shadow: 0 0 6px 1px rgba(245, 200, 122, .6);
  opacity: 0;
  animation-timing-function: linear, ease-in-out;
  animation-iteration-count: infinite, infinite;
  animation-direction: normal, alternate;
}
.dust span.up { top: 100%; animation-name: ef-dust-rise, ef-dust-sway; }
.dust span.down { top: -2%; animation-name: ef-dust-fall, ef-dust-sway; }
@keyframes ef-dust-rise {
  0%   { transform: translateY(0); opacity: 0; }
  10%  { opacity: var(--dust-o, .7); }
  88%  { opacity: var(--dust-o, .7); }
  100% { transform: translateY(-100vh); opacity: 0; }
}
@keyframes ef-dust-fall {
  0%   { transform: translateY(0); opacity: 0; }
  10%  { opacity: var(--dust-o, .7); }
  88%  { opacity: var(--dust-o, .7); }
  100% { transform: translateY(100vh); opacity: 0; }
}
@keyframes ef-dust-sway {
  from { margin-left: calc(var(--sway, 22px) * -1); }
  to   { margin-left: var(--sway, 22px); }
}
@media (prefers-reduced-motion: reduce) {
  .dust { display: none; }
}

/* ── 1c. Тёплая пыль для статей: тот же приём, но в цветах сайта (тил/терракот
   вместо золота - золото не видно на кремовом фоне разборов) и СКОЛЬКО в
   шапке статьи (position:absolute внутри .article, высота 620px, скроллится
   с текстом и уходит из виду) - не по всей длинной статье, чтение не
   отвлекает. Заметно реже и мельче, чем на главной - сдержанность вместо
   обилия (создаёт JS - addArticleDust). ── */
.article { position: relative; }
.dust-article {
  position: absolute; top: 0; left: 0; right: 0;
  height: 620px; overflow: hidden; z-index: 1; pointer-events: none;
}
.dust-article span {
  position: absolute; border-radius: 50%; opacity: 0;
  animation-timing-function: linear, ease-in-out;
  animation-iteration-count: infinite, infinite;
  animation-direction: normal, alternate;
}
.dust-article span.up { top: 100%; animation-name: ef-dust-rise, ef-dust-sway; }
.dust-article span.down { top: -2%; animation-name: ef-dust-fall, ef-dust-sway; }
.dust-article span.teal {
  background: radial-gradient(circle, #8FDDC7 0%, #2E7D6B 60%, transparent 78%);
  box-shadow: 0 0 5px 1px rgba(46, 125, 107, .4);
}
.dust-article span.amber {
  background: radial-gradient(circle, #F3C79A 0%, #B96C33 60%, transparent 78%);
  box-shadow: 0 0 5px 1px rgba(185, 108, 51, .4);
}
@media (prefers-reduced-motion: reduce) {
  .dust-article { display: none; }
}

/* ── 2. Reveal-on-scroll через IntersectionObserver (assets/effects.js):
   расширение паттерна .card из styles-v2.css на новые селекторы
   (сам .card здесь НЕ дублируется - образец, не цель) ── */
@media (prefers-reduced-motion: no-preference) {
  .js-reveal-ready .callout, .js-reveal-ready .turn, .js-reveal-ready .midcta,
  .js-reveal-ready .author, .js-reveal-ready .author-hero,
  .js-reveal-ready .ladder, .js-reveal-ready .meet, .js-reveal-ready .steps, .js-reveal-ready .trust {
    opacity: 0;
    transition: opacity .6s ease;
  }
  /* у .next-read a есть собственный hover-переход (translate/border-color/box-shadow,
     styles-v2.css) - transition здесь не должен его перебивать более высокой специфичностью,
     а translate у reveal здесь не трогаем вовсе (иначе .is-revealed забьёт hover-подъём) */
  .js-reveal-ready .next-read a {
    opacity: 0;
    transition: opacity .6s ease, translate .25s cubic-bezier(.2,.7,.3,1), border-color .25s, box-shadow .25s;
  }
  .js-reveal-ready .callout.is-revealed, .js-reveal-ready .turn.is-revealed,
  .js-reveal-ready .midcta.is-revealed, .js-reveal-ready .author.is-revealed,
  .js-reveal-ready .author-hero.is-revealed, .js-reveal-ready .next-read a.is-revealed,
  .js-reveal-ready .ladder.is-revealed, .js-reveal-ready .meet.is-revealed,
  .js-reveal-ready .steps.is-revealed, .js-reveal-ready .trust.is-revealed {
    opacity: 1;
  }
  /* лёгкий stagger для карточек «Что почитать дальше» через transition-delay */
  .js-reveal-ready .next-read .nr-list a:nth-child(1) { transition-delay: 0ms; }
  .js-reveal-ready .next-read .nr-list a:nth-child(2) { transition-delay: 90ms; }
  .js-reveal-ready .next-read .nr-list a:nth-child(3) { transition-delay: 180ms; }
}

/* ── 3. Kinetic gradient text (.kinetic) ── */
@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  .kinetic {
    display: inline-block;
    background: linear-gradient(90deg, var(--accent), var(--amber-soft), var(--accent));
    background-size: 200% auto;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  @media (prefers-reduced-motion: no-preference) {
    .kinetic { animation: ef-kinetic 6s ease-in-out infinite; }
    @keyframes ef-kinetic {
      0%   { background-position: 0% center; }
      50%  { background-position: 100% center; }
      100% { background-position: 0% center; }
    }
  }
}

/* ── 4. Spotlight cursor-glow (.effects-spotlight, JS вешает на контейнеры) ── */
.effects-spotlight { position: relative; }
.effects-spotlight::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity .4s;
  background: radial-gradient(320px circle at var(--mx,50%) var(--my,50%), rgba(255,255,255,.06), transparent 70%);
}
.effects-spotlight--active::before { opacity: 1; }
/* .cta и .turn в styles-v2.css не имеют position:relative - добавляем только им.
   .hero-photo/.band/.ladder/.trust/.meet/.steps либо уже позиционированы,
   либо не рискуют переполнением - overflow:hidden им не добавляем без нужды */
.cta.effects-spotlight, .turn.effects-spotlight {
  position: relative;
  overflow: hidden;
}
/* светлый вариант на случай, если spotlight понадобится на светлых карточках
   (.next-read a и т.п.) - по умолчанию JS его не навешивает, класс про запас */
.effects-spotlight--light::before {
  background: radial-gradient(320px circle at var(--mx,50%) var(--my,50%), rgba(0,0,0,.04), transparent 70%);
}

/* ── 5. Магнитные кнопки: только отзывчивый transition, JS ставит inline transform ── */
.btn {
  transition: transform .15s cubic-bezier(.2,.8,.2,1), background .25s, box-shadow .25s;
}

/* ── 6. Tilt-совместимость для vanilla-tilt.js (уровень C, только десктоп) ── */
.card, .next-read a {
  transform-style: preserve-3d;
}

/* ── 7. Counters-from-blur: число в .rail-head .hint проявляется из блюра ── */
.ef-count {
  display: inline-block;
  transition: filter .5s ease, opacity .5s ease;
  filter: blur(6px);
  opacity: .3;
}
.ef-count.is-in {
  filter: blur(0);
  opacity: 1;
}

/* ── Общий предохранитель: styles-v2.css уже глушит все animation/transition
   под prefers-reduced-motion:reduce глобально (звёздочка в самом низу файла) -
   это правило дублирует явно для новых ef-*/kinetic классов на всякий случай ── */
@media (prefers-reduced-motion: reduce) {
  .kinetic, [class*="ef-"] { animation: none !important; }
}
