// Intersection Observer for fade-in animations const observerOptions = { root: null, rootMargin: '0px', threshold: 0.1 }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('opacity-100', 'translate-y-0'); entry.target.classList.remove('opacity-0', 'translate-y-10'); } }); }, observerOptions); // Observe all cards and sections document.addEventListener('DOMContentLoaded', () => { const elements = document.querySelectorAll('section > div, .group'); elements.forEach((el, index) => { el.classList.add('transition-all', 'duration-700', 'opacity-0', 'translate-y-10'); el.style.transitionDelay = `${index * 50}ms`; observer.observe(el); }); // Form handling with real-time validation const form = document.querySelector('form'); if (form) { // Real-time input validation styling const inputs = form.querySelectorAll('input, textarea, select'); inputs.forEach(input => { input.addEventListener('focus', () => { input.parentElement.classList.add('focused'); }); input.addEventListener('blur', () => { input.parentElement.classList.remove('focused'); if (input.value.trim()) { input.classList.add('field-valid'); input.classList.remove('field-invalid'); } else if (input.hasAttribute('required')) { input.classList.add('field-invalid'); input.classList.remove('field-valid'); } }); // Live character feedback input.addEventListener('input', () => { if (input.tagName === 'TEXTAREA') { const remaining = 500 - input.value.length; let counter = input.parentElement.querySelector('.char-counter'); if (!counter) { counter = document.createElement('div'); counter.className = 'char-counter text-xs font-mono text-slate-500 text-right mt-1'; input.parentElement.appendChild(counter); } counter.textContent = `${remaining} caractères restants`; counter.style.color = remaining < 50 ? '#f59e0b' : remaining < 0 ? '#ef4444' : '#64748b'; } }); }); form.addEventListener('submit', (e) => { e.preventDefault(); const btn = form.querySelector('button[type="submit"]'); const originalText = btn.innerText; const originalClasses = btn.className; btn.innerHTML = ' ENVOI EN COURS...'; btn.disabled = true; btn.style.opacity = '0.8'; setTimeout(() => { btn.innerHTML = '✓ DEMANDE ENVOYÉE'; btn.className = btn.className.replace('from-primary', 'from-green-500').replace('to-cyan-600', 'to-green-600'); btn.style.opacity = '1'; // Success feedback on form form.style.transition = 'all 0.3s ease'; form.style.boxShadow = '0 0 30px rgba(34, 197, 94, 0.2)'; setTimeout(() => { form.style.boxShadow = ''; }, 2000); setTimeout(() => { form.reset(); inputs.forEach(input => { input.classList.remove('field-valid', 'field-invalid'); }); // Remove char counters form.querySelectorAll('.char-counter').forEach(c => c.remove()); btn.textContent = originalText; btn.disabled = false; btn.className = originalClasses; }, 3000); }, 1500); }); } // Smooth scroll for anchor links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const targetId = this.getAttribute('href'); const target = document.querySelector(targetId); if (target) { const navHeight = 80; const targetPosition = target.getBoundingClientRect().top + window.pageYOffset - navHeight; window.scrollTo({ top: targetPosition, behavior: 'smooth' }); } }); }); // Parallax effect on hero section const heroSection = document.querySelector('section'); if (heroSection) { window.addEventListener('scroll', () => { const scrolled = window.pageYOffset; const bgElements = heroSection.querySelectorAll('.absolute'); bgElements.forEach((el, i) => { const speed = 0.1 + (i * 0.05); el.style.transform = `translateY(${scrolled * speed}px)`; }); }, { passive: true }); } });