/* ══════════════════════════════════════════════════════════════════════
   АНИМАЦИИ ГЛАВНОЙ — единый файл параметров.

   Грузится ЧЕРЕЗ $preStylesheets, ДО homepage.css (index.php) — обычный
   <link>, версионированный тем же filemtime-приёмом, что и другие файлы
   сайта (см. комментарий у $preStylesheets в includes/header.php).

   ЧАСТЬ 1 (ниже) — ЖИВЫЕ CSS-переменные: реально подставляются через var()
   в homepage.css/index.php, менять числа нужно ТОЛЬКО здесь.

   ЧАСТЬ 2 (в конце файла) — ТОЛЬКО описание, без живых переменных:
   слайдеры/карусели, чьи тайминги — JS-константы/админ-настройки, не
   голые CSS-числа. */

:root{
  /* ── .reveal-item (shared.css/homepage.css — общий IntersectionObserver
     initRevealOnScroll(), site.js) — базовый fade+сдвиг вверх. Реально
     применяется только к #sec-b3 .proj-grid .reveal-item (Projects) —
     тот использует СВОИ доп. переменные ниже (translateX+blur поверх
     этой базы), см. .proj-reveal--*. */
  --reveal-move-y: 24px;
  --reveal-duration: .35s;

  /* Прячется ли блок прозрачностью, пока не дошла очередь появиться
     (2026-09-20, раунд «Главная 3», пункт 3). На ПК — да, 0: в этом весь
     эффект. В облегчённом профиле — 1, то есть не прячется вовсе: там
     сдвиг и блюр и так обнулены, и прятать содержимое ради анимации,
     которой почти не осталось, нечестно — на медленном телефоне пустые
     блоки читались как «страница не загрузилась». Читают токен
     .reveal-item, карточки проектов и .how-card. */
  --reveal-hidden-opacity: 0;

  /* ── #sec-b3 .proj-grid .reveal-item (карточки Completed Projects) —
     появление сбоку (влево у чётных/--left, вправо у нечётных/--right) с
     блюром, поверх базового .reveal-item выше. */
  --proj-reveal-move-x: 70px;
  --proj-reveal-blur: 16px;
  --proj-reveal-duration: .375s;

  /* ── .why-reveal (карточки #sec-b2 Why Clients Choose) — initWhyCardsReveal()
     в index.php. В отличие от .reveal-item/proj-reveal — БЕЗ opacity в
     анимации (карточка видна сразу), только сдвиг вверх + блюр, каждый со
     своей длительностью. --why-reveal-move-y-mobile — переопределяется в
     media-блоке ниже (≤980px), сама .why-reveal в homepage.css переопределений
     не содержит — только var(). */
  /* 2026-09-17: сдвиг 24px → 0. Прямая просьба владельца «временно
     отключить анимацию движения для карточек в sec-b2 и sec-how во время
     сролла» — карточки просто проявляются на месте. Ноль в ОБОИХ профилях
     (не только на телефоне): просьба вызвана не лагами, а тем, что «очень
     много активности в анимации… это отвлекает от главного», и на большом
     экране это верно так же. Вернуть движение — вписать сюда число. */
  --why-reveal-move-y: 0px;
  --why-reveal-blur: 8px;
  --why-reveal-move-duration: .25s;
  --why-reveal-blur-duration: .15s;

  /* ── #sec-b2/#sec-how .section-title (заголовки Why Clients Choose и How
     We Work) — один набор переменных на оба (значения совпадают) — сдвиг
     вправо-налево + блюр, initWhyCardsReveal()/initHowSteps(). Подзаголовка
     ни у одного из двух разделов сейчас в разметке нет — переменной под
     него тоже нет. */
  --section-title-move-x: 50px;
  --section-title-move-duration: .2s;
  --section-title-blur: 8px;
  --section-title-blur-duration: .15s;

  /* ── .how-card + .how-card-text h3/p (карточки #sec-how How We Work) —
     initHowSteps() в index.php. Появление карточки — блюр+выезд справа (c
     opacity, карточка действительно невидима до появления); текст внутри
     карточки — отдельный чуть более мелкий сдвиг с собственной задержкой
     (стаггер .12s/.22s зашит в homepage.css, не вынесен — двух чисел мало,
     чтобы оправдывать переменные). */
  /* 2026-09-17: сдвиги 70px и 22px → 0, по той же просьбе, что и у
     .why-reveal выше (sec-b2 и sec-how названы владельцем вместе).
     Карточка и текст внутри неё проявляются на месте.
     2026-09-20: блюр 16px → 0 и на ПК тоже (владелец, после осмотра:
     «работает, только блюр на ПК»). Движения у карточки нет, значит блюр
     оставался единственным и самым дорогим эффектом на странице — теперь
     карточка просто проявляется прозрачностью, как на телефоне. Вернуть —
     вписать сюда радиус, правило в homepage.css его читает. */
  --how-card-move-x: 0px;
  --how-card-blur: 0px;
  --how-card-duration: .375s;
  --how-card-text-move-x: 0px;

  /* ── .how-row-num-wrap (кружок-номер шага, #sec-how) — покоящееся
     состояние (маленький, размытый, блёклый) до того, как курсор (середина
     окна) дойдёт до его позиции, initHowSteps(). */
  --how-num-blur: 6px;
  --how-num-scale-dormant: .55;
  --how-num-opacity-dormant: .35;
  --how-num-duration: .25s;

  /* ══════════════════════════════════════════════════════════════════════
     HERO — пин-скролл (.hero фиксирован, .hero-spacer резервирует место в
     потоке, .hero-lift — непрозрачная обёртка следующего контента, наезжает
     снизу поверх hero). initHeroPinScroll() в index.php каждый кадр (rAF)
     считает для каждого элемента ниже "процент перекрытия" — какая доля ЕГО
     СОБСТВЕННОЙ высоты уже закрыта снизу наезжающим .hero-lift — и линейно
     интерполирует нужное CSS-свойство между значением на cover-start (0%
     эффекта) и cover-end (100% эффекта, дальше — обратно к исходному,
     "отмена", если явно не сказано иное). Пороги читаются JS ОДИН РАЗ при
     инициализации (getComputedStyle), сам расчёт — на каждый кадр. */

  /* (а) .hero-pitch (текст+CTA) + .hprogress (полоски-таймер слайдов) —
     перекрытие считается ОТ САМОГО .hero-pitch. На cover-end полностью
     скрывается (opacity 0) и остаётся скрытым до конца страницы. */
  --hero-pitch-cover-start: .1;
  --hero-pitch-cover-end: 1;
  --hero-pitch-blur-max: 8px;
  --hero-pitch-scale-min: .95;
  --hero-pitch-shift-max: 10px;

  /* (б) карусель (.hero-rails десктоп / .hero-rail-mobile мобильный) —
     блюр+масштаб(+сдвиг, только десктоп), перекрытие считается ОТ САМОЙ
     карусели. После cover-end блюр/масштаб ОТМЕНЯЮТСЯ (мгновенный возврат
     к блюру 0 / масштабу 1) — сдвиг, наоборот, ДЕРЖИТСЯ (по прямому
     запросу — откатывается только реальной обратной прокруткой, не
     обнуляется вместе с блюром). Пороги одинаковые на мобильном и
     десктопе; --hero-carousel-shift-max — горизонтальный сдвиг ТОЛЬКО
     десктопной пары .hero-rails (на мобильной ленте .hero-rail-mobile
     сдвига нет, только блюр+масштаб). */
  --hero-carousel-cover-start: .1;
  --hero-carousel-cover-end: 1;
  --hero-carousel-blur-max: 8px;
  --hero-carousel-scale-min: .95;
  --hero-carousel-shift-max: 140px;

  /* (в) фон hero-фото (#hslides, .hslide/.hshade — самый нижний слой,
     z-index:1) — блюр. Начало отсчитывается ОТ ПЕРЕКРЫТИЯ КАРУСЕЛИ
     (--hero-bg-cover-start), конец — от перекрытия САМОГО #hslides
     (--hero-bg-cover-end, разные элементы-ориентиры у начала и конца).
     После cover-end эффект ОТМЕНЯЕТСЯ (блюр мгновенно возвращается к 0). */
  --hero-bg-cover-start: .5;
  --hero-bg-cover-end: 1;
  --hero-bg-blur-max: 8px;

  /* (г) движение карусели (.hero-rail-track десктоп / .hero-rail-mobile-track
     мобильный) — БЕЗ порогов и без интерполяции, крутится само по себе
     анимацией CSS. С 2026-09-17 встаёт (animation-play-state:paused), пока
     hero полностью закрыт наезжающим контентом: класс body.hero-covered
     вешает тот же rAF-цикл, правило — в homepage.css. Десктоп — пара лент в разные стороны, две
     разные скорости; мобильный/планшетный — одна горизонтальная лента. */
  --hero-rail-desktop-duration: 70s;
  --hero-rail-desktop-duration-reverse: 110s;
  --hero-rail-mobile-duration: 150s;

  /* (д) .nav (шапка) — стиль "стеклянной панели при скролле", перекрытие
     считается ОТ КАРУСЕЛИ. Линейная интерполяция cover-start→cover-end
     управляет --p (0..1) у .nav (shared.css) — отступы, скругление,
     бордер и тень (фон и блюр с 2026-09-19 есть всегда, они от --p не
     зависят). После cover-end состояние ДЕРЖИТСЯ (не отменяется само по
     себе) — уменьшается обратно только при реальной обратной прокрутке,
     т.к. --p пересчитывается из живого перекрытия каждый кадр.
     Логотип в самом меню больше не проявляется по прокрутке (2026-09-19):
     он виден с первого кадра, как и стекло плашки. Токен
     --hero-brand-blur-max вместе с ним убран. */
  --hero-nav-cover-start: .7;
  --hero-nav-cover-end: 1;

  /* Общая длительность CSS-transition для сглаживания между кадрами rAF
     (не длительность самой анимации — та управляется положением скролла,
     не таймером) — используется у filter/opacity/transform всех групп
     выше. */
  --hero-cover-smoothing: .1s;

  /* Отдельная длительность для filter (2026-09-19). Переход на transform/
     opacity дешёвый (его считает композитор) и как раз он сглаживает шаг
     пересчёта, а переход на filter заставляет браузер пройти ПРОМЕЖУТОЧНЫЕ
     радиусы размытия — ровно то, ради чего вводилась ступень
     --hero-blur-step, наполовину съедалось им же (эта оговорка записана
     ниже, в комментарии к ступени). Поэтому в облегчённом профиле у filter
     сглаживание снимается, а у движения остаётся. */
  --hero-filter-smoothing: var(--hero-cover-smoothing);

  /* ── Шаг пересчёта анимации hero по прокрутке (2026-09-19, по прямому
     запросу: «чтобы она производилась не на каждый пиксель высоты, а с
     шагом, например 3-5px»). Цикл в index.php выполняет тело, только когда
     край наезжающего блока сдвинулся на столько пикселей; когда прокрутка
     останавливается, делается один доводочный проход до точного
     положения. 0 = пересчёт на каждый кадр, как было.
     Владелец 2026-09-19: «для ПК тоже давай сделаем также как на
     мобильном» — поэтому значение одно на оба профиля, здесь. ── */
  --hero-scroll-step: 4px;

  /* ── Ступень блюра hero (2026-09-17). Владелец: «блюр у фона карусели я
     бы хотел оставить, только может не такой плавный, может сделать его не
     на каждый пиксель прокрутки а с каким то шагом? чтобы снизить
     нагрузку».

     Почему это работает: браузер кеширует УЖЕ размытую картинку, пока не
     меняется радиус. Сейчас радиус пересчитывается каждый кадр и каждый раз
     новый — кеш не попадает ни разу. При шаге 2px на всём пути прокрутки
     получается 4-5 разных радиусов вместо шестидесяти в секунду.

     0 = без ступени, непрерывно (профиль ПК). Читается JS один раз при
     инициализации initHeroPinScroll() (index.php) и применяется только к
     блюру ФОНА и КАРУСЕЛИ — у текста hero и логотипа блюр в облегчённом
     профиле снят совсем.

     Оговорка: --hero-cover-smoothing стоит на filter, и при смене ступени
     браузер проходит промежуточные радиусы — примерно 6 кадров на ступень
     вместо каждого кадра. Выигрыш кратный, но не идеальный. Если на старом
     телефоне лаг останется — снимать сглаживание именно у filter. */
  --hero-blur-step: 0px;
}
/* ══════════════════════════════════════════════════════════════════════
   ОБЛЕГЧЁННЫЙ ПРОФИЛЬ (2026-09-17). Решение владельца: «давай сделаем два
   провиля для анимаций на ПК и для мобильных» — после репорта «на старых
   телефонах это очень лагает, когда такая сложная анимация. можем сделать
   без блюра например? и быстрее».

   Второй копии ПРАВИЛ при этом нет: все анимации главной читают var() из
   блока выше, поэтому профиль — это просто другой набор чисел. Разметка в
   homepage.css/index.php одна на оба профиля.

   Граница: ширина 980px ИЛИ грубый указатель. Ширина — уже существующая в
   этом файле граница (на 981px переключаются и сами hero-ленты);
   pointer:coarse добавлен, чтобы планшет в альбомной ориентации (iPad Pro
   шире 980px) тоже получил облегчённый профиль. Ноутбук с сенсорным
   экраном попадёт под облегчённый — сознательная плата за простое правило.

   Что именно снято: блюр во ВСЕХ появлениях (он и есть источник лагов —
   filter:blur заставляет заново растрировать всю площадь слоя), амплитуды
   урезаны, длительности сокращены. Что оставлено по прямому решению
   владельца: кружки-номера в How («они маленькие, не думаю что они сильно
   тормозят»), стеклянная шапка .nav («красиво появляется, можем ли мы пока
   это оставить»), блюр фона и карусели hero — но со ступенью.
   ══════════════════════════════════════════════════════════════════════ */
/* ДВА УРОВНЯ (2026-09-19, второй заход по просьбе владельца: «пропал блюр
   для текста на герое… для современных телефонов это было красиво»).
   Раньше уровень был один и включался по ширине экрана, поэтому новый
   телефон получал ровно то же, что и старый. Теперь признаки разведены, и
   их ставит ранний встроенный скрипт в includes/header.php — ДО первой
   отрисовки, там же, где выбирается тема:

     .lite-motion — узкий экран, грубый указатель ИЛИ слабое железо.
                    Средний уровень: тяжёлые появления секций без блюра
                    (их много и сразу), но эффекты САМОГО героя остаются —
                    на современном телефоне он выглядит как на ПК, только
                    блюр идёт ступенью в 2px, чтобы не пересчитывать радиус
                    на каждый кадр.
     .weak-device — только слабое железо (ядра/память). Снимает с героя
                    всё оставшееся: блюр текста и логотипа в ноль, блюр
                    фото вдвое, сглаживание фильтра прочь.

   Слабое устройство получает ОБА класса, поэтому блок .weak-device идёт
   ниже: вес селекторов одинаковый, решает порядок в файле.
   Через классы, а не через @media, потому что «слабое железо» из CSS не
   спрашивается. Без JavaScript анимаций на странице нет вовсе (их все
   ведёт rAF-цикл), так что класс — не менее надёжная опора, чем
   media-запрос. */
:root.lite-motion{
  --reveal-hidden-opacity: 1;
  --reveal-move-y: 16px;
  --reveal-duration: .25s;
  --proj-reveal-move-x: 20px;
  --proj-reveal-blur: 0px;
  --proj-reveal-duration: .25s;
  --why-reveal-blur: 0px;
  --section-title-move-x: 16px;
  --section-title-blur: 0px;
  /* --how-card-blur здесь больше не переопределяется: с 2026-09-20 он
     ноль в общих токенах, у обоих профилей. */
  --how-card-duration: .25s;
  /* Блюр героя на среднем уровне ОСТАЁТСЯ (возврат 2026-09-19): это
     один-два элемента, а не десяток карточек сразу, и именно он делал
     уход первого экрана красивым. Дешевизну держат ступень в 2px ниже и
     шаг пересчёта --hero-scroll-step. Значения --hero-pitch-blur-max,
     --hero-bg-blur-max и сглаживание фильтра здесь НЕ переопределяются —
     берутся из :root, как на ПК. */
  --hero-blur-step: 2px;
}

/* Слабое устройство — то, что до 2026-09-19 получали все телефоны. */
:root.weak-device{
  --hero-pitch-blur-max: 0px;
  /* Размытие полноэкранного фото — самая дорогая операция во всей
     анимации; по решению владельца уменьшено вдвое, а не убрано. */
  --hero-bg-blur-max: 4px;
  /* Сглаживание снимается только у filter, движение остаётся плавным. */
  --hero-filter-smoothing: 0s;
}

/* ══════════════════════════════════════════════════════════════════════
   ЧАСТЬ 2 — СЛАЙДЕРЫ/КАРУСЕЛИ (только описание, живых переменных нет —
   см. пояснение вверху файла). ══════════════════════════════════════════

   • Смена фото hero (.hslide, homepage.css) — кроссфейд opacity 0→1 за
     .6s ease. Автопрокрутка — JS-таймер HERO_INTERVAL_MS (index.php),
     значение из admin/adm-settings.php → site_settings.hero_autoplay_speed_ms
     (уже регулируемая настройка). Полоски-таймер под текстом — .hprogress/
     .hprog-fill, та же HERO_INTERVAL_MS через --hprog-dur.

   • Лента USP (.usp-track--marquee, @keyframes usp-marquee, homepage.css)
     — бесконечная горизонтальная прокрутка, 38s linear, захардкожено в
     самом keyframe-правиле, не вынесено никуда.

   • Рельса образцов MDF (.rail--sample, InfiniteCarousel, initSampleRail()
     в index.php) — автопрокрутка карточек, JS-таймер SAMPLE_AUTOPLAY_MS,
     значение из той же site_settings (carousel_autoplay_speed_ms) — тоже
     уже регулируемая настройка. Полоска-таймер — .rail-progress-fill.

   • Hero pin-scroll — непрерывный расчёт перекрытия каждого элемента
     каждый кадр (0..1 по факту скролла) — JS-логика, не CSS-число,
     вынести в чистый CSS нельзя по своей природе; сами пороги/максимумы —
     переменные выше (группы (а)-(д) в блоке HERO). */
