(function () { window.__site = true; var root = document.documentElement; var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; // Nav border on scroll var nav = document.getElementById('nav'); var onScroll = function () { nav && nav.classList.toggle('is-scrolled', window.scrollY > 8); }; onScroll(); window.addEventListener('scroll', onScroll, { passive: true }); // Mobile menu var menuBtn = document.getElementById('menu-btn'); var menu = document.getElementById('mobile-menu'); if (menuBtn && menu) { menuBtn.addEventListener('click', function () { var open = menu.hidden; menu.hidden = !open; menuBtn.setAttribute('aria-expanded', String(open)); menuBtn.setAttribute('aria-label', open ? 'Close menu' : 'Open menu'); }); document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && !menu.hidden) { menu.hidden = true; menuBtn.setAttribute('aria-expanded', 'false'); menuBtn.focus(); } }); } // Reveal on scroll var reveals = document.querySelectorAll('.reveal'); if ('IntersectionObserver' in window && !reduce) { var io = new IntersectionObserver(function (entries) { entries.forEach(function (en) { if (en.isIntersecting) { en.target.classList.add('is-in'); io.unobserve(en.target); } }); }, { rootMargin: '0px 0px -8% 0px', threshold: 0.05 }); reveals.forEach(function (el) { io.observe(el); }); } else { reveals.forEach(function (el) { el.classList.add('is-in'); }); } // Count-up numbers: 8+ var counters = document.querySelectorAll('[data-count]'); var run = function (el) { var end = parseInt(el.getAttribute('data-count'), 10); var suffix = el.getAttribute('data-suffix') || ''; var start = null; var dur = 1200; var step = function (t) { if (!start) start = t; var p = Math.min((t - start) / dur, 1); var eased = 1 - Math.pow(1 - p, 3); el.textContent = Math.round(end * eased) + suffix; if (p < 1) requestAnimationFrame(step); }; requestAnimationFrame(step); }; if ('IntersectionObserver' in window && !reduce) { var co = new IntersectionObserver(function (entries) { entries.forEach(function (en) { if (en.isIntersecting) { run(en.target); co.unobserve(en.target); } }); }, { threshold: 0.6 }); counters.forEach(function (el) { co.observe(el); }); } // Tabs (service lines) document.querySelectorAll('[data-tabs]').forEach(function (wrap) { var btns = wrap.querySelectorAll('[role="tab"]'); var panels = wrap.querySelectorAll('[role="tabpanel"]'); var select = function (i, focus) { btns.forEach(function (b, j) { var on = i === j; b.setAttribute('aria-selected', String(on)); b.tabIndex = on ? 0 : -1; panels[j].hidden = !on; }); if (focus) btns[i].focus(); }; btns.forEach(function (b, i) { b.addEventListener('click', function () { select(i); }); b.addEventListener('keydown', function (e) { var k = e.key; if (k === 'ArrowDown' || k === 'ArrowRight') { e.preventDefault(); select((i + 1) % btns.length, true); } if (k === 'ArrowUp' || k === 'ArrowLeft') { e.preventDefault(); select((i - 1 + btns.length) % btns.length, true); } }); }); var hash = location.hash.replace('#', ''); var start = 0; panels.forEach(function (p, j) { if (p.id === hash) start = j; }); select(start); }); // Copy buttons document.querySelectorAll('[data-copy]').forEach(function (b) { b.addEventListener('click', function () { var text = b.getAttribute('data-copy'); var label = b.textContent; var done = function () { b.textContent = 'Copied'; setTimeout(function () { b.textContent = label; }, 1600); }; try { navigator.clipboard.writeText(text).then(done, function () {}); } catch (e) {} }); }); // Inquiry form: opens the visitor's email client with the message prefilled. var form = document.getElementById('inquiry'); if (form) { form.addEventListener('submit', function (e) { e.preventDefault(); if (!form.reportValidity()) return; var d = new FormData(form); var body = [ 'Name: ' + d.get('name'), 'Email: ' + d.get('email'), d.get('company') ? 'Company: ' + d.get('company') : '', d.get('topic') ? 'Topic: ' + d.get('topic') : '', '', d.get('message') ].filter(function (l, i) { return l !== '' || i === 4; }).join('\n'); var subject = 'Inquiry from ' + d.get('name') + (d.get('topic') ? ' — ' + d.get('topic') : ''); window.location.href = 'mailto:' + form.getAttribute('data-to') + '?subject=' + encodeURIComponent(subject) + '&body=' + encodeURIComponent(body); var status = document.getElementById('form-status'); if (status) status.textContent = 'Your email app should open with the message ready to send.'; }); } root.classList.add('ready'); })();