// FOOTPASS Messenger v2 · Coffre-fort · intérieur (design validé au labo coffre-lab)
// Rendu SOUS l'arrivée (coffre-arrivee-v2) : compteurs · onglets Tous/À traiter/Accès/Expirés ·
// puces catégories · dossiers par entité (vues, zéro stockage) · droits par personne et par document.
// Modèle & atomes : coffre-lab-model.jsx (CFI, CF_CATS, CF_DOCS_INIT, CfPill, …).
const { useState: useStateCV2, useEffect: useEffectCV2, useMemo: useMemoCV2 } = React;

// ── Feuille document : entité + catégorie + droits par personne ──
function CfV2DocSheet({ doc, onClose, onGrant, onRefuse, onToggleRight, onRevoke, onAddAccess, onSign, onOpenDoc, onShare, onBack, toast }) {
  const [arm, setArm] = useStateCV2(null);
  const [adding, setAdding] = useStateCV2(false);
  const [aq, setAq] = useStateCV2('');
  const cat = CF_CATS[doc.cat] || CF_CATS.jur;
  return (
    <div className="cf-sheetwrap">
      <button className="cf-dim" onClick={onClose} aria-label="Fermer"></button>
      <div className="cf-sheet">
        <span className="cf-grab"></span>
        <div className="cf-sh-head">
          {onBack ? <button className="cf3-shback" onClick={onBack} aria-label="Retour"><CFI.Chevron s={13} /></button> : null}
          <CfDocIcon cat={doc.cat} size={42} />
          <span className="cf-sh-t">
            <b className={doc.title.length > 24 ? 'cf3-tfit' : ''}>{doc.title}</b>
            <em>{cat.label} · {cfEntLabel(doc.ent)}</em>
          </span>
          <CfPill state={doc.state} />
        </div>

        <div className="cf-info">
          <div className="cf-irow"><span>Dossier</span><b>{cfEntLabel(doc.ent)}</b></div>
          <div className="cf-irow"><span>Catégorie</span><b style={{ color: cfCatColor(doc.cat) }}>{cat.label}</b></div>
          {doc.tags && doc.tags.length ? <div className="cf-irow"><span>Tags</span><b>{doc.tags.join(' · ')}</b></div> : null}
          <div className="cf-irow"><span>État</span><b>{doc.meta}</b></div>
          <div className="cf-irow"><span>Empreinte</span><b className="mono">{doc.hash}</b></div>
          <div className="cf-irow"><span>Propriété</span><b className="cf3-owner"><FPAvatar size={18} initials={FP_ME.initials || 'AD'} src={FP_ME.photo} />{window.fpUpperLast(FP_ME.name || 'Alexandre Da Costa')}</b></div>
        </div>

        <div className="cf-sechead" style={{ marginTop: 16 }}><span>Accès à ce document</span></div>
        <div className="cf-acclist">
          {doc.access.map((a) => {
            const p = FP_PEERS[a.pid];
            if (!p) return null;
            return (
              <div key={a.pid} className="cf-accrow">
                <div className="cf-acc-id">
                  <FPAvatar size={30} initials={p.initials} src={p.photo} />
                  <span className="cf-acc-txt"><b>{cfName(a.pid)}</b><em>{p.role}{p.org ? ' · ' + p.org : ''}</em></span>
                  <button className={`cf-revoke ${arm === a.pid ? 'arm' : ''}`} onClick={() => (arm === a.pid ? onRevoke(doc.id, a.pid) : setArm(a.pid))}>
                    {arm === a.pid ? 'Confirmer ?' : 'Révoquer'}
                  </button>
                </div>
                <div className="cf-rights" aria-label={'Droits de ' + cfName(a.pid)}>
                  {CF_RIGHTS.map((r) => {
                    const on = a.rights.includes(r.k);
                    return (
                      <button key={r.k} aria-pressed={on} className={`cf-right ${on ? 'on' : ''}`} onClick={() => onToggleRight(doc.id, a.pid, r.k)}>
                        <r.Icon s={14} />
                        {r.label}
                      </button>
                    );
                  })}
                </div>
              </div>
            );
          })}

          {doc.request ? (
            <div className="cf-req">
              <div className="cf-acc-id">
                <span className="cf-doc-ic" style={{ width: 30, height: 30 }}><CFI.Med s={14} /></span>
                <span className="cf-acc-txt"><b>{doc.request.org} · demande d’accès</b><em>{doc.request.ask}</em></span>
              </div>
              <div className="cf-req-acts">
                <button className="cf-req-ok" onClick={() => onGrant(doc.id)}>Autoriser 30 jours</button>
                <button className="cf-req-no" onClick={() => onRefuse(doc.id)}>Refuser</button>
              </div>
            </div>
          ) : null}

          {onAddAccess ? (adding ? (
            <div className="cf2-addlist">
              <label className="cf-search" style={{ margin: 0, height: 38 }}>
                <CFI.Search s={13} />
                <input value={aq} onChange={(e) => setAq(e.target.value)} placeholder="Rechercher un contact…" autoFocus />
                {aq ? <button onClick={() => setAq('')} aria-label="Effacer">×</button> : null}
              </label>
              <div className="cf3-erows scroll">
                {(() => {
                  const naq = cfDeacc(aq.trim());
                  const base = Object.keys(FP_PEERS).filter((pid) => !doc.access.some((a) => a.pid === pid));
                  const list = naq
                    ? base.filter((pid) => { const p = FP_PEERS[pid]; return cfDeacc(p.name + ' ' + (p.role || '') + ' ' + (p.org || '')).includes(naq); }).slice(0, 8)
                    : base.filter((pid) => (window.FP_CONVOS || []).some((c) => c.id === pid));
                  if (!list.length) return <div className="cf2-empty">Aucun contact ne correspond.</div>;
                  return list.map((pid) => {
                    const p = FP_PEERS[pid];
                    return (
                      <button key={pid} className="cf2-prow" onClick={() => { onAddAccess(doc.id, pid); setAdding(false); setAq(''); }}>
                        <FPAvatar size={26} initials={p.initials} src={p.photo} />
                        <span className="cf2-prow-t"><b>{cfName(pid)}</b><em>{p.role}{p.org ? ' · ' + p.org : ''}</em></span>
                        <span className="cf3-echeck"><CFI.Check s={10} /></span>
                      </button>
                    );
                  });
                })()}
              </div>
              <button className="cf2-addcancel" onClick={() => { setAdding(false); setAq(''); }}>Annuler</button>
            </div>
          ) : (
            <button className="cf2-addrow" onClick={() => setAdding(true)}>
              <i><CFI.Plus s={13} /></i> Autoriser un contact
              <em>Il apparaît d’abord, puis vous accordez ses droits.</em>
            </button>
          )) : null}
        </div>
        <p className="cf-accnote cf3-center cf3-lines"><span>Ce document n’appartient qu’à <b>vous</b>.</span><span>Rien ne s’ouvre, rien ne circule, sans votre accord.</span></p>

        <div className="cf-sh-acts">
          {doc.state === 'sign' && onSign ? (
            <button className="cf-btn primary sm" onClick={() => onSign(doc.id)}><CFI.Pen s={14} /> Signer le document</button>
          ) : (
            <button className="cf-btn primary sm" onClick={() => (onOpenDoc ? onOpenDoc(doc.id) : toast('Déchiffré localement · document ouvert'))}><CFI.Eye s={14} /> Ouvrir le document</button>
          )}
          <div className={`cf3-actgrid ${doc.state === 'sign' && onSign ? 'three' : ''}`}>
            <button onClick={() => toast('Export filigrané « A. Da Costa » · prêt')}><CFI.Wm s={13} /> Exporter</button>
            <button onClick={() => (onShare ? onShare(doc.id) : toast('Invitation d’accès envoyée · révocable'))}><CFI.Share s={12} /> Partager</button>
            {doc.state === 'sign' && onSign ? <button onClick={() => (onOpenDoc ? onOpenDoc(doc.id) : toast('Déchiffré localement · document ouvert'))}><CFI.Eye s={13} /> Ouvrir</button> : null}
          </div>
        </div>
        <p className="cf-wmnote">Tout export porte empreinte, propriété et filigrane.</p>
      </div>
    </div>
  );
}

// ── Feuille personne : tous ses accès, groupés par catégorie ──
function CfV2PersonSheet({ pid, docs, onClose, onOpenDoc, onRemoveAll, toast }) {
  const [arm, setArm] = useStateCV2(false);
  const p = FP_PEERS[pid];
  const mine = docs.filter((d) => d.access.some((a) => a.pid === pid));
  const byCat = Object.keys(CF_CATS).map((k) => [k, mine.filter((d) => d.cat === k)]).filter(([, l]) => l.length);
  return (
    <div className="cf-sheetwrap">
      <button className="cf-dim" onClick={onClose} aria-label="Fermer"></button>
      <div className="cf-sheet">
        <span className="cf-grab"></span>
        <div className="cf-sh-head">
          <FPAvatar size={42} initials={p.initials} src={p.photo} />
          <span className="cf-sh-t">
            <b>{cfName(pid)}</b>
            <em>{p.role}{p.org ? ' · ' + p.org : ''} · {mine.length} document{mine.length > 1 ? 's' : ''}</em>
          </span>
        </div>

        {byCat.map(([k, list]) => (
          <div key={k} className="cf2-pgrp">
            <div className="cf2-pgrp-h"><i style={{ background: cfCatColor(k) }}></i>{CF_CATS[k].label}</div>
            {list.map((d) => {
              const a = d.access.find((x) => x.pid === pid);
              return (
                <button key={d.id} className="cf2-prow doc" onClick={() => onOpenDoc(d.id)}>
                  <span className="cf2-prow-t"><b>{d.title}</b><em>{cfEntLabel(d.ent)}</em></span>
                  <CfRightsIcons rights={a.rights} />
                  <CFI.Chevron s={11} dir="r" />
                </button>
              );
            })}
          </div>
        ))}

        <p className="cf-accnote">Les droits se règlent <b>document par document</b>, touchez-en un. Révocation à effet immédiat, consignée au journal.</p>
        <div className="cf-sh-acts">
          <button className={`cf-btn ${arm ? 'danger' : ''}`} onClick={() => { if (arm) { onRemoveAll(pid); } else setArm(true); }}><CFI.Ban s={13} /> {arm ? 'Confirmer · tout retirer ?' : 'Retirer tous les accès'}</button>
          <button className="cf-btn" onClick={() => toast('Journal · ' + cfName(pid) + ' · démo')}><CFI.Journal s={14} /> Historique</button>
        </div>
      </div>
    </div>
  );
}

// ── Intérieur du coffre v2 (déverrouillé · l'arrivée gère le verrou par-dessus) ──
function CoffreV2({ onBack, onLock, dark }) {
  const [docs, setDocs] = useStateCV2(CF_DOCS_INIT);
  const [sel, setSel] = useStateCV2(null);
  const [selP, setSelP] = useStateCV2(null);
  const [tab, setTab] = useStateCV2('tous');
  const [fam, setFam] = useStateCV2(null);
  const [ent, setEnt] = useStateCV2(null);
  const [q, setQ] = useStateCV2('');
  const [showStats, setShowStats] = useStateCV2(true);
  const [showSearch, setShowSearch] = useStateCV2(false);
  const [soonV, setSoonV] = useStateCV2(false);
  const [toastMsg, setToastMsg] = useStateCV2(null);
  const toast = (m) => { setToastMsg(m); clearTimeout(toast._t); toast._t = setTimeout(() => setToastMsg(null), 2100); };

  const toggleRight = (docId, pid, k) => {
    setDocs(docs.map((d) => d.id !== docId ? d : { ...d, access: d.access.map((a) => a.pid !== pid ? a : { ...a, rights: a.rights.includes(k) ? a.rights.filter((r) => r !== k) : [...a.rights, k] }) }));
    const d = docs.find((x) => x.id === docId); const a = d.access.find((x) => x.pid === pid);
    const on = !a.rights.includes(k); const lbl = (CF_RIGHTS.find((r) => r.k === k) || {}).label;
    toast(cfName(pid) + ' · ' + lbl + (on ? ' accordé' : ' retiré') + ' · effet immédiat');
  };
  const revoke = (docId, pid) => {
    setDocs(docs.map((d) => d.id !== docId ? d : { ...d, access: d.access.filter((a) => a.pid !== pid) }));
    toast('Accès de ' + cfName(pid) + ' révoqué · effet immédiat');
  };
  const removeAll = (pid) => {
    setDocs(docs.map((d) => ({ ...d, access: d.access.filter((a) => a.pid !== pid) })));
    setSelP(null);
    toast('Tous les accès de ' + cfName(pid) + ' retirés · consigné au journal');
  };
  const grant = (docId) => {
    setDocs(docs.map((d) => d.id !== docId ? d : { ...d, request: null, meta: d.meta + ' · AS Monaco 30 j', access: [...d.access, { pid: 'karim', rights: ['view'] }] }));
    toast('AS Monaco · lecture 30 jours · filigranée');
  };
  const refuse = (docId) => {
    setDocs(docs.map((d) => d.id !== docId ? d : { ...d, request: null }));
    toast('Demande refusée · AS Monaco notifié');
  };

  const selDoc = sel ? docs.find((d) => d.id === sel) : null;
  const expired = docs.filter((d) => d.state === 'expired');
  const alive = docs.filter((d) => d.state !== 'expired');
  const todo = docs.filter((d) => d.state === 'sign' || d.state === 'review' || d.request);
  const soonDocs = docs.filter((d) => d.soon);
  const people = useMemoCV2(() => {
    const m = {};
    docs.forEach((d) => d.access.forEach((a) => { (m[a.pid] = m[a.pid] || { n: 0, rights: new Set() }).n++; a.rights.forEach((r) => m[a.pid].rights.add(r)); }));
    return Object.keys(m).map((pid) => ({ pid, n: m[pid].n, rights: [...m[pid].rights] }));
  }, [docs]);

  const nq = cfDeacc(q.trim());
  const byFam = (list) => fam ? list.filter((d) => d.cat === fam) : list;
  const byEnt = (list) => ent ? list.filter((d) => d.ent === ent) : list;
  const results = nq ? docs.filter((d) => cfDeacc(d.title + ' ' + d.meta + ' ' + CF_CATS[d.cat].label + ' ' + cfEntLabel(d.ent)).includes(nq)) : null;

  const docCard = (d) => (
    <button key={d.id} className="cf-doc" onClick={() => setSel(d.id)}>
      <CfDocIcon cat={d.cat} />
      <span className="cf-doc-txt">
        <b>{d.title}</b>
        <em>{d.soon ? <span className="cf2-soon">Expire dans {d.soon} j</span> : null}{d.soon ? ' · ' : ''}{d.meta}</em>
      </span>
      <span className="cf-doc-side">
        <CfPill state={d.state} />
        <CfPrivacy access={d.access} />
      </span>
    </button>
  );

  const activity = (scope) => {
    const list = CF_ACTIVITY.filter((a) => !scope || a.ent === scope);
    if (!list.length) return null;
    return (
      <React.Fragment>
        <div className="cf-sechead" style={{ marginTop: 18 }}><span>Activité récente</span></div>
        <div className="cf2-acts">
          {list.map((a, i) => (
            <div key={i} className="cf2-act">
              <FPAvatar size={22} initials={a.who === 'me' ? (FP_ME.initials || 'AD') : FP_PEERS[a.who].initials} src={a.who === 'me' ? FP_ME.photo : FP_PEERS[a.who].photo} />
              <span><b>{a.who === 'me' ? 'Vous' : cfName(a.who)}</b> {a.txt}</span>
              <em>{a.when}</em>
            </div>
          ))}
        </div>
      </React.Fragment>
    );
  };

  const todoRows = () => todo.map((d) => {
    const kind = d.state === 'sign' ? 'sign' : d.state === 'review' ? 'review' : 'request';
    return (
      <button key={d.id} className={`cf-todorow ${kind}`} onClick={() => setSel(d.id)}>
        <i>{kind === 'sign' ? <CFI.Pen s={15} /> : kind === 'review' ? <CFI.Eye s={15} /> : <CFI.Share s={14} />}</i>
        <span className="cf-todo-txt">
          <b>{kind === 'request' ? d.request.org + ' demande un accès' : d.title}</b>
          <em>{kind === 'sign' ? 'Votre signature est attendue' : kind === 'review' ? 'Sira Keïta relit · vous serez notifié' : d.title}</em>
        </span>
        <span className="cf-todo-act">{kind === 'sign' ? 'Signer' : kind === 'request' ? 'Répondre' : 'Voir'} <CFI.Chevron s={11} dir="r" /></span>
      </button>
    );
  });

  return (
    <div className={`cf ${dark ? 'dark' : 'light'}`} data-screen-label="Coffre-fort">
      <FPStatusBar light={dark} />
      <div className="cf-head">
        <button className="cf-back" onClick={onBack} aria-label="Retour"><CFI.Chevron /></button>
        <h1 className="cf-h1">Coffre-fort</h1>
        <button className={`cf-hbtn ${showStats ? 'on' : ''}`} aria-label="Résumé" aria-pressed={showStats} onClick={() => setShowStats(!showStats)}><CFI.Stats /></button>
        <button className={`cf-hbtn ${showSearch ? 'on' : ''}`} aria-label="Rechercher" aria-pressed={showSearch} onClick={() => { setShowSearch(!showSearch); if (showSearch) setQ(''); }}><CFI.Search /></button>
        <button className="cf-hbtn" aria-label="Importer" onClick={() => toast('Import · démo')}><CFI.Plus /></button>
        <button className="cf-hbtn" aria-label="Verrouiller" onClick={onLock}><CFI.Lock s={15} /></button>
      </div>

      <div className="cf-scroll">
        <div className="cf-reveal">
          {showStats ? (
            <div className="cf2-stats">
              <button className="cf2-stat ok" onClick={() => { setTab('tous'); setEnt(null); setFam(null); setSoonV(false); }}><b>{alive.length}</b><span>Documents protégés</span></button>
              <button className="cf2-stat warn" onClick={() => { setTab('atraiter'); setSoonV(false); }}><b>{todo.length}</b><span>À traiter</span></button>
              <button className={`cf2-stat warn ${soonV ? 'on' : ''}`} aria-pressed={soonV} onClick={() => setSoonV(!soonV)}><b>{soonDocs.length}</b><span>{soonDocs.length > 1 ? 'Expirent bientôt' : 'Expire bientôt'}</span></button>
            </div>
          ) : null}

          {showSearch ? (
            <label className="cf-search">
              <CFI.Search s={14} />
              <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Document, entité, catégorie…" autoFocus />
              {q ? <button onClick={() => setQ('')} aria-label="Effacer">×</button> : null}
            </label>
          ) : null}

          {results ? (
            <React.Fragment>
              <div className="cf-sechead"><span>Résultats · {results.length}</span></div>
              <div className="cf-list">{results.map(docCard)}{!results.length ? <div className="cf2-empty">Aucun document ne correspond.</div> : null}</div>
            </React.Fragment>
          ) : soonV ? (
            <React.Fragment>
              <div className="cf2-token"><b>Expirent bientôt</b><button onClick={() => setSoonV(false)} aria-label="Fermer">×</button></div>
              <div className="cf-list">{soonDocs.map(docCard)}</div>
              <p className="cf-accnote">Échéances réelles des documents · aucun rappel artificiel.</p>
            </React.Fragment>
          ) : (
            <React.Fragment>
              <div className="cf2-tabs">
                {[['tous', 'Tous', 0], ['atraiter', 'À traiter', todo.length], ['acces', 'Accès', people.length], ['expires', 'Expirés', expired.length]].map(([id, lb, n]) => (
                  <button key={id} className={`cf2-tab ${tab === id ? 'on' : ''}`} onClick={() => { setTab(id); if (id === 'tous') { setEnt(null); setFam(null); } }}>{lb}{n ? <i>{n}</i> : null}</button>
                ))}
              </div>
              {(tab === 'tous' || tab === 'expires') ? (
                <div className="cf2-fams">
                  {Object.keys(CF_CATS).map((k) => (
                    <button key={k} className={`cf2-fam ${fam === k ? 'on' : ''}`} onClick={() => setFam(fam === k ? null : k)}>
                      <i style={{ background: cfCatColor(k) }}></i>{CF_CATS[k].label}
                    </button>
                  ))}
                </div>
              ) : null}

              {tab === 'tous' && !ent ? (
                <React.Fragment>
                  {CF_ENT_ORDER.map((k) => {
                    const list = byFam(alive.filter((d) => d.ent === k));
                    if (!list.length) return null;
                    const p = k === 'me' ? null : FP_PEERS[k];
                    return (
                      <React.Fragment key={k}>
                        <button className="cf2-group" onClick={() => setEnt(k)}>
                          {p ? <FPAvatar size={26} initials={p.initials} src={p.photo} /> : <span className="cf2-orgav">{(FP_ME.initials || 'AD')}</span>}
                          <b>{cfEntLabel(k)}</b>
                          <em>{cfEntSub(k)}</em>
                          <span className="cf2-gn">{list.length}</span>
                          <CFI.Chevron s={11} dir="r" />
                        </button>
                        <div className="cf-list">{list.map(docCard)}</div>
                      </React.Fragment>
                    );
                  })}
                  {activity(null)}
                  <div className="cf-foot"><FPIcon.Shield s={11} c="currentColor" /> Les dossiers ne stockent rien · chaque document existe une seule fois.</div>
                </React.Fragment>
              ) : null}

              {tab === 'tous' && ent ? (
                <React.Fragment>
                  <div className="cf2-token">
                    <b>Dossier · {cfEntLabel(ent)}</b>
                    <button onClick={() => setEnt(null)} aria-label="Fermer le dossier">×</button>
                  </div>
                  {byFam(byEnt(alive)).some((d) => d.soon) ? (
                    <button className="cf2-alert" onClick={() => setSel(byEnt(alive).find((d) => d.soon).id)}>
                      <b>Échéance</b> {byEnt(alive).find((d) => d.soon).title} · expire dans {byEnt(alive).find((d) => d.soon).soon} j
                    </button>
                  ) : null}
                  <div className="cf-list">{byFam(byEnt(alive)).map(docCard)}{!byFam(byEnt(alive)).length ? <div className="cf2-empty">Rien dans cette catégorie pour ce dossier.</div> : null}</div>
                  {activity(ent)}
                </React.Fragment>
              ) : null}

              {tab === 'atraiter' ? (
                <React.Fragment>
                  <div className="cf2-list-pad">{todoRows()}</div>
                  {soonDocs.length ? (
                    <React.Fragment>
                      <div className="cf-sechead" style={{ marginTop: 14 }}><span>Échéances · {soonDocs.length}</span></div>
                      <div className="cf-list">{soonDocs.map(docCard)}</div>
                    </React.Fragment>
                  ) : null}
                  <div className="cf-sechead" style={{ marginTop: 14 }}><span>Traitées · {CF_PROCESSED.length}</span></div>
                  <div className="cf2-done">
                    {CF_PROCESSED.map((x) => (
                      <div key={x.id} className="cf2-donerow">
                        <i className={x.okd ? 'ok' : 'no'}>{x.okd ? <CFI.Check s={11} /> : <CFI.Ban s={11} />}</i>
                        <span><b>{x.txt}</b><em>{x.sub}</em></span>
                      </div>
                    ))}
                  </div>
                </React.Fragment>
              ) : null}

              {tab === 'acces' ? (
                <React.Fragment>
                  <p className="cf2-hint">Qui peut ouvrir quoi · par personne, révocable en un geste.</p>
                  <div className="cf2-list-pad">
                    {people.map(({ pid, n, rights }) => {
                      const p = FP_PEERS[pid];
                      return (
                        <button key={pid} className="cf2-prow" onClick={() => setSelP(pid)}>
                          <FPAvatar size={32} initials={p.initials} src={p.photo} />
                          <span className="cf2-prow-t"><b>{cfName(pid)}</b><em>{p.role}{p.org ? ' · ' + p.org : ''} · {n} document{n > 1 ? 's' : ''}</em></span>
                          <CfRightsIcons rights={rights} />
                          <CFI.Chevron s={11} dir="r" />
                        </button>
                      );
                    })}
                  </div>
                  <p className="cf-accnote">Les <b>autorisations de représentation</b> vivent dans Autorisations · ici, uniquement l’accès aux documents.</p>
                </React.Fragment>
              ) : null}

              {tab === 'expires' ? (
                <React.Fragment>
                  <div className="cf-list">{byFam(expired).map(docCard)}{!byFam(expired).length ? <div className="cf2-empty">Aucun document expiré.</div> : null}</div>
                  <p className="cf-accnote">Conservés chiffrés pour votre historique · rien n’est supprimé sans vous.</p>
                </React.Fragment>
              ) : null}
            </React.Fragment>
          )}
        </div>
      </div>

      {selDoc ? (
        <CfV2DocSheet doc={selDoc} onClose={() => setSel(null)} toast={toast}
          onToggleRight={toggleRight} onRevoke={revoke} onGrant={grant} onRefuse={refuse} />
      ) : null}
      {selP && !selDoc ? (
        <CfV2PersonSheet pid={selP} docs={docs} onClose={() => setSelP(null)} toast={toast}
          onOpenDoc={(id) => { setSel(id); }} onRemoveAll={removeAll} />
      ) : null}
      {toastMsg ? <div className="cf-toast">{toastMsg}</div> : null}
    </div>
  );
}

Object.assign(window, { CoffreV2, CfV2DocSheet, CfV2PersonSheet });
