0
Skip to Content
Home
Lacey Lobetta Consulting
Lacey Lobetta Consulting
Home
Lacey Lobetta Consulting
Lacey Lobetta Consulting
Home
/* ================================================================ LACEY LOBETTA & CO. — main.js ================================================================ */ /* ── Nav Fix for Squarespace CSS Transform ────────────────────── CSS transform on the code block creates a new stacking context, which breaks position:fixed. We move only the nav + mobile menu to so they position correctly relative to the viewport. ────────────────────────────────────────────────────────────── */ (function () { var nav = document.getElementById('navbar'); var menu = document.getElementById('mobileMenu'); if (!nav || !nav.closest('.sqs-block-code')) return; document.body.insertBefore(nav, document.body.firstChild); if (menu) document.body.insertBefore(menu, nav.nextSibling); })(); document.addEventListener('DOMContentLoaded', () => { /* ── Navbar Scroll Behavior ─────────────────────────────────── */ const navbar = document.getElementById('navbar'); const onScroll = () => { navbar.classList.toggle('scrolled', window.scrollY > 60); }; window.addEventListener('scroll', onScroll, { passive: true }); /* ── Mobile Menu ────────────────────────────────────────────── */ const hamburger = document.getElementById('hamburger'); const mobileMenu = document.getElementById('mobileMenu'); const menuClose = document.getElementById('menuClose'); const mmLinks = document.querySelectorAll('.mm-link'); const openMenu = () => { mobileMenu.classList.add('open'); document.body.style.overflow = 'hidden'; }; const closeMenu = () => { mobileMenu.classList.remove('open'); document.body.style.overflow = ''; }; hamburger.addEventListener('click', openMenu); menuClose.addEventListener('click', closeMenu); mmLinks.forEach(l => l.addEventListener('click', closeMenu)); /* ── Scroll Reveal ──────────────────────────────────────────── */ const reveals = document.querySelectorAll('.reveal'); const revealObserver = new IntersectionObserver((entries) => { entries.forEach((entry, i) => { if (entry.isIntersecting) { // Stagger siblings slightly const siblings = [...entry.target.parentElement.querySelectorAll('.reveal:not(.visible)')]; const idx = siblings.indexOf(entry.target); setTimeout(() => { entry.target.classList.add('visible'); }, Math.min(idx * 80, 400)); revealObserver.unobserve(entry.target); } }); }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' }); reveals.forEach(el => revealObserver.observe(el)); /* ── Testimonial Slider ─────────────────────────────────────── */ const track = document.getElementById('testimonialTrack'); const dotsWrap = document.getElementById('tDots'); const prevBtn = document.getElementById('tPrev'); const nextBtn = document.getElementById('tNext'); if (track) { const cards = track.querySelectorAll('.testimonial-card'); let current = 0; let autoTimer = null; // Build dots cards.forEach((_, i) => { const dot = document.createElement('div'); dot.className = 't-dot' + (i === 0 ? ' active' : ''); dot.addEventListener('click', () => goTo(i)); dotsWrap.appendChild(dot); }); const goTo = (idx) => { current = (idx + cards.length) % cards.length; track.style.transform = `translateX(-${current * 100}%)`; dotsWrap.querySelectorAll('.t-dot').forEach((d, i) => { d.classList.toggle('active', i === current); }); }; prevBtn.addEventListener('click', () => { goTo(current - 1); resetAuto(); }); nextBtn.addEventListener('click', () => { goTo(current + 1); resetAuto(); }); const startAuto = () => { autoTimer = setInterval(() => goTo(current + 1), 5000); }; const resetAuto = () => { clearInterval(autoTimer); startAuto(); }; startAuto(); } /* ── Animated Counters ──────────────────────────────────────── */ const counters = document.querySelectorAll('.credbar__num'); const animateCounter = (el) => { const raw = el.textContent.trim(); const match = raw.match(/^([\$]?)(\d+(?:\.\d+)?)([MK+x]*)$/); if (!match) return; const prefix = match[1]; const target = parseFloat(match[2]); const suffix = match[3]; const em = el.querySelector('em'); const emText = em ? em.textContent : ''; const dur = 1800; const start = performance.now(); const tick = (now) => { const elapsed = now - start; const progress = Math.min(elapsed / dur, 1); const eased = 1 - Math.pow(1 - progress, 3); // ease-out-cubic const value = eased * target; const display = value >= 10 ? Math.round(value) : Math.round(value * 10) / 10; el.textContent = `${prefix}${display}${suffix.replace(emText, '')}`; if (em) { const newEm = document.createElement('em'); newEm.textContent = emText; el.appendChild(newEm); } if (progress < 1) requestAnimationFrame(tick); }; requestAnimationFrame(tick); }; const counterObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { animateCounter(entry.target); counterObserver.unobserve(entry.target); } }); }, { threshold: 0.5 }); counters.forEach(c => counterObserver.observe(c)); /* ── Contact Form (placeholder behavior) ───────────────────── */ const form = document.getElementById('contactForm'); if (form) { form.addEventListener('submit', (e) => { e.preventDefault(); const btn = form.querySelector('button[type="submit"]'); btn.textContent = 'Application Submitted ✓'; btn.style.background = '#3a7d44'; btn.style.color = '#fff'; btn.disabled = true; // Show a success note const note = document.createElement('p'); note.style.cssText = 'color:#C9A96E;font-size:0.85rem;text-align:center;margin-top:12px;font-style:italic;'; note.textContent = 'Thank you. We review every application personally and will be in touch within 48 hours.'; form.querySelector('.form-submit').appendChild(note); }); } /* ── Smooth anchor scrolling with offset for fixed nav ─────── */ document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', (e) => { const target = document.querySelector(anchor.getAttribute('href')); if (!target) return; e.preventDefault(); const offset = navbar.offsetHeight + 20; const top = target.getBoundingClientRect().top + window.scrollY - offset; window.scrollTo({ top, behavior: 'smooth' }); }); }); /* ── Parallax tilt on service cards (desktop only) ──────────── */ if (window.matchMedia('(hover: hover)').matches) { document.querySelectorAll('.service-card').forEach(card => { card.addEventListener('mousemove', (e) => { const rect = card.getBoundingClientRect(); const x = (e.clientX - rect.left) / rect.width - 0.5; const y = (e.clientY - rect.top) / rect.height - 0.5; card.style.transform = `perspective(600px) rotateY(${x * 6}deg) rotateX(${-y * 6}deg) translateY(-4px)`; }); card.addEventListener('mouseleave', () => { card.style.transform = ''; }); }); } });