// ─── Scroll reveal ───────────────────────────────────────── const reveals = document.querySelectorAll('.reveal'); const observer = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('visible'); observer.unobserve(e.target); } }); }, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' }); reveals.forEach(el => observer.observe(el)); // ─── Active nav link on scroll ────────────────────────────── const sections = document.querySelectorAll('section[id]'); const navLinks = document.querySelectorAll('.nav-links a'); window.addEventListener('scroll', () => { let current = ''; sections.forEach(s => { if (window.scrollY >= s.offsetTop - 120) current = s.id; }); navLinks.forEach(a => { a.style.color = a.getAttribute('href') === `#${current}` ? 'var(--mauve)' : ''; }); }); // ─── Project filters ────────────────────────────────────────────── const filterChips = document.querySelectorAll('.filter-chip'); const projectCards = document.querySelectorAll('#project-grid .project-card'); if (filterChips.length > 0 && projectCards.length > 0) { const applyFilter = (filter) => { projectCards.forEach(card => { const tech = (card.dataset.tech || '').split(/\s+/).filter(Boolean); const shouldShow = filter === 'all' || tech.includes(filter); card.classList.toggle('is-hidden', !shouldShow); }); }; filterChips.forEach(chip => { chip.addEventListener('click', () => { const selected = chip.dataset.filter || 'all'; filterChips.forEach(other => { other.classList.toggle('active', other === chip); }); applyFilter(selected); }); }); }