// portal-theme.jsx — Direction C "Esprit joueur" : tokens + composants partagés.
const K = {
  bg: "#F5F4F1", ink: "#191613", sub: "#6F6A63", line: "#E4E1DB",
  card: "#FFFFFF", black: "#1A1A1A",
  pink: "#E5446D", orange: "#F08C2E", blue: "#2D9CDB",
  amber: "#945C06", amberBg: "#FCF0D7", amberLine: "#EFDDB0",
  green: "#1E7B40", greenBg: "#E5F3E8", greenLine: "#C4E0CC",
  red: "#B3361E", redBg: "#FBE9E4", redLine: "#F0CCC2",
  blueS: "#1D5FAE", blueBg: "#E8F1FA",
  teal: "#0E7A74", tealBg: "#E2F2F1",
  purple: "#6D4FA3", purpleBg: "#EFEAF8",
  gray: "#6F6A63", grayBg: "#EFEDE9",
  grad: "linear-gradient(90deg,#E5446D,#F08C2E)",
  font: "'Public Sans', sans-serif",
  round: "'Baloo 2', sans-serif",
  mono: "'IBM Plex Mono', monospace"
};

const portalCss = `
  html, body { margin: 0; background: ${K.bg}; }
  body { font-family: ${K.font}; color: ${K.ink}; font-size: 14px; line-height: 1.5; }
  * { box-sizing: border-box; }
  .k-round { font-family: ${K.round}; }
  .k-mono { font-family: ${K.mono}; }
  .k-card { background: ${K.card}; border: 1px solid ${K.line}; border-radius: 14px; box-shadow: 0 1px 2px rgba(25,22,19,0.04); }
  .k-btn { font-family: ${K.font}; font-size: 14px; font-weight: 700; border-radius: 99px; padding: 10px 20px; cursor: pointer; transition: transform .08s ease, box-shadow .12s ease, background .12s ease; display: inline-flex; align-items: center; gap: 7px; }
  .k-btn:active { transform: scale(0.97); }
  .k-btn:disabled { opacity: .45; cursor: not-allowed; }
  .k-btn-primary { background: ${K.black}; color: #FFF; border: none; }
  .k-btn-primary:hover:not(:disabled) { box-shadow: 0 3px 10px rgba(25,22,19,0.25); }
  .k-btn-ghost { background: transparent; color: ${K.ink}; border: 1.5px solid ${K.line}; }
  .k-btn-ghost:hover:not(:disabled) { border-color: ${K.ink}; }
  .k-btn-sm { font-size: 12.5px; padding: 6px 14px; }
  .k-link { color: ${K.blueS}; font-weight: 600; text-decoration: none; }
  .k-link:hover { text-decoration: underline; }
  .k-label { font-size: 11.5px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: ${K.sub}; }
  .k-input, .k-textarea { font-family: ${K.font}; font-size: 14px; color: ${K.ink}; background: #FFF; border: 1.5px solid ${K.line}; border-radius: 10px; padding: 9px 12px; outline: none; width: 100%; }
  .k-input:focus, .k-textarea:focus { border-color: ${K.black}; }
  .k-textarea { font-family: ${K.mono}; font-size: 12.5px; line-height: 1.55; resize: vertical; }
  .k-copy:hover { background: ${K.grayBg}; }
  @keyframes k-toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
  @keyframes k-modal-in { from { opacity: 0; transform: translateY(14px) scale(.98); } to { opacity: 1; transform: translateY(0) scale(1); } }
  @keyframes k-stamp-in { from { opacity: 0; transform: rotate(-8deg) scale(1.6); } to { opacity: .9; transform: rotate(-8deg) scale(1); } }
`;

function Pill({ fg, bg, children }) {
  return <span style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: "4px 12px", borderRadius: 99, fontSize: 12, fontWeight: 700, color: fg, background: bg, whiteSpace: "nowrap" }}>{children}</span>;
}

function SectionLabel({ children, style }) {
  return <div className="k-label" style={{ marginTop: 30, marginBottom: 4, ...style }}>{children}</div>;
}

function Banner({ tone = "amber", children, style }) {
  const tones = {
    amber: { color: K.amber, background: K.amberBg },
    red: { color: K.red, background: K.redBg },
    green: { color: K.green, background: K.greenBg },
    gray: { color: K.sub, background: K.grayBg }
  };
  return <div style={{ borderRadius: 10, padding: "10px 14px", fontSize: 13, fontWeight: 600, ...tones[tone], ...style }}>{children}</div>;
}

// Tampon "Approved" (repris de la direction B, plébiscité)
function Stamp({ children, animate }) {
  return (
    <div style={{
      display: "inline-block", transform: "rotate(-8deg)",
      border: `2.5px solid ${K.green}`, color: K.green, borderRadius: 8,
      padding: "5px 14px", fontSize: 12, fontWeight: 800, letterSpacing: ".08em",
      textTransform: "uppercase", opacity: 0.9, fontFamily: K.font,
      animation: animate ? "k-stamp-in .35s ease-out" : "none",
      maskImage: "radial-gradient(circle at 30% 60%, black 96%, transparent 97%)"
    }}>{children}</div>);

}

function Modal({ title, onClose, children, width = 460 }) {
  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, background: "rgba(25,22,19,0.45)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100, padding: 20 }}>
      <div onClick={(e) => e.stopPropagation()} style={{ background: "#FFF", borderRadius: 18, width, maxWidth: "100%", padding: "24px 26px", animation: "k-modal-in .22s ease-out", boxShadow: "0 20px 60px rgba(25,22,19,0.3)" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 12 }}>
          <div className="k-round" style={{ fontSize: 19, fontWeight: 700 }}>{title}</div>
          <button onClick={onClose} style={{ background: "none", border: "none", fontSize: 20, cursor: "pointer", color: K.sub, lineHeight: 1 }}>×</button>
        </div>
        {children}
      </div>
    </div>);

}

// Toasts
function useToasts() {
  const [toasts, setToasts] = React.useState([]);
  const push = (msg, tone = "ok") => {
    const id = Date.now() + Math.random();
    setToasts((t) => [...t, { id, msg, tone }]);
    setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 3200);
  };
  return [toasts, push];
}
function ToastHost({ toasts }) {
  return (
    <div style={{ position: "fixed", bottom: 18, left: "50%", transform: "translateX(-50%)", zIndex: 200, display: "flex", flexDirection: "column", gap: 8, alignItems: "center" }}>
      {toasts.map((t) =>
      <div key={t.id} style={{ background: t.tone === "err" ? K.red : K.black, color: "#FFF", borderRadius: 99, padding: "9px 18px", fontSize: 13, fontWeight: 600, animation: "k-toast-in .25s ease-out", boxShadow: "0 6px 20px rgba(25,22,19,0.3)" }}>
          {t.tone === "ok" ? "✓ " : t.tone === "err" ? "⚠ " : ""}{t.msg}
        </div>
      )}
    </div>);

}

// Bouton copier (presse-papiers)
function CopyBtn({ text, label = "Copy", style }) {
  const [copied, setCopied] = React.useState(false);
  return (
    <button className="k-copy" onClick={() => {
      navigator.clipboard && navigator.clipboard.writeText(text);
      setCopied(true);setTimeout(() => setCopied(false), 1600);
    }} style={{ background: "#FFF", border: `1.5px solid ${copied ? K.green : K.line}`, color: copied ? K.green : K.ink, borderRadius: 8, padding: "4px 10px", fontSize: 12, fontWeight: 700, cursor: "pointer", fontFamily: K.font, whiteSpace: "nowrap", ...style }}>
      {copied ? "✓ Copied" : "⧉ " + label}
    </button>);

}

// Bandeau noir d'en-tête (ADN logo) — logo agrandi (feedback)
function TopBar({ title, right }) {
  return (
    <div style={{ background: K.black, color: "#FFF", padding: "33px 36px", display: "flex", alignItems: "center", justifyContent: "space-between", borderRadius: "0 0 18px 18px", height: "130px", boxSizing: "border-box" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
        <img src="assets/kodama-logo-white.png" alt="KODAMA — Playful spirit" style={{ height: 64, width: "auto", objectFit: "contain" }} />
        <div className="k-round" style={{ fontWeight: 700, fontSize: "30px", margin: "30px" }}>{title}</div>
      </div>
      <div style={{ textAlign: "right" }}>{right}</div>
    </div>);

}

// ——— Couleur d'accent par jeu (déterministe, palette « esprit joueur ») ———
const GAME_COLORS = [
  { fg: "#B05A10", mid: "#F6BE76", soft: "#FCEBD9" }, // orange
  { fg: "#0E7A74", mid: "#7FD0CA", soft: "#DFF1F0" }, // teal
  { fg: "#C2375B", mid: "#F7A3BA", soft: "#FBE3EA" }, // rose
  { fg: "#6D4FA3", mid: "#C5B0E6", soft: "#EFEAF8" }, // violet
  { fg: "#1D5FAE", mid: "#96C3EE", soft: "#E8F1FA" }, // bleu
];
function gameColor(name) {
  let h = 0;
  String(name || "").split("").forEach((c) => { h = (h * 31 + c.charCodeAt(0)) >>> 0; });
  return GAME_COLORS[h % GAME_COLORS.length];
}

// ——— Liens externes : les URLs collées sans protocole (drive.google.com/…) deviennent
// des liens relatifs cassés — on normalise systématiquement. ———
function extUrl(u) {
  if (!u) return "";
  const s = String(u).trim();
  return /^[a-z][a-z0-9+.-]*:\/\//i.test(s) ? s : "https://" + s;
}
function ExtLink({ href, children, className = "k-link", style, title }) {
  return <a className={className} href={extUrl(href)} target="_blank" rel="noopener noreferrer" style={style} title={title}>{children}</a>;
}

// ——— États de production : helpers + couleurs partagés entre les trois vues ———
const STATE_COLORS = { ok: "#2E9E58", waiting: "#EFAE3F", changes: "#D4543A", done: "#D2CEC7" };
function prodState(p) {
  if (p.statut === "Terminé") return "done";
  if (p.mpcOk) return "ok";
  if (p.statut === "Modifications des fichiers") return "changes";
  return "waiting";
}
function stateCounts(prods) {
  const c = { ok: 0, waiting: 0, changes: 0, done: 0 };
  prods.forEach((p) => { c[prodState(p)]++; });
  return c;
}
// La validation exige une vidéo mais le lien n'est pas encore renseigné
function needsVideoLink(p) {
  return !p.mpcOk && !!p.validation && p.validation.includes("Vidéo") && !p.mpcVideoUrl && p.statut !== "Terminé";
}
// Le partenaire doit valider : pas encore validé, pas en modifs / production / transport,
// et le matériel est là (statut « Validation MPC », ou tracking / vidéo déjà renseignés)
const POST_APPROVAL_STATUTS = ["En production", "Packing List envoyée", "Transport en Cours", "Livraison partielle", "🧾 Finaliser facturation", "Terminé"];
function needsApproval(p) {
  if (p.mpcOk || POST_APPROVAL_STATUTS.includes(p.statut)) return false;
  // « Modifications des fichiers » avec commentaire = demande de modifs en cours → pas de validation ;
  // sans commentaire (statut hérité / interne), on laisse valider si le matériel est là
  if (p.statut === "Modifications des fichiers") return !p.comment && (!!p.mpcTracking || !!p.mpcVideoUrl);
  return p.statut === "Validation MPC" || !!p.mpcTracking || !!p.mpcVideoUrl;
}
// Barre segmentée : vert (validé) / ambre (en attente) / rouge (modifs) / gris (terminé)
function StateBar({ counts, height = 8, style }) {
  const total = counts.ok + counts.waiting + counts.changes + counts.done;
  const seg = (n, color, key) => n > 0 ? <div key={key} style={{ flex: n, background: color, minWidth: 4 }}></div> : null;
  return (
    <div style={{ display: "flex", height, borderRadius: 99, overflow: "hidden", background: K.grayBg, gap: total ? 2 : 0, ...style }}>
      {seg(counts.ok, STATE_COLORS.ok, "ok")}
      {seg(counts.waiting, STATE_COLORS.waiting, "wa")}
      {seg(counts.changes, STATE_COLORS.changes, "ch")}
      {seg(counts.done, STATE_COLORS.done, "dn")}
    </div>);

}
// Compteurs colorés assortis à la barre
function StateCounters({ counts, labels = {}, style }) {
  const item = (n, color, sym, lbl, key) => n > 0 ?
  <span key={key} style={{ color, fontWeight: 700, whiteSpace: "nowrap" }}>{sym ? sym + "\u00A0" : ""}{n}{lbl ? " " + lbl : ""}</span> : null;
  const items = [
  item(counts.ok, K.green, "✓", labels.ok, "ok"),
  item(counts.waiting, "#B07916", "⏳", labels.waiting, "wa"),
  item(counts.changes, K.red, "✎", labels.changes, "ch"),
  item(counts.done, K.sub, "", labels.done, "dn")].
  filter(Boolean);
  return <span style={{ display: "inline-flex", gap: 12, fontSize: 12.5, alignItems: "baseline", ...style }}>{items}</span>;
}

Object.assign(window, { K, portalCss, Pill, SectionLabel, Banner, Stamp, Modal, useToasts, ToastHost, CopyBtn, TopBar, STATE_COLORS, prodState, stateCounts, needsVideoLink, needsApproval, StateBar, StateCounters, GAME_COLORS, gameColor, extUrl, ExtLink });