/* ============================================================
   Скролл-эффекты (scroll-fx). Приёмы из категории 21st.dev
   «Scroll Area», собранных в токенах сайта. Логика — js/scroll-fx.js,
   хуки в разметке — атрибуты data-sfx-*. Стили ничего в style.css и
   story.css не переопределяют, кроме двух строк для рельса таймлайна
   (position на .story-list и .story-card).

   Снять эффект целиком: убрать два подключения (css + js) и
   data-атрибуты; разметка при этом остаётся валидной и читаемой.
   ============================================================ */

/* --- 01 Scroll Progress: полоса прочитанного (story.html) ---------- */
.sfx-progress {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 60;
  background: var(--accent);
  transform-origin: left;
  transform: scaleX(var(--scroll, 0));
  pointer-events: none;
}

/* --- 02 Text Reveal: цитата «Мой опыт дал мне вопросы» -------------
   Высоту блока не трогаем и ничего не приклеиваем: слова наливаются из
   приглушённого в белое, пока цитата поднимается от нижней трети экрана
   к верхней (окно прогресса задаёт JS). --n (число слов) и --i (номер)
   ставит JS; окно в 3 слова, чтобы налив шёл мягко, а не по одному. */
.sfx-w {
  color: var(--fg);
  /* окно налива - 3 слова; +3 к числу слов, чтобы при p=1 последнее слово
     тоже дошло до единицы (иначе хвост цитаты оставался серым) */
  opacity: calc(0.18 + 0.82 * clamp(0, (var(--p, 1) * (var(--n, 1) + 3) - var(--i, 0)) / 3, 1));
  transition: opacity 0.1s linear;
}

/* --- 04 Timeline: рельс вдоль карточек истории (story.html) ---------
   Линия слева от списка заполняется охрой вслед за центром экрана;
   точка у карточки загорается, когда линия её прошла. Ниже 1180px места
   слева нет — рельс скрыт, карточки как были. */
.story-list[data-sfx-scrub] {
  position: relative;
}
.sfx-rail {
  position: absolute;
  top: 1.5rem;
  bottom: 1.5rem;
  left: -2.5rem;
  width: 1px;
  background: var(--border);
}
.sfx-rail-fill {
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform-origin: top;
  transform: scaleY(var(--p, 0));
}
.story-card {
  position: relative;
}
.story-card::before {
  content: "";
  position: absolute;
  left: calc(-2.5rem - 4px);
  top: calc(clamp(1.75rem, 3.5vw, 2.5rem) + 0.6rem);
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--border-strong);
  transition: background 0.3s var(--ease-out), border-color 0.3s var(--ease-out), transform 0.3s var(--ease-out);
}
.story-card.is-past::before {
  background: var(--accent);
  border-color: var(--accent);
  transform: scale(1.3);
}
@media (max-width: 999.98px) {
  .sfx-rail,
  .story-card::before { display: none; }
}

/* --- 05 Number Ticker: цифры досчитывают один раз -------------------
   Стилей не требует, всё в JS: [data-sfx-count] стартует с нуля при
   появлении и за 1.1с доходит до записанного в разметке значения. */

/* --- 08 + 04 Card Stack с рельсом: «Моя история» --------------------
   На всех ширинах карточка при подъёме прилипает под шапкой (высота меню
   + 12px - тот же приём, что и в «Работах»), следующая прилипает на 14px
   ниже и накрывает её - складывается стопка. Накрытые уходят в глубину:
   масштаб и яркость ставит JS (--s, --b) по тому, насколько следующая
   наехала. Точка таймлайна сидит на самой карточке и едет вместе с ней;
   рельс слева заполняется за центром экрана, но рельсу и точке ниже
   1000px негде поместиться (см. блок 04 выше) - там от эффекта остаётся
   только сама стопка. */
.story-section[data-sfx-stack] { padding-bottom: 22vh; }
.story-section[data-sfx-stack] .story-card { min-height: 46vh; }
.story-section[data-sfx-stack] .story-card-inner {
  position: sticky;
  top: calc(var(--nav-h) + 12px + var(--k, 0) * 14px);
  overflow: visible;               /* иначе точка таймлайна за краем карточки обрезалась бы */
  transform: scale(var(--s, 1));
  filter: brightness(var(--b, 1));
  transform-origin: top center;
  will-change: transform;
}
.story-section[data-sfx-stack] .story-card:nth-of-type(1) .story-card-inner { --k: 0; }
.story-section[data-sfx-stack] .story-card:nth-of-type(2) .story-card-inner { --k: 1; }
.story-section[data-sfx-stack] .story-card:nth-of-type(3) .story-card-inner { --k: 2; }
.story-section[data-sfx-stack] .story-card:nth-of-type(4) .story-card-inner { --k: 3; }
.story-section[data-sfx-stack] .story-card:nth-of-type(5) .story-card-inner { --k: 4; }
.story-section[data-sfx-stack] .story-card:nth-of-type(6) .story-card-inner { --k: 5; }

/* точка переезжает с ячейки на саму карточку, чтобы ехать с ней */
.story-section[data-sfx-stack] .story-card::before { display: none; }
.story-section[data-sfx-stack] .story-card-inner::before {
  content: "";
  position: absolute;
  left: calc(-2.5rem - 4px);
  top: calc(clamp(1.75rem, 3.5vw, 2.5rem) + 0.6rem);
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--border-strong);
  transition: background 0.3s var(--ease-out), border-color 0.3s var(--ease-out), transform 0.3s var(--ease-out);
}
.story-section[data-sfx-stack] .story-card.is-past .story-card-inner::before {
  background: var(--accent);
  border-color: var(--accent);
  transform: scale(1.3);
}
@media (max-width: 999.98px) {
  .story-section[data-sfx-stack] .story-card-inner::before { display: none; }
}

/* --- 08 Card Stack: «Работы» на главной ------------------------------
   Слотов нет: ход между карточками даёт обычный поток, пустоты не
   возникает. Карточка при подъёме прилипает под шапкой (высота меню + 12px,
   каждая следующая на 14px ниже), накрытая уходит в глубину - масштаб и
   яркость ставит JS (--s, --b). Работает на всех ширинах; различается
   только раскладка карточки: от 900px картинка слева и текст справа
   (иначе картинка 4:3 на всю ширину сделала бы карточку выше экрана),
   на телефоне - картинка сверху, как в исходной сетке. */
.portfolio-grid[data-sfx-stack] {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  background: none;
  padding-bottom: 6vh;
}
.portfolio-grid[data-sfx-stack] .portfolio-card {
  position: sticky;
  top: calc(var(--nav-h) + 12px + var(--k, 0) * 14px);
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 18px;
  overflow: hidden;
  box-shadow: none;
  transform: scale(var(--s, 1));
  filter: brightness(var(--b, 1));
  transform-origin: top center;
  will-change: transform;
}
.portfolio-grid[data-sfx-stack] .portfolio-card:nth-of-type(1) { --k: 0; }
.portfolio-grid[data-sfx-stack] .portfolio-card:nth-of-type(2) { --k: 1; }
.portfolio-grid[data-sfx-stack] .portfolio-card:nth-of-type(3) { --k: 2; }
.portfolio-grid[data-sfx-stack] .portfolio-card:nth-of-type(4) { --k: 3; }
.portfolio-grid[data-sfx-stack] .portfolio-card--spotlight {
  aspect-ratio: auto;
}
@media (min-width: 900px) {
  .portfolio-grid[data-sfx-stack] .portfolio-card {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    min-height: 52vh;
  }
  .portfolio-grid[data-sfx-stack] .portfolio-card-image {
    aspect-ratio: auto;        /* картинка на всю высоту левой колонки */
    height: 100%;
    min-height: 0;
  }
  .portfolio-grid[data-sfx-stack] .portfolio-card--spotlight {
    grid-template-columns: 1fr;
  }
  .portfolio-grid[data-sfx-stack] .portfolio-card-body {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
  }
}
@media (max-width: 899.98px) {
  /* флагман без картинки на телефоне слишком низкий - следующая карточка
     накрывала бы его почти сразу */
  .portfolio-grid[data-sfx-stack] .portfolio-card--spotlight { min-height: 46vh; }
}

/* --- 09 Horizontal Scroll: «Работы» на главной ------------------------------
   Трек .pf-track выше экрана ровно на ширину ленты, которая в экран не
   помещается (--hz-overflow в px ставит js/scroll-fx.js). Секция прилипает
   (sticky, только svh), вертикальная прокрутка везёт ленту карточек влево:
   1 px вниз - 1 px вбок, --pin от 0 до 1. Колёсико и жесты не перехватываются.
   Лента выходит за край сетки к краям экрана и там обрезается (overflow-x:
   clip у трека не мешает sticky и не даёт странице прокрутки вбок).
   Ширина карточки - от ширины экрана, но и от высоты: карточка с картинкой
   4:3 и подписью должна поместиться в экран под заголовком блока. */
.pf-track {
  --pf-w: min(clamp(280px, 30vw, 440px), (100svh - var(--nav-h) - 5svh - 400px) / 0.75);
  position: relative;
  height: calc(100svh + var(--hz-overflow, 0px));
  overflow-x: clip;
}
.pf-track > .portfolio-section {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-top: calc(var(--nav-h) + 2svh);
  padding-bottom: 3svh;
}
.pf-track .portfolio-head { margin-bottom: clamp(1.25rem, 3svh, 2.25rem); }
.pf-track .portfolio-grid {
  display: flex;
  align-items: stretch;
  gap: clamp(1rem, 1.5vw, 1.5rem);
  width: max-content;
  background: none;
  transform: translateX(calc(var(--pin, 0) * var(--hz-overflow, 0px) * -1));
}
.pf-track .portfolio-card {
  flex: 0 0 auto;
  width: var(--pf-w);
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 18px;
  overflow: hidden;
  box-shadow: none;
}
.pf-track .portfolio-card--spotlight {
  width: var(--pf-w); /* как у остальных карточек (просьба 2026-09-15; было в 1.2 раза шире) */
  aspect-ratio: auto;
}
/* узкий или низкий экран, «уменьшить движение»: без закрепления, лента
   листается пальцем (без scroll-snap - прокрутку не перехватываем) */
@media (max-width: 760px), (max-height: 480px), (prefers-reduced-motion: reduce) {
  .pf-track { height: auto; overflow-x: visible; }
  .pf-track > .portfolio-section {
    position: relative;
    height: auto;
    display: block;
    padding-top: var(--sp-section);
    padding-bottom: var(--sp-section);
  }
  .pf-track .portfolio-grid {
    width: auto;
    transform: none;
    overflow-x: auto;
    padding-bottom: 0.75rem;
  }
  .pf-track .portfolio-card { width: min(78vw, 340px); }
  .pf-track .portfolio-card--spotlight { width: min(78vw, 340px); }
}

/* --- reduced motion: движение убираем, содержание показываем сразу --- */
@media (prefers-reduced-motion: reduce) {
  .sfx-w { opacity: 1; transition: none; }
  .sfx-rail-fill { transform: none; }
  .story-section[data-sfx-stack] .story-card-inner { transform: none; filter: none; }
  .portfolio-grid[data-sfx-stack] .portfolio-card { transform: none; filter: none; }
  .story-card::before { transition: none; }
}

/* --- 05 Сцена главной: hero, вопросы, «Тогда / 13 лет спустя», цитата -----
   Один трек .hy-track, слой .hy-root прилипает (sticky, только svh).
   --pin (0..1) ставит js/scroll-fx.js; --s - сколько пройдено по треку, в svh.
  Ход трека --stotal: 640 на всех обычных экранах; сам
  трек на экран длиннее (740svh суммарно). Фазы по --s:
     0-236    hero: имя и «Поворотный момент» гаснут на 8-78, фигура уезжает
              вправо на 14-80, текст проявляется на 72-92, наливается на 92-218
         236-265  текст уходит вверх
         265-325  карточки «Тогда» (265-310) и «13 лет спустя» (280-325)
          входят вслед за текстом
         360-425  карточки быстро уходят по очереди; цитата начинает входить на 410
         410-455  цитата приезжает и наливается по словам
         500-600  видео раскрывается под цитатой
          В конце сцена отпускает страницу
   Окна налива в разметке - в svh хода, как --s (js делит их на --stotal):
  у .hy-story 92 и 218, у .hy-quote 410 и 455. Якорь #about стоит на 300: «Обо мне»
   открывает кадр с фотографиями.
   Имя и «Поворотный момент» гаснут через filter: opacity(), фигура едет
   свойством translate: у них в hero.css анимация появления с forwards, и её
   opacity и transform перебили бы наши. Всё, что въезжает и уезжает, до
   поры лежит за краем .hy-root (overflow: hidden) - прокрутки вбок нет. */
.hy-track {
  --pin: 0;
  --stotal: 640;
  --s: calc(var(--pin) * var(--stotal));
  --fade:   clamp(0, calc((var(--s) - 8) / 70), 1);
  --slide:  clamp(0, calc((var(--s) - 14) / 66), 1);
  --appear: clamp(0, calc((var(--s) - 72) / 20), 1);
  --rise:   clamp(0, calc((var(--s) - 236) / 100), 1);
  --story-fade: clamp(0, calc((var(--s) - 236) / 29), 1);
  --out:    clamp(0, calc((var(--s) - 236) / 80), 1);
  --in:     clamp(0, calc((var(--s) - 266) / 80), 1);   /* второй въезжает слева */
  --dark:   clamp(0, calc((var(--s) - 472) / 40), 1);
  --c1:     clamp(0, calc((var(--s) - 265) / 30), 1);
  --c2:     clamp(0, calc((var(--s) - 280) / 30), 1);
  --x1:     clamp(0, calc((var(--s) - 360) / 45), 1);
  --x2:     clamp(0, calc((var(--s) - 380) / 45), 1);
  --q:      clamp(0, calc((var(--s) - 410) / 45), 1);
  --gone:   clamp(0, calc((var(--s) - 610) / 40), 1);   /* вопросы гаснут */
  --lift:   clamp(0, calc((var(--s) - 500) / 40), 1);
  --v:      clamp(0, calc((var(--s) - 540) / 60), 1);
  --h2b:    clamp(0, calc((var(--s) - 360) / 30), 1);
  --h2out:  clamp(0, calc((var(--s) - 380) / 45), 1);
  /* сглаживание: уход с разгоном x², въезд с торможением 1 - (1 - x)² */
  --out-e: calc(var(--out) * var(--out));
  --in-e:  calc(var(--in) * (2 - var(--in)));
  --c1-e:  calc(var(--c1) * (2 - var(--c1)));
  --c2-e:  calc(var(--c2) * (2 - var(--c2)));
  --x1-e:  calc(var(--x1) * var(--x1));          /* уход - зеркало въезда: с разгоном */
  --x2-e:  calc(var(--x2) * var(--x2));
  --q-e:   calc(var(--q) * (2 - var(--q)));
  --lift-e: calc(var(--lift) * var(--lift) * (3 - 2 * var(--lift)));   /* плавно в обе стороны */
  --v-e:   calc(var(--v) * (2 - var(--v)));
  --h2out-e: calc(var(--h2out) * var(--h2out));
  --ph: calc(100svh - var(--nav-h) - 4svh);   /* высота портрета на широком экране */
  /* финал: видео под цитатой. --qh - высота цитаты (ставит js/scroll-fx.js),
     --cwv - ширина колонки, --vh - высота видео: сколько осталось под цитатой,
     но не больше, чем даёт ширина колонки при 16:9 */
  --qh: 0px;
  --vgap: 2.5svh;
  --vbot: 4svh;
  --cwv: min(100vw - 2 * var(--gutter), 40rem);
  --vh: min(var(--cwv) * 9 / 16, 100svh - var(--nav-h) - 3svh - var(--qh) - var(--vgap) - var(--vbot));
  --cl: max(var(--gutter), calc((100% - var(--container)) / 2 + var(--gutter)));   /* край сетки сайта */
  position: relative;
  height: calc((var(--stotal) + 100) * 1svh);   /* ход + экран */
}
.hy-track > .hy-root {
  position: sticky;
  top: 0;
  height: 100svh;
}
.hy-anchor {
  position: absolute;
  top: 300svh;
  left: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}
.hy-track .hy-word {
  filter: drop-shadow(0 0 26px rgba(255, 255, 255, 0.28)) opacity(calc(1 - var(--fade)));
  translate: 0 calc(var(--fade) * -3vh);
}
.hy-track .hy-turn { filter: opacity(calc(1 - var(--fade))); }
/* в сцене налив и так идёт за прокруткой - переход у каждого слова лишь
   заводил бы новые анимации на каждом кадре */
.hy-track .sfx-w { transition: none; }

/* текст hero: проявляется, наливается, на смене уходит вверх */
.hy-story {
  position: absolute;
  z-index: 6;
  top: calc(var(--nav-h) + (100% - var(--nav-h)) / 2);
  left: var(--cl);
  width: min(62vw, 1100px);
  opacity: calc(var(--appear) * (1 - var(--story-fade)));
  transform: translateY(calc(-50% + (1 - var(--appear)) * 32px - var(--rise) * 100svh));
  pointer-events: none;
}
.hy-story h2 {
  margin: 0 0 0.45em;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: min(5.3vw, 9.4svh, 96px);   /* 96px: на 1920 заголовок в две строки, не в три */
  line-height: 1.04;
  letter-spacing: -0.02em;
}
.hy-story p {
  margin: 0 0 0.55em;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: min(2.5vw, 4.4svh, 48px);
  line-height: 1.3;
  letter-spacing: -0.01em;
}
.hy-story .stat-inline { color: var(--accent-strong); }
.hy-story .stat-inline .sfx-w { color: inherit; }

/* вопросы и вывод: поднимаются снизу на смене, в конце темнеют */
.hy-root .hy-questions {
  position: absolute;
  z-index: 6;
  top: calc(var(--nav-h) + (100% - var(--nav-h)) / 2);
  left: var(--cl);
  right: var(--cl);
  display: block;             /* style.css на узком экране растворяет .split-copy */
  opacity: calc((1 - var(--dark) * 0.72) * (1 - var(--c2-e) * 0.6) * (1 - var(--gone)));   /* под крупными карточками - ещё темнее */
  transform: translateY(calc(-50% + (1 - var(--rise)) * 100svh));
  pointer-events: none;
}
.hy-questions > .split-questions { margin-top: 0; padding-top: 0; border-top: 0; gap: 0.35em; }
.hy-questions .split-questions p { line-height: 1.2; font-weight: 500; }
.hy-questions > p.body-text {
  max-width: none;
  margin: 1.1em 0 0;
  color: var(--fg);           /* вывод читается так же ярко, как вопросы */
  font-weight: 500;
}

/* второй герой: въезжает слева на смене, перед цитатой уходит вправо */
.hy-root .hy-portrait {
  position: absolute;
  z-index: 4;
  margin: 0;
  translate: calc((var(--in-e) - 1 + var(--h2out-e)) * 100vw) 0;
  pointer-events: none;
}

/* «Тогда» и «13 лет спустя»: выезжают справа по очереди, после паузы уезжают
   влево в том же порядке и с той же дистанцией - горизонтальная прокрутка.
   Фото во всю ширину карточки, чёрно-белое; при наведении курсора - цветное. */
.hy-then-now {
  position: absolute;
  z-index: 8;
  pointer-events: none;
  top: calc(var(--nav-h) + (100% - var(--nav-h)) / 2);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
  transform: translateY(-50%);
}
.hy-root .hy-card {
  padding: 0;
  gap: 0;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: var(--fx-glass-ring), var(--fx-glass-drop);
}
.hy-card > div:last-child { padding: clamp(0.85rem, 1.3vw, 1.2rem) clamp(1rem, 1.5vw, 1.35rem) clamp(1rem, 1.5vw, 1.35rem); }
.hy-card h3 { margin: 0.35rem 0 0.4rem; }
.hy-card p { max-width: none; }
/* Фото в карточках сцены цветные сразу и всегда, на всех ширинах: сперва так
   сделали для телефона (просьба 2026-09-15), затем и для десктопа
   (2026-09-16). Ховер и переход убраны: снимать больше нечего. */
.hy-card .compare-photo img { filter: none; }
.hy-card--then { translate: calc((1 - var(--c1-e) - var(--x1-e)) * 100vw) 0; }
.hy-card--now  { translate: calc((1 - var(--c2-e) - var(--x2-e)) * 100vw) 0; }

/* цитата «Мой опыт дал мне вопросы»: едет справа вслед за карточками, встаёт
   на место вопросов и наливается по словам */
.hy-quote {
  --qshift: 0px;              /* сдвиг вбок на подъёме; цитата и видео по центру - не нужен */
  text-align: center;         /* цитата стоит посередине экрана */
  position: absolute;
  z-index: 10;             /* выше видео: оно не заслоняет цитату */
  top: calc(var(--nav-h) + (100% - var(--nav-h)) / 2);
  left: var(--cl);
  right: var(--cl);
  transform-origin: left top;
  /* по центру экрана; на подъёме цитата, не уменьшаясь, встаёт прямо над
     видео: её низ - над верхом видео с зазором --vgap. Вниз не едет никогда
     (min с 0): если места под ней больше, чем нужно видео, стоит на месте */
  transform: translateY(-50%);
  translate: calc((1 - var(--q-e)) * 100vw + var(--lift-e) * var(--qshift)) calc(var(--lift-e) * min(0px, (100svh - var(--nav-h)) / 2 - var(--vbot) - var(--vh) - var(--vgap) - var(--qh) / 2));
  pointer-events: none;
}
.hy-quote p {
  /* абзац шириной в свой текст и по центру колонки - строки стоят посередине
     экрана, даже если text-align где-то не сработает */
  width: -webkit-fit-content;
  width: fit-content;
  margin: 0 auto;
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.12;
  letter-spacing: -0.01em;
}

/* видео «Если не хочется читать весь сайт»: после цитаты выезжает слева,
   крупно, под поднятой цитатой; щелчок запускает ролик (js/main.js) */
.hy-root .hy-video {
  position: absolute;
  z-index: 9;
  left: 0;
  right: 0;
  margin-inline: auto;                            /* по центру страницы, под цитатой */
  bottom: var(--vbot);
  width: calc(var(--vh) * 16 / 9);
  /* приём 30: видео раскрывается кругом в своей рамке, не на весь экран
     (просьба 2026-09-16). Радиус 72% перекрывает углы рамки */
  clip-path: circle(calc(var(--v-e) * 72%) at 50% 50%);
}

@media (min-width: 1024px) and (min-aspect-ratio: 6/5) {
  .hy-track {
    --pw: min(var(--ph) * 0.8, 42vw);   /* ширина портрета: на экранах 4:3 не больше 42% */
    --cwv: calc(100vw - 2 * max(var(--gutter), (100vw - var(--container)) / 2 + var(--gutter)));
  }
  .hy-track .hy-subject,
  .hy-track .hy-hand {
    translate: calc(var(--slide) * 34vw + var(--out-e) * 70vw) 0;
    scale: calc(1 - var(--slide) * 0.1);
    filter: brightness(calc(1 - var(--appear) * 0.45));
  }
  /* портрет во всю высоту под меню, прижат к низу и к левому краю */
  .hy-root .hy-portrait { left: 0; bottom: 0; width: var(--pw); aspect-ratio: 4 / 5; }
  /* затемнение прозрачностью, не filter: brightness() - браузер сводит её без
     перерисовки большой картинки на каждом кадре */
  .hy-portrait img { height: 100%; opacity: calc(0.62 - var(--dark) * 0.5 + var(--h2b) * 0.5); }
  /* колонка вопросов справа от портрета: начинается у его края (92% ширины -
     рукав, не лицо) и доходит до поля экрана */
  .hy-root .hy-questions {
    left: max(var(--cl), calc(var(--pw) * 0.92));
    right: var(--gutter);
    container-type: inline-size;
    /* Блок занимает кадр от меню до низа, содержимое по центру (просьба
       2026-09-21 «ниже» после «выше»). С Prata текст короче кадра и встаёт по
       центру; если текст выше кадра, блок растёт вниз от меню и под меню не
       залезает - потому min-height, а не bottom. Въезд снизу сохранён. */
    top: calc(var(--nav-h) + 2.5svh);   /* половина от запаса 5svh: иначе выше центра на 12px */
    min-height: calc(100% - var(--nav-h) - 5svh);
    display: flex; flex-direction: column; justify-content: center;
    transform: translateY(calc((1 - var(--rise, 1)) * 100svh));
  }
  /* кегль - меньшее из трёх: от ширины колонки (cqi), от высоты экрана и
     потолок; первая строка - запас для браузеров без cqi */
  .hy-questions .split-questions p {
    font-size: min(3.6vw, 6.5svh, 72px);
    font-size: min(6.3cqi, 6.8svh, 72px);
    line-height: 1.14;
  }
  .hy-questions > p.body-text {
    font-size: min(2.4vw, 4svh, 42px);
    font-size: min(3.8cqi, 4.2svh, 42px);
    line-height: 1.45;
  }
  /* карточки крупные, по центру: фото 5:4 во всю ширину карточки, под ним
     подпись до 250px; ширина - от высоты экрана, пара - во всю ширину экрана
     за вычетом полей, одна карточка не шире 860px */
  .hy-then-now {
    --cw: min((100% - 2 * var(--gutter) - 1.25rem) / 2, (100svh - var(--nav-h) - 6svh - 330px) * 1.25, 960px);   /* подпись 330 вместо 250 и потолок 960 вместо 860: текст крупнее (просьба 2026-09-21) */
    left: 50%;
    width: calc(var(--cw) * 2 + 1.25rem);
    transform: translate(-50%, -50%);
  }
  .hy-card .compare-photo { aspect-ratio: 5 / 4; }
  .hy-card .compare-photo--contain img { object-fit: cover; object-position: center 35%; }
  /* текст в карточках крупнее (просьба 2026-09-21): заголовок, абзац, подпись */
  .hy-card .eyebrow { font-size: 1rem; }
  .hy-card h3 { font-size: clamp(1.7rem, 2.6vw, 2.6rem); line-height: 1.12; }
  .hy-card p { font-size: clamp(1.15rem, 1.5vw, 1.65rem); line-height: 1.45; max-width: none; }
  /* второй шаг 2026-09-21: первый (34/22 на 1920) заказчик не заметил;
     теперь 42/26 против исходных 24/16, бюджет подписи 330 это вмещает */
  /* цитата по центру экрана: ширина колонки та же, что у вопросов справа от
     портрета (кегль не меняется), а посередине её держат поля auto между
     left: 0 и right: 0 - так центр считает сам браузер, одинаково в Chrome и
     Safari (расчёт left через проценты и max() Safari сдвигал влево) */
  .hy-quote {
    --qw: calc(100% - var(--gutter) - max(var(--cl), var(--pw) * 0.92));
    left: 0;
    right: 0;
    width: var(--qw);
    margin-inline: auto;
    container-type: inline-size;
  }
  .hy-quote p {
    font-size: min(4.4vw, 7.6svh, 84px);
    font-size: min(7cqi, 7.6svh, 84px);
  }
}
@media not all and (min-width: 1024px) and (min-aspect-ratio: 6/5) {
  .hy-anchor { top: 300svh; }
  .hy-track .hy-subject,
  .hy-track .hy-hand {
    translate: calc(var(--out-e) * 80vw) 0;
    filter: brightness(calc(1 - var(--slide) * 0.78));
  }
  .hy-story {
    left: var(--gutter);
    right: var(--gutter);
    width: auto;
    max-width: 40rem;
    margin-inline: auto;
  }
  .hy-story h2 { font-size: clamp(28px, min(8.4vw, 6svh), 56px); }
  .hy-story p { font-size: clamp(16px, min(4.6vw, 3.1svh), 26px); }
  .hy-root .hy-questions {
    left: var(--gutter);
    right: var(--gutter);
    max-width: 40rem;
    margin-inline: auto;
  }
  .hy-questions .split-questions p { font-size: clamp(18px, min(5.8vw, 3.9svh), 40px); }   /* поменьше, просьба 2026-09-22: на 430 было 28, стало 25 */
  .hy-questions > p.body-text { font-size: clamp(16px, min(4.8vw, 3svh), 27px); line-height: 1.5; }
  /* портрет по центру за текстом, притемнён сильнее */
  .hy-root .hy-portrait {
    left: 50%;
    top: calc(var(--nav-h) + (100% - var(--nav-h)) / 2);
    width: min(78vw, 560px, (100svh - var(--nav-h) - 8svh) * 0.8);
    transform: translate(-50%, -50%);
  }
  .hy-portrait img { opacity: calc(0.25 - var(--dark) * 0.1 + var(--h2b) * 0.1); }
  .hy-then-now {
    left: var(--gutter);
    right: var(--gutter);
    max-width: 52rem;
    margin-inline: auto;
  }
  .hy-quote { left: var(--gutter); right: var(--gutter); max-width: 40rem; margin-inline: auto; }
  .hy-quote p { font-size: clamp(26px, min(8vw, 5.4svh), 56px); }
  /* цитата и видео - одной группой чуть выше середины (просьба 2026-09-15):
     цитата с самого появления стоит на своём месте над видео и не двигается,
     видео выезжает под ней сразу после налива. Подъёма нет - ход трека
     короче на 60svh, окна налива в svh от этого не сдвигаются */
  .hy-track {
    --lift: 0;
    --v: clamp(0, calc((var(--s) - 540) / 60), 1);
    --gtop: calc(var(--nav-h) + (100svh - var(--nav-h) - var(--qh) - var(--vgap) - var(--vh)) * 0.4);
  }
  .hy-quote { top: var(--gtop); transform: none; translate: calc((1 - var(--q-e)) * 100vw) 0; }
  .hy-root .hy-video { top: calc(var(--gtop) + var(--qh) + var(--vgap)); bottom: auto; }
}
/* телефон: карточки друг под другом, крупнее; фото слева во всю высоту
   карточки - ровным краем, без пустоты под ним. Кегль ужимается по высоте
   экрана, чтобы пара карточек помещалась и на низком телефоне */
@media (max-width: 699.98px) {
  .hy-track .hy-subject,
  .hy-track .hy-hand {
    translate: calc(var(--out-e) * 110vw) 0;
    filter: brightness(calc(1 - var(--slide) * 0.78)) opacity(calc(1 - var(--out)));
  }
  /* Пара начинается под меню и не ниже кадра, карточки центрированы внутри;
     при перерасходе растёт вниз, а не под меню. На 375x667 с крупным кеглем
     пара выходила в 715px при допустимых 582 (2026-09-21). */
  .hy-then-now { grid-template-columns: minmax(0, 1fr); gap: 0.7rem; top: calc(var(--nav-h) + 2svh); transform: none;
    min-height: calc(100% - var(--nav-h) - 4svh); align-content: center; }
  .hy-root .hy-card { flex-direction: row; align-items: stretch; }
  .hy-card .compare-photo { flex: 0 0 40%; aspect-ratio: auto; }   /* 40% - под эту ширину подобран сдвиг кадра к лицам; 34% резало лица (2026-09-21) */
  /* лица не обрезать (просьба 2026-09-15): рамка узкая и высокая, снимки
     шире - кадр режется по бокам. Сдвиг к лицу по распознаванию лиц (Vision):
     на «Тогда» лицо на 17-62% ширины снимка, на «13 лет спустя» - на 46-81%;
     точки подобраны по рамкам телефонов 360-430 px: запас вокруг лица 12 px и больше */
  .hy-card .compare-photo--contain img { object-fit: cover; object-position: 25% 35%; }
  .hy-card .compare-photo--now img { object-position: 74% 7%; }
  /* Нижняя карточка на телефоне: снимок сверху во всю ширину, текст под ним
     (решение заказчика 2026-09-22). В прежней раскладке рамка была 156x442 с
     отношением 0.35 при снимке 0.90, и видно было 39% ширины - узкая полоса по
     лицу; раскладкой это не лечилось, потолок около 40%. Теперь по ширине не
     режется вовсе, по высоте видно 50-60%, окно смещено к лицу (28-59% высоты
     снимка), иначе подбородок уходит за край. Высота полосы в svh: пара должна
     помещаться и на низком телефоне. */
  /* сама раскладка - ниже, отдельным запросом: на низком телефоне не влезает */
  .hy-card > div:last-child { min-width: 0; padding: 0.85rem 0.9rem 0.95rem; }
  .hy-card .eyebrow { font-size: 14px; }
  /* кегль ужимается и по ширине: на узком телефоне (360 px) карточка иначе
     вытягивается в высоту, и узкая высокая рамка фото режет лицо по бокам.
     С 412 px и шире кегль прежний: 19 и 15.5 px */
  .hy-card h3 { font-size: clamp(18px, min(2.75svh, 5.3vw), 23px); margin: 0.3rem 0 0.4rem; }   /* крупнее (2026-09-21); на низком телефоне ведёт svh */
  .hy-card p { font-size: clamp(15px, min(2.3svh, 4.3vw), 18px); line-height: 1.45; }
}
/* низкий телефон: крупный кегль с фото в 40% не помещается в кадр (375x667 -
   пара 715 при допустимых 582), там кегль прежний. На 430x932 и выше -
   крупный. */
@media (max-width: 699.98px) and (max-height: 720px) {
  .hy-card h3 { font-size: clamp(16px, min(2.7svh, 4.65vw), 19px); }
  .hy-card p { font-size: clamp(13.5px, min(2.2svh, 3.8vw), 15.5px); }
  /* текст на обложке видео - по ширине рамки (cqi): на телефоне рамка 16:9
     низкая (188 px на 375), и кольцо с заголовком и подписью вылезали за её
     края. На планшете и шире стили прежние */
  .hy-root .hy-video { container-type: inline-size; }
  .hy-video .video-frame-content { padding: 4cqi; }
  .hy-video .play-ring { width: clamp(40px, 14cqi, 72px); height: clamp(40px, 14cqi, 72px); }
  .hy-video .play-ring svg { width: clamp(14px, 4.4cqi, 22px); height: clamp(14px, 4.4cqi, 22px); }
  .hy-video .video-frame-content p { font-size: clamp(15px, 4.6cqi, 1.4rem); line-height: 1.25; }
  .hy-video .video-frame-content span { margin-top: 0.4rem; font-size: clamp(11.5px, 3.3cqi, 0.85rem); line-height: 1.4; }
}
@media (prefers-reduced-motion: reduce) {
  .hy-track .hy-subject,
  .hy-track .hy-hand {
    translate: none;
    scale: none;
    filter: brightness(calc(1 - var(--slide) * 0.78)) opacity(calc(1 - var(--out)));
  }
  .hy-track .hy-word { translate: none; }
  .hy-story { transform: translateY(-50%); opacity: calc(var(--appear) * (1 - var(--rise))); }
  .hy-root .hy-questions { transform: translateY(-50%); opacity: calc(var(--rise) * (1 - var(--dark) * 0.72) * (1 - var(--c2) * 0.6) * (1 - var(--gone))); }
  .hy-root .hy-portrait { translate: none; opacity: calc(var(--in) * (1 - var(--h2out))); }
  .hy-card--then { translate: none; opacity: calc(var(--c1) * (1 - var(--x1))); }
  .hy-card--now  { translate: none; opacity: calc(var(--c2) * (1 - var(--x2))); }
  .hy-quote { translate: calc(var(--lift-e) * var(--qshift)) calc(var(--lift-e) * min(0px, (100svh - var(--nav-h)) / 2 - var(--vbot) - var(--vh) - var(--vgap) - var(--qh) / 2)); opacity: var(--q); }
  .hy-root .hy-video { translate: none; clip-path: none; opacity: var(--v); }
}
/* альбомный телефон: экран ниже 480px, закреплять нечего - всё идёт
   обычным потоком, текст стоит сразу целиком */
@media (max-height: 480px) {
  .hy-track { height: auto; }
  .hy-anchor { top: auto; bottom: 0; translate: 0 -100svh; }
  .hy-track > .hy-root { position: relative; height: auto; flex-direction: column; }
  .hy-track .hy-word { filter: drop-shadow(0 0 26px rgba(255, 255, 255, 0.28)); translate: none; }
  .hy-track .hy-turn, .hy-track .hy-subject { filter: none; translate: none; scale: none; }
  .hy-story,
  .hy-root .hy-questions,
  .hy-root .hy-portrait,
  .hy-then-now,
  .hy-quote,
  .hy-root .hy-video {
    position: relative;
    top: auto; right: auto; bottom: auto; left: auto;
    width: auto;
    max-width: 40rem;
    margin: 2rem auto 0;
    padding-inline: var(--gutter);
    opacity: 1;
    transform: none;
    translate: none;
    scale: none;
  }
  .hy-root .hy-video { max-width: 48rem; align-self: stretch; margin-bottom: 3rem; }
  .hy-root .hy-portrait { width: min(60vw, 280px); height: auto; padding-inline: 0; }
  .hy-portrait img { filter: none; opacity: 1; }
  .hy-then-now { align-self: stretch; max-width: var(--container); margin-bottom: 2rem; }
  .hy-card--then, .hy-card--now { translate: none; opacity: 1; }
  .hy-story h2 { font-size: 30px; }
  .hy-story p { font-size: 18px; }
  .hy-questions .split-questions p { font-size: 20px; }
  .hy-questions > p.body-text { font-size: 15px; }
  .hy-quote { margin-bottom: 3rem; }
  .hy-quote p { font-size: 26px; }
  .hy-track .sfx-w { opacity: 1; }
}

/* --- 10 Scrollspy: активный пункт меню -------------------------------------
   Горит пункт того раздела, в котором сейчас середина экрана; класс ставит
   js/scroll-fx.js. У .nav-pill a ::before занят заливкой при наведении,
   поэтому черта - на ::after. */
.nav-pill a.is-current { color: var(--fg); }
.nav-pill a.is-current::after { content: ""; position: absolute; left: 50%; bottom: .34rem; width: 16px; height: 1px; margin-left: -8px; background: var(--accent); }
.mobile-panel a.is-current { color: var(--fg); }

/* --- 11 Marker: охряная полоса под ключевой фразой --------------------------
   Тянется слева направо, пока фраза идёт от 82% высоты экрана к 52%. */
.sfx-mark { color: inherit; background: linear-gradient(rgba(209, 128, 63, .42), rgba(209, 128, 63, .42)) no-repeat 0 92% / calc(var(--p, 0) * 100%) .38em; padding: 0 .06em; }

/* --- 12 Path Draw: линия через пункты списка --------------------------------
   Кривую строит скрипт по точкам, поставленным у каждого пункта. */
.sfx-path { position: relative; }
.sfx-path-svg { position: absolute; left: 0; top: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.sfx-path-svg path { fill: none; stroke-linecap: round; }
.sfx-path-bg { stroke: var(--border); stroke-width: 1; }
.sfx-path-line { stroke: var(--accent); stroke-width: 2; stroke-dasharray: 1; stroke-dashoffset: 1; }
.sfx-path .help-list { gap: 1.5rem; }
.sfx-path .help-list li { padding-left: 2rem; }
.sfx-path .help-list li::before { display: none; }
.sfx-path .help-list li:nth-child(even) { margin-left: clamp(0px, 4vw, 3rem); }
/* Список «Направления работы» в Центре: без position:relative все точки пути складывались
   в одну на первой букве, а линия вырождалась в точку (скрин заказчика 2026-10-01). */
/* Зигзаг как у .help-list (просьба 2026-10-02), но сдвигом поля, а не margin: разделители
   пунктов остаются во всю ширину. --lp - верхнее поле пункта, его меняют ужимающие
   правила раздела 10 ниже; точка стоит на первой строке (line-height 1.5 -> .75em). */
.center-directions li { --lp: .85rem; } /* нарочно слабый селектор: ужимающие правила ниже его перебивают */
.sfx-cs-center .sfx-path .center-directions li { --zz: clamp(0px, 4vw, 3rem); position: relative; padding-left: 1.75rem; }
.sfx-cs-center .sfx-path .center-directions li:nth-child(even) { padding-left: calc(1.75rem + var(--zz)); }
.sfx-path .center-directions .sfx-path-dot { left: 6px; top: calc(var(--lp, .85rem) + .75em); margin-top: -5.5px; }
.sfx-path .center-directions li:nth-child(even) .sfx-path-dot { left: calc(6px + var(--zz, 0px)); }
.sfx-path-dot { position: absolute; left: 0; top: .5em; width: 11px; height: 11px; margin-left: -5px; border-radius: 50%; background: var(--bg); border: 1px solid var(--border-strong); transition: background .3s var(--ease-out), border-color .3s var(--ease-out), transform .3s var(--ease-out); }
.sfx-path li.is-past .sfx-path-dot { background: var(--accent); border-color: var(--accent); transform: scale(1.25); }

/* --- 14 Assemble: финальная фраза собирается из слов ------------------------ */
/* Приклеивание снято 2026-09-21: кадр во весь экран ради одной строки давал
   пустую полосу над формой. Фраза собирается по месту на экране, ход --pin
   ставит js (paintAs), пока блок въезжает снизу. */
.sfx-as { position: relative; }
.sfx-as-sticky { display: flex; align-items: center; justify-content: center; overflow: hidden; padding: clamp(2rem, 6svh, 4rem) 0; }

/* --- 15 Split Doors + Strike Through ----------------------------------------
   Створки лежат поверх панели и разъезжаются, пока панель въезжает в экран:
   без закрепления, поэтому низкая панель не обрезается. Зачёркивание идёт
   следом, по строкам «Не ...». */
.sfx-doors { position: relative; overflow: hidden; }
.sfx-door { --e: calc(var(--p, 0) * var(--p, 0) * (3 - 2 * var(--p, 0))); position: absolute; top: 0; bottom: 0; z-index: 3; width: 50.5%; display: flex; align-items: center; background: var(--bg-raised-2); }
.sfx-door--l { left: 0; justify-content: flex-end; border-right: 1px solid var(--border-strong); transform: translateX(calc(var(--e) * -101%)); }
.sfx-door--r { right: 0; justify-content: flex-start; border-left: 1px solid var(--border-strong); transform: translateX(calc(var(--e) * 101%)); }
.sfx-door span { font-family: var(--font-display); font-size: clamp(1.8rem, 6vw, 5rem); line-height: 1; white-space: nowrap; padding: 0 .12em; }
.sfx-door--r span { color: var(--accent-strong); }
.sfx-strike { background: linear-gradient(var(--accent), var(--accent)) no-repeat 0 60% / calc(var(--p, 0) * 100%) .08em; color: color-mix(in srgb, currentColor calc(100% - var(--p, 0) * 55%), transparent); }
.sfx-keep { color: color-mix(in srgb, currentColor calc(100% - var(--p, 0) * 100%), var(--accent-strong)); }

/* название раздела над текстом истории: кегль ставит js - чуть крупнее заголовка
   блока, шрифт и начертание те же. Пока надпись крупная, текст под ней притушен,
   иначе она легла бы поверх заголовка и абзацев */
.hy-story p.hy-story-label { margin: 0 0 clamp(1.8rem, 8svh, 5rem);   /* отдельно от текста, просьба 2026-09-21; в svh - чтобы блок не выдавило из кадра на 900 */ font-family: var(--font-display); font-weight: 500;
  font-size: inherit; line-height: 1.1; letter-spacing: -.02em; color: var(--fg); white-space: nowrap;
  transform-origin: 0 0; will-change: transform; }   /* p.: иначе .hy-story p перебивает шрифт на Manrope */
.hy-story-label a { color: inherit; pointer-events: auto; text-decoration: none; }
.hy-story-label a:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 5px; }
.hy-story h2, .hy-story > p:not(.hy-story-label) { opacity: var(--lt-text, 1); }

/* --- 16 Large Title Collapse: заголовок страницы ужимается в шапку ----------
     Полоску под меню создаёт скрипт; заголовок едет и ужимается по вёрстке,
     так что в конце совпадает с текстом полоски. */
.sfx-collapse { transform-origin: 0 0; will-change: transform; }
.sfx-cbar { position: fixed; left: 0; right: 0; top: var(--nav-h); z-index: 40; height: 3rem; display: flex; align-items: center; background: rgba(12, 12, 12, .86); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); border-bottom: 1px solid var(--border); opacity: 0; pointer-events: none; }
.sfx-cbar.is-on { opacity: 1; }
.sfx-cbar-text { font-family: var(--font-display); font-size: 1.3rem; line-height: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* --- 17 Rotating Seal: круглая надпись поворачивается от прокрутки ---------- */
.sfx-seal { position: relative; width: clamp(7.5rem, 14vw, 11rem); aspect-ratio: 1; }
.sfx-seal svg { width: 100%; height: 100%; display: block; transform: rotate(calc(var(--seal, 0) * 1deg)); will-change: transform; }
.sfx-seal text { font-family: var(--font-mono); font-size: 11.5px; text-transform: uppercase; fill: var(--fg-muted); }
.sfx-seal-core { position: absolute; inset: 29%; border-radius: 50%; border: 1.5px solid var(--accent); box-shadow: 0 0 0 8px rgba(209, 128, 63, .1); display: flex; align-items: center; justify-content: center; font-family: var(--font-mono); font-size: .62rem; letter-spacing: .1em; text-transform: uppercase; color: var(--accent-strong); }
.reels-hero-inner { position: relative; }
@media (min-width: 900px) { .reels-hero-inner .sfx-seal { position: absolute; right: 0; top: 50%; transform: translateY(-50%); } }
@media (max-width: 899.98px) { .reels-hero-inner .sfx-seal { margin-top: 2rem; } }

/* --- 18 Word Swap: слово в строке меняется ---------------------------------- */
/* Приклеивание снято по решению заказчика 2026-09-16. Кадр во весь экран
   оставлял под содержимым 215-237px пустоты, а укоротить его было нельзя: ход
   --pin считается как высота блока минус экран, и при коротком кадре слова
   домениваются раньше открепления. Без приклеивания секция занимает свою
   высоту без остатка; три слова стоят стопкой, смены на прокрутке нет,
   поэтому data-sfx-pin и data-sfx-ws с разметки сняты. */
/* Перестройка 2026-10-01 (заказчик: «блок кривой весь»). Было: три слова башней,
   под ними абзац слева и узкая сетка 2x2 справа, которая уходила ниже абзаца;
   заголовки карточек стояли на разной высоте (space-between при разной длине
   описаний). Стало: заголовок и слова по центру, слова одной строкой
   (башня - только на телефоне), абзац по центру и кнопка под ним, ниже ряд из
   четырёх одинаковых карточек: кадр 3:2, заголовок, описание - всё на одних
   линиях. Кегль абзаца прежний, как у рилсов и «Работ». До правки - _before-lib2/. */
.sfx-ws { position: relative; }
.sfx-ws-sticky { display: flex; flex-direction: column; align-items: center; gap: clamp(.9rem, 2.4svh, 1.75rem); padding: .5rem 0 0; }
.sfx-ws-sticky h2,
.sfx-ws-sticky .sfx-ws-slot { text-align: center; margin: 0; text-wrap: balance; }
.sfx-ws-sticky .sfx-notes { width: 100%; }
.sfx-ws-sticky .sfx-notes .lede { max-width: 42ch; margin: 0 auto; text-align: center; text-wrap: balance; font-size: clamp(1.4rem, 2.4vw, 2.1rem); line-height: 1.35; color: var(--fg); }
.sfx-ws-sticky .library-foot { margin-top: clamp(1.25rem, 3svh, 2rem); justify-content: center; }
/* 2026-10-01, заказчик: кнопка библиотеки крупнее. Было как у всех кнопок сайта - 0.98rem,
   поля .85rem 1.6rem (52px высоты). До правки - _before-lib-btn/. */
.sfx-ws-sticky .library-foot .btn { font-size: clamp(1.08rem, 1.3vw, 1.25rem); padding: clamp(1.05rem, 1.5vw, 1.25rem) clamp(2.1rem, 3vw, 2.75rem); }
/* 2026-10-01, заказчик: кегли поменяны местами - заголовок взял кегль трёх слов,
   три слова - кегль заголовка (.display-2: clamp(1.9rem, 4.2vw, 3.2rem)). До правки - _before-lib-swap/. */
/* 2026-10-01, заказчик ещё раз: заголовок ещё крупнее (было clamp(2.4rem, 4.6vw, 4.2rem), 66px
   на 1440), три слова чуть мельче (было clamp(1.9rem, 4.2vw, 3.2rem), 51px). До правки - _before-lib-size2/. */
.sfx-ws-sticky h2 { font-size: clamp(2.8rem, 5.8vw, 5.4rem); line-height: 1.05; }
.sfx-ws-slot { display: block; font-family: var(--font-display); font-size: clamp(1.7rem, 3.6vw, 2.75rem); line-height: 1.08; letter-spacing: -.01em; }
.sfx-ws-list { display: block; }
.sfx-ws-list span { display: inline-block; }
.sfx-ws-list span + span { margin-left: .3em; }
.sfx-ws-list span:nth-child(2) { color: var(--accent-strong); }

/* --- 19 Sidenotes: источники проявляются по ходу чтения --------------------- */
.sfx-notes { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(1.75rem, 4svh, 2.75rem); }
/* линии между карточками - обводкой самих карточек, а не фоном сетки: пока карточка
   не проявилась, фон сетки стоял серой плитой на её месте */
.sfx-notes .library-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); background: none; }
.sfx-notes .library-link { outline: 1px solid var(--border); }
.sfx-notes .library-link { min-height: 0; justify-content: flex-start; gap: .55rem; padding: clamp(1rem, 1.6vw, 1.4rem); }
.sfx-notes .library-link .wm-frame--card { margin: 0 0 .45rem; overflow: hidden; }
.sfx-notes .library-link .wm-frame--card canvas { transition: transform .4s var(--ease-out); }
.sfx-notes .library-link:hover .wm-frame--card canvas { transform: scale(1.04); }
.sfx-notes .library-link-top { gap: .75rem; font-size: clamp(1rem, 1.25vw, 1.12rem); line-height: 1.2; }
.sfx-notes .library-link p { line-height: 1.5; }
.sfx-note { opacity: 0; transform: translateY(12px); transition: opacity .45s var(--ease-out), transform .45s var(--ease-out); }
.sfx-note.is-on { opacity: 1; transform: none; }
@media (max-width: 999.98px) { .sfx-notes .library-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 760px) {
  .sfx-ws-list span { display: block; }
  .sfx-ws-list span + span { margin-left: 0; }
}
/* телефон: карточка в строку - кадр слева, текст справа, иначе четыре кадра 3:2 столбиком - это два экрана */
@media (max-width: 520px) {
  .sfx-notes .library-grid { grid-template-columns: minmax(0, 1fr); }
  .sfx-notes .library-link { display: grid; grid-template-columns: minmax(0, 42%) minmax(0, 1fr); grid-template-rows: auto 1fr; column-gap: .9rem; row-gap: .35rem; align-items: start; }
  .sfx-notes .library-link .wm-frame--card { grid-row: 1 / span 2; margin: 0; }
  .sfx-notes .library-link p { font-size: .84rem; }
}

/* --- 20 Accordion Panels: «Работы» раскрываются по очереди ------------------ */
.sfx-acc { position: relative; height: 280svh; }
.sfx-acc-sticky { position: sticky; top: 0; height: 100svh; display: flex; align-items: center; overflow: hidden; }
.sfx-acc-sticky > .portfolio-section { width: 100%; padding-top: calc(var(--nav-h) + 2svh); padding-bottom: 3svh; }
.sfx-acc-sticky .portfolio-head { margin-bottom: clamp(1.25rem, 3svh, 2.25rem); }
.sfx-acc-row { display: flex; gap: .75rem; height: min(62svh, 520px); }
/* Картинки панелей плывут по прокрутке (просьба 2026-10-01): холст чуть
   увеличен и сдвигается по --drift, пока раскрыта его панель. Увеличение 14%
   больше сдвига 6%, поэтому края кадра не показываются. Коробка обрезает
   увеличенный холст. Холст рисует js/watchman-fx.js, его код не тронут:
   transform не меняет размеры холста и перерисовки не вызывает. */
.sfx-acc-panel .wm-panel-art { overflow: hidden; }
.sfx-acc-panel .wm-panel-art canvas { transform: translate3d(calc(var(--drift, 0) * -6%), calc(var(--drift, 0) * -3%), 0) scale(1.14); will-change: transform; }
.sfx-acc-panel { --w: 0; position: relative; flex: calc(1 + var(--w) * 5) 1 0; min-width: 0; border: 1px solid var(--border); border-radius: 18px; background: linear-gradient(160deg, rgba(209, 128, 63, calc(var(--w) * .16)), transparent 55%), var(--bg-raised); overflow: hidden; }
.sfx-acc-num { position: absolute; top: 1rem; left: 1rem; font-family: var(--font-mono); font-size: .75rem; letter-spacing: .1em; color: var(--accent); }
.sfx-acc-spine { position: absolute; left: 1rem; bottom: 1.2rem; writing-mode: vertical-rl; transform: rotate(180deg); font-family: var(--font-display); font-size: clamp(1rem, 1.6vw, 1.35rem); white-space: nowrap; opacity: calc(1 - var(--w)); }
.sfx-acc-body { position: absolute; left: clamp(1.25rem, 3vw, 2.5rem); bottom: clamp(1.25rem, 3vw, 2.5rem); width: min(32rem, 50vw); opacity: clamp(0, calc((var(--w) - .55) / .45), 1); pointer-events: none; }
.sfx-acc-panel.is-open .sfx-acc-body { pointer-events: auto; }
.sfx-acc-body .portfolio-tag { position: static; display: inline-block; margin-bottom: .4rem; }
.sfx-acc-body h3 { font-size: clamp(1.3rem, 2.6vw, 2.2rem); line-height: 1.12; margin: .4rem 0 .7rem; }
.sfx-acc-body p { color: var(--fg-muted); line-height: 1.6; max-width: 38ch; margin: 0 0 1.25rem; }
@media (max-width: 760px) {
  .sfx-acc { height: 240svh; }
  .sfx-acc-row { flex-direction: column; height: 62svh; }
  .sfx-acc-spine { writing-mode: horizontal-tb; transform: none; left: 3.2rem; top: .85rem; bottom: auto; font-size: 1rem; }
  .sfx-acc-num { top: .95rem; }
  .sfx-acc-body { width: auto; right: 1.25rem; }
  .sfx-acc-body p { font-size: .92rem; margin-bottom: .9rem; }
}
/* Телефон, просьбы 2026-10-01/02: «анимацию видно полностью, без затемнения»,
   затем «больше, без обрезки». Было: кадр на всю панель под текстом,
   прозрачность .5 и маска, гаснущая к середине (css/watchman-fx.css).
   Стало: панель - сетка из двух рядов, кадр сверху во весь остаток высоты
   и во всю ширину карточки (боковых полей нет), текст под ним. Коробка кадра
   держит 16:9 через единицы контейнера, поэтому cover-кадр виден целиком;
   сдвиг-увеличение по прокрутке на телефоне снято. Высоту под кадр собрали
   отовсюду понемногу: ряд 100svh минус навигация и 11.5rem шапки раздела,
   раскрытой панели 15/18 ряда, корешки не ниже 2.75rem, поля текста плотнее,
   у абзаца снят предел 38ch (на телефоне он только добавлял строк).
   Селекторы длиннее, чем нужно, нарочно: watchman-fx.css грузится позже. */
@media (max-width: 760px) {
  .sfx-acc-sticky { align-items: flex-start; } /* лишнее уходит в нижнее поле секции, а не под навигацию */
  .sfx-acc-row { height: calc(100svh - var(--nav-h) - 11.5rem); }
  .sfx-acc-row .sfx-acc-panel { flex: calc(1 + var(--w) * 14) 1 0; min-height: 2.75rem; display: grid; grid-template-rows: minmax(0, 1fr) auto; }
  .sfx-acc-row .sfx-acc-panel .wm-panel-art { position: relative; inset: auto; width: auto; min-height: 0; margin: 2.25rem 0 .25rem; opacity: var(--w, 0);
    -webkit-mask-image: none; mask-image: none; container-type: size; display: grid; place-items: center; }
  .sfx-acc-row .sfx-acc-panel .wm-panel-art canvas { width: min(100cqw, 100cqh * 16 / 9); height: min(100cqh, 100cqw * 9 / 16); transform: none; will-change: auto; }
  .sfx-acc-row .sfx-acc-panel .sfx-acc-body { position: static; width: auto; padding: 0 1.25rem 1rem; }
  .sfx-acc-row .sfx-acc-panel .sfx-acc-body h3 { margin: .3rem 0 .5rem; }
  .sfx-acc-row .sfx-acc-panel .sfx-acc-body p { margin-bottom: .75rem; max-width: none; }
}
}

/* --- 21 Split Text: заголовок раскалывается пополам ------------------------- */
.sfx-split { --e: clamp(0, calc((var(--p, 0) - .1) / .5), 1); position: relative; display: inline-block; }
.sfx-split-t { display: inline-block; clip-path: inset(0 0 50% 0); transform: translateX(calc(var(--e) * -.16em)); }
.sfx-split-b { position: absolute; left: 0; top: 0; clip-path: inset(50% 0 0 0); transform: translateX(calc(var(--e) * .16em)); color: var(--accent-strong); }
.sfx-split-seam { position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--accent); transform: scaleX(var(--e)); transform-origin: left; }

/* --- «уменьшить движение»: новые приёмы стоят в конечном состоянии ---------- */
@media (prefers-reduced-motion: reduce) {
  .sfx-mark { background-size: 100% .38em; }
  .sfx-door { display: none; }
  .sfx-strike { background-size: 100% .08em; }
  .sfx-collapse { transform: none; } .sfx-cbar { display: none; }
  .sfx-seal svg { transform: none; }
  .sfx-note { opacity: 1; transform: none; transition: none; }
  .sfx-acc { height: auto; } .sfx-acc-sticky { position: static; height: auto; } .sfx-acc-row { flex-direction: column; height: auto; } .sfx-acc-panel { flex: none; min-height: 14rem; } .sfx-acc-spine { display: none; }
  .sfx-acc-body { position: static; opacity: 1; width: auto; padding: 2.5rem 1.25rem 1.25rem; pointer-events: auto; }
  .sfx-split-t, .sfx-split-b { transform: none; } .sfx-split-seam { transform: none; }
}

/* --- 22 Grid Drift: дальний фон едет медленнее страницы ---------------------
   Слой создаёт js/scroll-fx.js на каждой странице. Сетка лежит в отдельном
   слое и сдвигается transform'ом: экран не перерисовывается каждый кадр.
   Шаг сетки 88px, сдвиг берётся по модулю шага - поэтому он бесконечный и без
   рывка. Маска на обёртке, иначе она поехала бы вместе с сеткой. */
.sfx-grid { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden;
  -webkit-mask-image: radial-gradient(120% 90% at 50% 0%, #000 30%, transparent 100%);
          mask-image: radial-gradient(120% 90% at 50% 0%, #000 30%, transparent 100%); }
.sfx-grid-in { position: absolute; left: 0; right: 0; top: -88px; bottom: -88px;
  background:
    repeating-linear-gradient(0deg, rgba(246, 243, 236, 0.04) 0 1px, transparent 1px 88px),
    repeating-linear-gradient(90deg, rgba(246, 243, 236, 0.04) 0 1px, transparent 1px 88px);
  transform: translate3d(0, calc(var(--sfx-drift, 0) * 1px), 0); will-change: transform; }

/* --- 23 Odometer: число прокручивается барабаном ----------------------------
   Каждая цифра - столбик из десяти знаков; скрипт крутит его до нужной цифры
   один раз, когда число появилось в кадре. Барабан заменяет досчёт (приём 05)
   на числах в шапке «Моей истории»: значение всегда верное, когда стоит. */
.sfx-odo { --cell: 1.12em; display: inline-flex; line-height: 1; font-style: normal; }
/* окно и ячейка чуть выше кегля: у цифры верх выступает над строкой, и обрезка
   срезала бы полоску. Отрицательные поля возвращают внешнюю высоту к 1em,
   поэтому вёрстка шапки не двигается */
.sfx-odo-col { display: block; height: var(--cell); margin-block: calc((1em - var(--cell)) / 2); overflow: hidden; font-style: normal; }
.sfx-odo-in { display: block; font-style: normal; transform: translateY(calc(var(--v, 0) * var(--cell) * -1)); }
.sfx-odo-d { display: block; height: var(--cell); line-height: var(--cell); font-style: normal; }

@media (prefers-reduced-motion: reduce) {
  .sfx-grid-in { transform: none; }
}


/* --- 24 Сцена «Консультации + Центр» (просьба 2026-09-16) -------------------
   Один приклеенный кадр на две панели. Слои лежат друг на друге, створки
   накрывают весь кадр. Ход задаёт js по --pin: линия, створки сходятся, слой
   подменяется, створки расходятся, вторая линия.
   Панели в кадр влезают только на просторном экране: при 900 высоты «Центр»
   вылезал на 174px, на телефоне обе панели лишние на 638 и 799. Поэтому ниже
   900px по ширине и 820px по высоте приклеивания нет - обычная прокрутка. */
.sfx-cs { position: relative; height: 320svh; }
/* Оба слоя лежат в одной ячейке сетки: высота ряда равна большей из панелей,
   и обе растягиваются до неё. Иначе коробка створок меняется при подмене слоя
   и дверь соскакивает - панели разные, 745 и 936 при 1250. */
.sfx-cs-sticky { position: sticky; top: var(--nav-h, 0px); height: calc(100svh - var(--nav-h, 0px)); overflow: hidden;
  display: grid; grid-template-columns: 1fr; align-content: center; }
.sfx-cs-layer { grid-area: 1 / 1; display: flex; align-items: stretch; padding: 0 var(--gutter); opacity: var(--vis, 1); }
.sfx-cs-layer > .panel { width: 100%; max-width: var(--container); margin: 0 auto; max-height: calc(100svh - var(--nav-h, 0px)); overflow: hidden; }
.sfx-cs-center { opacity: var(--vis, 0); }
.sfx-cs-center .center-media { align-self: center; } /* картинка по середине колонки текста, а не по верху (просьба 2026-10-02) */
/* Створки закрываются в границах панели, а не во весь кадр: заказчик обвёл
   красным именно панель. Ширина - колонка страницы, верх и высота приходят
   замером от видимой панели, они у слоёв разные (745 и 936 при 1250). */
.sfx-cs-doors { position: absolute; left: 50%; transform: translateX(-50%);
  width: min(100% - var(--gutter) * 2, var(--container));
  top: var(--dt, 0px); height: var(--dh, 100%); overflow: hidden; z-index: 5; pointer-events: none; }
.sfx-cs .sfx-door { z-index: 5; }
/* Панель консультаций растянута до высоты «Центра» ради неподвижных створок,
   и внутри повисал воздух: фото было квадратным, сетка центрировала текст.
   Теперь фото на всю высоту панели, текст по центру своей колонки. */
.sfx-cs-help > .panel { display: flex; flex-direction: column; }
.sfx-cs-help .help-grid { flex: 1; min-height: 0; align-items: stretch; }
/* Снимок консультации 1600x900, на нём двое: Пётр справа (лицо на 64.9-74.2%
   ширины) и клиент слева. Растягивать его на всю высоту панели нельзя: колонка
   580x876, при заполнении по высоте видно 37% ширины и лицо Петра срезается
   справа (2026-09-22). Возвращён квадратный кадр из исходной вёрстки - 56%
   ширины, оба человека в кадре; остаток колонки делится поровну сверху и
   снизу, а не копится внизу. */
.sfx-cs-help .help-media { display: flex; align-items: center; }
.sfx-cs-help .help-media img { height: auto; }
.sfx-cs-help .help-content { display: flex; flex-direction: column; justify-content: center; }
.sfx-cs-help .help-content > .btn { align-self: center; } /* иначе flex растягивает кнопку на всю колонку */
/* «Центр» на 900 высоты не помещался: ужимаем поля и картинку внутри сцены */
@media (max-height: 950px) {
  .sfx-cs-layer > .panel { padding: clamp(1.25rem, 2.4vh, 2rem); }
  .sfx-cs-center .center-media img { max-height: 42svh; object-fit: cover; }
  /* строки «Не ...» крупнее с 2026-10-01; на низком экране кегль 1rem, иначе «Центр» вылезал из кадра на 73px при 900 */
  .sfx-cs-center .center-negatives p { font-size: 1rem; line-height: 1.45; }
  /* строки «Не ...» и здесь крупнее (2026-10-01); место под них в кадре - из полей пунктов «Направлений», ниже */
  .sfx-cs-center .center-negatives p:not(:last-child) { font-size: clamp(1.3rem, 1.75vw, 1.5rem); line-height: 1.25; }
}
/* Панель «Центра» в приклеенной сцене не влезала в кадр ниже 1100px высоты:
   при 900 сетка 824 при доступных 771, переполнение прятала обрезка. Было и
   до крупных строк «Не ...» - прежняя проверка мерила высоту панели, а она
   упирается в потолок. Ужимаем воздух: промежуток рядов и поля пунктов. */
@media (min-width: 900.02px) and (max-height: 1100px) {
  .sfx-cs-center .center-inner { row-gap: 1.25rem; }
  .sfx-cs-center .center-directions li { padding: 0.55rem 0; --lp: .55rem; }
}
/* 2026-10-01: крупные строки «Не ...» добавили «Центру» 14px - на 1536x864 панель
   обрезалась на 15px. Место берём из полей пунктов «Направлений» (было 0.55rem). */
@media (min-width: 900.02px) and (max-height: 950px) {
  .sfx-cs-center .center-directions li { padding: 0.42rem 0; --lp: .42rem; }
}
@media (max-width: 900px), (max-height: 820px) {
  .sfx-cs { height: auto; }
  .sfx-cs-sticky { position: static; height: auto; overflow: visible; display: block; }
  .sfx-cs-layer { display: block; opacity: 1; padding: 0; }
  .sfx-cs-layer > .panel { max-height: none; overflow: visible; }
  .sfx-cs-help { margin-bottom: var(--sp-section); }
  .sfx-cs .sfx-door, .sfx-cs-doors { display: none; }
}

/* --- Вопросы на телефоне: к верху под меню, а не по центру ------------------
   Центрирование в кадре давало 28% пустоты над блоком (просьба 2026-09-21).
   Стоит в конце файла нарочно: медиазапросы веса не добавляют, побеждает
   порядок, и это правило перекрывает и центрирование, и блок «уменьшить
   движение». Въезд снизу через --rise сохранён, приземление у верха. */
@media not all and (min-width: 1024px) and (min-aspect-ratio: 6/5) {
  /* Содержимое собрано в плотную группу и центрировано целиком (просьба
     2026-09-22 «оцентруй по вертикали»). Было space-evenly - оно заполняло низ
     по просьбе от 2026-09-21, но разводило вопросы и абзац на 120px, и блок
     читался как два куска. Требования противоположны, выбрано последнее. */
  .hy-root .hy-questions { top: calc(var(--nav-h) + 3.5svh); min-height: calc(100% - var(--nav-h) - 7svh);   /* 3.5 из 7: поровну сверху и снизу, иначе блок выше центра на 9px */ transform: translateY(calc((1 - var(--rise, 1)) * 100svh));
    display: flex; flex-direction: column; justify-content: center; gap: clamp(1rem, 4svh, 2.5rem); }   /* не ниже кадра: вопросы и абзац распределены по нему; при жёстком bottom абзац на 375x667 вылезал на 8px */
}

/* --- Узкий телефон: кегль карточек как на низком ---------------------------
   Правило мелкого кегля было привязано к высоте до 720px, и высокий узкий
   экран (360x740) в него не попадал: текст давал слишком много строк, верхняя
   карточка вырастала до 283px, и пара вылезала из кадра на 98px. В конце файла
   нарочно - перекрывает оба блока выше. */
@media (max-width: 389.98px) {
  .hy-card h3 { font-size: clamp(16px, min(2.7svh, 4.65vw), 19px); }
  .hy-card p { font-size: clamp(13.5px, min(2.2svh, 3.8vw), 15.5px); }
}

/* --- Нижняя карточка: снимок сверху во всю ширину (решение заказчика 2026-09-22) ---
   Только на телефонах выше 700px. На 375x667 под полосу фото остаётся не
   более 117px при 426px текста и зазоров: это уже не фотография, а полоска,
   и окно кадра сжимается до 36% высоты - подбородок уходит за край. Там
   остаётся прежний вид с фото слева, он в кадр помещается.
   Высота полосы в svh, окно смещено к лицу (оно на 28-59% высоты снимка):
   по ширине не режется вовсе, по высоте видно около половины. */
@media (max-width: 699.98px) and (min-height: 700px) {
  .hy-root .hy-card--now { flex-direction: column; }
  .hy-card--now .compare-photo { flex: none; width: 100%; height: clamp(150px, 26svh, 280px); }   /* 28svh давало на 390x844 запас в 4px - в пределах погрешности шрифта */
  /* Снимок вписан целиком, не обрезан ни по одной стороне (просьба 2026-09-22
     «по горизонту режет»). Во всю ширину полосы он не помещается: при ширине
     388 полной высоте отвечает 432px, и на текст остаётся 125 при нужных 235.
     Поэтому по бокам остаётся фон карточки, а снимок мельче. */
  .hy-card--now .compare-photo--now img { object-fit: contain; object-position: center; background: var(--bg); }
}

/* --- Хвостовые отступы: текст сидит выше центра ----------------------------
   Отступ последнего абзаца входит в высоту блока, но не виден, и центрирование
   считает его за содержимое: на 1920x1200 история стояла выше центра на 26px.
   Снимаем у последних детей обоих блоков. */
.hy-story > p:last-child,
.hy-questions > p.body-text:last-child,
.hy-questions .split-questions p:last-child { margin-bottom: 0; }

/* картинки панелей «Работ» без движения при «уменьшить движение» */
@media (prefers-reduced-motion: reduce) {
  .sfx-acc-panel .wm-panel-art canvas { transform: none; }
}
