mirror of
https://github.com/marcogll/join_landing_vanity.git
synced 2026-01-13 13:25:15 +00:00
789 lines
21 KiB
JavaScript
789 lines
21 KiB
JavaScript
/**
|
|
* MAIN.JS - Core interactions and form handling
|
|
* Mobile-first, progressive enhancement approach
|
|
*/
|
|
|
|
// Utility functions
|
|
const $ = (selector, context = document) => context.querySelector(selector);
|
|
const $$ = (selector, context = document) => [...context.querySelectorAll(selector)];
|
|
|
|
// Remove no-js class
|
|
document.documentElement.classList.remove('no-js');
|
|
|
|
// ==============================================
|
|
// MOBILE NAVIGATION
|
|
// ==============================================
|
|
|
|
function initMobileNav() {
|
|
const toggle = $('.nav__toggle');
|
|
const menu = $('#navMenu');
|
|
|
|
if (!toggle || !menu) return;
|
|
|
|
toggle.addEventListener('click', () => {
|
|
const isExpanded = toggle.getAttribute('aria-expanded') === 'true';
|
|
|
|
toggle.setAttribute('aria-expanded', String(!isExpanded));
|
|
menu.hidden = isExpanded;
|
|
|
|
// Trap focus when menu is open
|
|
if (!isExpanded) {
|
|
menu.querySelector('a')?.focus();
|
|
}
|
|
});
|
|
|
|
// Close menu when clicking outside
|
|
document.addEventListener('click', (e) => {
|
|
if (!toggle.contains(e.target) && !menu.contains(e.target)) {
|
|
toggle.setAttribute('aria-expanded', 'false');
|
|
menu.hidden = true;
|
|
}
|
|
});
|
|
|
|
// Close menu on escape key
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape' && toggle.getAttribute('aria-expanded') === 'true') {
|
|
toggle.setAttribute('aria-expanded', 'false');
|
|
menu.hidden = true;
|
|
toggle.focus();
|
|
}
|
|
});
|
|
}
|
|
|
|
// ==============================================
|
|
// ANIMATED HEADLINE
|
|
// ==============================================
|
|
|
|
function initAnimatedHeadline() {
|
|
const rotatingElement = $('#rotating');
|
|
if (!rotatingElement) return;
|
|
|
|
const words = ["Talento", "Pasión", "Servicio", "Actitud"];
|
|
let currentIndex = 0;
|
|
let currentText = '';
|
|
let isDeleting = false;
|
|
let typeSpeed = 120; // Speed of typing
|
|
let deleteSpeed = 60; // Speed of deleting
|
|
let pauseTime = 1500; // Pause between words
|
|
|
|
// Respect reduced motion preference
|
|
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
if (prefersReducedMotion) {
|
|
rotatingElement.textContent = words[0];
|
|
return;
|
|
}
|
|
|
|
function typeAnimation() {
|
|
const currentWord = words[currentIndex];
|
|
|
|
if (isDeleting) {
|
|
// Remove characters
|
|
currentText = currentWord.substring(0, currentText.length - 1);
|
|
rotatingElement.classList.add('typing');
|
|
} else {
|
|
// Add characters
|
|
currentText = currentWord.substring(0, currentText.length + 1);
|
|
rotatingElement.classList.add('typing');
|
|
}
|
|
|
|
rotatingElement.textContent = currentText;
|
|
|
|
// Determine next action
|
|
if (!isDeleting && currentText === currentWord) {
|
|
// Word is complete, pause then start deleting
|
|
rotatingElement.classList.remove('typing');
|
|
setTimeout(() => {
|
|
isDeleting = true;
|
|
typeAnimation();
|
|
}, pauseTime);
|
|
return;
|
|
}
|
|
|
|
if (isDeleting && currentText === '') {
|
|
// Finished deleting, move to next word
|
|
isDeleting = false;
|
|
currentIndex = (currentIndex + 1) % words.length;
|
|
rotatingElement.classList.remove('typing');
|
|
setTimeout(typeAnimation, 300); // Brief pause before starting new word
|
|
return;
|
|
}
|
|
|
|
// Continue typing/deleting
|
|
const speed = isDeleting ? deleteSpeed : typeSpeed;
|
|
|
|
// Add some randomness to typing speed for more natural feel
|
|
const randomSpeed = speed + (Math.random() * 40 - 20);
|
|
|
|
setTimeout(typeAnimation, randomSpeed);
|
|
}
|
|
|
|
// Start animation after initial delay
|
|
setTimeout(typeAnimation, 800);
|
|
}
|
|
|
|
// ==============================================
|
|
// SMOOTH SCROLLING
|
|
// ==============================================
|
|
|
|
function initSmoothScrolling() {
|
|
// Handle anchor links
|
|
$$('a[href^="#"]').forEach(link => {
|
|
link.addEventListener('click', (e) => {
|
|
const href = link.getAttribute('href');
|
|
if (href === '#') return;
|
|
|
|
const target = $(href);
|
|
if (!target) return;
|
|
|
|
e.preventDefault();
|
|
|
|
const headerHeight = $('.site-header')?.offsetHeight || 80;
|
|
const targetPosition = target.offsetTop - headerHeight;
|
|
|
|
window.scrollTo({
|
|
top: targetPosition,
|
|
behavior: 'smooth'
|
|
});
|
|
|
|
// Close mobile menu if open
|
|
const toggle = $('.nav__toggle');
|
|
const menu = $('#navMenu');
|
|
if (toggle && menu && toggle.getAttribute('aria-expanded') === 'true') {
|
|
toggle.setAttribute('aria-expanded', 'false');
|
|
menu.hidden = true;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// ==============================================
|
|
// IMAGE CAROUSEL
|
|
// ==============================================
|
|
|
|
function initImageCarousel() {
|
|
const carousel = $('#imageCarousel');
|
|
if (!carousel) return;
|
|
|
|
const track = carousel.querySelector('.carousel-track');
|
|
const slides = carousel.querySelectorAll('.carousel-slide');
|
|
const prevBtn = $('#carouselPrev');
|
|
const nextBtn = $('#carouselNext');
|
|
const indicators = carousel.querySelectorAll('.carousel-indicator');
|
|
|
|
let currentSlide = 0;
|
|
let autoPlayInterval;
|
|
const autoPlayDelay = 4000; // 4 seconds
|
|
|
|
// Respect reduced motion preference
|
|
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
function updateCarousel(slideIndex, manual = false) {
|
|
// Remove active class from all slides and indicators
|
|
slides.forEach(slide => slide.classList.remove('active'));
|
|
indicators.forEach(indicator => indicator.classList.remove('active'));
|
|
|
|
// Add active class to current slide and indicator
|
|
slides[slideIndex].classList.add('active');
|
|
indicators[slideIndex].classList.add('active');
|
|
|
|
currentSlide = slideIndex;
|
|
|
|
// Restart autoplay if this was a manual change
|
|
if (manual && !prefersReducedMotion) {
|
|
clearInterval(autoPlayInterval);
|
|
startAutoPlay();
|
|
}
|
|
|
|
// Track carousel interaction
|
|
if (typeof gtag !== 'undefined') {
|
|
gtag('event', 'carousel_slide', {
|
|
event_category: 'engagement',
|
|
event_label: `slide_${slideIndex}`,
|
|
value: slideIndex
|
|
});
|
|
}
|
|
}
|
|
|
|
function nextSlide() {
|
|
const nextIndex = (currentSlide + 1) % slides.length;
|
|
updateCarousel(nextIndex);
|
|
}
|
|
|
|
function prevSlide() {
|
|
const prevIndex = (currentSlide - 1 + slides.length) % slides.length;
|
|
updateCarousel(prevIndex);
|
|
}
|
|
|
|
function goToSlide(slideIndex) {
|
|
updateCarousel(slideIndex, true);
|
|
}
|
|
|
|
function startAutoPlay() {
|
|
if (prefersReducedMotion) return;
|
|
|
|
autoPlayInterval = setInterval(() => {
|
|
nextSlide();
|
|
}, autoPlayDelay);
|
|
}
|
|
|
|
function stopAutoPlay() {
|
|
clearInterval(autoPlayInterval);
|
|
}
|
|
|
|
// Event listeners
|
|
if (prevBtn) {
|
|
prevBtn.addEventListener('click', () => {
|
|
prevSlide();
|
|
});
|
|
}
|
|
|
|
if (nextBtn) {
|
|
nextBtn.addEventListener('click', () => {
|
|
nextSlide();
|
|
});
|
|
}
|
|
|
|
// Indicator clicks
|
|
indicators.forEach((indicator, index) => {
|
|
indicator.addEventListener('click', () => {
|
|
goToSlide(index);
|
|
});
|
|
});
|
|
|
|
// Keyboard navigation
|
|
carousel.addEventListener('keydown', (e) => {
|
|
if (e.key === 'ArrowLeft') {
|
|
e.preventDefault();
|
|
prevSlide();
|
|
} else if (e.key === 'ArrowRight') {
|
|
e.preventDefault();
|
|
nextSlide();
|
|
}
|
|
});
|
|
|
|
// Touch/swipe support
|
|
let touchStartX = 0;
|
|
let touchEndX = 0;
|
|
|
|
track.addEventListener('touchstart', (e) => {
|
|
touchStartX = e.changedTouches[0].screenX;
|
|
}, { passive: true });
|
|
|
|
track.addEventListener('touchend', (e) => {
|
|
touchEndX = e.changedTouches[0].screenX;
|
|
handleSwipe();
|
|
}, { passive: true });
|
|
|
|
function handleSwipe() {
|
|
const swipeThreshold = 50;
|
|
const swipeLength = touchEndX - touchStartX;
|
|
|
|
if (Math.abs(swipeLength) > swipeThreshold) {
|
|
if (swipeLength > 0) {
|
|
prevSlide();
|
|
} else {
|
|
nextSlide();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pause autoplay on hover
|
|
carousel.addEventListener('mouseenter', stopAutoPlay);
|
|
carousel.addEventListener('mouseleave', () => {
|
|
if (!prefersReducedMotion) startAutoPlay();
|
|
});
|
|
|
|
// Pause autoplay when page is not visible
|
|
document.addEventListener('visibilitychange', () => {
|
|
if (document.hidden) {
|
|
stopAutoPlay();
|
|
} else if (!prefersReducedMotion) {
|
|
startAutoPlay();
|
|
}
|
|
});
|
|
|
|
// Start autoplay
|
|
if (!prefersReducedMotion) {
|
|
startAutoPlay();
|
|
}
|
|
|
|
// Intersection Observer for performance
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
if (!prefersReducedMotion) startAutoPlay();
|
|
} else {
|
|
stopAutoPlay();
|
|
}
|
|
});
|
|
}, { threshold: 0.5 });
|
|
|
|
observer.observe(carousel);
|
|
}
|
|
|
|
// ==============================================
|
|
// HERO CAROUSEL - Auto-rotating image slideshow
|
|
// ==============================================
|
|
|
|
function initHeroCarousel() {
|
|
const carousel = $('#heroCarousel');
|
|
if (!carousel) return;
|
|
|
|
const slides = carousel.querySelectorAll('.hero__slide');
|
|
let currentSlide = 0;
|
|
let autoPlayInterval;
|
|
const autoPlayDelay = 3000; // 3 seconds
|
|
|
|
// Check for reduced motion preference
|
|
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
function showSlide(index) {
|
|
// Remove active class from all slides
|
|
slides.forEach(slide => slide.classList.remove('active'));
|
|
|
|
// Add active class to current slide
|
|
slides[index].classList.add('active');
|
|
|
|
// Track slide view
|
|
if (typeof gtag !== 'undefined') {
|
|
gtag('event', 'hero_slide_view', {
|
|
event_category: 'engagement',
|
|
event_label: `hero_slide_${index + 1}`,
|
|
value: index + 1
|
|
});
|
|
}
|
|
}
|
|
|
|
function nextSlide() {
|
|
currentSlide = (currentSlide + 1) % slides.length;
|
|
showSlide(currentSlide);
|
|
}
|
|
|
|
function startAutoPlay() {
|
|
if (prefersReducedMotion) return;
|
|
|
|
autoPlayInterval = setInterval(nextSlide, autoPlayDelay);
|
|
}
|
|
|
|
function stopAutoPlay() {
|
|
if (autoPlayInterval) {
|
|
clearInterval(autoPlayInterval);
|
|
autoPlayInterval = null;
|
|
}
|
|
}
|
|
|
|
// Initialize first slide
|
|
showSlide(currentSlide);
|
|
|
|
// Start autoplay
|
|
startAutoPlay();
|
|
|
|
// Pause autoplay on hover
|
|
carousel.addEventListener('mouseenter', stopAutoPlay);
|
|
carousel.addEventListener('mouseleave', startAutoPlay);
|
|
|
|
// Pause autoplay when page is not visible
|
|
document.addEventListener('visibilitychange', () => {
|
|
if (document.hidden) {
|
|
stopAutoPlay();
|
|
} else {
|
|
startAutoPlay();
|
|
}
|
|
});
|
|
|
|
// Pause autoplay on focus within carousel
|
|
carousel.addEventListener('focusin', stopAutoPlay);
|
|
carousel.addEventListener('focusout', startAutoPlay);
|
|
|
|
// Cleanup on page unload
|
|
window.addEventListener('beforeunload', stopAutoPlay);
|
|
}
|
|
|
|
// ==============================================
|
|
// TESTIMONIALS CAROUSEL - Auto-rotating testimonials
|
|
// ==============================================
|
|
|
|
function initTestimonialsCarousel() {
|
|
const carousel = $('#testimonialsCarousel');
|
|
if (!carousel) return;
|
|
|
|
const slides = carousel.querySelectorAll('.testimonial-slide');
|
|
const indicators = carousel.querySelectorAll('.testimonial-indicator');
|
|
let currentSlide = 0;
|
|
let autoPlayInterval;
|
|
const autoPlayDelay = 15000; // 15 seconds for testimonials
|
|
|
|
// Check for reduced motion preference
|
|
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
function showSlide(index) {
|
|
// Remove active class from all slides and indicators
|
|
slides.forEach(slide => slide.classList.remove('active'));
|
|
indicators.forEach(indicator => indicator.classList.remove('active'));
|
|
|
|
// Add active class to current slide and indicator
|
|
slides[index].classList.add('active');
|
|
indicators[index].classList.add('active');
|
|
|
|
// Track testimonial view
|
|
if (typeof gtag !== 'undefined') {
|
|
gtag('event', 'testimonial_view', {
|
|
event_category: 'engagement',
|
|
event_label: `testimonial_${index + 1}`,
|
|
value: index + 1
|
|
});
|
|
}
|
|
}
|
|
|
|
function nextSlide() {
|
|
currentSlide = (currentSlide + 1) % slides.length;
|
|
showSlide(currentSlide);
|
|
}
|
|
|
|
function prevSlide() {
|
|
currentSlide = (currentSlide - 1 + slides.length) % slides.length;
|
|
showSlide(currentSlide);
|
|
}
|
|
|
|
function goToSlide(index) {
|
|
currentSlide = index;
|
|
showSlide(currentSlide);
|
|
restartAutoPlay();
|
|
}
|
|
|
|
function startAutoPlay() {
|
|
if (prefersReducedMotion) return;
|
|
autoPlayInterval = setInterval(nextSlide, autoPlayDelay);
|
|
}
|
|
|
|
function stopAutoPlay() {
|
|
if (autoPlayInterval) {
|
|
clearInterval(autoPlayInterval);
|
|
autoPlayInterval = null;
|
|
}
|
|
}
|
|
|
|
function restartAutoPlay() {
|
|
stopAutoPlay();
|
|
startAutoPlay();
|
|
}
|
|
|
|
// Initialize first slide
|
|
showSlide(currentSlide);
|
|
|
|
// Add click handlers to indicators
|
|
indicators.forEach((indicator, index) => {
|
|
indicator.addEventListener('click', () => goToSlide(index));
|
|
});
|
|
|
|
// Add click handlers to navigation buttons
|
|
const prevBtn = $('#testimonioPrev');
|
|
const nextBtn = $('#testimonioNext');
|
|
|
|
if (prevBtn) {
|
|
prevBtn.addEventListener('click', () => {
|
|
prevSlide();
|
|
restartAutoPlay();
|
|
});
|
|
}
|
|
|
|
if (nextBtn) {
|
|
nextBtn.addEventListener('click', () => {
|
|
nextSlide();
|
|
restartAutoPlay();
|
|
});
|
|
}
|
|
|
|
// Start autoplay
|
|
startAutoPlay();
|
|
|
|
// Pause autoplay on hover
|
|
carousel.addEventListener('mouseenter', stopAutoPlay);
|
|
carousel.addEventListener('mouseleave', startAutoPlay);
|
|
|
|
// Pause autoplay when page is not visible
|
|
document.addEventListener('visibilitychange', () => {
|
|
if (document.hidden) {
|
|
stopAutoPlay();
|
|
} else {
|
|
startAutoPlay();
|
|
}
|
|
});
|
|
|
|
// Pause autoplay on focus within carousel
|
|
carousel.addEventListener('focusin', stopAutoPlay);
|
|
carousel.addEventListener('focusout', startAutoPlay);
|
|
|
|
// Cleanup on page unload
|
|
window.addEventListener('beforeunload', stopAutoPlay);
|
|
}
|
|
|
|
// ==============================================
|
|
// APPLICATION FORM HANDLING
|
|
// ==============================================
|
|
|
|
function initApplicationForm() {
|
|
const ctaButtons = $$('#openApplicationForm, .btn[href="#aplicar"]');
|
|
|
|
ctaButtons.forEach(button => {
|
|
button.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
|
|
// Track CTA click
|
|
if (typeof gtag !== 'undefined') {
|
|
gtag('event', 'application_form_open', {
|
|
event_category: 'engagement',
|
|
event_label: 'cta_button',
|
|
value: 1
|
|
});
|
|
}
|
|
|
|
// Redirect to application form
|
|
const formUrl = 'https://feedback.soul23.cloud/s/cmfsu7y5h003smo0170y0l0x5';
|
|
window.open(formUrl, '_blank', 'noopener,noreferrer');
|
|
});
|
|
});
|
|
}
|
|
|
|
// ==============================================
|
|
// FAQ ACCORDIONS - Elegant Accordion Behavior
|
|
// ==============================================
|
|
|
|
function initFAQAccordions() {
|
|
const faqItems = $$('.faq__item');
|
|
|
|
faqItems.forEach(item => {
|
|
const question = item.querySelector('.faq__question');
|
|
|
|
question?.addEventListener('click', (e) => {
|
|
e.preventDefault(); // Prevent default details behavior
|
|
|
|
const isCurrentlyOpen = item.open;
|
|
|
|
// Close all other FAQ items first
|
|
faqItems.forEach(otherItem => {
|
|
if (otherItem !== item && otherItem.open) {
|
|
otherItem.open = false;
|
|
}
|
|
});
|
|
|
|
// If the clicked item was closed, open it
|
|
if (!isCurrentlyOpen) {
|
|
item.open = true;
|
|
|
|
// Track FAQ interactions
|
|
if (typeof gtag !== 'undefined') {
|
|
gtag('event', 'faq_open', {
|
|
event_category: 'engagement',
|
|
event_label: question.textContent.trim(),
|
|
value: 1
|
|
});
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Enhanced keyboard navigation
|
|
faqItems.forEach((item, index) => {
|
|
const question = item.querySelector('.faq__question');
|
|
|
|
question?.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
e.preventDefault();
|
|
question.click();
|
|
} else if (e.key === 'ArrowDown') {
|
|
e.preventDefault();
|
|
const nextIndex = (index + 1) % faqItems.length;
|
|
faqItems[nextIndex].querySelector('.faq__question')?.focus();
|
|
} else if (e.key === 'ArrowUp') {
|
|
e.preventDefault();
|
|
const prevIndex = (index - 1 + faqItems.length) % faqItems.length;
|
|
faqItems[prevIndex].querySelector('.faq__question')?.focus();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// ==============================================
|
|
// ANALYTICS TRACKING
|
|
// ==============================================
|
|
|
|
function initAnalyticsTracking() {
|
|
// Track CTA clicks
|
|
$$('a[href="#aplicar"], .btn[href="#aplicar"]').forEach(button => {
|
|
button.addEventListener('click', () => {
|
|
if (typeof gtag !== 'undefined') {
|
|
gtag('event', 'apply_click', {
|
|
event_category: 'engagement',
|
|
event_label: button.textContent.trim(),
|
|
value: 1
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
// Track WhatsApp clicks
|
|
$$('a[href*="wa.me"], a[href*="whatsapp"]').forEach(link => {
|
|
link.addEventListener('click', () => {
|
|
if (typeof gtag !== 'undefined') {
|
|
gtag('event', 'whatsapp_click', {
|
|
event_category: 'engagement',
|
|
event_label: 'whatsapp_contact',
|
|
value: 1
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
// Track scroll depth
|
|
let maxScroll = 0;
|
|
const milestones = [25, 50, 75, 100];
|
|
const trackedMilestones = new Set();
|
|
|
|
function trackScrollDepth() {
|
|
const scrollTop = window.pageYOffset;
|
|
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
|
|
const scrollPercent = Math.round((scrollTop / docHeight) * 100);
|
|
|
|
if (scrollPercent > maxScroll) {
|
|
maxScroll = scrollPercent;
|
|
|
|
milestones.forEach(milestone => {
|
|
if (scrollPercent >= milestone && !trackedMilestones.has(milestone)) {
|
|
trackedMilestones.add(milestone);
|
|
|
|
if (typeof gtag !== 'undefined') {
|
|
gtag('event', 'scroll_depth', {
|
|
event_category: 'engagement',
|
|
event_label: `${milestone}%`,
|
|
value: milestone
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Throttled scroll tracking
|
|
let scrollTimer;
|
|
window.addEventListener('scroll', () => {
|
|
if (scrollTimer) clearTimeout(scrollTimer);
|
|
scrollTimer = setTimeout(trackScrollDepth, 100);
|
|
});
|
|
}
|
|
|
|
// ==============================================
|
|
// SCROLL ANIMATIONS
|
|
// ==============================================
|
|
|
|
function initScrollAnimations() {
|
|
// Check for reduced motion preference
|
|
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
if (prefersReducedMotion) return;
|
|
|
|
// Create intersection observer for scroll animations
|
|
const observerOptions = {
|
|
threshold: 0.1,
|
|
rootMargin: '0px 0px -50px 0px'
|
|
};
|
|
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
const element = entry.target;
|
|
|
|
// Add the animate-in class to trigger animations
|
|
element.classList.add('animate-in');
|
|
|
|
// For sections with multiple children, stagger their animations
|
|
const children = element.querySelectorAll('.benefit-card, .process__step, .faq__item, .stat-item');
|
|
children.forEach((child, index) => {
|
|
setTimeout(() => {
|
|
child.classList.add('animate-in');
|
|
}, index * 100); // 100ms delay between each child
|
|
});
|
|
|
|
// Special handling for CTA section
|
|
if (element.classList.contains('cta-carousel')) {
|
|
setTimeout(() => {
|
|
const text = element.querySelector('.cta-carousel__text');
|
|
const images = element.querySelector('.cta-carousel__images');
|
|
|
|
if (text) text.classList.add('animate-in');
|
|
setTimeout(() => {
|
|
if (images) images.classList.add('animate-in');
|
|
}, 200);
|
|
}, 100);
|
|
}
|
|
|
|
// Special handling for profile section
|
|
if (element.classList.contains('profile')) {
|
|
setTimeout(() => {
|
|
const requirements = element.querySelector('.profile__requirements');
|
|
const desired = element.querySelector('.profile__desired');
|
|
|
|
if (requirements) requirements.classList.add('animate-in');
|
|
setTimeout(() => {
|
|
if (desired) desired.classList.add('animate-in');
|
|
}, 200);
|
|
}, 100);
|
|
}
|
|
|
|
// Unobserve element after animation is triggered
|
|
observer.unobserve(element);
|
|
}
|
|
});
|
|
}, observerOptions);
|
|
|
|
// Observe all sections
|
|
const sections = $$('section:not(.hero)');
|
|
sections.forEach(section => {
|
|
observer.observe(section);
|
|
});
|
|
|
|
// Observe section headers
|
|
const headers = $$('.section-header');
|
|
headers.forEach(header => {
|
|
observer.observe(header);
|
|
});
|
|
|
|
// Observe individual elements that need animation
|
|
const animatedElements = $$('.benefit-card, .process__step, .faq__item');
|
|
animatedElements.forEach(element => {
|
|
observer.observe(element);
|
|
});
|
|
}
|
|
|
|
// ==============================================
|
|
// INITIALIZATION
|
|
// ==============================================
|
|
|
|
function init() {
|
|
initMobileNav();
|
|
initAnimatedHeadline();
|
|
initSmoothScrolling();
|
|
initHeroCarousel();
|
|
initTestimonialsCarousel();
|
|
initImageCarousel();
|
|
initApplicationForm();
|
|
initFAQAccordions();
|
|
initScrollAnimations();
|
|
initAnalyticsTracking();
|
|
}
|
|
|
|
// Initialize when DOM is ready
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
} else {
|
|
init();
|
|
}
|
|
|
|
// Handle page visibility changes (for analytics)
|
|
document.addEventListener('visibilitychange', () => {
|
|
if (document.visibilityState === 'hidden' && typeof gtag !== 'undefined') {
|
|
gtag('event', 'page_exit', {
|
|
event_category: 'engagement',
|
|
value: Math.round(performance.now() / 1000)
|
|
});
|
|
}
|
|
}); |