(() => { const menuButton = document.querySelector('[data-menu-toggle]'); const mobileNav = document.querySelector('[data-mobile-nav]'); if (menuButton && mobileNav) { menuButton.addEventListener('click', () => { const open = mobileNav.classList.toggle('open'); menuButton.classList.toggle('open', open); menuButton.setAttribute('aria-expanded', String(open)); }); mobileNav.querySelectorAll('a').forEach(a => a.addEventListener('click', () => { mobileNav.classList.remove('open'); menuButton.classList.remove('open'); menuButton.setAttribute('aria-expanded', 'false'); })); } const observer = 'IntersectionObserver' in window ? new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); observer.unobserve(entry.target); } }); }, {threshold: .12}) : null; document.querySelectorAll('.reveal-on-scroll').forEach(el => observer ? observer.observe(el) : el.classList.add('visible')); document.querySelectorAll('[data-contact-form]').forEach(form => { let challengePromise = fetch('/api/contact', {credentials: 'same-origin', cache: 'no-store'}).then(r => { if (!r.ok) throw new Error('challenge'); return r.json(); }).catch(() => null); form.addEventListener('submit', async event => { event.preventDefault(); if (!form.reportValidity()) return; const fd = new FormData(form); const lang = document.documentElement.lang || 'de'; const status = form.querySelector('.form-status'); const button = form.querySelector('button[type="submit"]'); button.disabled = true; status.style.display = 'block'; status.textContent = lang === 'de' ? 'Nachricht wird gesendet …' : 'Sending message …'; try { const challenge = await challengePromise; if (!challenge?.token) throw new Error('challenge'); const {token} = challenge; const payload = Object.fromEntries(fd.entries()); payload.token = token; payload.lang = lang; const response = await fetch('/api/contact', { method: 'POST', credentials: 'same-origin', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(payload) }); if (!response.ok) throw new Error('send'); status.textContent = lang === 'de' ? 'Vielen Dank. Ihre Nachricht wurde übermittelt.' : 'Thank you. Your message has been submitted.'; form.reset(); challengePromise = fetch('/api/contact', {credentials: 'same-origin', cache: 'no-store'}).then(r => r.json()).catch(() => null); } catch (_) { status.textContent = lang === 'de' ? 'Die Nachricht konnte nicht gesendet werden. Bitte versuchen Sie es später erneut oder schreiben Sie an info@dilibworld.com.' : 'Your message could not be sent. Please try again later or email info@dilibworld.com.'; } finally { button.disabled = false; } }); }); const notice = document.querySelector('[data-cookie-notice]'); const choice = localStorage.getItem('dilibworld-cookie-choice'); if (notice && !choice) notice.classList.add('show'); document.querySelectorAll('[data-cookie-choice]').forEach(btn => btn.addEventListener('click', () => { localStorage.setItem('dilibworld-cookie-choice', btn.dataset.cookieChoice); notice?.classList.remove('show'); })); document.querySelectorAll('[data-current-year]').forEach(el => el.textContent = new Date().getFullYear()); })();