488 lines
24 KiB
HTML
488 lines
24 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>WEVAL Value Chain — Agents</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Outfit:wght@300;500;700;900&display=swap" rel="stylesheet">
|
||
<style>@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@600;700;800;900&display=swap');
|
||
:root{--bg:#06080f;--card:#0c1020;--border:#1a2040;--text:#c8d0e0;--dim:#5a6580;--green:#22c55e;--red:#ef4444;--blue:#3b82f6;--purple:#a855f7;--amber:#f59e0b;--cyan:#06b6d4;--pink:#ec4899;--lime:#84cc16;}
|
||
*{margin:0;padding:0;box-sizing:border-box;}
|
||
body{background:var(--bg);color:var(--text);font-family:'Outfit',sans-serif;overflow-x:hidden;}
|
||
.noise{position:fixed;inset:0;opacity:.025;pointer-events:none;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='.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");}
|
||
|
||
header{padding:32px 40px 16px;border-bottom:1px solid var(--border);}
|
||
h1{font-size:2.4rem;font-weight:900;letter-spacing:-2px;}
|
||
h1 span{background:linear-gradient(135deg,var(--cyan),var(--purple));-webkit-background-clip:text;-webkit-text-fill-color:transparent;}
|
||
.sub{color:var(--dim);font-size:.85rem;margin-top:4px;}
|
||
|
||
.chain{padding:30px 24px 60px;position:relative;}
|
||
|
||
/* ═══ STAGE ═══ */
|
||
.stage{
|
||
position:relative;margin-bottom:12px;
|
||
border:1px solid var(--border);border-radius:16px;
|
||
background:var(--card);overflow:hidden;
|
||
animation:fadeIn .5s ease both;
|
||
}
|
||
.stage:nth-child(2){animation-delay:.1s}
|
||
.stage:nth-child(3){animation-delay:.2s}
|
||
.stage:nth-child(4){animation-delay:.3s}
|
||
.stage:nth-child(5){animation-delay:.4s}
|
||
.stage:nth-child(6){animation-delay:.5s}
|
||
.stage:nth-child(7){animation-delay:.6s}
|
||
.stage:nth-child(8){animation-delay:.7s}
|
||
@keyframes fadeIn{from{opacity:0;transform:translateX(-20px)}to{opacity:1;transform:none}}
|
||
|
||
.stage-header{
|
||
display:flex;align-items:center;gap:16px;
|
||
padding:16px 20px;cursor:pointer;
|
||
border-bottom:1px solid transparent;
|
||
transition:.2s;
|
||
}
|
||
.stage.open .stage-header{border-bottom:1px solid var(--border);}
|
||
.stage-header:hover{background:#0e1428;}
|
||
.stage-icon{
|
||
width:48px;height:48px;border-radius:12px;
|
||
display:flex;align-items:center;justify-content:center;
|
||
font-size:1.5rem;flex-shrink:0;
|
||
}
|
||
.stage-title{font-weight:700;font-size:1.1rem;color:#fff;}
|
||
.stage-sub{font-size:.78rem;color:var(--dim);margin-top:2px;}
|
||
.stage-right{margin-left:auto;display:flex;align-items:center;gap:12px;}
|
||
.stage-count{
|
||
font-family:'JetBrains Mono',monospace;font-size:.75rem;
|
||
background:#111830;padding:4px 10px;border-radius:8px;color:var(--cyan);
|
||
}
|
||
.stage-arrow{color:var(--dim);font-size:1.2rem;transition:transform .2s;}
|
||
.stage.open .stage-arrow{transform:rotate(90deg);}
|
||
|
||
.stage-body{display:none;padding:16px 20px;}
|
||
.stage.open .stage-body{display:block;}
|
||
|
||
/* ═══ FLOW CONNECTOR ═══ */
|
||
.flow-connector{
|
||
display:flex;justify-content:center;padding:4px 0;
|
||
}
|
||
.flow-line{
|
||
width:2px;height:24px;
|
||
background:linear-gradient(180deg,var(--cyan),var(--purple));
|
||
border-radius:2px;position:relative;
|
||
}
|
||
.flow-line::after{
|
||
content:'▼';position:absolute;bottom:-10px;left:50%;transform:translateX(-50%);
|
||
font-size:.6rem;color:var(--purple);
|
||
}
|
||
|
||
/* ═══ AGENTS ROW ═══ */
|
||
.agents-row{display:flex;flex-wrap:wrap;gap:10px;}
|
||
.agent-chip{
|
||
display:flex;align-items:center;gap:8px;
|
||
background:#111830;border:1px solid #1a2540;
|
||
border-radius:12px;padding:8px 14px;
|
||
transition:.2s;cursor:default;position:relative;
|
||
}
|
||
.agent-chip:hover{border-color:var(--cyan);transform:translateY(-2px);box-shadow:0 4px 16px rgba(6,182,212,.1);}
|
||
.agent-chip .av{
|
||
width:32px;height:32px;border-radius:8px;
|
||
display:flex;align-items:center;justify-content:center;
|
||
font-size:1rem;background:#1a2550;position:relative;
|
||
}
|
||
.agent-chip .av::after{
|
||
content:'';position:absolute;bottom:-1px;right:-1px;
|
||
width:8px;height:8px;border-radius:50%;background:var(--green);
|
||
border:1.5px solid #111830;
|
||
}
|
||
.agent-chip .info{display:flex;flex-direction:column;}
|
||
.agent-chip .name{font-weight:600;font-size:.82rem;color:#fff;}
|
||
.agent-chip .prod{font-family:'JetBrains Mono',monospace;font-size:.62rem;color:var(--cyan);opacity:.7;}
|
||
|
||
/* ═══ OUTPUTS ═══ */
|
||
.outputs{margin-top:12px;display:flex;flex-wrap:wrap;gap:6px;}
|
||
.output-tag{
|
||
font-family:'JetBrains Mono',monospace;font-size:.65rem;
|
||
background:#0a1225;border:1px solid #1a2040;
|
||
padding:3px 10px;border-radius:6px;color:var(--amber);
|
||
}
|
||
|
||
/* ═══ RISK BAR ═══ */
|
||
.risk-bar{
|
||
margin-top:12px;padding:8px 12px;
|
||
background:#1a0a0a;border:1px solid #3a1515;border-radius:8px;
|
||
display:flex;align-items:center;gap:8px;font-size:.75rem;
|
||
}
|
||
.risk-bar .icon{font-size:1rem;}
|
||
.risk-bar .text{color:#f87171;}
|
||
|
||
/* ═══ COLORS ═══ */
|
||
.bg-prospect{background:linear-gradient(135deg,#0a1a30,#081528);}
|
||
.bg-consulting{background:linear-gradient(135deg,#1a0a30,#120828);}
|
||
.bg-dev{background:linear-gradient(135deg,#0a2a1a,#081a12);}
|
||
.bg-infra{background:linear-gradient(135deg,#2a1a0a,#1a1208);}
|
||
.bg-security{background:linear-gradient(135deg,#2a0a0a,#1a0808);}
|
||
.bg-delivery{background:linear-gradient(135deg,#0a2a2a,#081a1a);}
|
||
.bg-pharma{background:linear-gradient(135deg,#1a0a2a,#120820);}
|
||
.bg-monitor{background:linear-gradient(135deg,#1a1a0a,#121208);}
|
||
|
||
@media(max-width:768px){
|
||
.agents-row{flex-direction:column;}
|
||
header{padding:20px;}
|
||
.chain{padding:16px 12px;}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body style="padding-top:60px"><div style="position:fixed;top:0;left:0;right:0;height:28px;background:#ffffffee;z-index:100;display:flex;align-items:center;padding:0 14px;font-family:Nunito,sans-serif;font-size:.65rem;gap:12px;border-bottom:1px solid #e2e8f0;backdrop-filter:blur(8px)"><b style="color:#059669">WEVIA</b></div>
|
||
<div style="position:fixed;top:30px;left:0;right:0;display:flex;justify-content:center;gap:5px;padding:4px;z-index:100;background:#f8fafcee;backdrop-filter:blur(8px);font-family:Nunito,sans-serif">
|
||
<a href="/agents-archi.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Architecture</a>
|
||
<a href="/director-center.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Director</a>
|
||
<a href="/wevia-meeting-rooms.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Rooms</a>
|
||
<a href="/enterprise-model.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Enterprise</a>
|
||
<a href="/agents-ia.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Pyramid</a>
|
||
<a href="/director-chat.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Chat</a>
|
||
<a href="/l99-brain.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">L99</a>
|
||
</div><div id="live-stats" ondblclick="this.remove()" style="position:fixed;top:0;left:0;right:0;z-index:9999;display:flex;justify-content:center;gap:12px;padding:4px 8px;background:linear-gradient(135deg,#1e293b,#0f172a);font-family:sans-serif"><div style="color:#4ade80;font:700 10px sans-serif"><body>#9889; <span id="ls-ag">669</span> Agents</div><div style="color:#60a5fa;font:700 10px sans-serif"><body>#127970; <span id="ls-dp">22</span> Depts</div><div style="color:#fbbf24;font:700 10px sans-serif"><body>#128051; 20 Docker</div><div style="color:#a78bfa;font:700 10px sans-serif"><body>#129302; 10 Ollama</div><div style="color:#f87171;font:700 10px sans-serif"><body>#128200; <span id="ls-nr">153/153</span></div><div style="color:#34d399;font:700 10px sans-serif"><body>#128274; SSO OK</div><div style="width:6px;height:6px;border-radius:50%;background:#4ade80;animation:lp 2s infinite;align-self:center"></div></div><style>@keyframes lp{0%,100%{opacity:1}50%{opacity:.3}}</style>
|
||
<div class="noise"></div>
|
||
|
||
<header>
|
||
<h1><span>WEVAL</span> Value Chain</h1>
|
||
<div class="sub">Où chaque agent agit — de la prospection à la livraison · Cliquez pour ouvrir</div>
|
||
</header>
|
||
|
||
<div class="chain" id="chain"></div>
|
||
|
||
<script>
|
||
const CHAIN = [
|
||
{
|
||
id:'prospect', icon:'🎯', title:'Prospection & Leads', color:'bg-prospect',
|
||
desc:'Acquisition clients, scraping B2B, enrichissement contacts',
|
||
agents:[
|
||
{n:'Ethica Scraper',e:'💊',p:'131K+ HCPs DZ/MA/TN'},
|
||
{n:'analyst',e:'🔍',p:'Analyse besoins client'},
|
||
{n:'writer',e:'✍️',p:'Cold emails, proposals'},
|
||
{n:'/sc:business_panel',e:'📊',p:'Analyse marché, KPIs'},
|
||
],
|
||
outputs:['weval_leads (166 contacts)','ethica_medecins (131K+)','linkedin_profiles (469)','Email campaigns B2B'],
|
||
risk:'Taux de réponse cold email < 5% — enrichissement emails en cours (gap: DZ 15K, MA 4.9K)',
|
||
},
|
||
{
|
||
id:'consulting', icon:'💼', title:'Consulting & Stratégie', color:'bg-consulting',
|
||
desc:'SWOT, audits, propositions commerciales, transformation digitale',
|
||
agents:[
|
||
{n:'CEO',e:'👔',p:'Décisions stratégiques autonomes'},
|
||
{n:'architect',e:'🏗️',p:'Architecture technique'},
|
||
{n:'planner',e:'📋',p:'Roadmaps, planning'},
|
||
{n:'critic',e:'⚖️',p:'Validation plans, risques'},
|
||
{n:'/sc:deep_research',e:'🔬',p:'Recherche approfondie'},
|
||
{n:'DeerFlow',e:'🦌',p:'Research multi-sources'},
|
||
],
|
||
outputs:['Propositions commerciales','Architecture technique','SWOT / PESTEL','Roadmaps migration','Audits conformité'],
|
||
risk:'12 providers cascade (0€): Groq→Cerebras→Gemini→Mistral→OpenRouter→SambaNova→Together→DeepSeek→Cohere→Nvidia→Qwen→ZhiPu — Ollama local en fallback',
|
||
},
|
||
{
|
||
id:'dev', icon:'⚡', title:'Développement & Code', color:'bg-dev',
|
||
desc:'Code, APIs, intégrations, 396 APIs PHP actives, 38 outils',
|
||
agents:[
|
||
{n:'executor',e:'⚡',p:'Exécution scripts, deploy'},
|
||
{n:'debugger',e:'🐛',p:'Trace bugs, root cause'},
|
||
{n:'code-reviewer',e:'👁️',p:'Reviews, severity rating'},
|
||
{n:'code-simplifier',e:'✂️',p:'Refactoring, clean code'},
|
||
{n:'designer',e:'🎨',p:'UI/UX, mockups'},
|
||
{n:'WEDROID',e:'🤖',p:'Backend auto-fix v5.0'},
|
||
{n:'/sc:token_efficiency',e:'⚡',p:'Code optimisé'},
|
||
],
|
||
outputs:['396 APIs PHP','WEVADS IA (36 pages)','WEVIA Chatbot (2842 lignes)','NonReg 153 tests','React SPA'],
|
||
risk:'Chatbot 24KB (refactoris — dette technique élevée, refonte par modules recommandée',
|
||
},
|
||
{
|
||
id:'infra', icon:'🏗️', title:'Infrastructure & DevOps', color:'bg-infra',
|
||
desc:'3 serveurs, 17 Docker, Ollama 5 modèles, Qdrant RAG',
|
||
agents:[
|
||
{n:'Watchdog',e:'🐕',p:'Auto-restart */3min'},
|
||
{n:'Guardian',e:'🛡️',p:'chattr +i, protection'},
|
||
{n:'Blade Sentinel',e:'💻',p:'Desktop agent PowerShell'},
|
||
{n:'git-master',e:'🌿',p:'Releases, branches'},
|
||
{n:'/sc:orchestration',e:'🎯',p:'Coordination multi-agent'},
|
||
],
|
||
outputs:['S204 (17 Docker)','S95 (192 Arsenal endpoints)','S151 (Ollama + tracking)','Blade (Razer laptop)','52 repos /opt/'],
|
||
risk:'Disk S204 82% — nettoyage régulier requis. S88 = DEAD (annulé, 0€)',
|
||
},
|
||
{
|
||
id:'security', icon:'🛡️', title:'Sécurité & Conformité', color:'bg-security',
|
||
desc:'OWASP, ISO 27001, RGPD, audit, chiffrement',
|
||
agents:[
|
||
{n:'security-reviewer',e:'🛡️',p:'Audit OWASP, vulns'},
|
||
{n:'verifier',e:'✅',p:'Conformité, checks'},
|
||
{n:'Guardian',e:'🛡️',p:'Protection fichiers'},
|
||
{n:'/sc:introspection',e:'🧠',p:'Méta-analyse sécurité'},
|
||
],
|
||
outputs:['Audit CLAUDE.md (secrets=clean)','Auth PHP session HMAC (simplifié, 0 dépendance)','AgentShield scan','chattr +i (8 fichiers protégés)'],
|
||
risk:'Auth PHP session + HMAC 30j — Authentik supprimé 8-avr (plus léger, plus stable)',
|
||
},
|
||
{
|
||
id:'delivery', icon:'🚀', title:'Livraison & QA', color:'bg-delivery',
|
||
desc:'Tests, NonReg, Playwright, L99, déploiement continu',
|
||
agents:[
|
||
{n:'qa-tester',e:'🧪',p:'Tests E2E, couverture'},
|
||
{n:'test-engineer',e:'🧰',p:'Suites CI/CD'},
|
||
{n:'tracer',e:'🔦',p:'Logs, debug chain'},
|
||
{n:'scientist',e:'🔬',p:'Benchmarks, métriques'},
|
||
],
|
||
outputs:['NonReg 153/153 PASS','L99 957/957 = 100% + NonReg 153/153 + PW 20/20','Playwright 20/20 + Visual 15/15','11 baselines visuelles','AI Benchmark (182 modèles)'],
|
||
risk:'L99 957/957 = 100% — 6σ DPMO 0',
|
||
},
|
||
{
|
||
id:'pharma', icon:'💊', title:'Pharma & Ethica', color:'bg-pharma',
|
||
desc:'HCP outreach Maghreb, campagnes email, consent RGPD',
|
||
agents:[
|
||
{n:'Ethica Scraper',e:'💊',p:'DabaDoc + LinkedIn'},
|
||
{n:'explore',e:'🧭',p:'Exploration nouvelles sources'},
|
||
{n:'document-specialist',e:'📝',p:'Templates campagnes'},
|
||
{n:'/sc:brainstorming',e:'💡',p:'Idées campagnes'},
|
||
{n:'MiroFish',e:'🐟',p:'Contenu créatif'},
|
||
],
|
||
outputs:['131K+ HCPs (DZ 95K, MA 19K, TN 17K)','Email drip */5min (DZ+MA+TN)','PhantomBuster LinkedIn','Consent RGPD (wevup.app)','16 scripts + 12 crons'],
|
||
risk:'Taux emails manquants: DZ 15K, MA 4.9K, TN 2.9K — enrichissement en cours',
|
||
},
|
||
{
|
||
id:'monitor', icon:'📡', title:'Monitoring & Intelligence', color:'bg-monitor',
|
||
desc:'Realtime monitor, KPIs, alertes, training data',
|
||
agents:[
|
||
{n:'Watchdog',e:'🐕',p:'Alerte Telegram restart'},
|
||
{n:'/sc:task_management',e:'📋',p:'Suivi tâches, deadlines'},
|
||
{n:'CEO',e:'👔',p:'Décisions autonomes'},
|
||
{n:'DeerFlow',e:'🦌',p:'Veille technologique'},
|
||
],
|
||
outputs:['Realtime Monitor v2','L99 Command Center','Uptime Kuma (99.9%)','Plausible Analytics','5,731+ training samples (GPU-ready, HuggingFace yace222/)'],
|
||
risk:'Fine-tune Phase 5 planifié — 5,731+ samples prêts, attente Colab/Kaggle',
|
||
},
|
||
];
|
||
|
||
function render(){
|
||
const el = document.getElementById('chain');
|
||
let html = '';
|
||
CHAIN.forEach((s,i) => {
|
||
html += `
|
||
<div class="stage" id="s-${s.id}" onclick="toggle('s-${s.id}')">
|
||
<div class="stage-header">
|
||
<div class="stage-icon ${s.color}">${s.icon}</div>
|
||
<div>
|
||
<div class="stage-title">${s.title}</div>
|
||
<div class="stage-sub">${s.desc}</div>
|
||
</div>
|
||
<div class="stage-right">
|
||
<div class="stage-count">${s.agents.length} agents · ${s.outputs.length} outputs</div>
|
||
<div class="stage-arrow">›</div>
|
||
</div>
|
||
</div>
|
||
<div class="stage-body">
|
||
<div class="agents-row">
|
||
${s.agents.map(a => `
|
||
<div class="agent-chip">
|
||
<div class="av">${a.e}</div>
|
||
<div class="info">
|
||
<div class="name">${a.n}</div>
|
||
<div class="prod">${a.p}</div>
|
||
</div>
|
||
</div>
|
||
`).join('')}
|
||
</div>
|
||
<div class="outputs">
|
||
${s.outputs.map(o => `<span class="output-tag">${o}</span>`).join('')}
|
||
</div>
|
||
<div class="risk-bar">
|
||
<span class="icon">⚠️</span>
|
||
<span class="text">${s.risk}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
if(i < CHAIN.length - 1){
|
||
html += `<div class="flow-connector"><div class="flow-line"></div></div>`;
|
||
}
|
||
});
|
||
el.innerHTML = html;
|
||
// Auto-open first
|
||
document.getElementById('s-prospect').classList.add('open');
|
||
}
|
||
|
||
function toggle(id){
|
||
document.getElementById(id).classList.toggle('open');
|
||
}
|
||
|
||
render();
|
||
</script>
|
||
<!-- CARTO_REMOVED -->
|
||
|
||
|
||
<script>
|
||
/* V75 AVATAR UNIFIER — Meeting-rooms emoji style (Opus 19avr) */
|
||
(function() {
|
||
if (window.__WEVAL_AVATAR_V75) return;
|
||
window.__WEVAL_AVATAR_V75 = true;
|
||
const REG_URL = '/api/agent-avatars-v75.json';
|
||
const SVG_EP = '/api/agent-avatar-svg.php';
|
||
function emojiSVGUrl(name, emoji) {
|
||
return SVG_EP + '?n=' + encodeURIComponent(name) + '&e=' + encodeURIComponent(emoji);
|
||
}
|
||
fetch(REG_URL + '?t=' + Date.now()).then(r => r.json()).then(REG => {
|
||
function getAvatarUrl(name) {
|
||
const rec = REG[name];
|
||
if (!rec) return null;
|
||
if (typeof rec === 'object' && rec.svg) return rec.svg;
|
||
if (typeof rec === 'object' && rec.emoji) return emojiSVGUrl(name, rec.emoji);
|
||
return typeof rec === 'string' ? rec : null;
|
||
}
|
||
function findCI(key) {
|
||
const lower = key.toLowerCase();
|
||
for (const k of Object.keys(REG)) if (k.toLowerCase() === lower) return k;
|
||
return null;
|
||
}
|
||
function apply() {
|
||
document.querySelectorAll('img').forEach(img => {
|
||
const key = img.alt || img.dataset.agent || img.dataset.name || img.title || '';
|
||
if (!key) return;
|
||
let url = getAvatarUrl(key);
|
||
if (!url) { const alt = findCI(key); if (alt) url = getAvatarUrl(alt); }
|
||
if (url && img.src !== url && !img.src.endsWith(url)) {
|
||
img.src = url;
|
||
img.setAttribute('data-weval-v75', '1');
|
||
}
|
||
});
|
||
document.querySelectorAll('[data-agent]:not([data-weval-v75-applied])').forEach(el => {
|
||
const name = el.dataset.agent;
|
||
const url = getAvatarUrl(name);
|
||
if (!url) return;
|
||
const img = document.createElement('img');
|
||
img.src = url; img.alt = name; img.title = name;
|
||
img.className = 'v75-avatar';
|
||
img.style.cssText = 'width:32px;height:32px;border-radius:50%;object-fit:cover;vertical-align:middle;background:transparent';
|
||
el.setAttribute('data-weval-v75-applied', '1');
|
||
el.prepend(img);
|
||
});
|
||
}
|
||
apply();
|
||
setTimeout(apply, 400); setTimeout(apply, 1200); setTimeout(apply, 3000);
|
||
const mo = new MutationObserver(() => apply());
|
||
mo.observe(document.body, {childList: true, subtree: true});
|
||
setTimeout(() => mo.disconnect(), 20000);
|
||
console.log('[V75 AvatarUnifier] applied from', Object.keys(REG).length, 'agents');
|
||
}).catch(e => console.warn('[V75] fetch failed', e));
|
||
})();
|
||
</script>
|
||
|
||
<!-- === OPUS UNIVERSAL DRILL-DOWN v1 19avr — append-only, doctrine #14 === -->
|
||
<script>
|
||
(function(){
|
||
if (window.__opusUniversalDrill) return; window.__opusUniversalDrill = true;
|
||
var d = document;
|
||
var m = d.createElement('div');
|
||
m.id = 'opus-udrill';
|
||
m.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.82);backdrop-filter:blur(6px);display:none;align-items:center;justify-content:center;z-index:99995;padding:20px;cursor:pointer';
|
||
var inner = d.createElement('div');
|
||
inner.id = 'opus-udrill-in';
|
||
inner.style.cssText = 'max-width:900px;width:100%;max-height:90vh;overflow:auto;background:#0b0d15;border:1px solid rgba(99,102,241,0.35);border-radius:14px;padding:28px;cursor:default;box-shadow:0 20px 60px rgba(0,0,0,0.6);color:#e2e8f0;font:14px/1.55 Inter,system-ui,sans-serif';
|
||
inner.addEventListener('click', function(e){ e.stopPropagation(); });
|
||
m.appendChild(inner);
|
||
m.addEventListener('click', function(){ m.style.display='none'; });
|
||
d.addEventListener('keydown', function(e){ if(e.key==='Escape') m.style.display='none'; });
|
||
(d.body || d.documentElement).appendChild(m);
|
||
|
||
function openCard(card) {
|
||
// Clone card content + show close btn + increase font-size
|
||
var html = '<div style="display:flex;justify-content:flex-end;margin-bottom:14px"><button id="opus-udrill-close" style="padding:6px 14px;background:#171b2a;border:1px solid rgba(99,102,241,0.25);color:#e2e8f0;border-radius:8px;cursor:pointer;font-size:12px">✕ Fermer (Esc)</button></div>';
|
||
html += '<div style="transform-origin:top left;font-size:1.05em">' + card.outerHTML + '</div>';
|
||
inner.innerHTML = html;
|
||
d.getElementById('opus-udrill-close').onclick = function(){ m.style.display='none'; };
|
||
m.style.display = 'flex';
|
||
}
|
||
|
||
function wire(root) {
|
||
var sels = '.card,[class*="card"],.kpi,[class*="kpi"],.stat,[class*="stat"],.tile,[class*="tile"],.metric,[class*="metric"],.widget,[class*="widget"]';
|
||
var cards = root.querySelectorAll(sels);
|
||
for (var i = 0; i < cards.length; i++) {
|
||
var c = cards[i];
|
||
if (c.__opusWired) continue;
|
||
if (c.closest('button, a, input, select, textarea, #opus-udrill')) continue;
|
||
var r = c.getBoundingClientRect();
|
||
if (r.width < 60 || r.height < 40) continue;
|
||
c.__opusWired = true;
|
||
c.style.cursor = 'pointer';
|
||
c.setAttribute('role','button');
|
||
c.setAttribute('tabindex','0');
|
||
c.addEventListener('click', function(ev){
|
||
// If a more-specific drill is already active (e.g. pp-card custom), let it handle
|
||
if (ev.target.closest('[data-pp-id]') && window.__opusDrillInit) return;
|
||
if (ev.target.closest('a,button,input,select')) return;
|
||
ev.preventDefault(); ev.stopPropagation();
|
||
openCard(this);
|
||
});
|
||
c.addEventListener('keydown', function(ev){ if(ev.key==='Enter'||ev.key===' '){ev.preventDefault();openCard(this);} });
|
||
}
|
||
}
|
||
|
||
// Initial + mutation observer
|
||
var initRun = function(){ wire(d.body || d.documentElement); };
|
||
if (d.readyState === 'loading') d.addEventListener('DOMContentLoaded', initRun);
|
||
else initRun();
|
||
var mo = new MutationObserver(function(muts){
|
||
var newCard = false;
|
||
for (var i=0;i<muts.length;i++) if (muts[i].addedNodes.length) { newCard = true; break; }
|
||
if (newCard) initRun();
|
||
});
|
||
mo.observe(d.body || d.documentElement, {childList:true, subtree:true});
|
||
})();
|
||
</script>
|
||
<!-- === OPUS UNIVERSAL DRILL-DOWN END === -->
|
||
|
||
|
||
<!-- === OPUS HONEST NR/L99 OVERLAY v1 19avr - append-only doctrine #14 === -->
|
||
<script>
|
||
(function(){
|
||
if (window.__opusHonestOverlay) return; window.__opusHonestOverlay = true;
|
||
async function updateHonestValues(){
|
||
try {
|
||
const r = await fetch('/api/l99-honest.php', {cache:'no-store'});
|
||
const d = await r.json();
|
||
if (!d.ok) return;
|
||
const realNR = `${d.combined.pass}/${d.combined.total}`;
|
||
const realSigma = d.sigma;
|
||
// Find elements showing the myth values
|
||
const mythRegex = /(153\/153|304\/304|NR status 153\/153|L99 status 304\/304|NR 153\/153|L99 304\/304)/g;
|
||
// Walk text nodes
|
||
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
|
||
const toReplace = [];
|
||
let node;
|
||
while (node = walker.nextNode()) {
|
||
if (node.nodeValue && mythRegex.test(node.nodeValue)) toReplace.push(node);
|
||
}
|
||
toReplace.forEach(textNode => {
|
||
const parent = textNode.parentNode;
|
||
if (!parent || parent.hasAttribute('data-opus-honest-applied')) return;
|
||
const newText = textNode.nodeValue.replace(/153\/153/g, realNR).replace(/304\/304/g, realNR);
|
||
textNode.nodeValue = newText;
|
||
parent.setAttribute('data-opus-honest-applied', '1');
|
||
});
|
||
// Add a small badge bottom-right showing honest live status
|
||
if (!document.getElementById('opus-honest-badge')) {
|
||
const b = document.createElement('div');
|
||
b.id = 'opus-honest-badge';
|
||
b.style.cssText = 'position:fixed;bottom:12px;right:12px;background:linear-gradient(90deg,#14b8a6,#a855f7);color:#05060a;padding:6px 12px;font:10px/1.3 Inter,system-ui,sans-serif;font-weight:700;border-radius:8px;z-index:99993;box-shadow:0 4px 12px rgba(0,0,0,0.3);cursor:pointer;max-width:280px';
|
||
b.title = 'Cliquer pour détails';
|
||
b.innerHTML = `✓ NR ${realNR} · ${realSigma} live`;
|
||
b.onclick = () => {
|
||
alert(`HONEST NonReg (doctrine #4):\n\nmaster: ${d.master.pass}/${d.master.total}\nopus: ${d.opus.pass}/${d.opus.total}\ncombined: ${realNR}\nsigma: ${realSigma}\n\n${d.myth_153}\n${d.myth_304}`);
|
||
};
|
||
document.body.appendChild(b);
|
||
}
|
||
} catch(e){console.error('L99-honest fetch error:', e);}
|
||
}
|
||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', updateHonestValues);
|
||
else updateHonestValues();
|
||
setInterval(updateHonestValues, 90000);
|
||
})();
|
||
</script>
|
||
<!-- === OPUS HONEST END === -->
|
||
|
||
</body>
|
||
</html>
|