// configurator-2026.jsx — Stepper 6 étapes + composants steps + live preview
// Source design : design-2026-handoff/iteration-02 à iteration-08
// Calculateur : window.RAYCAST_CALC_2026 (validé 167/167 tests)
// Catalogue : window.RAYCOM_DATA_2026
//
// Exposé : window.Configurator2026 (composant React)

(function () {
  const { useState, useEffect, useMemo } = React;

  // ============================================================================
  // INITIAL STATE — Phase 2 (avec nouveaux champs : HQ accounts, panel_capacity, scope, descriptions)
  // ============================================================================
  function buildInitialState2026() {
    return {
      data_version: "2026",
      project_type: "solaire_batterie",
      building_type: "residentiel_unifam",
      client: {
        name: "",
        phone: "",
        phone_2: "",                // Phase 2 : 2e téléphone (cell + maison)
        email: "",
        address_civic: "",
        address_street: "",
        address_city: "",
        address_postal: "",
        region_id: null,
        zone_key: null,
        orientation: "S",
        // Profil énergétique (variant A solaire/batt)
        hq_tariff: "D",
        bill_input_mode: "kwh",
        annual_hq_kwh: 0,
        annual_hq_bill: 0,
        ev_km_per_year: 0,
        ev_kwh_per_100km: 18,
        nb_ve: 0,                   // Phase 2 : 0/1/2 véhicules électriques
        hq_account_number: "",      // Phase 2 : n° client HQ (9 chiffres, admissibilité LogisVert)
        hq_meter_number: "",        // Phase 2 : n° compteur
        hq_contract_number: "",     // Phase 2 : n° contrat (commercial)
        // Profil borne (variant B)
        panel_capacity_a: 200,      // Phase 2 : 60/100/200/300/400 A
        // Financement + commercial
        financing_plan_id: "comptant",
        source: "Référence client"
      },
      solar: {
        // P8-B : départ à 0 $ — RIEN de configuré au début (total = 0 jusqu'à l'étape 4)
        panneaux: 0,                // 0 = pas de solaire encore → total 0$ étapes 1-3
        pitch_key: "standard",
        floors: 2,
        roof_type: "bardeau",
        battery_brand: "none",      // aucune batterie au départ → total 0$
        battery_subsystem: null,
        battery_bundle_id: null,
        with_dim: false,
        with_v2x: false,
        backup_mode: "none",        // none | partial | whole_home
        onds: 1,                    // Solo=1 · Duo=2 · Trio=3
        // V3-E : Tout-en-un (project_type="batterie") — config spécifique sans solaire
        pw_count: 1,                // Tesla : 1-3 Powerwall 3
        dc_expansions: 0,           // Tesla : DC Expansions par PW (0-3)
        sig_battery_kwh: 9,         // Sigenergy : 6 ou 9 kWh par batterie
        sig_battery_qty: 2,         // Sigenergy : 1-8 batteries
        _configured: false          // P8-B : devient true quand le vendeur configure l'étape 4
      },
      borne: {
        qty: 0,
        modele_key: "tesla_gen3_nacs",
        client_supplied: false,           // V3 : borne fournie par client (oui/non)
        // Legacy mode (slider_key + cable_m unique) — gardé pour rétrocompat
        slider_key: "B_garage_pvc",
        cable_m: 5,
        // V3 : multi-cables combinables (en mètres par type)
        cables: {
          A_int_nmd:     0,  // NMD90 6/2 intérieur
          B_garage_pvc:  0,  // PVC 3/4" + 3× #6 RW90 garage
          C_garage_teck: 0,  // TECK90 6/3 garage (clippé surface)
          D_ext_pvc:     0,  // PVC 3/4" + 3× #6 RW90 extérieur mural
          E_ext_teck:    0,  // TECK90 6/3 extérieur
          F_int_emt:     0   // EMT 3/4" + 3× #6 RW90 intérieur conduit
        },
        dcc_code: null,                   // OPT-DCC-12 / OPT-DCC-10-40A / etc. (exclusif avec DSDC)
        dsdc: false                       // DSDC Tesla (exclusif avec DCC)
      },
      options_electriques: [],
      services: [],
      // Pattern descriptions (iter 11)
      description_overrides: {},
      scope_text: "",
      scope_locked: false,
      scope_generated_at: null,
      // Phase 2 : statut décision soumission
      decision_status: "draft",     // draft | accepted | thinking | refused
      decided_at: null
    };
  }

  // ============================================================================
  // ÉTAPES DÉFINITION — V3 (mai 2026) : 6 étapes solaire/batt, 5 étapes borne
  // ============================================================================
  // Architecture V3 :
  //   - Solaire / Solaire+Batt / Batterie (tout-en-un) → 6 étapes
  //   - Borne seule → 5 étapes (saute "Profil énergétique" — pas pertinent pour borne)
  //
  // Internal idx 1-6 inchangé (mêmes composants). Le stepper masque l'étape 3
  // ET les numéros affichés se recompactent (1-2-3-4-5 pour borne).
  const STEPS = [
    { idx: 1, key: "type",          title: "Type de projet",     subtitle: "Solaire · borne · batterie",       showForBorne: true  },
    { idx: 2, key: "profil_client", title: "Coordonnées client", subtitle: "Coords · adresse · zone",          showForBorne: true  },
    { idx: 3, key: "profil_energie",title: "Profil énergétique", subtitle: "HQ · conso · VÉ",                   showForBorne: false }, // Sautée pour borne
    { idx: 4, key: "config",        title: "Configuration",      subtitle: "Système · borne",                   showForBorne: true  },
    { idx: 5, key: "options",       title: "Options techniques", subtitle: "Câblage · branchements",            showForBorne: true  },
    { idx: 6, key: "resume",        title: "Résumé client",      subtitle: "Décision",                          showForBorne: true  }
  ];

  // Helpers V3 : filtre les étapes visibles + renumérotation display
  function getVisibleSteps(projectType) {
    const isBorne = projectType === "borne";
    return STEPS.filter(s => !isBorne || s.showForBorne).map((s, displayIdx) => ({
      ...s,
      displayIdx: displayIdx + 1,                  // 1-5 pour borne, 1-6 pour autres
      totalSteps: isBorne ? 5 : 6
    }));
  }

  // Step 7 (SubmissionCompletion) géré hors stepper (post-décision)

  // ============================================================================
  // STEPPER COMPONENT — V5 (variant A : barre de progression + labels segmentés)
  // ============================================================================
  function Stepper({ currentStep, completedSteps, onStepClick, calc, state }) {
    // V3 : étapes visibles selon project_type
    const visibleSteps = getVisibleSteps(state.project_type);
    const currentStepMeta = visibleSteps.find(s => s.idx === currentStep);
    const currentDisplayIdx = currentStepMeta?.displayIdx || currentStep;
    const totalSteps = visibleSteps.length;

    // Progression : pourcentage basé sur l'étape courante (1-indexed)
    // Étape 1 → ~16% (1/6), Étape 6 → 100% — distribué uniformément
    const progressPct = Math.round(((currentDisplayIdx - 0.5) / totalSteps) * 100);

    return (
      <div className="r5-stepper-wrap">
        <div className="r5-stepper-bar">
          <div className="r5-stepper-fill" style={{ width: `${progressPct}%` }}></div>
        </div>
        <div className="r5-stepper-segments" style={{ gridTemplateColumns: `repeat(${totalSteps}, 1fr)` }}>
          {visibleSteps.map(s => {
            const isCurrent = s.idx === currentStep;
            const isDone = completedSteps.includes(s.idx);
            const canClick = isDone || isCurrent;
            const cls = `r5-stepper-seg ${isCurrent ? "active" : ""} ${isDone ? "done" : ""}`;
            return (
              <button key={s.idx} type="button"
                      className={cls}
                      onClick={() => canClick && onStepClick(s.idx)}
                      disabled={!canClick}
                      aria-current={isCurrent ? "step" : undefined}>
                <span className="r5-stepper-seg-num">
                  {isDone
                    ? <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
                    : String(s.displayIdx).padStart(2, "0")}
                </span>
                <span className="r5-stepper-seg-title">{s.title}</span>
              </button>
            );
          })}
        </div>
      </div>
    );
  }

  // ============================================================================
  // STEP 1 : Type de projet — V5 Phase 5 design
  // ============================================================================
  function Step1Type({ state, setState, onNext }) {
    // V5 icons — designed by Claude Design (02-step1-type-v5.html)
    const CheckSm = (
      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
    );
    const SvgSolar = (
      <svg width="32" height="32" viewBox="0 0 32 32" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
        <path d="M5 23 L9 9 L23 9 L27 23 Z"/>
        <path d="M16 9 L16 23"/>
        <path d="M7 16 L25 16"/>
        <circle cx="22" cy="5" r="2"/>
        <path d="M22 1 L22 2 M27 5 L26 5 M25 2 L24 3 M25 8 L24 7 M19 8 L20 7"/>
      </svg>
    );
    const SvgSolarBattery = (
      <svg width="32" height="32" viewBox="0 0 32 32" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
        <path d="M5 18 L8 8 L20 8 L23 18 Z"/>
        <path d="M14 8 L14 18"/>
        <path d="M7 13 L21 13"/>
        <rect x="20" y="20" width="8" height="10" rx="1"/>
        <path d="M22 18 L22 20 M26 18 L26 20"/>
        <path d="M22 25 L26 25"/>
      </svg>
    );
    const SvgBattery = (
      <svg width="32" height="32" viewBox="0 0 32 32" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
        <rect x="9" y="6" width="14" height="22" rx="2"/>
        <path d="M13 4 L13 6 M19 4 L19 6"/>
        <path d="M12 14 L20 14"/>
        <path d="M14 11 L16 11 L16 17 L18 17"/>
        <path d="M12 22 L20 22"/>
      </svg>
    );
    const SvgBorne = (
      <svg width="32" height="32" viewBox="0 0 32 32" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
        <rect x="10" y="6" width="12" height="18" rx="2"/>
        <path d="M14 12 L14 14"/>
        <path d="M18 12 L18 14"/>
        <path d="M13 18 L19 18"/>
        <path d="M16 24 L16 28"/>
        <path d="M11 28 L21 28"/>
        <path d="M22 14 L26 14 L26 22"/>
      </svg>
    );

    const types = [
      {
        key: "solaire", name: "SOLAIRE", icon: SvgSolar,
        tag: "Panneaux + onduleur. Production réseau, économies sur la facture HQ.",
        includes: ["5 à 80 panneaux Thornova 500 W", "Onduleur Fox ESS ou Sigenergy", "Subvention LogisVert HQ"],
        price: "À partir de", priceVal: "14 800 $"
      },
      {
        key: "solaire_batterie", name: <>SOLAIRE +<br/>BATTERIES</>, icon: SvgSolarBattery,
        tag: "Production solaire couplée à un stockage. Autonomie, backup en option, V2X.",
        includes: ["Tesla / Fox / Sigenergy au choix", "DIM HQ + V2X compatible", "Backup partiel ou whole-home"],
        ribbon: "Le plus choisi", priceVal: "29 400 $"
      },
      {
        key: "batterie", name: <>SYSTÈMES ESS<br/>TOUT-EN-UN</>, icon: SvgBattery,
        tag: "Stockage seul. Optimisation tarifaire HQ et backup, sans panneaux solaires.",
        includes: ["Tesla Powerwall 3", "Fox AIO ou H1 Hybrid", "Sigenergy modulaire 6–48 kWh"],
        price: "À partir de", priceVal: "15 200 $"
      },
      {
        key: "borne", name: "BORNE VÉ", icon: SvgBorne,
        tag: "Borne de recharge résidentielle ou multilog., installation électrique pro.",
        includes: ["Tesla Gen3 NACS / Universal", "FLO X3, X6, X8", "Subv. Roulez Vert 600 $"],
        price: "À partir de", priceVal: "1 494 $"
      }
    ];

    const buildings = [
      { key: "residentiel_unifam", label: "Résidentiel",      meta: "unifamilial · max 20 kW" },
      { key: "multilog",           label: "Multilogement",    meta: "4–19 log. · max 50 kW" },
      { key: "com_petit",          label: "Commercial petit", meta: "< 50 kW" },
      { key: "com_moyen",          label: "Commercial moyen", meta: "50–200 kW" },
      { key: "com_grand",          label: "Commercial grand", meta: "> 200 kW" }
    ];

    const handleTypeSelect = (key) => {
      // P8-B : ne JAMAIS forcer panneaux:20 ici → le total reste à 0$ jusqu'à l'étape 4.
      // On ne fait que réinitialiser la batterie selon le type choisi (cohérence), panneaux reste 0.
      const solarPatch = key === "batterie"
        ? { panneaux: 0, roof_type: "bardeau", pitch_key: "standard" }
        : key === "solaire"
        ? { battery_brand: "none", battery_subsystem: null, battery_bundle_id: null, backup_mode: "none" }
        : {};
      setState({ ...state, project_type: key, solar: { ...state.solar, ...solarPatch } });
    };

    return (
      <div>
        <div className="r5-step-intro">
          <div className="r5-step-eyebrow"><span className="r5-dot"></span>Étape 1 sur 6 · Type de projet</div>
          <h1>Quel projet souhaite-t-il réaliser&#8239;?</h1>
          <p>Vous pourrez ajuster la configuration en détail aux étapes suivantes. Cette première sélection oriente le parcours et les forfaits proposés.</p>
        </div>

        <div className="r5-project-grid">
          {types.map(t => {
            const isSelected = state.project_type === t.key;
            return (
              <button key={t.key} type="button"
                      className={`r5-project-card ${isSelected ? "selected" : ""}`}
                      onClick={() => handleTypeSelect(t.key)}
                      aria-pressed={isSelected}>
                <div className="r5-project-check">
                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
                </div>
                <div className="r5-project-icon">{t.icon}</div>
                <div className="r5-project-name">{t.name}</div>
                <div className="r5-project-tag">{t.tag}</div>
                <ul className="r5-project-includes">
                  {t.includes.map((inc, i) => (
                    <li key={i}>{CheckSm}{inc}</li>
                  ))}
                </ul>
                <div className="r5-project-foot">
                  {t.ribbon
                    ? <span className="r5-project-foot-tag">{t.ribbon}</span>
                    : <span>{t.price}</span>}
                  <span className="r5-project-foot-price">{t.priceVal}</span>
                </div>
              </button>
            );
          })}
        </div>

        <section className="r5-building-section">
          <div className="r5-section-head">
            <div className="r5-section-eyebrow">Type de bâtiment</div>
            <h2 className="r5-section-title">De quelle taille s'agit-il&#8239;?</h2>
            <p className="r5-section-subtitle">Détermine les forfaits, la puissance max et l'admissibilité aux subventions.</p>
          </div>
          <div className="r5-building-grid">
            {buildings.map(b => (
              <button key={b.key} type="button"
                      className={`r5-building-card ${state.building_type === b.key ? "selected" : ""}`}
                      onClick={() => setState({ ...state, building_type: b.key })}
                      aria-pressed={state.building_type === b.key}>
                <div className="r5-building-card-label">{b.label}</div>
                <div className="r5-building-card-meta">{b.meta}</div>
              </button>
            ))}
          </div>
        </section>

        <div className="r5-nav-row">
          <span></span>
          <button type="button" className="r5-btn r5-btn-primary r5-btn-lg" onClick={onNext}>
            Continuer
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
          </button>
        </div>
      </div>
    );
  }

  // ============================================================================
  // STEP 2 : Coordonnées client COMPLET (V3 — validations strictes + auto-formatage)
  // ============================================================================

  // V3 Validateurs regex stricts
  const V3_VALIDATORS = {
    nom: (v) => /^[A-Za-zÀ-ÿ\s'-]{2,50}$/.test((v || "").trim()),
    phone: (v) => /^\(\d{3}\)\s\d{3}-\d{4}$/.test(v || ""),
    email: (v) => !v || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v),
    civic: (v) => /^\d{1,7}[A-Z]?$/.test((v || "").trim().toUpperCase()),
    postal: (v) => /^[A-Z]\d[A-Z]\s\d[A-Z]\d$/.test((v || "").toUpperCase())
  };

  // V3 Auto-formateurs
  function formatPhone(raw) {
    // "5141234567" → "(514) 123-4567"
    const digits = (raw || "").replace(/\D/g, "").substr(0, 10);
    if (digits.length <= 3) return digits;
    if (digits.length <= 6) return `(${digits.substr(0,3)}) ${digits.substr(3)}`;
    return `(${digits.substr(0,3)}) ${digits.substr(3,3)}-${digits.substr(6)}`;
  }
  function formatPostal(raw) {
    // "j7k2k3" → "J7K 2K3"
    const cleaned = (raw || "").toUpperCase().replace(/[^A-Z0-9]/g, "").substr(0, 6);
    if (cleaned.length <= 3) return cleaned;
    return `${cleaned.substr(0,3)} ${cleaned.substr(3)}`;
  }
  function filterCivic(raw) {
    // Numérique + 1 lettre finale max (ex. "123" ou "456B")
    return (raw || "").toUpperCase().replace(/[^0-9A-Z]/g, "").replace(/([A-Z]).*$/, "$1").substr(0, 7);
  }
  function filterName(raw) {
    // Lettres + accents + espace + apostrophe + tiret
    return (raw || "").replace(/[^A-Za-zÀ-ÿ\s'-]/g, "");
  }

  function Step2ProfilClient({ state, setState, calc, onBack, onNext }) {
    const C = window.RAYCAST_CALC_2026;
    const D = window.RAYCOM_DATA_2026;
    const zone = calc?.zone || C.detectZone(state.client.address_postal);

    const updateClient = (patch) => setState({ ...state, client: { ...state.client, ...patch } });

    // P8-C : Typeahead client — recherche BDD à la frappe du nom, sélection auto-remplit tout
    const [clientResults, setClientResults] = useState([]);
    const [showResults, setShowResults] = useState(false);
    useEffect(() => {
      const q = (state.client.name || "").trim();
      if (q.length < 2 || !window.RaycastDB?.listClients) { setClientResults([]); return; }
      let alive = true;
      const t = setTimeout(async () => {
        try {
          const data = await window.RaycastDB.listClients({ search: q, limit: 6 });
          if (alive) setClientResults(data || []);
        } catch (_) { if (alive) setClientResults([]); }
      }, 250);
      return () => { alive = false; clearTimeout(t); };
    }, [state.client.name]);

    const pickClient = (cl) => {
      setShowResults(false);
      setState({ ...state, client: { ...state.client,
        client_id: cl.id, name: cl.name || "", phone: cl.phone || "", email: cl.email || "",
        address_civic: cl.address_civic || "", address_street: cl.address_street || "",
        address_city: cl.address_city || "", address_postal: cl.address_postal || "",
        source: cl.source || state.client.source, zone_key: null
      } });
    };

    // V3 : auto-formatage déclenché à chaque keystroke
    const updateClientFormatted = (field, value) => {
      let formatted = value;
      if (field === "phone")             formatted = formatPhone(value);
      else if (field === "phone_2")      formatted = formatPhone(value);
      else if (field === "address_postal")formatted = formatPostal(value);
      else if (field === "address_civic")formatted = filterCivic(value);
      else if (field === "name")         formatted = filterName(value);
      updateClient({ [field]: formatted, ...(field === "address_postal" ? { zone_key: null } : {}) });
    };

    // V3 Validations strictes + zone hors couverture autorisée (sur soumission)
    const v3 = {
      name: V3_VALIDATORS.nom(state.client.name),
      phone: V3_VALIDATORS.phone(state.client.phone),
      email: V3_VALIDATORS.email(state.client.email),
      civic: V3_VALIDATORS.civic(state.client.address_civic),
      postal: V3_VALIDATORS.postal(state.client.address_postal),
      street: !!(state.client.address_street && state.client.address_street.trim()),
      city:   !!(state.client.address_city   && state.client.address_city.trim())
    };
    const canProceed = v3.name && v3.phone && v3.email && v3.civic && v3.postal && v3.street && v3.city;

    // Warning intelligent : si project_type ne matche pas building_type (directive JF #3)
    const projType = state.project_type;
    const bldgType = state.building_type;
    const mismatchWarning = (() => {
      if (bldgType === "multilog" && projType === "solaire_batterie") {
        return "Tu as choisi solaire+batterie mais le bâtiment est un multilogement. Considère « Borne VÉ multilog » ou « Solaire commercial ».";
      }
      if ((bldgType === "com_petit" || bldgType === "com_moyen" || bldgType === "com_grand") && projType !== "solaire") {
        return "Bâtiment commercial sélectionné — pense à basculer vers Solutions efficaces HQ (subventions commerciales).";
      }
      return null;
    })();

    // V5 helpers
    const CheckSvg = (
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
    );
    const validClass = (isValid, hasValue) => hasValue && isValid ? "valid" : hasValue && !isValid ? "error" : "";
    const section01Complete = v3.name && v3.phone && v3.email;
    const section02Complete = v3.civic && v3.street && v3.city && v3.postal;

    return (
      <div className="r5-step2-layout"
           onKeyDown={(e) => {
             // P8-C : Entrée pour avancer (sauf dans un select/textarea ou si dropdown ouvert)
             if (e.key === "Enter" && canProceed && !showResults && e.target.tagName !== "SELECT" && e.target.tagName !== "TEXTAREA") {
               e.preventDefault(); onNext();
             }
           }}>
        <div>
          <div className="r5-step-intro">
            <div className="r5-step-eyebrow"><span className="r5-dot"></span>Étape 2 sur 6 · Profil client</div>
            <h1>Qui est le client&#8239;?</h1>
            <p>Coordonnées + adresse du chantier — le code postal détecte automatiquement la zone Raycom et les frais de déplacement.</p>
          </div>

          {mismatchWarning && (
            <div className="r5-alert warning" style={{ marginBottom: 24 }}>
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
              <div>
                <strong>Type de projet à confirmer</strong>
                <div style={{ marginTop: 4 }}>{mismatchWarning}</div>
                <button className="r5-btn r5-btn-ghost r5-btn-sm" style={{ marginTop: 8, padding: "4px 10px" }} onClick={onBack}>← Retour étape 1 pour ajuster</button>
              </div>
            </div>
          )}

          {/* Section 01 — Identité */}
          <section className="r5-form-section">
            <div className="r5-form-section-head">
              <span className="r5-form-section-num">01</span>
              <h2 className="r5-form-section-title">Identité</h2>
              <span className={`r5-form-section-status ${!section01Complete ? "incomplete" : ""}`}>
                {section01Complete && CheckSvg}
                {section01Complete ? "Complété" : "En cours"}
              </span>
            </div>
            <div className="r5-form-card">
              <div className="r5-form-grid">
                <div className="r5-field-v5 r5-form-grid-1" style={{ position: "relative" }}>
                  <label className="r5-field-label-v5">
                    Nom complet <span className="required">*</span>
                    <span className="r5-field-label-hint">recherche client BDD</span>
                  </label>
                  <div className="r5-input-wrap-v5">
                    <input type="text" className={`r5-input-v5 ${validClass(v3.name, !!state.client.name)}`}
                           value={state.client.name}
                           onChange={e => { updateClientFormatted("name", e.target.value); setShowResults(true); }}
                           onFocus={() => setShowResults(true)}
                           onBlur={() => setTimeout(() => setShowResults(false), 180)}
                           placeholder="Jean Tremblay" maxLength={50} autoComplete="off" />
                    {state.client.name && v3.name && <div className="r5-input-icon-v5 valid">{CheckSvg}</div>}
                  </div>
                  {showResults && clientResults.length > 0 && (
                    <div className="r5-typeahead">
                      {clientResults.map(cl => (
                        <button key={cl.id} type="button" className="r5-typeahead-item" onMouseDown={() => pickClient(cl)}>
                          <span className="r5-typeahead-name">{cl.name}</span>
                          <span className="r5-typeahead-meta">{[cl.address_city, cl.phone].filter(Boolean).join(" · ")}</span>
                        </button>
                      ))}
                    </div>
                  )}
                </div>
                <div className="r5-field-v5">
                  <label className="r5-field-label-v5">
                    Téléphone <span className="required">*</span>
                    <span className="r5-field-label-hint">format auto</span>
                  </label>
                  <div className="r5-input-wrap-v5">
                    <input type="tel" className={`r5-input-v5 ${validClass(v3.phone, !!state.client.phone)}`}
                           value={state.client.phone}
                           onChange={e => updateClientFormatted("phone", e.target.value)}
                           placeholder="(450) 555-1234" maxLength={14} inputMode="numeric" />
                    {state.client.phone && v3.phone && <div className="r5-input-icon-v5 valid">{CheckSvg}</div>}
                  </div>
                </div>
                <div className="r5-field-v5">
                  <label className="r5-field-label-v5">
                    Courriel <span className="required">*</span>
                  </label>
                  <div className="r5-input-wrap-v5">
                    <input type="email" className={`r5-input-v5 ${validClass(v3.email, !!state.client.email)}`}
                           value={state.client.email}
                           onChange={e => updateClient({ email: e.target.value })}
                           placeholder="jean@exemple.ca" />
                    {state.client.email && v3.email && <div className="r5-input-icon-v5 valid">{CheckSvg}</div>}
                  </div>
                  {state.client.email && !v3.email && (
                    <div className="r5-field-error">
                      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>
                      Format de courriel invalide
                    </div>
                  )}
                </div>
                <div className="r5-field-v5">
                  <label className="r5-field-label-v5">
                    Téléphone alt.
                    <span className="r5-field-label-hint">optionnel</span>
                  </label>
                  <div className="r5-input-wrap-v5">
                    <input type="tel" className="r5-input-v5" value={state.client.phone_2}
                           onChange={e => updateClientFormatted("phone_2", e.target.value)}
                           placeholder="Cell ou bureau" maxLength={14} inputMode="numeric" />
                  </div>
                </div>
                <div className="r5-field-v5 r5-form-grid-1">
                  <label className="r5-field-label-v5">
                    Source du lead
                    <span className="r5-field-label-hint">optionnel</span>
                  </label>
                  <div className="r5-select-wrap">
                    <select className="r5-select-v5" value={state.client.source}
                            onChange={e => updateClient({ source: e.target.value })}>
                      <option>Référence client direct</option>
                      <option>Publicité en ligne (Google/Facebook)</option>
                      <option>Via mPower (Tesla)</option>
                      <option>Via Larks Solar</option>
                      <option>Via Stardust Solar</option>
                      <option>Site web Raycom</option>
                      <option>Salon / événement</option>
                      <option>Autre</option>
                    </select>
                    <div className="r5-select-arrow">
                      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </section>

          {/* Section 02 — Adresse */}
          <section className="r5-form-section">
            <div className="r5-form-section-head">
              <span className="r5-form-section-num">02</span>
              <h2 className="r5-form-section-title">Adresse du chantier</h2>
              <span className={`r5-form-section-status ${!section02Complete ? "incomplete" : ""}`}>
                {section02Complete && CheckSvg}
                {section02Complete ? "Complété" : "Détection zone auto"}
              </span>
            </div>
            <div className="r5-form-card">
              <div className="r5-form-grid">
                <div className="r5-field-v5">
                  <label className="r5-field-label-v5">N° civique <span className="required">*</span></label>
                  <div className="r5-input-wrap-v5">
                    <input className={`r5-input-v5 ${validClass(v3.civic, !!state.client.address_civic)}`}
                           value={state.client.address_civic}
                           onChange={e => updateClientFormatted("address_civic", e.target.value)}
                           placeholder="123" maxLength={7} inputMode="numeric" />
                    {state.client.address_civic && v3.civic && <div className="r5-input-icon-v5 valid">{CheckSvg}</div>}
                  </div>
                </div>
                <div className="r5-field-v5">
                  <label className="r5-field-label-v5">Rue <span className="required">*</span></label>
                  <div className="r5-input-wrap-v5">
                    <input className={`r5-input-v5 ${validClass(v3.street, !!state.client.address_street)}`}
                           value={state.client.address_street}
                           onChange={e => updateClient({ address_street: e.target.value })}
                           placeholder="rue des Pins" />
                    {state.client.address_street && v3.street && <div className="r5-input-icon-v5 valid">{CheckSvg}</div>}
                  </div>
                </div>
                <div className="r5-field-v5">
                  <label className="r5-field-label-v5">Ville <span className="required">*</span></label>
                  <div className="r5-input-wrap-v5">
                    <input className={`r5-input-v5 ${validClass(v3.city, !!state.client.address_city)}`}
                           value={state.client.address_city}
                           onChange={e => updateClient({ address_city: e.target.value })}
                           placeholder="Mascouche" />
                    {state.client.address_city && v3.city && <div className="r5-input-icon-v5 valid">{CheckSvg}</div>}
                  </div>
                </div>
                <div className="r5-field-v5">
                  <label className="r5-field-label-v5">
                    Code postal <span className="required">*</span>
                    <span className="r5-field-label-hint">A1A 1A1</span>
                  </label>
                  <div className="r5-input-wrap-v5">
                    <input className={`r5-input-v5 ${validClass(v3.postal, !!state.client.address_postal)}`}
                           value={state.client.address_postal}
                           onChange={e => updateClientFormatted("address_postal", e.target.value)}
                           placeholder="J7K 0H4" maxLength={7} />
                    {state.client.address_postal && v3.postal && <div className="r5-input-icon-v5 valid">{CheckSvg}</div>}
                  </div>
                </div>
              </div>
            </div>
          </section>

          <div className="r5-nav-row">
            <button type="button" className="r5-btn r5-btn-secondary" onClick={onBack}>
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
              Précédent
            </button>
            <button type="button" className="r5-btn r5-btn-primary r5-btn-lg" onClick={onNext} disabled={!canProceed}
                    title={!canProceed ? "Compléter les champs requis · email valide · zone détectée" : ""}>
              Continuer
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
            </button>
          </div>
        </div>

        {/* Right sidebar — Zone detected */}
        <aside className="r5-zone-card">
          <div className="r5-zone-head">
            <div className="r5-zone-eyebrow">Détection auto</div>
            <h3 className="r5-zone-title">Zone Raycom</h3>
          </div>

          {zone && zone.zone_key && state.client.address_postal ? (
            <>
              <div className={`r5-zone-hero ${zone.blocked || zone.zone_key === "Z6" || zone.zone_key === "Z7" ? "warning" : ""}`}>
                <div className={`r5-zone-badge ${zone.blocked ? "danger" : zone.zone_key === "Z6" || zone.zone_key === "Z7" ? "warning" : ""}`}>
                  {!zone.blocked && CheckSvg}
                  {zone.blocked ? "Hors couverture" : zone.zone_key === "Z6" || zone.zone_key === "Z7" ? "Sur soumission" : "Couverte"}
                </div>
                <div className="r5-zone-name">{zone.zone_key} — {zone.label}</div>
                <div className="r5-zone-desc">{zone.sub || ""}</div>
                <div className="r5-zone-price">
                  <span className="r5-zone-price-label">Frais déplacement</span>
                  <span className="r5-zone-price-value">
                    {zone.sell_client > 0 ? C.fmtCAD0(zone.sell_client) : (zone.blocked ? "Sur devis" : "Inclus")}
                  </span>
                </div>
              </div>
              <div className="r5-zone-info">
                <div className="r5-zone-info-row">
                  <span className="k">FSA détecté</span>
                  <span className="v mono">{zone.fsa || state.client.address_postal.substring(0, 3)}</span>
                </div>
                <div className="r5-zone-info-row">
                  <span className="k">Couverture</span>
                  <span className="v">{zone.blocked ? "Sur devis" : "Standard"}</span>
                </div>
                {zone.zone_key === "Z1" && (
                  <div className="r5-zone-info-row">
                    <span className="k">Délai install</span>
                    <span className="v">~ 2 semaines</span>
                  </div>
                )}
              </div>
              {/* Mini map — Mascouche pin avec cercle Z1 30 km */}
              <div className="r5-zone-map">
                <svg viewBox="0 0 340 140" xmlns="http://www.w3.org/2000/svg">
                  <defs>
                    <radialGradient id="r5map-glow" cx="50%" cy="50%" r="50%">
                      <stop offset="0%" stopColor="#2563EB" stopOpacity="0.4"/>
                      <stop offset="100%" stopColor="#2563EB" stopOpacity="0"/>
                    </radialGradient>
                  </defs>
                  {/* Quebec outline simplified */}
                  <path d="M 30 110 Q 50 80 80 75 L 130 70 Q 170 65 200 75 L 260 80 Q 290 85 310 100 L 320 130 L 30 130 Z"
                        fill="#1E293B" stroke="#475569" strokeWidth="1"/>
                  {/* Z1 circle (Mascouche area) */}
                  <circle cx="170" cy="90" r="35" fill="url(#r5map-glow)"/>
                  <circle cx="170" cy="90" r="35" fill="none" stroke="#2563EB" strokeWidth="1" strokeDasharray="3 3"/>
                  {/* Pin */}
                  <circle cx="170" cy="90" r="4" fill="#2563EB"/>
                  <circle cx="170" cy="90" r="8" fill="none" stroke="#2563EB" strokeWidth="1.5"/>
                  <text x="170" y="115" fill="#94A3B8" fontSize="9" textAnchor="middle" fontFamily="JetBrains Mono">{zone.zone_key} · {state.client.address_city || "Mascouche"}</text>
                </svg>
              </div>
            </>
          ) : (
            <div className="r5-zone-info" style={{ padding: "32px 22px", textAlign: "center" }}>
              <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={{ color: "var(--r5-ink-5)", marginBottom: 12 }}><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
              <div style={{ fontSize: 13, color: "var(--r5-ink-4)", lineHeight: 1.4 }}>
                Saisis le code postal pour détecter automatiquement la zone et les frais de déplacement.
              </div>
            </div>
          )}
        </aside>
      </div>
    );
  }

  // ============================================================================
  // STEP 3 : Profil énergétique CONDITIONNEL (Phase 2 — 2 variants selon project_type)
  //   Variant A : solaire / solaire_batterie / batterie → tarif HQ + conso + VÉ + n°HQ
  //   Variant B : borne → capacité du panneau électrique (60/100/200/300/400 A)
  // ============================================================================
  function Step3ProfilEnergetique({ state, setState, onBack, onNext }) {
    const D = window.RAYCOM_DATA_2026;
    const C = window.RAYCAST_CALC_2026;
    const updateClient = (patch) => setState({ ...state, client: { ...state.client, ...patch } });
    const isBorneOnly = state.project_type === "borne";

    // === VARIANT B : Borne seule — capacité panneau électrique ===
    if (isBorneOnly) {
      const cap = state.client.panel_capacity_a;
      const needsUpgrade = cap > 0 && cap < 200;
      return (
        <div>
          <div className="r5-step-intro">
            <div className="r5-step-eyebrow"><span className="r5-dot"></span>Étape 3 sur 6 · Capacité électrique</div>
            <h1>Quelle est la capacité du panneau électrique&#8239;?</h1>
            <p>Pour une borne VÉ, on a juste besoin de connaître l'ampérage de l'entrée pour évaluer si une mise à niveau est requise.</p>
          </div>

          <section className="r5-form-section">
            <div className="r5-form-section-head">
              <span className="r5-form-section-num">01</span>
              <h2 className="r5-form-section-title">Ampérage actuel</h2>
              <span className="r5-form-section-desc">5 options · standard 200&nbsp;A</span>
            </div>
            <div className="r5-form-card">
              <div className="r5-grid" style={{ gridTemplateColumns: "repeat(auto-fit, minmax(120px, 1fr))" }}>
                {[60, 100, 200, 300, 400].map(a => (
                  <button key={a} type="button"
                          className={`r5-tariff-card ${cap === a ? "selected" : ""}`}
                          onClick={() => updateClient({ panel_capacity_a: a })}>
                    <div className="r5-tariff-head">
                      <span className="r5-tariff-code">{a} A</span>
                    </div>
                    <div className="r5-tariff-name">{a < 100 ? "Cabanon" : a === 100 ? "Petit" : a === 200 ? "Standard" : a === 300 ? "Indicatif" : "Grand / commercial"}</div>
                    <div className="r5-tariff-meta">{a === 200 ? "Standard résidentiel" : a === 300 ? "Sur soumission" : ""}</div>
                  </button>
                ))}
              </div>

              {needsUpgrade && (
                <div className="r5-alert warning" style={{ marginTop: 16 }}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
                  <div>
                    <strong>Mise à niveau panneau recommandée</strong>
                    <div style={{ marginTop: 4 }}>Pour brancher une borne VÉ (60&nbsp;A typique), il faudra passer le panneau de {cap}&nbsp;A à 200&nbsp;A. Option <code className="mono">OPT-PANNEAU-RECUP</code> ou <code className="mono">OPT-PANNEAU-NEUFS</code> ajoutée auto à l'étape 5.</div>
                  </div>
                </div>
              )}

              {cap === 300 && (
                <div className="r5-alert info" style={{ marginTop: 16 }}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
                  <div>
                    <strong>300&nbsp;A — option indicative</strong>
                    <div style={{ marginTop: 4 }}>Le prix d'upgrade 100 → 300&nbsp;A n'est pas dans la grille standard. JF / Marc-André confirmera par soumission ad hoc.</div>
                  </div>
                </div>
              )}

              <div className="r5-alert info" style={{ marginTop: 16 }}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
                <div>
                  <strong>Admissibilité subventions</strong>
                  <div style={{ marginTop: 4 }}>Le projet ne contient que des bornes EV — <b>LogisVert ne s'applique pas</b>. Seul <b>Roulez Vert (600&nbsp;$ max résid · 5 000&nbsp;$/borne multilog + ZEV 1 400&nbsp;$)</b> est disponible.</div>
                </div>
              </div>
            </div>
          </section>

          <div className="r5-nav-row">
            <button type="button" className="r5-btn r5-btn-secondary" onClick={onBack}>
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
              Précédent
            </button>
            <button type="button" className="r5-btn r5-btn-primary r5-btn-lg" onClick={onNext} disabled={!cap}>
              Continuer
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
            </button>
          </div>
        </div>
      );
    }

    // === VARIANT A : Solaire / Batterie — profil énergétique complet ===
    const tariff = D.hq_tariffs.find(t => t.id === state.client.hq_tariff) || D.hq_tariffs[0];
    const annual_kwh_eff = state.client.bill_input_mode === "kwh"
      ? (state.client.annual_hq_kwh || 0)
      : (state.client.annual_hq_bill || 0) * 100 / tariff.rate;
    const annual_bill_eff = state.client.bill_input_mode === "dollars"
      ? (state.client.annual_hq_bill || 0)
      : (state.client.annual_hq_kwh || 0) * tariff.rate / 100;
    const kw_reco = annual_kwh_eff > 0 ? Math.min(20, Math.max(4, Math.round(annual_kwh_eff / 1380))) : 0;
    const savings_25 = annual_bill_eff > 0 ? Math.round(annual_bill_eff * 0.6 * 25 * 1.02) : 0;
    const hqOk = !state.client.hq_account_number || /^[A-Za-z0-9-]{6,18}$/.test(state.client.hq_account_number.replace(/\s/g, ""));
    const flexDIncompat = state.client.hq_tariff === "FlexD" && state.solar?.battery_brand === "none";

    // Production NRCan estimate (10 kW × 1170 kWh/kW/an Mascouche)
    const sampleKw = kw_reco > 0 ? kw_reco : 10;
    const annualProd = Math.round(sampleKw * 1170);
    // Distribution mensuelle (% du total annuel)
    const monthlyDist = [3, 5, 8, 11, 13, 13, 13, 12, 9, 6, 4, 3]; // Jan-Déc
    const monthsLabels = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"];

    // Orientation compass
    const orientations = [
      { key: "N", label: "N", isReco: false },
      { key: "NE", label: "NE", isReco: false },
      { key: "E", label: "E", isReco: false },
      { key: "SE", label: "SE", isReco: false },
      { key: "S", label: "S", isReco: true },
      { key: "SO", label: "SO", isReco: true },
      { key: "O", label: "O", isReco: false },
      { key: "NO", label: "NO", isReco: false }
    ];

    return (
      <div className="r5-step3-layout">
        <div>
          <div className="r5-step-intro">
            <div className="r5-step-eyebrow"><span className="r5-dot"></span>Étape 3 sur 6 · Profil énergétique</div>
            <h1>Quel est son profil énergétique&#8239;?</h1>
            <p>Tarif HQ + consommation annuelle + véhicule électrique. Ces données alimentent l'estimation de couverture et le calcul des économies.</p>
          </div>

          {/* 01 — Tarif HQ */}
          <section className="r5-form-section">
            <div className="r5-form-section-head">
              <span className="r5-form-section-num">01</span>
              <h2 className="r5-form-section-title">Tarif Hydro-Québec</h2>
              <span className="r5-form-section-desc">{D.hq_tariffs.length} tarifs résidentiels &amp; commerciaux</span>
            </div>
            <div className="r5-form-card">
              <div className="r5-tariff-grid">
                {D.hq_tariffs.map(t => {
                  const isFlexDInRed = t.id === "FlexD" && state.solar?.battery_brand === "none";
                  return (
                    <button key={t.id} type="button"
                            className={`r5-tariff-card ${state.client.hq_tariff === t.id ? "selected" : ""}`}
                            onClick={() => updateClient({ hq_tariff: t.id })}
                            style={isFlexDInRed ? { borderColor: "var(--r5-danger)" } : {}}>
                      <div className="r5-tariff-head">
                        <span className="r5-tariff-code">{t.id}</span>
                      </div>
                      <div className="r5-tariff-name">{(t.label || "").split(" — ")[1] || (t.label || "").split(" — ")[0]}</div>
                      <div className="r5-tariff-meta">{t.rate} ¢/kWh{t.segment === "commercial" ? " · com." : ""}</div>
                    </button>
                  );
                })}
              </div>
              {flexDIncompat && (
                <div className="r5-alert warning" style={{ marginTop: 12 }}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
                  <div>FlexD/DP sont des tarifs dynamiques — peu rentables sans batterie. Recommander tarif D ou ajouter une batterie à l'étape 4.</div>
                </div>
              )}
            </div>
          </section>

          {/* 02 — Consommation */}
          <section className="r5-form-section">
            <div className="r5-form-section-head">
              <span className="r5-form-section-num">02</span>
              <h2 className="r5-form-section-title">Consommation annuelle</h2>
              <span className="r5-form-section-desc">Saisie en kWh ou en $</span>
            </div>
            <div className="r5-form-card">
              <div className="r5-consumption">
                <div className="r5-field-v5">
                  <label className="r5-field-label-v5">
                    Mode de saisie
                  </label>
                  <div className="r5-pill-row">
                    <button type="button" className={`r5-pill ${state.client.bill_input_mode === "kwh" ? "selected" : ""}`}
                            onClick={() => updateClient({ bill_input_mode: "kwh" })}>kWh / an</button>
                    <button type="button" className={`r5-pill ${state.client.bill_input_mode === "dollars" ? "selected" : ""}`}
                            onClick={() => updateClient({ bill_input_mode: "dollars" })}>$ / an</button>
                  </div>
                </div>
                <div className="r5-field-v5">
                  <label className="r5-field-label-v5">
                    Consommation annuelle <span className="required">*</span>
                  </label>
                  <div className="r5-input-wrap-v5">
                    <input type="number" className="r5-input-v5 mono"
                           value={state.client.bill_input_mode === "kwh" ? state.client.annual_hq_kwh : state.client.annual_hq_bill}
                           onChange={e => updateClient({
                             [state.client.bill_input_mode === "kwh" ? "annual_hq_kwh" : "annual_hq_bill"]: parseInt(e.target.value, 10) || 0
                           })}
                           placeholder={state.client.bill_input_mode === "kwh" ? "22 400" : "1 850"} />
                    <div className="r5-input-unit">{state.client.bill_input_mode === "kwh" ? "kWh" : "$"}</div>
                  </div>
                </div>
              </div>

              {(annual_kwh_eff > 0 || annual_bill_eff > 0) && (
                <div className="r5-grid r5-grid-4" style={{ marginTop: 18 }}>
                  <div className="r5-kpi" style={{ padding: "14px 16px" }}>
                    <div className="r5-kpi-eyebrow">Conso / an</div>
                    <div style={{ fontSize: 18, fontWeight: 700, color: "var(--r5-ink)", fontVariantNumeric: "tabular-nums" }}>{C.fmtNum(annual_kwh_eff)}</div>
                    <div className="r5-kpi-meta">kWh</div>
                  </div>
                  <div className="r5-kpi" style={{ padding: "14px 16px" }}>
                    <div className="r5-kpi-eyebrow">Facture</div>
                    <div style={{ fontSize: 18, fontWeight: 700, color: "var(--r5-ink)", fontVariantNumeric: "tabular-nums" }}>{C.fmtCAD0(annual_bill_eff)}</div>
                    <div className="r5-kpi-meta">/ an</div>
                  </div>
                  <div className="r5-kpi primary" style={{ padding: "14px 16px" }}>
                    <div className="r5-kpi-eyebrow">Système reco</div>
                    <div style={{ fontSize: 18, fontWeight: 700, color: "var(--r5-primary)", fontVariantNumeric: "tabular-nums" }}>{kw_reco} kW</div>
                    <div className="r5-kpi-meta">≈ {kw_reco * 2} panneaux</div>
                  </div>
                  <div className="r5-kpi success" style={{ padding: "14px 16px" }}>
                    <div className="r5-kpi-eyebrow">Économies 25 ans</div>
                    <div style={{ fontSize: 18, fontWeight: 700, color: "var(--r5-success)", fontVariantNumeric: "tabular-nums" }}>{C.fmtCAD0(savings_25)}</div>
                    <div className="r5-kpi-meta">estimées</div>
                  </div>
                </div>
              )}
            </div>
          </section>

          {/* 03 — Véhicule(s) électrique(s) */}
          <section className="r5-form-section">
            <div className="r5-form-section-head">
              <span className="r5-form-section-num">03</span>
              <h2 className="r5-form-section-title">Véhicule(s) électrique(s)</h2>
              <span className="r5-form-section-desc">Pour le calcul V2X et la charge auto</span>
            </div>
            <div className="r5-form-card">
              <div className="r5-ev-toggle">
                <div className="r5-ev-toggle-info">
                  <div className="r5-ev-toggle-name">Le client possède un VÉ&#8239;?</div>
                  <div className="r5-ev-toggle-meta">Active pour saisir km/an et conso/100&nbsp;km</div>
                </div>
                <button type="button"
                        className={`r5-toggle-switch ${state.client.nb_ve > 0 ? "on" : ""}`}
                        onClick={() => updateClient({ nb_ve: state.client.nb_ve > 0 ? 0 : 1 })}
                        aria-pressed={state.client.nb_ve > 0}
                        aria-label="Toggle VE"></button>
              </div>
              {state.client.nb_ve > 0 && (
                <>
                  <div className="r5-field-v5" style={{ marginBottom: 16 }}>
                    <label className="r5-field-label-v5">Nombre de VÉ</label>
                    <div className="r5-pill-row">
                      {[1, 2].map(n => (
                        <button key={n} type="button"
                                className={`r5-pill ${state.client.nb_ve === n ? "selected" : ""}`}
                                onClick={() => updateClient({ nb_ve: n })}>
                          {n} véhicule{n > 1 ? "s" : ""}
                        </button>
                      ))}
                    </div>
                  </div>
                  <div className="r5-ev-grid">
                    <div className="r5-field-v5">
                      <label className="r5-field-label-v5">Km par année (par VÉ)</label>
                      <div className="r5-input-wrap-v5">
                        <input type="number" className="r5-input-v5 mono"
                               value={state.client.ev_km_per_year}
                               onChange={e => updateClient({ ev_km_per_year: parseInt(e.target.value, 10) || 0 })}
                               placeholder="20 000" />
                        <div className="r5-input-unit">km</div>
                      </div>
                    </div>
                    <div className="r5-field-v5">
                      <label className="r5-field-label-v5">Conso (kWh / 100 km)</label>
                      <div className="r5-input-wrap-v5">
                        <input type="number" className="r5-input-v5 mono"
                               value={state.client.ev_kwh_per_100km}
                               onChange={e => updateClient({ ev_kwh_per_100km: parseFloat(e.target.value) || 0 })}
                               placeholder="18" />
                        <div className="r5-input-unit">kWh</div>
                      </div>
                    </div>
                  </div>
                </>
              )}
            </div>
          </section>

          {/* 04 — N° HQ + orientation + région */}
          <section className="r5-form-section">
            <div className="r5-form-section-head">
              <span className="r5-form-section-num">04</span>
              <h2 className="r5-form-section-title">Hydro-Québec + toiture</h2>
              <span className="r5-form-section-desc">Optionnel · accélère le dépôt LogisVert</span>
            </div>
            <div className="r5-form-card">
              <div className="r5-hq-grid">
                <div className="r5-field-v5">
                  <label className="r5-field-label-v5">
                    N° client HQ <span className="r5-field-label-hint">ex. G9SJ-1234567</span>
                  </label>
                  <div className="r5-input-wrap-v5">
                    <input className={`r5-input-v5 mono ${state.client.hq_account_number && !hqOk ? "error" : ""}`}
                           value={state.client.hq_account_number}
                           onChange={e => updateClient({ hq_account_number: e.target.value })}
                           placeholder="G9SJ-1234567" />
                  </div>
                  {state.client.hq_account_number && !hqOk && (
                    <div className="r5-field-error">
                      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>
                      Format HQ invalide (ex. G9SJ-1234567)
                    </div>
                  )}
                </div>
                <div className="r5-field-v5">
                  <label className="r5-field-label-v5">N° compteur <span className="r5-field-label-hint">optionnel</span></label>
                  <div className="r5-input-wrap-v5">
                    <input className="r5-input-v5 mono" value={state.client.hq_meter_number}
                           onChange={e => updateClient({ hq_meter_number: e.target.value })}
                           placeholder="Optionnel" />
                  </div>
                </div>
                <div className="r5-field-v5" style={{ gridColumn: "1 / -1" }}>
                  <label className="r5-field-label-v5">
                    Orientation toiture <span className="r5-field-label-hint">S+SO recommandés</span>
                  </label>
                  <div className="r5-orientation">
                    {orientations.map(o => (
                      <button key={o.key} type="button"
                              className={`r5-orient-pill ${state.client.orientation === o.key ? "selected" : ""} ${o.isReco ? "recommended" : ""}`}
                              onClick={() => updateClient({ orientation: o.key })}>
                        {o.label}
                      </button>
                    ))}
                  </div>
                </div>
              </div>
            </div>
          </section>

          <div className="r5-nav-row">
            <button type="button" className="r5-btn r5-btn-secondary" onClick={onBack}>
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
              Précédent
            </button>
            <button type="button" className="r5-btn r5-btn-primary r5-btn-lg" onClick={onNext}>
              Continuer
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
            </button>
          </div>
        </div>

        {/* Right sidebar — Production NRCan */}
        <aside className="r5-prod-card">
          <div className="r5-prod-head">
            <div className="r5-prod-eyebrow">Potentiel solaire</div>
            <h3 className="r5-prod-title">{state.client.address_city || "Mascouche"}</h3>
            <div className="r5-prod-source">Source · NRCan + NASA POWER API</div>
          </div>
          <div className="r5-prod-hero">
            <div className="r5-prod-hero-label">Production annuelle estimée</div>
            <div className="r5-prod-hero-value">
              {annualProd.toLocaleString("fr-CA")}<small> kWh/an</small>
            </div>
            <div className="r5-prod-hero-meta">Pour un système de <b>{sampleKw}&nbsp;kW</b> · 1 170&nbsp;kWh/kW · orientation {state.client.orientation || "S"}</div>
          </div>
          <div className="r5-seasonal">
            <div className="r5-seasonal-title">Distribution mensuelle</div>
            <div className="r5-seasonal-bars">
              {monthlyDist.map((pct, i) => (
                <div key={i} className="r5-seasonal-bar">
                  <div className="r5-seasonal-bar-track">
                    <div className="r5-seasonal-bar-fill" style={{ height: `${(pct / 13) * 100}%` }}></div>
                  </div>
                  <div className="r5-seasonal-bar-label">{monthsLabels[i]}</div>
                </div>
              ))}
            </div>
          </div>
          <div className="r5-prod-stats">
            <div className="r5-prod-stat">
              <div className="r5-prod-stat-label">Pic été</div>
              <div className="r5-prod-stat-value">{Math.round(annualProd * 0.13).toLocaleString("fr-CA")}&nbsp;kWh/mois</div>
            </div>
            <div className="r5-prod-stat">
              <div className="r5-prod-stat-label">Couverture</div>
              <div className="r5-prod-stat-value">
                {annual_kwh_eff > 0 ? `${Math.min(150, Math.round(annualProd / annual_kwh_eff * 100))} %` : "—"}
              </div>
            </div>
            <div className="r5-prod-stat">
              <div className="r5-prod-stat-label">Tilt optimal</div>
              <div className="r5-prod-stat-value">~ 38°</div>
            </div>
            <div className="r5-prod-stat">
              <div className="r5-prod-stat-label">GES évités</div>
              <div className="r5-prod-stat-value">{(annualProd * 0.000688).toFixed(1).replace(".", ",")}&nbsp;t/an</div>
            </div>
          </div>
        </aside>
      </div>
    );
  }

  // ============================================================================
  // V3-E : Step4Batterie — Sous-composant pour project_type="batterie" (tout-en-un sans solaire)
  // Exclusif Tesla / Fox AIO / Fox H1 / Sigenergy — pas de toiture/pente/panneaux
  // ============================================================================
  function Step4Batterie({ state, setState, calc, updateSolar, D, C }) {
    const brand = state.solar.battery_brand || "fox_aio";
    const pw_count = Math.max(1, Math.min(3, state.solar.pw_count || 1));
    const dc_exp = state.solar.dc_expansions || 0;
    const sig_kwh = state.solar.sig_battery_kwh || 9;
    const sig_qty = state.solar.sig_battery_qty || 2;
    const isFox = brand === "fox_aio" || brand === "fox_h1";

    const bcalc = calc?.batteryOnlyCalc;
    const fmt = (v) => C.fmtCAD0(v).replace(/\s/g, " ");

    const CheckSvg = (
      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
    );
    const InfoSvg = (
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
    );

    // Brands definition
    const brands = [
      {
        key: "tesla", mark: "TESLA", name: "Powerwall 3",
        match: (b) => b === "tesla",
        tagline: "Backup whole-home automatique jusqu'à 200 A. Gateway 3 incluse.",
        specs: [
          { label: "Capacité", val: "13,5 kWh" },
          { label: "Sortie", val: "11,5 kW" },
          { label: "Garantie", val: "10 ans" }
        ],
        onSelect: () => updateSolar({ battery_brand: "tesla", battery_subsystem: null, battery_bundle_id: null })
      },
      {
        key: "fox", mark: "FOX ESS", name: "AIO / H1 Hybrid",
        match: (b) => b === "fox_aio" || b === "fox_h1",
        tagline: "Compact tout-en-un ou hybride modulaire. Idéal petits espaces.",
        specs: [
          { label: "Capacité", val: "10–23 kWh" },
          { label: "Sortie", val: "9,6–11,4 kW" },
          { label: "Garantie", val: "10 ans" }
        ],
        onSelect: () => updateSolar({ battery_brand: "fox_aio", battery_subsystem: "aio", battery_bundle_id: "aio-114-4eq" })
      },
      {
        key: "sig", mark: "SIGENERGY", name: "SigenStor",
        match: (b) => b === "sig",
        badge: "V2X",
        tagline: "Modulaire empilable jusqu'à 48 kWh. Compatible V2X borne.",
        specs: [
          { label: "Capacité", val: "6–48 kWh" },
          { label: "Sortie", val: "6–12 kW" },
          { label: "Modules", val: "1–8" }
        ],
        onSelect: () => updateSolar({ battery_brand: "sig", battery_subsystem: null, battery_bundle_id: null })
      }
    ];

    // Qty stepper helper
    const QtyStepper = ({ value, min, max, onChange }) => (
      <div className="r5-qty">
        <button type="button" onClick={() => onChange(Math.max(min, value - 1))} disabled={value <= min} aria-label="Diminuer">−</button>
        <div className="r5-qty-display">{value}</div>
        <button type="button" onClick={() => onChange(Math.min(max, value + 1))} disabled={value >= max} aria-label="Augmenter">+</button>
      </div>
    );

    return (
      <>
        <div className="r5-step-intro">
          <div className="r5-step-eyebrow"><span className="r5-dot"></span>Étape 4 sur 6 · Tout-en-un (batterie seule)</div>
          <h1>Choisissez votre système de batterie.</h1>
          <p>Un seul fabricant par projet. Tesla pour le whole-home backup automatique, Fox ESS pour la compacité, Sigenergy pour la modularité et le V2X.</p>
        </div>

        {/* 01 — Brand selection */}
        <section className="r5-form-section">
          <div className="r5-form-section-head">
            <span className="r5-form-section-num">01</span>
            <h2 className="r5-form-section-title">Fabricant</h2>
            <span className="r5-form-section-desc">Choix exclusif</span>
          </div>
          <div className="r5-batt-brand-grid">
            {brands.map(b => {
              const isSelected = b.match(brand);
              return (
                <button key={b.key} type="button"
                        className={`r5-batt-brand ${isSelected ? "selected" : ""}`}
                        onClick={b.onSelect}
                        aria-pressed={isSelected}>
                  {b.badge && !isSelected && <div className="r5-batt-brand-badge">{b.badge}</div>}
                  <div className="r5-batt-brand-check">{CheckSvg}</div>
                  <div className="r5-batt-brand-mark">{b.mark}</div>
                  <div className="r5-batt-brand-name">{b.name}</div>
                  <div className="r5-batt-brand-tagline">{b.tagline}</div>
                  <div className="r5-batt-brand-specs">
                    {b.specs.map((s, i) => (
                      <div key={i}>
                        <div className="r5-batt-brand-spec-label">{s.label}</div>
                        <div className="r5-batt-brand-spec-value">{s.val}</div>
                      </div>
                    ))}
                  </div>
                </button>
              );
            })}
          </div>
        </section>

        {/* 02 — Brand-specific config */}
        <section className="r5-form-section">
          <div className="r5-form-section-head">
            <span className="r5-form-section-num">02</span>
            <h2 className="r5-form-section-title">
              {brand === "tesla" && "Configuration Tesla"}
              {isFox && "Configuration Fox ESS"}
              {brand === "sig" && "Configuration Sigenergy"}
            </h2>
            <span className="r5-form-section-desc">
              {brand === "tesla" && "Powerwall + Expansions DC"}
              {isFox && "Sous-système + bundle"}
              {brand === "sig" && "Modules + LoadHub"}
            </span>
          </div>

          <div className="r5-config-card">
            {/* TESLA */}
            {brand === "tesla" && (
              <>
                <div className="r5-config-row">
                  <div className="r5-config-row-head">
                    <div className="r5-config-row-label">Nombre de Powerwall&nbsp;3</div>
                    <div className="r5-config-row-hint">Onduleur intégré · backup automatique · max 3</div>
                  </div>
                  <QtyStepper value={pw_count} min={1} max={3} onChange={(v) => updateSolar({ pw_count: v })} />
                </div>

                <div className="r5-config-row">
                  <div className="r5-config-row-head">
                    <div className="r5-config-row-label">Expansions DC par Powerwall</div>
                    <div className="r5-config-row-hint">+13,5 kWh chacune · max 3 par PW · +9 750 $ matériel + 1 195 $ install</div>
                  </div>
                  <div className="r5-pw-units">
                    {Array.from({ length: pw_count }).map((_, i) => (
                      <div className="r5-pw-unit" key={i}>
                        <div className="r5-pw-icon"></div>
                        <div className="r5-pw-info">
                          <div className="r5-pw-name">Powerwall&nbsp;#{i + 1}</div>
                          <div className="r5-pw-meta">13,5 kWh · 11,5 kW · {dc_exp} expansion{dc_exp > 1 ? "s" : ""} DC</div>
                        </div>
                        <QtyStepper value={dc_exp} min={0} max={3} onChange={(v) => updateSolar({ dc_expansions: v })} />
                      </div>
                    ))}
                  </div>
                </div>

                <div className="r5-config-row">
                  <div className="r5-config-row-head">
                    <div className="r5-config-row-label">Mode de backup</div>
                    <div className="r5-config-row-hint">Gateway&nbsp;3 incluse · sélection requise</div>
                  </div>
                  <div className="r5-backup-grid">
                    <button type="button"
                            className={`r5-backup-card ${state.solar.backup_mode === "none" ? "selected" : ""}`}
                            onClick={() => updateSolar({ backup_mode: "none" })}>
                      <div className="r5-backup-card-title">Aucun backup</div>
                      <div className="r5-backup-card-desc">Optimisation tarifaire seulement. Charge HP, décharge HC.</div>
                      <div className="r5-backup-card-price">+ 0 $</div>
                    </button>
                    <button type="button"
                            className={`r5-backup-card ${state.solar.backup_mode === "partial" ? "selected" : ""}`}
                            onClick={() => updateSolar({ backup_mode: "partial" })}>
                      <div className="r5-backup-card-title">Backup partiel</div>
                      <div className="r5-backup-card-desc">Sub-panel charges critiques : frigo, chauffage, prises essentielles.</div>
                      <div className="r5-backup-card-price">+ 1 344 $</div>
                    </button>
                    <button type="button"
                            className={`r5-backup-card ${state.solar.backup_mode === "whole_home" ? "selected" : ""}`}
                            onClick={() => updateSolar({ backup_mode: "whole_home" })}>
                      <div className="r5-backup-card-title">Full Home Backup</div>
                      <div className="r5-backup-card-desc">Gateway&nbsp;3 commute toute la maison automatiquement jusqu'à 200&nbsp;A.</div>
                      <div className="r5-backup-card-price">+ 1 680 $</div>
                    </button>
                  </div>
                </div>

                <div className="r5-info-banner">
                  {InfoSvg}
                  <div>
                    <strong>Pourquoi Full Home Backup</strong> · Seul Tesla offre la commutation automatique de toute la maison. Le client n'a rien à faire — le Gateway&nbsp;3 détecte la panne et bascule en moins de 100&nbsp;ms.
                  </div>
                </div>
              </>
            )}

            {/* FOX ESS */}
            {isFox && (
              <>
                <div className="r5-config-row">
                  <div className="r5-config-row-head">
                    <div className="r5-config-row-label">Sous-système Fox ESS</div>
                    <div className="r5-config-row-hint">Ne JAMAIS mélanger EQ4000 (AIO) avec CM/CS (H1 Hybrid)</div>
                  </div>
                  <div className="r5-grid r5-grid-2">
                    <button type="button"
                            className={`r5-backup-card ${brand === "fox_aio" ? "selected" : ""}`}
                            onClick={() => updateSolar({ battery_brand: "fox_aio", battery_subsystem: "aio", battery_bundle_id: "aio-114-4eq" })}>
                      <div className="r5-backup-card-title">AIO — All-in-One</div>
                      <div className="r5-backup-card-desc">Onduleur H1-AIO Flex + modules <b>EQ4000</b> empilables (1-6 modules = 4-23 kWh).</div>
                    </button>
                    <button type="button"
                            className={`r5-backup-card ${brand === "fox_h1" ? "selected" : ""}`}
                            onClick={() => updateSolar({ battery_brand: "fox_h1", battery_subsystem: "h1_hybrid", battery_bundle_id: "h1-114-1cm-3cs" })}>
                      <div className="r5-backup-card-title">H1 Hybrid 2.0</div>
                      <div className="r5-backup-card-desc">Onduleur H1 + <b>CM4000</b> obligatoire + N×CS4000 (1-7) + Hub G2 + Inverter Kit.</div>
                    </button>
                  </div>
                </div>

                <div className="r5-config-row">
                  <div className="r5-config-row-head">
                    <div className="r5-config-row-label">Configuration (bundle)</div>
                    <div className="r5-config-row-hint">Capacité kWh + prix vendant</div>
                  </div>
                  <div className="r5-grid" style={{ gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))" }}>
                    {(brand === "fox_aio" ? D.fox_ess.aio.bundles : D.fox_ess.h1_hybrid.bundles).map(b => (
                      <button key={b.id} type="button"
                              className={`r5-backup-card ${state.solar.battery_bundle_id === b.id ? "selected" : ""}`}
                              onClick={() => updateSolar({ battery_bundle_id: b.id })}>
                        <div className="r5-backup-card-title">{b.label}</div>
                        <div className="r5-backup-card-desc">{b.kwh} kWh utilisables</div>
                        <div className="r5-backup-card-price">{C.fmtCAD0(b.sell)}</div>
                      </button>
                    ))}
                  </div>
                </div>

                <div className="r5-config-row">
                  <div className="r5-config-row-head">
                    <div className="r5-config-row-label">Mode de backup</div>
                    <div className="r5-config-row-hint">{brand === "fox_aio" ? "AIO : DIM intégré" : "H1 Hybrid : Hub G2 inclus dans bundle"}</div>
                  </div>
                  <div className="r5-backup-grid">
                    <button type="button"
                            className={`r5-backup-card ${state.solar.backup_mode === "none" ? "selected" : ""}`}
                            onClick={() => updateSolar({ backup_mode: "none" })}>
                      <div className="r5-backup-card-title">Aucun backup</div>
                      <div className="r5-backup-card-desc">TOU / peak shaving sans backup en panne.</div>
                    </button>
                    <button type="button"
                            className={`r5-backup-card ${state.solar.backup_mode === "partial" ? "selected" : ""}`}
                            onClick={() => updateSolar({ backup_mode: "partial" })}>
                      <div className="r5-backup-card-title">Backup partiel</div>
                      <div className="r5-backup-card-desc">Sub-panel charges critiques uniquement.</div>
                    </button>
                    <button type="button" disabled aria-disabled="true"
                            className="r5-backup-card"
                            title="Full home backup réservé Tesla">
                      <div className="r5-backup-card-title">Full Home Backup</div>
                      <div className="r5-backup-card-desc">Réservé Tesla Powerwall&nbsp;3.</div>
                    </button>
                  </div>
                </div>
              </>
            )}

            {/* SIGENERGY */}
            {brand === "sig" && (
              <>
                <div className="r5-config-row">
                  <div className="r5-config-row-head">
                    <div className="r5-config-row-label">Capacité par module batterie</div>
                    <div className="r5-config-row-hint">Tout le système doit utiliser le même format</div>
                  </div>
                  <div className="r5-pill-row">
                    <button type="button" className={`r5-pill ${sig_kwh === 6 ? "selected" : ""}`} onClick={() => updateSolar({ sig_battery_kwh: 6 })}>
                      SIG-BAT-6 · 6 kWh · 3&#8239;765 $
                    </button>
                    <button type="button" className={`r5-pill ${sig_kwh === 9 ? "selected" : ""}`} onClick={() => updateSolar({ sig_battery_kwh: 9 })}>
                      SIG-BAT-9 · 9 kWh · 4&#8239;939 $
                    </button>
                  </div>
                </div>

                <div className="r5-config-row">
                  <div className="r5-config-row-head">
                    <div className="r5-config-row-label">Nombre de modules (1–8)</div>
                    <div className="r5-config-row-hint">Capacité totale : <strong>{sig_qty * sig_kwh}&nbsp;kWh</strong></div>
                  </div>
                  <QtyStepper value={sig_qty} min={1} max={8} onChange={(v) => updateSolar({ sig_battery_qty: v })} />
                </div>

                <div className="r5-config-row">
                  <div className="r5-config-row-head">
                    <div className="r5-config-row-label">LoadHub Sigenergy (DIM 200&nbsp;A)</div>
                    <div className="r5-config-row-hint">Recommandé pour optimisation tarifaire + V2X</div>
                  </div>
                  <div className="r5-pill-row">
                    <button type="button" className={`r5-pill ${state.solar.with_dim ? "selected" : ""}`} onClick={() => updateSolar({ with_dim: true })}>
                      Avec LoadHub
                    </button>
                    <button type="button" className={`r5-pill ${!state.solar.with_dim ? "selected" : ""}`} onClick={() => updateSolar({ with_dim: false })}>
                      Sans LoadHub
                    </button>
                  </div>
                </div>

                <div className="r5-config-row">
                  <div className="r5-config-row-head">
                    <div className="r5-config-row-label">Mode de backup</div>
                    <div className="r5-config-row-hint">Aucun ou partiel · Full home réservé Tesla</div>
                  </div>
                  <div className="r5-backup-grid">
                    <button type="button"
                            className={`r5-backup-card ${state.solar.backup_mode === "none" ? "selected" : ""}`}
                            onClick={() => updateSolar({ backup_mode: "none" })}>
                      <div className="r5-backup-card-title">Aucun backup</div>
                      <div className="r5-backup-card-desc">TOU / peak shaving.</div>
                    </button>
                    <button type="button"
                            className={`r5-backup-card ${state.solar.backup_mode === "partial" ? "selected" : ""}`}
                            onClick={() => updateSolar({ backup_mode: "partial" })}>
                      <div className="r5-backup-card-title">Backup partiel</div>
                      <div className="r5-backup-card-desc">Sub-panel charges critiques.</div>
                    </button>
                    <button type="button" disabled aria-disabled="true" className="r5-backup-card">
                      <div className="r5-backup-card-title">Full Home Backup</div>
                      <div className="r5-backup-card-desc">Réservé Tesla.</div>
                    </button>
                  </div>
                </div>
              </>
            )}
          </div>
        </section>

        {/* Récap matériel (preview inline si pas de sidebar) */}
        {bcalc && bcalc.sell > 0 && (
          <div className="r5-card" style={{ marginTop: 24 }}>
            <div className="r5-card-head">
              <h3 className="r5-card-title">Récap matériel — détail</h3>
              <span className="r5-tag r5-tag-info">Auto-calculé</span>
            </div>
            {bcalc.breakdown.map((b, i) => (
              <div className="r5-preview-item" key={i}>
                <div className="r5-preview-item-key">{b.label}{b.qty > 1 ? ` × ${b.qty}` : ""}</div>
                <div className="r5-preview-item-val">{fmt(b.sell)}</div>
              </div>
            ))}
            <div className="r5-preview-item" style={{ borderTop: "1px solid var(--r5-line)", paddingTop: 10, marginTop: 6, borderBottom: "none" }}>
              <div className="r5-preview-item-key" style={{ fontWeight: 700, color: "var(--r5-ink)" }}>Sous-total matériel batterie</div>
              <div className="r5-preview-item-val" style={{ fontSize: 16 }}>{fmt(bcalc.sell)}</div>
            </div>
            {calc?.forfait && (
              <div className="r5-preview-item">
                <div className="r5-preview-item-key">{calc.forfait.code} · {calc.forfait.label}<small>Forfait d'installation auto</small></div>
                <div className="r5-preview-item-val">{fmt(calc.forfait.sell)}</div>
              </div>
            )}
          </div>
        )}
      </>
    );
  }

  // ============================================================================
  // STEP 4 : CONFIGURATION SOLAIRE — LA CRITIQUE (étages + pente + panneaux + bons increments)
  // ============================================================================
  function Step4Config({ state, setState, calc, onBack, onNext }) {
    const D = window.RAYCOM_DATA_2026;
    const C = window.RAYCAST_CALC_2026;
    const updateSolar = (patch) => setState({ ...state, solar: { ...state.solar, ...patch } });
    const updateBorne = (patch) => setState({ ...state, borne: { ...state.borne, ...patch } });

    const solarCalc = calc?.solarCalc;
    const isBorneOnly = state.project_type === "borne";
    const isBatteryOnly = state.project_type === "batterie";
    const showSolarSection = !isBorneOnly && !isBatteryOnly;

    // P8-B : départ à 0 $ — à l'arrivée sur l'étape 4 config solaire, si rien n'est encore
    // configuré (panneaux=0), on pré-remplit un défaut raisonnable (20 panneaux + onduleur).
    // Le total reste donc à 0 $ aux étapes 1-3, puis devient un vrai montant ici.
    useEffect(() => {
      if (showSolarSection && !state.solar._configured && (state.solar.panneaux || 0) === 0) {
        const patch = { panneaux: 20, _configured: true };
        if (state.project_type === "solaire_batterie" && state.solar.battery_brand === "none") {
          patch.battery_brand = "fox_aio"; patch.battery_subsystem = "aio"; patch.battery_bundle_id = "aio-114-4eq"; patch.with_dim = true;
        }
        setState({ ...state, solar: { ...state.solar, ...patch } });
      }
      if (isBatteryOnly && !state.solar._configured && state.solar.battery_brand === "none") {
        setState({ ...state, solar: { ...state.solar, battery_brand: "fox_aio", battery_subsystem: "aio", battery_bundle_id: "aio-114-4eq", _configured: true } });
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    // V3 : pas de kits préconfigurés — slider 4-50 kW par 0,5 kW
    // Panneau Thornova BBT54 500W → 1 panneau = 0,5 kW, donc 8 à 100 panneaux
    const pitchCol = C.pitchKeyToExcelCol(state.solar.pitch_key);
    const currentKw = (state.solar.panneaux || 0) * 0.5;
    // Prix indicatif à la pente actuelle pour les paliers proches
    const palierExact = D.solar_table_vendant.find(p => p.panneaux === state.solar.panneaux);
    const indicativePrice = palierExact ? palierExact[pitchCol] : null;

    // V5 helpers
    const panneaux = state.solar.panneaux || 5;
    const watts = panneaux * 500;
    const rangePct = Math.round(((panneaux - 5) / (80 - 5)) * 100);
    // Production estim 1170 kWh/kW/an Mascouche, ajustée par solarCalc si dispo
    const productionAnnuelle = calc?.production || Math.round(currentKw * 1170);
    const annualKwh = state.client?.annual_hq_kwh || 0;
    const coverage = annualKwh > 0 ? Math.min(150, Math.round((productionAnnuelle / annualKwh) * 100)) : 0;
    const logisVert = calc?.logisvert || 0;
    const ges = productionAnnuelle * 0.000688; // tonnes CO2/an

    // V5 SVG roof icons
    const roofIcons = {
      bardeau: <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12l9-9 9 9"/><path d="M5 10v10h14V10"/></svg>,
      metal: <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M2 12 L12 4 L22 12"/><path d="M4 10 L4 20 L20 20 L20 10"/><path d="M8 14 L8 20 M12 14 L12 20 M16 14 L16 20"/></svg>,
      tpo: <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 8 L21 8 L21 16 L3 16 Z"/><path d="M6 8 L6 16 M10 8 L10 16 M14 8 L14 16 M18 8 L18 16"/></svg>,
      epdm: <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 7 L21 7 L21 17 L3 17 Z"/><path d="M3 12 L21 12"/></svg>,
      beton: <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="6" width="18" height="12" rx="1"/><path d="M3 12 L21 12 M9 6 L9 18 M15 6 L15 18"/></svg>,
      ground: <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 20 L21 20"/><path d="M6 16 L10 8 L14 16"/><path d="M14 16 L18 10 L22 16"/></svg>
    };

    return (
      <div>
        <div className="r5-step-intro">
          <div className="r5-step-eyebrow"><span className="r5-dot"></span>Étape 4 sur 6 · {
            isBorneOnly ? "Borne de recharge"
            : isBatteryOnly ? "Tout-en-un (batterie seule)"
            : "Configuration du système solaire"
          }</div>
          <h1>
            {isBorneOnly && "Configuration de la borne EV"}
            {isBatteryOnly && "Choisissez votre système de batterie."}
            {showSolarSection && (state.project_type === "solaire" ? "Combien de panneaux solaires ?" : "Solaire + Batterie · combien ?")}
          </h1>
          <p>
            {isBorneOnly && "Modèle, type de câblage, longueur — combinez plusieurs câbles au besoin."}
            {isBatteryOnly && "Un seul fabricant par projet. Choix exclusif Tesla / Fox / Sigenergy."}
            {showSolarSection && "Le prix se met à jour en temps réel selon le nombre de panneaux Thornova 500 W. Panneau de référence non modifiable."}
          </p>
        </div>

        {/* === V3-E : TOUT-EN-UN (batterie sans solaire) === */}
        {isBatteryOnly && (
          <Step4Batterie state={state} setState={setState} calc={calc} updateSolar={updateSolar} D={D} C={C} />
        )}

        {/* === SOLAIRE V5 === */}
        {showSolarSection && (
          <>
            {/* 01 — Slider hero panneaux */}
            <section className="r5-form-section">
              <div className="r5-form-section-head">
                <span className="r5-form-section-num">01</span>
                <h2 className="r5-form-section-title">Puissance solaire</h2>
                <span className="r5-form-section-desc">Slider 5 à 80 panneaux Thornova 500&nbsp;W</span>
              </div>
              <div className="r5-slider-hero">
                <div className="r5-slider-hero-grid">
                  <div className="r5-slider-hero-value">
                    <div className="r5-slider-hero-number">{panneaux}</div>
                    <div className="r5-slider-hero-unit">
                      panneaux
                      <small>{currentKw.toFixed(1).replace(".", ",")}&nbsp;kW DC · {watts.toLocaleString("fr-CA")}&nbsp;W</small>
                    </div>
                  </div>
                  <div className="r5-slider-hero-side">
                    <div className="r5-slider-hero-side-label">Prix indicatif</div>
                    <div className="r5-slider-hero-side-value">{indicativePrice ? C.fmtCAD0(indicativePrice) : "—"}</div>
                    <div className="r5-slider-hero-side-meta">Solaire pur · sans onduleur ni forfait install</div>
                  </div>
                </div>
                <div className="r5-range-wrap">
                  <input
                    type="range"
                    className="r5-range"
                    min={5} max={80} step={1}
                    value={panneaux}
                    onChange={e => updateSolar({ panneaux: parseInt(e.target.value, 10) })}
                    style={{ "--r5-val": `${rangePct}%`, "--val": `${rangePct}%` }}
                  />
                  <div className="r5-range-ticks">
                    <span>5</span><span>20</span><span>40</span><span>60</span><span>80</span>
                  </div>
                </div>
                {/* 4 production stats live */}
                <div className="r5-production-bar">
                  <div className="r5-production-stat">
                    <div className="r5-production-stat-label">Production / an</div>
                    <div className="r5-production-stat-value">{productionAnnuelle.toLocaleString("fr-CA")}&nbsp;kWh</div>
                    <div className="r5-production-stat-meta">NRCan Mascouche</div>
                  </div>
                  <div className="r5-production-stat">
                    <div className="r5-production-stat-label">Couverture HQ</div>
                    <div className="r5-production-stat-value">{annualKwh > 0 ? `${coverage} %` : "—"}</div>
                    <div className="r5-production-stat-meta">{annualKwh > 0 ? `${annualKwh.toLocaleString("fr-CA")} kWh/an` : "Conso non saisie"}</div>
                  </div>
                  <div className="r5-production-stat">
                    <div className="r5-production-stat-label">Subv. LogisVert</div>
                    <div className="r5-production-stat-value">{logisVert > 0 ? C.fmtCAD0(logisVert) : "—"}</div>
                    <div className="r5-production-stat-meta">1 000 $/kW · plafond 40 %</div>
                  </div>
                  <div className="r5-production-stat">
                    <div className="r5-production-stat-label">GES évités</div>
                    <div className="r5-production-stat-value">{ges.toFixed(1).replace(".", ",")}&nbsp;t/an</div>
                    <div className="r5-production-stat-meta">≈ {Math.round(ges / 4.6)} voiture(s)</div>
                  </div>
                </div>
              </div>
              {solarCalc?.warnings?.length > 0 && (
                <div className="r5-alert warning">
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
                  <div>
                    <strong>Avertissements</strong>
                    <ul>{solarCalc.warnings.map((w, i) => <li key={i}>{w}</li>)}</ul>
                  </div>
                </div>
              )}
              {solarCalc?.errors?.length > 0 && (
                <div className="r5-alert error">
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>
                  <div>
                    <strong>Configuration bloquée — sur soumission ad hoc</strong>
                    <ul>{solarCalc.errors.map((e, i) => <li key={i}>{e}</li>)}</ul>
                  </div>
                </div>
              )}
            </section>

            {/* 02 — Toiture grid */}
            <section className="r5-form-section">
              <div className="r5-form-section-head">
                <span className="r5-form-section-num">02</span>
                <h2 className="r5-form-section-title">Type de toiture</h2>
                <span className="r5-form-section-desc">Bardeau / métal couverts · membrane sur soumission</span>
              </div>
              <div className="r5-roof-grid">
                {D.roof_types.map(r => {
                  const isBlocked = r.requires_quote;
                  const isWarning = !isBlocked && r.warning;
                  const isSelected = state.solar.roof_type === r.key;
                  const cls = `r5-roof-card ${isSelected ? "selected" : ""} ${isWarning ? "warning" : ""} ${isBlocked ? "blocked" : ""}`;
                  return (
                    <button key={r.key} type="button"
                            className={cls}
                            onClick={() => !isBlocked && updateSolar({ roof_type: r.key })}
                            disabled={isBlocked}>
                      <div className="r5-roof-icon">{roofIcons[r.key] || roofIcons.bardeau}</div>
                      <div className="r5-roof-card-info">
                        <div className="r5-roof-card-name">{r.label}</div>
                        <div className="r5-roof-card-meta">{isBlocked ? "Sur soumission" : isWarning ? "Visite technique requise" : r.sub}</div>
                      </div>
                    </button>
                  );
                })}
              </div>
            </section>

            {/* 03 — Pente + Étages double-block */}
            <section className="r5-form-section">
              <div className="r5-form-section-head">
                <span className="r5-form-section-num">03</span>
                <h2 className="r5-form-section-title">Pente et étages</h2>
                <span className="r5-form-section-desc">Impact direct sur le prix au watt</span>
              </div>
              <div className="r5-config-double">
                <div>
                  <div className="r5-config-block-head">
                    <span className="r5-config-block-label">Pente du toit</span>
                    <span className="r5-config-block-hint">Plat → grille p1 · Forte → p2 · Très forte → p3</span>
                  </div>
                  <div className="r5-pill-row" style={{ flexWrap: "wrap" }}>
                    {D.pitch_brackets_ui.map(p => (
                      <button key={p.key} type="button"
                              className={`r5-pill ${state.solar.pitch_key === p.key ? "selected" : ""}`}
                              onClick={() => updateSolar({ pitch_key: p.key })}>
                        {p.label} <span style={{ fontSize: 10, color: "var(--r5-ink-5)", marginLeft: 4 }}>{p.ratio}</span>
                      </button>
                    ))}
                  </div>
                </div>
                <div>
                  <div className="r5-config-block-head">
                    <span className="r5-config-block-label">Nombre d'étages</span>
                    <span className="r5-config-block-hint">+0,10&nbsp;$/W par étage au-delà de 2</span>
                  </div>
                  <div className="r5-qty">
                    <button type="button" onClick={() => updateSolar({ floors: Math.max(1, (state.solar.floors || 2) - 1) })} disabled={(state.solar.floors || 2) <= 1}>−</button>
                    <div className="r5-qty-display">{state.solar.floors || 2}</div>
                    <button type="button" onClick={() => updateSolar({ floors: Math.min(4, (state.solar.floors || 2) + 1) })} disabled={(state.solar.floors || 2) >= 4}>+</button>
                  </div>
                </div>
              </div>
            </section>

            {/* 04 — Onduleur (Fox / Sig / Tesla) */}
            <section className="r5-form-section">
              <div className="r5-form-section-head">
                <span className="r5-form-section-num">04</span>
                <h2 className="r5-form-section-title">Onduleur</h2>
                <span className="r5-form-section-desc">
                  {state.project_type === "solaire" ? "Tesla exclu pour solaire seul" : "Choix exclusif"}
                </span>
              </div>
              <div className="r5-ond-grid">
                <button type="button"
                        className={`r5-ond-card ${(state.solar.battery_brand === "fox_aio" || state.solar.battery_brand === "fox_h1") ? "selected" : ""}`}
                        onClick={() => updateSolar({ battery_brand: state.solar.battery_subsystem === "h1_hybrid" ? "fox_h1" : "fox_aio", battery_subsystem: state.solar.battery_subsystem || "aio", battery_bundle_id: state.solar.battery_bundle_id || (state.solar.battery_subsystem === "h1_hybrid" ? "h1-114-1cm-3cs" : "aio-114-4eq") })}>
                  <div className="r5-ond-card-brand">FOX ESS</div>
                  <div className="r5-ond-card-name">H1 Hybrid 11,4 kW</div>
                  <div className="r5-ond-card-meta">Auto ProJoy + dongle WiFi · AIO ou H1 Hybrid</div>
                </button>
                <button type="button"
                        className={`r5-ond-card ${state.solar.battery_brand === "sig" ? "selected" : ""}`}
                        onClick={() => updateSolar({ battery_brand: "sig", battery_subsystem: null })}>
                  <div className="r5-ond-card-brand">SIGENERGY</div>
                  <div className="r5-ond-card-name">SigenStor 11,5 kW</div>
                  <div className="r5-ond-card-meta">Auto Rapid Shutdown · V2X compatible · modulaire</div>
                </button>
                {state.project_type === "solaire" ? (
                  <button type="button" className="r5-ond-card locked" disabled aria-disabled="true" title="Tesla exclu pour solaire seul">
                    <div className="r5-ond-card-lock">
                      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
                    </div>
                    <div className="r5-ond-card-brand">TESLA</div>
                    <div className="r5-ond-card-name">Powerwall 3</div>
                    <div className="r5-ond-card-meta">Réservé "Solaire + batterie" ou "Tout-en-un"</div>
                  </button>
                ) : (
                  <button type="button"
                          className={`r5-ond-card ${state.solar.battery_brand === "tesla" ? "selected" : ""}`}
                          onClick={() => updateSolar({ battery_brand: "tesla", battery_subsystem: null })}>
                    <div className="r5-ond-card-brand">TESLA</div>
                    <div className="r5-ond-card-name">Powerwall 3</div>
                    <div className="r5-ond-card-meta">PW3 + Gateway 3 · 11,5 kW · 13,5 kWh/PW · MCI auto si solaire</div>
                  </button>
                )}
                {state.project_type === "solaire" && (
                  <button type="button"
                          className={`r5-ond-card ${state.solar.battery_brand === "none" ? "selected" : ""}`}
                          onClick={() => updateSolar({ battery_brand: "none", battery_subsystem: null, backup_mode: "none" })}>
                    <div className="r5-ond-card-brand">SOLAIRE PUR</div>
                    <div className="r5-ond-card-name">Sans batterie</div>
                    <div className="r5-ond-card-meta">Mesurage net seul · pas de backup en panne</div>
                  </button>
                )}
              </div>

              {/* Sous-chooser Fox AIO vs H1 */}
              {(state.solar.battery_brand === "fox_aio" || state.solar.battery_brand === "fox_h1") && (
                <div style={{ marginTop: 14 }}>
                  <div className="r5-config-block-head">
                    <span className="r5-config-block-label">Fox ESS — sous-système</span>
                    <span className="r5-config-block-hint">⚠️ Ne JAMAIS mélanger EQ4000 et CM/CS</span>
                  </div>
                  <div className="r5-config-double">
                    <button type="button"
                            className={`r5-ond-card ${state.solar.battery_brand === "fox_aio" ? "selected" : ""}`}
                            onClick={() => updateSolar({ battery_brand: "fox_aio", battery_subsystem: "aio", battery_bundle_id: "aio-114-4eq" })}>
                      <div className="r5-ond-card-brand">AIO</div>
                      <div className="r5-ond-card-name">All-in-One Flex</div>
                      <div className="r5-ond-card-meta">Onduleur H1-AIO + modules EQ4000 (1-6 = 4-23 kWh) · BMS intégré</div>
                    </button>
                    <button type="button"
                            className={`r5-ond-card ${state.solar.battery_brand === "fox_h1" ? "selected" : ""}`}
                            onClick={() => updateSolar({ battery_brand: "fox_h1", battery_subsystem: "h1_hybrid" })}>
                      <div className="r5-ond-card-brand">H1 HYBRID 2.0</div>
                      <div className="r5-ond-card-name">Modulaire CM + CS</div>
                      <div className="r5-ond-card-meta">CM4000 + 1-7×CS4000 + Hub G2 + Inverter Kit · jusqu'à 32 kWh</div>
                    </button>
                  </div>
                </div>
              )}

              {/* Capacité / unités batterie (solaire + batterie) — corrige C1/C2 : la batterie est chiffrée */}
              {state.solar.battery_brand === "tesla" && (
                <div style={{ marginTop: 14 }}>
                  <div className="r5-config-block-head">
                    <span className="r5-config-block-label">Capacité Tesla</span>
                    <span className="r5-config-block-hint">13,5 kWh / Powerwall · onduleur intégré · max 4 PW + 3 exp.</span>
                  </div>
                  <div className="r5-pill-row">
                    <span style={{ fontSize: 12, color: "var(--r5-ink-4)", alignSelf: "center", marginRight: 6 }}>Powerwall 3 :</span>
                    {[1, 2, 3, 4].map(n => (
                      <button key={n} type="button" className={`r5-pill ${(state.solar.pw_count || 1) === n ? "selected" : ""}`}
                              onClick={() => updateSolar({ pw_count: n })}>{n}</button>
                    ))}
                  </div>
                  <div className="r5-pill-row" style={{ marginTop: 8 }}>
                    <span style={{ fontSize: 12, color: "var(--r5-ink-4)", alignSelf: "center", marginRight: 6 }}>Expansions DC / PW :</span>
                    {[0, 1, 2, 3].map(n => (
                      <button key={n} type="button" className={`r5-pill ${(state.solar.dc_expansions || 0) === n ? "selected" : ""}`}
                              onClick={() => updateSolar({ dc_expansions: n })}>{n}</button>
                    ))}
                  </div>
                </div>
              )}
              {(state.solar.battery_brand === "fox_aio" || state.solar.battery_brand === "fox_h1") && (
                <div style={{ marginTop: 14 }}>
                  <div className="r5-config-block-head">
                    <span className="r5-config-block-label">Capacité Fox — {state.solar.battery_brand === "fox_aio" ? "modules EQ4000" : "CM4000 + CS4000"}</span>
                    <span className="r5-config-block-hint">Choisir la capacité (kWh)</span>
                  </div>
                  <div className="r5-grid" style={{ gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))" }}>
                    {(state.solar.battery_brand === "fox_aio" ? D.fox_ess.aio.bundles : D.fox_ess.h1_hybrid.bundles).map(b => (
                      <button key={b.id} type="button"
                              className={`r5-ond-card ${state.solar.battery_bundle_id === b.id ? "selected" : ""}`}
                              onClick={() => updateSolar({ battery_bundle_id: b.id })}>
                        <div className="r5-ond-card-name">{b.label}</div>
                        <div className="r5-ond-card-meta">{b.kwh} kWh · {C.fmtCAD0(b.sell)}</div>
                      </button>
                    ))}
                  </div>
                </div>
              )}
              {state.solar.battery_brand === "sig" && (
                <div style={{ marginTop: 14 }}>
                  <div className="r5-config-block-head">
                    <span className="r5-config-block-label">Capacité Sigenergy</span>
                    <span className="r5-config-block-hint">Modules 6 ou 9 kWh · 1 à 6 par colonne</span>
                  </div>
                  <div className="r5-pill-row">
                    <span style={{ fontSize: 12, color: "var(--r5-ink-4)", alignSelf: "center", marginRight: 6 }}>Module :</span>
                    <button type="button" className={`r5-pill ${(state.solar.sig_battery_kwh || 9) === 6 ? "selected" : ""}`} onClick={() => updateSolar({ sig_battery_kwh: 6 })}>6 kWh</button>
                    <button type="button" className={`r5-pill ${(state.solar.sig_battery_kwh || 9) === 9 ? "selected" : ""}`} onClick={() => updateSolar({ sig_battery_kwh: 9 })}>9 kWh</button>
                  </div>
                  <div className="r5-pill-row" style={{ marginTop: 8 }}>
                    <span style={{ fontSize: 12, color: "var(--r5-ink-4)", alignSelf: "center", marginRight: 6 }}>Nombre :</span>
                    {[1, 2, 3, 4, 5, 6].map(n => (
                      <button key={n} type="button" className={`r5-pill ${(state.solar.sig_battery_qty || 2) === n ? "selected" : ""}`}
                              onClick={() => updateSolar({ sig_battery_qty: n })}>{n}</button>
                    ))}
                  </div>
                </div>
              )}

              {/* Backup mode si batterie */}
              {state.solar.battery_brand !== "none" && (
                <div style={{ marginTop: 18 }}>
                  <div className="r5-config-block-head">
                    <span className="r5-config-block-label">Mode backup</span>
                    <span className="r5-config-block-hint">Sub-panel ou whole-home selon batterie</span>
                  </div>
                  <div className="r5-pill-row">
                    <button type="button" className={`r5-pill ${state.solar.backup_mode === "none" ? "selected" : ""}`}
                            onClick={() => updateSolar({ backup_mode: "none" })}>
                      Mesurage net seul
                    </button>
                    <button type="button" className={`r5-pill ${state.solar.backup_mode === "partial" ? "selected" : ""}`}
                            onClick={() => updateSolar({ backup_mode: "partial" })}>
                      Backup partiel (sub-panel)
                    </button>
                    {state.solar.battery_brand === "tesla" && (
                      <button type="button" className={`r5-pill ${state.solar.backup_mode === "whole_home" ? "selected" : ""}`}
                              onClick={() => updateSolar({ backup_mode: "whole_home" })}>
                        Full home backup (Tesla)
                      </button>
                    )}
                  </div>
                </div>
              )}

              {/* Forfait install auto-détecté */}
              {calc?.forfait && (
                <div className="r5-alert info" style={{ marginTop: 18 }}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
                  <div>
                    <strong>Forfait d'installation auto-détecté</strong> · <span className="mono">{calc.forfait.code}</span> · {calc.forfait.label} → <b>{C.fmtCAD0(calc.forfait.sell)}</b>
                    <div style={{ fontSize: 11, color: "var(--r5-ink-4)", marginTop: 4 }}>
                      2 ans MO Raycom · marge {(calc.forfait.marge * 100).toFixed(1)} % · coûtant {C.fmtCAD0(calc.forfait.cost)}
                    </div>
                  </div>
                </div>
              )}
            </section>
          </>
        )}

        {/* === BORNE V5 === */}
        {(isBorneOnly || state.borne.qty > 0) && (() => {
          const totalCableM = Object.values(state.borne.cables || {}).reduce((s, m) => s + (m || 0), 0);
          const borneCost = calc?.borne_sell || 0;
          return (
            <>
              {/* Section A — Quantité + modèle (only show for borne project type) */}
              {isBorneOnly && (
                <section className="r5-form-section">
                  <div className="r5-form-section-head">
                    <span className="r5-form-section-num">{showSolarSection ? "05" : "01"}</span>
                    <h2 className="r5-form-section-title">Quantité &amp; modèle</h2>
                    <span className="r5-form-section-desc">Forfait base 495 $/borne inclus</span>
                  </div>
                  <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
                    <div className="r5-qty-card">
                      <div className="r5-qty-card-label">
                        Nombre de bornes
                        <small>Forfait MO 2h + Z1 + breaker 60A 2P + connecteurs · 495 $/borne</small>
                      </div>
                      <div className="r5-qty">
                        <button type="button" onClick={() => updateBorne({ qty: Math.max(0, state.borne.qty - 1) })} disabled={state.borne.qty <= 0}>−</button>
                        <div className="r5-qty-display">{state.borne.qty}</div>
                        <button type="button" onClick={() => updateBorne({ qty: Math.min(50, state.borne.qty + 1) })} disabled={state.borne.qty >= 50}>+</button>
                      </div>
                    </div>

                    {state.borne.qty > 0 && (
                      <>
                        <div className="r5-qty-card">
                          <div className="r5-qty-card-label">
                            Borne fournie par le client&#8239;?
                            <small>Si oui, Raycom installe seulement (le matériel est exclu)</small>
                          </div>
                          <div className="r5-pill-row">
                            <button type="button" className={`r5-pill ${!state.borne.client_supplied ? "selected" : ""}`}
                                    onClick={() => updateBorne({ client_supplied: false })}>Non · Raycom fournit</button>
                            <button type="button" className={`r5-pill ${state.borne.client_supplied ? "selected" : ""}`}
                                    onClick={() => updateBorne({ client_supplied: true })}>Oui · client fournit</button>
                          </div>
                        </div>

                        {!state.borne.client_supplied && (
                          <div className="r5-model-grid">
                            {Object.entries(D.borne_ev.modeles)
                              .filter(([k, m]) => k !== "fournie_client" && k !== "flo_cable_remplacement")
                              .map(([k, m]) => (
                              <button key={k} type="button"
                                      className={`r5-model-card ${state.borne.modele_key === k ? "selected" : ""}`}
                                      onClick={() => updateBorne({ modele_key: k })}>
                                <div className="r5-model-card-mark">{m.brand.toUpperCase()}</div>
                                <div className="r5-model-card-name">{m.model}</div>
                                <div className="r5-model-card-meta">{m.kw} kW · {m.connector}</div>
                                <div className="r5-model-card-price">{C.fmtCAD0(m.sell)}</div>
                              </button>
                            ))}
                          </div>
                        )}
                      </>
                    )}
                  </div>
                </section>
              )}

              {/* Section B — Câblage combinable */}
              {state.borne.qty > 0 && (
                <section className="r5-form-section">
                  <div className="r5-form-section-head">
                    <span className="r5-form-section-num">{isBorneOnly ? "02" : (showSolarSection ? "06" : "01")}</span>
                    <h2 className="r5-form-section-title">Câblage — combinable</h2>
                    <span className="r5-form-section-desc">6 types · 0 à 50 m chacun</span>
                  </div>
                  <div className="r5-cable-card">
                    <div className="r5-cable-summary">
                      <div className="r5-cable-summary-total">
                        <div className="r5-cable-summary-num">{totalCableM}</div>
                        <div className="r5-cable-summary-unit">mètres au total</div>
                      </div>
                      <div className="r5-cable-summary-side">
                        <div className="r5-cable-summary-side-label">Coût câblage estim.</div>
                        <div className="r5-cable-summary-side-value">{borneCost > 0 ? C.fmtCAD0(borneCost) : "—"}</div>
                      </div>
                    </div>
                    <div className="r5-cable-list">
                      {Object.entries(D.borne_ev.sliders).map(([cableKey, slider]) => {
                        const currentM = (state.borne.cables && state.borne.cables[cableKey]) || 0;
                        const valPct = Math.round((currentM / 50) * 100);
                        const isActive = currentM > 0;
                        return (
                          <div key={cableKey} className={`r5-cable-row ${isActive ? "active" : ""}`}>
                            <div className="r5-cable-icon">
                              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                <path d="M4 20h16M6 16 Q 12 6 18 16"/>
                              </svg>
                            </div>
                            <div className="r5-cable-name">
                              {slider.label}
                              <small>{slider.spec.split("·")[0]?.trim()}</small>
                            </div>
                            <div className="r5-mini-range">
                              <input type="range" className="r5-mini"
                                     min={0} max={50} step={1} value={currentM}
                                     onChange={e => updateBorne({ cables: { ...(state.borne.cables || {}), [cableKey]: parseInt(e.target.value, 10) || 0 } })}
                                     style={{ "--r5-val": `${valPct}%`, "--val": `${valPct}%` }}
                                     aria-label={slider.label} />
                            </div>
                            <div className="r5-cable-length">
                              {currentM} m
                              {isActive && <small>actif</small>}
                            </div>
                          </div>
                        );
                      })}
                    </div>
                  </div>
                </section>
              )}

              {/* Section C — DCC / DSDC exclusif */}
              {state.borne.qty > 0 && (
                <section className="r5-form-section">
                  <div className="r5-form-section-head">
                    <span className="r5-form-section-num">{isBorneOnly ? "03" : (showSolarSection ? "07" : "02")}</span>
                    <h2 className="r5-form-section-title">Contrôleur de charge</h2>
                    <span className="r5-form-section-desc">DCC ou DSDC Tesla · exclusifs</span>
                  </div>
                  <div className="r5-dcc-grid">
                    <button type="button"
                            className={`r5-dcc-card none ${!state.borne.dcc_code && !state.borne.dsdc ? "selected" : ""}`}
                            onClick={() => updateBorne({ dcc_code: null, dsdc: false })}>
                      <div className="r5-dcc-card-name">Aucun</div>
                      <div className="r5-dcc-card-meta">0 $</div>
                    </button>
                    {Object.entries(D.borne_ev.dcc).map(([k, d]) => (
                      <button key={k} type="button"
                              className={`r5-dcc-card ${state.borne.dcc_code === k ? "selected" : ""}`}
                              onClick={() => updateBorne({ dcc_code: k, dsdc: false })}>
                        <div className="r5-dcc-card-name">{k.replace("OPT-", "")}</div>
                        <div className="r5-dcc-card-meta">{C.fmtCAD0(d.sell)}</div>
                      </button>
                    ))}
                    <button type="button"
                            className={`r5-dcc-card ${state.borne.dsdc ? "selected" : ""}`}
                            disabled={!state.borne.modele_key?.startsWith("tesla")}
                            onClick={() => updateBorne({ dsdc: true, dcc_code: null })}>
                      <div className="r5-dcc-card-name">DSDC Tesla</div>
                      <div className="r5-dcc-card-meta">650 $ · Tesla seul</div>
                    </button>
                  </div>
                </section>
              )}
            </>
          );
        })()}

        <div className="r5-nav-row">
          <button type="button" className="r5-btn r5-btn-secondary" onClick={onBack}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
            Précédent
          </button>
          <button type="button" className="r5-btn r5-btn-primary r5-btn-lg" onClick={onNext} disabled={solarCalc?.blocking}>
            Continuer
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
          </button>
        </div>
      </div>
    );
  }

  // ============================================================================
  // STEP 5 : Options techniques + Services (avec OptionDescriptionEditor par option)
  // ============================================================================
  function Step5Options({ state, setState, onBack, onNext }) {
    const D = window.RAYCOM_DATA_2026;
    const C = window.RAYCAST_CALC_2026;
    const Descr = window.RaycastDescriptions;
    const [filter, setFilter] = useState("");

    // V3 : options pertinentes par défaut selon project_type — 8 max au lieu de 51
    // Filtre intelligent : si pas de filter actif, on montre uniquement les options pertinentes
    // selon le contexte du projet. Lien "Voir toutes (51)" pour expand si besoin.
    const [showAllOptions, setShowAllOptions] = useState(false);

    const RELEVANT_FOR_SOLAR = new Set([
      "OPT-TECK-6-METRE", "OPT-PV-1S-METRE", "OPT-PV-2S-METRE", "OPT-PV-34S-METRE",
      "OPT-CONDUIT-METRE", "OPT-PANNEAU-RECUP", "OPT-PANNEAU-NEUFS", "OPT-MALT-AVANCEE"
    ]);
    const RELEVANT_FOR_BORNE = new Set([
      "OPT-TECK-6-METRE", "OPT-CABLE-NMD-10", "OPT-CABLE-8RW90", "OPT-CABLE-NMWU-6",
      "OPT-CONDUIT-PVC-2-ENF", "OPT-PANNEAU-RECUP", "OPT-PANNEAU-NEUFS", "OPT-SECTIONNEUR-60A"
    ]);
    const RELEVANT_FOR_BATTERIE = new Set([
      "OPT-TECK-6-METRE", "OPT-CABLE-NMD-10", "OPT-PANNEAU-RECUP", "OPT-PANNEAU-NEUFS",
      "OPT-RESEAU-WIFI", "OPT-GENERATRICE-TRANSFERT", "OPT-MALT-AVANCEE", "OPT-MO-EXTRA"
    ]);

    const relevantSet = state.project_type === "borne" ? RELEVANT_FOR_BORNE
                     : state.project_type === "batterie" ? RELEVANT_FOR_BATTERIE
                     : RELEVANT_FOR_SOLAR;

    const filteredOptions = D.options_electriques.filter(o => {
      // Filtre texte (toujours appliqué si présent)
      if (filter) {
        return o.label.toLowerCase().includes(filter.toLowerCase()) || o.code.toLowerCase().includes(filter.toLowerCase());
      }
      // V3 : sans filter texte, montrer seulement les pertinentes (sauf si showAllOptions activé)
      if (showAllOptions) return true;
      return relevantSet.has(o.code);
    });

    const toggleOption = (opt) => {
      const exists = state.options_electriques.find(o => o.code === opt.code);
      if (exists) {
        setState({ ...state, options_electriques: state.options_electriques.filter(o => o.code !== opt.code) });
      } else {
        setState({ ...state, options_electriques: [...state.options_electriques, { ...opt, qty: 1 }] });
      }
    };

    const setQty = (code, qty) => {
      setState({
        ...state,
        options_electriques: state.options_electriques.map(o => o.code === code ? { ...o, qty } : o)
      });
    };

    const toggleService = (sv) => {
      const exists = state.services.find(s => s.code === sv.code);
      if (exists) {
        setState({ ...state, services: state.services.filter(s => s.code !== sv.code) });
      } else {
        setState({ ...state, services: [...state.services, { ...sv, qty: 1 }] });
      }
    };

    return (
      <div>
        <div className="r26-step-intro">
          <div className="kicker"><span className="dot"></span>Étape 5 sur 6</div>
          <h1>Options techniques + services</h1>
          <p>Ajuste la soumission au contexte du chantier. Chaque option cochée affiche sa description catalogue — personnalisable au besoin pour cette soumission.</p>
        </div>

        <div className="r26-card">
          <div className="r26-card-head">
            <div className="title">Options électriques · {showAllOptions ? `${D.options_electriques.length} affichées` : `${filteredOptions.length} pertinentes`}</div>
            <button className="r26-btn r26-btn-ghost" style={{ marginLeft: "auto", padding: "4px 10px", fontSize: 11 }}
                    onClick={() => setShowAllOptions(v => !v)}>
              {showAllOptions ? "← Filtrer (8 pertinentes)" : `Voir toutes les ${D.options_electriques.length} options →`}
            </button>
          </div>
          <div className="r26-card-body">
            <input className="r26-input" placeholder={showAllOptions ? "Filtrer (ex: panneau, cable, spa…)" : "Rechercher dans toutes les options…"}
                   value={filter} onChange={e => setFilter(e.target.value)} style={{ marginBottom: 14 }} />
            {!showAllOptions && !filter && (
              <div className="r26-alert r26-alert-info" style={{ marginBottom: 12, fontSize: 12 }}>
                <div>💡 Affichage des options les plus pertinentes pour <b>{state.project_type === "borne" ? "borne VÉ" : state.project_type === "batterie" ? "stockage tout-en-un" : "système solaire"}</b>. Cliquez sur « Voir toutes » pour la liste complète.</div>
              </div>
            )}
            <div style={{ maxHeight: 540, overflowY: "auto", border: "1px solid var(--r26-line)", borderRadius: 8 }}>
              {filteredOptions.map(opt => {
                const selected = state.options_electriques.find(o => o.code === opt.code);
                return (
                  <div key={opt.code} style={{ padding: "10px 12px", borderBottom: "1px solid var(--r26-line)" }}>
                    <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                      <input type="checkbox" checked={!!selected} onChange={() => toggleOption(opt)} />
                      <div style={{ flex: 1 }}>
                        <div style={{ fontSize: 13, fontWeight: 600, color: "var(--r26-primary)" }}>{opt.label}</div>
                        <div style={{ fontSize: 11, color: "var(--r26-ink-3)" }}>{opt.code} · {opt.unit} · {C.fmtCAD0(opt.sell)}</div>
                      </div>
                      {selected && (
                        <input type="number" className="r26-input" style={{ width: 80 }} min={1} value={selected.qty} onChange={e => setQty(opt.code, parseInt(e.target.value, 10) || 1)} />
                      )}
                    </div>
                    {selected && Descr && (
                      <Descr.OptionDescriptionEditor code={opt.code} label={opt.label} state={state} setState={setState} />
                    )}
                  </div>
                );
              })}
            </div>
          </div>
        </div>

        <div className="r26-card">
          <div className="r26-card-head"><div className="title">Services vendeur ({D.services_vendeur.length} disponibles)</div></div>
          <div className="r26-card-body">
            {D.services_vendeur.map(sv => {
              const selected = state.services.find(s => s.code === sv.code);
              return (
                <div key={sv.code} style={{ padding: "8px 0", borderBottom: "1px solid var(--r26-line)" }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                    <input type="checkbox" checked={!!selected} onChange={() => toggleService(sv)} />
                    <div style={{ flex: 1 }}>
                      <div style={{ fontSize: 13, fontWeight: 600, color: "var(--r26-primary)" }}>{sv.label}</div>
                      <div style={{ fontSize: 11, color: "var(--r26-ink-3)" }}>{sv.code} · {C.fmtCAD0(sv.sell)}</div>
                    </div>
                  </div>
                  {selected && Descr && (
                    <Descr.OptionDescriptionEditor code={sv.code} label={sv.label} state={state} setState={setState} />
                  )}
                </div>
              );
            })}
          </div>
        </div>

        <div className="r26-btn-row">
          <button className="r26-btn r26-btn-ghost" onClick={onBack}>← Précédent</button>
          <button className="r26-btn r26-btn-primary" onClick={onNext}>Suivant →</button>
        </div>
      </div>
    );
  }

  // ============================================================================
  // STEP 6 : Résumé + Acceptation + PDF
  // ============================================================================
  function Step6Resume({ state, setState, calc, onBack, onSave, onGeneratePDF, onDecide }) {
    const C = window.RAYCAST_CALC_2026;
    const D = window.RAYCOM_DATA_2026;
    const fmt = (v) => C.fmtCAD0(v || 0);
    const Descr = window.RaycastDescriptions;

    // Group lines by category (V5 layout : Solaire / Batterie / Installation / Options / Bornes)
    const groups = useMemo(() => {
      const g = [];
      // Solaire
      if (calc?.solarCalc && calc.solar_sell > 0) {
        g.push({
          title: `Solaire · ${calc.solarCalc.panneaux} panneaux · ${calc.solarCalc.kw} kW`,
          sub: fmt(calc.solar_sell),
          rows: [{
            qty: `${calc.solarCalc.panneaux}×`,
            name: "Thornova BBT54 500W All Black Bifacial",
            desc: `Pente ${state.solar.pitch_key} · ${state.solar.floors} étage(s) · ${calc.solarCalc.kw} kW DC`,
            price: fmt(calc.solar_sell)
          }]
        });
      }
      // Batterie tout-en-un
      if (calc?.batteryOnlyCalc && calc.battery_sell > 0) {
        g.push({
          title: `Batterie ${calc.batteryOnlyCalc.brand === "tesla" ? "Tesla" : calc.batteryOnlyCalc.brand === "sig" ? "Sigenergy" : "Fox ESS"}`,
          sub: fmt(calc.battery_sell),
          rows: calc.batteryOnlyCalc.breakdown.map(b => ({
            qty: `${b.qty}×`,
            name: b.label,
            desc: "",
            price: fmt(b.sell)
          }))
        });
      } else if (calc?.battery_sell > 0) {
        g.push({
          title: "Batterie",
          sub: fmt(calc.battery_sell),
          rows: [{ qty: "1×", name: calc.battery_label || "Batterie", desc: "Onduleur + batteries · garantie manufacturier", price: fmt(calc.battery_sell) }]
        });
      }
      // Installation forfait
      if (calc?.forfait) {
        const zoneRow = calc.zone_sell > 0
          ? { qty: "—", name: `Zone ${calc.zone.zone_key}`, desc: calc.zone.label, price: fmt(calc.zone_sell) }
          : { qty: "—", name: `Zone ${calc.zone?.zone_key || "Z1"}`, desc: "Incluse dans le forfait", price: "0 $", priceClass: "success" };
        g.push({
          title: "Installation",
          sub: fmt(calc.install_sell + (calc.zone_sell || 0)),
          rows: [
            { qty: "1×", name: calc.forfait.label, desc: `${calc.forfait.code} · 2 ans MO Raycom`, price: fmt(calc.install_sell) },
            zoneRow
          ]
        });
      }
      // Borne EV
      if (calc?.borneCalc && calc.borne_sell > 0) {
        g.push({
          title: `Borne EV · ${calc.borneCalc.qty || 1} borne(s)`,
          sub: fmt(calc.borne_sell),
          rows: [{
            qty: `${calc.borneCalc.qty || 1}×`,
            name: calc.borneCalc.modele_label || "Borne EV",
            desc: `${calc.borneCalc.slider_label || ""} · forfait base inclus`,
            price: fmt(calc.borne_sell)
          }]
        });
      }
      // Options électriques
      const opts = state.options_electriques || [];
      if (opts.length > 0) {
        g.push({
          title: "Options électriques",
          sub: fmt(calc.options_sell),
          rows: opts.map(o => ({
            qty: `${o.qty || 1}×`,
            name: o.label,
            desc: `${o.code} · ${o.unit}`,
            price: fmt((o.sell || 0) * (o.qty || 1))
          }))
        });
      }
      // Services internes
      const svc = state.services || [];
      if (svc.length > 0) {
        g.push({
          title: "Services internes",
          sub: fmt(calc.services_sell),
          rows: svc.map(s => ({
            qty: `${s.qty || 1}×`,
            name: s.label,
            desc: s.code,
            price: fmt((s.sell || 0) * (s.qty || 1))
          }))
        });
      }
      return g;
    }, [state, calc]);

    // Hero KPIs
    const heroSavings = calc?.savings_25 || 0;
    const payback = isFinite(calc?.payback) ? calc.payback : 0;
    const ges = calc?.production ? (calc.production * 0.000688) : 0; // ~0.688 kg CO2/kWh × prod kWh → tonnes
    const autonomy = calc?.autonomy_days ? Math.round(calc.autonomy_days * 24) : 0;

    // Subv flow
    const grant = calc?.total_grant || 0;
    const htBeforeGrant = (calc?.ht || 0) + (calc?.tps || 0) + (calc?.tvq || 0);
    const netCost = calc?.net_cost || 0;

    // Payment plans
    const planId = state.client?.financing_plan_id || "comptant";
    const monthly = calc?.fin?.monthly || 0;
    const cashAmount = calc?.ttc || 0;
    const monthlyEstimate = (() => {
      const P = cashAmount; const r = 0.1299 / 12; const n = 240;
      const m = P > 0 ? P * (r / (1 - Math.pow(1 + r, -n))) : 0;
      return isFinite(m) ? m : 0;
    })();

    const projectScopeHTML = (() => {
      // Build a friendly scope description with chips
      const parts = [];
      if (calc?.solarCalc?.panneaux) {
        parts.push(<>Installation d'un système solaire de <span className="r5-scope-chip">{calc.solarCalc.panneaux} panneaux Thornova 500W</span> totalisant <span className="r5-scope-chip">{calc.solarCalc.kw} kW DC</span></>);
      }
      if (calc?.batteryOnlyCalc?.brand === "tesla") {
        parts.push(<>, couplé à <span className="r5-scope-chip">{state.solar.pw_count} Powerwall 3</span> avec <span className="r5-scope-chip">backup {state.solar.backup_mode === "whole_home" ? "whole-home automatique" : state.solar.backup_mode === "partial" ? "partiel" : "désactivé"}</span></>);
      } else if (calc?.battery_sell > 0) {
        parts.push(<>, couplé à <span className="r5-scope-chip">{calc.battery_label}</span></>);
      }
      if (state.solar?.roof_type && state.project_type !== "batterie" && state.project_type !== "borne") {
        parts.push(<>. Toiture <span className="r5-scope-chip">{state.solar.roof_type}</span>, pente <span className="r5-scope-chip">{state.solar.pitch_key}</span> sur résidence <span className="r5-scope-chip">{state.solar.floors} étage(s)</span></>);
      }
      if (calc?.zone) {
        parts.push(<> dans la <span className="r5-scope-chip">zone {calc.zone.zone_key} ({state.client?.address_city || ""})</span></>);
      }
      parts.push(<>. Le système comprend l'installation complète par notre équipe <span className="r5-scope-chip-info r5-scope-chip">RBQ 5590-9402</span>, la mise en service, et un suivi 2 ans MO. <span className="r5-scope-chip scope-chip-amber r5-scope-chip-amber">Permis municipal non inclus</span> — à la charge du client.</>);
      return parts;
    })();

    const decisionStatus = state.decision_status || "draft";

    return (
      <>
        <div className="r5-step-intro">
          <div className="r5-step-eyebrow"><span className="r5-dot"></span>Étape 6 sur 6 · Récap final</div>
          <h1>Voici le projet, {state.client?.name || "client"}.</h1>
          <div className="r5-step6-intro-meta">
            <span>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
              {state.client?.address_city || "Mascouche"} · Zone&nbsp;{calc?.zone?.zone_key || "Z1"}
            </span>
            <span>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 12l2 2 4-4"/></svg>
              Soumission valide 30 jours
            </span>
            <span>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
              {calc?.warnings?.length ? `${calc.warnings.length} avertissement(s)` : "Aucun avertissement"}
            </span>
          </div>
        </div>

        {/* HERO KPIs */}
        <div className="r5-kpi-row">
          <div className="r5-kpi hero">
            <div className="r5-kpi-eyebrow">Économies estimées sur 25 ans</div>
            <div className="r5-kpi-value">{fmt(heroSavings).replace(" $", "")}<span className="r5-kpi-unit">$</span></div>
            <div className="r5-kpi-meta">Net après subventions et financement. Hypothèse&nbsp;: tarif HQ&nbsp;{state.client?.hq_tariff || "D"}, +3 %/an.</div>
          </div>
          <div className="r5-kpi success">
            <div className="r5-kpi-eyebrow">Retour sur invest.</div>
            <div className="r5-kpi-value">{payback > 0 ? payback.toFixed(1).replace(".", ",") : "—"}<span className="r5-kpi-unit">ans</span></div>
            <div className="r5-kpi-meta">{planId === "comptant" ? "Comptant" : "Financement"}</div>
          </div>
          <div className="r5-kpi">
            <div className="r5-kpi-eyebrow">GES évités</div>
            <div className="r5-kpi-value">{ges > 0 ? ges.toFixed(1).replace(".", ",") : "—"}<span className="r5-kpi-unit">t/an</span></div>
            <div className="r5-kpi-meta">≈ {Math.round(ges / 4.6)} voiture(s) retirée(s)</div>
          </div>
          <div className="r5-kpi">
            <div className="r5-kpi-eyebrow">Autonomie batterie</div>
            <div className="r5-kpi-value">{autonomy > 0 ? autonomy : "—"}<span className="r5-kpi-unit">h</span></div>
            <div className="r5-kpi-meta">Charges critiques</div>
          </div>
        </div>

        {/* Body 2-col */}
        <div className="r5-step6-body">

          {/* Left column */}
          <div>
            {/* Subvention flow */}
            {grant > 0 && (
              <section className="r5-section-block">
                <div className="r5-section-head">
                  <h2 className="r5-section-title">Subventions disponibles</h2>
                </div>
                <div className="r5-subv-card">
                  <div className="r5-subv-flow">
                    <div className="r5-subv-col">
                      <div className="r5-subv-col-label">Coût avant subv.</div>
                      <div className="r5-subv-col-value">{fmt(htBeforeGrant)}</div>
                      <div className="r5-subv-col-sub">TTC tout inclus</div>
                    </div>
                    <div className="r5-subv-arrow">
                      <svg width="40" height="20" viewBox="0 0 40 20" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                        <path d="M2 10 L34 10"/>
                        <path d="M28 4 L34 10 L28 16"/>
                      </svg>
                    </div>
                    <div className="r5-subv-col">
                      <div className="r5-subv-col-label">Net après subv.</div>
                      <div className="r5-subv-col-value net">{fmt(netCost)}</div>
                      <div className="r5-subv-col-sub">−{fmt(grant)} d'aide</div>
                    </div>
                  </div>
                  <div className="r5-subv-details">
                    {calc.logisvert > 0 && (
                      <div className="r5-subv-item">
                        <div className="r5-subv-item-key">
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
                          LogisVert · Hydro-Québec ({calc.solarCalc?.kw || 0} kW × 1 000 $)
                        </div>
                        <div className="r5-subv-item-val">{fmt(calc.logisvert)}</div>
                      </div>
                    )}
                    {(calc.commercial_subv?.cii_federal || 0) > 0 && (
                      <div className="r5-subv-item">
                        <div className="r5-subv-item-key">
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
                          Crédit d'impôt fédéral CII (30 %)
                        </div>
                        <div className="r5-subv-item-val">{fmt(calc.commercial_subv.cii_federal)}</div>
                      </div>
                    )}
                    {(calc.commercial_subv?.solutions_efficaces || 0) > 0 && (
                      <div className="r5-subv-item">
                        <div className="r5-subv-item-key">
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
                          Solutions efficaces HQ (commercial)
                        </div>
                        <div className="r5-subv-item-val">{fmt(calc.commercial_subv.solutions_efficaces)}</div>
                      </div>
                    )}
                    {calc.rve > 0 && (
                      <div className="r5-subv-item">
                        <div className="r5-subv-item-key">
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
                          Roulez Vert (borne EV)
                        </div>
                        <div className="r5-subv-item-val">{fmt(calc.rve)}</div>
                      </div>
                    )}
                  </div>
                </div>
              </section>
            )}

            {/* Project scope */}
            <section className="r5-section-block">
              <div className="r5-section-head">
                <h2 className="r5-section-title">Description du projet</h2>
                {Descr && <button className="r5-section-link" onClick={() => Descr?.openCustomize?.(state, setState)}>Personnaliser</button>}
              </div>
              <div className="r5-scope-card">
                <p className="r5-scope-text">
                  {projectScopeHTML}
                </p>
              </div>
            </section>

            {/* Detail table grouped */}
            <section className="r5-section-block">
              <div className="r5-section-head">
                <h2 className="r5-section-title">Détail du devis</h2>
                <span className="r5-section-link" style={{ color: "var(--r5-ink-4)", cursor: "default" }}>
                  {groups.length} catégorie(s)
                </span>
              </div>
              <div className="r5-detail-card">
                {groups.map((g, gi) => (
                  <div key={gi} className="r5-detail-group">
                    <div className="r5-detail-group-head">
                      <span className="r5-detail-group-title">{g.title}</span>
                      <span className="r5-detail-group-sub">{g.sub}</span>
                    </div>
                    {g.rows.map((r, ri) => (
                      <div key={ri} className="r5-detail-row">
                        <div className="r5-detail-qty">{r.qty}</div>
                        <div>
                          <div className="r5-detail-name">{r.name}</div>
                          {r.desc && <div className="r5-detail-desc">{r.desc}</div>}
                        </div>
                        <div className={`r5-detail-price ${r.priceClass || ""}`}>{r.price}</div>
                      </div>
                    ))}
                  </div>
                ))}

                {/* Totals */}
                <div className="r5-detail-total">
                  <div className="r5-detail-total-label">Sous-total HT</div>
                  <div className="r5-detail-total-value">{fmt(calc?.ht)}</div>
                </div>
                {grant > 0 && (
                  <div className="r5-detail-row" style={{ background: "var(--r5-bg-soft)", borderTop: "1px solid var(--r5-line)", padding: "10px 24px" }}>
                    <div className="r5-detail-qty">−</div>
                    <div className="r5-detail-name" style={{ fontSize: 12, color: "var(--r5-ink-4)" }}>Subventions (LogisVert + CII + Roulez Vert + commercial)</div>
                    <div className="r5-detail-price success">−{fmt(grant)}</div>
                  </div>
                )}
                <div className="r5-detail-row" style={{ background: "var(--r5-bg-soft)", padding: "10px 24px" }}>
                  <div className="r5-detail-qty">+</div>
                  <div className="r5-detail-name" style={{ fontSize: 12, color: "var(--r5-ink-4)" }}>TPS 5,000 % + TVQ 9,975 %</div>
                  <div className="r5-detail-price">{fmt((calc?.tps || 0) + (calc?.tvq || 0))}</div>
                </div>
                <div className="r5-detail-total hero">
                  <div className="r5-detail-total-label">TOTAL net TTC</div>
                  <div className="r5-detail-total-value">{fmt(netCost > 0 ? netCost : (calc?.ttc || 0))}</div>
                </div>
              </div>
            </section>

            {/* Calendrier de paiement */}
            {(calc?.payment_schedule?.length || 0) > 0 && (
              <section className="r5-section-block">
                <div className="r5-section-head">
                  <h2 className="r5-section-title">Calendrier de paiement</h2>
                </div>
                <div className="r5-detail-card">
                  {calc.payment_schedule.map(p => (
                    <div key={p.sequence} className="r5-detail-row">
                      <div className="r5-detail-qty">{p.sequence}.</div>
                      <div>
                        <div className="r5-detail-name">{p.label}</div>
                        <div className="r5-detail-desc">Déclencheur : {p.trigger_event.replace(/_/g, " ")} · {p.method_options.join(" · ")}</div>
                      </div>
                      <div className="r5-detail-price">{fmt(p.amount_cad)}</div>
                    </div>
                  ))}
                </div>
              </section>
            )}

            {/* Commission vendeur retirée (V7 — directive JF 29 mai 2026) */}
          </div>

          {/* Right sidebar — sticky */}
          <aside className="r5-side-sticky">
            {/* Payment plans */}
            <div className="r5-pay-card">
              <div className="r5-pay-card-head">
                <div className="r5-pay-card-eyebrow">Choix de paiement</div>
                <h3 className="r5-pay-card-title">Comment souhaite-t-il payer&#8239;?</h3>
              </div>
              <div className="r5-pay-options">
                <button type="button"
                        className={`r5-pay-option ${planId === "comptant" ? "selected" : ""}`}
                        onClick={() => setState({ ...state, client: { ...state.client, financing_plan_id: "comptant" } })}>
                  <div className="r5-pay-option-head">
                    <span className="r5-pay-option-name">Comptant</span>
                    <span className="r5-pay-option-amount">{fmt(cashAmount)}</span>
                  </div>
                  <div className="r5-pay-option-meta">Aucuns frais · payback {payback > 0 ? payback.toFixed(1).replace(".", ",") : "—"} ans</div>
                </button>
                <button type="button"
                        className={`r5-pay-option ${planId === "fit_promo_0_3" ? "selected" : ""}`}
                        onClick={() => setState({ ...state, client: { ...state.client, financing_plan_id: "fit_promo_0_3" } })}>
                  <div className="r5-pay-option-head">
                    <span className="r5-pay-option-name">FinanceIT — 0 $ · 3 mois</span>
                    <span className="r5-pay-option-amount">{monthlyEstimate > 0 ? Math.round(monthlyEstimate).toLocaleString("fr-CA") : "—"}&nbsp;$<small>/ mois</small></span>
                  </div>
                  <div className="r5-pay-option-meta">0 $ et 0 % les 3 premiers mois · puis 240 mois</div>
                </button>
                <button type="button"
                        className={`r5-pay-option ${planId === "fit_240m" ? "selected" : ""}`}
                        onClick={() => setState({ ...state, client: { ...state.client, financing_plan_id: "fit_240m" } })}>
                  <div className="r5-pay-option-head">
                    <span className="r5-pay-option-name">FinanceIT 20 ans</span>
                    <span className="r5-pay-option-amount">{monthlyEstimate > 0 ? Math.round(monthlyEstimate).toLocaleString("fr-CA") : "—"}&nbsp;$<small>/ mois</small></span>
                  </div>
                  <div className="r5-pay-option-meta">240 mois · 12,99 % APR</div>
                </button>
              </div>
            </div>

            {/* Decision row */}
            <div className="r5-decision-card">
              <div className="r5-decision-eyebrow">Décision client</div>
              <button type="button" className="r5-btn-accept"
                      onClick={() => onDecide?.("accepted")}
                      disabled={calc?.blocking}
                      title="Le client signe maintenant">
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
                Accepter la soumission
              </button>
              <button type="button" className="r5-btn-think" onClick={() => onDecide?.("thinking")}>
                À réfléchir
              </button>
              <button type="button" className="r5-btn-refuse" onClick={() => onDecide?.("refused")}>
                Le client refuse
              </button>
            </div>

            {/* PDF download */}
            <div className="r5-pdf-card">
              <div className="r5-pdf-card-title">Soumission PDF</div>
              <div className="r5-pdf-card-desc">8 pages · branded · LogisVert + datasheet Thornova inclus.</div>
              <button type="button" className="r5-btn-pdf"
                      onClick={onGeneratePDF}
                      disabled={calc?.blocking}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
                Télécharger le PDF
              </button>
            </div>

            {/* P8-E : Page client interactive (présentation sur tablette) */}
            {(calc?.solarCalc?.kw || 0) > 0 && (
              <button type="button" className="r5-btn r5-btn-secondary" style={{ width: "100%" }}
                      onClick={() => {
                        try {
                          const payload = {
                            number: state.number || "Soumission",
                            kw: calc?.solarCalc?.kw || 0,
                            panneaux: state.solar?.panneaux || 0,
                            clientName: state.client?.name || "",
                            civic: state.client?.address_civic || "",
                            street: state.client?.address_street || "",
                            city: state.client?.address_city || "",
                            postal: state.client?.address_postal || "",
                            zoneKey: calc?.zone?.zone_key || "Z1"
                          };
                          localStorage.setItem("raycast_soumission_live", JSON.stringify(payload));
                          window.open("/soumission/?live=1", "_blank");
                        } catch (e) { console.error("[page client]", e); }
                      }}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>
                Voir la page client interactive
              </button>
            )}

            {/* Save draft */}
            <button type="button" className="r5-btn r5-btn-secondary" onClick={onSave} style={{ width: "100%" }}>
              💾 Sauvegarder brouillon
            </button>
          </aside>
        </div>

        {/* Barre de badges (RBQ·CMEQ·Tesla·2ans) retirée — V7/V2 §3.3 (épuration).
            Le RBQ légal reste au pied de page de l'app + dans le PDF. */}

        {/* Back nav */}
        <div className="r5-nav-row">
          <button type="button" className="r5-btn r5-btn-secondary" onClick={onBack}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
            Précédent
          </button>
          <span></span>
        </div>
      </>
    );
  }

  // ============================================================================
  // LIVE PREVIEW (right column)
  // ============================================================================
  function LivePreview({ calc, viewMode = "internal" }) {
    const C = window.RAYCAST_CALC_2026;
    if (!calc) return null;
    const internal = viewMode === "internal";

    return (
      <aside className="r26-preview">
        <h3>Aperçu en direct</h3>

        <div className="ps-card accent">
          <div className="lbl">Total TTC client</div>
          <div className="val">{C.fmtCAD0(calc.ttc)}</div>
          <div className="sub">HT {C.fmtCAD0(calc.ht)} · TPS+TVQ {C.fmtCAD0(calc.tps + calc.tvq)}</div>
        </div>

        {(calc.total_grant || 0) > 0 && (
          <div className="ps-card success">
            <div className="lbl">Subventions totales</div>
            <div className="val">−{C.fmtCAD0(calc.total_grant)}</div>
            <div className="sub">
              {calc.logisvert > 0 && <>LogisVert {C.fmtCAD0(calc.logisvert)} · </>}
              {calc.rve > 0 && <>RV {C.fmtCAD0(calc.rve)} · </>}
              Coût net : <b>{C.fmtCAD0(calc.net_cost)}</b>
            </div>
          </div>
        )}

        {calc.fin?.monthly > 0 && (
          <div className="ps-card" style={{ background: "#eff6ff", border: "1px solid #bfdbfe" }}>
            <div className="lbl">FinanceIT 240 mois @ 12,99 %</div>
            <div className="val">{C.fmtCAD0(calc.fin.monthly)}<span style={{ fontSize: 13, fontWeight: 500 }}>/mois</span></div>
            <div className="sub">Bimensuel {C.fmtCAD0(calc.fin.biweekly)} · Hebdo {C.fmtCAD0(calc.fin.weekly)}</div>
          </div>
        )}

        <div style={{ marginTop: 16 }}>
          <h3>Détail prix HT</h3>
          {calc.solar_sell > 0 && <div className="ps-row"><span className="k">Solaire au watt</span><span className="v">{C.fmtCAD0(calc.solar_sell)}</span></div>}
          {calc.install_sell > 0 && <div className="ps-row"><span className="k">Forfait install</span><span className="v">{C.fmtCAD0(calc.install_sell)}</span></div>}
          {calc.battery_sell > 0 && <div className="ps-row"><span className="k">Batterie</span><span className="v">{C.fmtCAD0(calc.battery_sell)}</span></div>}
          {calc.borne_sell > 0 && <div className="ps-row"><span className="k">Bornes EV</span><span className="v">{C.fmtCAD0(calc.borne_sell)}</span></div>}
          {calc.options_sell > 0 && <div className="ps-row"><span className="k">Options électriques</span><span className="v">{C.fmtCAD0(calc.options_sell)}</span></div>}
          {calc.services_sell > 0 && <div className="ps-row"><span className="k">Services internes</span><span className="v">{C.fmtCAD0(calc.services_sell)}</span></div>}
          {calc.zone_sell > 0 && <div className="ps-row"><span className="k">Déplacement {calc.zone?.zone_key}</span><span className="v">{C.fmtCAD0(calc.zone_sell)}</span></div>}
        </div>

        {calc.production > 0 && (
          <div style={{ marginTop: 16 }}>
            <h3>Production solaire</h3>
            <div className="ps-row"><span className="k">Production / an</span><span className="v">{C.fmtNum(calc.production)} kWh</span></div>
            <div className="ps-row"><span className="k">Couverture HQ</span><span className="v">{C.fmtPct(calc.coverage_pct, 0)}</span></div>
            <div className="ps-row"><span className="k">Économies / an</span><span className="v">{C.fmtCAD0(calc.savings?.total || 0)}</span></div>
            {isFinite(calc.payback) && <div className="ps-row"><span className="k">Payback</span><span className="v">{calc.payback.toFixed(1).replace(".", ",")} ans</span></div>}
            {calc.savings_25 > 0 && <div className="ps-row"><span className="k">Économies 25 ans</span><span className="v">{C.fmtCAD0(calc.savings_25)}</span></div>}
          </div>
        )}

        {/* V2X — éligibilité (directive #13) */}
        {calc.v2x?.eligible && calc.v2x.revenue > 0 && (
          <div className="ps-card" style={{ background: "#fef3c7", border: "1px solid #fde68a", marginTop: 12 }}>
            <div className="lbl" style={{ color: "#92400e" }}>⚡ V2X éligible</div>
            <div className="val" style={{ color: "#92400e" }}>{C.fmtCAD0(calc.v2x.revenue)}<span style={{ fontSize: 13, fontWeight: 500 }}>/an</span></div>
            <div className="sub">{C.fmtNum(calc.v2x.ev_kwh)} kWh × 0,15 $/kWh injection HQ</div>
          </div>
        )}

        {/* Info interne — marge vendeur (commission retirée V7) */}
        {internal && calc.marge_pct > 0 && (
          <div style={{ marginTop: 16 }}>
            <h3>💼 Info interne</h3>
            <div className="ps-row"><span className="k">Marge brute</span><span className="v">{C.fmtCAD0(calc.marge_brute)}</span></div>
            <div className="ps-row"><span className="k">Marge %</span><span className="v">{C.fmtPct(calc.marge_pct, 1)}</span></div>
          </div>
        )}

        {/* Payment schedule preview (vue interne) */}
        {internal && (calc.payment_schedule?.length || 0) > 0 && (
          <div style={{ marginTop: 16 }}>
            <h3>💳 Calendrier paiement</h3>
            {calc.payment_schedule.map(p => (
              <div key={p.sequence} className="ps-row">
                <span className="k">{p.sequence}. {p.trigger_event.replace(/_/g, " ")}</span>
                <span className="v">{C.fmtCAD0(p.amount_cad)}</span>
              </div>
            ))}
          </div>
        )}

        {/* Subventions commerciales */}
        {(calc.commercial_subv?.total || 0) > 0 && (
          <div className="ps-card" style={{ background: "#f0fdf4", border: "1px solid #bbf7d0", marginTop: 12 }}>
            <div className="lbl" style={{ color: "#166534" }}>🏢 Subventions commerciales</div>
            <div className="val" style={{ color: "#166534" }}>{C.fmtCAD0(calc.commercial_subv.total)}</div>
            <div className="sub">
              SE HQ {C.fmtCAD0(calc.commercial_subv.solutions_efficaces)} · CII 30 % {C.fmtCAD0(calc.commercial_subv.cii_federal)}
            </div>
          </div>
        )}

        {calc.warnings?.length > 0 && (
          <div className="r26-alert r26-alert-warning" style={{ marginTop: 16, fontSize: 11 }}>
            <div>
              <strong>⚠️ {calc.warnings.length} avertissement(s)</strong>
              <ul style={{ margin: "4px 0 0 16px", padding: 0 }}>
                {calc.warnings.slice(0, 3).map((w, i) => <li key={i}>{w}</li>)}
              </ul>
            </div>
          </div>
        )}

        {calc.errors?.length > 0 && (
          <div className="r26-alert r26-alert-error" style={{ marginTop: 16, fontSize: 12 }}>
            <strong>⛔ Bloquant</strong>
            <ul style={{ margin: "4px 0 0 16px", padding: 0 }}>
              {calc.errors.map((e, i) => <li key={i}>{e}</li>)}
            </ul>
          </div>
        )}
      </aside>
    );
  }

  // ============================================================================
  // STEP 7 : SubmissionCompletion (Phase 2 — post-décision CTA)
  // ============================================================================
  function SubmissionCompletion({ state, setState, calc, onReturnToDashboard, onGeneratePDF }) {
    const C = window.RAYCAST_CALC_2026;
    // REACT-5 Phase 3 : délai 6s (au lieu de 8) + animation plus douce via .r26-success-card-enter
    const [countdown, setCountdown] = useState(6);
    const [cancelled, setCancelled] = useState(false);
    const decision = state.decision_status || "accepted";

    useEffect(() => {
      if (cancelled) return;
      if (countdown <= 0) {
        onReturnToDashboard?.();
        return;
      }
      const t = setTimeout(() => setCountdown(countdown - 1), 1000);
      return () => clearTimeout(t);
    }, [countdown, cancelled, onReturnToDashboard]);

    const isAccept = decision === "accepted";
    const isThink = decision === "thinking";
    const isRefuse = decision === "refused";

    const heroBg = isAccept ? "linear-gradient(135deg, #10b981, #059669)"
                  : isThink ? "linear-gradient(135deg, #f59e0b, #d97706)"
                  : "linear-gradient(135deg, #94a3b8, #64748b)";
    const heroIcon = isAccept ? (
      <svg viewBox="0 0 48 48" width="42" height="42" fill="none" stroke="#fff" strokeWidth="4.5" strokeLinecap="round" strokeLinejoin="round">
        <polyline className="r26-success-check" points="10 24 21 35 38 14"/>
      </svg>
    ) : isThink ? "⋯" : "✗";
    const heroTitle = isAccept ? "Soumission acceptée !" : isThink ? "Soumission en réflexion" : "Soumission refusée";
    const heroSub = isAccept ? "Le contrat est en route vers le client."
                  : isThink ? "Relance programmée à J+5, J+12, J+30."
                  : "Documenté pour analyse — la soumission reste accessible.";

    return (
      <div className="r26-success-card-enter" style={{ maxWidth: 760, margin: "0 auto", textAlign: "center", padding: "20px 16px 60px" }}>
        <div style={{
          width: 96, height: 96, borderRadius: "50%",
          background: heroBg, margin: "0 auto 18px",
          display: "grid", placeItems: "center",
          fontSize: 48, color: "#fff", fontWeight: 800,
          boxShadow: "0 16px 36px rgba(16,185,129,.22)"
        }}>{heroIcon}</div>
        <h1 style={{ fontSize: 28, color: "var(--r26-primary)", margin: "0 0 8px", letterSpacing: "-0.02em" }}>{heroTitle}</h1>
        <p style={{ color: "var(--r26-ink-2)", margin: "0 0 24px", fontSize: 14 }}>
          Soumission <b>{state.quote_id || "brouillon"}</b> · {state.client?.name || "client"} · {C.fmtCAD0(calc?.ttc || 0)} TTC
        </p>
        <p style={{ color: "var(--r26-ink-3)", maxWidth: 480, margin: "0 auto 24px", fontSize: 13 }}>{heroSub}</p>

        {/* Status cards */}
        <div className="r26-grid-3" style={{ marginTop: 24, marginBottom: 24 }}>
          <div className="r26-card" style={{ marginBottom: 0 }}>
            <div className="r26-card-body" style={{ textAlign: "center", padding: "20px 12px" }}>
              <div style={{ width: 36, height: 36, borderRadius: "50%", background: "var(--r26-success)", margin: "0 auto 10px", display: "grid", placeItems: "center", color: "#fff", fontWeight: 700 }}>✓</div>
              <div style={{ fontSize: 13, fontWeight: 700, color: "var(--r26-primary)" }}>Soumission enregistrée</div>
              <div style={{ fontSize: 11, color: "var(--r26-ink-3)", marginTop: 4 }}>BD Supabase · {new Date().toLocaleTimeString("fr-CA")}</div>
            </div>
          </div>
          <div className="r26-card" style={{ marginBottom: 0 }}>
            <div className="r26-card-body" style={{ textAlign: "center", padding: "20px 12px" }}>
              <div style={{ width: 36, height: 36, borderRadius: "50%", background: "var(--r26-accent)", margin: "0 auto 10px", display: "grid", placeItems: "center", color: "#fff", fontWeight: 700 }}>📄</div>
              <div style={{ fontSize: 13, fontWeight: 700, color: "var(--r26-primary)" }}>PDF généré</div>
              <div style={{ fontSize: 11, color: "var(--r26-ink-3)", marginTop: 4 }}>html2canvas + jsPDF · téléchargé</div>
            </div>
          </div>
          <div className="r26-card" style={{ marginBottom: 0 }}>
            <div className="r26-card-body" style={{ textAlign: "center", padding: "20px 12px" }}>
              <div style={{ width: 36, height: 36, borderRadius: "50%", background: isAccept ? "var(--r26-success)" : "var(--r26-warning)", margin: "0 auto 10px", display: "grid", placeItems: "center", color: "#fff", fontWeight: 700 }}>{isAccept ? "✉" : "⏰"}</div>
              <div style={{ fontSize: 13, fontWeight: 700, color: "var(--r26-primary)" }}>{isAccept ? "Contrat envoyé" : "Relance programmée"}</div>
              <div style={{ fontSize: 11, color: "var(--r26-ink-3)", marginTop: 4 }}>{isAccept ? "Courriel client" : "J+5, J+12, J+30"}</div>
            </div>
          </div>
        </div>

        {/* Recap strip */}
        <div className="r26-card">
          <div className="r26-card-body" style={{ padding: 16 }}>
            <div style={{ display: "flex", gap: 8, flexWrap: "wrap", justifyContent: "center" }}>
              {calc?.solarCalc && <span className="r26-chip r26-chip-default">{calc.solarCalc.kw} kW · {calc.solarCalc.panneaux} panneaux 500W</span>}
              {calc?.battery_sell > 0 && <span className="r26-chip r26-chip-default">{calc.battery_label || "Batterie"}</span>}
              {calc?.borneCalc?.qty > 0 && <span className="r26-chip r26-chip-default">{calc.borneCalc.qty}× borne {calc.borneCalc.modele_label}</span>}
              {calc?.total_grant > 0 && <span className="r26-chip r26-chip-default">Subv {C.fmtCAD0(calc.total_grant)}</span>}
              {calc?.fin?.monthly > 0 && <span className="r26-chip r26-chip-default">{C.fmtCAD0(calc.fin.monthly)}/mois</span>}
            </div>
          </div>
        </div>

        {/* Actions */}
        <div className="r26-grid-4" style={{ marginTop: 20 }}>
          <button className="r26-btn r26-btn-primary" style={{ flexDirection: "column", padding: 16 }} onClick={() => { setCancelled(true); onReturnToDashboard?.(); }}>
            <div style={{ fontSize: 14 }}>🏠 Dashboard</div>
            <div style={{ fontSize: 10, opacity: 0.85, marginTop: 2 }}>retour {countdown > 0 && !cancelled ? `(${countdown}s)` : ""}</div>
          </button>
          <button className="r26-btn r26-btn-ghost" style={{ flexDirection: "column", padding: 16 }} onClick={() => { setCancelled(true); onGeneratePDF?.(); }}>
            <div style={{ fontSize: 14 }}>📄 Re-télécharger PDF</div>
            <div style={{ fontSize: 10, opacity: 0.85, marginTop: 2 }}>copie de sauvegarde</div>
          </button>
          <button className="r26-btn r26-btn-ghost" style={{ flexDirection: "column", padding: 16 }} onClick={() => setCancelled(true)}>
            <div style={{ fontSize: 14 }}>✉️ Renvoyer client</div>
            <div style={{ fontSize: 10, opacity: 0.85, marginTop: 2 }}>par courriel</div>
          </button>
          <button className="r26-btn r26-btn-ghost" style={{ flexDirection: "column", padding: 16 }} onClick={() => setCancelled(true)}>
            <div style={{ fontSize: 14 }}>📋 Dupliquer</div>
            <div style={{ fontSize: 10, opacity: 0.85, marginTop: 2 }}>nouveau brouillon</div>
          </button>
        </div>

        {!cancelled && (
          <div style={{ marginTop: 24, fontSize: 12, color: "var(--r26-ink-3)" }}>
            Retour automatique au dashboard dans <b>{countdown}</b> seconde{countdown > 1 ? "s" : ""}
            <button onClick={() => setCancelled(true)} style={{ marginLeft: 8, background: "transparent", border: 0, color: "var(--r26-accent)", cursor: "pointer", fontWeight: 600, textDecoration: "underline" }}>Annuler</button>
          </div>
        )}

        <style>{`@keyframes pop { 0%{transform:scale(0.7);opacity:0} 50%{transform:scale(1.08)} 100%{transform:scale(1);opacity:1} }`}</style>
      </div>
    );
  }

  // ============================================================================
  // MAIN COMPONENT
  // ============================================================================
  function Configurator2026({ state: extState, setState: extSetState, initialState, onSave, onGeneratePDF, user, submissionNumber, hideHeader }) {
    // Controlled (state/setState from props) ou standalone (state interne)
    const [innerState, setInnerState] = useState(() => extState || initialState || buildInitialState2026());
    const state = extState != null ? extState : innerState;
    const setState = extSetState || setInnerState;

    const [currentStep, setCurrentStep] = useState(1);
    const [completedSteps, setCompletedSteps] = useState([]);

    // Calcul live à chaque changement d'état
    const calc = useMemo(() => {
      try {
        return window.RAYCAST_CALC_2026.fullCalc2026(state);
      } catch (e) {
        console.error("fullCalc2026 error:", e);
        return window.RAYCAST_CALC_2026.zeroCalc();
      }
    }, [state]);

    // Mark step complete on next — V3 : skip step 3 (Profil énergétique) si project_type=borne
    const isBorne = state.project_type === "borne";
    const goNext = () => {
      if (!completedSteps.includes(currentStep)) {
        setCompletedSteps([...completedSteps, currentStep]);
      }
      let next = currentStep + 1;
      // V3 : borne saute Profil énergétique (étape 3 → directement étape 4)
      if (next === 3 && isBorne) next = 4;
      setCurrentStep(Math.min(7, next));
    };
    const goBack = () => {
      let prev = currentStep - 1;
      // V3 : retour depuis étape 4 quand borne → directement étape 2 (saute étape 3)
      if (prev === 3 && isBorne) prev = 2;
      setCurrentStep(Math.max(1, prev));
    };
    const goToStep = (idx) => {
      // V3 : empêcher de cliquer sur étape 3 si borne
      if (idx === 3 && isBorne) return;
      setCurrentStep(idx);
    };

    // V7 : scroll-to-top fluide à chaque changement d'étape (directive V2 §5 B.1)
    useEffect(() => {
      try { window.scrollTo({ top: 0, behavior: "smooth" }); }
      catch (e) { window.scrollTo(0, 0); }
    }, [currentStep]);

    const handleSave = () => onSave?.(state, calc);
    const handlePDF = () => onGeneratePDF?.(state, calc);

    // Phase 2 : décisions CTA étape 6 → étape 7 (SubmissionCompletion)
    const handleDecide = (decision) => {
      setState({ ...state, decision_status: decision, decided_at: new Date().toISOString() });
      if (!completedSteps.includes(6)) setCompletedSteps([...completedSteps, 6]);
      setCurrentStep(7);
      // Sauvegarde async + PDF si accept
      if (decision === "accepted") {
        handlePDF();
      }
      handleSave();
    };

    return (
      <div className="r26-app">
        {/* Header (caché si app shell v25 fournit déjà la Toolbar) */}
        {!hideHeader && (
        <header className="r26-header">
          <div className="r26-header-inner">
            <div className="r26-brand">
              <div className="r26-brand-mark">R</div>
              <div className="r26-brand-text">
                <div className="name">RAYCAST</div>
                <div className="sub">Raycom 2026</div>
              </div>
            </div>
            {submissionNumber && (
              <div className="r26-submission">
                <span className="num">#{submissionNumber}</span>
                <span className="divider"></span>
                <span className="client">{state.client.name || "Nouveau client"}</span>
                <span className="divider"></span>
                <span className="auto-save"><span className="dot"></span>auto</span>
              </div>
            )}
            <div className="r26-spacer"></div>
            <div className="r26-actions">
              <button className="r26-h-btn r26-h-btn-pdf" onClick={handlePDF} disabled={calc?.blocking}>
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
                Imprimer PDF
              </button>
              {user && (
                <button className="r26-user">
                  <span className="avatar">{(user.name || "?").substr(0, 1).toUpperCase()}</span>
                  <span className="who">{user.name || "Utilisateur"}<span className="role">{user.role || "—"}</span></span>
                </button>
              )}
            </div>
          </div>
        </header>
        )}

        {/* Stepper */}
        <Stepper
          currentStep={currentStep}
          completedSteps={completedSteps}
          onStepClick={goToStep}
          calc={calc}
          state={state}
        />

        {/* Main grid */}
        <main className="r26-main">
          <div className="r26-grid-main">
            <div>
              {currentStep === 1 && <Step1Type state={state} setState={setState} onNext={goNext} />}
              {currentStep === 2 && <Step2ProfilClient state={state} setState={setState} calc={calc} onBack={goBack} onNext={goNext} />}
              {currentStep === 3 && <Step3ProfilEnergetique state={state} setState={setState} onBack={goBack} onNext={goNext} />}
              {currentStep === 4 && <Step4Config state={state} setState={setState} calc={calc} onBack={goBack} onNext={goNext} />}
              {currentStep === 5 && <Step5Options state={state} setState={setState} onBack={goBack} onNext={goNext} />}
              {currentStep === 6 && <Step6Resume state={state} setState={setState} calc={calc} onBack={goBack} onSave={handleSave} onGeneratePDF={handlePDF} onDecide={handleDecide} />}
              {currentStep === 7 && <SubmissionCompletion state={state} setState={setState} calc={calc} onReturnToDashboard={() => onSave && onSave(state, calc, { goToDashboard: true })} onGeneratePDF={handlePDF} />}
            </div>
            <LivePreview calc={calc} />
          </div>
        </main>
      </div>
    );
  }

  // Expose
  window.Configurator2026 = Configurator2026;
  window.buildInitialState2026 = buildInitialState2026;
})();
