Spaces:
Running
Running
| // Custom cursor | |
| const cursor = document.getElementById('cursor'); | |
| const follower = document.getElementById('cursorFollower'); | |
| let mouseX = 0, mouseY = 0, followerX = 0, followerY = 0; | |
| document.addEventListener('mousemove', e => { | |
| mouseX = e.clientX; mouseY = e.clientY; | |
| cursor.style.left = mouseX + 'px'; | |
| cursor.style.top = mouseY + 'px'; | |
| }); | |
| function animateFollower() { | |
| followerX += (mouseX - followerX) * 0.1; | |
| followerY += (mouseY - followerY) * 0.1; | |
| follower.style.left = followerX + 'px'; | |
| follower.style.top = followerY + 'px'; | |
| requestAnimationFrame(animateFollower); | |
| } | |
| animateFollower(); | |
| document.querySelectorAll('a, button, .project-card, .service-card').forEach(el => { | |
| el.addEventListener('mouseenter', () => { cursor.classList.add('hover'); follower.classList.add('hover'); }); | |
| el.addEventListener('mouseleave', () => { cursor.classList.remove('hover'); follower.classList.remove('hover'); }); | |
| }); | |
| // Nav scroll | |
| const nav = document.getElementById('nav'); | |
| window.addEventListener('scroll', () => { | |
| nav.classList.toggle('scrolled', window.scrollY > 50); | |
| }); | |
| // Burger menu | |
| const burger = document.getElementById('burger'); | |
| const mobileMenu = document.getElementById('mobileMenu'); | |
| burger.addEventListener('click', () => { | |
| mobileMenu.classList.toggle('open'); | |
| const spans = burger.querySelectorAll('span'); | |
| if (mobileMenu.classList.contains('open')) { | |
| spans[0].style.transform = 'rotate(45deg) translate(5px,5px)'; | |
| spans[1].style.opacity = '0'; | |
| spans[2].style.transform = 'rotate(-45deg) translate(5px,-5px)'; | |
| } else { | |
| spans.forEach(s => { s.style.transform = ''; s.style.opacity = ''; }); | |
| } | |
| }); | |
| document.querySelectorAll('.mm-link').forEach(link => { | |
| link.addEventListener('click', () => { | |
| mobileMenu.classList.remove('open'); | |
| burger.querySelectorAll('span').forEach(s => { s.style.transform = ''; s.style.opacity = ''; }); | |
| }); | |
| }); | |
| // Scroll reveal | |
| const revealElements = document.querySelectorAll('.project-card, .service-card, .process-step, .testi-card, .about-content, .about-visual, .contact-left, .contact-right'); | |
| revealElements.forEach(el => el.classList.add('reveal')); | |
| const observer = new IntersectionObserver((entries) => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| entry.target.classList.add('visible'); | |
| observer.unobserve(entry.target); | |
| } | |
| }); | |
| }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }); | |
| revealElements.forEach(el => observer.observe(el)); | |
| // Contact form | |
| document.getElementById('contactForm').addEventListener('submit', e => { | |
| e.preventDefault(); | |
| const btn = e.target.querySelector('.btn-submit span'); | |
| const orig = btn.textContent; | |
| btn.textContent = 'Message Sent! ✓'; | |
| e.target.reset(); | |
| setTimeout(() => { btn.textContent = orig; }, 3000); | |
| }); | |
| // Smooth anchor scroll | |
| document.querySelectorAll('a[href^="#"]').forEach(anchor => { | |
| anchor.addEventListener('click', e => { | |
| const target = document.querySelector(anchor.getAttribute('href')); | |
| if (target) { e.preventDefault(); target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } | |
| }); | |
| }); | |