/* ============================================================
   МРЄ · герой, що розкривається при скролі
   Фото стартує компактною карткою по центру й розкривається на
   весь екран, поки читач гортає. Далі проявляються панель фактів
   і числа.

   Патерн узято зі Scroll Expansion Hero (21st.dev). Там він
   зроблений на Framer Motion, тут - на нативних scroll-driven
   animations: нуль байтів скриптів.

   Як влаштована математика діапазону.
   Секція має висоту 200vh, сцена всередині липка й заввишки
   100svh. Отже за таймлайном `cover` сцена приклеєна від 33%
   до 66% - саме в цьому вікні й відбувається розкриття.

   Базовий стан у CSS - КІНЦЕВИЙ (фото на весь екран, усе
   видно). Анімація вмикається лише там, де браузер її тягне.
   Тому без підтримки або з `prefers-reduced-motion` сторінка
   виглядає як звичайний повноекранний герой.
   ============================================================ */

.expand{position:relative;height:200vh}
.expand__stage{
  position:sticky;top:0;height:100svh;
  display:flex;align-items:center;overflow:hidden;isolation:isolate;
}

/* ---------- ТЛО: ЗРУЙНОВАНЕ МІСТО ---------------------------
   Нижній шар сцени. Лишається на місці, поки зелена картка
   розкривається поверх нього. Так сам скрол показує перехід
   від руйнування до відновлення.

   Знімок переведено в дуотон фірмовими кольорами напряму
   «Допомога ЗСУ»: бордовий у тінях, бежевий у світлах.
   Це водночас лікує головну проблему сцени - без суцільного
   темного тла білий заголовок губився на білому тлі сторінки
   всюди, де фото-картка його не перекривала.               */
.expand__bg{position:absolute;inset:0;z-index:-2;overflow:hidden}
.expand__bg img{
  width:100%;height:100%;object-fit:cover;
  filter:grayscale(1) contrast(1.1) brightness(.6);
}
.expand__bg::before{
  content:"";position:absolute;inset:0;
  background:linear-gradient(158deg,var(--c-bordo) 0%,#3A1A20 52%,var(--c-beige) 100%);
  mix-blend-mode:color;opacity:.9;
}
.expand__bg::after{
  content:"";position:absolute;inset:0;
  background:
    linear-gradient(76deg,rgba(22,9,11,.84) 0%,rgba(22,9,11,.62) 48%,rgba(22,9,11,.44) 100%),
    linear-gradient(0deg,rgba(22,9,11,.55) 0%,transparent 44%);
}

/* Рамка тримає фото і скрим, тому обрізаються вони разом. */
.expand__frame{
  position:absolute;inset:0;z-index:-1;
  clip-path:inset(0% 0% 0% 0% round 0px);
  box-shadow:0 40px 90px -30px rgba(0,0,0,.6);
}
.expand__img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:saturate(1.14) contrast(1.05);
  transform:scale(1);
}
.expand__frame::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(76deg,rgba(10,22,16,.86) 0%,rgba(10,22,16,.56) 48%,rgba(10,22,16,.18) 100%),
    linear-gradient(0deg,rgba(10,22,16,.5) 0%,transparent 46%);
}
.expand--cool .expand__frame::after{
  background:
    linear-gradient(76deg,rgba(8,18,32,.86) 0%,rgba(8,18,32,.56) 48%,rgba(8,18,32,.18) 100%),
    linear-gradient(0deg,rgba(8,18,32,.5) 0%,transparent 46%);
}

.expand__content{width:100%;position:relative;z-index:1}

/* Заголовок героя менший за загальний display: на 96px він
   виходив за свою колонку й налазив на скляну панель. Стеля
   ще нижча тому, що весь вміст мусить вміститися у 100svh -
   інакше сцена його обрізає згори й знизу.                   */
.expand .hero__title{
  font-size:clamp(2.25rem,1rem + 3.4vw,3.5rem);
  max-width:14ch;
}
.expand .hero__lead{margin-bottom:var(--s-5)}
.expand .facts>div{padding:var(--s-2) 0}
.expand__strip .stat__n{font-size:var(--t-h3)}
.expand__strip .glass-strip>*,
.expand__strip>*{padding:var(--s-4)}

/* Смуга чисел притиснута до низу сцени. */
.expand__strip{margin-top:var(--s-7)}

@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference) and (min-width:900px){
    :root:not([data-motion="off"]) .expand{
      view-timeline-name:--hero;
      view-timeline-axis:block;
    }
    :root:not([data-motion="off"]) .expand__frame{
      animation:frame-open linear both;
      animation-timeline:--hero;
      animation-range:cover 34% cover 60%;
    }
    :root:not([data-motion="off"]) .expand__img{
      animation:frame-settle linear both;
      animation-timeline:--hero;
      animation-range:cover 34% cover 66%;
    }
    :root:not([data-motion="off"]) .expand__title{
      animation:title-settle linear both;
      animation-timeline:--hero;
      animation-range:cover 34% cover 58%;
    }
    :root:not([data-motion="off"]) .expand__late{
      animation:late-in linear both;
      animation-timeline:--hero;
      animation-range:cover 46% cover 64%;
    }
    :root:not([data-motion="off"]) .expand__strip{
      animation:late-in linear both;
      animation-timeline:--hero;
      animation-range:cover 52% cover 68%;
    }
  }
}

@keyframes frame-open{
  from{clip-path:inset(17% 27% 17% 27% round 20px)}
  to{clip-path:inset(0% 0% 0% 0% round 0px)}
}
@keyframes frame-settle{
  from{transform:scale(1.18)}
  to{transform:scale(1)}
}
@keyframes title-settle{
  from{transform:scale(1.06) translateY(10px)}
  to{transform:none}
}
@keyframes late-in{
  from{opacity:0;transform:translateY(24px)}
  to{opacity:1;transform:none}
}

/* Підказка «гортайте». Зникає, щойно розкриття почалося. */
.expand__hint{
  position:absolute;left:50%;bottom:var(--s-6);translate:-50% 0;z-index:2;
  font-family:var(--f-head);font-size:var(--t-xs);letter-spacing:var(--ls-label);
  text-transform:uppercase;color:rgba(255,255,255,.7);
  display:none;
}
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference) and (min-width:900px){
    :root:not([data-motion="off"]) .expand__hint{
      display:block;
      animation:hint-out linear both;
      animation-timeline:--hero;
      animation-range:cover 34% cover 44%;
    }
  }
}
@keyframes hint-out{from{opacity:1}to{opacity:0}}

/* ---------- ЗАПАСНИЙ ПРИВІД -------------------------------
   Той самий рух там, де нативних scroll-driven animations
   немає: `js/enhance.js` рахує прогресію липкої фази і кладе
   її в змінну --p на секції, а вся геометрія лишається тут.

   Значення за замовчуванням --p:1 - це кінцевий стан. Тому
   якщо скрипт не завантажився, сцена виглядає так само, як
   без нього: повноекранне фото і весь текст на місці.       */
.js-expand .expand__frame{
  clip-path:inset(
    calc(17% * (1 - clamp(0,calc(var(--p,1) / .55),1)))
    calc(27% * (1 - clamp(0,calc(var(--p,1) / .55),1)))
    round calc(20px * (1 - clamp(0,calc(var(--p,1) / .55),1)))
  );
}
.js-expand .expand__img{
  transform:scale(calc(1 + .18 * (1 - clamp(0,calc(var(--p,1) / .66),1))));
}
.js-expand .expand__title{
  transform:scale(calc(1 + .05 * (1 - clamp(0,calc(var(--p,1) / .55),1))));
}
.js-expand .expand__late{
  opacity:clamp(0,calc((var(--p,1) - .38) / .22),1);
  transform:translateY(calc(24px * (1 - clamp(0,calc((var(--p,1) - .38) / .22),1))));
}
.js-expand .expand__strip{
  opacity:clamp(0,calc((var(--p,1) - .52) / .22),1);
  transform:translateY(calc(24px * (1 - clamp(0,calc((var(--p,1) - .52) / .22),1))));
}
.js-expand .expand__hint{
  display:block;
  opacity:clamp(0,calc(1 - var(--p,1) * 8),1);
}

/* На вузькому екрані секція не розтягується: там липкий герой
   на два екрани тільки заважає.                               */
@media (max-width:899px){
  .expand{height:auto}
  .expand__stage{position:static;height:auto;min-height:82svh;padding-block:var(--s-9)}
}

@media print{
  .expand{height:auto}
  .expand__stage{position:static;height:auto;min-height:0}
  .expand__frame,.expand__bg,.expand__hint{display:none}
}
