feat(arsenal-187-ecrans): Arsenal Master compteur exact recalibre - 183 live + 4 recovered S89 = 187 total - 4 pages historiques restaurees ethica-audit ethica-methodology manual-send-engine wevia-nexus-ultimate-2026 - section recovered ajoutee - badges live/honest/stub/recovered - NonReg 153/153
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled

This commit is contained in:
opus
2026-04-22 03:29:47 +02:00
parent 9e870d7919
commit 8c199e80d7
6 changed files with 1613 additions and 63 deletions

View File

@@ -1,73 +1,70 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,viewport-fit=cover">
<title>Arsenal Master · 183 ecrans · 46 sections</title>
<html lang="fr"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Arsenal Master · 187 ecrans · v3</title>
<style>
:root{--bg:#060a14;--s:#0c1220;--s2:#111827;--b:#1e293b;--t:#e2e8f0;--d:#64748b;--cy:#22d3ee;--gn:#34d399;--am:#fbbf24;--rd:#f87171;--pu:#a78bfa;--bl:#60a5fa}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--t);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;font-size:13px;line-height:1.5}
body{background:var(--bg);color:var(--t);font-family:-apple-system,'Segoe UI',sans-serif;font-size:13px;line-height:1.5}
.hdr{background:linear-gradient(180deg,var(--s),rgba(12,18,32,.95));border-bottom:1px solid var(--b);padding:18px 24px;display:flex;justify-content:space-between;align-items:center;position:sticky;top:0;z-index:10;backdrop-filter:blur(10px)}
.hdr h1{font-size:24px;font-weight:800;background:linear-gradient(135deg,var(--cy),var(--pu));-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.hdr .meta{color:var(--d);font-size:11px;margin-top:4px;font-family:'JetBrains Mono',monospace}
.btn{padding:9px 16px;border-radius:8px;border:1px solid var(--b);background:var(--s2);color:var(--t);text-decoration:none;font-size:11px;font-weight:600;transition:all .15s}
.btn:hover{border-color:var(--cy);transform:translateY(-1px)}
.btn{padding:9px 16px;border-radius:8px;border:1px solid var(--b);background:var(--s2);color:var(--t);text-decoration:none;font-size:11px;font-weight:600}
.btn:hover{border-color:var(--cy)}
.wrap{padding:28px 24px;max-width:1700px;margin:0 auto}
.kpi{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px;margin-bottom:32px}
.k{background:var(--s);border:1px solid var(--b);border-radius:12px;padding:22px;text-align:center;position:relative;overflow:hidden}
.kpi{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:14px;margin-bottom:32px}
.k{background:var(--s);border:1px solid var(--b);border-radius:12px;padding:22px;text-align:center}
.k .n{font-family:'JetBrains Mono',monospace;font-size:32px;font-weight:800}
.k .l{font-size:10px;text-transform:uppercase;color:var(--d);margin-top:8px;letter-spacing:.8px;font-weight:600}
.k.gn .n{color:var(--gn)}.k.am .n{color:var(--am)}.k.rd .n{color:var(--rd)}.k.cy .n{color:var(--cy)}.k.pu .n{color:var(--pu)}.k.bl .n{color:var(--bl)}
.ext{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:24px}
.ext{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:10px;margin-bottom:24px}
.ext a{padding:14px;background:var(--s);border:1px solid var(--b);border-radius:10px;color:var(--t);text-decoration:none;display:flex;align-items:center;justify-content:space-between;font-size:12px}
.ext a:hover{border-color:var(--am)}
.search{margin-bottom:24px}
.search input{width:100%;padding:16px 20px;background:var(--s);border:1px solid var(--b);border-radius:12px;color:var(--t);font-size:14px;font-family:inherit}
.search input:focus{outline:none;border-color:var(--cy);box-shadow:0 0 0 3px rgba(34,211,238,.1)}
.search input{width:100%;padding:16px 20px;background:var(--s);border:1px solid var(--b);border-radius:12px;color:var(--t);font-size:14px;margin-bottom:24px}
.search input:focus{outline:none;border-color:var(--cy)}
.cat{margin-bottom:32px}
.cat-h{font-size:14px;font-weight:700;margin-bottom:12px;display:flex;align-items:center;gap:10px;padding-bottom:8px;border-bottom:1px solid var(--b)}
.cat-h .cat-c{font-size:10px;font-weight:600;color:var(--d);background:var(--s2);padding:3px 10px;border-radius:12px;font-family:'JetBrains Mono',monospace}
.cat-h .cat-c{font-size:10px;color:var(--d);background:var(--s2);padding:3px 10px;border-radius:12px;font-family:'JetBrains Mono',monospace}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:8px}
.lnk{padding:11px 14px;background:var(--s);border:1px solid var(--b);border-radius:8px;color:var(--t);text-decoration:none;font-size:11.5px;display:flex;align-items:center;justify-content:space-between;gap:8px;transition:all .12s;text-transform:capitalize}
.lnk{padding:11px 14px;background:var(--s);border:1px solid var(--b);border-radius:8px;color:var(--t);text-decoration:none;font-size:11.5px;display:flex;align-items:center;justify-content:space-between;gap:8px;text-transform:capitalize}
.lnk:hover{border-color:var(--cy);background:var(--s2);transform:translateX(2px)}
.bd{font-size:8.5px;padding:2px 7px;border-radius:8px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;font-family:'JetBrains Mono',monospace}
.bd{font-size:8.5px;padding:2px 7px;border-radius:8px;font-weight:700;text-transform:uppercase;font-family:'JetBrains Mono',monospace}
.bd-live{background:rgba(52,211,153,.12);color:var(--gn)}
.bd-honest{background:rgba(167,139,250,.15);color:var(--pu)}
.bd-broken{background:rgba(251,191,36,.15);color:var(--am)}
.bd-stub{background:rgba(251,191,36,.15);color:var(--am)}
.bd-recovered{background:rgba(96,165,250,.15);color:var(--bl)}
</style></head><body>
<div class="hdr">
<div>
<h1>🎯 Arsenal Master</h1>
<div class="meta">183 ecrans · 46 sections · doctrine #4 honnetete · audit 22avr2026</div>
</div>
<div style="display:flex;gap:8px">
<a href="/weval-technology-platform.html" class="btn">⚙️ WTP ERP</a>
<a href="/all-ia-hub.html" class="btn">🤖 IA Hub</a>
<a href="/wevia-master.html" class="btn">✨ WEVIA</a>
</div>
<div>
<h1>🎯 Arsenal Master · 187 écrans</h1>
<div class="meta">183 live menu + 4 recovered S89 · 30 sections · 22avr2026 · zero perte</div>
</div>
<div style="display:flex;gap:8px">
<a href="/weval-technology-platform.html" class="btn">⚙️ WTP</a>
<a href="/weval-mega-master.html" class="btn">🌐 Mega</a>
<a href="/wevia-master.html" class="btn">✨ WEVIA</a>
</div>
</div>
<div class="wrap">
<div class="kpi">
<div class="k cy"><div class="n">183</div><div class="l">Total Ecrans</div></div>
<div class="k gn"><div class="n">170</div><div class="l">Live OK</div></div>
<div class="k pu"><div class="n">3</div><div class="l">Honest (was fake)</div></div>
<div class="k am"><div class="n">10</div><div class="l">Broken / Stub</div></div>
<div class="k bl"><div class="n">46</div><div class="l">Sections</div></div>
<div class="k rd"><div class="n">3</div><div class="l">External Services</div></div>
<div class="k cy"><div class="n">187</div><div class="l">Total Ecrans</div></div>
<div class="k gn"><div class="n">170</div><div class="l">Live OK</div></div>
<div class="k pu"><div class="n">3</div><div class="l">Honest (was fake)</div></div>
<div class="k am"><div class="n">10</div><div class="l">Stubs (was broken)</div></div>
<div class="k bl"><div class="n">4</div><div class="l">Recovered S89</div></div>
<div class="k rd"><div class="n">3</div><div class="l">Ext Services</div></div>
</div>
<div class="ext">
<a href="https://weval-consulting.com/arsenal-proxy/n8n.html" target="_blank">⚡ N8N Workflows (port 5678) <span class="bd bd-live">live</span></a>
<a href="https://weval-consulting.com/arsenal-proxy/hamid.html" target="_blank">🤖 HAMID IA (port 8080) <span class="bd bd-live">live</span></a>
<a href="https://weval-consulting.com/arsenal-proxy/dashboard.html" target="_blank">📊 ADX (port 5821) <span class="bd bd-honest">honest</span></a>
<a href="/arsenal-proxy/n8n.html" target="_blank">⚡ N8N Workflows (port 5678) <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/hamid.html" target="_blank">🤖 HAMID IA (port 8080) <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/dashboard.html" target="_blank">📊 ADX (port 5821) <span class="bd bd-honest">honest</span></a>
</div>
<div class="search">
<input type="text" id="q" placeholder="🔍 Rechercher parmi 183 ecrans (ex: brain, send, dark, ethica, sentinel...)" oninput="filter()">
<input type="text" id="q" placeholder="🔍 Rechercher parmi 187 ecrans (brain, send, ethica, sentinel, recovered...)" oninput="filter()">
</div>
<div class="cat">
@@ -136,7 +133,7 @@ body{background:var(--bg);color:var(--t);font-family:-apple-system,BlinkMacSyste
<a href="/arsenal-proxy/dark-slot.html" target="_blank" class="lnk" data-name="dark-slot.html">dark slot <span class="bd bd-live">live</span></a>
</div></div>
<div class="cat">
<div class="cat-h">🔍 Scraping & Discovery <span class="cat-c">10</span></div>
<div class="cat-h">🔍 Scraping <span class="cat-c">10</span></div>
<div class="grid">
<a href="/arsenal-proxy/advanced-craping-factory.html" target="_blank" class="lnk" data-name="advanced-craping-factory.html">advanced craping factory <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/data-manager.html" target="_blank" class="lnk" data-name="data-manager.html">data manager <span class="bd bd-live">live</span></a>
@@ -150,7 +147,7 @@ body{background:var(--bg);color:var(--t);font-family:-apple-system,BlinkMacSyste
<a href="/arsenal-proxy/scrapping-factory.html" target="_blank" class="lnk" data-name="scrapping-factory.html">scrapping factory <span class="bd bd-live">live</span></a>
</div></div>
<div class="cat">
<div class="cat-h">📺 YouTube & Affiliates <span class="cat-c">10</span></div>
<div class="cat-h">📺 YouTube/Affiliates <span class="cat-c">10</span></div>
<div class="grid">
<a href="/arsenal-proxy/ads-commander.html" target="_blank" class="lnk" data-name="ads-commander.html">ads commander <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/creative-factory.html" target="_blank" class="lnk" data-name="creative-factory.html">creative factory <span class="bd bd-live">live</span></a>
@@ -164,13 +161,13 @@ body{background:var(--bg);color:var(--t);font-family:-apple-system,BlinkMacSyste
<a href="/arsenal-proxy/youtube-factory.html" target="_blank" class="lnk" data-name="youtube-factory.html">youtube factory <span class="bd bd-honest">honest</span></a>
</div></div>
<div class="cat">
<div class="cat-h">📱 SMS Engines <span class="cat-c">2</span></div>
<div class="cat-h">📱 SMS <span class="cat-c">2</span></div>
<div class="grid">
<a href="/arsenal-proxy/sms-send-engine.html" target="_blank" class="lnk" data-name="sms-send-engine.html">sms send engine <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/sms-templates.html" target="_blank" class="lnk" data-name="sms-templates.html">sms templates <span class="bd bd-live">live</span></a>
</div></div>
<div class="cat">
<div class="cat-h">👥 Accounts & Identity <span class="cat-c">5</span></div>
<div class="cat-h">👥 Accounts <span class="cat-c">5</span></div>
<div class="grid">
<a href="/arsenal-proxy/account-creator.html" target="_blank" class="lnk" data-name="account-creator.html">account creator <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/gsuite-accounts.html" target="_blank" class="lnk" data-name="gsuite-accounts.html">gsuite accounts <span class="bd bd-live">live</span></a>
@@ -261,19 +258,19 @@ body{background:var(--bg);color:var(--t);font-family:-apple-system,BlinkMacSyste
<a href="/arsenal-proxy/test-integration.html" target="_blank" class="lnk" data-name="test-integration.html">test integration <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/test-metrics.html" target="_blank" class="lnk" data-name="test-metrics.html">test metrics <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/test-results-live.html" target="_blank" class="lnk" data-name="test-results-live.html">test results live <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/tools/blacklist-check.html" target="_blank" class="lnk" data-name="tools/blacklist-check.html">tools / blacklist check <span class="bd bd-broken">broken</span></a>
<a href="/arsenal-proxy/tools/bounce-handler.html" target="_blank" class="lnk" data-name="tools/bounce-handler.html">tools / bounce handler <span class="bd bd-broken">broken</span></a>
<a href="/arsenal-proxy/tools/content-analyzer.html" target="_blank" class="lnk" data-name="tools/content-analyzer.html">tools / content analyzer <span class="bd bd-broken">broken</span></a>
<a href="/arsenal-proxy/tools/dns-checker.html" target="_blank" class="lnk" data-name="tools/dns-checker.html">tools / dns checker <span class="bd bd-broken">broken</span></a>
<a href="/arsenal-proxy/tools/domain-monitor.html" target="_blank" class="lnk" data-name="tools/domain-monitor.html">tools / domain monitor <span class="bd bd-broken">broken</span></a>
<a href="/arsenal-proxy/tools/email-verifier.html" target="_blank" class="lnk" data-name="tools/email-verifier.html">tools / email verifier <span class="bd bd-broken">broken</span></a>
<a href="/arsenal-proxy/tools/ip-warmup.html" target="_blank" class="lnk" data-name="tools/ip-warmup.html">tools / ip warmup <span class="bd bd-broken">broken</span></a>
<a href="/arsenal-proxy/tools/smtp-tester.html" target="_blank" class="lnk" data-name="tools/smtp-tester.html">tools / smtp tester <span class="bd bd-broken">broken</span></a>
<a href="/arsenal-proxy/tools/spam-test.html" target="_blank" class="lnk" data-name="tools/spam-test.html">tools / spam test <span class="bd bd-broken">broken</span></a>
<a href="/arsenal-proxy/tools/blacklist-check.html" target="_blank" class="lnk" data-name="tools/blacklist-check.html">blacklist check <span class="bd bd-stub">stub</span></a>
<a href="/arsenal-proxy/tools/bounce-handler.html" target="_blank" class="lnk" data-name="tools/bounce-handler.html">bounce handler <span class="bd bd-stub">stub</span></a>
<a href="/arsenal-proxy/tools/content-analyzer.html" target="_blank" class="lnk" data-name="tools/content-analyzer.html">content analyzer <span class="bd bd-stub">stub</span></a>
<a href="/arsenal-proxy/tools/dns-checker.html" target="_blank" class="lnk" data-name="tools/dns-checker.html">dns checker <span class="bd bd-stub">stub</span></a>
<a href="/arsenal-proxy/tools/domain-monitor.html" target="_blank" class="lnk" data-name="tools/domain-monitor.html">domain monitor <span class="bd bd-stub">stub</span></a>
<a href="/arsenal-proxy/tools/email-verifier.html" target="_blank" class="lnk" data-name="tools/email-verifier.html">email verifier <span class="bd bd-stub">stub</span></a>
<a href="/arsenal-proxy/tools/ip-warmup.html" target="_blank" class="lnk" data-name="tools/ip-warmup.html">ip warmup <span class="bd bd-stub">stub</span></a>
<a href="/arsenal-proxy/tools/smtp-tester.html" target="_blank" class="lnk" data-name="tools/smtp-tester.html">smtp tester <span class="bd bd-stub">stub</span></a>
<a href="/arsenal-proxy/tools/spam-test.html" target="_blank" class="lnk" data-name="tools/spam-test.html">spam test <span class="bd bd-stub">stub</span></a>
<a href="/arsenal-proxy/warming-engine.html" target="_blank" class="lnk" data-name="warming-engine.html">warming engine <span class="bd bd-live">live</span></a>
</div></div>
<div class="cat">
<div class="cat-h">🔄 Pipelines & Workflows <span class="cat-c">8</span></div>
<div class="cat-h">🔄 Pipelines <span class="cat-c">8</span></div>
<div class="grid">
<a href="/arsenal-proxy/api-key-pool.html" target="_blank" class="lnk" data-name="api-key-pool.html">api key pool <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/auto-supply.html" target="_blank" class="lnk" data-name="auto-supply.html">auto supply <span class="bd bd-live">live</span></a>
@@ -285,24 +282,24 @@ body{background:var(--bg);color:var(--t);font-family:-apple-system,BlinkMacSyste
<a href="/arsenal-proxy/supply-chain.html" target="_blank" class="lnk" data-name="supply-chain.html">supply chain <span class="bd bd-live">live</span></a>
</div></div>
<div class="cat">
<div class="cat-h">🔌 APIs & Integrations <span class="cat-c">1</span></div>
<div class="cat-h">🔌 APIs <span class="cat-c">1</span></div>
<div class="grid">
<a href="/arsenal-proxy/kb-sync-monitor.html" target="_blank" class="lnk" data-name="kb-sync-monitor.html">kb sync monitor <span class="bd bd-live">live</span></a>
</div></div>
<div class="cat">
<div class="cat-h">⚙️ Admin & Config <span class="cat-c">3</span></div>
<div class="cat-h">⚙️ Admin <span class="cat-c">3</span></div>
<div class="grid">
<a href="/arsenal-proxy/arsenal-widget.html" target="_blank" class="lnk" data-name="arsenal-widget.html">arsenal widget <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/login-modern.html" target="_blank" class="lnk" data-name="login-modern.html">login modern <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/sidebar-admin.html" target="_blank" class="lnk" data-name="sidebar-admin.html">sidebar admin <span class="bd bd-live">live</span></a>
</div></div>
<div class="cat">
<div class="cat-h">🐦 Twitter Ads <span class="cat-c">1</span></div>
<div class="cat-h">🐦 Twitter <span class="cat-c">1</span></div>
<div class="grid">
<a href="/arsenal-proxy/twitter-ads.html" target="_blank" class="lnk" data-name="twitter-ads.html">twitter ads <span class="bd bd-live">live</span></a>
</div></div>
<div class="cat">
<div class="cat-h">💼 Ethica / Pharma <span class="cat-c">6</span></div>
<div class="cat-h">💼 Ethica/Pharma <span class="cat-c">6</span></div>
<div class="grid">
<a href="/arsenal-proxy/ethica-consent.html" target="_blank" class="lnk" data-name="ethica-consent.html">ethica consent <span class="bd bd-live">live</span></a>
<a href="/arsenal-proxy/ethica-crossvalidator.html" target="_blank" class="lnk" data-name="ethica-crossvalidator.html">ethica crossvalidator <span class="bd bd-live">live</span></a>
@@ -339,7 +336,7 @@ body{background:var(--bg);color:var(--t);font-family:-apple-system,BlinkMacSyste
<a href="/arsenal-proxy/wevads-architecture.html" target="_blank" class="lnk" data-name="wevads-architecture.html">wevads architecture <span class="bd bd-honest">honest</span></a>
</div></div>
<div class="cat">
<div class="cat-h">⏱️ Temp / Disposable <span class="cat-c">1</span></div>
<div class="cat-h">⏱️ Temp/Disposable <span class="cat-c">1</span></div>
<div class="grid">
<a href="/arsenal-proxy/menu-twig.html" target="_blank" class="lnk" data-name="menu-twig.html">menu twig <span class="bd bd-live">live</span></a>
</div></div>
@@ -349,12 +346,12 @@ body{background:var(--bg);color:var(--t);font-family:-apple-system,BlinkMacSyste
<a href="/arsenal-proxy/brain-consent.html" target="_blank" class="lnk" data-name="brain-consent.html">brain consent <span class="bd bd-live">live</span></a>
</div></div>
<div class="cat">
<div class="cat-h">🔥 Warmup & Deliverability <span class="cat-c">1</span></div>
<div class="cat-h">🔥 Warmup <span class="cat-c">1</span></div>
<div class="grid">
<a href="/arsenal-proxy/adherence-monitor.html" target="_blank" class="lnk" data-name="adherence-monitor.html">adherence monitor <span class="bd bd-live">live</span></a>
</div></div>
<div class="cat">
<div class="cat-h">📨 Campaign Send <span class="cat-c">1</span></div>
<div class="cat-h">📨 Campaign <span class="cat-c">1</span></div>
<div class="grid">
<a href="/arsenal-proxy/send-pipeline.html" target="_blank" class="lnk" data-name="send-pipeline.html">send pipeline <span class="bd bd-live">live</span></a>
</div></div>
@@ -367,7 +364,15 @@ body{background:var(--bg);color:var(--t);font-family:-apple-system,BlinkMacSyste
<div class="cat">
<div class="cat-h">✨ WEVIA IA <span class="cat-c">1</span></div>
<div class="grid">
<a href="/arsenal-proxy/nexus-control.html" target="_blank" class="lnk" data-name="nexus-control.html">nexus control <span class="bd bd-broken">broken</span></a>
<a href="/arsenal-proxy/nexus-control.html" target="_blank" class="lnk" data-name="nexus-control.html">nexus control <span class="bd bd-stub">stub</span></a>
</div></div>
<div class="cat">
<div class="cat-h">📦 Recovered Archives (S89) <span class="cat-c">4</span></div>
<div class="grid">
<a href="/arsenal-recovered/ethica-audit.html" target="_blank" class="lnk" data-name="recovered/ethica-audit.html">ethica audit <span class="bd bd-recovered">recovered</span></a>
<a href="/arsenal-recovered/ethica-methodology.html" target="_blank" class="lnk" data-name="recovered/ethica-methodology.html">ethica methodology <span class="bd bd-recovered">recovered</span></a>
<a href="/arsenal-recovered/manual-send-engine.html" target="_blank" class="lnk" data-name="recovered/manual-send-engine.html">manual send engine <span class="bd bd-recovered">recovered</span></a>
<a href="/arsenal-recovered/wevia-nexus-ultimate-2026.html" target="_blank" class="lnk" data-name="recovered/wevia-nexus-ultimate-2026.html">wevia nexus ultimate 2026 <span class="bd bd-recovered">recovered</span></a>
</div></div>
@@ -377,12 +382,11 @@ body{background:var(--bg);color:var(--t);font-family:-apple-system,BlinkMacSyste
function filter(){
var q = document.getElementById('q').value.toLowerCase();
document.querySelectorAll('.lnk').forEach(function(el){
var n = el.dataset.name.toLowerCase();
el.style.display = n.includes(q) ? '' : 'none';
el.style.display = el.dataset.name.toLowerCase().includes(q) ? '' : 'none';
});
document.querySelectorAll('.cat').forEach(function(c){
var visible = Array.from(c.querySelectorAll('.lnk')).some(function(l){ return l.style.display !== 'none'; });
c.style.display = visible ? '' : 'none';
var v = Array.from(c.querySelectorAll('.lnk')).some(function(l){ return l.style.display !== 'none'; });
c.style.display = v ? '' : 'none';
});
}
</script>

View File

@@ -0,0 +1,109 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>WEVADS • Ethica HCP Audit</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root{--bg:#0a0e17;--s:#111827;--s2:#1a2332;--b:#1e293b;--t:#e2e8f0;--d:#64748b;--am:#f59e0b;--gn:#10b981;--rd:#ef4444;--bl:#3b82f6;--cy:#06b6d4;--wh:#ffffff;--pr:#a855f7}
*{margin:0;padding:0;box-sizing:border-box}body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--t);overflow-x:hidden}
.header{padding:16px 24px;border-bottom:1px solid var(--b);display:flex;justify-content:space-between;align-items:center}.header h1{font-size:18px;font-weight:800}.header h1 span{color:var(--am)}.subtitle{font-size:10px;color:var(--d);margin-top:2px}
.live{display:flex;align-items:center;gap:6px;font-size:10px;color:var(--gn)}.live::before{content:'';width:6px;height:6px;border-radius:50%;background:var(--gn);animation:pulse 2s infinite}@keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}
.container{padding:20px 24px}.g4{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:16px}.g3{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:16px}.g2{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px}
.card{background:var(--s);border:1px solid var(--b);border-radius:10px;padding:16px;transition:all .2s}.card:hover{border-color:var(--am);transform:translateY(-1px)}.card-title{font-size:9px;text-transform:uppercase;letter-spacing:1px;color:var(--d);margin-bottom:6px}
.card-value{font-family:'JetBrains Mono',monospace;font-size:28px;font-weight:800}.card-sub{font-size:10px;color:var(--d);margin-top:4px}
.badge{padding:3px 10px;border-radius:4px;font-size:10px;font-weight:700;display:inline-block}.badge-gn{background:rgba(16,185,129,.15);color:var(--gn)}.badge-am{background:rgba(245,158,11,.15);color:var(--am)}.badge-rd{background:rgba(239,68,68,.15);color:var(--rd)}.badge-bl{background:rgba(59,130,246,.15);color:var(--bl)}.badge-cy{background:rgba(6,182,212,.15);color:var(--cy)}.badge-pr{background:rgba(168,85,247,.15);color:var(--pr)}
table{width:100%;border-collapse:collapse;margin-top:8px}th{padding:8px 12px;text-align:left;font-size:9px;text-transform:uppercase;letter-spacing:.5px;color:var(--d);border-bottom:1px solid var(--b);background:var(--s2)}td{padding:8px 12px;border-bottom:1px solid rgba(30,41,59,.3);font-size:12px;font-family:'JetBrains Mono',monospace}tr:hover{background:rgba(245,158,11,.03)}
.score-ring{width:80px;height:80px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:24px;font-weight:900;font-family:'JetBrains Mono',monospace;margin:0 auto 8px}
.tabs{display:flex;gap:4px;margin-bottom:16px;background:var(--s);padding:6px;border-radius:8px;border:1px solid var(--b)}.tab{padding:8px 20px;border-radius:6px;cursor:pointer;font-size:12px;font-weight:600;color:var(--d);transition:.2s}.tab:hover,.tab.active{background:rgba(245,158,11,.1);color:var(--am)}.tab-content{display:none}.tab-content.active{display:block}
.progress{background:var(--s2);border-radius:4px;height:6px;overflow:hidden;margin-top:6px}.progress-bar{height:100%;border-radius:4px;transition:width .8s}
.quality-row{display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid rgba(30,41,59,.3)}.quality-row:last-child{border:none}.qr-label{font-size:12px}.qr-value{font-family:'JetBrains Mono',monospace;font-size:12px;font-weight:700}
@media(max-width:1200px){.g4{grid-template-columns:repeat(2,1fr)}.g2{grid-template-columns:1fr}}
</style>
</head>
<body>
<div class="header"><div><h1>🔍 Ethica <span>HCP Audit</span></h1><div class="subtitle">Audit qualité temps réel — Base de données HCP Maghreb</div></div><div class="live">● LIVE <span id="clock"></span></div></div>
<div class="container">
<div class="tabs">
<div class="tab active" onclick="showTab('overview',this)">Vue d'ensemble</div>
<div class="tab" onclick="showTab('quality',this)">Qualité Data</div>
<div class="tab" onclick="showTab('coverage',this)">Couverture</div>
<div class="tab" onclick="showTab('sources',this)">Sources & Méthodologie</div>
</div>
<div id="tab-overview" class="tab-content active">
<div class="g4">
<div class="card"><div class="card-title">📊 Total HCPs</div><div class="card-value" style="color:var(--cy)" id="k-total"></div><div class="card-sub">Base complète Maghreb</div></div>
<div class="card"><div class="card-title">✅ Email Validés</div><div class="card-value" style="color:var(--gn)" id="k-valid"></div><div class="card-sub" id="k-valid-pct"></div></div>
<div class="card"><div class="card-title">📱 Avec Téléphone</div><div class="card-value" style="color:var(--pr)" id="k-phone"></div><div class="card-sub" id="k-phone-pct"></div></div>
<div class="card"><div class="card-title">🛡️ Score Qualité</div><div class="score-ring" style="border:3px solid var(--gn)" id="k-score"></div><div class="card-sub" style="text-align:center">Score global</div></div>
</div>
<div class="g3" id="country-cards"></div>
<div class="g2">
<div class="card"><div class="card-title">📋 Indicateurs Qualité</div><div id="quality-indicators"></div></div>
<div class="card"><div class="card-title">🎯 Spécialités Ethica (Cibles)</div><div id="target-specs" style="max-height:300px;overflow-y:auto"></div></div>
</div>
</div>
<div id="tab-quality" class="tab-content">
<div class="g2">
<div class="card"><div class="card-title">📧 Validation Email</div><div id="email-quality"></div></div>
<div class="card"><div class="card-title">📱 Validation Téléphone</div><div id="phone-quality"></div></div>
</div>
<div class="card" style="margin-bottom:16px"><div class="card-title">🔬 Échantillon Aléatoire (Vérification)</div><div id="sampling-results" style="overflow-x:auto"></div></div>
</div>
<div id="tab-coverage" class="tab-content">
<div class="card"><div class="card-title">🌍 Couverture par Spécialité × Pays</div><div style="overflow-x:auto" id="coverage-table"></div></div>
</div>
<div id="tab-sources" class="tab-content">
<div class="g2">
<div class="card"><div class="card-title">📚 Sources de Données</div><div id="sources-list" style="max-height:400px;overflow-y:auto"></div></div>
<div class="card"><div class="card-title">🔄 Méthodologie de Validation</div><div style="font-size:12px;line-height:1.8;padding:8px 0">
<div class="quality-row"><span class="qr-label">1. Collecte</span><span class="badge badge-gn">Annuaires officiels + médical</span></div>
<div class="quality-row"><span class="qr-label">2. Validation MX</span><span class="badge badge-gn">Vérification DNS/MX par domaine</span></div>
<div class="quality-row"><span class="qr-label">3. Syntaxe Email</span><span class="badge badge-gn">Regex RFC 5322</span></div>
<div class="quality-row"><span class="qr-label">4. Déduplication</span><span class="badge badge-gn">Email unique strict — 0 doublons</span></div>
<div class="quality-row"><span class="qr-label">5. Téléphone</span><span class="badge badge-gn">Format E.164 international</span></div>
<div class="quality-row"><span class="qr-label">6. Spécialité</span><span class="badge badge-gn">Normalisation standardisée</span></div>
<div class="quality-row"><span class="qr-label">7. Consentement</span><span class="badge badge-am">Pipeline e-consent actif</span></div>
</div></div>
</div>
</div>
</div>
<script>
const API='api/ethica-data-list-api.php',API2='api/ethica-scraper-api.php';
const fmt=n=>n!=null?Number(n).toLocaleString('fr-FR'):'—';
const pct=(a,b)=>b>0?(a/b*100).toFixed(1)+'%':'0%';
const flags={MA:'🇲🇦',ALG:'🇩🇿',TN:'🇹🇳'},names={MA:'Maroc',ALG:'Algérie',TN:'Tunisie'};
const ethicaTargets=['generaliste','pharmacien','rhumatologue','orthopediste','pneumologue','allergologue','orl','gastro-enterologue','pediatre','dentiste','gynecologue','cardiologue'];
function showTab(id,el){document.querySelectorAll('.tab-content').forEach(t=>t.classList.remove('active'));document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active'));document.getElementById('tab-'+id).classList.add('active');el.classList.add('active')}
async function loadAll(){try{
const[s,sc,sample,cov]=await Promise.all([
fetch(API+'?action=stats').then(r=>r.json()),
fetch(API2+'?action=stats').then(r=>r.json()),
fetch(API+'?action=list&page=1&limit=20&sort=id&dir=DESC').then(r=>r.json()),
fetch(API2+'?action=sources').then(r=>r.json())
]);
document.getElementById('k-total').textContent=fmt(s.total);
document.getElementById('k-valid').textContent=fmt(s.valid_email);
document.getElementById('k-valid-pct').textContent=pct(s.valid_email,s.total)+' validés';
document.getElementById('k-phone').textContent=fmt(s.with_phone);
document.getElementById('k-phone-pct').textContent=pct(s.with_phone,s.total)+' couverture';
const score=Math.round((s.valid_email/s.total*40)+(s.with_phone/s.total*30)+30);
const se=document.getElementById('k-score');se.textContent=score+'/100';se.style.borderColor=score>=80?'var(--gn)':score>=60?'var(--am)':'var(--rd)';
document.getElementById('country-cards').innerHTML=(s.by_pays||[]).map(p=>`<div class="card" style="text-align:center;border-left:3px solid var(--cy)"><div style="font-size:28px">${flags[p.pays]||''}</div><div style="font-size:12px;font-weight:700;margin:4px 0">${names[p.pays]||p.pays}</div><div class="card-value" style="font-size:22px;color:var(--cy)">${fmt(p.count)}</div><div class="card-sub">${pct(p.count,s.total)} de la base</div></div>`).join('');
document.getElementById('quality-indicators').innerHTML=[['Emails uniques (0 doublons)',s.total,s.total,'var(--gn)'],['Emails validés MX',s.valid_email,s.total,'var(--gn)'],['Avec téléphone',s.with_phone,s.total,'var(--pr)'],['Sources actives',sc.active_sources||0,sc.total_sources||30,'var(--bl)']].map(([l,v,m,c])=>`<div class="quality-row"><span class="qr-label">${l}</span><span class="qr-value" style="color:${c}">${fmt(v)} <span style="color:var(--d);font-weight:400">/ ${fmt(m)}</span></span></div><div class="progress"><div class="progress-bar" style="width:${pct(v,m)};background:${c}"></div></div>`).join('');
document.getElementById('target-specs').innerHTML='<table><tr><th>Spécialité</th><th>Contacts</th><th>Cible</th></tr>'+(s.by_spec||[]).filter(x=>ethicaTargets.includes(x.spec)).map(x=>`<tr><td>${x.spec}</td><td style="color:var(--cy);font-weight:700">${fmt(x.count)}</td><td><span class="badge badge-gn">✓ Cible</span></td></tr>`).join('')+'</table>';
document.getElementById('email-quality').innerHTML=[['Syntaxe valide (RFC 5322)',s.valid_email,s.total],['MX vérifié (25 domaines)',s.valid_email,s.total],['Domaines connus (Gmail, Yahoo, Outlook, ISPs)',s.valid_email,s.total]].map(([l,v,m])=>`<div class="quality-row"><span class="qr-label">${l}</span><span class="qr-value" style="color:var(--gn)">${pct(v,m)}</span></div><div class="progress"><div class="progress-bar" style="width:${pct(v,m)};background:var(--gn)"></div></div>`).join('')+'<div style="margin-top:12px;font-size:11px;color:var(--d)">Domaines MX : gmail.com, yahoo.fr, outlook.com, hotmail.fr/com, live.fr, djaweb.dz, menara.ma, iam.ma, planet.tn, topnet.tn, caramail.com + domaines médicaux</div>';
document.getElementById('phone-quality').innerHTML=`<div class="quality-row"><span class="qr-label">Avec téléphone</span><span class="qr-value" style="color:var(--gn)">${pct(s.with_phone,s.total)}</span></div><div class="progress"><div class="progress-bar" style="width:${pct(s.with_phone,s.total)};background:var(--gn)"></div></div><div class="quality-row"><span class="qr-label">Format international</span><span class="badge badge-gn">+212 / +213 / +216</span></div>`;
document.getElementById('sampling-results').innerHTML='<table><tr><th>Email</th><th>Nom</th><th>Prénom</th><th>Spécialité</th><th>Ville</th><th>Pays</th><th>Tél</th><th>Validé</th></tr>'+(sample.contacts||[]).map(c=>`<tr><td style="font-size:10px">${c.email}</td><td>${c.nom}</td><td>${c.prenom}</td><td><span class="badge badge-cy">${c.specialite}</span></td><td>${c.ville}</td><td>${flags[c.pays]||''} ${c.pays}</td><td style="font-size:10px">${c.telephone||''}</td><td><span class="badge badge-gn">${c.email_valid}</span></td></tr>`).join('')+'</table>';
// Coverage
const specCounts={};(s.by_spec||[]).forEach(x=>specCounts[x.spec]=x.count);
document.getElementById('coverage-table').innerHTML='<table><tr><th>Spécialité</th><th>Total</th><th>Cible Ethica</th></tr>'+Object.entries(specCounts).sort((a,b)=>b[1]-a[1]).map(([sp,c])=>`<tr style="${ethicaTargets.includes(sp)?'background:rgba(245,158,11,.05)':''}"><td style="font-weight:${ethicaTargets.includes(sp)?'700':'400'}">${sp}</td><td style="color:var(--cy);font-weight:700">${fmt(c)}</td><td>${ethicaTargets.includes(sp)?'<span class="badge badge-am">Ethica</span>':''}</td></tr>`).join('')+'</table>';
// Sources
const tc={official:'badge-gn',medical:'badge-cy',directory:'badge-am',social:'badge-pr',finder:'badge-bl',search:'badge-rd',maps:'badge-am',business:'badge-bl'};
document.getElementById('sources-list').innerHTML='<table><tr><th>Source</th><th>Type</th><th>Pays</th><th>Status</th></tr>'+(cov.sources||[]).map(x=>`<tr><td>${x.name}</td><td><span class="badge ${tc[x.type]||'badge-bl'}">${x.type}</span></td><td>${flags[x.pays]||'🌍'} ${x.pays}</td><td><span class="badge ${x.status==='active'?'badge-gn':'badge-rd'}">${x.status}</span></td></tr>`).join('')+'</table>';
}catch(e){console.error(e)}}
setInterval(()=>{document.getElementById('clock').textContent=new Date().toLocaleTimeString('fr-FR')},1000);
loadAll();
</script>
</body></html>

View File

@@ -0,0 +1,255 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ethica Methodology | WEVADS Arsenal</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root{--bg:#0a0e1a;--bg2:#111827;--bg3:#1a2236;--bg4:#1e293b;--tx:#e2e8f0;--t2:#94a3b8;--t3:#64748b;--cy:#22d3ee;--gn:#10b981;--rd:#ef4444;--or:#f59e0b;--pu:#a78bfa;--pk:#ec4899;--border:#1e293b}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--tx);font-family:'Segoe UI',system-ui,sans-serif;min-height:100vh}
.hd{padding:16px 24px;background:var(--bg2);border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between}
.hd h1{font-size:20px;font-weight:700;display:flex;align-items:center;gap:10px}
.hd h1 span{color:var(--cy)}
.container{padding:20px 24px;max-width:1400px;margin:0 auto}
.tabs{display:flex;gap:4px;margin-bottom:20px;background:var(--bg2);border-radius:10px;padding:4px;border:1px solid var(--border)}
.tab{padding:10px 20px;border-radius:8px;cursor:pointer;font-size:13px;font-weight:600;color:var(--t3);transition:.2s;display:flex;align-items:center;gap:6px}
.tab:hover{color:var(--tx)}.tab.active{background:rgba(34,211,238,.12);color:var(--cy)}
.tab-panel{display:none}.tab-panel.active{display:block}
.card{background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:20px;margin-bottom:16px}
.card h2{font-size:16px;font-weight:700;margin-bottom:12px;display:flex;align-items:center;gap:8px;color:var(--cy)}
.card h3{font-size:14px;font-weight:600;margin:12px 0 8px;color:var(--tx)}
.card p{font-size:13px;line-height:1.7;color:var(--t2);margin-bottom:8px}
.card ul{list-style:none;padding:0}.card li{font-size:13px;color:var(--t2);padding:4px 0 4px 20px;position:relative;line-height:1.6}
.card li::before{content:'✓';position:absolute;left:0;color:var(--gn);font-weight:700}
.g2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.g3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px}
.g4{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
.st{background:var(--bg3);border-radius:10px;padding:16px;text-align:center}
.st .v{font-size:24px;font-weight:800;font-family:'JetBrains Mono',monospace}
.st .l{font-size:10px;color:var(--t3);text-transform:uppercase;margin-top:4px}
.badge{padding:3px 10px;border-radius:4px;font-size:11px;font-weight:600;display:inline-block}
.b-gn{background:rgba(16,185,129,.15);color:var(--gn)}.b-cy{background:rgba(34,211,238,.15);color:var(--cy)}
.b-or{background:rgba(245,158,11,.15);color:var(--or)}.b-pu{background:rgba(167,139,250,.15);color:var(--pu)}
.b-pk{background:rgba(236,72,153,.15);color:var(--pk)}.b-rd{background:rgba(239,68,68,.15);color:var(--rd)}
table{width:100%;border-collapse:collapse;margin:8px 0}
th{background:var(--bg3);padding:10px 12px;text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--t2);border-bottom:1px solid var(--border)}
td{padding:8px 12px;border-bottom:1px solid rgba(30,41,59,.3);font-size:13px}
tr:hover{background:rgba(34,211,238,.03)}
.sim-box{background:var(--bg3);border:2px solid var(--cy);border-radius:12px;padding:24px}
.sim-row{display:flex;gap:16px;margin-bottom:16px;align-items:end;flex-wrap:wrap}
.sim-field{flex:1;min-width:180px}
.sim-field label{display:block;font-size:11px;color:var(--t3);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px}
.sim-field input,.sim-field select{width:100%;background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:10px 14px;color:var(--tx);font-size:14px;font-family:'JetBrains Mono',monospace}
.sim-field input:focus,.sim-field select:focus{outline:none;border-color:var(--cy)}
.btn{padding:10px 20px;border-radius:8px;border:none;cursor:pointer;font-size:13px;font-weight:700;transition:.2s;display:inline-flex;align-items:center;gap:6px}
.btn-cy{background:var(--cy);color:var(--bg)}.btn-cy:hover{filter:brightness(1.1)}
.result-box{background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:20px;margin-top:16px}
.price-big{font-size:36px;font-weight:800;color:var(--cy);font-family:'JetBrains Mono',monospace}
.price-label{font-size:11px;color:var(--t3);text-transform:uppercase}
.price-detail{font-size:12px;color:var(--t2);margin-top:4px;font-family:'JetBrains Mono',monospace}
.flow{display:flex;align-items:center;gap:4px;margin:16px 0;flex-wrap:wrap}
.flow-step{background:var(--bg3);border:1px solid var(--border);border-radius:8px;padding:12px 16px;text-align:center;flex:1;min-width:120px}
.flow-step .fs-icon{font-size:24px;margin-bottom:4px}
.flow-step .fs-title{font-size:11px;font-weight:700;color:var(--cy)}
.flow-step .fs-desc{font-size:10px;color:var(--t3);margin-top:2px}
.flow-arrow{color:var(--t3);font-size:18px}
.compliance-card{background:var(--bg3);border-radius:10px;padding:16px;border-left:3px solid var(--gn)}
.compliance-card h4{font-size:13px;font-weight:700;color:var(--gn);margin-bottom:6px}
.compliance-card p{font-size:12px;color:var(--t2);line-height:1.6}
.sms-rate{display:flex;align-items:center;gap:12px;background:var(--bg3);border-radius:8px;padding:12px 16px;margin-bottom:8px}
.sms-rate .flag{font-size:22px}.sms-rate .country{font-size:13px;font-weight:600;flex:1}
.sms-rate .rate{font-size:16px;font-weight:800;color:var(--cy);font-family:'JetBrains Mono',monospace}
.faq-item{border-bottom:1px solid var(--border);padding:12px 0}
.faq-q{font-size:14px;font-weight:700;color:var(--tx);cursor:pointer;display:flex;justify-content:space-between;align-items:center}
.faq-q:hover{color:var(--cy)}.faq-a{font-size:13px;color:var(--t2);line-height:1.7;padding-top:8px;display:none}
.faq-item.open .faq-a{display:block}.faq-item.open .faq-q .arrow{transform:rotate(90deg)}.faq-q .arrow{transition:.2s;color:var(--t3)}
@media(max-width:1200px){.g2,.g3{grid-template-columns:1fr}.g4{grid-template-columns:repeat(2,1fr)}}
</style>
</head>
<body>
<div class="hd"><h1>📐 <span>Ethica — Methodology & Pricing</span></h1><div style="display:flex;gap:8px"><span class="badge b-gn"><i class="fas fa-shield-alt"></i> Compliant</span><span class="badge b-cy"><i class="fas fa-envelope"></i> Email + SMS</span></div></div>
<div class="container">
<div class="tabs">
<div class="tab active" onclick="showTab('methodology')"><i class="fas fa-book"></i> Méthodologie</div>
<div class="tab" onclick="showTab('coverage')"><i class="fas fa-globe"></i> Couverture HCP</div>
<div class="tab" onclick="showTab('sms')"><i class="fas fa-sms"></i> Canal SMS</div>
<div class="tab" onclick="showTab('simulator')"><i class="fas fa-calculator"></i> Simulateur Prix</div>
<div class="tab" onclick="showTab('compliance')"><i class="fas fa-shield-alt"></i> Compliance</div>
<div class="tab" onclick="showTab('faq')"><i class="fas fa-question-circle"></i> FAQ Client</div>
</div>
<!-- TAB METHODOLOGY -->
<div class="tab-panel active" id="panel-methodology">
<div class="card"><h2><i class="fas fa-project-diagram"></i> Pipeline de Campagne E2E</h2><p>Chaque campagne suit un pipeline contrôlé de bout en bout :</p>
<div class="flow">
<div class="flow-step"><div class="fs-icon">🎯</div><div class="fs-title">Ciblage</div><div class="fs-desc">Spécialités × Pays × Ville</div></div><span class="flow-arrow"></span>
<div class="flow-step"><div class="fs-icon"></div><div class="fs-title">Qualification</div><div class="fs-desc">Vérif. HCP + Email + Tel</div></div><span class="flow-arrow"></span>
<div class="flow-step"><div class="fs-icon">📧</div><div class="fs-title">E-Consent</div><div class="fs-desc">Opt-in avant envoi</div></div><span class="flow-arrow"></span>
<div class="flow-step"><div class="fs-icon">🚀</div><div class="fs-title">Envoi</div><div class="fs-desc">Email + SMS multi-canal</div></div><span class="flow-arrow"></span>
<div class="flow-step"><div class="fs-icon">📊</div><div class="fs-title">Tracking</div><div class="fs-desc">Opens, Clicks, Conv.</div></div><span class="flow-arrow"></span>
<div class="flow-step"><div class="fs-icon">📋</div><div class="fs-title">Reporting</div><div class="fs-desc">KPIs par campagne</div></div>
</div></div>
<div class="g2">
<div class="card"><h2><i class="fas fa-database"></i> 1. Constitution de la Base</h2>
<p>Base constituée exclusivement de <strong>sources publiques professionnelles légales</strong> :</p>
<h3>Sources Officielles</h3><ul><li>Conseil National de l'Ordre des Médecins (CNOM) — MA, TN, DZ</li><li>Conseil de l'Ordre des Pharmaciens (CNOP)</li><li>Conseil de l'Ordre des Médecins Dentistes (CNOMD)</li><li>Registres professionnels nationaux</li></ul>
<h3>Sources Médicales</h3><ul><li>DabaDoc, Doctoralia, Avicenna (annuaires médicaux)</li><li>Annuaires d'établissements de santé publics et privés</li><li>Partenariats éditeurs spécialisés santé</li></ul>
<h3>Enrichissement IA</h3><ul><li>IA de qualification HCP depuis sources légales</li><li>Cross-validation automatique multi-sources</li><li>Détection doublons et normalisation</li></ul></div>
<div class="card"><h2><i class="fas fa-check-double"></i> 2. Vérification HCP — 5 Étapes</h2>
<h3>Étape 1 — Validation Identité</h3><ul><li>Croisement avec registres officiels de l'Ordre</li><li>Vérification numéro d'inscription</li><li>Confirmation spécialité et lieu d'exercice</li></ul>
<h3>Étape 2 — Validation Email</h3><ul><li>Vérification MX record du domaine</li><li>Test SMTP de délivrabilité</li><li>Classification : Valid / Risky / Catch-all / Invalid</li></ul>
<h3>Étape 3 — Validation Téléphone</h3><ul><li>Format international (+212, +216, +213)</li><li>Détection mobile vs fixe</li><li>Eligibilité SMS (mobile uniquement)</li></ul>
<h3>Étape 4 — Déduplication Cross-Source</h3><ul><li>Détection doublons multi-critères</li><li>Fusion des fiches multi-sources</li></ul>
<h3>Étape 5 — E-Consentement</h3><ul><li>Opt-in avec lien sécurisé (consent.wevup.app)</li><li>Horodatage : date, IP, méthode</li><li>Preuve exportable (audit trail)</li></ul></div>
</div>
<div class="g2">
<div class="card"><h2><i class="fas fa-sync-alt"></i> 3. Fréquence de Mise à Jour</h2>
<table><tr><th>Process</th><th>Fréquence</th><th>Action</th></tr>
<tr><td>Bounce processing</td><td><span class="badge b-gn">Temps réel</span></td><td>Suppression auto emails invalides après envoi</td></tr>
<tr><td>SMTP/MX validation</td><td><span class="badge b-cy">Hebdomadaire</span></td><td>Re-vérification technique emails actifs</td></tr>
<tr><td>Cross-validation Ordres</td><td><span class="badge b-or">Trimestrielle</span></td><td>Croisement registres officiels</td></tr>
<tr><td>Purge inactifs</td><td><span class="badge b-pu">Mensuelle</span></td><td>Suppression HCP inactifs > 6 mois</td></tr>
<tr><td>Enrichissement</td><td><span class="badge b-pk">Continue</span></td><td>Ajout nouveaux HCP via IA</td></tr>
<tr><td>Scraping annuaires</td><td><span class="badge b-cy">Bimensuelle</span></td><td>Re-scan <span id="src-count-inline">30</span> sources</td></tr></table></div>
<div class="card"><h2><i class="fas fa-inbox"></i> 4. Délivrabilité & KPIs</h2>
<table><tr><th>KPI</th><th>Industrie Pharma</th><th>Notre Objectif</th></tr>
<tr><td>Délivrabilité</td><td style="color:var(--t3)">85-90%</td><td style="color:var(--gn);font-weight:700">>95%</td></tr>
<tr><td>Open Rate</td><td style="color:var(--t3)">15-20%</td><td style="color:var(--gn);font-weight:700">25-35%</td></tr>
<tr><td>CTR</td><td style="color:var(--t3)">2-4%</td><td style="color:var(--gn);font-weight:700">5-8%</td></tr>
<tr><td>Bounce</td><td style="color:var(--t3)">5-10%</td><td style="color:var(--gn);font-weight:700">&lt;2%</td></tr>
<tr><td>Spam Complaint</td><td style="color:var(--t3)">0.1-0.3%</td><td style="color:var(--gn);font-weight:700">&lt;0.05%</td></tr></table>
<p style="margin-top:8px"><strong>Pourquoi ces résultats ?</strong></p>
<ul><li>Base qualifiée — uniquement HCP vérifiés</li><li>Infrastructure email propriétaire avec IP warm-up dédié</li><li>Rotation domaines + ISP-specific routing</li><li>Consentement préalable = meilleur engagement</li></ul></div>
</div></div>
<!-- TAB COVERAGE -->
<div class="tab-panel" id="panel-coverage">
<div class="g4" id="cov-stats">
<div class="st"><div class="v" style="color:var(--cy)" id="k-total-hcp"></div><div class="l">Total HCPs Base</div></div>
<div class="st"><div class="v" style="color:var(--gn)" id="k-target"></div><div class="l">Cibles Ethica</div></div>
<div class="st"><div class="v" style="color:var(--pu)" id="k-with-email"></div><div class="l">Avec Email</div></div>
<div class="st"><div class="v" style="color:var(--pk)" id="k-with-phone"></div><div class="l">Avec Téléphone (SMS)</div></div>
</div>
<div class="card" style="margin-top:16px"><h2><i class="fas fa-th"></i> Matrice de Couverture — Spécialités Ethica × Pays</h2>
<p>Nombre de HCPs par spécialité et par pays (base brute avant filtrage) :</p>
<div style="overflow-x:auto"><table><thead><tr><th>Spécialité</th><th>🇲🇦 Maroc</th><th>🇩🇿 Algérie</th><th>🇹🇳 Tunisie</th><th>Total</th></tr></thead>
<tbody id="matrix-body"><tr><td colspan="5" style="text-align:center;color:var(--t3);padding:20px">Chargement...</td></tr></tbody></table></div></div>
<div class="card"><h2><i class="fas fa-info-circle"></i> Note sur les Volumes</h2>
<p>Les chiffres ci-dessus = <strong>base brute totale</strong>. Après qualification complète (vérification HCP, validation email, déduplication, e-consentement), les volumes exploitables seront <strong>significativement réduits</strong>. C'est cette approche qualitative qui garantit les KPIs supérieurs.</p></div>
</div>
<!-- TAB SMS -->
<div class="tab-panel" id="panel-sms">
<div class="g2">
<div class="card"><h2><i class="fas fa-sms"></i> Canal SMS — Campagnes HCP</h2>
<p>Canal complémentaire à l'email pour les communications à fort taux de lecture.</p>
<h3>Avantages SMS HCP</h3><ul><li>Taux de lecture > 95% (vs 25% email)</li><li>Délai de lecture &lt; 3 min (vs 6h email)</li><li>Idéal : invitations congrès, alertes produit, rappels</li><li>Stratégie omnicanale Email + SMS</li><li>Fonctionne sans connexion internet</li></ul>
<h3>Types de Campagnes</h3>
<table><tr><th>Type</th><th>Usage</th><th>Exemple</th></tr>
<tr><td><span class="badge b-cy">Marketing</span></td><td>Promotion produit</td><td>"Découvrez [Produit] — info sur [lien]"</td></tr>
<tr><td><span class="badge b-gn">Invitation</span></td><td>Congrès / Webinaire</td><td>"Invitation au webinaire [X] le [date]"</td></tr>
<tr><td><span class="badge b-or">Rappel</span></td><td>Follow-up</td><td>"Rappel : votre invitation expire demain"</td></tr>
<tr><td><span class="badge b-pu">Consentement</span></td><td>Opt-in SMS</td><td>"Confirmez : répondez OUI"</td></tr></table></div>
<div><div class="card"><h2><i class="fas fa-money-bill"></i> Tarification SMS</h2>
<div class="sms-rate"><span class="flag">🇲🇦</span><span class="country">Maroc</span><span class="rate">0,04 €</span></div>
<div class="sms-rate"><span class="flag">🇹🇳</span><span class="country">Tunisie</span><span class="rate">0,05 €</span></div>
<div class="sms-rate"><span class="flag">🇩🇿</span><span class="country">Algérie</span><span class="rate">0,06 €</span></div>
<table style="margin-top:16px"><tr><th>Volume/mois</th><th>Coût estimé</th></tr>
<tr><td>5 000 SMS</td><td style="color:var(--cy);font-weight:700">~250 €</td></tr>
<tr><td>10 000 SMS</td><td style="color:var(--cy);font-weight:700">~500 €</td></tr>
<tr><td>25 000 SMS</td><td style="color:var(--cy);font-weight:700">~1 250 €</td></tr></table></div>
<div class="card"><h2><i class="fas fa-mobile-alt"></i> Couverture SMS</h2>
<div class="st" style="margin-bottom:12px"><div class="v" style="color:var(--pk)" id="k-sms-phones"></div><div class="l">HCPs avec mobile validé</div></div>
<h3>Infrastructure</h3><ul><li>10 providers SMS multi-routes</li><li>Sender ID personnalisable par marque</li><li>Opt-out auto (STOP SMS)</li><li>Reporting temps réel</li></ul></div></div>
</div></div>
<!-- TAB SIMULATOR -->
<div class="tab-panel" id="panel-simulator">
<div class="sim-box"><h2 style="color:var(--cy);margin-bottom:16px"><i class="fas fa-calculator"></i> Simulateur de Prix — Email + SMS</h2>
<div class="sim-row">
<div class="sim-field"><label>Emails par mois</label><input type="number" id="sim-emails" value="10000" min="0" step="1000" onchange="simulate()"></div>
<div class="sim-field"><label>SMS par mois</label><input type="number" id="sim-sms" value="5000" min="0" step="500" onchange="simulate()"></div>
<div class="sim-field"><label>Nombre de marques</label><select id="sim-brands" onchange="simulate()"><option value="1">1 marque</option><option value="2">2 marques</option><option value="3">3 marques</option><option value="5">5 marques</option><option value="8">8 marques</option><option value="10" selected>10 marques</option></select></div>
<div class="sim-field"><label>Durée (mois)</label><select id="sim-months" onchange="simulate()"><option value="1">1 mois</option><option value="3">3 mois</option><option value="6">6 mois</option><option value="12" selected>12 mois</option></select></div>
<div><button class="btn btn-cy" onclick="simulate()"><i class="fas fa-calculator"></i> Simuler</button></div>
</div>
<div class="result-box" id="sim-results">
<div class="g4">
<div class="st"><div class="price-label">Email / mois</div><div class="price-big" id="res-email"></div><div class="price-detail" id="res-email-detail"></div></div>
<div class="st"><div class="price-label">SMS / mois</div><div class="price-big" id="res-sms" style="color:var(--pk)"></div><div class="price-detail" id="res-sms-detail"></div></div>
<div class="st"><div class="price-label">Total Mensuel</div><div class="price-big" id="res-monthly" style="color:var(--gn)"></div><div class="price-detail" id="res-discount"></div></div>
<div class="st" style="border:2px solid var(--cy)"><div class="price-label">Total Période</div><div class="price-big" id="res-total"></div><div class="price-detail" id="res-period"></div></div>
</div>
<div class="g2" style="margin-top:16px">
<div class="card" style="margin:0"><h3 style="color:var(--or)"><i class="fas fa-chart-bar"></i> CPM (Cost Per Mille)</h3>
<table><tr><td>Email CPM</td><td style="font-weight:700;color:var(--cy)" id="res-cpm-email"></td><td style="color:var(--t3)">vs marché: 150-300€</td></tr>
<tr><td>SMS CPM</td><td style="font-weight:700;color:var(--pk)" id="res-cpm-sms"></td><td style="color:var(--t3)">vs marché: 40-80€</td></tr></table></div>
<div class="card" style="margin:0"><h3 style="color:var(--gn)"><i class="fas fa-tags"></i> Remise Multi-Marques</h3>
<table><tr><td>2 marques</td><td><span class="badge b-or">-5%</span></td></tr>
<tr><td>3-4 marques</td><td><span class="badge b-cy">-10%</span></td></tr>
<tr><td>5+ marques</td><td><span class="badge b-gn">-15%</span></td></tr></table></div>
</div></div></div>
<div class="card" style="margin-top:16px"><h2><i class="fas fa-receipt"></i> Grille Tarifaire Email</h2>
<table><tr><th>Tranche</th><th>Volume/mois</th><th>Tarif</th><th>CPM</th></tr>
<tr><td>1</td><td>1 à 15 000</td><td style="color:var(--cy);font-weight:700">3 000 €</td><td>200 €</td></tr>
<tr><td>2</td><td>15 001 à 30 000</td><td style="color:var(--cy);font-weight:700">6 000 €</td><td>200 €</td></tr>
<tr><td>3</td><td>30 001 à 45 000</td><td style="color:var(--cy);font-weight:700">9 000 €</td><td>200 €</td></tr>
<tr><td>N</td><td>+15 000</td><td style="color:var(--cy);font-weight:700">+3 000 €</td><td>200 €</td></tr></table>
<p style="margin-top:8px;font-size:12px;color:var(--t3)">Tarifs = volume total emails/mois, toutes campagnes et marques confondues. Remise multi-marques applicable.</p></div>
</div>
<!-- TAB COMPLIANCE -->
<div class="tab-panel" id="panel-compliance">
<div class="g3">
<div class="compliance-card"><h4>🇲🇦 Maroc — Loi 09-08</h4><p>CNDP. Déclaration préalable, consentement éclairé, droit d'accès/rectification/suppression.</p></div>
<div class="compliance-card"><h4>🇹🇳 Tunisie — Loi 63-2004</h4><p>INPDP. Consentement explicite, notification de traitement, droit d'opposition.</p></div>
<div class="compliance-card"><h4>🇩🇿 Algérie — Loi 18-07</h4><p>ANPDP. Déclaration obligatoire, consentement libre, finalité déterminée.</p></div>
</div>
<div class="card" style="margin-top:16px"><h2><i class="fas fa-lock"></i> Dispositif de Consentement</h2>
<div class="g2"><div><h3>E-Consent Email</h3><ul><li>URL : consent.wevup.app (SSL)</li><li>Token unique par contact</li><li>Opt-in / Opt-out / Préférences</li><li>Horodatage complet (date, IP, méthode)</li><li>Preuve exportable (audit)</li></ul></div>
<div><h3>E-Consent SMS</h3><ul><li>Opt-in par réponse SMS ("OUI"/"STOP")</li><li>Double opt-in : confirmation SMS</li><li>Désabonnement instantané (STOP)</li><li>Gestion séparée email/SMS</li><li>Registre auditable</li></ul></div></div></div>
<div class="card"><h2><i class="fas fa-file-contract"></i> Engagements Contractuels</h2>
<table><tr><th>Engagement</th><th>Détail</th></tr>
<tr><td>Base de données</td><td>Propriété WEVAL — aucune cession. Client = accès résultats campagne uniquement.</td></tr>
<tr><td>Exclusivité HCP</td><td>100% professionnels de santé vérifiés — zéro contact grand public.</td></tr>
<tr><td>SLA Délivrabilité</td><td>>95% délivrabilité. Sous-performance = re-envoi gratuit.</td></tr>
<tr><td>Confidentialité</td><td>NDA standard. Créatifs = propriété client.</td></tr>
<tr><td>Résiliation</td><td>Préavis 30 jours. Pas d'engagement minimum (hors pilote).</td></tr></table></div>
</div>
<!-- TAB FAQ -->
<div class="tab-panel" id="panel-faq">
<div class="card"><h2><i class="fas fa-question-circle"></i> FAQ Client — Ethica</h2>
<div class="faq-item open"><div class="faq-q" onclick="toggleFaq(this)">La base semble dépasser l'univers de référence. Pourquoi ? <span class="arrow"></span></div>
<div class="faq-a">La base partagée était <strong>brute et illustrative</strong>. Elle inclut tous les contacts identifiés sans filtrage. Après qualification complète (vérification HCP, validation email/tel, déduplication, e-consentement), les volumes exploitables seront significativement réduits. Ex : sur 175K généralistes bruts → 15-30K qualifiés et consentants.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Vos tarifs sont 3x supérieurs à nos fournisseurs actuels. <span class="arrow"></span></div>
<div class="faq-a">Nos tarifs = prestation complète (qualification HCP, infra propriétaire, consentement conforme, tracking). Les KPIs sont supérieurs (>25% open rate vs 15% marché). Le <strong>coût par contact engagé</strong> est inférieur. 1 email lu en inbox > 3 emails en spam. Remise jusqu'à <strong>-15% multi-marques</strong> (10 marques Ethica).</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Tarifs par campagne ou par mois ? <span class="arrow"></span></div>
<div class="faq-a">Volume <strong>total d'emails/mois</strong>, toutes campagnes et marques confondues. Ex : 2 campagnes × 5 000 = 10 000 emails = 3 000 €/mois (tranche 1). Plus avantageux pour les clients multi-marques.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Proposez-vous des campagnes SMS ? <span class="arrow"></span></div>
<div class="faq-a">Oui. 10 providers SMS configurés (MA/TN/DZ). Tarifs : 0,04€ (MA), 0,05€ (TN), 0,06€ (DZ)/SMS. Idéal en complément email : invitations congrès, rappels, alertes produit. Taux lecture >95%.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Comment gérez-vous le consentement ? <span class="arrow"></span></div>
<div class="faq-a">Opt-in obligatoire avant envoi via consent.wevup.app (token unique, horodatage, preuve exportable). Conforme Loi 09-08 (MA), 63-2004 (TN), 18-07 (DZ). Opt-out temps réel. Gestion séparée email/SMS.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Phase pilote possible ? <span class="arrow"></span></div>
<div class="faq-a">Oui : 1-2 spécialités × 1 pays pendant 1-2 mois. Tarif standard, sans engagement. Valide les KPIs avant déploiement large.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Quelle timeline de déploiement ? <span class="arrow"></span></div>
<div class="faq-a"><strong>Q4 2026</strong> : Pilote 1-2 marques. <strong>Q1 2027</strong> : Déploiement multi-marques + intégration BP 2027.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Quels formats de campagne ? <span class="arrow"></span></div>
<div class="faq-a">Email HTML responsive (templates fournis ou custom), SMS texte (160 car.), campagnes omnicanales (email + SMS séquencé). Client fournit créatifs, nous gérons intégration/envoi/suivi.</div></div>
</div></div>
</div>
<script>
const API='api/ethica-methodology-api.php';
function fmt(n){return n!=null?Number(n).toLocaleString('fr-FR'):'—'}
function fmtEur(n){return n!=null?Number(n).toLocaleString('fr-FR')+' €':'—'}
function showTab(id){document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active'));document.querySelectorAll('.tab-panel').forEach(p=>p.classList.remove('active'));document.getElementById('panel-'+id).classList.add('active');event.currentTarget.classList.add('active')}
function toggleFaq(el){el.parentElement.classList.toggle('open')}
async function loadCoverage(){try{const r=await fetch(API+'?action=coverage');const d=await r.json();document.getElementById('k-total-hcp').textContent=fmt(d.total_hcp);document.getElementById('k-target').textContent=fmt(d.target_total);document.getElementById('k-with-email').textContent=fmt(d.with_email);document.getElementById('k-with-phone').textContent=fmt(d.with_phone);document.getElementById('k-sms-phones').textContent=fmt(d.with_phone);if(d.sources)document.getElementById('src-count-inline').textContent=d.sources;const specs={};(d.target_specs||[]).forEach(s=>{if(!specs[s.specialite])specs[s.specialite]={MA:0,DZ:0,TN:0,total:0};specs[s.specialite][s.pays]=parseInt(s.c);specs[s.specialite].total+=parseInt(s.c)});const labels={'generaliste':'Médecin Généraliste','pharmacien':'Pharmacien','rhumatologue':'Rhumatologue','orthopediste':'Orthopédiste','pneumologue':'Pneumologue','allergologue':'Allergologue','orl':'ORL','gastro-enterologue':'Gastro-entérologue','pediatre':'Pédiatre','dentiste':'Dentiste','gynecologue':'Gynécologue','cardiologue':'Cardiologue'};let html='',tMA=0,tDZ=0,tTN=0,tAll=0;Object.keys(specs).sort().forEach(k=>{const s=specs[k];tMA+=s.MA;tDZ+=s.DZ;tTN+=s.TN;tAll+=s.total;html+=`<tr><td style="font-weight:600">${labels[k]||k}</td><td style="text-align:center">${fmt(s.MA)}</td><td style="text-align:center">${fmt(s.DZ)}</td><td style="text-align:center">${fmt(s.TN)}</td><td style="text-align:center;font-weight:700;color:var(--cy)">${fmt(s.total)}</td></tr>`});html+=`<tr style="background:var(--bg3);font-weight:700"><td>TOTAL</td><td style="text-align:center;color:var(--gn)">${fmt(tMA)}</td><td style="text-align:center;color:var(--gn)">${fmt(tDZ)}</td><td style="text-align:center;color:var(--gn)">${fmt(tTN)}</td><td style="text-align:center;color:var(--cy)">${fmt(tAll)}</td></tr>`;document.getElementById('matrix-body').innerHTML=html}catch(e){console.error(e)}}
function simulate(){const emails=parseInt(document.getElementById('sim-emails').value)||0;const sms=parseInt(document.getElementById('sim-sms').value)||0;const brands=parseInt(document.getElementById('sim-brands').value)||1;const months=parseInt(document.getElementById('sim-months').value)||12;const emailTranches=Math.max(0,Math.ceil(emails/15000));const emailCost=emailTranches*3000;const smsCost=Math.round(sms*0.05);let discount=0;if(brands>=5)discount=0.15;else if(brands>=3)discount=0.10;else if(brands>=2)discount=0.05;const monthly=Math.round((emailCost+smsCost)*(1-discount));document.getElementById('res-email').textContent=fmtEur(emailCost);document.getElementById('res-email-detail').textContent=emailTranches+' tranche(s) × 3 000 €';document.getElementById('res-sms').textContent=fmtEur(smsCost);document.getElementById('res-sms-detail').textContent=fmt(sms)+' SMS × 0,05 € moy.';document.getElementById('res-monthly').textContent=fmtEur(monthly);document.getElementById('res-discount').textContent=discount>0?'Remise '+discount*100+'% ('+brands+' marques)':'Sans remise';document.getElementById('res-total').textContent=fmtEur(monthly*months);document.getElementById('res-period').textContent='Sur '+months+' mois';document.getElementById('res-cpm-email').textContent=emails>0?fmtEur(Math.round(emailCost/emails*1000)):'—';document.getElementById('res-cpm-sms').textContent=sms>0?fmtEur(Math.round(smsCost/sms*1000)):'—'}
loadCoverage();simulate();
</script>
</body>
</html>

View File

@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="fr"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Arsenal Recovered · 4 Pages historiques</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{background:#060a14;color:#e2e8f0;font-family:-apple-system,'Segoe UI',sans-serif;font-size:13px;padding:30px;line-height:1.5}
h1{font-size:24px;background:linear-gradient(135deg,#22d3ee,#a78bfa);-webkit-background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:8px}
.meta{color:#64748b;font-size:11px;margin-bottom:24px;font-family:monospace}
.banner{background:rgba(52,211,153,.12);border:1px solid rgba(52,211,153,.3);padding:16px 20px;border-radius:10px;margin-bottom:24px;font-size:12px;color:#cbd5e1}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px;max-width:1200px}
.card{background:#0c1220;border:1px solid #1e293b;border-radius:12px;padding:20px;transition:all .2s}
.card:hover{border-color:#22d3ee;transform:translateY(-2px)}
.card h3{font-size:15px;margin-bottom:8px;color:#22d3ee;font-family:monospace}
.card .ts{color:#64748b;font-size:10px;margin-bottom:12px}
.card a{display:block;padding:9px 14px;background:#111827;border:1px solid #1e293b;border-radius:6px;color:#22d3ee;text-decoration:none;font-size:11px;font-weight:600;text-align:center}
.card a:hover{border-color:#22d3ee}
.btn-back{display:inline-block;padding:8px 16px;background:#0c1220;border:1px solid #1e293b;border-radius:8px;color:#22d3ee;text-decoration:none;font-size:11px;margin-top:24px}
</style></head><body>
<h1>📦 Arsenal Recovered · Pages historiques</h1>
<div class="meta">4 pages recuperees du S89 archive (jamais en live menu)</div>
<div class="banner">✅ Ces pages existaient dans l'archive S89 mais n'apparaissaient pas dans le menu Arsenal live. Restauration complete pour zero perte.</div>
<div class="grid">
<div class="card">
<h3>📚 Ethica Audit</h3>
<div class="ts">size: 13840B · source: S89 archive</div>
<a href="/arsenal-recovered/ethica-audit.html" target="_blank">Ouvrir page recovered</a>
</div><div class="card">
<h3>📚 Ethica Methodology</h3>
<div class="ts">size: 29159B · source: S89 archive</div>
<a href="/arsenal-recovered/ethica-methodology.html" target="_blank">Ouvrir page recovered</a>
</div><div class="card">
<h3>📚 Manual Send Engine</h3>
<div class="ts">size: 14844B · source: S89 archive</div>
<a href="/arsenal-recovered/manual-send-engine.html" target="_blank">Ouvrir page recovered</a>
</div><div class="card">
<h3>📚 Wevia Nexus Ultimate 2026</h3>
<div class="ts">size: 48193B · source: S89 archive</div>
<a href="/arsenal-recovered/wevia-nexus-ultimate-2026.html" target="_blank">Ouvrir page recovered</a>
</div></div>
<a href="/arsenal-master.html" class="btn-back">← Arsenal Master</a>
<a href="/arsenal-history/" class="btn-back">📚 Arsenal History (6 versions)</a>
<a href="/weval-mega-master.html" class="btn-back">🌐 Mega Master</a>
</body></html>

View File

@@ -0,0 +1,224 @@
<!DOCTYPE html><html lang="fr"><head>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>WEVADS - Manual Send Engine</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<style>
:root{--bg:#060a14;--s:#0c1220;--s2:#111827;--b:#1e293b;--t:#e2e8f0;--d:#64748b;--cy:#22d3ee;--gn:#34d399;--am:#fbbf24;--rd:#f87171;--pu:#a78bfa;--bl:#60a5fa;--og:#fb923c}
*{margin:0;padding:0;box-sizing:border-box}body{background:var(--bg);color:var(--t);font-family:'DM Sans',sans-serif;font-size:11px}
.hdr{background:var(--s);border-bottom:1px solid var(--b);padding:12px 20px;display:flex;align-items:center;justify-content:space-between}
.hdr h1{font-size:16px;font-weight:700}.hdr h1 span{color:var(--og)}
.wrap{padding:16px;max-width:1400px;margin:0 auto}
.tabs{display:flex;gap:4px;margin-bottom:16px;flex-wrap:wrap}
.tab{padding:8px 16px;border-radius:8px 8px 0 0;border:1px solid var(--b);border-bottom:none;background:var(--s2);color:var(--d);cursor:pointer;font-size:11px;font-weight:600;transition:.2s}
.tab.active{background:var(--s);color:var(--cy);border-color:var(--cy)}
.tab:hover{color:var(--t)}
.tab-content{display:none}.tab-content.active{display:block}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.grid3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px}
.grid4{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:8px}
.card{background:var(--s);border:1px solid var(--b);border-radius:10px;padding:16px;margin-bottom:12px;position:relative;overflow:hidden;transition:.25s}
.card:hover{transform:translateY(-1px);box-shadow:0 8px 24px rgba(0,0,0,.25)}
.card::after{content:'';position:absolute;bottom:0;left:0;right:0;height:2px;opacity:0;transition:.25s}.card:hover::after{opacity:.7}
.card-cy::after{background:var(--cy)}.card-gn::after{background:var(--gn)}.card-am::after{background:var(--am)}.card-rd::after{background:var(--rd)}.card-pu::after{background:var(--pu)}.card-og::after{background:var(--og)}
.form-row{margin-bottom:10px}.form-row label{display:block;font-size:9px;text-transform:uppercase;color:var(--d);margin-bottom:4px;letter-spacing:.5px}
.form-row input,.form-row select,.form-row textarea{width:100%;background:var(--s2);border:1px solid var(--b);color:var(--t);padding:8px;border-radius:6px;font-size:11px;font-family:'DM Sans',sans-serif}
.form-row select[multiple]{min-height:120px}
.form-row textarea{min-height:100px;font-family:'JetBrains Mono',monospace;font-size:10px}
.btn{padding:8px 16px;border-radius:8px;border:1px solid var(--b);background:var(--s2);color:var(--t);cursor:pointer;font-size:11px;font-weight:600;text-align:center;transition:.2s}.btn:hover{border-color:var(--cy);transform:translateY(-1px)}
.btn-send{background:rgba(248,113,113,.15);border-color:var(--rd);color:var(--rd);padding:14px;font-size:14px;font-weight:700;width:100%}
.btn-send:hover{background:rgba(248,113,113,.25)}
.btn-gn{background:rgba(52,211,153,.15);border-color:var(--gn);color:var(--gn)}
.btn-cy{background:rgba(34,211,238,.15);border-color:var(--cy);color:var(--cy)}
.btn-am{background:rgba(251,191,36,.15);border-color:var(--am);color:var(--am)}
.btn-pu{background:rgba(167,139,250,.15);border-color:var(--pu);color:var(--pu)}
.badge{font-size:8px;padding:2px 6px;border-radius:3px;font-weight:600}
.badge-gn{background:rgba(52,211,153,.15);color:var(--gn)}.badge-am{background:rgba(251,191,36,.15);color:var(--am)}.badge-rd{background:rgba(248,113,113,.15);color:var(--rd)}.badge-cy{background:rgba(34,211,238,.15);color:var(--cy)}
.stat{text-align:center;padding:12px}.stat .num{font-size:24px;font-weight:700;font-family:'JetBrains Mono',monospace}.stat .lbl{font-size:9px;color:var(--d);text-transform:uppercase;margin-top:4px}
.mono{font-family:'JetBrains Mono',monospace}
table{width:100%;border-collapse:collapse;font-size:10px}th{text-align:left;color:var(--d);text-transform:uppercase;font-size:9px;padding:6px 8px;border-bottom:1px solid var(--b)}td{padding:6px 8px;border-bottom:1px solid rgba(30,41,59,.3)}
.log{background:var(--bg);border:1px solid var(--b);border-radius:6px;padding:10px;font-family:'JetBrains Mono',monospace;font-size:10px;max-height:300px;overflow-y:auto;white-space:pre-wrap}
.step-num{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:50%;font-size:11px;font-weight:700;margin-right:8px}
.step-cy{background:rgba(34,211,238,.2);color:var(--cy);border:1px solid var(--cy)}
.step-gn{background:rgba(52,211,153,.2);color:var(--gn);border:1px solid var(--gn)}
.step-am{background:rgba(251,191,36,.2);color:var(--am);border:1px solid var(--am)}
.step-rd{background:rgba(248,113,113,.2);color:var(--rd);border:1px solid var(--rd)}
.step-pu{background:rgba(167,139,250,.2);color:var(--pu);border:1px solid var(--pu)}
.step-og{background:rgba(251,146,60,.2);color:var(--og);border:1px solid var(--og)}
.winner-tag{background:rgba(52,211,153,.15);color:var(--gn);border:1px solid var(--gn);padding:2px 8px;border-radius:4px;font-size:9px;font-weight:600}
.method-tag{display:inline-block;background:var(--s2);border:1px solid var(--b);border-radius:4px;padding:3px 8px;font-size:9px;margin:2px;cursor:pointer;transition:.2s}
.method-tag:hover,.method-tag.selected{border-color:var(--cy);color:var(--cy);background:rgba(34,211,238,.1)}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
.card{animation:fadeIn .4s ease both}
@media(max-width:900px){.grid2,.grid3,.grid4{grid-template-columns:1fr}}
#toast{position:fixed;bottom:20px;right:20px;padding:12px 20px;border-radius:8px;font-size:12px;font-weight:600;z-index:9999;display:none;animation:fadeIn .3s}
.toast-gn{background:rgba(52,211,153,.9);color:#000}.toast-rd{background:rgba(248,113,113,.9);color:#000}.toast-am{background:rgba(251,191,36,.9);color:#000}
</style>
<link rel="stylesheet" href="wevads-global.css?v1770777318">
</head><body>
<div class="hdr">
<div>
<h1>⚡ WEVADS • <span>Manual Send Engine</span></h1>
<p style="font-size:10px;color:var(--d);margin-top:4px">Envoi manuel par méthode — Brain-prefilled — Remplacement des crons</p>
</div>
<div style="display:flex;gap:8px;align-items:center">
<button class="btn btn-cy" onclick="loadBrainPresets()" style="padding:6px 12px">🧠 Load Brain</button>
<button class="btn btn-gn" onclick="refreshAll()" style="padding:6px 12px">🔄 Refresh</button>
<span class="badge badge-am">● MANUAL MODE</span>
<span class="mono" style="font-size:11px;color:var(--d)" id="clock"></span>
</div>
</div>
<div class="wrap">
<!-- Stats bar -->
<div class="grid4" style="margin-bottom:12px">
<div class="card card-cy"><div class="stat"><div class="num" style="color:var(--cy)" id="st-methods">14</div><div class="lbl">Send Methods</div></div></div>
<div class="card card-gn"><div class="stat"><div class="num" style="color:var(--gn)" id="st-winners">11</div><div class="lbl">Brain Winners</div></div></div>
<div class="card card-am"><div class="stat"><div class="num" style="color:var(--am)" id="st-contacts">927K</div><div class="lbl">Contacts</div></div></div>
<div class="card card-pu"><div class="stat"><div class="num" style="color:var(--pu)" id="st-offers">85</div><div class="lbl">Offers Active</div></div></div>
</div>
<!-- Tabs by Send Method -->
<div class="tabs" id="method-tabs">
<div class="tab active" onclick="switchTab('o365')">📧 O365 Graph</div>
<div class="tab" onclick="switchTab('pmta')">🔧 PMTA Direct</div>
<div class="tab" onclick="switchTab('smtp_relay')">📡 SMTP Relay</div>
<div class="tab" onclick="switchTab('gsuite')">🔷 GSuite</div>
<div class="tab" onclick="switchTab('hybrid')">🔀 Hybrid</div>
<div class="tab" onclick="switchTab('api')">🌐 API (SG/MG/SES)</div>
</div>
<!-- ============================================================ -->
<!-- UNIFIED SEND FORM (shared across tabs, method-specific hints) -->
<!-- ============================================================ -->
<div class="grid2">
<div>
<!-- STEP 1: Sponsor & Offer -->
<div class="card card-cy">
<h3 style="font-size:12px;margin-bottom:10px"><span class="step-num step-cy">1</span> <span style="color:var(--cy)">SPONSOR & OFFRE</span></h3>
<div class="grid2">
<div class="form-row"><label>Sponsor</label>
<select id="sel-sponsor" onchange="loadOffers()">
<option value="">— Sélectionner —</option>
<option value="1">CX3 Ads</option>
<option value="2">Double M</option>
<option value="3">Ethica Pharma</option>
</select></div>
<div class="form-row"><label>Offre</label>
<select id="sel-offer"><option value="">— Charger sponsor d'abord —</option></select></div>
</div>
<div class="form-row"><label>Tracking URL (auto-filled)</label>
<input id="in-tracking" readonly style="color:var(--cy);background:var(--bg)" placeholder="Sélectionner une offre..."></div>
<div style="font-size:9px;color:var(--d);margin-top:4px">Payout: <span id="lbl-payout" style="color:var(--gn);font-weight:700">$0.00</span></div>
</div>
<!-- STEP 2: Data / Recipients -->
<div class="card card-gn">
<h3 style="font-size:12px;margin-bottom:10px"><span class="step-num step-gn">2</span> <span style="color:var(--gn)">DATA / RECIPIENTS</span></h3>
<div class="form-row"><label>ISP Cible</label>
<select id="sel-isp" onchange="updateContactCount()">
<option value="all">Tous ISPs (927,007)</option>
<option value="hotmail">Hotmail/Outlook (303,858)</option>
<option value="gmx">GMX (176,966)</option>
<option value="tonline">T-Online (157,573)</option>
<option value="webde">Web.de (131,545)</option>
<option value="videotron">Videotron (131,386)</option>
<option value="gmail">Gmail (20,000)</option>
<option value="spectrum">Spectrum (5,679)</option>
</select></div>
<div class="grid3">
<div class="form-row"><label>Volume</label>
<select id="sel-volume">
<option value="10">10 (test)</option>
<option value="50">50</option>
<option value="100">100</option>
<option value="500">500</option>
<option value="1000">1,000</option>
<option value="5000">5,000</option>
<option value="10000">10,000</option>
<option value="50000">50,000</option>
<option value="all">Full list</option>
</select></div>
<div class="form-row"><label>Throttle/min</label>
<input type="number" id="in-throttle" value="20" min="1" max="500"></div>
<div class="form-row"><label>Warm contacts only</label>
<select id="sel-warm"><option value="0">Non — tout</option><option value="1">Oui — warm/hot</option></select></div>
</div>
<div style="font-size:9px;color:var(--d)">Contacts disponibles: <span id="lbl-contacts" style="color:var(--gn);font-weight:700">927,007</span></div>
</div>
<!-- STEP 3: Sender Config -->
<div class="card card-am">
<h3 style="font-size:12px;margin-bottom:10px"><span class="step-num step-am">3</span> <span style="color:var(--am)">SENDER / FROM</span></h3>
<div id="method-hint" style="font-size:10px;color:var(--og);margin-bottom:8px;padding:6px;background:var(--bg);border-radius:4px">
💡 <strong>O365 Graph:</strong> Envoie via Microsoft Graph API — sélectionner un tenant O365
</div>
<div class="grid2">
<div class="form-row"><label>From Domain</label>
<select id="sel-domain">
<option value="accoff04.onmicrosoft.com">accoff04.onmicrosoft.com</option>
<option value="accoff05.onmicrosoft.com">accoff05.onmicrosoft.com</option>
<option value="culturellemejean.charity">culturellemejean.charity</option>
<option value="aafjeshade.onmicrosoft.com">aafjeshade.onmicrosoft.com</option>
<option value="bethellhutchison.onmicrosoft.com">bethellhutchison.onmicrosoft.com</option>
<option value="garnetkimble.onmicrosoft.com">garnetkimble.onmicrosoft.com</option>
<option value="jamilpeterson.onmicrosoft.com">jamilpeterson.onmicrosoft.com</option>
<option value="hobfielder.onmicrosoft.com">hobfielder.onmicrosoft.com</option>
</select></div>
<div class="form-row"><label>From Name</label>
<input id="in-fromname" value="Service Client" placeholder="Ex: Dr. Martin, Support Santé..."></div>
</div>
<div class="form-row"><label>Reply-To (optionnel)</label>
<input id="in-replyto" placeholder="noreply@domain.com"></div>
<div id="brain-winner-box" style="display:none;margin-top:8px;padding:8px;background:var(--bg);border:1px solid var(--gn);border-radius:6px">
<div style="font-size:9px;color:var(--gn);font-weight:700;margin-bottom:4px">🧠 BRAIN WINNER CONFIG</div>
<div style="font-size:10px" id="brain-winner-detail">-</div>
</div>
</div>
</div>
<div>
<!-- STEP 4: Headers -->
<div class="card card-pu">
<h3 style="font-size:12px;margin-bottom:10px"><span class="step-num step-pu">4</span> <span style="color:var(--pu)">HEADERS</span></h3>
<div class="grid2">
<div class="form-row"><label>X-Mailer</label>
<select id="sel-xmailer">
<option value="">Aucun (recommandé Exchange)</option>
<option value="Microsoft Outlook 16.0">Microsoft Outlook 16.0</option>
<option value="Thunderbird 115.0">Thunderbird 115.0</option>
<option value="Apple Mail">Apple Mail</option>
<option value="random">🎲 Random (Brain Engine)</option>
</select></div>
<div class="form-row"><label>Content-Type</label>
<select id="sel-contenttype">
<option value="text/html">text/html</option>
<option value="multipart/alternative">multipart/alternative</option>
<option value="text/plain">text/plain</option>
</select></div>
</div>
<div class="form-row"><label>Priority</label>
<select id="sel-priority">
<option value="normal">Normal</option>
<option value="high">High (1)</option>
<option value="low">Low (5)</option>
</select></div>
<div class="form-row"><label>Custom Headers (JSON)</label>
<textarea id="in-headers" placeholder='{"X-Custom": "value", "List-Unsubscribe": "<mailto:unsub@dom.com>"}'>{}</textarea></div>
</div>
<!-- STEP 5: Subject & Body -->
<div class="card card-og">
<h3 style="font-size:12px;margin-bottom:10px"><span class="step-num step-og">5</span> <span style="color:var(--og)">SUBJECT & BODY</span></h3>
<div class="form-row"><label>Subject Line</label>
<input id="in-subject" placeholder="Ex: Votre accès gratuit expire demain — {FNAME}"></div>
<div style="display:flex;gap:6px;margin-bottom:8px">
<button class="btn" style="padding:4px 10px;font-size:9px" onclick="loadCreatives()">📝 Charger Creatives DB</button>
<button class="btn btn-pu" style="padding:4px 10px;font-size:9px" onclick="genSubject()">🧠 IA Subject</button>
</div>
<div class="form-row"><label>Creative / Template</label>
<select id="sel-creative" onchange="previewCreative()">
<option value="custom">— Créer manuellement —</option>
</select></div>
<div class="form-row"><label>Body HTML</label>
<textarea id="in-body" style="min-height:180px" placeholder="<html><body>Votre contenu ici... {TRACKING_LINK} {UNSUB}</body></html>

View File

@@ -0,0 +1,915 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WEVIA NEXUS ULTIMATE 2026 — SINGULARITY</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700&family=Outfit:wght@200;300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<style>
:root {
--bg: #0a0a0f; --surface: #111118; --surface2: #16161f; --surface3: #1c1c28;
--border: #252535; --border2: #2f2f42;
--text: #e8e8f0; --text2: #9999b3; --text3: #666680;
--primary: #00ffaa; --primary2: #00cc88; --primary-glow: rgba(0,255,170,0.15);
--secondary: #7b68ee; --secondary-glow: rgba(123,104,238,0.15);
--accent: #ff6b6b; --warning: #ffd93d; --info: #4ecdc4;
--success: #00ffaa; --danger: #ff4757;
--gradient1: linear-gradient(135deg, #00ffaa 0%, #7b68ee 50%, #ff6b6b 100%);
--gradient2: linear-gradient(135deg, #0a0a0f 0%, #111125 100%);
--font: 'Outfit', sans-serif; --mono: 'JetBrains Mono', monospace;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { font-family: var(--font); background: var(--bg); color: var(--text); min-height: 100vh; overflow-x: hidden; }
/* ═══ GLOBAL NOISE ═══ */
body::before {
content: ''; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E");
pointer-events: none; z-index: 0; opacity: 0.4;
}
/* ═══ ORBS ═══ */
.orb { position: fixed; border-radius: 50%; filter: blur(100px); pointer-events: none; z-index: 0; animation: orbFloat 20s infinite ease-in-out; }
.orb1 { width: 600px; height: 600px; background: rgba(0,255,170,0.06); top: -200px; right: -200px; }
.orb2 { width: 500px; height: 500px; background: rgba(123,104,238,0.06); bottom: -150px; left: -150px; animation-delay: -10s; }
.orb3 { width: 400px; height: 400px; background: rgba(255,107,107,0.04); top: 50%; left: 50%; animation-delay: -5s; }
@keyframes orbFloat { 0%,100% { transform: translate(0,0) scale(1); } 33% { transform: translate(30px,-20px) scale(1.05); } 66% { transform: translate(-20px,30px) scale(0.95); } }
/* ═══ HEADER ═══ */
.header {
position: sticky; top: 0; z-index: 100; background: rgba(10,10,15,0.85);
backdrop-filter: blur(20px); border-bottom: 1px solid var(--border);
padding: 0 24px; height: 64px; display: flex; align-items: center; justify-content: space-between;
}
.logo { display: flex; align-items: center; gap: 12px; }
.logo-icon {
width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center;
background: var(--gradient1); font-size: 20px; position: relative; overflow: hidden;
}
.logo-icon::after { content: ''; position: absolute; inset: 2px; border-radius: 8px; background: var(--bg); }
.logo-icon span { position: relative; z-index: 1; }
.logo-text h1 { font-size: 16px; font-weight: 700; letter-spacing: 2px; background: var(--gradient1); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.logo-text p { font-size: 10px; color: var(--text3); font-family: var(--mono); letter-spacing: 3px; text-transform: uppercase; }
.header-status { display: flex; align-items: center; gap: 16px; }
.status-badge {
display: flex; align-items: center; gap: 6px; padding: 6px 14px;
background: var(--primary-glow); border: 1px solid rgba(0,255,170,0.3);
border-radius: 20px; font-family: var(--mono); font-size: 11px; color: var(--primary);
}
.status-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--primary); animation: pulse 2s infinite; }
@keyframes pulse { 0%,100% { opacity: 1; box-shadow: 0 0 0 0 rgba(0,255,170,0.4); } 50% { opacity: 0.8; box-shadow: 0 0 0 6px rgba(0,255,170,0); } }
.header-actions { display: flex; gap: 8px; }
.header-btn {
background: var(--surface2); border: 1px solid var(--border); color: var(--text2);
padding: 6px 12px; border-radius: 8px; cursor: pointer; font-family: var(--mono);
font-size: 11px; transition: all 0.2s; display: flex; align-items: center; gap: 6px;
}
.header-btn:hover { background: var(--surface3); border-color: var(--primary); color: var(--primary); }
/* ═══ MAIN LAYOUT ═══ */
.main { position: relative; z-index: 1; max-width: 1600px; margin: 0 auto; padding: 24px; }
/* ═══ HERO SECTION ═══ */
.hero {
position: relative; padding: 48px 40px; margin-bottom: 24px;
background: var(--gradient2); border: 1px solid var(--border);
border-radius: 16px; overflow: hidden;
}
.hero::before {
content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
background: var(--gradient1);
}
.hero-grid { display: grid; grid-template-columns: 1fr auto; gap: 40px; align-items: center; }
.hero h2 { font-size: 32px; font-weight: 800; line-height: 1.1; margin-bottom: 8px; }
.hero h2 span { background: var(--gradient1); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.hero .subtitle { font-size: 14px; color: var(--text2); margin-bottom: 20px; font-family: var(--mono); }
.hero-stats { display: flex; gap: 32px; }
.hero-stat { text-align: center; }
.hero-stat .val { font-size: 28px; font-weight: 800; color: var(--primary); font-family: var(--mono); }
.hero-stat .lbl { font-size: 10px; color: var(--text3); text-transform: uppercase; letter-spacing: 1px; margin-top: 2px; }
.hero-right { display: flex; flex-direction: column; gap: 12px; }
.go-live-btn {
background: var(--gradient1); color: #000; border: none; padding: 16px 40px;
border-radius: 12px; font-size: 16px; font-weight: 800; letter-spacing: 2px;
cursor: pointer; font-family: var(--font); transition: all 0.3s;
text-transform: uppercase; position: relative; overflow: hidden;
}
.go-live-btn::after { content: ''; position: absolute; inset: 0; background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.2) 50%, transparent 100%); transform: translateX(-100%); animation: shimmer 3s infinite; }
@keyframes shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }
.go-live-btn:hover { transform: scale(1.02); box-shadow: 0 0 40px rgba(0,255,170,0.3); }
/* ═══ GRID LAYOUT ═══ */
.grid { display: grid; gap: 16px; margin-bottom: 24px; }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-2 { grid-template-columns: 1fr 1fr; }
.grid-12 { grid-template-columns: repeat(12, 1fr); }
/* ═══ CARDS ═══ */
.card {
background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
padding: 20px; position: relative; overflow: hidden; transition: all 0.3s;
}
.card:hover { border-color: var(--border2); transform: translateY(-1px); }
.card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
.card-title { font-size: 12px; text-transform: uppercase; letter-spacing: 1.5px; color: var(--text3); font-weight: 600; display: flex; align-items: center; gap: 8px; }
.card-title i { color: var(--primary); }
.card-badge { font-size: 10px; padding: 3px 8px; border-radius: 10px; font-family: var(--mono); font-weight: 600; }
.badge-live { background: rgba(0,255,170,0.15); color: var(--primary); border: 1px solid rgba(0,255,170,0.3); }
.badge-warn { background: rgba(255,217,61,0.15); color: var(--warning); border: 1px solid rgba(255,217,61,0.3); }
.badge-down { background: rgba(255,71,87,0.15); color: var(--danger); border: 1px solid rgba(255,71,87,0.3); }
.metric { margin-bottom: 12px; }
.metric-val { font-size: 32px; font-weight: 800; font-family: var(--mono); line-height: 1; }
.metric-label { font-size: 11px; color: var(--text3); margin-top: 4px; }
/* ═══ MODULES GRID ═══ */
.modules-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 10px; }
.module-card {
background: var(--surface2); border: 1px solid var(--border); border-radius: 10px;
padding: 14px; cursor: pointer; transition: all 0.2s; position: relative;
}
.module-card:hover { border-color: var(--primary); background: var(--surface3); }
.module-card.active::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px; background: var(--primary); border-radius: 10px 10px 0 0; }
.module-icon { font-size: 24px; margin-bottom: 8px; }
.module-name { font-size: 12px; font-weight: 600; margin-bottom: 2px; }
.module-desc { font-size: 10px; color: var(--text3); font-family: var(--mono); }
.module-status { position: absolute; top: 10px; right: 10px; width: 8px; height: 8px; border-radius: 50%; }
.module-status.on { background: var(--primary); box-shadow: 0 0 8px rgba(0,255,170,0.5); }
.module-status.off { background: var(--danger); }
/* ═══ PROVIDERS ═══ */
.provider-row {
display: flex; align-items: center; gap: 12px; padding: 10px 12px;
background: var(--surface2); border-radius: 8px; margin-bottom: 6px;
border: 1px solid transparent; transition: all 0.2s;
}
.provider-row:hover { border-color: var(--border2); }
.provider-icon { width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 16px; }
.provider-info { flex: 1; }
.provider-name { font-size: 13px; font-weight: 600; }
.provider-model { font-size: 10px; color: var(--text3); font-family: var(--mono); }
.provider-status { font-size: 10px; font-family: var(--mono); padding: 3px 8px; border-radius: 6px; }
/* ═══ CHAT PANEL ═══ */
.chat-panel {
background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
display: flex; flex-direction: column; height: 500px;
}
.chat-header {
padding: 14px 20px; border-bottom: 1px solid var(--border);
display: flex; align-items: center; justify-content: space-between;
}
.chat-messages { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.chat-msg { max-width: 85%; padding: 12px 16px; border-radius: 12px; font-size: 13px; line-height: 1.5; animation: fadeIn 0.3s; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
.msg-user { background: var(--secondary-glow); border: 1px solid rgba(123,104,238,0.3); align-self: flex-end; }
.msg-ai { background: var(--surface2); border: 1px solid var(--border); align-self: flex-start; }
.msg-meta { font-size: 9px; color: var(--text3); font-family: var(--mono); margin-top: 6px; }
.chat-input-area { padding: 12px 16px; border-top: 1px solid var(--border); display: flex; gap: 8px; }
.chat-input {
flex: 1; background: var(--surface2); border: 1px solid var(--border); color: var(--text);
padding: 10px 14px; border-radius: 10px; font-family: var(--font); font-size: 13px;
outline: none; resize: none;
}
.chat-input:focus { border-color: var(--primary); }
.chat-send {
background: var(--primary); color: #000; border: none; width: 40px; height: 40px;
border-radius: 10px; cursor: pointer; font-size: 16px; transition: all 0.2s;
}
.chat-send:hover { transform: scale(1.05); background: var(--primary2); }
/* ═══ DARK MODULE ═══ */
.dark-panel { background: linear-gradient(135deg, #0f0f18, #151525); }
.dark-input {
width: 100%; background: rgba(0,0,0,0.3); border: 1px solid var(--border);
color: var(--primary); padding: 10px 14px; border-radius: 8px;
font-family: var(--mono); font-size: 12px; outline: none;
}
.dark-results { margin-top: 12px; max-height: 300px; overflow-y: auto; }
.dark-item { padding: 8px; border-bottom: 1px solid var(--border); font-family: var(--mono); font-size: 11px; }
/* ═══ SOCIAL ═══ */
.social-platforms { display: flex; gap: 8px; margin-bottom: 12px; }
.social-btn {
padding: 6px 14px; border-radius: 8px; border: 1px solid var(--border);
background: var(--surface2); color: var(--text2); cursor: pointer; font-size: 12px;
transition: all 0.2s;
}
.social-btn:hover, .social-btn.active { border-color: var(--secondary); color: var(--secondary); background: var(--secondary-glow); }
.social-output { background: var(--surface2); border-radius: 8px; padding: 14px; font-size: 12px; line-height: 1.6; min-height: 120px; white-space: pre-wrap; }
/* ═══ SERVERS ═══ */
.server-row {
display: flex; align-items: center; gap: 12px; padding: 8px 12px;
border-bottom: 1px solid var(--border); font-family: var(--mono); font-size: 11px;
}
.server-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.server-name { flex: 1; font-weight: 500; color: var(--text); }
.server-ip { color: var(--text3); }
.server-role { color: var(--text2); font-size: 10px; }
/* ═══ TERMINAL ═══ */
.terminal {
background: #000; border-radius: 10px; padding: 16px; font-family: var(--mono);
font-size: 11px; color: var(--primary); max-height: 250px; overflow-y: auto;
line-height: 1.6;
}
.terminal .cmd { color: var(--text3); }
.terminal .ok { color: var(--success); }
.terminal .err { color: var(--danger); }
.terminal .warn { color: var(--warning); }
.terminal .info { color: var(--info); }
/* ═══ PROGRESS ═══ */
.progress-bar { height: 6px; background: var(--surface3); border-radius: 3px; overflow: hidden; margin-top: 8px; }
.progress-fill { height: 100%; border-radius: 3px; transition: width 1s ease; }
.progress-fill.green { background: var(--gradient1); }
.progress-fill.yellow { background: linear-gradient(90deg, var(--warning), #ff9f43); }
.progress-fill.red { background: linear-gradient(90deg, var(--danger), #ff6b81); }
/* ═══ TABS ═══ */
.tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--border); padding-bottom: 8px; }
.tab {
padding: 6px 14px; border-radius: 8px 8px 0 0; cursor: pointer; font-size: 12px;
color: var(--text3); transition: all 0.2s; border: 1px solid transparent; border-bottom: none;
}
.tab:hover { color: var(--text); }
.tab.active { color: var(--primary); background: var(--surface2); border-color: var(--border); }
/* ═══ SCROLL ═══ */
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-track { background: var(--surface); }
::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 2px; }
/* ═══ RESPONSIVE ═══ */
@media (max-width: 1200px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 768px) {
.grid-3, .grid-2, .grid-4 { grid-template-columns: 1fr; }
.hero-grid { grid-template-columns: 1fr; }
.hero-stats { flex-wrap: wrap; gap: 16px; }
.header { padding: 0 12px; }
.main { padding: 12px; }
.modules-grid { grid-template-columns: repeat(2, 1fr); }
}
</style>
</head>
<body>
<div class="orb orb1"></div>
<div class="orb orb2"></div>
<div class="orb orb3"></div>
<!-- ═══ HEADER ═══ -->
<header class="header">
<div class="logo">
<div class="logo-icon"><span>🧠</span></div>
<div class="logo-text">
<h1>WEVIA NEXUS</h1>
<p>SINGULARITY · 2026</p>
</div>
</div>
<div class="header-status">
<div class="status-badge"><div class="status-dot"></div><span id="statusText">INITIALIZING...</span></div>
<div class="header-actions">
<button class="header-btn" onclick="refreshAll()"><i class="fas fa-sync-alt"></i> Refresh</button>
<button class="header-btn" onclick="testProviders()"><i class="fas fa-vial"></i> Test IA</button>
<button class="header-btn" onclick="showArchitecture()"><i class="fas fa-project-diagram"></i> Archi</button>
</div>
</div>
</header>
<!-- ═══ MAIN ═══ -->
<div class="main">
<!-- HERO -->
<div class="hero" id="hero">
<div class="hero-grid">
<div>
<h2>GO LIVE — <span>SINGULARITY</span></h2>
<p class="subtitle">L'IA LA PLUS COMPLÈTE DE 2026 · TOUS MODULES CONNECTÉS</p>
<div class="hero-stats">
<div class="hero-stat"><div class="val" id="hModules"></div><div class="lbl">Modules</div></div>
<div class="hero-stat"><div class="val" id="hProviders"></div><div class="lbl">IA Providers</div></div>
<div class="hero-stat"><div class="val" id="hServers"></div><div class="lbl">Serveurs</div></div>
<div class="hero-stat"><div class="val" id="hKB"></div><div class="lbl">KB Entries</div></div>
<div class="hero-stat"><div class="val" id="hGPU"></div><div class="lbl">GPU Models</div></div>
<div class="hero-stat"><div class="val" id="hCrons"></div><div class="lbl">Crons</div></div>
</div>
</div>
<div class="hero-right">
<button class="go-live-btn" onclick="goLive()">⚡ GO LIVE 2026</button>
<div style="font-size:10px;color:var(--text3);text-align:center;font-family:var(--mono)">WEVAL Consulting · Casablanca</div>
</div>
</div>
</div>
<!-- ═══ HEALTH METRICS ═══ -->
<div class="grid grid-4" id="metricsGrid">
<div class="card">
<div class="card-header"><span class="card-title"><i class="fas fa-microchip"></i> CPU / LOAD</span><span class="card-badge badge-live" id="cpuBadge">LIVE</span></div>
<div class="metric"><div class="metric-val" id="cpuLoad"></div><div class="metric-label">Load Average</div></div>
<div class="progress-bar"><div class="progress-fill green" id="cpuBar" style="width:0%"></div></div>
</div>
<div class="card">
<div class="card-header"><span class="card-title"><i class="fas fa-memory"></i> MÉMOIRE</span><span class="card-badge badge-live">RAM</span></div>
<div class="metric"><div class="metric-val" id="memVal"></div><div class="metric-label" id="memLabel">Usage</div></div>
<div class="progress-bar"><div class="progress-fill green" id="memBar" style="width:0%"></div></div>
</div>
<div class="card">
<div class="card-header"><span class="card-title"><i class="fas fa-hdd"></i> DISQUE</span><span class="card-badge badge-live">SSD</span></div>
<div class="metric"><div class="metric-val" id="diskVal"></div><div class="metric-label" id="diskLabel">Espace</div></div>
<div class="progress-bar"><div class="progress-fill yellow" id="diskBar" style="width:0%"></div></div>
</div>
<div class="card">
<div class="card-header"><span class="card-title"><i class="fas fa-clock"></i> UPTIME</span><span class="card-badge badge-live">ON</span></div>
<div class="metric"><div class="metric-val" id="uptimeVal" style="font-size:18px"></div><div class="metric-label">Serveur principal</div></div>
</div>
</div>
<!-- ═══ MODULES CONNECTÉS ═══ -->
<div class="card" style="margin-bottom:24px">
<div class="card-header">
<span class="card-title"><i class="fas fa-cube"></i> MODULES CONNECTÉS — ARCHITECTURE COMPLÈTE</span>
<span class="card-badge badge-live" id="modulesCount">11 ACTIVE</span>
</div>
<div class="modules-grid" id="modulesGrid"></div>
</div>
<!-- ═══ MAIN PANELS ═══ -->
<div class="grid grid-2">
<!-- CHAT IA -->
<div class="chat-panel">
<div class="chat-header">
<span class="card-title"><i class="fas fa-robot"></i> BRAIN ENGINE — CHAT IA</span>
<select id="providerSelect" style="background:var(--surface2);border:1px solid var(--border);color:var(--text);padding:4px 8px;border-radius:6px;font-size:11px;font-family:var(--mono)">
<option value="auto">🤖 Auto (Failover)</option>
<option value="cerebras">⚡ Cerebras</option>
<option value="groq">🚀 Groq</option>
<option value="sambanova">🔥 SambaNova</option>
<option value="ollama-gpu">🖥️ Ollama GPU (DeepSeek R1 32B)</option>
<option value="ollama-qwen">💻 Ollama Qwen Coder 14B</option>
<option value="ollama-llama">🦙 Ollama Llama 3.1 8B</option>
<option value="deepseek">🌊 DeepSeek</option>
<option value="mistral">🇫🇷 Mistral</option>
</select>
</div>
<div class="chat-messages" id="chatMessages">
<div class="msg-ai">
🧠 <strong>WEVIA NEXUS ULTIMATE 2026</strong> — SINGULARITY<br><br>
Tous les modules sont connectés. Je suis l'IA la plus complète de 2026 avec :<br>
• 11 Providers IA (Cloud + GPU Local)<br>
• 7 Serveurs interconnectés<br>
• 1710+ entrées KB<br>
• Dark Intelligence + Inconscient Collectif + Réseaux Sociaux<br><br>
Que puis-je faire pour vous ?
<div class="msg-meta">WEVIA NEXUS · SINGULARITY · Prêt</div>
</div>
</div>
<div class="chat-input-area">
<textarea class="chat-input" id="chatInput" rows="1" placeholder="Message à WEVIA NEXUS..." onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();sendChat()}"></textarea>
<button class="chat-send" onclick="sendChat()"><i class="fas fa-arrow-up"></i></button>
</div>
</div>
<!-- RIGHT COLUMN -->
<div style="display:flex;flex-direction:column;gap:16px">
<!-- PROVIDERS -->
<div class="card" style="flex:1">
<div class="card-header">
<span class="card-title"><i class="fas fa-brain"></i> IA PROVIDERS</span>
<button class="header-btn" onclick="testProviders()" style="font-size:10px;padding:4px 10px"><i class="fas fa-play"></i> Test All</button>
</div>
<div id="providersList"></div>
</div>
<!-- SERVERS -->
<div class="card">
<div class="card-header">
<span class="card-title"><i class="fas fa-server"></i> SERVEURS</span>
<span class="card-badge badge-live" id="serversCount">7</span>
</div>
<div id="serversList"></div>
</div>
</div>
</div>
<!-- ═══ DARK + SOCIAL + COLLECTIVE ═══ -->
<div class="grid grid-3" style="margin-top:24px">
<!-- DARK INTELLIGENCE -->
<div class="card dark-panel">
<div class="card-header">
<span class="card-title"><i class="fas fa-user-secret"></i> DARK INTELLIGENCE</span>
<span class="card-badge badge-live">OSINT</span>
</div>
<input type="text" class="dark-input" id="darkTarget" placeholder="Domaine ou URL cible..." onkeydown="if(event.key==='Enter')darkScan()">
<div style="display:flex;gap:6px;margin-top:8px">
<button class="header-btn" onclick="darkScan()" style="flex:1"><i class="fas fa-search"></i> Scan DNS</button>
<button class="header-btn" onclick="darkScrape()" style="flex:1"><i class="fas fa-spider"></i> Deep Scrape</button>
</div>
<div class="dark-results" id="darkResults"></div>
</div>
<!-- INCONSCIENT COLLECTIF -->
<div class="card">
<div class="card-header">
<span class="card-title"><i class="fas fa-atom"></i> INCONSCIENT COLLECTIF</span>
<span class="card-badge badge-live">RAG+KB</span>
</div>
<input type="text" class="dark-input" id="collectiveQuery" placeholder="Interroger la mémoire collective..." style="color:var(--secondary);border-color:rgba(123,104,238,0.3)" onkeydown="if(event.key==='Enter')queryCollective()">
<button class="header-btn" onclick="queryCollective()" style="width:100%;margin-top:8px;justify-content:center"><i class="fas fa-brain"></i> Requête Collective</button>
<div id="collectiveResults" style="margin-top:12px;max-height:280px;overflow-y:auto"></div>
</div>
<!-- SOCIAL NETWORKS -->
<div class="card">
<div class="card-header">
<span class="card-title"><i class="fas fa-share-alt"></i> RÉSEAUX SOCIAUX</span>
<span class="card-badge badge-live">CONTENT</span>
</div>
<div class="social-platforms">
<button class="social-btn active" onclick="selectPlatform(this,'linkedin')"><i class="fab fa-linkedin"></i> LinkedIn</button>
<button class="social-btn" onclick="selectPlatform(this,'twitter')"><i class="fab fa-twitter"></i> Twitter</button>
<button class="social-btn" onclick="selectPlatform(this,'email_b2b')"><i class="fas fa-envelope"></i> B2B</button>
</div>
<input type="text" class="dark-input" id="socialTopic" placeholder="Sujet du contenu..." style="color:var(--info)" onkeydown="if(event.key==='Enter')generateSocial()">
<button class="header-btn" onclick="generateSocial()" style="width:100%;margin-top:8px;justify-content:center"><i class="fas fa-magic"></i> Générer</button>
<div class="social-output" id="socialOutput" style="margin-top:10px">Sélectionnez une plateforme et un sujet...</div>
</div>
</div>
<!-- ═══ TERMINAL ═══ -->
<div class="card" style="margin-top:24px">
<div class="card-header">
<span class="card-title"><i class="fas fa-terminal"></i> SYSTEM LOG</span>
<span class="card-badge badge-live" id="logBadge">LIVE</span>
</div>
<div class="terminal" id="terminal"></div>
</div>
</div>
<script>
// ═══════════════════════════════════════════════════════════════
// WEVIA NEXUS ULTIMATE 2026 — FRONTEND ENGINE
// ═══════════════════════════════════════════════════════════════
const API = 'http://89.167.40.150:80/api/wevia-nexus-ultimate.php';
let currentPlatform = 'linkedin';
let systemData = null;
// ═══ TERMINAL LOG ═══
function log(msg, type = '') {
const t = document.getElementById('terminal');
const ts = new Date().toLocaleTimeString('fr-FR');
t.innerHTML += `<div><span class="cmd">[${ts}]</span> <span class="${type}">${msg}</span></div>`;
t.scrollTop = t.scrollHeight;
}
// ═══ API CALL ═══
// === WEVIA PDF AUTO-GENERATE ===
async function handlePdfResponse(respText, msgs, r) {
const pdfMatch = respText.match(/```json-pdf\n([\s\S]*?)\n```/) || respText.match(/json-pdf\n([\s\S]*?)\n```/);
if (!pdfMatch) return false;
try {
const pdfJson = JSON.parse(pdfMatch[1]);
msgs.innerHTML += '<div class="msg-ai">\u{1F4C4} <b>Generation du document PDF en cours...</b><br><span style="color:var(--muted)">\u0022' + (pdfJson.title || 'Document') + '\u0022 \u2014 ' + (pdfJson.sections?.length || 0) + ' sections</span></div>';
msgs.scrollTop = msgs.scrollHeight;
const pdfResp = await fetch('/hamid-generate.php', {
method: 'POST', headers: {'Content-Type': 'application/json'},
body: JSON.stringify({type:'pdf', title: pdfJson.title||'Document', content: pdfJson, structured: true, brand: pdfJson.brand||'weval'})
});
const pdfData = await pdfResp.json();
if (pdfData.status === 'ok') {
msgs.innerHTML += '<div class="msg-ai" style="background:rgba(16,185,129,0.08);border-left:4px solid var(--success)">\u2705 <b>PDF genere!</b><br>\u{1F4CA} ' + (pdfData.pages||'?') + ' pages \u00b7 ' + Math.round((pdfData.size||0)/1024) + ' KB<br><a href="' + pdfData.url + '" target="_blank" style="color:var(--accent);font-weight:bold;font-size:14px">\u{1F4E5} Telecharger: ' + pdfData.filename + '</a></div>';
log('PDF: ' + pdfData.filename + ' (' + pdfData.pages + 'p)', 'ok');
} else {
msgs.innerHTML += '<div class="msg-ai"><span style="color:var(--danger)">\u274c PDF Error: ' + pdfData.error + '</span></div>';
}
return true;
} catch(e) { console.error('PDF parse:', e); return false; }
}
async function api(action, params = {}) {
try {
const url = new URL(API);
url.searchParams.set('action', action);
Object.entries(params).forEach(([k, v]) => { if (typeof v === 'string') url.searchParams.set(k, v); });
const opts = { method: 'GET' };
if (params._body) {
opts.method = 'POST';
opts.headers = { 'Content-Type': 'application/json' };
opts.body = JSON.stringify(params._body);
}
const r = await fetch(url, opts);
return await r.json();
} catch (e) {
log(`API Error: ${action}${e.message}`, 'err');
return null;
}
}
// ═══ INIT ═══
async function init() {
log('🚀 WEVIA NEXUS ULTIMATE 2026 — INITIALIZING...', 'info');
log('Codename: SINGULARITY', 'info');
await refreshAll();
renderModules();
renderProviders();
renderServers();
log('✅ ALL SYSTEMS NOMINAL — SINGULARITY ACTIVE', 'ok');
document.getElementById('statusText').textContent = 'SINGULARITY ACTIVE';
}
// ═══ REFRESH ALL ═══
async function refreshAll() {
log('Fetching system status...', 'cmd');
const data = await api('status');
if (!data) { log('❌ Cannot reach NEXUS API', 'err'); return; }
systemData = data;
// Hero stats
const a = data.arsenal || {};
document.getElementById('hModules').textContent = (a.total || 0).toLocaleString();
document.getElementById('hProviders').textContent = data.providers_configured || 11;
document.getElementById('hServers').textContent = data.servers || 7;
document.getElementById('hKB').textContent = (a.kb_entries || 0).toLocaleString();
document.getElementById('hGPU').textContent = (data.health?.gpu_models?.length || 0);
document.getElementById('hCrons').textContent = data.health?.crons || 0;
// Health metrics
const h = data.health || {};
const load = h.load?.[0]?.toFixed(2) || '—';
document.getElementById('cpuLoad').textContent = load;
const loadPct = Math.min((parseFloat(load) / 4) * 100, 100);
document.getElementById('cpuBar').style.width = loadPct + '%';
const mem = h.memory || {};
document.getElementById('memVal').textContent = mem.usage_pct ? mem.usage_pct + '%' : '—';
document.getElementById('memLabel').textContent = mem.used_mb ? `${mem.used_mb}MB / ${mem.total_mb}MB` : '';
document.getElementById('memBar').style.width = (mem.usage_pct || 0) + '%';
const disk = h.disk || {};
document.getElementById('diskVal').textContent = disk.usage_pct ? disk.usage_pct + '%' : '—';
document.getElementById('diskLabel').textContent = disk.used ? `${disk.used} / ${disk.total}` : '';
document.getElementById('diskBar').style.width = (disk.usage_pct || 0) + '%';
document.getElementById('uptimeVal').textContent = h.uptime || '—';
log(`Modules: ${a.total} | KB: ${a.kb_entries} | GPU: ${h.gpu_models?.length} models | Crons: ${h.crons}`, 'ok');
// Services
const svcs = h.services || {};
Object.entries(svcs).forEach(([name, status]) => {
log(` ${status === 'running' ? '✅' : '⚠️'} ${name}: ${status}`, status === 'running' ? 'ok' : 'warn');
});
log(` ${h.gpu_server === 'online' ? '✅' : '❌'} GPU Server: ${h.gpu_server}`, h.gpu_server === 'online' ? 'ok' : 'err');
}
// ═══ RENDER MODULES ═══
function renderModules() {
const modules = [
{ id: 'dark', icon: '🕵️', name: 'Dark Intelligence', desc: 'OSINT · Scraping · Intel', active: true },
{ id: 'collective', icon: '🧬', name: 'Inconscient Collectif', desc: 'RAG · KB · Mémoire', active: true },
{ id: 'social', icon: '📡', name: 'Réseaux Sociaux', desc: 'LinkedIn · Twitter · B2B', active: true },
{ id: 'brain', icon: '🧠', name: 'Brain Engine', desc: '11 Providers · Failover', active: true },
{ id: 'arsenal', icon: '⚔️', name: 'Arsenal Ops', desc: '1415 Modules · 150 Écrans', active: true },
{ id: 'email', icon: '📧', name: 'Email Pipeline', desc: 'PMTA · O365 · E2E', active: true },
{ id: 'sentinel', icon: '🛡️', name: 'Sentinel', desc: 'Exec · Monitor · Guard', active: true },
{ id: 'vision', icon: '👁️', name: 'Vision & OCR', desc: 'Image · PDF · Scan', active: true },
{ id: 'voice', icon: '🎤', name: 'Voice & TTS', desc: 'Speech · Audio', active: true },
{ id: 'code', icon: '💻', name: 'Code Sandbox', desc: 'Execute · CLI · Debug', active: true },
{ id: 'docs', icon: '📄', name: 'Doc Generator', desc: 'PDF · Word · Excel · PPT', active: true },
];
const grid = document.getElementById('modulesGrid');
grid.innerHTML = modules.map(m => `
<div class="module-card ${m.active ? 'active' : ''}" onclick="activateModule('${m.id}')">
<div class="module-status ${m.active ? 'on' : 'off'}"></div>
<div class="module-icon">${m.icon}</div>
<div class="module-name">${m.name}</div>
<div class="module-desc">${m.desc}</div>
</div>
`).join('');
}
// ═══ RENDER PROVIDERS ═══
function renderProviders() {
const providers = [
{ name: 'Cerebras', icon: '⚡', model: 'llama-3.3-70b', speed: '429ms', tier: 'primary' },
{ name: 'Groq', icon: '🚀', model: 'llama-3.3-70b-versatile', speed: '192ms', tier: 'primary' },
{ name: 'SambaNova', icon: '🔥', model: 'Meta-Llama-3.3-70B', speed: '800ms', tier: 'primary' },
{ name: 'Ollama GPU', icon: '🖥️', model: 'deepseek-r1:32b (RTX 4000)', speed: '2000ms', tier: 'local' },
{ name: 'Qwen Coder', icon: '💻', model: 'qwen2.5-coder:14b', speed: '1500ms', tier: 'local' },
{ name: 'Llama 3.1', icon: '🦙', model: 'llama3.1:8b', speed: '1000ms', tier: 'local' },
{ name: 'DeepSeek', icon: '🌊', model: 'deepseek-chat', speed: '1200ms', tier: 'cloud' },
{ name: 'Gemini', icon: '💎', model: 'gemini-pro', speed: '600ms', tier: 'cloud' },
{ name: 'Mistral', icon: '🇫🇷', model: 'mistral-large', speed: '700ms', tier: 'cloud' },
{ name: 'Cohere', icon: '🔮', model: 'command-r-plus', speed: '900ms', tier: 'cloud' },
{ name: 'Hyperbolic', icon: '∞', model: 'Llama-3.3-70B', speed: '500ms', tier: 'cloud' },
];
const tierColors = { primary: 'var(--primary)', local: 'var(--warning)', cloud: 'var(--info)' };
const tierLabels = { primary: 'PRIMARY', local: 'LOCAL GPU', cloud: 'CLOUD' };
document.getElementById('providersList').innerHTML = providers.map(p => `
<div class="provider-row">
<div class="provider-icon" style="background:${tierColors[p.tier]}22;color:${tierColors[p.tier]}">${p.icon}</div>
<div class="provider-info">
<div class="provider-name">${p.name}</div>
<div class="provider-model">${p.model} · ${p.speed}</div>
</div>
<span class="provider-status" style="background:${tierColors[p.tier]}22;color:${tierColors[p.tier]}">${tierLabels[p.tier]}</span>
</div>
`).join('');
}
// ═══ RENDER SERVERS ═══
function renderServers() {
const servers = [
{ name: 'WEVADS Prod', ip: '89.167.40.150', role: 'Email + Brain', online: true },
{ name: 'WEVIA IA', ip: '46.62.220.135', role: 'IA + Arsenal', online: true },
{ name: 'GPU RTX 4000', ip: '88.198.4.195', role: 'Ollama + Models', online: true },
{ name: 'MTA-EU Relay', ip: '89.167.1.139', role: 'SMTP Relay', online: true },
{ name: 'OVH Tracking', ip: '151.80.235.110', role: 'Click Tracking', online: true },
{ name: 'Huawei HW1', ip: '110.238.76.155', role: 'MTA China 1', online: true },
{ name: 'Huawei HW2', ip: '122.8.135.130', role: 'MTA China 2', online: true },
];
document.getElementById('serversList').innerHTML = servers.map(s => `
<div class="server-row">
<div class="server-dot" style="background:${s.online ? 'var(--primary)' : 'var(--danger)'}"></div>
<div class="server-name">${s.name}</div>
<div class="server-ip">${s.ip}</div>
<div class="server-role">${s.role}</div>
</div>
`).join('');
}
// ═══ CHAT ═══
async function sendChat() {
const input = document.getElementById('chatInput');
const msg = input.value.trim();
if (!msg) return;
input.value = '';
const msgs = document.getElementById('chatMessages');
msgs.innerHTML += `<div class="msg-user">${msg}</div>`;
msgs.innerHTML += `<div class="msg-ai" id="typing" style="opacity:0.5">⏳ Réflexion en cours...</div>`;
msgs.scrollTop = msgs.scrollHeight;
const provider = document.getElementById('providerSelect').value;
log(`Chat → ${provider}: "${msg.substring(0, 50)}..."`, 'info');
const data = await api('chat', { _body: { action: 'chat', message: msg, provider } });
const typingEl = document.getElementById('typing');
if (typingEl) typingEl.remove();
if (data?.result?.response) {
const r = data.result;
// Try PDF generation first
const pdfHandled = await handlePdfResponse(r.response, msgs, r);
if (!pdfHandled) {
msgs.innerHTML += `
<div class="msg-ai">
${r.response.replace(/\n/g, '<br>')}
<div class="msg-meta">${r.reasoning_tag||'🧠'} <b>${r.reasoning_mode||'standard'}</b> · Depth ${r.reasoning_depth||3}/5 │ ${r.provider||'?'} · ${r.model||'?'} · ${r.latency_ms||'?'}ms</div>
</div>`;
}
log(`✅ Response from ${r.provider} (${r.latency_ms}ms)`, 'ok');
} else {
msgs.innerHTML += `<div class="msg-ai"><span style="color:var(--danger)">❌ ${data?.result?.error || 'Erreur connexion'}</span></div>`;
log(`❌ Chat error: ${data?.result?.error || 'unknown'}`, 'err');
}
msgs.scrollTop = msgs.scrollHeight;
}
// ═══ TEST PROVIDERS ═══
async function testProviders() {
log('🧪 Testing ALL IA providers...', 'info');
const data = await api('test_providers');
if (!data?.providers) { log('❌ Test failed', 'err'); return; }
Object.entries(data.providers).forEach(([name, info]) => {
const icon = info.status === 'LIVE' ? '✅' : info.status === 'NO_KEY' ? '🔑' : '❌';
const latency = info.latency ? ` (${info.latency}ms)` : '';
log(` ${icon} ${name}: ${info.status}${latency}${info.error ? ' — ' + info.error : ''}`, info.status === 'LIVE' ? 'ok' : 'warn');
});
}
// ═══ DARK INTELLIGENCE ═══
async function darkScan() {
const target = document.getElementById('darkTarget').value.trim();
if (!target) return;
log(`🕵️ Dark Scan: ${target}`, 'info');
const data = await api('dark_scan', { target });
const results = document.getElementById('darkResults');
if (data?.dark) {
const d = data.dark;
let html = '<div style="margin-top:8px">';
if (d.osint?.dns?.length) {
html += '<div class="dark-item" style="color:var(--primary)">📡 DNS Records:</div>';
d.osint.dns.forEach(r => { html += `<div class="dark-item">&nbsp;&nbsp;${r.type}: ${r.value}</div>`; });
}
if (d.osint?.server) html += `<div class="dark-item">🖥️ Server: ${d.osint.server}</div>`;
if (d.osint?.security_headers) {
const sh = d.osint.security_headers;
html += `<div class="dark-item">🔒 CSP: ${sh.csp ? '✅' : '❌'} | HSTS: ${sh.hsts ? '✅' : '❌'} | X-Frame: ${sh.xframe ? '✅' : '❌'}</div>`;
}
html += '</div>';
results.innerHTML = html;
log(`✅ Dark scan complete: ${d.osint?.dns?.length || 0} DNS records`, 'ok');
}
}
async function darkScrape() {
const url = document.getElementById('darkTarget').value.trim();
if (!url) return;
const fullUrl = url.startsWith('http') ? url : 'https://' + url;
log(`🕷️ Deep Scrape: ${fullUrl}`, 'info');
const data = await api('dark_scrape', { url: fullUrl });
const results = document.getElementById('darkResults');
if (data?.scrape) {
const s = data.scrape;
let html = `
<div class="dark-item" style="color:var(--primary)">📄 ${s.title || 'No title'} (${(s.size/1024).toFixed(1)}KB)</div>
<div class="dark-item">🔧 Tech: ${s.technologies?.join(', ') || 'None detected'}</div>
<div class="dark-item">📧 Emails: ${s.emails?.length || 0} found</div>
<div class="dark-item">📞 Phones: ${s.phones?.length || 0} found</div>
<div class="dark-item">🔗 Links: ${s.links?.length || 0} extracted</div>
`;
if (s.emails?.length) html += `<div class="dark-item" style="color:var(--warning)">${s.emails.join(', ')}</div>`;
results.innerHTML = html;
log(`✅ Scrape: ${s.technologies?.length} techs, ${s.emails?.length} emails, ${s.links?.length} links`, 'ok');
}
}
// ═══ COLLECTIVE UNCONSCIOUS ═══
async function queryCollective() {
const query = document.getElementById('collectiveQuery').value.trim();
if (!query) return;
log(`🧬 Collective query: "${query}"`, 'info');
const data = await api('collective', { q: query });
const results = document.getElementById('collectiveResults');
if (data?.knowledge) {
const k = data.knowledge;
let html = `<div style="padding:8px;background:var(--surface2);border-radius:8px;margin-bottom:8px">
<div style="font-size:11px;color:var(--secondary);font-family:var(--mono)">Confidence: ${k.fusion?.confidence || 0}% | KB: ${k.fusion?.total_kb || 0} | HAMID: ${k.fusion?.total_hamid || 0} | Winners: ${k.fusion?.total_winners || 0}</div>
</div>`;
if (k.kb?.length) {
k.kb.forEach(item => {
html += `<div style="padding:8px;border-bottom:1px solid var(--border);font-size:11px">
<div style="color:var(--primary);font-weight:600">${item.title || 'KB Entry'}</div>
<div style="color:var(--text2);margin-top:4px">${(item.content || '').substring(0, 200)}...</div>
</div>`;
});
}
if (k.fusion?.synthesis) {
html += `<div style="padding:8px;margin-top:8px;background:var(--secondary-glow);border-radius:8px;font-size:11px;border:1px solid rgba(123,104,238,0.3)">
<div style="color:var(--secondary);font-weight:600">🧬 Synthèse Collective</div>
<div style="margin-top:4px;color:var(--text2)">${k.fusion.synthesis.substring(0, 500)}</div>
</div>`;
}
results.innerHTML = html;
log(`✅ Collective: ${k.fusion?.confidence}% confidence, ${k.fusion?.total_kb} KB matches`, 'ok');
}
}
// ═══ SOCIAL ═══
function selectPlatform(btn, platform) {
document.querySelectorAll('.social-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentPlatform = platform;
}
async function generateSocial() {
const topic = document.getElementById('socialTopic').value.trim();
if (!topic) return;
log(`📡 Social generate: ${currentPlatform} — "${topic}"`, 'info');
const data = await api('social_generate', { _body: { action: 'social_generate', topic, platform: currentPlatform } });
if (data?.social?.content) {
document.getElementById('socialOutput').textContent = data.social.content;
log(`✅ Content generated for ${currentPlatform}`, 'ok');
}
}
// ═══ GO LIVE ═══
async function goLive() {
const hero = document.getElementById('hero');
hero.style.background = 'linear-gradient(135deg, #001a0d 0%, #0a1a2e 50%, #1a0a1a 100%)';
hero.style.borderColor = 'var(--primary)';
log('', '');
log('╔══════════════════════════════════════════════════════╗', 'ok');
log('║ WEVIA NEXUS ULTIMATE 2026 — GO LIVE ║', 'ok');
log('║ CODENAME: SINGULARITY ║', 'ok');
log('║ WEVAL Consulting · Casablanca · Maroc ║', 'ok');
log('╚══════════════════════════════════════════════════════╝', 'ok');
log('', '');
const checks = [
['Brain Engine (11 Providers)', true],
['GPU Server RTX 4000 Ada (7 Models)', true],
['Dark Intelligence Module', true],
['Inconscient Collectif (RAG + KB 1710)', true],
['Réseaux Sociaux Engine', true],
['Arsenal Ops (1415 Modules)', true],
['Email Pipeline (PMTA + O365)', true],
['Sentinel Exec & Monitor', true],
['Vision & OCR', true],
['Voice & TTS', true],
['Code Sandbox', true],
['Doc Generator (PDF/Word/Excel/PPT)', true],
['Knowledge Base (1710 entries)', true],
['7 Serveurs Interconnectés', true],
['39 Crons Automatiques', true],
];
for (const [name, ok] of checks) {
await new Promise(r => setTimeout(r, 200));
log(` ${ok ? '✅' : '❌'} ${name}`, ok ? 'ok' : 'err');
}
log('', '');
log('🚀 ════════════════════════════════════════════════', 'ok');
log('🚀 SINGULARITY IS LIVE — L\'IA DE 2026 EST ACTIVE', 'ok');
log('🚀 ════════════════════════════════════════════════', 'ok');
document.getElementById('statusText').textContent = '⚡ SINGULARITY LIVE';
}
// ═══ ARCHITECTURE ═══
function showArchitecture() {
const msgs = document.getElementById('chatMessages');
msgs.innerHTML += `<div class="msg-ai" style="font-family:var(--mono);font-size:11px;white-space:pre;line-height:1.4">
<span style="color:var(--primary)">╔══════════════════════════════════════════════════════════╗
║ WEVIA NEXUS ULTIMATE 2026 — ARCHITECTURE ║
╠══════════════════════════════════════════════════════════╣
║ ║
║ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ║
║ │ DARK │ │COLLEC│ │SOCIAL│ │BRAIN │ │ARSEN.│ ║
║ │INTEL │ │UNCON.│ │NETWK │ │ENGINE│ │ OPS │ ║
║ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ ║
║ └──────┬──┴────┬────┴────┬────┴────┬────┘ ║
║ │ MASTER ORCHESTRATOR API │ ║
║ └────────────┬───────────────┘ ║
║ ┌──────────┬───────┤────────┬──────────┐ ║
║ ▼ ▼ ▼ ▼ ▼ ║
║ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ║
║ │89.167│ │46.62 │ │88.198│ │HW1/2 │ │ OVH │ ║
║ │WEVADS│ │WEVIA │ │ GPU │ │HUAWEI│ │TRACK │ ║
║ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ ║
║ ║
║ PROVIDERS: Cerebras│Groq│SambaNova│Ollama│DeepSeek ║
║ Gemini│Mistral│Cohere│Hyperbolic ║
╚══════════════════════════════════════════════════════════╝</span>
</div>`;
msgs.scrollTop = msgs.scrollHeight;
}
// ═══ MODULE ACTIVATION ═══
function activateModule(id) {
log(`🔌 Module activated: ${id}`, 'info');
// Scroll to relevant section based on module
const scrollTargets = {
dark: 'darkTarget', collective: 'collectiveQuery', social: 'socialTopic',
brain: 'chatInput', email: 'terminal', sentinel: 'terminal'
};
const target = scrollTargets[id];
if (target) document.getElementById(target)?.focus();
}
// ═══ LAUNCH ═══
document.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>