// Smooth scrolling 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) { target.scrollIntoView({ behavior: 'smooth' }); } }); }); // Scroll progress bar const progressBar = document.getElementById('progress-bar'); window.addEventListener('scroll', () => { const scrollTop = window.scrollY; const docHeight = document.documentElement.scrollHeight - window.innerHeight; const progress = (scrollTop / docHeight) * 100; progressBar.style.width = progress + '%'; }); // Student discount logic const studentCheckbox = document.getElementById('student'); const plans = { normal: { full: 10, label: 'Normal' }, premium: { full: 15, label: 'Premium' } }; function updatePrices() { const isStudent = studentCheckbox.checked; document.querySelectorAll('.radio-group label').forEach(lbl => { const input = lbl.querySelector('input[type="radio"]'); if (!input) return; const plan = plans[input.value]; if (!plan) return; const discounted = (plan.full * 0.7).toFixed(2); if (isStudent) { lbl.innerHTML = ` ${plan.label} — $${plan.full}/mes 20% OFF $${discounted}/mes `; } else { lbl.innerHTML = ` ${plan.label} — $${plan.full}/mes `; } }); } studentCheckbox.addEventListener('change', updatePrices); // Character counter for textarea const textarea = document.getElementById('reason'); const counter = document.getElementById('reason-counter'); const MAX_CHARS = 300; textarea.addEventListener('input', () => { const len = textarea.value.length; counter.textContent = `${len} / ${MAX_CHARS}`; counter.classList.remove('near-limit', 'at-limit'); if (len >= MAX_CHARS) { textarea.value = textarea.value.slice(0, MAX_CHARS); counter.classList.add('at-limit'); } else if (len >= MAX_CHARS * 0.8) { counter.classList.add('near-limit'); } }); // Form validation function setFieldState(input, isValid) { const group = input.closest('.field-group'); if (!group) return; group.classList.remove('error', 'success'); if (input.value.trim() === '') return; group.classList.add(isValid ? 'success' : 'error'); } // Name and Lastname ['name', 'lastname'].forEach(id => { document.getElementById(id).addEventListener('input', function() { setFieldState(this, this.value.trim().length >= 2); }); }); // Email document.getElementById('email').addEventListener('input', function() { const valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.value); setFieldState(this, valid); }); // MMAA validation document.getElementById('expiry').addEventListener('input', function() { this.value = this.value.replace(/[^\d]/g, '').slice(0, 4); if (this.value.length > 2) { this.value = this.value.slice(0, 2) + '/' + this.value.slice(2); } const valid = /^(0[1-9]|1[0-2])\/\d{2}$/.test(this.value); setFieldState(this, valid); }); // CVV document.getElementById('cvv').addEventListener('input', function() { this.value = this.value.replace(/\D/g, '').slice(0, 4); setFieldState(this, this.value.length >= 3); }); // Plan preview logic const planData = { normal: { name: 'Normal', price: '$10/mes', priceStudent: '$7.00/mes', features: [ '250 g por envío', '1 café de origen único por mes', 'Envío gratuito', 'Guía de preparación' ] }, premium: { name: 'Premium', price: '$15/mes', priceStudent: '$10.50/mes', features: [ '500 g por envío', '2 cafés de origen único por mes', 'Envío gratuito', 'Guía de preparación', 'Acceso a lotes exclusivos' ] } }; const planPreview = document.getElementById('plan-preview'); const planPreviewName = document.getElementById('plan-preview-name'); const planPreviewPrice = document.getElementById('plan-preview-price'); const planPreviewFeatures = document.getElementById('plan-preview-features'); function updatePlanPreview() { const selected = document.querySelector('input[name="plan"]:checked'); if (!selected) { planPreview.classList.remove('visible'); return; } const plan = planData[selected.value]; const isStudent = document.getElementById('student').checked; planPreviewName.textContent = plan.name; planPreviewPrice.textContent = isStudent ? plan.priceStudent : plan.price; planPreviewFeatures.innerHTML = plan.features .map(f => `