/* ── Navbar scroll ── */ const navbar = document.getElementById('navbar'); window.addEventListener('scroll', () => { navbar.classList.toggle('scrolled', window.scrollY > 20); }); /* ── Mobile menu ── */ const mobileToggle = document.getElementById('mobileToggle'); const mobileMenu = document.getElementById('mobileMenu'); mobileToggle.addEventListener('click', () => { mobileMenu.classList.toggle('open'); }); function closeMobile() { mobileMenu.classList.remove('open'); } /* ── Toast ── */ function showToast(msg) { const toast = document.getElementById('toast'); document.getElementById('toast-msg').textContent = msg; toast.classList.add('show'); setTimeout(() => toast.classList.remove('show'), 2500); } /* ── FAQ ── */ function toggleFaq(btn) { const item = btn.closest('.faq-item'); const isOpen = item.classList.contains('open'); document.querySelectorAll('.faq-item').forEach(i => i.classList.remove('open')); if (!isOpen) item.classList.add('open'); btn.setAttribute('aria-expanded', !isOpen); } /* ── Calculator ── */ let currentResult = null; function switchTab(tabName) { document.querySelectorAll('.tab-content').forEach(t => t.style.display = 'none'); document.querySelectorAll('.tool-tab').forEach(b => b.classList.remove('active')); document.getElementById(tabName + '-tab').style.display = 'block'; document.getElementById('tab-' + tabName).classList.add('active'); clearResults(); } function calculateBasic() { const value = parseFloat(document.getElementById('basicValue').value); const pct = parseFloat(document.getElementById('basicPercentage').value); if (isNaN(value) || isNaN(pct)) { showErr('Please enter valid numbers'); return; } const result = (value * pct) / 100; currentResult = { type: 'basic', result, description: `${pct}% of ${value}`, calculation: `(${value} × ${pct}) ÷ 100 = ${result.toFixed(2)}` }; renderResult(); } function calculateIncrease() { const original = parseFloat(document.getElementById('increaseOriginal').value); const newVal = parseFloat(document.getElementById('increaseNew').value); if (isNaN(original) || isNaN(newVal)) { showErr('Please enter valid numbers'); return; } if (original === 0) { showErr('Original value cannot be zero'); return; } const diff = newVal - original; const pctChange = (diff / original) * 100; const isInc = diff >= 0; currentResult = { type: 'change', result: Math.abs(pctChange), isIncrease: isInc, description: `${isInc ? '▲ Increase' : '▼ Decrease'} of ${Math.abs(diff).toFixed(2)}`, calculation: `((${newVal} − ${original}) ÷ ${original}) × 100 = ${pctChange.toFixed(2)}%` }; renderResult(); } function calculatePart() { const part = parseFloat(document.getElementById('partValue').value); const whole = parseFloat(document.getElementById('wholeValue').value); if (isNaN(part) || isNaN(whole)) { showErr('Please enter valid numbers'); return; } if (whole === 0) { showErr('Whole value cannot be zero'); return; } const pct = (part / whole) * 100; currentResult = { type: 'part', result: pct, description: `${part} is ${pct.toFixed(2)}% of ${whole}`, calculation: `(${part} ÷ ${whole}) × 100 = ${pct.toFixed(2)}%` }; renderResult(); } function renderResult() { const box = document.getElementById('results'); let numClass = ''; if (currentResult.type === 'change') numClass = currentResult.isIncrease ? 'increase' : 'decrease'; const numStr = currentResult.result.toFixed(2) + (currentResult.type !== 'basic' ? '%' : ''); box.innerHTML = `
${numStr}
${currentResult.description}
${currentResult.calculation}
`; document.getElementById('action-buttons').style.display = 'flex'; } function showErr(msg) { document.getElementById('results').innerHTML = `⚠ ${msg}`; document.getElementById('action-buttons').style.display = 'none'; } function clearResults() { document.getElementById('results').innerHTML = `Enter values above and hit calculate`; document.getElementById('action-buttons').style.display = 'none'; currentResult = null; } function copyResult() { if (!currentResult) return; const text = `Result: ${currentResult.result.toFixed(2)}${currentResult.type !== 'basic' ? '%' : ''}\n${currentResult.description}\nFormula: ${currentResult.calculation}`; navigator.clipboard.writeText(text).then(() => showToast('Result copied to clipboard!')).catch(() => { const ta = document.createElement('textarea'); ta.value = text; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); showToast('Copied!'); }); } function shareResult() { if (!currentResult) return; const url = window.location.href.split('?')[0]; const shareUrl = `${url}?result=${encodeURIComponent(JSON.stringify(currentResult))}`; navigator.clipboard.writeText(shareUrl).then(() => showToast('Share link copied!')).catch(() => prompt('Copy this link:', shareUrl)); } /* ── Load shared result from URL ── */ window.addEventListener('load', () => { const params = new URLSearchParams(window.location.search); const shared = params.get('result'); if (shared) { try { currentResult = JSON.parse(decodeURIComponent(shared)); renderResult(); } catch (e) { console.error('Invalid shared result'); } } }); /* ── Enter key support ── */ document.addEventListener('keypress', (e) => { if (e.key === 'Enter') { const active = document.querySelector('.tab-content:not([style*="none"])'); if (active) { const btn = active.querySelector('.calc-btn'); if (btn) btn.click(); } } }); /* ── Scroll reveal (Intersection Observer) ── */ const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; observer.unobserve(entry.target); } }); }, { threshold: 0.1 }); document.querySelectorAll('.feature-card, .step, .usecase-card, .testimonial-card, .pricing-card, .faq-item').forEach(el => { el.style.opacity = '0'; el.style.transform = 'translateY(20px)'; el.style.transition = 'opacity 0.5s ease, transform 0.5s ease'; observer.observe(el); });