import { useState, useEffect } from 'react';
import {
    Eye, ChevronDown, ChevronUp, Clock, CheckCircle, XCircle, History, FileText,
    AlertTriangle, Check, X, ShieldCheck, Paperclip, ListChecks, Receipt
} from 'lucide-react';

interface Fichier { fileName: string; uploadUrl: string; }
interface Participant { nom: string; prenom: string; societe?: string; }
interface TvaItem { taux: string; montantTTC: string; }
interface LigneDepense {
    qrNoteRef?: string; categorie?: string; libelle?: string;
    date?: string; montant?: string; km?: string; chevaux?: string;
    tauxTVA?: string; description?: string;
    nombreParticipants?: string; participants?: Participant[];
    tvaItems?: TvaItem[];
    qrFiles?: { fileName: string; uploadUrl: string; origin?: string }[];
}
interface NonConforme { fileName: string; motif: string; statut: string; dateSignalement: string; }
interface NoteAVerifier {
    id: number; reference?: string; libelle?: string; collaborateur?: string;
    campus?: string; departement?: string; date?: string; montant?: number;
    statut?: string; lignesJson?: string; fichiers?: string;
    nonConformes?: NonConforme[];
    lignesRefusees?: { index: number; motif: string }[];
}
interface ModalNok { noteId: number; ligneIndex: number; ligneLabel: string; }
interface VerifHistorique {
    id: number; reference?: string; libelle?: string; collaborateur?: string;
    campus?: string; departement?: string; montant?: number;
    dateVerification: string; commentaire?: string; statut?: 'VERIFIEE' | 'REFUSEE';
    nbLignes: number; nbLignesOk: number; nbLignesRefusees: number;
    lignesJson?: string; fichiers?: string;
    lignesRefusees?: { index: number; motif: string }[];
}
interface LigneState { status: 'ok' | 'refused' | 'pending'; motif?: string; }

const fmt = (n: number) => new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' }).format(n);
const fmtDate = (d?: string) => d ? new Date(d).toLocaleDateString('fr-FR') : '—';
const getIndemniteKm = (km: number, cv: number) => {
    const BAREME: Record<number, number> = { 3: 0.529, 4: 0.606, 5: 0.636, 6: 0.665, 7: 0.697 };
    return km * (BAREME[Math.min(Math.max(cv, 3), 7)] ?? 0.697);
};
const ligneKey = (noteId: number, idx: number) => `${noteId}-l${idx}`;
const SYSTEME_KEYWORDS = ['soumission', 'resoumission', 'recap-paiement', 'recap', 'signe-approuve', 'signeapprouve', 'signe_approuve'];
const isSystemFile = (f: Fichier) => SYSTEME_KEYWORDS.some(kw => (f.fileName ?? '').toLowerCase().includes(kw));
const isApprovalFile = (f: Fichier) => {
    const n = (f.fileName ?? '').toLowerCase();
    return (n.includes('signe') || n.includes('signé')) && (n.includes('approuve') || n.includes('approuvé'));
};
const getCatMeta = (cat?: string) => {
    const c = (cat || '').toLowerCase();
    if (c.includes('kilom')) return { color: '#7c3aed', bg: '#ede9fe', light: '#f5f3ff', emoji: '🚗', label: 'Kilométrique' };
    if (c.includes('repas') || c.includes('restaurant')) return { color: '#d97706', bg: '#fef3c7', light: '#fffbeb', emoji: '🍽️', label: 'Repas' };
    if (c.includes('transport') || c.includes('avion') || c.includes('train')) return { color: '#0369a1', bg: '#dbeafe', light: '#eff6ff', emoji: '🚆', label: 'Transport' };
    if (c.includes('hebergement') || c.includes('hotel')) return { color: '#059669', bg: '#dcfce7', light: '#f0fdf4', emoji: '🏨', label: 'Hébergement' };
    return { color: '#6366f1', bg: '#eef2ff', light: '#f5f3ff', emoji: '📋', label: 'Autre' };
};

// Group lines by category
const groupByCategory = (lignes: LigneDepense[]) => {
    const groups: Record<string, { cat: string; indices: number[]; total: number }> = {};
    lignes.forEach((l, i) => {
        const cat = l.categorie || 'Autre';
        if (!groups[cat]) groups[cat] = { cat, indices: [], total: 0 };
        groups[cat].indices.push(i);
        const isKm = cat.toLowerCase().includes('kilom');
        const km = parseFloat(l.km || '0') || 0;
        const cv = parseInt(l.chevaux || '7') || 7;
        groups[cat].total += isKm ? getIndemniteKm(km, cv) : (parseFloat(l.montant || '0') || 0);
    });
    return Object.values(groups);
};

interface Props {
    notesAVerifier: NoteAVerifier[];
    onVerified: (noteId: number) => void;
    API: string;
    hdrs: Record<string, string>;
    proxyUrl?: (url: string) => string;
    setPreviewUrl?: (v: { url: string; name: string }) => void;
}

const CSS = `
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@300;400;500;600;700&family=DM+Mono:wght@400;500&display=swap');
*{box-sizing:border-box;}
.vf-root{font-family:'DM Sans',system-ui,sans-serif;--accent:#5b21b6;--accent-bg:#ede9fe;--green:#15803d;--green-bg:#dcfce7;--red:#dc2626;--red-bg:#fee2e2;--amber:#d97706;--amber-bg:#fef3c7;--border:#e5e7eb;--border2:#f3f4f6;--muted:#6b7280;--text:#111827;--bg:#fff;--bg2:#f9fafb;--mono:'DM Mono',monospace;--panel-border:1px solid #e5e7eb;}

/* ── Tabs ── */
.vf-tabs{display:flex;gap:2px;background:#f3f4f6;border-radius:10px;padding:3px;margin-bottom:14px;}
.vf-tab{flex:1;padding:7px 12px;border:none;border-radius:8px;cursor:pointer;font-family:'DM Sans',sans-serif;font-size:12px;font-weight:600;background:transparent;color:var(--muted);display:flex;align-items:center;justify-content:center;gap:5px;transition:all .15s;}
.vf-tab.active{background:#fff;color:var(--accent);box-shadow:0 1px 3px rgba(0,0,0,.1);}
.vf-tab-badge{background:#ef4444;color:#fff;font-size:9px;font-weight:700;padding:1px 5px;border-radius:20px;}
.vf-tab.active .vf-tab-badge{background:var(--accent);}

/* ── Note card (collapsed) ── */
.vf-note{border:1px solid var(--border);border-radius:11px;overflow:hidden;margin-bottom:9px;background:var(--bg);}
.vf-note-trigger{width:100%;display:flex;align-items:stretch;background:none;border:none;cursor:pointer;padding:0;font-family:inherit;text-align:left;}
.vf-note-bar{width:4px;flex-shrink:0;background:var(--accent);}
.vf-note-hd{flex:1;padding:10px 14px;display:flex;align-items:center;justify-content:space-between;gap:10px;}
.vf-note-chev{padding:0 13px;display:flex;align-items:center;border-left:1px solid var(--border);color:var(--muted);}
.vf-ref{font-size:9px;font-weight:700;color:var(--accent);background:var(--accent-bg);padding:1px 7px;border-radius:20px;font-family:var(--mono);display:inline-block;margin-bottom:2px;}
.vf-note-title{font-size:13px;font-weight:700;color:var(--text);}
.vf-note-meta{font-size:10px;color:var(--muted);margin-top:1px;}
.vf-note-amt{font-size:17px;font-weight:800;color:var(--accent);font-family:var(--mono);}
.vf-note-sub{font-size:9px;color:var(--muted);text-align:right;}

/* ── Progress strip ── */
.vf-prog-strip{padding:4px 14px 6px;border-top:1px solid var(--border2);background:#f5f3ff;display:flex;align-items:center;gap:8px;}
.vf-prog-track{flex:1;height:3px;background:#e5e7eb;border-radius:99px;overflow:hidden;}
.vf-prog-fill{height:100%;border-radius:99px;transition:width .3s;}
.vf-pills{display:flex;gap:3px;flex-wrap:wrap;}
.vf-pill{font-size:9px;font-weight:700;padding:1px 6px;border-radius:20px;white-space:nowrap;}
.vf-pill-ok{background:var(--green-bg);color:var(--green);}
.vf-pill-nok{background:var(--red-bg);color:var(--red);}
.vf-pill-wait{background:#f3f4f6;color:var(--muted);}
.vf-pill-adj{background:var(--amber-bg);color:var(--amber);}

/* ── 5-panel grid ── */
.vf-4grid{display:grid;grid-template-columns:175px 155px 200px 1fr 205px;border-top:1px solid var(--border);min-height:520px;}
.vf-panel{border-right:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden;}
.vf-panel:last-child{border-right:none;}
.vf-panel-hd{padding:7px 10px;border-bottom:1px solid var(--border);background:var(--bg2);display:flex;align-items:center;gap:5px;flex-shrink:0;}
.vf-panel-label{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);}
.vf-panel-body{padding:8px;flex:1;display:flex;flex-direction:column;gap:6px;overflow-y:auto;}

/* ── Panel 3: compact ligne list ── */
.vf-lrow{display:flex;align-items:center;gap:6px;padding:6px 8px;border:1px solid var(--border);border-radius:6px;cursor:pointer;background:var(--bg);transition:all .12s;}
.vf-lrow:hover{border-color:#c4b5fd;background:#faf5ff;}
.vf-lrow.active{border-color:#7c3aed;background:#f5f3ff;box-shadow:0 0 0 2px rgba(124,58,237,.1);}
.vf-lrow.ok{border-color:#86efac;background:#f0fdf4;}
.vf-lrow.ok.active{border-color:#16a34a;box-shadow:0 0 0 2px rgba(22,163,74,.1);}
.vf-lrow.refused{border-color:#fca5a5;background:#fff5f5;}
.vf-lrow.refused.active{border-color:#dc2626;box-shadow:0 0 0 2px rgba(220,38,38,.1);}
.vf-lrow-num{width:20px;height:20px;border-radius:4px;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:800;flex-shrink:0;}
.vf-lrow-body{flex:1;min-width:0;}
.vf-lrow-name{font-size:10px;font-weight:700;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vf-lrow-meta{font-size:8px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vf-lrow-right{display:flex;flex-direction:column;align-items:flex-end;flex-shrink:0;gap:2px;}
.vf-lrow-price{font-size:10px;font-weight:800;font-family:var(--mono);}
.vf-lrow-arrow{font-size:9px;color:var(--muted);}

/* ── Panel 4: ligne detail ── */
.vf-detail-hd{display:flex;align-items:center;gap:8px;padding:10px 11px;border-bottom:1px solid var(--border);}
.vf-detail-num{width:28px;height:28px;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:800;flex-shrink:0;}
.vf-detail-title{font-size:12px;font-weight:700;color:var(--text);flex:1;}
.vf-detail-price{font-size:14px;font-weight:800;font-family:var(--mono);flex-shrink:0;}
.vf-detail-section{border-bottom:1px solid var(--border2);}
.vf-detail-section-hd{padding:5px 11px;font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);background:var(--bg2);}
.vf-detail-section-body{padding:8px 11px;display:flex;flex-direction:column;gap:5px;}
.vf-detail-row{display:flex;justify-content:space-between;align-items:center;font-size:10px;}
.vf-detail-row-lbl{color:var(--muted);}
.vf-detail-row-val{font-weight:700;font-family:var(--mono);color:var(--text);}
.vf-detail-alert{margin:8px 11px;padding:6px 9px;background:#fffbeb;border:1px solid #fde68a;border-radius:6px;font-size:9px;color:#92400e;font-weight:600;display:flex;align-items:center;gap:5px;flex-wrap:wrap;}
.vf-detail-justif-file{display:flex;align-items:center;gap:7px;padding:7px 11px;border-bottom:1px solid var(--border2);cursor:pointer;}
.vf-detail-justif-file:last-child{border-bottom:none;}
.vf-detail-justif-file:hover{background:var(--bg2);}
.vf-detail-justif-icon{width:32px;height:32px;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:16px;background:var(--bg2);border:1px solid var(--border);flex-shrink:0;}
.vf-detail-justif-name{flex:1;font-size:10px;font-weight:600;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vf-detail-justif-btn{padding:3px 8px;font-size:9px;font-weight:700;border-radius:4px;border:1px solid var(--border);background:var(--bg);cursor:pointer;font-family:inherit;display:flex;align-items:center;gap:3px;color:#374151;flex-shrink:0;}
.vf-detail-justif-btn:hover{background:#f3f4f6;}
.vf-detail-actions{padding:8px 11px;display:flex;gap:6px;border-top:1px solid var(--border);background:var(--bg2);}
.vf-detail-missing{padding:10px 11px;display:flex;align-items:center;gap:6px;font-size:10px;color:var(--red);font-weight:600;}
.vf-detail-km{margin:8px 11px;padding:7px 10px;background:#f5f3ff;border:1px solid #ddd6fe;border-radius:7px;font-size:9px;color:#5b21b6;display:flex;flex-direction:column;gap:3px;}
.vf-detail-km-row{display:flex;justify-content:space-between;align-items:center;}
.vf-detail-km-lbl{color:#7c3aed;font-weight:600;}
.vf-detail-km-val{font-weight:800;font-family:var(--mono);color:#4c1d95;}

/* ── Panel 1: Note summary ── */
.vf-summary{border:1px solid var(--border);border-radius:7px;overflow:hidden;}
.vf-summary-top{height:3px;background:linear-gradient(90deg,#7c3aed,#a78bfa);}
.vf-summary-body{padding:9px 11px;}
.vf-sum-price-lbl{font-size:9px;text-transform:uppercase;letter-spacing:.4px;color:var(--muted);}
.vf-sum-price{font-size:20px;font-weight:800;font-family:var(--mono);color:var(--text);line-height:1.1;}
.vf-sum-price.adj{color:var(--green);}
.vf-sum-adj{font-size:9px;color:var(--green);font-weight:600;margin-top:1px;}
.vf-sum-div{height:1px;background:var(--border);margin:7px 0;}
.vf-sum-meta{font-size:10px;color:var(--muted);line-height:1.7;}
.vf-sum-prog{padding:5px 11px 9px;}
.vf-appro{border:1px solid #d8b4fe;border-radius:7px;overflow:hidden;margin-top:6px;}
.vf-appro-hd{display:flex;align-items:center;gap:5px;padding:5px 9px;background:#f5f3ff;border-bottom:1px solid #e9d5ff;font-size:9px;font-weight:700;color:var(--accent);}
.vf-appro-body{padding:4px 7px;display:flex;flex-direction:column;gap:3px;}

/* ── Panel 2: Category list ── */
.vf-cat-item{border:1px solid var(--border);border-radius:7px;overflow:hidden;cursor:pointer;transition:all .15s;background:var(--bg);}
.vf-cat-item:hover{border-color:#c4b5fd;background:#faf5ff;}
.vf-cat-item.active{border-color:#7c3aed;background:#f5f3ff;box-shadow:0 0 0 2px rgba(124,58,237,.12);}
.vf-cat-hd{display:flex;align-items:center;gap:7px;padding:7px 9px;}
.vf-cat-emoji{font-size:14px;flex-shrink:0;}
.vf-cat-info{flex:1;min-width:0;}
.vf-cat-name{font-size:10px;font-weight:700;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vf-cat-sub{font-size:9px;color:var(--muted);}
.vf-cat-right{text-align:right;flex-shrink:0;}
.vf-cat-amt{font-size:11px;font-weight:800;font-family:var(--mono);}
.vf-cat-progress{height:2px;background:var(--border2);}
.vf-cat-progress-fill{height:100%;border-radius:0 0 7px 7px;transition:width .3s;}
.vf-cat-status-strip{display:flex;gap:2px;padding:3px 9px;border-top:1px solid var(--border2);flex-wrap:wrap;}

/* ── Panel 3: Ligne detail ── */
.vf-empty-panel{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;padding:24px;color:var(--muted);text-align:center;}
.vf-ligne-card{border:1px solid var(--border);border-radius:7px;overflow:hidden;background:var(--bg);}
.vf-ligne-card.ok{border-color:#86efac;background:#f0fdf4;}
.vf-ligne-card.refused{border-color:#fca5a5;background:#fff5f5;}
.vf-ligne-hd{display:flex;align-items:center;gap:7px;padding:8px 10px;border-bottom:1px solid rgba(0,0,0,.06);}
.vf-ligne-num{width:22px;height:22px;border-radius:5px;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:800;flex-shrink:0;}
.vf-ligne-name{font-size:11px;font-weight:700;color:var(--text);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vf-ligne-date{font-size:9px;color:var(--muted);flex-shrink:0;}
.vf-ligne-price{font-size:13px;font-weight:800;font-family:var(--mono);flex-shrink:0;}
.vf-ligne-details{padding:5px 10px;display:flex;gap:10px;flex-wrap:wrap;border-bottom:1px solid rgba(0,0,0,.04);background:rgba(0,0,0,.015);}
.vf-det{display:flex;align-items:center;gap:3px;}
.vf-det-l{font-size:9px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.3px;}
.vf-det-v{font-size:9px;font-weight:700;color:var(--text);font-family:var(--mono);}
.vf-ligne-desc{padding:4px 10px;font-size:9px;color:#78350f;font-style:italic;background:#fffbeb;border-left:2px solid #f59e0b;border-bottom:1px solid #fde68a;}
.vf-ligne-participants{padding:4px 10px;display:flex;flex-wrap:wrap;gap:3px;align-items:center;border-bottom:1px solid rgba(0,0,0,.04);}
.vf-ligne-justifs{padding:5px 10px;display:flex;flex-wrap:wrap;gap:4px;align-items:center;border-bottom:1px solid rgba(0,0,0,.04);}
.vf-jlabel{font-size:9px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.3px;flex-shrink:0;}
.vf-jbtn{display:flex;align-items:center;gap:3px;padding:2px 7px;background:var(--bg);border:1px solid var(--border);border-radius:4px;cursor:pointer;font-family:inherit;font-size:9px;font-weight:600;color:#374151;white-space:nowrap;}
.vf-jbtn:hover{background:#f3f4f6;}
.vf-jkm{font-size:9px;color:var(--accent);font-weight:600;}
.vf-jmissing{font-size:9px;color:var(--red);font-weight:600;}
.vf-ligne-alert{display:flex;align-items:center;gap:5px;padding:4px 10px;background:#fffbeb;border-left:2px solid #f59e0b;border-bottom:1px solid #fde68a;font-size:9px;color:#92400e;font-weight:600;flex-wrap:wrap;}
.vf-prorata-btn{padding:1px 7px;border-radius:4px;cursor:pointer;font-family:'DM Sans',sans-serif;font-size:9px;font-weight:700;border:1px solid #6366f1;color:#6366f1;background:var(--bg);}
.vf-prorata-restore{padding:1px 7px;border-radius:4px;cursor:pointer;font-family:'DM Sans',sans-serif;font-size:9px;font-weight:700;border:1px solid #d1d5db;color:var(--muted);background:var(--bg);}
.vf-prorata-result{padding:3px 10px;font-size:9px;color:var(--green);font-weight:600;background:#f0fdf4;border-bottom:1px solid #86efac;display:flex;align-items:center;gap:4px;flex-wrap:wrap;}
.vf-ligne-actions{display:flex;align-items:center;gap:5px;padding:5px 10px;background:rgba(0,0,0,.015);}
.vf-status{flex:1;font-size:9px;font-weight:700;display:flex;align-items:center;gap:3px;}
.vf-status.ok{color:var(--green);}
.vf-status.refused{color:var(--red);}
.vf-status.pending{color:var(--muted);}
.vf-motif{flex:1;font-size:9px;font-style:italic;color:var(--red);background:#fff5f5;border:1px dashed #fca5a5;padding:2px 6px;border-radius:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vf-btn-edit{border:none;background:none;color:var(--accent);font-family:inherit;font-size:9px;font-weight:600;cursor:pointer;padding:1px 4px;text-decoration:underline;}
.vf-btn-ok{padding:3px 9px;font-family:'DM Sans',sans-serif;font-size:10px;font-weight:700;border-radius:4px;cursor:pointer;display:flex;align-items:center;gap:3px;border:1.5px solid #16a34a;color:#16a34a;background:var(--bg);transition:all .12s;}
.vf-btn-ok:hover{background:#f0fdf4;}
.vf-btn-ok.active{background:#16a34a;color:#fff;}
.vf-btn-refuse{padding:3px 9px;font-family:'DM Sans',sans-serif;font-size:10px;font-weight:700;border-radius:4px;cursor:pointer;display:flex;align-items:center;gap:3px;border:1.5px solid var(--red);color:var(--red);background:var(--bg);transition:all .12s;}
.vf-btn-refuse:hover{background:#fff5f5;}
.vf-btn-refuse.active{background:var(--red);color:#fff;}

/* ── Panel 4: Decision ── */
.vf-dec{border:1px solid var(--border);border-radius:7px;overflow:hidden;}
.vf-dec-hd{padding:5px 9px;background:var(--bg2);border-bottom:1px solid var(--border);font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);display:flex;align-items:center;gap:4px;}
.vf-dec-body{padding:6px 8px;display:flex;flex-direction:column;gap:4px;}
.vf-ls-row{display:flex;align-items:center;gap:5px;padding:3px 7px;border-radius:4px;border:1px solid var(--border);}
.vf-ls-dot{width:5px;height:5px;border-radius:50%;flex-shrink:0;}
.vf-ls-label{flex:1;font-size:9px;font-weight:600;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vf-ls-tag{font-size:8px;font-weight:700;padding:1px 5px;border-radius:20px;white-space:nowrap;}
.vf-ls-tag.ok{background:var(--green-bg);color:var(--green);}
.vf-ls-tag.wait{background:var(--bg2);color:var(--muted);}
.vf-ls-tag.refused{background:var(--red-bg);color:var(--red);}
.vf-ls-tag.adj{background:var(--amber-bg);color:var(--amber);}
.vf-dec-total{display:flex;justify-content:space-between;align-items:center;padding:6px 9px;background:var(--bg2);border-top:1px solid var(--border);}
.vf-dec-total-lbl{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.4px;color:var(--muted);}
.vf-dec-total-val{font-size:13px;font-weight:800;font-family:var(--mono);}
.vf-dec-final{padding:7px 9px;border-top:1px solid var(--border);display:flex;flex-direction:column;gap:5px;}
.vf-dec-hint{font-size:10px;color:var(--muted);}
.vf-dec-hint.ok{color:var(--green);font-weight:600;}
.vf-dec-hint.nok{color:var(--red);font-weight:600;}
.vf-btn-validate{width:100%;padding:7px 0;background:var(--green);color:#fff;border:none;border-radius:6px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:5px;}
.vf-btn-validate:hover:not(:disabled){background:#166534;}
.vf-btn-validate:disabled{opacity:.4;cursor:not-allowed;}
.vf-btn-reject{width:100%;padding:7px 0;background:var(--bg);color:var(--red);border:1.5px solid var(--red);border-radius:6px;font-family:'DM Sans',sans-serif;font-size:11px;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:5px;}
.vf-btn-reject:hover:not(:disabled){background:var(--red-bg);}
.vf-btn-reject:disabled{opacity:.4;cursor:not-allowed;}
.vf-notify{display:flex;align-items:center;gap:5px;font-size:10px;color:var(--muted);cursor:pointer;}
.vf-jcard{border:1px solid var(--border);border-radius:7px;overflow:hidden;}
.vf-jcard-hd{padding:5px 9px;background:var(--bg2);border-bottom:1px solid var(--border);font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);display:flex;align-items:center;gap:4px;}
.vf-jfile{display:flex;align-items:center;gap:5px;padding:5px 9px;border-bottom:1px solid var(--border);}
.vf-jfile:last-child{border-bottom:none;}
.vf-jfile-icon{width:22px;height:22px;border-radius:4px;display:flex;align-items:center;justify-content:center;font-size:11px;background:var(--bg2);flex-shrink:0;}
.vf-jfile-name{font-size:9px;flex:1;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vf-jfile-see{font-size:9px;font-weight:600;color:var(--muted);border:1px solid var(--border);background:var(--bg);border-radius:3px;padding:1px 6px;cursor:pointer;font-family:inherit;white-space:nowrap;}

/* ── History ── */
.vf-banner{display:flex;align-items:center;gap:9px;padding:9px 13px;border-radius:9px;border:1px solid;margin-bottom:11px;}
.vf-hist-card{background:var(--bg);border:1px solid var(--border);border-radius:9px;overflow:hidden;margin-bottom:7px;}
.vf-hist-hd{padding:9px 13px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:7px;background:var(--bg2);border-bottom:1px solid var(--border2);}
.vf-hist-body{padding:7px 13px;display:flex;gap:7px;flex-wrap:wrap;align-items:center;}
.vf-hist-stat{display:flex;align-items:center;gap:4px;font-size:10px;font-weight:600;}
.vf-hist-comment{font-size:9px;color:var(--muted);font-style:italic;padding:4px 8px;background:var(--bg2);border-radius:5px;border:1px solid var(--border2);margin-top:3px;}
.vf-hist-badge{font-size:9px;font-weight:700;padding:2px 7px;border-radius:20px;}
.vf-hist-badge.ok{background:var(--green-bg);color:var(--green);}
.vf-hist-badge.refused{background:var(--red-bg);color:var(--red);}
.vf-empty{background:var(--bg2);border:1px solid var(--border);border-radius:11px;padding:44px 24px;text-align:center;}

/* ── Modals ── */
.vf-modal-bg{position:fixed;inset:0;z-index:10001;background:rgba(0,0,0,.4);display:flex;align-items:center;justify-content:center;padding:1rem;}
.vf-modal{background:var(--bg);border-radius:13px;width:100%;max-width:450px;border:1px solid var(--border);overflow:hidden;box-shadow:0 20px 56px rgba(0,0,0,.18);}
.vf-mnt-modal{background:var(--bg);border-radius:15px;width:100%;max-width:410px;overflow:hidden;box-shadow:0 26px 65px rgba(0,0,0,.2);}
.vf-mnt-hd{padding:16px 20px 13px;background:#6366f1;color:#fff;}
.vf-mnt-hd-icon{width:38px;height:38px;border-radius:9px;background:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;font-size:17px;margin-bottom:9px;}
.vf-mnt-hd-title{font-size:14px;font-weight:800;margin-bottom:2px;}
.vf-mnt-hd-sub{font-size:10px;opacity:.85;}
.vf-mnt-body{padding:16px 20px;}
.vf-mnt-recap{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-bottom:14px;}
.vf-mnt-recap-item{background:var(--bg2);border:1px solid var(--border);border-radius:7px;padding:7px 9px;}
.vf-mnt-recap-lbl{font-size:9px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.3px;margin-bottom:2px;}
.vf-mnt-recap-val{font-size:13px;font-weight:800;font-family:var(--mono);}
.vf-mnt-input-wrap{position:relative;margin-bottom:5px;}
.vf-mnt-input{width:100%;padding:11px 40px 11px 13px;font-size:17px;font-weight:800;font-family:var(--mono);border:2px solid #6366f1;border-radius:7px;outline:none;color:var(--text);background:var(--bg);box-sizing:border-box;}
.vf-mnt-input:focus{box-shadow:0 0 0 3px rgba(99,102,241,.15);}
.vf-mnt-input.error{border-color:#ef4444;}
.vf-mnt-currency{position:absolute;right:12px;top:50%;transform:translateY(-50%);font-size:15px;font-weight:800;color:#6366f1;pointer-events:none;}
.vf-mnt-hint{font-size:10px;color:var(--muted);margin-bottom:13px;}
.vf-mnt-hint.error{color:#ef4444;font-weight:600;}
.vf-mnt-preset{padding:3px 9px;background:#eef2ff;color:#6366f1;border:1px solid #c7d2fe;border-radius:20px;cursor:pointer;font-size:10px;font-weight:700;font-family:inherit;margin-bottom:14px;display:inline-block;}
.vf-mnt-preset:hover,.vf-mnt-preset.active{background:#6366f1;color:#fff;}
.vf-mnt-footer{padding:10px 20px;border-top:1px solid var(--border);display:flex;gap:7px;justify-content:flex-end;background:var(--bg2);}
.vf-mnt-btn-cancel{padding:7px 14px;background:var(--bg);border:1.5px solid var(--border);border-radius:7px;cursor:pointer;font-family:inherit;font-size:12px;font-weight:600;color:var(--muted);}
.vf-mnt-btn-confirm{padding:7px 16px;background:#6366f1;color:#fff;border:none;border-radius:7px;cursor:pointer;font-family:inherit;font-size:12px;font-weight:700;display:flex;align-items:center;gap:4px;}
.vf-mnt-btn-confirm:disabled{opacity:.4;cursor:not-allowed;}

/* ── All-lines bulk validation strip ── */
.vf-bulk-strip{display:flex;gap:5px;padding:5px 8px;border-top:1px solid var(--border2);background:#f5f3ff;flex-wrap:wrap;}
.vf-bulk-btn{padding:3px 10px;font-size:9px;font-weight:700;border-radius:4px;cursor:pointer;font-family:inherit;display:flex;align-items:center;gap:3px;}
.vf-bulk-ok{background:#f0fdf4;color:var(--green);border:1.5px solid #86efac;}
.vf-bulk-ok:hover{background:#dcfce7;}
`;

export default function VerificateurFinance4Panels({
    notesAVerifier: initialNotes, onVerified, API, hdrs,
    proxyUrl = u => u, setPreviewUrl,
}: Props) {
    const [notes, setNotes] = useState<NoteAVerifier[]>(initialNotes);
    const [ligneStates, setLigneStates] = useState<Record<string, LigneState>>({});
    const [modalNok, setModalNok] = useState<ModalNok | null>(null);
    const [nokReason, setNokReason] = useState('');
    const [submitting, setSubmitting] = useState(false);
    const [notifyOnReject, setNotifyOnReject] = useState(true);
    const [expandedNotes, setExpandedNotes] = useState<Set<number>>(new Set());
    const [activeTab, setActiveTab] = useState<'pending' | 'history'>('pending');
    const [history, setHistory] = useState<VerifHistorique[]>([]);
    const [historyLoaded, setHistoryLoaded] = useState(false);

    const [montantsModifies, setMontantsModifies] = useState<Record<string, number>>({});
    const [modalCommentaire, setModalCommentaire] = useState<{
        noteId: number; lignesData: LigneDepense[];
        modifs: { ligneIndex: number; montantOriginal: number; montantRetenu: number }[];
    } | null>(null);
    const [commentaireInput, setCommentaireInput] = useState('');
    const [modalMontant, setModalMontant] = useState<{
        noteId: number; ligneIndex: number; ligneLabel: string;
        montantOriginal: number; montantProrataMax: number; valeurSaisie: string;
    } | null>(null);

    // Panel 2 → 3: selected category per note
    const [selectedCat, setSelectedCat] = useState<Record<number, string | null>>({});
    // Panel 3 → 4: selected ligne index per note
    const [selectedLigne, setSelectedLigne] = useState<Record<number, number | null>>({});

    useEffect(() => {
        setNotes(initialNotes);
        const s: Record<string, LigneState> = {};
        for (const note of initialNotes)
            (note.lignesRefusees || []).forEach(r => { s[ligneKey(note.id, r.index)] = { status: 'refused', motif: r.motif }; });
        if (Object.keys(s).length) setLigneStates(prev => ({ ...prev, ...s }));
    }, [initialNotes]);

    const toggleNote = (id: number) => setExpandedNotes(prev => { const n = new Set(prev); n.has(id) ? n.delete(id) : n.add(id); return n; });
    const setLigne = (key: string, status: LigneState['status'], motif?: string) => setLigneStates(prev => ({ ...prev, [key]: { status, motif } }));
    const openRefuse = (noteId: number, ligneIndex: number, ligneLabel: string) => {
        setModalNok({ noteId, ligneIndex, ligneLabel });
        setNokReason(ligneStates[ligneKey(noteId, ligneIndex)]?.motif || '');
    };
    const loadHistory = async () => {
        if (historyLoaded) return;
        try { const r = await fetch(`${API}/api/verificateur/historique`, { headers: hdrs }); if (r.ok) { const d = await r.json(); if (Array.isArray(d)) setHistory(d); } } catch { }
        setHistoryLoaded(true);
    };
    const handleTabChange = (tab: 'pending' | 'history') => { setActiveTab(tab); if (tab === 'history') loadHistory(); };

    const getFilesForLigne = (l: LigneDepense, li: number, jr: Fichier[], fg: Fichier[], qrRefs: string[], all: LigneDepense[]): Fichier[] => {
        if (l.qrFiles?.length) return l.qrFiles.map(f => ({ fileName: f.fileName, uploadUrl: f.uploadUrl }));
        const ref = l.qrNoteRef || '';
        if (ref) { const found = jr.filter(f => f.fileName?.includes(ref) || f.uploadUrl?.includes(ref)); if (found.length) return found; }
        if (!qrRefs.length) return fg.slice(Math.floor(li * fg.length / all.length), Math.floor((li + 1) * fg.length / all.length));
        return [];
    };

    const submitValidation = async (noteId: number, lignesData: LigneDepense[], modifs: { ligneIndex: number; montantOriginal: number; montantRetenu: number }[], commentaire: string) => {
        setSubmitting(true);
        try {
            const r = await fetch(`${API}/api/verificateur/notes/${noteId}/verifier`, { method: 'PUT', headers: hdrs, body: JSON.stringify({ commentaire, montantsModifies: modifs }) });
            const d = await r.json(); if (!r.ok) throw new Error(d.error || 'Erreur');
            onVerified(noteId); setNotes(prev => prev.filter(n => n.id !== noteId));
            setLigneStates(prev => { const n = { ...prev }; lignesData.forEach((_, i) => delete n[ligneKey(noteId, i)]); return n; });
            setMontantsModifies(prev => { const n = { ...prev }; lignesData.forEach((_, i) => delete n[`${noteId}-${i}`]); return n; });
            setModalCommentaire(null); setHistoryLoaded(false); setHistory([]); setActiveTab('history'); handleTabChange('history');
        } catch (e: any) { alert(e.message); } finally { setSubmitting(false); }
    };

    const submitDecision = async (noteId: number, action: 'validate' | 'reject', lignesData: LigneDepense[], lignesRefusees: { index: number; motif: string }[]) => {
        if (action === 'validate') {
            const modifs = Object.entries(montantsModifies).filter(([k]) => k.startsWith(`${noteId}-`))
                .map(([k, v]) => { const idx = parseInt(k.split('-')[1]); return { ligneIndex: idx, montantOriginal: parseFloat(lignesData[idx]?.montant || '0'), montantRetenu: v }; });
            setCommentaireInput(''); setModalCommentaire({ noteId, lignesData, modifs }); return;
        }
        setSubmitting(true);
        try {
            const r = await fetch(`${API}/api/verificateur/notes/${noteId}/refuser`, { method: 'POST', headers: hdrs, body: JSON.stringify({ lignesRefusees, notifier: notifyOnReject }) });
            const d = await r.json(); if (!r.ok) throw new Error(d.error || 'Erreur');
            onVerified(noteId); setNotes(prev => prev.filter(n => n.id !== noteId));
            setLigneStates(prev => { const n = { ...prev }; lignesData.forEach((_, i) => delete n[ligneKey(noteId, i)]); return n; });
            setMontantsModifies(prev => { const n = { ...prev }; lignesData.forEach((_, i) => delete n[`${noteId}-${i}`]); return n; });
            setHistoryLoaded(false); setHistory([]); setActiveTab('history'); handleTabChange('history');
        } catch (e: any) { alert(e.message); } finally { setSubmitting(false); }
    };

    // Compact list for panel 3
    const renderLignesPanel = (note: NoteAVerifier, lignesData: LigneDepense[], jr: Fichier[], fg: Fichier[], qrRefs: string[], catName: string | null) => {
        if (!catName) {
            return (
                <div className="vf-empty-panel">
                    <Receipt size={28} color="#c4b5fd" />
                    <div style={{ fontSize: 11, fontWeight: 600, color: '#7c3aed' }}>Sélectionnez une catégorie</div>
                    <div style={{ fontSize: 10 }}>Les lignes s'afficheront ici</div>
                </div>
            );
        }
        const indices = lignesData.map((l, i) => ({ l, i })).filter(({ l }) => (l.categorie || 'Autre') === catName);
        const activeLi = selectedLigne[note.id] ?? null;
        return (
            <>
                {indices.map(({ l, i: li }) => {
                    const isKm = (l.categorie || '').toLowerCase().includes('kilom');
                    const km = parseFloat(l.km || '0') || 0;
                    const cv = parseInt(l.chevaux || '7') || 7;
                    const montantOriginal = parseFloat(l.montant || '0') || 0;
                    const mKey = `${note.id}-${li}`;
                    const montantEff = montantsModifies[mKey] ?? (isKm ? getIndemniteKm(km, cv) : montantOriginal);
                    const cat = getCatMeta(l.categorie);
                    const key = ligneKey(note.id, li);
                    const state = ligneStates[key] ?? { status: 'pending' as const };
                    const cls = state.status;
                    const label = l.libelle || l.categorie || `Ligne ${li + 1}`;
                    const estModifie = montantsModifies[mKey] !== undefined;
                    const isActive = activeLi === li;
                    const isRepas = (l.categorie || '').toLowerCase().includes('repas');
                    const isEv = /\b(ev[eè]nement|[eé]v[eè]nement)\b/i.test(l.libelle || '') || /\b(ev[eè]nement|[eé]v[eè]nement)\b/i.test(l.description || '');
                    const nbConvives = Math.max(1, (parseInt(l.nombreParticipants || '0') || 0) + 1);
                    const ppp = isRepas && montantEff > 0 ? montantEff / nbConvives : 0;
                    const depasse = isRepas && !isEv && ppp > 25;

                    return (
                        <div key={li}
                            className={`vf-lrow ${isActive ? 'active' : ''} ${cls === 'ok' ? 'ok' : cls === 'refused' ? 'refused' : ''}`}
                            onClick={() => setSelectedLigne(prev => ({ ...prev, [note.id]: isActive ? null : li }))}>
                            <div className="vf-lrow-num" style={{ background: cat.bg, color: cat.color }}>{li + 1}</div>
                            <div className="vf-lrow-body">
                                <div className="vf-lrow-name">{label}</div>
                                <div className="vf-lrow-meta">
                                    {fmtDate(l.date)}
                                    {depasse && <span style={{ color: '#d97706', fontWeight: 700, marginLeft: 4 }}>⚠ plafond</span>}
                                    {state.status === 'refused' && <span style={{ color: '#dc2626', fontWeight: 700, marginLeft: 4 }}>✗ refusée</span>}
                                    {state.status === 'ok' && <span style={{ color: '#15803d', fontWeight: 700, marginLeft: 4 }}>✓ ok{estModifie ? ' ajusté' : ''}</span>}
                                </div>
                            </div>
                            <div className="vf-lrow-right">
                                <div className="vf-lrow-price" style={{ color: estModifie ? '#15803d' : cat.color }}>{fmt(montantEff)}</div>
                                <div className="vf-lrow-arrow">›</div>
                            </div>
                        </div>
                    );
                })}
                {indices.length > 1 && (
                    <div className="vf-bulk-strip">
                        <span style={{ fontSize: 9, color: 'var(--muted)', fontWeight: 700, flex: 1 }}>Groupé</span>
                        <button className="vf-bulk-btn vf-bulk-ok" onClick={() => indices.forEach(({ i }) => setLigne(ligneKey(note.id, i), 'ok'))}>
                            <Check size={9} /> Tout valider ({indices.length})
                        </button>
                    </div>
                )}
            </>
        );
    };

    // Panel 4: full detail of selected ligne
    const renderLigneDetail = (note: NoteAVerifier, lignesData: LigneDepense[], jr: Fichier[], fg: Fichier[], qrRefs: string[]) => {
        const li = selectedLigne[note.id] ?? null;
        if (li === null) {
            return (
                <div className="vf-empty-panel">
                    <Eye size={26} color="#c4b5fd" />
                    <div style={{ fontSize: 11, fontWeight: 600, color: '#7c3aed' }}>Sélectionnez une dépense</div>
                    <div style={{ fontSize: 10 }}>Détails et justificatifs ici</div>
                </div>
            );
        }
        const l = lignesData[li];
        if (!l) return null;

        const isKm = (l.categorie || '').toLowerCase().includes('kilom');
        const km = parseFloat(l.km || '0') || 0;
        const cv = parseInt(l.chevaux || '7') || 7;
        const montantOriginal = parseFloat(l.montant || '0') || 0;
        const mKey = `${note.id}-${li}`;
        const isRepas = (l.categorie || '').toLowerCase().includes('repas');
        const isEv = /\b(ev[eè]nement|[eé]v[eè]nement)\b/i.test(l.libelle || '') || /\b(ev[eè]nement|[eé]v[eè]nement)\b/i.test(l.description || '');
        const nbConvives = Math.max(1, (parseInt(l.nombreParticipants || '0') || 0) + 1);
        const montantEff = montantsModifies[mKey] ?? (isKm ? getIndemniteKm(km, cv) : montantOriginal);
        const ppp = isRepas && montantEff > 0 ? montantEff / nbConvives : 0;
        const depasse = isRepas && !isEv && ppp > 25;
        const prorataMax = parseFloat((25 * nbConvives).toFixed(2));
        const taux = parseFloat(l.tauxTVA || '0') || 0;
        const ht = (!isKm && taux > 0) ? montantEff / (1 + taux / 100) : null;
        const tva = ht !== null ? montantEff - ht : null;
        const cat = getCatMeta(l.categorie);
        const files = getFilesForLigne(l, li, jr, fg, qrRefs, lignesData);
        const key = ligneKey(note.id, li);
        const state = ligneStates[key] ?? { status: 'pending' as const };
        const cls = state.status;
        const label = l.libelle || l.categorie || `Ligne ${li + 1}`;
        const estModifie = montantsModifies[mKey] !== undefined;

        return (
            <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
                {/* Header */}
                <div className="vf-detail-hd" style={{ background: cat.light, borderColor: cat.bg }}>
                    <div className="vf-detail-num" style={{ background: cat.bg, color: cat.color }}>{li + 1}</div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                        <div className="vf-detail-title">{label}</div>
                        <div style={{ fontSize: 9, color: cat.color, fontWeight: 600 }}>{cat.emoji} {l.categorie} · {fmtDate(l.date)}</div>
                    </div>
                    <div style={{ textAlign: 'right', flexShrink: 0 }}>
                        <div className="vf-detail-price" style={{ color: estModifie ? '#15803d' : cat.color }}>{fmt(montantEff)}</div>
                        {estModifie && <div style={{ fontSize: 9, color: '#6b7280', textDecoration: 'line-through', fontFamily: 'DM Mono,monospace' }}>{fmt(montantOriginal)}</div>}
                    </div>
                </div>

                <div style={{ flex: 1, overflowY: 'auto', display: 'flex', flexDirection: 'column' }}>
                    {/* Montants */}
                    {(isKm || taux > 0 || isRepas) && (
                        <div className="vf-detail-section">
                            <div className="vf-detail-section-hd">Montants</div>
                            {isKm ? (
                                <div className="vf-detail-km">
                                    <div className="vf-detail-km-row"><span className="vf-detail-km-lbl">Distance</span><span className="vf-detail-km-val">{km} km</span></div>
                                    <div className="vf-detail-km-row"><span className="vf-detail-km-lbl">Puissance</span><span className="vf-detail-km-val">{cv} CV</span></div>
                                    <div className="vf-detail-km-row"><span className="vf-detail-km-lbl">Barème</span><span className="vf-detail-km-val">{(montantEff / (km || 1)).toFixed(3)} €/km</span></div>
                                    <div style={{ height: 1, background: '#ddd6fe', margin: '3px 0' }} />
                                    <div className="vf-detail-km-row"><span style={{ color: '#4c1d95', fontWeight: 700, fontSize: 10 }}>Indemnité</span><span style={{ fontWeight: 800, fontFamily: 'DM Mono,monospace', fontSize: 13, color: '#4c1d95' }}>{fmt(montantEff)}</span></div>
                                </div>
                            ) : (
                                <div className="vf-detail-section-body">
                                    <div className="vf-detail-row"><span className="vf-detail-row-lbl">Montant TTC</span><span className="vf-detail-row-val">{fmt(montantEff)}</span></div>
                                    {ht !== null && <div className="vf-detail-row"><span className="vf-detail-row-lbl">Montant HT</span><span className="vf-detail-row-val">{fmt(ht)}</span></div>}
                                    {tva !== null && <div className="vf-detail-row"><span className="vf-detail-row-lbl">TVA ({taux}%)</span><span className="vf-detail-row-val">{fmt(tva)}</span></div>}
                                    {isRepas && <div className="vf-detail-row"><span className="vf-detail-row-lbl">Convives</span><span className="vf-detail-row-val">{nbConvives} pers.</span></div>}
                                    {isRepas && <div className="vf-detail-row"><span className="vf-detail-row-lbl">Par personne</span><span className="vf-detail-row-val" style={{ color: depasse ? '#dc2626' : '#15803d' }}>{fmt(ppp)}</span></div>}
                                </div>
                            )}
                        </div>
                    )}

                    {/* Description */}
                    {l.description && (
                        <div className="vf-detail-section">
                            <div className="vf-detail-section-hd">Commentaire</div>
                            <div style={{ padding: '8px 11px', fontSize: 10, color: '#78350f', fontStyle: 'italic', lineHeight: 1.5 }}>💬 {l.description}</div>
                        </div>
                    )}

                    {/* Participants */}
                    {l.participants && l.participants.length > 0 && (
                        <div className="vf-detail-section">
                            <div className="vf-detail-section-hd">Participants ({l.participants.length})</div>
                            <div className="vf-detail-section-body">
                                {l.participants.map((p, pi) => (
                                    <div key={pi} style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '3px 0' }}>
                                        <div style={{ width: 22, height: 22, borderRadius: '50%', background: '#eef2ff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 9, fontWeight: 700, color: '#4338ca', flexShrink: 0 }}>
                                            {(p.prenom[0] || '') + (p.nom[0] || '')}
                                        </div>
                                        <div>
                                            <div style={{ fontSize: 10, fontWeight: 700, color: '#111827' }}>{p.prenom} {p.nom}</div>
                                            {p.societe && <div style={{ fontSize: 9, color: '#6b7280' }}>{p.societe}</div>}
                                        </div>
                                    </div>
                                ))}
                            </div>
                        </div>
                    )}

                    {/* Alerte plafond */}
                    {depasse && (
                        <div className="vf-detail-alert">
                            <AlertTriangle size={10} style={{ color: '#f59e0b', flexShrink: 0 }} />
                            <div style={{ flex: 1 }}>
                                <div>Plafond dépassé : {fmt(ppp)}/pers. &gt; 25 €</div>
                                {estModifie && <div style={{ color: '#15803d', marginTop: 2 }}>✅ Ajusté à {fmt(montantsModifies[mKey])}</div>}
                            </div>
                            <button className="vf-prorata-btn" onClick={() => setModalMontant({ noteId: note.id, ligneIndex: li, ligneLabel: label, montantOriginal, montantProrataMax: prorataMax, valeurSaisie: (montantsModifies[mKey] ?? prorataMax).toFixed(2) })}>✏️ Ajuster</button>
                            {estModifie && <button className="vf-prorata-restore" onClick={() => setMontantsModifies(prev => { const n = { ...prev }; delete n[mKey]; return n; })}>↩</button>}
                        </div>
                    )}

                    {/* Justificatifs */}
                    <div className="vf-detail-section">
                        <div className="vf-detail-section-hd"><Paperclip size={9} style={{ display: 'inline', marginRight: 4 }} />Justificatifs</div>
                        {isKm ? (
                            <div style={{ padding: '8px 11px', fontSize: 10, color: '#7c3aed', fontWeight: 600 }}>✓ Aucun justificatif requis (frais kilométriques)</div>
                        ) : files.length === 0 ? (
                            <div className="vf-detail-missing"><AlertTriangle size={13} color="#dc2626" /> Aucun justificatif trouvé</div>
                        ) : (
                            files.map((f, fi) => {
                                const isImg = /\.(jpg|jpeg|png|gif|webp)$/i.test(f.fileName);
                                return (
                                    <div key={fi} className="vf-detail-justif-file" onClick={() => setPreviewUrl?.({ url: proxyUrl(f.uploadUrl), name: f.fileName })}>
                                        <div className="vf-detail-justif-icon">{isImg ? '🖼️' : '📄'}</div>
                                        <div className="vf-detail-justif-name">{f.fileName}</div>
                                        <button className="vf-detail-justif-btn"><Eye size={9} /> Voir</button>
                                    </div>
                                );
                            })
                        )}
                    </div>

                    {/* Refus motif si refusé */}
                    {cls === 'refused' && state.motif && (
                        <div style={{ margin: '8px 11px', padding: '7px 10px', background: '#fff5f5', border: '1px solid #fca5a5', borderRadius: 6, fontSize: 10, color: '#dc2626', fontStyle: 'italic' }}>
                            ✗ Motif : {state.motif}
                        </div>
                    )}
                </div>

                {/* Actions */}
                <div className="vf-detail-actions">
                    {cls === 'refused' && (
                        <button className="vf-btn-edit" style={{ fontSize: 10 }} onClick={() => openRefuse(note.id, li, label)}>Modifier le motif</button>
                    )}
                    <div style={{ flex: 1 }} />
                    <button className={`vf-btn-ok ${cls === 'ok' ? 'active' : ''}`} onClick={() => setLigne(key, 'ok')}><Check size={10} /> OK</button>
                    <button className={`vf-btn-refuse ${cls === 'refused' ? 'active' : ''}`} onClick={() => openRefuse(note.id, li, label)}><X size={10} /> Refuser</button>
                </div>
            </div>
        );
    };

    return (
        <>
            <style>{CSS}</style>
            <div className="vf-root">
                <div className="vf-tabs">
                    <button className={`vf-tab ${activeTab === 'pending' ? 'active' : ''}`} onClick={() => handleTabChange('pending')}>
                        <Eye size={11} /> À vérifier {notes.length > 0 && <span className="vf-tab-badge">{notes.length}</span>}
                    </button>
                    <button className={`vf-tab ${activeTab === 'history' ? 'active' : ''}`} onClick={() => handleTabChange('history')}>
                        <History size={11} /> Historique {history.length > 0 && <span className="vf-tab-badge" style={{ background: activeTab === 'history' ? '#5b21b6' : '#6b7280' }}>{history.length}</span>}
                    </button>
                </div>

                {activeTab === 'pending' && (notes.length === 0 ? (
                    <div className="vf-empty">
                        <Eye size={34} color="#a78bfa" style={{ display: 'block', margin: '0 auto 9px' }} />
                        <p style={{ fontSize: 12, fontWeight: 700, color: '#5b21b6', marginBottom: 3 }}>Aucune note en attente</p>
                        <span style={{ fontSize: 10, color: '#6b7280' }}>Les notes approuvées apparaîtront ici</span>
                    </div>
                ) : notes.map(note => {
                    const isOpen = expandedNotes.has(note.id);
                    let lignesData: LigneDepense[] = []; try { if (note.lignesJson) lignesData = JSON.parse(note.lignesJson); } catch { }
                    let tousLesFichiers: Fichier[] = []; try { tousLesFichiers = note.fichiers ? JSON.parse(note.fichiers as string) : []; } catch { }
                    const fichierApprobation = tousLesFichiers.filter(f => isApprovalFile(f));
                    const jr = tousLesFichiers.filter(f => !isSystemFile(f) && !isApprovalFile(f));
                    const qrRefs = lignesData.map(l => l.qrNoteRef).filter(Boolean) as string[];
                    const fg = qrRefs.length ? jr.filter(f => !qrRefs.some(ref => f.fileName?.includes(ref) || f.uploadUrl?.includes(ref))) : jr;
                    const okCount = lignesData.filter((_, i) => ligneStates[ligneKey(note.id, i)]?.status === 'ok').length;
                    const refusedList = lignesData.map((_, i) => ({ i, s: ligneStates[ligneKey(note.id, i)] })).filter(x => x.s?.status === 'refused').map(x => ({ index: x.i, motif: x.s!.motif || '' }));
                    const refusedCount = refusedList.length;
                    const pendingCount = lignesData.length - okCount - refusedCount;
                    const pct = lignesData.length > 0 ? Math.round(((okCount + refusedCount) / lignesData.length) * 100) : 0;
                    const allChecked = lignesData.length > 0 && pendingCount === 0;
                    const canValidate = allChecked && refusedCount === 0;
                    const canReject = refusedCount > 0 && pendingCount === 0;
                    const nbModifs = Object.keys(montantsModifies).filter(k => k.startsWith(`${note.id}-`)).length;
                    const totalAjuste = lignesData.reduce((sum, l, i) => {
                        const isK = (l.categorie || '').toLowerCase().includes('kilom');
                        const km = parseFloat(l.km || '0') || 0; const cv = parseInt(l.chevaux || '7') || 7;
                        return sum + (montantsModifies[`${note.id}-${i}`] ?? (isK ? getIndemniteKm(km, cv) : parseFloat(l.montant || '0') || 0));
                    }, 0);

                    const catGroups = groupByCategory(lignesData);
                    const activeCat = selectedCat[note.id] ?? null;

                    return (
                        <div key={note.id} className="vf-note">
                            {/* Note header */}
                            <button className="vf-note-trigger" onClick={() => toggleNote(note.id)}>
                                <div className="vf-note-bar" />
                                <div className="vf-note-hd">
                                    <div>
                                        <span className="vf-ref">{note.reference}</span>
                                        <div className="vf-note-title">{note.libelle}</div>
                                        <div className="vf-note-meta">{[note.collaborateur, note.campus, note.departement, fmtDate(note.date)].filter(Boolean).join(' · ')}</div>
                                    </div>
                                    <div style={{ textAlign: 'right' }}>
                                        <div className={`vf-note-amt ${nbModifs > 0 ? 'adj' : ''}`} style={{ color: nbModifs > 0 ? '#15803d' : undefined }}>{nbModifs > 0 ? fmt(totalAjuste) : fmt(note.montant || 0)}</div>
                                        {nbModifs > 0 && <div style={{ fontSize: 9, color: '#6b7280', textDecoration: 'line-through', fontFamily: 'DM Mono,monospace', textAlign: 'right' }}>{fmt(note.montant || 0)}</div>}
                                        <div className="vf-note-sub">{lignesData.length} ligne{lignesData.length > 1 ? 's' : ''}{nbModifs > 0 ? ` · ${nbModifs} ajust.` : ''}</div>
                                    </div>
                                </div>
                                <div className="vf-note-chev">{isOpen ? <ChevronUp size={14} /> : <ChevronDown size={14} />}</div>
                            </button>

                            {lignesData.length > 0 && (
                                <div className="vf-prog-strip">
                                    <div className="vf-prog-track">
                                        <div className="vf-prog-fill" style={{ width: `${pct}%`, background: refusedCount > 0 ? '#ef4444' : '#5b21b6' }} />
                                    </div>
                                    <span style={{ fontSize: 9, fontWeight: 700, color: '#5b21b6', flexShrink: 0 }}>{pct}%</span>
                                    <div className="vf-pills">
                                        {okCount > 0 && <span className="vf-pill vf-pill-ok">{okCount} OK</span>}
                                        {refusedCount > 0 && <span className="vf-pill vf-pill-nok">{refusedCount} refus.</span>}
                                        {pendingCount > 0 && <span className="vf-pill vf-pill-wait">{pendingCount} att.</span>}
                                        {nbModifs > 0 && <span className="vf-pill vf-pill-adj">✂️ {nbModifs}</span>}
                                    </div>
                                </div>
                            )}

                            {isOpen && (
                                <div className="vf-4grid">

                                    {/* ── PANEL 1 : La note ── */}
                                    <div className="vf-panel">
                                        <div className="vf-panel-hd">
                                            <FileText size={10} color="#6b7280" />
                                            <span className="vf-panel-label">La note</span>
                                        </div>
                                        <div className="vf-panel-body">
                                            <div className="vf-summary">
                                                <div className="vf-summary-top" />
                                                <div className="vf-summary-body">
                                                    <span className="vf-ref">{note.reference}</span>
                                                    <div style={{ fontSize: 11, fontWeight: 700, color: '#111827', marginBottom: 3 }}>{note.libelle}</div>
                                                    <div className="vf-sum-div" />
                                                    <div className="vf-sum-price-lbl">Total demandé</div>
                                                    <div className={`vf-sum-price ${nbModifs > 0 ? 'adj' : ''}`}>{fmt(note.montant || 0)}</div>
                                                    {nbModifs > 0 && <div className="vf-sum-adj">→ {fmt(totalAjuste)} après ajust.</div>}
                                                    <div className="vf-sum-div" />
                                                    <div className="vf-sum-meta">
                                                        {note.collaborateur && <div>👤 {note.collaborateur}</div>}
                                                        {note.campus && <div>🏢 {note.campus}</div>}
                                                        {note.departement && <div>🗂 {note.departement}</div>}
                                                        {note.date && <div>📅 {fmtDate(note.date)}</div>}
                                                    </div>
                                                </div>
                                                <div className="vf-sum-prog">
                                                    <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 3 }}>
                                                        <span style={{ fontSize: 9, fontWeight: 700, color: '#6b7280', textTransform: 'uppercase', letterSpacing: '.4px' }}>Progression</span>
                                                        <span style={{ fontSize: 9, fontWeight: 700, color: '#5b21b6' }}>{pct}%</span>
                                                    </div>
                                                    <div className="vf-prog-track"><div className="vf-prog-fill" style={{ width: `${pct}%`, background: refusedCount > 0 ? '#ef4444' : '#5b21b6' }} /></div>
                                                    <div className="vf-pills" style={{ marginTop: 4 }}>
                                                        {okCount > 0 && <span className="vf-pill vf-pill-ok">{okCount} OK</span>}
                                                        {refusedCount > 0 && <span className="vf-pill vf-pill-nok">{refusedCount} refus.</span>}
                                                        {pendingCount > 0 && <span className="vf-pill vf-pill-wait">{pendingCount} att.</span>}
                                                    </div>
                                                </div>
                                            </div>

                                            {fichierApprobation.length > 0 && (
                                                <div className="vf-appro">
                                                    <div className="vf-appro-hd"><FileText size={10} color="#7c3aed" /> Approbation signée</div>
                                                    <div className="vf-appro-body">
                                                        {fichierApprobation.map((f, fi) => (
                                                            <div key={fi} style={{ display: 'flex', alignItems: 'center', gap: 4, padding: '2px 0' }}>
                                                                <span style={{ fontSize: 10 }}>📄</span>
                                                                <span style={{ fontSize: 9, flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: '#111827' }}>{f.fileName.length > 22 ? f.fileName.slice(0, 20) + '…' : f.fileName}</span>
                                                                <button className="vf-jfile-see" onClick={() => setPreviewUrl?.({ url: proxyUrl(f.uploadUrl), name: f.fileName })}><Eye size={8} style={{ display: 'inline', marginRight: 2 }} /> Voir</button>
                                                            </div>
                                                        ))}
                                                    </div>
                                                </div>
                                            )}
                                        </div>
                                    </div>

                                    {/* ── PANEL 2 : Catégories ── */}
                                    <div className="vf-panel">
                                        <div className="vf-panel-hd">
                                            <ListChecks size={10} color="#6b7280" />
                                            <span className="vf-panel-label">Catégories</span>
                                            <span style={{ marginLeft: 'auto', fontSize: 9, color: '#6b7280' }}>{catGroups.length}</span>
                                        </div>
                                        <div className="vf-panel-body">
                                            {catGroups.map(({ cat, indices, total }) => {
                                                const catMeta = getCatMeta(cat);
                                                const okInCat = indices.filter(i => ligneStates[ligneKey(note.id, i)]?.status === 'ok').length;
                                                const refInCat = indices.filter(i => ligneStates[ligneKey(note.id, i)]?.status === 'refused').length;
                                                const pendInCat = indices.length - okInCat - refInCat;
                                                const catPct = indices.length > 0 ? Math.round(((okInCat + refInCat) / indices.length) * 100) : 0;
                                                const isActive = activeCat === cat;
                                                return (
                                                    <div key={cat} className={`vf-cat-item ${isActive ? 'active' : ''}`}
                                                        onClick={() => {
                                                            setSelectedCat(prev => ({ ...prev, [note.id]: isActive ? null : cat }));
                                                            setSelectedLigne(prev => ({ ...prev, [note.id]: null }));
                                                        }}>
                                                        <div className="vf-cat-hd">
                                                            <span className="vf-cat-emoji">{catMeta.emoji}</span>
                                                            <div className="vf-cat-info">
                                                                <div className="vf-cat-name">{cat}</div>
                                                                <div className="vf-cat-sub">{indices.length} ligne{indices.length > 1 ? 's' : ''}</div>
                                                            </div>
                                                            <div className="vf-cat-right">
                                                                <div className="vf-cat-amt" style={{ color: catMeta.color }}>{fmt(total)}</div>
                                                                <div style={{ fontSize: 8, color: '#6b7280', textAlign: 'right' }}>{catPct}%</div>
                                                            </div>
                                                        </div>
                                                        <div className="vf-cat-progress">
                                                            <div className="vf-cat-progress-fill" style={{ width: `${catPct}%`, background: refInCat > 0 ? '#ef4444' : catMeta.color }} />
                                                        </div>
                                                        <div className="vf-cat-status-strip">
                                                            {okInCat > 0 && <span className="vf-pill vf-pill-ok">{okInCat} OK</span>}
                                                            {refInCat > 0 && <span className="vf-pill vf-pill-nok">{refInCat} refus.</span>}
                                                            {pendInCat > 0 && <span className="vf-pill vf-pill-wait">{pendInCat} att.</span>}
                                                        </div>
                                                    </div>
                                                );
                                            })}
                                        </div>
                                    </div>

                                    {/* ── PANEL 3 : Lignes de la catégorie (liste compacte) ── */}
                                    <div className="vf-panel">
                                        <div className="vf-panel-hd">
                                            <Receipt size={10} color="#6b7280" />
                                            <span className="vf-panel-label">
                                                {activeCat ? activeCat : 'Dépenses'}
                                            </span>
                                            {activeCat && (
                                                <span style={{ marginLeft: 'auto', fontSize: 9, color: '#6b7280' }}>
                                                    {lignesData.filter(l => (l.categorie || 'Autre') === activeCat).length}
                                                </span>
                                            )}
                                        </div>
                                        <div className="vf-panel-body">
                                            {renderLignesPanel(note, lignesData, jr, fg, qrRefs, activeCat)}
                                        </div>
                                    </div>

                                    {/* ── PANEL 4 : Détail de la ligne sélectionnée ── */}
                                    <div className="vf-panel">
                                        <div className="vf-panel-hd">
                                            <Eye size={10} color="#6b7280" />
                                            <span className="vf-panel-label">
                                                {selectedLigne[note.id] !== null && selectedLigne[note.id] !== undefined
                                                    ? `Ligne ${(selectedLigne[note.id] ?? 0) + 1} — détail`
                                                    : 'Détail & justificatifs'}
                                            </span>
                                        </div>
                                        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
                                            {renderLigneDetail(note, lignesData, jr, fg, qrRefs)}
                                        </div>
                                    </div>

                                    {/* ── PANEL 5 : Décision ── */}
                                    <div className="vf-panel">
                                        <div className="vf-panel-hd">
                                            <ShieldCheck size={10} color="#6b7280" />
                                            <span className="vf-panel-label">Décision</span>
                                        </div>
                                        <div className="vf-panel-body">
                                            <div className="vf-dec">
                                                <div className="vf-dec-hd"><ListChecks size={9} /> Statut lignes</div>
                                                <div className="vf-dec-body">
                                                    {lignesData.map((l, li) => {
                                                        const cat = getCatMeta(l.categorie);
                                                        const st = ligneStates[ligneKey(note.id, li)]?.status ?? 'pending';
                                                        const adj = montantsModifies[`${note.id}-${li}`] !== undefined;
                                                        const lbl = l.libelle || l.categorie || `Ligne ${li + 1}`;
                                                        const isActiveCatRow = activeCat === (l.categorie || 'Autre');
                                                        return (
                                                            <div key={li} className="vf-ls-row"
                                                                style={isActiveCatRow ? { background: '#faf5ff', borderColor: '#c4b5fd', cursor: 'pointer' } : { cursor: 'pointer' }}
                                                                onClick={() => setSelectedCat(prev => ({ ...prev, [note.id]: l.categorie || 'Autre' }))}>
                                                                <span className="vf-ls-dot" style={{ background: cat.color }} />
                                                                <span className="vf-ls-label" title={lbl}>{lbl}</span>
                                                                {st === 'ok' && adj && <span className="vf-ls-tag adj">OK ajusté</span>}
                                                                {st === 'ok' && !adj && <span className="vf-ls-tag ok">OK</span>}
                                                                {st === 'pending' && <span className="vf-ls-tag wait">Attente</span>}
                                                                {st === 'refused' && <span className="vf-ls-tag refused">Refusée</span>}
                                                            </div>
                                                        );
                                                    })}
                                                </div>
                                                <div className="vf-dec-total">
                                                    <span className="vf-dec-total-lbl">Total retenu</span>
                                                    <span className="vf-dec-total-val" style={{ color: nbModifs > 0 ? '#15803d' : '#111827' }}>{fmt(nbModifs > 0 ? totalAjuste : (note.montant || 0))}</span>
                                                </div>
                                                <div className="vf-dec-final">
                                                    {canValidate && <p className="vf-dec-hint ok"><CheckCircle size={9} style={{ display: 'inline', marginRight: 2 }} />Toutes conformes{nbModifs > 0 ? ` (${nbModifs} ajust.)` : ''}</p>}
                                                    {canReject && <p className="vf-dec-hint nok"><AlertTriangle size={9} style={{ display: 'inline', marginRight: 2 }} />{refusedCount} refusée{refusedCount > 1 ? 's' : ''}</p>}
                                                    {!allChecked && <p className="vf-dec-hint">{pendingCount} ligne{pendingCount > 1 ? 's' : ''} à vérifier</p>}
                                                    {canReject && (
                                                        <label className="vf-notify">
                                                            <input type="checkbox" checked={notifyOnReject} onChange={e => setNotifyOnReject(e.target.checked)} style={{ accentColor: '#dc2626' }} />
                                                            Notifier collaborateur & N1
                                                        </label>
                                                    )}
                                                    {canValidate && <button className="vf-btn-validate" disabled={submitting} onClick={() => submitDecision(note.id, 'validate', lignesData, [])}><CheckCircle size={11} />{submitting ? 'Envoi…' : 'Valider — Notifier Finance'}</button>}
                                                    {canReject && <button className="vf-btn-reject" disabled={submitting} onClick={() => submitDecision(note.id, 'reject', lignesData, refusedList)}><XCircle size={11} />{submitting ? 'Envoi…' : `Refuser (${refusedCount})`}</button>}
                                                    {!allChecked && <button className="vf-btn-validate" disabled><Clock size={11} /> Vérifiez toutes les lignes</button>}
                                                </div>
                                            </div>
                                        </div>
                                    </div>

                                </div>
                            )}
                        </div>
                    );
                }))}

                {/* History tab */}
                {activeTab === 'history' && (
                    <div>
                        <div className="vf-banner" style={{ background: '#f0fdf4', borderColor: '#86efac' }}>
                            <div style={{ width: 32, height: 32, borderRadius: 7, background: '#15803d', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><History size={15} color="#fff" /></div>
                            <div>
                                <div style={{ fontSize: 11, fontWeight: 700, color: '#15803d' }}>Historique des vérifications</div>
                                <div style={{ fontSize: 9, color: '#166534', marginTop: 1 }}>Traçabilité complète de vos contrôles Finance</div>
                            </div>
                            {history.length > 0 && <div style={{ marginLeft: 'auto', background: '#15803d', color: '#fff', fontSize: 10, fontWeight: 700, padding: '2px 9px', borderRadius: 20 }}>{history.length}</div>}
                        </div>
                        {!historyLoaded ? (
                            <div style={{ textAlign: 'center', padding: '40px 24px', color: '#6b7280' }}><Clock size={26} style={{ display: 'block', margin: '0 auto 8px', opacity: .4 }} /><p style={{ fontSize: 11 }}>Chargement…</p></div>
                        ) : history.length === 0 ? (
                            <div className="vf-empty"><History size={34} color="#a78bfa" style={{ display: 'block', margin: '0 auto 9px' }} /><p style={{ fontSize: 12, fontWeight: 700, color: '#5b21b6', marginBottom: 3 }}>Aucune vérification effectuée</p><span style={{ fontSize: 10, color: '#6b7280' }}>Les notes traitées apparaîtront ici</span></div>
                        ) : history.map((h, i) => {
                            const isRefusee = h.statut === 'REFUSEE' || (h.nbLignesRefusees ?? 0) > 0;
                            return (
                                <div key={i} className="vf-hist-card">
                                    <div className="vf-hist-hd">
                                        <div>
                                            <div style={{ display: 'flex', alignItems: 'center', gap: 5, marginBottom: 2, flexWrap: 'wrap' }}>
                                                <span style={{ fontFamily: 'DM Mono,monospace', fontSize: 9, fontWeight: 700, color: '#5b21b6', background: '#ede9fe', padding: '1px 5px', borderRadius: 20 }}>{h.reference}</span>
                                                <span className={`vf-hist-badge ${isRefusee ? 'refused' : 'ok'}`}>{isRefusee ? '✗ Refusée' : '✓ Validée'}</span>
                                            </div>
                                            <div style={{ fontSize: 12, fontWeight: 700, color: '#111827' }}>{h.libelle}</div>
                                            <div style={{ fontSize: 9, color: '#6b7280', marginTop: 1 }}>{[h.collaborateur, h.campus, h.departement].filter(Boolean).join(' · ')}</div>
                                        </div>
                                        <div style={{ textAlign: 'right' }}>
                                            <div style={{ fontSize: 15, fontWeight: 800, color: isRefusee ? '#dc2626' : '#15803d', fontFamily: 'DM Mono,monospace' }}>{fmt(h.montant || 0)}</div>
                                            <div style={{ fontSize: 9, color: '#6b7280' }}>{new Date(h.dateVerification).toLocaleDateString('fr-FR', { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' })}</div>
                                        </div>
                                    </div>
                                    <div className="vf-hist-body">
                                        <div className="vf-hist-stat"><FileText size={10} color="#6b7280" /><span style={{ color: '#6b7280' }}>{h.nbLignes} ligne{h.nbLignes > 1 ? 's' : ''}</span></div>
                                        {(h.nbLignesOk ?? 0) > 0 && <div className="vf-hist-stat"><CheckCircle size={10} color="#15803d" /><span style={{ color: '#15803d' }}>{h.nbLignesOk} OK</span></div>}
                                        {(h.nbLignesRefusees ?? 0) > 0 && <div className="vf-hist-stat"><XCircle size={10} color="#dc2626" /><span style={{ color: '#dc2626' }}>{h.nbLignesRefusees} refus.</span></div>}
                                        {h.commentaire && <div style={{ width: '100%' }}><div className="vf-hist-comment">💬 {h.commentaire}</div></div>}
                                    </div>
                                </div>
                            );
                        })}
                    </div>
                )}

                {/* Modal refus */}
                {modalNok && (
                    <div className="vf-modal-bg" onClick={() => { setModalNok(null); setNokReason(''); }}>
                        <div className="vf-modal" onClick={e => e.stopPropagation()}>
                            <div style={{ padding: '12px 15px', display: 'flex', alignItems: 'center', gap: 9, borderBottom: '1px solid #fee2e2', background: '#fff5f5' }}>
                                <div style={{ width: 30, height: 30, borderRadius: '50%', background: '#fee2e2', border: '1px solid #fca5a5', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, flexShrink: 0 }}>⚠️</div>
                                <div><div style={{ fontWeight: 700, fontSize: 12, color: '#991b1b' }}>Refuser cette ligne</div><div style={{ fontSize: 9, color: '#6b7280', marginTop: 1 }}>Le motif sera transmis au collaborateur</div></div>
                            </div>
                            <div style={{ padding: '13px 15px', display: 'flex', flexDirection: 'column', gap: 9 }}>
                                <div style={{ display: 'flex', alignItems: 'center', gap: 7, padding: '7px 9px', background: '#f9fafb', border: '1px solid #e5e7eb', borderRadius: 6 }}>
                                    <span style={{ fontSize: 13 }}>📋</span>
                                    <div><div style={{ fontSize: 9, color: '#6b7280' }}>Ligne</div><div style={{ fontSize: 11, fontWeight: 600, color: '#111827', marginTop: 1 }}>{modalNok.ligneLabel}</div></div>
                                </div>
                                <div>
                                    <label style={{ fontSize: 10, color: '#374151', fontWeight: 600, display: 'block', marginBottom: 4 }}>Motif <span style={{ color: '#dc2626' }}>*</span></label>
                                    <textarea value={nokReason} onChange={e => setNokReason(e.target.value)} autoFocus placeholder="Ex : Justificatif illisible, montant différent…"
                                        style={{ width: '100%', minHeight: 65, resize: 'vertical', padding: '6px 8px', fontSize: 11, borderRadius: 6, border: `1.5px solid ${nokReason.trim() ? '#d1d5db' : '#fca5a5'}`, fontFamily: 'DM Sans,sans-serif', color: '#111827', background: '#fff', boxSizing: 'border-box' as const }} />
                                    {!nokReason.trim() && <div style={{ fontSize: 9, color: '#dc2626', marginTop: 2 }}>Obligatoire</div>}
                                </div>
                                <div style={{ padding: '7px 9px', background: '#fffbeb', border: '1px solid #fde68a', borderRadius: 6, fontSize: 9, color: '#92400e' }}>💡 Le collaborateur ne corrigera <strong>que cette ligne</strong>.</div>
                            </div>
                            <div style={{ padding: '9px 15px', borderTop: '1px solid #e5e7eb', display: 'flex', justifyContent: 'flex-end', gap: 6, background: '#f9fafb' }}>
                                <button onClick={() => { setModalNok(null); setNokReason(''); }} style={{ padding: '5px 12px', background: '#fff', border: '1px solid #d1d5db', borderRadius: 6, cursor: 'pointer', fontFamily: 'inherit', fontSize: 11, color: '#374151', fontWeight: 500 }}>Annuler</button>
                                <button disabled={!nokReason.trim()} onClick={() => { if (!nokReason.trim() || !modalNok) return; setLigne(ligneKey(modalNok.noteId, modalNok.ligneIndex), 'refused', nokReason.trim()); setModalNok(null); setNokReason(''); }}
                                    style={{ padding: '5px 13px', background: nokReason.trim() ? '#dc2626' : '#fca5a5', color: '#fff', border: 'none', borderRadius: 6, cursor: nokReason.trim() ? 'pointer' : 'not-allowed', fontFamily: 'inherit', fontSize: 11, fontWeight: 700 }}>Confirmer le refus</button>
                            </div>
                        </div>
                    </div>
                )}

                {/* Modal montant */}
                {modalMontant && (() => {
                    const valeur = parseFloat(modalMontant.valeurSaisie.replace(',', '.'));
                    const isValid = !isNaN(valeur) && valeur > 0 && valeur <= modalMontant.montantOriginal;
                    const isOver = !isNaN(valeur) && valeur > modalMontant.montantOriginal;
                    const eco = isValid ? modalMontant.montantOriginal - valeur : 0;
                    return (
                        <div className="vf-modal-bg" onClick={() => setModalMontant(null)}>
                            <div className="vf-mnt-modal" onClick={e => e.stopPropagation()}>
                                <div className="vf-mnt-hd">
                                    <div className="vf-mnt-hd-icon">✂️</div>
                                    <div className="vf-mnt-hd-title">Ajuster le montant remboursé</div>
                                    <div className="vf-mnt-hd-sub">{modalMontant.ligneLabel}</div>
                                </div>
                                <div className="vf-mnt-body">
                                    <div className="vf-mnt-recap">
                                        <div className="vf-mnt-recap-item"><div className="vf-mnt-recap-lbl">Original</div><div className="vf-mnt-recap-val" style={{ color: '#dc2626' }}>{fmt(modalMontant.montantOriginal)}</div></div>
                                        <div className="vf-mnt-recap-item" style={{ background: '#f0fdf4', borderColor: '#86efac' }}><div className="vf-mnt-recap-lbl">Plafond légal</div><div className="vf-mnt-recap-val" style={{ color: '#15803d' }}>{fmt(modalMontant.montantProrataMax)}</div></div>
                                    </div>
                                    <button type="button" className={`vf-mnt-preset ${modalMontant.valeurSaisie === modalMontant.montantProrataMax.toFixed(2) ? 'active' : ''}`}
                                        onClick={() => setModalMontant(prev => prev ? { ...prev, valeurSaisie: prev.montantProrataMax.toFixed(2) } : null)}>
                                        ✓ Plafond exact — {fmt(modalMontant.montantProrataMax)}
                                    </button>
                                    <div style={{ fontSize: 10, fontWeight: 700, color: '#374151', marginBottom: 6 }}>Ou saisir un montant précis</div>
                                    <div className="vf-mnt-input-wrap">
                                        <input type="number" min="0.01" max={modalMontant.montantOriginal} step="0.01" className={`vf-mnt-input ${isOver ? 'error' : ''}`}
                                            value={modalMontant.valeurSaisie} autoFocus
                                            onChange={e => setModalMontant(prev => prev ? { ...prev, valeurSaisie: e.target.value } : null)}
                                            onKeyDown={e => { if (e.key === 'Enter' && isValid) { setMontantsModifies(prev => ({ ...prev, [`${modalMontant.noteId}-${modalMontant.ligneIndex}`]: valeur })); setModalMontant(null); } if (e.key === 'Escape') setModalMontant(null); }} />
                                        <span className="vf-mnt-currency">€</span>
                                    </div>
                                    <div className={`vf-mnt-hint ${isOver ? 'error' : ''}`}>{isOver ? `⛔ Max ${fmt(modalMontant.montantOriginal)}` : isValid && eco > 0 ? `Économie : ${fmt(eco)}` : `Entre 0,01 € et ${fmt(modalMontant.montantOriginal)}`}</div>
                                </div>
                                <div className="vf-mnt-footer">
                                    <button type="button" className="vf-mnt-btn-cancel" onClick={() => setModalMontant(null)}>Annuler</button>
                                    <button type="button" className="vf-mnt-btn-confirm" disabled={!isValid}
                                        onClick={() => { if (!isValid) return; setMontantsModifies(prev => ({ ...prev, [`${modalMontant.noteId}-${modalMontant.ligneIndex}`]: valeur })); setModalMontant(null); }}>
                                        <CheckCircle size={12} /> Confirmer — {isValid ? fmt(valeur) : '—'}
                                    </button>
                                </div>
                            </div>
                        </div>
                    );
                })()}

                {/* Modal commentaire validation */}
                {modalCommentaire && (
                    <div className="vf-modal-bg" onClick={() => setModalCommentaire(null)}>
                        <div className="vf-modal" onClick={e => e.stopPropagation()} style={{ maxWidth: 440 }}>
                            <div style={{ padding: '13px 17px', background: '#15803d', display: 'flex', alignItems: 'center', gap: 9 }}>
                                <div style={{ width: 32, height: 32, borderRadius: 7, background: 'rgba(255,255,255,.2)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 15 }}>✅</div>
                                <div><div style={{ fontSize: 13, fontWeight: 800, color: '#fff' }}>Valider la note</div><div style={{ fontSize: 9, color: 'rgba(255,255,255,.8)', marginTop: 1 }}>Commentaire (optionnel)</div></div>
                                <button onClick={() => setModalCommentaire(null)} style={{ marginLeft: 'auto', background: 'rgba(255,255,255,.2)', border: 'none', borderRadius: 6, width: 26, height: 26, cursor: 'pointer', color: '#fff', fontSize: 13, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>✕</button>
                            </div>
                            <div style={{ padding: '14px 17px', display: 'flex', flexDirection: 'column', gap: 10 }}>
                                {modalCommentaire.modifs.length > 0 && (
                                    <div style={{ background: '#fffbeb', border: '1px solid #fde68a', borderRadius: 7, padding: '9px 11px' }}>
                                        <div style={{ fontSize: 10, fontWeight: 700, color: '#92400e', marginBottom: 5 }}>✂️ {modalCommentaire.modifs.length} montant{modalCommentaire.modifs.length > 1 ? 's' : ''} ajusté{modalCommentaire.modifs.length > 1 ? 's' : ''}</div>
                                        {modalCommentaire.modifs.map((m, i) => { const l = modalCommentaire.lignesData[m.ligneIndex]; return (<div key={i} style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: '#78350f', padding: '2px 0', borderBottom: i < modalCommentaire.modifs.length - 1 ? '1px solid #fde68a' : 'none' }}><span>{l?.libelle || `Ligne ${m.ligneIndex + 1}`}</span><span style={{ fontFamily: 'DM Mono,monospace', fontWeight: 700 }}><span style={{ textDecoration: 'line-through', color: '#b45309', marginRight: 4 }}>{fmt(m.montantOriginal)}</span>→ {fmt(m.montantRetenu)}</span></div>); })}
                                    </div>
                                )}
                                <div>
                                    <label style={{ fontSize: 10, fontWeight: 700, color: '#374151', display: 'block', marginBottom: 5 }}>Commentaire</label>
                                    <textarea autoFocus value={commentaireInput} onChange={e => setCommentaireInput(e.target.value)} placeholder="Ex : Dossier complet, bon pour accord…"
                                        rows={3} style={{ width: '100%', padding: '7px 9px', border: '1.5px solid #d1d5db', borderRadius: 6, resize: 'vertical', fontFamily: 'DM Sans,sans-serif', fontSize: 11, color: '#111827', background: '#fff', outline: 'none', boxSizing: 'border-box' as const }}
                                        onKeyDown={e => { if (e.key === 'Enter' && e.ctrlKey) submitValidation(modalCommentaire.noteId, modalCommentaire.lignesData, modalCommentaire.modifs, commentaireInput.trim()); }} />
                                    <div style={{ fontSize: 9, color: '#9ca3af', marginTop: 2 }}>Ctrl+Entrée pour valider</div>
                                </div>
                            </div>
                            <div style={{ padding: '9px 17px', borderTop: '1px solid #e5e7eb', display: 'flex', justifyContent: 'flex-end', gap: 6, background: '#f9fafb' }}>
                                <button onClick={() => setModalCommentaire(null)} style={{ padding: '7px 13px', background: '#fff', border: '1.5px solid #e5e7eb', borderRadius: 6, cursor: 'pointer', fontFamily: 'inherit', fontSize: 11, fontWeight: 600, color: '#6b7280' }}>Annuler</button>
                                <button disabled={submitting} onClick={() => submitValidation(modalCommentaire.noteId, modalCommentaire.lignesData, modalCommentaire.modifs, commentaireInput.trim())}
                                    style={{ padding: '7px 16px', background: submitting ? '#86efac' : '#15803d', color: '#fff', border: 'none', borderRadius: 6, cursor: submitting ? 'not-allowed' : 'pointer', fontFamily: 'inherit', fontSize: 11, fontWeight: 700, display: 'flex', alignItems: 'center', gap: 5 }}>
                                    {submitting ? '⏳ Envoi…' : '✅ Confirmer'}
                                </button>
                            </div>
                        </div>
                    </div>
                )}
            </div>
        </>
    );
} 