Files
html/enterprise-complete.html

648 lines
35 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>WEVAL · Enterprise Complete — 20 départements · 169 KPIs · Gap Agents · Macro Process</title>
<style>
:root{
--bg-0:#05060a; --bg-1:#0b0d15; --bg-2:#11141f; --bg-3:#171b2a; --bg-tile:#0f1420;
--border:rgba(99,102,241,0.15); --border-h:rgba(99,102,241,0.35);
--text:#e2e8f0; --dim:#94a3b8; --mute:#64748b;
--accent:#14b8a6; --accent2:#6366f1; --purple:#a855f7; --cyan:#06b6d4;
--ok:#22c55e; --warn:#f59e0b; --err:#ef4444; --rose:#f43f5e; --gold:#eab308;
--c-fin:#3b82f6; --c-sup:#06b6d4; --c-mfg:#f59e0b; --c-sales:#10b981;
--c-hr:#a855f7; --c-it:#ec4899; --c-legal:#64748b; --c-esg:#22c55e;
}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:'Inter',system-ui,sans-serif;background:radial-gradient(ellipse at top,#0f1420,#05060a 60%);color:var(--text);min-height:100vh;font-size:13px;line-height:1.5}
.container{max-width:1800px;margin:0 auto;padding:20px 26px 80px}
.shell{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;padding:12px 18px;background:var(--bg-1);border:1px solid var(--border);border-radius:10px}
.breadcrumb{font-size:12px;color:var(--dim)}
.breadcrumb a{color:var(--accent);text-decoration:none}
.breadcrumb .sep{margin:0 7px;color:var(--mute)}
.breadcrumb .current{color:var(--text);font-weight:600}
.shell h1{font-size:18px;font-weight:800;background:linear-gradient(90deg,#22d3ee,#a855f7,#eab308);-webkit-background-clip:text;background-clip:text;color:transparent}
.shell .pulse{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--ok);box-shadow:0 0 0 0 rgba(34,197,94,.7);animation:pulse 2s infinite;margin-right:6px;vertical-align:middle}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(34,197,94,.7)}70%{box-shadow:0 0 0 8px rgba(34,197,94,0)}}
.shell-actions{display:flex;gap:8px;flex-wrap:wrap}
.btn{padding:6px 12px;background:var(--bg-2);border:1px solid var(--border);color:var(--text);border-radius:6px;font-size:11.5px;cursor:pointer;text-decoration:none;font-family:inherit;transition:all .15s}
.btn:hover{border-color:var(--accent);color:var(--accent)}
.btn.primary{background:linear-gradient(135deg,var(--accent),var(--cyan));color:white;border:none;font-weight:600}
.kpi-super{display:grid;grid-template-columns:repeat(6,1fr);gap:10px;margin-bottom:14px}
@media(max-width:1200px){.kpi-super{grid-template-columns:repeat(3,1fr)}}
.ks{background:var(--bg-1);border:1px solid var(--border);border-radius:10px;padding:12px 14px;border-left:3px solid var(--accent);position:relative;overflow:hidden}
.ks.gold{border-left-color:var(--gold)}
.ks.danger{border-left-color:var(--err)}
.ks.cyan{border-left-color:var(--cyan)}
.ks.purple{border-left-color:var(--purple)}
.ks.ok{border-left-color:var(--ok)}
.ks .l{font-size:10px;color:var(--dim);text-transform:uppercase;letter-spacing:0.5px;font-weight:600}
.ks .v{font-size:22px;font-weight:800;margin-top:4px;line-height:1;font-family:'JetBrains Mono',monospace}
.ks .v.gold{background:linear-gradient(135deg,var(--gold),var(--warn));-webkit-background-clip:text;background-clip:text;color:transparent}
.ks .s{font-size:10px;color:var(--mute);margin-top:2px}
.filters{display:flex;gap:5px;flex-wrap:wrap;margin-bottom:14px;padding:8px 12px;background:var(--bg-1);border:1px solid var(--border);border-radius:10px;align-items:center}
.filters .lbl{font-size:11px;color:var(--dim);font-weight:700;margin-right:8px;text-transform:uppercase;letter-spacing:0.4px}
.fb{padding:5px 11px;background:var(--bg-3);border:1px solid var(--border);color:var(--dim);border-radius:14px;font-size:11px;cursor:pointer;font-family:inherit;transition:all .15s}
.fb:hover{color:var(--text);border-color:var(--accent)}
.fb.active{background:linear-gradient(135deg,var(--accent),var(--cyan));color:white;border:none;font-weight:700}
.sec-title{font-size:12px;font-weight:800;letter-spacing:2px;text-transform:uppercase;color:var(--dim);margin:22px 0 10px;padding-bottom:6px;border-bottom:1px solid var(--bg-3);display:flex;justify-content:space-between;align-items:center}
.sec-title .count{color:var(--accent);font-size:11px;letter-spacing:0}
.depts-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:12px;margin-bottom:22px}
.dept{background:var(--bg-tile);border:1px solid var(--border);border-radius:12px;overflow:hidden;transition:all .2s;cursor:pointer;display:flex;flex-direction:column}
.dept:hover{transform:translateY(-3px);border-color:var(--border-h);box-shadow:0 10px 30px rgba(0,0,0,0.4)}
.dept-head{padding:12px 14px;display:flex;align-items:center;gap:10px;position:relative;border-bottom:1px solid rgba(255,255,255,0.04)}
.dept-head::before{content:'';position:absolute;left:0;top:0;width:4px;height:100%;background:var(--dc)}
.dept-icon{font-size:28px;line-height:1}
.dept-meta{flex:1}
.dept-name{font-size:13px;font-weight:700;color:var(--text);line-height:1.2}
.dept-agents-info{font-size:10px;color:var(--mute);margin-top:3px;font-family:'JetBrains Mono',monospace}
.dept-status{padding:2px 7px;background:var(--bg-3);border-radius:10px;font-size:9px;font-weight:700;letter-spacing:0.3px;font-family:'JetBrains Mono',monospace;text-transform:uppercase}
.dept-status.ok{background:rgba(34,197,94,0.15);color:#86efac}
.dept-status.warn{background:rgba(245,158,11,0.15);color:#fbbf24}
.dept-status.critical{background:rgba(239,68,68,0.18);color:#fca5a5}
.dept-kpis{padding:10px 14px;flex:1}
.kpi-row{display:grid;grid-template-columns:1fr 80px 14px;gap:8px;align-items:center;padding:5px 0;font-size:11px;border-bottom:1px dashed var(--bg-3)}
.kpi-row:last-child{border-bottom:none}
.kpi-name{color:var(--dim);font-size:10.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kpi-val{font-family:'JetBrains Mono',monospace;font-weight:700;color:var(--text);text-align:right;font-size:11px}
.kpi-dot{width:8px;height:8px;border-radius:50%}
.kpi-dot.ok{background:var(--ok)} .kpi-dot.warn{background:var(--warn)} .kpi-dot.critical{background:var(--err)}
.dept-footer{padding:10px 14px;background:rgba(0,0,0,0.25);border-top:1px solid rgba(255,255,255,0.04);display:flex;justify-content:space-between;align-items:center;gap:8px}
.dept-avatars{display:flex;align-items:center}
.dept-avatars img{width:26px;height:26px;border-radius:50%;border:2px solid var(--bg-tile);margin-left:-6px;background:var(--bg-3);object-fit:cover}
.dept-avatars img:first-child{margin-left:0}
.dept-avatars .more{width:26px;height:26px;border-radius:50%;background:var(--bg-3);color:var(--dim);font-size:9px;font-weight:800;display:inline-flex;align-items:center;justify-content:center;border:2px solid var(--bg-tile);margin-left:-6px}
.dept-cta{font-size:10.5px;color:var(--accent);font-weight:700;white-space:nowrap}
.gap-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:10px;margin-bottom:22px}
.gap{background:var(--bg-1);border:1px solid var(--border);border-radius:10px;padding:12px 14px;border-left:3px solid var(--purple);transition:all .2s}
.gap:hover{border-color:var(--border-h);transform:translateY(-2px)}
.gap.high{border-left-color:var(--warn)}
.gap.medium{border-left-color:var(--cyan)}
.gap-head{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.gap-avatar{width:36px;height:36px;border-radius:50%;background:var(--bg-3);overflow:hidden;flex-shrink:0}
.gap-avatar img{width:100%;height:100%;object-fit:cover}
.gap-name{font-size:12.5px;font-weight:700;color:var(--text);line-height:1.2}
.gap-fw{display:inline-block;margin-top:2px;font-size:9.5px;padding:1px 6px;border-radius:4px;background:rgba(99,102,241,0.15);color:#a5b4fc;font-family:'JetBrains Mono',monospace}
.gap-role{font-size:10.5px;color:var(--dim);line-height:1.4;min-height:2.8em}
.gap-foot{display:flex;justify-content:space-between;align-items:center;margin-top:8px;padding-top:8px;border-top:1px dashed var(--bg-3)}
.gap-save{font-size:11px;color:var(--gold);font-family:'JetBrains Mono',monospace;font-weight:700}
.gap-status{font-size:9px;font-weight:700;padding:2px 7px;border-radius:5px;text-transform:uppercase;letter-spacing:0.3px}
.gap-status.to_build{background:rgba(245,158,11,0.15);color:#fbbf24}
.gap-status.partial{background:rgba(6,182,212,0.18);color:#7dd3fc}
.gap-status.deployed{background:rgba(34,197,94,0.18);color:#86efac}
.today{background:var(--bg-1);border:1px solid var(--border);border-radius:12px;padding:16px;margin-bottom:20px}
.today-head{font-size:12px;font-weight:800;letter-spacing:1.5px;text-transform:uppercase;color:var(--dim);margin-bottom:12px;display:flex;justify-content:space-between}
.today-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:8px}
.today-item{background:var(--bg-2);border-radius:8px;padding:10px 12px;border-left:3px solid var(--accent);transition:all .15s;cursor:pointer;text-decoration:none;color:var(--text);display:block}
.today-item:hover{background:var(--bg-3);transform:translateX(2px)}
.today-item .ver{font-size:9.5px;font-family:'JetBrains Mono',monospace;font-weight:700;color:var(--gold);margin-bottom:3px;letter-spacing:0.3px}
.today-item .name{font-size:11.5px;font-weight:700;color:var(--text);line-height:1.2;margin-bottom:3px}
.today-item .desc{font-size:10px;color:var(--dim);line-height:1.4;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.proc-wrap{background:var(--bg-1);border:1px solid var(--border);border-radius:12px;padding:16px;margin-bottom:20px}
.proc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:10px}
.proc{background:var(--bg-2);border-radius:8px;padding:10px 12px;border-left:2px solid var(--cyan)}
.proc-name{font-weight:700;font-size:11.5px;color:var(--text)}
.proc-steps{font-size:10px;color:var(--dim);margin-top:4px;line-height:1.45}
.proc-depts{font-size:9.5px;color:var(--mute);margin-top:5px;font-family:'JetBrains Mono',monospace}
.loading{text-align:center;padding:40px;color:var(--dim)}
.spinner{width:32px;height:32px;border:3px solid var(--bg-3);border-top-color:var(--accent);border-radius:50%;margin:0 auto 12px;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.clock{font-family:'JetBrains Mono',monospace;color:var(--accent);font-size:10.5px;margin-top:2px}
/* === 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 === */
/* V8.4 FIX OVERFLOW agent names (doctrine 14 additive) */
.dept-avatars img { color: transparent; font-size: 0 !important; line-height: 0 !important; }
.dept-avatars img::before { content: ""; display: block; width: 100%; height: 100%; background: var(--bg-3); border-radius: 50%; }
.dept-avatars { max-height: 32px; overflow: hidden; }
.dept-footer { overflow: hidden; max-height: 50px; }
.dept { overflow: hidden !important; }
</style>
<script src="/api/weval-avatar-helper.js?v=d91" defer></script>
<style id="d91-persona-style">
/* ------ D91 PERSONA AVATARS ------ */
.p-av{display:inline-flex;align-items:center;justify-content:center;border-radius:50%;
background:#ffffff0a;border:1.5px solid #6366f1;flex-shrink:0;
font-family:Apple Color Emoji,Segoe UI Emoji,Noto Color Emoji,sans-serif;line-height:1;
box-shadow:0 2px 6px #0006,inset 0 1px 0 #ffffff18}
.p-av[data-persona="master"]{background:linear-gradient(135deg,#f59e0b22,#dc262622);border-color:#f59e0b;box-shadow:0 0 10px #f59e0b44}
.p-av[data-persona="tool"]{background:#64748b15;border-color:#64748b;border-style:dashed}
.p-av[data-persona="human"]{background:#8b5cf611;border-color:#6366f1}
.dept-avatars .p-av{width:28px;height:28px;font-size:17px;margin-left:-6px;border-width:2px;border-color:var(--bg-tile,#0f1420)}
.dept-avatars .p-av:first-child{margin-left:0}
.dept-avatars .p-av:hover{transform:translateY(-2px);z-index:2;transition:all .2s}
.gap-avatar .p-av{width:100%;height:100%;font-size:22px;border:none;box-shadow:none;background:transparent}
.today-item .p-av{width:22px;height:22px;font-size:13px}
/* tooltip on hover */
.p-av{position:relative;cursor:default}
.p-av:hover::after{content:attr(data-name);position:absolute;top:100%;left:50%;transform:translateX(-50%);
background:#0a0c14ee;color:#e2e8f0;padding:3px 8px;border-radius:4px;font:600 10px Nunito,sans-serif;
white-space:nowrap;z-index:100;margin-top:4px;pointer-events:none;border:1px solid #6366f144}
</style>
<!-- WEVAL-D91-PERSONA-AVATAR -->
<!-- DOCTRINE-60-UX-ENRICH direct-inject-20260424-143847 -->
<style id="doctrine60-ux-direct">
/* DOCTRINE-60-UX-ENRICH injected-direct */
body::before {
content: '';
position: fixed;
top: 0; left: 0; width: 100vw; height: 100vh;
background: radial-gradient(circle at 50% 50%, rgba(100,180,255,0.08), transparent 60%);
pointer-events: none;
z-index: -1;
}
.card, .kpi, .panel, .btn {
transition: all 0.3s cubic-bezier(0.2,0,0.1,1);
}
.card:hover, .kpi:hover, .panel:hover {
box-shadow: 0 4px 20px rgba(100,180,255,0.2);
border-color: rgba(100,180,255,0.5);
}
@keyframes pulseD60 {
0%,100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(1.05); }
}
.pulse, .live-indicator, .active, .online {
animation: pulseD60 3s ease-in-out infinite;
}
.modal, .chat, .speech, .overlay {
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.enter-stagger {
animation: enterStagD60 0.5s cubic-bezier(0.2,0,0.1,1) forwards;
}
@keyframes enterStagD60 {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body>
<div class="container">
<div class="shell">
<div>
<div class="breadcrumb">
<a href="/weval-technology-platform.html">🏠 WTP</a>
<span class="sep"></span>
<span class="current">Enterprise Complete · V73</span>
</div>
<h1 style="margin-top:4px"><span class="pulse"></span>🏢 Enterprise Complete — 20 dépts · 169 KPIs · SAP/Oracle/Sage-class</h1>
<div class="clock" id="clock"></div>
</div>
<div class="shell-actions">
<a href="/agents-archi.html" class="btn">🤖 Agents 3D</a>
<a href="/wevia-meeting-rooms.html" class="btn">👥 Meeting Rooms</a>
<a href="/enterprise-model.html" class="btn">🏢 Model</a>
<a href="/dg-command-center.html" class="btn">🎖 DG Center</a>
<a href="/sales-hub.html" class="btn primary">🚀 Sales Hub</a>
</div>
</div>
<div class="kpi-super">
<div class="ks gold"><div class="l">Départements</div><div class="v gold" id="k-depts"></div><div class="s">macro entreprise</div></div>
<div class="ks cyan"><div class="l">KPIs tracés</div><div class="v" id="k-kpis"></div><div class="s">all-in-one ERP</div></div>
<div class="ks purple"><div class="l">Gap agents méthode</div><div class="v" id="k-gap"></div><div class="s">Scrum/SAFe/Agile/DevOps</div></div>
<div class="ks ok"><div class="l">Agents déployés</div><div class="v" id="k-agents"></div><div class="s">fleet WEVAL</div></div>
<div class="ks danger"><div class="l">Integrations ready</div><div class="v" id="k-int"></div><div class="s">ERP/CRM/SaaS/DB</div></div>
<div class="ks"><div class="l">Innovations 24h</div><div class="v" id="k-inn"></div><div class="s">WEVL Predict</div></div>
</div>
<div class="filters">
<span class="lbl">Catégorie</span>
<button class="fb active" data-cat="all">Tous (20)</button>
<button class="fb" data-cat="finance">💰 Finance (6)</button>
<button class="fb" data-cat="supply">📦 Supply (2)</button>
<button class="fb" data-cat="mfg">🏭 Production (3)</button>
<button class="fb" data-cat="sales">💼 Sales (3)</button>
<button class="fb" data-cat="hr">👥 RH (2)</button>
<button class="fb" data-cat="it">💻 IT (2)</button>
<button class="fb" data-cat="legal">⚖️ Legal (2)</button>
</div>
<div class="today">
<div class="today-head">
<span>⚡ Créations du jour · innovations WEVAL 18 avr 2026</span>
<span id="innov-count" style="font-family:'JetBrains Mono',monospace;font-weight:700;color:var(--accent)"></span>
</div>
<div class="today-grid" id="today-grid"><div class="loading"><div class="spinner"></div></div></div>
</div>
<div class="sec-title">
<span>📊 Les 20 départements · KPIs macro + agents unifiés + status live</span>
<span class="count" id="depts-count"></span>
</div>
<div class="depts-grid" id="depts-grid"><div class="loading"><div class="spinner"></div></div></div>
<div class="sec-title">
<span>🎭 Gap Agents Méthode · Scrum/SAFe/Agile/DevOps/OKR — à développer Q2</span>
<span class="count" id="gap-count"></span>
</div>
<div class="gap-grid" id="gap-grid"><div class="loading"><div class="spinner"></div></div></div>
<div class="sec-title">
<span>⚙️ Macro processes par département · base SCOR + APQC</span>
<span class="count">8 macro streams</span>
</div>
<div class="proc-wrap">
<div class="proc-grid" id="proc-grid"></div>
</div>
</div>
<script>
const API_V70 = '/api/wevia-v70-enterprise-complete.php';
const API_V71 = '/api/wevia-v71-intelligence-growth.php';
const AVATAR_API = '/api/agent-avatars.json';
let DATA70 = null, DATA71 = null, AVATARS = {};
let filter = 'all';
const DEPT_META = {
finance_general: {cat:'finance', color:'var(--c-fin)'},
controlling: {cat:'finance', color:'var(--c-fin)'},
treasury: {cat:'finance', color:'var(--c-fin)'},
billing_ar: {cat:'finance', color:'var(--c-fin)'},
accounts_payable: {cat:'finance', color:'var(--c-fin)'},
tax_compliance: {cat:'finance', color:'var(--c-fin)'},
supply_chain: {cat:'supply', color:'var(--c-sup)'},
procurement: {cat:'supply', color:'var(--c-sup)'},
manufacturing: {cat:'mfg', color:'var(--c-mfg)'},
quality_qhse: {cat:'mfg', color:'var(--c-mfg)'},
rd_innovation: {cat:'mfg', color:'var(--c-mfg)'},
sales: {cat:'sales', color:'var(--c-sales)'},
marketing: {cat:'sales', color:'var(--c-sales)'},
customer_success: {cat:'sales', color:'var(--c-sales)'},
hr: {cat:'hr', color:'var(--c-hr)'},
payroll: {cat:'hr', color:'var(--c-hr)'},
dsi_it: {cat:'it', color:'var(--c-it)'},
cybersecurity: {cat:'it', color:'var(--c-it)'},
legal_compliance: {cat:'legal', color:'var(--c-legal)'},
esg: {cat:'legal', color:'var(--c-esg)'}
};
const DEPT_AGENTS = {
finance_general: ['Fast Close Orchestrator','Cash Flow Predictor AI','Budget Variance Watchdog'],
controlling: ['Budget Variance Watchdog','Forecast AI'],
treasury: ['Cash Flow Predictor AI','FX Hedger'],
billing_ar: ['Collection AI Agent','Dunning Router'],
accounts_payable: ['Invoice Auto-Match','Duplicate Payment Detector'],
tax_compliance: ['Tax Validator','Audit Trail Watcher'],
supply_chain: ['Demand Forecast Pro','Stockout Prevention','OTD Optimizer'],
procurement: ['Supplier Risk Monitor','Contract Compliance'],
manufacturing: ['OEE Live','Predictive Maintenance','Takt Time Monitor'],
quality_qhse: ['CAPA Closer','Incident Watcher'],
rd_innovation: ['Patent Scanner','PoC Tracker'],
sales: ['Pipeline Scorer','Lead Qualifier','CPQ AI'],
marketing: ['Content Generator','CAC Optimizer'],
customer_success: ['Churn Predictor','NPS Analyzer'],
hr: ['Talent Scout','Attrition Predictor','Skills Matcher'],
payroll: ['Payroll Accuracy AI','Compliance Checker'],
dsi_it: ['DevOps','AutoFix','Fiability','Monitor'],
cybersecurity: ['Security','Fraud Detection Agent','MFA Enforcer'],
legal_compliance: ['Contract Watcher','GDPR Auditor'],
esg: ['Carbon Tracker','Sustainability Reporter']
};
const MACRO_PROCESSES = [
{name:'Record-to-Report (R2R)', steps:'Journal → Reconciliation → Close → Report', depts:['finance_general','controlling']},
{name:'Order-to-Cash (O2C)', steps:'Quote → Order → Ship → Invoice → Collect', depts:['sales','billing_ar']},
{name:'Procure-to-Pay (P2P)', steps:'Requisition → PO → Receipt → Invoice → Pay', depts:['procurement','accounts_payable']},
{name:'Plan-to-Produce', steps:'Demand → MRP → Production → QC → Stock', depts:['manufacturing','quality_qhse']},
{name:'Hire-to-Retire (H2R)', steps:'Recruit → Onboard → Manage → Separate', depts:['hr','payroll']},
{name:'Market-to-Lead (M2L)', steps:'Campaign → Traffic → MQL → SQL → Handoff', depts:['marketing','sales']},
{name:'Design-to-Deploy (D2D)', steps:'Ideate → Spec → Build → Test → Release', depts:['rd_innovation','dsi_it']},
{name:'Risk-to-Remediate', steps:'Identify → Assess → Mitigate → Monitor', depts:['legal_compliance','cybersecurity']}
];
function clockTick(){const d=new Date();document.getElementById('clock').textContent=d.toLocaleDateString('fr-FR')+' '+d.toLocaleTimeString('fr-FR')+' · auto-refresh 60s';}
setInterval(clockTick,1000); clockTick();
function avatarUrl(name) {
// D91 deprecated — kept for backward compat; use avatarPill() instead
if (AVATARS && AVATARS[name]) return AVATARS[name];
return 'https://api.dicebear.com/9.x/adventurer/svg?seed=' + encodeURIComponent(name || 'default');
}
function avatarPill(name, size){
size = size || 26;
// Prefer v2 registry via WevalAvatar (persona emojis)
if (window.WevalAvatar && WevalAvatar.isReady && WevalAvatar.isReady()){
const e = WevalAvatar.get(name);
const bg = (e.color||'#6366f1')+'22';
return '<span class="p-av" data-persona="'+(e.persona||'human')+'" data-name="'+esc(name)+'" '+
'style="width:'+size+'px;height:'+size+'px;font-size:'+Math.round(size*0.62)+'px;border-color:'+(e.color||'#6366f1')+';background:'+bg+'">'+e.emoji+'</span>';
}
// fallback: img dicebear
return '<img src="'+avatarUrl(name)+'" alt="" title="'+esc(name)+'" data-agent="'+esc(name)+'" style="width:'+size+'px;height:'+size+'px;border-radius:50%;vertical-align:middle" onerror="this.style.display=\'none\'">';
}
function esc(s){ return String(s||'').replace(/[&<>"]/g,function(c){return{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c];}); }
async function load() {
try {
const [av, d70, d71] = await Promise.all([
fetch(AVATAR_API+'?t='+Date.now()).then(r=>r.json()).catch(()=>({})),
fetch(API_V70+'?t='+Date.now()).then(r=>r.json()).catch(()=>null),
fetch(API_V71+'?t='+Date.now()).then(r=>r.json()).catch(()=>null)
]);
AVATARS = av || {};
DATA70 = d70;
DATA71 = d71;
render();
} catch(e){console.error('load err',e);}
}
function render() {
if (!DATA70) return;
const s70 = DATA70.summary;
document.getElementById('k-depts').textContent = s70.departments;
document.getElementById('k-kpis').textContent = s70.kpis_total;
document.getElementById('k-gap').textContent = DATA71 ? DATA71.summary.agility_agents_gap : '—';
// TRUTH SYNC (Opus Yacine 19avr) · fetch dynamically
document.getElementById('k-agents').textContent = 950; // fallback
fetch('/api/source-of-truth.json?t=' + Date.now(), {cache:'no-store'})
.then(r => r.json())
.then(d => {
var n = d.agents_count || d.agents_total || 950;
var el = document.getElementById('k-agents');
if (el) el.textContent = n;
})
.catch(e => {});
document.getElementById('k-int').textContent = s70.integrations_total;
document.getElementById('k-inn').textContent = DATA71 ? DATA71.summary.innovations_last_24h : '—';
// Today
if (DATA71) {
const innovs = DATA71.wevl_predict_innovations.innovations.filter(i => i.date === '2026-04-18');
document.getElementById('innov-count').textContent = innovs.length + ' créations aujourd\'hui';
document.getElementById('today-grid').innerHTML = innovs.map(i => `
<a href="${i.url}" class="today-item" target="_blank">
<div class="ver">${(i.type||'').toUpperCase()} · ${'★'.repeat(i.novelty||3)}</div>
<div class="name">${i.name}</div>
<div class="desc">${i.description||''}</div>
</a>
`).join('');
}
// Depts
const depts = DATA70.enterprise_departments;
const entries = Object.entries(depts);
const filtered = filter === 'all' ? entries : entries.filter(([k,v]) => (DEPT_META[k]||{}).cat === filter);
document.getElementById('depts-count').textContent = filtered.length + ' affichés / ' + entries.length;
document.getElementById('depts-grid').innerHTML = filtered.map(([key, d]) => {
const meta = DEPT_META[key] || {cat:'other', color:'var(--accent)'};
const agents = (DEPT_AGENTS[key] || []).slice(0,5);
const critCount = (d.kpis||[]).filter(k => k.s === 'critical').length;
const warnCount = (d.kpis||[]).filter(k => k.s === 'warn').length;
const status = critCount > 2 ? 'critical' : (warnCount > (d.kpis||[]).length/2 ? 'warn' : 'ok');
const topKpis = (d.kpis||[]).slice(0,4);
return `<div class="dept" style="--dc:${meta.color}" onclick="window.open('/dg-command-center.html','_blank')">
<div class="dept-head">
<span class="dept-icon">${d.icon||'📊'}</span>
<div class="dept-meta">
<div class="dept-name">${d.label}</div>
<div class="dept-agents-info">${(d.kpis||[]).length} KPIs · ${agents.length} agents · ${(d.integrations||[]).length} ERPs</div>
</div>
<span class="dept-status ${status}">${status}</span>
</div>
<div class="dept-kpis">
${topKpis.map(k => `<div class="kpi-row">
<div class="kpi-name" title="${k.k}">${k.k}</div>
<div class="kpi-val">${k.v}${k.u||''}</div>
<div class="kpi-dot ${k.s||'ok'}"></div>
</div>`).join('')}
</div>
<div class="dept-footer">
<div class="dept-avatars">
${agents.slice(0,4).map(a => avatarPill(a,28)).join('')}
${agents.length > 4 ? `<span class="more">+${agents.length-4}</span>` : ''}
</div>
<span class="dept-cta">→ pilotage</span>
</div>
</div>`;
}).join('');
// Gap agents
if (DATA71) {
const gaps = DATA71.agility_agents_gap.agents || [];
document.getElementById('gap-count').textContent = gaps.length + ' agents · ' + DATA71.agility_agents_gap.total_fte_saved_year + ' FTE savings/an';
document.getElementById('gap-grid').innerHTML = gaps.map(g => `
<div class="gap ${g.priority||'medium'}">
<div class="gap-head">
<div class="gap-avatar">${avatarPill(g.name, 36)}</div>
<div style="flex:1">
<div class="gap-name">${g.name}</div>
<span class="gap-fw">${g.framework||''}</span>
</div>
</div>
<div class="gap-role">${g.role||''}</div>
<div class="gap-foot">
<span class="gap-save">💰 ${g.savings_fte_year||0} FTE/an</span>
<span class="gap-status ${g.status||'to_build'}">${(g.status||'to_build').replace('_',' ')}</span>
</div>
</div>
`).join('');
}
// Macro processes
document.getElementById('proc-grid').innerHTML = MACRO_PROCESSES.map(p => {
const deptLabels = p.depts.map(d => (depts[d]||{}).label || d).join(' + ');
return `<div class="proc">
<div class="proc-name">${p.name}</div>
<div class="proc-steps">${p.steps}</div>
<div class="proc-depts">${deptLabels}</div>
</div>`;
}).join('');
}
document.querySelectorAll('.fb').forEach(b => b.onclick = e => {
filter = e.target.dataset.cat;
document.querySelectorAll('.fb').forEach(x => x.classList.toggle('active', x.dataset.cat === filter));
render();
});
load();
setInterval(load, 60000);
</script>
<script id="d91-rerender">
(function(){
const wait = setInterval(function(){
if (window.WevalAvatar && WevalAvatar.isReady && WevalAvatar.isReady()){
clearInterval(wait);
if (typeof render === 'function') render();
}
}, 120);
setTimeout(function(){clearInterval(wait);},8000);
})();
</script>
<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) {
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 === -->
<script src="/api/a11y-auto-enhancer.js" defer></script>
<!-- WTP_UDOCK_V1 (Opus 21-avr t32b4) --><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-direct">
// DOCTRINE-60-UX-JS staggered entrance
(function(){
if (!('IntersectionObserver' in window)) return;
const obs = new IntersectionObserver((entries) => {
entries.forEach((e, i) => {
if (e.isIntersecting) {
setTimeout(() => e.target.classList.add('enter-stagger'), i * 80);
obs.unobserve(e.target);
}
});
});
document.querySelectorAll('.card, .kpi, .panel').forEach(el => obs.observe(el));
})();
</script>
</body>
</html>