// ============= GOOGLE ADS TAG (injection automatique) ============= (function() { if (window.__ticoqueGtagInjected) return; window.__ticoqueGtagInjected = true; var s = document.createElement('script'); s.async = true; s.src = 'https://www.googletagmanager.com/gtag/js?id=AW-18145448272'; document.head.appendChild(s); window.dataLayer = window.dataLayer || []; window.gtag = function() { dataLayer.push(arguments); }; gtag('js', new Date()); gtag('config', 'AW-18145448272'); })(); // ==================================================================== // SIMULATOR TICOQUE V16 — Projet Complet Piscine + Aménagement // Décisions validées 4 voix (Seb + Claude Chat + ChatGPT + Code) le 03/05/2026 // Tarifs V3 catalogue 2026 + ajout DP-S180 + photo H1600 corrigée + dim+longueur // + Margelles auto + Plage 5 procédés + Avantage progressif 500/1000/1500 € // ==================================================================== // ============= CATALOG PISCINES ============= var TICOQUE_CATALOG = { spas: [ {ref:'SPA-01', nom:'Demoiselle', dim:'2,10×1,84×0,62m', surface:'3,9 m²', perimetre:8.7, prix:3453, photo:'ticoque-spa_demoiselle_01_clean.jpg'}, {ref:'SPA-02', nom:'Anémone', dim:'⌀1,80×1,00m', surface:'2,5 m²', perimetre:7.9, prix:3942, photo:'ticoque-spa_anemone_01_clean.jpg'}, {ref:'SPA-03', nom:'Galet', dim:'2,20×2,20×0,90m', surface:'4,8 m²', perimetre:9.7, prix:4574, photo:'ticoque-spa_galet_01_clean.jpg'} ], petites: [ {ref:'FPS-01', nom:'Picot', dim:'3,00×2,00×1,00m', surface:'6,0 m²', perimetre:11.0, prix:9900, photo:'ticoque_picot_01_clean.jpg'}, {ref:'FPS-02', nom:'Sirima', dim:'3,60×2,15×1,00m', surface:'7,7 m²', perimetre:12.7, prix:10500, photo:'ticoque_sirima_03_clean.jpg'}, {ref:'FPS-03', nom:'Baliste', dim:'3,20×2,00×1,20m', surface:'6,4 m²', perimetre:11.4, prix:11900, photo:'ticoque_baliste_02_clean_branded.jpg', badge:'Best-seller'}, {ref:'FPS-04', nom:'Tang', dim:'3,60×2,15×1,40m', surface:'9,7 m²', perimetre:12.7, prix:12900, photo:'ticoque_tang_02_clean.jpg'} ], design: [ {ref:'DSP-01', nom:'Capucin', dim:'5,40×2,20×1,40m', surface:'11,9 m²', perimetre:16.7, prix:16900, photo:'capucin-1.jpg'}, {ref:'DSP-02', nom:'Bourgeois', dim:'5,80×2,20×1,20m', surface:'12,8 m²', perimetre:17.6, prix:16900, photo:'bourgeois-1.jpg'}, {ref:'DSP-02C', nom:'Bourgeois Sport', dim:'5,64×2,20×1-1,3m', surface:'12,4 m²', perimetre:17.2, prix:17900, photo:'bourgeois-sport-1.jpg'}, {ref:'DSP-03', nom:'Perroquet', dim:'6,00×2,00×1,20m', surface:'12,0 m²', perimetre:17.6, prix:16900, photo:'perroquet-1.jpg'}, {ref:'DSP-04', nom:'Bécune', dim:'6,00×2,45×1,45m', surface:'14,7 m²', perimetre:18.6, prix:17900, photo:'becune-1.jpg'}, {ref:'DSP-05', nom:'Empereur', dim:'7,00×2,30×1,40m', surface:'16,1 m²', perimetre:20.5, prix:19500, photo:'empereur-1.jpg'} ], modulaires: [ {ref:'MSP-04', nom:'Mérou', dim:'6,00×3,00×1,50m', surface:'18,0 m²', perimetre:18.0, prix:20900, photo:'ticoque_merou_02_clean.jpg', badge:'Best-seller'}, {ref:'MSP-01', nom:'Carangue', dim:'8,00×4,00×1,60m', surface:'32,0 m²', perimetre:26.4, prix:26900, photo:'ticoque_carangue_03_clean.jpg'}, {ref:'MSP-02', nom:'Wahoo', dim:'8,00×4,00×1,60m', surface:'32,0 m²', perimetre:26.4, prix:28900, photo:'ticoque_wahoo_01_clean.jpg'}, {ref:'MSP-03', nom:'Bonite', dim:'8,00×4,00×1,60m', surface:'32,0 m²', perimetre:26.4, prix:29900, photo:'ticoque_bonite_01_clean_nologo.jpg'}, {ref:'MSP-05', nom:'Thazard', dim:'8,00×4,00×1,60m', surface:'32,0 m²', perimetre:26.4, prix:32900, photo:'tc-3d-real-msp05.jpg'}, {ref:'MSP-06', nom:'Marlin', dim:'9,00×6,00×1,60m', surface:'54,0 m²', perimetre:30.0, prix:49900, photo:'ticoque_marlin_02_clean.jpg', badge:'Exclusivité 974'} ], toboggans: [ {ref:'DP-S178', nom:'T-1,8 Compact', dim:'H 1,78 m · L 2,80 m', emprise:'1,55x2,07m', prix:5990, photo:'toboggan-02-1_branded.jpg'}, {ref:'DP-S180', nom:'T-1,8 Grand', dim:'H 1,80 m · L 8,00 m', emprise:'8,60x3,50m', prix:10534, photo:'ticoque_toboggan_s180_clean.png'}, {ref:'DP-H1000', nom:'T-1,0 Famille', dim:'H 1,00 m · L 8,00 m', emprise:'5,00x5,00m', prix:10190, photo:'TiCoque_Toboggan_T-10-Famille_H1000_01-scaled.png'}, {ref:'DP-H1600', nom:'T-1,6 Parcours', dim:'H 1,60 m · L 6,00 m', emprise:'5,70x3,40m', prix:11546, photo:'ticoque_toboggan_h1600_clean.png'}, {ref:'DP-H120', nom:'T-1,2 XL', dim:'H 1,20 m · L 10,50 m', emprise:'4,60x7,40m', prix:12044, photo:'ticoque_toboggan_dp-h120_01_clean.jpg'}, {ref:'DP-CS200', nom:'T-2,0 Sensation', dim:'H 2,00 m · L 18,00 m', emprise:'3,60x2,90m', prix:14069, photo:'ticoque_toboggan_dp-cs200_01_clean.jpg', badge:'Nouveau'}, {ref:'DP-H230', nom:'T-2,3 Pro', dim:'H 2,30 m · L 14,60 m', emprise:'7,60x4,50m', prix:19109, photo:'ticoque_toboggan_h230_02_clean.jpg', badge:'Top de gamme'}, {ref:'DP-H220', nom:'T-2,2 Sport', dim:'H 2,20 m · L 16,50 m', emprise:'6,50x4,50m', prix:19522, photo:'ticoque_toboggan_h220_01_clean.jpg'} ] }; // ============= TARIFS ARE ============= var ARE_PLAGE_PRICES = {imprime:120, cire:170, enduit:110, gazon:100, ndp:130}; var ARE_PLAGE_NAMES = { imprime:'Béton imprimé sol', cire:'Béton ciré extérieur', enduit:'Enduit projeté / sol décoratif', gazon:'Gazon synthétique', ndp:'À définir au RDV' }; var ARE_MARGELLE_PRICE_ML = 100; // €/ml posé var PACK_OFFER_END = '2026-06-30'; // ============= PHOTOS BASE URL ============= var PHOTO_BASE_URL = 'https://ti-coque.re/wp-content/uploads/2026/04/'; var PHOTO_BASE_URL_2026_05 = 'https://ti-coque.re/wp-content/uploads/2026/05/'; function photoUrl(filename) { if (!filename) return ''; // URL complete deja fournie if (filename.indexOf('http') === 0) return filename; // Photos uploaded in May (toboggan-h1600, s180, becune, empereur) if (filename.indexOf('h1600_clean.png') >= 0 || filename.indexOf('s180_clean.png') >= 0 || filename === 'becune-1.jpg' || filename === 'empereur-1.jpg') { return PHOTO_BASE_URL_2026_05 + filename; } return PHOTO_BASE_URL + filename; } // ============= STATE ============= var state = { selectedPiscine: null, selectedToboggan: null, margelles: 'rdv', // 'oui' | 'non' | 'rdv' plage: 'rdv', // 'oui' | 'non' | 'rdv' procede: null, // 'imprime' | 'cire' | 'enduit' | 'gazon' | 'ndp' surface: null, // number (m²) | 'ndp' surfaceNdp: false }; // ============= RENDER MODELES ============= function renderModels(catKey, containerId, isToboggan) { var container = document.getElementById(containerId); if (!container) return; var items = TICOQUE_CATALOG[catKey]; if (!items) return; container.innerHTML = ''; items.forEach(function(item) { var card = document.createElement('div'); card.className = 'tc-model'; card.dataset.ref = item.ref; var hasPhoto = item.photo && item.photo.length > 0; var photoStyle = hasPhoto ? 'background:url(\'' + photoUrl(item.photo) + '\') center/cover no-repeat;' : 'background:linear-gradient(135deg,var(--navy),var(--navy-deep));'; var badgeHtml = item.badge ? '' + item.badge + '' : ''; var dimHtml = isToboggan ? '
' + item.dim + ' · emprise ' + item.emprise + '
' : '
' + item.dim + ' · ' + item.surface + '
'; card.innerHTML = '
' + '
' + item.nom + ' ' + badgeHtml + '
' + dimHtml + '
' + item.ref + '
' + '
' + item.prix.toLocaleString('fr-FR') + ' € TTC
'; card.addEventListener('click', function() { if (isToboggan) { if (card.classList.contains('selected')) { card.classList.remove('selected'); state.selectedToboggan = null; } else { var allCards = container.querySelectorAll('.tc-model'); allCards.forEach(function(c) { c.classList.remove('selected'); }); card.classList.add('selected'); state.selectedToboggan = item; } } else { // Piscine : single select across all piscine grids var allPiscineCards = document.querySelectorAll('#models-spas .tc-model, #models-petites .tc-model, #models-design .tc-model, #models-modulaires .tc-model'); allPiscineCards.forEach(function(c) { c.classList.remove('selected'); }); card.classList.add('selected'); state.selectedPiscine = item; // Update margelles preview updateMargelleAuto(); } updateTotals(); }); container.appendChild(card); }); } // ============= MARGELLES + PLAGE HANDLERS ============= function updateMargelleAuto() { if (!state.selectedPiscine) return; var ml = state.selectedPiscine.perimetre; var prix = ml * ARE_MARGELLE_PRICE_ML; var metaEl = document.getElementById('marg-auto-meta'); var priceEl = document.getElementById('marg-auto-price'); if (metaEl) metaEl.textContent = ml.toFixed(1) + ' ml × 100 €/ml posé (périmètre × 1,10)'; if (priceEl) priceEl.textContent = prix.toLocaleString('fr-FR') + ' €'; } function setupChoiceGroup(name, defaultValue, onChange) { var btns = document.querySelectorAll('[data-' + name + ']'); btns.forEach(function(btn) { btn.addEventListener('click', function() { btns.forEach(function(b) { b.classList.remove('selected'); }); btn.classList.add('selected'); var val = btn.dataset[name.replace(/-/g, '')] || btn.getAttribute('data-' + name); if (onChange) onChange(val); updateTotals(); }); if (btn.getAttribute('data-' + name) === defaultValue) { btn.classList.add('selected'); } }); } // ============= CALCULS ============= function calcSubtotalTicoque() { var t = 0; if (state.selectedPiscine) t += state.selectedPiscine.prix; if (state.selectedToboggan) t += state.selectedToboggan.prix; return t; } function calcSubtotalAre() { var t = 0; if (state.margelles === 'oui' && state.selectedPiscine) { t += state.selectedPiscine.perimetre * ARE_MARGELLE_PRICE_ML; } if (state.plage === 'oui' && state.procede && state.surface && state.surface !== 'ndp') { var surf = parseFloat(state.surface); if (!isNaN(surf) && surf > 0) { t += surf * ARE_PLAGE_PRICES[state.procede]; } } return t; } function calcAvantage() { // Verrou : margelles + plage (avec procédé + surface valide) requis if (state.margelles !== 'oui') return 0; if (state.plage !== 'oui') return 0; if (!state.procede) return 0; if (!state.surface || state.surface === 'ndp') return 0; var surf = parseFloat(state.surface); if (isNaN(surf) || surf <= 0) return 0; var totalProjet = calcSubtotalTicoque() + calcSubtotalAre(); if (totalProjet >= 30000) return 1500; if (totalProjet >= 20000) return 1000; if (totalProjet >= 15000) return 500; return 0; } function calcTotal() { return calcSubtotalTicoque() + calcSubtotalAre() - calcAvantage(); } // ============= UPDATE TOTALS + RECAP ============= function updateTotals() { var subtotal = calcSubtotalTicoque() + calcSubtotalAre(); var avantage = calcAvantage(); var total = subtotal - avantage; var formattedTotal = total > 0 ? total.toLocaleString('fr-FR') + ' €' : '—'; ['step2-total', 'step3-total'].forEach(function(id) { var el = document.getElementById(id); if (el) el.innerHTML = formattedTotal + ' TTC clé en main'; }); // Recap text var recap = ''; if (state.selectedPiscine) recap += state.selectedPiscine.nom + ' (' + state.selectedPiscine.ref + ')'; if (state.selectedToboggan) recap += (recap ? ' + ' : '') + 'toboggan ' + state.selectedToboggan.nom; if (state.margelles === 'oui') recap += (recap ? ' + ' : '') + 'margelles'; if (state.plage === 'oui' && state.procede && state.surface && state.surface !== 'ndp') { recap += (recap ? ' + ' : '') + ARE_PLAGE_NAMES[state.procede].toLowerCase(); } if (!recap) recap = 'Sélectionnez vos produits'; ['step2-recap', 'step3-recap'].forEach(function(id) { var el = document.getElementById(id); if (el) el.textContent = recap; }); // Detail récap 3 lignes (sous-total / avantage / total) var subEl = document.getElementById('recap-subtotal'); var avRow = document.getElementById('recap-avantage-row'); var avVal = document.getElementById('recap-avantage-value'); var totalNetEl = document.getElementById('recap-total-net'); var palierBadge = document.getElementById('recap-palier-badge'); if (subEl) subEl.textContent = subtotal > 0 ? subtotal.toLocaleString('fr-FR') + ' €' : '—'; if (avRow) avRow.style.display = avantage > 0 ? '' : 'none'; if (avVal) avVal.textContent = '−' + avantage.toLocaleString('fr-FR') + ' €'; if (totalNetEl) totalNetEl.textContent = total > 0 ? total.toLocaleString('fr-FR') + ' € TTC' : '—'; if (palierBadge) { if (avantage === 500) palierBadge.textContent = 'Palier 15-20 k€'; else if (avantage === 1000) palierBadge.textContent = 'Palier 20-30 k€'; else if (avantage === 1500) palierBadge.textContent = 'Palier > 30 k€'; else palierBadge.textContent = ''; palierBadge.style.display = avantage > 0 ? '' : 'none'; } // Message contextuel d'incitation Avantage Projet Complet var incitEl = document.getElementById('avantage-incitation'); if (incitEl) { var hasPiscine = !!state.selectedPiscine; var hasMarg = state.margelles === 'oui'; var hasPlage = state.plage === 'oui' && state.procede && state.surface && state.surface !== 'ndp'; if (hasPiscine && hasMarg && hasPlage && avantage > 0) { incitEl.style.display = ''; incitEl.className = 'tc-incitation tc-incitation-active'; incitEl.innerHTML = '✓ Avantage Projet Complet : −' + avantage.toLocaleString('fr-FR') + ' € activé. Déduit de la facture aménagement (Atelier Roche & Eau).'; } else if (hasPiscine && hasMarg && !hasPlage) { incitEl.style.display = ''; incitEl.className = 'tc-incitation tc-incitation-hint'; incitEl.innerHTML = '💡 Ajoutez une plage décorative ou gazon synthétique pour activer l\'Avantage Projet Complet (jusqu\'à 1 500 € sur la facture aménagement).'; } else if (hasPiscine && !hasMarg && hasPlage) { incitEl.style.display = ''; incitEl.className = 'tc-incitation tc-incitation-hint'; incitEl.innerHTML = '💡 Ajoutez des margelles pour activer l\'Avantage Projet Complet (jusqu\'à 1 500 € sur la facture aménagement).'; } else if (hasPiscine && !hasMarg && !hasPlage) { incitEl.style.display = ''; incitEl.className = 'tc-incitation tc-incitation-hint'; incitEl.innerHTML = '💡 Ajoutez margelles + plage décorative ou gazon synthétique pour bénéficier de l\'Avantage Projet Complet (jusqu\'à 1 500 € sur la facture aménagement).'; } else { incitEl.style.display = 'none'; } } } // ============= NAVIGATION ÉTAPES ============= function goStep(n) { ['step-1','step-2','step-3','step-final'].forEach(function(id, i) { var el = document.getElementById(id); if (!el) return; if (i === n - 1 || (n === 4 && id === 'step-final')) { el.classList.remove('hidden'); } else { el.classList.add('hidden'); } }); ['ps-1','ps-2','ps-3'].forEach(function(id, i) { var el = document.getElementById(id); if (!el) return; el.classList.toggle('done', i < n - 1); el.classList.toggle('active', i === n - 1); }); window.scrollTo({top: 0, behavior: 'smooth'}); } window.goStep = goStep; // ============= ENVOI DEVIS ============= function submitDevis() { var prenom = document.getElementById('c-prenom').value.trim(); var nom = document.getElementById('c-nom').value.trim(); var email = document.getElementById('c-email').value.trim(); var tel = document.getElementById('c-tel').value.trim(); var rgpd = document.getElementById('c-rgpd').checked; var honeypot = document.getElementById('c-website').value; if (!prenom || !nom || !email || !tel) { alert('Merci de remplir tous les champs obligatoires.'); return; } if (!rgpd) { alert('Merci de cocher la case d\'acceptation RGPD.'); return; } // Build lines for plugin var lines = []; if (state.selectedPiscine) { lines.push({ type: 'piscine-coque', title: 'Piscine ' + state.selectedPiscine.nom + ' · ' + state.selectedPiscine.ref, detail: 'Coque polyester ' + state.selectedPiscine.dim + ' · ' + state.selectedPiscine.surface + ' · TTC clé en main posée par Ti-Coque · Garantie 10 ans coque + 1 an INARYO.', qty: 1, pu: state.selectedPiscine.prix, total: state.selectedPiscine.prix, photo: state.selectedPiscine.photo ? photoUrl(state.selectedPiscine.photo) : '' }); } if (state.selectedToboggan) { lines.push({ type: 'toboggan', title: 'Toboggan ' + state.selectedToboggan.nom + ' · ' + state.selectedToboggan.ref, detail: 'Toboggan aquatique · ' + state.selectedToboggan.dim + ' · emprise ' + state.selectedToboggan.emprise + ' · TTC clé en main posé par Ti-Coque.', qty: 1, pu: state.selectedToboggan.prix, total: state.selectedToboggan.prix, photo: state.selectedToboggan.photo ? photoUrl(state.selectedToboggan.photo) : '' }); } if (state.margelles === 'oui' && state.selectedPiscine) { var ml = state.selectedPiscine.perimetre; var pmar = ml * ARE_MARGELLE_PRICE_ML; lines.push({ type: 'are-margelles', title: 'Margelles posées · ' + ml.toFixed(1) + ' ml', detail: 'Margelle de base, fourni-posé par Atelier Roche & Eau. Calcul auto périmètre × 1,10 (coupes). Mesure définitive au RDV technique.', qty: ml, pu: ARE_MARGELLE_PRICE_ML, total: pmar, photo: '' }); } if (state.plage === 'oui' && state.procede) { var procedeName = ARE_PLAGE_NAMES[state.procede]; var prixM2 = ARE_PLAGE_PRICES[state.procede]; if (state.surface === 'ndp' || !state.surface) { lines.push({ type: 'are-plage', title: 'Plage ' + procedeName + ' · surface à définir', detail: 'Posée par Atelier Roche & Eau. Surface définitive et chiffrage au RDV technique. Tarif indicatif : ' + prixM2 + ' €/m².', qty: 1, pu: 0, total: 0, photo: '' }); } else { var surf = parseFloat(state.surface); var pp = surf * prixM2; lines.push({ type: 'are-plage', title: 'Plage ' + procedeName + ' · ' + surf + ' m²', detail: surf + ' m² fourni-posé par Atelier Roche & Eau au tarif ' + prixM2 + ' €/m². Surface définitive à confirmer au RDV technique.', qty: surf, pu: prixM2, total: pp, photo: '' }); } } var subtotalAre = calcSubtotalAre(); var avantage = calcAvantage(); var totalHT_real = (calcTotal() / 1.085); var devisNum = 'TC-' + Date.now().toString(36).toUpperCase(); // Construct projets label var projets = ''; if (state.selectedPiscine) projets += state.selectedPiscine.nom; if (state.selectedToboggan) projets += (projets ? ' + ' : '') + state.selectedToboggan.nom; if (state.margelles === 'oui') projets += (projets ? ' + ' : '') + 'margelles'; if (state.plage === 'oui') projets += (projets ? ' + ' : '') + 'plage'; var projInfo = { commune: document.getElementById('proj-commune') ? document.getElementById('proj-commune').value : '', acces: document.getElementById('proj-acces') ? document.getElementById('proj-acces').value : '', delai: document.getElementById('proj-delai') ? document.getElementById('proj-delai').value : '', budget: document.getElementById('proj-budget') ? document.getElementById('proj-budget').value : '', message: document.getElementById('proj-message') ? document.getElementById('proj-message').value : '' }; var apiPayload = { devisNum: devisNum, client: {prenom: prenom, nom: nom, email: email, tel: tel}, projets: projets, totalHT: totalHT_real, lines: lines, source: window.location.hostname, _projectInfo: projInfo, _isTTC: true, _pack: { avantage: avantage, subtotalTicoque: calcSubtotalTicoque(), subtotalAre: subtotalAre, total: calcTotal(), offerEnd: PACK_OFFER_END, hasMargelles: state.margelles === 'oui', hasPlage: state.plage === 'oui', procede: state.procede, surface: state.surface, avantageEligible: (state.margelles === 'oui' && state.plage === 'oui' && state.procede && state.surface && state.surface !== 'ndp') }, _honeypot: honeypot }; // GA4 tracking if (typeof gtag === 'function') { try { gtag('event', 'complete_simulator', { pack_selected: apiPayload._pack.avantageEligible, pack_components: (state.selectedPiscine ? 'piscine_' : '') + (state.selectedToboggan ? 'toboggan_' : '') + (state.margelles === 'oui' ? 'margelles_' : '') + (state.plage === 'oui' ? 'plage' : '').replace(/_$/, ''), tier_avantage: avantage, total_value_eur: Math.round(calcTotal()), selected_model: state.selectedPiscine ? state.selectedPiscine.ref : 'none', procede_plage: state.procede || 'none' }); } catch(e) {} } // Submit to plugin endpoint var endpoint = window.location.origin + '/wp-json/inaryo/v1/devis'; fetch(endpoint, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(apiPayload) }).then(function(r) { return r.json(); }).then(function(d) { if (d.success) { // Google Ads conversion tracking if (typeof gtag === 'function') { gtag('event', 'conversion', { 'send_to': 'AW-18145448272/T9v7CJnDp6kcENCitsxD', 'value': 50.0, 'currency': 'EUR', 'transaction_id': devisNum }); } var devisNumEl = document.getElementById('devis-num'); if (devisNumEl) devisNumEl.textContent = devisNum; goStep(4); } else { alert('Erreur lors de l\'envoi : ' + (d.error || 'inconnu') + '. Merci de nous contacter directement à contact@ti-coque.re'); } }).catch(function(e) { alert('Erreur réseau : ' + e.message + '. Merci de nous contacter directement à contact@ti-coque.re'); }); } window.submitDevis = submitDevis; // ============= INIT ============= function initSimulator() { renderModels('spas', 'models-spas'); renderModels('petites', 'models-petites'); renderModels('design', 'models-design'); renderModels('modulaires', 'models-modulaires'); renderModels('toboggans', 'models-toboggans', true); setupChoiceGroup('marg', 'rdv', function(v) { state.margelles = v; }); setupChoiceGroup('plage', 'rdv', function(v) { state.plage = v; var details = document.getElementById('plage-details'); if (details) details.style.display = (v === 'oui') ? 'block' : 'none'; }); setupChoiceGroup('procede', null, function(v) { state.procede = v; }); // Surface input var surfaceInput = document.getElementById('surface-input'); var ndpLink = document.getElementById('surface-ndp-link'); var ndpActive = document.getElementById('surface-ndp-active'); var ndpCancel = document.getElementById('surface-ndp-cancel'); if (surfaceInput) { surfaceInput.addEventListener('input', function() { var v = parseFloat(surfaceInput.value); if (!isNaN(v) && v > 0) { state.surface = String(Math.round(v)); state.surfaceNdp = false; } else { state.surface = null; } updateTotals(); }); } if (ndpLink) { ndpLink.addEventListener('click', function(e) { e.preventDefault(); state.surface = 'ndp'; state.surfaceNdp = true; if (surfaceInput) surfaceInput.value = ''; ndpLink.style.display = 'none'; if (ndpActive) ndpActive.style.display = 'block'; updateTotals(); }); } if (ndpCancel) { ndpCancel.addEventListener('click', function(e) { e.preventDefault(); state.surface = null; state.surfaceNdp = false; if (ndpLink) ndpLink.style.display = 'inline'; if (ndpActive) ndpActive.style.display = 'none'; if (surfaceInput) surfaceInput.focus(); updateTotals(); }); } updateTotals(); // GA4 — start_simulator quand on ouvre la page if (typeof gtag === 'function') { try { gtag('event', 'start_simulator', { pack_offer_active: new Date() < new Date(PACK_OFFER_END) }); } catch(e) {} } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initSimulator); } else { setTimeout(initSimulator, 50); }