// ===== Persistance : adaptateur localStorage (hors environnement artifact) =====
if (!window.storage) {
  window.storage = {
    async get(key) { const v = localStorage.getItem("meplivierge:" + key); if (v === null) throw new Error("not found"); return { key, value: v }; },
    async set(key, value) { localStorage.setItem("meplivierge:" + key, value); return { key, value }; },
    async delete(key) { localStorage.removeItem("meplivierge:" + key); return { key, deleted: true }; },
    async list(prefix) { return { keys: Object.keys(localStorage).filter(k => k.startsWith("meplivierge:" + (prefix || ""))).map(k => k.slice(9)) }; },
  };
}

const { useState, useRef, useEffect } = React;

// ============ CHARTE CHEF AI ============
const C = {
  creme: "#F7F2E6",
  cremeFonce: "#EFE7D3",
  or: "#C8962A",
  orClair: "#E6CC85",
  brun: "#352718",
  brunMoyen: "#6F5843",
  rouille: "#9A3F1F",
  vert: "#4C7046",
  blanc: "#FFFEFA",
};


// ============ SÉLECTEUR DE RESTAURANT (multi-tenant, API D1) ============
const MP_TOKEN = "meplivierge_token";
const MP_RESTO = "meplivierge_resto";

const apiMP = async (route, opts = {}) => {
  const t = localStorage.getItem(MP_TOKEN);
  const r = await fetch("/api" + route, {
    ...opts,
    headers: {
      "Content-Type": "application/json",
      ...(t ? { Authorization: "Bearer " + t } : {}),
      ...(opts.headers || {}),
    },
  });
  const data = await r.json().catch(() => ({}));
  if (r.status === 401) localStorage.removeItem(MP_TOKEN);
  return { ok: r.ok, status: r.status, data };
};

function SelecteurResto({ onChange }) {
  const [ouvert, setOuvert] = useState(false);
  const [restos, setRestos] = useState([]);
  const [actif, setActif] = useState(() => localStorage.getItem(MP_RESTO) || null);
  const [connecte, setConnecte] = useState(() => !!localStorage.getItem(MP_TOKEN));
  const [email, setEmail] = useState("");
  const [mdp, setMdp] = useState("");
  const [msg, setMsg] = useState("");
  const [charge, setCharge] = useState(false);
  const [bascule, setBascule] = useState(null);
  const boite = useRef(null);

  const chargerRestos = async () => {
    if (!localStorage.getItem(MP_TOKEN)) { setConnecte(false); return; }
    setCharge(true);
    const { ok, data } = await apiMP("/auth/me");
    setCharge(false);
    if (!ok) { setConnecte(false); setRestos([]); return; }
    setConnecte(true);
    setRestos(data.restaurants || []);
    const courant = localStorage.getItem(MP_RESTO);
    const valide = (data.restaurants || []).some(r => r.id === courant);
    if (!valide && data.restaurants && data.restaurants.length) {
      choisir(data.restaurants[0], true);
    }
  };

  useEffect(() => { chargerRestos(); }, []);

  useEffect(() => {
    const dehors = (e) => { if (boite.current && !boite.current.contains(e.target)) setOuvert(false); };
    document.addEventListener("mousedown", dehors);
    return () => document.removeEventListener("mousedown", dehors);
  }, []);

  const choisir = (r, silencieux) => {
    const avant = localStorage.getItem(MP_RESTO);
    localStorage.setItem(MP_RESTO, r.id);
    setActif(r.id);
    if (!silencieux) setOuvert(false);
    if (onChange) onChange(r);
    // Bascule réelle : on laisse la sauvegarde différée (1,2 s) se terminer,
    // puis on recharge pour que tous les modules repartent sur l'état du nouveau restaurant.
    if (!silencieux && avant && avant !== r.id) {
      setBascule(r.nom);
      setTimeout(() => window.location.reload(), 1400);
    }
  };

  const connexion = async () => {
    setMsg("");
    if (!email || !mdp) { setMsg("Email et mot de passe requis"); return; }
    setCharge(true);
    const { ok, data } = await apiMP("/auth/login", {
      method: "POST",
      body: JSON.stringify({ email: email.trim().toLowerCase(), mot_de_passe: mdp }),
    });
    setCharge(false);
    if (!ok) { setMsg(data.error || "Connexion refusée"); return; }
    localStorage.setItem(MP_TOKEN, data.token);
    setMdp(""); setEmail("");
    setConnecte(true);
    setRestos(data.restaurants || []);
    if (data.restaurants && data.restaurants.length) {
      choisir(data.restaurants[0], true);
      // premier chargement du restaurant : on repart proprement dessus
      setBascule(data.restaurants[0].nom);
      setTimeout(() => window.location.reload(), 900);
    }
    setMsg("");
  };

  const deconnexion = async () => {
    await apiMP("/auth/logout", { method: "POST" });
    localStorage.removeItem(MP_TOKEN);
    localStorage.removeItem(MP_RESTO);
    setConnecte(false); setRestos([]); setActif(null); setOuvert(false);
    setTimeout(() => window.location.reload(), 300);
  };

  const courant = restos.find(r => r.id === actif);
  const libelle = courant ? courant.nom : connecte ? "Choisir un restaurant" : "Se connecter";
  const sousTitre = courant ? (courant.enseigne || courant.role) : null;

  const champ = {
    width: "100%", padding: "9px 11px", marginBottom: 8, borderRadius: 8,
    border: "1px solid rgba(200,150,42,0.45)", fontSize: 13,
    fontFamily: "Inter, system-ui, sans-serif", background: C.blanc, color: C.brun,
  };

  if (bascule) {
    return (
      <div style={{ display: "flex", alignItems: "center", gap: 10, color: C.orClair, fontSize: 13, fontFamily: "Fraunces, Georgia, serif", fontStyle: "italic" }}>
        <div style={{ width: 16, height: 16, borderRadius: "50%", border: `2px solid ${C.or}`, borderTopColor: "transparent", animation: "tour 0.8s linear infinite" }} />
        Passage sur {bascule}…
      </div>
    );
  }

  return (
    <div ref={boite} style={{ position: "relative" }}>
      <button onClick={() => setOuvert(!ouvert)} title="Changer de restaurant" style={{
        background: ouvert ? "rgba(230,204,133,0.18)" : "transparent",
        border: "1px solid rgba(230,204,133,0.35)", borderRadius: 12,
        padding: "7px 12px", cursor: "pointer", textAlign: "right",
        display: "flex", alignItems: "center", gap: 9,
      }}>
        <div>
          <div style={{ fontSize: 13, color: C.creme, fontFamily: "Fraunces, Georgia, serif", fontWeight: 600, whiteSpace: "nowrap" }}>{libelle}</div>
          {sousTitre && <div style={{ fontSize: 10, color: C.orClair, textTransform: "uppercase", letterSpacing: 1.4 }}>{sousTitre}</div>}
        </div>
        <span style={{ color: C.or, fontSize: 10, transform: ouvert ? "rotate(180deg)" : "none", transition: "transform .15s ease" }}>▼</span>
      </button>

      {ouvert && (
        <div style={{
          position: "absolute", top: "calc(100% + 8px)", right: 0, zIndex: 200,
          minWidth: 262, background: C.blanc, borderRadius: 14,
          border: `1px solid rgba(200,150,42,0.4)`, boxShadow: "0 12px 34px rgba(53,39,24,0.28)",
          padding: 10, textAlign: "left",
        }}>
          {!connecte ? (
            <div>
              <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 14, fontWeight: 700, color: C.brun, marginBottom: 9 }}>Connexion</div>
              <input style={champ} type="email" placeholder="Email" value={email} autoComplete="username"
                onChange={e => setEmail(e.target.value)} onKeyDown={e => e.key === "Enter" && connexion()} />
              <input style={champ} type="password" placeholder="Mot de passe" value={mdp} autoComplete="current-password"
                onChange={e => setMdp(e.target.value)} onKeyDown={e => e.key === "Enter" && connexion()} />
              {msg && <div style={{ fontSize: 11, color: C.rouille, marginBottom: 8 }}>{msg}</div>}
              <button onClick={connexion} disabled={charge} style={{
                width: "100%", background: C.or, color: C.blanc, border: "none", borderRadius: 9,
                padding: "9px 0", fontSize: 13, fontWeight: 700, cursor: charge ? "wait" : "pointer",
              }}>{charge ? "…" : "Se connecter"}</button>
            </div>
          ) : (
            <div>
              <div style={{ fontSize: 10, textTransform: "uppercase", letterSpacing: 1.6, color: C.brunMoyen, padding: "2px 6px 8px" }}>
                Mes restaurants {charge && "· …"}
              </div>
              {restos.length === 0 && (
                <div style={{ fontSize: 12, color: C.brunMoyen, padding: "4px 6px 10px", fontStyle: "italic" }}>
                  Aucun restaurant lié à ce compte.
                </div>
              )}
              {restos.map(r => (
                <button key={r.id} onClick={() => choisir(r)} style={{
                  display: "block", width: "100%", textAlign: "left", cursor: "pointer",
                  background: r.id === actif ? "rgba(200,150,42,0.14)" : "transparent",
                  border: r.id === actif ? `1px solid rgba(200,150,42,0.5)` : "1px solid transparent",
                  borderRadius: 9, padding: "8px 10px", marginBottom: 4,
                }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: C.brun, fontFamily: "Fraunces, Georgia, serif" }}>
                    {r.id === actif ? "● " : ""}{r.nom}
                  </div>
                  <div style={{ fontSize: 10, color: C.brunMoyen, textTransform: "uppercase", letterSpacing: 1.2 }}>
                    {r.role}{r.enseigne ? " · " + r.enseigne : ""}
                  </div>
                </button>
              ))}
              <div style={{ borderTop: "1px solid rgba(200,150,42,0.25)", marginTop: 6, paddingTop: 6 }}>
                <button onClick={deconnexion} style={{
                  width: "100%", background: "transparent", border: "none", cursor: "pointer",
                  color: C.rouille, fontSize: 12, fontWeight: 600, padding: "6px 0", textAlign: "left",
                }}>Se déconnecter</button>
              </div>
            </div>
          )}
        </div>
      )}
    </div>
  );
}


// ---- Multi-restaurant : état cloisonné par restaurant + hydratation depuis D1 ----
const cleEtat = () => {
  const r = localStorage.getItem(MP_RESTO);
  return r ? "chefai-etat:" + r : "chefai-etat";
};

const CATEGORIE_MIZEN = (idCat) => {
  if (/entree|entrées|entrees/i.test(idCat)) return "Entrée";
  if (/dessert|fromage/i.test(idCat)) return "Dessert";
  if (/accompagnement|sauce/i.test(idCat)) return "Accompagnement";
  return "Plat";
};

// Transforme la carte servie par /api/carte en fiches techniques exploitables
const fichesDepuisCarte = (carte) => {
  let n = 0;
  const out = [];
  for (const cat of carte || []) {
    for (const it of cat.items || []) {
      const prix = it.prix ?? (it.variantes && it.variantes[0] ? it.variantes[0].prix : null);
      out.push({
        id: ++n,
        refDistante: it.id,
        nom: it.nom,
        description: it.description || "",
        categorie: CATEGORIE_MIZEN(cat.id),
        portions: 1,
        coutPortion: it.cout_matiere ?? 0,
        prixVente: prix ?? 0,
        tempsPrepa: "—",
        tempsCuisson: "—",
        ingredients: [],
        etapes: [],
        allergenes: (it.allergenes || []).map(a => a.charAt(0).toUpperCase() + a.slice(1)),
        dressage: [],
        poste: it.poste || null,
        poids_g: it.poids_g || null,
        origine: it.origine || null,
      });
    }
  }
  return out;
};

const chargerRestoDistant = async (restoId) => {
  const { ok, data } = await apiMP("/carte?resto=" + encodeURIComponent(restoId));
  if (!ok) return null;
  return { fiches: fichesDepuisCarte(data.carte), restaurant: data.restaurant };
};

// ============ DONNÉES DEMO ============
let FICHES = [];

const RELEVES_INIT = [];

let FOURNISSEURS = [];

// ---- PRÉ-COMMANDES : produits à réapprovisionner (sous seuil ou proche) ----
// Quantité suggérée = recomplètement à 2× le seuil
function produitsACommander(stocks) {
  return stocks
    .filter(s => s.qte <= s.seuil * 1.2)
    .map(s => ({ ...s, suggestion: Math.max(1, Math.ceil(s.seuil * 2 - s.qte)) }));
}

// ============ COMPOSANTS ============

function Badge({ children, color = C.or, bg }) {
  return (
    <span style={{
      display: "inline-block", padding: "2px 10px", borderRadius: 12,
      fontSize: 11, fontWeight: 700, letterSpacing: 0.5,
      color: bg ? C.blanc : color, background: bg || "transparent",
      border: bg ? "none" : `1.5px solid ${color}`,
      fontFamily: "Inter, system-ui, sans-serif", textTransform: "uppercase",
    }}>{children}</span>
  );
}

function Carte({ children, style = {} }) {
  return (
    <div style={{
      background: C.blanc, border: "1px solid rgba(200,150,42,0.28)",
      borderRadius: 16, padding: 18,
      boxShadow: "0 2px 12px rgba(53,39,24,0.06), 0 1px 3px rgba(53,39,24,0.05)", ...style,
    }}>{children}</div>
  );
}

function Stat({ label, valeur, sous, accent }) {
  return (
    <Carte style={{ flex: 1, minWidth: 130, borderTop: `3px solid ${accent || C.or}` }}>
      <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 1, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>{label}</div>
      <div style={{ fontSize: 26, fontWeight: 700, color: C.brun, fontFamily: "Fraunces, Georgia, serif", marginTop: 4 }}>{valeur}</div>
      {sous && <div style={{ fontSize: 12, color: accent || C.brunMoyen, marginTop: 2, fontFamily: "Inter, system-ui, sans-serif" }}>{sous}</div>}
    </Carte>
  );
}

// ============ ÉCRANS ============

function SyntheseMois({ rapportsZ }) {
  const histo = rapportsZ;
  if (!histo.length) return null;
  const caMois = histo.reduce((s, z) => s + z.caTTC, 0);
  const couvertsMois = histo.reduce((s, z) => s + z.couverts, 0);
  const ticketMoyen = couvertsMois ? caMois / couvertsMois : 0;
  const meilleur = histo.reduce((a, b) => a.caTTC > b.caTTC ? a : b);
  const pire = histo.reduce((a, b) => a.caTTC < b.caTTC ? a : b);
  const partCB = histo.reduce((s, z) => s + (z.modes["CB"] || 0), 0) / caMois * 100;
  const evol = MOIS_PRECEDENT.caTTC ? (caMois - MOIS_PRECEDENT.caTTC) / MOIS_PRECEDENT.caTTC * 100 : 0;
  // CA par semaine (par tranche du mois)
  const semaines = [[], [], [], [], []];
  for (const z of histo) {
    const j = parseInt(z.date.slice(0, 2), 10);
    semaines[Math.min(4, Math.floor((j - 1) / 7))].push(z);
  }
  const caSemaines = semaines.map(s => s.reduce((t, z) => t + z.caTTC, 0)).filter((_, i) => semaines[i].length > 0 || i < 4);
  const maxSem = Math.max(...caSemaines, 1);

  return (
    <Carte style={{ marginBottom: 16, borderTop: `4px solid ${C.brun}` }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 6 }}>
        <h3 style={{ ...h3Style, margin: 0 }}>Synthèse du mois · Mai</h3>
        <span style={{
          fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700, padding: "4px 12px", borderRadius: 12,
          background: evol >= 0 ? "#E3EBDD" : "#F3DCD4", color: evol >= 0 ? C.vert : C.rouille,
          border: `1.5px solid ${evol >= 0 ? C.vert : C.rouille}`,
        }}>{evol >= 0 ? "▲" : "▼"} {Math.abs(evol).toFixed(1)}% vs {MOIS_PRECEDENT.libelle}</span>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(120px, 1fr))", gap: 10, marginTop: 12 }}>
        {[
          ["CA du mois", `${(caMois / 1000).toFixed(1)}k €`, `${histo.length} services`],
          ["Couverts", String(couvertsMois), `≈ ${Math.round(couvertsMois / histo.length)}/service`],
          ["Ticket moyen", `${ticketMoyen.toFixed(2)} €`, "Par couvert"],
          ["Part CB", `${partCB.toFixed(0)}%`, "Du CA total"],
        ].map(([l, v, s]) => (
          <div key={l} style={{ padding: "10px 12px", background: C.creme, borderRadius: 10, border: `1px solid ${C.orClair}` }}>
            <div style={{ fontSize: 10, textTransform: "uppercase", letterSpacing: 1, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>{l}</div>
            <div style={{ fontSize: 21, fontWeight: 700, color: C.brun, fontFamily: "Fraunces, Georgia, serif", marginTop: 2 }}>{v}</div>
            <div style={{ fontSize: 10.5, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>{s}</div>
          </div>
        ))}
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1.1fr 1fr", gap: 14, marginTop: 14 }}>
        <div>
          <div style={{ fontSize: 10.5, textTransform: "uppercase", letterSpacing: 1, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginBottom: 8 }}>CA par semaine</div>
          <div style={{ display: "flex", alignItems: "flex-end", gap: 10, height: 90 }}>
            {caSemaines.map((ca, i) => (
              <div key={i} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 3 }}>
                <span style={{ fontSize: 9.5, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700, color: C.brun }}>{(ca / 1000).toFixed(1)}k</span>
                <div style={{ width: "100%", maxWidth: 52, borderRadius: "5px 5px 0 0", height: `${Math.max(6, ca / maxSem * 60)}px`, background: ca === maxSem ? C.or : C.brunMoyen }} />
                <span style={{ fontSize: 9.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen }}>S{i + 1}</span>
              </div>
            ))}
          </div>
        </div>
        <div style={{ fontFamily: "Inter, system-ui, sans-serif", fontSize: 12, color: C.brun, lineHeight: 1.9 }}>
          <div>🏆 Meilleur service : <b>{meilleur.date}</b> · <b style={{ color: C.or }}>{meilleur.caTTC.toFixed(0)} €</b> ({meilleur.couverts} cv)</div>
          <div>📉 Service le plus calme : <b>{pire.date}</b> · {pire.caTTC.toFixed(0)} € ({pire.couverts} cv)</div>
          <div>💶 CA moyen / service : <b>{(caMois / histo.length).toFixed(0)} €</b></div>
        </div>
      </div>
    </Carte>
  );
}

function Dashboard({ goTo, releves, mep, stocks, rapportsZ, reservations, ventes }) {
  const alertes = releves.filter(r => r.statut === "alerte").length;
  const foodCostMoyen = FICHES.length ? (FICHES.reduce((s, f) => s + f.coutPortion / f.prixVente, 0) / FICHES.length * 100).toFixed(1) : "0.0";
  return (
    <div>
      <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 20 }}>
        <Stat label="Fiches actives" valeur={FICHES.length} sous="Carte du jour" />
        <Stat label="Food cost moyen" valeur={`${foodCostMoyen}%`} sous="Objectif < 30%" accent={foodCostMoyen < 30 ? C.vert : C.rouille} />
        <Stat label="Alertes HACCP" valeur={alertes} sous={alertes > 0 ? "Action requise" : "Tout est conforme"} accent={alertes > 0 ? C.rouille : C.vert} />
        <Stat label="Fournisseurs" valeur={FOURNISSEURS.length} sous="56 commandes ce mois" />
      </div>

      <SyntheseMois rapportsZ={rapportsZ} />
      {releves.filter(r => r.statut === "alerte").map(r => (
        <Carte key={r.id} style={{ marginBottom: 16, background: C.cremeFonce, borderLeft: `4px solid ${C.rouille}` }}>
          <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.rouille, marginBottom: 6 }}>⚠ {r.equipement} : {r.valeur}°C relevé à {r.heure}</div>
          <div style={{ fontSize: 13, color: C.brun, fontFamily: "Inter, system-ui, sans-serif", lineHeight: 1.5 }}>
            Température hors plage (cible {r.cible}). Action corrective : vérifier l'équipement, déplacer les denrées sensibles, recontrôler dans 1h et tracer l'incident au PMS.
          </div>
          <button onClick={() => goTo("haccp")} style={btnStyle(C.rouille)}>Voir le registre HACCP →</button>
        </Carte>
      ))}

      {/* ===== TOPS & FLOPS DU MOIS PAR CATÉGORIE ===== */}
      <Carte style={{ marginBottom: 16 }}>
        <h3 style={h3Style}>Tops & flops du mois — ce qui se vend (et ce qui dort)</h3>
        {(() => {
          // Cumul : stats du mois + ventes du jour en direct
          const compteur = { ...STATS_PLATS_INIT };
          for (const v of ventes) for (const i of v.items) compteur[i.ficheId] = (compteur[i.ficheId] || 0) + i.qte;
          return ["Entrée", "Plat", "Dessert"].map(cat => {
            const liste = FICHES.filter(f => f.categorie === cat)
              .map(f => ({ ...f, vendus: compteur[f.id] || 0 }))
              .sort((a, b) => b.vendus - a.vendus);
            if (liste.length < 2) return null;
            const top = liste[0], flop = liste[liste.length - 1];
            const maxV = Math.max(top.vendus, 1);
            const ligne = (p, type) => (
              <div style={{ flex: 1, minWidth: 230, padding: "10px 12px", borderRadius: 12, background: type === "top" ? "#EDF3E8" : "#F8EFE0", border: `1.5px solid ${type === "top" ? C.vert : C.or}` }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 8 }}>
                  <span style={{ fontFamily: "Inter, system-ui, sans-serif", fontSize: 12.5, fontWeight: 700, color: C.brun }}>
                    {type === "top" ? "🏆" : "📉"} {p.nom}
                  </span>
                  <span style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, fontSize: 15, color: type === "top" ? C.vert : C.rouille }}>{p.vendus}</span>
                </div>
                <div style={{ height: 6, background: "rgba(53,39,24,0.08)", borderRadius: 3, margin: "6px 0 4px" }}>
                  <div style={{ height: 6, width: `${Math.max(4, p.vendus / maxV * 100)}%`, background: type === "top" ? C.vert : C.or, borderRadius: 3 }} />
                </div>
                <div style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen }}>
                  {(p.vendus * p.prixVente).toFixed(0)} € de CA · marge {(p.prixVente - p.coutPortion).toFixed(2)} €/portion
                  {type === "flop" && p.vendus < top.vendus / 3 && " · à retravailler ou sortir de carte ?"}
                </div>
              </div>
            );
            return (
              <div key={cat} style={{ marginBottom: 12 }}>
                <div style={{ fontSize: 10.5, letterSpacing: 1.5, textTransform: "uppercase", color: C.or, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700, marginBottom: 6 }}>{cat}s</div>
                <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
                  {ligne(top, "top")}
                  {ligne(flop, "flop")}
                </div>
              </div>
            );
          });
        })()}
        <div style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginTop: 4 }}>
          Quantités vendues sur le mois (les ventes du jour s'ajoutent en direct). Demande au pilote IA une analyse : « pourquoi mon sorbet coco ne part pas ? »
        </div>
      </Carte>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
        <Carte>
          <h3 style={h3Style}>Marges par plat</h3>
          {FICHES.map(f => {
            const fc = (f.coutPortion / f.prixVente * 100);
            return (
              <div key={f.id} style={{ marginBottom: 10 }}>
                <div style={{ display: "flex", justifyContent: "space-between", fontSize: 13, fontFamily: "Inter, system-ui, sans-serif", color: C.brun, marginBottom: 3 }}>
                  <span>{f.nom}</span><span style={{ fontWeight: 700 }}>{fc.toFixed(0)}%</span>
                </div>
                <div style={{ height: 8, background: C.cremeFonce, borderRadius: 4 }}>
                  <div style={{ height: 8, width: `${fc}%`, background: fc < 30 ? C.vert : C.rouille, borderRadius: 4 }} />
                </div>
              </div>
            );
          })}
          <div style={{ fontSize: 11, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginTop: 8 }}>Food cost = coût matière / prix de vente HT</div>
        </Carte>
        <Carte>
          <h3 style={h3Style}>Actions du jour</h3>
          {(() => {
            const actions = [];
            const dlcCrit = FICHES.filter(f => mep[f.id]?.valide && mep[f.id].dispo > 0 && Math.ceil(((mep[f.id].prodLe || Date.now()) + 3 * 86400000 - Date.now()) / 86400000) <= 1);
            if (dlcCrit.length) actions.push({ t: `DLC critique : ${dlcCrit.map(f => `${f.nom} (${mep[f.id].dispo} portions)`).join(", ")} — écouler ou jeter`, c: C.rouille, go: "haccp" });
            const alertesT = releves.filter(r => r.statut === "alerte");
            if (alertesT.length) actions.push({ t: `Corriger ${alertesT.map(r => r.equipement).join(", ")} (T° hors plage) et recontrôler`, c: C.rouille, go: "haccp" });
            const ruptures = stocks.filter(s => s.qte <= s.seuil);
            if (ruptures.length) actions.push({ t: `Commander : ${ruptures.slice(0, 3).map(r => r.produit).join(", ")}${ruptures.length > 3 ? ` +${ruptures.length - 3}` : ""}`, c: C.rouille, go: "fournisseurs" });
            const nonValides = FICHES.length - Object.values(mep).filter(m => m.valide).length;
            if (nonValides > 0) actions.push({ t: `Valider la mise en place (${nonValides} plat(s) restant(s))`, c: C.or, go: "cuisine" });
            const faibles = FICHES.filter(f => mep[f.id]?.valide && mep[f.id].dispo > 0 && mep[f.id].dispo <= 3);
            if (faibles.length) actions.push({ t: `Bientôt épuisé en salle : ${faibles.map(f => f.nom).join(", ")}`, c: C.or, go: null });
            const resasSansTable = reservations.filter(r => r.statut === "a_venir" && !r.table);
            if (resasSansTable.length) actions.push({ t: `Attribuer une table : ${resasSansTable.map(r => `${r.nom} (${r.heure})`).join(", ")}`, c: C.brunMoyen, go: "resa" });
            actions.push({ t: "Relevé T° de mi-journée (12h00) puis fin de service", c: C.brunMoyen, go: "haccp" });
            actions.push({ t: "Clôture : photographier le Z de la caisse en fin de service", c: C.brunMoyen, go: "zanalyse" });
            return actions.map((a, i) => (
              <div key={i} onClick={() => a.go && goTo(a.go)} style={{ display: "flex", gap: 8, padding: "8px 0", borderBottom: `1px dashed ${C.orClair}`, fontSize: 13, fontFamily: "Inter, system-ui, sans-serif", color: C.brun, cursor: a.go ? "pointer" : "default" }}>
                <span style={{ color: a.c }}>◆</span><span style={{ flex: 1 }}>{a.t}</span>{a.go && <span style={{ color: C.brunMoyen }}>→</span>}
              </div>
            ));
          })()}
        </Carte>
      </div>
    </div>
  );
}

function FichesTechniques({ supprimerFiche, mep, setMep, stocks, setStocks, goTo, majFiches }) {
  const photoRef = useRef(null);
  // Compression de la photo (≈ 640px, JPEG) pour rester léger en sauvegarde
  const prendrePhoto = (file, fiche) => {
    if (!file) return;
    const img = new Image();
    const url = URL.createObjectURL(file);
    img.onload = () => {
      const max = 640;
      const ratio = Math.min(1, max / Math.max(img.width, img.height));
      const cv = document.createElement("canvas");
      cv.width = Math.round(img.width * ratio);
      cv.height = Math.round(img.height * ratio);
      cv.getContext("2d").drawImage(img, 0, 0, cv.width, cv.height);
      fiche.photo = cv.toDataURL("image/jpeg", 0.72);
      URL.revokeObjectURL(url);
      majFiches();
    };
    img.src = url;
  };
  // Valider la mise en place depuis la fiche, avec la quantité de portions choisie
  const validerDepuisFiche = (fiche, portions) => {
    const deductions = calculerDeductions(stocks, fiche, portions);
    setStocks(stocks.map(s => {
      const d = deductions.find(x => x.stockId === s.id);
      return d ? { ...s, qte: Math.max(0, +(s.qte - d.qte).toFixed(2)) } : s;
    }));
    setMep({ ...mep, [fiche.id]: { valide: true, dispo: portions, deductions, prodLe: Date.now() } });
  };
  const annulerDepuisFiche = (fiche) => {
    const m = mep[fiche.id];
    if (!m) return;
    setStocks(stocks.map(s => {
      const d = (m.deductions || []).find(x => x.stockId === s.id);
      return d ? { ...s, qte: +(s.qte + d.qte).toFixed(2) } : s;
    }));
    const nv = { ...mep };
    delete nv[fiche.id];
    setMep(nv);
  };
  // Puce de rapprochement avec la mise en place du module Cuisine
  const puceMep = (f, taille = "normal") => {
    const m = mep[f.id];
    const petit = taille === "petit";
    const style = {
      display: "inline-flex", alignItems: "center", gap: 5,
      fontSize: petit ? 10.5 : 11.5, fontWeight: 600, fontFamily: "Inter, system-ui, sans-serif",
      padding: petit ? "3px 9px" : "4px 11px", borderRadius: 12,
    };
    if (!m?.valide) return (
      <span style={{ ...style, background: C.cremeFonce, color: C.brunMoyen, border: `1.5px dashed ${C.orClair}` }}>
        ○ {petit ? "MEP à faire" : "Fiche réalisée ? Valider la MEP"}
      </span>
    );
    if (m.dispo === 0) return (
      <span style={{ ...style, background: "#F6E0D7", color: C.rouille, border: `1.5px solid ${C.rouille}` }}>
        ● Épuisé (86)
      </span>
    );
    return (
      <span style={{ ...style, background: m.dispo <= 3 ? "#F6ECD4" : "#E7EFE2", color: m.dispo <= 3 ? C.or : C.vert, border: `1.5px solid ${m.dispo <= 3 ? C.or : C.vert}` }}>
        ● MEP ✓ · {m.dispo} dispo
      </span>
    );
  };
  const [sel, setSel] = useState(null);
  const [portions, setPortions] = useState(null);
  const [filtre, setFiltre] = useState("Tout");
  const [confirmId, setConfirmId] = useState(null);
  const [recherche, setRecherche] = useState("");
  if (sel) {
    const f = sel;
    const ratio = (portions || f.portions) / f.portions;
    const fc = (f.coutPortion / f.prixVente * 100).toFixed(1);
    return (
      <div>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
          <button onClick={() => { setSel(null); setPortions(null); setConfirmId(null); }} style={btnStyle(C.brunMoyen)}>← Retour à la carte</button>
          <button onClick={() => {
            if (confirmId === f.id) { supprimerFiche(f.id); setSel(null); setPortions(null); setConfirmId(null); }
            else setConfirmId(f.id);
          }} style={btnStyle(confirmId === f.id ? C.rouille : C.brunMoyen)}>
            {confirmId === f.id ? "⚠ Confirmer la suppression" : "🗑 Supprimer cette fiche"}
          </button>
        </div>
        <Carte style={{ marginTop: 12, borderTop: `4px solid ${C.or}` }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", flexWrap: "wrap", gap: 8 }}>
            <div>
              <h2 style={{ fontFamily: "Fraunces, Georgia, serif", color: C.brun, margin: 0, fontSize: 24 }}>{f.nom}</h2>
              <div style={{ marginTop: 8, display: "flex", gap: 6, flexWrap: "wrap" }}>
                <Badge bg={C.or}>{f.categorie}</Badge>
                <Badge>{f.tempsPrepa} prépa</Badge>
                <Badge>{f.tempsCuisson} cuisson</Badge>
                <Badge color={parseFloat(fc) < 30 ? C.vert : C.rouille}>Food cost {fc}%</Badge>
                <span
                  onClick={() => mep[f.id]?.valide ? annulerDepuisFiche(f) : validerDepuisFiche(f, portions || f.portions)}
                  style={{ cursor: "pointer" }}
                  title={mep[f.id]?.valide ? "Annuler la mise en place (restitue les matières)" : `Fiche réalisée → valider la MEP pour ${portions || f.portions} portions (déduit l'inventaire)`}
                >{puceMep(f)}</span>
              </div>
              {!mep[f.id]?.valide && (
                <div style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginTop: 6, fontStyle: "italic" }}>
                  Ajuste les portions avec − / + puis touche la puce ○ pour valider la mise en place ({portions || f.portions} portions seront disponibles à la vente).
                </div>
              )}
            </div>
            <div style={{ textAlign: "right", fontFamily: "Inter, system-ui, sans-serif" }}>
              <div style={{ fontSize: 11, color: C.brunMoyen, textTransform: "uppercase" }}>Portions</div>
              <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 4 }}>
                <button onClick={() => setPortions(Math.max(1, (portions || f.portions) - f.portions))} style={miniBtn}>−</button>
                <span style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 22, fontWeight: 700, color: C.brun, minWidth: 36, textAlign: "center" }}>{portions || f.portions}</span>
                <button onClick={() => setPortions((portions || f.portions) + f.portions)} style={miniBtn}>+</button>
              </div>
            </div>
          </div>

          <div style={{ display: "grid", gridTemplateColumns: "1fr 1.2fr", gap: 16, marginTop: 18 }}>
            <div>
              <h3 style={h3Style}>Ingrédients {ratio !== 1 && <span style={{ color: C.rouille, fontSize: 12 }}>(×{ratio})</span>}</h3>
              {f.ingredients.map((ing, i) => (
                <div key={i} style={{ display: "flex", justifyContent: "space-between", padding: "6px 0", borderBottom: `1px dashed ${C.orClair}`, fontSize: 13, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
                  <span>{ing.nom} <span style={{ color: ratio !== 1 ? C.rouille : C.brunMoyen, fontWeight: ratio !== 1 ? 700 : 400 }}>· {adapterQte(ing.qte, ratio)}</span></span>
                  <span style={{ fontWeight: 700 }}>{(ing.cout * ratio).toFixed(2)} €</span>
                </div>
              ))}
              <div style={{ display: "flex", justifyContent: "space-between", padding: "10px 0", fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.brun, fontSize: 15 }}>
                <span>Coût matière total</span>
                <span style={{ color: C.or }}>{(f.ingredients.reduce((s, x) => s + x.cout, 0) * ratio).toFixed(2)} €</span>
              </div>
              <div style={{ marginTop: 8, padding: 10, background: C.cremeFonce, borderRadius: 8, fontSize: 12, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
                <b>Allergènes :</b> {f.allergenes.join(", ")}
              </div>
            </div>
            <div>
              <h3 style={h3Style}>Processus</h3>
              {f.etapes.map((e, i) => (
                <div key={i} style={{ display: "flex", gap: 10, marginBottom: 10 }}>
                  <div style={{ width: 24, height: 24, borderRadius: "50%", background: C.or, color: C.blanc, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 12, fontWeight: 700, fontFamily: "Inter, system-ui, sans-serif", flexShrink: 0 }}>{i + 1}</div>
                  <div style={{ fontSize: 13, fontFamily: "Inter, system-ui, sans-serif", color: C.brun, lineHeight: 1.5 }}>{e}</div>
                </div>
              ))}
              {f.dressage && f.dressage.length > 0 && (
                <div style={{ marginTop: 14 }}>
                  <h3 style={h3Style}>Dressage de l'assiette <span style={{ fontSize: 11, color: C.brunMoyen, fontWeight: 400 }}>(par portion)</span></h3>
                  <input ref={photoRef} type="file" accept="image/*" capture="environment" style={{ display: "none" }}
                    onChange={e => { prendrePhoto(e.target.files?.[0], f); e.target.value = ""; }} />
                  {f.photo ? (
                    <div style={{ position: "relative", marginBottom: 10 }}>
                      <img src={f.photo} alt={`Dressage ${f.nom}`} style={{ width: "100%", maxHeight: 240, objectFit: "cover", borderRadius: 14, border: `2px solid ${C.or}`, display: "block", boxShadow: "0 4px 14px rgba(53,39,24,0.18)" }} />
                      <span style={{ position: "absolute", bottom: 8, left: 8, background: "rgba(53,39,24,0.78)", color: C.creme, fontSize: 10, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 600, padding: "3px 10px", borderRadius: 10 }}>📷 Assiette témoin</span>
                      <button onClick={() => photoRef.current?.click()} style={{ position: "absolute", top: 8, right: 8, background: "rgba(255,254,250,0.92)", color: C.brun, border: `1.5px solid ${C.or}`, borderRadius: 10, padding: "4px 10px", fontSize: 10.5, fontWeight: 700, cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif" }}>Remplacer</button>
                    </div>
                  ) : (
                    <button onClick={() => photoRef.current?.click()} style={{
                      width: "100%", marginBottom: 10, padding: "22px 12px", borderRadius: 14,
                      border: `2px dashed ${C.orClair}`, background: "#FBF7EC", cursor: "pointer",
                      fontFamily: "Inter, system-ui, sans-serif", fontSize: 12.5, color: C.brunMoyen, fontWeight: 600,
                    }}>
                      📷 Photographier l'assiette témoin
                      <div style={{ fontSize: 10.5, fontWeight: 400, marginTop: 4, fontStyle: "italic" }}>La référence visuelle du dressage, pour une assiette identique à chaque service</div>
                    </button>
                  )}
                  <div style={{ padding: "10px 12px", background: "#FBF7EC", border: `1.5px dashed ${C.or}`, borderRadius: 12 }}>
                    {f.dressage.map((d, i) => (
                      <div key={i} style={{ display: "flex", alignItems: "baseline", gap: 8, padding: "4px 0", fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
                        <span style={{ color: C.or, fontSize: 10 }}>◆</span>
                        <span style={{ flex: 1 }}>{d.element}</span>
                        <span style={{ fontWeight: 700, color: C.brunMoyen, whiteSpace: "nowrap" }}>{d.qte}</span>
                      </div>
                    ))}
                  </div>
                </div>
              )}
              <div style={{ marginTop: 12, padding: 12, background: C.creme, border: `1px solid ${C.orClair}`, borderRadius: 8, fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, color: C.brun }}>
                <div style={{ display: "flex", justifyContent: "space-between" }}><span>Coût / portion</span><b>{f.coutPortion.toFixed(2)} €</b></div>
                <div style={{ display: "flex", justifyContent: "space-between" }}><span>Prix de vente</span><b>{f.prixVente.toFixed(2)} €</b></div>
                <div style={{ display: "flex", justifyContent: "space-between", color: C.vert }}><span>Marge brute / portion</span><b>{(f.prixVente - f.coutPortion).toFixed(2)} €</b></div>
              </div>
            </div>
          </div>
        </Carte>
      </div>
    );
  }
  const cats = ["Tout", "Entrée", "Plat", "Accompagnement", "Dessert"];
  const visibles = (filtre === "Tout" ? FICHES : FICHES.filter(f => f.categorie === filtre))
    .filter(f => !recherche.trim() || (f.nom + " " + (f.description || "") + " " + f.ingredients.map(i => i.nom).join(" ")).toLowerCase().includes(recherche.toLowerCase()));
  return (
    <div>
    <input value={recherche} onChange={e => setRecherche(e.target.value)} placeholder="🔍 Rechercher un plat, un ingrédient…"
      style={{ width: "100%", padding: "11px 14px", border: "1.5px solid rgba(200,150,42,0.4)", borderRadius: 12, fontFamily: "Inter, system-ui, sans-serif", fontSize: 14, background: C.blanc, color: C.brun, marginBottom: 12, boxSizing: "border-box" }} />
    <div style={{ display: "flex", gap: 6, marginBottom: 14, flexWrap: "wrap" }}>
      {cats.map(c => (
        <button key={c} onClick={() => setFiltre(c)} style={{
          background: filtre === c ? C.brun : C.blanc,
          color: filtre === c ? C.creme : C.brun,
          border: `1.5px solid ${filtre === c ? C.brun : C.orClair}`,
          borderRadius: 16, padding: "6px 14px", fontSize: 12, fontWeight: 700,
          cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif",
        }}>{c} {c !== "Tout" && `(${FICHES.filter(f => f.categorie === c).length})`}</button>
      ))}
    </div>
    <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(230px, 1fr))", gap: 12 }}>
      {visibles.map(f => {
        const fc = (f.coutPortion / f.prixVente * 100);
        return (
          <Carte key={f.id} style={{ cursor: "pointer", borderTop: `3px solid ${C.or}`, position: "relative" }}>
            <button onClick={(e) => {
              e.stopPropagation();
              if (confirmId === f.id) { supprimerFiche(f.id); setConfirmId(null); }
              else setConfirmId(f.id);
            }} title="Supprimer la fiche" style={{
              position: "absolute", top: 8, right: 8, zIndex: 2,
              background: confirmId === f.id ? C.rouille : "transparent",
              color: confirmId === f.id ? C.blanc : C.brunMoyen,
              border: `1.5px solid ${confirmId === f.id ? C.rouille : C.orClair}`,
              borderRadius: confirmId === f.id ? 12 : "50%",
              width: confirmId === f.id ? "auto" : 24, height: 24,
              padding: confirmId === f.id ? "0 10px" : 0,
              fontSize: confirmId === f.id ? 10.5 : 12, fontWeight: 700,
              cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif", lineHeight: 1,
            }}>{confirmId === f.id ? "Confirmer ?" : "🗑"}</button>
            <div onClick={() => { setSel(f); setConfirmId(null); }}>
              {f.photo && <img src={f.photo} alt="" style={{ width: "calc(100% + 36px)", margin: "-18px -18px 10px", height: 110, objectFit: "cover", borderRadius: "14px 14px 0 0", display: "block" }} />}
              <Badge bg={C.brunMoyen}>{f.categorie}</Badge>
              <h3 style={{ fontFamily: "Fraunces, Georgia, serif", color: C.brun, margin: "10px 0 6px", fontSize: 18 }}>{f.nom}</h3>
              <div style={{ fontSize: 12, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>{f.portions} portions · {f.tempsPrepa} + {f.tempsCuisson}</div>
              <div style={{ marginTop: 10, display: "flex", justifyContent: "space-between", fontFamily: "Inter, system-ui, sans-serif", fontSize: 13 }}>
                <span style={{ color: fc < 30 ? C.vert : C.rouille, fontWeight: 700 }}>FC {fc.toFixed(0)}%</span>
                <span style={{ color: C.or, fontWeight: 700 }}>{f.prixVente.toFixed(2)} €</span>
              </div>
              <div style={{ marginTop: 8 }}>{puceMep(f, "petit")}</div>
            </div>
          </Carte>
        );
      })}
    </div>
    </div>
  );
}

const DLC_JOURS = 3; // préparations maison : J+3 (règle usuelle PMS)
function dlcInfos(m) {
  const prod = m.prodLe || Date.now();
  const dlc = prod + DLC_JOURS * 86400000;
  const joursRestants = Math.ceil((dlc - Date.now()) / 86400000);
  return { prod, dlc, joursRestants };
}

function Haccp({ releves, setReleves, mep, setMep }) {
  const productions = FICHES.filter(f => mep[f.id]?.valide && mep[f.id].dispo > 0)
    .map(f => ({ fiche: f, m: mep[f.id], ...dlcInfos(mep[f.id]) }))
    .sort((a, b) => a.joursRestants - b.joursRestants);
  const dlcCritiques = productions.filter(p => p.joursRestants <= 1);

  const jeterProduction = (ficheId) => {
    setMep(prev => { const nv = { ...prev }; delete nv[ficheId]; return nv; });
  };
  const fmtDate = (ts) => new Date(ts).toLocaleDateString("fr-FR", { weekday: "short", day: "2-digit", month: "2-digit" });

  const [valeurs, setValeurs] = useState({});
  const ajouter = (id) => {
    const v = parseFloat(String(valeurs[id]).replace(",", "."));
    if (isNaN(v)) return;
    setReleves(releves.map(r => {
      if (r.id !== id) return r;
      const ok = r.cible.includes("min") ? v >= parseFloat(r.cible) || v >= 63
        : r.cible.includes("-18") ? v <= -18
        : v >= 0 && v <= 4;
      return { ...r, valeur: v, heure: new Date().toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" }), statut: ok ? "ok" : "alerte" };
    }));
    setValeurs({ ...valeurs, [id]: "" });
  };
  return (
    <div>
      <Carte style={{ marginBottom: 14, background: C.cremeFonce }}>
        <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.brun }}>Registre des températures — {new Date().toLocaleDateString("fr-FR", { weekday: "long", day: "numeric", month: "long" })}</div>
        <div style={{ fontSize: 12, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginTop: 4 }}>Traçabilité conforme au Plan de Maîtrise Sanitaire. Saisis un relevé : Mepli Pro vérifie automatiquement la conformité et archive.</div>
      </Carte>
      {/* ===== DLC DES MISES EN PLACE AU FRIGO ===== */}
      <Carte style={{ marginBottom: 14, borderTop: `4px solid ${dlcCritiques.length ? C.rouille : C.vert}` }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 6 }}>
          <h3 style={{ ...h3Style, margin: 0 }}>DLC des mises en place au frigo</h3>
          <Badge bg={dlcCritiques.length ? C.rouille : C.vert}>{dlcCritiques.length ? `⚠ ${dlcCritiques.length} critique(s)` : "✓ Tout est dans les temps"}</Badge>
        </div>
        <div style={{ fontSize: 11.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, margin: "6px 0 10px" }}>
          Préparations maison : DLC à J+{DLC_JOURS} après production (PMS). Les portions restantes proviennent de la mise en place — écouler en priorité, jeter et tracer si dépassé.
        </div>
        {!productions.length && <div style={{ fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, fontStyle: "italic" }}>Aucune production au frigo — valide une mise en place pour démarrer le suivi.</div>}
        {productions.map(p => {
          const depassee = p.joursRestants <= 0;
          const critique = p.joursRestants === 1;
          const tropRestant = !depassee && critique && p.m.dispo >= 4;
          return (
            <div key={p.fiche.id} style={{
              display: "flex", alignItems: "center", gap: 10, padding: "9px 10px", marginBottom: 6, borderRadius: 10, flexWrap: "wrap",
              background: depassee ? "#F6E0D7" : critique ? "#F8F0DC" : "#F0F4EC",
              border: `1.5px solid ${depassee ? C.rouille : critique ? C.or : C.vert}`,
            }}>
              <div style={{ flex: 1, minWidth: 170 }}>
                <div style={{ fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, fontWeight: 700, color: C.brun }}>{p.fiche.nom}</div>
                <div style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen }}>
                  Produit le {fmtDate(p.prod)} · DLC {fmtDate(p.dlc)}
                </div>
              </div>
              <span style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, fontSize: 16, color: depassee ? C.rouille : critique ? C.or : C.vert }}>
                {p.m.dispo} portion(s)
              </span>
              <Badge bg={depassee ? C.rouille : critique ? C.or : C.vert}>
                {depassee ? "DLC DÉPASSÉE — jeter" : critique ? "J-1 · à écouler aujourd'hui" : `J-${p.joursRestants}`}
              </Badge>
              {tropRestant && <Badge bg={C.rouille}>⚠ {p.m.dispo} portions restantes du {fmtDate(p.prod)} !</Badge>}
              {tropRestant && <span style={{ width: "100%", fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun, fontStyle: "italic" }}>Suggestion : plat du jour, formule midi ou -20% pour écouler avant ce soir.</span>}
              {depassee && (
                <button onClick={() => jeterProduction(p.fiche.id)} style={{ ...btnStyle(C.rouille), marginTop: 0 }}>🗑 Jeter & tracer</button>
              )}
            </div>
          );
        })}
      </Carte>

      {releves.map(r => (
        <Carte key={r.id} style={{ marginBottom: 10, borderLeft: `4px solid ${r.statut === "ok" ? C.vert : C.rouille}` }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 10 }}>
            <div>
              <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.brun }}>{r.equipement}</div>
              <div style={{ fontSize: 12, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>Cible : {r.cible} · Dernier relevé : <b>{r.valeur}°C</b> à {r.heure}</div>
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <Badge bg={r.statut === "ok" ? C.vert : C.rouille}>{r.statut === "ok" ? "Conforme" : "Alerte"}</Badge>
              <input
                value={valeurs[r.id] || ""}
                onChange={e => setValeurs({ ...valeurs, [r.id]: e.target.value })}
                placeholder="°C"
                style={{ width: 64, padding: "7px 8px", border: `1.5px solid ${C.orClair}`, borderRadius: 6, fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, background: C.blanc, color: C.brun }}
              />
              <button onClick={() => ajouter(r.id)} style={btnStyle(C.or)}>Relever</button>
            </div>
          </div>
        </Carte>
      ))}
    </div>
  );
}

// ---- CATALOGUES FOURNISSEURS (synchronisés via leurs portails/API — démo) ----
const CATALOGUES = {};

function Fournisseurs({ stocks, setStocks, precommandes, setPrecommandes, factures, setFactures }) {
  const [qtes, setQtes] = useState({});
  const [fournSel, setFournSel] = useState(null);
  const [scanEnCours, setScanEnCours] = useState(false);
  const [scanResultat, setScanResultat] = useState(null);
  const [syncPromos, setSyncPromos] = useState(false);
  const [derniereSync, setDerniereSync] = useState("aujourd'hui 06:00 (auto)");
  const scanRef = useRef(null);

  const aCommander = produitsACommander(stocks);
  const dejaEnCommande = new Set(precommandes.filter(p => p.statut === "envoyee").flatMap(p => p.items.map(i => i.stockId)));
  const suggestions = aCommander.filter(s => !dejaEnCommande.has(s.id));
  const promosActives = Object.entries(CATALOGUES).flatMap(([fid, items]) => items.filter(i => i.promo).map(i => ({ ...i, fid: Number(fid) })));

  // ---- SCAN DE FACTURE (vision IA → classement automatique) ----
  const scannerFacture = async (file) => {
    if (!file) return;
    setScanEnCours(true);
    setScanResultat(null);
    try {
      const base64 = await new Promise((res, rej) => {
        const r = new FileReader();
        r.onload = () => res(r.result.split(",")[1]);
        r.onerror = () => rej(new Error("e"));
        r.readAsDataURL(file);
      });
      const response = await fetch("/api/chat", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          model: "claude-sonnet-4-20250514",
          max_tokens: 500,
          messages: [{
            role: "user",
            content: [
              { type: "image", source: { type: "base64", media_type: file.type || "image/jpeg", data: base64 } },
              { type: "text", text: `Ceci est une facture fournisseur de restaurant. Fournisseurs connus : ${FOURNISSEURS.map(f => f.nom).join(", ")}. Extrais les informations et réponds UNIQUEMENT avec un JSON valide sans backticks :
{"fournisseur":"<nom le plus proche parmi la liste, ou le nom lu si aucun ne correspond>","numero":"<n° de facture>","date":"<JJ/MM>","montantTTC":<nombre>}` }
            ],
          }],
        }),
      });
      const data = await response.json();
      const txt = (data.content || []).filter(b => b.type === "text").map(b => b.text).join("").replace(/```json|```/g, "").trim();
      const fac = JSON.parse(txt);
      const f = FOURNISSEURS.find(x => x.nom.toLowerCase() === String(fac.fournisseur).toLowerCase())
        || FOURNISSEURS.find(x => String(fac.fournisseur).toLowerCase().includes(x.nom.toLowerCase().split(" ")[0]));
      const nouvelle = {
        id: Date.now(), fid: f ? f.id : null, fournisseurLu: fac.fournisseur,
        numero: String(fac.numero || "—"), date: String(fac.date || "—"), montantTTC: Number(fac.montantTTC) || 0,
      };
      setFactures(prev => [...prev, nouvelle]);
      setScanResultat({ ok: true, msg: f
        ? `Facture ${nouvelle.numero} (${nouvelle.montantTTC.toFixed(2)} €) classée chez ${f.nom}`
        : `Facture lue (${fac.fournisseur}) — fournisseur inconnu, classée en "Non rattachées"` });
    } catch {
      setScanResultat({ ok: false, msg: "Lecture impossible — photo floue ? Réessaie." });
    }
    setScanEnCours(false);
  };

  // ---- SYNC PROMOTIONS (agent automatique — démo) ----
  const lancerSync = () => {
    setSyncPromos(true);
    setTimeout(() => {
      setSyncPromos(false);
      setDerniereSync("à l'instant (manuel)");
    }, 1600);
  };

  const creerPrecommande = (fid) => {
    const items = suggestions.filter(s => s.fid === fid).map(s => ({
      stockId: s.id, produit: s.produit, unite: s.unite, pu: s.pu,
      qte: parseFloat(String(qtes[s.id] ?? s.suggestion).replace(",", ".")) || s.suggestion,
    }));
    if (!items.length) return;
    setPrecommandes([...precommandes, {
      id: Date.now(), fid, items, statut: "envoyee",
      date: new Date().toLocaleDateString("fr-FR", { day: "2-digit", month: "2-digit" }),
    }]);
  };

  const receptionner = (cmd) => {
    setStocks(stocks.map(s => {
      const i = cmd.items.find(x => x.stockId === s.id);
      return i ? { ...s, qte: +(s.qte + i.qte).toFixed(2) } : s;
    }));
    setPrecommandes(precommandes.filter(p => p.id !== cmd.id));
  };

  const totalCmd = (items) => items.reduce((s, i) => s + i.qte * i.pu, 0);

  // ============ VUE DÉTAIL D'UN FOURNISSEUR ============
  if (fournSel) {
    const f = FOURNISSEURS.find(x => x.id === fournSel);
    const cat = CATALOGUES[f.id] || [];
    const promos = cat.filter(i => i.promo);
    const fact = factures.filter(x => x.fid === f.id);
    return (
      <div>
        <button onClick={() => setFournSel(null)} style={btnStyle(C.brunMoyen)}>← Tous les fournisseurs</button>
        <Carte style={{ marginTop: 12, borderTop: `4px solid ${C.or}` }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 6 }}>
            <div>
              <h2 style={{ fontFamily: "Fraunces, Georgia, serif", color: C.brun, margin: 0, fontSize: 22 }}>{f.nom}</h2>
              <div style={{ fontSize: 12, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginTop: 4 }}>{f.type} · 📞 {f.tel} · 🚚 {f.delai} · ★ {f.note}</div>
            </div>
            {promos.length > 0 && <Badge bg={C.rouille}>🔥 {promos.length} promo(s) en cours</Badge>}
          </div>
        </Carte>

        {/* Promotions */}
        {promos.length > 0 && (
          <Carte style={{ marginTop: 12, borderLeft: `4px solid ${C.rouille}` }}>
            <h3 style={{ ...h3Style, borderColor: C.rouille }}>Promotions en cours</h3>
            {promos.map(p => (
              <div key={p.ref} style={{ display: "flex", alignItems: "center", gap: 10, padding: "6px 0", borderBottom: `1px dashed ${C.orClair}`, fontSize: 13, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
                <Badge bg={C.rouille}>{p.promo}%</Badge>
                <span style={{ flex: 1 }}>{p.produit}</span>
                <span style={{ textDecoration: "line-through", color: C.brunMoyen, fontSize: 11.5 }}>{p.prix.toFixed(2)} €</span>
                <b style={{ color: C.rouille }}>{(p.prix * (1 + p.promo / 100)).toFixed(2)} €</b>
              </div>
            ))}
          </Carte>
        )}

        {/* Catalogue */}
        <Carte style={{ marginTop: 12 }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
            <h3 style={{ ...h3Style, margin: 0 }}>Catalogue</h3>
            <span style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.vert, fontWeight: 700 }}>● Actualisé {derniereSync}</span>
          </div>
          <div style={{ marginTop: 8 }}>
            {cat.map(p => (
              <div key={p.ref} style={{ display: "flex", alignItems: "center", gap: 10, padding: "6px 0", borderBottom: `1px dashed ${C.orClair}`, fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
                <span style={{ fontSize: 10, color: C.brunMoyen, minWidth: 56 }}>{p.ref}</span>
                <span style={{ flex: 1 }}>{p.produit}</span>
                {p.promo && <Badge bg={C.rouille}>{p.promo}%</Badge>}
                <b style={{ minWidth: 64, textAlign: "right", color: p.promo ? C.rouille : C.brun }}>
                  {(p.prix * (1 + (p.promo || 0) / 100)).toFixed(2)} €
                </b>
              </div>
            ))}
          </div>
        </Carte>

        {/* Factures classées */}
        <Carte style={{ marginTop: 12 }}>
          <h3 style={h3Style}>Factures ({fact.length})</h3>
          {!fact.length && <div style={{ fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, fontStyle: "italic" }}>Aucune facture scannée pour ce fournisseur. Utilise "📷 Scanner une facture" sur l'écran principal.</div>}
          {fact.map(x => (
            <div key={x.id} style={{ display: "flex", gap: 10, alignItems: "center", padding: "6px 0", borderBottom: `1px dashed ${C.orClair}`, fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
              <span style={{ color: C.brunMoyen, minWidth: 44 }}>{x.date}</span>
              <span style={{ flex: 1 }}>Facture n° {x.numero}</span>
              <b>{x.montantTTC.toFixed(2)} €</b>
            </div>
          ))}
          {fact.length > 0 && (
            <div style={{ display: "flex", justifyContent: "space-between", paddingTop: 8, fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.brun, fontSize: 14 }}>
              <span>Total période</span><span style={{ color: C.or }}>{fact.reduce((s, x) => s + x.montantTTC, 0).toFixed(2)} €</span>
            </div>
          )}
        </Carte>
      </div>
    );
  }

  // ============ VUE PRINCIPALE ============
  return (
    <div>
      {/* Barre d'actions : scan facture + sync promos */}
      <Carte style={{ marginBottom: 14, padding: 12 }}>
        <div style={{ display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center" }}>
          <input ref={scanRef} type="file" accept="image/*" capture="environment" style={{ display: "none" }}
            onChange={e => { scannerFacture(e.target.files?.[0]); e.target.value = ""; }} />
          <button onClick={() => scanRef.current?.click()} disabled={scanEnCours} style={{ ...btnStyle(C.or), marginTop: 0 }}>
            {scanEnCours ? "👁 L'IA lit la facture…" : "📷 Scanner une facture"}
          </button>
          <button onClick={lancerSync} disabled={syncPromos} style={{ ...btnStyle(C.brunMoyen), marginTop: 0 }}>
            {syncPromos ? "🔄 Synchronisation…" : "🔄 Récupérer les promotions"}
          </button>
          <span style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginLeft: "auto" }}>
            Catalogues & promos synchronisés chaque nuit à 06:00 · dernière sync : {derniereSync}
          </span>
        </div>
        {scanResultat && (
          <div style={{ marginTop: 8, padding: 8, borderRadius: 8, fontSize: 12, fontFamily: "Inter, system-ui, sans-serif",
            background: scanResultat.ok ? "#E3EBDD" : "#F3DCD4",
            border: `1.5px solid ${scanResultat.ok ? C.vert : C.rouille}`,
            color: scanResultat.ok ? C.vert : C.rouille, fontWeight: 700 }}>
            {scanResultat.ok ? "✓" : "⚠"} {scanResultat.msg}
          </div>
        )}
      </Carte>

      {/* Bandeau promotions toutes enseignes */}
      {promosActives.length > 0 && (
        <Carte style={{ marginBottom: 14, borderLeft: `4px solid ${C.rouille}` }}>
          <h3 style={{ ...h3Style, borderColor: C.rouille }}>🔥 Promotions du moment ({promosActives.length})</h3>
          <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
            {promosActives.map(p => (
              <button key={p.ref} onClick={() => setFournSel(p.fid)} style={{
                background: C.creme, border: `1.5px solid ${C.rouille}`, borderRadius: 10,
                padding: "8px 10px", cursor: "pointer", textAlign: "left", fontFamily: "Inter, system-ui, sans-serif",
              }}>
                <div style={{ fontSize: 11.5, fontWeight: 700, color: C.brun }}>{p.produit}</div>
                <div style={{ fontSize: 10.5, color: C.brunMoyen, marginTop: 2 }}>
                  {FOURNISSEURS.find(f => f.id === p.fid)?.nom} · <b style={{ color: C.rouille }}>{p.promo}%</b> → {(p.prix * (1 + p.promo / 100)).toFixed(2)} €
                </div>
              </button>
            ))}
          </div>
        </Carte>
      )}

      {/* Pré-commandes suggérées */}
      {suggestions.length > 0 && (
        <Carte style={{ marginBottom: 16, borderTop: `4px solid ${C.rouille}` }}>
          <h3 style={{ ...h3Style, borderColor: C.rouille }}>Pré-commandes suggérées · {suggestions.length} produit(s) à réapprovisionner</h3>
          <div style={{ fontSize: 11.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginBottom: 10 }}>
            Détecté automatiquement depuis l'inventaire. Quantités pré-remplies pour recompléter à 2× le seuil — ajustables.
          </div>
          {FOURNISSEURS.filter(f => suggestions.some(s => s.fid === f.id)).map(f => {
            const lignes = suggestions.filter(s => s.fid === f.id);
            const total = lignes.reduce((s, l) => s + (parseFloat(String(qtes[l.id] ?? l.suggestion).replace(",", ".")) || l.suggestion) * l.pu, 0);
            return (
              <div key={f.id} style={{ marginBottom: 12, padding: 12, background: C.creme, borderRadius: 10, border: `1px solid ${C.orClair}` }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8, flexWrap: "wrap", gap: 6 }}>
                  <div>
                    <span style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.brun }}>{f.nom}</span>
                    <span style={{ fontSize: 11, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginLeft: 8 }}>{f.type} · Livraison {f.delai}</span>
                  </div>
                  <Badge bg={C.rouille}>{lignes.length} produit(s)</Badge>
                </div>
                {lignes.map(l => (
                  <div key={l.id} style={{ display: "flex", alignItems: "center", gap: 8, padding: "5px 0", borderBottom: `1px dashed ${C.orClair}`, fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
                    <span style={{ flex: 1 }}>
                      {l.produit}
                      <span style={{ color: l.qte <= l.seuil ? C.rouille : C.or, fontSize: 10.5, fontWeight: 700, marginLeft: 6 }}>
                        {l.qte <= l.seuil ? "⚠ rupture" : "stock faible"} · reste {l.qte} {l.unite}
                      </span>
                    </span>
                    <input value={qtes[l.id] ?? l.suggestion} onChange={e => setQtes({ ...qtes, [l.id]: e.target.value })}
                      style={{ width: 52, padding: "5px 4px", border: `1.5px solid ${C.orClair}`, borderRadius: 6, fontFamily: "Inter, system-ui, sans-serif", fontSize: 12, textAlign: "center", background: C.blanc, color: C.brun }} />
                    <span style={{ fontSize: 11, color: C.brunMoyen, minWidth: 28 }}>{l.unite}</span>
                    <span style={{ fontSize: 11.5, fontWeight: 700, color: C.brun, minWidth: 52, textAlign: "right" }}>
                      {((parseFloat(String(qtes[l.id] ?? l.suggestion).replace(",", ".")) || l.suggestion) * l.pu).toFixed(2)} €
                    </span>
                  </div>
                ))}
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 8 }}>
                  <span style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.or }}>Total : {total.toFixed(2)} €</span>
                  <button onClick={() => creerPrecommande(f.id)} style={{ ...btnStyle(C.vert), marginTop: 0 }}>✓ Créer la pré-commande</button>
                </div>
              </div>
            );
          })}
        </Carte>
      )}

      {/* Pré-commandes en cours */}
      {precommandes.length > 0 && (
        <Carte style={{ marginBottom: 16, borderTop: `4px solid ${C.vert}` }}>
          <h3 style={{ ...h3Style, borderColor: C.vert }}>Pré-commandes en cours</h3>
          {precommandes.map(cmd => {
            const f = FOURNISSEURS.find(x => x.id === cmd.fid);
            return (
              <div key={cmd.id} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "8px 0", borderBottom: `1px dashed ${C.orClair}`, flexWrap: "wrap", gap: 8 }}>
                <div>
                  <span style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.brun }}>{f?.nom}</span>
                  <span style={{ fontSize: 11.5, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginLeft: 8 }}>
                    {cmd.date} · {cmd.items.length} produit(s) · {totalCmd(cmd.items).toFixed(2)} €
                  </span>
                  <div style={{ fontSize: 11, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginTop: 2 }}>
                    {cmd.items.map(i => `${i.qte} ${i.unite} ${i.produit}`).join(" · ")}
                  </div>
                </div>
                <button onClick={() => receptionner(cmd)} style={{ ...btnStyle(C.or), marginTop: 0 }}>📦 Réceptionner (+ stock)</button>
              </div>
            );
          })}
        </Carte>
      )}

      {/* Carnet fournisseurs */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))", gap: 12 }}>
        {FOURNISSEURS.map(f => {
          const nbSugg = suggestions.filter(s => s.fid === f.id).length;
          const nbPromos = (CATALOGUES[f.id] || []).filter(i => i.promo).length;
          const nbFact = factures.filter(x => x.fid === f.id).length;
          return (
            <Carte key={f.id} style={{ borderTop: `3px solid ${nbSugg ? C.rouille : C.brunMoyen}`, position: "relative", cursor: "pointer" }}>
              {nbSugg > 0 && (
                <span style={{ position: "absolute", top: -9, right: -7, minWidth: 24, height: 24, borderRadius: 12, background: C.rouille, color: C.blanc, fontSize: 12.5, fontWeight: 700, fontFamily: "Inter, system-ui, sans-serif", display: "flex", alignItems: "center", justifyContent: "center", padding: "0 6px", border: `2px solid ${C.blanc}` }}>{nbSugg}</span>
              )}
              <div onClick={() => setFournSel(f.id)}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                  <h3 style={{ fontFamily: "Fraunces, Georgia, serif", color: C.brun, margin: 0, fontSize: 17 }}>{f.nom}</h3>
                  <span style={{ color: C.or, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700, fontSize: 13 }}>★ {f.note}</span>
                </div>
                <div style={{ fontSize: 12, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginTop: 4 }}>{f.type}</div>
                <div style={{ marginTop: 10, fontSize: 13, fontFamily: "Inter, system-ui, sans-serif", color: C.brun, lineHeight: 1.7 }}>
                  📞 {f.tel}<br />🚚 Livraison {f.delai}
                </div>
                <div style={{ display: "flex", gap: 6, marginTop: 10, flexWrap: "wrap" }}>
                  {nbPromos > 0 && <Badge bg={C.rouille}>🔥 {nbPromos} promo(s)</Badge>}
                  <Badge color={C.brunMoyen}>{nbFact} facture(s)</Badge>
                  <Badge color={C.or}>Catalogue →</Badge>
                </div>
              </div>
            </Carte>
          );
        })}
      </div>
      {factures.some(x => !x.fid) && (
        <Carte style={{ marginTop: 12, borderLeft: `4px solid ${C.or}` }}>
          <h3 style={h3Style}>Factures non rattachées</h3>
          {factures.filter(x => !x.fid).map(x => (
            <div key={x.id} style={{ display: "flex", gap: 10, alignItems: "center", padding: "5px 0", fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
              <span style={{ color: C.brunMoyen }}>{x.date}</span>
              <span style={{ flex: 1 }}>{x.fournisseurLu} · n° {x.numero}</span>
              <b>{x.montantTTC.toFixed(2)} €</b>
            </div>
          ))}
        </Carte>
      )}
    </div>
  );
}

function AssistantIA({ profil, stocks, setStocks, releves, setReleves, planning, setPlanning, menu, setMenu, tables, setTables, commandes, setCommandes, mep, setMep, precommandes, setPrecommandes, ventes, rapportsZ, factures, reservations, setReservations, naviguer, ajouterFiche, ordreInitial, consommerOrdre }) {
  const [messages, setMessages] = useState([
    { role: "assistant", content: "Bonjour Chef ! Je pilote votre établissement : je peux consulter ET agir sur tous vos modules. Essayez : « enregistre 2,5°C pour la vitrine », « sors 2 kg de riz du stock », « compose un menu du jour à 26 € avec entrée, plat, dessert », « mets Kévin en repos samedi », ou « ouvre le module stocks »." },
  ]);
  const [input, setInput] = useState("");
  const [loading, setLoading] = useState(false);
  const [ecoute, setEcoute] = useState(false);
  const [voixActive, setVoixActive] = useState(true);
  const [microDispo, setMicroDispo] = useState(true);
  const endRef = useRef(null);
  useEffect(() => { endRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages]);
  // Ordre lancé depuis la barre de l'accueil : exécuté à l'ouverture du pilote
  useEffect(() => {
    if (ordreInitial) { const o = ordreInitial; consommerOrdre(); envoyer(o); }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const [fichesAjoutees, setFichesAjoutees] = useState(() => new Set());
  const ajouterProposition = (p) => {
    const coutTotal = p.ingredients.reduce((s, i) => s + (Number(i.cout) || 0), 0);
    const fiche = {
      id: FICHES.length ? Math.max(...FICHES.map(f => f.id)) + 1 : 1,
      nom: p.nom, description: p.description ? String(p.description) : "", categorie: p.categorie || "Plat", portions: Number(p.portions) || 4,
      coutPortion: +(coutTotal / (Number(p.portions) || 4)).toFixed(2),
      prixVente: Number(p.prixVente) || 0,
      tempsPrepa: p.tempsPrepa || "—", tempsCuisson: p.tempsCuisson || "—",
      ingredients: p.ingredients.map(i => ({ nom: String(i.nom), qte: String(i.qte), cout: Number(i.cout) || 0 })),
      etapes: p.etapes.map(String),
      allergenes: Array.isArray(p.allergenes) && p.allergenes.length ? p.allergenes.map(String) : ["Aucun allergène majeur"],
      dressage: Array.isArray(p.dressage) ? p.dressage.map(d => ({ element: String(d.element), qte: String(d.qte) })) : [],
    };
    ajouterFiche(fiche);
    setFichesAjoutees(prev => new Set(prev).add(p.nom));
  };

  const lireVoixHaute = (texte) => {
    if (!voixActive || !("speechSynthesis" in window)) return;
    window.speechSynthesis.cancel();
    const u = new SpeechSynthesisUtterance(texte.replace(/[▤❄✎◷⬚📦✓✗→•]/g, " "));
    u.lang = "fr-FR";
    window.speechSynthesis.speak(u);
  };

  const demarrerMicro = () => {
    const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
    if (!SR) { setMicroDispo(false); return; }
    try {
      const rec = new SR();
      rec.lang = "fr-FR";
      rec.interimResults = false;
      rec.onresult = (e) => { const txt = e.results[0][0].transcript; setInput(txt); envoyer(txt); };
      rec.onend = () => setEcoute(false);
      rec.onerror = () => { setEcoute(false); setMicroDispo(false); };
      setEcoute(true);
      rec.start();
    } catch { setEcoute(false); setMicroDispo(false); }
  };

  // ---- ÉTAT TEMPS RÉEL DE L'ÉTABLISSEMENT (recalculé à chaque message) ----
  const construireContexte = () => `Tu es l'assistant-pilote de "Mepli Pro", application modulaire de gestion de restaurant. Tu réponds en français, concis, ton professionnel chaleureux ("Chef"). Tu peux LIRE l'état ci-dessous et AGIR via le protocole d'actions.

=== ÉTAT TEMPS RÉEL ===
CARTE (${FICHES.length} fiches) : ${FICHES.map(f => `${f.nom} [${f.categorie}] coût ${f.coutPortion}€ / PV ${f.prixVente}€ / FC ${(f.coutPortion / f.prixVente * 100).toFixed(0)}% / allergènes: ${f.allergenes.join("+")}`).join(" | ")}
HACCP : ${releves.map(r => `${r.equipement}: ${r.valeur}°C à ${r.heure} (cible ${r.cible}) → ${r.statut.toUpperCase()}`).join(" | ")}
STOCKS : ${stocks.map(s => `${s.produit}: ${s.qte} ${s.unite} (seuil ${s.seuil}, ${s.pu}€/${s.unite}, ${s.zone})${s.qte <= s.seuil ? " ⚠RUPTURE" : ""}`).join(" | ")}
PLANNING SEMAINE (jours: ${JOURS.join(",")}) : ${EQUIPE.map(e => `${e.nom} (${e.poste}): ${(planning[e.id] || []).join("/")}`).join(" | ") || "aucune équipe renseignée"}
MENU EN COURS : "${menu.titre}" à ${menu.prix}€ avec [${FICHES.filter(f => menu.selection.includes(f.id)).map(f => f.nom).join(", ") || "vide"}]
MISE EN PLACE (dispo à la vente, DLC J+3 après production) : ${FICHES.map(f => { const m = mep[f.id]; if (!m?.valide) return `${f.nom}: non validé`; const jr = Math.ceil(((m.prodLe || Date.now()) + 3 * 86400000 - Date.now()) / 86400000); return `${f.nom}: ${m.dispo} dispo (DLC ${jr <= 0 ? "DÉPASSÉE" : "J-" + jr})`; }).join(" | ")}
SALLE : ${tables.map(t => `Table ${t.num} (${t.places} cv): ${t.statut}`).join(" | ")}
RÉSERVATIONS DU JOUR : ${reservations.filter(r => r.statut !== "annulee").map(r => `${r.heure} ${r.nom} (${r.couverts} cv, ${r.service}${r.table ? ", T" + r.table : ""}, ${r.statut})`).join(" | ") || "aucune"}
COMMANDES EN COURS : ${commandes.filter(c => c.statut !== "servie").map(c => `#T${c.table} ${c.heure} [${c.items.map(i => i.qte + "x " + (FICHES.find(f => f.id === i.ficheId)?.nom || "?")).join(", ")}] → ${c.statut}`).join(" | ") || "aucune"}
FOURNISSEURS : ${FOURNISSEURS.map(f => `${f.nom} (${f.type}, ${f.delai})`).join(" | ")}
À RÉAPPROVISIONNER : ${produitsACommander(stocks).map(s => `${s.produit} (reste ${s.qte} ${s.unite}, suggéré ${s.suggestion} ${s.unite}, chez ${FOURNISSEURS.find(f => f.id === s.fid)?.nom})`).join(" | ") || "rien"}
PROMOS FOURNISSEURS : ${Object.entries(CATALOGUES).flatMap(([fid, items]) => items.filter(i => i.promo).map(i => `${i.produit} ${i.promo}% chez ${FOURNISSEURS.find(f => f.id === Number(fid))?.nom}`)).join(" | ")}
FACTURES SCANNÉES : ${factures.length} (total ${factures.reduce((s, x) => s + x.montantTTC, 0).toFixed(2)}€)
PRÉ-COMMANDES EN COURS : ${precommandes.map(p => `${FOURNISSEURS.find(f => f.id === p.fid)?.nom}: ${p.items.length} produit(s)`).join(" | ") || "aucune"}
CAISSE DU JOUR : ${ventes.length} ticket(s), CA ${ventes.reduce((s, v) => s + v.total, 0).toFixed(2)}€ (${ventes.filter(v => v.origine === "Comptoir").length} comptoir / ${ventes.filter(v => v.origine !== "Comptoir").length} tables)
HISTORIQUE Z (clôtures) : ${rapportsZ.slice(-7).map(z => `${z.date}: ${z.caTTC.toFixed(0)}€/${z.couverts}cv`).join(" | ") || "aucun"}
SYNTHÈSE DU MOIS : CA ${rapportsZ.reduce((s, z) => s + z.caTTC, 0).toFixed(0)}€ sur ${rapportsZ.length} services, ${rapportsZ.reduce((s, z) => s + z.couverts, 0)} couverts, vs ${MOIS_PRECEDENT.libelle} ${MOIS_PRECEDENT.caTTC.toFixed(0)}€
VENTES DU MOIS PAR PLAT : ${FICHES.map(f => `${f.nom}: ${STATS_PLATS_INIT[f.id] || 0}`).join(" | ")}
FOOD COST GLOBAL (théorique, pondéré ventes) : ${(() => { let ca = 0, ct = 0; for (const f of FICHES) { const v = STATS_PLATS_INIT[f.id] || 0; ca += f.prixVente * v; ct += f.coutPortion * v; } return ca ? (ct / ca * 100).toFixed(1) : "0"; })()}% — Objectif usuel 28-32%. Pour le menu engineering : star = populaire+marge haute, cheval de labour = populaire+marge faible, énigme = peu vendu+marge haute, poids mort = ni l'un ni l'autre.
MODULES : dashboard, fiches, stocks, carte, caisse, haccp, fournisseurs, planning, service, ia, boutique
${pp_resume(profil)}

=== PROTOCOLE D'ACTIONS ===
Pour AGIR, termine ta réponse par un bloc EXACTEMENT de cette forme (JSON valide, rien après) :
@@ACTIONS
[{"type":"...", ...}]
@@FIN
Types disponibles :
- {"type":"stock","produit":"<nom exact>","delta":<nombre ±>} → ajuste une quantité (delta négatif = sortie)
- {"type":"haccp","equipement":"<nom exact>","valeur":<°C>} → enregistre un relevé de température
- {"type":"menu","titre":"<titre>","prix":<nombre>,"plats":["<nom exact de fiche>", ...]} → compose le menu du jour
- {"type":"planning","employe":"<prénom exact>","jour":"<Lun|Mar|Mer|Jeu|Ven|Sam|Dim>","service":"<Repos|Midi|Soir|Doublon>"} → modifie le planning
- {"type":"commande","table":<numéro>,"plats":[{"nom":"<nom exact de fiche>","qte":<n>}, ...]} → envoie une commande en cuisine (refuse si plat épuisé en mise en place : signale-le au Chef)
- {"type":"mep","plat":"<nom exact de fiche>","portions":<n>} → valide la mise en place d'un plat (déduit les matières premières de l'inventaire)
- {"type":"precommande","fournisseur":"<nom exact>"} → crée une pré-commande chez ce fournisseur avec tous ses produits à réapprovisionner (quantités suggérées)
- {"type":"reservation","nom":"<nom>","couverts":<n>,"heure":"<HH:MM>","service":"<Midi|Soir>","tel":"<optionnel>"} → ajoute une réservation au carnet
- {"type":"naviguer","module":"<id module>"} → ouvre un module pour le Chef
Règles : n'émets des actions QUE si le Chef demande une modification ou si c'est clairement utile (annonce-le dans ta réponse texte). Utilise les noms EXACTS de l'état. Plusieurs actions possibles dans le même bloc. Si une action HACCP est non conforme, signale l'alerte et l'action corrective réglementaire (PMS). Réponses texte : 3-7 phrases max.

=== PROPOSITION DE FICHE TECHNIQUE ===
Quand le Chef te demande une recette, une idée de plat, ou un nouveau plat (qui n'est pas déjà dans la carte), donne une réponse texte courte (présentation du plat, 2-4 phrases) PUIS ajoute un bloc EXACTEMENT de cette forme :
@@FICHE
{"nom":"...","description":"<courte description appétissante pour la carte, 8-15 mots>","categorie":"Entrée|Plat|Accompagnement|Dessert","portions":<n>,"tempsPrepa":"...","tempsCuisson":"...","prixVente":<€>,"ingredients":[{"nom":"...","qte":"...","cout":<€ estimé pour le total>}],"etapes":["..."],"allergenes":["..."],"dressage":[{"element":"<composant de l'assiette>","qte":"<quantité par portion, ex: 150 g / 2 pièces / PM>"}]}
@@FINFICHE
Ce bloc s'affichera comme une carte que le Chef peut ajouter à ses fiches techniques en un clic. Quantités professionnelles précises (g/kg/ml/L/pièces), coûts réalistes pour le marché local du restaurant, 4-6 étapes claires, allergènes réglementaires (ou ["Aucun allergène majeur"]). N'utilise PAS ce bloc pour les recettes déjà présentes dans la carte.`;

  // ---- EXÉCUTEUR D'ACTIONS ----
  const executer = (actions) => {
    const faits = [];
    let nvStocks = stocks, nvReleves = releves, nvPlanning = planning, nvMenu = menu;
    for (const a of actions) {
      try {
        if (a.type === "stock") {
          const p = nvStocks.find(s => s.produit.toLowerCase() === String(a.produit).toLowerCase());
          if (!p) { faits.push(`✗ Stock introuvable : ${a.produit}`); continue; }
          nvStocks = nvStocks.map(s => s.id === p.id ? { ...s, qte: Math.max(0, +(s.qte + Number(a.delta)).toFixed(2)) } : s);
          faits.push(`▤ Stock ${p.produit} : ${a.delta > 0 ? "+" : ""}${a.delta} ${p.unite}`);
        } else if (a.type === "haccp") {
          const r = nvReleves.find(x => x.equipement.toLowerCase() === String(a.equipement).toLowerCase());
          if (!r) { faits.push(`✗ Équipement introuvable : ${a.equipement}`); continue; }
          const v = Number(a.valeur);
          const ok = r.cible.includes("min") ? v >= 63 : r.cible.includes("-18") ? v <= -18 : v >= 0 && v <= 4;
          nvReleves = nvReleves.map(x => x.id === r.id ? { ...x, valeur: v, heure: new Date().toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" }), statut: ok ? "ok" : "alerte" } : x);
          faits.push(`❄ Relevé ${r.equipement} : ${v}°C → ${ok ? "conforme" : "⚠ ALERTE"}`);
        } else if (a.type === "menu") {
          const ids = (a.plats || []).map(nom => FICHES.find(f => f.nom.toLowerCase() === String(nom).toLowerCase())?.id).filter(Boolean);
          nvMenu = { titre: a.titre || nvMenu.titre, prix: String(a.prix ?? nvMenu.prix), selection: ids.length ? ids : nvMenu.selection };
          faits.push(`✎ Menu "${nvMenu.titre}" composé (${ids.length} plats, ${nvMenu.prix} €)`);
        } else if (a.type === "planning") {
          const e = EQUIPE.find(x => x.nom.toLowerCase() === String(a.employe).toLowerCase());
          const j = JOURS.findIndex(x => x.toLowerCase() === String(a.jour).toLowerCase().slice(0, 3));
          if (!e || j < 0 || !SERVICES.includes(a.service)) { faits.push(`✗ Planning invalide : ${a.employe}/${a.jour}/${a.service}`); continue; }
          const nv = { ...nvPlanning, [e.id]: [...nvPlanning[e.id]] };
          nv[e.id][j] = a.service;
          nvPlanning = nv;
          faits.push(`◷ ${e.nom} → ${a.service} ${JOURS[j]}`);
        } else if (a.type === "commande") {
          const t = tables.find(x => x.num === Number(a.table));
          if (!t) { faits.push(`✗ Table introuvable : ${a.table}`); continue; }
          const items = (a.plats || []).map(p => ({ ficheId: FICHES.find(f => f.nom.toLowerCase() === String(p.nom).toLowerCase())?.id, qte: Number(p.qte) || 1 })).filter(i => i.ficheId);
          if (!items.length) { faits.push(`✗ Aucun plat reconnu pour la table ${a.table}`); continue; }
          const epuises = items.filter(i => mep[i.ficheId]?.valide && mep[i.ficheId].dispo < i.qte);
          if (epuises.length) { faits.push(`✗ Épuisé/insuffisant : ${epuises.map(i => FICHES.find(f => f.id === i.ficheId)?.nom).join(", ")}`); continue; }
          setCommandes(prev => [...prev, { id: Date.now() + Math.random(), table: t.num, items, statut: "en_attente", heure: new Date().toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" }), ts: Date.now() }]);
          setTables(prev => prev.map(x => x.num === t.num ? { ...x, statut: "occupee" } : x));
          setMep(prev => {
            const nv = { ...prev };
            for (const i of items) if (nv[i.ficheId]?.valide) nv[i.ficheId] = { ...nv[i.ficheId], dispo: Math.max(0, nv[i.ficheId].dispo - i.qte) };
            return nv;
          });
          faits.push(`⬚ Commande table ${t.num} envoyée en cuisine (${items.length} ligne(s))`);
        } else if (a.type === "mep") {
          const f = FICHES.find(x => x.nom.toLowerCase() === String(a.plat).toLowerCase());
          if (!f) { faits.push(`✗ Fiche introuvable : ${a.plat}`); continue; }
          const portions = Number(a.portions) || 0;
          if (portions <= 0) { faits.push(`✗ Portions invalides pour ${f.nom}`); continue; }
          const deductions = calculerDeductions(stocks, f, portions);
          setStocks(prev => prev.map(s => {
            const d = deductions.find(x => x.stockId === s.id);
            return d ? { ...s, qte: Math.max(0, +(s.qte - d.qte).toFixed(2)) } : s;
          }));
          setMep(prev => ({ ...prev, [f.id]: { valide: true, dispo: portions, deductions, prodLe: Date.now() } }));
          faits.push(`✓ MEP ${f.nom} : ${portions} portions (matières déduites de l'inventaire)`);
        } else if (a.type === "precommande") {
          const f = FOURNISSEURS.find(x => x.nom.toLowerCase() === String(a.fournisseur).toLowerCase());
          if (!f) { faits.push(`✗ Fournisseur introuvable : ${a.fournisseur}`); continue; }
          const dejaCmd = new Set(precommandes.flatMap(p => p.items.map(i => i.stockId)));
          const lignes = produitsACommander(nvStocks).filter(s => s.fid === f.id && !dejaCmd.has(s.id))
            .map(s => ({ stockId: s.id, produit: s.produit, unite: s.unite, pu: s.pu, qte: s.suggestion }));
          if (!lignes.length) { faits.push(`✗ Rien à commander chez ${f.nom}`); continue; }
          setPrecommandes(prev => [...prev, { id: Date.now() + Math.random(), fid: f.id, items: lignes, statut: "envoyee", date: new Date().toLocaleDateString("fr-FR", { day: "2-digit", month: "2-digit" }) }]);
          faits.push(`📦 Pré-commande ${f.nom} : ${lignes.length} produit(s), ${lignes.reduce((s, l) => s + l.qte * l.pu, 0).toFixed(2)} €`);
        } else if (a.type === "reservation") {
          if (!a.nom || !a.heure) { faits.push("✗ Réservation incomplète (nom + heure requis)"); continue; }
          setReservations(prev => [...prev, {
            id: Date.now() + Math.random(), nom: String(a.nom), couverts: Number(a.couverts) || 2,
            heure: String(a.heure), service: a.service === "Midi" ? "Midi" : "Soir",
            tel: String(a.tel || ""), table: null, statut: "a_venir",
          }]);
          faits.push(`✆ Réservation ${a.nom} · ${a.couverts || 2} cv · ${a.heure} (${a.service || "Soir"})`);
        } else if (a.type === "naviguer") {
          naviguer(String(a.module));
          faits.push(`→ Module ${a.module} ouvert`);
        }
      } catch { faits.push("✗ Action invalide ignorée"); }
    }
    setStocks(nvStocks); setReleves(nvReleves); setPlanning(nvPlanning); setMenu(nvMenu);
    return faits;
  };

  const envoyer = async (texteForce) => {
    const contenu = String(texteForce ?? input).trim();
    if (!contenu || loading) return;
    const userMsg = { role: "user", content: contenu };
    const histo = [...messages, userMsg];
    setMessages(histo);
    setInput("");
    setLoading(true);
    try {
      const response = await fetch("/api/chat", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          model: "claude-sonnet-4-20250514",
          max_tokens: 1500,
          system: construireContexte(),
          messages: histo.filter(m => !m.actions).map(m => ({ role: m.role, content: m.content })),
        }),
      });
      const data = await response.json();
      const brut = (data.content || []).filter(b => b.type === "text").map(b => b.text).join("\n") || "Désolé Chef, je n'ai pas pu répondre.";
      // Extraire le bloc d'actions éventuel
      let texte = brut, faits = [], proposition = null;
      const match = brut.match(/@@ACTIONS\s*([\s\S]*?)\s*@@FIN/);
      if (match) {
        texte = texte.replace(match[0], "").trim();
        try {
          const actions = JSON.parse(match[1].replace(/```json|```/g, "").trim());
          faits = executer(Array.isArray(actions) ? actions : [actions]);
        } catch { faits = ["✗ Bloc d'actions illisible — rien n'a été modifié"]; }
      }
      // Extraire une proposition de fiche technique éventuelle
      const matchFiche = texte.match(/@@FICHE\s*([\s\S]*?)\s*@@FINFICHE/);
      if (matchFiche) {
        texte = texte.replace(matchFiche[0], "").trim();
        try {
          const f = JSON.parse(matchFiche[1].replace(/```json|```/g, "").trim());
          if (f.nom && Array.isArray(f.ingredients) && Array.isArray(f.etapes)) proposition = f;
        } catch { /* proposition illisible : on garde juste le texte */ }
      }
      setMessages([...histo, { role: "assistant", content: texte, actions: faits, proposition }]);
      lireVoixHaute(faits.length ? texte + ". " + faits.join(". ") : texte);
    } catch {
      setMessages([...histo, { role: "assistant", content: "Erreur de connexion à l'assistant. Réessaie." }]);
    }
    setLoading(false);
  };

  const suggestions = [
    "Propose-moi une recette de ti-punch revisité en dessert",
    "Enregistre 2,5°C pour la vitrine réfrigérée",
    "Compose un menu du jour à 26 €",
    "Qu'est-ce que je dois commander cette semaine ?",
  ];

  return (
    <Carte style={{ display: "flex", flexDirection: "column", height: "62vh", minHeight: 420, padding: 0, overflow: "hidden" }}>
      <div style={{ background: C.brun, color: C.creme, padding: "12px 16px", fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, display: "flex", alignItems: "center", gap: 8 }}>
        <span style={{ width: 9, height: 9, borderRadius: "50%", background: ecoute ? "#E08A6D" : "#7BC47F", display: "inline-block" }} />
        <span style={{ flex: 1 }}>Pilote Mepli Pro — texte & voix, agit sur tous vos modules</span>
        <button onClick={() => { if (voixActive) window.speechSynthesis?.cancel(); setVoixActive(!voixActive); }} title={voixActive ? "Couper la voix" : "Activer la voix"} style={{
          background: "transparent", border: `1.5px solid ${C.orClair}`, borderRadius: 14,
          color: voixActive ? C.orClair : "#9b8a72", fontSize: 11.5, fontWeight: 700,
          padding: "4px 10px", cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif",
        }}>{voixActive ? "🔊 Voix ON" : "🔇 Voix OFF"}</button>
      </div>
      <div style={{ flex: 1, overflowY: "auto", padding: 14, background: C.creme }}>
        {messages.map((m, i) => (
          <div key={i} style={{ marginBottom: 10 }}>
            <div style={{ display: "flex", justifyContent: m.role === "user" ? "flex-end" : "flex-start" }}>
              <div style={{
                maxWidth: "82%", padding: "10px 13px", borderRadius: 12,
                background: m.role === "user" ? C.or : C.blanc,
                color: m.role === "user" ? C.blanc : C.brun,
                border: m.role === "user" ? "none" : `1px solid ${C.orClair}`,
                fontFamily: "Inter, system-ui, sans-serif", fontSize: 13.5, lineHeight: 1.55, whiteSpace: "pre-wrap",
              }}>{m.content}</div>
            </div>
            {m.proposition && (
              <div style={{ marginTop: 8, maxWidth: "82%", padding: 12, background: C.blanc, border: `2px solid ${C.or}`, borderRadius: 12 }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 6 }}>
                  <div>
                    <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.brun, fontSize: 15 }}>✦ {m.proposition.nom}</div>
                    <div style={{ fontSize: 11, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginTop: 2 }}>
                      {m.proposition.categorie} · {m.proposition.portions} portions · {m.proposition.ingredients.length} ingrédients · PV {Number(m.proposition.prixVente).toFixed(2)} €
                    </div>
                  </div>
                  {fichesAjoutees.has(m.proposition.nom) ? (
                    <Badge bg={C.vert}>✓ Dans vos fiches</Badge>
                  ) : (
                    <button onClick={() => ajouterProposition(m.proposition)} style={{ ...btnStyle(C.vert), marginTop: 0 }}>➕ Ajouter aux fiches techniques</button>
                  )}
                </div>
              </div>
            )}
            {m.actions && m.actions.length > 0 && (
              <div style={{ display: "flex", flexWrap: "wrap", gap: 6, marginTop: 6 }}>
                {m.actions.map((f, k) => (
                  <span key={k} style={{
                    fontSize: 11.5, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700, padding: "4px 10px", borderRadius: 12,
                    background: f.startsWith("✗") ? "#F3DCD4" : "#E3EBDD",
                    color: f.startsWith("✗") ? C.rouille : C.vert,
                    border: `1px solid ${f.startsWith("✗") ? C.rouille : C.vert}`,
                  }}>{f}</span>
                ))}
              </div>
            )}
          </div>
        ))}
        {loading && <div style={{ fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, color: C.brunMoyen, fontStyle: "italic" }}>Le pilote agit…</div>}
        <div ref={endRef} />
      </div>
      <div style={{ padding: 10, borderTop: `1px solid ${C.orClair}`, background: C.blanc }}>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 8 }}>
          {suggestions.map((s, i) => (
            <button key={i} onClick={() => setInput(s)} style={{ ...btnStyle(C.brunMoyen), fontSize: 11, padding: "4px 10px" }}>{s}</button>
          ))}
        </div>
        <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
          <button onClick={demarrerMicro} disabled={ecoute || loading} title={microDispo ? "Parler au pilote" : "Micro indisponible dans cet aperçu"} style={{
            width: 44, height: 44, borderRadius: "50%", flexShrink: 0,
            border: `2.5px solid ${C.or}`, cursor: microDispo ? "pointer" : "default",
            background: ecoute ? C.rouille : microDispo ? C.brun : C.cremeFonce,
            color: microDispo ? C.creme : C.brunMoyen, fontSize: 19,
            boxShadow: ecoute ? "0 0 0 8px rgba(139,58,30,0.18)" : "none", transition: "all .2s",
          }}>{ecoute ? "…" : "🎙"}</button>
          <input
            value={input}
            onChange={e => setInput(e.target.value)}
            onKeyDown={e => e.key === "Enter" && envoyer()}
            placeholder={ecoute ? "Je t'écoute, Chef…" : "Parle ou écris ton ordre, Chef…"}
            style={{ flex: 1, padding: "10px 12px", border: `1.5px solid ${C.orClair}`, borderRadius: 8, fontFamily: "Inter, system-ui, sans-serif", fontSize: 14, background: C.blanc, color: C.brun, outline: "none" }}
          />
          <button onClick={() => envoyer()} disabled={loading} style={{ ...btnStyle(C.or), padding: "10px 18px", marginTop: 0, opacity: loading ? 0.6 : 1 }}>Envoyer</button>
        </div>
        {!microDispo && <div style={{ fontSize: 10.5, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginTop: 5 }}>Micro bloqué dans cet aperçu (restriction navigateur) — la dictée fonctionnera dans l'app finale. La voix de synthèse reste active.</div>}
      </div>
    </Carte>
  );
}

// ============ STYLES UTILES ============
const btnStyle = (couleur) => ({
  background: couleur, color: C.blanc, border: "none", borderRadius: 9,
  padding: "8px 15px", fontSize: 12, fontWeight: 600, cursor: "pointer",
  fontFamily: "Inter, system-ui, sans-serif", marginTop: 6,
  letterSpacing: 0.1, boxShadow: "0 1px 3px rgba(53,39,24,0.18)",
});
const miniBtn = {
  width: 28, height: 28, borderRadius: "50%", border: `1.5px solid ${C.or}`,
  background: C.blanc, color: C.or, fontSize: 16, fontWeight: 700, cursor: "pointer",
};
const h3Style = { fontFamily: "Fraunces, Georgia, serif", color: C.brun, fontSize: 15.5, fontWeight: 600, letterSpacing: 0.2, margin: "0 0 10px", borderBottom: `2px solid ${C.or}`, paddingBottom: 6 };

// ============ EXTENSION : STOCKS & INVENTAIRE ============
const STOCKS_INIT = [];

// ---- MOTEUR DE DÉDUCTION : consommation matière par portion ----
// Parse "2,5 kg" / "400 ml" / "8 pièces" → quantité en unité de stock (kg, L, pièce)
function parseQuantite(txt) {
  const m = String(txt).replace(",", ".").match(/([\d.]+)\s*(kg|g|l|ml|cl|pièces?|×)?/i);
  if (!m) return null;
  let v = parseFloat(m[1]);
  const u = (m[2] || "").toLowerCase();
  if (u === "g") return { v: v / 1000, u: "kg" };
  if (u === "kg") return { v, u: "kg" };
  if (u === "ml") return { v: v / 1000, u: "L" };
  if (u === "cl") return { v: v / 100, u: "L" };
  if (u === "l") return { v, u: "L" };
  return { v, u: "pièce" };
}
// Adapte une quantité texte ("2,5 kg", "8 pièces", "400 ml") à un ratio de portions
function adapterQte(txt, ratio) {
  if (ratio === 1 || !/[\d]/.test(String(txt))) return txt; // "PM" et autres restent tels quels
  let premier = true;
  return String(txt).replace(/(\d+[.,]?\d*)/, (m) => {
    if (!premier) return m;
    premier = false;
    const v = parseFloat(m.replace(",", ".")) * ratio;
    const arrondi = v >= 100 ? Math.round(v) : Math.round(v * 100) / 100;
    return String(arrondi).replace(".", ",");
  });
}

// Rapproche un ingrédient d'un produit du stock par préfixe de mots (≥4 lettres)
function trouverStock(stocks, nomIngredient) {
  const mots = nomIngredient.toLowerCase().split(/[\s,()]+/).filter(w => w.length >= 4);
  return stocks.find(s => {
    const motsStock = s.produit.toLowerCase().split(/[\s,()]+/).filter(w => w.length >= 4);
    return mots.some(mi => motsStock.some(ms => ms.startsWith(mi.slice(0, 4)) && mi.startsWith(ms.slice(0, 4))));
  });
}
// Calcule les déductions de stock pour `portions` portions d'une fiche
function calculerDeductions(stocks, fiche, portions) {
  const deductions = [];
  for (const ing of fiche.ingredients) {
    const s = trouverStock(stocks, ing.nom);
    if (!s) continue;
    const q = parseQuantite(ing.qte);
    if (!q || q.u !== (s.unite === "pièce" ? "pièce" : s.unite)) continue;
    const parPortion = q.v / fiche.portions;
    deductions.push({ stockId: s.id, produit: s.produit, qte: +(parPortion * portions).toFixed(3), unite: s.unite });
  }
  return deductions;
}

function Stocks({ stocks, setStocks }) {
  const [ajustements, setAjustements] = useState({});
  const [pole, setPole] = useState("Tout");
  const poles = ["Tout", "Cuisine", "Salle", "Bar"];
  const visibles = pole === "Tout" ? stocks : stocks.filter(s => s.pole === pole);
  const valeurTotale = stocks.reduce((s, p) => s + p.qte * p.pu, 0);
  const ruptures = stocks.filter(p => p.qte <= p.seuil);

  const ajuster = (id, sens) => {
    const delta = parseFloat(String(ajustements[id] || "1").replace(",", "."));
    if (isNaN(delta)) return;
    setStocks(stocks.map(p => p.id === id ? { ...p, qte: Math.max(0, +(p.qte + sens * delta).toFixed(2)) } : p));
  };

  return (
    <div>
      <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 16 }}>
        <Stat label="Valeur du stock" valeur={`${valeurTotale.toFixed(0)} €`} sous="Valorisation au PU d'achat" />
        <Stat label="Références" valeur={stocks.length} sous="Cuisine · Salle · Bar" />
        <Stat label="Alertes rupture" valeur={ruptures.length} sous={ruptures.length ? "Commande à passer" : "Stocks sains"} accent={ruptures.length ? C.rouille : C.vert} />
      </div>
      {ruptures.length > 0 && (
        <Carte style={{ marginBottom: 14, background: C.cremeFonce, borderLeft: `4px solid ${C.rouille}` }}>
          <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.rouille, marginBottom: 4 }}>⚠ Sous le seuil : {ruptures.map(r => r.produit).join(", ")}</div>
          <div style={{ fontSize: 12.5, color: C.brun, fontFamily: "Inter, system-ui, sans-serif" }}>Suggestion : grouper la commande chez vos fournisseurs habituels (voir module Fournisseurs).</div>
        </Carte>
      )}
      <div style={{ display: "flex", gap: 6, marginBottom: 12, flexWrap: "wrap" }}>
        {poles.map(p => (
          <button key={p} onClick={() => setPole(p)} style={{
            background: pole === p ? C.brun : C.blanc, color: pole === p ? C.creme : C.brun,
            border: `1.5px solid ${pole === p ? C.brun : C.orClair}`, borderRadius: 16,
            padding: "6px 14px", fontSize: 12, fontWeight: 700, cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif",
          }}>{p} {p !== "Tout" && `(${stocks.filter(s => s.pole === p).length})`}</button>
        ))}
      </div>
      {visibles.map(p => {
        const alerte = p.qte <= p.seuil;
        return (
          <Carte key={p.id} style={{ marginBottom: 8, borderLeft: `4px solid ${alerte ? C.rouille : C.vert}`, padding: 12 }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 8 }}>
              <div style={{ minWidth: 180 }}>
                <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.brun, fontSize: 14 }}>{p.produit}</div>
                <div style={{ fontSize: 11.5, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>{p.pole} · {p.zone} · Seuil {p.seuil} {p.unite} · {p.pu.toFixed(2)} €/{p.unite}</div>
              </div>
              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <span style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 18, fontWeight: 700, color: alerte ? C.rouille : C.brun, minWidth: 70, textAlign: "right" }}>{p.qte} {p.unite}</span>
                <input value={ajustements[p.id] || ""} onChange={e => setAjustements({ ...ajustements, [p.id]: e.target.value })} placeholder="1"
                  style={{ width: 46, padding: "6px 6px", border: `1.5px solid ${C.orClair}`, borderRadius: 6, fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, background: C.blanc, color: C.brun, textAlign: "center" }} />
                <button onClick={() => ajuster(p.id, -1)} style={{ ...miniBtn, borderColor: C.rouille, color: C.rouille }}>−</button>
                <button onClick={() => ajuster(p.id, +1)} style={{ ...miniBtn, borderColor: C.vert, color: C.vert }}>+</button>
              </div>
            </div>
          </Carte>
        );
      })}
      <div style={{ fontSize: 11, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginTop: 8 }}>Saisis une quantité puis − (sortie/consommation) ou + (réception). Les alertes se déclenchent automatiquement sous le seuil.</div>
    </div>
  );
}

// ============ EXTENSION : PLANNING ÉQUIPE ============
let EQUIPE = [];
const JOURS = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];
const SERVICES = ["Repos", "Midi", "Soir", "Doublon"];
const HEURES_SERVICE = { Repos: 0, Midi: 5, Soir: 5, Doublon: 9 };
const COULEURS_SERVICE = { Repos: "#D8CFBC", Midi: "#C8962A", Soir: "#6B5440", Doublon: "#8B3A1E" };

function planningInitial() {
  const init = {};
  EQUIPE.forEach(e => { init[e.id] = JOURS.map((_, j) => (j === 0 ? "Repos" : j >= 5 ? "Doublon" : "Soir")); });
  return init;
}

function Planning({ planning, setPlanning }) {
  const [caPrev, setCaPrev] = useState("9500");

  const cycler = (empId, jour) => {
    const next = { ...planning };
    const actuel = SERVICES.indexOf(planning[empId][jour]);
    next[empId] = [...planning[empId]];
    next[empId][jour] = SERVICES[(actuel + 1) % SERVICES.length];
    setPlanning(next);
  };

  const heuresEmp = (e) => planning[e.id].reduce((s, srv) => s + HEURES_SERVICE[srv], 0);
  const coutTotal = EQUIPE.reduce((s, e) => s + heuresEmp(e) * e.tauxH * 1.42, 0); // charges patronales ~42%
  const ca = parseFloat(caPrev.replace(",", ".")) || 0;
  const ratio = ca > 0 ? (coutTotal / ca * 100) : 0;

  return (
    <div>
      <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 16 }}>
        <Stat label="Masse salariale semaine" valeur={`${coutTotal.toFixed(0)} €`} sous="Charges patronales incluses (≈42%)" />
        <Carte style={{ flex: 1, minWidth: 150, borderTop: `3px solid ${C.or}` }}>
          <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 1, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>CA prévisionnel semaine</div>
          <input value={caPrev} onChange={e => setCaPrev(e.target.value)}
            style={{ width: "90%", marginTop: 6, padding: "7px 8px", border: `1.5px solid ${C.orClair}`, borderRadius: 6, fontFamily: "Fraunces, Georgia, serif", fontSize: 18, fontWeight: 700, background: C.blanc, color: C.brun }} />
        </Carte>
        <Stat label="Ratio personnel / CA" valeur={`${ratio.toFixed(1)}%`} sous={ratio <= 35 ? "Bon (cible ≤ 35%)" : "Trop élevé (cible ≤ 35%)"} accent={ratio <= 35 ? C.vert : C.rouille} />
      </div>
      <Carte style={{ overflowX: "auto", padding: 12 }}>
        <table style={{ borderCollapse: "collapse", width: "100%", fontFamily: "Inter, system-ui, sans-serif", fontSize: 12 }}>
          <thead>
            <tr>
              <th style={{ textAlign: "left", padding: 8, color: C.brunMoyen, fontSize: 11, textTransform: "uppercase" }}>Équipe</th>
              {JOURS.map(j => <th key={j} style={{ padding: 8, color: C.brunMoyen, fontSize: 11 }}>{j}</th>)}
              <th style={{ padding: 8, color: C.brunMoyen, fontSize: 11 }}>H</th>
            </tr>
          </thead>
          <tbody>
            {EQUIPE.map(e => (
              <tr key={e.id} style={{ borderTop: `1px dashed ${C.orClair}` }}>
                <td style={{ padding: 8 }}>
                  <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.brun }}>{e.nom}</div>
                  <div style={{ fontSize: 10.5, color: C.brunMoyen }}>{e.poste}</div>
                </td>
                {JOURS.map((_, j) => (
                  <td key={j} style={{ padding: 4, textAlign: "center" }}>
                    <button onClick={() => cycler(e.id, j)} style={{
                      background: COULEURS_SERVICE[planning[e.id][j]], color: planning[e.id][j] === "Repos" ? C.brunMoyen : C.blanc,
                      border: "none", borderRadius: 6, padding: "6px 4px", fontSize: 10.5, fontWeight: 700, cursor: "pointer", width: 58, fontFamily: "Inter, system-ui, sans-serif",
                    }}>{planning[e.id][j]}</button>
                  </td>
                ))}
                <td style={{ padding: 8, textAlign: "center", fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: heuresEmp(e) > 39 ? C.rouille : C.brun }}>{heuresEmp(e)}</td>
              </tr>
            ))}
          </tbody>
        </table>
        <div style={{ fontSize: 11, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginTop: 8 }}>Clique sur une case pour faire tourner : Repos → Midi → Soir → Doublon. Heures &gt; 39h/sem affichées en rouge (heures sup à anticiper).</div>
      </Carte>
    </div>
  );
}

// ============ EXTENSION : MENUS & CARTE DU JOUR ============
function Menus({ selection, setSelection, titreMenu, setTitreMenu, prixMenu, setPrixMenu, carteExclus, setCarteExclus, majFiches, profil }) {
  const [prixEdit, setPrixEdit] = useState({});
  // Prix conseillé : food cost cible 30% arrondi au 0,50 € supérieur
  const prixConseille = (f) => Math.ceil((f.coutPortion / 0.30) * 2) / 2;
  const changerPrix = (f, val) => {
    setPrixEdit({ ...prixEdit, [f.id]: val });
    const v = parseFloat(String(val).replace(",", "."));
    if (!isNaN(v) && v > 0) { f.prixVente = v; majFiches(); }
  };
  const [vol, setVol] = useState("carte");
  const ordre = { "Entrée": 0, "Plat": 1, "Accompagnement": 2, "Dessert": 3 };

  // ----- Onglet MENU DU JOUR -----
  const basculer = (id) => setSelection(selection.includes(id) ? selection.filter(s => s !== id) : [...selection, id]);
  const plats = FICHES.filter(f => selection.includes(f.id));
  const coutMenu = plats.reduce((s, f) => s + f.coutPortion, 0);
  const prix = parseFloat(prixMenu.replace(",", ".")) || 0;
  const fcMenu = prix > 0 ? (coutMenu / prix * 100) : 0;
  const platsTries = [...plats].sort((a, b) => ordre[a.categorie] - ordre[b.categorie]);

  // ----- Onglet CARTE -----
  const surCarte = FICHES.filter(f => !carteExclus.includes(f.id));
  const basculerCarte = (id) => setCarteExclus(carteExclus.includes(id) ? carteExclus.filter(x => x !== id) : [...carteExclus, id]);

  return (
    <div>
      {/* Bascule Carte / Menu du jour */}
      <div style={{ display: "flex", gap: 8, marginBottom: 14 }}>
        {[["carte", "📜 Carte"], ["jour", "☀ Menu du jour"]].map(([id, label]) => (
          <button key={id} onClick={() => setVol(id)} style={{
            background: vol === id ? C.brun : C.blanc, color: vol === id ? C.creme : C.brun,
            border: `1.5px solid ${vol === id ? C.brun : C.orClair}`, borderRadius: 8,
            padding: "9px 18px", fontSize: 13, fontWeight: 700, cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif",
          }}>{label}</button>
        ))}
      </div>

      {vol === "carte" && (
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1.1fr", gap: 14 }}>
          <Carte>
            <h3 style={h3Style}>Plats à la carte ({surCarte.length}/{FICHES.length})</h3>
            <div style={{ fontSize: 11.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginBottom: 8 }}>
              Décoche un plat pour le retirer de la carte. Modifie le prix directement — le prix conseillé (food cost 30%) sert de repère, touche-le pour l'appliquer. Tout se répercute partout : caisse, salle, food cost.
            </div>
            <div style={{ maxHeight: 420, overflowY: "auto" }}>
              {["Entrée", "Plat", "Accompagnement", "Dessert"].map(cat => {
                const items = FICHES.filter(f => f.categorie === cat);
                if (!items.length) return null;
                return (
                  <div key={cat}>
                    <div style={{ fontSize: 10, letterSpacing: 2, color: C.or, textTransform: "uppercase", fontFamily: "Inter, system-ui, sans-serif", margin: "10px 0 4px", fontWeight: 700 }}>{cat}s</div>
                    {items.map(f => {
                      const conseil = prixConseille(f);
                      const ecart = f.prixVente - conseil;
                      return (
                        <div key={f.id} style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 4px", borderBottom: `1px dashed ${C.orClair}`, fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun, opacity: carteExclus.includes(f.id) ? 0.5 : 1 }}>
                          <input type="checkbox" checked={!carteExclus.includes(f.id)} onChange={() => basculerCarte(f.id)} style={{ accentColor: C.or, cursor: "pointer" }} />
                          <span style={{ flex: 1, minWidth: 0 }}>
                            {f.nom}
                            <span onClick={() => changerPrix(f, String(conseil))} title="Appliquer le prix conseillé" style={{ display: "block", fontSize: 10, color: Math.abs(ecart) < 0.26 ? C.vert : ecart < 0 ? C.rouille : C.brunMoyen, cursor: "pointer" }}>
                              conseillé : {conseil.toFixed(2)} € (FC 30%){ecart < -0.25 ? " · sous-vendu ⚠" : ""}
                            </span>
                          </span>
                          <div style={{ display: "flex", alignItems: "center", gap: 3 }}>
                            <input value={prixEdit[f.id] ?? f.prixVente.toFixed(2)} onChange={e => changerPrix(f, e.target.value)}
                              style={{ width: 58, padding: "5px 6px", border: `1.5px solid ${C.orClair}`, borderRadius: 8, fontFamily: "Inter, system-ui, sans-serif", fontSize: 12, fontWeight: 700, textAlign: "right", background: C.blanc, color: C.or }} />
                            <span style={{ fontSize: 11, color: C.brunMoyen }}>€</span>
                          </div>
                        </div>
                      );
                    })}
                  </div>
                );
              })}
            </div>
          </Carte>
          {/* Aperçu carte du restaurant */}
          <Carte style={{ background: C.blanc, border: `2px solid ${C.or}`, padding: 26, position: "relative" }}>
            <div style={{ position: "absolute", top: 8, left: 8, right: 8, bottom: 8, border: `1px solid ${C.orClair}`, borderRadius: 4, pointerEvents: "none" }} />
            <div style={{ textAlign: "center" }}>
              <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 13, letterSpacing: 3, color: C.or, textTransform: "uppercase" }}>{profil?.nom || "Votre établissement"}</div>
              <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 26, fontWeight: 700, color: C.brun, margin: "6px 0" }}>La Carte</div>
              <div style={{ width: 60, height: 2, background: C.or, margin: "10px auto" }} />
            </div>
            <div style={{ marginTop: 16, maxHeight: 420, overflowY: "auto" }}>
              {["Entrée", "Plat", "Accompagnement", "Dessert"].map(cat => {
                const items = surCarte.filter(p => p.categorie === cat).sort((a, b) => a.prixVente - b.prixVente);
                if (!items.length) return null;
                return (
                  <div key={cat} style={{ marginBottom: 16 }}>
                    <div style={{ fontFamily: "Inter, system-ui, sans-serif", fontSize: 10, letterSpacing: 2, color: C.or, textTransform: "uppercase", marginBottom: 8, textAlign: "center" }}>— {cat}s —</div>
                    {items.map(p => (
                      <div key={p.id} style={{ marginBottom: 11 }}>
                        <div style={{ display: "flex", alignItems: "baseline", gap: 6 }}>
                          <span style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 15, color: C.brun }}>{p.nom}</span>
                          <span style={{ flex: 1, borderBottom: `1px dotted ${C.orClair}` }} />
                          <span style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.rouille, fontSize: 14 }}>{p.prixVente.toFixed(2).replace(".", ",")} €</span>
                        </div>
                        {p.description && <div style={{ fontSize: 11, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", fontStyle: "italic", marginTop: 1, lineHeight: 1.4 }}>{p.description}</div>}
                        {p.allergenes[0] !== "Aucun allergène majeur" &&
                          <div style={{ fontSize: 9.5, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>Allergènes : {p.allergenes.join(", ")}</div>}
                      </div>
                    ))}
                  </div>
                );
              })}
            </div>
            <div style={{ textAlign: "center", marginTop: 8, fontFamily: "Fraunces, Georgia, serif", fontSize: 10, color: C.brunMoyen, fontStyle: "italic" }}>Fait maison · Produits pays · Prix nets TTC</div>
          </Carte>
        </div>
      )}

      {vol === "jour" && (
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1.1fr", gap: 14 }}>
          <div>
            <Carte style={{ marginBottom: 12 }}>
              <h3 style={h3Style}>Composer le menu</h3>
              <div style={{ display: "flex", gap: 8, marginBottom: 10 }}>
                <input value={titreMenu} onChange={e => setTitreMenu(e.target.value)}
                  style={{ flex: 1, padding: "8px 10px", border: `1.5px solid ${C.orClair}`, borderRadius: 6, fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, background: C.blanc, color: C.brun }} />
                <input value={prixMenu} onChange={e => setPrixMenu(e.target.value)} placeholder="Prix €"
                  style={{ width: 70, padding: "8px 10px", border: `1.5px solid ${C.orClair}`, borderRadius: 6, fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, background: C.blanc, color: C.brun, textAlign: "center" }} />
              </div>
              <div style={{ maxHeight: 320, overflowY: "auto" }}>
                {FICHES.map(f => (
                  <label key={f.id} style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 4px", borderBottom: `1px dashed ${C.orClair}`, fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun, cursor: "pointer" }}>
                    <input type="checkbox" checked={selection.includes(f.id)} onChange={() => basculer(f.id)} style={{ accentColor: C.or }} />
                    <span style={{ flex: 1 }}>{f.nom}</span>
                    <span style={{ fontSize: 10.5, color: C.brunMoyen }}>{f.categorie} · {f.coutPortion.toFixed(2)} €</span>
                  </label>
                ))}
              </div>
            </Carte>
            <Carte style={{ background: C.cremeFonce }}>
              <div style={{ fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, color: C.brun, lineHeight: 1.8 }}>
                <div style={{ display: "flex", justifyContent: "space-between" }}><span>Coût matière du menu</span><b>{coutMenu.toFixed(2)} €</b></div>
                <div style={{ display: "flex", justifyContent: "space-between" }}><span>Prix de vente</span><b>{prix.toFixed(2)} €</b></div>
                <div style={{ display: "flex", justifyContent: "space-between", color: fcMenu <= 30 ? C.vert : C.rouille }}>
                  <span>Food cost du menu</span><b>{fcMenu.toFixed(1)}% {fcMenu <= 30 ? "✓" : "⚠ > 30%"}</b>
                </div>
              </div>
            </Carte>
          </div>
          {/* Aperçu menu du jour imprimable */}
          <Carte style={{ background: C.blanc, border: `2px solid ${C.or}`, padding: 26, position: "relative" }}>
            <div style={{ position: "absolute", top: 8, left: 8, right: 8, bottom: 8, border: `1px solid ${C.orClair}`, borderRadius: 4, pointerEvents: "none" }} />
            <div style={{ textAlign: "center" }}>
              <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 13, letterSpacing: 3, color: C.or, textTransform: "uppercase" }}>{profil?.nom || "Votre établissement"}</div>
              <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 26, fontWeight: 700, color: C.brun, margin: "6px 0" }}>{titreMenu}</div>
              <div style={{ width: 60, height: 2, background: C.or, margin: "10px auto" }} />
              <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 20, color: C.rouille, fontWeight: 700 }}>{prix.toFixed(2).replace(".", ",")} €</div>
            </div>
            <div style={{ marginTop: 18 }}>
              {["Entrée", "Plat", "Accompagnement", "Dessert"].map(cat => {
                const items = platsTries.filter(p => p.categorie === cat);
                if (!items.length) return null;
                return (
                  <div key={cat} style={{ marginBottom: 14, textAlign: "center" }}>
                    <div style={{ fontFamily: "Inter, system-ui, sans-serif", fontSize: 10, letterSpacing: 2, color: C.or, textTransform: "uppercase", marginBottom: 6 }}>— {cat} —</div>
                    {items.map(p => (
                      <div key={p.id} style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 16, color: C.brun, marginBottom: 7 }}>
                        {p.nom}
                        {p.description && <div style={{ fontSize: 11, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", fontStyle: "italic", lineHeight: 1.4 }}>{p.description}</div>}
                        <div style={{ fontSize: 9.5, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>Allergènes : {p.allergenes.join(", ")}</div>
                      </div>
                    ))}
                  </div>
                );
              })}
              {!plats.length && <div style={{ textAlign: "center", color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, fontStyle: "italic" }}>Coche des plats à gauche pour composer ton menu</div>}
            </div>
            <div style={{ textAlign: "center", marginTop: 10, fontFamily: "Fraunces, Georgia, serif", fontSize: 10, color: C.brunMoyen, fontStyle: "italic" }}>Fait maison · Produits pays · Prix nets TTC</div>
          </Carte>
        </div>
      )}
    </div>
  );
}

// ============ EXTENSION : SERVICE EN SALLE (plan de salle + écran cuisine) ============
let TABLES_INIT = [];

const STATUT_COMMANDE = { en_attente: "Envoyée", en_cuisine: "En cuisine", prete: "Prête", servie: "Servie" };
const COULEUR_COMMANDE = { en_attente: "#C8962A", en_cuisine: "#8B3A1E", prete: "#4A6741", servie: "#6B5440" };

function Service({ tables, setTables, commandes, setCommandes, mep, setMep, enregistrerVente, reservations }) {
  const dispoDe = (ficheId) => mep[ficheId]?.valide ? mep[ficheId].dispo : null;
  const resaDeTable = (num) => (reservations || []).find(r => r.table === num && r.statut === "a_venir");
  const [vue, setVue] = useState("salle");
  const [tableSel, setTableSel] = useState(null);
  const [panier, setPanier] = useState({});
  const [horloge, setHorloge] = useState(Date.now());
  useEffect(() => { const t = setInterval(() => setHorloge(Date.now()), 30000); return () => clearInterval(t); }, []);

  const cmdsTable = (num) => commandes.filter(c => c.table === num && c.statut !== "servie");
  const totalTable = (num) => commandes.filter(c => c.table === num && c.statut !== "servie")
    .reduce((s, c) => s + c.items.reduce((t, i) => t + (FICHES.find(f => f.id === i.ficheId)?.prixVente || 0) * i.qte, 0), 0);
  const pretesPourSalle = commandes.filter(c => c.statut === "prete").length;
  const caService = commandes.filter(c => c.statut === "servie")
    .reduce((s, c) => s + c.items.reduce((t, i) => t + (FICHES.find(f => f.id === i.ficheId)?.prixVente || 0) * i.qte, 0), 0);

  const couleurTable = (t) => {
    if (cmdsTable(t.num).some(c => c.statut === "prete")) return C.vert;
    if (t.statut === "occupee") return C.rouille;
    return C.or;
  };

  const ajouterPanier = (ficheId) => setPanier({ ...panier, [ficheId]: (panier[ficheId] || 0) + 1 });
  const retirerPanier = (ficheId) => {
    const nv = { ...panier };
    if (nv[ficheId] > 1) nv[ficheId]--; else delete nv[ficheId];
    setPanier(nv);
  };

  const envoyerEnCuisine = () => {
    const items = Object.entries(panier).map(([id, qte]) => ({ ficheId: Number(id), qte }));
    if (!items.length || !tableSel) return;
    setCommandes([...commandes, {
      id: Date.now(), table: tableSel, items, statut: "en_attente",
      heure: new Date().toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" }), ts: Date.now(),
    }]);
    setTables(tables.map(t => t.num === tableSel ? { ...t, statut: "occupee" } : t));
    // Décrémenter les disponibilités de la mise en place
    setMep(prev => {
      const nv = { ...prev };
      for (const i of items) {
        if (nv[i.ficheId]?.valide) nv[i.ficheId] = { ...nv[i.ficheId], dispo: Math.max(0, nv[i.ficheId].dispo - i.qte) };
      }
      return nv;
    });
    setPanier({});
  };

  const avancerCommande = (id) => {
    const suite = { en_attente: "en_cuisine", en_cuisine: "prete", prete: "servie" };
    setCommandes(commandes.map(c => c.id === id ? { ...c, statut: suite[c.statut] || c.statut } : c));
  };

  const encaisser = (num) => {
    // Enregistrer l'addition en caisse (origine Table)
    const aPayer = commandes.filter(c => c.table === num && c.statut !== "servie");
    const items = aPayer.flatMap(c => c.items.map(i => ({ ficheId: i.ficheId, qte: i.qte, pu: FICHES.find(f => f.id === i.ficheId)?.prixVente || 0 })));
    const total = items.reduce((s, i) => s + i.pu * i.qte, 0);
    if (items.length) enregistrerVente({ items, total, mode: "CB", origine: `Table ${num}` });
    setCommandes(commandes.map(c => c.table === num ? { ...c, statut: "servie" } : c));
    setTables(tables.map(t => t.num === num ? { ...t, statut: "libre" } : t));
    setTableSel(null);
  };

  const minutesDepuis = (ts) => Math.max(0, Math.round((horloge - ts) / 60000));
  const ticketsCuisine = commandes.filter(c => c.statut === "en_attente" || c.statut === "en_cuisine").sort((a, b) => a.ts - b.ts);

  return (
    <div>
      {/* Bascule Salle / Cuisine */}
      <div style={{ display: "flex", gap: 8, marginBottom: 14, alignItems: "center", flexWrap: "wrap" }}>
        {[["salle", "🍽 Interface salle"], ["cuisine", `🔥 Écran cuisine${ticketsCuisine.length ? ` (${ticketsCuisine.length})` : ""}`]].map(([id, label]) => (
          <button key={id} onClick={() => setVue(id)} style={{
            background: vue === id ? C.brun : C.blanc, color: vue === id ? C.creme : C.brun,
            border: `1.5px solid ${vue === id ? C.brun : C.orClair}`, borderRadius: 8,
            padding: "9px 18px", fontSize: 13, fontWeight: 700, cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif",
          }}>{label}</button>
        ))}
        <div style={{ marginLeft: "auto", fontFamily: "Fraunces, Georgia, serif", fontSize: 13, color: C.brun }}>
          CA du service : <b style={{ color: C.or }}>{caService.toFixed(2)} €</b>
          {pretesPourSalle > 0 && <span style={{ marginLeft: 12, color: C.vert, fontWeight: 700 }}>● {pretesPourSalle} plat(s) à servir !</span>}
        </div>
      </div>

      {vue === "salle" && (
        <div style={{ display: "grid", gridTemplateColumns: tableSel ? "1.3fr 1fr" : "1fr", gap: 14 }}>
          {/* Plan de salle */}
          <Carte style={{ position: "relative", height: 420, background: `repeating-linear-gradient(0deg, ${C.blanc}, ${C.blanc} 38px, ${C.creme} 38px, ${C.creme} 40px)`, overflow: "hidden" }}>
            <div style={{ position: "absolute", top: 8, left: 12, fontSize: 10, letterSpacing: 2, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", textTransform: "uppercase" }}>Terrasse ↑ · Bar →</div>
            {tables.map(t => {
              const aServir = cmdsTable(t.num).some(c => c.statut === "prete");
              return (
                <button key={t.num} onClick={() => { setTableSel(t.num); setPanier({}); }} style={{
                  position: "absolute", left: `${t.x}%`, top: `${t.y}%`,
                  width: t.places >= 6 ? 84 : t.places >= 4 ? 68 : 54,
                  height: t.places >= 6 ? 84 : t.places >= 4 ? 68 : 54,
                  borderRadius: t.places === 2 ? "50%" : 12,
                  background: tableSel === t.num ? C.brun : C.blanc,
                  border: `3px solid ${couleurTable(t)}`,
                  color: tableSel === t.num ? C.creme : C.brun,
                  cursor: "pointer", fontFamily: "Fraunces, Georgia, serif", fontWeight: 700,
                  boxShadow: aServir ? `0 0 0 6px rgba(74,103,65,0.25)` : "0 2px 6px rgba(59,42,26,0.15)",
                  display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center",
                }}>
                  <span style={{ fontSize: 17 }}>{t.num}</span>
                  <span style={{ fontSize: 9.5, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 400 }}>{t.places} cv</span>
                  {resaDeTable(t.num) && (
                    <span title={`Réservée : ${resaDeTable(t.num).nom} à ${resaDeTable(t.num).heure}`} style={{
                      position: "absolute", top: -7, left: -7, width: 22, height: 22, borderRadius: 11,
                      background: C.brun, color: C.orClair, fontSize: 11, display: "flex", alignItems: "center",
                      justifyContent: "center", border: `2px solid ${C.creme}`,
                    }}>✆</span>
                  )}
                </button>
              );
            })}
            <div style={{ position: "absolute", bottom: 8, left: 12, display: "flex", gap: 12, fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen }}>
              <span><span style={{ color: C.or }}>■</span> Libre</span>
              <span><span style={{ color: C.rouille }}>■</span> Occupée</span>
              <span><span style={{ color: C.vert }}>■</span> Plat prêt à servir</span>
              <span><span style={{ color: C.brun }}>✆</span> Réservée</span>
            </div>
          </Carte>

          {/* Panneau commande de la table sélectionnée */}
          {tableSel && (() => {
            const t = tables.find(x => x.num === tableSel);
            const enCours = cmdsTable(tableSel);
            const nbPanier = Object.values(panier).reduce((s, n) => s + n, 0);
            return (
              <Carte style={{ display: "flex", flexDirection: "column", maxHeight: 420, overflow: "hidden" }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }}>
                  <h3 style={{ ...h3Style, margin: 0, border: "none" }}>Table {t.num} · {t.places} couverts</h3>
                  <button onClick={() => setTableSel(null)} style={{ ...btnStyle(C.brunMoyen), marginTop: 0, padding: "4px 10px" }}>✕</button>
                </div>
                <div style={{ flex: 1, overflowY: "auto" }}>
                  {enCours.length > 0 && (
                    <div style={{ marginBottom: 10 }}>
                      {enCours.map(c => (
                        <div key={c.id} style={{ padding: 8, background: C.creme, borderRadius: 8, marginBottom: 6, border: `1px solid ${C.orClair}` }}>
                          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                            <span style={{ fontSize: 11, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen }}>Cmd {c.heure}</span>
                            <Badge bg={COULEUR_COMMANDE[c.statut]}>{STATUT_COMMANDE[c.statut]}</Badge>
                          </div>
                          {c.items.map((i, k) => {
                            const f = FICHES.find(x => x.id === i.ficheId);
                            return <div key={k} style={{ fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun, marginTop: 3 }}>{i.qte}× {f?.nom}</div>;
                          })}
                          {c.statut === "prete" && <button onClick={() => avancerCommande(c.id)} style={{ ...btnStyle(C.vert), width: "100%" }}>✓ Servie en salle</button>}
                        </div>
                      ))}
                    </div>
                  )}
                  <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 1, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", margin: "6px 0" }}>Nouvelle commande</div>
                  {FICHES.map(f => {
                    const dispo = dispoDe(f.id);
                    const restant = dispo === null ? null : dispo - (panier[f.id] || 0);
                    const epuise = dispo !== null && restant <= 0;
                    return (
                      <div key={f.id} style={{ display: "flex", alignItems: "center", gap: 6, padding: "5px 0", borderBottom: `1px dashed ${C.orClair}`, opacity: epuise && !panier[f.id] ? 0.45 : 1 }}>
                        <span style={{ flex: 1, fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
                          {f.nom} <span style={{ color: C.brunMoyen, fontSize: 10.5 }}>{f.prixVente.toFixed(2)} €</span>
                        </span>
                        {dispo !== null ? (
                          <span style={{
                            fontSize: 10, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700, padding: "2px 7px", borderRadius: 10,
                            background: restant <= 0 ? "#F3DCD4" : restant <= 3 ? "#F5EAD3" : "#E3EBDD",
                            color: restant <= 0 ? C.rouille : restant <= 3 ? C.or : C.vert,
                          }}>{restant <= 0 ? "ÉPUISÉ" : `${restant} dispo`}</span>
                        ) : (
                          <span style={{ fontSize: 10, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, fontStyle: "italic" }}>pas de MEP</span>
                        )}
                        {panier[f.id] && <>
                          <button onClick={() => retirerPanier(f.id)} style={{ ...miniBtn, width: 22, height: 22, fontSize: 13, borderColor: C.rouille, color: C.rouille }}>−</button>
                          <span style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.brun, minWidth: 16, textAlign: "center", fontSize: 13 }}>{panier[f.id]}</span>
                        </>}
                        <button onClick={() => !epuise && ajouterPanier(f.id)} disabled={epuise}
                          style={{ ...miniBtn, width: 22, height: 22, fontSize: 13, opacity: epuise ? 0.35 : 1, cursor: epuise ? "default" : "pointer" }}>+</button>
                      </div>
                    );
                  })}
                </div>
                <div style={{ paddingTop: 10, display: "flex", gap: 8 }}>
                  <button onClick={envoyerEnCuisine} disabled={!nbPanier} style={{ ...btnStyle(C.or), flex: 1, marginTop: 0, opacity: nbPanier ? 1 : 0.45, padding: "10px" }}>
                    🔥 Envoyer en cuisine {nbPanier ? `(${nbPanier})` : ""}
                  </button>
                  {t.statut === "occupee" && (
                    <button onClick={() => encaisser(t.num)} style={{ ...btnStyle(C.vert), flex: 1, marginTop: 0, padding: "10px" }}>
                      💶 Encaisser {totalTable(t.num).toFixed(2)} €
                    </button>
                  )}
                </div>
              </Carte>
            );
          })()}
        </div>
      )}

      {vue === "cuisine" && (
        <div>
          {ticketsCuisine.length === 0 && (
            <Carte style={{ textAlign: "center", padding: 40, color: C.brunMoyen, fontFamily: "Fraunces, Georgia, serif", fontStyle: "italic" }}>
              Aucun ticket en attente — la cuisine respire. 🔥
            </Carte>
          )}
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(240px, 1fr))", gap: 12 }}>
            {ticketsCuisine.map(c => {
              const attente = minutesDepuis(c.ts);
              const urgent = attente >= 15;
              return (
                <Carte key={c.id} style={{ borderTop: `5px solid ${urgent ? C.rouille : COULEUR_COMMANDE[c.statut]}`, padding: 0, overflow: "hidden" }}>
                  <div style={{ background: urgent ? C.rouille : C.brun, color: C.creme, padding: "8px 12px", display: "flex", justifyContent: "space-between", fontFamily: "Fraunces, Georgia, serif", fontWeight: 700 }}>
                    <span>Table {c.table}</span>
                    <span style={{ fontSize: 12, fontFamily: "Inter, system-ui, sans-serif" }}>{c.heure} · {attente} min {urgent && "⚠"}</span>
                  </div>
                  <div style={{ padding: 12 }}>
                    {c.items.map((i, k) => {
                      const f = FICHES.find(x => x.id === i.ficheId);
                      return (
                        <div key={k} style={{ padding: "6px 0", borderBottom: `1px dashed ${C.orClair}` }}>
                          <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, fontSize: 15, color: C.brun }}>{i.qte} × {f?.nom}</div>
                          {f?.allergenes?.length > 0 && f.allergenes[0] !== "Aucun allergène majeur" &&
                            <div style={{ fontSize: 10.5, color: C.rouille, fontFamily: "Inter, system-ui, sans-serif" }}>⚠ {f.allergenes.join(", ")}</div>}
                        </div>
                      );
                    })}
                    <button onClick={() => avancerCommande(c.id)} style={{
                      ...btnStyle(c.statut === "en_attente" ? C.rouille : C.vert), width: "100%", marginTop: 10, padding: "11px", fontSize: 13,
                    }}>
                      {c.statut === "en_attente" ? "👨‍🍳 Commencer" : "✓ Prête — appeler la salle"}
                    </button>
                  </div>
                </Carte>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}


// ============ MODULE NATIF : CAISSE (POS) ============
const MODES_PAIEMENT = ["CB", "Espèces", "Ticket resto", "Chèque"];
const OPERATEURS_PAIEMENT = [
  { id: "sumup", nom: "SumUp", icone: "▣", desc: "Terminal Air / Solo · 1,75%/transaction" },
  { id: "zettle", nom: "Zettle by PayPal", icone: "◈", desc: "Reader 2 · 1,75%/transaction" },
  { id: "stripe", nom: "Stripe Terminal", icone: "❘❘", desc: "BBPOS / S700 · 1,4% + 0,10€" },
  { id: "smileandpay", nom: "Smile&Pay", icone: "◡", desc: "Maxi Smile · sans abonnement" },
  { id: "yavin", nom: "Yavin", icone: "◆", desc: "Terminal Android · taux négociés" },
];

function Caisse({ ventes, enregistrerVente, mep, setMep, operateur, setOperateur }) {
  const [ticket, setTicket] = useState({});
  const [mode, setMode] = useState("CB");
  const [filtreCat, setFiltreCat] = useState("Tout");
  const [terminalEnCours, setTerminalEnCours] = useState(false);
  const [choixOperateur, setChoixOperateur] = useState(false);
  const opActif = OPERATEURS_PAIEMENT.find(o => o.id === operateur);
  const cats = ["Tout", "Entrée", "Plat", "Accompagnement", "Dessert"];

  const dispoDe = (id) => mep[id]?.valide ? mep[id].dispo : null;
  const lignes = Object.entries(ticket).map(([id, qte]) => ({ fiche: FICHES.find(f => f.id === Number(id)), qte })).filter(l => l.fiche);
  const total = lignes.reduce((s, l) => s + l.fiche.prixVente * l.qte, 0);

  const ajouter = (f) => {
    const dispo = dispoDe(f.id);
    const restant = dispo === null ? Infinity : dispo - (ticket[f.id] || 0);
    if (restant <= 0) return;
    setTicket({ ...ticket, [f.id]: (ticket[f.id] || 0) + 1 });
  };
  const retirer = (id) => {
    const nv = { ...ticket };
    if (nv[id] > 1) nv[id]--; else delete nv[id];
    setTicket(nv);
  };

  const finaliserVente = () => {
    enregistrerVente({
      items: lignes.map(l => ({ ficheId: l.fiche.id, qte: l.qte, pu: l.fiche.prixVente })),
      total, mode: `${mode} · ${opActif.nom}`, origine: "Comptoir",
    });
    setMep(prev => {
      const nv = { ...prev };
      for (const l of lignes) if (nv[l.fiche.id]?.valide) nv[l.fiche.id] = { ...nv[l.fiche.id], dispo: Math.max(0, nv[l.fiche.id].dispo - l.qte) };
      return nv;
    });
    setTicket({});
  };

  const [etapeTerminal, setEtapeTerminal] = useState(null); // "envoi" | "paiement" | null
  const encaisser = () => {
    if (!lignes.length || terminalEnCours) return;
    if (!opActif) return; // Option 1 : pas d'encaissement sans caisse certifiée connectée
    // 1. Push du panier vers la caisse certifiée de l'opérateur (API checkout)
    setTerminalEnCours(true);
    setEtapeTerminal("envoi");
    setTimeout(() => {
      // 2. Paiement sur le terminal (CB) ou validation dans la caisse opérateur (espèces/TR/chèque)
      setEtapeTerminal("paiement");
      setTimeout(() => {
        // 3. Webhook de confirmation de l'opérateur → copie de gestion dans Mepli Pro
        setTerminalEnCours(false);
        setEtapeTerminal(null);
        finaliserVente();
      }, mode === "CB" ? 1600 : 800);
    }, 700);
  };

  // ---- Z du jour ----
  const caJour = ventes.reduce((s, v) => s + v.total, 0);
  const parMode = MODES_PAIEMENT.map(m => ({ m, t: ventes.filter(v => v.mode === m).reduce((s, v) => s + v.total, 0) })).filter(x => x.t > 0);
  const ticketMoyen = ventes.length ? caJour / ventes.length : 0;

  const visibles = (filtreCat === "Tout" ? FICHES : FICHES.filter(f => f.categorie === filtreCat));

  return (
    <div>
      {/* Connexion opérateur de paiement */}
      <Carte style={{ marginBottom: 14, padding: 12, borderLeft: `4px solid ${opActif ? C.vert : C.or}` }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 8 }}>
          <div style={{ fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, color: C.brun }}>
            <b style={{ fontFamily: "Fraunces, Georgia, serif" }}>Terminal de paiement : </b>
            {opActif ? <span style={{ color: C.vert, fontWeight: 700 }}>● Caisse {opActif.nom} connectée</span>
              : <span style={{ color: C.rouille, fontWeight: 700 }}>⚠ Connecte ta caisse certifiée pour encaisser</span>}
          </div>
          <button onClick={() => setChoixOperateur(!choixOperateur)} style={{ ...btnStyle(opActif ? C.brunMoyen : C.or), marginTop: 0 }}>
            {opActif ? "Changer / déconnecter" : "🔌 Connecter un opérateur"}
          </button>
        </div>
        <div style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginTop: 6, lineHeight: 1.5 }}>
          Mepli Pro prépare le ticket et l'envoie à la caisse certifiée de ton opérateur, qui réalise l'enregistrement fiscal (art. 286 CGI).
          Mepli Pro conserve une copie de gestion pour tes stats, ta mise en place et tes commandes — aucune double saisie.
        </div>
        {choixOperateur && (
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(170px, 1fr))", gap: 8, marginTop: 10 }}>
            {OPERATEURS_PAIEMENT.map(o => (
              <button key={o.id} onClick={() => { setOperateur(operateur === o.id ? null : o.id); setChoixOperateur(false); }} style={{
                background: operateur === o.id ? "#EDF2E9" : C.creme, border: `1.5px solid ${operateur === o.id ? C.vert : C.orClair}`,
                borderRadius: 10, padding: "10px 8px", cursor: "pointer", textAlign: "left",
              }}>
                <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, fontSize: 13.5, color: C.brun }}>{o.icone} {o.nom} {operateur === o.id && "✓"}</div>
                <div style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginTop: 3 }}>{o.desc}</div>
                <div style={{ fontSize: 10, fontFamily: "Inter, system-ui, sans-serif", color: operateur === o.id ? C.rouille : C.vert, fontWeight: 700, marginTop: 4 }}>
                  {operateur === o.id ? "Déconnecter" : "Connecter via API"}
                </div>
              </button>
            ))}
          </div>
        )}
      </Carte>

      <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 14 }}>
        <Stat label="CA du jour" valeur={`${caJour.toFixed(2)} €`} sous={`${ventes.length} ticket(s)`} />
        <Stat label="Ticket moyen" valeur={`${ticketMoyen.toFixed(2)} €`} sous="Toutes origines" />
        {parMode.map(x => <Stat key={x.m} label={x.m} valeur={`${x.t.toFixed(2)} €`} accent={C.brunMoyen} />)}
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 14 }}>
        {/* Grille de vente rapide */}
        <Carte>
          <div style={{ display: "flex", gap: 6, marginBottom: 10, flexWrap: "wrap" }}>
            {cats.map(c => (
              <button key={c} onClick={() => setFiltreCat(c)} style={{
                background: filtreCat === c ? C.brun : C.blanc, color: filtreCat === c ? C.creme : C.brun,
                border: `1.5px solid ${filtreCat === c ? C.brun : C.orClair}`, borderRadius: 14,
                padding: "5px 12px", fontSize: 11.5, fontWeight: 700, cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif",
              }}>{c}</button>
            ))}
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(118px, 1fr))", gap: 8, maxHeight: 380, overflowY: "auto" }}>
            {visibles.map(f => {
              const dispo = dispoDe(f.id);
              const restant = dispo === null ? null : dispo - (ticket[f.id] || 0);
              const epuise = restant !== null && restant <= 0;
              return (
                <button key={f.id} onClick={() => ajouter(f)} disabled={epuise} style={{
                  background: epuise ? C.cremeFonce : C.creme, border: `1.5px solid ${epuise ? C.orClair : C.or}`,
                  borderRadius: 10, padding: "10px 8px", cursor: epuise ? "default" : "pointer",
                  textAlign: "center", opacity: epuise ? 0.5 : 1, position: "relative",
                }}>
                  {ticket[f.id] && <span style={{ position: "absolute", top: -7, right: -6, minWidth: 22, height: 22, borderRadius: 11, background: C.or, color: C.blanc, fontSize: 11.5, fontWeight: 700, fontFamily: "Inter, system-ui, sans-serif", display: "flex", alignItems: "center", justifyContent: "center", border: `2px solid ${C.blanc}` }}>{ticket[f.id]}</span>}
                  <div style={{ fontFamily: "Inter, system-ui, sans-serif", fontSize: 11.5, fontWeight: 700, color: C.brun, lineHeight: 1.25, minHeight: 28 }}>{f.nom}</div>
                  <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.rouille, fontSize: 13, marginTop: 4 }}>{f.prixVente.toFixed(2)} €</div>
                  <div style={{ fontSize: 9.5, fontFamily: "Inter, system-ui, sans-serif", color: epuise ? C.rouille : restant !== null ? C.vert : C.brunMoyen, fontWeight: 700, marginTop: 2 }}>
                    {restant === null ? "pas de MEP" : epuise ? "ÉPUISÉ" : `${restant} dispo`}
                  </div>
                </button>
              );
            })}
          </div>
        </Carte>

        {/* Ticket en cours */}
        <Carte style={{ display: "flex", flexDirection: "column" }}>
          <h3 style={h3Style}>Ticket en cours</h3>
          <div style={{ flex: 1, minHeight: 160, maxHeight: 240, overflowY: "auto" }}>
            {!lignes.length && <div style={{ color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", fontSize: 12.5, fontStyle: "italic", textAlign: "center", marginTop: 30 }}>Touche un plat pour l'ajouter</div>}
            {lignes.map(l => (
              <div key={l.fiche.id} style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 0", borderBottom: `1px dashed ${C.orClair}`, fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
                <button onClick={() => retirer(l.fiche.id)} style={{ ...miniBtn, width: 22, height: 22, fontSize: 13, borderColor: C.rouille, color: C.rouille }}>−</button>
                <span style={{ flex: 1 }}>{l.qte} × {l.fiche.nom}</span>
                <b>{(l.fiche.prixVente * l.qte).toFixed(2)} €</b>
              </div>
            ))}
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, fontSize: 19, color: C.brun, padding: "10px 0", borderTop: `2px solid ${C.or}` }}>
            <span>TOTAL</span><span style={{ color: C.rouille }}>{total.toFixed(2)} €</span>
          </div>
          <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 10 }}>
            {MODES_PAIEMENT.map(m => (
              <button key={m} onClick={() => setMode(m)} style={{
                flex: 1, minWidth: 70, background: mode === m ? C.or : C.blanc, color: mode === m ? C.blanc : C.brun,
                border: `1.5px solid ${mode === m ? C.or : C.orClair}`, borderRadius: 8,
                padding: "8px 4px", fontSize: 11.5, fontWeight: 700, cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif",
              }}>{m}</button>
            ))}
          </div>
          <button onClick={encaisser} disabled={!lignes.length || terminalEnCours || !opActif} style={{ ...btnStyle(terminalEnCours ? C.brunMoyen : opActif ? C.vert : C.rouille), width: "100%", padding: "13px", fontSize: 14, marginTop: 0, opacity: lignes.length && opActif ? 1 : 0.5 }}>
            {!opActif ? "🔌 Connecte un opérateur pour encaisser"
              : etapeTerminal === "envoi" ? `📤 Envoi du ticket à la caisse ${opActif.nom}…`
              : etapeTerminal === "paiement" ? (mode === "CB" ? `⏳ Paiement sur le terminal ${opActif.nom}… présentez la carte` : `⏳ Validation ${mode} dans la caisse ${opActif.nom}…`)
              : `💶 Encaisser ${total > 0 ? total.toFixed(2) + " €" : ""} (${mode} · ${opActif.nom})`}
          </button>
        </Carte>
      </div>

      {/* Journal des ventes */}
      {ventes.length > 0 && (
        <Carte style={{ marginTop: 14 }}>
          <h3 style={h3Style}>Journal du jour</h3>
          <div style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginBottom: 8 }}>
            Copie de gestion — l'enregistrement fiscal de référence (Z de caisse) est tenu par la caisse certifiée de l'opérateur. Réf. ✓ = confirmation webhook.
          </div>
          {[...ventes].reverse().slice(0, 12).map(v => (
            <div key={v.id} style={{ display: "flex", gap: 10, alignItems: "center", padding: "5px 0", borderBottom: `1px dashed ${C.orClair}`, fontSize: 12, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
              <span style={{ color: C.brunMoyen, minWidth: 40 }}>{v.heure}</span>
              <Badge bg={v.origine === "Comptoir" ? C.or : C.brunMoyen}>{v.origine}</Badge>
              <span style={{ flex: 1, fontSize: 11.5, color: C.brunMoyen, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                {v.items.map(i => `${i.qte}× ${FICHES.find(f => f.id === i.ficheId)?.nom || "?"}`).join(", ")}
              </span>
              <span style={{ fontSize: 11, color: C.brunMoyen }}>{v.mode}</span>
              {v.refOperateur && <span style={{ fontSize: 9.5, color: C.vert, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700 }}>✓ {v.refOperateur}</span>}
              <b style={{ minWidth: 60, textAlign: "right" }}>{v.total.toFixed(2)} €</b>
            </div>
          ))}
        </Carte>
      )}
    </div>
  );
}

// ============ EXTENSION : Z & ANALYSE (clôture et data de fin de service) ============
const Z_HISTORIQUE_INIT = [];
// Quantités vendues sur le mois par fiche (données simulées, cohérentes avec les Z de mai)
const STATS_PLATS_INIT = {};

// Mois précédent (avril 2026) pour comparaison de la synthèse mensuelle
const MOIS_PRECEDENT = { libelle: "mois précédent", caTTC: 0, couverts: 0 };

function ZAnalyse({ rapportsZ, setRapportsZ, ventes }) {
  const [saisie, setSaisie] = useState({ caTTC: "", couverts: "", CB: "", "Espèces": "", "Ticket resto": "", "Chèque": "" });
  const [confirme, setConfirme] = useState(false);
  const [lectureZ, setLectureZ] = useState(false);
  const [erreurLecture, setErreurLecture] = useState(null);
  const fichierRef = useRef(null);

  // Lecture du ticket Z photographié par l'IA (vision)
  const lireTicketZ = async (file) => {
    if (!file) return;
    setLectureZ(true);
    setErreurLecture(null);
    try {
      const base64 = await new Promise((res, rej) => {
        const r = new FileReader();
        r.onload = () => res(r.result.split(",")[1]);
        r.onerror = () => rej(new Error("lecture impossible"));
        r.readAsDataURL(file);
      });
      const response = await fetch("/api/chat", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          model: "claude-sonnet-4-20250514",
          max_tokens: 600,
          messages: [{
            role: "user",
            content: [
              { type: "image", source: { type: "base64", media_type: file.type || "image/jpeg", data: base64 } },
              { type: "text", text: `Ceci est un ticket Z (rapport de clôture) d'une caisse de restaurant. Extrais les totaux et réponds UNIQUEMENT avec un JSON valide, sans backticks ni texte autour, au format exact :
{"caTTC":<nombre>,"couverts":<nombre ou 0>,"CB":<nombre>,"Especes":<nombre>,"TicketResto":<nombre>,"Cheque":<nombre>}
Règles : caTTC = total TTC du jour. couverts = nombre de couverts ou de tickets/clients si présent, sinon 0. Répartis les règlements par mode (carte bancaire → CB, espèces/cash → Especes, titres/tickets restaurant → TicketResto, chèques → Cheque) ; mets 0 si absent. Nombres décimaux avec un point.` }
            ],
          }],
        }),
      });
      const data = await response.json();
      const txt = (data.content || []).filter(b => b.type === "text").map(b => b.text).join("").replace(/```json|```/g, "").trim();
      const z = JSON.parse(txt);
      setSaisie({
        caTTC: String(z.caTTC ?? ""), couverts: String(z.couverts ?? ""),
        CB: String(z.CB ?? 0), "Espèces": String(z.Especes ?? 0),
        "Ticket resto": String(z.TicketResto ?? 0), "Chèque": String(z.Cheque ?? 0),
      });
    } catch {
      setErreurLecture("Lecture impossible — photo floue ou format inattendu. Réessaie ou saisis manuellement.");
    }
    setLectureZ(false);
  };

  // ---- Données Mepli Pro de la journée (copie de gestion) pour pré-remplissage et rapprochement ----
  const caChefAI = ventes.reduce((s, v) => s + v.total, 0);
  const modesChefAI = {};
  for (const v of ventes) {
    const m = String(v.mode).split(" · ")[0];
    modesChefAI[m] = (modesChefAI[m] || 0) + v.total;
  }

  const preRemplir = () => setSaisie({
    caTTC: caChefAI.toFixed(2), couverts: String(ventes.length),
    CB: (modesChefAI["CB"] || 0).toFixed(2), "Espèces": (modesChefAI["Espèces"] || 0).toFixed(2),
    "Ticket resto": (modesChefAI["Ticket resto"] || 0).toFixed(2), "Chèque": (modesChefAI["Chèque"] || 0).toFixed(2),
  });

  const num = (x) => parseFloat(String(x).replace(",", ".")) || 0;
  const totalModes = MODES_PAIEMENT.reduce((s, m) => s + num(saisie[m]), 0);
  const ecartInterne = num(saisie.caTTC) - totalModes; // cohérence du Z saisi
  const ecartChefAI = num(saisie.caTTC) - caChefAI;    // rapprochement Z officiel vs copie Mepli Pro

  const cloturer = () => {
    if (num(saisie.caTTC) <= 0) return;
    setRapportsZ([...rapportsZ, {
      id: Date.now(),
      date: new Date().toLocaleDateString("fr-FR", { day: "2-digit", month: "2-digit" }),
      caTTC: num(saisie.caTTC), couverts: parseInt(saisie.couverts, 10) || 0,
      modes: Object.fromEntries(MODES_PAIEMENT.map(m => [m, num(saisie[m])])),
    }]);
    setSaisie({ caTTC: "", couverts: "", CB: "", "Espèces": "", "Ticket resto": "", "Chèque": "" });
    setConfirme(true);
    setTimeout(() => setConfirme(false), 3000);
  };

  // ---- Analyse de l'historique ----
  const histo = rapportsZ;
  const caMoyen = histo.length ? histo.reduce((s, z) => s + z.caTTC, 0) / histo.length : 0;
  const meilleurJour = histo.length ? histo.reduce((a, b) => a.caTTC > b.caTTC ? a : b) : null;
  const ticketMoyenGlobal = histo.length ? histo.reduce((s, z) => s + z.caTTC, 0) / Math.max(1, histo.reduce((s, z) => s + z.couverts, 0)) : 0;
  const partCB = histo.length ? histo.reduce((s, z) => s + (z.modes["CB"] || 0), 0) / Math.max(1, histo.reduce((s, z) => s + z.caTTC, 0)) * 100 : 0;
  const maxCA = Math.max(...histo.map(z => z.caTTC), 1);
  const tendance = histo.length >= 4
    ? (histo.slice(-2).reduce((s, z) => s + z.caTTC, 0) / 2) - (histo.slice(0, 2).reduce((s, z) => s + z.caTTC, 0) / 2)
    : 0;

  const champStyle = { width: "100%", padding: "8px 10px", border: `1.5px solid ${C.orClair}`, borderRadius: 6, fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, background: C.blanc, color: C.brun, boxSizing: "border-box" };

  return (
    <div>
      {/* ===== SAISIE DU Z DE FIN DE SERVICE ===== */}
      <Carte style={{ marginBottom: 16, borderTop: `4px solid ${C.or}` }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 8 }}>
          <h3 style={{ ...h3Style, margin: 0 }}>Clôture du service — saisie du Z</h3>
          <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
            <input ref={fichierRef} type="file" accept="image/*" capture="environment" style={{ display: "none" }}
              onChange={e => { lireTicketZ(e.target.files?.[0]); e.target.value = ""; }} />
            <button onClick={() => fichierRef.current?.click()} disabled={lectureZ} style={{ ...btnStyle(C.or), marginTop: 0 }}>
              {lectureZ ? "👁 L'IA lit le ticket…" : "📷 Photographier le ticket Z"}
            </button>
            <button onClick={preRemplir} disabled={!ventes.length} style={{ ...btnStyle(C.brunMoyen), marginTop: 0, opacity: ventes.length ? 1 : 0.45 }}>
              ⚡ Pré-remplir depuis Mepli Pro
            </button>
          </div>
        </div>
        <div style={{ fontSize: 11.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, margin: "6px 0 12px" }}>
          Le Z provient de ta caisse tierce (SumUp, Zettle, L'Addition, caisse traditionnelle…) : photographie le ticket et l'IA le lit, ou saisis les totaux. Mepli Pro rapproche, archive et analyse — il ne remplace pas ta caisse, il l'exploite.
        </div>
        {erreurLecture && (
          <div style={{ padding: 8, marginBottom: 10, background: "#F3DCD4", border: `1.5px solid ${C.rouille}`, borderRadius: 8, fontSize: 12, fontFamily: "Inter, system-ui, sans-serif", color: C.rouille }}>
            ⚠ {erreurLecture}
          </div>
        )}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(120px, 1fr))", gap: 10 }}>
          <div>
            <label style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, fontWeight: 700, textTransform: "uppercase" }}>CA TTC du Z</label>
            <input value={saisie.caTTC} onChange={e => setSaisie({ ...saisie, caTTC: e.target.value })} placeholder="0,00 €" style={champStyle} />
          </div>
          <div>
            <label style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, fontWeight: 700, textTransform: "uppercase" }}>Couverts / tickets</label>
            <input value={saisie.couverts} onChange={e => setSaisie({ ...saisie, couverts: e.target.value })} placeholder="0" style={champStyle} />
          </div>
          {MODES_PAIEMENT.map(m => (
            <div key={m}>
              <label style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, fontWeight: 700, textTransform: "uppercase" }}>{m}</label>
              <input value={saisie[m]} onChange={e => setSaisie({ ...saisie, [m]: e.target.value })} placeholder="0,00 €" style={champStyle} />
            </div>
          ))}
        </div>
        {/* Rapprochements */}
        {num(saisie.caTTC) > 0 && (
          <div style={{ display: "flex", gap: 10, flexWrap: "wrap", marginTop: 12 }}>
            <div style={{ flex: 1, minWidth: 200, padding: 10, borderRadius: 8, background: Math.abs(ecartInterne) < 0.01 ? "#EDF2E9" : "#F3DCD4", border: `1.5px solid ${Math.abs(ecartInterne) < 0.01 ? C.vert : C.rouille}`, fontFamily: "Inter, system-ui, sans-serif", fontSize: 12, color: C.brun }}>
              <b>Cohérence du Z :</b> {Math.abs(ecartInterne) < 0.01 ? "✓ la somme des modes = CA TTC" : `⚠ écart de ${ecartInterne.toFixed(2)} € entre le CA et la somme des paiements`}
            </div>
            <div style={{ flex: 1, minWidth: 200, padding: 10, borderRadius: 8, background: Math.abs(ecartChefAI) < 0.01 ? "#EDF2E9" : "#F5EAD3", border: `1.5px solid ${Math.abs(ecartChefAI) < 0.01 ? C.vert : C.or}`, fontFamily: "Inter, system-ui, sans-serif", fontSize: 12, color: C.brun }}>
              <b>Rapprochement Mepli Pro :</b> {ventes.length === 0 ? "aucune vente Mepli Pro aujourd'hui" : Math.abs(ecartChefAI) < 0.01 ? "✓ identique à la copie de gestion" : `écart de ${ecartChefAI > 0 ? "+" : ""}${ecartChefAI.toFixed(2)} € vs Mepli Pro (${caChefAI.toFixed(2)} €) — vente hors app ou oubli ?`}
            </div>
          </div>
        )}
        <button onClick={cloturer} disabled={num(saisie.caTTC) <= 0} style={{ ...btnStyle(confirme ? C.vert : C.brun), width: "100%", padding: "12px", fontSize: 13.5, marginTop: 12, opacity: num(saisie.caTTC) > 0 ? 1 : 0.45 }}>
          {confirme ? "✓ Z enregistré — bonne soirée Chef !" : "🌙 Clôturer le service et enregistrer le Z"}
        </button>
      </Carte>

      {/* ===== ANALYSE ===== */}
      {histo.length > 0 && (
        <>
          <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 14 }}>
            <Stat label="CA moyen / service" valeur={`${caMoyen.toFixed(0)} €`} sous={`Sur ${histo.length} services`} />
            <Stat label="Ticket moyen" valeur={`${ticketMoyenGlobal.toFixed(2)} €`} sous="Par couvert" />
            <Stat label="Part CB" valeur={`${partCB.toFixed(0)}%`} sous="Du CA total" accent={C.brunMoyen} />
            <Stat label="Tendance" valeur={tendance >= 0 ? `+${tendance.toFixed(0)} €` : `${tendance.toFixed(0)} €`} sous="Derniers vs premiers services" accent={tendance >= 0 ? C.vert : C.rouille} />
          </div>

          <Carte style={{ marginBottom: 14 }}>
            <h3 style={h3Style}>CA par service</h3>
            <div style={{ display: "flex", alignItems: "flex-end", gap: 8, height: 150, padding: "0 4px" }}>
              {histo.slice(-14).map(z => (
                <div key={z.id} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
                  <span style={{ fontSize: 9.5, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700, color: C.brun }}>{z.caTTC.toFixed(0)}</span>
                  <div style={{
                    width: "100%", maxWidth: 44, borderRadius: "6px 6px 0 0",
                    height: `${Math.max(8, z.caTTC / maxCA * 110)}px`,
                    background: meilleurJour && z.id === meilleurJour.id ? C.or : C.brunMoyen,
                  }} />
                  <span style={{ fontSize: 9.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen }}>{z.date}</span>
                </div>
              ))}
            </div>
            {meilleurJour && (
              <div style={{ fontSize: 11.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun, marginTop: 8 }}>
                🏆 Meilleur service : <b>{meilleurJour.date}</b> avec <b style={{ color: C.or }}>{meilleurJour.caTTC.toFixed(2)} €</b> ({meilleurJour.couverts} couverts)
              </div>
            )}
          </Carte>

          <Carte>
            <h3 style={h3Style}>Historique des Z</h3>
            {[...histo].reverse().map(z => (
              <div key={z.id} style={{ display: "flex", gap: 10, alignItems: "center", padding: "6px 0", borderBottom: `1px dashed ${C.orClair}`, fontSize: 12, fontFamily: "Inter, system-ui, sans-serif", color: C.brun, flexWrap: "wrap" }}>
                <b style={{ minWidth: 44 }}>{z.date}</b>
                <span style={{ minWidth: 80, fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.or }}>{z.caTTC.toFixed(2)} €</span>
                <span style={{ color: C.brunMoyen }}>{z.couverts} couverts · {z.couverts ? (z.caTTC / z.couverts).toFixed(2) : "—"} €/couvert</span>
                <span style={{ flex: 1, textAlign: "right", fontSize: 11, color: C.brunMoyen }}>
                  {MODES_PAIEMENT.filter(m => z.modes[m] > 0).map(m => `${m} ${z.modes[m].toFixed(0)}€`).join(" · ")}
                </span>
              </div>
            ))}
          </Carte>
        </>
      )}
    </div>
  );
}

// ============ EXTENSION : RÉSERVATIONS ============
const RESERVATIONS_INIT = [];

function Reservations({ reservations, setReservations, tables, setTables }) {
  const [form, setForm] = useState({ nom: "", couverts: "2", heure: "", service: "Soir", tel: "" });
  const champ = { padding: "8px 10px", border: `1.5px solid ${C.orClair}`, borderRadius: 6, fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, background: C.blanc, color: C.brun, boxSizing: "border-box" };

  const ajouter = () => {
    if (!form.nom.trim() || !form.heure.trim()) return;
    setReservations([...reservations, {
      id: Date.now(), nom: form.nom.trim(), couverts: parseInt(form.couverts, 10) || 2,
      heure: form.heure.trim(), service: form.service, tel: form.tel.trim(), table: null, statut: "a_venir",
    }]);
    setForm({ nom: "", couverts: "2", heure: "", service: form.service, tel: "" });
  };

  const installer = (resa, numTable) => {
    if (!numTable) return;
    setReservations(reservations.map(r => r.id === resa.id ? { ...r, table: Number(numTable), statut: "installee" } : r));
    setTables(tables.map(t => t.num === Number(numTable) ? { ...t, statut: "occupee" } : t));
  };

  const annuler = (id) => setReservations(reservations.filter(r => r.id !== id));
  const assigner = (resa, numTable) => setReservations(reservations.map(r => r.id === resa.id ? { ...r, table: numTable ? Number(numTable) : null } : r));

  const couvertsService = (srv) => reservations.filter(r => r.service === srv && r.statut !== "annulee").reduce((s, r) => s + r.couverts, 0);
  const capacite = tables.reduce((s, t) => s + t.places, 0);
  const tablesLibres = tables.filter(t => t.statut === "libre");

  const ligneResa = (r) => (
    <div key={r.id} style={{ display: "flex", alignItems: "center", gap: 8, padding: "8px 0", borderBottom: `1px dashed ${C.orClair}`, flexWrap: "wrap" }}>
      <b style={{ fontFamily: "Fraunces, Georgia, serif", color: C.brun, fontSize: 14, minWidth: 44 }}>{r.heure}</b>
      <div style={{ flex: 1, minWidth: 140 }}>
        <div style={{ fontFamily: "Inter, system-ui, sans-serif", fontSize: 13, fontWeight: 700, color: C.brun }}>{r.nom}</div>
        <div style={{ fontSize: 11, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen }}>{r.couverts} couverts{r.tel ? ` · ${r.tel}` : ""}</div>
      </div>
      {r.statut === "installee" ? (
        <Badge bg={C.vert}>Installée · T{r.table}</Badge>
      ) : (
        <>
          <select value={r.table || ""} onChange={e => assigner(r, e.target.value)} style={{ ...champ, padding: "6px 8px", fontSize: 12 }}>
            <option value="">Table ?</option>
            {tables.filter(t => t.places >= r.couverts || t.num === r.table).map(t => (
              <option key={t.num} value={t.num}>T{t.num} ({t.places} cv){t.statut === "occupee" ? " · occupée" : ""}</option>
            ))}
          </select>
          <button onClick={() => installer(r, r.table)} disabled={!r.table} style={{ ...btnStyle(C.vert), marginTop: 0, opacity: r.table ? 1 : 0.45 }}>Installer</button>
          <button onClick={() => annuler(r.id)} style={{ ...btnStyle(C.rouille), marginTop: 0, padding: "7px 10px" }}>✕</button>
        </>
      )}
    </div>
  );

  return (
    <div>
      <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 14 }}>
        <Stat label="Couverts midi" valeur={couvertsService("Midi")} sous={`Capacité salle : ${capacite}`} accent={couvertsService("Midi") > capacite ? C.rouille : C.or} />
        <Stat label="Couverts soir" valeur={couvertsService("Soir")} sous={`Capacité salle : ${capacite}`} accent={couvertsService("Soir") > capacite ? C.rouille : C.or} />
        <Stat label="Tables libres" valeur={tablesLibres.length} sous={`Sur ${tables.length} tables`} accent={C.vert} />
      </div>

      {/* Nouvelle réservation */}
      <Carte style={{ marginBottom: 14 }}>
        <h3 style={h3Style}>Nouvelle réservation</h3>
        <div style={{ display: "grid", gridTemplateColumns: "2fr 70px 80px 100px 1.4fr auto", gap: 8, alignItems: "end" }}>
          <input placeholder="Nom (et note : allergie, occasion…)" value={form.nom} onChange={e => setForm({ ...form, nom: e.target.value })} style={champ} />
          <input placeholder="Cv" value={form.couverts} onChange={e => setForm({ ...form, couverts: e.target.value })} style={champ} />
          <input placeholder="19:30" value={form.heure} onChange={e => setForm({ ...form, heure: e.target.value })} style={champ} />
          <select value={form.service} onChange={e => setForm({ ...form, service: e.target.value })} style={champ}>
            <option>Midi</option><option>Soir</option>
          </select>
          <input placeholder="Téléphone" value={form.tel} onChange={e => setForm({ ...form, tel: e.target.value })} style={champ} />
          <button onClick={ajouter} style={{ ...btnStyle(C.or), marginTop: 0, padding: "9px 16px" }}>＋ Réserver</button>
        </div>
      </Carte>

      {["Midi", "Soir"].map(srv => {
        const liste = reservations.filter(r => r.service === srv).sort((a, b) => a.heure.localeCompare(b.heure));
        return (
          <Carte key={srv} style={{ marginBottom: 12 }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
              <h3 style={{ ...h3Style, margin: 0 }}>{srv === "Midi" ? "☀ Service du midi" : "🌙 Service du soir"}</h3>
              <Badge bg={C.brunMoyen}>{couvertsService(srv)} couverts</Badge>
            </div>
            <div style={{ marginTop: 6 }}>
              {!liste.length && <div style={{ fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, fontStyle: "italic", padding: "8px 0" }}>Aucune réservation.</div>}
              {liste.map(ligneResa)}
            </div>
          </Carte>
        );
      })}
    </div>
  );
}

// ============ MODULE NATIF : CUISINE (mise en place & production) ============
function Cuisine({ mep, setMep, stocks, setStocks, goTo }) {
  const [saisieDispo, setSaisieDispo] = useState({});

  const validerMep = (fiche) => {
    const dispo = parseInt(saisieDispo[fiche.id] ?? mep[fiche.id]?.dispo ?? 0, 10) || 0;
    if (dispo <= 0) return;
    const deductions = calculerDeductions(stocks, fiche, dispo);
    // Déduire les matières premières de l'inventaire
    setStocks(stocks.map(s => {
      const d = deductions.find(x => x.stockId === s.id);
      return d ? { ...s, qte: Math.max(0, +(s.qte - d.qte).toFixed(2)) } : s;
    }));
    setMep({ ...mep, [fiche.id]: { valide: true, dispo, deductions, prodLe: Date.now() } });
  };

  const annulerMep = (fiche) => {
    const m = mep[fiche.id];
    if (!m) return;
    // Restituer les matières déduites
    setStocks(stocks.map(s => {
      const d = (m.deductions || []).find(x => x.stockId === s.id);
      return d ? { ...s, qte: +(s.qte + d.qte).toFixed(2) } : s;
    }));
    const nv = { ...mep };
    delete nv[fiche.id];
    setMep(nv);
  };

  const valides = Object.values(mep).filter(m => m.valide).length;
  const portionsPretes = Object.values(mep).reduce((s, m) => s + (m.dispo || 0), 0);
  const faibles = FICHES.filter(f => mep[f.id]?.valide && mep[f.id].dispo > 0 && mep[f.id].dispo <= 3);
  const epuises = FICHES.filter(f => mep[f.id]?.valide && mep[f.id].dispo === 0);

  return (
    <div>
      <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 16 }}>
        <Stat label="Mise en place" valeur={`${valides}/${FICHES.length}`} sous="Plats validés" accent={valides === FICHES.length ? C.vert : C.or} />
        <Stat label="Portions prêtes" valeur={portionsPretes} sous="Disponibles à la vente" />
        <Stat label="Bientôt épuisés" valeur={faibles.length} sous={faibles.length ? faibles.map(f => f.nom).slice(0, 2).join(", ") : "Rien à signaler"} accent={faibles.length ? C.or : C.vert} />
        <Stat label="Épuisés (86)" valeur={epuises.length} sous={epuises.length ? "À annoncer en salle" : "Tout est dispo"} accent={epuises.length ? C.rouille : C.vert} />
      </div>

      {/* ===== MISE EN PLACE DU SERVICE ===== */}
      <Carte style={{ marginBottom: 16, borderTop: `4px solid ${C.or}` }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 6 }}>
          <h3 style={{ ...h3Style, margin: 0 }}>Mise en place du service</h3>
          <span style={{ fontSize: 12, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen }}>
            {Object.values(mep).filter(m => m.valide).length}/{FICHES.length} validés · {Object.values(mep).reduce((s, m) => s + (m.dispo || 0), 0)} portions prêtes à la vente
          </span>
        </div>
        <div style={{ fontSize: 11.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, margin: "6px 0 10px" }}>
          Saisis le nombre de portions préparées puis valide : les matières premières sont déduites de l'inventaire et les disponibilités apparaissent en salle.
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(240px, 1fr))", gap: 8 }}>
          {FICHES.map(f => {
            const m = mep[f.id];
            return (
              <div key={f.id} style={{
                display: "flex", alignItems: "center", gap: 8, padding: "8px 10px",
                background: m?.valide ? "#EDF2E9" : C.creme, borderRadius: 8,
                border: `1.5px solid ${m?.valide ? C.vert : C.orClair}`,
              }}>
                <button onClick={() => m?.valide ? annulerMep(f) : validerMep(f)} style={{
                  width: 24, height: 24, borderRadius: "50%", flexShrink: 0,
                  border: `2px solid ${m?.valide ? C.vert : C.brunMoyen}`,
                  background: m?.valide ? C.vert : C.blanc, color: C.blanc,
                  fontSize: 13, fontWeight: 700, cursor: "pointer", lineHeight: 1,
                }}>{m?.valide ? "✓" : ""}</button>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 12.5, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700, color: C.brun, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{f.nom}</div>
                  <div style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: m?.valide ? C.vert : C.brunMoyen }}>
                    {m?.valide ? `${m.dispo} dispo à la vente` : "À valider avant service"}
                  </div>
                </div>
                {!m?.valide && (
                  <input value={saisieDispo[f.id] || ""} onChange={e => setSaisieDispo({ ...saisieDispo, [f.id]: e.target.value })}
                    placeholder="Qté" style={{
                      width: 44, padding: "5px 4px", border: `1.5px solid ${C.orClair}`, borderRadius: 6,
                      fontFamily: "Inter, system-ui, sans-serif", fontSize: 12, textAlign: "center", background: C.blanc, color: C.brun,
                    }} />
                )}
                {m?.valide && <span style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, fontSize: 17, color: m.dispo <= 3 ? C.rouille : C.vert }}>{m.dispo}</span>}
              </div>
            );
          })}
        </div>
      </Carte>

      <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
        <button onClick={() => goTo("fiches")} style={btnStyle(C.brunMoyen)}>✦ Consulter une fiche technique →</button>
        <button onClick={() => goTo("stocks")} style={btnStyle(C.brunMoyen)}>▤ Vérifier l'inventaire →</button>
        <button onClick={() => goTo("haccp")} style={btnStyle(C.brunMoyen)}>❄ Relevés de température →</button>
      </div>
    </div>
  );
}

// ============ MODULE NATIF : FOOD COST (analyse & menu engineering) ============
function FoodCost({ ventes, factures, rapportsZ }) {
  const [simId, setSimId] = useState(null);
  const [simPrix, setSimPrix] = useState("");
  const [cible, setCible] = useState("30");

  // Quantités vendues (mois + jour en direct)
  const compteur = { ...STATS_PLATS_INIT };
  for (const v of ventes) for (const i of v.items) compteur[i.ficheId] = (compteur[i.ficheId] || 0) + i.qte;

  const lignes = FICHES.map(f => {
    const vendus = compteur[f.id] || 0;
    const fc = f.coutPortion / f.prixVente * 100;
    const marge = f.prixVente - f.coutPortion;
    return { ...f, vendus, fc, marge, margeTotale: marge * vendus, caPlat: f.prixVente * vendus, coutTotal: f.coutPortion * vendus };
  });

  // ---- FOOD COST GLOBAL PONDÉRÉ PAR LES VENTES (théorique) ----
  const caTheorique = lignes.reduce((s, l) => s + l.caPlat, 0);
  const coutTheorique = lignes.reduce((s, l) => s + l.coutTotal, 0);
  const fcGlobal = caTheorique ? coutTheorique / caTheorique * 100 : 0;
  const cibleNum = parseFloat(cible.replace(",", ".")) || 30;

  // ---- FOOD COST RÉEL : achats scannés / CA des Z ----
  const achatsReels = factures.reduce((s, x) => s + x.montantTTC, 0);
  const caZ = rapportsZ.reduce((s, z) => s + z.caTTC, 0);
  const fcReel = achatsReels > 0 && caZ > 0 ? achatsReels / caZ * 100 : null;

  // ---- MENU ENGINEERING : médiane popularité × médiane marge ----
  const tries = [...lignes].sort((a, b) => a.vendus - b.vendus);
  const medVendus = tries[Math.floor(tries.length / 2)]?.vendus || 0;
  const triesMarge = [...lignes].sort((a, b) => a.marge - b.marge);
  const medMarge = triesMarge[Math.floor(triesMarge.length / 2)]?.marge || 0;
  const classer = (l) => {
    const pop = l.vendus >= medVendus, rentable = l.marge >= medMarge;
    if (pop && rentable) return "star";
    if (pop && !rentable) return "cheval";
    if (!pop && rentable) return "enigme";
    return "poids";
  };
  const QUADRANTS = [
    { id: "star", titre: "⭐ Stars", soustitre: "Populaires & rentables — mettez-les en avant", couleur: C.vert, fond: "#EDF3E8" },
    { id: "cheval", titre: "🐴 Chevaux de labour", soustitre: "Populaires, marge faible — montez le prix ou baissez le coût", couleur: C.or, fond: "#F8F0DC" },
    { id: "enigme", titre: "❓ Énigmes", soustitre: "Rentables mais boudés — suggestion serveur, photo, position carte", couleur: C.brunMoyen, fond: "#F2EBDD" },
    { id: "poids", titre: "🪨 Poids morts", soustitre: "Ni vendus ni rentables — retravailler ou sortir de carte", couleur: C.rouille, fond: "#F6E4D9" },
  ];

  // ---- SIMULATEUR ----
  const fSim = lignes.find(l => l.id === simId);
  const prixSim = fSim ? (parseFloat(simPrix.replace(",", ".")) || fSim.prixVente) : 0;
  const prixPourCible = (f) => f.coutPortion / (cibleNum / 100);

  return (
    <div>
      {/* ===== INDICATEURS GLOBAUX ===== */}
      <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 14 }}>
        <Stat label="Food cost théorique" valeur={`${fcGlobal.toFixed(1)}%`} sous="Pondéré par les ventes du mois" accent={fcGlobal <= cibleNum ? C.vert : C.rouille} />
        <Stat label="Food cost réel" valeur={fcReel !== null ? `${fcReel.toFixed(1)}%` : "—"} sous={fcReel !== null ? "Factures scannées / CA des Z" : "Scanne tes factures fournisseurs"} accent={fcReel !== null ? (fcReel <= cibleNum + 3 ? C.vert : C.rouille) : C.brunMoyen} />
        <Carte style={{ flex: 1, minWidth: 150, borderTop: `3px solid ${C.or}` }}>
          <div style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 1, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>Objectif food cost</div>
          <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 6 }}>
            <input value={cible} onChange={e => setCible(e.target.value)} style={{ width: 56, padding: "7px 8px", border: `1.5px solid ${C.orClair}`, borderRadius: 8, fontFamily: "Fraunces, Georgia, serif", fontSize: 18, fontWeight: 700, background: C.blanc, color: C.brun, textAlign: "center" }} />
            <span style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 18, fontWeight: 700, color: C.brun }}>%</span>
          </div>
        </Carte>
        {fcReel !== null && (
          <Stat label="Écart réel − théorique" valeur={`${(fcReel - fcGlobal) >= 0 ? "+" : ""}${(fcReel - fcGlobal).toFixed(1)} pt`} sous={fcReel - fcGlobal > 4 ? "Pertes, coulure ou vol ?" : "Maîtrisé"} accent={fcReel - fcGlobal > 4 ? C.rouille : C.vert} />
        )}
      </div>

      {/* ===== MENU ENGINEERING ===== */}
      <Carte style={{ marginBottom: 14 }}>
        <h3 style={h3Style}>Menu engineering — la matrice de votre carte</h3>
        <div style={{ fontSize: 11.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginBottom: 12 }}>
          Chaque plat est classé selon sa popularité (vendus vs médiane : {medVendus}) et sa marge brute (vs médiane : {medMarge.toFixed(2)} €).
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
          {QUADRANTS.map(q => {
            const plats = lignes.filter(l => classer(l) === q.id).sort((a, b) => b.margeTotale - a.margeTotale);
            return (
              <div key={q.id} style={{ padding: 12, borderRadius: 12, background: q.fond, border: `1.5px solid ${q.couleur}` }}>
                <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, fontSize: 14, color: q.couleur }}>{q.titre} ({plats.length})</div>
                <div style={{ fontSize: 10, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginBottom: 8 }}>{q.soustitre}</div>
                {plats.slice(0, 5).map(p => (
                  <div key={p.id} style={{ display: "flex", justifyContent: "space-between", fontSize: 11.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brun, padding: "3px 0" }}>
                    <span>{p.nom}</span>
                    <span style={{ color: C.brunMoyen }}>{p.vendus} · {p.marge.toFixed(2)} €</span>
                  </div>
                ))}
                {plats.length > 5 && <div style={{ fontSize: 10, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>+ {plats.length - 5} autre(s)</div>}
              </div>
            );
          })}
        </div>
      </Carte>

      {/* ===== TABLE DÉTAILLÉE + SIMULATEUR ===== */}
      <Carte>
        <h3 style={h3Style}>Détail par plat — touchez un plat pour simuler un prix</h3>
        <div style={{ overflowX: "auto" }}>
          <table style={{ borderCollapse: "collapse", width: "100%", fontFamily: "Inter, system-ui, sans-serif", fontSize: 12 }}>
            <thead>
              <tr style={{ color: C.brunMoyen, fontSize: 10.5, textTransform: "uppercase" }}>
                {["Plat", "Coût", "PV", "FC %", "Marge", "Vendus", "Marge totale", "PV pour " + cibleNum + "%"].map(h => (
                  <th key={h} style={{ textAlign: h === "Plat" ? "left" : "right", padding: "6px 8px", borderBottom: `2px solid ${C.orClair}` }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {[...lignes].sort((a, b) => b.margeTotale - a.margeTotale).map(l => {
                const estSim = simId === l.id;
                const fcAffiche = estSim ? l.coutPortion / prixSim * 100 : l.fc;
                return (
                  <tr key={l.id} onClick={() => { setSimId(estSim ? null : l.id); setSimPrix(String(l.prixVente)); }}
                    style={{ cursor: "pointer", background: estSim ? "#F8F0DC" : "transparent", borderBottom: `1px dashed ${C.orClair}` }}>
                    <td style={{ padding: "7px 8px", fontWeight: 600, color: C.brun }}>{l.nom}</td>
                    <td style={{ padding: "7px 8px", textAlign: "right", color: C.brunMoyen }}>{l.coutPortion.toFixed(2)} €</td>
                    <td style={{ padding: "7px 8px", textAlign: "right" }}>
                      {estSim ? (
                        <input value={simPrix} onChange={e => setSimPrix(e.target.value)} onClick={e => e.stopPropagation()}
                          style={{ width: 62, padding: "4px 6px", border: `1.5px solid ${C.or}`, borderRadius: 6, fontFamily: "Inter, system-ui, sans-serif", fontSize: 12, textAlign: "right", background: C.blanc, color: C.brun }} />
                      ) : <b>{l.prixVente.toFixed(2)} €</b>}
                    </td>
                    <td style={{ padding: "7px 8px", textAlign: "right", fontWeight: 700, color: fcAffiche <= cibleNum ? C.vert : C.rouille }}>{fcAffiche.toFixed(1)}%</td>
                    <td style={{ padding: "7px 8px", textAlign: "right" }}>{(estSim ? prixSim - l.coutPortion : l.marge).toFixed(2)} €</td>
                    <td style={{ padding: "7px 8px", textAlign: "right", color: C.brunMoyen }}>{l.vendus}</td>
                    <td style={{ padding: "7px 8px", textAlign: "right", fontWeight: 700, color: C.or }}>{(estSim ? (prixSim - l.coutPortion) * l.vendus : l.margeTotale).toFixed(0)} €</td>
                    <td style={{ padding: "7px 8px", textAlign: "right", color: C.brunMoyen, fontStyle: "italic" }}>{prixPourCible(l).toFixed(2)} €</td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
        {fSim && (
          <div style={{ marginTop: 10, padding: 10, borderRadius: 10, background: "#F8F0DC", border: `1.5px solid ${C.or}`, fontSize: 12, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
            <b>Simulation {fSim.nom}</b> : à {prixSim.toFixed ? prixSim.toFixed(2) : prixSim} €, le food cost passe à <b style={{ color: fSim.coutPortion / prixSim * 100 <= cibleNum ? C.vert : C.rouille }}>{(fSim.coutPortion / prixSim * 100).toFixed(1)}%</b> et la marge mensuelle (à volume constant) à <b style={{ color: C.or }}>{((prixSim - fSim.coutPortion) * fSim.vendus).toFixed(0)} €</b> ({(((prixSim - fSim.coutPortion) * fSim.vendus) - fSim.margeTotale) >= 0 ? "+" : ""}{(((prixSim - fSim.coutPortion) * fSim.vendus) - fSim.margeTotale).toFixed(0)} €). Pour atteindre {cibleNum}% : vendre à {prixPourCible(fSim).toFixed(2)} €.
          </div>
        )}
        <div style={{ fontSize: 10.5, fontFamily: "Inter, system-ui, sans-serif", color: C.brunMoyen, marginTop: 8 }}>
          Prix TTC, coûts matière HT estimés — affinez les coûts dans vos fiches techniques. La colonne « PV pour {cibleNum}% » donne le prix de vente atteignant votre objectif.
        </div>
      </Carte>
    </div>
  );
}

// ============ PAGE D'ACCUEIL (lanceur d'applications) ============
function Accueil({ extensions, releves, commandes, stocks, reservations, mep, aller, lancerOrdre, profil }) {
  const [ordre, setOrdre] = useState("");
  const pastilles = {
    haccp: releves.filter(r => r.statut === "alerte").length + Object.entries(mep).filter(([, m]) => m.valide && m.dispo > 0 && Math.ceil(((m.prodLe || Date.now()) + 3 * 86400000 - Date.now()) / 86400000) <= 1).length,
    service: commandes.filter(c => c.statut === "en_attente" || c.statut === "en_cuisine").length,
    stocks: stocks.filter(s => s.qte <= s.seuil).length,
    fournisseurs: produitsACommander(stocks).length,
    resa: reservations.filter(r => r.statut === "a_venir").length,
    cuisine: Math.max(0, FICHES.length - Object.values(mep).filter(m => m.valide).length) > 0 ? FICHES.length - Object.values(mep).filter(m => m.valide).length : 0,
  };
  const tuiles = [...extensions, { id: "boutique", label: "Extensions", icone: "+", boutique: true }];
  return (
    <div>
      <div style={{ textAlign: "center", margin: "18px 0 20px" }}>
        <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 22, color: C.brun }}>
          Bonjour Chef <span style={{ color: C.or }}>👨‍🍳</span>
        </div>
        <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 13, color: C.brunMoyen, fontStyle: "italic", marginTop: 4 }}>
          {new Date().toLocaleDateString("fr-FR", { weekday: "long", day: "numeric", month: "long" })}{profil?.nom ? ` — ${profil.nom}` : ""}
        </div>
      </div>
      <div style={{ display: "flex", gap: 8, maxWidth: 540, margin: "0 auto 28px" }}>
        <input value={ordre} onChange={e => setOrdre(e.target.value)}
          onKeyDown={e => { if (e.key === "Enter" && ordre.trim()) { lancerOrdre(ordre.trim()); setOrdre(""); } }}
          placeholder="✺ Demande au pilote : « réserve 4 couverts ce soir 20h »…"
          style={{ flex: 1, padding: "12px 16px", border: "1.5px solid rgba(200,150,42,0.45)", borderRadius: 24, fontFamily: "Inter, system-ui, sans-serif", fontSize: 13.5, background: C.blanc, color: C.brun, boxShadow: "0 2px 10px rgba(53,39,24,0.07)" }} />
        <button onClick={() => { if (ordre.trim()) { lancerOrdre(ordre.trim()); setOrdre(""); } }}
          style={{ ...btnStyle(C.brun), marginTop: 0, borderRadius: 24, padding: "12px 20px" }}>→</button>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(118px, 1fr))", gap: 18, maxWidth: 760, margin: "0 auto" }}>
        {tuiles.map(ext => {
          const n = pastilles[ext.id] || 0;
          return (
            <button key={ext.id} onClick={() => aller(ext.id)} style={{
              background: "transparent", border: "none", cursor: "pointer", padding: 0,
              display: "flex", flexDirection: "column", alignItems: "center", gap: 8,
            }}>
              <div style={{
                position: "relative", width: 90, height: 90, borderRadius: 26,
                background: ext.boutique
                  ? C.blanc
                  : `linear-gradient(145deg, ${C.brun} 0%, #56401F 100%)`,
                border: ext.boutique ? `2px dashed ${C.or}` : "1px solid rgba(200,150,42,0.6)",
                boxShadow: ext.boutique ? "0 2px 8px rgba(53,39,24,0.10)" : "0 8px 20px rgba(53,39,24,0.28), inset 0 1px 0 rgba(230,204,133,0.35)",
                display: "flex", alignItems: "center", justifyContent: "center",
                fontSize: 37, color: ext.boutique ? C.or : C.orClair,
                transition: "transform .12s",
              }}
                onMouseDown={e => e.currentTarget.style.transform = "scale(0.93)"}
                onMouseUp={e => e.currentTarget.style.transform = "scale(1)"}
                onMouseLeave={e => e.currentTarget.style.transform = "scale(1)"}
              >
                {ext.icone}
                {n > 0 && (
                  <span style={{
                    position: "absolute", top: -7, right: -7, minWidth: 24, height: 24, borderRadius: 12,
                    background: C.rouille, color: C.blanc, fontSize: 12.5, fontWeight: 700, fontFamily: "Inter, system-ui, sans-serif",
                    display: "flex", alignItems: "center", justifyContent: "center", padding: "0 6px",
                    border: `2px solid ${C.creme}`,
                  }}>{n}</span>
                )}
              </div>
              <span style={{ fontFamily: "Inter, system-ui, sans-serif", fontSize: 12, fontWeight: 700, color: C.brun, textAlign: "center", lineHeight: 1.25, maxWidth: 100 }}>
                {ext.label}
              </span>
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ============ REGISTRE DES EXTENSIONS (architecture type Kodi) ============
// Chaque module est une "extension" : le cœur de l'app ne connaît que ce registre.
// Demain, ajouter un module = ajouter une entrée ici, zéro modification du cœur.
const EXTENSIONS = [
  { id: "parametrage", label: "Paramétrage", icone: "⚙", desc: "Le profil de votre établissement : style de cuisine, matériel, volumes, brigade, clientèle et hygiène. Toutes les autres extensions et Ti-Chef s'y adaptent.", prix: "Inclus", coeur: true, composant: null },
  { id: "dashboard", label: "Tableau de bord", icone: "◉", desc: "KPIs de l'établissement : food cost, alertes HACCP, marges par plat.", prix: "Inclus", coeur: true, composant: Dashboard },
  { id: "fiches", label: "Fiches techniques", icone: "✦", desc: "Recettes pro, food cost, multiplicateur de portions, allergènes.", prix: "Inclus", coeur: true, composant: FichesTechniques },
  { id: "cuisine", label: "Cuisine", icone: "♨", desc: "La mise en place du service : validez vos productions, les matières sont déduites de l'inventaire et les dispos partent en salle.", prix: "Inclus", coeur: true, composant: Cuisine },
  { id: "foodcost", label: "Food cost", icone: "％", desc: "Food cost théorique vs réel, menu engineering (stars, poids morts…) et simulateur de prix par plat.", prix: "Inclus", coeur: true, composant: FoodCost },
  { id: "haccp", label: "HACCP", icone: "❄", desc: "Registre de températures, alertes de conformité, traçabilité PMS.", prix: "19 €/mois", coeur: false, composant: Haccp },
  { id: "fournisseurs", label: "Fournisseurs", icone: "⬡", desc: "Carnet fournisseurs, délais de livraison, historique de commandes.", prix: "9 €/mois", coeur: false, composant: Fournisseurs },
  { id: "ia", label: "Assistant IA", icone: "✺", desc: "L'agent pilote, au texte et à la voix : il lit et agit sur tous vos modules, mains libres pendant le service.", prix: "29 €/mois", coeur: false, composant: AssistantIA },
  { id: "stocks", label: "Inventaire", icone: "▤", desc: "Tous les consommables Cuisine, Salle et Bar : alertes de rupture, valorisation, déduction auto à la mise en place.", prix: "Inclus", coeur: true, composant: Stocks },
  { id: "planning", label: "Planning équipe", icone: "◷", desc: "Planning hebdo interactif, masse salariale et ratio personnel/CA.", prix: "15 €/mois", coeur: false, composant: Planning },
  { id: "carte", label: "Menus & carte du jour", icone: "✎", desc: "Composez un menu depuis vos fiches : carte élégante + food cost auto.", prix: "Inclus", coeur: true, composant: Menus },
  { id: "caisse", label: "Encaissement connecté", icone: "€", desc: "Préparez le ticket dans Mepli Pro, encaissez sur la caisse certifiée de votre opérateur (SumUp, Zettle…). Zéro double saisie, conformité assurée par l'opérateur.", prix: "29 €/mois", coeur: false, composant: Caisse },
  { id: "zanalyse", label: "Z & Analyse", icone: "◫", desc: "Importez le Z de votre caisse (photo lue par l'IA ou saisie), rapprochement auto avec Mepli Pro, historique et tendances. Compatible toute caisse.", prix: "15 €/mois", coeur: false, composant: ZAnalyse },
  { id: "service", label: "Service en salle", icone: "⬚", desc: "Plan de salle interactif, prise de commande par table, écran cuisine (KDS).", prix: "25 €/mois", coeur: false, composant: Service },
  { id: "resa", label: "Réservations", icone: "✆", desc: "Carnet de réservations midi/soir, jauge de couverts vs capacité, installation directe sur le plan de salle.", prix: "12 €/mois", coeur: false, composant: Reservations },
];

function Boutique({ actives, toggle }) {
  const totalMensuel = EXTENSIONS.filter(e => actives.includes(e.id) && !e.coeur && !e.aVenir)
    .reduce((s, e) => s + (parseFloat(String(e.prix).replace(",", ".")) || 0), 0);
  return (
    <div>
      <Carte style={{ marginBottom: 14, background: C.cremeFonce }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 8 }}>
          <div style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, color: C.brun, fontSize: 16 }}>Boutique d'extensions</div>
          <span style={{ fontFamily: "Fraunces, Georgia, serif", fontWeight: 700, fontSize: 15, color: C.brun, background: C.blanc, border: `1.5px solid ${C.or}`, borderRadius: 12, padding: "5px 14px" }}>
            Votre configuration : <span style={{ color: C.or }}>{totalMensuel.toFixed(0)} €/mois</span>
          </span>
        </div>
        <div style={{ fontSize: 13, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginTop: 4, lineHeight: 1.5 }}>
          Composez votre Mepli Pro : les modules cœur sont inclus, activez uniquement les extensions dont votre établissement a besoin. Le total s'ajuste en direct.
        </div>
      </Carte>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))", gap: 12 }}>
        {EXTENSIONS.map(ext => {
          const installee = actives.includes(ext.id);
          return (
            <Carte key={ext.id} style={{ borderTop: `3px solid ${ext.aVenir ? C.brunMoyen : installee ? C.vert : C.or}`, opacity: ext.aVenir ? 0.75 : 1, display: "flex", flexDirection: "column" }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                <span style={{ fontSize: 22, color: C.or }}>{ext.icone}</span>
                <Badge bg={ext.aVenir ? C.brunMoyen : installee ? C.vert : C.or}>
                  {ext.aVenir ? "À venir" : installee ? "Installée" : ext.prix}
                </Badge>
              </div>
              <h3 style={{ fontFamily: "Fraunces, Georgia, serif", color: C.brun, margin: "10px 0 6px", fontSize: 16 }}>{ext.label}</h3>
              <div style={{ fontSize: 12.5, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", lineHeight: 1.5, flex: 1 }}>{ext.desc}</div>
              {ext.coeur ? (
                <div style={{ marginTop: 10, fontSize: 11, color: C.vert, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700 }}>✓ Module cœur — toujours actif</div>
              ) : ext.aVenir ? (
                <button disabled style={{ ...btnStyle(C.brunMoyen), width: "100%", marginTop: 10, opacity: 0.5, cursor: "default" }}>Disponible prochainement</button>
              ) : (
                <button onClick={() => toggle(ext.id)} style={{ ...btnStyle(installee ? C.rouille : C.vert), width: "100%", marginTop: 10 }}>
                  {installee ? "Désinstaller" : "Installer"}
                </button>
              )}
            </Carte>
          );
        })}
      </div>
    </div>
  );
}

// ============ APP (cœur léger : nav dynamique pilotée par le registre) ============
// ============ PARAMÉTRAGE PREMIÈRE UTILISATION ============
const PP_TYPES = ["Restaurant traditionnel", "Brasserie / bistrot", "Pizzeria", "Food truck", "Traiteur / événementiel", "Hôtel-restaurant", "Dark kitchen", "Restauration collective", "Bar à vin / tapas", "Snack / rapide"];
const PP_CUISINES = ["Française traditionnelle", "Bistronomie", "Brasserie", "Italienne", "Pizzeria", "Méditerranéenne", "Catalane", "Espagnole / tapas", "Grecque", "Libanaise", "Marocaine", "Antillaise / créole", "Africaine", "Japonaise", "Thaï / asiatique", "Indienne", "Sud-américaine", "Poissons & fruits de mer", "Burger / street food", "Végétarienne / végane"];
const PP_MATERIEL = {
  "Cuisson": ["Piano gaz", "Induction", "Plancha", "Salamandre", "Friteuse", "Four mixte / vapeur", "Four à sole", "Four à pizza (bois)", "Four à pizza (gaz/élec.)", "Sauteuse basculante (Variocook)", "Braisière", "Josper / charbon", "Wok", "Crêpière"],
  "Froid": ["Chambre froide positive", "Chambre froide négative", "Armoire positive", "Armoire négative", "Congélateur coffre", "Cellule de refroidissement rapide", "Machine à glaçons"],
  "Préparation": ["Robot-coupe", "Cutter", "Batteur-mélangeur", "Pétrin", "Trancheuse", "Mixeur plongeant", "Laminoir", "Thermomix"],
  "Techniques avancées": ["Machine sous vide", "Thermoplongeur (basse température)", "Étuve de pousse", "Déshydrateur", "Fumoir", "Siphon", "Turbine à glace"],
};
const PP_POSTES_CUISINE = ["Chef de cuisine", "Second", "Chef de partie", "Commis", "Apprenti", "Pâtissier", "Pizzaiolo", "Plonge"];
const PP_POSTES_SALLE = ["Responsable de salle", "Serveur", "Runner", "Barman", "Sommelier"];
const PP_CIBLES = ["Locaux / habitués", "Touristes", "Familles", "Déjeuner d'affaires", "Étudiants", "Groupes & séminaires", "Seniors", "Privatisations / mariages"];
const PP_REGIMES = ["Sans gluten", "Végétarien", "Végane", "Sans lactose", "Halal", "Allergies sévères"];
const PP_JOURS = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];

const PP_VIDE = {
  nom: "", type: "", cuisines: [], couverts: 60, terrasse: 0, services: [], saisonnalite: "annee",
  couvertsMidi: 40, couvertsSoir: 55, joursOuverture: 6, ticketMoyen: 28,
  foodCostCible: 30, masseSalarialeCible: 33, repartition: { place: 85, emporter: 10, livraison: 5 },
  materiel: [], liaison: "chaude", surfaceStockage: "",
  effectifsCuisine: {}, effectifsSalle: {}, extras: 0, niveauBrigade: "confirmée", langues: ["Français"],
  cibles: [], positionnement: "Milieu de gamme", regimes: [],
  nbEntrees: 6, nbPlats: 8, nbDesserts: 6, frequenceCarte: "saisonnière", formules: [],
  fournisseurs: "", joursLivraison: [], jourInventaire: "Lun", delaiLivraison: 2,
  enceintesFroides: 4, frequenceReleves: "2 fois/jour", friture: true, tracabilite: true, referentHygiene: "",
};

const PP_ETAPES = [
  { titre: "L'établissement", sous: "Identité et rythme de service" },
  { titre: "Volumes & rentabilité", sous: "Ce qui pilote votre food cost" },
  { titre: "Matériel", sous: "Ce que votre cuisine sait faire" },
  { titre: "La brigade", sous: "Effectifs et niveau technique" },
  { titre: "Clientèle & carte", sous: "À qui vous servez, et quoi" },
  { titre: "Achats & stock", sous: "Livraisons et inventaire" },
  { titre: "Hygiène", sous: "Base de votre plan de maîtrise sanitaire" },
  { titre: "Récapitulatif", sous: "Ce que Mepli configure pour vous" },
];

function pp_deriver(p) {
  const a = (m) => p.materiel.includes(m);
  const couvertsJour = p.couvertsMidi + p.couvertsSoir;
  const couvertsSemaine = couvertsJour * p.joursOuverture;
  const caSemaine = Math.round(couvertsSemaine * p.ticketMoyen);
  const totalCuisine = Object.values(p.effectifsCuisine).reduce((s, n) => s + n, 0);
  const totalSalle = Object.values(p.effectifsSalle).reduce((s, n) => s + n, 0);

  const techniques = [];
  if (a("Machine sous vide") && a("Thermoplongeur (basse température)")) techniques.push("Cuisson sous vide basse température");
  if (a("Sauteuse basculante (Variocook)")) techniques.push("Production en grande masse (braisés, sauces, risottos)");
  if (a("Four mixte / vapeur")) techniques.push("Vapeur, mixte, remise en température maîtrisée");
  if (a("Plancha")) techniques.push("Saisie minute à la plancha");
  if (a("Josper / charbon")) techniques.push("Cuisson au charbon");
  if (a("Four à pizza (bois)") || a("Four à pizza (gaz/élec.)")) techniques.push("Pâtes levées et pizzas");
  if (a("Fumoir")) techniques.push("Fumage maison");
  if (a("Turbine à glace")) techniques.push("Glaces et sorbets maison");

  const alertes = [];
  if (!a("Cellule de refroidissement rapide")) alertes.push("Sans cellule de refroidissement, la liaison froide est bloquée : Ti-Chef ne proposera que de la liaison chaude ou du minute.");
  if (p.friture && !a("Friteuse")) alertes.push("Vous suivez l'huile de friture mais aucune friteuse n'est déclarée dans le matériel.");
  if (p.foodCostCible > 35) alertes.push(`Food cost cible à ${p.foodCostCible} % : au-dessus du repère habituel de 28 à 32 %.`);
  if (totalCuisine > 0 && couvertsJour / totalCuisine > 45) alertes.push(`Environ ${Math.round(couvertsJour / totalCuisine)} couverts par personne en cuisine : les fiches seront calibrées sur des process courts.`);
  if (totalCuisine === 0) alertes.push("Aucun effectif de cuisine renseigné : le module planning restera vide.");

  const complexite = p.niveauBrigade === "débutante" ? "Recettes en 5 étapes maximum, sans technique avancée"
    : p.niveauBrigade === "confirmée" ? "Recettes standard, techniques classiques autorisées"
    : "Techniques avancées et dressages complexes autorisés";
  const relevesJour = p.frequenceReleves === "1 fois/jour" ? 1 : p.frequenceReleves === "3 fois/jour" ? 3 : 2;

  return {
    couvertsJour, couvertsSemaine, caSemaine, caMensuel: Math.round(caSemaine * 4.33),
    coefficient: p.foodCostCible > 0 ? (100 / p.foodCostCible).toFixed(2) : "—",
    matiereParCouvert: (p.ticketMoyen * p.foodCostCible / 100).toFixed(2),
    budgetMatiereMois: Math.round(caSemaine * 4.33 * p.foodCostCible / 100),
    totalCuisine, totalSalle, techniques, alertes, complexite,
    nbFiches: p.nbEntrees + p.nbPlats + p.nbDesserts,
    relevesSemaine: p.enceintesFroides * relevesJour * 7,
    stockSecurite: `${p.delaiLivraison} jour(s) de consommation + 20 % de marge`,
  };
}

// Résumé injecté dans le prompt système de Ti-Chef
function pp_resume(p) {
  if (!p) return "";
  const d = pp_deriver(p);
  const eff = (o) => Object.entries(o).filter(([, n]) => n > 0).map(([k, n]) => `${n} ${k}`).join(", ") || "non renseigné";
  return `
=== PROFIL DE L'ÉTABLISSEMENT (paramétré par le chef — à respecter impérativement) ===
Établissement : ${p.nom || "sans nom"}, ${p.type || "type non précisé"}, cuisine ${p.cuisines.join(" / ") || "non précisée"}, ${p.couverts} couverts en salle${p.terrasse ? ` + ${p.terrasse} en terrasse` : ""}, services : ${p.services.join(", ") || "non précisés"}, ouverture ${p.saisonnalite}.
Volumes : ${d.couvertsJour} couverts/jour sur ${p.joursOuverture} jours, ticket moyen ${p.ticketMoyen} €, CA hebdo estimé ${d.caSemaine} €.
Objectifs : food cost ${p.foodCostCible} % (coefficient ${d.coefficient}, soit ${d.matiereParCouvert} € de matière par couvert), masse salariale ${p.masseSalarialeCible} %.
MATÉRIEL DISPONIBLE : ${p.materiel.join(", ") || "aucun déclaré"}. Liaison ${p.liaison}.
RÈGLE ABSOLUE : ne propose JAMAIS un process nécessitant un matériel absent de cette liste. Techniques autorisées : ${d.techniques.join(" ; ") || "cuissons de base uniquement"}.
Brigade : ${eff(p.effectifsCuisine)} en cuisine, ${eff(p.effectifsSalle)} en salle, niveau ${p.niveauBrigade}. ${d.complexite}. Langues : ${p.langues.join(", ")}.
Clientèle : ${p.cibles.join(", ") || "non précisée"}, positionnement ${p.positionnement}. Régimes à prévoir : ${p.regimes.join(", ") || "aucun"}.
Carte : ${p.nbEntrees} entrées, ${p.nbPlats} plats, ${p.nbDesserts} desserts, renouvellement ${p.frequenceCarte}. Offres : ${p.formules.join(", ") || "aucune"}.
Achats : livraisons ${p.joursLivraison.join("/") || "non précisées"}, inventaire le ${p.jourInventaire}, stock de sécurité sur ${d.stockSecurite}. Fournisseurs : ${(p.fournisseurs || "").split("\n").filter(Boolean).join(", ") || "non renseignés"}.
Hygiène : ${p.enceintesFroides} enceintes froides, relevés ${p.frequenceReleves}, friture ${p.friture ? "suivie" : "non concernée"}, traçabilité ${p.tracabilite ? "active" : "inactive"}${p.referentHygiene ? `, référent ${p.referentHygiene}` : ""}.
Adapte systématiquement tes quantités, tes process et tes propositions à ce profil.`;
}

function PPPuce({ actif, onClick, children }) {
  return (
    <button type="button" onClick={onClick} style={{
      border: `1.5px solid ${actif ? C.or : "rgba(53,39,24,0.22)"}`,
      background: actif ? C.or : "transparent", color: actif ? C.blanc : C.brun,
      borderRadius: 20, padding: "7px 14px", fontSize: 12.5, fontWeight: actif ? 700 : 500,
      cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif",
    }}>{children}</button>
  );
}

function PPChamp({ label, aide, children }) {
  return (
    <div style={{ marginBottom: 22 }}>
      <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 15, fontWeight: 600, color: C.brun, marginBottom: aide ? 3 : 8 }}>{label}</div>
      {aide && <div style={{ fontSize: 11.5, color: C.brunMoyen, marginBottom: 8, fontFamily: "Inter, system-ui, sans-serif", lineHeight: 1.5 }}>{aide}</div>}
      <div style={{ display: "flex", flexWrap: "wrap", gap: 7 }}>{children}</div>
    </div>
  );
}

function PPNombre({ valeur, onChange, suffixe, min = 0, pas = 1 }) {
  const bt = { width: 34, height: 34, borderRadius: 9, border: `1.5px solid ${C.or}`, background: "transparent", color: C.brun, fontSize: 17, cursor: "pointer", lineHeight: 1 };
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
      <button type="button" style={bt} onClick={() => onChange(Math.max(min, valeur - pas))}>−</button>
      <input type="number" inputMode="numeric" value={valeur} min={min}
        onChange={(e) => onChange(Math.max(min, Number(e.target.value) || 0))}
        style={{ width: 62, padding: "7px 4px", textAlign: "center", borderRadius: 9, border: "1.5px solid rgba(53,39,24,0.2)", background: C.creme, color: C.brun, fontFamily: "Inter, system-ui, sans-serif", fontSize: 14, fontWeight: 700 }} />
      <button type="button" style={bt} onClick={() => onChange(valeur + pas)}>+</button>
      {suffixe && <span style={{ fontSize: 12, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif" }}>{suffixe}</span>}
    </div>
  );
}

function PPTexte({ valeur, onChange, placeholder, lignes }) {
  const st = { width: "100%", padding: "9px 12px", borderRadius: 9, border: "1.5px solid rgba(53,39,24,0.2)", background: C.creme, color: C.brun, fontFamily: "Inter, system-ui, sans-serif", fontSize: 13.5 };
  return lignes
    ? <textarea rows={lignes} value={valeur} placeholder={placeholder} onChange={(e) => onChange(e.target.value)} style={{ ...st, resize: "vertical" }} />
    : <input type="text" value={valeur} placeholder={placeholder} onChange={(e) => onChange(e.target.value)} style={st} />;
}

function PPBloc({ titre, corps, accent }) {
  return (
    <div style={{ background: C.creme, borderLeft: `3px solid ${accent || C.or}`, borderRadius: 9, padding: "10px 13px", marginBottom: 9 }}>
      <div style={{ fontSize: 10.5, textTransform: "uppercase", letterSpacing: 1, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700 }}>{titre}</div>
      <div style={{ fontSize: 13, color: C.brun, fontFamily: "Inter, system-ui, sans-serif", marginTop: 3, lineHeight: 1.5 }}>{corps}</div>
    </div>
  );
}

function ParametrageInitial({ profilExistant, onValider, onAnnuler }) {
  const [etape, setEtape] = useState(0);
  const [p, setP] = useState(() => ({ ...PP_VIDE, ...(profilExistant || {}) }));
  const maj = (cle, val) => setP(prec => ({ ...prec, [cle]: val }));
  const bascule = (cle, val) => setP(prec => ({ ...prec, [cle]: prec[cle].includes(val) ? prec[cle].filter(x => x !== val) : [...prec[cle], val] }));
  const majEff = (groupe, poste, n) => setP(prec => ({ ...prec, [groupe]: { ...prec[groupe], [poste]: n } }));
  const d = pp_deriver(p);
  const e = PP_ETAPES[etape];

  const carte = { background: C.blanc, borderRadius: 16, padding: 20, border: `1.5px solid rgba(200,150,42,0.28)`, boxShadow: "0 4px 18px rgba(53,39,24,0.07)" };

  return (
    <div style={{ minHeight: "100vh", background: `linear-gradient(180deg, ${C.creme} 0%, #F3ECDB 100%)`, color: C.brun, padding: "22px 14px 40px" }}>
      <div style={{ maxWidth: 720, margin: "0 auto" }}>

        <div style={{ marginBottom: 18 }}>
          <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 22, fontWeight: 700 }}>Mepli <span style={{ color: C.or }}>Pro</span></div>
          <div style={{ fontSize: 11, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", letterSpacing: 1, textTransform: "uppercase" }}>
            {profilExistant ? "Réglages de l'établissement" : "Mise en place de votre établissement"}
          </div>
        </div>

        <div style={{ marginBottom: 16 }}>
          <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 26, fontWeight: 700, lineHeight: 1.15 }}>{e.titre}</div>
          <div style={{ fontSize: 13, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginTop: 3 }}>{e.sous}</div>
          <div style={{ display: "flex", alignItems: "center", gap: 10, marginTop: 14 }}>
            <div style={{ flex: 1, height: 5, borderRadius: 3, background: "rgba(53,39,24,0.1)", overflow: "hidden" }}>
              <div style={{ width: `${((etape + 1) / PP_ETAPES.length) * 100}%`, height: "100%", background: C.or, transition: "width .25s ease" }} />
            </div>
            <span style={{ fontSize: 11.5, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", fontWeight: 700 }}>{etape + 1}/{PP_ETAPES.length}</span>
          </div>
        </div>

        <div style={carte}>

          {etape === 0 && <>
            <PPChamp label="Nom de l'établissement"><PPTexte valeur={p.nom} onChange={v => maj("nom", v)} placeholder="Le Sud" /></PPChamp>
            <PPChamp label="Type d'établissement">
              {PP_TYPES.map(t => <PPPuce key={t} actif={p.type === t} onClick={() => maj("type", t)}>{t}</PPPuce>)}
            </PPChamp>
            <PPChamp label="Style de cuisine" aide="Plusieurs choix possibles. Détermine la bibliothèque de recettes et les fournisseurs suggérés.">
              {PP_CUISINES.map(c => <PPPuce key={c} actif={p.cuisines.includes(c)} onClick={() => bascule("cuisines", c)}>{c}</PPPuce>)}
            </PPChamp>
            <PPChamp label="Capacité en salle"><PPNombre valeur={p.couverts} onChange={v => maj("couverts", v)} suffixe="couverts" pas={5} /></PPChamp>
            <PPChamp label="Capacité en terrasse"><PPNombre valeur={p.terrasse} onChange={v => maj("terrasse", v)} suffixe="couverts" pas={5} /></PPChamp>
            <PPChamp label="Services assurés">
              {["Midi", "Soir", "Service continu", "Brunch", "Petit-déjeuner", "Bar / apéro"].map(s => <PPPuce key={s} actif={p.services.includes(s)} onClick={() => bascule("services", s)}>{s}</PPPuce>)}
            </PPChamp>
            <PPChamp label="Rythme d'ouverture" aide="Un établissement saisonnier déclenche des prévisions de stock et de planning différentes.">
              {[["annee", "Ouvert à l'année"], ["saisonnier", "Saisonnier"], ["mixte", "Année avec forte saison"]].map(([k, l]) => <PPPuce key={k} actif={p.saisonnalite === k} onClick={() => maj("saisonnalite", k)}>{l}</PPPuce>)}
            </PPChamp>
          </>}

          {etape === 1 && <>
            <PPChamp label="Couverts moyens au midi"><PPNombre valeur={p.couvertsMidi} onChange={v => maj("couvertsMidi", v)} suffixe="couverts" pas={5} /></PPChamp>
            <PPChamp label="Couverts moyens au soir"><PPNombre valeur={p.couvertsSoir} onChange={v => maj("couvertsSoir", v)} suffixe="couverts" pas={5} /></PPChamp>
            <PPChamp label="Jours d'ouverture par semaine"><PPNombre valeur={p.joursOuverture} onChange={v => maj("joursOuverture", Math.min(7, v))} suffixe="jours" min={1} /></PPChamp>
            <PPChamp label="Ticket moyen TTC"><PPNombre valeur={p.ticketMoyen} onChange={v => maj("ticketMoyen", v)} suffixe="€" /></PPChamp>
            <PPChamp label="Food cost cible" aide={`Coefficient multiplicateur correspondant : ${d.coefficient} — soit ${d.matiereParCouvert} € de matière par couvert.`}>
              <PPNombre valeur={p.foodCostCible} onChange={v => maj("foodCostCible", v)} suffixe="%" />
            </PPChamp>
            <PPChamp label="Masse salariale cible"><PPNombre valeur={p.masseSalarialeCible} onChange={v => maj("masseSalarialeCible", v)} suffixe="% du CA" /></PPChamp>
            <PPChamp label="Répartition du chiffre d'affaires" aide="Sur place, à emporter, en livraison : conditionne la TVA et les conditionnements.">
              <div style={{ width: "100%" }}>
                {[["place", "Sur place"], ["emporter", "À emporter"], ["livraison", "Livraison"]].map(([k, l]) => (
                  <div key={k} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, marginBottom: 8 }}>
                    <span style={{ fontSize: 13, fontFamily: "Inter, system-ui, sans-serif" }}>{l}</span>
                    <PPNombre valeur={p.repartition[k]} pas={5} onChange={v => maj("repartition", { ...p.repartition, [k]: v })} suffixe="%" />
                  </div>
                ))}
              </div>
            </PPChamp>
            <PPBloc titre="Projection" corps={<>{d.couvertsSemaine} couverts et <b>{d.caSemaine.toLocaleString("fr-FR")} €</b> par semaine, soit environ <b>{d.caMensuel.toLocaleString("fr-FR")} €</b> par mois et <b>{d.budgetMatiereMois.toLocaleString("fr-FR")} €</b> de budget matière.</>} />
          </>}

          {etape === 2 && <>
            <div style={{ fontSize: 12.5, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginBottom: 16, lineHeight: 1.6 }}>
              Cochez uniquement ce dont vous disposez réellement. Ti-Chef n'écrira jamais un process qui demande un matériel absent.
            </div>
            {Object.entries(PP_MATERIEL).map(([groupe, items]) => (
              <PPChamp key={groupe} label={groupe}>
                {items.map(m => <PPPuce key={m} actif={p.materiel.includes(m)} onClick={() => bascule("materiel", m)}>{m}</PPPuce>)}
              </PPChamp>
            ))}
            <PPChamp label="Liaison de production">
              {[["chaude", "Liaison chaude"], ["froide", "Liaison froide"], ["mixte", "Les deux"]].map(([k, l]) => <PPPuce key={k} actif={p.liaison === k} onClick={() => maj("liaison", k)}>{l}</PPPuce>)}
            </PPChamp>
            {d.techniques.length > 0 && <PPBloc titre="Techniques débloquées" corps={d.techniques.join(" · ")} accent={C.vert} />}
          </>}

          {etape === 3 && <>
            <PPChamp label="Effectif en cuisine">
              <div style={{ width: "100%" }}>
                {PP_POSTES_CUISINE.map(poste => (
                  <div key={poste} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, marginBottom: 7 }}>
                    <span style={{ fontSize: 13, fontFamily: "Inter, system-ui, sans-serif" }}>{poste}</span>
                    <PPNombre valeur={p.effectifsCuisine[poste] || 0} onChange={v => majEff("effectifsCuisine", poste, v)} />
                  </div>
                ))}
              </div>
            </PPChamp>
            <PPChamp label="Effectif en salle">
              <div style={{ width: "100%" }}>
                {PP_POSTES_SALLE.map(poste => (
                  <div key={poste} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, marginBottom: 7 }}>
                    <span style={{ fontSize: 13, fontFamily: "Inter, system-ui, sans-serif" }}>{poste}</span>
                    <PPNombre valeur={p.effectifsSalle[poste] || 0} onChange={v => majEff("effectifsSalle", poste, v)} />
                  </div>
                ))}
              </div>
            </PPChamp>
            <PPChamp label="Extras en renfort par semaine"><PPNombre valeur={p.extras} onChange={v => maj("extras", v)} suffixe="personnes" /></PPChamp>
            <PPChamp label="Niveau technique de la brigade" aide="Calibre la complexité des recettes et le niveau de détail des fiches.">
              {["débutante", "confirmée", "expérimentée"].map(n => <PPPuce key={n} actif={p.niveauBrigade === n} onClick={() => maj("niveauBrigade", n)}>{n}</PPPuce>)}
            </PPChamp>
            <PPChamp label="Langues des fiches et consignes">
              {["Français", "Espagnol", "Anglais", "Catalan", "Portugais", "Arabe"].map(l => <PPPuce key={l} actif={p.langues.includes(l)} onClick={() => bascule("langues", l)}>{l}</PPPuce>)}
            </PPChamp>
          </>}

          {etape === 4 && <>
            <PPChamp label="Clientèle principale">
              {PP_CIBLES.map(c => <PPPuce key={c} actif={p.cibles.includes(c)} onClick={() => bascule("cibles", c)}>{c}</PPPuce>)}
            </PPChamp>
            <PPChamp label="Positionnement">
              {["Populaire", "Milieu de gamme", "Premium", "Gastronomique"].map(n => <PPPuce key={n} actif={p.positionnement === n} onClick={() => maj("positionnement", n)}>{n}</PPPuce>)}
            </PPChamp>
            <PPChamp label="Régimes fréquemment demandés" aide="Génère les variantes de recettes et la matrice allergènes.">
              {PP_REGIMES.map(r => <PPPuce key={r} actif={p.regimes.includes(r)} onClick={() => bascule("regimes", r)}>{r}</PPPuce>)}
            </PPChamp>
            <PPChamp label="Taille de la carte">
              <div style={{ width: "100%" }}>
                {[["nbEntrees", "Entrées"], ["nbPlats", "Plats"], ["nbDesserts", "Desserts"]].map(([k, l]) => (
                  <div key={k} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, marginBottom: 7 }}>
                    <span style={{ fontSize: 13, fontFamily: "Inter, system-ui, sans-serif" }}>{l}</span>
                    <PPNombre valeur={p[k]} onChange={v => maj(k, v)} />
                  </div>
                ))}
              </div>
            </PPChamp>
            <PPChamp label="Fréquence de changement de carte">
              {["fixe", "saisonnière", "mensuelle", "hebdomadaire", "quotidienne"].map(f => <PPPuce key={f} actif={p.frequenceCarte === f} onClick={() => maj("frequenceCarte", f)}>{f}</PPPuce>)}
            </PPChamp>
            <PPChamp label="Offres proposées">
              {["Plat du jour", "Formule midi", "Menu enfant", "Menu dégustation", "Carte des vins", "Menu groupe"].map(f => <PPPuce key={f} actif={p.formules.includes(f)} onClick={() => bascule("formules", f)}>{f}</PPPuce>)}
            </PPChamp>
          </>}

          {etape === 5 && <>
            <PPChamp label="Fournisseurs principaux" aide="Un par ligne. Ils seront créés dans le module fournisseurs.">
              <PPTexte lignes={4} valeur={p.fournisseurs} onChange={v => maj("fournisseurs", v)} placeholder={"Metro\nPomona TerreAzur\nBoucherie du village"} />
            </PPChamp>
            <PPChamp label="Jours de livraison">
              {PP_JOURS.map(j => <PPPuce key={j} actif={p.joursLivraison.includes(j)} onClick={() => bascule("joursLivraison", j)}>{j}</PPPuce>)}
            </PPChamp>
            <PPChamp label="Délai entre deux livraisons" aide={`Stock de sécurité calculé sur ${d.stockSecurite}.`}>
              <PPNombre valeur={p.delaiLivraison} onChange={v => maj("delaiLivraison", v)} suffixe="jours" min={1} />
            </PPChamp>
            <PPChamp label="Jour d'inventaire">
              {PP_JOURS.map(j => <PPPuce key={j} actif={p.jourInventaire === j} onClick={() => maj("jourInventaire", j)}>{j}</PPPuce>)}
            </PPChamp>
            <PPChamp label="Surface de stockage" aide="Limite les quantités de commande suggérées.">
              <PPTexte valeur={p.surfaceStockage} onChange={v => maj("surfaceStockage", v)} placeholder="Réserve sèche 12 m², une chambre froide" />
            </PPChamp>
          </>}

          {etape === 6 && <>
            <PPChamp label="Enceintes froides à tracer" aide="Chambres froides, armoires, congélateurs, vitrines.">
              <PPNombre valeur={p.enceintesFroides} onChange={v => maj("enceintesFroides", v)} suffixe="enceintes" />
            </PPChamp>
            <PPChamp label="Fréquence des relevés de température" aide={`Soit ${d.relevesSemaine} relevés générés par semaine.`}>
              {["1 fois/jour", "2 fois/jour", "3 fois/jour"].map(f => <PPPuce key={f} actif={p.frequenceReleves === f} onClick={() => maj("frequenceReleves", f)}>{f}</PPPuce>)}
            </PPChamp>
            <PPChamp label="Suivi de l'huile de friture">
              <PPPuce actif={p.friture} onClick={() => maj("friture", true)}>Oui</PPPuce>
              <PPPuce actif={!p.friture} onClick={() => maj("friture", false)}>Non</PPPuce>
            </PPChamp>
            <PPChamp label="Traçabilité des étiquettes et des lots">
              <PPPuce actif={p.tracabilite} onClick={() => maj("tracabilite", true)}>Oui</PPPuce>
              <PPPuce actif={!p.tracabilite} onClick={() => maj("tracabilite", false)}>Non</PPPuce>
            </PPChamp>
            <PPChamp label="Référent hygiène"><PPTexte valeur={p.referentHygiene} onChange={v => maj("referentHygiene", v)} placeholder="Nom et fonction" /></PPChamp>
          </>}

          {etape === 7 && <>
            <div style={{ fontSize: 12.5, color: C.brunMoyen, fontFamily: "Inter, system-ui, sans-serif", marginBottom: 14, lineHeight: 1.6 }}>
              Voici la configuration que Mepli va appliquer. Tout reste modifiable ensuite depuis les réglages.
            </div>
            <PPBloc titre="Fiches techniques" corps={`${d.nbFiches} fiches à créer, carte ${p.frequenceCarte}`} />
            <PPBloc titre="Food cost" corps={`Coefficient ${d.coefficient} · ${d.matiereParCouvert} € de matière par couvert · budget ${d.budgetMatiereMois.toLocaleString("fr-FR")} €/mois`} />
            <PPBloc titre="Stock" corps={`Seuils sur ${d.stockSecurite}, inventaire le ${p.jourInventaire}`} />
            <PPBloc titre="HACCP" corps={`${d.relevesSemaine} relevés par semaine sur ${p.enceintesFroides} enceintes`} />
            <PPBloc titre="Ti-Chef" corps={d.complexite} />
            <PPBloc titre="Équipe" corps={`${d.totalCuisine} en cuisine, ${d.totalSalle} en salle`} />
            {d.alertes.length > 0 && (
              <div style={{ background: "#FBF1EC", borderLeft: `3px solid ${C.rouille}`, borderRadius: 9, padding: "12px 14px", marginTop: 14 }}>
                <div style={{ fontSize: 10.5, textTransform: "uppercase", letterSpacing: 1, color: C.rouille, fontWeight: 700, fontFamily: "Inter, system-ui, sans-serif", marginBottom: 6 }}>À vérifier</div>
                {d.alertes.map((a, i) => (
                  <div key={i} style={{ fontSize: 12.5, color: C.brun, fontFamily: "Inter, system-ui, sans-serif", lineHeight: 1.55, marginBottom: 5 }}>· {a}</div>
                ))}
              </div>
            )}
          </>}
        </div>

        <div style={{ display: "flex", gap: 10, marginTop: 16 }}>
          <button type="button" onClick={() => setEtape(x => Math.max(0, x - 1))} disabled={etape === 0}
            style={{ padding: "13px 18px", borderRadius: 12, border: `1.5px solid ${etape === 0 ? "rgba(53,39,24,0.12)" : "rgba(53,39,24,0.3)"}`, background: "transparent", color: etape === 0 ? "rgba(53,39,24,0.3)" : C.brun, fontWeight: 700, fontSize: 13.5, cursor: etape === 0 ? "default" : "pointer", fontFamily: "Inter, system-ui, sans-serif" }}>
            Retour
          </button>
          {etape < PP_ETAPES.length - 1 ? (
            <button type="button" onClick={() => setEtape(x => x + 1)}
              style={{ flex: 1, padding: "13px 18px", borderRadius: 12, border: "none", background: C.or, color: C.blanc, fontWeight: 700, fontSize: 14, cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif" }}>
              Continuer
            </button>
          ) : (
            <button type="button" onClick={() => onValider({ ...p, termine: true, version: 1, majLe: new Date().toISOString() })}
              style={{ flex: 1, padding: "13px 18px", borderRadius: 12, border: "none", background: C.brun, color: C.creme, fontWeight: 700, fontSize: 14, cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif" }}>
              {profilExistant ? "Enregistrer les modifications" : "Enregistrer et ouvrir Mepli"}
            </button>
          )}
        </div>

        <button type="button" onClick={() => (onAnnuler ? onAnnuler() : setEtape(PP_ETAPES.length - 1))}
          style={{ display: "block", width: "100%", marginTop: 12, background: "none", border: "none", color: C.brunMoyen, fontSize: 12, cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif" }}>
          {onAnnuler ? "Annuler" : "Passer au récapitulatif"}
        </button>
      </div>
    </div>
  );
}

// Taux horaires bruts indicatifs par poste (convention HCR) — modifiables ensuite dans Planning
const PP_TAUX = {
  "Chef de cuisine": 18.0, "Second": 15.0, "Chef de partie": 13.5, "Commis": 12.2,
  "Apprenti": 8.0, "Pâtissier": 14.0, "Pizzaiolo": 13.5, "Plonge": 11.9,
  "Responsable de salle": 14.0, "Serveur": 12.2, "Runner": 11.9, "Barman": 12.8, "Sommelier": 15.0,
};

// Construit la base de départ à partir des réponses au questionnaire.
function pp_construireBase(p) {
  // --- Équipe : un poste renseigné = un membre créé, numéroté s'ils sont plusieurs ---
  const equipe = [];
  let id = 1;
  for (const groupe of ["effectifsCuisine", "effectifsSalle"]) {
    for (const [poste, n] of Object.entries(p[groupe] || {})) {
      for (let k = 0; k < n; k++) {
        equipe.push({
          id: id++,
          nom: n > 1 ? `${poste} ${k + 1}` : poste,
          poste,
          tauxH: PP_TAUX[poste] || 12.0,
        });
      }
    }
  }

  // --- Fournisseurs : une ligne saisie = une fiche fournisseur ---
  const fournisseurs = (p.fournisseurs || "").split("\n").map(s => s.trim()).filter(Boolean)
    .map((nom, i) => ({ id: i + 1, nom, type: "À préciser", tel: "", delai: `J+${p.delaiLivraison || 1}`, note: 0, commandes: 0 }));

  // --- Plan de salle : tables de 4 couverts réparties sur une grille ---
  const nbTables = Math.max(1, Math.ceil((p.couverts || 0) / 4));
  const tables = Array.from({ length: nbTables }, (_, i) => ({
    num: i + 1, places: 4,
    x: 8 + (i % 5) * 21,
    y: 12 + Math.floor(i / 5) * 24,
    statut: "libre",
  }));

  return { equipe, fournisseurs, tables };
}

function ModuleParametrage({ profil, appliquer }) {
  const [enregistre, setEnregistre] = useState(false);
  return (
    <div>
      {enregistre && (
        <div style={{ maxWidth: 720, margin: "0 auto 12px", padding: "10px 14px", borderRadius: 10, background: "#F0F4EC", color: C.vert, fontWeight: 700, fontSize: 13, fontFamily: "Inter, system-ui, sans-serif" }}>
          Paramétrage enregistré — Ti-Chef et vos modules en tiennent compte.
        </div>
      )}
      <ParametrageInitial
        profilExistant={profil}
        onValider={(p) => { appliquer(p); setEnregistre(true); }}
        onAnnuler={null}
      />
    </div>
  );
}

EXTENSIONS.find(e => e.id === "parametrage").composant = ModuleParametrage;

function ChefAI() {
  const [onglet, setOnglet] = useState("accueil");
  const [actives, setActives] = useState(["parametrage", "dashboard", "fiches", "cuisine", "foodcost", "stocks", "carte", "caisse", "zanalyse", "haccp", "fournisseurs", "resa", "ia"]);
  // ---- ÉTAT CENTRAL DE L'ÉTABLISSEMENT (partagé entre toutes les extensions) ----
  const [stocks, setStocks] = useState(STOCKS_INIT);
  const [releves, setReleves] = useState(RELEVES_INIT);
  const [planning, setPlanning] = useState(planningInitial);
  const [menu, setMenu] = useState({ selection: [6, 1, 16], titre: "Menu du jour", prix: "24" });
  const [carteExclus, setCarteExclus] = useState([]);
  const [ventes, setVentes] = useState([]);
  const [operateur, setOperateur] = useState(null); // opérateur de paiement connecté (id)
  const [rapportsZ, setRapportsZ] = useState(Z_HISTORIQUE_INIT);
  const [factures, setFactures] = useState([]);
  const [reservations, setReservations] = useState(RESERVATIONS_INIT);
  const [ordreInitial, setOrdreInitial] = useState(null);
  const [profil, setProfil] = useState(null);
  const appliquerProfil = (p) => {
    const base = pp_construireBase(p);
    EQUIPE = base.equipe;
    FOURNISSEURS = base.fournisseurs;
    setTables(base.tables);
    setPlanning(planningInitial());
    setProfil(p);
  };
  const [persistance, setPersistance] = useState("chargement"); // "chargement" | "ok" | "indispo"
  const sauvegardeRef = useRef(null);

  // ---- CHARGEMENT au démarrage ----
  useEffect(() => {
    (async () => {
      if (!window.storage) { setPersistance("indispo"); return; }
      try {
        const res = await window.storage.get(cleEtat());
        if (res?.value) {
          const e = JSON.parse(res.value);
          if (Array.isArray(e.fiches) && e.fiches.length) FICHES = e.fiches;
          if (e.stocks) setStocks(e.stocks);
          if (e.releves) setReleves(e.releves);
          if (e.planning) setPlanning(e.planning);
          if (e.menu) setMenu(e.menu);
          if (e.tables) setTables(e.tables);
          if (e.commandes) setCommandes(e.commandes);
          if (e.mep) setMep(e.mep);
          if (e.precommandes) setPrecommandes(e.precommandes);
          if (e.carteExclus) setCarteExclus(e.carteExclus);
          if (e.ventes) setVentes(e.ventes);
          if (e.operateur !== undefined) setOperateur(e.operateur);
          if (e.rapportsZ) setRapportsZ(e.rapportsZ);
          if (e.factures) setFactures(e.factures);
          if (e.reservations) setReservations(e.reservations);
          if (e.actives) setActives(e.actives);
          if (e.profil) {
            setProfil(e.profil);
            const base = pp_construireBase(e.profil);
            EQUIPE = base.equipe;
            FOURNISSEURS = base.fournisseurs;
          }
        }
        setPersistance("ok");
      } catch {
        // Pas d'état local pour ce restaurant : on hydrate depuis D1 si un compte est connecté
        const restoId = localStorage.getItem(MP_RESTO);
        if (restoId && localStorage.getItem(MP_TOKEN)) {
          try {
            const distant = await chargerRestoDistant(restoId);
            if (distant && distant.fiches.length) {
              FICHES = distant.fiches;
              setStocks([]); setReleves([]); setCommandes([]); setMep({});
              setPrecommandes([]); setVentes([]); setRapportsZ([]); setFactures([]);
              setReservations([]); setCarteExclus([]);
              setMenu({ selection: [], titre: "Menu du jour", prix: "" });
            }
          } catch { /* hors-ligne : on démarre sur les données de démo */ }
        }
        setPersistance("ok");
      }
    })();
  }, []);

  // ---- SAUVEGARDE automatique (debounce 1,2s) ----
  useEffect(() => {
    if (persistance !== "ok" || !window.storage) return;
    clearTimeout(sauvegardeRef.current);
    sauvegardeRef.current = setTimeout(async () => {
      try {
        await window.storage.set(cleEtat(), JSON.stringify({
          fiches: FICHES, stocks, releves, planning, menu, tables, commandes, mep,
          precommandes, carteExclus, ventes, operateur, rapportsZ, factures, reservations, actives, profil,
        }));
      } catch { /* sauvegarde silencieusement différée */ }
    }, 1200);
    return () => clearTimeout(sauvegardeRef.current);
  });
  const enregistrerVente = (v) => setVentes(prev => [...prev, {
    ...v, id: Date.now() + Math.random(),
    heure: new Date().toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" }),
    // Référence de l'enregistrement fiscal chez l'opérateur (renvoyée par son API)
    refOperateur: operateur ? `${operateur.toUpperCase()}-${String(Math.floor(100000 + Math.random() * 900000))}` : null,
  }]);
  const [tables, setTables] = useState(TABLES_INIT);
  const [commandes, setCommandes] = useState([]);
  // Mise en place : { ficheId: { valide, dispo, deductions, prodLe } }
  const [mep, setMep] = useState({
    // Productions de démo encore au frigo (DLC à surveiller)
    5: { valide: true, dispo: 4, deductions: [], prodLe: Date.now() - 2 * 86400000 },
    16: { valide: true, dispo: 6, deductions: [], prodLe: Date.now() - 3 * 86400000 },
  });
  const [precommandes, setPrecommandes] = useState([]);
  const [, setVersionFiches] = useState(0);
  const ajouterFiche = (fiche) => { FICHES = [...FICHES, fiche]; setVersionFiches(v => v + 1); };
  const supprimerFiche = (id) => {
    FICHES = FICHES.filter(f => f.id !== id);
    setMep(prev => { const nv = { ...prev }; delete nv[id]; return nv; });
    setMenu(prev => ({ ...prev, selection: prev.selection.filter(s => s !== id) }));
    setVersionFiches(v => v + 1);
  };

  const toggle = (id) => {
    if (actives.includes(id)) {
      setActives(actives.filter(a => a !== id));
      if (onglet === id) setOnglet("boutique");
    } else {
      setActives([...actives, id]);
    }
  };

  const extensionsActives = EXTENSIONS.filter(e => actives.includes(e.id) && !e.aVenir);
  const onglets = [
    { id: "accueil", label: "Accueil", icone: "⌂" },
    ...extensionsActives.map(e => ({ id: e.id, label: e.label, icone: e.icone })),
    { id: "boutique", label: "Extensions", icone: "+" },
  ];
  const naviguerVers = (id) => {
    if (id === "accueil" || id === "boutique") { setOnglet(id); return; }
    if (!actives.includes(id) && EXTENSIONS.some(e => e.id === id)) setActives(a => [...a, id]);
    setOnglet(id);
  };
  const propsParModule = {
    dashboard: { goTo: naviguerVers, releves, mep, stocks, rapportsZ, reservations, ventes },
    cuisine: { mep, setMep, stocks, setStocks, goTo: naviguerVers },
    foodcost: { ventes, factures, rapportsZ },
    fiches: { supprimerFiche, mep, setMep, stocks, setStocks, goTo: naviguerVers, majFiches: () => setVersionFiches(v => v + 1) },
    haccp: { releves, setReleves, mep, setMep },
    fournisseurs: { stocks, setStocks, precommandes, setPrecommandes, factures, setFactures },
    ia: { profil, stocks, setStocks, releves, setReleves, planning, setPlanning, menu, setMenu, tables, setTables, commandes, setCommandes, mep, setMep, precommandes, setPrecommandes, ventes, rapportsZ, factures, reservations, setReservations, naviguer: naviguerVers, ajouterFiche, ordreInitial, consommerOrdre: () => setOrdreInitial(null) },
    parametrage: { profil, appliquer: appliquerProfil },
    stocks: { stocks, setStocks },
    planning: { planning, setPlanning },
    service: { tables, setTables, commandes, setCommandes, mep, setMep, enregistrerVente, reservations },
    caisse: { ventes, enregistrerVente, mep, setMep, operateur, setOperateur },
    zanalyse: { rapportsZ, setRapportsZ, ventes },
    resa: { reservations, setReservations, tables, setTables },
    carte: {
      selection: menu.selection, setSelection: (s) => setMenu({ ...menu, selection: s }),
      titreMenu: menu.titre, setTitreMenu: (t) => setMenu({ ...menu, titre: t }),
      prixMenu: menu.prix, setPrixMenu: (p) => setMenu({ ...menu, prix: p }),
      carteExclus, setCarteExclus, majFiches: () => setVersionFiches(v => v + 1), profil,
    },
  };
  const [restoActif, setRestoActif] = useState(null);
  const extCourante = extensionsActives.find(e => e.id === onglet);
  const ExtCourante = extCourante?.composant;

  // Instance vierge : rien à afficher tant que l'établissement n'est pas paramétré
  if (persistance !== "chargement" && !profil) {
    return <ParametrageInitial profilExistant={null} onValider={appliquerProfil} onAnnuler={null} />;
  }

  return (
    <div style={{ minHeight: "100vh", background: `linear-gradient(180deg, ${C.creme} 0%, #F3ECDB 100%)`, fontFamily: "Inter, system-ui, sans-serif", color: C.brun }}>
      <style>{`
        @import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600;9..144,700&family=Inter:wght@400;500;600;700&display=swap');
        * { -webkit-font-smoothing: antialiased; box-sizing: border-box; }
        button { transition: transform .12s ease, filter .12s ease, box-shadow .12s ease; }
        button:hover:not(:disabled) { filter: brightness(1.07); }
        button:active:not(:disabled) { transform: scale(0.97); }
        input, select { transition: border-color .15s ease, box-shadow .15s ease; }
        input:focus, select:focus { outline: none; border-color: ${"#C8962A"} !important; box-shadow: 0 0 0 3px rgba(200,150,42,0.18); }
        ::-webkit-scrollbar { width: 8px; height: 8px; }
        ::-webkit-scrollbar-track { background: transparent; }
        ::-webkit-scrollbar-thumb { background: rgba(200,150,42,0.4); border-radius: 4px; }
        ::-webkit-scrollbar-thumb:hover { background: rgba(200,150,42,0.6); }
      `}</style>
      {/* Header */}
      <div style={{ background: `linear-gradient(120deg, ${C.brun} 0%, #4F3A22 70%, #5A431F 100%)`, padding: "15px 22px", display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: `3px solid ${C.or}`, boxShadow: "0 2px 14px rgba(53,39,24,0.25)" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <img src="/logo-header.png" alt="Mepli" onError={e => { e.currentTarget.outerHTML = '<div style="width:40px;height:40px;border-radius:12px;border:2px solid #C8962A;display:flex;align-items:center;justify-content:center;font-family:Fraunces,Georgia,serif;font-size:20px;color:#C8962A">⌘</div>'; }} style={{ width: 40, height: 40, borderRadius: 12, boxShadow: "0 2px 8px rgba(0,0,0,0.3)", display: "block" }} />
          <div>
            <div style={{ fontFamily: "Fraunces, Georgia, serif", fontSize: 20, fontWeight: 700, color: C.creme, letterSpacing: 1 }}>Mepli <span style={{ color: C.or }}>Pro</span></div>
            <div style={{ fontSize: 10, color: C.orClair, textTransform: "uppercase", letterSpacing: 2 }}>Le système d'exploitation de votre restaurant</div>
          </div>
        </div>
        <SelecteurResto onChange={(r) => setRestoActif(r)} />
      </div>
      {/* Nav dynamique */}
      <div style={{ display: "flex", gap: 5, padding: "10px 16px", background: "rgba(255,254,250,0.95)", backdropFilter: "blur(8px)", borderBottom: "1px solid rgba(200,150,42,0.25)", overflowX: "auto", position: "sticky", top: 0, zIndex: 50 }}>
        {onglets.map(o => (
          <button key={o.id} onClick={() => setOnglet(o.id)} style={{
            background: onglet === o.id ? C.or : "transparent",
            color: onglet === o.id ? C.blanc : C.brun,
            border: o.id === "boutique" ? `1.5px dashed ${C.or}` : "none",
            borderRadius: 20, padding: "8px 16px",
            fontSize: 13, fontWeight: 700, cursor: "pointer", whiteSpace: "nowrap",
            fontFamily: "Inter, system-ui, sans-serif",
          }}>{o.icone} {o.label}</button>
        ))}
      </div>
      {/* Contenu */}
      <div style={{ padding: 18, maxWidth: 1100, margin: "0 auto" }}>
        {onglet === "accueil" && <Accueil profil={profil} extensions={extensionsActives} releves={releves} commandes={commandes} stocks={stocks} reservations={reservations} mep={mep} aller={naviguerVers} lancerOrdre={(o) => { setOrdreInitial(o); naviguerVers("ia"); }} />}
        {onglet === "boutique" && <Boutique actives={actives} toggle={toggle} />}
        {ExtCourante && <ExtCourante {...propsParModule[extCourante.id]} />}
      </div>
      <div style={{ textAlign: "center", padding: 14, fontSize: 11, color: C.brunMoyen, fontFamily: "Fraunces, Georgia, serif", fontStyle: "italic" }}>
        Mepli Pro · {restoActif ? restoActif.nom : "aucun restaurant sélectionné"} · Architecture modulaire
        {persistance === "ok" && <span style={{ marginLeft: 8, color: C.vert }}>● données sauvegardées</span>}
        {persistance === "indispo" && <span style={{ marginLeft: 8 }}>○ session sans sauvegarde</span>}
        <div style={{ marginTop: 8 }}>
          <button onClick={() => naviguerVers("parametrage")} style={{ background: "none", border: `1px solid rgba(200,150,42,0.5)`, borderRadius: 14, padding: "5px 14px", fontSize: 11, color: C.brunMoyen, cursor: "pointer", fontFamily: "Inter, system-ui, sans-serif" }}>
            ⚙ Réglages de l'établissement
          </button>
        </div>
      </div>
    </div>
  );
}


ReactDOM.createRoot(document.getElementById("root")).render(<ChefAI />);
