489 lines
28 KiB
HTML
489 lines
28 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>WEVAL · Intelligence & Growth Insights — DarkScout + WEVL Predict</title>
|
|
<style>
|
|
:root{--bg-0:#05060a;--bg-1:#0b0d15;--bg-2:#11141f;--bg-3:#171b2a;--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}
|
|
*{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:1760px;margin:0 auto;padding:24px 28px 80px}
|
|
header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:18px;padding-bottom:14px;border-bottom:1px solid var(--border)}
|
|
h1{font-size:25px;font-weight:800;background:linear-gradient(90deg,#22d3ee,#a855f7,#eab308);-webkit-background-clip:text;background-clip:text;color:transparent;letter-spacing:-0.4px}
|
|
.sub{color:var(--dim);font-size:12.5px;margin-top:4px}
|
|
.actions{display:flex;gap:8px}
|
|
.btn{padding:7px 13px;background:var(--bg-2);border:1px solid var(--border);color:var(--text);border-radius:8px;font-size:11.5px;cursor:pointer;text-decoration:none;transition:all .2s}
|
|
.btn:hover{border-color:var(--accent);color:var(--accent)}
|
|
.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}
|
|
@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)}}
|
|
/* KPI strip */
|
|
.kpi-strip{display:grid;grid-template-columns:repeat(6,1fr);gap:10px;margin-bottom:16px}
|
|
@media(max-width:1100px){.kpi-strip{grid-template-columns:repeat(3,1fr)}}
|
|
.kpi-big{background:var(--bg-1);border:1px solid var(--border);border-radius:10px;padding:12px 14px;position:relative;border-left:3px solid var(--accent2)}
|
|
.kpi-big.gold{border-left-color:var(--gold)}
|
|
.kpi-big.danger{border-left-color:var(--err)}
|
|
.kpi-big.cyan{border-left-color:var(--cyan)}
|
|
.kpi-big.rose{border-left-color:var(--rose)}
|
|
.kpi-big.green{border-left-color:var(--ok)}
|
|
.kpi-lbl{font-size:10px;color:var(--dim);text-transform:uppercase;letter-spacing:0.5px;font-weight:600}
|
|
.kpi-val{font-size:22px;font-weight:800;margin-top:4px;line-height:1;font-family:'JetBrains Mono',monospace}
|
|
.kpi-val.gold{background:linear-gradient(135deg,var(--gold),var(--warn));-webkit-background-clip:text;background-clip:text;color:transparent}
|
|
.kpi-sub{font-size:10px;color:var(--mute);margin-top:2px}
|
|
/* Section */
|
|
.section{background:var(--bg-1);border:1px solid var(--border);border-radius:12px;padding:18px;margin-bottom:16px}
|
|
.sec-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--bg-3)}
|
|
.sec-title{font-size:14px;font-weight:700;color:var(--text);display:flex;align-items:center;gap:8px}
|
|
.sec-badge{font-size:10px;padding:3px 8px;border-radius:8px;font-weight:700}
|
|
.sec-badge.danger{background:rgba(239,68,68,0.2);color:#fca5a5}
|
|
.sec-badge.ok{background:rgba(34,197,94,0.18);color:#86efac}
|
|
.sec-badge.info{background:rgba(99,102,241,0.18);color:#a5b4fc}
|
|
.sec-badge.gold{background:rgba(234,179,8,0.18);color:#fde047}
|
|
/* Competitors grid */
|
|
.comp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:10px}
|
|
.comp-card{background:var(--bg-2);border-radius:10px;padding:13px;border-left:3px solid var(--dim);transition:all .2s}
|
|
.comp-card:hover{border-color:var(--border-h);background:var(--bg-3)}
|
|
.comp-card.high{border-left-color:var(--err)}
|
|
.comp-card.medium{border-left-color:var(--warn)}
|
|
.comp-card.low{border-left-color:var(--ok)}
|
|
.comp-name{font-size:13px;font-weight:700;color:var(--text);display:flex;justify-content:space-between;align-items:flex-start}
|
|
.comp-threat{font-size:9px;padding:2px 6px;border-radius:5px;font-weight:700;text-transform:uppercase}
|
|
.comp-threat.high{background:rgba(239,68,68,0.2);color:#fca5a5}
|
|
.comp-threat.medium{background:rgba(245,158,11,0.2);color:#fbbf24}
|
|
.comp-threat.low{background:rgba(34,197,94,0.18);color:#86efac}
|
|
.comp-meta{font-size:10.5px;color:var(--dim);margin-top:3px}
|
|
.comp-section{font-size:10.5px;margin-top:7px;line-height:1.4}
|
|
.comp-section strong{color:var(--accent);font-weight:600}
|
|
.comp-diff{margin-top:7px;padding:6px 8px;background:rgba(20,184,166,0.08);border-left:2px solid var(--accent);border-radius:4px;font-size:10.5px;color:#5eead4}
|
|
.comp-score{display:inline-block;margin-top:5px;font-family:'JetBrains Mono',monospace;font-size:10px;color:var(--mute)}
|
|
/* Market signals */
|
|
.market-signals{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:8px;margin-top:12px;padding-top:12px;border-top:1px dashed var(--border)}
|
|
.market-sig{background:var(--bg-2);padding:8px 10px;border-radius:6px;font-size:10.5px}
|
|
.market-sig .s{color:var(--dim)}
|
|
.market-sig .v{font-weight:700;margin-top:2px}
|
|
.market-sig .v.up{color:var(--ok)}
|
|
.market-sig .v.down{color:var(--err)}
|
|
/* Innovations timeline */
|
|
.innov-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:10px}
|
|
.innov-card{background:var(--bg-2);border-radius:8px;padding:12px;border-left:3px solid var(--cyan);transition:all .2s}
|
|
.innov-card:hover{background:var(--bg-3);transform:translateX(2px)}
|
|
.innov-head{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:4px}
|
|
.innov-name{font-size:12.5px;font-weight:700;color:var(--text)}
|
|
.innov-date{font-size:9.5px;color:var(--mute);font-family:'JetBrains Mono',monospace}
|
|
.innov-type{font-size:9.5px;padding:1px 6px;border-radius:4px;background:rgba(168,85,247,0.15);color:#d4a7fa;display:inline-block;margin-top:3px;text-transform:uppercase;letter-spacing:0.3px;font-weight:600}
|
|
.innov-desc{font-size:11px;color:var(--dim);margin-top:6px;line-height:1.4}
|
|
.innov-value{font-size:10.5px;color:#5eead4;margin-top:5px;font-weight:500}
|
|
.innov-stars{color:var(--gold);font-size:11px;margin-top:3px;letter-spacing:1px}
|
|
/* Agility agents */
|
|
.agil-wrap{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:8px}
|
|
.agil-card{background:var(--bg-2);border-radius:8px;padding:10px 12px;border-left:3px solid var(--purple);display:flex;flex-direction:column;gap:4px}
|
|
.agil-card.high{border-left-color:var(--warn)}
|
|
.agil-card.medium{border-left-color:var(--cyan)}
|
|
.agil-card.low{border-left-color:var(--mute)}
|
|
.agil-head{display:flex;justify-content:space-between;align-items:flex-start;font-size:12px}
|
|
.agil-name{font-weight:700;color:var(--text)}
|
|
.agil-framework{font-size:10px;padding:1px 6px;border-radius:4px;background:rgba(99,102,241,0.15);color:#a5b4fc}
|
|
.agil-role{font-size:10.5px;color:var(--dim);line-height:1.4;margin-top:2px}
|
|
.agil-save{font-size:10.5px;color:var(--gold);font-family:'JetBrains Mono',monospace;margin-top:3px;font-weight:600}
|
|
.agil-status{font-size:9.5px;color:var(--warn);text-transform:uppercase;letter-spacing:0.4px;font-weight:700;margin-top:2px}
|
|
.agil-status.partial{color:var(--cyan)}
|
|
/* Chatbots / Leads */
|
|
.chat-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:12px}
|
|
.chat-stat{text-align:center;padding:10px;background:var(--bg-2);border-radius:8px;border-top:2px solid var(--accent)}
|
|
.chat-stat.warn{border-top-color:var(--warn)}
|
|
.chat-stat.ok{border-top-color:var(--ok)}
|
|
.chat-stat-v{font-size:22px;font-weight:800;font-family:'JetBrains Mono',monospace;color:var(--text)}
|
|
.chat-stat-l{font-size:10px;color:var(--dim);margin-top:3px;text-transform:uppercase;letter-spacing:0.3px}
|
|
.chat-funnel{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-top:10px}
|
|
.chat-funnel-step{background:var(--bg-2);padding:10px;border-radius:6px;text-align:center;border-bottom:2px solid var(--cyan)}
|
|
.chat-funnel-pct{font-size:18px;font-weight:800;color:var(--cyan);font-family:'JetBrains Mono',monospace}
|
|
.chat-funnel-lbl{font-size:10px;color:var(--dim);margin-top:3px}
|
|
.chat-alerts{margin-top:12px;padding:10px;background:rgba(245,158,11,0.08);border-left:2px solid var(--warn);border-radius:4px;font-size:11px;color:#fbbf24;line-height:1.5}
|
|
.chat-alerts strong{display:block;margin-bottom:3px;color:#fde047}
|
|
/* Opportunities */
|
|
.oppo-wrap{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:8px}
|
|
.oppo-card{background:var(--bg-2);border-radius:8px;padding:10px 12px;border-left:3px solid var(--accent2)}
|
|
.oppo-card.critical{border-left-color:var(--err)}
|
|
.oppo-card.high{border-left-color:var(--warn)}
|
|
.oppo-card.medium{border-left-color:var(--cyan)}
|
|
.oppo-head{display:flex;justify-content:space-between;align-items:flex-start;font-size:12px;margin-bottom:4px}
|
|
.oppo-src{font-size:9.5px;padding:1px 6px;border-radius:4px;background:rgba(168,85,247,0.15);color:#d4a7fa}
|
|
.oppo-signal{font-weight:600;color:var(--text);font-size:12px;margin-top:4px}
|
|
.oppo-action{font-size:10.5px;color:var(--dim);margin-top:3px;line-height:1.4}
|
|
.oppo-foot{display:flex;justify-content:space-between;align-items:center;margin-top:6px;font-size:10px}
|
|
.oppo-val{font-family:'JetBrains Mono',monospace;font-weight:700;color:var(--gold)}
|
|
.oppo-urg{text-transform:uppercase;font-weight:700;letter-spacing:0.4px}
|
|
.oppo-urg.critical{color:#fca5a5}
|
|
.oppo-urg.high{color:#fbbf24}
|
|
.oppo-urg.medium{color:#7dd3fc}
|
|
/* Value KPIs */
|
|
.vkpi-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:8px}
|
|
.vkpi-cell{background:var(--bg-2);padding:10px 12px;border-radius:8px;border-left:2px solid var(--dim)}
|
|
.vkpi-cell.ok{border-left-color:var(--ok)}
|
|
.vkpi-cell.warn{border-left-color:var(--warn)}
|
|
.vkpi-cell.critical{border-left-color:var(--err)}
|
|
.vkpi-lbl{font-size:10px;color:var(--dim);text-transform:uppercase;letter-spacing:0.3px;font-weight:600}
|
|
.vkpi-v{font-size:17px;font-weight:800;font-family:'JetBrains Mono',monospace;color:var(--text);margin-top:3px}
|
|
.vkpi-target{font-size:9.5px;color:var(--mute);margin-top:2px}
|
|
.loading{text-align:center;padding:40px;color:var(--dim)}
|
|
.spinner{width:34px;height:34px;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:11px;margin-top:3px}
|
|
|
|
/* === 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>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
|
|
<header>
|
|
<div>
|
|
<h1><span class="pulse"></span>🌐 Intelligence & Growth Insights</h1>
|
|
<div class="sub">DarkScout compétiteurs · WEVL Predict innovations · Agility agents gap · Lead Capture Hub · Opportunities Watch</div>
|
|
<div class="clock" id="clock">—</div>
|
|
</div>
|
|
<div class="actions">
|
|
<a href="/weval-technology-platform.html" class="btn">🏠 WTP</a>
|
|
<a href="/dg-command-center.html" class="btn">🎖️ DG Center</a>
|
|
<a href="/agent-roi-simulator.html" class="btn">🧮 ROI Sim</a>
|
|
<button class="btn" onclick="load()">↻ Refresh</button>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- KPI STRIP -->
|
|
<div class="kpi-strip">
|
|
<div class="kpi-big danger"><div class="kpi-lbl">🎯 Compétiteurs trackés</div><div class="kpi-val" id="kpi-comp">—</div><div class="kpi-sub"><span id="kpi-comp-high">—</span> high threat</div></div>
|
|
<div class="kpi-big green"><div class="kpi-lbl">⚡ Innovations 24h</div><div class="kpi-val gold" id="kpi-innov24">—</div><div class="kpi-sub">total <span id="kpi-innov">—</span></div></div>
|
|
<div class="kpi-big cyan"><div class="kpi-lbl">🎭 Agility Agents GAP</div><div class="kpi-val" id="kpi-agil">—</div><div class="kpi-sub"><span id="kpi-agil-fte">—</span> FTE savings/an</div></div>
|
|
<div class="kpi-big rose"><div class="kpi-lbl">🤖 Chatbots deployed</div><div class="kpi-val" id="kpi-chat">—</div><div class="kpi-sub">sur <span id="kpi-chat-tot">—</span> planifiés</div></div>
|
|
<div class="kpi-big gold"><div class="kpi-lbl">💰 Opportunities pipeline</div><div class="kpi-val gold" id="kpi-oppo">—</div><div class="kpi-sub"><span id="kpi-oppo-urg">—</span> urgent</div></div>
|
|
<div class="kpi-big"><div class="kpi-lbl">📐 Value KPIs</div><div class="kpi-val" id="kpi-vkpis">—</div><div class="kpi-sub">cross-cutting</div></div>
|
|
</div>
|
|
|
|
<!-- DARKSCOUT -->
|
|
<div class="section">
|
|
<div class="sec-head">
|
|
<div class="sec-title">🎯 DarkScout — Veille concurrentielle temps-réel</div>
|
|
<div class="sec-badge danger" id="ds-count">—</div>
|
|
</div>
|
|
<div class="comp-grid" id="comp-grid"><div class="loading"><div class="spinner"></div></div></div>
|
|
<div class="market-signals" id="market-signals"></div>
|
|
</div>
|
|
|
|
<!-- INNOVATIONS -->
|
|
<div class="section">
|
|
<div class="sec-head">
|
|
<div class="sec-title">⚡ WEVL Predict — Innovations live</div>
|
|
<div class="sec-badge gold" id="innov-velocity">—</div>
|
|
</div>
|
|
<div class="innov-grid" id="innov-grid"><div class="loading"><div class="spinner"></div></div></div>
|
|
</div>
|
|
|
|
<!-- AGILITY AGENTS GAP -->
|
|
<div class="section">
|
|
<div class="sec-head">
|
|
<div class="sec-title">🎭 Agility Agents Gap — Scrum/SAFe/Agile/DevOps</div>
|
|
<div class="sec-badge info" id="agil-total-sav">—</div>
|
|
</div>
|
|
<div class="agil-wrap" id="agil-wrap"><div class="loading"><div class="spinner"></div></div></div>
|
|
</div>
|
|
|
|
<!-- LEAD CAPTURE HUB -->
|
|
<div class="section">
|
|
<div class="sec-head">
|
|
<div class="sec-title">🤖 Lead Capture Hub — 40 chatbots publics</div>
|
|
<div class="sec-badge info" id="lch-status">—</div>
|
|
</div>
|
|
<div class="chat-stats" id="chat-stats"></div>
|
|
<div style="font-size:11px;color:var(--dim);margin-top:10px;margin-bottom:6px;font-weight:600">Conversion funnel lead :</div>
|
|
<div class="chat-funnel" id="chat-funnel"></div>
|
|
<div class="chat-alerts" id="chat-alerts"></div>
|
|
</div>
|
|
|
|
<!-- OPPORTUNITIES -->
|
|
<div class="section">
|
|
<div class="sec-head">
|
|
<div class="sec-title">💼 Opportunities Watch — LinkedIn + Web + Referrals</div>
|
|
<div class="sec-badge gold" id="oppo-val">—</div>
|
|
</div>
|
|
<div class="oppo-wrap" id="oppo-wrap"><div class="loading"><div class="spinner"></div></div></div>
|
|
</div>
|
|
|
|
<!-- VALUE KPIS -->
|
|
<div class="section">
|
|
<div class="sec-head">
|
|
<div class="sec-title">📐 Value KPIs cross-cutting (exploitation force archi)</div>
|
|
<div class="sec-badge info">12 KPIs</div>
|
|
</div>
|
|
<div class="vkpi-grid" id="vkpi-grid"><div class="loading"><div class="spinner"></div></div></div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
const API = '/api/wevia-v71-intelligence-growth.php';
|
|
let DATA = null;
|
|
function clockTick(){const d=new Date();document.getElementById('clock').textContent=d.toLocaleDateString('fr-FR')+' · '+d.toLocaleTimeString('fr-FR')+' · auto-refresh 30s';}
|
|
setInterval(clockTick,1000); clockTick();
|
|
function fmt(n){if(!n&&n!==0)return'—';if(Math.abs(n)>=1000000)return(n/1000000).toFixed(2)+'M';if(Math.abs(n)>=1000)return(n/1000).toFixed(1)+'k';return Math.round(n);}
|
|
|
|
async function load(){
|
|
try {
|
|
const r = await fetch(API+'?t='+Date.now());
|
|
DATA = await r.json();
|
|
render();
|
|
} catch(e) { console.error(e); }
|
|
}
|
|
|
|
function render(){
|
|
if(!DATA) return;
|
|
const s = DATA.summary;
|
|
|
|
// KPI strip
|
|
document.getElementById('kpi-comp').textContent = s.competitors_tracked;
|
|
document.getElementById('kpi-comp-high').textContent = s.competitors_high_threat;
|
|
document.getElementById('kpi-innov24').textContent = s.innovations_last_24h;
|
|
document.getElementById('kpi-innov').textContent = s.innovations_total;
|
|
document.getElementById('kpi-agil').textContent = s.agility_agents_gap;
|
|
document.getElementById('kpi-agil-fte').textContent = s.agility_fte_savings_year;
|
|
document.getElementById('kpi-chat').textContent = s.chatbots_deployed;
|
|
document.getElementById('kpi-chat-tot').textContent = s.chatbots_total;
|
|
document.getElementById('kpi-oppo').textContent = fmt(s.opportunities_total_value_keur*1000) + '€';
|
|
document.getElementById('kpi-oppo-urg').textContent = s.opportunities_high_urgency;
|
|
document.getElementById('kpi-vkpis').textContent = s.value_kpis_count;
|
|
|
|
// DarkScout
|
|
const ds = DATA.darkscout_competitors;
|
|
document.getElementById('ds-count').textContent = ds.tracked_count + ' compétiteurs · MAJ ' + new Date(ds.updated_at).toLocaleTimeString('fr-FR');
|
|
document.getElementById('comp-grid').innerHTML = ds.competitors.map(c => `
|
|
<div class="comp-card ${c.threat_level}">
|
|
<div class="comp-name">${c.name}<span class="comp-threat ${c.threat_level}">${c.threat_level}</span></div>
|
|
<div class="comp-meta">${c.category} · ${c.market}</div>
|
|
<div class="comp-section"><strong>💰 Prix :</strong> ${c.pricing_estimate}</div>
|
|
<div class="comp-section"><strong>🎯 Positioning :</strong> ${c.positioning}</div>
|
|
<div class="comp-section"><strong>📰 Moves récents :</strong> ${c.recent_moves.slice(0,2).join(' · ')}</div>
|
|
<div class="comp-diff">🛡 <strong>WEVAL differentiator :</strong> ${c.weval_differentiator}</div>
|
|
<div class="comp-score">risk_score ${c.risk_score}/25</div>
|
|
</div>
|
|
`).join('');
|
|
// Market signals
|
|
const ms = ds.market_signals;
|
|
document.getElementById('market-signals').innerHTML = Object.entries(ms).map(([k,v]) => {
|
|
const dir = v.startsWith('UP') ? 'up' : v.startsWith('DOWN') ? 'down' : '';
|
|
return `<div class="market-sig"><div class="s">${k.replace(/_/g,' ')}</div><div class="v ${dir}">${dir==='up'?'↑':dir==='down'?'↓':''} ${v}</div></div>`;
|
|
}).join('');
|
|
|
|
// Innovations
|
|
const innov = DATA.wevl_predict_innovations;
|
|
document.getElementById('innov-velocity').textContent = innov.innovation_velocity;
|
|
document.getElementById('innov-grid').innerHTML = innov.innovations.map(i => `
|
|
<div class="innov-card">
|
|
<div class="innov-head">
|
|
<div class="innov-name">${i.name}</div>
|
|
<div class="innov-date">${i.date}</div>
|
|
</div>
|
|
<span class="innov-type">${i.type}</span>
|
|
<div class="innov-desc">${i.description}</div>
|
|
<div class="innov-value">💎 ${i.value_prop}</div>
|
|
<div class="innov-stars">${'★'.repeat(i.novelty)}${'☆'.repeat(5-i.novelty)}</div>
|
|
</div>
|
|
`).join('');
|
|
|
|
// Agility agents
|
|
const ag = DATA.agility_agents_gap;
|
|
document.getElementById('agil-total-sav').textContent = ag.total_fte_saved_year + ' FTE / ' + fmt(ag.total_savings_year_eur) + '€ savings potentiels';
|
|
document.getElementById('agil-wrap').innerHTML = ag.agents.map(a => `
|
|
<div class="agil-card ${a.priority}">
|
|
<div class="agil-head"><div class="agil-name">${a.name}</div><div class="agil-framework">${a.framework}</div></div>
|
|
<div class="agil-role">${a.role}</div>
|
|
<div class="agil-save">💰 ${a.savings_fte_year} FTE/an (~${Math.round(a.savings_fte_year*90)}k€)</div>
|
|
<div class="agil-status ${a.status}">${a.status.replace('_',' ')}</div>
|
|
</div>
|
|
`).join('');
|
|
|
|
// Lead Capture Hub
|
|
const lch = DATA.lead_capture_hub;
|
|
document.getElementById('lch-status').textContent = lch.chatbots_deployed + '/' + lch.chatbots_total + ' déployés';
|
|
document.getElementById('chat-stats').innerHTML = `
|
|
<div class="chat-stat ok"><div class="chat-stat-v">${lch.chatbots_deployed}</div><div class="chat-stat-l">Deployed</div></div>
|
|
<div class="chat-stat warn"><div class="chat-stat-v">${lch.chatbots_planned}</div><div class="chat-stat-l">À wirer</div></div>
|
|
<div class="chat-stat"><div class="chat-stat-v">${lch.leads_captured_7d}</div><div class="chat-stat-l">Leads 7j</div></div>
|
|
<div class="chat-stat"><div class="chat-stat-v">${lch.leads_captured_month}</div><div class="chat-stat-l">Leads mois</div></div>
|
|
`;
|
|
document.getElementById('chat-funnel').innerHTML = lch.conversion_signals.map(cs => `
|
|
<div class="chat-funnel-step">
|
|
<div class="chat-funnel-pct">${cs.rate_pct}%</div>
|
|
<div class="chat-funnel-lbl">${cs.signal}</div>
|
|
</div>
|
|
`).join('');
|
|
document.getElementById('chat-alerts').innerHTML = '<strong>⚠️ Alertes :</strong>' + lch.alerts.map(a => '• ' + a).join('<br>');
|
|
|
|
// Opportunities
|
|
const ow = DATA.opportunities_watch;
|
|
document.getElementById('oppo-val').textContent = fmt(DATA.summary.opportunities_total_value_keur*1000) + '€ pipeline';
|
|
document.getElementById('oppo-wrap').innerHTML = ow.opportunities.map(o => `
|
|
<div class="oppo-card ${o.urgency}">
|
|
<div class="oppo-head"><span class="oppo-src">${o.source}</span></div>
|
|
<div class="oppo-signal">${o.signal}</div>
|
|
<div class="oppo-action">→ ${o.action}</div>
|
|
<div class="oppo-foot">
|
|
<span class="oppo-val">${o.estimated_value_keur?fmt(o.estimated_value_keur*1000)+'€':'—'}</span>
|
|
<span class="oppo-urg ${o.urgency}">${o.urgency}</span>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
|
|
// Value KPIs
|
|
document.getElementById('vkpi-grid').innerHTML = DATA.value_kpis.map(k => `
|
|
<div class="vkpi-cell ${k.s}">
|
|
<div class="vkpi-lbl">${k.k}</div>
|
|
<div class="vkpi-v">${k.v}${k.u}</div>
|
|
<div class="vkpi-target">target ${k.t}${k.u}</div>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
|
|
load();
|
|
setInterval(load, 30000);
|
|
</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) {
|
|
// 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/a11y-auto-enhancer.js" defer></script>
|
|
</body>
|
|
</html>
|