// Sticky nav background on scroll const nav = document.getElementById('nav'); const onScroll = () => { if (window.scrollY > 60) nav.classList.add('is-scrolled'); else nav.classList.remove('is-scrolled'); }; window.addEventListener('scroll', onScroll, { passive: true }); onScroll(); // Mobile burger (toggles a quick overlay menu) const burger = document.getElementById('burger'); if (burger) { burger.addEventListener('click', () => { const menu = document.querySelector('.nav__menu'); if (!menu) return; const open = menu.style.display === 'flex'; menu.style.display = open ? '' : 'flex'; menu.style.flexDirection = 'column'; menu.style.position = 'absolute'; menu.style.top = '100%'; menu.style.left = '0'; menu.style.right = '0'; menu.style.padding = open ? '' : '24px'; menu.style.background = open ? '' : 'rgba(245,242,236,.96)'; menu.style.color = open ? '' : '#1a1a1a'; menu.style.backdropFilter = 'blur(12px)'; }); } // Works filter const chips = document.querySelectorAll('.chip'); const cards = document.querySelectorAll('.grid .card'); chips.forEach(chip => { chip.addEventListener('click', () => { chips.forEach(c => c.classList.remove('is-active')); chip.classList.add('is-active'); const filter = chip.dataset.filter; cards.forEach(card => { const cat = card.dataset.cat; const show = filter === 'all' || cat === filter; card.style.display = show ? '' : 'none'; }); }); }); // Reveal-on-scroll const revealTargets = document.querySelectorAll( '.section__head, .card, .about__media, .about__text, .service, .post, .quote blockquote, .contact__inner' ); revealTargets.forEach(el => el.classList.add('reveal')); const io = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('is-in'); io.unobserve(entry.target); } }); }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' }); revealTargets.forEach(el => io.observe(el)); // Init AI Canvas Background for Hero initAICanvas(); function initAICanvas() { const canvas = document.getElementById('ai-canvas'); if (!canvas) return; const ctx = canvas.getContext('2d'); let width, height; function resize() { width = canvas.width = window.innerWidth; height = canvas.height = window.innerHeight; } window.addEventListener('resize', resize); resize(); const particles = []; const particleCount = window.innerWidth > 768 ? 120 : 60; for (let i = 0; i < particleCount; i++) { particles.push({ x: Math.random() * width, y: Math.random() * height, vx: (Math.random() - 0.5) * 0.5, vy: (Math.random() - 0.5) * 0.5, size: Math.random() * 2 + 0.5 }); } function draw() { ctx.clearRect(0, 0, width, height); // Draw lines ctx.lineWidth = 0.5; for (let i = 0; i < particleCount; i++) { for (let j = i + 1; j < particleCount; j++) { const dx = particles[i].x - particles[j].x; const dy = particles[i].y - particles[j].y; const dist = Math.sqrt(dx * dx + dy * dy); if (dist < 150) { ctx.strokeStyle = `rgba(0, 240, 255, ${0.2 - dist/150*0.2})`; ctx.beginPath(); ctx.moveTo(particles[i].x, particles[i].y); ctx.lineTo(particles[j].x, particles[j].y); ctx.stroke(); } } } // Draw particles ctx.fillStyle = 'rgba(0, 240, 255, 0.6)'; for (let i = 0; i < particleCount; i++) { const p = particles[i]; p.x += p.vx; p.y += p.vy; if (p.x < 0 || p.x > width) p.vx *= -1; if (p.y < 0 || p.y > height) p.vy *= -1; ctx.beginPath(); ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2); ctx.fill(); } requestAnimationFrame(draw); } draw(); }