/*
  Scroll-linked reveals + spy via a single shared IntersectionObserver
  (ANIMATION_SPEC §3: no scroll-handler layout reads). Content is never gated
  behind these — everything is visible if JS is absent.
*/

/* ---------- Reveal-once (A2, A4, A8) ---------- */
const revealTargets = document.querySelectorAll<HTMLElement>('[data-reveal]');
if (revealTargets.length && 'IntersectionObserver' in window) {
  const revealObserver = new IntersectionObserver(
    (entries, obs) => {
      for (const entry of entries) {
        if (entry.isIntersecting) {
          entry.target.classList.add('is-revealed');
          obs.unobserve(entry.target);
        }
      }
    },
    { threshold: 0.2, rootMargin: '0px 0px -10% 0px' },
  );
  revealTargets.forEach((t) => revealObserver.observe(t));
} else {
  // No observer support: show everything immediately.
  revealTargets.forEach((t) => t.classList.add('is-revealed'));
}

/* ---------- Scroll-spy for same-page anchors (case-study MiniToc) ---------- */
const spySections = document.querySelectorAll<HTMLElement>('[data-spy]');
const spyLinks = new Map<string, HTMLElement>();
document.querySelectorAll<HTMLElement>('[data-spy-link]').forEach((link) => {
  const id = link.dataset.spyLink;
  if (id) spyLinks.set(id, link);
});

if (spySections.length && spyLinks.size && 'IntersectionObserver' in window) {
  const setActive = (id: string) => {
    spyLinks.forEach((link, key) => link.classList.toggle('is-active', key === id));
  };
  const spyObserver = new IntersectionObserver(
    (entries) => {
      for (const entry of entries) {
        if (entry.isIntersecting && entry.target.id) setActive(entry.target.id);
      }
    },
    { rootMargin: '-20% 0px -70% 0px', threshold: 0 },
  );
  spySections.forEach((s) => spyObserver.observe(s));
}
