/* =========================================================================
   KERIA — Simulateur « coût des désistements » (Promoteurs)
   Composant React autonome. Tout visible, recalcul live, compteurs animés.
   Monté sur #sim-desist-root. S'appuie sur keria.css + keria-sim-desist.css.
   ========================================================================= */
(function () {
  'use strict';
  var h = React.createElement;
  var useState = React.useState, useEffect = React.useEffect, useRef = React.useRef;

  /* ---------- Formatage FR ---------- */
  var _eur = new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 });
  var _nf  = new Intl.NumberFormat('fr-FR', { maximumFractionDigits: 0 });
  function nf0(n) { return _nf.format(Math.round(n)); }
  var REDUCE = !!(window.matchMedia && window.matchMedia('(prefers-reduced-motion:reduce)').matches);

  /* Intervalle non nominatif pour la mesure d'audience (aligné sur KeriaAnalytics.bucketize). */
  function analyticsBucket(value) {
    var n = typeof value === 'number' ? value : parseFloat(value);
    if (!isFinite(n)) return 'unknown';
    if (n < 0) return 'negative';
    if (n === 0) return '0';
    if (n < 1000) return '<1k';
    if (n < 5000) return '1k-5k';
    if (n < 10000) return '5k-10k';
    if (n < 50000) return '10k-50k';
    if (n < 100000) return '50k-100k';
    if (n < 500000) return '100k-500k';
    return '500k+';
  }

  /* ---------- Valeurs sectorielles par défaut ("Je ne sais pas") ----------
     Chaque entrée contient :
       v       — valeur numérique utilisée dans le calcul
       disp    — affichage formaté
       note    — libellé court affiché dans la pastille "badge"
       src     — description complète de la source (tooltip)
       srcUrl  — URL de la source (optionnel, ouvre dans un onglet)
  ========================================================================= */
  var SECT = {
    logements: {
      v: 150,
      disp: '150\u00A0lots',
      note: 'Programme type \u00B7 FPI',
      src:  'FPI \u2014 Observatoire national : ~100\u00A0000 lots/an commercialis\u00E9s. Programme r\u00E9sidentiel type estim\u00E9.',
      srcUrl: 'https://www.fpi-france.fr'
    },
    prix: {
      v: 250000,
      disp: '250\u00A0000\u00A0\u20AC',
      note: 'SDES \u00B7 ECLN \u2014 T2 2025',
      src:  'SDES, Enqu\u00EAte ECLN, T2 2025 : prix moyen appartement neuf 4\u00A0953\u00A0\u20AC/m\u00B2 \u00D7 ~50\u00A0m\u00B2 \u2248 250\u00A0000\u00A0\u20AC.',
      srcUrl: 'https://www.statistiques.developpement-durable.gouv.fr/commercialisation-des-logements-neufs-vente-aux-particuliers-au-2e-trimestre-2025'
    },
    tauxAct: {
      v: 18,
      disp: '18\u00A0%',
      note: 'Estimation \u00B7 2023\u20132025',
      src:  'Estimation sectorielle \u2014 d\u00E9sistements acquéreurs en p\u00E9riode de resserrement du cr\u00E9dit (2023\u20132025). Variable selon le programme et la localisation.',
      srcUrl: null
    },
    delai: {
      v: 4,
      disp: '4\u00A0mois',
      note: 'Estimation \u00B7 re-commercialisation',
      src:  'Estimation \u2014 d\u00E9lai moyen de re-commercialisation constat\u00E9 sur op\u00E9rations en cours. Aucune publication sectorielle disponible.',
      srcUrl: null
    },
    decote: {
      v: 3,
      disp: '3\u00A0%',
      note: 'Estimation courante',
      src:  'Estimation \u2014 d\u00E9cote commerciale n\u00E9cessaire \u00E0 une revente rapide apr\u00E8s d\u00E9sistement. Aucune publication sectorielle disponible.',
      srcUrl: null
    },
    portage: {
      v: 5,
      disp: '5\u00A0%',
      note: 'Barom\u00E8tre financement \u00B7 2025',
      src:  'Look&Fin / Homunity \u2014 cr\u00E9dit de promotion immobili\u00E8re : taux indicatif 2024\u20132025 (taux effectifs observ\u00E9s : 5\u20136\u00A0%).',
      srcUrl: 'https://www.homunity.com/fr/blog/immobilier/le-financement-de-la-promotion-immobiliere'
    },
    admin: {
      v: 1200,
      disp: '1\u00A0200\u00A0\u20AC',
      note: 'Estimation courante',
      src:  'Estimation \u2014 co\u00FBt administratif par dossier annul\u00E9 (relance, acte de d\u00E9sistement, r\u00E9-\u00E9tude). Aucune publication sectorielle disponible.',
      srcUrl: null
    },
    tauxCible: {
      v: 5,
      disp: '5\u00A0%',
      note: 'Objectif \u00B7 phase pilote Keria',
      src:  'Objectif observ\u00E9 en phase pilote Keria (technologie C\u00E9zam). Variable selon le programme et le profil des acqu\u00E9reurs.',
      srcUrl: null
    },
    coutKeria: {
      v: 6000,
      disp: '6\u00A0000\u00A0\u20AC',
      note: 'Tarif indicatif Keria',
      src:  'Tarification indicative Keria \u2014 \u00E0 confirmer selon le p\u00E9rim\u00E8tre et le volume.',
      srcUrl: null
    }
  };

  var ATTESTATION_PRIX   = 30;   /* € par attestation */
  var ATTESTATION_CREDIT = 300;  /* € crédit par dossier courtage validé (10 × 30 €) */

  /* ---------- Tween (compteur animé) ---------- */
  function useTween(target, ms) {
    var dur = ms || 640;
    var _s = useState(target), val = _s[0], setVal = _s[1];
    var raf = useRef(0), cur = useRef(target);
    useEffect(function () {
      if (REDUCE) { cur.current = target; setVal(target); return; }
      var from = cur.current;
      var start = performance.now();
      cancelAnimationFrame(raf.current);
      function step(now) {
        var p = Math.min((now - start) / dur, 1);
        var e = 1 - Math.pow(1 - p, 3);
        cur.current = from + (target - from) * e;
        setVal(cur.current);
        if (p < 1) raf.current = requestAnimationFrame(step);
        else { cur.current = target; setVal(target); }
      }
      raf.current = requestAnimationFrame(step);
      return function () { cancelAnimationFrame(raf.current); };
    }, [target]);
    return val;
  }
  function AnimNum(props) { var v = useTween(props.value); return nf0(v); }
  function AnimEur(props) { var v = useTween(props.value); return nf0(v); }

  /* ---------- Remplissage de piste des curseurs ---------- */
  function fillTrack(value, min, max, dark) {
    var p = ((value - min) / (max - min || 1)) * 100;
    var fg = dark ? 'var(--cobalt-bright)' : 'var(--cobalt)';
    var bg = dark ? 'rgba(255,255,255,.16)' : 'var(--line-2)';
    return { background: 'linear-gradient(90deg,' + fg + ' ' + p + '%,' + bg + ' ' + p + '%)' };
  }

  /* ---------- Icônes inline ---------- */
  function Ico(props) {
    return h('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, 'aria-hidden': 'true' },
      h('path', { d: props.d, strokeLinecap: 'round', strokeLinejoin: 'round' }));
  }
  var D_ARROW = 'M5 12h14M13 6l6 6-6 6';
  var D_INFO  = 'M12 16v-4M12 8h.01M12 22a10 10 0 100-20 10 10 0 000 20z';
  var D_RESET = 'M3 12a9 9 0 109-9 9 9 0 00-7 3.5M3 4v4h4';
  var D_CHECK = 'M20 6L9 17l-5-5';
  var D_EXT   = 'M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6M15 3h6v6M10 14L21 3';

  /* ---------- Bouton "Je ne sais pas" ---------- */
  function UnkToggle(props) {
    return h('button', {
      type: 'button',
      className: 'dsim-unk' + (props.active ? ' active' : '') + (props.dark ? ' dark' : ''),
      onClick: props.onClick,
      title: props.active ? 'Cliquer pour entrer votre valeur' : 'Je ne connais pas cette valeur \u2014 utiliser une moyenne'
    }, props.active ? 'Estim\u00E9\u00A0\u00B7\u00A0secteur' : 'Je ne sais pas');
  }

  /* ---------- Popover de source (cliquable) ---------- */
  function SourcePopover(props) {
    var s = props.sect || {};
    if (!s.src) return null;
    var _o = useState(false), open = _o[0], setOpen = _o[1];
    var wrapRef = useRef(null);
    useEffect(function () {
      if (!open) return;
      function onDown(e) {
        if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
      }
      document.addEventListener('mousedown', onDown);
      document.addEventListener('touchstart', onDown);
      return function () {
        document.removeEventListener('mousedown', onDown);
        document.removeEventListener('touchstart', onDown);
      };
    }, [open]);
    return h('span', { className: 'dsim-src-wrap', ref: wrapRef },
      h('button', {
        type: 'button',
        className: 'dsim-sect-info' + (open ? ' open' : '') + (props.dark ? ' dark' : ''),
        onClick: function (e) { e.stopPropagation(); setOpen(!open); },
        'aria-label': 'Source de la valeur estim\u00E9e',
        'aria-expanded': open
      }, h(Ico, { d: D_INFO })),
      open
        ? h('div', { className: 'dsim-src-pop' + (props.dark ? ' dark' : '') },
            h('p', { className: 'dsim-src-text' }, s.src),
            s.srcUrl
              ? h('a', {
                  href: s.srcUrl, target: '_blank', rel: 'noopener noreferrer',
                  className: 'dsim-src-link',
                  onClick: function (e) { e.stopPropagation(); }
                },
                  'Consulter la source\u00A0',
                  h(Ico, { d: D_EXT })
                )
              : null
          )
        : null
    );
  }

  /* ---------- Affichage valeur estimée (secteur) ---------- */
  function SectVal(props) {
    var s = props.sect || {};
    return h('div', { className: 'dsim-sect-val' + (props.dark ? ' dark' : '') },
      h('span', { className: 'dsim-sect-badge' }, s.note || ''),
      h('span', { className: 'dsim-sect-num' }, s.disp || ''),
      h(SourcePopover, { sect: s, dark: props.dark })
    );
  }

  /* ---------- Curseur réutilisable ---------- */
  function Slider(props) {
    var dark = !!props.dark;
    var isUnk = !!props.unknown;
    return h('div', { className: props.cls || 'dsim-field' },
      h('div', { className: 'top' },
        h('label', { htmlFor: props.id }, props.label),
        h('div', { className: 'dsim-top-right' },
          props.onToggleUnknown
            ? h(UnkToggle, { active: isUnk, onClick: props.onToggleUnknown, dark: dark })
            : null,
          !isUnk ? h('span', { className: 'val' }, props.display) : null
        )
      ),
      isUnk
        ? h(SectVal, { sect: props.sect, dark: dark })
        : h('input', {
            className: dark ? 'range' : 'range-light',
            type: 'range', id: props.id,
            min: props.min, max: props.max, step: props.step, value: props.value,
            style: fillTrack(props.value, props.min, props.max, dark),
            'aria-valuetext': props.display,
            onChange: function (e) { props.onChange(parseFloat(e.target.value)); }
          }),
      !isUnk && props.scale
        ? h('div', { className: 'dsim-scale' }, h('span', null, props.scale[0]), h('span', null, props.scale[1]))
        : null
    );
  }

  /* ---------- Champ montant € ---------- */
  function Money(props) {
    var isUnk = !!props.unknown;
    function onChange(e) {
      var digits = (e.target.value || '').replace(/[^\d]/g, '');
      var n = digits === '' ? 0 : parseInt(digits, 10);
      if (props.max && n > props.max) n = props.max;
      props.onChange(n);
    }
    return h('div', { className: props.cls || 'dsim-field' },
      h('div', { className: 'top' },
        h('label', { htmlFor: props.id }, props.label),
        props.onToggleUnknown
          ? h(UnkToggle, { active: isUnk, onClick: props.onToggleUnknown, dark: !!props.dark })
          : null
      ),
      isUnk
        ? h(SectVal, { sect: props.sect, dark: !!props.dark })
        : h('div', { className: 'dsim-money' + (props.dark ? ' dark' : '') },
            h('input', {
              id: props.id, type: 'text', inputMode: 'numeric',
              value: nf0(props.value), 'aria-label': props.label,
              onChange: onChange
            }),
            h('span', { className: 'cur' }, '\u20AC')
          )
    );
  }

  /* ---------- Ligne breakdown (libellé + barre) ---------- */
  function BkRow(props) {
    var pct = props.total > 0 ? (props.value / props.total) * 100 : 0;
    return h('div', { className: 'row ' + props.cls },
      h('div', { className: 'l' },
        h('span', null, props.label),
        h('b', null, h(AnimEur, { value: props.value }), '\u00A0\u20AC')
      ),
      h('div', { className: 'track' },
        h('i', { style: { width: pct.toFixed(1) + '%' } })
      )
    );
  }

  /* ---------- Boîte tarification Keria ---------- */
  function PricingBoxDesist(p) {
    var isGratuit = p.credit >= p.brut;
    var net = Math.max(0, p.brut - p.credit);
    return h('div', { className: 'dsim-pricing-box' },
      h('div', { className: 'pb-row' },
        h('span', { className: 'pb-label' }, 'Attestations'),
        h('span', { className: 'pb-calc' }, nf0(p.nb) + '\u00A0\u00D7\u00A030\u00A0\u20AC'),
        h('span', { className: 'pb-val' }, nf0(p.brut) + '\u00A0\u20AC')
      ),
      h('div', { className: 'pb-row pb-credit' },
        h('span', { className: 'pb-label' }, 'Cr\u00E9dit courtage'),
        h('span', { className: 'pb-calc' }, nf0(p.dossiers) + '\u00A0\u00D7\u00A0300\u00A0\u20AC'),
        h('span', { className: 'pb-val' }, '\u2212\u00A0' + nf0(p.credit) + '\u00A0\u20AC')
      ),
      h('div', { className: 'pb-total' + (isGratuit ? ' pb-free' : '') },
        h('span', null, 'Co\u00FBt net Keria'),
        h('span', null, isGratuit
          ? h(React.Fragment, null,
              h('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2.5, width: 14, height: 14, style: { marginRight: '5px', verticalAlign: 'middle' } },
                h('path', { d: D_CHECK, strokeLinecap: 'round', strokeLinejoin: 'round' })),
              'Couvert par le courtage')
          : nf0(net) + '\u00A0\u20AC\u00A0/\u00A0an'
        )
      )
    );
  }

  /* ========================================================================
     Composant principal
     ===================================================================== */
  function SimDesistements() {

    /* — Étape 1 : activité — */
    var _l = useState(200),    logements = _l[0], setLogements = _l[1];
    var _p = useState(280000), prix      = _p[0], setPrix      = _p[1];
    var _t = useState(15),     tauxAct   = _t[0], setTauxAct   = _t[1];
    /* — Étape 2 : impact commercial — */
    var _d  = useState(3),   delai   = _d[0],  setDelai   = _d[1];
    var _dc = useState(3),   decote  = _dc[0], setDecote  = _dc[1];
    /* — Étape 3 : impact financier — */
    var _po = useState(6),    portage = _po[0], setPortage = _po[1];
    var _ad = useState(1500), admin   = _ad[0], setAdmin   = _ad[1];
    /* — Hypothèses Keria (ajustables) — */
    var _tc = useState(5),    tauxCible = _tc[0], setTauxCible = _tc[1];
    var _dc = useState(80), dossiersCourtage = _dc[0], setDossiersCourtage = _dc[1];
    var _ck = useState(6000), coutKeria = _ck[0], setCoutKeria = _ck[1];

    /* — État "Je ne sais pas" — */
    var _u = useState({}), unknowns = _u[0], setUnknowns = _u[1];
    function toggleUnk(key) {
      setUnknowns(function (prev) {
        var n = Object.assign({}, prev);
        n[key] = !prev[key];
        return n;
      });
    }

    /* — Formulaire email — */
    var _em = useState(''),    email   = _em[0], setEmail   = _em[1];
    var _co = useState(false), consent = _co[0], setConsent = _co[1];
    var _sn = useState(false), sent    = _sn[0], setSent    = _sn[1];
    var _er = useState(''),    formErr = _er[0], setFormErr = _er[1];

    /* — Valeurs effectives : user ou moyenne sectorielle — */
    var effLogements = unknowns.logements ? SECT.logements.v : logements;
    var effPrix      = unknowns.prix      ? SECT.prix.v      : prix;
    var effTauxAct   = unknowns.tauxAct   ? SECT.tauxAct.v   : tauxAct;
    var effDelai     = unknowns.delai     ? SECT.delai.v     : delai;
    var effDecote    = unknowns.decote    ? SECT.decote.v    : decote;
    var effPortage   = unknowns.portage   ? SECT.portage.v   : portage;
    var effAdmin     = unknowns.admin     ? SECT.admin.v     : admin;
    /* Tarification attestations */
    var nbAttestations = effLogements;
    var coutBrut       = nbAttestations * ATTESTATION_PRIX;
    var creditCourtage = dossiersCourtage * ATTESTATION_CREDIT;
    var coutNet        = Math.max(0, coutBrut - creditCourtage);

    /* taux cible ne dépasse jamais le taux actuel effectif */
    var rawCible = unknowns.tauxCible ? SECT.tauxCible.v : tauxCible;
    var cible = Math.min(rawCible, effTauxAct);

    /* --- Calcul --- */
    function compute(taux) {
      var desist   = effLogements * (taux / 100);
      var cDecote  = desist * effPrix * (effDecote / 100);
      var cPortage = desist * effPrix * (effPortage / 100) * (effDelai / 12);
      var cAdmin   = desist * effAdmin;
      return { desist: desist, decote: cDecote, portage: cPortage, admin: cAdmin, total: cDecote + cPortage + cAdmin };
    }
    var avant  = compute(effTauxAct);
    var apres  = compute(cible);
    var gain   = Math.max(0, avant.total - apres.total);
    var roi    = coutNet > 0 ? gain / coutNet : 0;
    var apresPct = avant.total > 0 ? (apres.total / avant.total) * 100 : 0;

    function reset() {
      setTauxCible(5);
      setDossiersCourtage(Math.round(effLogements * 0.4) || 80);
      setUnknowns(function (prev) {
        var n = Object.assign({}, prev);
        delete n.tauxCible;
        return n;
      });
    }

    function submit(e) {
      e.preventDefault();
      if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
        setFormErr('Indiquez une adresse e\u2011mail valide.'); return;
      }
      if (!consent) { setFormErr('Merci d\u2019accepter d\u2019\u00EAtre recontact\u00E9(e) (RGPD).'); return; }
      setFormErr('');
      var details = 'Logements/an : ' + effLogements
        + ' · Prix moyen : ' + nf0(effPrix) + ' €'
        + ' · Taux désistement actuel : ' + effTauxAct + ' %'
        + ' · Désistements/an : ' + Math.round(avant.desist)
        + ' · Coût total actuel : ' + nf0(Math.round(avant.total)) + ' €'
        + ' · Taux cible Keria : ' + cible + ' %'
        + ' · Gain annuel estimé : ' + nf0(Math.round(gain)) + ' €'
        + ' · ROI : ' + (Math.round(roi * 10) / 10) + '×';
      var fields = {
        email: email,
        simulateur_type: 'Désistements (promoteurs)',
        simulation_cout_actuel: String(Math.round(avant.total)),
        simulation_gain_keria: String(Math.round(gain)),
        simulation_details: details,
        source_provenance: 'simulateur-desistements',
        page_d_origine: location.pathname + location.search
      };
      try { var qs = new URLSearchParams(location.search); ['utm_source','utm_medium','utm_campaign'].forEach(function(k){ var v = qs.get(k); if (v) fields[k] = v; }); } catch (_) {}
      setSent(true);
      if (window.keriaSubmitHubSpot) { window.keriaSubmitHubSpot('simulateur-desistements', fields); }
      try {
        if (window.KeriaAnalytics && window.KeriaAnalytics.track) {
          window.KeriaAnalytics.track('keria_sim_result', {
            simulator: 'desistements',
            cout_actuel_bucket: analyticsBucket(Math.round(avant.total)),
            gain_keria_bucket: analyticsBucket(Math.round(gain))
          });
        }
      } catch (_) {}
      try { if (window.plausible) window.plausible('sim_desist_lead', { props: { roi: Math.round(roi) } }); } catch (_) {}
    }

    /* ---- Étape 1 ---- */
    var step1 = h('div', { className: 'dsim-step' },
      h('div', { className: 'dsim-step-head' },
        h('span', { className: 'n' }, '1'),
        h('h3', null, 'Votre activit\u00E9'),
        h('span', { className: 'cap' }, 'Programme')
      ),
      h(Slider, {
        id: 'd-logements', label: 'Logements commercialis\u00E9s / an',
        min: 0, max: 1000, step: 5, value: logements, onChange: setLogements,
        display: nf0(logements) + '\u00A0lots', scale: ['0', '1\u00A0000'],
        unknown: unknowns.logements, onToggleUnknown: function () { toggleUnk('logements'); },
        sect: SECT.logements
      }),
      h(Money, {
        id: 'd-prix', label: 'Prix moyen d\u2019un lot',
        value: prix, max: 5000000, onChange: setPrix,
        unknown: unknowns.prix, onToggleUnknown: function () { toggleUnk('prix'); },
        sect: SECT.prix
      }),
      h(Slider, {
        id: 'd-taux', label: 'Taux de d\u00E9sistement actuel',
        min: 0, max: 30, step: 1, value: tauxAct,
        onChange: function (v) { setTauxAct(v); if (tauxCible > v) setTauxCible(v); },
        display: tauxAct + '\u00A0%', scale: ['0\u00A0%', '30\u00A0%'],
        unknown: unknowns.tauxAct, onToggleUnknown: function () { toggleUnk('tauxAct'); },
        sect: SECT.tauxAct
      })
    );

    /* ---- Étape 2 ---- */
    var step2 = h('div', { className: 'dsim-step' },
      h('div', { className: 'dsim-step-head' },
        h('span', { className: 'n' }, '2'),
        h('h3', null, 'Impact commercial'),
        h('span', { className: 'cap' }, 'Revente')
      ),
      h(Slider, {
        id: 'd-delai', label: 'D\u00E9lai moyen de revente apr\u00E8s annulation',
        min: 0, max: 12, step: 1, value: delai, onChange: setDelai,
        display: delai + '\u00A0mois', scale: ['0', '12\u00A0mois'],
        unknown: unknowns.delai, onToggleUnknown: function () { toggleUnk('delai'); },
        sect: SECT.delai
      }),
      h(Slider, {
        id: 'd-decote', label: 'D\u00E9cote n\u00E9cessaire pour revendre',
        min: 0, max: 10, step: 0.5, value: decote, onChange: setDecote,
        display: decote + '\u00A0%', scale: ['0\u00A0%', '10\u00A0%'],
        unknown: unknowns.decote, onToggleUnknown: function () { toggleUnk('decote'); },
        sect: SECT.decote
      })
    );

    /* ---- Étape 3 ---- */
    var step3 = h('div', { className: 'dsim-step' },
      h('div', { className: 'dsim-step-head' },
        h('span', { className: 'n' }, '3'),
        h('h3', null, 'Impact financier'),
        h('span', { className: 'cap' }, 'Portage')
      ),
      h(Slider, {
        id: 'd-portage', label: 'Co\u00FBt annuel de portage',
        min: 0, max: 15, step: 0.5, value: portage, onChange: setPortage,
        display: portage + '\u00A0%', scale: ['0\u00A0%', '15\u00A0%'],
        unknown: unknowns.portage, onToggleUnknown: function () { toggleUnk('portage'); },
        sect: SECT.portage
      }),
      h(Money, {
        id: 'd-admin', label: 'Co\u00FBt administratif par dossier annul\u00E9',
        value: admin, max: 100000, onChange: setAdmin,
        unknown: unknowns.admin, onToggleUnknown: function () { toggleUnk('admin'); },
        sect: SECT.admin
      })
    );

    /* ---- Carte contrôles ---- */
    var controls = h('div', { className: 'dsim-controls dsim-in' },
      step1, step2, step3,
      h('p', { className: 'dsim-controls-note' },
        h(Ico, { d: D_INFO }),
        h('span', null,
          'Estimation indicative. \u00AB\u00A0Je ne sais pas\u00A0\u00BB substitue une valeur de r\u00E9f\u00E9rence sectorielle (ⓘ\u00A0= source). Sans valeur contractuelle.'
        )
      )
    );

    /* ---- Nombre de désistements ---- */
    var nbDesist = Math.round(avant.desist);
    var coutParDesist = nbDesist > 0 ? avant.total / nbDesist : 0;

    /* ---- Carte résultat ---- */
    var result = h('div', { className: 'dsim-result dsim-in', style: { animationDelay: '.09s' } },
      h('span', { className: 'tag' }, 'Votre co\u00FBt annuel estim\u00E9'),
      h('div', { className: 'dsim-total' },
        h(AnimEur, { value: avant.total }),
        h('em', null, '\u00A0\u20AC')
      ),
      h('p', { className: 'sub' }, 'Co\u00FBt des d\u00E9sistements sur vos programmes, hors Keria, sur la base de vos param\u00E8tres.'),
      h('div', { className: 'dsim-bk' },
        h(BkRow, { cls: 'dsim-c-decote',  label: 'D\u00E9cote commerciale',  value: avant.decote,  total: avant.total }),
        h(BkRow, { cls: 'dsim-c-portage', label: 'Portage financier',       value: avant.portage, total: avant.total }),
        h(BkRow, { cls: 'dsim-c-admin',   label: 'Gestion administrative',  value: avant.admin,   total: avant.total })
      ),
      h('div', { className: 'dsim-foot' },
        h('div', { className: 'f' },
          h('div', { className: 'n' }, h(AnimNum, { value: nbDesist })),
          h('div', { className: 'l' }, 'D\u00E9sistements / an')),
        h('div', { className: 'f' },
          h('div', { className: 'n' }, effTauxAct + '\u00A0%'),
          h('div', { className: 'l' }, 'Taux actuel')),
        h('div', { className: 'f' },
          h('div', { className: 'n' }, h(AnimEur, { value: coutParDesist }), h('span', { className: 'eu' }, '\u00A0\u20AC')),
          h('div', { className: 'l' }, 'Co\u00FBt\u00A0/ d\u00E9sistement'))
      ),
      /* — Capture e-mail (.lc) — */
      h('form', { className: 'lc' + (sent ? ' is-sent' : ''), onSubmit: submit, noValidate: true },
        h('label', { className: 'lc-label', htmlFor: 'd-email' }, 'Recevez votre simulation complète + votre gain potentiel avec Keria par e-mail'),
        h('div', { className: 'lc-row' },
          h('input', { type: 'email', id: 'd-email', name: 'email', autoComplete: 'email',
            placeholder: 'vous@promoteur.fr', value: email,
            onChange: function (e) { setEmail(e.target.value); } }),
          h('button', { type: 'submit', className: 'btn btn-gold' }, 'Recevoir\u00A0', h(Ico, { d: D_ARROW }))
        ),
        h('label', { className: 'consent' },
          h('input', { type: 'checkbox', name: 'consent', checked: consent,
            onChange: function (e) { setConsent(e.target.checked); } }),
          h('span', null, 'J\u2019accepte d\u2019\u00EAtre recontact\u00E9(e) par Keria (RGPD).')
        ),
        h('p', { className: 'lc-note', style: formErr ? { color: '#FCA5A5' } : null },
          formErr || 'R\u00E9ponse sous 24\u00A0h\u00A0\u00B7 sans engagement\u00A0\u00B7 RGPD.'
        ),
        h('div', { className: 'lc-success' },
          h('span', { className: 'ck' },
            h('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2.6, 'aria-hidden': 'true' },
              h('path', { d: D_CHECK, strokeLinecap: 'round', strokeLinejoin: 'round' })
            )
          ),
          h('div', null,
            h('b', null, 'E-mail envoyé — votre simulation est en route.'),
            h('p', null, 'Vous recevez le détail chiffré + votre gain potentiel avec Keria. Un expert vous recontacte sous 24 h.')
          ),
          h('div', { className: 'lc-actions' },
            h('button', { type: 'button', className: 'btn btn-ghost on-navy', onClick: function () { setSent(false); setEmail(''); setConsent(false); setFormErr(''); } }, h(Ico, { d: D_RESET }), 'Refaire une simulation'),
            h('a', { className: 'btn btn-gold', href: 'promoteurs.html' }, 'Retour à la page promoteurs\u00A0', h(Ico, { d: D_ARROW }))
          )
        )
      )
    );

    /* ---- Section impact Keria ---- */
    var impact = h('section', { className: 'section nocturne', id: 'impact-keria' },
      h('span', { className: 'beam', style: { top: '-30%', right: '-6%', opacity: '.45' } }),
      h('div', { className: 'wrap-wide', style: { position: 'relative', zIndex: 2 } },

        h('div', { className: 'section-head center' },
          h('span', { className: 'eyebrow' }, 'Impact potentiel avec Keria'),
          h('h2', null, 'Et si la finan\u00E7abilit\u00E9 \u00E9tait ', h('span', { className: 'serif-i gold' }, 'v\u00E9rifi\u00E9e avant la r\u00E9servation'), '\u00A0?'),
          h('p', { className: 'lead' }, 'En qualifiant la solvabilit\u00E9 r\u00E9elle de l\u2019acqu\u00E9reur en amont, Keria r\u00E9duit drastiquement les d\u00E9sistements. Ajustez les hypoth\u00E8ses ci-dessous.')
        ),

        /* Hypothèses ajustables */
        h('div', { className: 'dsim-impact' },
          h('div', { className: 'dsim-hyp' },
            /* Taux cible */
            h('div', { className: 'hfield' },
              h('div', { className: 'top' },
                h('label', { htmlFor: 'd-cible' }, 'Taux de d\u00E9sistement vis\u00E9 avec Keria'),
                h('div', { className: 'dsim-top-right' },
                  h(UnkToggle, { active: !!unknowns.tauxCible, onClick: function () { toggleUnk('tauxCible'); }, dark: true }),
                  !unknowns.tauxCible ? h('span', { className: 'val' }, cible + '\u00A0%') : null
                )
              ),
              unknowns.tauxCible
                ? h(SectVal, { sect: SECT.tauxCible, dark: true })
                : h('input', {
                    className: 'range', type: 'range', id: 'd-cible',
                    min: 0, max: Math.max(1, effTauxAct), step: 0.5, value: cible,
                    style: fillTrack(cible, 0, Math.max(1, effTauxAct), true),
                    'aria-label': 'Taux de d\u00E9sistement vis\u00E9 avec Keria',
                    onChange: function (e) { setTauxCible(parseFloat(e.target.value)); }
                  })
            ),
            /* Coût Keria */
            h(Money, {
              id: 'd-cout', cls: 'hfield', label: 'Co\u00FBt annuel Keria',
              value: coutKeria, max: 1000000, dark: true, onChange: setCoutKeria,
              unknown: unknowns.coutKeria, onToggleUnknown: function () { toggleUnk('coutKeria'); },
              sect: SECT.coutKeria
            }),
            /* Reset */
            h('div', { className: 'reset' },
              h('button', { type: 'button', onClick: reset },
                h(Ico, { d: D_RESET }), 'R\u00E9initialiser')
            )
          )
        ),

        /* Tarification */
        h(PricingBoxDesist, { nb: nbAttestations, dossiers: dossiersCourtage, brut: coutBrut, credit: creditCourtage }),

        /* Barres Avant / Après + Gain + ROI */
        h('div', { className: 'dsim-payoff' },
          /* Barres comparatives */
          h('div', { className: 'dsim-compare' },
            h('div', { className: 'dsim-bar avant' },
              h('div', { className: 'amt' }, h(AnimEur, { value: avant.total }), '\u00A0\u20AC'),
              h('div', { className: 'track' }, h('div', { className: 'col', style: { height: '100%' } })),
              h('div', { className: 'cap' }, 'Avant Keria',
                h('span', { className: 'capn' }, effTauxAct + '\u00A0% de d\u00E9sistements'))
            ),
            h('div', { className: 'dsim-bar apres' },
              h('div', { className: 'amt' }, h(AnimEur, { value: apres.total }), '\u00A0\u20AC'),
              h('div', { className: 'track' },
                h('div', { className: 'col', style: { height: Math.max(2, apresPct).toFixed(1) + '%' } })
              ),
              h('div', { className: 'cap' }, 'Avec Keria',
                h('span', { className: 'capn' }, cible + '\u00A0% de d\u00E9sistements'))
            )
          ),
          /* Gain + ROI */
          h('div', null,
            h('div', { className: 'dsim-gain' },
              h('span', { className: 'tag' }, 'Gain annuel estim\u00E9'),
              h('div', { className: 'big' }, h(AnimEur, { value: gain }), '\u00A0\u20AC'),
              h('p', null, 'De pertes \u00E9vit\u00E9es chaque ann\u00E9e en s\u00E9curisant la finan\u00E7abilit\u00E9 d\u00E8s la r\u00E9servation.')
            ),
            coutNet > 0
              ? h('div', { className: 'dsim-roi' },
                  h('div', { className: 'x' }, h(AnimNum, { value: roi }), h('i', null, '×')),
                  h('div', { className: 'rt' },
                    h('b', null, 'ROI estimé'),
                    h('p', null,
                      'Pour chaque euro investi dans Keria, vous pourriez économiser jusqu’à ',
                      h('b', { style: { display: 'inline', color: 'var(--cobalt-bright)' } }, nf0(roi) + ' €'),
                      ' de pertes liées aux désistements.'
                    )
                  )
                )
              : h('div', { className: 'dsim-roi' },
                  h('div', { className: 'x', style: { color: 'var(--green-bright)' } }, '∞'),
                  h('div', { className: 'rt' },
                    h('b', null, 'ROI estimé'),
                    h('p', null, 'Les commissions courtage couvrent intégralement le coût des attestations Keria.')
                  )
                )
          )
        ),

        h('p', { className: 'dsim-disclaimer' },
          h(Ico, { d: D_INFO }),
          h('span', null,
            'Hypoth\u00E8ses ajustables et indicatives. La r\u00E9duction du taux de d\u00E9sistement, le co\u00FBt annuel Keria et le calcul de ROI sont fournis \u00E0 titre d\u2019illustration, sans valeur contractuelle, et varient selon le p\u00E9rim\u00E8tre, le profil des acqu\u00E9reurs et l\u2019accord bancaire d\u00E9finitif.')
        )
      )
    );

    /* ---- Section conversion ---- */
    var conversion = h('section', { className: 'section', id: 'conversion' },
      h('div', { className: 'wrap' },
        h('div', { className: 'cta-band nocturne' },
          h('span', { className: 'beam' }),
          h('span', { className: 'eyebrow', style: { justifyContent: 'center', marginBottom: '16px' } }, 'Passons \u00E0 votre programme'),
          h('h2', { style: { position: 'relative', zIndex: 2 } },
            'D\u00E9couvrez votre potentiel r\u00E9el de r\u00E9duction des d\u00E9sistements.'),
          h('p', { className: 'lead', style: { position: 'relative', zIndex: 2, margin: '0 auto 32px' } },
            'Demandez une d\u00E9monstration personnalis\u00E9e et obtenez une estimation adapt\u00E9e \u00E0 votre activit\u00E9, vos programmes et vos acqu\u00E9reurs.'),
          h('div', { className: 'row' },
            h('a', { href: 'contact.html', className: 'btn btn-gold btn-lg' },
              'Demander une d\u00E9monstration\u00A0', h(Ico, { d: D_ARROW })),
            h('a', { href: 'pilote-promoteur.html', className: 'btn btn-ghost on-navy btn-lg' },
              'Tester Keria')
          )
        )
      )
    );

    /* Section « Impact avec Keria » retirée du visible → projection envoyée par e-mail */
    var sentNotice = h('section', { className: 'section nocturne', id: 'impact-keria' },
      h('span', { className: 'beam', style: { top: '-30%', right: '-6%', opacity: '.45' } }),
      h('div', { className: 'wrap-wide', style: { position: 'relative', zIndex: 2 } },
        h('div', { className: 'section-head center' },
          h('span', { className: 'eyebrow' }, 'Votre projection personnalisée'),
          h('h2', null, 'Votre gain potentiel avec Keria ', h('span', { className: 'serif-i gold' }, 'arrive par e-mail'), '.'),
          h('p', { className: 'lead' }, 'Nous venons d’envoyer votre simulation complète — coût actuel des désistements et gain estimé avec Keria — à votre adresse. Un expert vous recontacte sous 24 h ; pensez à vérifier vos courriers indésirables.')
        )
      )
    );

    return h(React.Fragment, null,
      h('section', { className: 'section', id: 'simulateur' },
        h('div', { className: 'wrap-wide' },
          h('div', { className: 'section-head center' },
            h('span', { className: 'eyebrow' }, 'Simulateur \u00B7 Promoteurs'),
            h('h2', null, 'R\u00E9glez vos param\u00E8tres,\u00A0', h('span', { className: 'serif-i gold' }, 'lisez le co\u00FBt r\u00E9el'), '.'),
            h('p', { className: 'lead' }, 'Tout se recalcule en direct. Les chiffres ci-contre s\u2019actualisent \u00E0 chaque r\u00E9glage.')
          ),
          h('div', { className: 'dsim dsim-grid' }, controls, result)
        )
      ),
      sent ? sentNotice : null,
      conversion
    );
  }

  /* --- Montage --- */
  var mount = document.getElementById('sim-desist-root');
  if (mount) { ReactDOM.createRoot(mount).render(h(SimDesistements)); }

})();
