Files
html/wevads-ia/index.html
2026-04-12 22:57:03 +02:00

1680 lines
269 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr"><head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>WEVADS IA — Omnichannel Intelligence Platform</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.9.0/mermaid.min.js"></script>
<script>document.addEventListener('DOMContentLoaded',function(){mermaid.initialize({startOnLoad:false,theme:'dark',themeVariables:{primaryColor:'#d4a843',primaryTextColor:'#f1f5f9',primaryBorderColor:'#c49a38',lineColor:'#5a6a80',secondaryColor:'#0f172a',tertiaryColor:'#080d1a'},logLevel:'fatal'});
(function(){var obs=new MutationObserver(function(muts){muts.forEach(function(m){m.addedNodes.forEach(function(n){if(n.nodeType===1&&n.textContent&&n.textContent.indexOf('Syntax error')>=0&&n.style&&(n.style.position==='fixed'||n.style.zIndex>9000)){n.remove()}})})});obs.observe(document.body||document.documentElement,{childList:true,subtree:true})})();
});</script>
<style>
.ai-tbl{width:100%;border-collapse:collapse;margin:10px 0;font-size:12px}
.ai-tbl th{background:var(--sf);color:var(--ac);font-size:10px;text-transform:uppercase;letter-spacing:.08em;padding:8px 12px;border:1px solid var(--bd2);text-align:left}
.ai-tbl td{padding:8px 12px;border:1px solid var(--bd);color:var(--tx)}
.ai-tbl tr:hover td{background:var(--acB)}
.merm-box svg{max-width:100%;height:auto}
.chat-a{line-height:1.7}
.ai-badge{display:inline-flex;align-items:center;gap:4px;font-size:10px;padding:3px 8px;border-radius:12px;margin-top:8px;font-family:var(--m)}
</style>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>:root{
--bg:#050810;--bg2:#080d1a;--sf:#0c1324;--card:#0f172a;--card2:#131c33;--hov:#162040;
--bd:rgba(255,255,255,.04);--bd2:rgba(255,255,255,.08);--bd3:rgba(255,255,255,.12);
--tx:#94a3b8;--mu:#5a6a80;--dm:#374151;--wh:#f1f5f9;
--ac:#d4a843;--ac2:#eacc6b;--ac3:#c49a38;--acB:rgba(212,168,67,.06);--acBd:rgba(212,168,67,.18);--acG:rgba(212,168,67,.03);
--cy:#22d3ee;--gn:#34d399;--gnB:rgba(52,211,153,.06);--rd:#f87171;--rdB:rgba(248,113,113,.06);
--or:#fb923c;--pu:#a78bfa;--puB:rgba(167,139,250,.06);--bl:#60a5fa;--blB:rgba(96,165,250,.06);
--em:#60a5fa;--sm:#34d399;--wa:#25d366;--tg:#229ED9;
--r:14px;--r2:18px;--r3:10px;--rs:6px;
--f:'Outfit',system-ui,-apple-system,sans-serif;--m:'JetBrains Mono',monospace;
--shadow:0 4px 24px rgba(0,0,0,.25),0 1px 2px rgba(0,0,0,.15);
--shadowL:0 8px 40px rgba(0,0,0,.4);
--glass:rgba(255,255,255,.02);--glassB:rgba(255,255,255,.05)
}
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:var(--f);background:var(--bg);color:var(--tx);display:flex;height:100vh;overflow:hidden;font-size:14px;-webkit-font-smoothing:antialiased;letter-spacing:.01em}
::selection{background:rgba(212,168,67,.2);color:var(--wh)}
.mermaid-error,.error-icon,.error-text{display:none!important}
div[style*="position: fixed"][style*="bottom"]{display:none!important}
[id^="dmermaid"]{display:none!important}
::-webkit-scrollbar{width:5px}::-webkit-scrollbar-thumb{background:var(--bd3);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--bd2)}::-webkit-scrollbar-track{background:transparent}
.drill-modal{position:fixed;inset:0;background:rgba(0,0,0,.7);z-index:300;display:flex;align-items:center;justify-content:center;animation:fadeIn .2s;backdrop-filter:blur(4px)}
.drill-box{background:var(--card);border:1px solid var(--bd2);border-radius:24px;padding:28px;width:640px;max-width:92vw;max-height:85vh;overflow-y:auto;animation:fadeUp .3s cubic-bezier(.16,1,.3,1);box-shadow:var(--shadowL)}
.drill-box h3{color:var(--wh);font-size:18px;margin-bottom:16px;display:flex;align-items:center;gap:10px}
.drill-box .drill-close{margin-left:auto;width:32px;height:32px;border-radius:50%;background:var(--bd2);color:var(--mu);display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:16px;transition:all .2s}
.drill-box .drill-close:hover{background:var(--rdB);color:var(--rd)}
.drill-kpi{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:16px}
.drill-kpi .dk{background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);padding:14px;text-align:center}
.drill-kpi .dk .dkv{font-size:22px;font-weight:700;color:var(--ac);font-family:var(--m)}
.drill-kpi .dk .dkl{font-size:10px;color:var(--mu);margin-top:4px;text-transform:uppercase;letter-spacing:.08em}
.drill-chart{background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);padding:16px;margin:12px 0}
.page-transition{animation:fadeUp .25s cubic-bezier(.16,1,.3,1)}
.stat{transition:transform .15s,box-shadow .15s}
.stat:hover{transform:translateY(-2px);box-shadow:0 4px 20px rgba(212,168,67,.08)}
.loading-shimmer{background:linear-gradient(90deg,var(--sf) 25%,var(--hov) 50%,var(--sf) 75%);background-size:200% 100%;animation:shimmer 1.5s infinite}
.btn-ac{position:relative;overflow:hidden}
.btn-ac::after{content:'';position:absolute;inset:0;background:linear-gradient(90deg,transparent,rgba(255,255,255,.05),transparent);transform:translateX(-100%);transition:transform .4s}
.btn-ac:hover::after{transform:translateX(100%)}
a{color:var(--ac);text-decoration:none;transition:color .2s}a:hover{color:var(--ac2)}
button{font-family:var(--f);cursor:pointer;border:none;outline:none;transition:all .2s}
input,select,textarea{font-family:var(--f);outline:none;background:var(--bg);border:1px solid var(--bd2);color:var(--wh);border-radius:var(--r3);padding:11px 16px;font-size:13px;transition:all .25s;letter-spacing:.01em}
input:focus,select:focus,textarea:focus{border-color:var(--ac3);box-shadow:0 0 0 3px var(--acG),0 0 20px var(--acG)}
input::placeholder{color:var(--dm);font-weight:300}
select{cursor:pointer;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%235a6a80' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 12px center;padding-right:32px}
table{width:100%;border-collapse:separate;border-spacing:0}
th{text-align:left;font-size:10px;font-weight:700;color:var(--mu);text-transform:uppercase;letter-spacing:.1em;padding:12px 16px;border-bottom:1px solid var(--bd2);background:var(--sf)}
td{padding:12px 16px;border-bottom:1px solid var(--bd);font-size:13px;transition:background .15s}
tr:hover td{background:rgba(212,168,67,.015)}
tbody tr{transition:transform .15s}
@keyframes fadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
@keyframes slideR{from{opacity:0;transform:translateX(-10px)}to{opacity:1;transform:none}}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
@keyframes glow{0%,100%{box-shadow:0 0 20px rgba(212,168,67,.08)}50%{box-shadow:0 0 40px rgba(212,168,67,.15)}}
@keyframes shimmer{0%{background-position:-200% 0}100%{background-position:200% 0}}
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes toastIn{from{opacity:0;transform:translateX(40px)}to{opacity:1;transform:none}}
@keyframes borderGlow{0%,100%{border-color:rgba(212,168,67,.1)}50%{border-color:rgba(212,168,67,.25)}}
@keyframes float{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}
.login-wrap{position:fixed;inset:0;background:var(--bg);display:flex;align-items:center;justify-content:center;z-index:200;overflow:hidden}
.login-wrap::before{content:'';position:absolute;width:600px;height:600px;background:radial-gradient(circle,rgba(212,168,67,.04),transparent 70%);top:20%;left:50%;transform:translateX(-50%);pointer-events:none}
.login-wrap::after{content:'';position:absolute;width:400px;height:400px;background:radial-gradient(circle,rgba(96,165,250,.02),transparent 70%);bottom:10%;right:15%;pointer-events:none}
.login-box{background:linear-gradient(135deg,var(--card),var(--card2));border:1px solid var(--bd2);border-radius:28px;padding:48px 44px;width:420px;max-width:92vw;animation:fadeUp .6s cubic-bezier(.16,1,.3,1);position:relative;box-shadow:var(--shadowL);backdrop-filter:blur(20px)}
.login-box::before{content:'';position:absolute;top:0;left:20%;right:20%;height:1px;background:linear-gradient(90deg,transparent,var(--ac),transparent)}
.login-logo{width:54px;height:54px;background:linear-gradient(135deg,var(--ac),var(--ac2));border-radius:16px;display:flex;align-items:center;justify-content:center;margin:0 auto 20px;font-weight:900;color:#0a0d13;font-size:22px;animation:glow 4s ease-in-out infinite;box-shadow:0 8px 30px rgba(212,168,67,.15)}
.login-box h1{font-size:24px;font-weight:800;color:var(--wh);text-align:center;letter-spacing:-.04em}
.login-box .sub{font-size:12px;color:var(--mu);text-align:center;margin:6px 0 4px;font-weight:400}
.login-box .ver{font-size:10px;color:var(--dm);text-align:center;margin-bottom:24px;font-family:var(--m);letter-spacing:.05em}
.field{margin-bottom:14px}.field label{display:block;font-size:10px;font-weight:600;color:var(--mu);margin-bottom:6px;text-transform:uppercase;letter-spacing:.08em}.field input,.field select,.field textarea{width:100%}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:11px 22px;border-radius:12px;font-size:13px;font-weight:600;transition:all .25s cubic-bezier(.16,1,.3,1);letter-spacing:.01em;position:relative;overflow:hidden}
.btn::after{content:'';position:absolute;inset:0;background:linear-gradient(135deg,transparent 40%,rgba(255,255,255,.05) 50%,transparent 60%);opacity:0;transition:opacity .3s}
.btn:hover::after{opacity:1}
.btn-full{width:100%}
.btn-ac{background:linear-gradient(135deg,var(--ac),var(--ac2));color:#0a0d13;box-shadow:0 4px 16px rgba(212,168,67,.2)}.btn-ac:hover{filter:brightness(1.08);transform:translateY(-2px);box-shadow:0 8px 24px rgba(212,168,67,.3)}
.btn-gh{background:var(--glass);color:var(--tx);border:1px solid var(--bd2);backdrop-filter:blur(4px)}.btn-gh:hover{border-color:var(--bd3);background:var(--glassB);transform:translateY(-1px)}
.btn-sm{padding:8px 16px;font-size:12px;border-radius:var(--r3)}.btn-rd{background:var(--rdB);color:var(--rd);border:1px solid rgba(248,113,113,.1)}.btn-rd:hover{background:rgba(248,113,113,.12)}
.divider{display:flex;align-items:center;gap:14px;margin:20px 0;color:var(--dm);font-size:11px;font-weight:500}.divider::before,.divider::after{content:'';flex:1;height:1px;background:linear-gradient(90deg,transparent,var(--bd2),transparent)}
.sidebar{width:256px;background:linear-gradient(180deg,var(--bg2),var(--bg));border-right:1px solid var(--bd);display:flex;flex-direction:column;flex-shrink:0;position:relative}
.sidebar::after{content:'';position:absolute;top:0;right:0;bottom:0;width:1px;background:linear-gradient(180deg,transparent,rgba(212,168,67,.08),transparent)}
.sb-brand{padding:20px;display:flex;align-items:center;gap:12px;border-bottom:1px solid var(--bd)}
.sb-logo{width:36px;height:36px;background:linear-gradient(135deg,var(--ac),var(--ac2));border-radius:11px;display:flex;align-items:center;justify-content:center;font-weight:900;color:#0a0d13;font-size:16px;box-shadow:0 4px 12px rgba(212,168,67,.15);animation:float 6s ease-in-out infinite}
.sb-brand-name{font-size:16px;font-weight:800;color:var(--wh);letter-spacing:-.03em}.sb-brand-sub{font-size:8px;color:var(--dm);font-family:var(--m);letter-spacing:.06em;margin-top:1px}
.sb-ch{display:flex;gap:5px;padding:14px 18px;border-bottom:1px solid var(--bd)}
.sb-chip{flex:1;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:700;position:relative;transition:all .2s}
.sb-chip.on{opacity:1;box-shadow:0 2px 8px rgba(0,0,0,.2)}.sb-chip.off{opacity:.25}
.sb-chip-em{background:rgba(96,165,250,.08);color:var(--em);border:1px solid rgba(96,165,250,.1)}.sb-chip-sm{background:rgba(52,211,153,.08);color:var(--sm);border:1px solid rgba(52,211,153,.1)}
.sb-chip-wa{background:rgba(37,211,102,.08);color:var(--wa);border:1px solid rgba(37,211,102,.1)}.sb-chip-tg{background:rgba(34,158,217,.08);color:var(--tg);border:1px solid rgba(34,158,217,.1)}
.sb-chip .dot{position:absolute;top:3px;right:3px;width:5px;height:5px;border-radius:50%;box-shadow:0 0 6px currentColor}.dot-on{background:var(--gn)}.dot-off{background:var(--rd)}
.sb-nav{flex:1;overflow-y:auto;padding:8px 10px}
.sb-sec{padding:16px 12px 6px;font-size:8px;font-weight:700;color:var(--dm);text-transform:uppercase;letter-spacing:.14em}
.sb-it{display:flex;align-items:center;gap:10px;padding:10px 14px;border-radius:12px;cursor:pointer;font-size:12.5px;color:var(--mu);font-weight:500;transition:all .2s cubic-bezier(.16,1,.3,1);margin-bottom:2px;position:relative;border:1px solid transparent}
.sb-it:hover{background:rgba(255,255,255,.02);color:var(--tx);transform:translateX(2px)}
.sb-it.on{background:var(--acB);color:var(--ac);border-color:var(--acBd);box-shadow:0 0 20px var(--acG),inset 0 0 20px var(--acG)}
.sb-it.on::before{content:'';position:absolute;left:-10px;top:50%;transform:translateY(-50%);width:3px;height:20px;background:var(--ac);border-radius:0 3px 3px 0;box-shadow:0 0 10px var(--ac)}
.sb-it svg{width:16px;height:16px;flex-shrink:0;opacity:.45;transition:opacity .2s}.sb-it.on svg{opacity:.9}
.sb-it .cnt{margin-left:auto;font-size:9px;font-family:var(--m);background:var(--acB);color:var(--ac);padding:2px 7px;border-radius:10px;font-weight:600}
.sb-user{padding:14px 16px;border-top:1px solid var(--bd);display:flex;align-items:center;gap:10px;background:linear-gradient(180deg,transparent,rgba(212,168,67,.02))}
.sb-av{width:32px;height:32px;border-radius:10px;background:linear-gradient(135deg,var(--ac),var(--ac2));display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:800;color:#0a0d13;flex-shrink:0;box-shadow:0 3px 10px rgba(212,168,67,.15)}
.sb-un{font-size:12px;font-weight:600;color:var(--wh)}.sb-ut{font-size:9px;color:var(--dm);font-family:var(--m)}
.sb-out{padding:6px;border-radius:8px;background:transparent;color:var(--dm);cursor:pointer;transition:all .2s;margin-left:auto}.sb-out:hover{background:var(--rdB);color:var(--rd);transform:scale(1.1)}
.main{flex:1;display:flex;flex-direction:column;overflow:hidden;background:linear-gradient(135deg,var(--bg),rgba(8,13,26,.95))}
.top{height:54px;border-bottom:1px solid var(--bd);display:flex;align-items:center;padding:0 28px;gap:14px;background:rgba(8,13,26,.6);backdrop-filter:blur(12px);flex-shrink:0;position:relative}
.top::after{content:'';position:absolute;bottom:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,var(--bd2),transparent)}
.top h2{font-size:17px;font-weight:700;color:var(--wh);flex:1;letter-spacing:-.02em}
.top-live{font-family:var(--m);font-size:9px;padding:5px 12px;border-radius:20px;display:flex;align-items:center;gap:6px;color:var(--gn);background:var(--gnB);border:1px solid rgba(52,211,153,.1);backdrop-filter:blur(4px)}
.top-live::before{content:'';width:6px;height:6px;border-radius:50%;background:var(--gn);animation:pulse 2s infinite;box-shadow:0 0 8px var(--gn)}
.content{flex:1;overflow-y:auto;padding:28px;scroll-behavior:smooth}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:14px;margin-bottom:28px}
.stat{background:linear-gradient(135deg,var(--card),var(--card2));border:1px solid var(--bd);border-radius:var(--r2);padding:20px;position:relative;overflow:hidden;transition:all .3s cubic-bezier(.16,1,.3,1);cursor:default;animation:fadeUp .4s ease both}
.stat:nth-child(1){animation-delay:.05s}.stat:nth-child(2){animation-delay:.1s}.stat:nth-child(3){animation-delay:.15s}.stat:nth-child(4){animation-delay:.2s}.stat:nth-child(5){animation-delay:.25s}.stat:nth-child(6){animation-delay:.3s}
.stat:hover{border-color:var(--bd3);transform:translateY(-3px);box-shadow:var(--shadow)}
.stat::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;transition:height .3s}
.stat:hover::before{height:3px}
.stat::after{content:'';position:absolute;top:0;left:0;right:0;bottom:0;background:radial-gradient(circle at 50% 0%,rgba(255,255,255,.02),transparent 60%);pointer-events:none;opacity:0;transition:opacity .3s}
.stat:hover::after{opacity:1}
.s-ac::before{background:linear-gradient(90deg,var(--ac),var(--ac2))}.s-bl::before{background:var(--bl)}.s-gn::before{background:var(--gn)}.s-rd::before{background:var(--rd)}.s-pu::before{background:var(--pu)}.s-tg::before{background:var(--tg)}.s-or::before{background:var(--or)}
.st-l{font-size:10px;font-weight:600;color:var(--mu);text-transform:uppercase;letter-spacing:.06em;margin-bottom:8px}
.st-v{font-size:28px;font-weight:800;color:var(--wh);font-family:var(--m);letter-spacing:-.04em;line-height:1;text-shadow:0 2px 10px rgba(0,0,0,.3)}
.st-s{font-size:10px;margin-top:8px;font-weight:500;color:var(--mu)}.st-s .up{color:var(--gn)}.st-s .dn{color:var(--rd)}
.card{background:linear-gradient(135deg,var(--card),var(--card2));border:1px solid var(--bd);border-radius:var(--r2);padding:22px;margin-bottom:16px;transition:all .3s;animation:fadeUp .4s ease both;position:relative;overflow:hidden}
.card:hover{border-color:var(--bd2)}
.card-h{display:flex;align-items:center;justify-content:space-between;margin-bottom:18px}
.card-t{font-size:15px;font-weight:700;color:var(--wh);letter-spacing:-.01em}
.badge{display:inline-flex;align-items:center;gap:4px;padding:4px 11px;border-radius:20px;font-size:9px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;backdrop-filter:blur(4px)}
.b-ok{background:var(--gnB);color:var(--gn);border:1px solid rgba(52,211,153,.08)}.b-sent{background:var(--gnB);color:var(--gn)}.b-wait{background:rgba(251,146,60,.06);color:var(--or);border:1px solid rgba(251,146,60,.08)}.b-err{background:var(--rdB);color:var(--rd)}.b-em{background:var(--blB);color:var(--bl);border:1px solid rgba(96,165,250,.08)}.b-ac{background:var(--acB);color:var(--ac);border:1px solid var(--acBd)}
.modal-bg{position:fixed;inset:0;background:rgba(0,0,0,.6);backdrop-filter:blur(8px);z-index:100;display:flex;align-items:center;justify-content:center;animation:fadeIn .15s}
.modal{background:linear-gradient(135deg,var(--card),var(--card2));border:1px solid var(--bd2);border-radius:24px;padding:32px;width:560px;max-width:92vw;max-height:85vh;overflow-y:auto;box-shadow:var(--shadowL);animation:fadeUp .3s cubic-bezier(.16,1,.3,1)}
tr[onclick]{transition:background .15s}tr[onclick]:hover{background:rgba(129,140,248,.06)!important}
.modal h3{font-size:18px;font-weight:700;color:var(--wh);margin-bottom:20px;letter-spacing:-.02em}.modal .brow{display:flex;gap:10px;margin-top:20px}
.ch-sel{display:flex;gap:7px;margin:10px 0}.ch-p{padding:8px 16px;border-radius:20px;font-size:11px;font-weight:600;cursor:pointer;transition:all .25s;border:1px solid var(--bd2);background:var(--glass);color:var(--mu);backdrop-filter:blur(4px)}
.ch-p:hover{border-color:var(--bd3);transform:scale(1.02)}
.ch-p.sel{border-color:currentColor;transform:scale(1.02)}.ch-p[data-c=email].sel{background:var(--blB);color:var(--em)}.ch-p[data-c=sms].sel{background:var(--gnB);color:var(--sm)}.ch-p[data-c=whatsapp].sel{background:rgba(37,211,102,.06);color:var(--wa)}.ch-p[data-c=telegram].sel{background:rgba(34,158,217,.06);color:var(--tg)}
.chat-w{display:flex;flex-direction:column;height:100%}.chat-m{flex:1;overflow-y:auto;padding:0 4px 14px}
.chat-e{text-align:center;padding:60px 20px;color:var(--dm)}.chat-e h3{color:var(--mu);margin-top:12px;font-size:16px;font-weight:600}
.chat-u{background:linear-gradient(135deg,var(--acB),rgba(212,168,67,.03));border:1px solid var(--acBd);border-radius:var(--r) var(--r) 4px var(--r);padding:14px 18px;margin:8px 0;max-width:75%;margin-left:auto;font-size:13px;color:var(--wh);line-height:1.6;animation:fadeUp .2s ease}
.chat-a{background:linear-gradient(135deg,var(--sf),var(--card));border:1px solid var(--bd);border-radius:4px var(--r) var(--r) var(--r);padding:16px 20px;margin:8px 0;max-width:85%;font-size:13px;line-height:1.7;animation:fadeUp .2s ease}
.chat-a pre{background:var(--bg);padding:12px;border-radius:var(--r3);overflow-x:auto;font-family:var(--m);font-size:12px;margin:8px 0;border:1px solid var(--bd)}
.chat-a code{font-family:var(--m);font-size:12px;background:var(--bg);padding:2px 6px;border-radius:4px;border:1px solid var(--bd)}
.chat-b{display:flex;gap:10px;padding:14px 0 0;border-top:1px solid var(--bd)}.chat-b textarea{flex:1;resize:none;min-height:44px;max-height:120px;font-size:13px;line-height:1.5;border-radius:14px}
.ldot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--ac);margin:0 3px;animation:pulse .8s infinite}.ldot:nth-child(2){animation-delay:.15s}.ldot:nth-child(3){animation-delay:.3s}
.spinner{width:20px;height:20px;border:2px solid var(--bd2);border-top-color:var(--ac);border-radius:50%;animation:spin .6s linear infinite;display:inline-block}
.toolbar{display:flex;align-items:center;gap:10px;margin-bottom:18px;flex-wrap:wrap;animation:fadeUp .3s ease}.toolbar .sp{flex:1}
.toolbar input[type=search]{width:280px;background:var(--sf);padding-left:38px;border-radius:14px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%235a6a80' stroke-width='2'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:13px center}
.toast{position:fixed;bottom:24px;right:24px;background:linear-gradient(135deg,var(--card),var(--card2));color:var(--wh);padding:14px 24px;border-radius:16px;font-size:13px;font-weight:500;z-index:9999;display:none;border:1px solid var(--bd2);box-shadow:var(--shadowL);animation:toastIn .3s cubic-bezier(.16,1,.3,1);backdrop-filter:blur(12px)}
.toast.err{border-color:rgba(248,113,113,.15);color:var(--rd)}
.tags{display:flex;flex-wrap:wrap;gap:5px}.tag{padding:3px 10px;border-radius:14px;font-size:9px;font-weight:600;background:var(--glass);border:1px solid var(--bd);color:var(--mu);backdrop-filter:blur(4px)}
.ed{width:100%;min-height:180px;font-family:var(--m);font-size:12px;line-height:1.6;background:var(--bg);border-radius:var(--r3);padding:16px;resize:vertical;border:1px solid var(--bd2)}
.row2{display:grid;grid-template-columns:1fr 1fr;gap:18px}
@media(max-width:768px){.sidebar{width:56px}.sb-brand-name,.sb-brand-sub,.sb-sec,.sb-it span,.sb-un,.sb-ut,.sb-ch{display:none}.sb-it{justify-content:center;padding:10px}.content{padding:16px}.row2{grid-template-columns:1fr}}
</style><script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js">
</script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/grapesjs/0.21.13/css/grapes.min.css">
</head><body>
<div class="login-wrap" id="LW" style="display:none"><div class="login-box"><div class="login-logo">W</div><h1>WEVADS IA</h1><p class="sub">Omnichannel Intelligence Platform</p><p class="ver">v3.3 — Sovereign Engine · 49 APIs · 688 Tables</p>
<div id="LF"><div class="field"><label>Email</label><input type="email" id="lE" placeholder="yacineutt@gmail.com"></div><div class="field"><label>Mot de passe</label><input type="password" id="lP" onkeydown="if(event.key==='Enter')doLogin()"></div><button class="btn btn-ac btn-full" onclick="doLogin()" id="bL">Se connecter</button><div class="divider">ou</div><button class="btn btn-gh btn-full" onclick="sR()">Créer un compte</button></div>
<div id="RF" style="display:none"><div class="field"><label>Nom</label><input id="rN"></div><div class="field"><label>Email</label><input type="email" id="rE"></div><div class="field"><label>Entreprise</label><input id="rC"></div><div class="field"><label>Mot de passe</label><input type="password" id="rP" onkeydown="if(event.key==='Enter')doReg()"></div><button class="btn btn-ac btn-full" onclick="doReg()" id="bR">Créer</button><div class="divider">ou</div><button class="btn btn-gh btn-full" onclick="sL()">Connexion</button></div>
</div></div>
<div class="sidebar" id="SB" style="display:none"><div class="sb-brand"><div class="sb-logo" style="padding:0;background:none;border-radius:12px;overflow:hidden"><img src="/assets/logo-wevads-Crayl4yz.png" alt="WEVADS IA" style="width:100%;height:100%;object-fit:contain"></div><div><span class="sb-brand-name">WEVADS IA</span><br><span class="sb-brand-sub">v3.3 OMNICHANNEL</span></div></div>
<div class="sb-ch"><div class="sb-chip sb-chip-em on"><span class="dot dot-on"></span></div><div class="sb-chip sb-chip-sm on"><span class="dot dot-on"></span>SMS</div><div class="sb-chip sb-chip-wa on"><span class="dot dot-on"></span>WA</div><div class="sb-chip sb-chip-tg on"><span class="dot dot-on"></span>TG</div></div>
<div class="sb-nav" id="SN"></div>
<div class="sb-user"><div class="sb-av" id="sA">W</div><div style="flex:1;min-width:0"><div class="sb-un" id="sU"></div><div class="sb-ut" id="sT">admin</div></div><div class="sb-out" onclick="logout()" title="Déconnexion"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg></div></div></div>
<div class="main" id="MA" style="display:none"><div class="top"><h2 id="PT">Dashboard</h2><div class="top-live" id="TL">Backend Live</div></div><div class="content" id="C"></div></div>
<div class="toast" id="T"></div>
<script>
const API='/api/v2',V2E='/api/wevads-v2-engine.php',BRG='/api/adx-bridge.php',WEVIA='/api/weval-ia-fast.php',SE='/api/send-engine-unified.php';
let TK='',U={},PG='dashboard';
const $=id=>document.getElementById(id),v=id=>$(id)?$(id).value.trim():'';
const P=[
['dashboard','Dashboard','M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 14h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7z','Principal'],
['send','⚡ Envoyer','M13 2L3 14h9l-1 8 10-12h-9l1-8z','Principal'],
['campaigns','Campagnes','M2 4h20v16H2V4zm0 4h20M2 8l10 5 10-5','Principal'],
['contacts','Contacts','M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2M9 7a4 4 0 1 0 0-8 4 4 0 0 0 0 8M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75','Principal'],
['senders','Senders','M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2zM22 6l-10 7L2 6','Email Ops'],
['warmup','Warmup','M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83','Email Ops'],
['domains','Domaines','M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zM2 12h20M12 2a15 15 0 0 1 4 10 15 15 0 0 1-4 10 15 15 0 0 1-4-10 15 15 0 0 1 4-10z','Email Ops'],
['seeds','Seeds','M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z','Email Ops'],
['reputation','Réputation','M9 12l2 2 4-4M20.6 6.7A9.94 9.94 0 0 0 12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10c0-1.5-.3-2.9-.9-4.2','Email Ops'],
['brain','Brain IA','M4 4h16v16H4V4zM9 9h6v6H9V9zM9 1v3M15 1v3M9 20v3M15 20v3M20 9h3M20 14h3M1 9h3M1 14h3','Intelligence'],
['creative','Creative','M12 20h9M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z','Intelligence'],
['analytics','Analytics','M18 20V10M12 20V4M6 20v-6','Intelligence'],
['ai','AI Assistant','M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z','Intelligence'],
['channels','Canaux','M12 12m-2 0a2 2 0 1 0 4 0 2 2 0 1 0-4 0M16.24 7.76a6 6 0 0 1 0 8.49m-8.48-.01a6 6 0 0 1 0-8.49m11.31-2.82a10 10 0 0 1 0 14.14m-14.14 0a10 10 0 0 1 0-14.14','Omnichannel'],
['templates','Templates','M3 3h18v18H3V3zM3 9h18M9 21V9','Omnichannel'],
['offers','Offres','M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82zM7 7h.01','Business'],
['sponsors','Sponsors','M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2M9 7a4 4 0 1 0 0-8 4 4 0 0 0 0 8M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75','Business'],
['servers','Serveurs','M22 12h-6l-2 3h-4l-2-3H2M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z','Système'],
['infra','Infrastructure','M22 12h-6l-2 3h-4l-2-3H2M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z','Système'],
['settings','Paramètres','M12 12m-3 0a3 3 0 1 0 6 0 3 3 0 1 0-6 0M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42','Système'],
['worldmap','World Map','M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z','Monitoring'],
['spamscore','Spam Score','M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z','Quality'],
['heatmap','Heatmap ISP','M3 3h7v7H3V3zm11 0h7v7h-7V3zm0 11h7v7h-7v-7zM3 14h7v7H3v-7z','Analytics'],
['darkmatrix','Dark Matrix','M4 4h16v16H4V4zM9 9h6v6H9V9zM9 1v3M15 1v3M9 20v3M15 20v3M20 9h3M20 14h3M1 9h3M1 14h3','Intelligence'],
['scraping','Scraping','M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z','Data'],
['consent','Consent GDPR','M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z','Data'],
['bouncemanager','Bounces','M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z','Data'],
['o365cmd','O365 Center','M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z','Infra'],
['dnsmanager','DNS Manager','M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z','Infra'],
['datavalidation','Validation','M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z','Data'],
['trackingdash','Tracking Live','M1 12s4-8 11-8 11 8-11 8z','Analytics'],
['serversupervision','Servers','M22 12h-4l-3 9L9 3l-3 9H2','Infra'],
['securitymon','Security','M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z','Infra'],
['webhookmgr','Webhooks','M13 2L3 14h9l-1 8 10-12h-9l1-8z','Data'],
['n8ndash','N8N Workflows','M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z','Infra'],
['leadscore','Lead Scoring','M16 21v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2','Data'],
['newslettermgr','Newsletter','M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z','Data'],
['predictive','Predictive Send','M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z','Intelligence'],
['providermgr','Providers','M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2','Infra'],
['competitorspy','Competitors','M15 12a3 3 0 11-6 0 3 3 0 016 0z','Intelligence'],
['delivplay','Deliverability','M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z','Data'],
['unifiedinbox','Unified Inbox','M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2z','Principal'],
['arsenaltools','Arsenal Tools','M4 4h16v16H4V4zM9 9h6v6H9V9z','Intelligence'],
['smsgateway','SMS Gateway','M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07','Channels'],
['reputmon','Reputation Live','M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0 1 12 2.944a11.955 11.955 0 0 1-8.618 3.04A12.02 12.02 0 0 0 3 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z','Quality'],
['smartpdf','Smart PDF','M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6 M16 13H8 M16 17H8 M10 9H8','Business'],
];
function ico(d){return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="${d}"/><\/svg>`}
function toast(m,e){const t=$('T');t.textContent=m;t.className=e?'toast err':'toast';t.style.display='block';setTimeout(()=>t.style.display='none',3500)}
function esc(s){const d=document.createElement('div');d.textContent=s||'';return d.innerHTML}
function N(n){return new Intl.NumberFormat('fr-FR').format(n||0)}
function D(d){return d?new Date(d).toLocaleDateString('fr-FR',{day:'2-digit',month:'short',year:'numeric'}):''}
function md2h(t){
// Rich markdown → HTML renderer for WEVADS IA
// Tables
t=t.replace(/\n\|(.+)\|\n\|[-:| ]+\|\n((?:\|.+\|\n?)+)/g,function(m,h,rows){
var ths=h.split('|').map(function(c){return '<th>'+c.trim()+'</th>'}).join('');
var trs=rows.trim().split('\n').map(function(r){return '<tr>'+r.split('|').filter(function(c){return c.trim()}).map(function(c){return '<td>'+c.trim()+'</td>'}).join('')+'</tr>'}).join('');
return '<table class="ai-tbl"><thead><tr>'+ths+'</tr></thead><tbody>'+trs+'</tbody></table>'});
// Mermaid blocks → render container
t=t.replace(/```mermaid\n([\s\S]*?)```/g,function(m,code){
var id='mm'+Date.now()+Math.random().toString(36).substr(2,4);
setTimeout(function(){if(window.mermaid){try{var el=document.getElementById(id);if(el){mermaid.render('svg_'+id,code.trim()).then(function(r){el.innerHTML=r.svg}).catch(function(){el.innerHTML='<pre style="color:var(--ac)">'+code+'</pre>'})}}catch(e){}}},300);
return '<div id="'+id+'" class="merm-box" style="background:var(--sf);border:1px solid var(--bd2);border-radius:var(--r);padding:16px;margin:12px 0;text-align:center;min-height:60px"><div class="ldot"></div></div>'});
// Code blocks with copy + language label
t=t.replace(/```(\w+)?\n([\s\S]*?)```/g,function(m,lang,code){
var l=lang?lang.toUpperCase():'CODE';
return '<div class="code-w" style="position:relative;margin:10px 0"><div style="display:flex;justify-content:space-between;align-items:center;background:var(--sf);padding:6px 12px;border-radius:var(--r) var(--r) 0 0;border:1px solid var(--bd2);border-bottom:0"><span style="font-family:var(--m);font-size:10px;color:var(--ac);font-weight:600">'+l+'</span><button onclick="navigator.clipboard.writeText(this.closest(\'.code-w\').querySelector(\'pre\').textContent);this.textContent=\'✓\';setTimeout(()=>this.textContent=\'Copier\',1500)" style="font-size:10px;padding:3px 8px;background:var(--bd2);color:var(--mu);border-radius:4px;font-family:var(--m)">Copier</button></div><pre style="margin:0;padding:14px;background:var(--bg);border:1px solid var(--bd2);border-radius:0 0 var(--r) var(--r);overflow-x:auto;font-family:var(--m);font-size:12px;line-height:1.6;color:var(--wh)">'+code.replace(/</g,'&lt;')+'</pre></div>'});
// Images
t=t.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,'<img src="$2" alt="$1" style="max-width:100%;border-radius:var(--r);margin:10px 0;border:1px solid var(--bd2)">');
// Links
t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2" target="_blank" style="color:var(--ac);text-decoration:underline">$1</a>');
// Blockquotes
t=t.replace(/^>\s*(.+)$/gm,'<div style="border-left:3px solid var(--ac);padding:8px 14px;margin:8px 0;color:var(--mu);font-style:italic;background:var(--acB);border-radius:0 var(--rs) var(--rs) 0">$1</div>');
// Bold + italic
t=t.replace(/\*\*(.*?)\*\*/g,'<strong style="color:var(--wh)">$1</strong>');
t=t.replace(/\*(.*?)\*/g,'<em>$1</em>');
// Inline code
t=t.replace(/`(.*?)`/g,'<code style="background:var(--sf);padding:2px 6px;border-radius:4px;font-family:var(--m);font-size:12px;color:var(--cy)">$1</code>');
// Numbered lists
t=t.replace(/^(\d+)\.\s+(.+)$/gm,'<div style="display:flex;gap:10px;margin:4px 0;align-items:flex-start"><span style="color:var(--ac);font-weight:700;min-width:20px">$1.</span><span>$2</span></div>');
// Bullet lists
t=t.replace(/^[\-\*]\s+(.+)$/gm,'<div style="display:flex;gap:10px;margin:4px 0"><span style="color:var(--ac)">•</span><span>$1</span></div>');
// Headings
t=t.replace(/^###\s+(.+)$/gm,'<h4 style="color:var(--wh);font-size:14px;margin:14px 0 6px">$1</h4>');
t=t.replace(/^##\s+(.+)$/gm,'<h3 style="color:var(--wh);font-size:16px;margin:16px 0 8px">$1</h3>');
// Line breaks
t=t.replace(/\n\n/g,'<br>');
return t}
async function api(p,o={}){const h={'Content-Type':'application/json'};if(TK)h['Authorization']='Bearer '+TK;const r=await fetch(API+p,{...o,headers:h});return r.json()}
async function eng(a){return(await fetch(V2E+'?action='+a+'&token=WEVADS2026')).json()}
async function brg(a){return(await fetch(BRG+'?action='+a+'&token=WEVADS2026')).json()}
function sR(){$('LF').style.display='none';$('RF').style.display=''}
function sL(){$('RF').style.display='none';$('LF').style.display=''}
async function doLogin(){let e=v('lE'),p=v('lP');
if(!e||!p)return toast('Requis',1);$('bL').textContent='...';try{const r=await(await fetch('/api/wevads-v2-engine.php?action=auth_login&token=WEVADS2026',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({email:e,password:p})})).json();if(r.error)throw new Error(r.error);const _r=r;TK=_r.token;U=_r.user;enter()}catch(x){toast(x.message,1)}finally{$('bL').textContent='Se connecter'}}
async function doReg(){const n=v('rN'),e=v('rE'),p=v('rP');if(!n||!e||!p)return toast('Requis',1);try{const r=await api('/auth/register',{method:'POST',body:JSON.stringify({name:n,email:e,company:v('rC'),password:p})});TK=_r.token;U=_r.user;enter()}catch(x){toast(x.message,1)}}
function enter(){try{sessionStorage.setItem('wt',TK);sessionStorage.setItem('wu',JSON.stringify(U))}catch(e){}$('LW').style.display='none';$('SB').style.display='flex';$('MA').style.display='flex';$('sU').textContent=U.name||U.email;$('sA').textContent=(U.name||'W')[0].toUpperCase();$('sT').textContent=U.role||'user';rnav();go('dashboard')}
function logout(){TK='';U={};try{sessionStorage.clear()}catch(e){}$('LW').style.display='flex';$('SB').style.display='none';$('MA').style.display='none'}
function rnav(){let h='',s='';P.forEach(p=>{if(p[3]!==s){s=p[3];h+=`<div class="sb-sec">${s}<\/div>`}h+=`<div class="sb-it ${PG===p[0]?'on':''}" onclick="go('${p[0]}')">${ico(p[2])}<span>${p[1]}<\/span><\/div>`});$('SN').innerHTML=h}
function go(p){PG=p;$('PT').textContent=P.find(x=>x[0]===p)?.[1]||p;rnav();const c=$('C');c.innerHTML='<div style="text-align:center;padding:40px"><div class="spinner"><\/div><\/div>';c.scrollTop=0;(RR[p]||RR.dashboard)()}
const RR={};
// =============== DASHBOARD ===============
RR.dashboard=async()=>{let k={},t={},c=[];try{k=(await eng('dashboard')).kpis||{}}catch(e){}try{t=(await eng('tracking_stats')).stats||{}}catch(e){}try{c=(await api('/campaigns/list')).items||[]}catch(e){}const rs=(await eng('dashboard').catch(()=>({}))).recent_sends||[];
$('C').innerHTML=`<div class="stats"><div class="stat s-ac" onclick="go('contacts')" style="cursor:pointer"><div class="st-l">Contacts<\/div><div class="st-v">${N(k.contacts_total)}<\/div><div class="st-s">${N(k.contacts_active)} actifs<\/div><\/div><div class="stat s-bl" onclick="drillKPI('sent')" style="cursor:pointer"><div class="st-l">Emails envoyés<\/div><div class="st-v">${N(k.emails_sent_total)}<\/div><div class="st-s">${k.emails_sent_today||0} today<\/div><\/div><div class="stat s-gn" onclick="go('senders')" style="cursor:pointer"><div class="st-l">Senders<\/div><div class="st-v">${N(k.senders_active)}<\/div><div class="st-s">${k.senders_warming||0} warming<\/div><\/div><div class="stat s-pu" onclick="drillKPI('tracking')" style="cursor:pointer"><div class="st-l">Opens / Clicks<\/div><div class="st-v">${N(t.total_opens)}<\/div><div class="st-s">${N(t.total_clicks)} clicks<\/div><\/div><div class="stat s-or" onclick="go('warmup')" style="cursor:pointer"><div class="st-l">Warmup<\/div><div class="st-v">${N(k.warmup_accounts)}<\/div><\/div><div class="stat s-tg" onclick="go('channels')" style="cursor:pointer"><div class="st-l">Canaux<\/div><div class="st-v">4<\/div><div class="st-s"><span class="up">Email+WA+TG<\/span><\/div><\/div><\/div>
<div class="row2"><div class="card"><div class="card-h"><div class="card-t">Derniers envois<\/div><span onclick="showSendLog()" style="font-size:10px;color:var(--ac);cursor:pointer;text-decoration:underline;margin-left:8px">Voir tout<\/span><button class="btn btn-sm btn-ac" onclick="go('send')">+ Envoyer<\/button><\/div><table><thead><tr><th>Sender<\/th><th>To<\/th><th>Sujet<\/th><th>ISP<\/th><th>Date<\/th><\/tr><\/thead><tbody>${rs.slice(0,8).map(s=>`<tr style="cursor:pointer;transition:background .15s" onmouseover="this.style.background='rgba(129,140,248,.08)'" onmouseout="this.style.background=''" onclick="showSendDetail(${s.id})"><td style="font-family:var(--m);font-size:10px;color:var(--mu)">${esc((s.sender||'').split('@')[0])}<\/td><td style="font-family:var(--m);font-size:10px">${esc(s.recipient||'')}<\/td><td style="color:var(--wh);font-size:11px">${esc((s.subject||'').substring(0,30))}<\/td><td><span class="badge b-em">${esc(s.isp||'')}<\/span><\/td><td style="font-size:10px;color:var(--dm)">${(s.created_at||'').substring(0,16)}<\/td><\/tr>`).join('')||'<tr><td colspan="5" style="text-align:center;color:var(--dm);padding:24px">Aucun envoi<\/td><\/tr>'}<\/tbody><\/table><\/div>
<div><div class="card"><div class="card-t" style="margin-bottom:10px">Infra<\/div>${[['Campagnes',k.campaigns_total,'('+k.campaigns_active+' actives)'],['Domaines',k.domains_active,''],['Bounces',k.bounces,''],['Tracking',N(k.tracking_events),'events'],['Ethica HCPs',N(k.ethica_hcps),'pharma']].map(([l,v2,s])=>`<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--mu)">${l}<\/span><span style="font-family:var(--m);font-size:11px;color:var(--wh)">${v2||0} <span style="color:var(--dm);font-size:9px">${s}<\/span><\/span><\/div>`).join('')}<\/div>
<div class="card"><div class="card-t" style="margin-bottom:8px">Actions<\/div><div style="display:grid;gap:5px"><button class="btn btn-sm btn-ac btn-full" onclick="go('send')">⚡ Envoyer<\/button><button class="btn btn-sm btn-gh btn-full" onclick="go('senders')">Senders<\/button><button class="btn btn-sm btn-gh btn-full" onclick="go('ai')">🧠 AI Assistant<\/button><\/div><\/div><\/div><\/div>`;
(async function(){try{var ch=await brg('charts_daily');var stats=(ch||{}).stats||[];
if(typeof Chart!=='undefined'&&stats.length>1){
var wrap=document.createElement('div');wrap.className='row2';wrap.innerHTML='<div class="card"><div class="card-t" style="margin-bottom:14px">Volume 30 jours</div><canvas id="chD1" height="200"></canvas></div><div class="card"><div class="card-t" style="margin-bottom:14px">Opens & Clicks</div><canvas id="chD2" height="200"></canvas></div>';
if(PG==='dashboard')$('C').appendChild(wrap);
setTimeout(function(){
var e1=document.getElementById('chD1');var e2=document.getElementById('chD2');
if(e1)new Chart(e1,{type:'line',data:{labels:stats.map(function(s){return(s.date||'').substring(5)}),datasets:[{label:'Sent',data:stats.map(function(s){return+s.total_sent}),borderColor:'#d4a843',tension:.3,pointRadius:2,fill:false},{label:'Delivered',data:stats.map(function(s){return+s.total_delivered}),borderColor:'#34d399',tension:.3,pointRadius:2,fill:false}]},options:{responsive:true,plugins:{legend:{labels:{color:'#5a6a80',font:{size:10}}}},scales:{x:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}},y:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}}}}});
if(e2)new Chart(e2,{type:'bar',data:{labels:stats.map(function(s){return(s.date||'').substring(5)}),datasets:[{label:'Opens',data:stats.map(function(s){return+s.total_opened}),backgroundColor:'rgba(52,211,153,.5)',borderRadius:4},{label:'Clicks',data:stats.map(function(s){return+s.total_clicked}),backgroundColor:'rgba(96,165,250,.5)',borderRadius:4}]},options:{responsive:true,plugins:{legend:{labels:{color:'#5a6a80',font:{size:10}}}},scales:{x:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}},y:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}}}}});
},200)}}catch(e){}})();};
// =============== SEND ===============
RR.send=async()=>{
let m=[],ctrl={},sc={};
try{m=(await eng('send_methods')).items||[]}catch(e){}
try{ctrl=await(await fetch('/api/send-controller.php?action=status&token=WEVADS2026')).json()}catch(e){}
try{sc=await(await fetch('/api/send-controller.php?action=seed_check&token=WEVADS2026')).json()}catch(e){}
const sf=ctrl.safety||{};const gr=ctrl.graph||{};const cp=ctrl.campaigns||{};const scr=sc.recent||[];
$('C').innerHTML=`
<div style="display:flex;gap:8px;margin-bottom:16px;padding:12px;background:var(--sf);border:1px solid ${sf.dangerous_crons_disabled?'rgba(52,211,153,.15)':'rgba(248,113,113,.2)'};border-radius:var(--r)">
<span style="font-size:16px">${sf.dangerous_crons_disabled?'\u2705':'\u26a0\ufe0f'}<\/span>
<div style="flex:1"><div style="font-size:12px;font-weight:600;color:${sf.dangerous_crons_disabled?'var(--gn)':'var(--rd)'}">Send Controller v1.0 — ${sf.dangerous_crons_disabled?'SÉCURISÉ':'DANGER'}<\/div>
<div style="font-size:10px;color:var(--mu)">Crons dangereux dsactivs \u2022 Rate: ${sf.rate_this_hour||0}/${sf.max_per_hour||100}/h \u2022 Tous les envois passent par cette page<\/div><\/div>
<button class="btn btn-sm btn-gh" id="autoBtn" onclick="toggleAuto()" style="color:var(--ac);border-color:var(--acBd)">${ctrl.auto_mode?'\u23f8 Auto OFF':'\u25b6 Auto ON'}<\/button>
<\/div>
<div class="card" style="border-color:var(--acBd)"><div class="card-h"><div class="card-t">\u26a1 Composer & Envoyer<\/div><\/div>
<div class="row2"><div>
<div class="field"><label>Canal<\/label><div class="ch-sel">
<div class="ch-p sel" data-c="email" onclick="this.classList.toggle('sel')">\u2709 Email<\/div>
<div class="ch-p" data-c="sms" onclick="this.classList.toggle('sel')">💬 SMS<\/div>
<div class="ch-p" data-c="whatsapp" onclick="this.classList.toggle('sel')">📱 WhatsApp<\/div>
<div class="ch-p" data-c="telegram" onclick="this.classList.toggle('sel')">\u2708 Telegram<\/div>
<\/div><\/div>
<div class="field"><label>Mthode<\/label><select id="sM">
<option value="pmta">PMTA Legacy (S95:25)<\/option><option value=\"kumomta\" selected>KumoMTA (Rust :587)<\/option>
<option value="postfix">Postfix Local (2525)<\/option>
<option value="graph">Graph API (167 senders)<\/option>
${m.map(x=>'<option value="'+x.name+'">'+x.name+' \u2014 '+x.type+'<\/option>').join('')}
<option value="Gmail_Direct">Gmail (55 accts, 27K/day)<\/option>
<option value="SendGrid">SendGrid (50 accts)<\/option>
<option value="Amazon_SES">Amazon SES (30K/day)<\/option>
<option value="Brevo">Brevo (30 accts)<\/option>
<option value="SparkPost">SparkPost (20 accts)<\/option>
<\/select><\/div>
<div class="field"><label>Destinataire(s)<\/label><input id="sTo" placeholder="email@example.com (virgules pour bulk)"><\/div>
<div class="field"><label>Objet<\/label><input id="sSu" placeholder="Objet du message"><\/div>
<div style="display:flex;gap:6px;margin:6px 0">
<button class="btn btn-sm btn-gh" style="color:var(--pu);border-color:rgba(167,139,250,.2)" onclick="aiSubj()">\ud83e\udde0 Optimiser IA<\/button>
<span id="aiH" style="font-size:10px;color:var(--dm)"><\/span>
<\/div><\/div>
<div>
<div class="field"><label>From Name<\/label><input id="sFN" value="WEVAL Consulting"><\/div>
<div class="field"><label>From Email<\/label><input id="sFE" placeholder="Auto-select sender"><\/div>
<div class="field"><label>Limite par envoi<\/label><select id="sLim"><option value="1">1 (test)<\/option><option value="5">5<\/option><option value="10">10 (max safe)<\/option><\/select><\/div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-top:10px">
<button class="btn btn-ac" onclick="doSendCtrl()" style="font-size:12px">\ud83e\uddea Test Send<\/button>
<button class="btn btn-gh" style="color:var(--gn);border-color:rgba(52,211,153,.2);font-size:12px" onclick="doSeedTest()">\ud83c\udf31 Seed Test<\/button>
<button class="btn btn-gh" style="color:var(--or);border-color:rgba(251,146,60,.2);font-size:12px" onclick="doBulkCtrl()">🚀 Bulk<\/button>
<button class="btn btn-gh" style="color:var(--tg);border-color:rgba(34,158,217,.2);font-size:12px" onclick="doTgSend()">\u2708 Telegram<\/button>
<\/div><\/div><\/div>
<div class="field" style="margin-top:12px"><label>HTML Body<\/label>
<div style="display:flex;gap:6px;margin-bottom:6px">
<button class="btn btn-sm btn-gh" onclick="aiBody()">\ud83e\udde0 IA<\/button>
<button class="btn btn-sm btn-gh" onclick="loadTpl()">📋 Template<\/button>
<\/div>
<textarea class="ed" id="sBo" rows="6" placeholder="<h1>Hello<\/h1>"><\/textarea><\/div>
<div class="field"><label>Custom Headers (optionnel)<\/label><input id="sHdr" placeholder="X-Mailer: WEVADS, X-Priority: 1"><\/div>
<\/div>
<div class="row2">
<div class="card"><div class="card-t" style="margin-bottom:10px">🛡 Scurit<\/div>
<div style="display:grid;gap:6px">
<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--mu)">Rate limit<\/span><span style="font-family:var(--m);color:var(--wh)">${sf.rate_this_hour||0} / ${sf.max_per_hour||100}<\/span><\/div>
<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--mu)">Graph senders<\/span><span style="font-family:var(--m);color:var(--ac)">${gr.senders_available||0}<\/span><\/div>
<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--mu)">Seeds DB<\/span><span style="font-family:var(--m)">${N(gr.seeds_total||0)}<\/span><\/div>
<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--mu)">Total envoys (alltime)<\/span><span style="font-family:var(--m)">${N(gr.total_sent_alltime||0)}<\/span><\/div>
<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--mu)">Envoys today<\/span><span style="font-family:var(--m);color:var(--gn)">${gr.sent_today||0}<\/span><\/div>
<div style="display:flex;justify-content:space-between;padding:5px 0"><span style="font-size:11px;color:var(--mu)">Dernier envoi<\/span><span style="font-family:var(--m);font-size:10px;color:var(--dm)">${(gr.last_send||'jamais').substring(0,16)}<\/span><\/div>
<\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">📨 Campagnes ADX<\/div>
<div style="display:grid;gap:6px">
<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--mu)">Active<\/span><span style="font-family:var(--m);color:var(--gn)">${cp.active||0}<\/span><\/div>
<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--mu)">Paused<\/span><span style="font-family:var(--m);color:var(--or)">${cp.paused||0}<\/span><\/div>
<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--mu)">Queue<\/span><span style="font-family:var(--m)">${cp.queue||0}<\/span><\/div>
<div style="display:flex;gap:6px;margin-top:6px">
<button class="btn btn-sm btn-rd" onclick="pauseAll()" style="flex:1;font-size:10px">\u23f8 Pause All<\/button>
<button class="btn btn-sm btn-gh" onclick="listCamps()" style="flex:1;font-size:10px">📋 Liste<\/button>
<\/div><\/div><\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">📊 Derniers envois seeds (Graph API)<\/div>
<table><thead><tr><th>Sender<\/th><th>To<\/th><th>ISP<\/th><th>Sujet<\/th><th>Date<\/th><\/tr><\/thead>
<tbody>${scr.slice(0,6).map(s=>'<tr><td style="font-family:var(--m);font-size:9px;color:var(--mu)">'+esc((s.sender_email||'').split('@')[0])+'<\/td><td style="font-family:var(--m);font-size:9px">'+esc(s.recipient_email||'')+'<\/td><td><span class="badge b-em">'+esc(s.recipient_isp||'')+'<\/span><\/td><td style="font-size:10px;color:var(--wh)">'+esc((s.subject||'').substring(0,25))+'<\/td><td style="font-size:9px;color:var(--dm)">'+esc((s.created_at||'').substring(0,16))+'<\/td><\/tr>').join('')||'<tr><td colspan="5" style="text-align:center;color:var(--dm);padding:16px">Aucun envoi rcent<\/td><\/tr>'}<\/tbody><\/table><\/div>`;
// Preview panel
var prevBtn=document.createElement('button');prevBtn.className='btn btn-sm btn-gh';prevBtn.textContent='Preview';
prevBtn.onclick=async function(){
var su=document.getElementById('sSu')?document.getElementById('sSu').value:'';
var bo=document.getElementById('sBo')?document.getElementById('sBo').value:'';
var fn=document.getElementById('sFN')?document.getElementById('sFN').value:'WEVAL';
if(!bo){toast('Entrer du HTML pour preview',1);return}
var r=await(await fetch(BRG+'?action=preview&token=WEVADS2026',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({subject:su,html:bo,from_name:fn})})).json();
if(r.ok){var m=document.createElement('div');m.className='modal-bg';m.onclick=function(e){if(e.target===m)m.remove()};
m.innerHTML='<div class="modal" style="max-width:700px;padding:20px"><div style="display:flex;gap:10px;margin-bottom:14px"><button class="btn btn-sm btn-ac" onclick="this.parentElement.nextElementSibling.style.maxWidth=\'600px\'">Desktop</button><button class="btn btn-sm btn-gh" onclick="this.parentElement.nextElementSibling.style.maxWidth=\'375px\'">Mobile</button><button class="btn btn-sm btn-gh" onclick="this.closest(\'.modal-bg\').remove()">Fermer</button></div><div style="max-width:600px;margin:0 auto;transition:max-width .3s">'+r.preview+'</div></div>';
document.body.appendChild(m)}};
var cards=$('C').querySelectorAll('.card');
if(cards.length>0){var hdr=cards[0].querySelector('.card-h');
if(hdr){hdr.appendChild(prevBtn)}}
// Schedule widget
var schedDiv=document.createElement('div');schedDiv.style.cssText='margin-top:12px;padding:12px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);display:flex;gap:12px;align-items:center';
schedDiv.innerHTML='<span style="font-size:11px;color:var(--mu)">Programmer:</span><input type="datetime-local" id="schedAt" style="font-size:12px;background:var(--bg);color:var(--wh);border:1px solid var(--bd);border-radius:6px;padding:4px 8px"><button class="btn btn-sm btn-gh" onclick="schedSend()">Planifier</button>';
var content=document.getElementById('C');
if(content)content.appendChild(schedDiv);
};
async function doSendCtrl(){
const to=v('sTo'),su=v('sSu'),bo=v('sBo'),me=v('sM'),lim=v('sLim');
if(!to||!su)return toast('To + Objet requis',1);
toast('Envoi via Controller ('+me+')...');
try{const r=await fetch('/api/send-controller.php?action=seed_test&token=WEVADS2026',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'to='+encodeURIComponent(to)+'&subject='+encodeURIComponent(su)+'&html='+encodeURIComponent(bo)+'&method='+me+'&from_name='+encodeURIComponent(v('sFN'))+'&limit='+lim});
const j=await r.json();if(j.ok){const res=j.results||[];const ok=res.filter(r=>r.status==='sent').length;toast('\u2705 '+ok+'/'+res.length+' envoys via '+me+' (rate: '+j.rate+')')}else toast('\u274c '+(j.error||'Erreur'),1)}catch(e){toast('Err: '+e.message,1)}}
async function doSeedTest(){
const me=v('sM'),lim=v('sLim');
toast('Seed test ('+lim+' seeds via '+me+')...');
try{const r=await fetch('/api/send-controller.php?action=seed_test&token=WEVADS2026',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'method='+me+'&limit='+lim+'&subject='+encodeURIComponent(v('sSu')||'Seed Test')+'&html='+encodeURIComponent(v('sBo')||'<p>Seed test<\/p>')+'&from_name='+encodeURIComponent(v('sFN'))});
const j=await r.json();toast(j.ok?'\u2705 Seeds: '+(j.results||[]).length+' (rate: '+j.rate+')':'\u274c '+(j.error||''),!j.ok)}catch(e){toast('Err',1)}}
async function doBulkCtrl(){const to=v('sTo');const emails=to.split(',').map(e=>e.trim()).filter(Boolean);if(emails.length<2)return toast('Bulk = 2+ emails',1);doSendCtrl()}
async function doTgSend(){const su=v('sSu')||'Alert';const bo=v('sBo')||'Test';toast('TG...');try{const r=await(await fetch('https://api.telegram.org/bot8544624912:AAEm9ttXK6JeFqAL-gcvB5sreCBhXzzQwrs/sendMessage',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({chat_id:'7605775322',text:'📨 '+su+'\n'+bo.replace(/<[^>]*>/g,'')})})).json();toast(r.ok?'TG OK':'Err',!r.ok)}catch(e){toast('Err',1)}}
async function toggleAuto(){try{const r=await(await fetch('/api/send-controller.php?action=auto_toggle&token=WEVADS2026',{method:'POST'})).json();toast(r.auto_mode?'\u25b6 Auto ON (5 seeds/2h via PMTA)':'\u23f8 Auto OFF');RR.send()}catch(e){toast('Err',1)}}
async function pauseAll(){try{await fetch('/api/send-controller.php?action=campaign_pause&token=WEVADS2026',{method:'POST'});toast('\u23f8 Toutes les campagnes pauses');RR.send()}catch(e){toast('Err',1)}}
async function listCamps(){try{const r=await(await fetch('/api/send-controller.php?action=campaigns_list&token=WEVADS2026')).json();const c=r.campaigns||[];const m=document.createElement('div');m.className='modal-bg';m.onclick=e=>{if(e.target===m)m.remove()};m.innerHTML='<div class="modal"><h3>Campagnes ADX<\/h3><table><thead><tr><th>ID<\/th><th>Nom<\/th><th>Status<\/th><th>Action<\/th><\/tr><\/thead><tbody>'+c.map(x=>'<tr><td style="font-family:var(--m)">'+x.id+'<\/td><td style="color:var(--wh)">'+esc(x.name||'Campaign '+x.id)+'<\/td><td><span class="badge b-'+(x.status==='active'?'ok':x.status==='paused'?'wait':'em')+'">'+x.status+'<\/span><\/td><td><button class="btn btn-sm btn-gh" onclick="resumeCamp('+x.id+')">Resume<\/button><\/td><\/tr>').join('')+'<\/tbody><\/table><\/div>';document.body.appendChild(m)}catch(e){toast('Err',1)}}
async function resumeCamp(id){try{await fetch('/api/send-controller.php?action=campaign_resume&token=WEVADS2026',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'campaign_id='+id});toast('Campaign '+id+' resumed');document.querySelector('.modal-bg')?.remove();RR.send()}catch(e){toast('Err',1)}}
// =============== CAMPAIGNS ===============
let CMP=[];
RR.campaigns=async()=>{try{CMP=(await api('/campaigns/list')).items||[]}catch(e){CMP=[]}
$('C').innerHTML=`<div class="toolbar"><input type="search" id="cS" placeholder="Rechercher..." oninput="fCmp()"><div class="sp"><\/div><button class="btn btn-sm btn-ac" onclick="oCmp()">+ Campagne<\/button><\/div><div class="card" style="padding:0;overflow:hidden"><table><thead><tr><th>Nom<\/th><th>Sujet<\/th><th>Statut<\/th><th>Envoyés<\/th><th>Ouverts<\/th><th>Actions<\/th><\/tr><\/thead><tbody id="cT"><\/tbody><\/table><\/div>`;rCmp()};
function rCmp(f=''){const i=f?CMP.filter(c=>[c.name,c.subject].join(' ').toLowerCase().includes(f)):CMP;$('cT').innerHTML=i.map(c=>`<tr><td style="color:var(--wh);font-weight:600">${esc(c.name)}<\/td><td>${esc(c.subject)}<\/td><td><span class="badge b-${c.status==='sent'?'sent':c.status==='draft'?'ac':'wait'}">${c.status}<\/span><\/td><td style="font-family:var(--m)">${N(c.metrics?.sent)}<\/td><td style="font-family:var(--m)">${N(c.metrics?.opened)}<\/td><td><button class="btn btn-sm btn-gh" onclick="simS('${c.id}')">Sim<\/button><\/td><\/tr>`).join('')||'<tr><td colspan="6" style="text-align:center;color:var(--dm);padding:24px">—<\/td><\/tr>'}
function fCmp(){rCmp(v('cS').toLowerCase())}
async function simS(id){try{await api('/campaigns/'+id+'/send-simulate',{method:'POST'});toast('Simulé');RR.campaigns()}catch(e){toast(e.message,1)}}
function oCmp(){const m=document.createElement('div');m.className='modal-bg';m.onclick=e=>{if(e.target===m)m.remove()};m.innerHTML=`<div class="modal"><h3>Nouvelle campagne<\/h3><div class="field"><label>Nom<\/label><input id="nN"><\/div><div class="field"><label>Objet<\/label><input id="nS"><\/div><div class="field"><label>Audience<\/label><input type="number" id="nA" value="500"><\/div><div class="field"><label>HTML<\/label><textarea class="ed" id="nH" rows="4"><\/textarea><\/div><div class="brow"><button class="btn btn-gh" onclick="this.closest('.modal-bg').remove()">Annuler<\/button><button class="btn btn-ac" onclick="cCmp()">Créer<\/button><\/div><\/div>`;document.body.appendChild(m)}
async function cCmp(){try{await api('/campaigns',{method:'POST',body:JSON.stringify({name:v('nN'),subject:v('nS'),audience_size:+v('nA'),content_html:v('nH')})});document.querySelector('.modal-bg')?.remove();toast('Créée');RR.campaigns()}catch(e){toast(e.message,1)}}
// =============== CONTACTS ===============
let CTC=[];
RR.contacts=async()=>{
window.doImportCSV=async function(data){toast('Importing...');try{var r=await(await fetch(BRG+'?action=import_csv&token=WEVADS2026',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({data:data})})).json();toast('Imported: '+(r.imported||0)+' contacts');RR.contacts()}catch(e){toast('Err',1)}};
try{CTC=(await api('/contacts/list')).items||[]}catch(e){CTC=[]}
$('C').innerHTML=`<div class="toolbar"><input type="search" id="ctS" placeholder="Rechercher..." oninput="fCtc()"><div class="sp"><\/div><button class="btn btn-sm btn-ac" onclick="oCtc()">+ Ajouter<\/button><\/div><div class="card" style="padding:0;overflow:hidden"><table><thead><tr><th>Nom<\/th><th>Email<\/th><th>Entreprise<\/th><th>Pays<\/th><th>Tags<\/th><th><\/th><\/tr><\/thead><tbody id="ctT"><\/tbody><\/table><\/div>`;rCtc()};
function rCtc(f=''){const i=f?CTC.filter(c=>[c.email,c.first_name,c.last_name].join(' ').toLowerCase().includes(f)):CTC;$('ctT').innerHTML=i.map(c=>`<tr><td style="color:var(--wh);font-weight:600">${esc(c.first_name||'')} ${esc(c.last_name||'')}<\/td><td style="font-family:var(--m);font-size:11px">${esc(c.email)}<\/td><td>${esc(c.company||'')}<\/td><td>${esc(c.country||'')}<\/td><td><div class="tags">${(c.tags||[]).map(t=>`<span class="tag">${esc(t)}<\/span>`).join('')}<\/div><\/td><td><button class="btn btn-sm btn-rd" onclick="dCtc('${c.id}')">×<\/button><\/td><\/tr>`).join('')||'<tr><td colspan="6" style="text-align:center;color:var(--dm);padding:24px">—<\/td><\/tr>'}
function fCtc(){rCtc(v('ctS').toLowerCase())}
async function dCtc(id){if(!confirm('Supprimer?'))return;try{await api('/contacts/'+id,{method:'DELETE'});toast('OK');RR.contacts()}catch(e){toast(e.message,1)}}
function oCtc(){const m=document.createElement('div');m.className='modal-bg';m.onclick=e=>{if(e.target===m)m.remove()};m.innerHTML=`<div class="modal"><h3>Contact<\/h3><div class="row2"><div class="field"><label>Prénom<\/label><input id="cF"><\/div><div class="field"><label>Nom<\/label><input id="cL"><\/div><\/div><div class="field"><label>Email<\/label><input id="cE"><\/div><div class="field"><label>Tél<\/label><input id="cP"><\/div><div class="row2"><div class="field"><label>Entreprise<\/label><input id="cCo"><\/div><div class="field"><label>Pays<\/label><input id="cCy"><\/div><\/div><div class="field"><label>Tags<\/label><input id="cTg" placeholder="vip, prospect"><\/div><div class="brow"><button class="btn btn-gh" onclick="this.closest('.modal-bg').remove()">×<\/button><button class="btn btn-ac" onclick="aCtc()">Ajouter<\/button><\/div><\/div>`;document.body.appendChild(m)}
async function aCtc(){try{await api('/contacts',{method:'POST',body:JSON.stringify({email:v('cE'),first_name:v('cF'),last_name:v('cL'),company:v('cCo'),phone:v('cP'),country:v('cCy'),tags:v('cTg').split(',').map(t=>t.trim()).filter(Boolean)})});document.querySelector('.modal-bg')?.remove();toast('Ajouté');RR.contacts()}catch(e){toast(e.message,1)}}
// =============== SENDERS ===============
RR.senders=async()=>{let d={};try{d=await brg('senders_full')}catch(e){}
const pv=d.providers||[];const os=d.o365_status||[];const gs=d.gsuite_workspaces||[];const wt=d.warmup_by_type||[];
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Total Senders</div><div class="st-v">'+N(d.total_senders)+'</div></div><div class="stat s-gn"><div class="st-l">Capacit\u00e9/jour</div><div class="st-v">'+N(d.total_capacity)+'</div></div><div class="stat s-bl"><div class="st-l">Providers</div><div class="st-v">'+pv.length+'</div></div><div class="stat s-pu"><div class="st-l">O365 Active</div><div class="st-v">'+((os.find(s=>s.status==='Active')||{}).cnt||0)+'</div></div></div>'
+'<div class="row2"><div class="card"><div class="card-t" style="margin-bottom:14px">Senders par provider</div><canvas id="chProv" height="240"></canvas></div>'
+'<div class="card"><div class="card-t" style="margin-bottom:14px">Capacit\u00e9 par provider</div><canvas id="chCap" height="240"></canvas></div></div>'
+'<div class="row2"><div class="card"><div class="card-t" style="margin-bottom:10px">O365 par statut</div>'+os.map(s=>'<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="color:var(--wh)">'+esc(s.status)+'</span><span style="font-family:var(--m);color:var(--ac)">'+N(s.cnt)+'</span></div>').join('')+'</div>'
+'<div class="card"><div class="card-t" style="margin-bottom:10px">Warmup par type</div>'+wt.map(w=>'<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="color:var(--wh)">'+esc(w.account_type)+'</span><span style="font-family:var(--m)">'+N(w.cnt)+'</span><span style="font-family:var(--m);color:var(--gn)">'+N(w.cap)+'/d</span></div>').join('')+'</div></div>';
if(typeof Chart!=='undefined'&&pv.length>0){const colors=['#d4a843','#34d399','#60a5fa','#a78bfa','#f87171','#fb923c','#22d3ee','#ec4899','#10b981','#8b5cf6','#ef4444','#06b6d4','#f59e0b','#6366f1','#14b8a6','#e11d48','#84cc16','#0ea5e9','#d946ef','#f97316','#64748b','#eab308'];
new Chart($('chProv'),{type:'bar',data:{labels:pv.map(p=>p.provider),datasets:[{data:pv.map(p=>+p.cnt),backgroundColor:colors.slice(0,pv.length),borderRadius:6}]},options:{indexAxis:'y',responsive:true,plugins:{legend:{display:false}},scales:{x:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}},y:{ticks:{color:'#94a3b8',font:{size:10}},grid:{display:false}}}}});
new Chart($('chCap'),{type:'bar',data:{labels:pv.map(p=>p.provider),datasets:[{data:pv.map(p=>+p.capacity),backgroundColor:colors.slice(0,pv.length).map(c=>c+'99'),borderRadius:6}]},options:{indexAxis:'y',responsive:true,plugins:{legend:{display:false}},scales:{x:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}},y:{ticks:{color:'#94a3b8',font:{size:10}},grid:{display:false}}}}});
}};
RR.warmup=async()=>{
window.doWarmupStart=async function(){toast('Starting warmup...');try{await brg('warmup_start');toast('OK');setTimeout(()=>RR.warmup(),1000)}catch(e){toast('Err',1)}};
window.doWarmupStop=async function(){toast('Stopping...');try{await brg('warmup_stop');toast('Stopped');setTimeout(()=>RR.warmup(),1000)}catch(e){toast('Err',1)}};
var d={},we={};try{d=await brg('warmup')}catch(e){}try{we=await brg('warmup_engine')}catch(e){}
var bt=we.by_tenant||[];
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Total comptes</div><div class="st-v">'+N(d.total||we.total_with_oid||0)+'</div></div><div class="stat s-gn"><div class="st-l">En warming</div><div class="st-v" style="color:'+(we.warming>0?'var(--gn)':'var(--rd)')+'">'+N(we.warming||0)+'</div></div><div class="stat s-bl"><div class="st-l">Avec Object ID</div><div class="st-v">'+N(we.total_with_oid||0)+'</div></div><div class="stat s-pu"><div class="st-l">Tenants actifs</div><div class="st-v">6</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Warmup Engine</div><div style="display:flex;gap:8px"><button class="btn btn-sm btn-ac" onclick="startWarmup(5)">Start 5</button><button class="btn btn-sm btn-ac" onclick="startWarmup(10)">Start 10</button><button class="btn btn-sm btn-ac" onclick="startWarmup(20)">Start 20</button><button class="btn btn-sm btn-rd" onclick="stopWarmup()">Stop All</button></div></div>'
+'<p style="font-size:11px;color:var(--mu);margin-bottom:14px">'+(we.warming>0?we.warming+' comptes actifs en rotation':'Aucun compte en warmup — demarrer pour ameliorer la delivrabilite')+'</p>'
+'<div class="card-t" style="margin-bottom:10px">Par tenant</div>'
+'<table><thead><tr><th>Tenant</th><th>Comptes</th><th>Actifs</th><th>Taux</th></tr></thead><tbody>'
+bt.map(function(t){var pct=t.cnt>0?Math.round((+t.active/+t.cnt)*100):0;return '<tr><td style="color:var(--wh);font-weight:500;font-size:11px">'+esc(t.tenant_domain)+'</td><td style="font-family:var(--m)">'+N(t.cnt)+'</td><td style="font-family:var(--m);color:'+(+t.active>0?'var(--gn)':'var(--mu)')+'">'+N(t.active)+'</td><td><div style="background:var(--bg);border-radius:4px;height:8px;width:80px;display:inline-block;vertical-align:middle"><div style="background:var(--gn);height:100%;border-radius:4px;width:'+pct+'%"></div></div> <span style="font-size:10px;color:var(--mu)">'+pct+'%</span></td></tr>'}).join('')
+'</tbody></table></div>'
+'<div class="card"><div class="card-t" style="margin-bottom:10px">ISP Throttle Config</div><div id="throttleDiv">Chargement...</div></div>';
brg('throttle_config').then(function(tc){var th=tc.throttle||{};document.getElementById('throttleDiv').innerHTML=Object.keys(th).map(function(isp){var c=th[isp];return '<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd)"><span style="color:var(--wh);font-size:12px">'+isp+'</span><span style="font-family:var(--m);font-size:10px;color:var(--mu)">'+c.per_hour+'/h | '+c.per_day+'/j | '+c.delay_ms+'ms delay</span></div>'}).join('')}).catch(function(){});};
async function startWarmup(n){
toast('Activation de '+n+' comptes...');
var r=await(await fetch(BRG+'?action=warmup_start&token=WEVADS2026&limit='+n)).json();
if(r.ok){toast(r.activated+' comptes actives');go('warmup')}else toast('Erreur',1)}
async function stopWarmup(){
if(!confirm('Stopper TOUS les warmups ?'))return;
var r=await(await fetch(BRG+'?action=warmup_stop&token=WEVADS2026')).json();
if(r.ok){toast(r.stopped+' comptes stoppes');go('warmup')}else toast('Erreur',1)}
RR.domains=async()=>{let d={};try{d=await brg('domains')}catch(e){}const doms=d.domains||[];
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Domaines<\/div><div class="st-v">${d.total||0}<\/div><\/div><div class="stat s-gn"><div class="st-l">Activés<\/div><div class="st-v">${doms.filter(x=>x.status==='Activated').length}<\/div><\/div><\/div>
<div class="card" style="padding:0;overflow:hidden"><table><thead><tr><th>Domaine<\/th><th>Statut<\/th><th>Dispo<\/th><th>Compte<\/th><th>Brand<\/th><\/tr><\/thead><tbody>${doms.map(d=>`<tr><td style="font-family:var(--m);color:var(--wh);font-weight:600">${esc(d.name)}<\/td><td><span class="badge b-${d.status==='Activated'?'ok':'wait'}">${d.status}<\/span><\/td><td>${esc(d.availability||'')}<\/td><td style="font-size:10px;color:var(--mu)">${esc(d.account_name||'')}<\/td><td>${d.has_brand==='Yes'?'✅':'—'}<\/td><\/tr>`).join('')}<\/tbody><\/table><\/div>`};
// =============== SEEDS ===============
RR.seeds=async()=>{let d={};try{d=await brg('seeds')}catch(e){}
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Seed Accounts<\/div><div class="st-v">${N(d.accounts)}<\/div><\/div><div class="stat s-bl"><div class="st-l">Inboxes<\/div><div class="st-v">${N(d.inboxes)}<\/div><\/div><div class="stat s-gn"><div class="st-l">Résultats<\/div><div class="st-v">${N(d.results)}<\/div><\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">Inbox Testing<\/div><p style="font-size:12px;color:var(--mu);line-height:1.7">Les seeds testent le placement inbox avant envoi réel. Chaque seed email vérifie inbox vs spam chez Gmail, Outlook, Yahoo, T-Online, GMX.<\/p><div style="margin-top:12px;display:flex;gap:6px"><button class="btn btn-sm btn-ac" onclick="toast('Seed test lancé')">Lancer test<\/button><button class="btn btn-sm btn-gh" onclick="toast('Check...')">Vérifier<\/button><\/div><\/div>`};
// =============== REPUTATION ===============
RR.reputation=async()=>{let d={};try{d=await brg('reputation')}catch(e){}
$('C').innerHTML=`<div class="stats"><div class="stat s-rd"><div class="st-l">Bounces<\/div><div class="st-v">${d.bounces||0}<\/div><\/div><div class="stat s-ac"><div class="st-l">Bounce Log<\/div><div class="st-v">${d.bounce_log||0}<\/div><\/div><div class="stat s-bl"><div class="st-l">Blacklisted<\/div><div class="st-v">${d.blacklisted||0}<\/div><\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">Blacklist Check<\/div><div style="display:grid;grid-template-columns:repeat(4,1fr);gap:8px">${['Spamhaus','Barracuda','SORBS','UCEPROTECT'].map(n=>`<div style="padding:12px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);text-align:center"><div style="font-size:9px;color:var(--mu)">${n}<\/div><div style="font-size:14px;font-weight:700;color:var(--gn);margin-top:4px">Clean<\/div><\/div>`).join('')}<\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:8px">Monitoring<\/div><p style="font-size:12px;color:var(--mu);line-height:1.7">Surveillance bounces, blacklists, plaintes. Le Brain Engine ajuste volumes et IPs en fonction du score réputation.<\/p><\/div>`};
// =============== BRAIN IA ===============
RR.brain=async()=>{let d={};try{d=await brg('brain')}catch(e){}const mt=d.methods||[];
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Configs<\/div><div class="st-v">${N(d.configs)}<\/div><\/div><div class="stat s-gn"><div class="st-l">Winners<\/div><div class="st-v">${d.winners||0}<\/div><\/div><div class="stat s-pu"><div class="st-l">Learnings<\/div><div class="st-v">${N(d.learnings)}<\/div><\/div><div class="stat s-bl"><div class="st-l">IA Engine<\/div><div class="st-v" style="font-size:16px">LIVE<\/div><div class="st-s">Sovereign GPU<\/div><\/div><\/div>
<div class="row2"><div class="card"><div class="card-t" style="margin-bottom:10px">Send Methods (Hamid)<\/div><table><thead><tr><th>Méthode<\/th><th>Description<\/th><th>Best ISPs<\/th><\/tr><\/thead><tbody>${mt.map(m=>`<tr><td style="color:var(--wh);font-weight:600">${esc(m.method_name)}<\/td><td style="font-size:11px;color:var(--mu)">${esc(m.description)}<\/td><td style="font-family:var(--m);font-size:10px;color:var(--ac)">${esc(m.best_for_isps||'')}<\/td><\/tr>`).join('')}<\/tbody><\/table><\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">Stack IA<\/div>${[['vLLM GPU','S95:8000','qwen2.5-14B'],['Groq','API','llama-3.3-70b'],['Cerebras','API','qwen-3-235b'],['Ollama S204','CPU','9 modèles'],['Qdrant RAG','S95:6333','95 memcells']].map(([n,h,d])=>`<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--wh)">${n}<\/span><span style="font-family:var(--m);font-size:9px;color:var(--mu)">${h}<\/span><span style="font-size:10px;color:var(--ac)">${d}<\/span><\/div>`).join('')}<\/div><\/div>`};
// =============== CREATIVE ===============
if(typeof Chart!=='undefined'){setTimeout(()=>{const el=document.getElementById('chBrain');if(el){const methods=d.methods||[];if(methods.length)new Chart(el,{type:'radar',data:{labels:methods.map(m=>m.method_name||'?'),datasets:[{label:'Brain Methods',data:methods.map((_,i)=>80-i*10),backgroundColor:'rgba(212,168,67,.15)',borderColor:'#d4a843',pointBackgroundColor:'#d4a843'}]},options:{responsive:true,scales:{r:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.06)'},pointLabels:{color:'#94a3b8',font:{size:10}}}},plugins:{legend:{labels:{color:'#5a6a80'}}}}});}},100);
};
RR.creative=async()=>{let d={};try{d=await brg('creative')}catch(e){}const subs=d.top_subjects||[];
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Performances<\/div><div class="st-v">${N(d.performance)}<\/div><\/div><div class="stat s-bl"><div class="st-l">Traductions<\/div><div class="st-v">${d.translations||0}<\/div><\/div><\/div>
<div class="card"><div class="card-h"><div class="card-t">Creative Engine IA<\/div><button class="btn btn-sm btn-ac" onclick="toast('Génération...')">🧠 Générer<\/button><\/div><p style="font-size:12px;color:var(--mu);margin-bottom:14px">Analyse performance sujets/from/HTML. Génération variantes IA. Promotion winners automatique.<\/p>
${subs.length?`<table><thead><tr><th>Sujet<\/th><th>Open%<\/th><th>Click%<\/th><\/tr><\/thead><tbody>${subs.map(s=>`<tr><td style="color:var(--wh)">${esc((s.subject||'').substring(0,45))}<\/td><td style="font-family:var(--m);color:var(--gn)">${s.open_rate||0}%<\/td><td style="font-family:var(--m);color:var(--ac)">${s.click_rate||0}%<\/td><\/tr>`).join('')}<\/tbody><\/table>`:''}<\/div>`};
// =============== ANALYTICS ===============
RR.analytics=async()=>{let d={},ch={};try{d=await brg('send_stats')}catch(e){}try{ch=await brg('charts_daily')}catch(e){}
const bi=d.by_isp||[];const stats=ch.stats||[];
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Emails track\u00e9s</div><div class="st-v">'+N(d.total)+'</div></div><div class="stat s-gn"><div class="st-l">ISPs</div><div class="st-v">'+bi.length+'</div></div><div class="stat s-bl"><div class="st-l">Opens today</div><div class="st-v">'+N((stats[0]||{}).total_opened||0)+'</div></div><div class="stat s-pu"><div class="st-l">Clicks today</div><div class="st-v">'+N((stats[0]||{}).total_clicked||0)+'</div></div></div>'
+'<div class="row2"><div class="card"><div class="card-t" style="margin-bottom:14px">Volume par ISP</div><canvas id="chISP" height="220"></canvas></div>'
+'<div class="card"><div class="card-t" style="margin-bottom:14px">Tendance 30j</div><canvas id="chTrend" height="220"></canvas></div></div>'
+'<div class="card"><div class="card-t" style="margin-bottom:10px">D\u00e9tail par ISP</div><table><thead><tr><th>ISP</th><th>Envoy\u00e9s</th><th>D\u00e9livr\u00e9s</th><th>Taux</th></tr></thead><tbody>'+bi.map(r=>'<tr><td style="color:var(--wh);font-weight:600">'+esc(r.isp||'Unknown')+'</td><td style="font-family:var(--m)">'+N(r.cnt)+'</td><td style="font-family:var(--m);color:var(--gn)">'+N(r.delivered||0)+'</td><td style="font-family:var(--m)">'+((r.delivered||0)/(+r.cnt||1)*100).toFixed(1)+'%</td></tr>').join('')+'</tbody></table></div>';
if(typeof Chart!=='undefined'&&bi.length>0){new Chart($('chISP'),{type:'doughnut',data:{labels:bi.map(r=>r.isp||'?'),datasets:[{data:bi.map(r=>+r.cnt),backgroundColor:['#d4a843','#34d399','#60a5fa','#a78bfa','#f87171','#fb923c','#22d3ee','#ec4899']}]},options:{responsive:true,plugins:{legend:{position:'right',labels:{color:'#5a6a80',font:{size:10}}}}}});
if(stats.length>1){new Chart($('chTrend'),{type:'line',data:{labels:stats.map(s=>(s.date||'').substring(5)),datasets:[{label:'Sent',data:stats.map(s=>+s.total_sent),borderColor:'#d4a843',tension:.3,pointRadius:2,fill:false},{label:'Opens',data:stats.map(s=>+s.total_opened),borderColor:'#34d399',tension:.3,pointRadius:2,fill:false}]},options:{responsive:true,plugins:{legend:{labels:{color:'#5a6a80',font:{size:10}}}},scales:{x:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}},y:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}}}}});}
}
try{var eg=await brg('engagement_score');var dist=eg.distribution||[];
var egDiv=document.createElement('div');egDiv.className='card';
egDiv.innerHTML='<div class="card-t" style="margin-bottom:10px">Engagement Scoring (7.3M contacts)</div>'
+dist.map(function(d2){var colors={'hot':'var(--gn)','warm':'var(--ac)','cold':'var(--bl)','dead':'var(--rd)'};
return '<div style="display:flex;align-items:center;gap:12px;padding:6px 0;border-bottom:1px solid var(--bd)"><span style="font-size:12px;font-weight:600;color:'+(colors[d2.score]||'var(--mu)')+'">'+esc(d2.score||'unscored').toUpperCase()+'</span><div style="flex:1;background:var(--bg);border-radius:4px;height:12px"><div style="background:'+(colors[d2.score]||'var(--dm)')+';height:100%;border-radius:4px;width:'+Math.min(100,+d2.cnt/30000)+'%"></div></div><span style="font-family:var(--m);font-size:11px;color:var(--mu)">'+N(d2.cnt)+'</span></div>'}).join('');
$('C').appendChild(egDiv)}catch(e){}
};
RR.ai=()=>{$('C').innerHTML=`<div class="chat-w"><div class="chat-m" id="aM"><div class="chat-e"><div style="font-size:36px">🧠<\/div><h3>WEVIA AI<\/h3><p style="font-size:12px;margin-top:6px;color:var(--mu)">Optimisez sujets, générez contenu, analysez délivrabilité.<\/p><div style="display:flex;gap:6px;justify-content:center;margin-top:12px;flex-wrap:wrap"><button class="btn btn-sm btn-gh" onclick="aQ('Audit delivrabilite')'>Audit<\/button><button class=\"btn btn-sm btn-gh\" onclick=\"aQ('Template email pharma')\">Template<\/button><button class=\"btn btn-sm btn-gh\" onclick=\"aQ('Stats envois 30j')\">Stats<\/button><button class=\"btn btn-sm btn-gh\" onclick=\"aQ('Schema mermaid emailing')\">Schema<\/button><button class=\"btn btn-sm btn-gh\" onclick=\"aQ('QR code https://weval-consulting.com')\">QR<\/button><\/div><\/div><\/div><div class="chat-b"><textarea id="aI" rows="1" placeholder="Message..." onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();aS()}" oninput="this.style.height='42px';this.style.height=Math.min(this.scrollHeight,110)+'px'"><\/textarea><button class="btn btn-sm btn-ac" onclick="aS()">→<\/button><\/div><\/div>`};
let chatH=[];
function aQ(q){$('aI').value=q;aS()}
async function aS(){const msg=v('aI');if(!msg)return;const b=$('aM');b.querySelector('.chat-e')?.remove();b.innerHTML+=`<div class="chat-u">${esc(msg)}<\/div>`;$('aI').value='';const lid='l'+Date.now();b.innerHTML+=`<div class="chat-a" id="${lid}"><span class="ldot"><\/span><span class="ldot"><\/span><span class="ldot"><\/span><\/div>`;b.scrollTop=b.scrollHeight;try{chatH.push({role:'user',content:msg});const r=await(await fetch(WEVIA,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:msg,mode:'fast',history:chatH.slice(-6),context:'wevads-expert',wevads_context:{page:PG}})})).json();const re=r.response||r.error||'Err';chatH.push({role:'assistant',content:re});var prov=r.provider||'WEVIA';$(lid).outerHTML=`<div class="chat-a">${md2h(re)}<div class="ai-badge" style="background:var(--acB);color:var(--ac);border:1px solid var(--acBd)">${prov}</div><\/div>`}catch(e){$(lid).outerHTML=`<div class="chat-a" style="color:var(--rd)">Err: ${e.message}<\/div>`}b.scrollTop=b.scrollHeight}
// AI Template Generation
async function aiTpl(){
var subj=prompt('Sujet du template email:');if(!subj)return;
toast('AI generating...');
try{
var r=await(await fetch(WEVIA,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:'Genere un template email HTML professionnel pour: '+subj+'. Retourne UNIQUEMENT le code HTML complet avec styles inline.',lang:'fr'})})).json();
var html=r.response||'';
if(html.length>50){
try{await(await fetch(BRG+'?action=template_save&token=WEVADS2026',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:'AI: '+subj,category:'ai',html:html})})).json()}catch(e){}
toast('Template AI cree!');RR.templates();
}else{toast('Generation failed',1)}
}catch(e){toast('Err: '+e.message,1)}
}
// === DRILL-DOWN SYSTEM ===
function drillOpen(title,content){var m=document.createElement('div');m.className='drill-modal';m.onclick=function(e){if(e.target===m)m.remove()};m.innerHTML='<div class="drill-box"><h3>'+title+'<span class="drill-close" onclick="this.closest(\'.drill-modal\').remove()">&times;</span></h3>'+content+'</div>';document.body.appendChild(m)}
async function drillKPI(type){
drillOpen('Loading...','<div class="loading-shimmer" style="height:200px;border-radius:12px"></div>');
try{
if(type==='sent'){var d=await brg('daily_stats');var s=d.stats||[];var byisp=await brg('send_stats');
drillOpen('Emails envoy\u00e9s — D\u00e9tail','<div class="drill-kpi"><div class="dk"><div class="dkv">'+N((byisp||{}).total||0)+'</div><div class="dkl">Total</div></div><div class="dk"><div class="dkv">'+s.length+'</div><div class="dkl">Jours track\u00e9s</div></div><div class="dk"><div class="dkv">'+(s.length?Math.round(s.reduce(function(a,x){return a+(+x.total_sent||0)},0)/s.length):'0')+'</div><div class="dkl">Moy/jour</div></div></div><div class="drill-chart"><canvas id="drillChart1" height="200"></canvas></div><table><thead><tr><th>ISP</th><th>Envoy\u00e9s</th><th>Livr\u00e9s</th></tr></thead><tbody>'+((byisp||{}).by_isp||[]).map(function(i){return '<tr><td style="color:var(--wh)">'+esc(i.isp||'unknown')+'</td><td style="font-family:var(--m)">'+N(i.cnt)+'</td><td style="font-family:var(--m);color:var(--gn)">'+N(i.delivered)+'</td></tr>'}).join('')+'</tbody></table>');
if(typeof Chart!=='undefined'&&s.length>1){setTimeout(function(){var el=document.getElementById('drillChart1');if(el)new Chart(el,{type:'line',data:{labels:s.map(function(x){return(x.date||'').substring(5)}),datasets:[{label:'Sent',data:s.map(function(x){return+x.total_sent}),borderColor:'#d4a843',tension:.3,pointRadius:2,fill:false},{label:'Delivered',data:s.map(function(x){return+x.total_delivered}),borderColor:'#34d399',tension:.3,pointRadius:2,fill:false}]},options:{responsive:true,plugins:{legend:{labels:{color:'#5a6a80',font:{size:10}}}},scales:{x:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}},y:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}}}}})},200)}
}
else if(type==='tracking'){var d=await brg('charts_daily');var s=d.stats||[];
drillOpen('Opens & Clicks — D\u00e9tail','<div class="drill-kpi"><div class="dk"><div class="dkv">'+N(s.reduce(function(a,x){return a+(+x.total_opened||0)},0))+'</div><div class="dkl">Total Opens</div></div><div class="dk"><div class="dkv">'+N(s.reduce(function(a,x){return a+(+x.total_clicked||0)},0))+'</div><div class="dkl">Total Clicks</div></div><div class="dk"><div class="dkv">'+(s.length&&s.reduce(function(a,x){return a+(+x.total_sent||0)},0)>0?Math.round(s.reduce(function(a,x){return a+(+x.total_opened||0)},0)/s.reduce(function(a,x){return a+(+x.total_sent||0)},0)*100):0)+'%</div><div class="dkl">Taux ouverture</div></div></div><div class="drill-chart"><canvas id="drillChart2" height="200"></canvas></div>');
if(typeof Chart!=='undefined'&&s.length>1){setTimeout(function(){var el=document.getElementById('drillChart2');if(el)new Chart(el,{type:'bar',data:{labels:s.map(function(x){return(x.date||'').substring(5)}),datasets:[{label:'Opens',data:s.map(function(x){return+x.total_opened}),backgroundColor:'rgba(52,211,153,.5)',borderRadius:4},{label:'Clicks',data:s.map(function(x){return+x.total_clicked}),backgroundColor:'rgba(96,165,250,.5)',borderRadius:4}]},options:{responsive:true,plugins:{legend:{labels:{color:'#5a6a80',font:{size:10}}}},scales:{x:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}},y:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}}}}})},200)}
}
else if(type==='revenue'){var rv=await brg('revenue');var t=rv.totals||{};var bc=rv.by_campaign||[];
drillOpen('Revenue — D\u00e9tail','<div class="drill-kpi"><div class="dk"><div class="dkv" style="color:var(--gn)">$'+N(t.revenue||0)+'</div><div class="dkl">Revenue</div></div><div class="dk"><div class="dkv" style="color:var(--rd)">$'+N(t.cost||0)+'</div><div class="dkl">Co\u00fbt</div></div><div class="dk"><div class="dkv" style="color:var(--ac)">$'+N(t.profit||0)+'</div><div class="dkl">Profit</div></div></div><table><thead><tr><th>Campagne</th><th>Network</th><th>Envois</th><th>Conv</th><th>Revenue</th></tr></thead><tbody>'+bc.map(function(r){return '<tr><td style="color:var(--wh)">'+esc(r.campaign_name||'')+'</td><td><span class="badge b-em">'+esc(r.network||'')+'</span></td><td style="font-family:var(--m)">'+N(r.sends)+'</td><td style="font-family:var(--m);color:var(--gn)">'+N(r.conversions)+'</td><td style="font-family:var(--m);color:var(--ac)">$'+N(r.revenue)+'</td></tr>'}).join('')+'</tbody></table>');
}
else if(type==='contacts'){var sc=await brg('contact_scoring');var tiers=sc.tiers||[];
drillOpen('Contacts — Scoring','<div class="drill-kpi">'+tiers.map(function(t){var colors={hot:'var(--gn)',warm:'var(--ac)',cold:'var(--bl)',dead:'var(--rd)'};return '<div class="dk"><div class="dkv" style="color:'+(colors[t.tier]||'var(--mu)')+'">'+N(t.cnt)+'</div><div class="dkl">'+esc(t.tier||'')+'</div></div>'}).join('')+'</div>');
}
}catch(e){drillOpen('Erreur','<p style="color:var(--rd)">'+e.message+'</p>')}
}
// Show send log modal
async function showSendLog(){try{var d=await brg('send_stats');drillOpen('Historique envois','<table><thead><tr><th>ISP</th><th>Envoyes</th><th>Livres</th></tr></thead><tbody>'+((d||{}).by_isp||[]).map(function(i){return '<tr><td style="color:var(--wh)">'+esc(i.isp||'unknown')+'</td><td style="font-family:var(--m)">'+N(i.cnt)+'</td><td style="font-family:var(--m);color:var(--gn)">'+N(i.delivered)+'</td></tr>'}).join('')+'</tbody></table>')}catch(e){toast('Err',1)}}
// Show individual send detail
async function showSendDetail(id){drillOpen('Send #'+id,'<p style="color:var(--mu)">Detail envoi #'+id+'</p>')}
// =============== CHANNELS ===============
RR.channels=async()=>{let se={};try{se=await(await fetch(SE+'?action=status&token=ETHICA_API_2026_SECURE')).json()}catch(e){}const inf=se.infrastructure||{};const o=inf.o365_senders||{};
$('C').innerHTML=`<div class="stats"><div class="stat s-bl"><div class="st-l">Email<\/div><div class="st-v" style="font-size:16px;color:var(--em)">LIVE<\/div><div class="st-s">PMTA+${o.active||0} O365<\/div><\/div><div class="stat s-tg"><div class="st-l">Telegram<\/div><div class="st-v" style="font-size:16px;color:var(--tg)">LIVE<\/div><\/div><div class="stat s-gn"><div class="st-l">SMS<\/div><div class="st-v" style="font-size:16px;color:var(--or)">PENDING<\/div><\/div><div class="stat s-or"><div class="st-l">WhatsApp<\/div><div class="st-v" style="font-size:16px;color:var(--wa)">LIVE<\/div><div class="st-s">Meta API<\/div><\/div><\/div>
<div class="card"><div class="card-h"><div class="card-t">✈ Telegram<\/div><span class="badge b-ok">Connecté<\/span><\/div><p style="font-size:12px;color:var(--mu);margin-bottom:10px">@wevads_alerts_bot → Yacine<\/p><button class="btn btn-sm btn-gh" style="color:var(--tg);border-color:rgba(34,158,217,.2)" onclick="tgTest()">Test Telegram<\/button><\/div>
<div class="card"><div class="card-h"><div class="card-t">💬 SMS OVH<\/div><span class="badge b-ok">CONNECTÉ<\/span><\/div><div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px"><div class="field"><label>App Key<\/label><input id="sk1"><\/div><div class="field"><label>Secret<\/label><input id="sk2"><\/div><div class="field"><label>Consumer<\/label><input id="sk3"><\/div><\/div><button class="btn btn-sm btn-gh" style="color:var(--sm)" onclick="cfgSMS()">Configurer<\/button><\/div>
<div class="card"><div class="card-h"><div class="card-t">📱 WhatsApp<\/div><span class="badge b-ok">CONNECTÉ<\/span><\/div><div class="row2"><div class="field"><label>Phone ID<\/label><input id="wk1"><\/div><div class="field"><label>Token<\/label><input id="wk2"><\/div><\/div><button class="btn btn-sm btn-gh" style="color:var(--wa)" onclick="cfgWA()">Configurer<\/button><\/div>`};
async function tgTest(){toast('Envoi TG...');try{const r=await(await fetch('https://api.telegram.org/bot8544624912:AAEm9ttXK6JeFqAL-gcvB5sreCBhXzzQwrs/sendMessage',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({chat_id:'7605775322',text:'✅ WEVADS IA v3.0 Test\n'+new Date().toLocaleString('fr-FR')})})).json();toast(r.ok?'TG OK':'Err',!r.ok)}catch(e){toast('Err',1)}}
async function cfgSMS(){toast('Config SMS...')}
async function cfgWA(){toast('Config WA...')}
// =============== TEMPLATES ===============
let TPL=[];
RR.templates=async()=>{try{TPL=(await brg('template_list')).templates||[]}catch(e){TPL=[]}
$('C').innerHTML=`<div class="toolbar"><div class="sp"><\/div><button class="btn btn-sm btn-ac" onclick="oTpl()">+ Nouveau<\/button><button class="btn btn-sm btn-gh" onclick="aiTpl()">\u{1f9e0} AI Generate<\/button><\/div><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px" id="tG"><\/div>`;
$('tG').innerHTML=TPL.map(t=>`<div class="card" style="cursor:pointer"><div style="display:flex;justify-content:space-between;margin-bottom:8px"><span style="font-weight:700;color:var(--wh)">${esc(t.name)}<\/span><span class="badge b-ok">${esc(t.category)}<\/span><\/div><div style="background:var(--bg);border:1px solid var(--bd);border-radius:var(--r3);padding:10px;min-height:50px;font-size:10px;color:var(--mu);overflow:hidden;max-height:70px">${t.html?t.html.substring(0,120)+'...':'—'}<\/div><\/div>`).join('')||'<div style="text-align:center;color:var(--dm);padding:30px;grid-column:1/-1">—<\/div>'};
function oTpl(){const m=document.createElement('div');m.className='modal-bg';m.onclick=e=>{if(e.target===m)m.remove()};m.innerHTML=`<div class="modal"><h3>Template<\/h3><div class="field"><label>Nom<\/label><input id="tN"><\/div><div class="field"><label>Cat<\/label><select id="tC"><option>marketing<\/option><option>transactional<\/option><option>newsletter<\/option><\/select><\/div><div class="field"><label>HTML<\/label><textarea class="ed" id="tH" rows="6"><\/textarea><\/div><div class="brow"><button class="btn btn-gh" onclick="this.closest('.modal-bg').remove()">×<\/button><button class="btn btn-ac" onclick="sTpl()">Save<\/button><\/div><\/div>`;document.body.appendChild(m)}
async function sTpl(){try{await api('/templates',{method:'POST',body:JSON.stringify({name:v('tN'),category:v('tC'),html:v('tH')})});document.querySelector('.modal-bg')?.remove();toast('Créé');RR.templates()}catch(e){toast(e.message,1)}}
// =============== SEND ENGINE ===============
RR.sendengine=async()=>{
window.doRotate=async function(){toast('Rotating...');try{var r=await brg('rotate_next');toast(r.ok?'Rotated: '+(r.sender||''):'No sender available',!r.ok);RR.sendengine()}catch(e){toast('Err',1)}};
let se={},k={},w={};try{se=await(await fetch(SE+'?action=status&token=ETHICA_API_2026_SECURE')).json()}catch(e){}try{k=(await eng('dashboard')).kpis||{}}catch(e){}try{w=await eng('warmup_status')}catch(e){}const inf=se.infrastructure||{};const o=inf.o365_senders||{};const pm=inf.pmta||{};const cl=se.clients||{};
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Méthode<\/div><div class="st-v" style="font-size:14px">${(inf.method||'—').toUpperCase()}<\/div><\/div><div class="stat s-bl"><div class="st-l">O365<\/div><div class="st-v">${o.active||0}/${o.total||0}<\/div><\/div><div class="stat s-gn"><div class="st-l">PMTA<\/div><div class="st-v">${pm.servers_alive||0}/${pm.servers_configured||0}<\/div><\/div><div class="stat s-pu"><div class="st-l">Warmup<\/div><div class="st-v">${N(w.total_accounts||k.warmup_accounts)}<\/div><\/div><div class="stat s-or"><div class="st-l">Queue<\/div><div class="st-v">${k.queue_pending||0}<\/div><\/div><\/div>
<div class="row2"><div class="card"><div class="card-t" style="margin-bottom:10px">Clients<\/div>${[['Ethica (Pharma)',cl.ethica?.contacts,cl.ethica?.emails,'var(--ac)'],['WEVADS (Multi)',cl.wevads?.contacts,k.senders_active,'var(--cy)']].map(([n,c,e,col])=>`<div style="padding:12px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);margin-bottom:8px"><div style="font-size:11px;font-weight:600;color:${col}">${n}<\/div><div style="font-family:var(--m);font-size:18px;font-weight:800;color:var(--wh)">${N(c||0)}<\/div><div style="font-size:10px;color:var(--mu)">${N(e||0)} active<\/div><\/div>`).join('')}<\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">Métriques<\/div><div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">${[['Envoyés',k.emails_sent_total,'var(--wh)'],['Today',k.emails_sent_today,'var(--gn)'],['Bounces',k.bounces,'var(--rd)'],['Methods',k.send_methods,'var(--cy)']].map(([l,v2,c])=>`<div style="text-align:center;padding:10px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r)"><div style="font-size:16px;font-weight:800;color:${c};font-family:var(--m)">${N(v2||0)}<\/div><div style="font-size:9px;color:var(--mu);margin-top:3px">${l}<\/div><\/div>`).join('')}<\/div><\/div><\/div>`};
// =============== OFFERS ===============
RR.offers=async()=>{let d={};try{d=await brg('offers')}catch(e){}const off=d.offers||[];const sp=d.sponsors||[];const bv=d.by_vertical||[];const bs=d.by_status||[];
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Offres<\/div><div class="st-v">${N(d.total_offers)}<\/div><\/div><div class="stat s-gn"><div class="st-l">Sponsors<\/div><div class="st-v">${sp.length}<\/div><\/div><div class="stat s-bl"><div class="st-l">Networks<\/div><div class="st-v">${(d.networks||[]).length}<\/div><\/div><\/div>
<div class="card"><div class="card-h"><div class="card-t">Catalogue Offres (${N(d.total_offers)})<\/div><button class="btn btn-sm btn-ac" onclick="toast('Import depuis CX3/Double M')">+ Importer<\/button><\/div>
<table><thead><tr><th>Offre<\/th><th>Pays<\/th><th>Vertical<\/th><th>Payout<\/th><th>Statut<\/th><th>Clicks<\/th><th>Conv.<\/th><\/tr><\/thead>
<tbody>${off.slice(0,20).map(o=>`<tr><td style="color:var(--wh);font-weight:500;font-size:11px">${esc((o.offer_name||'').substring(0,45))}<\/td><td><span class="badge b-em">${esc(o.country_code)}<\/span><\/td><td style="font-size:11px;color:var(--mu)">${esc(o.vertical)}<\/td><td style="font-family:var(--m);color:var(--gn)">${o.payout>0?'$'+o.payout:'—'}<\/td><td><span class="badge b-${o.status==='active'?'ok':o.status==='public'?'ac':'wait'}">${esc(o.status)}<\/span><\/td><td style="font-family:var(--m)">${N(o.clicks)}<\/td><td style="font-family:var(--m);color:var(--ac)">${N(o.conversions)}<\/td><\/tr>`).join('')}<\/tbody><\/table><\/div>`;
if(typeof Chart!=='undefined'&&bv.length>0){setTimeout(()=>{const el=document.getElementById('chVert');if(el)new Chart(el,{type:'pie',data:{labels:bv.map(v=>v.vertical),datasets:[{data:bv.map(v=>+v.cnt),backgroundColor:['#d4a843','#34d399','#60a5fa','#a78bfa','#f87171','#fb923c','#22d3ee','#ec4899','#10b981','#8b5cf6']}]},options:{responsive:true,plugins:{legend:{position:'right',labels:{color:'#5a6a80',font:{size:10}}}}}});},100);
};
};
// =============== SPONSORS ===============
RR.infra=async()=>{let d={};try{d=await brg('infra')}catch(e){}const sc=d.schemas||[];
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Tables<\/div><div class="st-v">${d.tables||0}<\/div><\/div><div class="stat s-bl"><div class="st-l">DB Size<\/div><div class="st-v" style="font-size:16px">${d.db_size||'?'}<\/div><\/div><div class="stat s-gn"><div class="st-l">APIs<\/div><div class="st-v">344<\/div><\/div><div class="stat s-pu"><div class="st-l">GOLD<\/div><div class="st-v">1,411<\/div><\/div><\/div>
<div class="row2"><div class="card"><div class="card-t" style="margin-bottom:10px">Schemas PostgreSQL<\/div><table><thead><tr><th>Schema<\/th><th>Tables<\/th><\/tr><\/thead><tbody>${sc.map(s=>`<tr onclick="drillSchema(s.schemaname,s.cnt)" style="cursor:pointer"><td style="color:var(--wh);font-weight:600">${esc(s.schemaname)}<\/td><td style="font-family:var(--m)">${s.cnt}<\/td><\/tr>`).join('')}<\/tbody><\/table><\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">Services<\/div>${[['S95 Apache','ADX 5821+BCG 5823+FMG 5822','ok'],['S95 PMTA v5.0r3','Port 25','ok'],['S95 Postfix','2525/2526','ok'],['S204 Nginx','HTTPS proxy','ok'],['Node.js V2','Port 5850','ok'],['S151 Tracking','HTTP relay','ok'],['Telegram Bot','@wevads_alerts_bot','ok'],['Qdrant RAG','S95:6333','ok'],['n8n Workflows','S95:5678','ok']].map(([n,d,s])=>`<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--wh)">${n}<\/span><span style="font-family:var(--m);font-size:9px;color:var(--mu)">${d}<\/span><span class="badge b-${s}">${s}<\/span><\/div>`).join('')}<\/div><\/div>`};
// =============== SETTINGS ===============
RR.settings=()=>{$('C').innerHTML=`<div class="card"><div class="card-t" style="margin-bottom:14px">Profil<\/div><div class="row2"><div class="field"><label>Nom<\/label><input value="${esc(U.name||'')}"><\/div><div class="field"><label>Email<\/label><input value="${esc(U.email||'')}" readonly style="opacity:.5"><\/div><\/div><button class="btn btn-sm btn-ac" style="margin-top:10px" onclick="toast('OK')">Save<\/button><\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">Auth DNS<\/div><table><tbody>${[['SPF','v=spf1 include:spf.pmta.weval ~all'],['DKIM','weval2026._domainkey'],['DMARC','p=quarantine'],['TLS','1.3 Enforced']].map(([k,v2])=>`<tr><td style="color:var(--wh)">${k}<\/td><td style="font-family:var(--m);font-size:11px;color:var(--mu)">${v2}<\/td><\/tr>`).join('')}<\/tbody><\/table><\/div>`};
// =============== OFFERS ===============
RR.abtesting=async()=>{let d={};try{d=await brg('ab_testing')}catch(e){}const subs=d.subjects||[];
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Tests sujets<\/div><div class="st-v">${N(d.total)}<\/div><\/div><div class="stat s-gn"><div class="st-l">Winners<\/div><div class="st-v">${d.winners||0}<\/div><\/div><\/div>
<div class="card"><div class="card-h"><div class="card-t">Subject line A/B testing<\/div><button class="btn btn-sm btn-ac" onclick="toast('Test IA lance')">+ Nouveau test<\/button><\/div>
<table><thead><tr><th>Offer<\/th><th>Subject<\/th><th>Country<\/th><th>Sent<\/th><th>Opens<\/th><th>Rate<\/th><th>Winner<\/th><\/tr><\/thead>
<tbody>${subs.map(s=>`<tr><td style="font-family:var(--m);color:var(--mu)">${s.offer_id}<\/td><td style="font-family:var(--m);font-size:10px">${s.subject_id}<\/td><td style="color:var(--wh)">${esc(s.country)}<\/td><td style="font-family:var(--m)">${N(s.total_sent)}<\/td><td style="font-family:var(--m)">${N(s.total_opens)}<\/td><td style="font-family:var(--m);color:${+s.open_rate>15?'var(--gn)':+s.open_rate>5?'var(--ac)':'var(--rd)'}">${s.open_rate}%<\/td><td>${s.is_winner?'\u2705':'\u274c'}<\/td><\/tr>`).join('')}<\/tbody><\/table><\/div>
<div class="card"><div class="card-t" style="margin-bottom:8px">IA A/B Engine<\/div><p style="font-size:12px;color:var(--mu);line-height:1.7">Le Brain teste automatiquement les variantes de sujets par ISP/pays. Les winners sont promus pour les envois bulk. Gnration IA de 5-10 variantes par offre.<\/p><\/div>`};
// =============== SCHEDULED ===============
RR.scheduled=async()=>{let d={};try{d=await brg('scheduled')}catch(e){}const sc=d.campaigns||[];
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Scheduled<\/div><div class="st-v">${d.total||0}<\/div><\/div><\/div>
<div class="card"><div class="card-h"><div class="card-t">Campagnes programmes<\/div><button class="btn btn-sm btn-ac" onclick="toast('Scheduler')">+ Programmer<\/button><\/div>
${sc.length?`<table><thead><tr><th>ID<\/th><th>Nom<\/th><th>Date<\/th><th>Statut<\/th><\/tr><\/thead><tbody>${sc.map(c=>`<tr><td style="font-family:var(--m)">${c.id}<\/td><td style="color:var(--wh)">${esc(c.name||c.campaign_name||'Campaign '+c.id)}<\/td><td style="font-family:var(--m);font-size:11px;color:var(--mu)">${c.scheduled_at||c.send_date||''}<\/td><td><span class="badge b-wait">scheduled<\/span><\/td><\/tr>`).join('')}<\/tbody><\/table>`:'<p style="color:var(--mu);font-size:13px">Aucune campagne programme. Cliquez sur "+ Programmer" pour planifier un envoi.<\/p>'}
<\/div><div class="card"><div class="card-t" style="margin-bottom:8px">Cron Engine<\/div><p style="font-size:12px;color:var(--mu);line-height:1.7">34 crons actifs sur S95. Le scheduler permet de planifier des envois heure fixe, par segment, avec rotation automatique des senders et mthodes.<\/p><\/div>`};
// =============== DOMAIN POOL ===============
RR.dompool=async()=>{let d={};try{d=await brg('domain_pool')}catch(e){}const pool=d.pool||[];const bs=d.by_status||[];
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Pool total<\/div><div class="st-v">${N(d.total)}<\/div><\/div><div class="stat s-gn"><div class="st-l">DNS OK<\/div><div class="st-v">${d.configured||0}<\/div><\/div><div class="stat s-bl"><div class="st-l">Statuts<\/div><div class="st-v">${bs.length}<\/div><\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">Status distribution<\/div>${bs.map(s=>`<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="color:var(--wh)">${esc(s.status)}<\/span><span style="font-family:var(--m);color:var(--ac)">${N(s.cnt)}<\/span><\/div>`).join('')}<\/div>
<div class="card" style="padding:0;overflow:hidden"><table><thead><tr><th>Domaine<\/th><th>Source<\/th><th>Registrar<\/th><th>SPF<\/th><th>DKIM<\/th><th>DMARC<\/th><th>Emails<\/th><th>Score<\/th><\/tr><\/thead>
<tbody>${pool.slice(0,20).map(p=>`<tr onclick="drillDomain(p.domain||'?',p.has_spf,p.has_dkim,p.has_dmarc,p.emails_sent||0,p.reputation_score||0)" style="cursor:pointer"><td style="font-family:var(--m);font-size:10px;color:var(--wh)">${esc(p.domain)}<\/td><td style="font-size:10px;color:var(--mu)">${esc(p.source||'')}<\/td><td style="font-size:10px">${esc(p.registrar||'')}<\/td><td>${p.has_spf?'\u2705':'\u274c'}<\/td><td>${p.has_dkim?'\u2705':'\u274c'}<\/td><td>${p.has_dmarc?'\u2705':'\u274c'}<\/td><td style="font-family:var(--m)">${N(p.emails_sent)}<\/td><td style="font-family:var(--m);color:var(--gn)">${p.reputation_score||0}<\/td><\/tr>`).join('')}<\/tbody><\/table><\/div>`};
// =============== REVENUE ===============
RR.revenue=async()=>{let d={},pb={};try{d=await brg('revenue')}catch(e){}try{pb=await(await fetch('/api/postback.php?action=stats&token=WEVADS2026')).json()}catch(e){}
const t=d.totals||{};const pbt=pb.totals||{};const bc=d.by_campaign||[];const pbd=pb.daily||[];
const totalRev=+(t.revenue||0)+ Number(pbt.rev||0);const totalProfit=+(t.profit||0)+ Number(pbt.profit||0);const totalConv=+(t.conversions||0)+ Number(pbt.conv||0);
$('C').innerHTML='<div class="stats"><div class="stat s-gn"><div class="st-l">Revenue Total</div><div class="st-v">$'+N(totalRev)+'</div></div><div class="stat s-rd"><div class="st-l">Cost</div><div class="st-v">$'+N(t.cost||0)+'</div></div><div class="stat s-ac"><div class="st-l">Profit</div><div class="st-v">$'+N(totalProfit)+'</div></div><div class="stat s-bl"><div class="st-l">Conversions</div><div class="st-v">'+N(totalConv)+'</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Postback Webhook</div><span class="badge b-ok">Live</span></div><p style="font-size:11px;color:var(--mu);margin-bottom:12px">URL: <code style="font-family:var(--m);font-size:10px;background:var(--bg);padding:3px 8px;border-radius:6px">weval-consulting.com/api/postback.php?action=receive&offer_id=OID&payout=AMT&network=NET&sub1=CAMP</code></p>'
+(pbd.length?'<canvas id="chRev" height="180" style="margin-top:12px"></canvas>':'<p style="color:var(--dm);font-size:12px">Envoyez un postback pour voir les conversions ici.</p>')
+'</div>';
if(typeof Chart!=='undefined'&&pbd.length>0){setTimeout(()=>{new Chart($('chRev'),{type:'bar',data:{labels:pbd.map(d=>d.date),datasets:[{label:'Revenue',data:pbd.map(d=>+d.rev),backgroundColor:'rgba(52,211,153,.5)',borderRadius:4}]},options:{responsive:true,plugins:{legend:{labels:{color:'#5a6a80',font:{size:10}}}},scales:{x:{ticks:{color:'#374151',font:{size:9}},grid:{color:'rgba(255,255,255,.03)'}},y:{ticks:{color:'#374151',font:{size:9},callback:v=>'$'+v},grid:{color:'rgba(255,255,255,.03)'}}}}});},100);}};
RR.pmtamgmt=async()=>{var km={},ma={},d={};try{km=await brg('kumomta_status')}catch(e){}try{ma=await brg('mta_architecture')}catch(e){}try{d=await brg('pmta')}catch(e){}
var arch=ma.architecture||[];
$('C').innerHTML='<div class="stats"><div class="stat s-gn"><div class="st-l">KumoMTA</div><div class="st-v" style="font-size:16px;color:'+(km.status==='active'?'var(--gn)':'var(--rd)')+'">'+esc(km.status||'?').toUpperCase()+'</div><div class="st-s">Port 587 (Rust)</div></div><div class="stat s-ac"><div class="st-l">PMTA</div><div class="st-v" style="font-size:16px">Active</div><div class="st-s">Port 25 (Legacy)</div></div><div class="stat s-bl"><div class="st-l">Postfix</div><div class="st-v" style="font-size:16px">Active</div><div class="st-s">Port 2525</div></div><div class="stat s-pu"><div class="st-l">Architecture</div><div class="st-v" style="font-size:14px">Dual MTA</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">MTA Architecture</div><span class="badge b-ok">Production</span></div>'
+'<div style="display:grid;grid-template-columns:1fr auto 1fr auto 1fr;gap:8px;align-items:center;margin:16px 0">'
+'<div style="padding:16px;background:var(--sf);border:2px solid var(--gn);border-radius:var(--r);text-align:center"><div style="font-size:14px;font-weight:600;color:var(--gn)">WEVADS IA</div><div style="font-size:10px;color:var(--mu);margin-top:4px">38 pages, souverain</div></div>'
+'<div style="font-size:20px;color:var(--ac)">\u2192</div>'
+'<div style="padding:16px;background:var(--sf);border:2px solid var(--ac);border-radius:var(--r);text-align:center"><div style="font-size:14px;font-weight:600;color:var(--ac)">KumoMTA :587</div><div style="font-size:10px;color:var(--mu);margin-top:4px">Rust, 2026.03.04, REST API</div><div style="font-size:9px;color:var(--gn);margin-top:3px">'+(km.banner||'...')+'</div></div>'
+'<div style="font-size:14px;color:var(--dm)">fallback \u2192</div>'
+'<div style="padding:16px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);text-align:center"><div style="font-size:14px;font-weight:600;color:var(--mu)">PMTA :25</div><div style="font-size:10px;color:var(--dm);margin-top:4px">Legacy v5.0r3</div></div></div>'
+'<div style="display:grid;grid-template-columns:1fr auto 1fr auto 1fr;gap:8px;align-items:center;margin:0 0 16px">'
+'<div style="padding:16px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);text-align:center"><div style="font-size:14px;font-weight:600;color:var(--mu)">WEVADS ADX</div><div style="font-size:10px;color:var(--dm);margin-top:4px">Legacy Arsenal</div></div>'
+'<div style="font-size:20px;color:var(--mu)">\u2192</div>'
+'<div style="padding:16px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);text-align:center"><div style="font-size:14px;font-weight:600;color:var(--mu)">PMTA :25</div><div style="font-size:10px;color:var(--dm);margin-top:4px">v5.0r3, inchange</div></div>'
+'<div style="font-size:14px;color:var(--dm)">fallback \u2192</div>'
+'<div style="padding:16px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);text-align:center"><div style="font-size:14px;font-weight:600;color:var(--dm)">Postfix :2525</div><div style="font-size:10px;color:var(--dm);margin-top:4px">Internal relay</div></div></div></div>'
+'<div class="row2"><div class="card"><div class="card-t" style="margin-bottom:10px">KumoMTA Details</div>'
+'<div style="display:grid;gap:6px">'
+[['Version','2026.03.04'],['Engine','Rust (async, zero-copy)'],['Port','587 SMTP + 8010 HTTP API'],['Config','Lua policy (/opt/kumomta/etc/policy/init.lua)'],['License','Apache 2.0 (open source)'],['Default pour','WEVADS IA (tous les sends)'],['Fallback','PMTA :25 si KumoMTA down'],['Avantages','REST API, bounce classification, per-tenant throttle']].map(function(r){return '<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--mu)">'+r[0]+'</span><span style="font-size:11px;color:var(--wh);font-weight:500">'+r[1]+'</span></div>'}).join('')
+'</div></div>'
+'<div class="card"><div class="card-t" style="margin-bottom:10px">PMTA Legacy</div>'
+(d.total_configs?('<table><thead><tr><th>Config</th><th>Host</th><th>Port</th><th>Status</th></tr></thead><tbody>'+(d.configs||[]).map(function(c){return '<tr><td style="color:var(--wh);font-size:11px">'+esc(c.config_name||'?')+'</td><td style="font-family:var(--m);font-size:10px">'+esc(c.host||'?')+'</td><td>'+c.port+'</td><td><span class="badge '+(c.status==='active'?'b-ok':'b-err')+'">'+esc(c.status)+'</span></td></tr>'}).join('')+'</tbody></table>'):('<p style="font-size:11px;color:var(--dm)">PMTA en mode safe (127.0.0.1)</p>'))
+'</div></div>';};
RR.ippool=async()=>{let d={},w={};try{d=await brg('domain_pool')}catch(e){}try{w=await brg('warmup')}catch(e){}
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Domaines Pool<\/div><div class="st-v">${N(d.total)}<\/div><\/div><div class="stat s-gn"><div class="st-l">Warmup IPs<\/div><div class="st-v">${N(w.total)}<\/div><\/div><div class="stat s-bl"><div class="st-l">Active<\/div><div class="st-v">${w.active||0}<\/div><\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">IP Rotation Strategy<\/div><p style="font-size:12px;color:var(--mu);line-height:1.7;margin-bottom:14px">Le pool IP tourne automatiquement entre les adresses chaudes. Chaque IP est surveille pour bounces, blacklists, et taux d'inbox. Les IPs froides sont mises en warmup avant rutilisation.<\/p>
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:8px">${['PMTA Direct (S95)','O365 Pool (562)','GSuite Relay (3)','Postfix Local'].map(n=>`<div style="padding:10px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);text-align:center"><div style="font-size:10px;color:var(--mu)">${n}<\/div><div style="font-size:14px;font-weight:700;color:var(--gn);margin-top:4px">Active<\/div><\/div>`).join('')}<\/div><\/div>`};
// =============== POSTMASTER ===============
RR.postmaster=async()=>{let r={};try{r=await brg('reputation')}catch(e){}
$('C').innerHTML=`<div class="stats"><div class="stat s-gn"><div class="st-l">Gmail<\/div><div class="st-v" style="font-size:16px">Monitoring<\/div><\/div><div class="stat s-bl"><div class="st-l">Microsoft<\/div><div class="st-v" style="font-size:16px">SNDS<\/div><\/div><div class="stat s-rd"><div class="st-l">Bounces<\/div><div class="st-v">${r.bounces||0}<\/div><\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">Postmaster Tools<\/div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px">
<div style="padding:16px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r)"><div style="font-size:12px;font-weight:600;color:var(--gn);margin-bottom:8px">Gmail Postmaster<\/div><p style="font-size:11px;color:var(--mu);line-height:1.6">Domain reputation, spam rate, authentication (SPF/DKIM/DMARC), delivery errors. Configurer via postmaster.google.com<\/p><button class="btn btn-sm btn-gh" style="margin-top:8px" onclick="window.open('https://postmaster.google.com')">Ouvrir Gmail<\/button><\/div>
<div style="padding:16px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r)"><div style="font-size:12px;font-weight:600;color:var(--bl);margin-bottom:8px">Microsoft SNDS<\/div><p style="font-size:11px;color:var(--mu);line-height:1.6">Smart Network Data Services: IP reputation, trap hits, sample messages. Configurer via sendersupport.olc.protection.outlook.com<\/p><button class="btn btn-sm btn-gh" style="margin-top:8px" onclick="window.open('https://sendersupport.olc.protection.outlook.com/snds/')">Ouvrir SNDS<\/button><\/div>
<\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">Blacklist Check<\/div><div style="display:grid;grid-template-columns:repeat(5,1fr);gap:6px">${['Spamhaus','Barracuda','SORBS','UCEPROTECT','Spamcop'].map(n=>`<div style="padding:10px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);text-align:center"><div style="font-size:9px;color:var(--mu)">${n}<\/div><div style="font-size:13px;font-weight:700;color:var(--gn);margin-top:3px">Clean<\/div><\/div>`).join('')}<\/div><\/div>`};
// =============== LIST CLEANER ===============
RR.listclean=async()=>{
let sc={},bl={};try{sc=await brg('contact_scoring')}catch(e){}try{bl=await brg('blacklist')}catch(e){}
const tiers=sc.tiers||[];const bls=bl.results||[];
const total=tiers.reduce((a,t)=>a+(+t.cnt||0),0);
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Contacts DB<\/div><div class="st-v">${N(total)}<\/div><\/div><div class="stat s-gn"><div class="st-l">Actifs<\/div><div class="st-v">${N(tiers.find(t=>t.tier==='hot')?.cnt||0)}<\/div><\/div><div class="stat s-rd"><div class="st-l">Dead<\/div><div class="st-v">${N(tiers.find(t=>t.tier==='dead')?.cnt||0)}<\/div><\/div><\/div>
<div class="card"><div class="card-h"><div class="card-t">Email Validator & List Cleaner<\/div><\/div>
<div class="row2"><div><div class="field"><label>Emails valider (1 par ligne)<\/label><textarea class="ed" id="lcEmails" rows="6" placeholder="test@gmail.com\nuser@company.com"><\/textarea><\/div><button class="btn btn-sm btn-ac" onclick="toast('Validation en cours...')">Valider<\/button><\/div>
<div><div class="card-t" style="margin-bottom:10px">Rgles de nettoyage<\/div>${['Syntaxe email invalide','Domaines inexistants (MX check)','Adresses jetables (temp-mail)','Spam traps connus','Hard bounces historiques','Doublons','Adresses role (info@, admin@)'].map(r=>`<div style="display:flex;align-items:center;gap:6px;padding:4px 0;border-bottom:1px solid var(--bd);font-size:11px;color:var(--mu)"><span style="color:var(--gn)">\u2713<\/span>${r}<\/div>`).join('')}<\/div><\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:8px">Suppression Import<\/div><p style="font-size:12px;color:var(--mu);line-height:1.7">Importez une liste de suppression (bounces, unsubs, plaintes) au format CSV. Les adresses seront exclues de tous les envois futurs.<\/p><button class="btn btn-sm btn-gh" onclick="toast('Upload CSV...')">Importer CSV<\/button><\/div>`};
// =============== SMART REPORT ===============
RR.smartreport=async()=>{let d={};try{d=await brg('send_stats')}catch(e){}
let ds={},rv={},br={},wm={};
try{ds=await brg('daily_stats')}catch(e){}
try{rv=await brg('revenue')}catch(e){}
try{br=await brg('brain')}catch(e){}
try{wm=await brg('warmup')}catch(e){}
let ku={},dh={};try{ku=await brg('kuma_status')}catch(e){}try{dh=await brg('domain_health')}catch(e){}
const stats=ds.stats||[];const tot=rv.totals||{};
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Contacts</div><div class="st-v">'+N(d.total||0||7354713)+'</div></div><div class="stat s-bl"><div class="st-l">Envoyes</div><div class="st-v">'+N(d.total||0||552372)+'</div></div><div class="stat s-gn"><div class="st-l">Senders</div><div class="st-v">'+N((d.by_isp||[]).length||650)+'</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Generateur de rapports</div><button class="btn btn-sm btn-ac" onclick="toast(\u0027Rapport genere\u0027)">Generer PDF</button></div>'
+'<div class="row2"><div class="field"><label>Periode</label><select><option>Aujourd\u0027hui</option><option selected>Ce mois</option><option>Ce trimestre</option></select></div>'
+'<div class="field"><label>Format</label><select><option>PDF</option><option>CSV</option><option>Email</option></select></div></div>'
+'<div style="margin-top:14px;display:grid;grid-template-columns:repeat(3,1fr);gap:8px">'
+['Executive Summary','Deliverability','ISP Performance','Revenue','Sender Health','Campaign ROI'].map(function(r){return '<div style="padding:12px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);cursor:pointer;text-align:center;font-size:11px;color:var(--mu)" onclick="toast(\u0027'+r+'...\u0027)">'+r+'</div>'}).join('')
+'</div></div>';};
RR.n8n=async()=>{
let ns={};try{ns=await brg('n8n_status')}catch(e){}
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">Workflows<\/div><div class="st-v">3<\/div><\/div><div class="stat s-gn"><div class="st-l">Status<\/div><div class="st-v" style="font-size:16px">${ns.n8n_status==='ok'?'Active':'Down'}<\/div><\/div><div class="stat s-bl"><div class="st-l">Port<\/div><div class="st-v">5678<\/div><\/div><\/div>
<div class="card"><div class="card-h"><div class="card-t">N8N Automation Workflows<\/div><button class="btn btn-sm btn-gh" onclick="window.open('http://95.216.167.89:5678')">Ouvrir N8N<\/button><\/div>
<div style="display:grid;gap:10px">${[
['Health Monitor','Vrifie toutes les 5min: Apache, PG, PMTA, Node.js. Alerte Telegram si down.','active'],
['AutoLearn','15 scnarios Qdrant. Apprend des rsultats d\'envoi pour optimiser configs.','active'],
['Error Recovery','Dtecte les erreurs serveur et tente auto-repair. Logs dans brain_learning_log.','active']
].map(([n,d,s])=>`<div style="padding:14px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);display:flex;justify-content:space-between;align-items:center"><div><div style="font-size:13px;font-weight:600;color:var(--wh)">${n}<\/div><div style="font-size:11px;color:var(--mu);margin-top:3px">${d}<\/div><\/div><span class="badge b-ok">${s}<\/span><\/div>`).join('')}<\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:8px">Credentials<\/div><p style="font-size:12px;color:var(--mu)">Login: yacineutt / YacineWeval2026 — S95:5678<\/p><\/div>`};
// =============== ETHICA DASHBOARD ===============
RR.ethicadash=async()=>{let d={};try{d=await brg('ethica')}catch(e){}const co=d.countries||[];
$('C').innerHTML=`<div class="stats"><div class="stat s-ac"><div class="st-l">HCPs Total<\/div><div class="st-v">${N(d.total_hcp)}<\/div><\/div><div class="stat s-bl"><div class="st-l">Emails<\/div><div class="st-v">${N(d.emails)}<\/div><\/div><div class="stat s-gn"><div class="st-l">Tlphones<\/div><div class="st-v">${N(d.phones)}<\/div><\/div><div class="stat s-pu"><div class="st-l">Marques<\/div><div class="st-v">${d.brands||0}<\/div><\/div><\/div>
<div class="card"><div class="card-t" style="margin-bottom:14px">Consent Funnel<\/div>
<div style="display:flex;gap:8px;align-items:center">${[
[N(d.total_hcp),'BASE','var(--ac)','100%'],
[N(d.phones),'TEL','var(--gn)','95%'],
['0','SMS','var(--or)','0%'],
['0','OPT-IN','var(--rd)','0%']
].map(([v2,l,c,p])=>`<div style="flex:1;text-align:center"><div style="padding:14px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r)"><div style="font-family:var(--m);font-size:20px;font-weight:800;color:${c}">${v2}<\/div><div style="font-size:10px;color:var(--mu);margin-top:3px">${l}<\/div><\/div><\/div><div style="color:var(--dm)">${'\u2192'}<\/div>`).slice(0,-1).join('')}<\/div><\/div>
<div class="row2"><div class="card"><div class="card-t" style="margin-bottom:10px">Par pays<\/div>
${co.map(c=>{const pct=d.total_hcp>0?((+c.cnt/d.total_hcp)*100).toFixed(1):'0';return`<div style="margin-bottom:10px;cursor:pointer" onclick="drillCountry('${esc(c.country||'?')}')""><div style="display:flex;justify-content:space-between;margin-bottom:4px"><span style="color:var(--wh);font-weight:600">${esc(c.country||'?')}<\/span><span style="font-family:var(--m);color:var(--ac)">${N(c.cnt)} (${pct}%)<\/span><\/div><div style="height:6px;background:var(--sf);border-radius:3px;overflow:hidden"><div style="height:100%;width:${pct}%;background:var(--ac);border-radius:3px"><\/div><\/div><\/div>`}).join('')}<\/div>
<div class="card"><div class="card-t" style="margin-bottom:10px">18 Marques Pharma<\/div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:6px">${['Doliprane 1g','Doliprane Vit C','Maxilase','Enterogermina','Telfast','Nasacort','No Spa','Aspgic','Flagyl','Uvedose','Allegra','Doliprane Ped','Duphalac','Smecta','Motilium','Spasfon','Voltarne','Dafalgan'].map(b=>`<div style="padding:6px 8px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);font-size:10px;color:var(--wh);text-align:center">${b}<\/div>`).join('')}<\/div><\/div><\/div>
<div class="card"><div class="card-h"><div class="card-t">Actions Ethica<\/div><\/div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:8px">
<button class="btn btn-sm btn-ac btn-full" onclick="window.open('https://ethica.wevup.app/ethica-app-v3.html')">Dashboard Ethica<\/button>
<button class="btn btn-sm btn-gh btn-full" onclick="window.open('https://consent.wevup.app')">Page Consent<\/button>
<button class="btn btn-sm btn-gh btn-full" onclick="toast('Export...')">Exporter HCPs<\/button>
<\/div><\/div>`};
async function runSeedTest(){toast('Envoi seed test...');try{const r=await fetch(V2E+'?action=seed_test&token=WEVADS2026',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({count:3,isp:'HOTMAIL'})});const j=await r.json();toast(j.sent?j.sent+'/'+j.total+' seeds envoys':'Err: '+(j.error||'0 seeds'),!j.sent)}catch(e){toast('Err: '+e.message,1)}}
// =============== DRILL-DOWN SYSTEM ===============
function modal(title,body){document.getElementById('M').innerHTML='<div class="modal-bg" onclick="if(event.target===this)closeM()"><div class="modal"><div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:18px"><h3 style="margin:0">'+title+'<\/h3><button class="btn btn-sm btn-gh" onclick="closeM()" style="padding:4px 10px">\u2715<\/button><\/div>'+body+'<\/div><\/div>';document.getElementById('M').style.display='block'}
function closeM(){document.getElementById('M').innerHTML='';document.getElementById('M').style.display='none'}
// Dashboard KPI drill
async function drillKPI(type){
if(type==='contacts'){go('contacts');return}
if(type==='senders'){go('senders');return}
if(type==='campaigns'){go('campaigns');return}
if(type==='ethica'){go('ethicadash');return}
if(type==='offers'){go('offers');return}
if(type==='tracking'){
let t={};try{t=await eng('tracking_stats')}catch(e){}
const r=(t.recent||[]).slice(0,15);
modal('📊 Tracking Events ('+N(t.stats?.total_events||0)+')',
'<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-bottom:14px"><div class="stat s-gn" style="margin:0;animation:none"><div class="st-l">Opens<\/div><div class="st-v">'+N(t.stats?.total_opens||0)+'<\/div><\/div><div class="stat s-bl" style="margin:0;animation:none"><div class="st-l">Clicks<\/div><div class="st-v">'+N(t.stats?.total_clicks||0)+'<\/div><\/div><div class="stat s-rd" style="margin:0;animation:none"><div class="st-l">Bounces<\/div><div class="st-v">'+N(t.stats?.total_bounces||0)+'<\/div><\/div><\/div>'
+'<table><thead><tr><th>Tracking ID<\/th><th>Event<\/th><th>IP<\/th><th>Date<\/th><\/tr><\/thead><tbody>'+r.map(e=>'<tr><td style="font-family:var(--m);font-size:10px">'+esc((e.tracking_id||'').substring(0,22))+'<\/td><td><span class="badge b-'+(e.event_type==='open'?'ok':'em')+'">'+e.event_type+'<\/span><\/td><td style="font-size:10px;color:var(--dm)">'+esc(e.ip||'')+'<\/td><td style="font-size:10px;color:var(--dm)">'+(e.created_at||'').substring(0,19)+'<\/td><\/tr>').join('')+'<\/tbody><\/table>');return}
if(type==='infra'){go('infra');return}
if(type==='sent'){
let d={};try{d=await brg('send_stats')}catch(e){}
modal('📧 Envois par ISP ('+N(d.total||0)+' total)',
'<table><thead><tr><th>ISP<\/th><th>Envoy\u00e9s<\/th><th>D\u00e9livr\u00e9s<\/th><th>Taux<\/th><\/tr><\/thead><tbody>'+(d.by_isp||[]).map(i=>{const r=i.cnt>0?((+i.delivered/+i.cnt)*100).toFixed(1):'0';return'<tr><td style="color:var(--wh);font-weight:600">'+esc(i.isp||'Unknown')+'<\/td><td style="font-family:var(--m)">'+N(i.cnt)+'<\/td><td style="font-family:var(--m);color:var(--gn)">'+N(i.delivered)+'<\/td><td><span style="font-family:var(--m);color:'+(+r>80?'var(--gn)':+r>50?'var(--or)':'var(--rd)')+'">'+r+'%<\/span><\/td><\/tr>'}).join('')+'<\/tbody><\/table>');return}
}
// Senders provider drill
async function drillProvider(provider){
let d={};try{d=await brg('senders_full')}catch(e){}
const os=(d.o365_status||[]);const gs=(d.gsuite_workspaces||[]);const sm=(d.smtp_configs||[]);const wt=(d.warmup_by_type||[]);
let body='';
if(provider==='o365'){body='<div class="card-t" style="margin-bottom:12px">Office 365 Status Breakdown<\/div><table><thead><tr><th>Status<\/th><th>Count<\/th><th>%<\/th><\/tr><\/thead><tbody>'+os.map(s=>{const p=d.total_senders>0?((+s.cnt/d.total_senders)*100).toFixed(1):'0';return'<tr><td><span class="badge b-'+(s.status==='Active'||s.status==='active'?'ok':s.status==='Blocked'?'err':'wait')+'">'+s.status+'<\/span><\/td><td style="font-family:var(--m)">'+N(s.cnt)+'<\/td><td style="font-family:var(--m);color:var(--mu)">'+p+'%<\/td><\/tr>'}).join('')+'<\/tbody><\/table>'}
else if(provider==='gsuite'){body='<div class="card-t" style="margin-bottom:12px">GSuite Workspaces<\/div><table><thead><tr><th>Domain<\/th><th>Users<\/th><th>Method<\/th><\/tr><\/thead><tbody>'+gs.map(g=>'<tr><td style="color:var(--wh);font-family:var(--m)">'+esc(g.domain)+'<\/td><td style="font-family:var(--m)">'+g.users_count+'<\/td><td><span class="badge b-ac">'+esc(g.method)+'<\/span><\/td><\/tr>').join('')+'<\/tbody><\/table>'}
else if(provider==='smtp'){body='<div class="card-t" style="margin-bottom:12px">SMTP Configurations<\/div><table><thead><tr><th>Name<\/th><th>Provider<\/th><th>Host<\/th><th>Port<\/th><th>Limit/day<\/th><\/tr><\/thead><tbody>'+sm.map(s=>'<tr><td style="color:var(--wh)">'+esc(s.config_name)+'<\/td><td><span class="badge b-em">'+esc(s.provider)+'<\/span><\/td><td style="font-family:var(--m);font-size:10px">'+esc(s.host)+'<\/td><td style="font-family:var(--m)">'+s.port+'<\/td><td style="font-family:var(--m);color:var(--gn)">'+N(s.daily_limit)+'<\/td><\/tr>').join('')+'<\/tbody><\/table>'}
else if(provider==='warmup'){body='<div class="card-t" style="margin-bottom:12px">Warmup par type<\/div><table><thead><tr><th>Type<\/th><th>Comptes<\/th><th>Capacit\u00e9/jour<\/th><\/tr><\/thead><tbody>'+wt.map(w=>'<tr><td style="color:var(--wh);font-weight:600">'+esc(w.account_type)+'<\/td><td style="font-family:var(--m)">'+N(w.cnt)+'<\/td><td style="font-family:var(--m);color:var(--gn)">'+N(w.cap)+'<\/td><\/tr>').join('')+'<\/tbody><\/table>'}
else{body='<p style="color:var(--mu)">Drill: '+provider+'<\/p>'}
modal('📨 '+provider.toUpperCase()+' Detail',body);
}
// Offers drill
function drillOffer(id,name,payout,vertical,status){
modal('📦 Offre #'+id,
'<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:16px">'
+'<div><div class="st-l">Nom<\/div><div style="color:var(--wh);font-size:13px;margin-top:4px">'+esc(name)+'<\/div><\/div>'
+'<div><div class="st-l">Payout<\/div><div style="color:var(--gn);font-size:24px;font-weight:800;font-family:var(--m)">$'+payout+'<\/div><\/div>'
+'<div><div class="st-l">Vertical<\/div><span class="badge b-ac">'+esc(vertical)+'<\/span><\/div>'
+'<div><div class="st-l">Status<\/div><span class="badge b-'+(status==='active'?'ok':'wait')+'">'+status+'<\/span><\/div><\/div>'
+'<div class="divider">Actions<\/div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px">'
+'<button class="btn btn-sm btn-ac" onclick="go(\'send\');closeM()">Envoyer<\/button>'
+'<button class="btn btn-sm btn-gh" onclick="toast(\'Dupliqu\u00e9e\');closeM()">Dupliquer<\/button>'
+'<button class="btn btn-sm btn-gh" onclick="toast(\'A/B lanc\u00e9\');closeM()">A/B Test<\/button><\/div>'
)}
// Brain config drill
async function drillBrain(){
let d={};try{d=await brg('brain')}catch(e){}
const methods=d.methods||[];
modal('\ud83e\udde0 Brain IA Detail',
'<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-bottom:16px"><div class="stat s-ac" style="margin:0;animation:none"><div class="st-l">Configs<\/div><div class="st-v">'+N(d.configs)+'<\/div><\/div><div class="stat s-gn" style="margin:0;animation:none"><div class="st-l">Winners<\/div><div class="st-v">'+N(d.winners)+'<\/div><\/div><div class="stat s-bl" style="margin:0;animation:none"><div class="st-l">Learnings<\/div><div class="st-v">'+N(d.learnings)+'<\/div><\/div><\/div>'
+'<div class="card-t" style="margin-bottom:10px">M\u00e9thodes d\'envoi Brain<\/div>'
+'<table><thead><tr><th>M\u00e9thode<\/th><th>Description<\/th><th>Best ISPs<\/th><\/tr><\/thead><tbody>'
+methods.map(m=>'<tr><td style="color:var(--wh);font-weight:600;font-size:12px">'+esc(m.method_name)+'<\/td><td style="font-size:11px;color:var(--mu)">'+esc((m.description||'').substring(0,50))+'<\/td><td style="font-size:10px"><span class="badge b-em">'+esc(m.best_for_isps||'all')+'<\/span><\/td><\/tr>').join('')
+'<\/tbody><\/table>'
)}
// Creative drill
async function drillCreative(){
let d={};try{d=await brg('creative')}catch(e){}
const ts=d.top_subjects||[];
modal('\u2728 Top Subject Lines',
'<table><thead><tr><th>Subject<\/th><th>Open Rate<\/th><th>Click Rate<\/th><\/tr><\/thead><tbody>'
+ts.map(s=>'<tr><td style="color:var(--wh);font-size:12px">'+esc((s.subject||'').substring(0,40))+'<\/td><td style="font-family:var(--m);color:'+(+s.open_rate>15?'var(--gn)':+s.open_rate>5?'var(--ac)':'var(--rd)')+'">'+s.open_rate+'%<\/td><td style="font-family:var(--m);color:var(--bl)">'+(s.click_rate||0)+'%<\/td><\/tr>').join('')
+'<\/tbody><\/table>'
)}
// Domain pool drill
function drillDomain(domain,spf,dkim,dmarc,sent,score){
modal('\ud83c\udf10 '+esc(domain),
'<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin-bottom:16px">'
+[['SPF',spf],['DKIM',dkim],['DMARC',dmarc]].map(([n,v])=>'<div style="text-align:center;padding:12px;background:var(--sf);border-radius:var(--r3);border:1px solid '+(v?'rgba(52,211,153,.15)':'rgba(248,113,113,.15)')+'"><div style="font-size:18px">'+(v?'\u2705':'\u274c')+'<\/div><div style="font-size:9px;color:var(--mu);margin-top:4px">'+n+'<\/div><\/div>').join('')
+'<div style="text-align:center;padding:12px;background:var(--sf);border-radius:var(--r3)"><div style="font-family:var(--m);font-size:18px;color:var(--ac)">'+N(sent)+'<\/div><div style="font-size:9px;color:var(--mu);margin-top:4px">Emails<\/div><\/div>'
+'<div style="text-align:center;padding:12px;background:var(--sf);border-radius:var(--r3)"><div style="font-family:var(--m);font-size:18px;color:var(--gn)">'+score+'<\/div><div style="font-size:9px;color:var(--mu);margin-top:4px">Score<\/div><\/div><\/div>'
+'<div style="display:flex;gap:8px"><button class="btn btn-sm btn-ac" onclick="toast(\'V\u00e9rification DNS...\')">Check DNS<\/button><button class="btn btn-sm btn-gh" onclick="go(\'postmaster\');closeM()">Postmaster<\/button><\/div>'
)}
// Ethica country drill
async function drillCountry(country){
let d={};try{d=await brg('ethica')}catch(e){}
const total=d.total_hcp||0;const co=(d.countries||[]).find(c=>c.country===country)||{};
modal('\ud83c\udf0d '+country+' \u2014 '+N(co.cnt||0)+' HCPs',
'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:16px"><div class="stat s-ac" style="margin:0;animation:none"><div class="st-l">HCPs<\/div><div class="st-v">'+N(co.cnt||0)+'<\/div><\/div><div class="stat s-bl" style="margin:0;animation:none"><div class="st-l">% du total<\/div><div class="st-v">'+(total>0?((+co.cnt/total)*100).toFixed(1):'0')+'%<\/div><\/div><\/div>'
+'<div class="card-t" style="margin-bottom:10px">Actions '+country+'<\/div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px">'
+'<button class="btn btn-sm btn-ac" onclick="toast(\'Export '+country+'...\');closeM()">Exporter CSV<\/button>'
+'<button class="btn btn-sm btn-gh" onclick="toast(\'Campagne '+country+'...\');closeM()">Cr\u00e9er campagne<\/button>'
+'<button class="btn btn-sm btn-gh" onclick="go(\'send\');closeM()">Envoyer<\/button><\/div>'
)}
// Analytics ISP drill
async function drillISP(isp){
let d={};try{d=await eng('deliverability')}catch(e){}
const stats=(d.stats||[]).find(s=>s.isp===isp)||{};
modal('📊 '+isp+' Deliverability',
'<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:16px">'
+'<div class="stat s-bl" style="margin:0;animation:none"><div class="st-l">Envoy\u00e9s<\/div><div class="st-v">'+N(stats.sent||0)+'<\/div><\/div>'
+'<div class="stat s-gn" style="margin:0;animation:none"><div class="st-l">D\u00e9livr\u00e9s<\/div><div class="st-v">'+N(stats.delivered||0)+'<\/div><\/div>'
+'<div class="stat s-ac" style="margin:0;animation:none"><div class="st-l">Opens<\/div><div class="st-v">'+N(stats.opened||0)+'<\/div><\/div>'
+'<div class="stat s-rd" style="margin:0;animation:none"><div class="st-l">Bounces<\/div><div class="st-v">'+N(stats.bounced||0)+'<\/div><\/div><\/div>'
+'<div style="display:flex;gap:8px"><button class="btn btn-sm btn-gh" onclick="go(\'postmaster\');closeM()">Postmaster '+isp+'<\/button><button class="btn btn-sm btn-gh" onclick="go(\'reputation\');closeM()">R\u00e9putation<\/button><\/div>'
)}
// Infra schema drill
async function drillSchema(schema,cnt){
modal('🗄 Schema: '+esc(schema)+' ('+cnt+' tables)',
'<p style="color:var(--mu);font-size:12px;margin-bottom:12px">Ce sch\u00e9ma contient '+cnt+' tables dans la base adx_system (9.3GB).<\/p>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">'
+'<button class="btn btn-sm btn-ac" onclick="toast(\'Export sch\u00e9ma...\')">Exporter DDL<\/button>'
+'<button class="btn btn-sm btn-gh" onclick="toast(\'Analyse...\')">Analyser taille<\/button><\/div>'
)}
async function checkSpam(){
const su=$('sSu')?$('sSu').value:'';const bo=$('sBo')?$('sBo').value:'';
if(!su&&!bo){toast('Remplir sujet et/ou body',1);return}
toast('Analyse anti-spam...');
try{const r=await(await fetch('/api/spam-score.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({subject:su,html:bo})})).json();
if(r.ok){let msg='Score: '+r.score+'/100 ('+r.verdict+')';if(r.issues.length)msg+='\n'+r.issues.join('\n');
const d=document.createElement('div');d.className='modal-bg';d.onclick=e=>{if(e.target===d)d.remove()};
d.innerHTML='<div class="modal"><h3>\u26a0 Spam Score: '+r.score+'/100</h3><div style="margin-bottom:16px"><span class="badge '+(r.verdict==='clean'?'b-ok':r.verdict==='warning'?'b-wait':'b-err')+'">'+r.verdict.toUpperCase()+'</span></div>'+(r.issues.length?'<div class="card-t" style="margin-bottom:8px">Probl\u00e8mes d\u00e9tect\u00e9s</div>'+r.issues.map(i=>'<div style="padding:5px 0;border-bottom:1px solid var(--bd);font-size:12px;color:var(--rd)">\u274c '+i+'</div>').join(''):'<div style="color:var(--gn);font-size:14px">\u2705 Email propre!</div>')+'<div style="margin-top:16px"><div class="card-t" style="margin-bottom:6px">Conseils</div>'+r.tips.map(t=>'<div style="font-size:11px;color:var(--mu);padding:3px 0">\u2022 '+t+'</div>').join('')+'</div><div class="brow"><button class="btn btn-ac btn-full" onclick="this.closest(\'.modal-bg\').remove()">OK</button></div></div>';
document.body.appendChild(d);
}else toast('Err',1)}catch(e){toast('Err: '+e.message,1)}}
document.addEventListener('keydown',e=>{
if((e.metaKey||e.ctrlKey)&&e.key==='s'){e.preventDefault();if(typeof doSend==='function')doSend();else toast('Ctrl+S: Send')}
if((e.metaKey||e.ctrlKey)&&e.key==='n'){e.preventDefault();go('send')}
if(e.key==='/'){e.preventDefault();showCmdPalette()}
if(e.key==='F5'){e.preventDefault();var pg=PG||'dashboard';go(pg)}
if(e.key==='Escape'){const m=document.querySelector('.modal-bg');if(m)m.remove()}
});
// =============== CRM TWENTY ===============
RR.crm=async()=>{let d={};try{d=await brg('twenty_crm')}catch(e){}
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">CRM</div><div class="st-v" style="font-size:18px">Twenty</div></div><div class="stat s-gn"><div class="st-l">Status</div><div class="st-v" style="font-size:16px">Running</div></div><div class="stat s-bl"><div class="st-l">Features</div><div class="st-v">6</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Twenty CRM — Pipeline & Deals</div><button class="btn btn-sm btn-ac" onclick="window.open(\'https://crm.weval-consulting.com\')">Ouvrir CRM</button></div>'
+'<p style="font-size:12px;color:var(--mu);margin-bottom:16px">CRM souverain open-source (28K GitHub stars). Contacts, Companies, Deals, Pipeline, Tasks, Notes. GraphQL API.</p>'
+'<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px">'
+['Vistex Partner','Ethica / Kaouther','Confluent Digital','Cosumar','Huawei Cloud','Carrefour'].map(d2=>'<div style="padding:14px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);text-align:center"><div style="font-size:12px;font-weight:600;color:var(--wh)">'+d2+'</div><div style="font-size:10px;color:var(--mu);margin-top:4px">Deal actif</div></div>').join('')
+'</div></div>'
+'<div class="card"><div class="card-t" style="margin-bottom:10px">Int\u00e9gration WEVADS \u2194 Twenty</div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">'
+'<div style="padding:12px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r)"><div style="font-size:11px;font-weight:600;color:var(--gn)">Contacts sync</div><div style="font-size:10px;color:var(--mu);margin-top:3px">7.3M WEVADS \u2192 Twenty CRM bidirectionnel</div></div>'
+'<div style="padding:12px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r)"><div style="font-size:11px;font-weight:600;color:var(--bl)">Deal tracking</div><div style="font-size:10px;color:var(--mu);margin-top:3px">Pipeline: Lead \u2192 Qualified \u2192 Proposal \u2192 Won</div></div>'
+'<div style="padding:12px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r)"><div style="font-size:11px;font-weight:600;color:var(--pu)">Campaign link</div><div style="font-size:10px;color:var(--mu);margin-top:3px">Chaque campagne WEVADS li\u00e9e \u00e0 un deal</div></div>'
+'<div style="padding:12px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r)"><div style="font-size:11px;font-weight:600;color:var(--or)">Revenue attribution</div><div style="font-size:10px;color:var(--mu);margin-top:3px">Postback \u2192 Deal value update automatique</div></div>'
+'</div></div>';};
// =============== AI STUDIO ===============
RR.aistudio=async()=>{let m={};try{m=await brg('ollama_models')}catch(e){}
const s204=m.s204||[];const s151=m.s151||[];
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Mod\u00e8les S204</div><div class="st-v">'+s204.length+'</div></div><div class="stat s-gn"><div class="st-l">Mod\u00e8les S151</div><div class="st-v">'+s151.length+'</div></div><div class="stat s-bl"><div class="st-l">Total</div><div class="st-v">'+(m.total||0)+'</div></div><div class="stat s-pu"><div class="st-l">GPU</div><div class="st-v" style="font-size:16px">Souverain</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">G\u00e9n\u00e9rateur IA souverain</div></div>'
+'<div class="row2"><div><div class="field"><label>Mod\u00e8le</label><select id="aiModel">'
+s204.map(m2=>'<option value="'+m2.name+'|s204">'+m2.name+' ('+m2.size+', '+m2.family+')</option>').join('')
+s151.map(m2=>'<option value="'+m2.name+'|s151">'+m2.name+' (S151)</option>').join('')
+'</select></div>'
+'<div class="field"><label>Prompt</label><textarea id="aiPrompt" class="ed" rows="4" placeholder="G\u00e9n\u00e9rer un sujet d email pour une offre assurance..."></textarea></div>'
+'<button class="btn btn-ac btn-full" onclick="genAI()">G\u00e9n\u00e9rer</button></div>'
+'<div><div class="card-t" style="margin-bottom:10px">R\u00e9sultat</div><div id="aiResult" style="font-size:12px;color:var(--mu);line-height:1.7;min-height:150px;padding:14px;background:var(--bg);border-radius:var(--r3);border:1px solid var(--bd);font-family:var(--m)">En attente...</div></div></div></div>'
+'<div class="row2"><div class="card"><div class="card-t" style="margin-bottom:10px">S204 Ollama (9 mod\u00e8les)</div>'
+s204.map(m2=>'<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:12px;color:var(--wh)">'+esc(m2.name)+'</span><span style="font-family:var(--m);font-size:10px;color:var(--mu)">'+m2.size+'</span><span style="font-size:10px;color:var(--dm)">'+esc(m2.family)+'</span></div>').join('')
+'</div><div class="card"><div class="card-t" style="margin-bottom:10px">S151 Ollama (5 mod\u00e8les)</div>'
+s151.map(m2=>'<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:12px;color:var(--wh)">'+esc(m2.name)+'</span><span class="badge b-ok">S151</span></div>').join('')
+'</div></div>';};
async function genAI(){const sel=$('aiModel').value.split('|');const model=sel[0];const server=sel[1];
const prompt=$('aiPrompt').value;if(!prompt){toast('Entrer un prompt',1);return}
$('aiResult').textContent='G\u00e9n\u00e9ration en cours ('+model+' sur '+server+')...';
try{const r=await(await fetch(BRG+'?action=ollama_generate&token=WEVADS2026',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({model,prompt,server})})).json();
$('aiResult').textContent=r.response||'Pas de r\u00e9ponse';if(r.eval_duration)$('aiResult').textContent+='\n\n['+r.eval_duration.toFixed(1)+'s sur '+server+']';
}catch(e){$('aiResult').textContent='Erreur: '+e.message;}}
// =============== INFRA LIVE ===============
RR.infrastatus=async()=>{let d={},q={};try{d=await brg('infra_status')}catch(e){}try{q=await brg('qdrant')}catch(e){}
const sv=d.services||[];const up=d.up||0;const total=d.total||0;const colls=q.collections||[];
$('C').innerHTML='<div class="stats"><div class="stat s-gn"><div class="st-l">Services UP</div><div class="st-v">'+up+'/'+total+'</div></div><div class="stat s-ac"><div class="st-l">Qdrant</div><div class="st-v">'+colls.length+' collections</div></div><div class="stat s-bl"><div class="st-l">Docker</div><div class="st-v">15</div><div class="st-s">containers</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Services en temps r\u00e9el</div><button class="btn btn-sm btn-gh" onclick="go(\'infrastatus\')">Refresh</button></div>'
+'<div style="display:grid;grid-template-columns:repeat(2,1fr);gap:8px">'
+sv.map(s=>'<div style="padding:12px;background:var(--sf);border:1px solid '+(s.status==='up'?'rgba(52,211,153,.1)':'rgba(248,113,113,.15)')+';border-radius:var(--r);display:flex;justify-content:space-between;align-items:center"><div><div style="font-size:12px;font-weight:600;color:var(--wh)">'+esc(s.name)+'</div><div style="font-size:9px;color:var(--dm);font-family:var(--m)">'+esc(s.host)+'</div></div><span class="badge '+(s.status==='up'?'b-ok':'b-err')+'">'+s.status+'</span></div>').join('')
+'</div></div>'
+'<div class="row2"><div class="card"><div class="card-t" style="margin-bottom:10px">Qdrant Collections</div>'
+colls.map(c=>'<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd)"><span style="font-size:12px;color:var(--wh)">'+esc(c.name)+'</span><span style="font-family:var(--m);color:var(--ac)">'+N(c.points)+' vectors</span></div>').join('')
+'</div><div class="card"><div class="card-t" style="margin-bottom:10px">Liens rapides</div>'
+'<div style="display:grid;gap:6px">'
+[['Twenty CRM','https://crm.weval-consulting.com'],['Uptime Kuma','https://kuma.weval-consulting.com'],['n8n','http://95.216.167.89:5678'],['Mattermost','http://localhost:8065'],['SearXNG','http://localhost:8080']].map(l=>'<a href="'+l[1]+'" target="_blank" style="display:block;padding:8px 12px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r3);font-size:11px;color:var(--ac)">'+l[0]+'</a>').join('')
+'</div></div></div>';};
document.addEventListener('keydown',function(e){
if((e.metaKey||e.ctrlKey)&&e.key==='k'){e.preventDefault();showCmdPalette()}
if((e.metaKey||e.ctrlKey)&&e.key==='s'){e.preventDefault();if(typeof doSend==='function')doSend();else toast('Ctrl+S')}
if((e.metaKey||e.ctrlKey)&&e.key==='n'){e.preventDefault();go('send')}
if(e.key==='Escape'){var m=document.querySelector('.modal-bg');if(m)m.remove()}
});
function showCmdPalette(){
// =============== GLOBAL UTILS ===============
window.exportCSV=function(tableId,filename){
var t=document.querySelector(tableId||'#C table');if(!t){toast('No table',1);return}
var rows=[];t.querySelectorAll('tr').forEach(function(r){
var cols=[];r.querySelectorAll('th,td').forEach(function(c){cols.push('"'+c.textContent.replace(/"/g,'""')+'"')});
rows.push(cols.join(','))});
var blob=new Blob([rows.join('\n')],{type:'text/csv'});var a=document.createElement('a');
a.href=URL.createObjectURL(blob);a.download=(filename||'export')+'.csv';a.click();toast('CSV exported')};
var pages=[['dashboard','Dashboard'],['send','Envoyer'],['campaigns','Campagnes'],['contacts','Contacts'],['senders','Senders'],['warmup','Warmup'],['domains','Domaines'],['seeds','Seeds'],['reputation','Reputation'],['brain','Brain IA'],['creative','Creative'],['analytics','Analytics'],['ai','AI Assistant'],['channels','Canaux'],['templates','Templates'],['sendengine','Send Engine'],['infra','Infrastructure'],['offers','Offers'],['abtesting','A/B Testing'],['scheduled','Scheduled'],['dompool','Domain Pool'],['revenue','Revenue'],['pmtamgmt','PMTA'],['ippool','IP Pool'],['postmaster','Postmaster'],['listclean','List Cleaner'],['smartreport','Smart Report'],['n8n','N8N'],['ethicadash','Ethica'],['crm','CRM Twenty'],['aistudio','AI Studio'],['infrastatus','Infra Live'],['editor','Email Editor'],['landing','Landing Pages'],['forms','Signup Forms'],['deerflow','DeerFlow Agent'],['autolearn','Auto-Learning'],['alerts','Alertes MM'],['worldmap','World Map'],['spamscore','Spam Score'],['heatmap','Heatmap ISP'],['darkmatrix','Dark Matrix'],['reputmon','Reputation'],['smartpdf','Smart PDF'],['delisting','Delisting'],['qualitygate','Quality Gate'],['spamcheck','Spam Check'],['healthmon','Infra Live'],['sequences','Sequences'],['inbox','Unified Inbox'],['whatsapp','WhatsApp'],['aicopy','AI Copywriter'],['ragsearch','RAG Search'],['emailpreview','Email Preview'],['timeline','Contact Timeline'],['automation','Automation Flow']];
var m=document.createElement('div');m.className='modal-bg';m.onclick=function(ev){if(ev.target===m)m.remove()};
m.innerHTML='<div class="modal" style="padding:20px;width:480px"><input id="cmdI" style="width:100%;margin-bottom:14px;font-size:15px" placeholder="Rechercher... (Ctrl+K)" autofocus><div id="cmdR" style="max-height:360px;overflow-y:auto"></div></div>';
document.body.appendChild(m);
var inp=document.getElementById('cmdI');
function render(q){var flt=q?pages.filter(function(p){return p[1].toLowerCase().indexOf(q.toLowerCase())>=0}):pages;
document.getElementById('cmdR').innerHTML=flt.map(function(p){return '<div style="padding:10px 14px;border-radius:10px;cursor:pointer;font-size:13px;color:var(--wh);transition:background .15s" onmouseover="this.style.background=\'var(--hov)\'" onmouseout="this.style.background=\'transparent\'" onclick="go(\''+p[0]+'\' );document.querySelector(\'.modal-bg\').remove()">'+p[1]+'</div>'}).join('')}
render('');inp.addEventListener('input',function(ev){render(ev.target.value)});
inp.addEventListener('keydown',function(ev){if(ev.key==='Escape')m.remove()});
setTimeout(function(){inp.focus()},50)}
async function schedSend(){
var dt=document.getElementById('schedAt');
if(!dt||!dt.value){toast('Choisir date/heure',1);return}
toast('Envoi programme pour '+dt.value);
}
RR.sequences=async()=>{var d={},sl={};try{d=await brg('sequences')}catch(e){}try{sl=await brg('sequence_list')}catch(e){}
var seqs=sl.sequences||[];
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Sequences</div><div class="st-v">'+N(d.total||0)+'</div></div><div class="stat s-gn"><div class="st-l">Active</div><div class="st-v">'+N(d.active||0)+'</div></div><div class="stat s-bl"><div class="st-l">Enrolled</div><div class="st-v">'+N(d.enrolled||0)+'</div></div><div class="stat s-pu"><div class="st-l">Events</div><div class="st-v">'+N(d.events||0)+'</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Sequences Multi-Step</div><button class="btn btn-sm btn-ac" onclick="createSequence()">+ Nouvelle</button></div>'
+'<p style="font-size:11px;color:var(--mu);margin-bottom:14px">Automatisez vos campagnes: D0 email \u2192 D3 relance \u2192 D7 dernier rappel. Chaque step s adapte au comportement du contact.</p>'
+(seqs.length?'<table><thead><tr><th>Nom</th><th>Steps</th><th>Contacts</th><th>Actifs</th><th>Status</th></tr></thead><tbody>'+seqs.map(function(s){return '<tr><td style="color:var(--wh);font-weight:500">'+esc(s.name)+'</td><td style="font-family:var(--m)">'+N(s.step_count)+'</td><td style="font-family:var(--m)">'+N(s.total_contacts)+'</td><td style="font-family:var(--m);color:var(--gn)">'+N(s.active_contacts)+'</td><td><span class="badge '+(s.status==='active'?'b-ok':'b-wait')+'">'+esc(s.status)+'</span></td></tr>'}).join('')+'</tbody></table>':'<p style="color:var(--dm);font-size:12px;text-align:center;padding:20px">Aucune sequence. Cliquez + Nouvelle pour commencer.</p>')
+'</div>'
+'<div class="card"><div class="card-t" style="margin-bottom:10px">Comment ca marche</div>'
+'<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:8px">'
+['D0: Email initial','D3: Relance si pas ouvert','D7: Dernier rappel','D14: Archive si no reply'].map(function(s,i){return '<div style="padding:14px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);text-align:center;position:relative"><div style="font-size:24px;font-weight:600;color:var(--ac)">'+(i+1)+'</div><div style="font-size:11px;color:var(--wh);margin-top:6px">'+s+'</div>'+(i<3?'<div style="position:absolute;right:-14px;top:50%;transform:translateY(-50%);color:var(--dm);font-size:18px">\u2192</div>':'')+'</div>'}).join('')
+'</div></div>';};
async function createSequence(){
var name=prompt('Nom de la sequence:');
if(!name)return;
toast('Creation...');
var r=await(await fetch('/api/sequence-engine.php?action=create&token=WEVADS2026',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:name,steps:[{type:'email',delay_days:0,subject:'',wait_hours:0},{type:'email',delay_days:3,subject:'',wait_hours:72},{type:'email',delay_days:7,subject:'',wait_hours:168}]})})).json();
if(r.ok){toast('Sequence #'+r.id+' creee');go('sequences')}else toast('Erreur',1)}
RR.inbox=async()=>{
let acc={},sd={};try{acc=await brg('accounts')}catch(e){}try{sd=await brg('seeds')}catch(e){}
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Inbox</div><div class="st-v" style="font-size:18px">Unified</div></div><div class="stat s-gn"><div class="st-l">O365 comptes</div><div class="st-v">${acc.o365_total||0}</div></div><div class="stat s-bl"><div class="st-l">IMAP</div><div class="st-v" style="font-size:14px">Ready</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Unified Inbox</div><button class="btn btn-sm btn-ac" onclick="refreshInbox()">Refresh</button></div>'
+'<p style="font-size:11px;color:var(--mu);margin-bottom:14px">Centralisez les reponses de vos 197 comptes Graph. Detectez les out-of-office, les bounces, et les reponses positives.</p>'
+'<div id="inboxList" style="min-height:200px">'
+'<div style="display:grid;gap:6px">'
+['Reply detection (positif/negatif/OOO)','Auto-tag contacts (interested/not-interested/bounced)','Forward important replies to Telegram','Track reply rates per sequence step','Sentiment analysis via Ollama'].map(function(f){return '<div style="padding:10px 14px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);display:flex;align-items:center;gap:10px"><span style="color:var(--gn);font-size:14px">\u2713</span><span style="font-size:12px;color:var(--wh)">'+f+'</span></div>'}).join('')
+'</div>'
+'</div></div>'
+'<div class="row2"><div class="card"><div class="card-t" style="margin-bottom:10px">Reply Categories</div>'
+[['Positive','Interesses, demande de meeting','var(--gn)','12'],['Negative','Not interested, unsubscribe','var(--rd)','5'],['OOO','Out of office auto-reply','var(--ac)','23'],['Bounce','Hard bounce, mailbox full','var(--mu)','8']].map(function(c){return '<div style="display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--bd)"><div><div style="font-size:12px;font-weight:600;color:'+c[2]+'">'+c[0]+'</div><div style="font-size:10px;color:var(--mu)">'+c[1]+'</div></div><span style="font-family:var(--m);font-size:16px;font-weight:600;color:'+c[2]+'">'+c[3]+'</span></div>'}).join('')
+'</div><div class="card"><div class="card-t" style="margin-bottom:10px">Graph Accounts Monitored</div><div id="inboxAccounts">Chargement...</div></div></div>';
try{var we=await brg('warmup_engine');var bt=we.by_tenant||[];
document.getElementById('inboxAccounts').innerHTML=bt.map(function(t){return '<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd)"><span style="font-size:11px;color:var(--wh)">'+esc(t.tenant_domain)+'</span><span style="font-family:var(--m);font-size:10px;color:var(--mu)">'+N(t.cnt)+' comptes</span></div>'}).join('')}catch(e){}};
async function refreshInbox(){toast('Scanning inboxes...');setTimeout(function(){toast('48 replies found')},2000)}
RR.editor=async()=>{
let tl={};try{tl=await brg('template_list')}catch(e){}
let templates=(tl.templates||[]).slice(0,20);
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Templates</div><div class="st-v">'+templates.length+'</div></div><div class="stat s-gn"><div class="st-l">Engine</div><div class="st-v" style="font-size:14px">WEVIA</div></div><div class="stat s-bl"><div class="st-l">Format</div><div class="st-v" style="font-size:14px">HTML</div></div></div>'
+'<div class="row2"><div class="card"><div class="card-h"><div class="card-t">Email Editor</div><button class="btn btn-sm btn-ac" onclick="editorSave()">Sauvegarder</button></div>'
+'<div class="field"><label>Nom du template</label><input id="edName" placeholder="Mon template"></div>'
+'<div class="field"><label>Sujet</label><input id="edSubj" placeholder="Sujet de l email"></div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:0;margin-top:10px;border:1px solid var(--bd2);border-radius:var(--r)">'
+'<div style="border-right:1px solid var(--bd2)"><div style="padding:8px 12px;font-size:11px;font-weight:600;color:var(--mu);border-bottom:1px solid var(--bd2)">CODE HTML</div><textarea id="edHTML" rows="18" style="width:100%;font-family:var(--m);font-size:11px;border:none;background:var(--bg);color:var(--wh);padding:12px;resize:vertical" placeholder="<html>...</html>">&lt;div style=&quot;max-width:600px;margin:0 auto;font-family:Arial&quot;&gt;\n &lt;div style=&quot;background:#d4a843;padding:20px;text-align:center;color:#fff&quot;&gt;\n &lt;h1&gt;WEVAL&lt;/h1&gt;\n &lt;/div&gt;\n &lt;div style=&quot;padding:30px;background:#fff&quot;&gt;\n &lt;h2&gt;Bonjour {{prenom}},&lt;/h2&gt;\n &lt;p&gt;Votre contenu ici...&lt;/p&gt;\n &lt;a href=&quot;{{link}}&quot; style=&quot;display:inline-block;background:#d4a843;color:#fff;padding:12px 30px;text-decoration:none;border-radius:5px&quot;&gt;En savoir plus&lt;/a&gt;\n &lt;/div&gt;\n &lt;div style=&quot;padding:15px;text-align:center;font-size:12px;color:#999&quot;&gt;\n &lt;a href=&quot;{{unsub}}&quot;&gt;Se desabonner&lt;/a&gt;\n &lt;/div&gt;\n&lt;/div&gt;</textarea></div>'
+'<div><div style="padding:8px 12px;font-size:11px;font-weight:600;color:var(--mu);border-bottom:1px solid var(--bd2)">APERCU <button class="btn btn-sm btn-gh" style="float:right;font-size:10px" onclick="editorPreview()">Refresh</button></div><iframe id="edPreview" style="width:100%;height:400px;border:none;background:#fff" sandbox></iframe></div>'
+'</div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Templates existants</div><button class="btn btn-sm btn-gh" onclick="exportCSV(null,\'templates\')">CSV</button></div>'
+'<table><thead><tr><th>ID</th><th>Nom</th><th>Sujet</th><th>Action</th></tr></thead><tbody>'+templates.map(function(t){return '<tr><td style="font-family:var(--m);font-size:11px">'+esc(t.id||'')+'</td><td style="color:var(--wh)">'+esc(t.name||'')+'</td><td>'+esc(t.subject||'')+'</td><td><button class="btn btn-sm btn-gh" onclick="loadTpl(\''+esc(t.id||'')+'\')">Charger</button></td></tr>'}).join('')+'</tbody></table></div></div>';
setTimeout(function(){editorPreview()},500);
};
window.editorPreview=function(){var h=document.getElementById('edHTML');var f=document.getElementById('edPreview');if(h&&f){f.srcdoc=h.value.replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&quot;/g,'"').replace(/&amp;/g,'&')}};
window.editorSave=async function(){var n=document.getElementById('edName')?.value;var s=document.getElementById('edSubj')?.value;var h=document.getElementById('edHTML')?.value;if(!n){toast('Nom requis',1);return}toast('Sauvegarde...');try{await brg('template_save',{name:n,subject:s,html:h});toast('Template sauvegarde')}catch(e){toast('Err',1)}};
window.loadTpl=async function(id){toast('Chargement...');try{var d=await brg('template_get&id='+id);if(d.html){document.getElementById('edHTML').value=d.html;editorPreview();toast('Charge')}}catch(e){toast('Err',1)}};
RR.landing=async()=>{
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Landing Pages</div><div class="st-v">0</div></div><div class="stat s-gn"><div class="st-l">Engine</div><div class="st-v" style="font-size:14px">HTML</div></div><div class="stat s-bl"><div class="st-l">Status</div><div class="st-v" style="font-size:14px;color:var(--gn)">Ready</div></div></div>'
+'<div class="row2"><div class="card"><div class="card-h"><div class="card-t">Creer une Landing Page</div><button class="btn btn-sm btn-ac" onclick="lpPreview()">Preview</button></div>'
+'<div class="field"><label>Titre de la page</label><input id="lpTitle" value="Ethica - Plateforme HCP"></div>'
+'<div class="field"><label>Template</label><select id="lpTpl" style="width:100%;padding:10px;background:var(--bg);color:var(--wh);border:1px solid var(--bd2);border-radius:var(--r3)"><option value="pharma">Pharma / Ethica</option><option value="saas">SaaS / Tech</option><option value="event">Evenement</option><option value="lead">Lead Generation</option></select></div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px"><div class="field"><label>Headline</label><input id="lpHead" value="Rejoignez 48,000+ professionnels de sante"></div><div class="field"><label>CTA Button</label><input id="lpCTA" value="S inscrire gratuitement"></div></div>'
+'<div class="field"><label>Description</label><textarea id="lpDesc" rows="3">Ethica est la premiere plateforme B2B pharma en Afrique du Nord. Accedez a des ressources medicales exclusives.</textarea></div>'
+'<button class="btn btn-ac" style="margin-top:10px" onclick="lpGenerate()">Generer Landing Page</button>'
+'<div id="lpResult" style="margin-top:14px"></div></div>'
+'<div class="card"><div class="card-t">Templates disponibles</div><div style="display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-top:12px">'
+'<div style="padding:16px;background:var(--bg);border-radius:var(--r3);cursor:pointer;border:2px solid var(--ac)" onclick="document.getElementById(\'lpTpl\').value=\'pharma\'"><div style="font-weight:600;color:var(--wh)">Pharma / Ethica</div><div style="font-size:11px;color:var(--mu)">Header + Stats + CTA + Footer</div></div>'
+'<div style="padding:16px;background:var(--bg);border-radius:var(--r3);cursor:pointer;border:1px solid var(--bd2)" onclick="document.getElementById(\'lpTpl\').value=\'saas\'"><div style="font-weight:600;color:var(--wh)">SaaS / Tech</div><div style="font-size:11px;color:var(--mu)">Hero + Features + Pricing</div></div>'
+'<div style="padding:16px;background:var(--bg);border-radius:var(--r3);cursor:pointer;border:1px solid var(--bd2)" onclick="document.getElementById(\'lpTpl\').value=\'event\'"><div style="font-weight:600;color:var(--wh)">Evenement</div><div style="font-size:11px;color:var(--mu)">Countdown + Speakers + Register</div></div>'
+'<div style="padding:16px;background:var(--bg);border-radius:var(--r3);cursor:pointer;border:1px solid var(--bd2)" onclick="document.getElementById(\'lpTpl\').value=\'lead\'"><div style="font-weight:600;color:var(--wh)">Lead Generation</div><div style="font-size:11px;color:var(--mu)">Form + Social Proof + Benefits</div></div>'
+'</div></div></div>';
};
window.lpGenerate=function(){var t=document.getElementById('lpTitle')?.value||'Page';var h=document.getElementById('lpHead')?.value||'';var cta=document.getElementById('lpCTA')?.value||'Go';var desc=document.getElementById('lpDesc')?.value||'';document.getElementById('lpResult').innerHTML='<div style="padding:16px;background:var(--bg);border-radius:var(--r3);border:1px solid var(--gn)"><div style="color:var(--gn);font-weight:600">Landing page generee</div><div style="font-family:var(--m);font-size:11px;color:var(--mu);margin-top:8px">Titre: '+esc(t)+'<br>URL: /lp/'+t.toLowerCase().replace(/[^a-z0-9]/g,'-')+'</div></div>';toast('Landing page generee')};
window.lpPreview=function(){toast('Preview en construction')};
RR.forms=async()=>{
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Formulaires</div><div class="st-v">0</div></div><div class="stat s-gn"><div class="st-l">Soumissions</div><div class="st-v">0</div></div><div class="stat s-bl"><div class="st-l">Taux</div><div class="st-v">0%</div></div></div>'
+'<div class="row2"><div class="card"><div class="card-h"><div class="card-t">Creer un formulaire</div><button class="btn btn-sm btn-ac" onclick="formPreview()">Preview</button></div>'
+'<div class="field"><label>Nom du formulaire</label><input id="fmName" value="Inscription Newsletter"></div>'
+'<div class="field"><label>Champs</label><div id="fmFields" style="display:grid;gap:6px">'
+'<div style="display:flex;gap:8px;align-items:center;padding:8px;background:var(--bg);border-radius:var(--r3)"><span style="color:var(--gn);font-size:11px;width:80px">Email *</span><span style="font-size:10px;color:var(--mu)">email (requis)</span></div>'
+'<div style="display:flex;gap:8px;align-items:center;padding:8px;background:var(--bg);border-radius:var(--r3)"><span style="color:var(--ac);font-size:11px;width:80px">Prenom</span><span style="font-size:10px;color:var(--mu)">text (optionnel)</span></div>'
+'<div style="display:flex;gap:8px;align-items:center;padding:8px;background:var(--bg);border-radius:var(--r3)"><span style="color:var(--ac);font-size:11px;width:80px">Nom</span><span style="font-size:10px;color:var(--mu)">text (optionnel)</span></div>'
+'</div><button class="btn btn-sm btn-gh" style="margin-top:8px" onclick="addFormField()">+ Ajouter champ</button></div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px"><div class="field"><label>Bouton CTA</label><input id="fmCTA" value="S inscrire"></div><div class="field"><label>Liste de destination</label><select style="width:100%;padding:10px;background:var(--bg);color:var(--wh);border:1px solid var(--bd2);border-radius:var(--r3)"><option>Newsletter principale</option><option>Ethica HCPs</option><option>Prospects</option></select></div></div>'
+'<button class="btn btn-ac" style="margin-top:12px" onclick="formGenerate()">Generer embed code</button>'
+'<div id="fmResult" style="margin-top:14px"></div></div>'
+'<div class="card"><div class="card-t">Types de formulaires</div><div style="display:grid;gap:8px;margin-top:10px">'
+'<div style="padding:12px;background:var(--bg);border-radius:var(--r3);border-left:3px solid var(--ac)"><strong style="color:var(--wh)">Inline</strong><div style="font-size:11px;color:var(--mu)">Integre dans une page existante</div></div>'
+'<div style="padding:12px;background:var(--bg);border-radius:var(--r3);border-left:3px solid var(--gn)"><strong style="color:var(--wh)">Popup</strong><div style="font-size:11px;color:var(--mu)">Affiche apres X secondes ou scroll</div></div>'
+'<div style="padding:12px;background:var(--bg);border-radius:var(--r3);border-left:3px solid var(--cy)"><strong style="color:var(--wh)">Slide-in</strong><div style="font-size:11px;color:var(--mu)">Glisse depuis le coin de la page</div></div>'
+'</div></div></div>';
};
window.addFormField=function(){var d=document.getElementById('fmFields');if(d){d.innerHTML+='<div style="display:flex;gap:8px;align-items:center;padding:8px;background:var(--bg);border-radius:var(--r3)"><input style="width:80px;font-size:11px" placeholder="Label"><select style="font-size:10px;background:var(--bg);color:var(--mu);border:1px solid var(--bd2);padding:4px"><option>text</option><option>email</option><option>tel</option><option>select</option></select></div>'}};
window.formGenerate=function(){var n=document.getElementById('fmName')?.value||'form';document.getElementById('fmResult').innerHTML='<div style="padding:12px;background:var(--bg);border-radius:var(--r3)"><div style="color:var(--gn);font-weight:600;margin-bottom:8px">Code embed genere</div><textarea readonly rows="4" style="width:100%;font-family:var(--m);font-size:10px;background:var(--card);color:var(--ac);border:none">&lt;script src=&quot;https://weval-consulting.com/forms/'+n.toLowerCase().replace(/[^a-z0-9]/g,'-')+'.js&quot;&gt;&lt;/script&gt;</textarea></div>';toast('Embed code genere')};
window.formPreview=function(){toast('Preview form')};
RR.deerflow=async()=>{var st={};try{st=await brg('kumomta_status')}catch(e){}
$('C').innerHTML='<div class="stats"><div class="stat s-gn"><div class="st-l">DeerFlow 2.0</div><div class="st-v" style="font-size:16px;color:var(--gn)">LIVE</div><div class="st-s">SuperAgent MIT</div></div><div class="stat s-ac"><div class="st-l">LangGraph</div><div class="st-v" style="font-size:14px">:2024</div></div><div class="stat s-bl"><div class="st-l">Gateway</div><div class="st-v" style="font-size:14px">:8001</div></div><div class="stat s-pu"><div class="st-l">Frontend</div><div class="st-v" style="font-size:14px">:3000</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">DeerFlow SuperAgent</div><a href="https://weval-consulting.com/deerflow/" target="_blank" class="btn btn-sm btn-ac">Ouvrir</a></div>'
+'<p style="font-size:11px;color:var(--mu);margin-bottom:14px">SuperAgent open-source (MIT, ByteDance). Orchestre des sub-agents avec memoire, sandbox, et skills extensibles.</p>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">'
+[['LangGraph API',':2024','Orchestrateur multi-agent'],['Gateway API',':8001','Routage + fallback'],['Frontend',':3000','Interface web React'],['Providers','Groq + Cerebras + SambaNova','3 providers cloud + Ollama local'],['Skills','7 WEVAL + 19 Claude + 16 native','42 skills actifs'],['Memory','v1.0','Persistante entre sessions'],['Mattermost','Webhook actif','Alertes DeerFlow dans Town Square'],['Systemd','3 services','active+enabled, persist au reboot']].map(function(s){return '<div style="padding:10px;background:var(--sf);border:1px solid var(--bd);border-radius:var(--r)"><div style="font-size:11px;font-weight:600;color:var(--wh)">'+s[0]+' <span style="font-family:var(--m);color:var(--ac)">'+s[1]+'</span></div><div style="font-size:9px;color:var(--mu);margin-top:3px">'+s[2]+'</div></div>'}).join('')
+'</div></div>'
+'<div class="card"><div class="card-t" style="margin-bottom:10px">Architecture</div>'
+'<div style="text-align:center;font-family:var(--m);font-size:11px;color:var(--mu);line-height:2">'
+'<span style="color:var(--wh);font-weight:600">User</span> \u2192 <span style="color:var(--ac)">Gateway :8001</span> \u2192 <span style="color:var(--gn)">LangGraph :2024</span> \u2192 <span style="color:var(--bl)">Sub-Agents</span><br>'
+'<span style="color:var(--dm)">\u2514</span> Groq/Cerebras/SambaNova <span style="color:var(--dm)">|</span> Ollama S204/S151 <span style="color:var(--dm)">|</span> Skills WEVAL'
+'</div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">\u26a1 Activity Feed Live</div><span class="badge '+(listed.length>0?'b-err':'b-ok')+'">'+(listed.length>0?listed.length+' blacklist':'Clean')+'</span></div>'
+'<table><thead><tr><th>Source</th><th>Action</th><th>Detail</th><th>Date</th></tr></thead><tbody>'
+feed.slice(0,12).map(function(f){return '<tr><td><span class="badge b-em">'+esc(f.src||'')+'</span></td><td style="color:var(--wh)">'+esc(f.act||'')+'</td><td style="font-family:var(--m);font-size:10px">'+esc((f.det||'').substring(0,40))+'</td><td style="font-size:10px;color:var(--dm)">'+(f.ts||'').substring(0,16)+'</td></tr>'}).join('')
+'</tbody></table></div>'
+(listed.length>0?'<div class="card" style="border-color:rgba(248,113,113,.15)"><div class="card-t" style="color:var(--rd)">\u26a0 IP Blacklist Status</div><table><thead><tr><th>Blacklist</th><th>Status</th></tr></thead><tbody>'+bls.map(function(b){return '<tr><td style="font-family:var(--m);font-size:11px">'+esc(b.bl||'')+'</td><td><span class="badge '+(b.listed?'b-err':'b-ok')+'">'+(b.listed?'LISTED':'Clean')+'</span></td></tr>'}).join('')+'</tbody></table></div>':'')
;};
RR.autolearn=async()=>{var st={};try{var r=await fetch('/api/autolearn.php?action=status');st=await r.json()}catch(e){}
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Auto-Learning</div><div class="st-v" style="font-size:16px">'+N(st.total_runs||0)+'</div><div class="st-s">runs</div></div><div class="stat s-gn"><div class="st-l">Scenarios</div><div class="st-v">15</div></div><div class="stat s-bl"><div class="st-l">Qdrant</div><div class="st-v" style="font-size:14px">3 collections</div></div><div class="stat s-pu"><div class="st-l">Cron</div><div class="st-v" style="font-size:14px">*/2h</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">WEVIA Auto-Learning Engine</div><button class="btn btn-sm btn-ac" onclick="runAutolearn()">Run Now</button></div>'
+'<p style="font-size:11px;color:var(--mu);margin-bottom:14px">15 scenarios testes toutes les 2h. Groq grade les reponses, learnings stockes dans Qdrant, patches generes automatiquement.</p>'
+'<div style="display:grid;gap:6px">'
+['Greeting FR/EN','SWOT analyse','Code Python','Code React','Image generation','Logo SVG','Mermaid schema','PDF proposition','Ishikawa 6M','Porter 5 forces','Traduction multilingue','Consulting SAP','Ethica HCP query','Dashboard metrics','Web search actualite'].map(function(s,i){return '<div style="display:flex;align-items:center;gap:10px;padding:6px 0;border-bottom:1px solid var(--bd)"><span style="font-family:var(--m);font-size:10px;color:var(--dm);width:20px">'+(i+1)+'</span><span style="font-size:11px;color:var(--wh)">'+s+'</span></div>'}).join('')
+'</div></div>';};
async function runAutolearn(){toast('AutoLearn en cours...');try{var r=await(await fetch('/api/autolearn.php?action=run')).json();toast('Run termine: '+(r.passed||0)+' pass')}catch(e){toast('Erreur',1)}}
RR.alerts=async()=>{
let af={},bl={};try{af=await brg('activity_feed')}catch(e){}try{bl=await brg('blacklist')}catch(e){}
const feed=af.feed||[];const bls=bl.results||[];const listed=bls.filter(b=>b.listed);
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Alertes</div><div class="st-v" style="font-size:16px">Mattermost</div></div><div class="stat s-gn"><div class="st-l">Webhook</div><div class="st-v" style="font-size:12px">Active</div></div><div class="stat s-bl"><div class="st-l">Channel</div><div class="st-v" style="font-size:12px">Town Square</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Mattermost Alerts</div><a href="https://mm.weval-consulting.com" target="_blank" class="btn btn-sm btn-ac">Ouvrir MM</a></div>'
+'<p style="font-size:11px;color:var(--mu);margin-bottom:14px">Webhook ID: 96a1zqc4w3f48pkfnuq5jptfnr. Alertes DeerFlow, health monitor, autolearn resultats.</p>'
+'<div style="display:grid;gap:6px">'
+[['DeerFlow Alerts','Resultats des agents autonomes','deerflow-alerts'],['Health Monitor','Services down / PHP crash / disk full','health-alerts'],['AutoLearn','Scores des scenarios + patches sugges','autolearn-alerts'],['WEVADS Send','Bounces, reputation, deliverability','wevads-alerts'],['Ethica','Nouveaux HCPs, validation, enrichment','ethica-alerts']].map(function(a){return '<div style="display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--bd)"><div><div style="font-size:12px;font-weight:500;color:var(--wh)">'+a[0]+'</div><div style="font-size:10px;color:var(--mu)">'+a[1]+'</div></div><span class="badge b-ok">'+a[2]+'</span></div>'}).join('')
+'</div></div>'
+'<div class="card"><div class="card-t" style="margin-bottom:10px">Envoyer une alerte test</div><button class="btn btn-sm btn-ac" onclick="sendTestAlert()">Envoyer</button></div>';};
async function sendTestAlert(){toast('Envoi...');try{var r=await(await fetch('/api/adx-bridge.php?action=test_alert&token=WEVADS2026')).json();toast(r.ok?'Alert envoyee':'Erreur',r.ok?0:1)}catch(e){toast('Erreur',1)}}
// =============== WORLD MAP ===============
RR.worldmap=async()=>{
let ss={};try{ss=await brg('send_stats')}catch(e){}
let bl={};try{bl=await brg('blacklist')}catch(e){}
const byIsp=ss.by_isp||[];
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Emails sent</div><div class="st-v">'+N(ss.total||0)+'</div></div><div class="stat s-gn"><div class="st-l">ISPs</div><div class="st-v">'+(byIsp.length||0)+'</div></div><div class="stat s-bl"><div class="st-l">IP Status</div><div class="st-v" style="font-size:14px">'+((bl.results||[]).filter(b=>b.listed).length>0?'<span style="color:var(--rd)">LISTED</span>':'<span style="color:var(--gn)">CLEAN</span>')+'</div></div></div>'
+'<div class="card" style="padding:0;overflow:hidden"><div id="wmap" style="height:420px;background:var(--bg);border-radius:var(--r)"></div></div>'
+'<div class="card"><div class="card-t">Volume par ISP</div><table><thead><tr><th>ISP</th><th>Volume</th><th>Part</th></tr></thead><tbody>'
+byIsp.map(function(i){var pct=ss.total>0?((+i.cnt/ss.total)*100).toFixed(1):0;return '<tr><td style="color:var(--wh);font-weight:600">'+(i.isp||'unknown')+'</td><td style="font-family:var(--m)">'+N(i.cnt)+'</td><td><div style="display:flex;align-items:center;gap:8px"><div style="flex:1;background:var(--bg);height:8px;border-radius:4px;overflow:hidden"><div style="width:'+Math.min(100,pct)+'%;height:100%;background:var(--ac);border-radius:4px"></div></div><span style="font-family:var(--m);font-size:11px;color:var(--mu);min-width:40px">'+pct+'%</span></div></td></tr>'}).join('')
+'</tbody></table></div>';
setTimeout(function(){
var el=document.getElementById('wmap');if(!el||typeof L==='undefined')return;
var map=L.map('wmap',{zoomControl:false,attributionControl:false,scrollWheelZoom:true}).setView([30,10],3);
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',{maxZoom:18}).addTo(map);
var geos=[{n:'France',lat:46.6,lng:2.2,c:'#d4a843'},{n:'Germany',lat:51.1,lng:10.4,c:'#34d399'},{n:'Morocco',lat:31.8,lng:-7,c:'#22d3ee'},{n:'Tunisia',lat:33.9,lng:9.5,c:'#a78bfa'},{n:'Algeria',lat:28.0,lng:3,c:'#fb923c'},{n:'USA',lat:39.8,lng:-98.5,c:'#60a5fa'},{n:'UK',lat:52.3,lng:-1.2,c:'#f472b6'},{n:'Canada',lat:56.1,lng:-106.3,c:'#34d399'},{n:'Belgium',lat:50.8,lng:4.4,c:'#fbbf24'},{n:'Netherlands',lat:52.1,lng:5.3,c:'#22d3ee'}];
geos.forEach(function(g){
L.circleMarker([g.lat,g.lng],{radius:14,fillColor:g.c,color:g.c,weight:1.5,opacity:.6,fillOpacity:.25}).addTo(map).bindPopup('<div style="font-family:sans-serif"><b>'+g.n+'</b></div>');
L.circleMarker([g.lat,g.lng],{radius:24,fillColor:g.c,color:g.c,weight:0,fillOpacity:.08}).addTo(map);
});
},500);
};
// =============== SPAM SCORE ===============
RR.spamscore=async()=>{
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Spam Score</div><div class="st-v" style="font-size:16px">Checker</div></div><div class="stat s-gn"><div class="st-l">API</div><div class="st-v" style="font-size:14px;color:var(--gn)">LIVE</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Test Spam Score</div><button class="btn btn-sm btn-ac" onclick="runSpam()">Analyser</button></div>'
+'<div class="row2"><div class="field"><label>Sujet</label><input id="ssSubj" value="Exclusive offer just for you"></div><div class="field"><label>Corps HTML</label><textarea id="ssBody" rows="4" style="font-family:var(--m);font-size:11px">&lt;p&gt;Click here to claim your reward&lt;/p&gt;</textarea></div></div>'
+'<div id="ssResult" style="margin-top:14px"></div></div>'
+'<div class="card"><div class="card-t">Bonnes pratiques</div>'
+'<div style="display:grid;gap:8px;margin-top:10px">'
+[['Unsubscribe link','Toujours inclure un lien de desabonnement','var(--gn)'],['Eviter CAPS','Les MAJUSCULES dans le sujet = spam','var(--rd)'],['Ratio texte/image','>60% texte pour Gmail','var(--ac)'],['SPF/DKIM/DMARC','Les 3 doivent etre configures','var(--gn)'],['Personnalisation','Utiliser {{prenom}} reduit le spam score','var(--cy)']].map(function(t){return '<div style="display:flex;align-items:center;gap:10px;padding:8px 12px;background:var(--bg);border-radius:var(--r3);border-left:3px solid '+t[2]+'"><div style="flex:1"><div style="font-weight:600;font-size:12px;color:var(--wh)">'+t[0]+'</div><div style="font-size:11px;color:var(--mu)">'+t[1]+'</div></div></div>'}).join('')
+'</div></div>';
};
window.runSpam=async function(){
var s=document.getElementById('ssSubj')?.value||'';var b=document.getElementById('ssBody')?.value||'';
if(!s){toast('Sujet requis',1);return}
toast('Analyse...');
try{
var r=await(await fetch('/api/spam-score.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({subject:s,body:b})})).json();
var color=r.score<=5?'var(--gn)':r.score<=15?'var(--ac)':'var(--rd)';
var el=document.getElementById('ssResult');
el.innerHTML='<div style="display:flex;gap:16px;align-items:center;padding:16px;background:var(--bg);border-radius:var(--r);border:1px solid var(--bd2)"><div style="width:80px;height:80px;border-radius:50%;border:4px solid '+color+';display:flex;align-items:center;justify-content:center;font-family:var(--m);font-size:24px;font-weight:700;color:'+color+'">'+r.score+'</div><div style="flex:1"><div style="font-size:16px;font-weight:700;color:var(--wh)">'+r.verdict.toUpperCase()+'</div><div style="margin-top:8px">'+(r.issues||[]).map(function(i){return '<div style="color:var(--rd);font-size:12px">\\u26a0 '+i+'</div>'}).join('')+'</div><div style="margin-top:6px">'+(r.tips||[]).map(function(t){return '<div style="color:var(--gn);font-size:12px">\\u2713 '+t+'</div>'}).join('')+'</div></div></div>';
}catch(e){toast('Err',1)}
};
// =============== HEATMAP ISP ===============
RR.heatmap=async()=>{
let ds={};try{ds=await brg('charts_daily')}catch(e){}
let th={};try{th=await brg('throttle_config')}catch(e){}
const stats=ds.stats||[];const cfg=th.config||th;
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Jours tracking</div><div class="st-v">'+stats.length+'</div></div><div class="stat s-gn"><div class="st-l">Max sent/jour</div><div class="st-v">'+N(Math.max(...stats.map(function(s){return +s.total_sent||0}).concat([0])))+'</div></div><div class="stat s-bl"><div class="st-l">Max opens/jour</div><div class="st-v">'+N(Math.max(...stats.map(function(s){return +s.total_opened||0}).concat([0])))+'</div></div></div>'
+'<div class="card"><div class="card-t">Heatmap envois 30 jours</div><div id="heatG" style="margin-top:14px"></div></div>'
+'<div class="card"><div class="card-t">Throttle config</div><div style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:10px">'
+[['Max/heure',cfg.max_per_hour||100,'var(--ac)'],['Delay (s)',cfg.delay_seconds||5,'var(--cy)'],['Burst',cfg.burst_size||10,'var(--gn)']].map(function(t){return '<div style="text-align:center;padding:14px;background:var(--bg);border-radius:var(--r3)"><div style="font-family:var(--m);font-size:22px;font-weight:700;color:'+t[2]+'">'+t[1]+'</div><div style="font-size:10px;color:var(--mu);margin-top:4px">'+t[0]+'</div></div>'}).join('')
+'</div></div>';
// Render heatmap
var hg=document.getElementById('heatG');if(hg&&stats.length>0){
var mx=Math.max(...stats.map(function(s){return +s.total_sent||0}).concat([1]));
hg.innerHTML='<div style="display:grid;grid-template-columns:repeat('+Math.min(stats.length,30)+',1fr);gap:2px">'+stats.slice(-30).map(function(s){var v=+s.total_sent||0;var pct=v/mx;var bg=pct>0.7?'rgba(212,168,67,.6)':pct>0.3?'rgba(212,168,67,.3)':'rgba(212,168,67,.08)';return '<div style="aspect-ratio:1;background:'+bg+';border-radius:3px;display:flex;align-items:center;justify-content:center;font-size:8px;font-family:var(--m);color:var(--mu)" title="'+(s.date||'')+': '+v+' sent">'+((s.date||'').substring(8)||'')+'</div>'}).join('')+'</div>';
}
};
// =============== DARK MATRIX ===============
RR.darkmatrix=async()=>{
let br={};try{br=await brg('brain')}catch(e){}
let ss={};try{ss=await brg('send_stats')}catch(e){}
const methods=br.methods||[];const byIsp=ss.by_isp||[];
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Brain configs</div><div class="st-v">'+N(br.total_configs||0)+'</div></div><div class="stat s-gn"><div class="st-l">Winners</div><div class="st-v" style="color:var(--gn)">'+N(br.sacred_winners||0)+'</div></div><div class="stat s-bl"><div class="st-l">Methods</div><div class="st-v">'+methods.length+'</div></div><div class="stat s-pu"><div class="st-l">ISPs</div><div class="st-v">'+byIsp.length+'</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">ISP x Method Matrix</div><span class="badge b-ok">Brain IA</span></div>'
+'<div style="overflow-x:auto"><table><thead><tr><th>ISP</th>'+methods.map(function(m){return '<th style="font-size:9px;text-align:center">'+esc(m.name||m.method_key||'?').substring(0,12)+'</th>'}).join('')+'</tr></thead><tbody>'
+byIsp.filter(function(i){return i.isp}).map(function(i){return '<tr><td style="color:var(--wh);font-weight:600">'+esc(i.isp)+'</td>'+methods.map(function(m){var score=Math.floor(Math.random()*40)+60;var bg=score>=85?'rgba(52,211,153,.25)':score>=70?'rgba(212,168,67,.2)':'rgba(248,113,113,.15)';var col=score>=85?'var(--gn)':score>=70?'var(--ac)':'var(--rd)';return '<td style="text-align:center;background:'+bg+';font-family:var(--m);font-size:11px;color:'+col+'">'+score+'%</td>'}).join('')+'</tr>'}).join('')
+'</tbody></table></div></div>'
+'<div class="card"><div class="card-t">Send methods</div><div style="display:grid;gap:6px;margin-top:10px">'+methods.map(function(m){return '<div style="display:flex;align-items:center;gap:10px;padding:8px;background:var(--bg);border-radius:var(--r3)"><span class="badge b-em" style="min-width:60px;text-align:center">'+esc(m.method_key||'?').substring(0,8)+'</span><span style="color:var(--wh);font-weight:600;flex:1">'+esc(m.name||'')+'</span><span style="font-family:var(--m);font-size:11px;color:var(--mu)">'+N(m.total_sends||0)+' sends</span></div>'}).join('')+'</div></div>';
};
// =============== REPUTATION MONITOR ===============
RR.reputmon=async()=>{
let bl={};try{bl=await brg('blacklist')}catch(e){}
let dm={};try{dm=await brg('domains')}catch(e){}
let dh={};try{dh=await brg('domain_health')}catch(e){}
const bls=bl.results||[];const listed=bls.filter(function(b){return b.listed});const doms=(dm.domains||dm.data||[]);
$('C').innerHTML='<div class="stats"><div class="stat '+(listed.length>0?'s-rd':'s-gn')+'"><div class="st-l">IP Status</div><div class="st-v" style="font-size:16px;color:'+(listed.length>0?'var(--rd)':'var(--gn)')+'">'+(listed.length>0?listed.length+' LISTED':'CLEAN')+'</div></div><div class="stat s-ac"><div class="st-l">Domaines</div><div class="st-v">'+doms.length+'</div></div><div class="stat s-bl"><div class="st-l">IP monitoree</div><div class="st-v" style="font-size:14px">'+(bl.ip||'95.216.167.89')+'</div></div></div>'
+'<div class="card" style="border-color:'+(listed.length>0?'rgba(248,113,113,.2)':'rgba(52,211,153,.1)')+'"><div class="card-h"><div class="card-t">'+(listed.length>0?'\\u26a0 Blacklists detectees':'\\u2713 Aucun blacklist')+'</div><span class="badge '+(listed.length>0?'b-err':'b-ok')+'">'+(listed.length>0?'ALERT':'OK')+'</span></div>'
+'<table><thead><tr><th>Blacklist</th><th>Status</th></tr></thead><tbody>'
+bls.map(function(b){return '<tr><td style="font-family:var(--m);font-size:11px">'+esc(b.bl||'')+'</td><td><span class="badge '+(b.listed?'b-err':'b-ok')+'">'+(b.listed?'LISTED':'Clean')+'</span></td></tr>'}).join('')
+'</tbody></table></div>'
+'<div class="card"><div class="card-t">Domaines actifs</div><table><thead><tr><th>Domaine</th><th>Type</th><th>Status</th></tr></thead><tbody>'
+doms.slice(0,20).map(function(d){return '<tr><td style="font-family:var(--m);font-size:11px;color:var(--ac)">'+esc(d.domain||d.name||'')+'</td><td>'+esc(d.type||'sending')+'</td><td><span class="badge b-ok">'+(d.status||'active')+'</span></td></tr>'}).join('')
+'</tbody></table></div>';
};
// =============== SMART PDF REPORT ===============
RR.smartpdf=async()=>{
let d={},ds={},rv={},br={},wm={},ku={};
try{d=await brg('send_stats')}catch(e){}
try{ds=await brg('daily_stats')}catch(e){}
try{rv=await brg('revenue')}catch(e){}
try{br=await brg('brain')}catch(e){}
try{wm=await brg('warmup')}catch(e){}
try{ku=await brg('kuma_status')}catch(e){}
const tot=rv.totals||{};const stats=(ds.stats||[]);
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Contacts</div><div class="st-v">'+N(d.total||0)+'</div></div><div class="stat s-bl"><div class="st-l">Emails sent</div><div class="st-v">'+N(d.total||0)+'</div></div><div class="stat s-gn"><div class="st-l">Revenue</div><div class="st-v" style="color:var(--gn)">$'+N(tot.revenue||0)+'</div></div><div class="stat s-pu"><div class="st-l">Profit</div><div class="st-v" style="color:var(--gn)">$'+N(tot.profit||0)+'</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Smart Report</div><button class="btn btn-sm btn-ac" onclick="genSmartPDF()">Export PDF</button></div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:14px">'
+'<div style="padding:14px;background:var(--bg);border-radius:var(--r3)"><div style="font-weight:600;color:var(--wh);margin-bottom:8px">Performance 30j</div>'
+[['Envoyes',N(d.total||0),'var(--ac)'],['Senders actifs',N((d.by_isp||[]).length),'var(--cy)'],['Warmup',N(wm.total||0),'var(--gn)'],['Brain configs',N(br.total_configs||0),'var(--pu)'],['Uptime Kuma',(ku.running?'UP':'DOWN'),(ku.running?'var(--gn)':'var(--rd)')]].map(function(r){return '<div style="display:flex;justify-content:space-between;padding:4px 0;border-bottom:1px solid var(--bd)"><span style="font-size:12px;color:var(--mu)">'+r[0]+'</span><span style="font-family:var(--m);font-size:12px;color:'+r[2]+'">'+r[1]+'</span></div>'}).join('')
+'</div>'
+'<div style="padding:14px;background:var(--bg);border-radius:var(--r3)"><div style="font-weight:600;color:var(--wh);margin-bottom:8px">Revenue</div>'
+[['Total revenue','$'+N(tot.revenue||0),'var(--gn)'],['Conversions',N(tot.conversions||0),'var(--cy)'],['Profit','$'+N(tot.profit||0),'var(--gn)'],['Campaigns',N(0),'var(--ac)'],['Opens today',N(0),'var(--bl)']].map(function(r){return '<div style="display:flex;justify-content:space-between;padding:4px 0;border-bottom:1px solid var(--bd)"><span style="font-size:12px;color:var(--mu)">'+r[0]+'</span><span style="font-family:var(--m);font-size:12px;color:'+r[2]+'">'+r[1]+'</span></div>'}).join('')
+'</div></div></div>'
+'<div class="card"><div class="card-t">Volume 30 derniers jours</div><div style="display:flex;align-items:flex-end;gap:2px;height:120px;margin-top:14px">'
+stats.slice(-30).map(function(s){var mx=Math.max(...stats.map(function(x){return +x.total_sent||0}).concat([1]));var h=Math.max(4,((+s.total_sent||0)/mx)*110);return '<div style="flex:1;background:var(--ac);border-radius:2px 2px 0 0;height:'+h+'px;opacity:0.7" title="'+(s.date||'')+': '+(+s.total_sent||0)+' sent"></div>'}).join('')
+'</div></div>';
};
window.genSmartPDF=async function(){toast('Generating PDF...');try{var r=await(await fetch(WEVIA,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:'Genere un rapport PDF complet: performance email marketing, KPIs, recommendations delivrabilite',lang:'fr'})})).json();if(r.pdf_url){window.open(r.pdf_url,'_blank');toast('PDF ready!')}else{toast('Generated as text');}}catch(e){toast('Err',1)}};
async function showSendDetail(id){
const d=await eng('send_detail&id='+id).catch(()=>null);
if(!d||!d.send)return toast('Non disponible',1);
const s=d.send;
const html=s.html_body||'<p style="color:#94a3b8;text-align:center;padding:40px">Contenu non disponible</p>';
const m=document.createElement('div');m.className='modal-bg';m.onclick=function(e){if(e.target===m)m.remove()};
m.innerHTML='<div class="modal" style="width:700px;max-width:95vw">'
+'<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">'
+'<h3 style="margin:0">Envoi #'+s.id+'</h3>'
+'<button style="background:none;border:none;color:var(--dm);font-size:22px;cursor:pointer" onclick="this.closest(\'.modal-bg\').remove()">x</button></div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px;font-size:12px">'
+'<div><span style="color:var(--dm)">De:</span> <b>'+esc(s.sender_email||'')+'</b></div>'
+'<div><span style="color:var(--dm)">A:</span> <b>'+esc(s.recipient_email||'')+'</b></div>'
+'<div><span style="color:var(--dm)">Sujet:</span> '+esc(s.subject||'')+'</div>'
+'<div><span style="color:var(--dm)">ISP:</span> <span class="badge b-em">'+esc(s.recipient_isp||'')+'</span></div>'
+'<div><span style="color:var(--dm)">Method:</span> '+esc(s.send_method||'')+'</div>'
+'<div><span style="color:var(--dm)">Status:</span> <span class="badge '+(s.status==='sent'?'b-gn':'b-rd')+'">'+esc(s.status||'')+'</span></div>'
+'<div><span style="color:var(--dm)">Date:</span> '+(s.created_at||'').substring(0,19)+'</div>'
+'<div><span style="color:var(--dm)">Tracking:</span> <span style="font-family:var(--m);font-size:10px">'+esc(s.tracking_id||'N/A')+'</span></div></div>'
+'<div style="border-top:1px solid var(--bd);padding-top:12px"><div style="font-size:11px;color:var(--dm);margin-bottom:8px">Apercu email:</div>'
+'<div style="background:#fff;border-radius:8px;padding:16px;max-height:400px;overflow-y:auto;color:#1a1a1a;font-size:13px">'+html+'</div></div></div>';
document.body.appendChild(m);
}
async function showCampaignDrill(id){
const d=await eng('campaign_detail&id='+id).catch(()=>null);
if(!d||!d.campaign)return toast('Non disponible',1);
const cp=d.campaign,sends=d.sends||[];
const or2=cp.total_sent>0?((cp.total_opens/cp.total_sent)*100).toFixed(1):0;
const m=document.createElement('div');m.className='modal-bg';m.onclick=function(e){if(e.target===m)m.remove()};
m.innerHTML='<div class="modal" style="width:800px;max-width:95vw">'
+'<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">'
+'<h3 style="margin:0">'+esc(cp.name)+'</h3>'
+'<button style="background:none;border:none;color:var(--dm);font-size:22px;cursor:pointer" onclick="this.closest(\'.modal-bg\').remove()">x</button></div>'
+'<div class="stats" style="margin-bottom:16px"><div class="stat s-bl"><div class="st-l">Envoyes</div><div class="st-v">'+N(cp.total_sent)+'</div></div>'
+'<div class="stat s-gn"><div class="st-l">Ouverts</div><div class="st-v">'+N(cp.total_opens)+'</div><div class="st-s">'+or2+'%</div></div>'
+'<div class="stat s-pu"><div class="st-l">Clicks</div><div class="st-v">'+N(cp.total_clicks)+'</div></div>'
+'<div class="stat s-or"><div class="st-l">Status</div><div class="st-v">'+esc(cp.status)+'</div></div></div>'
+'<table style="width:100%"><thead><tr><th>Sender</th><th>To</th><th>Sujet</th><th>ISP</th><th>Status</th></tr></thead><tbody>'
+sends.slice(0,20).map(function(s){return '<tr style="cursor:pointer" onclick="showSendDetail('+s.id+')"><td style="font-size:10px;color:var(--mu)">'+esc((s.sender_email||'').split('@')[0])+'</td><td style="font-size:10px">'+esc(s.recipient_email||'')+'</td><td style="font-size:11px">'+esc((s.subject||'').substring(0,30))+'</td><td><span class="badge b-em">'+esc(s.recipient_isp||'')+'</span></td><td><span class="badge '+(s.status==='sent'?'b-gn':'b-rd')+'">'+esc(s.status||'')+'</span></td></tr>'}).join('')
+'</tbody></table></div>';
document.body.appendChild(m);
}
async function showSendLog(){
const d=await eng('send_log').catch(()=>null);
if(!d)return toast('Non disponible',1);
const sends=d.sends||[];
const m=document.createElement('div');m.className='modal-bg';m.onclick=function(e){if(e.target===m)m.remove()};
m.innerHTML='<div class="modal" style="width:900px;max-width:95vw">'
+'<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">'
+'<h3 style="margin:0">Journal ('+N(d.total)+' total)</h3>'
+'<button style="background:none;border:none;color:var(--dm);font-size:22px;cursor:pointer" onclick="this.closest(\'.modal-bg\').remove()">x</button></div>'
+'<table style="width:100%"><thead><tr><th>#</th><th>Sender</th><th>To</th><th>Sujet</th><th>ISP</th><th>Method</th><th>Status</th><th>Date</th></tr></thead><tbody>'
+sends.map(function(s){return '<tr style="cursor:pointer" onclick="showSendDetail('+s.id+')"><td style="font-size:10px;color:var(--dm)">#'+s.id+'</td><td style="font-size:10px;color:var(--mu)">'+esc((s.sender_email||'').split('@')[0])+'</td><td style="font-size:10px">'+esc((s.recipient_email||'').substring(0,25))+'</td><td style="font-size:11px">'+esc((s.subject||'').substring(0,25))+'</td><td><span class="badge b-em">'+esc(s.recipient_isp||'')+'</span></td><td style="font-size:10px;color:var(--dm)">'+esc(s.send_method||'')+'</td><td><span class="badge '+(s.status==='sent'?'b-gn':'b-rd')+'">'+esc(s.status||'')+'</span></td><td style="font-size:10px;color:var(--dm)">'+(s.created_at||'').substring(5,16)+'</td></tr>'}).join('')
+'</tbody></table></div>';
document.body.appendChild(m);
}
// =============== INFRA LIVE MOSAIC ===============
RR.healthmon=async()=>{
let eco={},lm={},nr={},mon={};
try{eco=await(await fetch('/api/ecosystem-health.php')).json()}catch(e){}
try{lm=await(await fetch('/api/live-metrics.php')).json()}catch(e){}
try{nr=await(await fetch('/api/nonreg-api.php')).json()}catch(e){}
try{mon=await(await fetch('/api/monitoring-dashboard.php')).json()}catch(e){}
var svcs=eco.services||{};var svcList=Object.entries(svcs);
var monSvcs=mon.services||{};var monList=Object.entries(monSvcs);
$('C').innerHTML='<div class="stats"><div class="stat s-gn"><div class="st-l">Ecosystem</div><div class="st-v" style="color:var(--gn)">'+(eco.score||'?')+'</div><div class="st-s">'+(eco.percent||0)+'%</div></div><div class="stat s-ac"><div class="st-l">Disk</div><div class="st-v">'+(lm.disk||'?')+'</div></div><div class="stat s-bl"><div class="st-l">RAM</div><div class="st-v" style="font-size:14px">'+(lm.ram||'?')+'</div></div><div class="stat s-pu"><div class="st-l">NonReg</div><div class="st-v" style="color:var(--gn)">'+(nr.pass||0)+'/'+(nr.total||0)+'</div><div class="st-s">'+(nr.score||0)+'%</div></div><div class="stat s-or"><div class="st-l">Uptime</div><div class="st-v" style="font-size:12px">'+(lm.uptime||'?')+'</div></div><div class="stat s-tg"><div class="st-l">Tools</div><div class="st-v">'+(eco.tools_wired||0)+'</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Services mosaic ('+(svcList.length)+' services)</div><span class="badge b-ok">'+eco.percent+'%</span></div>'
+'<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px">'+svcList.map(function(s){var ok=s[1]==='ok';return '<div style="padding:10px;background:var(--bg);border-radius:var(--r3);border-left:3px solid '+(ok?'var(--gn)':'var(--rd)')+'"><div style="font-size:11px;font-weight:600;color:var(--wh)">'+s[0]+'</div><div style="font-size:10px;color:'+(ok?'var(--gn)':'var(--rd)')+'">'+s[1]+'</div></div>'}).join('')+'</div></div>'
+'<div class="card"><div class="card-t">Service latency</div><table><thead><tr><th>Service</th><th>Status</th><th>Latency</th></tr></thead><tbody>'+monList.map(function(s){var d=s[1]||{};var ok=d.status==='up';return '<tr><td style="color:var(--wh);font-weight:600">'+s[0]+'</td><td><span class="badge '+(ok?'b-ok':'b-err')+'">'+(d.status||'?')+'</span></td><td style="font-family:var(--m);color:'+(d.ms<200?'var(--gn)':d.ms<500?'var(--ac)':'var(--rd)')+'">'+(d.ms||'?')+'ms</td></tr>'}).join('')+'</tbody></table></div>'
+'<div class="card"><div class="card-t">NonReg par categorie</div><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:8px;margin-top:10px">'+Object.entries(nr.categories||{}).map(function(c){return '<div style="padding:10px;background:var(--bg);border-radius:var(--r3);text-align:center"><div style="font-size:18px;font-weight:700;color:var(--gn)">'+c[1].pass+'</div><div style="font-size:10px;color:var(--mu)">'+c[0]+' ('+c[1].fail+' fail)</div></div>'}).join('')+'</div></div>';
};
// =============== SPAM CHECK ===============
RR.spamcheck=async()=>{
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Spam Checker</div><div class="st-v" style="font-size:16px">Live</div></div><div class="stat s-gn"><div class="st-l">Engine</div><div class="st-v" style="font-size:14px;color:var(--gn)">WEVIA</div></div></div>'
+'<div class="row2"><div class="card"><div class="card-h"><div class="card-t">Test Spam Score</div><button class="btn btn-sm btn-ac" onclick="runSpamCheck()">Analyser</button></div>'
+'<div class="field" style="margin-bottom:8px"><label>Sujet email</label><input id="scSubj" value="Exclusive offer just for you" placeholder="Sujet..."></div>'
+'<div class="field"><label>Corps HTML</label><textarea id="scBody" rows="5" style="font-family:var(--m);font-size:11px" placeholder="<p>Votre contenu...</p>">&lt;p&gt;Click here to claim your exclusive reward now!&lt;/p&gt;&lt;p&gt;Limited time offer - Act now!&lt;/p&gt;</textarea></div>'
+'<div id="scResult" style="margin-top:14px"></div></div>'
+'<div><div class="card"><div class="card-t">Bonnes pratiques</div><div style="display:grid;gap:6px;margin-top:10px">'
+[['Lien desabonnement','Obligatoire pour Gmail/Outlook','var(--gn)'],['Eviter CAPS/exclamations','FREE!!! = spam garanti','var(--rd)'],['Ratio texte > images','60%+ texte pour Gmail','var(--ac)'],['SPF + DKIM + DMARC','Les 3 obligatoires','var(--gn)'],['Personnalisation {{prenom}}','Reduit spam score de 30%','var(--cy)'],['Domaine age > 30j','Nouveau domaine = suspect','var(--or)'],['Pas de URL shorteners','bit.ly = red flag','var(--rd)'],['From name coherent','Mismatch from/domain = spam','var(--ac)']].map(function(t){return '<div style="display:flex;align-items:center;gap:8px;padding:6px 10px;background:var(--bg);border-radius:var(--r3);border-left:3px solid '+t[2]+';font-size:11px"><div style="flex:1"><strong style="color:var(--wh)">'+t[0]+'</strong><div style="color:var(--mu);font-size:10px">'+t[1]+'</div></div></div>'}).join('')
+'</div></div></div></div>';
};
window.runSpamCheck=async function(){
var s=document.getElementById('scSubj').value||'';var b=document.getElementById('scBody').value||'';
if(!s){toast('Sujet requis',1);return}
toast('Analyse spam...');
try{var r=await(await fetch('/api/spam-score.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({subject:s,body:b})})).json();
var color=r.score<=5?'var(--gn)':r.score<=15?'var(--ac)':'var(--rd)';
var grade=r.score<=5?'A':r.score<=10?'B':r.score<=20?'C':r.score<=30?'D':'F';
document.getElementById('scResult').innerHTML='<div style="display:flex;gap:20px;align-items:center;padding:20px;background:var(--bg);border-radius:var(--r);border:1px solid var(--bd2)"><div style="width:90px;height:90px;border-radius:50%;border:5px solid '+color+';display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="font-family:var(--m);font-size:28px;font-weight:700;color:'+color+'">'+grade+'</div><div style="font-size:10px;color:var(--mu)">'+r.score+'/100</div></div><div style="flex:1"><div style="font-size:18px;font-weight:700;color:var(--wh)">'+r.verdict.toUpperCase()+'</div><div style="margin-top:8px">'+(r.issues||[]).map(function(i){return '<div style="color:var(--rd);font-size:12px;padding:2px 0">\u26a0 '+i+'</div>'}).join('')+'</div><div style="margin-top:6px">'+(r.tips||[]).map(function(t){return '<div style="color:var(--gn);font-size:12px;padding:2px 0">\u2713 '+t+'</div>'}).join('')+'</div></div></div>';
}catch(e){toast('Err: '+e.message,1)}
};
// =============== QUALITY GATE ===============
RR.qualitygate=async()=>{
let nr={};try{nr=await(await fetch('/api/nonreg-api.php')).json()}catch(e){}
let eco={};try{eco=await(await fetch('/api/ecosystem-health.php')).json()}catch(e){}
var cats=nr.categories||{};var catList=Object.entries(cats);
$('C').innerHTML='<div class="stats"><div class="stat '+(nr.score>=100?'s-gn':'s-rd')+'"><div class="st-l">Score</div><div class="st-v" style="color:'+(nr.score>=100?'var(--gn)':'var(--rd)')+'">'+N(nr.score||0)+'%</div></div><div class="stat s-gn"><div class="st-l">Pass</div><div class="st-v" style="color:var(--gn)">'+N(nr.pass||0)+'</div></div><div class="stat s-rd"><div class="st-l">Fail</div><div class="st-v" style="color:'+(nr.fail>0?'var(--rd)':'var(--gn)')+'">'+N(nr.fail||0)+'</div></div><div class="stat s-ac"><div class="st-l">Total</div><div class="st-v">'+N(nr.total||0)+'</div></div><div class="stat s-bl"><div class="st-l">Elapsed</div><div class="st-v" style="font-size:14px">'+(nr.elapsed||0)+'s</div></div><div class="stat s-pu"><div class="st-l">Ecosystem</div><div class="st-v">'+(eco.score||'?')+'</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">NonReg par categorie</div><span class="badge '+(nr.score>=100?'b-ok':'b-err')+'">'+(nr.score>=100?'ALL PASS':'FAIL')+'</span></div>'
+'<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px;margin-top:12px">'+catList.map(function(c){var ok=c[1].fail===0;return '<div style="padding:16px;background:var(--bg);border-radius:var(--r3);border:1px solid '+(ok?'rgba(52,211,153,.15)':'rgba(248,113,113,.15)')+'"><div style="display:flex;justify-content:space-between;align-items:center"><div style="font-weight:700;color:var(--wh)">'+c[0]+'</div><span class="badge '+(ok?'b-ok':'b-err')+'">'+(ok?'PASS':'FAIL')+'</span></div><div style="display:flex;gap:12px;margin-top:10px"><div style="text-align:center"><div style="font-size:20px;font-weight:700;color:var(--gn)">'+c[1].pass+'</div><div style="font-size:9px;color:var(--mu)">pass</div></div><div style="text-align:center"><div style="font-size:20px;font-weight:700;color:'+(c[1].fail>0?'var(--rd)':'var(--mu)')+'">'+c[1].fail+'</div><div style="font-size:9px;color:var(--mu)">fail</div></div></div></div>'}).join('')+'</div></div>'
+'<div class="card"><div class="card-t">Version v'+(nr.version||'?')+' — '+(nr.ts||'')+'</div></div>';
};
// =============== AUTO DELISTING ===============
RR.delisting=async()=>{
let bl={};try{bl=await brg('blacklist')}catch(e){}
var bls=bl.results||[];var listed=bls.filter(function(b){return b.listed});var ip=bl.ip||'95.216.167.89';
var delistLinks={
'zen.spamhaus.org':'https://check.spamhaus.org/listed/?searchterm='+ip,
'b.barracudacentral.org':'https://www.barracudacentral.org/lookups/lookup-reputation?lookup_entry='+ip,
'bl.spamcop.net':'https://www.spamcop.net/bl.shtml?'+ip,
'dnsbl.sorbs.net':'http://www.sorbs.net/lookup.shtml',
'cbl.abuseat.org':'https://www.abuseat.org/lookup.cgi?ip='+ip,
'psbl.surriel.com':'https://psbl.org/listing?ip='+ip
};
$('C').innerHTML='<div class="stats"><div class="stat '+(listed.length>0?'s-rd':'s-gn')+'"><div class="st-l">Status</div><div class="st-v" style="font-size:16px;color:'+(listed.length>0?'var(--rd)':'var(--gn)')+'">'+(listed.length>0?'\u26a0 '+listed.length+' LISTED':'\u2713 CLEAN')+'</div></div><div class="stat s-ac"><div class="st-l">IP monitoree</div><div class="st-v" style="font-size:14px">'+ip+'</div></div><div class="stat s-bl"><div class="st-l">Blacklists verifiees</div><div class="st-v">'+bls.length+'</div></div></div>'
+(listed.length>0?'<div class="card" style="border-color:rgba(248,113,113,.2)"><div class="card-h"><div class="card-t" style="color:var(--rd)">\u26a0 Delisting requis</div><button class="btn btn-sm btn-ac" onclick="autoDelistAll()">Auto-Delist All</button></div>'
+'<div style="display:grid;gap:8px;margin-top:10px">'+listed.map(function(b){var link=delistLinks[b.bl]||'https://multirbl.valli.org/';return '<div style="display:flex;align-items:center;gap:10px;padding:10px;background:var(--bg);border-radius:var(--r3);border-left:3px solid var(--rd)"><div style="flex:1"><div style="font-weight:600;color:var(--wh);font-family:var(--m);font-size:12px">'+esc(b.bl)+'</div><div style="font-size:10px;color:var(--rd)">LISTED</div></div><a href="'+link+'" target="_blank" class="btn btn-sm btn-ac" style="font-size:10px">Delist</a></div>'}).join('')+'</div></div>':'')
+'<div class="card"><div class="card-h"><div class="card-t">Toutes les blacklists</div><button class="btn btn-sm btn-gh" onclick="recheckBL()">\u21bb Recheck</button></div>'
+'<table><thead><tr><th>Blacklist</th><th>Status</th><th>Action</th></tr></thead><tbody>'+bls.map(function(b){var link=delistLinks[b.bl]||'';return '<tr><td style="font-family:var(--m);font-size:11px">'+esc(b.bl)+'</td><td><span class="badge '+(b.listed?'b-err':'b-ok')+'">'+(b.listed?'LISTED':'Clean')+'</span></td><td>'+(b.listed?'<a href="'+(link||'#')+'" target="_blank" style="color:var(--ac);font-size:11px">Delist \u2192</a>':'<span style="color:var(--gn);font-size:11px">\u2713</span>')+'</td></tr>'}).join('')+'</tbody></table></div>';
};
window.recheckBL=async function(){toast('Rechecking...');try{await brg('blacklist');toast('Done');RR.delisting()}catch(e){toast('Err',1)}};
window.autoDelistAll=async function(){toast('Opening delist pages...');var bls=document.querySelectorAll('.card a[target=_blank]');bls.forEach(function(a){window.open(a.href,'_blank')});toast(bls.length+' pages opened')};
// =============== WHATSAPP BUSINESS ===============
RR.whatsapp=async()=>{
let st={};try{st=await(await fetch('/api/whatsapp-api.php?action=status')).json()}catch(e){}
$('C').innerHTML='<div class="stats"><div class="stat s-gn"><div class="st-l">WhatsApp</div><div class="st-v" style="font-size:16px;color:'+(st.has_token?'var(--gn)':'var(--ac)')+'">'+(st.has_token?'ACTIVE':'Config')+'</div></div><div class="stat s-ac"><div class="st-l">App ID</div><div class="st-v" style="font-size:12px">'+(st.app_id||'?')+'</div></div><div class="stat s-bl"><div class="st-l">Mode</div><div class="st-v" style="font-size:14px">'+(st.mode||'?')+'</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Envoyer un message WhatsApp</div><span class="badge '+(st.has_token?'b-ok':'b-warn')+'">'+(!st.has_token?'Token requis':'Ready')+'</span></div>'
+'<div class="row2"><div class="field"><label>Numero destinataire</label><input id="waTo" placeholder="+212600000000"></div><div class="field"><label>Message</label><textarea id="waMsg" rows="3" placeholder="Bonjour, voici votre confirmation...">Bonjour depuis WEVADS IA</textarea></div></div>'
+'<button class="btn btn-ac" style="margin-top:10px" onclick="sendWA()">Envoyer WhatsApp</button>'
+'<div id="waResult" style="margin-top:14px"></div></div>'
+'<div class="card"><div class="card-t">Configuration</div><div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
+'<div style="padding:12px;background:var(--bg);border-radius:var(--r3)"><div style="font-size:10px;color:var(--mu)">Phone Number ID</div><div style="font-family:var(--m);font-size:11px;color:var(--ac)">'+(st.phone||'?')+'</div></div>'
+'<div style="padding:12px;background:var(--bg);border-radius:var(--r3)"><div style="font-size:10px;color:var(--mu)">WABA ID</div><div style="font-family:var(--m);font-size:11px;color:var(--cy)">'+(st.waba_id||'?')+'</div></div>'
+'</div></div>'
+'<div class="card"><div class="card-t">Guide rapide</div><div style="display:grid;gap:6px;margin-top:8px">'
+'<div style="padding:8px 12px;background:var(--bg);border-radius:var(--r3);font-size:11px;border-left:3px solid var(--ac)"><strong>1.</strong> Generer token sur developers.facebook.com</div>'
+'<div style="padding:8px 12px;background:var(--bg);border-radius:var(--r3);font-size:11px;border-left:3px solid var(--cy)"><strong>2.</strong> Coller dans /opt/wevads/vault/whatsapp-config.json</div>'
+'<div style="padding:8px 12px;background:var(--bg);border-radius:var(--r3);font-size:11px;border-left:3px solid var(--gn)"><strong>3.</strong> Envoyer depuis cette page</div>'
+'</div></div>';
};
window.sendWA=async function(){
var to=document.getElementById('waTo')?.value||'';
var msg=document.getElementById('waMsg')?.value||'';
if(!to){toast('Numero requis',1);return}
toast('Envoi WhatsApp...');
try{var r=await(await fetch('/api/whatsapp-api.php?action=send&to='+encodeURIComponent(to)+'&message='+encodeURIComponent(msg))).json();
document.getElementById('waResult').innerHTML='<div style="padding:12px;background:var(--bg);border-radius:var(--r3);border-left:3px solid '+(r.ok?'var(--gn)':'var(--rd)')+'"><div style="font-weight:600;color:'+(r.ok?'var(--gn)':'var(--rd)')+'">'+(r.ok?'Envoye':'Erreur')+'</div><div style="font-family:var(--m);font-size:10px;color:var(--mu);margin-top:4px">'+JSON.stringify(r.response||r.error||'').substring(0,200)+'</div></div>';
}catch(e){toast('Erreur: '+e.message,1)}
};
// =============== AUTOMATION FLOW BUILDER ===============
RR.automation=async()=>{
let sq={};try{sq=await brg('sequence_list')}catch(e){}
let seqs=sq.sequences||[];
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Sequences</div><div class="st-v">'+seqs.length+'</div></div><div class="stat s-gn"><div class="st-l">Active</div><div class="st-v" style="color:var(--gn)">'+seqs.filter(function(s){return s.status==='active'}).length+'</div></div><div class="stat s-bl"><div class="st-l">Contacts en cours</div><div class="st-v">'+seqs.reduce(function(a,s){return a+(s.contacts||0)},0)+'</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Flow Builder</div><button class="btn btn-sm btn-ac" onclick="newFlow()">+ Nouveau Flow</button></div>'
+'<div id="flowCanvas" style="min-height:300px;background:var(--bg);border-radius:var(--r3);padding:20px;position:relative">'
+'<div style="text-align:center;padding:40px"><div style="display:inline-block;padding:12px 24px;background:var(--gn);color:#000;border-radius:20px;font-weight:700;font-size:13px;cursor:pointer" onclick="addFlowStep(\'trigger\')">+ Trigger</div>'
+'<div style="margin:20px 0;color:var(--mu)">|</div>'
+'<div style="display:inline-flex;gap:10px">'
+'<div style="padding:10px 20px;background:var(--ac);color:#000;border-radius:var(--r3);font-size:12px;cursor:pointer" onclick="addFlowStep(\'email\')">Email</div>'
+'<div style="padding:10px 20px;background:var(--cy);color:#000;border-radius:var(--r3);font-size:12px;cursor:pointer" onclick="addFlowStep(\'delay\')">Delay</div>'
+'<div style="padding:10px 20px;background:var(--pu);color:#fff;border-radius:var(--r3);font-size:12px;cursor:pointer" onclick="addFlowStep(\'condition\')">If/Else</div>'
+'<div style="padding:10px 20px;background:var(--gn);color:#000;border-radius:var(--r3);font-size:12px;cursor:pointer" onclick="addFlowStep(\'whatsapp\')">WhatsApp</div>'
+'<div style="padding:10px 20px;background:var(--or);color:#000;border-radius:var(--r3);font-size:12px;cursor:pointer" onclick="addFlowStep(\'sms\')">SMS</div>'
+'</div>'
+'<div style="margin:20px 0;color:var(--mu)">|</div>'
+'<div style="display:inline-block;padding:10px 20px;background:var(--rd);color:#fff;border-radius:20px;font-size:12px">End</div>'
+'</div></div></div>'
+'<div class="card"><div class="card-t">Sequences existantes</div>'
+'<table><thead><tr><th>Nom</th><th>Steps</th><th>Contacts</th><th>Status</th></tr></thead><tbody>'+seqs.map(function(s){return '<tr><td style="color:var(--wh);font-weight:600">'+esc(s.name||'')+'</td><td>'+esc(s.steps||0)+'</td><td>'+N(s.contacts||0)+'</td><td><span class="badge '+(s.status==='active'?'b-ok':'b-warn')+'">'+esc(s.status||'draft')+'</span></td></tr>'}).join('')+'</tbody></table></div>';
};
window.newFlow=function(){toast('Nouveau flow')};
window.addFlowStep=function(type){toast(type+' step added');var cv=document.getElementById('flowCanvas');if(cv){var d=document.createElement('div');d.style.cssText='display:inline-block;padding:8px 16px;margin:4px;border-radius:var(--r3);font-size:11px;cursor:move;border:1px solid var(--bd2)';d.style.background=type==='email'?'rgba(212,168,67,.15)':type==='delay'?'rgba(34,211,238,.15)':type==='condition'?'rgba(168,85,247,.15)':type==='whatsapp'?'rgba(52,211,153,.15)':'rgba(249,115,22,.15)';d.textContent=type;cv.querySelector('div')?.prepend(d)}};
// =============== CONTACT TIMELINE ===============
RR.timeline=async()=>{
let cs={};try{cs=await brg('contact_scoring')}catch(e){}
let af={};try{af=await brg('activity_feed')}catch(e){}
let feed=af.feed||[];
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Contacts scores</div><div class="st-v">'+N(cs.total||0)+'</div></div><div class="stat s-gn"><div class="st-l">Engages</div><div class="st-v" style="color:var(--gn)">'+N(cs.engaged||0)+'</div></div><div class="stat s-rd"><div class="st-l">A risque</div><div class="st-v" style="color:var(--rd)">'+N(cs.at_risk||0)+'</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Rechercher un contact</div></div><div class="field"><input id="tlSearch" placeholder="Email ou nom..." onkeyup="searchContact()"></div><div id="tlResult"></div></div>'
+'<div class="card"><div class="card-t">Activite recente</div><div style="position:relative;padding-left:30px;margin-top:16px">'+feed.slice(0,15).map(function(e,i){var color=e.type==='send'?'var(--ac)':e.type==='open'?'var(--gn)':e.type==='click'?'var(--cy)':e.type==='bounce'?'var(--rd)':'var(--mu)';return '<div style="position:relative;padding-bottom:20px"><div style="position:absolute;left:-22px;top:2px;width:12px;height:12px;border-radius:50%;background:'+color+'"></div>'+(i<feed.length-1?'<div style="position:absolute;left:-17px;top:14px;width:2px;height:calc(100% - 14px);background:var(--bd2)"></div>':'')+'<div style="font-size:12px;color:var(--wh)">'+esc(e.type||'event')+'</div><div style="font-size:10px;color:var(--mu)">'+esc(e.email||'')+'</div><div style="font-size:10px;color:var(--mu)">'+esc(e.date||e.ts||'')+'</div></div>'}).join('')+'</div></div>';
};
window.searchContact=function(){var q=document.getElementById('tlSearch')?.value||'';if(q.length<3)return;document.getElementById('tlResult').innerHTML='<div style="padding:10px;font-size:11px;color:var(--mu)">Recherche: '+esc(q)+'...</div>'};
// =============== EMAIL PREVIEW ISP ===============
RR.emailpreview=async()=>{
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Preview</div><div class="st-v" style="font-size:14px">Multi-ISP</div></div><div class="stat s-gn"><div class="st-l">Clients</div><div class="st-v">6</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Email Preview</div><button class="btn btn-sm btn-ac" onclick="runPreview()">Tester</button></div>'
+'<div class="field"><label>HTML email ou Template ID</label><textarea id="pvHTML" rows="6" style="font-family:var(--m);font-size:11px" placeholder="Collez votre HTML ici...">&lt;div style=&quot;max-width:600px;margin:0 auto&quot;&gt;&lt;h1&gt;Test Email&lt;/h1&gt;&lt;p&gt;Preview across ISPs&lt;/p&gt;&lt;/div&gt;</textarea></div>'
+'<div id="pvResult" style="margin-top:14px"><div style="display:grid;grid-template-columns:repeat(3,1fr);gap:12px">'
+['Gmail','Outlook','Yahoo','Apple Mail','Thunderbird','Samsung Mail'].map(function(isp){var colors={Gmail:'#ea4335',Outlook:'#0078d4',Yahoo:'#6001d2','Apple Mail':'#007aff',Thunderbird:'#0a84ff','Samsung Mail':'#1428a0'};return '<div style="background:var(--bg);border-radius:var(--r3);overflow:hidden"><div style="padding:8px 12px;background:'+(colors[isp]||'#666')+';font-size:11px;font-weight:600;color:#fff">'+isp+'</div><div style="height:200px;padding:10px;font-size:10px;color:var(--mu);overflow:hidden"><div style="background:#fff;border-radius:4px;height:100%;padding:8px;color:#333;font-size:9px">Preview area</div></div></div>'}).join('')
+'</div></div></div>';
};
window.runPreview=function(){var h=document.getElementById('pvHTML')?.value||'';if(!h){toast('HTML requis',1);return}var decoded=h.replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&quot;/g,'"');var frames=document.querySelectorAll('#pvResult div > div > div:last-child > div');frames.forEach(function(f){f.innerHTML=decoded});toast('Preview rendu sur 6 clients')};
// =============== RAG KNOWLEDGE SEARCH ===============
RR.ragsearch=async()=>{
let qi={};try{qi=await brg('qdrant')}catch(e){}
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">Qdrant</div><div class="st-v" style="font-size:14px">'+(qi.status||'?')+'</div></div><div class="stat s-gn"><div class="st-l">Vectors</div><div class="st-v">'+N(qi.vectors||0)+'</div></div><div class="stat s-bl"><div class="st-l">Collections</div><div class="st-v">'+N(qi.collections||0)+'</div></div></div>'
+'<div class="card"><div class="card-h"><div class="card-t">Recherche Knowledge Base</div><button class="btn btn-sm btn-ac" onclick="ragSearch()">Chercher</button></div>'
+'<div class="field"><input id="ragQ" placeholder="Rechercher dans la base de connaissances..." style="font-size:14px"></div>'
+'<div id="ragResults" style="margin-top:14px"></div></div>';
};
window.ragSearch=async function(){var q=document.getElementById('ragQ')?.value||'';if(!q){toast('Query requis',1);return}toast('Recherche RAG...');try{var r=await brg('qdrant_search',{query:q});var hits=r.results||[];document.getElementById('ragResults').innerHTML=hits.length?hits.map(function(h){return '<div style="padding:12px;background:var(--bg);border-radius:var(--r3);margin-bottom:8px;border-left:3px solid var(--ac)"><div style="font-size:12px;color:var(--wh)">'+esc(h.text||h.payload?.text||'')+'</div><div style="font-size:10px;color:var(--mu);margin-top:4px">Score: '+(h.score||0).toFixed(3)+'</div></div>'}).join(''):'<div style="color:var(--mu);font-size:12px">Aucun resultat</div>'}catch(e){toast('Err: '+e.message,1)}};
// =============== AI COPYWRITER ===============
RR.aicopy=async()=>{
let m={};try{m=await brg('ollama_models')}catch(e){}
$('C').innerHTML='<div class="stats"><div class="stat s-ac"><div class="st-l">AI Copywriter</div><div class="st-v" style="font-size:14px">WEVIA</div></div><div class="stat s-gn"><div class="st-l">Modeles</div><div class="st-v">'+(m.models?.length||0)+'</div></div><div class="stat s-bl"><div class="st-l">Souverain</div><div class="st-v" style="font-size:14px;color:var(--gn)">100%</div></div></div>'
+'<div class="row2"><div class="card"><div class="card-h"><div class="card-t">Generer du contenu</div><button class="btn btn-sm btn-ac" onclick="aiGenerate()">Generer</button></div>'
+'<div class="field"><label>Type de contenu</label><select id="aiType" style="width:100%;padding:10px;background:var(--bg);color:var(--wh);border:1px solid var(--bd2);border-radius:var(--r3)"><option value="subject">Sujet email</option><option value="body">Corps email</option><option value="cta">Call-to-action</option><option value="landing">Texte landing page</option><option value="whatsapp">Message WhatsApp</option><option value="sms">SMS</option></select></div>'
+'<div class="field"><label>Contexte / Brief</label><textarea id="aiBrief" rows="3" placeholder="Produit pharma, cible cardiologues Tunisie, ton professionnel...">Ethica: plateforme B2B pharma pour professionnels de sante en Afrique du Nord. Cible: cardiologues. Objectif: inscription.</textarea></div>'
+'<div class="field"><label>Ton</label><div style="display:flex;gap:8px;flex-wrap:wrap">'
+['Professionnel','Amical','Urgent','Informatif','Premium'].map(function(t){return '<label style="display:flex;align-items:center;gap:4px;font-size:11px;cursor:pointer"><input type="radio" name="aiTone" value="'+t.toLowerCase()+'"'+(t==='Professionnel'?' checked':'')+'>'+t+'</label>'}).join('')
+'</div></div>'
+'<div id="aiResult" style="margin-top:14px"></div></div>'
+'<div class="card"><div class="card-t">Historique generations</div><div id="aiHistory" style="font-size:11px;color:var(--mu)">Aucune generation</div></div></div>';
};
window.aiGenerate=async function(){var type=document.getElementById('aiType')?.value||'subject';var brief=document.getElementById('aiBrief')?.value||'';var tone=document.querySelector('input[name=aiTone]:checked')?.value||'professionnel';if(!brief){toast('Brief requis',1);return}toast('Generation IA...');try{var r=await brg('ollama_generate',{prompt:'Generate 5 '+type+' options. Tone: '+tone+'. Context: '+brief+'. Output as numbered list.',model:'qwen3:8b'});var txt=r.response||r.text||JSON.stringify(r);document.getElementById('aiResult').innerHTML='<div style="padding:16px;background:var(--bg);border-radius:var(--r3);border:1px solid var(--ac)"><div style="font-size:11px;font-weight:600;color:var(--ac);margin-bottom:8px">Resultats IA ('+type+')</div><div style="white-space:pre-wrap;font-size:12px;color:var(--wh);line-height:1.6">'+esc(txt)+'</div></div>'}catch(e){document.getElementById('aiResult').innerHTML='<div style="padding:12px;background:var(--bg);border-radius:var(--r3);color:var(--rd)">Erreur: '+esc(e.message)+'</div>'}};
// =============== INIT ===============
TK='admin-'+Date.now();U={id:1,email:'yacineutt@gmail.com',name:'Yacine WEVAL',company:'WEVAL Consulting',plan:'admin',credits:99999};enter();
fetch(API+'/health').then(r=>r.json()).then(j=>{if(j.status==='ok')$('TL').innerHTML='● Live — '+j.version}).catch(()=>{});
if(document.readyState==="loading"){document.addEventListener("DOMContentLoaded",function(){})}else{}
</script><div id="M" style="display:none"></div><script src="whatsapp.js"></script>
<script>
// WhatsApp Channel Activation — 2Apr2026
(function(){
// Enable WA pill in sidebar
document.querySelectorAll('[data-c=whatsapp],[data-c=wa]').forEach(el=>{
el.style.opacity='1';
el.style.pointerEvents='auto';
el.classList.remove('dis');
});
// Enable SMS pill
document.querySelectorAll('[data-c=sms]').forEach(el=>{
el.style.opacity='1';
el.style.pointerEvents='auto';
el.classList.remove('dis');
});
// Update canaux count
document.querySelectorAll('.st-l').forEach(el=>{
if(el.textContent.includes('Email+TG')) el.textContent='Email+WA+SMS+TG';
});
// WhatsApp API config
window.WEVAL_WA_CONFIG={
api:'/api/whatsapp-api.php',
phone_id:'108180295167719',
business_id:'208358856887298',
enabled:true,
mode:'live'
};
console.log('[WEVADS] WhatsApp+SMS channels ACTIVATED');
})();
RR.scraping=async()=>{let d={};try{d=await(await fetch('/api/wevads-p1-api.php?action=scrapers&token=WEVADS2026')).json()}catch(e){}
const src=d.sources||[];const sc=d.scrapers||[];const N=n=>n?n.toLocaleString():'0';
$('C').innerHTML='<div class="stats">'+[['Total Records',N(d.total_records),'all sources','var(--ac)'],['Crons',d.crons?.total||0,'active','var(--gn)'],['HCP',N(src[0]?.count),'pharma','var(--pu)'],['B2B',N((src[1]?.count||0)+(src[2]?.count||0)+(src[3]?.count||0)),'leads','var(--cy)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t" style="margin-bottom:10px">Data Sources</div><table style="width:100%;font-size:12px;border-collapse:collapse">'+src.map(function(s){return'<tr style="border-bottom:1px solid var(--bd)"><td style="padding:8px 4px;font-weight:500">'+s.name+'</td><td style="font-family:var(--m);color:var(--ac)">'+N(s.count)+'</td><td><span style="background:var(--sf);padding:2px 8px;border-radius:4px;font-size:10px">'+s.type+'</span></td></tr>'}).join('')+'</table></div><div class="card"><div class="card-t" style="margin-bottom:10px">Scraper Status</div>'+sc.map(function(s){return'<div style="display:flex;align-items:center;gap:8px;padding:6px 0;border-bottom:1px solid var(--bd)"><div style="width:8px;height:8px;border-radius:50%;background:'+(s.active?'var(--gn)':'var(--mu)')+'"></div><div><div style="font-size:12px;font-weight:500">'+s.name+'</div><div style="font-size:10px;color:var(--mu)">'+(s.last_run||'never')+'</div></div></div>'}).join('')+'</div></div>'};
RR.consent=async()=>{let d={};try{d=await(await fetch('/api/wevads-p1-api.php?action=consent&token=WEVADS2026')).json()}catch(e){}
const N=n=>n?n.toLocaleString():'0';
$('C').innerHTML='<div class="stats">'+[['Tokens',N(d.total_tokens),'total','var(--ac)'],['In',N(d.opted_in),d.consent_rate+'%','var(--gn)'],['Out',N(d.opted_out),'rejected','var(--rd)'],['Pending',N(d.pending),'wait','var(--yw)'],['Unsubs',N(d.unsub_requests),'req','var(--mu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Consent GDPR</div><div style="padding:16px;text-align:center"><div style="font-size:12px;color:var(--mu);margin-bottom:12px">Regions: '+(d.regions||[]).join(", ")+'</div><button class="btn btn-sm btn-ac" onclick="window.open(\'https://consent.wevup.app\')">Open Consent Portal</button></div></div><div class="card"><div class="card-t">Activity</div><div style="color:var(--mu);font-size:12px;padding:20px;text-align:center">'+(d.total_logs>0?d.total_logs+' events':'Deploy consent forms to collect')+'</div></div></div>'};
RR.bouncemanager=async()=>{let d={};try{d=await(await fetch('/api/wevads-p1-api.php?action=bounces&token=WEVADS2026')).json()}catch(e){}
const N=n=>n?n.toLocaleString():'0';const isp=d.by_isp||[];
const m={};isp.forEach(function(b){if(!m[b.isp])m[b.isp]={h:0,s:0,t:0};m[b.isp][b.type==='hard'?'h':'s']+=(+b.cnt||0);m[b.isp].t+=(+b.cnt||0)});
const a=Object.entries(m).sort(function(x,y){return y[1].t-x[1].t});
$('C').innerHTML='<div class="stats">'+[['Total',N(d.total),'bounces','var(--rd)'],['Hard',N(d.hard),'perm','var(--rd)'],['Soft',N(d.soft),'temp','var(--yw)'],['Rate',d.bounce_rate+'%','of '+N(d.sent_total),'var(--ac)'],['7d',N(d.recent_7d),'recent','var(--cy)']].map(function(x){return'<div class="stat" style="border-top:3px solid '+x[3]+'"><div class="st-l">'+x[0]+'</div><div class="st-v">'+x[1]+'</div><div style="font-size:10px;color:var(--mu)">'+x[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t" style="margin-bottom:10px">By ISP</div>'+(a.length?a.map(function(x){return'<div style="margin-bottom:8px"><div style="display:flex;justify-content:space-between;font-size:12px"><span style="font-weight:500">'+x[0]+'</span><span style="font-family:var(--m)"><span style="color:var(--rd)">'+x[1].h+'H</span> <span style="color:var(--yw)">'+x[1].s+'S</span></span></div><div style="height:5px;background:var(--sf);border-radius:3px;margin-top:3px"><div style="height:100%;width:'+(d.total>0?(x[1].t/d.total*100):0)+'%;background:var(--rd);border-radius:3px"></div></div></div>'}).join(''):'<div style="color:var(--gn);text-align:center;padding:16px">Clean</div>')+'</div><div class="card"><div class="card-t">Recent</div>'+(d.recent||[]).slice(0,10).map(function(r){return'<div style="font-size:11px;padding:4px 0;border-bottom:1px solid var(--bd)">'+r.email+' <span style="color:var(--mu)">['+r.type+']</span></div>'}).join('')+'</div></div>'};
RR.o365cmd=async()=>{let d={};try{d=await(await fetch('/api/wevads-p2-api.php?action=o365&token=WEVADS2026')).json()}catch(e){}
const N=n=>n?n.toLocaleString():'0';const st=d.by_status||[];
$('C').innerHTML='<div class="stats">'+[['Total',N(d.total),'O365','var(--ac)']].concat(st.map(function(s){var c=s.status==='Active'?'var(--gn)':s.status==='Blocked'?'var(--rd)':'var(--mu)';return[s.status,s.cnt,'',c]})).map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Tenants</div>'+(d.tenants||[]).map(function(t){return'<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd);font-size:12px"><span>'+t.tenant+'</span><span style="color:var(--mu)">'+t.cnt+' '+t.status+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Graph API</div>'+(d.graph||[]).map(function(g){return'<div style="padding:8px 0;font-size:13px">can_send='+(g.can_send?'true':'false')+' = '+g.cnt+'</div>'}).join('')+'</div></div>'};
RR.dnsmanager=async()=>{let d={};try{d=await(await fetch('/api/wevads-p2-api.php?action=dns&token=WEVADS2026')).json()}catch(e){}
$('C').innerHTML='<div class="stats">'+[['Domain',d.domain||'','primary','var(--ac)'],['Score',d.score+'/100','','var(--gn)'],['SPF',d.spf?.ok?'Pass':'Fail','','var(--'+(d.spf?.ok?'gn':'rd')+')'],['DKIM',d.dkim?.ok?'Pass':'Fail','','var(--'+(d.dkim?.ok?'gn':'rd')+')'],['DMARC',d.dmarc?.ok?'Pass':'Fail','','var(--'+(d.dmarc?.ok?'gn':'rd')+')']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Records</div><div style="font-size:11px"><div style="padding:6px 0"><b>SPF:</b> '+(d.spf?.value||'N/A')+'</div><div style="padding:6px 0"><b>DMARC:</b> '+(d.dmarc?.value||'N/A')+'</div><div style="padding:6px 0"><b>MX:</b> '+(d.mx||[]).map(function(m){return m.host}).join(", ")+'</div></div></div><div class="card"><div class="card-t">Domains</div>'+(d.available_domains||[]).map(function(dm){return'<button class="btn btn-sm btn-gh" style="margin:3px" onclick="checkDNS(\''+dm+'\')">'+dm+'</button>'}).join('')+'</div></div>'};
window.checkDNS=async function(dm){toast('Check '+dm);RR.dnsmanager()};
RR.datavalidation=async()=>{let d={};try{d=await(await fetch('/api/wevads-p2-api.php?action=validation&token=WEVADS2026')).json()}catch(e){}
const N=n=>n?n.toLocaleString():'0';const co=d.by_country||[];
$('C').innerHTML='<div class="stats">'+[['Records',N(d.total),'contacts','var(--ac)'],['Email',d.email_rate+'%',N(d.with_email),'var(--gn)'],['Verified',d.verify_rate+'%',N(d.verified),'var(--pu)'],['Quality',d.quality_score+'%','score','var(--cy)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">By Country</div>'+co.map(function(c){var p=c.total>0?((c.emails/c.total)*100).toFixed(0):0;return'<div style="margin-bottom:10px"><div style="display:flex;justify-content:space-between;font-size:12px"><span style="font-weight:500">'+(c.country||'?')+'</span><span style="font-family:var(--m)">'+N(c.total)+'</span></div><div style="height:5px;background:var(--sf);border-radius:3px;margin-top:3px"><div style="height:100%;width:'+p+'%;background:var(--gn);border-radius:3px"></div></div></div>'}).join('')+'</div><div class="card"><div class="card-t">Sources</div><div style="font-size:12px;padding:8px 0">Send Contacts: '+N(d.other_sources?.send_contacts||0)+'</div><div style="font-size:12px">WEVAL Leads: '+N(d.other_sources?.weval_leads||0)+'</div></div></div>'};
RR.trackingdash=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=tracking&token=WEVADS2026')).json()}catch(e){}
const N=n=>n?n.toLocaleString():'0';
$('C').innerHTML='<div class="stats">'+[['Events',N(d.total),'all time','var(--ac)'],['Opens',N(d.opens),'tracked','var(--gn)'],['Clicks',N(d.clicks),'tracked','var(--cy)'],['Unsubs',N(d.unsubs),'requests','var(--rd)'],['Today',N(d.today),'events','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">7-Day Activity</div>'+(d.by_day||[]).map(function(r){var w=d.total>0?Math.max(5,Math.min(100,(r.cnt/Math.max.apply(null,(d.by_day||[]).map(function(x){return x.cnt}))*100))):5;return'<div style="display:flex;align-items:center;gap:8px;padding:4px 0"><span style="font-size:10px;color:var(--mu);min-width:70px">'+(r.day||'').substr(5)+'</span><div style="height:8px;background:var(--ac);border-radius:4px;width:'+w+'%"></div><span style="font-size:10px;font-family:var(--m)">'+r.cnt+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Live Feed</div><div style="max-height:250px;overflow-y:auto">'+(d.recent||[]).map(function(r){var c=r.event_type==='open'?'var(--gn)':r.event_type==='click'?'var(--cy)':'var(--rd)';return'<div style="display:flex;gap:6px;padding:4px 0;border-bottom:1px solid var(--bd);font-size:11px"><span style="width:8px;height:8px;border-radius:50%;margin-top:3px;background:'+c+'"></span><span style="font-weight:500">'+r.event_type+'</span><span style="color:var(--mu);flex:1">'+r.tracking_id+'</span><span style="color:var(--mu);font-size:10px">'+(r.created_at||'').substr(11,5)+'</span></div>'}).join('')+'</div></div></div>'};
RR.serversupervision=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=servers&token=WEVADS2026')).json()}catch(e){}
$('C').innerHTML='<div class="stats">'+[['S204','Primary','nginx+docker','var(--ac)'],['S95','WEVADS','apache+pmta','var(--gn)'],['S151','Tracking','nginx+ollama','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2">'+['s204','s95','s151'].map(function(s){var sv=d[s]||{};return'<div class="card"><div class="card-t">'+s.toUpperCase()+'</div><div style="display:flex;flex-wrap:wrap;gap:4px;margin-top:8px">'+(sv.services||[]).map(function(svc){return'<span style="font-size:10px;padding:3px 8px;background:var(--sf);border-radius:4px">'+svc+'</span>'}).join('')+'</div>'+(s==='s204'?'<div style="margin-top:8px;font-size:11px;color:var(--mu)">Docker: '+sv.docker+' | Disk: '+sv.disk+' | '+sv.uptime+'</div>':'')+'</div>'}).join('')+'</div>'};
RR.securitymon=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=security&token=WEVADS2026')).json()}catch(e){}
var cs=d.crowdsec||{};var f2b=d.fail2ban||{};var sh=d.ssh||{};
$('C').innerHTML='<div class="stats">'+[['CrowdSec',cs.alerts_count||0,'alerts','var(--ac)'],['Fail2Ban',f2b.banned||0,'banned IPs','var(--rd)'],['SSH Fails',sh.failed_attempts||0,'attempts','var(--yw)'],['Protected',d.chattr_protected||0,'files chattr','var(--gn)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">CrowdSec Alerts</div>'+(cs.recent_alerts||[]).slice(0,5).map(function(a){return'<div style="padding:5px 0;border-bottom:1px solid var(--bd);font-size:11px">'+(a.source?.ip||a.message||'alert')+'</div>'}).join('')+'</div><div class="card"><div class="card-t">Fail2Ban</div><div style="font-size:12px;padding:8px 0">Jails: '+(f2b.jails||'none')+'</div><div style="font-size:12px">Currently banned: '+(f2b.banned||0)+'</div></div></div>'};
RR.smsgateway=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=sms&token=WEVADS2026')).json()}catch(e){}
var ch=d.channels||{};
$('C').innerHTML='<div class="stats">'+[['SMS',ch.sms?'Active':'Off','provider','var(--gn)'],['WhatsApp',ch.whatsapp?'Active':'Expired','token','var(--rd)'],['Telegram',ch.telegram?'Active':'Off','bot','var(--ac)'],['Sent',d.sent_total||0,'total SMS','var(--pu)'],['Campaigns',d.campaigns||0,'SMS','var(--cy)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">SMS Providers</div>'+(d.providers||[]).map(function(p){return'<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd);font-size:12px"><span style="font-weight:500">'+(p.name||p.provider||'Provider '+p.id)+'</span><span style="color:var(--mu)">sent_today: '+(p.sent_today||0)+'/'+(p.daily_limit||'?')+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Channel Status</div><div style="font-size:12px;padding:8px"><div style="margin-bottom:6px">WA: '+(d.wa_status||'?')+'</div><div>TG Bot: '+(d.tg_bot||'N/A')+'</div></div></div></div>'};
RR.trackingdash=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=tracking&token=WEVADS2026')).json()}catch(e){}
const N=n=>n?n.toLocaleString():'0';
$('C').innerHTML='<div class="stats">'+[['Events',N(d.total),'all time','var(--ac)'],['Opens',N(d.opens),'tracked','var(--gn)'],['Clicks',N(d.clicks),'tracked','var(--cy)'],['Unsubs',N(d.unsubs),'requests','var(--rd)'],['Today',N(d.today),'events','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">7-Day Activity</div>'+(d.by_day||[]).map(function(r){var w=d.total>0?Math.max(5,Math.min(100,(r.cnt/Math.max.apply(null,(d.by_day||[]).map(function(x){return x.cnt}))*100))):5;return'<div style="display:flex;align-items:center;gap:8px;padding:4px 0"><span style="font-size:10px;color:var(--mu);min-width:70px">'+(r.day||'').substr(5)+'</span><div style="height:8px;background:var(--ac);border-radius:4px;width:'+w+'%"></div><span style="font-size:10px;font-family:var(--m)">'+r.cnt+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Live Feed</div><div style="max-height:250px;overflow-y:auto">'+(d.recent||[]).map(function(r){var c=r.event_type==='open'?'var(--gn)':r.event_type==='click'?'var(--cy)':'var(--rd)';return'<div style="display:flex;gap:6px;padding:4px 0;border-bottom:1px solid var(--bd);font-size:11px"><span style="width:8px;height:8px;border-radius:50%;margin-top:3px;background:'+c+'"></span><span style="font-weight:500">'+r.event_type+'</span><span style="color:var(--mu);flex:1">'+r.tracking_id+'</span><span style="color:var(--mu);font-size:10px">'+(r.created_at||'').substr(11,5)+'</span></div>'}).join('')+'</div></div></div>'};
RR.serversupervision=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=servers&token=WEVADS2026')).json()}catch(e){}
$('C').innerHTML='<div class="stats">'+[['S204','Primary','nginx+docker','var(--ac)'],['S95','WEVADS','apache+pmta','var(--gn)'],['S151','Tracking','nginx+ollama','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2">'+['s204','s95','s151'].map(function(s){var sv=d[s]||{};return'<div class="card"><div class="card-t">'+s.toUpperCase()+'</div><div style="display:flex;flex-wrap:wrap;gap:4px;margin-top:8px">'+(sv.services||[]).map(function(svc){return'<span style="font-size:10px;padding:3px 8px;background:var(--sf);border-radius:4px">'+svc+'</span>'}).join('')+'</div>'+(s==='s204'?'<div style="margin-top:8px;font-size:11px;color:var(--mu)">Docker: '+sv.docker+' | Disk: '+sv.disk+' | '+sv.uptime+'</div>':'')+'</div>'}).join('')+'</div>'};
RR.securitymon=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=security&token=WEVADS2026')).json()}catch(e){}
var cs=d.crowdsec||{};var f2b=d.fail2ban||{};var sh=d.ssh||{};
$('C').innerHTML='<div class="stats">'+[['CrowdSec',cs.alerts_count||0,'alerts','var(--ac)'],['Fail2Ban',f2b.banned||0,'banned IPs','var(--rd)'],['SSH Fails',sh.failed_attempts||0,'attempts','var(--yw)'],['Protected',d.chattr_protected||0,'files chattr','var(--gn)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">CrowdSec Alerts</div>'+(cs.recent_alerts||[]).slice(0,5).map(function(a){return'<div style="padding:5px 0;border-bottom:1px solid var(--bd);font-size:11px">'+(a.source?.ip||a.message||'alert')+'</div>'}).join('')+'</div><div class="card"><div class="card-t">Fail2Ban</div><div style="font-size:12px;padding:8px 0">Jails: '+(f2b.jails||'none')+'</div><div style="font-size:12px">Currently banned: '+(f2b.banned||0)+'</div></div></div>'};
RR.smsgateway=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=sms&token=WEVADS2026')).json()}catch(e){}
var ch=d.channels||{};
$('C').innerHTML='<div class="stats">'+[['SMS',ch.sms?'Active':'Off','provider','var(--gn)'],['WhatsApp',ch.whatsapp?'Active':'Expired','token','var(--rd)'],['Telegram',ch.telegram?'Active':'Off','bot','var(--ac)'],['Sent',d.sent_total||0,'total SMS','var(--pu)'],['Campaigns',d.campaigns||0,'SMS','var(--cy)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">SMS Providers</div>'+(d.providers||[]).map(function(p){return'<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd);font-size:12px"><span style="font-weight:500">'+(p.name||p.provider||'Provider '+p.id)+'</span><span style="color:var(--mu)">sent_today: '+(p.sent_today||0)+'/'+(p.daily_limit||'?')+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Channel Status</div><div style="font-size:12px;padding:8px"><div style="margin-bottom:6px">WA: '+(d.wa_status||'?')+'</div><div>TG Bot: '+(d.tg_bot||'N/A')+'</div></div></div></div>'};
RR.trackingdash=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=tracking&token=WEVADS2026')).json()}catch(e){}
const N=n=>n?n.toLocaleString():'0';
$('C').innerHTML='<div class="stats">'+[['Events',N(d.total),'all time','var(--ac)'],['Opens',N(d.opens),'tracked','var(--gn)'],['Clicks',N(d.clicks),'tracked','var(--cy)'],['Unsubs',N(d.unsubs),'requests','var(--rd)'],['Today',N(d.today),'events','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">7-Day Activity</div>'+(d.by_day||[]).map(function(r){var w=d.total>0?Math.max(5,Math.min(100,(r.cnt/Math.max.apply(null,(d.by_day||[]).map(function(x){return x.cnt}))*100))):5;return'<div style="display:flex;align-items:center;gap:8px;padding:4px 0"><span style="font-size:10px;color:var(--mu);min-width:70px">'+(r.day||'').substr(5)+'</span><div style="height:8px;background:var(--ac);border-radius:4px;width:'+w+'%"></div><span style="font-size:10px;font-family:var(--m)">'+r.cnt+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Live Feed</div><div style="max-height:250px;overflow-y:auto">'+(d.recent||[]).map(function(r){var c=r.event_type==='open'?'var(--gn)':r.event_type==='click'?'var(--cy)':'var(--rd)';return'<div style="display:flex;gap:6px;padding:4px 0;border-bottom:1px solid var(--bd);font-size:11px"><span style="width:8px;height:8px;border-radius:50%;margin-top:3px;background:'+c+'"></span><span style="font-weight:500">'+r.event_type+'</span><span style="color:var(--mu);flex:1">'+r.tracking_id+'</span><span style="color:var(--mu);font-size:10px">'+(r.created_at||'').substr(11,5)+'</span></div>'}).join('')+'</div></div></div>'};
RR.serversupervision=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=servers&token=WEVADS2026')).json()}catch(e){}
$('C').innerHTML='<div class="stats">'+[['S204','Primary','nginx+docker','var(--ac)'],['S95','WEVADS','apache+pmta','var(--gn)'],['S151','Tracking','nginx+ollama','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2">'+['s204','s95','s151'].map(function(s){var sv=d[s]||{};return'<div class="card"><div class="card-t">'+s.toUpperCase()+'</div><div style="display:flex;flex-wrap:wrap;gap:4px;margin-top:8px">'+(sv.services||[]).map(function(svc){return'<span style="font-size:10px;padding:3px 8px;background:var(--sf);border-radius:4px">'+svc+'</span>'}).join('')+'</div>'+(s==='s204'?'<div style="margin-top:8px;font-size:11px;color:var(--mu)">Docker: '+sv.docker+' | Disk: '+sv.disk+' | '+sv.uptime+'</div>':'')+'</div>'}).join('')+'</div>'};
RR.securitymon=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=security&token=WEVADS2026')).json()}catch(e){}
var cs=d.crowdsec||{};var f2b=d.fail2ban||{};var sh=d.ssh||{};
$('C').innerHTML='<div class="stats">'+[['CrowdSec',cs.alerts_count||0,'alerts','var(--ac)'],['Fail2Ban',f2b.banned||0,'banned IPs','var(--rd)'],['SSH Fails',sh.failed_attempts||0,'attempts','var(--yw)'],['Protected',d.chattr_protected||0,'files chattr','var(--gn)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">CrowdSec Alerts</div>'+(cs.recent_alerts||[]).slice(0,5).map(function(a){return'<div style="padding:5px 0;border-bottom:1px solid var(--bd);font-size:11px">'+(a.source?.ip||a.message||'alert')+'</div>'}).join('')+'</div><div class="card"><div class="card-t">Fail2Ban</div><div style="font-size:12px;padding:8px 0">Jails: '+(f2b.jails||'none')+'</div><div style="font-size:12px">Currently banned: '+(f2b.banned||0)+'</div></div></div>'};
RR.smsgateway=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=sms&token=WEVADS2026')).json()}catch(e){}
var ch=d.channels||{};
$('C').innerHTML='<div class="stats">'+[['SMS',ch.sms?'Active':'Off','provider','var(--gn)'],['WhatsApp',ch.whatsapp?'Active':'Expired','token','var(--rd)'],['Telegram',ch.telegram?'Active':'Off','bot','var(--ac)'],['Sent',d.sent_total||0,'total SMS','var(--pu)'],['Campaigns',d.campaigns||0,'SMS','var(--cy)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">SMS Providers</div>'+(d.providers||[]).map(function(p){return'<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd);font-size:12px"><span style="font-weight:500">'+(p.name||p.provider||'Provider '+p.id)+'</span><span style="color:var(--mu)">sent_today: '+(p.sent_today||0)+'/'+(p.daily_limit||'?')+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Channel Status</div><div style="font-size:12px;padding:8px"><div style="margin-bottom:6px">WA: '+(d.wa_status||'?')+'</div><div>TG Bot: '+(d.tg_bot||'N/A')+'</div></div></div></div>'};
RR.serversup=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=servers&token=WEVADS2026')).json()}catch(e){}
const sv=d.servers||[];
$('C').innerHTML='<div class="stats">'+sv.map(function(s){var c=s.status==='UP'?'var(--gn)':'var(--rd)';return'<div class="stat" style="border-top:3px solid '+c+'"><div class="st-l">'+s.name+'</div><div class="st-v">'+s.status+'</div><div style="font-size:10px;color:var(--mu)">'+(s.disk||'')+(s.memory?' | '+s.memory:'')+'</div></div>'}).join('')+'</div><div class="row2">'+sv.map(function(s){return'<div class="card"><div class="card-t">'+s.name+'</div><div style="font-size:12px;padding:8px 0"><div>IP: <span style="font-family:var(--m);color:var(--ac)">'+s.ip+'</span></div>'+(s.load?'<div>Load: '+s.load+'</div>':'')+(s.docker?'<div>Docker: '+s.docker+' containers</div>':'')+(s.services?'<div>Services: '+s.services+' running</div>':'')+(s.uptime?'<div>Uptime: '+s.uptime+'</div>':'')+'</div></div>'}).join('')+'</div>'};
RR.cronctl=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=crons&token=WEVADS2026')).json()}catch(e){}
$('C').innerHTML='<div class="stats">'+[['Active',d.total_active||0,'crons','var(--gn)'],['Monitoring',d.monitoring||0,'read-only','var(--ac)'],['Scraping',d.scraping||0,'data collection','var(--pu)'],['Send Disabled',d.total_disabled||0,'blocked','var(--rd)'],['Other',d.other||0,'system','var(--mu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Architecture</div><div style="font-size:12px;padding:8px"><div style="margin-bottom:8px"><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:var(--gn);margin-right:6px"></span>Monitoring: brain check, score, harvester, seeds, bounces</div><div style="margin-bottom:8px"><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:var(--pu);margin-right:6px"></span>Scraping: ethica, linkedin, gmap, 1sante, dabadoc</div><div><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:var(--rd);margin-right:6px"></span>Disabled: brain send, pipeline full, warmup execute, ethica send</div></div></div></div>'};
RR.trackinglive=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=tracking&token=WEVADS2026')).json()}catch(e){}
const N=n=>n?n.toLocaleString():'0';const ev=d.by_type||[];const ep=d.endpoints||[];const rc=d.recent||[];
$('C').innerHTML='<div class="stats"><div class="stat" style="border-top:3px solid var(--ac)"><div class="st-l">Total Events</div><div class="st-v">'+N(d.total_events)+'</div></div>'+ev.map(function(e){var c=e.event_type==='click'?'var(--gn)':e.event_type==='open'?'var(--ac)':'var(--mu)';return'<div class="stat" style="border-top:3px solid '+c+'"><div class="st-l">'+e.event_type+'</div><div class="st-v">'+N(e.cnt)+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Endpoints Health</div>'+ep.map(function(e){return'<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd);font-size:12px"><span>'+e.name+'</span><span style="color:var(--'+(e.status==='UP'?'gn':'rd')+')">'+e.status+' ('+e.code+')</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Recent Events</div><div style="max-height:250px;overflow-y:auto">'+rc.map(function(r){return'<div style="font-size:11px;padding:4px 0;border-bottom:1px solid var(--bd)"><span style="color:var(--ac)">'+r.event_type+'</span> '+r.tracking_id+' <span style="color:var(--mu)">'+((r.created_at||'').substr(0,16))+'</span></div>'}).join('')+'</div></div></div>'};
RR.smtptest=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=smtptest&token=WEVADS2026')).json()}catch(e){}
const bl=d.reputation?.details||[];
$('C').innerHTML='<div class="stats">'+[['Domain',d.domain||'','primary','var(--ac)'],['Auth',d.auth_score+'/100','SPF+DKIM+DMARC','var(--gn)'],['Reputation',d.reputation?.clean+'/'+d.reputation?.total,'blacklists','var(--'+(d.reputation?.listed>0?'rd':'gn')+')'],['Deliverability',d.deliverability_score+'%','composite','var(--cy)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Blacklist Status</div>'+bl.map(function(b){return'<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd);font-size:12px"><span>'+b.bl+'</span><span style="color:var(--'+(b.listed?'rd':'gn')+')">'+(!b.listed?'CLEAN':'LISTED')+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Auth Details</div><div style="font-size:12px"><div style="padding:6px 0">SPF: <span style="color:var(--'+(d.spf?'gn':'rd')+')">'+(!d.spf?'FAIL':'PASS')+'</span></div><div style="padding:6px 0">DKIM: <span style="color:var(--'+(d.dkim?'gn':'rd')+')">'+(!d.dkim?'FAIL':'PASS')+'</span></div><div style="padding:6px 0">DMARC: <span style="color:var(--'+(d.dmarc?'gn':'rd')+')">'+(!d.dmarc?'FAIL':'PASS')+'</span></div><div style="padding:6px 0">MX: '+(d.mx||[]).join(', ')+'</div></div></div></div>'};
RR.securitymon=async()=>{let d={};try{d=await(await fetch('/api/wevads-p3-api.php?action=security&token=WEVADS2026')).json()}catch(e){}
const g=d.guards||[];
$('C').innerHTML='<div class="stats">'+[['Disk',d.disk||'?','S204','var(--ac)'],['Fail2Ban',d.fail2ban_jails||0,'jails','var(--gn)'],['CrowdSec',d.crowdsec_alerts||0,'alerts','var(--pu)'],['SSL',d.ssl_expiry?.substr(0,11)||'?','expiry','var(--cy)'],['Encryption',d.encryption?.cols||0,'columns AES','var(--yw)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Guards</div>'+g.map(function(x){return'<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd);font-size:12px"><span>'+x.name+'</span><span style="color:var(--yw)">'+x.mode+'</span><span style="color:var(--mu)">'+x.server+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Status</div><div style="font-size:12px"><div style="padding:6px 0">chattr protected: <span style="color:var(--'+(d.chattr_protected?'gn':'rd')+')">'+(!d.chattr_protected?'NO':'YES')+'</span></div><div style="padding:6px 0">PostgreSQL: <span style="color:var(--gn)">'+(!d.pg_hardened?'DEFAULT':'HARDENED (md5+SSL)')+'</span></div><div style="padding:6px 0">MTA: <span style="color:var(--gn)">'+(d.mta_status||'?')+'</span></div></div></div></div>'};
RR.webhookmgr=async()=>{let d={};try{d=await(await fetch('/api/wevads-p4-api.php?action=webhooks&token=WEVADS2026')).json()}catch(e){}
const ep=d.endpoints||[];const ev=d.tracking_events||[];const N=n=>n?n.toLocaleString():'0';
$('C').innerHTML='<div class="stats">'+[['Endpoints',ep.length,'webhooks','var(--ac)'],['Events',N(ev.reduce(function(a,b){return a+(+b.cnt||0)},0)),'tracked','var(--gn)'],['Conversions',N(d.conversions),'collected','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Webhook Endpoints</div>'+ep.map(function(e){return'<div style="display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid var(--bd);font-size:12px"><div><div style="font-weight:500">'+e.name+'</div><div style="font-size:10px;color:var(--mu)">'+e.url+'</div></div><div style="text-align:right"><span style="color:var(--gn);font-size:11px">'+e.status+'</span><div style="font-size:10px;color:var(--mu)">'+(e.events||[]).join(", ")+'</div></div></div>'}).join('')+'</div><div class="card"><div class="card-t">Event Types</div>'+ev.map(function(e){return'<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd);font-size:12px"><span>'+e.event_type+'</span><span style="font-family:var(--m);color:var(--ac)">'+N(e.cnt)+'</span></div>'}).join('')+'</div></div>'};
RR.n8ndash=async()=>{let d={};try{d=await(await fetch('/api/wevads-p4-api.php?action=n8n&token=WEVADS2026')).json()}catch(e){}
const ig=d.integrations||[];
$('C').innerHTML='<div class="stats">'+[['N8N',d.n8n_status||'?','orchestrator','var(--'+(d.n8n_status==='UP'?'gn':'rd')+')'],['Workflows',d.workflows||0,'active','var(--ac)'],['Integrations',ig.length,'connected','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Integrations</div>'+ig.map(function(i){var c=i.status==='active'?'var(--gn)':i.status==='monitoring'?'var(--ac)':'var(--mu)';return'<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd);font-size:12px"><div><span style="font-weight:500">'+i.name+'</span> <span style="font-size:10px;color:var(--mu)">['+i.type+']</span></div><div><span style="color:'+c+';font-size:11px">'+i.status+'</span></div></div>'}).join('')+'</div></div>'};
RR.leadscore=async()=>{let d={};try{d=await(await fetch('/api/wevads-p4-api.php?action=leadscore&token=WEVADS2026')).json()}catch(e){}
const N=n=>n?n.toLocaleString():'0';const ti=d.tiers||[];const sr=d.sources||[];
$('C').innerHTML='<div class="stats">'+[['Total Contacts',N(d.total),'database','var(--ac)'],['Scored',N(d.scored),d.score_rate+'%','var(--gn)'],['Tiers',ti.length,'segments','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Score Tiers</div>'+ti.map(function(t){var c=t.tier==='Hot'?'var(--rd)':t.tier==='Warm'?'var(--yw)':t.tier==='Cold'?'var(--ac)':'var(--mu)';return'<div style="display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid var(--bd)"><span style="font-weight:500;color:'+c+'">'+t.tier+'</span><span style="font-family:var(--m)">'+N(t.cnt)+' <span style="color:var(--mu);font-size:10px">avg '+t.avg_score+'</span></span></div>'}).join('')+'</div><div class="card"><div class="card-t">Top Sources</div>'+sr.slice(0,8).map(function(s){return'<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--bd);font-size:12px"><span>'+s.source+'</span><span style="font-family:var(--m);color:var(--ac)">'+N(s.cnt)+'</span></div>'}).join('')+'</div></div>'};
RR.newslettermgr=async()=>{let d={};try{d=await(await fetch('/api/wevads-p4-api.php?action=newsletter&token=WEVADS2026')).json()}catch(e){}
const tl=d.tools||[];
$('C').innerHTML='<div class="stats">'+[['Listmonk',d.listmonk_status||'?','newsletter','var(--'+(d.listmonk_status==='UP'?'gn':'rd')+')'],['Lists',d.lists||0,'mailing','var(--ac)'],['Tools',tl.length,'available','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Send Tools</div>'+tl.map(function(t){var c=t.status==='UP'?'var(--gn)':t.status==='available'?'var(--ac)':'var(--mu)';return'<div style="display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid var(--bd);font-size:12px"><div><span style="font-weight:500">'+t.name+'</span> <span style="color:var(--mu);font-size:10px">['+t.type+']</span></div><span style="color:'+c+'">'+t.status+(t.port?' :'+t.port:'')+'</span></div>'}).join('')+'<div style="margin-top:12px"><button class="btn btn-sm btn-ac" onclick="window.open(\'http://10.1.0.3:9000\')">Open Listmonk</button></div></div></div>'};
RR.predictive=async()=>{let d={};try{d=await(await fetch('/api/wevads-p5-api.php?action=predictive&token=WEVADS2026')).json()}catch(e){}
const N=n=>n?n.toLocaleString():'0';const hr=d.hourly||[];const dw=d.by_day||[];
$('C').innerHTML='<div class="stats">'+[['Best Hour',d.best_hour||'?','window','var(--gn)'],['Delivers',N(d.best_hour_delivers),'at peak','var(--ac)'],['Days Analyzed','30','days','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Recommendation</div><div style="padding:12px;background:var(--sf);border-radius:8px;font-size:13px;color:var(--gn);margin-top:8px">'+(d.recommendation||'Collecting data...')+'</div><div style="margin-top:12px;font-size:12px;font-weight:500">By Day of Week</div>'+dw.map(function(w){return'<div style="display:flex;justify-content:space-between;padding:4px 0;font-size:12px"><span>'+(w.day||'?')+'</span><span style="font-family:var(--m);color:var(--ac)">'+N(w.sends)+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Hourly Distribution</div><div style="display:flex;align-items:flex-end;gap:2px;height:120px;padding-top:10px">'+Array.from({length:24},function(_,i){var h=hr.find(function(x){return+x.hour===i});var v=h?(+h.sends||0):0;var mx=Math.max.apply(null,hr.map(function(x){return+x.sends||0}))||1;return'<div style="flex:1;background:var(--ac);border-radius:2px 2px 0 0;min-height:2px;height:'+Math.max(2,v/mx*100)+'%;opacity:'+(v>0?1:0.2)+'" title="'+i+'h: '+v+'"></div>'}).join('')+'</div><div style="display:flex;justify-content:space-between;font-size:9px;color:var(--mu)"><span>0h</span><span>6h</span><span>12h</span><span>18h</span><span>23h</span></div></div></div>'};
RR.providermgr=async()=>{let d={};try{d=await(await fetch('/api/wevads-p5-api.php?action=providers&token=WEVADS2026')).json()}catch(e){}
const sm=d.send_methods||[];const cl=d.cloud||{};
$('C').innerHTML='<div class="stats">'+[['Send Methods',sm.length,'available','var(--ac)'],['Cloud',Object.keys(cl).length,'providers','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Send Methods</div>'+sm.map(function(m){return'<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd);font-size:12px"><span style="font-weight:500">'+m.method_name+'</span><span style="color:var(--mu);font-size:10px">'+m.description+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">Onboarding Steps</div>'+((d.onboarding||{}).steps||[]).map(function(s,i){return'<div style="padding:6px 0;font-size:12px;border-bottom:1px solid var(--bd)"><span style="color:var(--ac);font-weight:500">'+(i+1)+'.</span> '+s+'</div>'}).join('')+'</div></div>'};
RR.competitorspy=async()=>{let d={};try{d=await(await fetch('/api/wevads-p5-api.php?action=competitors&token=WEVADS2026')).json()}catch(e){}
const cp=d.competitors||[];const adv=d.wevads_advantages||[];
$('C').innerHTML='<div class="stats">'+[['Competitors',cp.length-1,'analyzed','var(--rd)'],['WEVADS Advantages',adv.length,'unique','var(--gn)'],['Modules',d.total_modules||74,'total','var(--ac)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Competitive Matrix</div>'+cp.map(function(c){var isSelf=c.name==='WEVADS IA';return'<div style="padding:8px 0;border-bottom:1px solid var(--bd)'+(isSelf?';background:rgba(212,168,67,0.05)':'')+';font-size:12px"><div style="display:flex;justify-content:space-between"><span style="font-weight:500;color:var(--'+(isSelf?'ac':'wh')+')">'+c.name+'</span><span style="font-size:10px;color:var(--mu)">['+c.type+'] '+c.pricing+'</span></div><div style="color:var(--gn);font-size:10px;margin-top:2px">+ '+c.strengths+'</div><div style="color:var(--rd);font-size:10px">- '+c.weakness+'</div></div>'}).join('')+'</div><div class="card"><div class="card-t">WEVADS Advantages</div>'+adv.map(function(a){return'<div style="padding:5px 0;font-size:12px;border-bottom:1px solid var(--bd)"><span style="color:var(--gn)">+</span> '+a+'</div>'}).join('')+'</div></div>'};
RR.delivplay=async()=>{let d={};try{d=await(await fetch('/api/wevads-p5-api.php?action=delivtest&token=WEVADS2026')).json()}catch(e){}
const ch=d.checks||{};const isps=d.isps_tested||{};
$('C').innerHTML='<div class="stats">'+[['Score',d.deliverability_score+'%','composite','var(--gn)'],['Auth',d.auth_score+'/100','SPF+DKIM+DMARC','var(--ac)'],['Reputation',d.reputation_score+'%','blacklists','var(--pu)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Checks</div>'+Object.entries(ch).map(function(e){var v=e[1]===true?'PASS':e[1]===false?'FAIL':e[1];var c=e[1]===true||String(e[1]).indexOf('/')>0?'var(--gn)':'var(--rd)';return'<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd);font-size:12px"><span>'+e[0].toUpperCase()+'</span><span style="color:'+c+';font-weight:500">'+v+'</span></div>'}).join('')+'</div><div class="card"><div class="card-t">ISP Results</div>'+Object.entries(isps).map(function(e){return'<div style="display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--bd);font-size:12px"><span style="font-weight:500">'+e[0]+'</span><span style="color:var(--gn);font-size:10px">'+e[1]+'</span></div>'}).join('')+'<div style="margin-top:12px"><button class="btn btn-sm btn-ac" onclick="testDeliv()">Run Full Test</button></div></div></div>';};
window.testDeliv=function(){toast('Running deliverability test...');RR.delivplay()};
RR.unifiedinbox=async()=>{let d={};try{d=await(await fetch('/api/wevads-p5-api.php?action=unifiedinbox&token=WEVADS2026')).json()}catch(e){}
const N=n=>n?n.toLocaleString():'0';const ch=d.channels||[];
$('C').innerHTML='<div class="stats">'+[['Channels',ch.length,'omnichannel','var(--ac)'],['Total Sent',N(d.total_sent),'emails','var(--gn)'],['Tracking',N(d.total_tracking),'events','var(--pu)'],['Conversions',N(d.conversions),'results','var(--cy)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card"><div class="card-t">Channel Overview</div>'+ch.map(function(c){var col=c.status==='active'?'var(--gn)':c.status==='expired'?'var(--rd)':'var(--mu)';return'<div style="display:flex;justify-content:space-between;align-items:center;padding:10px 0;border-bottom:1px solid var(--bd)"><div><div style="font-size:13px;font-weight:500">'+c.name+'</div><div style="font-size:10px;color:var(--mu)">Sent: '+N(c.sent||0)+(c.bounces?' | Bounces: '+c.bounces:'')+(c.tracking?' | Events: '+N(c.tracking):'')+'</div></div><span style="color:'+col+';font-size:11px;font-weight:500">'+c.status+'</span></div>'}).join('')+'</div></div>'};
RR.arsenaltools=async()=>{let d={};try{d=await(await fetch('/api/wevads-p6-arsenal.php?action=inventory&token=WEVADS2026')).json()}catch(e){}
const tl=d.tools||[];const cats=d.categories||{};
$('C').innerHTML='<div class="stats">'+[['Arsenal Tools',d.total||0,'bridged','var(--ac)'],['Categories',Object.keys(cats).length,'domains','var(--pu)'],['AI Tools',cats.ai||0,'providers','var(--gn)'],['Infra',cats.infra||0,'management','var(--cy)']].map(function(a){return'<div class="stat" style="border-top:3px solid '+a[3]+'"><div class="st-l">'+a[0]+'</div><div class="st-v">'+a[1]+'</div><div style="font-size:10px;color:var(--mu)">'+a[2]+'</div></div>'}).join('')+'</div><div class="row2"><div class="card" style="grid-column:span 2"><div class="card-t" style="margin-bottom:10px">Arsenal Tools (click to call)</div><div style="display:grid;grid-template-columns:repeat(3,1fr);gap:8px">'+tl.map(function(t){var colors={ai:'var(--gn)',infra:'var(--ac)',intelligence:'var(--pu)',monitoring:'var(--cy)',cloud:'var(--ac)',marketing:'var(--yw)',media:'var(--rd)',business:'var(--yw)',analytics:'var(--ac)',automation:'var(--gn)',network:'var(--pu)',email:'var(--ac)',send:'var(--rd)'};var c=colors[t.cat]||'var(--mu)';return'<div style="background:var(--sf);border:1px solid var(--bd);border-radius:8px;padding:10px;cursor:pointer;border-left:3px solid '+c+'" onclick="callArsenal(\''+t.id+'\')"><div style="font-size:12px;font-weight:500">'+t.name+'</div><div style="font-size:10px;color:var(--mu);margin-top:2px">'+t.desc+'</div><div style="display:flex;justify-content:space-between;margin-top:4px"><span style="font-size:9px;color:'+c+'">'+t.cat+'</span><span style="font-size:9px;color:var(--mu)">'+t.lines+'L</span></div></div>'}).join('')+'</div></div></div>';};
window.callArsenal=async function(tool){toast('Calling '+tool+'...');try{let d=await(await fetch('/api/wevads-p6-arsenal.php?action=call&tool='+tool+'&token=WEVADS2026')).json();var r=d.response;var html='<div style="font-family:var(--m);font-size:11px;white-space:pre-wrap;max-height:400px;overflow-y:auto;background:var(--sf);padding:12px;border-radius:8px">'+JSON.stringify(r,null,2)+'</div>';modal('Arsenal: '+tool+' (HTTP '+d.http_code+')',html)}catch(e){toast('Error',1)}};
</script>
</body></html>