// header scroll const hdr = document.getElementById('hdr'); const onScroll = () => { hdr.classList.toggle('scrolled', window.scrollY > 12); }; onScroll(); window.addEventListener('scroll', onScroll, { passive: true }); // nav scrollspy: highlight the nav link for the section currently in view const navLinkMap = new Map(); document.querySelectorAll('.nav-links a[href^="#"]').forEach((a) => { navLinkMap.set(a.getAttribute('href').slice(1), a); }); const spySections = [...navLinkMap.keys()].map((id) => document.getElementById(id)).filter(Boolean); if (spySections.length) { const spy = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (!entry.isIntersecting) return; const link = navLinkMap.get(entry.target.id); if (!link) return; navLinkMap.forEach((a) => a.classList.remove('active')); link.classList.add('active'); }); }, { rootMargin: '-40% 0px -50% 0px', threshold: 0 }); spySections.forEach((sec) => spy.observe(sec)); } // reveal on scroll const io = new IntersectionObserver((es) => { es.forEach(e => { if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); } }); }, { threshold: 0.12, rootMargin: '0px 0px -6% 0px' }); document.querySelectorAll('.reveal').forEach(el => io.observe(el)); // marquee logos const logos = [ ['Stellar', 'hgi-global'], ['Soroban', 'hgi-source-code'], ['Paillier FHE', 'hgi-lock-01'], ['Nova IVC', 'hgi-layers-01'], ['Shamir SSS', 'hgi-user-multiple-02'], ['Merkle Trees', 'hgi-git-fork'], ['SEP-8', 'hgi-checkmark-circle-01'], ['Groth16', 'hgi-shield-01'], ]; const mk = (name, icon) => `
${name}
`; const html = logos.map(l => mk(l[0], l[1])).join(''); const mq = document.getElementById('mq'); if (mq) mq.innerHTML = html + html; // console proof animation const rows = [...document.querySelectorAll('.proof-row')]; const bar = document.getElementById('pbar'); function runProofs() { rows.forEach(r => r.classList.remove('show')); if (bar) { bar.style.transition = 'none'; bar.style.width = '0%'; } rows.forEach((r, i) => setTimeout(() => r.classList.add('show'), 400 + i * 600)); setTimeout(() => { if (bar) { bar.style.transition = 'width 1.8s cubic-bezier(.22,.61,.36,1)'; bar.style.width = '100%'; } }, 600); } const cons = document.querySelector('.console'); if (cons) { let interval; const co = new IntersectionObserver((es) => { es.forEach(e => { if (e.isIntersecting) { runProofs(); interval = setInterval(runProofs, 5000); } else { clearInterval(interval); } }); }, { threshold: 0.3 }); co.observe(cons); } // count-up stats const animateCount = (el) => { const to = +el.dataset.to; const dur = 1100; const t0 = performance.now(); const tick = (t) => { const p = Math.min((t - t0) / dur, 1); const e = 1 - Math.pow(1 - p, 3); el.textContent = Math.round(to * e); if (p < 1) requestAnimationFrame(tick); }; requestAnimationFrame(tick); }; const so = new IntersectionObserver((es) => { es.forEach(e => { if (e.isIntersecting) { animateCount(e.target); so.unobserve(e.target); } }); }, { threshold: 0.6 }); document.querySelectorAll('.count').forEach(el => so.observe(el)); // mobile nav toggle const toggle = document.querySelector('.nav-toggle'); const navLinks = document.querySelector('.nav-links'); if (toggle && navLinks) { toggle.addEventListener('click', () => { const open = navLinks.style.display === 'flex'; navLinks.style.display = open ? '' : 'flex'; navLinks.style.flexDirection = 'column'; navLinks.style.position = 'absolute'; navLinks.style.top = '68px'; navLinks.style.left = '12px'; navLinks.style.right = '12px'; navLinks.style.background = '#fff'; navLinks.style.border = '1px solid #E4E4E7'; navLinks.style.borderRadius = '12px'; navLinks.style.padding = '8px'; navLinks.style.boxShadow = '0 8px 24px rgba(0,0,0,.1)'; navLinks.style.zIndex = '300'; }); } // scroll progress bar const progressBar = document.createElement('div'); progressBar.className = 'scroll-progress'; document.body.appendChild(progressBar); const updateProgress = () => { const h = document.documentElement; const scrolled = (h.scrollTop) / (h.scrollHeight - h.clientHeight || 1) * 100; progressBar.style.width = scrolled + '%'; }; updateProgress(); window.addEventListener('scroll', updateProgress, { passive: true }); // cursor spotlight glow const spotlight = document.createElement('div'); spotlight.className = 'spotlight'; document.body.appendChild(spotlight); window.addEventListener('mousemove', (e) => { spotlight.style.opacity = '1'; spotlight.style.left = e.clientX + 'px'; spotlight.style.top = e.clientY + 'px'; }, { passive: true }); window.addEventListener('mouseleave', () => { spotlight.style.opacity = '0'; }); // magnetic buttons + 3D tilt cards (desktop pointer only, respects reduced motion) (function () { const canHover = window.matchMedia('(hover: hover) and (pointer: fine)').matches; const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (!canHover || reduced) return; document.querySelectorAll('.btn-lg').forEach((btn) => { let raf = null; let lastEvent = null; const apply = () => { if (!lastEvent) return; const r = btn.getBoundingClientRect(); const x = lastEvent.clientX - (r.left + r.width / 2); const y = lastEvent.clientY - (r.top + r.height / 2); btn.style.transform = `translate(${(x * 0.18).toFixed(2)}px, ${(y * 0.35).toFixed(2)}px)`; raf = null; }; btn.addEventListener('pointermove', (e) => { lastEvent = e; if (raf === null) raf = requestAnimationFrame(apply); }); btn.addEventListener('pointerleave', () => { btn.style.transform = ''; }); }); const tiltEls = document.querySelectorAll('.card, .feat, .step, .uc, .integ, .quote, .gstat'); tiltEls.forEach((el) => { let raf = null; let lastEvent = null; const apply = () => { if (!lastEvent) return; const r = el.getBoundingClientRect(); const px = (lastEvent.clientX - r.left) / r.width - 0.5; const py = (lastEvent.clientY - r.top) / r.height - 0.5; el.style.transform = `perspective(700px) rotateX(${(-py * 7).toFixed(2)}deg) rotateY(${(px * 9).toFixed(2)}deg) translateY(-4px)`; raf = null; }; el.addEventListener('pointerenter', () => { el.style.willChange = 'transform'; }); el.addEventListener('pointermove', (e) => { lastEvent = e; if (raf === null) raf = requestAnimationFrame(apply); }); el.addEventListener('pointerleave', () => { el.style.transform = ''; el.style.willChange = 'auto'; }); }); })();