// Debounce utility function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // Active navigation highlighting function initNavigation() { const sections = document.querySelectorAll('section[id]'); const navLinks = document.querySelectorAll('.nav-link'); if (!sections.length || !navLinks.length) return; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const id = entry.target.id; navLinks.forEach(link => { link.classList.remove('active'); if (link.getAttribute('href') === `#${id}`) { link.classList.add('active'); } }); } }); }, { rootMargin: '-30% 0px -70% 0px', threshold: 0 }); sections.forEach(section => observer.observe(section)); } // Mobile menu toggle function initMobileMenu() { const mobileMenuBtn = document.getElementById('mobile-menu-btn'); const mobileMenu = document.getElementById('mobile-menu'); const mobileMenuLinks = mobileMenu?.querySelectorAll('a'); if (!mobileMenuBtn || !mobileMenu) return; mobileMenuBtn.addEventListener('click', () => { mobileMenu.classList.toggle('open'); }); // Close menu when link is clicked mobileMenuLinks?.forEach(link => { link.addEventListener('click', () => { mobileMenu.classList.remove('open'); }); }); // Close menu on escape key document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { mobileMenu.classList.remove('open'); } }); } // Animate stats counters function animateStats() { const stats = document.querySelectorAll('[data-stat]'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const target = entry.target; const finalValue = parseInt(target.getAttribute('data-stat')); const duration = 1500; const startTime = performance.now(); function updateCounter(currentTime) { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); const currentValue = Math.floor(progress * finalValue); target.textContent = currentValue.toLocaleString(); if (progress < 1) { requestAnimationFrame(updateCounter); } else { target.textContent = finalValue.toLocaleString(); } } requestAnimationFrame(updateCounter); observer.unobserve(target); } }); }, { threshold: 0.5 }); stats.forEach(stat => observer.observe(stat)); } // Add fade-in animation to cards on scroll function initScrollAnimations() { const cards = document.querySelectorAll('.glass-card, .spec-block, .node-card, .benefit-card, .use-case-card, .component-card, .network-card, .learning-card, .path-card, .final-card'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('fade-in-up'); observer.unobserve(entry.target); } }); }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }); cards.forEach(card => observer.observe(card)); } // Smooth scroll for navigation links function initSmoothScroll() { const links = document.querySelectorAll('a[href^="#"]'); links.forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); const targetId = link.getAttribute('href'); const targetElement = document.querySelector(targetId); if (targetElement) { const headerOffset = 80; const elementPosition = targetElement.offsetTop; const offsetPosition = elementPosition - headerOffset; window.scrollTo({ top: offsetPosition, behavior: 'smooth' }); // Update URL without jumping history.pushState(null, null, targetId); } }); }); } // Parallax effect for hero background function initParallax() { const hero = document.getElementById('hero'); if (!hero) return; window.addEventListener('scroll', debounce(() => { const scrolled = window.pageYOffset; const rate = scrolled * -0.5; hero.style.transform = `translateY(${rate}px)`; }, 10)); } // Handle anchor links on page load function handleAnchorLinks() { if (window.location.hash) { const element = document.querySelector(window.location.hash); if (element) { setTimeout(() => { const headerOffset = 80; const elementPosition = element.offsetTop; const offsetPosition = elementPosition - headerOffset; window.scrollTo({ top: offsetPosition, behavior: 'smooth' }); }, 100); } } } // Initialize all functionality document.addEventListener('DOMContentLoaded', () => { initNavigation(); initMobileMenu(); initSmoothScroll();