/* ============================================================ sonith.de — Main JavaScript ============================================================ */ document.addEventListener('DOMContentLoaded', () => { initMobileMenu(); initScrollSpy(); initNavbarScroll(); initFadeIn(); }); /* ---- Mobile Menu ---- */ function initMobileMenu() { const btn = document.getElementById('mobile-menu-btn'); const menu = document.getElementById('mobile-menu'); const iconOpen = document.getElementById('menu-icon-open'); const iconClose = document.getElementById('menu-icon-close'); if (!btn || !menu) return; btn.addEventListener('click', () => { const isOpen = !menu.classList.contains('hidden'); menu.classList.toggle('hidden'); iconOpen.classList.toggle('hidden'); iconClose.classList.toggle('hidden'); btn.setAttribute('aria-label', isOpen ? 'Menü öffnen' : 'Menü schließen'); }); // Menü schließen bei Klick auf Link menu.querySelectorAll('a').forEach(link => { link.addEventListener('click', () => { menu.classList.add('hidden'); iconOpen.classList.remove('hidden'); iconClose.classList.add('hidden'); btn.setAttribute('aria-label', 'Menü öffnen'); }); }); } /* ---- Scroll Spy (aktiver Menüpunkt) ---- */ function initScrollSpy() { 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.getAttribute('id'); navLinks.forEach(link => { link.classList.toggle('active', link.getAttribute('href') === `#${id}`); }); } }); }, { rootMargin: '-20% 0px -60% 0px', threshold: 0 }); sections.forEach(section => observer.observe(section)); } /* ---- Navbar Background on Scroll ---- */ function initNavbarScroll() { const navbar = document.getElementById('navbar'); if (!navbar) return; const update = () => { navbar.classList.toggle('scrolled', window.scrollY > 50); }; window.addEventListener('scroll', update, { passive: true }); update(); } /* ---- Fade-in on Scroll ---- */ function initFadeIn() { const elements = document.querySelectorAll('.fade-in, .service-card'); if (!elements.length) return; const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); observer.unobserve(entry.target); } }); }, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' }); elements.forEach(el => observer.observe(el)); }