Files
html/wevia-autonomy-dashboard.html
Opus 9a5f534d8b
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
phase30 doctrine 167 cascade enrich 6 pages - 18 pages UX doctrine 60 total
6 pages centrales enrichies via cascade Cerebras:
- wevia-chat-v2 (+1328B)
- sovereign-monitor (+1271B)
- wevia-audit (+1266B)
- wevia-console (+1263B)
- wevia-autonomy-dashboard (+1292B)
- wevia-business-visual-studio (+1300B)

Handler /var/www/html/api/enrich-hub-cascade.sh:
- Try Cerebras qwen-3-235b primary
- Fallback Ollama llama3.2 LOCAL (zero rate limit)
- GOLD backup + chattr handling + lint
- Markers DOCTRINE-60-UX-ENRICH idempotent

Intent wevia_enrich_hub_cascade_cerebras_ollama wired pour chat NL.
Total: 18 pages UX doctrine 60 (12 avant + 6 aujourd hui).

Cascade zero-rate-limit effective: Cerebras OK + Ollama llama3.2 ready.
Disk 87% stable apres recovery phase 29 +19GB.
2026-04-24 10:44:16 +02:00

348 lines
22 KiB
HTML

<!DOCTYPE html>
<html lang="fr"><head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>🧠 WEVIA Autonomy Dashboard · NeuroRAG v2</title>
<style>
:root{--bg:#0a0e1a;--panel:#141933;--panel2:#1a2140;--border:#263161;--text:#e4e8f7;--muted:#8b95b8;
--green:#10b981;--amber:#f59e0b;--red:#ef4444;--blue:#6ba3ff;--purple:#c084fc;--accent:#00d4b4}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,Segoe UI,Roboto,sans-serif;background:var(--bg);color:var(--text);padding:20px;min-height:100vh;line-height:1.5}
.header{display:flex;justify-content:space-between;align-items:center;padding:20px 26px;background:linear-gradient(135deg,#1e1b4b,#312e81);border-radius:14px;margin-bottom:22px;border:1px solid var(--border)}
.header h1{color:#fff;font-size:26px;display:flex;align-items:center;gap:12px}
.header .sub{color:rgba(255,255,255,.75);font-size:12px;margin-top:4px}
.autonomy-score-box{display:grid;grid-template-columns:1fr auto;gap:28px;padding:22px 28px;background:linear-gradient(135deg,#065f46,#064e3b);border-radius:14px;margin-bottom:22px;border:1px solid rgba(16,185,129,.3)}
.autonomy-score-box .label{font-size:12px;color:#6ee7b7;text-transform:uppercase;letter-spacing:1px}
.autonomy-score-box .score{font-size:66px;font-weight:900;font-family:'SF Mono',monospace;color:#fff;line-height:1}
.autonomy-score-box .score .max{font-size:20px;color:rgba(255,255,255,.5);margin-left:6px}
.autonomy-score-box .level{margin-top:6px;padding:6px 14px;background:rgba(255,255,255,.15);color:#fff;border-radius:99px;font-size:12px;font-weight:700;letter-spacing:1px;display:inline-block}
.bar-container{background:rgba(0,0,0,.3);padding:14px;border-radius:10px;min-width:280px}
.bar-row{display:grid;grid-template-columns:150px 1fr 60px;gap:10px;align-items:center;margin-bottom:8px;font-size:11px}
.bar-row:last-child{margin-bottom:0}
.bar-row .lbl{color:rgba(255,255,255,.75);text-transform:uppercase;font-weight:500}
.bar-bg{height:14px;background:rgba(255,255,255,.12);border-radius:7px;overflow:hidden}
.bar-fill{height:100%;background:linear-gradient(90deg,#10b981,#34d399);transition:width .4s}
.bar-row .val{text-align:right;color:#fff;font-family:'SF Mono',monospace;font-weight:600;font-size:11px}
.kpi-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-bottom:22px}
.kpi{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:16px 18px;position:relative}
.kpi::before{content:'';position:absolute;top:0;left:0;width:4px;height:100%;background:var(--accent);border-radius:4px 0 0 4px}
.kpi.green::before{background:var(--green)}.kpi.amber::before{background:var(--amber)}.kpi.blue::before{background:var(--blue)}.kpi.purple::before{background:var(--purple)}
.kpi .l{font-size:10.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.6px;font-weight:500;margin-bottom:6px}
.kpi .v{font-size:28px;font-weight:800;color:var(--text);font-family:'SF Mono',Monaco,monospace;line-height:1.1}
.kpi .v.good{color:#6ee7b7}
.kpi .s{font-size:11px;color:var(--muted);margin-top:4px}
.section{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:22px;margin-bottom:20px}
.section h2{color:var(--purple);font-size:16px;font-weight:600;margin-bottom:14px;padding-bottom:10px;border-bottom:1px dashed var(--border)}
.table{width:100%;border-collapse:collapse;font-size:13px}
.table th{background:var(--panel2);color:var(--muted);padding:10px 14px;text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.6px;font-weight:600;border-bottom:1px solid var(--border)}
.table td{padding:10px 14px;border-bottom:1px solid var(--border);color:var(--text)}
.table tr:hover td{background:rgba(0,212,180,.03)}
.badge{padding:3px 9px;border-radius:4px;font-size:10.5px;font-weight:600;letter-spacing:.4px}
.badge.green{background:rgba(16,185,129,.2);color:#6ee7b7}
.badge.amber{background:rgba(245,158,11,.2);color:#fbbf24}
.badge.red{background:rgba(239,68,68,.2);color:#fca5a5}
.badge.blue{background:rgba(108,163,255,.2);color:#93c5fd}
.badge.purple{background:rgba(192,132,252,.2);color:#d8b4fe}
.n{font-family:'SF Mono',Monaco,monospace;font-weight:600;color:var(--accent)}
.domains-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:10px}
.dom-card{background:var(--panel2);border:1px solid var(--border);border-radius:8px;padding:12px 14px}
.dom-card .name{font-weight:600;text-transform:uppercase;font-size:11px;color:var(--accent);letter-spacing:.4px}
.dom-card .bar{margin-top:6px;height:10px;background:rgba(0,0,0,.3);border-radius:5px;overflow:hidden}
.dom-card .fill-green{height:100%;background:var(--green)}
.dom-card .fill-amber{height:100%;background:var(--amber)}
.dom-card .fill-red{height:100%;background:var(--red)}
.dom-card .meta{display:flex;justify-content:space-between;margin-top:6px;font-size:11px}
.dom-card .wired{color:#6ee7b7;font-family:'SF Mono',monospace;font-weight:600}
.dom-card .gap{color:#fca5a5;font-family:'SF Mono',monospace;font-weight:600}
.skills-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:12px}
.skill-card{background:var(--panel2);border:1px solid var(--border);border-radius:10px;padding:16px}
.skill-card .title{font-size:15px;font-weight:700;color:var(--accent);margin-bottom:4px}
.skill-card .src{font-size:10.5px;color:var(--muted);font-family:'SF Mono',monospace;margin-bottom:10px}
.skill-card .desc{font-size:12.5px;color:var(--text);margin-bottom:10px}
.skill-card .tags{display:flex;gap:6px;flex-wrap:wrap}
.skill-card .tag{font-size:10px;padding:2px 7px;border-radius:4px;background:rgba(0,212,180,.12);color:var(--accent)}
.skill-card button{margin-top:10px;padding:7px 12px;background:var(--accent);color:#000;border:none;border-radius:6px;cursor:pointer;font-size:11px;font-weight:600}
.gap-card{background:rgba(239,68,68,.05);border:1px solid rgba(239,68,68,.3);border-radius:8px;padding:14px;margin-bottom:8px;display:grid;grid-template-columns:70px 1fr auto;gap:14px;align-items:center}
.gap-card .prio{padding:4px 10px;background:rgba(239,68,68,.2);color:#fca5a5;border-radius:4px;font-size:11px;font-weight:700;text-align:center}
.gap-card .name{font-weight:600;color:var(--text)}
.gap-card .fix{font-size:11.5px;color:var(--muted);margin-top:2px}
.footer{text-align:center;margin-top:20px;font-size:10.5px;color:var(--muted)}
.footer a{color:#93c5fd;text-decoration:none;margin:0 8px}
.status-bar{position:sticky;bottom:0;background:linear-gradient(0deg,var(--bg),rgba(10,14,26,.95));padding:12px 18px;margin:0 -20px -20px -20px;display:flex;justify-content:space-between;font-size:11.5px;color:var(--muted);border-top:1px solid var(--border)}
.loading{text-align:center;padding:30px;color:var(--muted);font-size:13px}
/* === OPUS RESPONSIVE FIX v2 19avr — append-only, doctrine #14 === */
@media(max-width: 480px) {
html, body { overflow-x: hidden !important; max-width: 100vw; }
body, main, section, article { word-break: break-word; overflow-wrap: anywhere; }
img, video, iframe, canvas, svg, table, pre, code { max-width: 100% !important; }
pre, code { white-space: pre-wrap; word-break: break-all; }
table { display: block; overflow-x: auto; }
.container, [class*="container"], [class*="wrapper"] { max-width: 100vw !important; padding-left: 12px !important; padding-right: 12px !important; }
[class*="grid"], [class*="-grid"] { grid-template-columns: 1fr !important; gap: 10px !important; }
[class*="kpi"], [class*="stats"], [class*="-cards"] { grid-template-columns: 1fr !important; }
header, nav, footer { flex-wrap: wrap !important; }
header > *, nav > *, footer > * { max-width: 100%; }
h1 { font-size: 22px !important; word-break: break-word; }
h2 { font-size: 18px !important; }
.pitch, [class*="pitch"], [class*="hero"] { word-break: break-word; overflow-wrap: anywhere; }
}
/* === OPUS RESPONSIVE FIX v2 END === */
</style><!-- DOCTRINE-60-UX-ENRICH cerebras-qwen-235b 20260424-104142 --><style id="doctrine60-ux-wevia-autonomy-dashboard">
body::before {
content: '';
position: fixed;
width: 100%;
height: 100%;
background: radial-gradient(circle, rgba(0,0,0,0.12), transparent 70%);
z-index: -1;
pointer-events: none;
}
.card, .btn, .kpi, .panel {
opacity: 0;
transform: translateY(20px);
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.enter-stagger {
opacity: 1;
transform: translateY(0);
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
.pulse, .active, .live-indicator, .online {
animation: pulse 3s ease-in-out infinite;
}
.card:hover {
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
border-color: var(--accent);
}
.modal, .chat, .speech, .overlay {
backdrop-filter: blur(12px);
}
</style>
</head>
<body>
<div class="header">
<div>
<h1>🧠 WEVIA Autonomy Dashboard <span style="padding:5px 12px;background:rgba(16,185,129,.2);color:#6ee7b7;border:1px solid rgba(16,185,129,.4);border-radius:99px;font-size:11px;font-weight:600">● LIVE v2</span></h1>
<div class="sub">NeuroRAG · Qdrant · 15K+ skills · 310 intents · 61 agents · 13 providers</div>
</div>
<div style="text-align:right"><div style="font-size:11px;color:rgba(255,255,255,.6)"></div><a href="/weval-technology-platform.html" style="color:#93c5fd;text-decoration:none;font-size:13px">WTP Platform Portal</a></div>
</div>
<div id="autonomy-score" class="autonomy-score-box"><div class="loading" style="grid-column:1/-1">Chargement…</div></div>
<div id="kpis" class="kpi-row"><div class="loading"></div></div>
<div class="section"><h2>📊 Arena Domains · 310 intents répartis · 187 wired · 107 gap</h2><div class="domains-grid" id="domains-grid"><div class="loading"></div></div></div>
<div class="section"><h2>📦 Top Qdrant Collections (mémoire + skills + KB)</h2>
<table class="table"><thead><tr><th>Collection</th><th>Points</th><th>Type</th></tr></thead><tbody id="cols-tbody"><tr><td colspan="3" class="loading"></td></tr></tbody></table></div>
<div class="section"><h2>⚡ 6 Skills stratégiques (from Yacine screenshots)</h2><div class="skills-grid" id="skills-grid"></div></div>
<div class="section"><h2>🔴 Gaps autonomie · Actions P1-P3</h2><div id="gaps-list"><div class="loading"></div></div></div>
<div class="status-bar"><div>Autonomy v2 · <span id="ts"></span></div><div>NonReg <span id="nr"></span>/<span id="nr-total">153</span> · <span id="nr-pct" style="color:#6ee7b7">100%</span> · L99 invariant · WEVIA Master</div></div>
<div class="footer">
<a href="/visual-management.html">Visual Management</a>·<a href="/wevia-business-visual-studio.html">BVS</a>·<a href="/weval-technology-platform.html">WTP</a>·<a href="/l99.html">L99</a>·<a href="/wevia-master.html">WEVIA Master</a>
</div>
<script>
const SKILLS = [
{title:"Feynman Research",src:"github.com/getcompanion-ai/feynman",desc:"4 agents parallèles · research/review/draft/verify · live citations",tags:["research","parallel","citations"],trigger:"feynman research"},
{title:"Magika Scan",src:"github.com/google/magika · 15K",desc:"AI file type detection 99% accuracy · Apache 2.0",tags:["security","google"],trigger:"magika scan"},
{title:"Sous-agents Claude Code",src:"Claude Code /agents",desc:"Pattern parallel backend/frontend/payment · ~2k tokens par agent",tags:["parallel","pattern"],trigger:"sous agents"},
{title:"Gemma 4 Inside",src:"Google · Apache 2.0",desc:"80% LiveCodeBench · 256k context · 0$ coding alternative",tags:["LLM","coding","free"],trigger:"gemma 4"},
{title:"bitnet.cpp",src:"1-bit framework",desc:"100B params on CPU · 82% less energy · 100% open",tags:["CPU","offline"],trigger:"bitnet status"},
{title:"AirLLM",src:"github.com/lyogavin/airllm",desc:"405B LLMs on 8GB VRAM · layered inference",tags:["GPU","quantize"],trigger:"airllm status"}
];
function fmt(n){return (n||0).toLocaleString('fr-FR');}
function esc(s){return String(s||'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));}
async function refresh(){
try{
const r = await fetch('/api/wevia-neurorag-api.php?action=status&t='+Date.now(),{cache:'no-store'});
const d = await r.json();
const a = d.autonomy || {};
const I = a.intents || {}, S = a.skills || {}, AG = a.agents || {}, Q = a.qdrant || {};
document.getElementById('ts').textContent = (d.ts||'').replace('T',' ').split('+')[0];
document.getElementById('nr').textContent = a.nonreg_pass ?? a.nonreg_total ?? 153;
document.getElementById('nr-total').textContent = a.nonreg_total ?? 153;
document.getElementById('nr-pct').textContent = (a.nonreg_score ?? 100) + '%';
// Autonomy score
const score = a.autonomy_score || 0;
const level = a.autonomy_level || '—';
const levelColor = level==='MAX AUTONOMY' ? '#6ee7b7' : level==='HIGH' ? '#fbbf24' : '#fca5a5';
const cats = [
{l:'Skills TOTAL', v:S.TOTAL_ALL_SOURCES||0, m:15000},
{l:'Intents arena', v:I.TOTAL_MAX||0, m:375},
{l:'Agents TOTAL', v:AG.TOTAL||0, m:120},
{l:'Providers LLM', v:a.sovereign_providers||0, m:15},
{l:'Qdrant cols', v:Q.collections_count||0, m:30},
];
document.getElementById('autonomy-score').innerHTML =
'<div>'+
'<div class="label">Autonomy Score · '+esc(level)+'</div>'+
'<div class="score">'+score+'<span class="max">/100</span></div>'+
'<div class="level" style="background:'+levelColor+'33;color:'+levelColor+'">'+esc(level)+'</div>'+
'</div>'+
'<div class="bar-container">'+
cats.map(c=>{
const p = Math.min(100,(c.v/c.m)*100);
return '<div class="bar-row"><span class="lbl">'+esc(c.l)+'</span><div class="bar-bg"><div class="bar-fill" style="width:'+p+'%"></div></div><span class="val">'+fmt(c.v)+'</span></div>';
}).join('')+
'</div>';
// KPIs
document.getElementById('kpis').innerHTML =
'<div class="kpi green"><div class="l">Skills TOTAL</div><div class="v good">'+fmt(S.TOTAL_ALL_SOURCES)+'</div><div class="s">Qdrant '+fmt(S.qdrant_weval_skills_points)+' + tools '+fmt(S.tools_registry)+'</div></div>'+
'<div class="kpi blue"><div class="l">Intents Arena</div><div class="v">'+fmt(I.TOTAL_MAX)+'</div><div class="s">'+fmt(I.arena_wired)+' wired · gap '+fmt(I.arena_gap)+'</div></div>'+
'<div class="kpi purple"><div class="l">Agents TOTAL</div><div class="v">'+fmt(AG.TOTAL)+'</div><div class="s">'+fmt(AG.agent_files)+' files + '+fmt(AG.agent_stubs)+' stubs</div></div>'+
'<div class="kpi amber"><div class="l">Qdrant Points</div><div class="v">'+fmt(Q.total_points)+'</div><div class="s">'+fmt(Q.collections_count)+' collections</div></div>'+
'<div class="kpi green"><div class="l">Sovereign LLMs</div><div class="v good">'+(a.sovereign_providers||0)+'/13</div><div class="s">providers 0$</div></div>'+
'<div class="kpi green"><div class="l">NonReg</div><div class="v good">'+(a.nonreg_pass||a.nonreg_total||153)+'/'+(a.nonreg_total||153)+'</div><div class="s">'+(a.nonreg_score||100)+'% · invariant</div></div>';
// Domains
const domains = a.arena_domains || {};
const domHtml = Object.entries(domains).map(([name,info])=>{
const w = info.wired||0, t = info.count||0, g = info.gap||0;
const pct = t ? (w/t)*100 : 0;
const cls = pct===100 ? 'fill-green' : pct>=50 ? 'fill-amber' : 'fill-red';
return '<div class="dom-card"><div class="name">'+esc(name)+'</div><div class="bar"><div class="'+cls+'" style="width:'+pct+'%"></div></div><div class="meta"><span class="wired">'+w+'/'+t+' wired</span><span class="gap">gap '+g+'</span></div></div>';
}).join('');
document.getElementById('domains-grid').innerHTML = domHtml || '<div class="loading">N/A</div>';
// Collections
const cols = Q.top_collections || [];
const colHtml = cols.map(c=>{
const type = c.name.includes('memory')?'Memory':c.name.includes('skill')?'Skill':'KB';
const badge = type==='Memory'?'green':type==='Skill'?'purple':'blue';
return '<tr><td><code>'+esc(c.name)+'</code></td><td class="n">'+fmt(c.points)+'</td><td><span class="badge '+badge+'">'+type+'</span></td></tr>';
}).join('');
document.getElementById('cols-tbody').innerHTML = colHtml || '<tr><td colspan="3">N/A</td></tr>';
// Skills
document.getElementById('skills-grid').innerHTML = SKILLS.map(s=>
'<div class="skill-card"><div class="title">'+esc(s.title)+'</div><div class="src">'+esc(s.src)+'</div><div class="desc">'+esc(s.desc)+'</div><div class="tags">'+s.tags.map(t=>'<span class="tag">'+esc(t)+'</span>').join('')+'</div><button onclick="runIntent(\''+esc(s.trigger)+'\')">▶ '+esc(s.trigger)+'</button></div>'
).join('');
// Gaps
const gaps = a.gaps || [];
document.getElementById('gaps-list').innerHTML = gaps.length ?
gaps.map(g=>'<div class="gap-card"><span class="prio">'+esc(g.priority)+'</span><div><div class="name">'+esc(g.name)+'</div><div class="fix">'+esc(g.fix)+'</div></div><button onclick="runIntent(\'fix '+esc(g.priority).toLowerCase()+'\')" style="padding:7px 12px;background:var(--accent);color:#000;border:none;border-radius:6px;cursor:pointer;font-weight:600">Fix</button></div>').join('') :
'<div style="color:var(--muted);padding:12px">Aucun gap critique</div>';
}catch(e){console.error(e);}
}
async function runIntent(t){
try{
const r = await fetch('/api/wevia-master-api.php?fast=1',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:t})});
const x = await r.text();
alert('WEVIA ('+x.length+'b):\n'+x.substring(0,500));
}catch(e){alert('Error: '+e.message);}
}
refresh(); setInterval(refresh, 45000);
</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 === -->
<script src="/api/archi-meta-badge.js" defer></script>
<script src="/api/a11y-auto-enhancer.js" defer></script>
<!-- WTP_UDOCK_V1 (Opus 21-avr t33b6) --><script src="/wtp-unified-dock.js" defer></script>
<script src="/opus-antioverlap-doctrine.js?v=1776776094" defer></script>
<!-- DOCTRINE-60-UX-JS --><script id="doctrine60-ux-js-wevia-autonomy-dashboard">
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry, index) => {
if (entry.isIntersecting) {
setTimeout(() => {
entry.target.classList.add('enter-stagger');
}, index * 80);
}
});
}, { threshold: 0.1 });
document.querySelectorAll('.card, .btn, .kpi, .panel').forEach(el => {
observer.observe(el);
});
</script>
</body></html>