1// Mobile nav toggle 2const toggle = document.querySelector('.nav-toggle'); 3const links = document.querySelector('.nav-links'); 4if (toggle && links) { 5 toggle.addEventListener('click', () => links.classList.toggle('open')); 6 7 // Close mobile nav on link click 8 document.querySelectorAll('.nav-links a').forEach(link => { 9 link.addEventListener('click', () => links.classList.remove('open')); 10 }); 11} 12 13// Enso: opens mobile menu on narrow screens, scrolls to About on desktop 14const enso = document.querySelector('.enso-container'); 15if (enso && links) { 16 enso.addEventListener('click', () => { 17 if (window.innerWidth <= 640) { 18 links.classList.toggle('open'); 19 } else { 20 const about = document.getElementById('about'); 21 if (about) about.scrollIntoView({ behavior: 'smooth' }); 22 } 23 }); 24} 25 26// Support section toggle (scoped to the Gift section) 27const supportToggle = document.querySelector('#support .support-toggle'); 28const supportExpanded = document.getElementById('support-expanded'); 29 30function openSupport() { 31 if (supportExpanded && !supportExpanded.classList.contains('open')) { 32 supportExpanded.classList.add('open'); 33 supportToggle.setAttribute('aria-expanded', 'true'); 34 supportToggle.innerHTML = 'Hide ↑'; 35 } 36} 37 38if (supportToggle && supportExpanded) { 39 supportExpanded.removeAttribute('hidden'); 40 supportToggle.addEventListener('click', () => { 41 const isOpen = supportExpanded.classList.toggle('open'); 42 supportToggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); 43 supportToggle.innerHTML = isOpen ? 'Hide ↑' : 'Offer a gift →'; 44 }); 45 46 // Auto-expand when someone clicks a Support nav link 47 document.querySelectorAll('a[href="#support"]').forEach(link => { 48 link.addEventListener('click', () => openSupport()); 49 }); 50 51 // Auto-expand if the page is loaded with #support in the URL 52 if (window.location.hash === '#support') { 53 openSupport(); 54 } 55} 56 57// Fees toggle (Private Practice Guidance) 58const feesToggle = document.getElementById('fees-toggle'); 59const feesExpanded = document.getElementById('fees-expanded'); 60if (feesToggle && feesExpanded) { 61 feesExpanded.removeAttribute('hidden'); 62 feesToggle.addEventListener('click', () => { 63 const isOpen = feesExpanded.classList.toggle('open'); 64 feesToggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); 65 feesToggle.innerHTML = isOpen ? 'Hide ↑' : 'View fees →'; 66 }); 67} 68 69// Dana frequency toggle (one-time vs monthly) 70const danaToggleOptions = document.querySelectorAll('.dana-toggle-option'); 71const danaOnceWrap = document.querySelector('.dana-tiers-once'); 72const danaMonthlyWrap = document.querySelector('.dana-tiers-monthly'); 73if (danaOnceWrap && danaMonthlyWrap) { 74 danaToggleOptions.forEach(option => { 75 option.addEventListener('click', () => { 76 const frequency = option.dataset.frequency; 77 danaToggleOptions.forEach(o => { 78 o.classList.toggle('active', o === option); 79 o.setAttribute('aria-selected', o === option ? 'true' : 'false'); 80 }); 81 if (frequency === 'once') { 82 danaOnceWrap.removeAttribute('hidden'); 83 danaMonthlyWrap.setAttribute('hidden', ''); 84 } else { 85 danaOnceWrap.setAttribute('hidden', ''); 86 danaMonthlyWrap.removeAttribute('hidden'); 87 } 88 }); 89 }); 90} 91 92// Contact form â AJAX submit with inline success message (falls back to normal POST if fetch fails) 93const contactForm = document.querySelector('.contact-form'); 94if (contactForm) { 95 contactForm.addEventListener('submit', (e) => { 96 e.preventDefault(); 97 const button = contactForm.querySelector('.contact-button'); 98 const success = contactForm.querySelector('.contact-success'); 99 button.disabled = true; 100 button.textContent = 'Sendingâ¦'; 101 fetch('/', { 102 method: 'POST', 103 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 104 body: new URLSearchParams(new FormData(contactForm)).toString() 105 }) 106 .then((res) => { 107 if (!res.ok) throw new Error('Submit failed'); 108 contactForm.querySelectorAll('.contact-form-row, .contact-textarea, .contact-button').forEach(el => el.setAttribute('hidden', '')); 109 success.removeAttribute('hidden'); 110 }) 111 .catch(() => { 112 // Fall back to a standard form POST (Netlify's default success page). 113 // form.submit() does not re-fire the submit event, so no loop. 114 contactForm.submit(); 115 }); 116 }); 117} 118 119// Scroll fade-in 120const observer = new IntersectionObserver((entries) => {
121 entries.forEach(entry => { 122 if (entry.isIntersecting) { 123 entry.target.classList.add('visible'); 124 } 125 }); 126}, { threshold: 0.15 }); 127 128document.querySelectorAll('.fade-in-section').forEach(el => observer.observe(el));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.