/* global React */
// CRMPage — page dédiée CRM avec tabs Odoo / Audits Énergies / Personnalisation
// Respect Règle n°0 : UI Claude Design structure (aside+main+cards)
// Respect Règle n°6 : onglet Personnalisation obligatoire

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

  // ────────────────────────────────────────────────────────────────────────
  // ClientAnalyzeButton — bouton "🧠 Analyser ce client" (Claude Vision + texte)
  // Appelle /api/intel/client/:id/analyze qui :
  //   1. Récupère TOUTES les données rattachées (opps, devis, visites, dossiers)
  //   2. Analyse chaque photo via Claude Vision (équipements, plaques, factures)
  //   3. Synthétise tout dans un rapport consolidé + recommandations FOST
  //   4. Optionnellement applique les actions (créer drafts CEE, enrichir contact)
  // ────────────────────────────────────────────────────────────────────────
  // contactId = AE contact (depuis tab Audits Énergies), OU odooPartnerId pour Odoo partner, OU quoteId pour devis Odoo
  function ClientAnalyzeButton({ contactId, odooPartnerId, quoteId }) {
    const [busy, setBusy] = useState(false);
    const [open, setOpen] = useState(false);
    const [result, setResult] = useState(null);
    const [error, setError] = useState(null);
    const [applying, setApplying] = useState(false);
    const API = (window.AE_API && window.AE_API.BASE) || '';

    if (!contactId && !odooPartnerId && !quoteId) {
      return (
        <button disabled title="Aucune entité analysable" style={{
          padding: '5px 10px', fontSize: 11,
          background: 'var(--paper-3)', color: 'var(--ink-5)',
          border: '1px solid var(--line)', borderRadius: 4, cursor: 'not-allowed',
        }}>🧠 Analyser</button>
      );
    }

    const run = async () => {
      setBusy(true); setError(null); setResult(null); setOpen(true);
      try {
        let url;
        if (contactId)         url = `${API}/api/intel/client/${contactId}/analyze`;
        else if (odooPartnerId) url = `${API}/api/intel/odoo-partner/${odooPartnerId}/analyze`;
        else                    url = `${API}/api/intel/odoo-quote/${quoteId}/analyze`;
        const r = await fetch(url, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ includeOdoo: true, maxImages: quoteId ? 12 : 8, applyActions: false }),
        }).then(x => x.json());
        if (r.ok) setResult(r);
        else setError(r.error || 'Analyse échouée');
      } catch (e) { setError(e.message); }
      finally { setBusy(false); }
    };

    const apply = async () => {
      if (!result?.consolidated) return;
      if (!contactId) {
        alert('Application automatique disponible uniquement pour les contacts AE.\nPour Odoo, copier manuellement les recommandations dans un nouveau dossier CEE.');
        return;
      }
      if (!confirm('Appliquer les recommandations ? Cela créera les dossiers CEE prioritaires + enrichira la fiche contact.')) return;
      setApplying(true);
      try {
        const r = await fetch(`${API}/api/intel/client/${contactId}/apply`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ analysis: result.consolidated, dryRun: false }),
        }).then(x => x.json());
        if (r.ok) {
          alert('✓ Appliqué : ' + (r.applied?.length || 0) + ' actions exécutées');
          if (window.AE_API?.hydrate) window.AE_API.hydrate();
          setOpen(false);
        } else alert('Erreur : ' + (r.error || 'inconnu'));
      } catch (e) { alert('Erreur : ' + e.message); }
      finally { setApplying(false); }
    };

    return (
      <>
        <button onClick={run} disabled={busy} title="Analyser tous les éléments (photos, devis, visites, notes) avec Claude" style={{
          padding: '5px 10px', fontSize: 11, fontWeight: 600,
          background: busy ? 'var(--paper-3)' : 'var(--copper-tint)',
          color: busy ? 'var(--ink-4)' : 'var(--copper)',
          border: '1px solid var(--copper)', borderRadius: 4, cursor: busy ? 'wait' : 'pointer',
        }}>{busy ? '🧠 Analyse…' : '🧠 Analyser (IA)'}</button>

        {open && (
          <div onClick={() => setOpen(false)} style={{
            position: 'fixed', inset: 0, background: 'rgba(0,0,0,.5)', zIndex: 9999,
            display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24,
          }}>
            <div onClick={e => e.stopPropagation()} style={{
              background: 'var(--paper)', borderRadius: 10, maxWidth: 880, width: '100%',
              maxHeight: '90vh', overflowY: 'auto', boxShadow: '0 8px 40px rgba(0,0,0,.3)',
              fontFamily: 'inherit',
            }}>
              <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', gap: 10 }}>
                <div style={{ fontSize: 16, fontWeight: 700, flex: 1 }}>🧠 Analyse Claude — Contact #{contactId}</div>
                <button onClick={() => setOpen(false)} style={{ padding: 4, fontSize: 16 }}>×</button>
              </div>

              <div style={{ padding: 20 }}>
                {busy && (
                  <div style={{ textAlign: 'center', padding: 40, color: 'var(--ink-3)', fontSize: 13 }}>
                    ⏳ Analyse en cours… Claude examine toutes les pièces jointes (photos, factures, devis), notes et entités liées.
                    <div style={{ fontSize: 11, color: 'var(--ink-4)', marginTop: 8 }}>Peut prendre 20-60s selon le nombre d'images.</div>
                  </div>
                )}
                {error && (
                  <div style={{ padding: 16, background: 'rgba(220,38,38,.06)', border: '1px solid var(--rouge)', borderRadius: 6, color: 'var(--rouge)', fontSize: 12 }}>
                    ❌ {error}
                  </div>
                )}
                {result && <AnalysisResultView result={result} onApply={apply} applying={applying} />}
              </div>
            </div>
          </div>
        )}
      </>
    );
  }

  function AnalysisResultView({ result, onApply, applying }) {
    const c = result.consolidated || {};
    const counts = result.counts || {};
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        {/* Stats analyse */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(6,1fr)', gap: 6 }}>
          {[
            ['Pièces jointes', counts.attachments],
            ['Images analysées', counts.images],
            ['Notes', counts.notes],
            ['Opportunités', counts.opportunities],
            ['Visites', counts.visites],
            ['Devis Odoo', counts.odooQuotes],
          ].map(([l, v]) => (
            <div key={l} style={{ padding: '8px 10px', background: 'var(--paper-2)', border: '1px solid var(--line)', borderRadius: 5, textAlign: 'center' }}>
              <div className="mono" style={{ fontSize: 9, color: 'var(--ink-5)', textTransform: 'uppercase', letterSpacing: '.05em', fontWeight: 600 }}>{l}</div>
              <div style={{ fontSize: 16, fontWeight: 700 }}>{v ?? 0}</div>
            </div>
          ))}
        </div>

        {/* Synthèse */}
        {c.summary && (
          <div style={{ padding: 14, background: 'var(--copper-tint)', border: '1px solid var(--copper)', borderRadius: 6 }}>
            <div className="mono" style={{ fontSize: 9, color: 'var(--copper)', textTransform: 'uppercase', letterSpacing: '.05em', fontWeight: 700, marginBottom: 6 }}>Synthèse Claude</div>
            <div style={{ fontSize: 12, color: 'var(--ink-2)', lineHeight: 1.5 }}>{c.summary}</div>
          </div>
        )}

        {/* Équipements détectés */}
        {c.consolidatedEquipments?.length > 0 && (
          <div>
            <div className="mono" style={{ fontSize: 10, color: 'var(--ink-5)', textTransform: 'uppercase', letterSpacing: '.05em', fontWeight: 600, marginBottom: 6 }}>🔧 Équipements détectés ({c.consolidatedEquipments.length})</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
              {c.consolidatedEquipments.map((e, i) => (
                <div key={i} style={{ display: 'grid', gridTemplateColumns: '90px 1fr 70px 80px 60px', gap: 8, padding: '6px 10px', background: 'var(--paper-2)', border: '1px solid var(--hairline)', borderRadius: 4, fontSize: 11 }}>
                  <span style={{ fontWeight: 600 }}>{e.type}</span>
                  <span>{[e.brand, e.model].filter(Boolean).join(' ') || '—'}</span>
                  <span style={{ textAlign: 'right' }}>{e.power_kw ? e.power_kw + ' kW' : '—'}</span>
                  <span style={{ textAlign: 'right' }}>×{e.qty || 1}</span>
                  <span className="mono" style={{ color: 'var(--ink-5)', fontSize: 9, textAlign: 'right' }}>{e.source}</span>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* FOST recommandés */}
        {c.fostRecommendations?.length > 0 && (
          <div>
            <div className="mono" style={{ fontSize: 10, color: 'var(--ink-5)', textTransform: 'uppercase', letterSpacing: '.05em', fontWeight: 600, marginBottom: 6 }}>📋 FOST recommandés ({c.fostRecommendations.length})</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {c.fostRecommendations.map((f, i) => (
                <div key={i} style={{ padding: 10, background: 'var(--signal-tint)', border: '1px solid var(--signal-soft)', borderRadius: 5 }}>
                  <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: 4 }}>
                    <span className="mono" style={{ fontSize: 11, fontWeight: 700, color: 'var(--signal-deep)' }}>{f.code}</span>
                    <span style={{ fontSize: 12, fontWeight: 600 }}>{f.label}</span>
                    <span style={{ flex: 1 }} />
                    <span className="mono" style={{ fontSize: 10, padding: '1px 6px', background: f.priority === 'high' ? 'var(--rouge)' : f.priority === 'medium' ? 'var(--copper)' : 'var(--ink-5)', color: '#fff', borderRadius: 3, fontWeight: 600, textTransform: 'uppercase' }}>{f.priority}</span>
                  </div>
                  <div style={{ fontSize: 11, color: 'var(--ink-3)', lineHeight: 1.4 }}>{f.rationale}</div>
                  <div style={{ marginTop: 4, fontSize: 11, color: 'var(--ink-4)' }}>
                    ≈ <strong>{(f.kwhCumacEstime || 0).toLocaleString('fr-FR')} kWh cumac</strong> · prime ≈ <strong>{(f.primeEstimee || 0).toLocaleString('fr-FR')} €</strong>
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* Infos manquantes */}
        {c.missingInfo?.length > 0 && (
          <div style={{ padding: 12, background: 'var(--paper-2)', border: '1px dashed var(--copper)', borderRadius: 5 }}>
            <div className="mono" style={{ fontSize: 9, color: 'var(--copper)', textTransform: 'uppercase', letterSpacing: '.05em', fontWeight: 700, marginBottom: 4 }}>⚠ Infos manquantes pour boucler le dossier</div>
            <ul style={{ margin: 0, paddingLeft: 16, fontSize: 11, color: 'var(--ink-3)', lineHeight: 1.5 }}>
              {c.missingInfo.map((m, i) => <li key={i}>{m}</li>)}
            </ul>
          </div>
        )}

        {/* Actions appliquables */}
        {c.fostRecommendations?.filter(f => f.priority === 'high').length > 0 && (
          <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, paddingTop: 8, borderTop: '1px solid var(--hairline)' }}>
            <button onClick={onApply} disabled={applying} style={{
              padding: '8px 16px', borderRadius: 5, fontSize: 12, fontWeight: 600,
              background: applying ? 'var(--paper-3)' : 'var(--ink)', color: applying ? 'var(--ink-4)' : 'var(--paper)',
              border: 'none', cursor: applying ? 'wait' : 'pointer',
            }}>
              {applying ? 'Application…' : '✓ Créer les dossiers CEE prioritaires + enrichir contact'}
            </button>
          </div>
        )}

        {/* Détail images analysées (collapsible) */}
        {result.imageAnalyses?.length > 0 && (
          <details>
            <summary style={{ fontSize: 11, color: 'var(--ink-4)', cursor: 'pointer', padding: 4 }}>📸 Détail des images analysées ({result.imageAnalyses.length})</summary>
            <div style={{ marginTop: 8, display: 'flex', flexDirection: 'column', gap: 6 }}>
              {result.imageAnalyses.map((ia, i) => (
                <div key={i} style={{ padding: 8, background: 'var(--paper-2)', border: '1px solid var(--hairline)', borderRadius: 4, fontSize: 11 }}>
                  <div style={{ fontWeight: 600 }}>{ia.attachmentName || '#' + ia.attachmentId}</div>
                  {ia.ok ? (
                    <pre style={{ margin: '4px 0 0', fontSize: 10, color: 'var(--ink-3)', whiteSpace: 'pre-wrap', maxHeight: 120, overflowY: 'auto' }}>{JSON.stringify(ia.analysis, null, 2)}</pre>
                  ) : (
                    <div style={{ color: 'var(--rouge)', fontSize: 10 }}>❌ {ia.error}</div>
                  )}
                </div>
              ))}
            </div>
          </details>
        )}

        {/* Footer */}
        <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: 'var(--ink-5)', paddingTop: 8 }}>
          <span>Modèle : <span className="mono">{result.model}</span></span>
          <span>Durée : {(result.durationMs / 1000).toFixed(1)}s</span>
        </div>
      </div>
    );
  }


  function CRMPage({ onOpenDossier }) {
    const [tab, setTab] = useState('odoo'); // 'odoo' | 'audits' | 'settings'
    const [odooStatus, setOdooStatus] = useState(null);
    const [odooPartners, setOdooPartners] = useState([]);
    const [odooCount, setOdooCount] = useState(0);
    const [aeContacts, setAeContacts] = useState([]);
    const [aeOrgs, setAeOrgs] = useState([]);
    const [odooLeads, setOdooLeads] = useState([]);
    const [q, setQ] = useState('');
    const [loading, setLoading] = useState(true);
    const [sel, setSel] = useState(null);
    const [syncMsg, setSyncMsg] = useState(null);
    const [syncing, setSyncing] = useState(false);
    const [odooFilter, setOdooFilter] = useState('all'); // 'all' | 'companies' | 'contacts'

    const API = () => (window.AE_API && window.AE_API.BASE) || '';

    useEffect(() => {
      fetch(`${API()}/api/odoo/status`).then(r => r.json()).then(setOdooStatus).catch(() => {});
      Promise.all([
        fetch(`${API()}/api/odoo/partners?limit=500`).then(r => r.json()).catch(() => ({ partners: [] })),
        fetch(`${API()}/api/contacts`).then(r => r.json()).catch(() => []),
        fetch(`${API()}/api/organizations`).then(r => r.json()).catch(() => []),
        fetch(`${API()}/api/odoo/leads?limit=200`).then(r => r.json()).catch(() => ({ leads: [] })),
      ]).then(([partners, contacts, orgs, leads]) => {
        setOdooPartners(partners.partners || []);
        setOdooCount(partners.count || (partners.partners?.length || 0));
        setAeContacts(Array.isArray(contacts) ? contacts : []);
        setAeOrgs(Array.isArray(orgs) ? orgs : []);
        setOdooLeads(leads.leads || []);
        setLoading(false);
      });
    }, []);

    const doSync = async () => {
      setSyncing(true); setSyncMsg(null);
      const r = await fetch(`${API()}/api/odoo/sync`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{"mode":"incremental"}' }).then(r => r.json()).catch(e => ({ error: e.message }));
      setSyncMsg(r?.error ? `⚠ ${r.error}` : `✓ ${r.created || 0} créés, ${r.updated || 0} maj`);
      setTimeout(() => setSyncMsg(null), 4000);
      // Refresh
      const p = await fetch(`${API()}/api/odoo/partners?limit=500`).then(r => r.json()).catch(() => ({ partners: [] }));
      setOdooPartners(p.partners || []);
      setOdooCount(p.count || (p.partners?.length || 0));
      setSyncing(false);
      if (window.AE_API?.hydrate) window.AE_API.hydrate();
    };

    const filtered = useMemo(() => {
      let list = [];
      if (tab === 'odoo') list = odooPartners;
      else if (tab === 'audits') list = aeContacts;
      else if (tab === 'orgs') list = aeOrgs;
      else if (tab === 'leads') list = odooLeads;
      if (tab === 'odoo' && odooFilter === 'companies') list = list.filter(p => p.is_company === true);
      if (tab === 'odoo' && odooFilter === 'contacts') list = list.filter(p => !p.is_company);
      if (!q) return list;
      return list.filter(o => {
        const str = [o.name, o.legalName, o.firstName, o.lastName, o.fullName, o.email, o.phone, o.city, o.company, o.siret, o.siren, o.industry, o.email_from, Array.isArray(o.partner_id) ? o.partner_id[1] : '', Array.isArray(o.stage_id) ? o.stage_id[1] : ''].filter(Boolean).join(' ').toLowerCase();
        return str.includes(q.toLowerCase());
      });
    }, [tab, odooPartners, aeContacts, aeOrgs, odooLeads, q, odooFilter]);

    const companiesCount = odooPartners.filter(p => p.is_company).length;
    const contactsCount = odooPartners.length - companiesCount;

    return (
      <div style={{ padding: '16px 24px 80px' }}>
        {/* Header */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16 }}>
          <h1 style={{ fontSize: 20, fontWeight: 600, letterSpacing: '-0.02em', margin: 0 }}>CRM Clients</h1>
          <span className="mono" style={{ fontSize: 11, color: 'var(--ink-4)', padding: '2px 8px', border: '1px solid var(--line)', borderRadius: 999 }}>
            {odooCount} Odoo · {aeContacts.length} contacts · {aeOrgs.length} orgas
          </span>
          <span style={{ flex: 1 }} />
          <Btn variant="outline" size="sm" onClick={doSync} disabled={syncing}>
            {syncing ? '⏳ Sync…' : syncMsg || '⟳ Sync Odoo'}
          </Btn>
          {tab === 'orgs' && (
            <Btn variant="outline" size="sm" icon={<Icon.plus />} onClick={async () => {
              const name = window.prompt('Nom de l\'organisation (vous pourrez éditer les autres champs après création) :');
              if (!name || !name.trim()) return;
              try {
                const r = await fetch(`${API()}/api/organizations`, {
                  method: 'POST', headers: { 'Content-Type': 'application/json' },
                  body: JSON.stringify({ name: name.trim(), source: 'manual' }),
                }).then(r => r.json());
                if (r?.error) throw new Error(r.error);
                setAeOrgs(os => [...os, r]);
                setSel(r);
                if (window.AE_API?.hydrate) window.AE_API.hydrate();
              } catch (e) { window.alert(`Erreur : ${e.message}`); }
            }}>Nouvelle organisation</Btn>
          )}
          <Btn variant="signal" size="sm" icon={<Icon.plus />} onClick={() => {
            const r = document.createElement('div'); document.body.appendChild(r);
            const rr = ReactDOM.createRoot(r);
            rr.render(React.createElement(window.CreateOpportunityModal, {
              onClose: () => { rr.unmount(); r.remove(); },
              onCreated: () => { if (window.AE_API?.hydrate) window.AE_API.hydrate(); },
            }));
          }}>Nouvelle opp</Btn>
        </div>

        {/* Tabs */}
        <div style={{ display: 'flex', gap: 2, padding: 2, background: 'var(--paper-2)', border: '1px solid var(--line)', borderRadius: 6, width: 'fit-content', marginBottom: 16 }}>
          {[
            { k: 'odoo', l: `Clients Odoo (${odooCount})`, i: '🟣' },
            { k: 'leads', l: `Opps Odoo (${odooLeads.length})`, i: '📊' },
            { k: 'audits', l: `Contacts AE (${aeContacts.length})`, i: '⚡' },
            { k: 'orgs', l: `Organisations (${aeOrgs.length})`, i: '🏢' },
            { k: 'settings', l: '⚙️ Personnalisation', i: '' },
          ].map(t => (
            <button key={t.k} onClick={() => { setTab(t.k); setSel(null); }} style={{
              padding: '6px 14px', fontSize: 12, fontWeight: 500,
              background: tab === t.k ? 'var(--paper)' : 'transparent',
              color: tab === t.k ? 'var(--ink)' : 'var(--ink-3)',
              border: tab === t.k ? '1px solid var(--line)' : '1px solid transparent',
              borderRadius: 4,
            }}>{t.i} {t.l}</button>
          ))}
        </div>

        {/* Settings tab */}
        {tab === 'settings' && <CRMSettings odooStatus={odooStatus} />}

        {/* Odoo / AE list+detail */}
        {tab !== 'settings' && (
          <div style={{ display: 'grid', gridTemplateColumns: '380px 1fr', gap: 14 }}>
            <div style={{ display: 'flex', flexDirection: 'column', border: '1px solid var(--line)', borderRadius: 6, overflow: 'hidden', background: 'var(--paper-2)', maxHeight: 'calc(100vh - 220px)' }}>
              {tab === 'odoo' && (
                <div style={{ display: 'flex', gap: 1, padding: 4, borderBottom: '1px solid var(--hairline)', background: 'var(--paper-2)' }}>
                  {[
                    { k: 'all', l: `Tous (${odooPartners.length})` },
                    { k: 'companies', l: `Entreprises (${companiesCount})` },
                    { k: 'contacts', l: `Contacts (${contactsCount})` },
                  ].map(f => (
                    <button key={f.k} onClick={() => setOdooFilter(f.k)} style={{
                      flex: 1, padding: '4px 6px', fontSize: 10, fontWeight: 500,
                      background: odooFilter === f.k ? 'var(--paper)' : 'transparent',
                      color: odooFilter === f.k ? 'var(--ink)' : 'var(--ink-3)',
                      border: odooFilter === f.k ? '1px solid var(--line)' : '1px solid transparent',
                      borderRadius: 3,
                    }}>{f.l}</button>
                  ))}
                </div>
              )}
              <input value={q} onChange={e => setQ(e.target.value)} placeholder="Rechercher…" style={{ padding: '10px 12px', fontSize: 12, border: 'none', borderBottom: '1px solid var(--hairline)', background: 'var(--paper)' }} />
              <div style={{ flex: 1, overflowY: 'auto' }}>
                {loading && <div style={{ padding: 12, fontSize: 11, color: 'var(--ink-4)' }}>Chargement…</div>}
                {!loading && filtered.length === 0 && (
                  <div style={{ padding: 12, fontSize: 11, color: 'var(--ink-4)' }}>
                    Aucun résultat. {tab === 'audits' && aeContacts.length === 0 && (
                      <div style={{ marginTop: 8, padding: 8, background: 'var(--signal-tint)', borderRadius: 4, color: 'var(--signal-deep)' }}>
                        💡 La base Audits Énergies sync automatiquement les contacts Odoo (partners is_company=false). Clique « Sync Odoo » en haut.
                      </div>
                    )}
                  </div>
                )}
                {filtered.map(o => {
                  if (tab === 'leads') {
                    const partnerName = Array.isArray(o.partner_id) ? o.partner_id[1] : (o.email_from || '—');
                    const stage = Array.isArray(o.stage_id) ? o.stage_id[1] : '—';
                    const amount = Number(o.expected_revenue || 0);
                    return (
                      <button key={o.id} onClick={() => setSel(o)} style={{
                        display: 'block', width: '100%', textAlign: 'left', padding: '10px 12px',
                        background: sel?.id === o.id ? 'var(--paper)' : 'transparent',
                        borderLeft: sel?.id === o.id ? '2px solid var(--signal)' : '2px solid transparent',
                        borderBottom: '1px solid var(--hairline)',
                      }}>
                        <div style={{ fontSize: 12, fontWeight: 600, display: 'flex', alignItems: 'center', gap: 6 }}>
                          <span style={{ fontSize: 8, padding: '1px 4px', background: 'var(--plasma-tint)', color: 'var(--plasma)', borderRadius: 3, fontWeight: 700 }}>📊</span>
                          {o.name || '(sans titre)'}
                        </div>
                        <div style={{ fontSize: 10, color: 'var(--ink-4)' }}>
                          Odoo #{o.id} · {partnerName} · {stage}{amount ? ` · ${new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 }).format(amount)}` : ''}
                        </div>
                      </button>
                    );
                  }
                  const name = o.name || o.fullName || `${o.firstName || ''} ${o.lastName || ''}`.trim();
                  const isCompany = tab === 'odoo' ? o.is_company : (tab === 'orgs' ? true : o.isCompany);
                  const subline = tab === 'odoo'
                    ? `Odoo #${o.id} · ${o.email || o.phone || o.city || '—'}`
                    : tab === 'audits'
                    ? `AE #${o.id}${o.odooId ? ` · Odoo #${o.odooId}` : ''} · ${o.email || o.phone || o.mobile || o.company || '—'}`
                    : `Org AE #${o.id} · ${o.city || o.industry || o.category || '—'} · ${o.contacts?.length || 0} contacts`;
                  return (
                    <button key={o.id} onClick={() => setSel(o)} style={{
                      display: 'block', width: '100%', textAlign: 'left', padding: '10px 12px',
                      background: sel?.id === o.id ? 'var(--paper)' : 'transparent',
                      borderLeft: sel?.id === o.id ? '2px solid var(--signal)' : '2px solid transparent',
                      borderBottom: '1px solid var(--hairline)',
                    }}>
                      <div style={{ fontSize: 12, fontWeight: 600, display: 'flex', alignItems: 'center', gap: 6 }}>
                        {isCompany && <span style={{ fontSize: 8, padding: '1px 4px', background: 'var(--plasma-tint)', color: 'var(--plasma)', borderRadius: 3, fontWeight: 700 }}>🏢</span>}
                        {!isCompany && <span style={{ fontSize: 8, padding: '1px 4px', background: 'var(--signal-tint)', color: 'var(--signal-deep)', borderRadius: 3, fontWeight: 700 }}>👤</span>}
                        {name || '(sans nom)'}
                      </div>
                      <div style={{ fontSize: 10, color: 'var(--ink-4)' }}>{subline}</div>
                    </button>
                  );
                })}
              </div>
            </div>

            <div style={{ border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)', padding: 20, overflow: 'auto', maxHeight: 'calc(100vh - 220px)' }}>
              {!sel && <div style={{ display: 'grid', placeItems: 'center', height: '100%', color: 'var(--ink-4)', fontSize: 12 }}>
                {tab === 'orgs' ? "Sélectionne une organisation pour voir ses détails + contacts rattachés" : tab === 'leads' ? "Sélectionne une opportunité Odoo pour voir ses détails + chatter + relances" : "Sélectionne un client pour voir ses détails + édition + opportunités liées"}
              </div>}
              {sel && tab === 'leads' && <OdooLeadDetail leadId={sel.id} onChanged={() => {}} />}
              {sel && tab === 'orgs' && <OrganizationDetail org={sel}
                onUpdated={(upd) => { setSel(upd); setAeOrgs(os => os.map(o => o.id === upd.id ? upd : o)); }}
                onDeleted={(deletedId) => { setSel(null); setAeOrgs(os => os.filter(o => o.id !== deletedId)); }}
                onOpenContact={(c) => { setTab('audits'); setSel(c); }}
              />}
              {sel && tab !== 'orgs' && tab !== 'leads' && <CRMClientDetail client={sel} mode={tab}
                onUpdated={(upd) => {
                  setSel(upd);
                  if (tab === 'odoo') setOdooPartners(ps => ps.map(p => p.id === upd.id ? upd : p));
                  else setAeContacts(cs => cs.map(c => c.id === upd.id ? upd : c));
                }}
                onDeleted={(deletedId) => {
                  setSel(null);
                  if (tab === 'odoo') setOdooPartners(ps => ps.filter(p => p.id !== deletedId));
                  else setAeContacts(cs => cs.filter(c => c.id !== deletedId));
                }}
                onOpenDossier={onOpenDossier} />}
            </div>
          </div>
        )}
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // ChatterPanel — notes + activities + attachments natifs Discovery
  // Composant polymorphique réutilisable : passe (entityType, entityId).
  // ────────────────────────────────────────────────────────────
  function ChatterPanel({ entityType, entityId }) {
    const API = () => (window.AE_API && window.AE_API.BASE) || '';
    const [notes, setNotes] = useState([]);
    const [activities, setActivities] = useState([]);
    const [attachments, setAttachments] = useState([]);
    const [newNote, setNewNote] = useState('');
    const [newAct, setNewAct] = useState({ summary: '', deadline: '', kind: 'todo' });
    const [busy, setBusy] = useState(false);
    const [uploadBusy, setUploadBusy] = useState(false);

    const base = `${API()}/api/chatter/${entityType}/${entityId}`;

    const reload = () => {
      Promise.all([
        fetch(`${base}/notes`).then(r => r.json()).catch(() => ({ notes: [] })),
        fetch(`${base}/activities`).then(r => r.json()).catch(() => ({ activities: [] })),
        fetch(`${base}/attachments`).then(r => r.json()).catch(() => ({ attachments: [] })),
      ]).then(([n, a, at]) => {
        setNotes(n.notes || []);
        setActivities(a.activities || []);
        setAttachments(at.attachments || []);
      });
    };

    useEffect(() => {
      if (!entityId) return;
      reload();
    }, [entityType, entityId]);

    const addNote = async () => {
      if (!newNote.trim()) return;
      setBusy(true);
      try {
        await fetch(`${base}/notes`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ body: newNote, kind: 'note' }) });
        setNewNote(''); reload();
      } finally { setBusy(false); }
    };

    const addActivity = async () => {
      if (!newAct.summary.trim()) return;
      setBusy(true);
      try {
        await fetch(`${base}/activities`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newAct) });
        setNewAct({ summary: '', deadline: '', kind: 'todo' }); reload();
      } finally { setBusy(false); }
    };

    const toggleActivity = async (a) => {
      const next = a.state === 'done' ? 'open' : 'done';
      await fetch(`${API()}/api/chatter/activities/${a.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ state: next }) });
      reload();
    };

    const deleteActivity = async (id) => {
      if (!window.confirm('Supprimer cette tâche ?')) return;
      await fetch(`${API()}/api/chatter/activities/${id}`, { method: 'DELETE' });
      reload();
    };

    const deleteNote = async (id) => {
      if (!window.confirm('Supprimer cette note ?')) return;
      await fetch(`${API()}/api/chatter/notes/${id}`, { method: 'DELETE' });
      reload();
    };

    const deleteAttachment = async (id) => {
      if (!window.confirm('Supprimer cette pièce jointe ?')) return;
      await fetch(`${API()}/api/chatter/attachment/${id}`, { method: 'DELETE' });
      reload();
    };

    const upload = async (files) => {
      if (!files || !files.length) return;
      setUploadBusy(true);
      try {
        const fd = new FormData();
        Array.from(files).forEach(f => fd.append('files', f));
        await fetch(`${base}/attachments`, { method: 'POST', body: fd });
        reload();
      } finally { setUploadBusy(false); }
    };

    const lbl = { fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 };
    const inp = { padding: '6px 8px', fontSize: 12, border: '1px solid var(--line-2)', borderRadius: 4, background: 'var(--paper-2)', color: 'var(--ink)', fontFamily: 'inherit', boxSizing: 'border-box' };
    const btn = { padding: '5px 12px', fontSize: 11, background: 'var(--signal)', color: 'var(--ink)', border: 'none', borderRadius: 4, fontWeight: 600, cursor: 'pointer' };

    const images = attachments.filter(a => a.mimetype?.startsWith('image/'));
    const others = attachments.filter(a => !a.mimetype?.startsWith('image/'));

    return (
      <div style={{ marginTop: 16, padding: 12, background: 'var(--paper-2)', border: '1px solid var(--hairline)', borderRadius: 6 }}>
        <div style={{ fontSize: 11, color: 'var(--plasma)', fontWeight: 600, marginBottom: 12, display: 'flex', alignItems: 'center', gap: 6 }}>
          <span>💬 Chatter natif Discovery</span>
          <span style={{ fontSize: 10, color: 'var(--ink-4)', fontWeight: 400 }}>notes · relances · photos — stockées en local</span>
        </div>

        {/* Upload + vignettes */}
        <div style={lbl}>Pièces jointes ({attachments.length})</div>
        <label htmlFor={`ch-up-${entityType}-${entityId}`} style={{
          display: 'inline-block', padding: '6px 12px', fontSize: 11, fontWeight: 500,
          background: 'var(--paper)', border: '1px dashed var(--line-2)', borderRadius: 4,
          cursor: uploadBusy ? 'wait' : 'pointer', marginBottom: 8,
        }}>{uploadBusy ? '📤 Envoi…' : '📎 Ajouter fichier(s)'}</label>
        <input id={`ch-up-${entityType}-${entityId}`} type="file" multiple style={{ display: 'none' }}
          onChange={e => { upload(e.target.files); e.target.value = ''; }}/>
        {images.length > 0 && (
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(96px, 1fr))', gap: 6, marginBottom: 8 }}>
            {images.map(a => (
              <div key={a.id} style={{ position: 'relative', aspectRatio: '1', overflow: 'hidden', border: '1px solid var(--hairline)', borderRadius: 4, background: 'var(--paper)' }}>
                <a href={API() + a.url} target="_blank" rel="noopener" title={a.name}>
                  <img src={API() + (a.preview_url || a.url)} alt={a.name} loading="lazy" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}/>
                </a>
                <button onClick={() => deleteAttachment(a.id)} title="Supprimer" style={{ position: 'absolute', top: 2, right: 2, padding: '1px 5px', fontSize: 10, background: 'rgba(0,0,0,.6)', color: '#fff', border: 'none', borderRadius: 3, cursor: 'pointer' }}>×</button>
                <div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, padding: '2px 4px', background: 'rgba(0,0,0,.55)', color: '#fff', fontSize: 9, lineHeight: 1.2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{a.name}</div>
              </div>
            ))}
          </div>
        )}
        {others.length > 0 && (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 4, marginBottom: 8 }}>
            {others.map(a => (
              <div key={a.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 8px', background: 'var(--paper)', border: '1px solid var(--hairline)', borderRadius: 4, fontSize: 11 }}>
                <span>{a.mimetype?.includes('pdf') ? '📄' : '📎'}</span>
                <a href={API() + a.url} target="_blank" rel="noopener" style={{ flex: 1, color: 'var(--ink-2)', textDecoration: 'none' }}>{a.name}</a>
                <span className="mono" style={{ fontSize: 10, color: 'var(--ink-4)' }}>{Math.round((a.fileSize || 0) / 1024)} Ko</span>
                <button onClick={() => deleteAttachment(a.id)} style={{ padding: '2px 6px', fontSize: 10, background: 'var(--rouge-tint)', color: 'var(--rouge)', border: '1px solid var(--rouge)', borderRadius: 3, cursor: 'pointer' }}>×</button>
              </div>
            ))}
          </div>
        )}

        {/* Activities */}
        <div style={{ ...lbl, marginTop: 14 }}>Tâches planifiées ({activities.length})</div>
        <div style={{ display: 'grid', gridTemplateColumns: '110px 1fr 130px auto', gap: 6, marginBottom: 8 }}>
          <select value={newAct.kind} onChange={e => setNewAct(a => ({ ...a, kind: e.target.value }))} style={inp}>
            <option value="todo">📋 Todo</option>
            <option value="call">📞 Appel</option>
            <option value="meeting">📅 RDV</option>
            <option value="relance">🔔 Relance</option>
            <option value="email">📧 Email</option>
          </select>
          <input value={newAct.summary} onChange={e => setNewAct(a => ({ ...a, summary: e.target.value }))} placeholder="Résumé de la tâche…" style={inp}/>
          <input type="date" value={newAct.deadline} onChange={e => setNewAct(a => ({ ...a, deadline: e.target.value }))} style={inp}/>
          <button onClick={addActivity} disabled={busy || !newAct.summary.trim()} style={btn}>+ Ajouter</button>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
          {activities.map(a => {
            const overdue = a.state === 'open' && a.deadline && new Date(a.deadline) < new Date(new Date().toDateString());
            const done = a.state === 'done';
            const icon = { todo: '📋', call: '📞', meeting: '📅', relance: '🔔', email: '📧' }[a.kind] || '•';
            return (
              <div key={a.id} style={{
                display: 'grid', gridTemplateColumns: 'auto 1fr auto auto', gap: 8, alignItems: 'center',
                padding: '6px 10px', background: 'var(--paper)', borderLeft: '3px solid ' + (done ? 'var(--signal)' : overdue ? 'var(--rouge)' : 'var(--plasma)'),
                borderRadius: 3, fontSize: 11, opacity: done ? 0.6 : 1,
              }}>
                <button onClick={() => toggleActivity(a)} title={done ? 'Rouvrir' : 'Marquer fait'} style={{ width: 18, height: 18, padding: 0, fontSize: 12, background: done ? 'var(--signal)' : 'var(--paper-2)', border: '1px solid var(--line-2)', borderRadius: 3, cursor: 'pointer' }}>{done ? '✓' : ''}</button>
                <div style={{ textDecoration: done ? 'line-through' : 'none' }}>
                  <span style={{ marginRight: 4 }}>{icon}</span>
                  <span style={{ fontWeight: 500 }}>{a.summary}</span>
                </div>
                <span style={{ fontSize: 10, color: overdue ? 'var(--rouge)' : 'var(--ink-4)' }}>{a.deadline || '—'}</span>
                <button onClick={() => deleteActivity(a.id)} style={{ padding: '1px 6px', fontSize: 10, background: 'transparent', color: 'var(--ink-4)', border: 'none', cursor: 'pointer' }}>×</button>
              </div>
            );
          })}
        </div>

        {/* Notes */}
        <div style={{ ...lbl, marginTop: 14 }}>Notes ({notes.length})</div>
        <div style={{ display: 'flex', gap: 6, marginBottom: 8 }}>
          <textarea value={newNote} onChange={e => setNewNote(e.target.value)} rows={2} placeholder="Ajouter une note (log interne)…"
            style={{ ...inp, flex: 1, resize: 'vertical' }}/>
          <button onClick={addNote} disabled={busy || !newNote.trim()} style={btn}>+ Note</button>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
          {notes.map(n => (
            <div key={n.id} style={{ padding: '6px 10px', background: 'var(--paper)', borderLeft: '2px solid var(--plasma)', fontSize: 11, position: 'relative' }}>
              <div style={{ fontSize: 10, color: 'var(--ink-4)', marginBottom: 2 }}>
                {n.authorName || n.authorEmail || 'Anonyme'} · {new Date(n.createdAt).toLocaleString('fr-FR')}
              </div>
              <div style={{ color: 'var(--ink-2)', whiteSpace: 'pre-wrap' }}>{n.body}</div>
              <button onClick={() => deleteNote(n.id)} style={{ position: 'absolute', top: 4, right: 4, padding: '1px 6px', fontSize: 10, background: 'transparent', color: 'var(--ink-4)', border: 'none', cursor: 'pointer' }}>×</button>
            </div>
          ))}
        </div>
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // OdooLeadDetail — détail opportunité Odoo (crm.lead) + chatter Odoo + chatter natif
  // ────────────────────────────────────────────────────────────
  function OdooLeadDetail({ leadId, onChanged }) {
    const API = () => (window.AE_API && window.AE_API.BASE) || '';
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [err, setErr] = useState(null);

    useEffect(() => {
      setLoading(true); setErr(null);
      fetch(`${API()}/api/odoo/leads/${leadId}`).then(r => r.json())
        .then(d => { if (d?.status === 'ok') setData(d); else setErr(d?.message || 'Erreur'); })
        .catch(e => setErr(e.message))
        .finally(() => setLoading(false));
    }, [leadId]);

    if (loading) return <div style={{ fontSize: 11, color: 'var(--ink-4)' }}>Chargement opportunité…</div>;
    if (err) return <div style={{ fontSize: 11, color: 'var(--rouge)' }}>⚠ {err}</div>;
    if (!data) return null;
    const { lead, attachments = [], messages = [], activities = [] } = data;
    const partnerName = Array.isArray(lead.partner_id) ? lead.partner_id[1] : (lead.email_from || '—');
    const stage = Array.isArray(lead.stage_id) ? lead.stage_id[1] : '—';
    const owner = Array.isArray(lead.user_id) ? lead.user_id[1] : '—';
    const amount = Number(lead.expected_revenue || 0);
    const fmtEur = (n) => new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 }).format(n || 0);

    return (
      <>
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, borderBottom: '1px solid var(--hairline)', paddingBottom: 12, marginBottom: 12 }}>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 18, fontWeight: 700, display: 'flex', alignItems: 'center', gap: 8 }}>
              📊 {lead.name}
              <span style={{ fontSize: 10, padding: '2px 6px', background: 'var(--plasma-tint)', color: 'var(--plasma)', borderRadius: 3, fontWeight: 600 }}>{stage}</span>
            </div>
            <div style={{ fontSize: 11, color: 'var(--ink-4)' }}>Odoo lead #{lead.id} · {partnerName} · {owner}</div>
          </div>
          <a href={`https://discovery1.odoo.com/odoo/crm/${lead.id}`} target="_blank" rel="noopener" style={{ padding: '5px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4, textDecoration: 'none', color: 'var(--ink-2)' }}>↗ Odoo</a>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10, marginBottom: 14 }}>
          <div><div style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>Montant prévu</div><div className="mono" style={{ fontSize: 14, fontWeight: 600, color: 'var(--signal-deep)' }}>{fmtEur(amount)}</div></div>
          <div><div style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>Probabilité</div><div className="mono" style={{ fontSize: 14, fontWeight: 600 }}>{lead.probability || 0}%</div></div>
          <div><div style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>Date deadline</div><div style={{ fontSize: 12 }}>{lead.date_deadline || '—'}</div></div>
          <div><div style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>Priorité</div><div style={{ fontSize: 12 }}>{lead.priority || '—'}</div></div>
        </div>

        {(lead.email_from || lead.phone || lead.city) && (
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 10, marginBottom: 14, padding: 10, background: 'var(--paper)', borderRadius: 5 }}>
            {lead.email_from && <div><div style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>Email</div><div style={{ fontSize: 11 }}>{lead.email_from}</div></div>}
            {lead.phone && <div><div style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>Téléphone</div><div style={{ fontSize: 11 }}>{lead.phone}</div></div>}
            {(lead.city || lead.zip) && <div><div style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>Ville</div><div style={{ fontSize: 11 }}>{[lead.zip, lead.city].filter(Boolean).join(' ')}</div></div>}
          </div>
        )}

        {lead.description && (
          <div style={{ padding: 10, background: 'var(--paper)', border: '1px solid var(--line)', borderRadius: 5, fontSize: 12, marginBottom: 14, whiteSpace: 'pre-wrap' }}>
            <div style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600, marginBottom: 4 }}>Description</div>
            <div dangerouslySetInnerHTML={{ __html: lead.description }}/>
          </div>
        )}

        {/* Pièces jointes Odoo */}
        {attachments.length > 0 && (() => {
          const images = attachments.filter(a => a.mimetype?.startsWith('image/'));
          const others = attachments.filter(a => !a.mimetype?.startsWith('image/'));
          return (
            <div style={{ marginBottom: 14 }}>
              <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>
                Pièces jointes Odoo ({attachments.length})
              </div>
              {images.length > 0 && (
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(96px, 1fr))', gap: 6, marginBottom: 8 }}>
                  {images.map(a => (
                    <a key={a.id} href={API() + a.url} target="_blank" rel="noopener" title={a.name} style={{ position: 'relative', display: 'block', aspectRatio: '1', overflow: 'hidden', border: '1px solid var(--hairline)', borderRadius: 4, background: 'var(--paper)' }}>
                      <img src={API() + (a.preview_url || a.url)} alt={a.name} loading="lazy" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}/>
                      <div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, padding: '2px 4px', background: 'rgba(0,0,0,.55)', color: '#fff', fontSize: 9, lineHeight: 1.2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{a.name}</div>
                    </a>
                  ))}
                </div>
              )}
              {others.length > 0 && (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                  {others.map(a => (
                    <a key={a.id} href={API() + a.url} target="_blank" rel="noopener" style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 8px', background: 'var(--paper)', border: '1px solid var(--hairline)', borderRadius: 4, fontSize: 11, color: 'var(--ink-2)', textDecoration: 'none' }}>
                      <span>{a.mimetype?.includes('pdf') ? '📄' : '📎'}</span>
                      <span style={{ flex: 1 }}>{a.name}</span>
                      <span className="mono" style={{ fontSize: 10, color: 'var(--ink-4)' }}>{Math.round((a.file_size || 0) / 1024)} Ko</span>
                    </a>
                  ))}
                </div>
              )}
            </div>
          );
        })()}

        {/* Activities Odoo */}
        {activities.length > 0 && (
          <div style={{ marginBottom: 14 }}>
            <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>Tâches planifiées Odoo ({activities.length})</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
              {activities.map(a => {
                const typ = Array.isArray(a.activity_type_id) ? a.activity_type_id[1] : '—';
                const user = Array.isArray(a.user_id) ? a.user_id[1] : '—';
                const overdue = a.date_deadline && new Date(a.date_deadline) < new Date();
                return (
                  <div key={a.id} style={{ display: 'grid', gridTemplateColumns: 'auto 1fr auto', gap: 10, padding: '6px 10px', background: 'var(--paper)', border: '1px solid ' + (overdue ? 'var(--rouge)' : 'var(--hairline)'), borderRadius: 4, fontSize: 11, alignItems: 'center' }}>
                    <span style={{ fontSize: 10, padding: '1px 6px', background: overdue ? 'var(--rouge-tint)' : 'var(--paper-2)', color: overdue ? 'var(--rouge)' : 'var(--ink-3)', borderRadius: 3, fontWeight: 500 }}>{typ}</span>
                    <div><div style={{ fontWeight: 500 }}>{a.summary || typ}</div></div>
                    <div style={{ textAlign: 'right', fontSize: 10, color: overdue ? 'var(--rouge)' : 'var(--ink-4)' }}>{a.date_deadline || '—'}<br/><span style={{ fontSize: 9 }}>{user}</span></div>
                  </div>
                );
              })}
            </div>
          </div>
        )}

        {/* Chatter Odoo */}
        {messages.length > 0 && (
          <div style={{ marginBottom: 14 }}>
            <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>Historique Odoo ({messages.length})</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
              {messages.slice(0, 8).map((m, i) => {
                const author = Array.isArray(m.author_id) ? m.author_id[1] : 'Système';
                return (
                  <div key={m.id || i} style={{ padding: '6px 10px', background: 'var(--paper)', borderLeft: '2px solid var(--plasma)', fontSize: 11 }}>
                    <div style={{ fontSize: 10, color: 'var(--ink-4)', marginBottom: 2 }}>{author} · {m.date}</div>
                    <div style={{ color: 'var(--ink-2)' }} dangerouslySetInnerHTML={{ __html: (m.body || '').replace(/<p>/g, '').replace(/<\/p>/g, '\n').slice(0, 300) }}/>
                  </div>
                );
              })}
            </div>
          </div>
        )}

        {/* Chatter natif Discovery */}
        {window.ChatterPanel && <window.ChatterPanel entityType="odoo_lead" entityId={lead.id}/>}
      </>
    );
  }

  // ────────────────────────────────────────────────────────────
  // CRMClientDetail — détail client avec édition inline + opps liées
  // ────────────────────────────────────────────────────────────
  function CRMClientDetail({ client, mode, onUpdated, onDeleted, onOpenDossier }) {
    const API = () => (window.AE_API && window.AE_API.BASE) || '';
    const [editMode, setEditMode] = useState(false);
    const [draft, setDraft] = useState({});
    const [saving, setSaving] = useState(false);
    const [deleting, setDeleting] = useState(false);
    const [msg, setMsg] = useState(null);
    const [linkedOpps, setLinkedOpps] = useState([]);
    // P6.3 — entités liées (visites, études, devis, emails)
    const [linkedVisites, setLinkedVisites] = useState([]);
    const [linkedEtudes, setLinkedEtudes] = useState([]);
    const [linkedEmails, setLinkedEmails] = useState([]);
    // Bundle Odoo (avatar + attachments + chatter + activities) chargé à la volée
    const [odooBundle, setOdooBundle] = useState({ avatar_url: null, attachments: [], messages: [], activities: [] });
    const [previewLoading, setPreviewLoading] = useState(false);

    useEffect(() => {
      setEditMode(false); setDraft({}); setMsg(null);
      setOdooBundle({ avatar_url: null, attachments: [], messages: [], activities: [] });
      setLinkedVisites([]); setLinkedEtudes([]); setLinkedEmails([]);
      // Fetch opportunités liées
      const partnerKey = mode === 'odoo' ? ['externalId:' + client.id, `odoo:quote:${client.id}`] : [`contactId:${client.id}`];
      fetch(`${API()}/api/crm/opportunities?limit=100`).then(r => r.json()).then(d => {
        const all = d?.opportunities || [];
        const linked = all.filter(o => {
          if (mode === 'odoo') {
            return o.source === 'odoo' && (o.partnerName === client.name || (o.rawData && o.rawData.partner_id && o.rawData.partner_id[0] === client.id));
          }
          return o.contactId === client.id;
        });
        setLinkedOpps(linked);
      }).catch(() => {});

      // P6.3 — Visites liées (filter par contactId pour AE, par partnerName pour Odoo)
      fetch(`${API()}/api/visite?limit=200`).then(r => r.json()).then(d => {
        const all = d?.visits || d?.items || [];
        const linked = all.filter(v => {
          if (mode === 'odoo') return v.clientName === client.name || v.contactId === client.id;
          return v.contactId === client.id;
        });
        setLinkedVisites(linked);
      }).catch(() => {});

      // P6.3 — Études thermiques liées
      fetch(`${API()}/api/thermique-reglementaire/etudes?limit=100`).then(r => r.json()).then(d => {
        const all = Array.isArray(d) ? d : (d?.etudes || []);
        const linked = all.filter(e => {
          if (mode === 'odoo') return e.clientName === client.name;
          return e.contactId === client.id;
        });
        setLinkedEtudes(linked);
      }).catch(() => {});

      // P6.3 — Emails liés (depuis comm inbox)
      const emailField = mode === 'odoo' ? client.email : (client.email || '');
      if (emailField) {
        fetch(`${API()}/api/comm/inbox?search=${encodeURIComponent(emailField)}&limit=20`).then(r => r.json()).then(d => {
          setLinkedEmails(d?.messages || []);
        }).catch(() => {});
      }
      // Fetch détail Odoo complet (photos posées sur la fiche client, log notes, relances)
      if (mode === 'odoo' && client?.id) {
        fetch(`${API()}/api/odoo/partners/${client.id}`).then(r => r.json()).then(d => {
          if (d?.status === 'ok') {
            setOdooBundle({
              avatar_url: d.partner?.avatar_url || null,
              attachments: d.attachments || [],
              messages: d.messages || [],
              activities: d.activities || [],
            });
          }
        }).catch(() => {});
      }
    }, [client?.id, mode]);

    const startEdit = () => {
      if (mode === 'odoo') {
        setDraft({
          name: client.name || '',
          email: client.email || '',
          phone: client.phone || '',
          mobile: client.mobile || '',
          street: client.street || '',
          street2: client.street2 || '',
          city: client.city || '',
          zip: client.zip || '',
          vat: client.vat || '',
          website: client.website || '',
          function: client.function || '',
          is_company: !!client.is_company,
          comment: client.comment || '',
        });
      } else {
        setDraft({
          // identité
          firstName: client.firstName || '',
          lastName: client.lastName || '',
          isCompany: !!client.isCompany,
          title: client.title || '',
          function: client.function || '',
          // coordonnées
          email: client.email || '',
          emailSecondary: client.emailSecondary || '',
          phone: client.phone || '',
          mobile: client.mobile || '',
          website: client.website || '',
          // adresse
          street: client.street || '',
          street2: client.street2 || '',
          city: client.city || '',
          zip: client.zip || '',
          country: client.country || '',
          // société
          company: client.company || '',
          vat: client.vat || '',
          siret: client.siret || '',
          siren: client.siren || '',
          industry: client.industry || '',
          // notes
          notes: client.notes || '',
        });
      }
      setEditMode(true);
    };

    // Suppression (Odoo : tentative unlink → sinon archive ; AE : DELETE /api/contacts)
    const deleteClient = async () => {
      const label = client.name || `${client.firstName || ''} ${client.lastName || ''}`.trim();
      if (!window.confirm(`Supprimer définitivement « ${label} » ?\n\nSi Odoo refuse (devis liés), le contact sera archivé (mis en inactif) à la place.`)) return;
      setDeleting(true); setMsg(null);
      try {
        let r;
        if (mode === 'odoo') {
          r = await fetch(`${API()}/api/odoo/partners/${client.id}`, { method: 'DELETE' }).then(r => r.json());
          if (r?.status === 'error') {
            // Fallback archive si unlink refusé
            r = await fetch(`${API()}/api/odoo/partners/${client.id}?archive=1`, { method: 'DELETE' }).then(r => r.json());
          }
        } else {
          r = await fetch(`${API()}/api/contacts/${client.id}`, { method: 'DELETE' }).then(r => r.json()).catch(() => ({ status: 'ok' }));
        }
        if (r?.error || r?.status === 'error') throw new Error(r.error || r.message);
        setMsg(r.archived ? '✓ Archivé (devis liés empêchaient la suppression)' : '✓ Supprimé');
        if (onDeleted) onDeleted(client.id);
        if (window.AE_API?.hydrate) window.AE_API.hydrate();
      } catch (e) {
        setMsg(`⚠ ${e.message}`);
      } finally { setDeleting(false); }
    };
    const save = async () => {
      setSaving(true); setMsg(null);
      try {
        const url = mode === 'odoo' ? `${API()}/api/odoo/partners/${client.id}` : `${API()}/api/contacts/${client.id}`;
        const method = mode === 'odoo' ? 'PATCH' : 'PUT';
        const r = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(draft) }).then(r => r.json());
        if (r?.error || r?.status === 'error') throw new Error(r.error || r.message);
        onUpdated({ ...client, ...draft });
        setEditMode(false);
        setMsg('✓ Enregistré');
        if (window.AE_API?.hydrate) window.AE_API.hydrate();
        setTimeout(() => setMsg(null), 3000);
      } catch (e) {
        setMsg(`⚠ ${e.message}`);
      } finally { setSaving(false); }
    };

    const previewPortal = async () => {
      setPreviewLoading(true); setMsg(null);
      try {
        // 1. Cherche un dossier CEE lié via les opps déjà chargées
        let dossierId = linkedOpps.find(o => o.ceeDossierId)?.ceeDossierId || null;
        // 2. Si rien dans les opps, cherche directement dans les dossiers du contact
        if (!dossierId) {
          const param = mode === 'odoo' ? `odooPartnerId=${client.id}` : `contactId=${client.id}`;
          const d = await fetch(`${API()}/api/cee/drafts?${param}&limit=5`).then(r => r.json()).catch(() => null);
          dossierId = (d?.drafts || d?.dossiers || [])[0]?.id || null;
        }
        if (!dossierId) throw new Error('Aucun dossier CEE trouvé pour ce contact. Créez un dossier depuis l\'onglet Dossiers CEE.');
        const r = await fetch(`${API()}/api/client-portal/invite`, {
          method: 'POST', headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ dossierId, preview: true }),
        }).then(x => x.json());
        if (!r?.ok) throw new Error(r?.error || 'Échec génération du lien');
        window.open(r.portalUrl, '_blank');
      } catch (e) {
        setMsg(`⚠ Vue client : ${e.message}`);
        setTimeout(() => setMsg(null), 5000);
      } finally { setPreviewLoading(false); }
    };

    const inputStyle = { padding: '6px 8px', fontSize: 12, border: '1px solid var(--line-2)', borderRadius: 4, background: 'var(--paper)', color: 'var(--ink)', fontFamily: 'inherit', width: '100%', boxSizing: 'border-box' };
    const name = client.name || `${client.firstName || ''} ${client.lastName || ''}`.trim();

    return (
      <>
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, borderBottom: '1px solid var(--hairline)', paddingBottom: 12, marginBottom: 12 }}>
          {odooBundle.avatar_url && (
            <img src={API() + odooBundle.avatar_url} alt="" style={{
              width: 42, height: 42, borderRadius: '50%', objectFit: 'cover',
              border: '1px solid var(--hairline)', flexShrink: 0,
            }}/>
          )}
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 18, fontWeight: 700 }}>{name}</div>
            <div style={{ fontSize: 11, color: 'var(--ink-4)' }}>
              {mode === 'odoo' ? `Odoo partner #${client.id}` : `Contact AE #${client.id}`} · {client.email || '—'}
            </div>
          </div>
          {!editMode
            ? <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
                <ClientAnalyzeButton contactId={mode === 'odoo' ? null : client.id} odooPartnerId={mode === 'odoo' ? client.id : null} />
                <button
                  onClick={previewPortal}
                  disabled={previewLoading}
                  title="Ouvrir la vue portail client (lien aperçu 2h)"
                  style={{ padding: '5px 10px', fontSize: 11, background: 'var(--signal-tint)', border: '1px solid var(--signal-soft)', borderRadius: 4, color: 'var(--signal-deep)', fontWeight: 600, cursor: 'pointer' }}>
                  {previewLoading ? '…' : '🌐 Vue client'}
                </button>
                <button onClick={startEdit} style={{ padding: '5px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>✏️ Éditer</button>
                <button onClick={deleteClient} disabled={deleting} style={{ padding: '5px 10px', fontSize: 11, background: 'var(--rouge-tint)', color: 'var(--rouge)', border: '1px solid var(--rouge)', borderRadius: 4 }}>{deleting ? '…' : '🗑 Supprimer'}</button>
              </div>
            : <div style={{ display: 'flex', gap: 6 }}>
                <button onClick={() => setEditMode(false)} disabled={saving} style={{ padding: '5px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>Annuler</button>
                <button onClick={save} disabled={saving} style={{ padding: '5px 12px', fontSize: 11, background: 'var(--signal)', color: 'var(--ink)', border: 'none', borderRadius: 4, fontWeight: 600 }}>{saving ? '…' : '✓ Enregistrer'}</button>
              </div>}
        </div>

        {msg && <div style={{ marginBottom: 10, padding: '6px 10px', fontSize: 11, background: msg.startsWith('⚠') ? 'var(--rouge-tint)' : 'var(--signal-tint)', border: '1px solid ' + (msg.startsWith('⚠') ? 'var(--rouge)' : 'var(--signal-soft)'), borderRadius: 5, color: msg.startsWith('⚠') ? 'var(--rouge)' : 'var(--signal-deep)' }}>{msg}</div>}

        {!editMode ? (
          <>
            {/* Infos */}
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 18 }}>
              {mode === 'odoo' ? (
                <>
                  <Kv3 label="Type" v={client.is_company ? '🏢 Société' : '👤 Personne physique'} />
                  <Kv3 label="Fonction" v={client.function} />
                  <Kv3 label="Email" v={client.email} />
                  <Kv3 label="Téléphone" v={client.phone} />
                  <Kv3 label="Mobile" v={client.mobile} />
                  <Kv3 label="Ville" v={client.city} />
                  <Kv3 label="Code postal" v={client.zip} />
                  <Kv3 label="Adresse" v={[client.street, client.street2].filter(Boolean).join(', ')} full />
                  <Kv3 label="VAT / SIRET" v={client.vat} />
                  <Kv3 label="Site web" v={client.website} />
                  <Kv3 label="Commentaire" v={client.comment} full />
                </>
              ) : (
                <>
                  <Kv3 label="Type" v={client.isCompany ? '🏢 Société' : '👤 Personne physique'} />
                  <Kv3 label="Civilité" v={client.title} />
                  <Kv3 label="Prénom" v={client.firstName} />
                  <Kv3 label="Nom" v={client.lastName} />
                  <Kv3 label="Fonction" v={client.function} />
                  <Kv3 label="Organisation" v={client.organization?.name || client.company || client.organizationId} />
                  <Kv3 label="Email principal" v={client.email} />
                  <Kv3 label="Email secondaire" v={client.emailSecondary} />
                  <Kv3 label="Téléphone" v={client.phone} />
                  <Kv3 label="Mobile" v={client.mobile} />
                  <Kv3 label="Site web" v={client.website} />
                  <Kv3 label="Industrie" v={client.industry} />
                  <Kv3 label="Adresse" v={[client.street, client.street2].filter(Boolean).join(', ')} full />
                  <Kv3 label="Code postal" v={client.zip} />
                  <Kv3 label="Ville" v={client.city} />
                  <Kv3 label="SIRET" v={client.siret} />
                  <Kv3 label="VAT" v={client.vat} />
                  {client.notes && <Kv3 label="Notes" v={client.notes} full />}
                </>
              )}
            </div>

            {/* Opps liées */}
            <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>Opportunités liées ({linkedOpps.length})</div>
            {linkedOpps.length === 0 && <div style={{ fontSize: 11, color: 'var(--ink-4)', padding: 10 }}>Aucune opp liée. Crée-en une depuis « Nouvelle opp ».</div>}
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {linkedOpps.map(o => (
                <div key={o.id} style={{ display: 'grid', gridTemplateColumns: 'auto 1fr auto auto', gap: 10, padding: '8px 10px', background: 'var(--paper)', border: '1px solid var(--hairline)', borderRadius: 5, fontSize: 11, alignItems: 'center' }}>
                  <span className="mono" style={{ fontSize: 10, padding: '1px 5px', background: 'var(--paper-2)', borderRadius: 3, color: 'var(--ink-3)' }}>{o.reference || o.name}</span>
                  <div>
                    <div style={{ fontWeight: 500 }}>{o.name}</div>
                    <div style={{ fontSize: 10, color: 'var(--ink-4)' }}>{o.discoveryStage} · {o.source}</div>
                  </div>
                  <span className="mono" style={{ fontSize: 11, color: 'var(--signal-deep)' }}>{Math.round(parseFloat(o.amount || 0))} €</span>
                  {onOpenDossier && <button onClick={() => onOpenDossier({ ref: o.reference || o.name, client: o.partnerName, fost: '—', fostName: o.name, cumac: 0, amount: Math.round(parseFloat(o.amount || 0)), stage: o.discoveryStage, city: '—', zone: '—', owner: o.ownerName, risk: 50, coherence: 0, pieces: { ok: 0, total: 10 }, signatures: { done: 0, total: 3 } })} style={{ fontSize: 10, padding: '2px 8px', background: 'var(--paper-2)', border: '1px solid var(--line-2)', borderRadius: 3 }}>Ouvrir</button>}
                </div>
              ))}
            </div>

            {/* P6.3 — Visites liées */}
            {linkedVisites.length > 0 && (
              <div style={{ marginTop: 16 }}>
                <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>📹 Visites IA liées ({linkedVisites.length})</div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                  {linkedVisites.map(v => (
                    <div key={v.id} style={{ display: 'grid', gridTemplateColumns: 'auto 1fr auto auto', gap: 10, padding: '8px 10px', background: 'var(--paper)', border: '1px solid var(--hairline)', borderRadius: 5, fontSize: 11, alignItems: 'center' }}>
                      <span className="mono" style={{ fontSize: 10, padding: '1px 5px', background: 'var(--paper-2)', borderRadius: 3, color: 'var(--ink-3)' }}>{v.ref}</span>
                      <div>
                        <div style={{ fontWeight: 500 }}>{v.type || 'video'} · {v.technicianName || '—'}</div>
                        <div style={{ fontSize: 10, color: 'var(--ink-4)' }}>{v.status} · {v.startedAt ? new Date(v.startedAt).toLocaleDateString('fr-FR') : '—'}</div>
                      </div>
                      <span className="mono" style={{ fontSize: 11, color: 'var(--signal-deep)' }}>{Math.round((v.durationSeconds || 0) / 60)}min</span>
                      <button onClick={() => window.AE_NAV?.('visites')} style={{ fontSize: 10, padding: '2px 8px', background: 'var(--paper-2)', border: '1px solid var(--line-2)', borderRadius: 3 }}>Ouvrir ↗</button>
                    </div>
                  ))}
                </div>
              </div>
            )}

            {/* P6.3 — Études thermiques liées */}
            {linkedEtudes.length > 0 && (
              <div style={{ marginTop: 16 }}>
                <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>📐 Études réglementaires ({linkedEtudes.length})</div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                  {linkedEtudes.map(e => (
                    <div key={e.id} style={{ display: 'grid', gridTemplateColumns: 'auto 1fr auto', gap: 10, padding: '8px 10px', background: 'var(--paper)', border: '1px solid var(--hairline)', borderRadius: 5, fontSize: 11, alignItems: 'center' }}>
                      <span className="mono" style={{ fontSize: 10, padding: '1px 5px', background: 'var(--paper-2)', borderRadius: 3, color: 'var(--ink-3)' }}>{e.ref || `#${e.id}`}</span>
                      <div>
                        <div style={{ fontWeight: 500 }}>{e.methode || '3CL-DPE'} · {e.resultats?.classes?.classeFinale || '—'}</div>
                        <div style={{ fontSize: 10, color: 'var(--ink-4)' }}>{e.status} · {e.createdAt ? new Date(e.createdAt).toLocaleDateString('fr-FR') : '—'}</div>
                      </div>
                      <button onClick={() => window.AE_NAV?.('etudes-reg')} style={{ fontSize: 10, padding: '2px 8px', background: 'var(--paper-2)', border: '1px solid var(--line-2)', borderRadius: 3 }}>Ouvrir ↗</button>
                    </div>
                  ))}
                </div>
              </div>
            )}

            {/* P6.3 — Emails reçus de ce client */}
            {linkedEmails.length > 0 && (
              <div style={{ marginTop: 16 }}>
                <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>✉️ Emails reçus ({linkedEmails.length})</div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                  {linkedEmails.slice(0, 5).map(em => (
                    <div key={em.id} style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: 8, padding: '6px 10px', background: 'var(--paper)', border: '1px solid var(--hairline)', borderRadius: 4, fontSize: 11 }}>
                      <div style={{ minWidth: 0, overflow: 'hidden' }}>
                        <div style={{ fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{em.subject || '(sans objet)'}</div>
                        <div style={{ fontSize: 10, color: 'var(--ink-4)' }}>{em.receivedAt ? new Date(em.receivedAt).toLocaleString('fr-FR') : ''}</div>
                      </div>
                      <button onClick={() => window.AE_NAV?.('comm')} style={{ fontSize: 10, padding: '2px 8px', background: 'var(--paper-2)', border: '1px solid var(--line-2)', borderRadius: 3, whiteSpace: 'nowrap' }}>Ouvrir ↗</button>
                    </div>
                  ))}
                  {linkedEmails.length > 5 && (
                    <button onClick={() => window.AE_NAV?.('comm')} style={{ fontSize: 11, padding: 6, color: 'var(--ink-3)', textAlign: 'center', background: 'transparent', border: 'none' }}>
                      Voir tous les {linkedEmails.length} emails →
                    </button>
                  )}
                </div>
              </div>
            )}

            {/* Photos/docs attachés à la fiche client Odoo */}
            {mode === 'odoo' && odooBundle.attachments.length > 0 && (() => {
              const images = odooBundle.attachments.filter(a => a.mimetype?.startsWith('image/'));
              const others = odooBundle.attachments.filter(a => !a.mimetype?.startsWith('image/'));
              return (
                <div style={{ marginTop: 16 }}>
                  <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>
                    Pièces jointes ({odooBundle.attachments.length})
                  </div>
                  {images.length > 0 && (
                    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(96px, 1fr))', gap: 6, marginBottom: 8 }}>
                      {images.map(a => (
                        <a key={a.id} href={API() + a.url} target="_blank" rel="noopener" title={a.name} style={{
                          position: 'relative', display: 'block', aspectRatio: '1', overflow: 'hidden',
                          border: '1px solid var(--hairline)', borderRadius: 4, background: 'var(--paper)',
                          textDecoration: 'none',
                        }}>
                          <img src={API() + (a.preview_url || a.url)} alt={a.name} loading="lazy" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}/>
                          <div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, padding: '2px 4px', background: 'rgba(0,0,0,.55)', color: '#fff', fontSize: 9, lineHeight: 1.2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{a.name}</div>
                        </a>
                      ))}
                    </div>
                  )}
                  {others.length > 0 && (
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
                      {others.map(a => (
                        <a key={a.id} href={API() + a.url} target="_blank" rel="noopener" style={{
                          display: 'flex', alignItems: 'center', gap: 8, padding: '6px 10px',
                          background: 'var(--paper)', border: '1px solid var(--hairline)', borderRadius: 4,
                          fontSize: 12, color: 'var(--ink-2)', textDecoration: 'none',
                        }}>
                          <span style={{ fontSize: 14 }}>{a.mimetype?.includes('pdf') ? '📄' : '📎'}</span>
                          <span style={{ flex: 1 }}>{a.name}</span>
                          <span className="mono" style={{ fontSize: 10, color: 'var(--ink-4)' }}>{Math.round((a.file_size || 0) / 1024)} Ko</span>
                        </a>
                      ))}
                    </div>
                  )}
                </div>
              );
            })()}

            {/* Activities Odoo (relances, appels à faire) */}
            {mode === 'odoo' && odooBundle.activities.length > 0 && (
              <div style={{ marginTop: 16 }}>
                <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>
                  Tâches planifiées ({odooBundle.activities.length})
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
                  {odooBundle.activities.map(a => {
                    const typ = Array.isArray(a.activity_type_id) ? a.activity_type_id[1] : '—';
                    const user = Array.isArray(a.user_id) ? a.user_id[1] : '—';
                    const overdue = a.date_deadline && new Date(a.date_deadline) < new Date();
                    return (
                      <div key={a.id} style={{
                        display: 'grid', gridTemplateColumns: 'auto 1fr auto', gap: 10, padding: '6px 10px',
                        background: 'var(--paper)', border: '1px solid ' + (overdue ? 'var(--rouge)' : 'var(--hairline)'),
                        borderRadius: 4, fontSize: 11, alignItems: 'center',
                      }}>
                        <span style={{ fontSize: 10, padding: '1px 6px', background: overdue ? 'var(--rouge-tint)' : 'var(--paper-2)', color: overdue ? 'var(--rouge)' : 'var(--ink-3)', borderRadius: 3, fontWeight: 500 }}>{typ}</span>
                        <div>
                          <div style={{ fontWeight: 500 }}>{a.summary || typ}</div>
                          {a.note && <div style={{ fontSize: 10, color: 'var(--ink-4)' }} dangerouslySetInnerHTML={{ __html: (a.note || '').replace(/<[^>]+>/g, '').slice(0, 150) }}/>}
                        </div>
                        <div style={{ textAlign: 'right', fontSize: 10, color: overdue ? 'var(--rouge)' : 'var(--ink-4)' }}>
                          {a.date_deadline || '—'}<br/><span style={{ fontSize: 9 }}>{user}</span>
                        </div>
                      </div>
                    );
                  })}
                </div>
              </div>
            )}

            {/* RDV liés au contact (règle n°3 Interconnexion) */}
            {window.ContactAppointmentsPanel && client.id && (
              <window.ContactAppointmentsPanel client={client} mode={mode} />
            )}

            {/* Chatter natif Discovery (notes + activities + attachments) */}
            <ChatterPanel
              entityType={mode === 'odoo' ? 'odoo_partner' : 'contact'}
              entityId={client.id}
            />

            {/* Chatter Odoo (log notes + emails) */}
            {mode === 'odoo' && odooBundle.messages.length > 0 && (
              <div style={{ marginTop: 16 }}>
                <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>
                  Historique ({odooBundle.messages.length})
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
                  {odooBundle.messages.slice(0, 8).map((m, i) => {
                    const author = Array.isArray(m.author_id) ? m.author_id[1] : 'Système';
                    return (
                      <div key={m.id || i} style={{ padding: '6px 10px', background: 'var(--paper)', borderLeft: '2px solid var(--plasma)', fontSize: 11 }}>
                        <div style={{ fontSize: 10, color: 'var(--ink-4)', marginBottom: 2 }}>{author} · {m.date}</div>
                        <div style={{ color: 'var(--ink-2)' }} dangerouslySetInnerHTML={{ __html: (m.body || '').replace(/<p>/g, '').replace(/<\/p>/g, '\n').slice(0, 300) }}/>
                      </div>
                    );
                  })}
                </div>
              </div>
            )}
          </>
        ) : (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            {mode === 'odoo' ? (
              <>
                <EditF3 label="Nom" v={draft.name} onChange={v => setDraft(d => ({ ...d, name: v }))} full />
                {/* Type partner */}
                <div style={{ gridColumn: '1 / -1', display: 'flex', gap: 6 }}>
                  {[
                    { k: false, l: '👤 Personne physique' },
                    { k: true,  l: '🏢 Société' },
                  ].map(o => (
                    <button key={String(o.k)} type="button" onClick={() => setDraft(d => ({ ...d, is_company: o.k }))}
                      style={{
                        padding: '6px 12px', fontSize: 11, fontWeight: 500, cursor: 'pointer',
                        background: draft.is_company === o.k ? 'var(--ink)' : 'var(--paper)',
                        color: draft.is_company === o.k ? 'var(--paper)' : 'var(--ink-2)',
                        border: '1px solid var(--line-2)', borderRadius: 4,
                      }}>{o.l}</button>
                  ))}
                </div>
                <EditF3 label="Email" v={draft.email} onChange={v => setDraft(d => ({ ...d, email: v }))} type="email" />
                <EditF3 label="Téléphone" v={draft.phone} onChange={v => setDraft(d => ({ ...d, phone: v }))} />
                <EditF3 label="Mobile" v={draft.mobile} onChange={v => setDraft(d => ({ ...d, mobile: v }))} />
                <EditF3 label={draft.is_company ? 'Poste (interlocuteur)' : 'Fonction'} v={draft.function} onChange={v => setDraft(d => ({ ...d, function: v }))} />
                <EditF3 label="Adresse ligne 1" v={draft.street} onChange={v => setDraft(d => ({ ...d, street: v }))} full />
                <EditF3 label="Adresse ligne 2 (bât., étage…)" v={draft.street2} onChange={v => setDraft(d => ({ ...d, street2: v }))} full />
                <EditF3 label="Code postal" v={draft.zip} onChange={v => setDraft(d => ({ ...d, zip: v }))} />
                <EditF3 label="Ville" v={draft.city} onChange={v => setDraft(d => ({ ...d, city: v }))} />
                <EditF3 label="N° TVA / SIRET" v={draft.vat} onChange={v => setDraft(d => ({ ...d, vat: v }))} />
                <EditF3 label="Site web" v={draft.website} onChange={v => setDraft(d => ({ ...d, website: v }))} type="url" />
                <EditF3 label="Commentaire interne" v={draft.comment} onChange={v => setDraft(d => ({ ...d, comment: v }))} full textarea />
              </>
            ) : (
              <>
                {/* Type */}
                <div style={{ gridColumn: '1 / -1', display: 'flex', gap: 6 }}>
                  {[
                    { k: false, l: '👤 Personne physique' },
                    { k: true,  l: '🏢 Société' },
                  ].map(o => (
                    <button key={String(o.k)} type="button" onClick={() => setDraft(d => ({ ...d, isCompany: o.k }))}
                      style={{
                        padding: '6px 12px', fontSize: 11, fontWeight: 500, cursor: 'pointer',
                        background: draft.isCompany === o.k ? 'var(--ink)' : 'var(--paper)',
                        color: draft.isCompany === o.k ? 'var(--paper)' : 'var(--ink-2)',
                        border: '1px solid var(--line-2)', borderRadius: 4,
                      }}>{o.l}</button>
                  ))}
                </div>

                <EditF3 label="Civilité" v={draft.title} onChange={v => setDraft(d => ({ ...d, title: v }))} />
                <EditF3 label="Fonction / poste" v={draft.function} onChange={v => setDraft(d => ({ ...d, function: v }))} />
                <EditF3 label="Prénom" v={draft.firstName} onChange={v => setDraft(d => ({ ...d, firstName: v }))} />
                <EditF3 label="Nom" v={draft.lastName} onChange={v => setDraft(d => ({ ...d, lastName: v }))} />

                <EditF3 label="Email principal" v={draft.email} onChange={v => setDraft(d => ({ ...d, email: v }))} type="email" />
                <EditF3 label="Email secondaire" v={draft.emailSecondary} onChange={v => setDraft(d => ({ ...d, emailSecondary: v }))} type="email" />
                <EditF3 label="Téléphone" v={draft.phone} onChange={v => setDraft(d => ({ ...d, phone: v }))} />
                <EditF3 label="Mobile" v={draft.mobile} onChange={v => setDraft(d => ({ ...d, mobile: v }))} />
                <EditF3 label="Site web" v={draft.website} onChange={v => setDraft(d => ({ ...d, website: v }))} type="url" />

                <EditF3 label="Adresse ligne 1" v={draft.street} onChange={v => setDraft(d => ({ ...d, street: v }))} full />
                <EditF3 label="Adresse ligne 2" v={draft.street2} onChange={v => setDraft(d => ({ ...d, street2: v }))} full />
                <EditF3 label="Code postal" v={draft.zip} onChange={v => setDraft(d => ({ ...d, zip: v }))} />
                <EditF3 label="Ville" v={draft.city} onChange={v => setDraft(d => ({ ...d, city: v }))} />
                <EditF3 label="Pays" v={draft.country} onChange={v => setDraft(d => ({ ...d, country: v }))} />
                <EditF3 label="Industrie" v={draft.industry} onChange={v => setDraft(d => ({ ...d, industry: v }))} />

                <EditF3 label="Société (texte libre)" v={draft.company} onChange={v => setDraft(d => ({ ...d, company: v }))} />
                <EditF3 label="SIRET" v={draft.siret} onChange={v => setDraft(d => ({ ...d, siret: v }))} />
                <EditF3 label="SIREN" v={draft.siren} onChange={v => setDraft(d => ({ ...d, siren: v }))} />
                <EditF3 label="VAT (n° TVA)" v={draft.vat} onChange={v => setDraft(d => ({ ...d, vat: v }))} />

                <EditF3 label="Notes internes" v={draft.notes} onChange={v => setDraft(d => ({ ...d, notes: v }))} full textarea />
              </>
            )}
          </div>
        )}
      </>
    );

    function Kv3({ label, v, full }) {
      return (
        <div style={{ gridColumn: full ? '1 / -1' : 'auto' }}>
          <div style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>{label}</div>
          <div style={{ fontSize: 12, color: v ? 'var(--ink)' : 'var(--ink-4)', fontWeight: v ? 500 : 400 }}>{v || '—'}</div>
        </div>
      );
    }
    function EditF3({ label, v, onChange, type, textarea, full }) {
      return (
        <div style={{ gridColumn: full ? '1 / -1' : 'auto', display: 'flex', flexDirection: 'column', gap: 3 }}>
          <span style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>{label}</span>
          {textarea
            ? <textarea value={v || ''} onChange={e => onChange(e.target.value)} rows={2} style={{ ...inputStyle, resize: 'vertical' }} />
            : <input type={type || 'text'} value={v || ''} onChange={e => onChange(e.target.value)} style={inputStyle} />}
        </div>
      );
    }
  }

  // ────────────────────────────────────────────────────────────
  // OrganizationDetail — détail organisation avec édition inline
  // Règle 5 CRUD : read + update + delete + contacts rattachés
  // ────────────────────────────────────────────────────────────
  function OrganizationDetail({ org, onUpdated, onDeleted, onOpenContact }) {
    const API = () => (window.AE_API && window.AE_API.BASE) || '';
    const [editMode, setEditMode] = useState(false);
    const [draft, setDraft] = useState({});
    const [saving, setSaving] = useState(false);
    const [deleting, setDeleting] = useState(false);
    const [msg, setMsg] = useState(null);

    useEffect(() => { setEditMode(false); setDraft({}); setMsg(null); }, [org?.id]);

    const startEdit = () => {
      setDraft({
        name: org.name || '', legalName: org.legalName || '', description: org.description || '',
        siret: org.siret || '', siren: org.siren || '', vat: org.vat || '', legalForm: org.legalForm || '',
        phone: org.phone || '', email: org.email || '', website: org.website || '',
        address: org.address || '', address2: org.address2 || '', city: org.city || '', zip: org.zip || '', country: org.country || '',
        industry: org.industry || '', category: org.category || '', size: org.size || '',
        notes: org.notes || '',
      });
      setEditMode(true);
    };

    const save = async () => {
      setSaving(true); setMsg(null);
      try {
        const r = await fetch(`${API()}/api/organizations/${org.id}`, {
          method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(draft),
        }).then(r => r.json());
        if (r?.error) throw new Error(r.error);
        onUpdated(r);
        setEditMode(false);
        setMsg('✓ Enregistré');
        if (window.AE_API?.hydrate) window.AE_API.hydrate();
        setTimeout(() => setMsg(null), 3000);
      } catch (e) { setMsg(`⚠ ${e.message}`); } finally { setSaving(false); }
    };

    const deleteOrg = async () => {
      if (!window.confirm(`Supprimer définitivement « ${org.name} » ?\n\nCascade : les contacts rattachés seront détachés (organizationId → null), pas supprimés.`)) return;
      setDeleting(true); setMsg(null);
      try {
        const r = await fetch(`${API()}/api/organizations/${org.id}`, { method: 'DELETE' }).then(r => r.json());
        if (r?.error) throw new Error(r.error);
        if (onDeleted) onDeleted(org.id);
        if (window.AE_API?.hydrate) window.AE_API.hydrate();
      } catch (e) { setMsg(`⚠ ${e.message}`); } finally { setDeleting(false); }
    };

    const inputStyle = { padding: '6px 8px', fontSize: 12, border: '1px solid var(--line-2)', borderRadius: 4, background: 'var(--paper)', color: 'var(--ink)', fontFamily: 'inherit', width: '100%', boxSizing: 'border-box' };
    const kvLabel = { fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 };
    const Kv = ({ label, v, full }) => (
      <div style={{ gridColumn: full ? '1 / -1' : 'auto' }}>
        <div style={kvLabel}>{label}</div>
        <div style={{ fontSize: 12, color: v ? 'var(--ink)' : 'var(--ink-4)', fontWeight: v ? 500 : 400, whiteSpace: 'pre-wrap' }}>{v || '—'}</div>
      </div>
    );
    const Ef = ({ label, v, onChange, type, textarea, full }) => (
      <div style={{ gridColumn: full ? '1 / -1' : 'auto', display: 'flex', flexDirection: 'column', gap: 3 }}>
        <span style={kvLabel}>{label}</span>
        {textarea
          ? <textarea value={v || ''} onChange={e => onChange(e.target.value)} rows={3} style={{ ...inputStyle, resize: 'vertical' }} />
          : <input type={type || 'text'} value={v || ''} onChange={e => onChange(e.target.value)} style={inputStyle} />}
      </div>
    );

    const contacts = org.contacts || [];

    return (
      <>
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, borderBottom: '1px solid var(--hairline)', paddingBottom: 12, marginBottom: 12 }}>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 18, fontWeight: 700, display: 'flex', alignItems: 'center', gap: 8 }}>
              🏢 {org.name}
              {org.legalForm && <span style={{ fontSize: 10, padding: '2px 6px', background: 'var(--plasma-tint)', color: 'var(--plasma)', borderRadius: 3, fontWeight: 600, fontFamily: 'var(--font-mono)' }}>{org.legalForm}</span>}
            </div>
            <div style={{ fontSize: 11, color: 'var(--ink-4)' }}>
              Organisation AE #{org.id} · {org.industry || org.category || '—'} · {contacts.length} contact{contacts.length > 1 ? 's' : ''}
            </div>
          </div>
          {!editMode
            ? <div style={{ display: 'flex', gap: 6 }}>
                <button onClick={startEdit} style={{ padding: '5px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>✏️ Éditer</button>
                <button onClick={deleteOrg} disabled={deleting} style={{ padding: '5px 10px', fontSize: 11, background: 'var(--rouge-tint)', color: 'var(--rouge)', border: '1px solid var(--rouge)', borderRadius: 4 }}>{deleting ? '…' : '🗑 Supprimer'}</button>
              </div>
            : <div style={{ display: 'flex', gap: 6 }}>
                <button onClick={() => setEditMode(false)} disabled={saving} style={{ padding: '5px 10px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 4 }}>Annuler</button>
                <button onClick={save} disabled={saving} style={{ padding: '5px 12px', fontSize: 11, background: 'var(--signal)', color: 'var(--ink)', border: 'none', borderRadius: 4, fontWeight: 600 }}>{saving ? '…' : '✓ Enregistrer'}</button>
              </div>}
        </div>

        {msg && <div style={{ marginBottom: 10, padding: '6px 10px', fontSize: 11, background: msg.startsWith('⚠') ? 'var(--rouge-tint)' : 'var(--signal-tint)', border: '1px solid ' + (msg.startsWith('⚠') ? 'var(--rouge)' : 'var(--signal-soft)'), borderRadius: 5, color: msg.startsWith('⚠') ? 'var(--rouge)' : 'var(--signal-deep)' }}>{msg}</div>}

        {!editMode ? (
          <>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 18 }}>
              <Kv label="Raison sociale" v={org.legalName} />
              <Kv label="Forme juridique" v={org.legalForm} />
              <Kv label="SIRET" v={org.siret} />
              <Kv label="SIREN" v={org.siren} />
              <Kv label="N° TVA" v={org.vat} />
              <Kv label="Secteur" v={org.industry} />
              <Kv label="Catégorie" v={org.category} />
              <Kv label="Effectifs" v={org.size} />
              <Kv label="Email" v={org.email} />
              <Kv label="Téléphone" v={org.phone} />
              <Kv label="Site web" v={org.website} />
              <Kv label="Ville" v={org.city} />
              <Kv label="Adresse siège" v={[org.address, org.address2, org.zip, org.city, org.country].filter(Boolean).join(' ')} full />
              {org.description && <Kv label="Description" v={org.description} full />}
              {org.notes && <Kv label="Notes internes" v={org.notes} full />}
            </div>

            {/* Contacts rattachés */}
            <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>
              Contacts rattachés ({contacts.length})
            </div>
            {contacts.length === 0 && <div style={{ fontSize: 11, color: 'var(--ink-4)', padding: 10 }}>Aucun contact lié. Associe des contacts via l'onglet « Contacts AE » (champ organizationId).</div>}
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {contacts.map(c => {
                const fullName = c.fullName || `${c.firstName || ''} ${c.lastName || ''}`.trim() || '(sans nom)';
                return (
                  <div key={c.id} style={{ display: 'grid', gridTemplateColumns: 'auto 1fr auto auto', gap: 10, padding: '8px 10px', background: 'var(--paper)', border: '1px solid var(--hairline)', borderRadius: 5, fontSize: 11, alignItems: 'center' }}>
                    <span style={{ fontSize: 9, padding: '1px 5px', background: c.isCompany ? 'var(--plasma-tint)' : 'var(--signal-tint)', color: c.isCompany ? 'var(--plasma)' : 'var(--signal-deep)', borderRadius: 3, fontWeight: 700 }}>{c.isCompany ? '🏢' : '👤'}</span>
                    <div>
                      <div style={{ fontWeight: 500 }}>{fullName}</div>
                      <div style={{ fontSize: 10, color: 'var(--ink-4)' }}>{c.function || c.title || '—'} · {c.email || c.phone || '—'}</div>
                    </div>
                    <span className="mono" style={{ fontSize: 10, color: 'var(--ink-4)' }}>AE #{c.id}</span>
                    {onOpenContact && <button onClick={() => onOpenContact(c)} style={{ fontSize: 10, padding: '2px 8px', background: 'var(--paper-2)', border: '1px solid var(--line-2)', borderRadius: 3 }}>Ouvrir</button>}
                  </div>
                );
              })}
            </div>

            {/* Chatter natif (notes + activities + attachments) sur l'organisation */}
            <ChatterPanel entityType="organization" entityId={org.id} />
          </>
        ) : (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <Ef label="Nom usuel" v={draft.name} onChange={v => setDraft(d => ({ ...d, name: v }))} full />
            <Ef label="Raison sociale" v={draft.legalName} onChange={v => setDraft(d => ({ ...d, legalName: v }))} full />
            <Ef label="Forme juridique (SAS, SARL…)" v={draft.legalForm} onChange={v => setDraft(d => ({ ...d, legalForm: v }))} />
            <Ef label="Secteur / industrie" v={draft.industry} onChange={v => setDraft(d => ({ ...d, industry: v }))} />
            <Ef label="Catégorie (prospect, client, partenaire)" v={draft.category} onChange={v => setDraft(d => ({ ...d, category: v }))} />
            <Ef label="Effectifs (TPE, PME, ETI, GE)" v={draft.size} onChange={v => setDraft(d => ({ ...d, size: v }))} />

            <Ef label="SIRET" v={draft.siret} onChange={v => setDraft(d => ({ ...d, siret: v }))} />
            <Ef label="SIREN" v={draft.siren} onChange={v => setDraft(d => ({ ...d, siren: v }))} />
            <Ef label="N° TVA intra." v={draft.vat} onChange={v => setDraft(d => ({ ...d, vat: v }))} full />

            <Ef label="Email générique" v={draft.email} onChange={v => setDraft(d => ({ ...d, email: v }))} type="email" />
            <Ef label="Téléphone" v={draft.phone} onChange={v => setDraft(d => ({ ...d, phone: v }))} />
            <Ef label="Site web" v={draft.website} onChange={v => setDraft(d => ({ ...d, website: v }))} type="url" full />

            <Ef label="Adresse ligne 1" v={draft.address} onChange={v => setDraft(d => ({ ...d, address: v }))} full />
            <Ef label="Adresse ligne 2" v={draft.address2} onChange={v => setDraft(d => ({ ...d, address2: v }))} full />
            <Ef label="Code postal" v={draft.zip} onChange={v => setDraft(d => ({ ...d, zip: v }))} />
            <Ef label="Ville" v={draft.city} onChange={v => setDraft(d => ({ ...d, city: v }))} />
            <Ef label="Pays" v={draft.country} onChange={v => setDraft(d => ({ ...d, country: v }))} full />

            <Ef label="Description publique" v={draft.description} onChange={v => setDraft(d => ({ ...d, description: v }))} full textarea />
            <Ef label="Notes internes" v={draft.notes} onChange={v => setDraft(d => ({ ...d, notes: v }))} full textarea />
          </div>
        )}
      </>
    );
  }

  // ────────────────────────────────────────────────────────────
  // CRMSettings — onglet Personnalisation (Règle n°6)
  // ────────────────────────────────────────────────────────────
  function CRMSettings({ odooStatus }) {
    const [stages, setStages] = useState([]);
    const [syncAuto, setSyncAuto] = useState(true);
    useEffect(() => {
      fetch(`${(window.AE_API?.BASE) || ''}/api/crm/stages`).then(r => r.json()).then(d => setStages(d?.stages || []));
    }, []);
    return (
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
        <div style={{ padding: 18, border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)' }}>
          <div style={{ fontSize: 11, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 10 }}>Stages du pipeline CEE</div>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', marginBottom: 12, lineHeight: 1.5 }}>
            Les stages du Kanban sont définis côté backend (<span className="mono" style={{ fontSize: 10 }}>modules/crm/stageWorkflow.js</span>). Ordre et couleurs sont aussi affichés ici.
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            {stages.map((s, i) => (
              <div key={s.key} style={{ display: 'grid', gridTemplateColumns: '24px 1fr 80px', gap: 8, alignItems: 'center', padding: '6px 10px', background: 'var(--paper)', border: '1px solid var(--hairline)', borderRadius: 4 }}>
                <span className="mono" style={{ fontSize: 10, color: 'var(--ink-4)' }}>{String(i + 1).padStart(2, '0')}</span>
                <div>
                  <div style={{ fontSize: 12, fontWeight: 500 }}>{s.label}</div>
                  <div style={{ fontSize: 9, color: 'var(--ink-4)' }} className="mono">{s.key}</div>
                </div>
                <span style={{ display: 'inline-block', width: 14, height: 14, borderRadius: 3, background: s.color || 'var(--ink-5)' }} />
              </div>
            ))}
          </div>
        </div>

        <div style={{ padding: 18, border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)' }}>
          <div style={{ fontSize: 11, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 10 }}>Intégration Odoo</div>
          <Kv4 label="Statut" v={odooStatus?.status === 'ok' ? '● Connecté' : '○ Hors ligne'} />
          <Kv4 label="URL Odoo" v={odooStatus?.url} />
          <Kv4 label="Base" v={odooStatus?.db} />
          <Kv4 label="UID authentifié" v={odooStatus?.uid} />
          <Kv4 label="Dernière vérif" v={odooStatus?.ts ? new Date(odooStatus.ts).toLocaleString('fr-FR') : '—'} />
          <div style={{ marginTop: 12 }}>
            <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12 }}>
              <input type="checkbox" checked={syncAuto} onChange={e => setSyncAuto(e.target.checked)} />
              Sync auto toutes les 15 min (CRM_SYNC_AUTO)
            </label>
          </div>
        </div>

        <div style={{ padding: 18, border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)' }}>
          <div style={{ fontSize: 11, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 10 }}>Champs custom contact</div>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', lineHeight: 1.5, marginBottom: 10 }}>Ajouter des attributs propres à l'organisation (secteur d'activité, taille, notation, etc.). En développement.</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6, opacity: 0.5 }}>
            <div style={{ padding: '6px 10px', background: 'var(--paper)', border: '1px dashed var(--line-2)', borderRadius: 4, fontSize: 11 }}>+ Ajouter un champ (prochainement)</div>
          </div>
        </div>

        <div style={{ padding: 18, border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)' }}>
          <div style={{ fontSize: 11, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600, marginBottom: 10 }}>Templates email</div>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', lineHeight: 1.5 }}>Les emails de relance sont générés par Claude (/api/generate/email). Les templates sont dans <span className="mono" style={{ fontSize: 10 }}>modules/generate/routes.js</span>.</div>
          <div style={{ marginTop: 10, fontSize: 11, color: 'var(--signal-deep)' }}>💡 Règle Claude-first : pas de templates figés — Claude génère le texte contextuel.</div>
        </div>

        {/* CRM externes — portés de pg-crm line 2699 (parité ancienne V) */}
        <div style={{ gridColumn: '1 / -1', marginTop: 8, fontSize: 11, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600 }}>
          CRM externes connectables
        </div>
        <ExternalCrmCard
          color="#714B67"
          icon="🟣"
          title="Odoo CRM"
          fields={[
            { k: 'url', label: 'Instance URL', placeholder: 'https://discovery1.odoo.com', defaultValue: odooStatus?.url || 'https://discovery1.odoo.com' },
            { k: 'db', label: 'Base de données', placeholder: 'discovery1', defaultValue: odooStatus?.db || 'discovery1' },
            { k: 'user', label: 'Utilisateur', placeholder: 'discovery@auditsenergies.com' },
            { k: 'key', label: 'API Key', type: 'password', placeholder: '••••••••' },
          ]}
          testLabel="🔌 Tester la connexion"
          onTest={async () => {
            const r = await fetch(`${(window.AE_API?.BASE) || ''}/api/odoo/status`).then(r => r.json()).catch(e => ({ error: e.message }));
            return r?.status === 'ok' ? `✓ Connecté (UID ${r.uid})` : `⚠ ${r?.error || 'Hors ligne'}`;
          }}
        />
        <ExternalCrmCard
          color="#0052CC"
          icon="☁️"
          title="Salesforce"
          fields={[
            { k: 'url', label: 'Instance URL', placeholder: 'https://moncompte.salesforce.com' },
            { k: 'clientId', label: 'Client ID', placeholder: 'OAuth2 Client ID' },
            { k: 'clientSecret', label: 'Client Secret', type: 'password', placeholder: '••••••••' },
          ]}
          testLabel="🔌 Connecter via OAuth2"
          disabled
          disabledMsg="OAuth2 Salesforce à brancher — v1.1"
        />
        <ExternalCrmCard
          color="#FF5A1F"
          icon="🟠"
          title="HubSpot"
          fields={[
            { k: 'token', label: 'API Key / Token', placeholder: 'pat-na1-...' },
            { k: 'portalId', label: 'Portal ID', placeholder: '12345678' },
          ]}
          testLabel="🔌 Tester HubSpot"
          disabled
          disabledMsg="API HubSpot à brancher — v1.1"
        />
        <ExternalCrmCard
          color="var(--ink-3)"
          icon="🔗"
          title="CRM générique (REST/Webhook)"
          fields={[
            { k: 'url', label: 'URL API', placeholder: 'https://api.moncrm.com/v1' },
            { k: 'token', label: 'API Key / Bearer', type: 'password', placeholder: '••••••••' },
            { k: 'contactField', label: 'Champ contact', placeholder: 'contact_id, partner_id...' },
          ]}
          testLabel="💾 Enregistrer"
          disabled
          disabledMsg="Webhook générique à brancher — v1.1"
        />
      </div>
    );
  }

  function ExternalCrmCard({ color, icon, title, fields, testLabel, onTest, disabled, disabledMsg }) {
    const [values, setValues] = useState(() => Object.fromEntries(fields.map(f => [f.k, f.defaultValue || ''])));
    const [msg, setMsg] = useState(null);
    const [busy, setBusy] = useState(false);
    const iStyle = { padding: '6px 8px', fontSize: 12, border: '1px solid var(--line-2)', borderRadius: 4, background: 'var(--paper)', color: 'var(--ink)', fontFamily: 'inherit', width: '100%', boxSizing: 'border-box' };
    const run = async () => {
      if (!onTest) return;
      setBusy(true); setMsg(null);
      try { setMsg(await onTest(values)); } catch (e) { setMsg(`⚠ ${e.message}`); } finally { setBusy(false); }
      setTimeout(() => setMsg(null), 5000);
    };
    return (
      <div style={{ padding: 18, border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)', opacity: disabled ? 0.75 : 1 }}>
        <div style={{ fontSize: 13, fontWeight: 600, color, marginBottom: 10 }}>{icon} {title}</div>
        {fields.map(f => (
          <div key={f.k} style={{ display: 'flex', flexDirection: 'column', gap: 3, marginBottom: 8 }}>
            <span style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>{f.label}</span>
            <input type={f.type || 'text'} placeholder={f.placeholder} value={values[f.k] || ''} onChange={e => setValues(v => ({ ...v, [f.k]: e.target.value }))} style={iStyle} disabled={disabled} />
          </div>
        ))}
        <button onClick={run} disabled={busy || disabled} style={{ marginTop: 4, padding: '6px 12px', fontSize: 11, background: disabled ? 'var(--paper-2)' : 'var(--signal)', color: disabled ? 'var(--ink-4)' : 'var(--ink)', border: '1px solid var(--line-2)', borderRadius: 4, fontWeight: 600, cursor: disabled ? 'not-allowed' : 'pointer' }}>
          {busy ? '…' : testLabel}
        </button>
        {msg && <div style={{ marginTop: 8, fontSize: 11, color: msg.startsWith('⚠') ? 'var(--rouge)' : 'var(--signal-deep)' }}>{msg}</div>}
        {disabled && disabledMsg && <div style={{ marginTop: 8, fontSize: 10, color: 'var(--ink-4)', fontStyle: 'italic' }}>{disabledMsg}</div>}
      </div>
    );
  }

  function Kv4({ label, v }) {
    return (
      <div style={{ marginBottom: 6 }}>
        <div style={{ fontSize: 9, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600 }}>{label}</div>
        <div style={{ fontSize: 12, color: v ? 'var(--ink)' : 'var(--ink-4)' }}>{v || '—'}</div>
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // NewContactModal — création manuelle d'un Contact AE
  // ────────────────────────────────────────────────────────────
  function NewContactModal({ onClose, onCreated, prefillOrg }) {
    const API = () => (window.AE_API && window.AE_API.BASE) || '';
    const [isCompany, setIsCompany] = useState(false);
    const [firstName, setFirstName] = useState('');
    const [lastName, setLastName] = useState('');
    const [title, setTitle] = useState('');
    const [func, setFunc] = useState('');
    const [email, setEmail] = useState('');
    const [phone, setPhone] = useState('');
    const [mobile, setMobile] = useState('');
    const [street, setStreet] = useState('');
    const [city, setCity] = useState('');
    const [zip, setZip] = useState('');
    const [organizationId, setOrganizationId] = useState(prefillOrg?.id || null);
    const [orgQuery, setOrgQuery] = useState(prefillOrg?.name || '');
    const [orgResults, setOrgResults] = useState([]);
    const [siret, setSiret] = useState('');
    const [company, setCompany] = useState('');
    const [notes, setNotes] = useState('');
    const [busy, setBusy] = useState(false);
    const [error, setError] = useState(null);

    // Charger orgs à la demande
    useEffect(() => {
      if (!orgQuery || organizationId) { setOrgResults([]); return; }
      let c = false;
      fetch(`${API()}/api/organizations`)
        .then(r => r.json())
        .then(d => {
          if (c) return;
          const needle = orgQuery.toLowerCase();
          setOrgResults((Array.isArray(d) ? d : []).filter(o => (o.name || '').toLowerCase().includes(needle)).slice(0, 10));
        })
        .catch(() => {});
      return () => { c = true; };
    }, [orgQuery, organizationId]);

    const save = async () => {
      setBusy(true); setError(null);
      try {
        const payload = {
          firstName: firstName || null,
          lastName: lastName || null,
          fullName: isCompany ? (company || [firstName, lastName].filter(Boolean).join(' ')) : [firstName, lastName].filter(Boolean).join(' '),
          isCompany, title: title || null, function: func || null,
          email: email || null, phone: phone || null, mobile: mobile || null,
          street: street || null, city: city || null, zip: zip || null,
          company: company || null, siret: (siret || '').replace(/\s+/g, '') || null,
          organizationId: organizationId || null,
          notes: notes || null,
          source: 'manual', tags: [],
        };
        const r = await fetch(`${API()}/api/contacts`, {
          method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload),
        }).then(r => r.json());
        if (r?.error) throw new Error(r.error);
        if (onCreated) onCreated(r);
        if (window.AE_API?.hydrate) window.AE_API.hydrate();
      } catch (e) { setError(e.message); }
      setBusy(false);
    };

    const input = { padding: '7px 10px', fontSize: 13, border: '1px solid var(--line-2)', borderRadius: 5, background: 'var(--paper-2)', color: 'var(--ink)', fontFamily: 'inherit', width: '100%', boxSizing: 'border-box' };
    const label = { fontSize: 10, color: 'var(--ink-4)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0.4 };
    const field = { display: 'flex', flexDirection: 'column', gap: 4 };

    return (
      <div style={{ position: 'fixed', inset: 0, zIndex: 100, background: 'rgba(14,16,16,0.6)', display: 'grid', placeItems: 'center', backdropFilter: 'blur(3px)', padding: 16 }}
        onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
        <div style={{ width: 'min(700px, 100%)', maxHeight: '92vh', overflowY: 'auto', background: 'var(--paper)', borderRadius: 12, boxShadow: 'var(--shadow-3)', border: '1px solid var(--line-2)' }}>
          <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', gap: 10, position: 'sticky', top: 0, background: 'var(--paper)', zIndex: 1 }}>
            <Dot tone="signal" size={8} pulse />
            <div>
              <div style={{ fontSize: 14, fontWeight: 600 }}>Nouveau contact</div>
              <div style={{ fontSize: 11, color: 'var(--ink-4)' }}>Audits Énergies · création manuelle</div>
            </div>
            <span style={{ flex: 1 }} />
            <button onClick={onClose} style={{ color: 'var(--ink-4)' }}><Icon.cross /></button>
          </div>
          <div style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 14 }}>
            {/* Type */}
            <div style={{ display: 'flex', gap: 6 }}>
              {[
                { k: false, l: '👤 Personne physique' },
                { k: true,  l: '🏢 Société' },
              ].map(o => (
                <button key={String(o.k)} type="button" onClick={() => setIsCompany(o.k)}
                  style={{
                    padding: '6px 12px', fontSize: 11, fontWeight: 500, cursor: 'pointer',
                    background: isCompany === o.k ? 'var(--ink)' : 'var(--paper)',
                    color: isCompany === o.k ? 'var(--paper)' : 'var(--ink-2)',
                    border: '1px solid var(--line-2)', borderRadius: 4,
                  }}>{o.l}</button>
              ))}
            </div>

            {/* Identité */}
            <div style={{ display: 'grid', gridTemplateColumns: '100px 1fr 1fr', gap: 10 }}>
              <label style={field}><span style={label}>Civilité</span>
                <select value={title} onChange={e => setTitle(e.target.value)} style={input}>
                  <option value="">—</option><option>M.</option><option>Mme</option><option>Dr</option>
                </select>
              </label>
              <label style={field}><span style={label}>Prénom</span><input value={firstName} onChange={e => setFirstName(e.target.value)} style={input}/></label>
              <label style={field}><span style={label}>Nom</span><input value={lastName} onChange={e => setLastName(e.target.value)} style={input}/></label>
            </div>
            <label style={field}><span style={label}>Fonction / poste</span><input value={func} onChange={e => setFunc(e.target.value)} placeholder="Directeur commercial, Chef de projet…" style={input}/></label>

            {/* Coordonnées */}
            <div style={{ fontSize: 10, color: 'var(--ink-4)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.6, marginTop: 4, borderBottom: '1px solid var(--hairline)', paddingBottom: 4 }}>Coordonnées</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
              <label style={field}><span style={label}>Email</span><input type="email" value={email} onChange={e => setEmail(e.target.value)} style={input}/></label>
              <label style={field}><span style={label}>Téléphone</span><input value={phone} onChange={e => setPhone(e.target.value)} style={input}/></label>
              <label style={field}><span style={label}>Mobile</span><input value={mobile} onChange={e => setMobile(e.target.value)} style={input}/></label>
              <label style={field}><span style={label}>SIRET</span><input value={siret} onChange={e => setSiret(e.target.value)} placeholder="14 chiffres" style={input}/></label>
            </div>

            {/* Adresse */}
            <div style={{ fontSize: 10, color: 'var(--ink-4)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.6, marginTop: 4, borderBottom: '1px solid var(--hairline)', paddingBottom: 4 }}>Adresse</div>
            <label style={field}><span style={label}>Rue</span><input value={street} onChange={e => setStreet(e.target.value)} style={input}/></label>
            <div style={{ display: 'grid', gridTemplateColumns: '120px 1fr', gap: 10 }}>
              <label style={field}><span style={label}>Code postal</span><input value={zip} onChange={e => setZip(e.target.value)} style={input}/></label>
              <label style={field}><span style={label}>Ville</span><input value={city} onChange={e => setCity(e.target.value)} style={input}/></label>
            </div>

            {/* Organisation */}
            <div style={{ fontSize: 10, color: 'var(--ink-4)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.6, marginTop: 4, borderBottom: '1px solid var(--hairline)', paddingBottom: 4 }}>Rattachement organisation</div>
            {organizationId ? (
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 12px', background: 'var(--signal-tint)', border: '1px solid var(--signal-soft)', borderRadius: 5 }}>
                <span style={{ fontSize: 13, fontWeight: 500, color: 'var(--signal-deep)' }}>✓ {orgQuery}</span>
                <span className="mono" style={{ fontSize: 10, color: 'var(--ink-4)' }}>Org #{organizationId}</span>
                <span style={{ flex: 1 }}/>
                <button onClick={() => { setOrganizationId(null); setOrgQuery(''); }}
                  style={{ padding: '3px 8px', fontSize: 11, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 3 }}>Changer</button>
              </div>
            ) : (
              <div style={{ position: 'relative' }}>
                <input value={orgQuery} onChange={e => setOrgQuery(e.target.value)} placeholder="Rechercher une organisation AE existante (optionnel)…" style={input}/>
                {orgResults.length > 0 && (
                  <div style={{ position: 'absolute', top: '100%', left: 0, right: 0, marginTop: 3, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 5, boxShadow: 'var(--shadow-2)', zIndex: 5, maxHeight: 200, overflowY: 'auto' }}>
                    {orgResults.map(o => (
                      <button key={o.id} type="button" onClick={() => { setOrganizationId(o.id); setOrgQuery(o.name); setOrgResults([]); }}
                        style={{ display: 'block', width: '100%', textAlign: 'left', padding: '6px 10px', fontSize: 12, borderBottom: '1px solid var(--hairline)', background: 'var(--paper)' }}>
                        🏢 {o.name} <span style={{ fontSize: 10, color: 'var(--ink-4)' }}>#{o.id}</span>
                      </button>
                    ))}
                  </div>
                )}
                {isCompany && (
                  <label style={{ ...field, marginTop: 8 }}><span style={label}>Ou nom société (texte libre)</span><input value={company} onChange={e => setCompany(e.target.value)} style={input}/></label>
                )}
              </div>
            )}

            <label style={field}><span style={label}>Notes</span><textarea value={notes} onChange={e => setNotes(e.target.value)} rows={2} style={{ ...input, resize: 'vertical' }}/></label>

            {error && <div style={{ fontSize: 11, color: 'var(--rouge)' }}>Erreur : {error}</div>}
            <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
              <button onClick={onClose} style={{ padding: '8px 14px', fontSize: 12, color: 'var(--ink-3)' }}>Annuler</button>
              <button onClick={save} disabled={busy || (!firstName && !lastName && !company)}
                style={{ padding: '8px 14px', fontSize: 12, fontWeight: 600, background: (firstName || lastName || company) ? 'var(--signal)' : 'var(--paper-3)', color: (firstName || lastName || company) ? 'var(--ink)' : 'var(--ink-4)', border: 'none', borderRadius: 5 }}>
                {busy ? 'Création…' : 'Créer le contact'}
              </button>
            </div>
          </div>
        </div>
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // NewOrganizationModal — création org avec SIRET autofill (SIRENE INSEE)
  // ────────────────────────────────────────────────────────────
  function NewOrganizationModal({ onClose, onCreated }) {
    const API = () => (window.AE_API && window.AE_API.BASE) || '';
    const [name, setName] = useState('');
    const [legalName, setLegalName] = useState('');
    const [legalForm, setLegalForm] = useState('');
    const [siret, setSiret] = useState('');
    const [siren, setSiren] = useState('');
    const [vat, setVat] = useState('');
    const [industry, setIndustry] = useState('');
    const [category, setCategory] = useState('');
    const [size, setSize] = useState('');
    const [phone, setPhone] = useState('');
    const [email, setEmail] = useState('');
    const [website, setWebsite] = useState('');
    const [address, setAddress] = useState('');
    const [city, setCity] = useState('');
    const [zip, setZip] = useState('');
    const [country, setCountry] = useState('France');
    const [description, setDescription] = useState('');
    const [notes, setNotes] = useState('');
    const [sireneResult, setSireneResult] = useState(null);
    const [sireneLoading, setSireneLoading] = useState(false);
    const [busy, setBusy] = useState(false);
    const [error, setError] = useState(null);

    // SIRET auto-lookup (14 digits)
    useEffect(() => {
      const clean = (siret || '').replace(/\s+/g, '');
      if (clean.length !== 14) { setSireneResult(null); return; }
      setSireneLoading(true);
      fetch(`${API()}/api/integrations/siret?siret=${clean}`)
        .then(r => r.json())
        .then(res => {
          setSireneResult(res);
          if (res) {
            // Auto-fill vides uniquement (ne pas écraser saisies user)
            if (res.nom_complet && !name) setName(res.nom_complet);
            if (res.nom_complet && !legalName) setLegalName(res.nom_complet);
            if (res.categorie_juridique_libelle && !legalForm) setLegalForm(res.categorie_juridique_libelle);
            if (res.activite_principale && !industry) setIndustry(res.activite_principale);
            if (res.tranche_effectifs && !size) setSize(res.tranche_effectifs);
            if (res.siren && !siren) setSiren(res.siren);
            if (res.adresse && !address) setAddress(res.adresse);
            if (res.code_postal && !zip) setZip(res.code_postal);
            if (res.ville && !city) setCity(res.ville);
          }
        })
        .catch(() => {})
        .finally(() => setSireneLoading(false));
    }, [siret]);

    const save = async () => {
      if (!name.trim()) { setError('Nom requis'); return; }
      setBusy(true); setError(null);
      try {
        const payload = {
          name: name.trim(),
          legalName: legalName || null,
          legalForm: legalForm || null,
          siret: (siret || '').replace(/\s+/g, '') || null,
          siren: (siren || '').replace(/\s+/g, '') || null,
          vat: vat || null,
          industry: industry || null,
          category: category || null,
          size: size || null,
          phone: phone || null,
          email: email || null,
          website: website || null,
          address: address || null,
          city: city || null,
          zip: zip || null,
          country: country || null,
          description: description || null,
          notes: notes || null,
          source: 'manual',
        };
        const r = await fetch(`${API()}/api/organizations`, {
          method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload),
        }).then(r => r.json());
        if (r?.error) throw new Error(r.error);
        if (onCreated) onCreated(r);
        if (window.AE_API?.hydrate) window.AE_API.hydrate();
      } catch (e) { setError(e.message); }
      setBusy(false);
    };

    const input = { padding: '7px 10px', fontSize: 13, border: '1px solid var(--line-2)', borderRadius: 5, background: 'var(--paper-2)', color: 'var(--ink)', fontFamily: 'inherit', width: '100%', boxSizing: 'border-box' };
    const label = { fontSize: 10, color: 'var(--ink-4)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0.4 };
    const field = { display: 'flex', flexDirection: 'column', gap: 4 };

    return (
      <div style={{ position: 'fixed', inset: 0, zIndex: 100, background: 'rgba(14,16,16,0.6)', display: 'grid', placeItems: 'center', backdropFilter: 'blur(3px)', padding: 16 }}
        onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
        <div style={{ width: 'min(760px, 100%)', maxHeight: '92vh', overflowY: 'auto', background: 'var(--paper)', borderRadius: 12, boxShadow: 'var(--shadow-3)', border: '1px solid var(--line-2)' }}>
          <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', gap: 10, position: 'sticky', top: 0, background: 'var(--paper)', zIndex: 1 }}>
            <Dot tone="plasma" size={8} pulse />
            <div>
              <div style={{ fontSize: 14, fontWeight: 600 }}>Nouvelle organisation</div>
              <div style={{ fontSize: 11, color: 'var(--ink-4)' }}>Tape le SIRET pour auto-remplir depuis SIRENE INSEE</div>
            </div>
            <span style={{ flex: 1 }} />
            <button onClick={onClose} style={{ color: 'var(--ink-4)' }}><Icon.cross /></button>
          </div>
          <div style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 14 }}>
            {/* SIRET (premier — déclenche autofill) */}
            <label style={field}>
              <span style={label}>SIRET (14 chiffres — auto-remplit depuis SIRENE)</span>
              <div style={{ position: 'relative' }}>
                <input value={siret} onChange={e => setSiret(e.target.value)} placeholder="Ex: 552 056 152 00010" autoFocus style={input}/>
                {sireneLoading && <div style={{ position: 'absolute', right: 10, top: 9, fontSize: 11, color: 'var(--plasma)' }}>⏳ SIRENE…</div>}
              </div>
            </label>
            {sireneResult && sireneResult.nom_complet && (
              <div style={{ padding: '8px 12px', fontSize: 11, color: 'var(--signal-deep)', background: 'var(--signal-tint)', border: '1px solid var(--signal-soft)', borderRadius: 5 }}>
                ✓ SIRENE : <strong>{sireneResult.nom_complet}</strong> · {sireneResult.activite_principale || ''}
              </div>
            )}

            {/* Identité */}
            <div style={{ fontSize: 10, color: 'var(--ink-4)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.6, marginTop: 4, borderBottom: '1px solid var(--hairline)', paddingBottom: 4 }}>Identité</div>
            <label style={field}><span style={label}>Nom usuel *</span><input value={name} onChange={e => setName(e.target.value)} style={input}/></label>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
              <label style={field}><span style={label}>Raison sociale</span><input value={legalName} onChange={e => setLegalName(e.target.value)} style={input}/></label>
              <label style={field}><span style={label}>Forme juridique</span>
                <select value={legalForm} onChange={e => setLegalForm(e.target.value)} style={input}>
                  <option value="">—</option>
                  {['SAS','SASU','SARL','EURL','SA','SCI','SCOP','Auto-entrepreneur','EI','GIE','Association','Autre'].map(f => <option key={f} value={f}>{f}</option>)}
                </select>
              </label>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10 }}>
              <label style={field}><span style={label}>SIREN</span><input value={siren} onChange={e => setSiren(e.target.value)} placeholder="9 chiffres" style={input}/></label>
              <label style={field}><span style={label}>N° TVA intra</span><input value={vat} onChange={e => setVat(e.target.value)} placeholder="FR12345678901" style={input}/></label>
              <label style={field}><span style={label}>Effectifs</span>
                <select value={size} onChange={e => setSize(e.target.value)} style={input}>
                  <option value="">—</option><option>TPE (&lt; 10)</option><option>PME (10-250)</option><option>ETI (250-5000)</option><option>GE (&gt; 5000)</option>
                </select>
              </label>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
              <label style={field}><span style={label}>Secteur / industrie</span><input value={industry} onChange={e => setIndustry(e.target.value)} placeholder="Code NAF ou description" style={input}/></label>
              <label style={field}><span style={label}>Catégorie interne</span>
                <select value={category} onChange={e => setCategory(e.target.value)} style={input}>
                  <option value="">—</option>
                  {['prospect','client','partenaire','fournisseur','sous-traitant','délégataire','mandataire'].map(c => <option key={c} value={c}>{c}</option>)}
                </select>
              </label>
            </div>

            {/* Coordonnées */}
            <div style={{ fontSize: 10, color: 'var(--ink-4)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.6, marginTop: 4, borderBottom: '1px solid var(--hairline)', paddingBottom: 4 }}>Coordonnées</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10 }}>
              <label style={field}><span style={label}>Email</span><input type="email" value={email} onChange={e => setEmail(e.target.value)} style={input}/></label>
              <label style={field}><span style={label}>Téléphone</span><input value={phone} onChange={e => setPhone(e.target.value)} style={input}/></label>
              <label style={field}><span style={label}>Site web</span><input type="url" value={website} onChange={e => setWebsite(e.target.value)} style={input}/></label>
            </div>

            {/* Adresse siège */}
            <div style={{ fontSize: 10, color: 'var(--ink-4)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.6, marginTop: 4, borderBottom: '1px solid var(--hairline)', paddingBottom: 4 }}>Adresse siège</div>
            <label style={field}><span style={label}>Rue</span><input value={address} onChange={e => setAddress(e.target.value)} style={input}/></label>
            <div style={{ display: 'grid', gridTemplateColumns: '120px 1fr 150px', gap: 10 }}>
              <label style={field}><span style={label}>Code postal</span><input value={zip} onChange={e => setZip(e.target.value)} style={input}/></label>
              <label style={field}><span style={label}>Ville</span><input value={city} onChange={e => setCity(e.target.value)} style={input}/></label>
              <label style={field}><span style={label}>Pays</span><input value={country} onChange={e => setCountry(e.target.value)} style={input}/></label>
            </div>

            <label style={field}><span style={label}>Description publique</span><textarea value={description} onChange={e => setDescription(e.target.value)} rows={2} style={{ ...input, resize: 'vertical' }}/></label>
            <label style={field}><span style={label}>Notes internes</span><textarea value={notes} onChange={e => setNotes(e.target.value)} rows={2} style={{ ...input, resize: 'vertical' }}/></label>

            {error && <div style={{ fontSize: 11, color: 'var(--rouge)' }}>Erreur : {error}</div>}
            <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
              <button onClick={onClose} style={{ padding: '8px 14px', fontSize: 12, color: 'var(--ink-3)' }}>Annuler</button>
              <button onClick={save} disabled={busy || !name.trim()}
                style={{ padding: '8px 14px', fontSize: 12, fontWeight: 600, background: !name.trim() ? 'var(--paper-3)' : 'var(--signal)', color: !name.trim() ? 'var(--ink-4)' : 'var(--ink)', border: 'none', borderRadius: 5 }}>
                {busy ? 'Création…' : 'Créer l\'organisation'}
              </button>
            </div>
          </div>
        </div>
      </div>
    );
  }

  window.CRMPage = CRMPage;
  window.NewContactModal = NewContactModal;
  window.NewOrganizationModal = NewOrganizationModal;
  window.ChatterPanel = ChatterPanel;
  window.ClientAnalyzeButton = ClientAnalyzeButton;
})();
