/* Motion engine — reveals (scale/blur), parallax, count-up.
   Baseado em scroll + rect checks (NÃO depende de IntersectionObserver,
   que pode não disparar em alguns ambientes). Respeita reduced-motion. */

const REDUCED = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

function inView(el, frac) {
  const r = el.getBoundingClientRect();
  const h = window.innerHeight || document.documentElement.clientHeight;
  return r.top < h * (frac || 0.9) && r.bottom > 0;
}

/* ---- Reveal ---- */
function revealCheck() {
  const els = document.querySelectorAll(".reveal:not(.is-in)");
  els.forEach((el) => { if (REDUCED || inView(el)) el.classList.add("is-in"); });
}
function revealAll() {
  document.querySelectorAll(".reveal:not(.is-in)").forEach((el) => el.classList.add("is-in"));
}

/* ---- Count-up ---- */
function animateCount(el) {
  const raw = el.dataset.count;
  const target = parseFloat(raw);
  const dec = raw.indexOf(".") >= 0 ? 1 : 0;
  if (REDUCED) { el.textContent = target.toFixed(dec); return; }
  const dur = 1400, start = performance.now();
  function tick(now) {
    const p = Math.min(1, (now - start) / dur);
    const eased = 1 - Math.pow(1 - p, 3);
    el.textContent = (target * eased).toFixed(dec);
    if (p < 1) requestAnimationFrame(tick);
    else el.textContent = target.toFixed(dec);
  }
  requestAnimationFrame(tick);
}
function counterCheck() {
  const els = document.querySelectorAll("[data-count]:not([data-counted])");
  els.forEach((el) => {
    if (inView(el, 0.85)) { el.setAttribute("data-counted", ""); animateCount(el); }
  });
}

/* ---- Parallax ---- */
let parallaxEls = [];
function collectParallax() { parallaxEls = Array.from(document.querySelectorAll("[data-parallax]")); }
function parallaxFrame() {
  if (REDUCED) return;
  const vh = window.innerHeight;
  for (const el of parallaxEls) {
    const r = el.getBoundingClientRect();
    const off = (r.top + r.height / 2 - vh / 2) / vh;
    const f = parseFloat(el.dataset.parallax) || 0.1;
    el.style.transform = `translate3d(0, ${(-off * f * 100).toFixed(2)}px, 0)`;
  }
}

/* ---- Unified scroll loop ---- */
let ticking = false;
function frame() { ticking = false; revealCheck(); counterCheck(); parallaxFrame(); }
function onScroll() { if (!ticking) { ticking = true; requestAnimationFrame(frame); } }

let wired = false;
function initParallax() {
  collectParallax();
  if (!wired) {
    wired = true;
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", () => { collectParallax(); onScroll(); }, { passive: true });
  }
  onScroll();
}

/* Re-run after variant changes inject new nodes */
function refreshMotion() {
  collectParallax();
  revealCheck();
  counterCheck();
  parallaxFrame();
  setTimeout(revealCheck, 120);
  // failsafe: se NADA revelou (ambiente sem scroll/rAF), libera tudo
  setTimeout(() => {
    if (document.querySelectorAll(".reveal.is-in").length === 0) revealAll();
    counterCheck();
  }, 1800);
}

window.Motion = { REDUCED, initParallax, refreshMotion, revealCheck, revealAll };
