/* ============================================================
   scroll-fx.css — hiệu ứng cuộn "big wow" cho index (nạp SAU style.css).
   Quy ước: dùng individual properties (translate/scale/rotate) để không
   đụng transform/opacity mà .reveal và hệ hero đang sở hữu trên cùng phần tử.
   ============================================================ */

/* ---------- A. Word-by-word heading reveal (JS split span.w) ---------- */

html.js .section__title .w,
html.js .facts__title .w {
  display: inline-block;
  opacity: 0;
  translate: 0 0.6em;
  scale: 0.96;
  transition:
    opacity var(--dur-long) var(--ease-out),
    translate var(--dur-long) var(--ease-out),
    scale var(--dur-long) var(--ease-out);
  transition-delay: calc(var(--wi, 0) * 55ms);
}

html.js .words-in .w {
  opacity: 1;
  translate: 0 0;
  scale: 1;
}

/* ---------- B. Hero entrance choreography — pattern y hệt .ch:
   paused mặc định, html.hero-go (main.js thêm lúc parse) mới chạy đồng hồ.
   Delay > 0.9s để stagger lộ đúng lúc preloader (850ms) mờ dần.
   Không đụng .hero__scroll — nó dùng translate để căn giữa. ---------- */

@keyframes fx-hero-rise {
  from { opacity: 0; translate: 0 1.25rem; }
}

html.js .hero__label,
html.js .hero__real,
html.js .hero__tagline,
html.js .hero__cta .btn {
  animation: fx-hero-rise 0.7s var(--ease-out) both;
  animation-play-state: paused;
}

html.hero-go .hero__label   { animation-delay: 0.9s;   animation-play-state: running; }
html.hero-go .hero__real    { animation-delay: 1.0s;   animation-play-state: running; }
html.hero-go .hero__tagline { animation-delay: 1.12s;  animation-play-state: running; }
html.hero-go .hero__cta .btn { animation-delay: 1.26s; animation-play-state: running; }
html.hero-go .hero__cta .btn:last-child { animation-delay: 1.36s; }

/* ---------- C. Card 3D tilt — about/metrics/awards (SDT only).
   `rotate: x` individual property compose với transform của .reveal.
   Firefox non-SDT: không tilt (có wipe + reveal lớn hơn) — precedent cũ. ---------- */

/* pop ở 82% — gần hết entry range; scale dùng ease-in-out không được
   trong view() timeline linear, nên tự vẽ đường cong: hold phẳng tới 82%
   rồi 3 bước giữa nảy mượt kiểu spring lên scale 1 */
@keyframes fx-tilt {
  0%   { rotate: x var(--tilt, 14deg); scale: 0.8; translate: 0 4rem; opacity: 0.3; }
  38%  { rotate: x calc(var(--tilt, 14deg) * 0.9); translate: 0 3.4rem; opacity: 0.6; }
  72%  { scale: 0.8; }
  79%  { scale: 0.965; }
  86%  { scale: 0.985; }
  92%  { scale: 0.995; }
  100% { rotate: x 0deg; scale: 1; translate: 0 0; opacity: 1; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .stats,
    .awards,
    .facts__list,
    .contact__socials,
    .about__grid { perspective: 1100px; }

    .stat-card,
    .award,
    .facts__row,
    .contact-chip,
    .about__lede {
      --tilt: 14deg;
      animation: fx-tilt auto linear both;
      animation-timeline: view();
      /* cover 25%: range dài hơn entry — cùng biên độ nhưng trải ra quãng
         cuộn dài hơn → chậm và mượt hơn hẳn */
      animation-range: entry 0% cover 25%;
    }

    /* card dẫn nghiêng mạnh hơn — lớp gần nhất */
    .stat-card--lead { --tilt: 18deg; }
    .about__lede { --tilt: 8deg; }

    @media (max-width: 48rem) {
      .stat-card, .award, .facts__row, .contact-chip, .about__lede { --tilt: 8deg; }
    }
  }
}

/* ---------- D. Reveal wipe — opt-in (.reveal--wipe): clip-path mở từ dưới lên.
   Inset âm giữ box-shadow không bị cắt. CHỈ ~15 phần tử structural —
   không wipe văn bản (paint đắt + chữ cắt giữa chừng xấu). ---------- */

html.js .reveal--wipe {
  clip-path: inset(100% -2% -2% -2%);
  transition:
    opacity var(--dur-long) var(--ease-out),
    transform var(--dur-long) var(--ease-out),
    clip-path var(--dur-long) var(--ease-out);
  /* shorthand reset delay về 0s — khai báo lại để stagger của .stats.stagger sống */
  transition-delay: var(--d, 0ms);
}

html.js .reveal--visible.reveal--wipe {
  clip-path: inset(-2% -2% -2% -2%);
}

/* ---------- E. Stack progress rail — thanh "you are here" cho #projects.
   --stack-p do initScrollFx (main.js) ghi, piggyback rAF loop sẵn có.
   Desktop ≥48.0625rem: mobile card position: static, rail vô nghĩa. ---------- */

@media (prefers-reduced-motion: no-preference) and (min-width: 48.0625rem) {
  .stack { position: relative; }

  .stack::before,
  .stack::after {
    content: '';
    position: absolute;
    inset-block: 0;
    inset-inline-start: calc(-1 * var(--space-md));
    inline-size: 2px;
    border-radius: var(--radius-pill);
  }

  .stack::after { background: var(--color-rule); }

  .stack::before {
    background: var(--color-ink);
    transform: scaleY(var(--stack-p, 0));
    transform-origin: 0 0;
  }
}

/* ---------- F. Marquee chữ khổng lồ — velocity-reactive (JS ghi --mx).
   aria-hidden, không data-i18n → check.mjs không scan; applyLangText không đụng. ---------- */

.marquee {
  overflow: clip;
  padding-block: var(--space-sm);
  pointer-events: none;
  user-select: none;
}

.marquee__track {
  display: flex;
  inline-size: max-content;
  white-space: nowrap;
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 0.95;
  font-size: clamp(4.5rem, 13vw, 12rem);
  letter-spacing: -0.02em;
  color: transparent;
  -webkit-text-stroke: 2px var(--color-rule);
  transform: translate3d(calc(var(--mx, 0px) * var(--dir, 1)), 0, 0);
  will-change: transform;
}

/* strip giữa tint bạc cho variety — token, theme-aware */
.marquee:nth-of-type(even) .marquee__track { -webkit-text-stroke-color: var(--color-silver); }

/* strip lẻ chạy ngược chiều */
.marquee:nth-of-type(odd) { --dir: -1; }

/* ---------- G. Reduced motion: tắt hẳn, không chỉ kẹp 150ms ---------- */

@media (prefers-reduced-motion: reduce) {
  html.js .section__title .w,
  html.js .facts__title .w {
    opacity: 1;
    translate: none;
    scale: none;
    transition: none;
  }

  html.js .hero__label,
  html.js .hero__real,
  html.js .hero__tagline,
  html.js .hero__cta .btn {
    animation: none;
  }

  html.js .reveal--wipe { clip-path: none; }

  .marquee { display: none; }
}
