// Dashboard — Carte : carte pro (visuel partagé CardVisual.jsx), verrouillage
// instantané réversible, réglages sans contact / en ligne / étranger, plafonds
// modifiables (jauges donut), opérations carte avec états (pré-autorisé → réglé |
// refusé), PIN à appui maintenu, opposition → carte de remplacement.
// États démo : normal | loading | empty | error (rigueur « 3 états »).
// Données : ui_kits/shared/carte.js. window.OryzeDash.CarteView
(function () {
  const { Card, Amount, Tag, Button, StatusBadge, Dialog, Avatar, Tabs, StatTile, IconButton, Toggle, ProgressRing, Input, Skeleton, EmptyState } = window.OryzeDesignSystem_78c60a;
  const Ic = window.OryzeIcons;

  const lbl = { fontFamily: "var(--font-mono)", fontSize: 10.5, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--text-muted)" };

  const CARTE = window.OryzeCarte.card;
  const OPERATIONS = window.OryzeCarte.operations;
  const STATUT_CARTE = window.OryzeCarte.statutCarte;
  const CardVisual = window.OryzeShared.CardVisual;
  const { NewCardFlow, PinChangeFlow, ClosureVerify, DeliveryInfoPanel } = window.OryzeShared;

  function SettingRow({ icon, label, sub, checked, onChange, disabled, first }) {
    return (
      <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 18px", borderTop: first ? "none" : "1px solid var(--line-divider)", opacity: disabled ? 0.45 : 1 }}>
        <span style={{ width: 32, height: 32, borderRadius: 8, background: "var(--surface-sunken)", border: "var(--border-hair) solid var(--line-divider)", display: "inline-flex", alignItems: "center", justifyContent: "center", flex: "none", color: "var(--text-body)" }}>{icon}</span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13.5, fontWeight: 600 }}>{label}</div>
          <div style={{ fontSize: 11.5, color: "var(--text-subtle)", marginTop: 1 }}>{sub}</div>
        </div>
        <Toggle checked={checked} onChange={onChange} disabled={disabled} />
      </div>
    );
  }

  function OperationRow({ op, onOpen }) {
    const [h, setH] = React.useState(false);
    return (
      <div onClick={onOpen} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
        style={{ display: "flex", alignItems: "center", gap: 12, padding: "11px 18px", borderBottom: "1px solid var(--line-divider)", cursor: "pointer", background: h ? "var(--surface-page)" : "transparent", transition: "background var(--dur-fast) var(--ease-out)" }}>
        <Avatar initials={op.init} tone={op.tone} size={32} />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13.5, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{op.label}</div>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: op.status === "failed" ? "var(--fin-negative)" : "var(--text-subtle)", marginTop: 2 }}>
            {op.date} · {op.cat}{op.note ? " · " + op.note : ""}
          </div>
        </div>
        <Amount cents={op.cents} size="sm" tone={op.status === "failed" ? "muted" : "default"} />
        <StatusBadge size="sm" status={op.status} label={op.status === "failed" ? "Refusé" : op.status === "pending" ? "Pré-autorisé" : "Réglé"} />
        <Ic.chevronRight size={16} style={{ color: "var(--text-subtle)", flex: "none" }} />
      </div>
    );
  }

  function LimitRow({ title, spentCents, limitCents, period, first }) {
    const pct = Math.min(100, Math.round((spentCents / limitCents) * 100));
    return (
      <div style={{ display: "flex", alignItems: "center", gap: 14, padding: "13px 18px", borderTop: first ? "none" : "1px solid var(--line-divider)" }}>
        <ProgressRing value={pct} size={52} thickness={7} label={<span style={{ fontFamily: "var(--font-mono)", fontSize: 11, fontWeight: 700 }}>{pct}%</span>} />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13.5, fontWeight: 600 }}>{title}</div>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 11.5, color: "var(--text-subtle)", marginTop: 3 }}>
            {(spentCents / 100).toLocaleString("fr-FR", { minimumFractionDigits: 2 })} € / {(limitCents / 100).toLocaleString("fr-FR", { minimumFractionDigits: 0 })} € · {period}
          </div>
        </div>
      </div>
    );
  }

  function CarteView({ demoState = "normal" }) {
    const [statut, setStatut] = React.useState("active"); // active | locked | opposed
    const [prefs, setPrefs] = React.useState({ nfc: true, online: true, abroad: false });
    const [revealed, setRevealed] = React.useState(false);
    const [tab, setTab] = React.useState("all");
    const [limits, setLimits] = React.useState(window.OryzeCarte.limitsDefault); // centimes
    const [modal, setModal] = React.useState(null); // {type:'pin'|'oppo'|'limits'|'op', op?}
    const [retrying, setRetrying] = React.useState(false);

    const opposed = statut === "opposed";
    const paiements = OPERATIONS.filter((o) => o.type === "paiement" && o.status === "executed");
    const spentPay = -paiements.reduce((a, o) => a + o.cents, 0);
    const spentCash = -OPERATIONS.filter((o) => o.type === "retrait" && o.status === "executed").reduce((a, o) => a + o.cents, 0);
    const failed = OPERATIONS.filter((o) => o.status === "failed");
    const list = OPERATIONS.filter((o) =>
      tab === "all" ? true : tab === "failed" ? o.status === "failed" : o.type === tab && o.status !== "failed");
    const st = STATUT_CARTE[statut];

    // ---- États démo : chargement / vide / erreur (patterns guidelines/states.html) ----
    if (demoState === "empty") {
      return (
        <EmptyState framed title="Aucune carte pour l'instant"
          description="Commandez votre carte pro : verrouillage réversible, plafonds modifiables et réglages instantanés dès l'activation."
          action={<Button size="sm" iconLeft={<Ic.card size={15} />}>Commander une carte</Button>} />
      );
    }
    if (demoState === "loading") {
      return (
        <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
          <div style={{ display: "grid", gridTemplateColumns: "1.5fr 1fr", gap: 16, alignItems: "stretch" }}>
            <Card variant="hero" padding="22px">
              <div style={{ display: "flex", gap: 24, flexWrap: "wrap" }}>
                <Skeleton variant="block" width={300} height={190} style={{ borderRadius: 16, flex: "none" }} />
                <div style={{ flex: 1, minWidth: 210, display: "flex", flexDirection: "column", gap: 14 }}>
                  <Skeleton variant="text" lines={4} />
                  <div style={{ display: "flex", gap: 8 }}>
                    <Skeleton variant="block" width={132} height={34} />
                    <Skeleton variant="block" width={104} height={34} />
                  </div>
                </div>
              </div>
            </Card>
            <Card variant="flat" padding="18px">
              <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
                {[0, 1, 2, 3].map((i) => (
                  <div key={i} style={{ display: "flex", alignItems: "center", gap: 12 }}>
                    <Skeleton variant="circle" size={32} />
                    <Skeleton variant="text" lines={1} style={{ flex: 1 }} />
                    <Skeleton variant="block" width={40} height={22} style={{ borderRadius: 999 }} />
                  </div>
                ))}
              </div>
            </Card>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(3,1fr)", gap: 16 }}>
            {[0, 1, 2].map((i) => <Skeleton key={i} variant="block" height={92} />)}
          </div>
          <Skeleton variant="block" height={220} />
        </div>
      );
    }
    if (demoState === "error") {
      return (
        <Card variant="flat" padding="44px 24px" style={{ textAlign: "center" }}>
          <div style={{ width: 44, height: 44, margin: "0 auto 14px", display: "flex", alignItems: "center", justifyContent: "center", background: "var(--oryze-coral)", border: "var(--border-key) solid var(--line-keyline)", borderRadius: "var(--radius-md)", color: "var(--oryze-coral-ink)" }}>
            <Ic.alert size={22} />
          </div>
          <div style={{ fontWeight: 700, fontSize: 17, letterSpacing: "-0.01em" }}>Impossible de charger votre carte</div>
          <div style={{ fontSize: 13.5, color: "var(--text-muted)", marginTop: 5 }}>Vos données sont en sécurité — c'est un problème de connexion, pas de contenu.</div>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--text-subtle)", marginTop: 7 }}>GET /carte · 503 · réf. c7e2-…</div>
          <Button variant="secondary" size="sm" loading={retrying} style={{ marginTop: 16 }}
            onClick={() => { setRetrying(true); setTimeout(() => setRetrying(false), 1400); }}>Réessayer</Button>
        </Card>
      );
    }

    const detail = (k, v) => (
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 12, padding: "7px 0", borderBottom: "1px solid var(--line-divider)" }}>
        <span style={{ fontSize: 13, color: "var(--text-muted)", whiteSpace: "nowrap" }}>{k}</span>
        <span style={{ fontSize: 13, fontWeight: 600, textAlign: "right", minWidth: 0 }}>{v}</span>
      </div>
    );

    return (
      <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
        {/* Carte héros + réglages */}
        <div style={{ display: "grid", gridTemplateColumns: "1.5fr 1fr", gap: 16, alignItems: "stretch" }}>
          <Card variant="hero" padding="22px" style={{ minWidth: 0 }}>
            <div style={{ display: "flex", gap: 24, flexWrap: "wrap" }}>
              <CardVisual statut={statut} revealed={revealed && !opposed} />
              <div style={{ flex: 1, minWidth: 210, display: "flex", flexDirection: "column" }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 10 }}>
                  <span style={lbl}>Carte pro · physique</span>
                  <StatusBadge size="sm" status={st.status} label={st.label} />
                </div>
                <div style={{ marginTop: 10 }}>
                  {detail("Numéro", <span style={{ fontFamily: "var(--font-mono)", fontSize: 12.5 }}>{revealed && !opposed ? CARTE.full : CARTE.masked}</span>)}
                  {detail("CVV", <span style={{ fontFamily: "var(--font-mono)", fontSize: 12.5 }}>{revealed && !opposed ? CARTE.cvv : "•••"}</span>)}
                  {detail("Expiration", <span style={{ fontFamily: "var(--font-mono)", fontSize: 12.5 }}>{CARTE.exp}</span>)}
                  {detail("Débit", "Immédiat")}
                </div>
                <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginTop: 14 }}>
                  <Button size="sm" variant="secondary" disabled={opposed} iconLeft={revealed ? <Ic.eyeOff size={15} /> : <Ic.eye size={15} />} onClick={() => setRevealed((r) => !r)}>
                    {revealed ? "Masquer" : "Voir le numéro"}
                  </Button>
                  <Button size="sm" variant="ghost" disabled={opposed} iconLeft={<Ic.lock size={15} />} onClick={() => setModal({ type: "pin" })}>Code PIN</Button>
                  <Button size="sm" variant="ghost" iconLeft={<Ic.plus size={15} />} onClick={() => setModal({ type: "new" })}>Nouvelle carte</Button>
                </div>
                {statut === "locked" && (
                  <div style={{ marginTop: 12, fontSize: 12, fontWeight: 600, color: "var(--oryze-butter-ink)", background: "var(--oryze-butter)", border: "var(--border-thin) solid var(--line-keyline)", borderRadius: "var(--radius-md)", padding: "8px 12px" }}>
                    Carte verrouillée — tout paiement sera refusé jusqu'au déverrouillage.
                  </div>
                )}
                {opposed && (
                  <div style={{ marginTop: 12, fontSize: 12, fontWeight: 600, color: "var(--oryze-coral-ink)", background: "var(--oryze-coral)", border: "var(--border-thin) solid var(--line-keyline)", borderRadius: "var(--radius-md)", padding: "8px 12px" }}>
                    Opposition enregistrée — carte définitivement désactivée. Une carte de remplacement est en préparation.
                  </div>
                )}
              </div>
            </div>
          </Card>

          <Card variant="flat" padding="0" style={{ minWidth: 0 }}>
            <div style={{ padding: "14px 18px 10px" }}>
              <div style={{ fontWeight: 700, fontSize: 15 }}>Réglages</div>
              <div style={{ fontSize: 11.5, color: "var(--text-subtle)", marginTop: 2 }}>Prise en compte immédiate.</div>
            </div>
            <SettingRow first icon={<Ic.lock size={16} />} label="Verrouiller la carte" sub="Blocage instantané, réversible"
              checked={statut === "locked"} disabled={opposed} onChange={(v) => setStatut(v ? "locked" : "active")} />
            <SettingRow icon={<Ic.contactless size={16} />} label="Sans contact" sub="Paiements NFC en magasin"
              checked={prefs.nfc} disabled={opposed} onChange={(v) => setPrefs((p) => ({ ...p, nfc: v }))} />
            <SettingRow icon={<Ic.bag size={16} />} label="Paiements en ligne" sub="E-commerce · 3-D Secure actif"
              checked={prefs.online} disabled={opposed} onChange={(v) => setPrefs((p) => ({ ...p, online: v }))} />
            <SettingRow icon={<Ic.globe size={16} />} label="Paiements à l'étranger" sub="Hors zone euro"
              checked={prefs.abroad} disabled={opposed} onChange={(v) => setPrefs((p) => ({ ...p, abroad: v }))} />
          </Card>
        </div>

        {/* KPIs du mois */}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3,1fr)", gap: 16 }}>
          <StatTile label="Paiements carte · avril" value={<Amount cents={-spentPay} size="lg" />} hint={paiements.length + " paiements · 1 pré-autorisation"} />
          <StatTile label="Plafond 30 j restant" value={<Amount cents={limits.pay - spentPay} size="lg" />} accent="var(--oryze-mint)" hint={"sur " + (limits.pay / 100).toLocaleString("fr-FR") + " € de paiements"} />
          <StatTile label="Refusés · 30 j" value={<span style={{ fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: 26 }}>{failed.length}</span>} accent="var(--oryze-coral)" hint="3-D Secure expiré — aucun débit" />
        </div>

        {/* Opérations + colonne droite */}
        <div style={{ display: "grid", gridTemplateColumns: "1.6fr 1fr", gap: 16, alignItems: "start" }}>
          <Card variant="flat" padding="0" style={{ minWidth: 0 }}>
            <div style={{ display: "flex", flexWrap: "wrap", alignItems: "center", justifyContent: "space-between", gap: "6px 12px", padding: "12px 18px", borderBottom: "1.5px solid var(--line-keyline)" }}>
              <div style={{ fontWeight: 700, fontSize: 15, minWidth: 0 }}>Opérations</div>
              <Tabs value={tab} onChange={setTab} tabs={[
                { value: "all", label: "Toutes" },
                { value: "paiement", label: "Paiements" },
                { value: "retrait", label: "Retraits" },
                { value: "failed", label: "Refusées", count: failed.length }]} />
            </div>
            {list.map((op) => (
              <OperationRow key={op.id} op={op} onOpen={() => setModal({ type: "op", op })} />
            ))}
            {list.length === 0 && (
              <div style={{ padding: "36px", textAlign: "center", color: "var(--text-muted)", fontSize: 13.5 }}>Aucune opération dans cet état.</div>
            )}
          </Card>

          <div style={{ display: "flex", flexDirection: "column", gap: 16, minWidth: 0 }}>
            <Card variant="flat" padding="0" style={{ minWidth: 0 }}>
              <div style={{ display: "flex", flexWrap: "wrap", alignItems: "center", justifyContent: "space-between", gap: "6px 12px", padding: "14px 18px", borderBottom: "1.5px solid var(--line-keyline)" }}>
                <div style={{ fontWeight: 700, fontSize: 15, minWidth: 0 }}>Plafonds</div>
                <Button size="sm" variant="ghost" onClick={() => setModal({ type: "limits" })}>Modifier</Button>
              </div>
              <LimitRow first title="Paiements · 30 jours" spentCents={spentPay} limitCents={limits.pay} period="glissants" />
              <LimitRow title="Retraits · 7 jours" spentCents={spentCash} limitCents={limits.cash} period="glissants" />
            </Card>

            <Card variant="flat" padding="0" style={{ minWidth: 0 }}>
              <div style={{ padding: "14px 18px", borderBottom: "1.5px solid var(--line-keyline)", fontWeight: 700, fontSize: 15 }}>Sécurité</div>
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, padding: "12px 18px", borderBottom: "1px solid var(--line-divider)" }}>
                <div>
                  <div style={{ fontSize: 13.5, fontWeight: 600 }}>3-D Secure</div>
                  <div style={{ fontSize: 11.5, color: "var(--text-subtle)", marginTop: 1 }}>Confirmation forte pour l'e-commerce</div>
                </div>
                <Tag tone="paid" dot>Actif</Tag>
              </div>
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, padding: "12px 18px" }}>
                <div>
                  <div style={{ fontSize: 13.5, fontWeight: 600 }}>Perte ou vol</div>
                  <div style={{ fontSize: 11.5, color: "var(--text-subtle)", marginTop: 1 }}>Opposition immédiate et définitive</div>
                </div>
                {opposed
                  ? <StatusBadge size="sm" status="rejected" label="Opposée" />
                  : <Button size="sm" variant="secondary" iconLeft={<Ic.shield size={14} />} onClick={() => setModal({ type: "oppo" })}>Faire opposition</Button>}
              </div>
            </Card>

            {opposed && (
              <Card variant="flat" padding="16px 18px" style={{ minWidth: 0 }}>
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10 }}>
                  <div style={{ fontWeight: 700, fontSize: 15 }}>Carte de remplacement</div>
                  <StatusBadge size="sm" status="pending" label="En préparation" />
                </div>
                <div style={{ fontFamily: "var(--font-mono)", fontSize: 11.5, color: "var(--text-subtle)", marginTop: 6 }}>•••• 5310 · expédition sous 5 j ouvrés</div>
                <div style={{ fontSize: 12.5, color: "var(--text-body)", marginTop: 8, lineHeight: 1.5 }}>
                  Vos plafonds et réglages seront repris à l'activation. Rien à faire de votre côté.
                </div>
                <Button size="sm" variant="secondary" iconLeft={<Ic.send size={14} />} style={{ marginTop: 12 }} onClick={() => setModal({ type: "delivery" })}>Suivi de livraison</Button>
              </Card>
            )}
          </div>
        </div>

        <PinDialog open={modal && modal.type === "pin"} onClose={() => setModal(null)} onChangePin={() => setModal({ type: "pinchange" })} />
        <OppositionDialog open={modal && modal.type === "oppo"} onClose={() => setModal(null)} onConfirm={() => { setStatut("opposed"); setRevealed(false); }} />
        <LimitsDialog open={modal && modal.type === "limits"} limits={limits} onClose={() => setModal(null)} onSave={(l) => { setLimits(l); setModal(null); }} />
        <OperationDialog modal={modal} onClose={() => setModal(null)} />

        {/* Nouvelle carte — finition + livraison + frais */}
        <Dialog open={modal && modal.type === "new"} onClose={() => setModal(null)} width={430}
          title="Nouvelle carte" subtitle="Carte physique — mode démo, aucune commande réelle">
          {modal && modal.type === "new" && <NewCardFlow onCancel={() => setModal(null)} onDone={() => setModal(null)} />}
        </Dialog>

        {/* Changement de PIN — vérification → nouveau → confirmation */}
        <Dialog open={modal && modal.type === "pinchange"} onClose={() => setModal(null)} width={420}
          title="Changer le PIN" subtitle="Carte •••• 4827">
          {modal && modal.type === "pinchange" && <PinChangeFlow onClose={() => setModal(null)} />}
        </Dialog>

        {/* Suivi de livraison — carte de remplacement */}
        <Dialog open={modal && modal.type === "delivery"} onClose={() => setModal(null)} width={440}
          title="Suivi de livraison" subtitle="Mode démo — expédition fictive">
          {modal && modal.type === "delivery" && <DeliveryInfoPanel />}
        </Dialog>
      </div>
    );
  }

  // ---- Code PIN — révélé à l'appui maintenu ----
  function PinDialog({ open, onClose, onChangePin }) {
    const [held, setHeld] = React.useState(false);
    React.useEffect(() => { if (open) setHeld(false); }, [open]);
    return (
      <Dialog open={!!open} onClose={onClose} width={360} title="Code PIN" subtitle="Carte •••• 4827">
        {open && (
          <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 14, padding: "8px 0 4px", textAlign: "center" }}>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 32, fontWeight: 600, letterSpacing: "0.35em", padding: "14px 22px 14px calc(22px + 0.35em)", background: "var(--surface-sunken)", border: "var(--border-thin) solid var(--line-keyline)", borderRadius: "var(--radius-md)" }}>
              {held ? "4921" : "••••"}
            </div>
            <div style={{ display: "flex", flexWrap: "wrap", justifyContent: "center", gap: 8, maxWidth: "100%" }}>
              <Button size="sm" variant="secondary"
                onPointerDown={() => setHeld(true)} onPointerUp={() => setHeld(false)} onPointerLeave={() => setHeld(false)}
                iconLeft={<Ic.eye size={15} />}>Maintenir pour afficher</Button>
              <Button size="sm" variant="ghost" onClick={() => onChangePin && onChangePin()}>Changer le PIN</Button>
            </div>
            <div style={{ fontSize: 11.5, color: "var(--text-subtle)", lineHeight: 1.5, maxWidth: 260 }}>
              Ne le communiquez jamais. On ne vous le demandera jamais — ni par téléphone, ni par e-mail.
            </div>
          </div>
        )}
      </Dialog>
    );
  }

  // ---- Opposition — définitive, vérifiée par code, remplacement automatique ----
  function OppositionDialog({ open, onClose, onConfirm }) {
    const [phase, setPhase] = React.useState("edit"); // edit | verify | done
    React.useEffect(() => { if (open) setPhase("edit"); }, [open]);
    return (
      <Dialog open={!!open} onClose={onClose} width={440} title="Perte ou vol"
        subtitle={phase === "done" ? "Mode démo — carte fictive" : phase === "verify" ? "Vérification — étape 2/2" : "Opposition immédiate et définitive"}>
        {open && (phase === "done" ? (
          <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 12, padding: "14px 0 6px", textAlign: "center" }}>
            <StatusBadge status="rejected" label="Opposée" />
            <div style={{ fontWeight: 700, fontSize: 18, letterSpacing: "-0.02em" }}>Carte opposée</div>
            <div style={{ fontSize: 13, color: "var(--text-body)", lineHeight: 1.55, maxWidth: 330 }}>
              La carte <span style={{ fontFamily: "var(--font-mono)" }}>•••• 4827</span> est désactivée. Une carte de remplacement
              <span style={{ fontFamily: "var(--font-mono)" }}> •••• 5310</span> arrive sous 5 j ouvrés — plafonds et réglages repris à l'activation.
            </div>
            <Button size="sm" variant="secondary" onClick={onClose} style={{ marginTop: 4 }}>Fermer</Button>
          </div>
        ) : phase === "verify" ? (
          <ClosureVerify onCancel={onClose} onVerified={() => { onConfirm(); setPhase("done"); }} />
        ) : (
          <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
            <div style={{ fontSize: 13.5, color: "var(--text-body)", lineHeight: 1.55 }}>
              L'opposition désactive définitivement la carte <span style={{ fontFamily: "var(--font-mono)" }}>•••• 4827</span> :
              paiements, retraits et abonnements seront refusés. Une carte de remplacement est expédiée automatiquement.
            </div>
            <div style={{ fontSize: 12, fontWeight: 600, color: "var(--oryze-butter-ink)", background: "var(--oryze-butter)", border: "var(--border-thin) solid var(--line-keyline)", borderRadius: "var(--radius-md)", padding: "9px 12px", lineHeight: 1.5 }}>
              Simple doute ? Verrouillez plutôt la carte — c'est réversible à tout moment.
            </div>
            <div style={{ display: "flex", gap: 10, justifyContent: "space-between", paddingTop: 2 }}>
              <Button variant="ghost" size="md" onClick={onClose}>Annuler</Button>
              <Button size="md" iconLeft={<Ic.shield size={15} />} onClick={() => setPhase("verify")}>Faire opposition</Button>
            </div>
          </div>
        ))}
      </Dialog>
    );
  }

  // ---- Plafonds — édition (démo) ----
  function LimitsDialog({ open, limits, onClose, onSave }) {
    const [pay, setPay] = React.useState("3 000");
    const [cash, setCash] = React.useState("500");
    const [error, setError] = React.useState(null);
    React.useEffect(() => {
      if (open) { setPay((limits.pay / 100).toLocaleString("fr-FR")); setCash((limits.cash / 100).toLocaleString("fr-FR")); setError(null); }
    }, [open]);
    const parse = (s) => Math.round((parseFloat(String(s).replace(/[\s\u202F]/g, "").replace(",", ".")) || 0) * 100);
    function save() {
      const p = parse(pay), c = parse(cash);
      if (p < 10000 || p > 1000000) { setError("Plafond paiements : entre 100 € et 10 000 €."); return; }
      if (c < 5000 || c > 200000) { setError("Plafond retraits : entre 50 € et 2 000 €."); return; }
      onSave({ pay: p, cash: c });
    }
    return (
      <Dialog open={!!open} onClose={onClose} width={400} title="Modifier les plafonds" subtitle="Prise en compte immédiate — mode démo">
        {open && (
          <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
            <Input label="Paiements · 30 jours glissants" value={pay} onChange={(e) => setPay(e.target.value)} mono suffix="€" />
            <Input label="Retraits · 7 jours glissants" value={cash} onChange={(e) => setCash(e.target.value)} mono suffix="€" />
            <div style={{ fontSize: 11.5, color: "var(--text-subtle)", lineHeight: 1.5 }}>
              Au-delà de 10 000 € / 30 j, une vérification complémentaire est demandée.
            </div>
            {error && <div style={{ fontSize: 12.5, color: "var(--fin-negative)", fontWeight: 600 }}>{error}</div>}
            <div style={{ display: "flex", gap: 10, justifyContent: "space-between", paddingTop: 2 }}>
              <Button variant="ghost" size="md" onClick={onClose}>Annuler</Button>
              <Button size="md" iconLeft={<Ic.check size={15} />} onClick={save}>Enregistrer</Button>
            </div>
          </div>
        )}
      </Dialog>
    );
  }

  // ---- Détail d'une opération ----
  function OperationDialog({ modal, onClose }) {
    const open = modal && modal.type === "op";
    const op = open ? modal.op : null;
    const row = (k, v) => (
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 12 }}>
        <span style={{ fontSize: 13, color: "var(--text-muted)", whiteSpace: "nowrap" }}>{k}</span>
        <span style={{ fontSize: 13, fontWeight: 600, textAlign: "right", minWidth: 0 }}>{v}</span>
      </div>
    );
    return (
      <Dialog open={!!open} onClose={onClose} width={440} title={op ? op.label : ""} subtitle={op ? "Carte •••• 4827 · " + op.date : ""}>
        {op && (
          <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 }}>
              <Amount cents={op.cents} size="xl" tone={op.status === "failed" ? "muted" : "default"} />
              <StatusBadge status={op.status} label={op.status === "failed" ? "Refusé" : op.status === "pending" ? "Pré-autorisé" : "Réglé"} />
            </div>
            <div style={{ display: "flex", flexDirection: "column", gap: 8, padding: "13px 14px", background: "var(--surface-sunken)", border: "var(--border-hair) solid var(--line-divider)", borderRadius: "var(--radius-md)" }}>
              {row("Type", op.type === "retrait" ? "Retrait" : "Paiement carte")}
              {row("Catégorie", op.cat)}
              {row("Mode", op.type === "retrait" ? "Distributeur" : "Sans contact")}
              {op.note ? row(op.status === "failed" ? "Motif du refus" : "Note", op.note) : null}
            </div>
            {op.status === "pending" && (
              <div style={{ fontSize: 12, color: "var(--text-subtle)", lineHeight: 1.5 }}>
                Montant réservé par le commerçant — débité à la facturation, sous 7 jours en général.
              </div>
            )}
            <div style={{ display: "flex", gap: 10, justifyContent: "flex-end" }}>
              {op.status === "executed" && <Button variant="ghost" size="sm" iconLeft={<Ic.receipt size={14} />}>Joindre un justificatif</Button>}
              {op.status === "failed" && <Button variant="secondary" size="sm">Signaler un problème</Button>}
            </div>
          </div>
        )}
      </Dialog>
    );
  }

  window.OryzeDash = window.OryzeDash || {};
  window.OryzeDash.CarteView = CarteView;
})();
