/* ============================================================ BUILDORA — main.js ============================================================ */ (function () { 'use strict'; /* ====== RULER TICKS ====== */ const ruler = document.getElementById('ruler'); if (ruler) { const frag = document.createDocumentFragment(); for (let i = 0; i < 100; i++) { const t = document.createElement('div'); t.className = 't'; frag.appendChild(t); } ruler.appendChild(frag); } /* ====== NAVBAR SHRINK ====== */ const topbar = document.getElementById('topbar'); if (topbar) { window.addEventListener('scroll', () => { topbar.classList.toggle('shrink', window.scrollY > 40); }, { passive: true }); } /* ====== MOBILE MENU ====== */ const mm = document.getElementById('mobileMenu'); const burger = document.getElementById('burger'); const closeBtn= document.getElementById('closeMenu'); function openMenu() { if (!mm || !burger) return; mm.classList.add('on'); burger.classList.add('on'); burger.setAttribute('aria-expanded', 'true'); document.body.style.overflow = 'hidden'; } function closeMenu() { if (!mm || !burger) return; mm.classList.remove('on'); burger.classList.remove('on'); burger.setAttribute('aria-expanded', 'false'); document.body.style.overflow = ''; } if (burger) burger.addEventListener('click', openMenu); if (closeBtn) closeBtn.addEventListener('click', closeMenu); if (mm) { mm.querySelectorAll('a').forEach(a => a.addEventListener('click', closeMenu)); } document.addEventListener('keydown', e => { if (e.key === 'Escape') closeMenu(); }); /* ====== SERVICE SWITCHER ====== */ const svcImg = document.getElementById('svcImg'); const svcTitle = document.getElementById('svcTitle'); const svcDesc = document.getElementById('svcDesc'); if (svcImg) { svcImg.style.transition = 'opacity .3s ease'; function activateSvc(el) { document.querySelectorAll('.svc').forEach(s => s.classList.remove('active')); el.classList.add('active'); svcImg.style.opacity = '0'; setTimeout(() => { svcImg.src = el.dataset.img || svcImg.src; svcImg.alt = el.dataset.title || ''; if (svcTitle) svcTitle.textContent = el.dataset.title || ''; if (svcDesc) svcDesc.textContent = el.dataset.desc || ''; svcImg.style.opacity = '1'; }, 220); } document.querySelectorAll('.svc').forEach(s => { s.addEventListener('click', () => activateSvc(s)); s.addEventListener('keydown', e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); activateSvc(s); } }); }); } /* ====== FAQ ACCORDION ====== */ function syncHeight(acc) { const body = acc.querySelector('.acc-body'); if (!body) return; body.style.maxHeight = acc.classList.contains('open') ? body.scrollHeight + 'px' : '0'; } document.querySelectorAll('.acc').forEach(acc => { const head = acc.querySelector('.acc-head'); if (!head) return; head.addEventListener('click', () => { const wasOpen = acc.classList.contains('open'); document.querySelectorAll('.acc').forEach(a => { a.classList.remove('open'); syncHeight(a); }); if (!wasOpen) { acc.classList.add('open'); syncHeight(acc); } }); }); window.addEventListener('load', () => { document.querySelectorAll('.acc.open').forEach(syncHeight); }); /* ====== REVEAL ON SCROLL ====== */ const revealObserver = new IntersectionObserver(entries => { entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('in'); revealObserver.unobserve(e.target); } }); }, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' }); document.querySelectorAll('.reveal:not(.in)').forEach(el => revealObserver.observe(el)); /* ====== COUNT UP ====== */ function animateCount(el) { const target = parseFloat(el.dataset.count); const suffix = el.dataset.suffix || ''; const isFloat = target % 1 !== 0; const dur = 1600; const start = performance.now(); const sup = '+'; function step(now) { const p = Math.min((now - start) / dur, 1); const ease = 1 - Math.pow(1 - p, 3); const val = target * ease; el.innerHTML = (isFloat ? val.toFixed(1) : Math.floor(val)) + suffix + sup; if (p < 1) requestAnimationFrame(step); } requestAnimationFrame(step); } const countObserver = new IntersectionObserver(entries => { entries.forEach(e => { if (e.isIntersecting) { animateCount(e.target); countObserver.unobserve(e.target); } }); }, { threshold: 0.5 }); document.querySelectorAll('[data-count]').forEach(el => countObserver.observe(el)); /* ====== TESTIMONIALS ROTATOR ====== */ const quotes = [ '« Ils maîtrisent leur métier : leur approche professionnelle et leur manière de travailler en font un vrai partenaire d\'équipe pour les propriétaires et leurs consultants. »', '« Un accompagnement irréprochable du début à la fin. Les délais ont été tenus et la qualité dépasse nos attentes. »', '« Une équipe à l\'écoute, rigoureuse et créative. Nous leur confions désormais tous nos projets immobiliers. »' ]; const quoteEl = document.getElementById('quote'); const dots = document.querySelectorAll('.dots i'); let qi = 1; if (quoteEl) { quoteEl.style.transition = 'opacity .35s ease'; setInterval(() => { qi = (qi + 1) % quotes.length; quoteEl.style.opacity = '0'; setTimeout(() => { quoteEl.textContent = quotes[qi]; quoteEl.style.opacity = '1'; dots.forEach((d, i) => d.classList.toggle('on', i === qi)); }, 360); }, 5500); } /* ====== CONTACT FORM ====== */ const sendBtn = document.getElementById('sendBtn'); const contactForm = document.getElementById('contactForm'); if (sendBtn && contactForm) { sendBtn.addEventListener('click', () => { if (contactForm.checkValidity()) { const orig = sendBtn.innerHTML; sendBtn.innerHTML = 'Message envoyé ✓'; sendBtn.style.background = '#22a95a'; sendBtn.disabled = true; contactForm.reset(); setTimeout(() => { sendBtn.innerHTML = orig; sendBtn.style.background = ''; sendBtn.disabled = false; }, 3000); } else { contactForm.reportValidity(); } }); } /* ====== NEWSLETTER ====== */ window.handleNewsletter = function (e) { e.preventDefault(); const btn = e.target.querySelector('button[type="submit"]'); if (!btn) return; const orig = btn.innerHTML; btn.innerHTML = 'Inscrit ✓'; btn.style.background = '#22a95a'; e.target.reset(); setTimeout(() => { btn.innerHTML = orig; btn.style.background = ''; }, 2800); }; })();