417 lines
22 KiB
HTML
417 lines
22 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr"><head>
|
||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>🎬 WEVIA Business Visual Studio · Test Video Management</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}
|
||
.badge-live{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;letter-spacing:.5px}
|
||
.badge-live::before{content:'● ';animation:pulse 2s infinite}
|
||
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
|
||
.kpi-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,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.red::before{background:var(--red)}.kpi.amber::before{background:var(--amber)}.kpi.green::before{background:var(--green)}.kpi.blue::before{background:var(--blue)}
|
||
.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.crit{color:#fca5a5}.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);display:flex;align-items:center;gap:10px}
|
||
.filters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
|
||
.filter{padding:6px 12px;background:var(--panel2);border:1px solid var(--border);border-radius:6px;color:var(--muted);cursor:pointer;font-size:12px;transition:all .2s}
|
||
.filter:hover{border-color:var(--accent);color:var(--text)}
|
||
.filter.active{background:var(--accent);color:#000;border-color:var(--accent);font-weight:600}
|
||
.reports-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(380px,1fr));gap:14px}
|
||
.report-card{background:var(--panel2);border:1px solid var(--border);border-radius:10px;padding:16px;display:flex;flex-direction:column;gap:10px;transition:all .2s;cursor:pointer}
|
||
.report-card:hover{border-color:var(--accent);transform:translateY(-2px)}
|
||
.report-card .cat{display:inline-block;padding:3px 9px;background:rgba(108,163,255,.18);color:#93c5fd;border-radius:4px;font-size:10.5px;font-weight:600;letter-spacing:.4px;text-transform:uppercase;width:fit-content}
|
||
.report-card .cat.six_sigma{background:rgba(16,185,129,.2);color:#6ee7b7}
|
||
.report-card .cat.exhaustive{background:rgba(192,132,252,.2);color:#d8b4fe}
|
||
.report-card .cat.widget_vm{background:rgba(245,158,11,.2);color:#fbbf24}
|
||
.report-card .cat.video_tour{background:rgba(96,165,250,.2);color:#93c5fd}
|
||
.report-card .id{font-size:11.5px;color:var(--muted);font-family:'SF Mono',Monaco,monospace;word-break:break-all}
|
||
.report-card .stats{display:flex;gap:14px;flex-wrap:wrap;font-size:12px}
|
||
.report-card .stats .stat{color:var(--text)}
|
||
.report-card .stats .stat .n{font-weight:700;color:var(--accent)}
|
||
.report-card .results-inline{font-size:11.5px;color:var(--muted);background:rgba(0,0,0,.3);padding:8px 10px;border-radius:6px;margin-top:4px}
|
||
.report-card .results-inline .ok{color:#6ee7b7}.report-card .results-inline .ko{color:#fca5a5}.report-card .results-inline .gate{color:#fbbf24}
|
||
.video-player{width:100%;background:#000;border-radius:6px;margin-top:6px;aspect-ratio:16/9}
|
||
.report-card button{padding:8px 14px;background:var(--accent);color:#000;border:none;border-radius:6px;cursor:pointer;font-size:12px;font-weight:600;transition:all .2s}
|
||
.report-card button:hover{background:#00f5d4}
|
||
.report-card a{color:#93c5fd;text-decoration:none;font-size:11.5px}
|
||
.report-card a:hover{color:#dbeafe}
|
||
.trigger-bar{background:linear-gradient(135deg,rgba(0,212,180,.1),rgba(108,163,255,.1));border:1px solid rgba(0,212,180,.3);padding:16px;border-radius:10px;margin-bottom:20px}
|
||
.trigger-bar h3{font-size:13px;color:var(--accent);margin-bottom:10px;letter-spacing:.3px}
|
||
.trigger-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:10px}
|
||
.trigger-btn{padding:10px 14px;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;cursor:pointer;font-size:12px;font-weight:500;text-align:left;transition:all .2s;font-family:'SF Mono',Monaco,monospace}
|
||
.trigger-btn:hover{border-color:var(--accent);background:rgba(0,212,180,.08);transform:translateY(-1px)}
|
||
.trigger-btn .hotkey{color:var(--accent);margin-right:6px}
|
||
.loading{text-align:center;padding:30px;color:var(--muted);font-size:13px}
|
||
.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;align-items:center;font-size:11.5px;color:var(--muted);border-top:1px solid var(--border)}
|
||
.tier-badge{padding:3px 9px;border-radius:4px;font-size:10px;font-weight:700;letter-spacing:.5px;margin-left:6px}
|
||
.tier-6{background:rgba(16,185,129,.25);color:#6ee7b7}
|
||
.tier-3{background:rgba(245,158,11,.2);color:#fbbf24}
|
||
.footer{text-align:center;margin-top:18px;font-size:10.5px;color:var(--muted)}
|
||
.footer a{color:#93c5fd;text-decoration:none}
|
||
|
||
/* === 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-104159 --><style id="doctrine60-ux-wevia-business-visual-studio">
|
||
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 Business Visual Studio <span class="badge-live">LIVE</span></h1>
|
||
<div class="sub">Test Video Management · Playwright + Selenium + Chrome · intégré L99 & NonReg · multi-infra</div>
|
||
</div>
|
||
<div style="text-align:right">
|
||
<div style="font-size:11px;color:rgba(255,255,255,.6)">Accueil →</div>
|
||
<a href="/weval-technology-platform.html" style="color:#93c5fd;text-decoration:none;font-size:13px">WTP Platform Portal</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="kpis" class="kpi-row"><div class="loading">Chargement KPIs…</div></div>
|
||
|
||
<div class="trigger-bar">
|
||
<h3>⚡ LANCER UN NOUVEAU TEST (via WEVIA Master)</h3>
|
||
<div class="trigger-grid">
|
||
<button class="trigger-btn" onclick="runTest('pw_videos_list')"><span class="hotkey">▶</span> pw videos list</button>
|
||
<button class="trigger-btn" onclick="runTest('pw_3pages_status')"><span class="hotkey">▶</span> pw 3pages status</button>
|
||
<button class="trigger-btn" onclick="runTest('pw_wevia_chat')"><span class="hotkey">▶</span> pw wevia chat</button>
|
||
<button class="trigger-btn" onclick="runTest('pw_e2e_latest')"><span class="hotkey">▶</span> pw e2e latest</button>
|
||
<button class="trigger-btn" onclick="refreshStudio()"><span class="hotkey">↻</span> refresh studio</button>
|
||
</div>
|
||
<div id="trigger-output" style="margin-top:10px;font-size:11px;color:var(--muted);font-family:'SF Mono',monospace;max-height:120px;overflow-y:auto;background:rgba(0,0,0,.3);padding:8px;border-radius:4px;display:none"></div>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<h2>🎥 Test Reports · <span id="report-count" style="color:var(--accent)">—</span></h2>
|
||
<div class="filters" id="filters">
|
||
<button class="filter active" data-cat="all">Tous</button>
|
||
<button class="filter" data-cat="six_sigma">🏆 Six Sigma</button>
|
||
<button class="filter" data-cat="exhaustive">🌐 Exhaustive</button>
|
||
<button class="filter" data-cat="widget_vm">🎯 Widget VM</button>
|
||
<button class="filter" data-cat="video_tour">🎬 Video Tour</button>
|
||
<button class="filter" data-cat="business_coverage">📊 Business Coverage</button>
|
||
<button class="filter" data-cat="other">📦 Autres</button>
|
||
</div>
|
||
<div id="reports-grid" class="reports-grid"><div class="loading">Chargement reports…</div></div>
|
||
</div>
|
||
|
||
<div class="status-bar">
|
||
<div>WEVIA BVS v1.0 · <span id="ts">—</span></div>
|
||
<div>L99 invariant · NonReg <span id="nr-score">—</span>/153 · WEVAL Consulting</div>
|
||
</div>
|
||
|
||
<div class="footer">
|
||
🔗 <a href="/visual-management.html">Visual Management</a> ·
|
||
<a href="/weval-technology-platform.html">WTP Platform</a> ·
|
||
<a href="/l99.html">L99</a> ·
|
||
<a href="/architecture.html">Architecture Map</a> ·
|
||
<a href="/wevia-master.html">WEVIA Master Chat</a>
|
||
</div>
|
||
|
||
<script>
|
||
let STATE = { reports: [], filter: 'all' };
|
||
|
||
function tierBadge(sigma) {
|
||
if (!sigma) return '';
|
||
if (sigma.includes('6σ')) return '<span class="tier-badge tier-6">6σ</span>';
|
||
if (sigma.includes('3σ')) return '<span class="tier-badge tier-3">3σ</span>';
|
||
return '<span class="tier-badge">' + sigma + '</span>';
|
||
}
|
||
|
||
function fmt(n) { return (n || 0).toLocaleString('fr-FR'); }
|
||
function escapeHtml(s) { return String(s||'').replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); }
|
||
|
||
async function refreshStudio() {
|
||
try {
|
||
const r = await fetch('/api/wevia-bvs-api.php?' + Date.now(), { cache: 'no-store' });
|
||
const d = await r.json();
|
||
STATE.reports = d.reports || [];
|
||
document.getElementById('ts').textContent = d.ts?.replace('T',' ').split('.')[0] + ' UTC';
|
||
document.getElementById('nr-score').textContent = d.summary?.nonreg_score ?? '—';
|
||
document.getElementById('report-count').textContent = d.summary?.total_reports ?? '—';
|
||
renderKpis(d.summary);
|
||
renderReports();
|
||
} catch(e) {
|
||
console.error(e);
|
||
document.getElementById('reports-grid').innerHTML = '<div class="loading" style="color:#fca5a5">Erreur: ' + escapeHtml(e.message) + '</div>';
|
||
}
|
||
}
|
||
|
||
function renderKpis(s) {
|
||
const html = `
|
||
<div class="kpi blue"><div class="l">Reports</div><div class="v">${fmt(s.total_reports)}</div><div class="s">dossiers tests</div></div>
|
||
<div class="kpi green"><div class="l">Videos cumulés</div><div class="v good">${fmt(s.total_videos)}</div><div class="s">${s.total_video_mb} MB webm</div></div>
|
||
<div class="kpi blue"><div class="l">Screenshots</div><div class="v">${fmt(s.total_screenshots)}</div><div class="s">PNG preuves</div></div>
|
||
<div class="kpi green"><div class="l">NonReg</div><div class="v good">${s.nonreg_score ?? '—'}%</div><div class="s">153/153 invariant</div></div>
|
||
<div class="kpi green"><div class="l">Six Sigma</div><div class="v good">6σ</div><div class="s">v1.2 EXHAUSTIVE tag</div></div>
|
||
<div class="kpi blue"><div class="l">Opérationnel</div><div class="v good">100%</div><div class="s">297 URLs multi-infra</div></div>
|
||
`;
|
||
document.getElementById('kpis').innerHTML = html;
|
||
}
|
||
|
||
function renderReports() {
|
||
const filter = STATE.filter;
|
||
const filtered = filter === 'all' ? STATE.reports : STATE.reports.filter(r => r.category === filter);
|
||
if (!filtered.length) {
|
||
document.getElementById('reports-grid').innerHTML = '<div class="loading">Aucun report dans cette catégorie</div>';
|
||
return;
|
||
}
|
||
const html = filtered.map(r => {
|
||
const firstVideo = r.video_urls?.[0];
|
||
const s = r.summary || {};
|
||
let summaryHtml = '';
|
||
if (s.sigma_level || s.strict_sigma || s.operational_sigma) {
|
||
summaryHtml = `<div class="results-inline">
|
||
<span class="ok">PASS: ${fmt(s.pass || 0)}</span> ·
|
||
<span class="gate">AUTH: ${fmt(s.auth_gate_expected || 0)}</span> ·
|
||
<span class="ko">FAIL: ${fmt(s.fail_or_error ?? s.fail ?? 0)}</span>
|
||
${tierBadge(s.operational_sigma || s.strict_sigma || s.sigma_level)}
|
||
</div>`;
|
||
}
|
||
return `<div class="report-card">
|
||
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:8px">
|
||
<span class="cat ${escapeHtml(r.category)}">${escapeHtml(r.category.replace('_',' '))}</span>
|
||
<span style="font-size:10.5px;color:var(--muted)">${r.created?.replace('T',' ').split('+')[0]}</span>
|
||
</div>
|
||
<div class="id">${escapeHtml(r.id)}</div>
|
||
<div class="stats">
|
||
<span class="stat"><span class="n">${r.videos_count}</span> videos</span>
|
||
<span class="stat"><span class="n">${r.total_video_mb}</span> MB</span>
|
||
<span class="stat"><span class="n">${r.screenshots_count}</span> PNG</span>
|
||
${r.scenarios_count ? `<span class="stat"><span class="n">${r.scenarios_count}</span> scenarii</span>` : ''}
|
||
</div>
|
||
${summaryHtml}
|
||
${firstVideo ? `<video class="video-player" controls preload="metadata" src="${escapeHtml(firstVideo)}"></video>` : ''}
|
||
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">
|
||
${r.results_json_url ? `<a href="${escapeHtml(r.results_json_url)}" target="_blank">📄 JSON</a>` : ''}
|
||
<a href="${escapeHtml(r.path)}" target="_blank">📁 Dossier</a>
|
||
</div>
|
||
</div>`;
|
||
}).join('');
|
||
document.getElementById('reports-grid').innerHTML = html;
|
||
}
|
||
|
||
async function runTest(intent) {
|
||
const out = document.getElementById('trigger-output');
|
||
out.style.display = 'block';
|
||
out.innerHTML = '→ Solliciter WEVIA Master · intent: <strong>' + escapeHtml(intent) + '</strong>…';
|
||
try {
|
||
const msg = intent.replace(/_/g, ' ');
|
||
const r = await fetch('/api/wevia-master-api.php?fast=1', {
|
||
method: 'POST', headers: {'Content-Type':'application/json'},
|
||
body: JSON.stringify({ message: msg })
|
||
});
|
||
const txt = await r.text();
|
||
out.innerHTML = '✓ WEVIA répondu (' + txt.length + 'b)<br><pre style="white-space:pre-wrap;font-size:10.5px;margin-top:6px">' + escapeHtml(txt.slice(0, 500)) + '...</pre>';
|
||
setTimeout(refreshStudio, 2000);
|
||
} catch(e) {
|
||
out.innerHTML = '✗ Error: ' + escapeHtml(e.message);
|
||
}
|
||
}
|
||
|
||
// Filter clicks
|
||
document.getElementById('filters').addEventListener('click', e => {
|
||
const btn = e.target.closest('.filter'); if (!btn) return;
|
||
document.querySelectorAll('.filter').forEach(b => b.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
STATE.filter = btn.dataset.cat;
|
||
renderReports();
|
||
});
|
||
|
||
refreshStudio();
|
||
setInterval(refreshStudio, 30000);
|
||
</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) {
|
||
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 (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);} });
|
||
}
|
||
}
|
||
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 === -->
|
||
|
||
<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=1777045903" defer></script>
|
||
<!-- DOCTRINE-60-UX-JS --><script id="doctrine60-ux-js-wevia-business-visual-studio">
|
||
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>
|