/* ============================================ AW Interiors — Premium Script v3 Elite microinteractions & animations ============================================ */ // ─── PRELOADER ────────────────────────────── document.body.style.overflow = 'hidden'; window.addEventListener('load', () => { const fill = document.getElementById('preloaderFill'); const preloader = document.getElementById('preloader'); if (!fill || !preloader) return; requestAnimationFrame(() => { fill.style.width = '100%'; }); setTimeout(() => { preloader.classList.add('hidden'); document.body.style.overflow = 'auto'; initCounters(); initReveal(); }, 2100); }); // ─── CUSTOM CURSOR ─────────────────────────── const cursor = document.getElementById('cursor'); const follower = document.getElementById('cursor-follower'); if (cursor && follower) { let mX = window.innerWidth / 2; let mY = window.innerHeight / 2; let fX = mX, fY = mY; let raf; document.addEventListener('mousemove', (e) => { mX = e.clientX; mY = e.clientY; cursor.style.left = mX + 'px'; cursor.style.top = mY + 'px'; }); document.addEventListener('mousedown', () => document.body.classList.add('cursor-click')); document.addEventListener('mouseup', () => document.body.classList.remove('cursor-click')); document.addEventListener('mouseleave', () => { cursor.style.opacity = '0'; follower.style.opacity = '0'; }); document.addEventListener('mouseenter', () => { cursor.style.opacity = ''; follower.style.opacity = ''; }); (function loopFollower() { fX += (mX - fX) * 0.095; fY += (mY - fY) * 0.095; follower.style.left = fX + 'px'; follower.style.top = fY + 'px'; requestAnimationFrame(loopFollower); })(); const hoverTargets = 'a, button, .portfolio-item, .tag, .filter-btn, .process-step, .testimonial-card, .award-item, .contact-detail'; document.querySelectorAll(hoverTargets).forEach(el => { el.addEventListener('mouseenter', () => document.body.classList.add('cursor-hover')); el.addEventListener('mouseleave', () => document.body.classList.remove('cursor-hover')); }); } // ─── NAV SCROLL ────────────────────────────── const nav = document.getElementById('nav'); let lastScrollY = 0; window.addEventListener('scroll', () => { const y = window.scrollY; if (nav) nav.classList.toggle('scrolled', y > 60); lastScrollY = y; }, { passive: true }); // ─── MOBILE NAV ─────────────────────────────── const navToggle = document.getElementById('navToggle'); const navMobile = document.getElementById('navMobile'); if (navToggle && navMobile) { navToggle.addEventListener('click', () => { const open = navMobile.classList.toggle('open'); navToggle.classList.toggle('open', open); navToggle.setAttribute('aria-expanded', String(open)); document.body.style.overflow = open ? 'hidden' : ''; }); navMobile.querySelectorAll('a').forEach(a => { a.addEventListener('click', () => { navMobile.classList.remove('open'); navToggle.classList.remove('open'); document.body.style.overflow = ''; }); }); } // ─── PARTICLES ──────────────────────────────── (function createParticles() { const container = document.getElementById('heroParticles'); if (!container) return; const style = document.createElement('style'); style.textContent = ` @keyframes pFloat { 0%,100%{transform:translateY(0) translateX(0) scale(1);opacity:var(--op)} 30%{transform:translateY(-24px) translateX(14px) scale(1.12);opacity:calc(var(--op)*1.6)} 65%{transform:translateY(16px) translateX(-10px) scale(0.88);opacity:calc(var(--op)*0.5)} } `; document.head.appendChild(style); for (let i = 0; i < 28; i++) { const p = document.createElement('div'); const size = (Math.random() * 2.8 + 0.5).toFixed(1); const op = (Math.random() * 0.22 + 0.04).toFixed(2); p.style.cssText = [ 'position:absolute', `width:${size}px`, `height:${size}px`, 'background:rgba(200,169,106,1)', 'border-radius:50%', `left:${(Math.random() * 92 + 4).toFixed(1)}%`, `top:${(Math.random() * 92 + 4).toFixed(1)}%`, `--op:${op}`, `opacity:${op}`, `animation:pFloat ${(Math.random() * 12 + 9).toFixed(1)}s ease-in-out infinite`, `animation-delay:-${(Math.random() * 8).toFixed(1)}s`, 'pointer-events:none', 'will-change:transform' ].join(';'); container.appendChild(p); } })(); // ─── REVEAL ON SCROLL ───────────────────────── let revealObserver; function initReveal() { revealObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (!entry.isIntersecting) return; const el = entry.target; el.classList.add('visible'); revealObserver.unobserve(el); }); }, { threshold: 0.07, rootMargin: '0px 0px -48px 0px' }); document.querySelectorAll('.reveal').forEach((el) => { const siblings = Array.from(el.parentElement.querySelectorAll('.reveal')); const idx = siblings.indexOf(el); if (idx > 0 && idx < 6) { const existing = parseFloat(el.style.transitionDelay) || 0; el.style.transitionDelay = (existing + idx * 0.09) + 's'; } revealObserver.observe(el); }); } // ─── COUNTER ANIMATION ──────────────────────── function initCounters() { const easeOutExpo = t => t === 1 ? 1 : 1 - Math.pow(2, -10 * t); document.querySelectorAll('.hero-stat-num').forEach(el => { const target = parseInt(el.dataset.count, 10); if (!target) return; const dur = 2000; const start = performance.now(); function tick(now) { const p = Math.min((now - start) / dur, 1); el.textContent = Math.round(easeOutExpo(p) * target); if (p < 1) requestAnimationFrame(tick); else el.textContent = target; } requestAnimationFrame(tick); }); } // ─── PORTFOLIO FILTER ───────────────────────── const filterBtns = document.querySelectorAll('.filter-btn'); const portfolioItems = document.querySelectorAll('.portfolio-item'); filterBtns.forEach(btn => { btn.addEventListener('click', () => { if (btn.classList.contains('active')) return; filterBtns.forEach(b => b.classList.remove('active')); btn.classList.add('active'); const filter = btn.dataset.filter; let delay = 0; portfolioItems.forEach(item => { const match = filter === 'all' || item.dataset.category === filter; if (match) { item.classList.remove('filtered-out'); item.style.opacity = '0'; item.style.transform = 'translateY(12px) scale(0.98)'; item.style.transition = 'none'; requestAnimationFrame(() => { setTimeout(() => { item.style.transition = `opacity 0.55s ease ${delay}s, transform 0.55s cubic-bezier(0.16,1,0.3,1) ${delay}s`; item.style.opacity = '1'; item.style.transform = 'translateY(0) scale(1)'; }, 16); }); delay += 0.06; } else { item.style.transition = 'opacity 0.3s ease, transform 0.3s ease'; item.style.opacity = '0'; item.style.transform = 'scale(0.97)'; setTimeout(() => { item.classList.add('filtered-out'); item.style.opacity = ''; item.style.transform = ''; item.style.transition = ''; }, 310); } }); }); }); // ─── MAGNETIC BUTTONS ───────────────────────── document.querySelectorAll('.btn-primary, .nav-cta').forEach(btn => { btn.addEventListener('mousemove', (e) => { const rect = btn.getBoundingClientRect(); const dx = (e.clientX - rect.left - rect.width / 2) * 0.22; const dy = (e.clientY - rect.top - rect.height / 2) * 0.22; btn.style.transform = `translate(${dx}px, ${dy}px)`; }); btn.addEventListener('mouseleave', () => { btn.style.transform = ''; }); }); // ─── CONTACT FORM ───────────────────────────── const form = document.getElementById('contactForm'); const formSuccess = document.getElementById('formSuccess'); if (form) { form.addEventListener('submit', (e) => { e.preventDefault(); const btn = form.querySelector('button[type="submit"]'); if (btn.disabled) return; const originalHTML = btn.innerHTML; btn.innerHTML = `Wysyłanie`; btn.disabled = true; if (!document.getElementById('spinBtnStyle')) { const s = document.createElement('style'); s.id = 'spinBtnStyle'; s.textContent = '@keyframes spinBtn{to{rotate:360deg}}'; document.head.appendChild(s); } setTimeout(() => { form.reset(); if (formSuccess) { formSuccess.classList.add('visible'); setTimeout(() => formSuccess.classList.remove('visible'), 5500); } btn.innerHTML = originalHTML; btn.disabled = false; }, 1700); }); // Live label animation for select const select = form.querySelector('select'); if (select) { select.style.color = 'rgba(244,239,232,0.3)'; select.addEventListener('change', () => { select.style.color = select.value ? 'var(--white)' : 'rgba(244,239,232,0.3)'; }); } } // ─── SMOOTH ANCHOR SCROLL ───────────────────── document.querySelectorAll('a[href^="#"]').forEach(link => { link.addEventListener('click', (e) => { const href = link.getAttribute('href'); if (href === '#') return; const target = document.querySelector(href); if (target) { e.preventDefault(); const navH = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--nav-h'), 10) || 78; const offset = target.getBoundingClientRect().top + window.scrollY - navH; window.scrollTo({ top: offset, behavior: 'smooth' }); } }); }); // ─── PARALLAX ───────────────────────────────── function onScroll() { const y = window.scrollY; const heroGrid = document.querySelector('.hero-grid'); if (heroGrid && y < window.innerHeight * 1.6) { heroGrid.style.transform = `translateY(${y * 0.22}px)`; } const philoBg = document.querySelector('.philosophy-bg'); if (philoBg) { const rect = philoBg.parentElement.getBoundingClientRect(); if (rect.top < window.innerHeight && rect.bottom > 0) { const progress = (window.innerHeight - rect.top) / (window.innerHeight + rect.height); philoBg.style.transform = `scale(1.06) translateY(${(progress - 0.5) * -28}px)`; } } } window.addEventListener('scroll', onScroll, { passive: true }); // ─── SECTION SEPARATOR LINES ────────────────── const sepStyle = document.createElement('style'); sepStyle.textContent = ` .section-sep{height:1px;background:linear-gradient(to right,transparent,rgba(200,169,106,0.28),transparent);transform:scaleX(0);transform-origin:left;transition:transform 1.3s cubic-bezier(0.16,1,0.3,1)} .section-sep.line-visible{transform:scaleX(1)} `; document.head.appendChild(sepStyle); const lineObs = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('line-visible'); }); }, { threshold: 0.3 }); document.querySelectorAll('.section-sep').forEach(el => lineObs.observe(el)); // ─── TILT ON HOVER — PORTFOLIO CARDS ────────── document.querySelectorAll('.portfolio-item').forEach(card => { card.addEventListener('mousemove', (e) => { const rect = card.getBoundingClientRect(); const x = (e.clientX - rect.left) / rect.width - 0.5; const y = (e.clientY - rect.top) / rect.height - 0.5; card.style.transform = `translateY(-3px) rotateX(${-y * 4}deg) rotateY(${x * 4}deg)`; }); card.addEventListener('mouseleave', () => { card.style.transform = ''; }); });