(function() { 'use strict'; const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; // Update year in footer const yearEl = document.getElementById('current-year'); if (yearEl) { yearEl.textContent = new Date().getFullYear(); } // Custom cursor const cursor = document.querySelector('.cursor-follower'); let mouseX = 0, mouseY = 0; let cursorX = 0, cursorY = 0; let cursorVisible = false; let animationFrameId = null; if (cursor && !prefersReducedMotion && window.matchMedia('(pointer: fine)').matches) { function startCursorAnimation() { if (animationFrameId) return; animateCursor(); } function stopCursorAnimation() { if (animationFrameId) { cancelAnimationFrame(animationFrameId); animationFrameId = null; } } document.addEventListener('mousemove', (e) => { mouseX = e.clientX; mouseY = e.clientY; if (!cursorVisible) { cursorVisible = true; cursor.classList.add('active'); startCursorAnimation(); } }); document.addEventListener('mouseleave', () => { cursorVisible = false; cursor.classList.remove('active'); stopCursorAnimation(); }); const interactiveElements = document.querySelectorAll('a, button, input, textarea, [tabindex]'); interactiveElements.forEach(el => { el.addEventListener('mouseenter', () => cursor.classList.add('hover')); el.addEventListener('mouseleave', () => cursor.classList.remove('hover')); }); function animateCursor() { const ease = 0.15; cursorX += (mouseX - cursorX) * ease; cursorY += (mouseY - cursorY) * ease; cursor.style.left = cursorX + 'px'; cursor.style.top = cursorY + 'px'; if (cursorVisible) { animationFrameId = requestAnimationFrame(animateCursor); } } } // Navigation scroll effect const nav = document.querySelector('.main-nav'); window.addEventListener('scroll', () => { if (window.scrollY > 50) { nav.classList.add('scrolled'); } else { nav.classList.remove('scrolled'); } }, { passive: true }); // Mobile navigation toggle const navToggle = document.querySelector('.nav-toggle'); const navLinks = document.querySelector('.nav-links'); if (navToggle && navLinks) { navToggle.addEventListener('click', () => { const isOpen = navToggle.getAttribute('aria-expanded') === 'true'; navToggle.setAttribute('aria-expanded', !isOpen); navLinks.classList.toggle('open'); document.body.style.overflow = isOpen ? '' : 'hidden'; }); navLinks.querySelectorAll('a').forEach(link => { link.addEventListener('click', () => { navToggle.setAttribute('aria-expanded', 'false'); navLinks.classList.remove('open'); document.body.style.overflow = ''; }); }); // Close on escape document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && navLinks.classList.contains('open')) { navToggle.setAttribute('aria-expanded', 'false'); navLinks.classList.remove('open'); document.body.style.overflow = ''; navToggle.focus(); } }); } // Reveal animations with Intersection Observer if (!prefersReducedMotion) { const reveals = document.querySelectorAll('.reveal'); let revealDelay = 0; const revealObserver = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { setTimeout(() => { entry.target.classList.add('visible'); }, revealDelay); revealDelay += 80; setTimeout(() => { revealDelay = 0; }, 500); revealObserver.unobserve(entry.target); } }); }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }); reveals.forEach(el => revealObserver.observe(el)); } else { document.querySelectorAll('.reveal').forEach(el => { el.classList.add('visible'); }); } // Smooth scroll for anchor links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function(e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { const offsetTop = target.offsetTop - 80; window.scrollTo({ top: offsetTop, behavior: prefersReducedMotion ? 'auto' : 'smooth' }); // Move focus to target for accessibility target.setAttribute('tabindex', '-1'); target.focus({ preventScroll: true }); } }); }); // Form handling with validation const contactForm = document.getElementById('contact-form'); if (contactForm) { const nameInput = contactForm.querySelector('#name'); const emailInput = contactForm.querySelector('#email'); function validateField(input, errorEl) { let isValid = true; let message = ''; if (input.required && !input.value.trim()) { isValid = false; message = 'שדה חובה'; } else if (input.type === 'email' && input.value) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(input.value)) { isValid = false; message = 'כתובת דוא״ל לא תקינה'; } } if (errorEl) { errorEl.textContent = message; } input.classList.toggle('error', !isValid); return isValid; } [nameInput, emailInput].forEach(input => { if (input) { const errorEl = input.parentElement.querySelector('.error-message'); input.addEventListener('blur', () => validateField(input, errorEl)); input.addEventListener('input', () => { if (input.classList.contains('error')) { validateField(input, errorEl); } }); } }); contactForm.addEventListener('submit', function(e) { e.preventDefault(); const nameError = nameInput.parentElement.querySelector('.error-message'); const emailError = emailInput.parentElement.querySelector('.error-message'); const nameValid = validateField(nameInput, nameError); const emailValid = validateField(emailInput, emailError); if (!nameValid || !emailValid) { const firstInvalid = contactForm.querySelector('.error'); if (firstInvalid) firstInvalid.focus(); return; } const btn = this.querySelector('.submit-btn'); const btnText = btn.querySelector('span'); const status = this.querySelector('.form-status'); const originalText = btnText.textContent; btnText.textContent = 'שולח...'; btn.disabled = true; // Simulate submission setTimeout(() => { btnText.textContent = 'נשלח בהצלחה!'; btn.classList.add('success'); status.textContent = 'תודה! נחזור אליכם בהקדם.'; setTimeout(() => { btnText.textContent = originalText; btn.classList.remove('success'); btn.disabled = false; status.textContent = ''; contactForm.reset(); // Clear any error states contactForm.querySelectorAll('.error').forEach(el => el.classList.remove('error')); contactForm.querySelectorAll('.error-message').forEach(el => el.textContent = ''); }, 3000); }, 1500); }); } // Kanji rotation on scroll (only if motion is allowed) if (!prefersReducedMotion) { const kanji = document.querySelector('.kanji-overlay'); const aboutSection = document.querySelector('.about'); if (kanji && aboutSection) { const kanjiObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { window.addEventListener('scroll', handleKanjiScroll, { passive: true }); } else { window.removeEventListener('scroll', handleKanjiScroll); } }); }, { threshold: 0 }); function handleKanjiScroll() { const rect = aboutSection.getBoundingClientRect(); const progress = 1 - (rect.bottom / (window.innerHeight + rect.height)); const rotation = Math.max(0, Math.min(progress * 10, 10)); const isRTL = document.documentElement.dir === 'rtl'; const translateX = isRTL ? '50%' : '-50%'; kanji.style.transform = `translate(${translateX}, -50%) rotate(${rotation}deg)`; } kanjiObserver.observe(aboutSection); } } })();