Files
html/wepredict.html

1670 lines
74 KiB
HTML
Raw 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" data-version="V146">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>WePredict Cockpit · V146 · WEVAL ecosystem</title>
<meta name="description" content="Cockpit prédictif WEVAL — 4 piliers × 4 domaines · 16 cockpits · 64 prédictions · WEVIA · Products · Business · Infra">
<meta name="wevia-version" content="V146">
<meta name="wevia-preserve" content="mirofish.weval-consulting.com:v0.1-Preview">
<meta name="wevia-coverage" content="full-weval-ecosystem-not-sap-only">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Unbounded:wght@300;400;500;600;700&family=Figtree:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root{
--bg-void: #05070e;
--bg-base: #0a0e1a;
--bg-surface: #0e1424;
--bg-elev: #131a2e;
--bg-glass: rgba(20,27,47,0.55);
--bg-glass-strong: rgba(14,20,36,0.85);
--bd-hair: rgba(255,255,255,0.05);
--bd-soft: rgba(255,255,255,0.08);
--bd-mid: rgba(255,255,255,0.14);
--bd-strong: rgba(255,255,255,0.22);
--tx-1: #eef2ff;
--tx-2: #c7d0e5;
--tx-3: #8591af;
--tx-4: #5a6688;
--tx-dim: #3a4666;
/* 4 prediction levels */
--strat-1: #d946ef; --strat-2: #a855f7; --strat-glow: rgba(168,85,247,0.35);
--tact-1: #22d3ee; --tact-2: #3b82f6; --tact-glow: rgba(59,130,246,0.35);
--op-1: #84cc16; --op-2: #10b981; --op-glow: rgba(16,185,129,0.35);
--infra-1: #f59e0b; --infra-2: #ef4444; --infra-glow: rgba(245,158,11,0.35);
/* 4 WEVAL pillars — distinct from level colors */
--p-wevia-1: #7c3aed; --p-wevia-2: #ec4899; /* WEVIA sovereign AI */
--p-product-1: #06b6d4; --p-product-2: #14b8a6; /* WEVAL native products */
--p-biz-1: #f59e0b; --p-biz-2: #ec4899; /* Business SAP + sales */
--p-infra-1: #64748b; --p-infra-2: #475569; /* Cloud & infra */
/* Taxonomy badges */
--tax-wevia: #a855f7;
--tax-native: #14b8a6;
--tax-sap: #3b82f6;
--tax-hybrid: #f59e0b;
--tax-partner: #ec4899;
--tax-infra: #64748b;
--good: #34d399;
--warn: #fbbf24;
--bad: #f87171;
--neutral: #94a3b8;
--ff-display: 'Unbounded', ui-sans-serif, system-ui;
--ff-body: 'Figtree', ui-sans-serif, system-ui;
--ff-mono: 'JetBrains Mono', ui-monospace, monospace;
--r-sm: 8px; --r-md: 14px; --r-lg: 20px; --r-xl: 28px;
--ease: cubic-bezier(.2,.7,.1,1);
}
*,*::before,*::after{ box-sizing: border-box; }
html,body{ margin:0; padding:0; }
body{
background:
radial-gradient(1200px 700px at 85% -10%, rgba(168,85,247,0.08), transparent 60%),
radial-gradient(900px 600px at -10% 40%, rgba(20,184,166,0.07), transparent 55%),
radial-gradient(900px 500px at 110% 60%, rgba(245,158,11,0.05), transparent 60%),
radial-gradient(700px 400px at 50% 110%, rgba(100,116,139,0.06), transparent 60%),
var(--bg-void);
color: var(--tx-1);
font-family: var(--ff-body);
font-size: 14px; line-height: 1.55;
min-height: 100vh; overflow-x: hidden;
-webkit-font-smoothing: antialiased;
}
body::before{
content:""; position: fixed; inset: 0;
background-image:
repeating-linear-gradient(0deg, rgba(255,255,255,0.012) 0 1px, transparent 1px 3px),
repeating-linear-gradient(90deg, rgba(255,255,255,0.012) 0 1px, transparent 1px 3px);
pointer-events: none; z-index: 0;
}
main, header, footer, nav, section{ position: relative; z-index: 1; }
a{ color: inherit; text-decoration: none; }
button{ font: inherit; color: inherit; cursor: pointer; background: none; border: 0; }
/* =============== HEXA-PIVOT XNAV =============== */
.xnav{
display: flex; align-items: center; gap: 4px;
padding: 14px 28px;
background: linear-gradient(180deg, rgba(10,14,26,0.95), rgba(10,14,26,0.7));
border-bottom: 1px solid var(--bd-hair);
backdrop-filter: blur(18px);
position: sticky; top: 0; z-index: 50;
font-family: var(--ff-mono);
font-size: 11px; letter-spacing: 0.04em;
text-transform: uppercase;
overflow-x: auto; white-space: nowrap;
}
.xnav a{
padding: 8px 14px; border-radius: 999px;
border: 1px solid var(--bd-soft);
color: var(--tx-3);
transition: all .25s var(--ease);
display: inline-flex; align-items: center; gap: 6px;
}
.xnav a:hover{ color: var(--tx-1); border-color: var(--bd-mid); background: var(--bg-glass); }
.xnav a.current{
color: var(--tx-1); border-color: transparent;
background: linear-gradient(135deg, var(--p-wevia-1), var(--p-product-1));
box-shadow: 0 0 0 1px var(--bd-mid), 0 8px 24px -8px rgba(124,58,237,0.5);
}
.xnav .sep{ color: var(--tx-dim); font-size: 10px; }
/* =============== HERO =============== */
.hero{ padding: 48px 32px 32px; max-width: 1600px; margin: 0 auto; }
.hero-head{
display: grid; grid-template-columns: 1.2fr auto;
gap: 24px; align-items: end; margin-bottom: 36px;
}
.eyebrow{
font-family: var(--ff-mono);
font-size: 11px; letter-spacing: 0.22em; text-transform: uppercase;
color: var(--tx-3);
display: inline-flex; align-items: center; gap: 10px;
margin-bottom: 18px;
}
.eyebrow .dot{
width: 6px; height: 6px; border-radius: 50%;
background: var(--good);
box-shadow: 0 0 0 4px rgba(52,211,153,0.15), 0 0 14px var(--good);
animation: pulse 2.2s var(--ease) infinite;
}
@keyframes pulse{ 50%{ opacity: .4; transform: scale(.85); } }
.hero h1{
font-family: var(--ff-display); font-weight: 500;
font-size: clamp(40px, 5.4vw, 78px);
line-height: 0.95; letter-spacing: -0.02em;
margin: 0 0 14px; color: var(--tx-1);
}
.hero h1 em{
font-style: normal;
background: linear-gradient(110deg, var(--p-wevia-1) 0%, var(--p-product-1) 45%, var(--p-biz-1) 80%);
-webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero-sub{ font-size: 16px; color: var(--tx-2); max-width: 720px; line-height: 1.6; }
.hero-sub strong{ color: var(--tx-1); font-weight: 600; }
.hero-meta{
display: flex; flex-direction: column; align-items: flex-end; gap: 10px;
font-family: var(--ff-mono);
font-size: 11px; color: var(--tx-3);
}
.hero-meta .ts{ color: var(--tx-4); }
.hero-meta .ver{
padding: 4px 10px; border: 1px solid var(--bd-mid);
border-radius: 4px; color: var(--tx-1);
background: linear-gradient(90deg, rgba(124,58,237,0.15), rgba(6,182,212,0.15));
}
/* =============== PILLAR HERO (4 cards) =============== */
.pillars-hero{
display: grid; grid-template-columns: repeat(4, 1fr);
gap: 14px; margin-top: 14px;
}
.phero{
position: relative; padding: 22px 20px 20px;
border-radius: var(--r-lg);
background: linear-gradient(180deg, var(--bg-glass), rgba(14,20,36,0.25));
border: 1px solid var(--bd-soft);
backdrop-filter: blur(14px);
overflow: hidden;
transition: transform .35s var(--ease);
}
.phero:hover{ transform: translateY(-2px); }
.phero::before{
content:""; position: absolute; inset: -1px; border-radius: inherit;
padding: 1px;
background: linear-gradient(135deg, var(--pc-1), var(--pc-2));
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor; mask-composite: exclude;
opacity: .45;
}
.phero[data-pillar="wevia"]{ --pc-1: var(--p-wevia-1); --pc-2: var(--p-wevia-2); }
.phero[data-pillar="product"]{ --pc-1: var(--p-product-1); --pc-2: var(--p-product-2); }
.phero[data-pillar="biz"]{ --pc-1: var(--p-biz-1); --pc-2: var(--p-biz-2); }
.phero[data-pillar="infra"]{ --pc-1: var(--p-infra-1); --pc-2: var(--p-infra-2); }
.phero-tag{
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase;
color: var(--tx-3);
margin-bottom: 6px;
display: inline-flex; align-items: center; gap: 6px;
}
.phero-tag::before{
content:""; width: 7px; height: 7px; border-radius: 2px;
background: linear-gradient(135deg, var(--pc-1), var(--pc-2));
}
.phero h3{
font-family: var(--ff-display); font-weight: 500;
font-size: 18px; letter-spacing: -0.01em;
margin: 0 0 12px; color: var(--tx-1);
line-height: 1.2;
}
.phero-score{
display: flex; align-items: baseline; gap: 6px;
margin-bottom: 12px;
}
.phero-score .v{
font-family: var(--ff-mono); font-weight: 700;
font-size: 34px; line-height: 1;
background: linear-gradient(110deg, var(--pc-1), var(--pc-2));
-webkit-background-clip: text; background-clip: text; color: transparent;
}
.phero-score .u{ font-family: var(--ff-mono); font-size: 14px; color: var(--tx-3); }
.phero-score .d{ margin-left: auto; font-family: var(--ff-mono); font-size: 11px; color: var(--good); }
.phero-score .d.down{ color: var(--bad); }
.phero-dots{
display: flex; gap: 5px;
font-family: var(--ff-mono); font-size: 10px; color: var(--tx-3);
margin-top: 10px;
}
.phero-dots span{
flex: 1; text-align: center; padding: 4px;
background: rgba(5,7,14,0.5);
border: 1px solid var(--bd-hair);
border-radius: 4px;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* =============== LEVEL GAUGES =============== */
.gauges-sep{
margin: 40px 0 18px;
display: flex; align-items: center; gap: 16px;
}
.gauges-sep-line{ flex: 1; height: 1px; background: var(--bd-hair); }
.gauges-sep-txt{
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase;
color: var(--tx-3);
}
.gauges{
display: grid; grid-template-columns: repeat(4, 1fr);
gap: 14px;
}
.gauge-card{
position: relative; padding: 20px 18px 18px;
border-radius: var(--r-lg);
background: linear-gradient(180deg, var(--bg-glass), rgba(14,20,36,0.3));
border: 1px solid var(--bd-soft);
backdrop-filter: blur(14px);
overflow: hidden;
transition: transform .35s var(--ease);
}
.gauge-card::before{
content:""; position: absolute; inset: -1px; border-radius: inherit;
padding: 1px;
background: linear-gradient(135deg, var(--g-c1), var(--g-c2));
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor; mask-composite: exclude;
opacity: .35;
transition: opacity .35s var(--ease);
}
.gauge-card:hover{ transform: translateY(-2px); }
.gauge-card:hover::before{ opacity: .8; }
.gauge-card[data-level="strat"]{ --g-c1: var(--strat-1); --g-c2: var(--strat-2); }
.gauge-card[data-level="tact"]{ --g-c1: var(--tact-1); --g-c2: var(--tact-2); }
.gauge-card[data-level="op"]{ --g-c1: var(--op-1); --g-c2: var(--op-2); }
.gauge-card[data-level="infra"]{ --g-c1: var(--infra-1); --g-c2: var(--infra-2); }
.gauge-head{ display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.gauge-label{
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
color: var(--tx-3);
}
.gauge-chip{
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.1em;
padding: 3px 8px; border-radius: 4px;
background: var(--bg-void); color: var(--g-c1);
border: 1px solid var(--bd-soft);
}
.gauge-body{ display: grid; grid-template-columns: 96px 1fr; gap: 12px; align-items: center; }
.gauge-body svg{ display: block; }
.gauge-stats .val{
font-family: var(--ff-mono);
font-size: 24px; font-weight: 600;
color: var(--tx-1); line-height: 1; margin-bottom: 4px;
}
.gauge-stats .val small{ font-size: 13px; color: var(--tx-3); margin-left: 3px; font-weight: 500; }
.gauge-stats .sub{ font-size: 11px; color: var(--tx-3); line-height: 1.4; }
.gauge-trend{
margin-top: 10px; display: flex; align-items: center; gap: 8px;
font-family: var(--ff-mono); font-size: 11px; color: var(--tx-3);
}
.gauge-trend .delta{ color: var(--g-c1); font-weight: 600; }
/* =============== TICKER =============== */
.ticker{
margin: 24px 0 0; padding: 14px 20px;
border-radius: var(--r-md);
background: linear-gradient(90deg, rgba(14,20,36,0.7), rgba(14,20,36,0.3));
border: 1px solid var(--bd-hair);
display: grid; grid-template-columns: auto 1fr auto;
align-items: center; gap: 20px;
font-family: var(--ff-mono); font-size: 12px; color: var(--tx-2);
overflow: hidden;
}
.ticker-label{
color: var(--tx-3); letter-spacing: 0.18em; text-transform: uppercase;
font-size: 10px;
display: inline-flex; align-items: center; gap: 8px;
}
.ticker-label .dot{
width: 6px; height: 6px; border-radius: 50%;
background: var(--good);
box-shadow: 0 0 0 3px rgba(52,211,153,0.2);
animation: pulse 2s var(--ease) infinite;
}
.ticker-stream{
display: flex; gap: 28px; overflow: hidden;
mask-image: linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%);
}
.ticker-stream .item{ white-space: nowrap; }
.ticker-stream .item .k{ color: var(--tx-4); margin-right: 6px; }
.ticker-stream .item .up{ color: var(--good); }
.ticker-stream .item .down{ color: var(--bad); }
.ticker-cta{
font-size: 11px; color: var(--tx-3);
padding: 6px 12px;
border: 1px solid var(--bd-soft); border-radius: 999px;
transition: all .2s var(--ease);
}
.ticker-cta:hover{ color: var(--tx-1); border-color: var(--bd-mid); background: var(--bg-glass); }
/* =============== SECTION HEADS =============== */
.section{ max-width: 1600px; margin: 0 auto; padding: 48px 32px 0; }
.section-head{
display: flex; align-items: flex-end; justify-content: space-between;
gap: 20px; margin-bottom: 24px; padding-bottom: 16px;
border-bottom: 1px solid var(--bd-hair);
}
.section-head h2{
font-family: var(--ff-display); font-weight: 400;
font-size: clamp(22px, 2.4vw, 32px); letter-spacing: -0.01em;
margin: 0; color: var(--tx-1);
}
.section-head .tag{
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase;
color: var(--tx-3); margin-bottom: 6px;
}
.section-head p{ color: var(--tx-3); font-size: 13px; margin: 4px 0 0; max-width: 620px; }
/* =============== PILLAR GROUP (for matrix + cards) =============== */
.pgroup{ margin-bottom: 24px; }
.pgroup-head{
display: flex; align-items: center; gap: 14px;
margin-bottom: 14px;
padding: 10px 14px;
border-radius: var(--r-sm);
background: linear-gradient(90deg, var(--pg-bg), transparent 60%);
border-left: 3px solid var(--pg-c1);
}
.pgroup[data-pillar="wevia"]{ --pg-c1: var(--p-wevia-1); --pg-c2: var(--p-wevia-2); --pg-bg: rgba(124,58,237,0.10); }
.pgroup[data-pillar="product"]{ --pg-c1: var(--p-product-1); --pg-c2: var(--p-product-2); --pg-bg: rgba(6,182,212,0.10); }
.pgroup[data-pillar="biz"]{ --pg-c1: var(--p-biz-1); --pg-c2: var(--p-biz-2); --pg-bg: rgba(245,158,11,0.10); }
.pgroup[data-pillar="infra"]{ --pg-c1: var(--p-infra-1); --pg-c2: var(--p-infra-2); --pg-bg: rgba(100,116,139,0.12); }
.pgroup-head .num{
font-family: var(--ff-display);
font-weight: 500; font-size: 14px;
color: var(--pg-c1);
min-width: 24px;
}
.pgroup-head .lbl{
font-family: var(--ff-display);
font-weight: 500; font-size: 16px;
color: var(--tx-1);
letter-spacing: -0.01em;
}
.pgroup-head .desc{
font-size: 12px; color: var(--tx-3);
margin-left: 10px;
font-family: var(--ff-body);
}
.pgroup-head .score{
margin-left: auto;
font-family: var(--ff-mono);
font-size: 11px; color: var(--tx-3);
display: inline-flex; align-items: center; gap: 10px;
}
.pgroup-head .score b{
color: var(--tx-1); font-weight: 600;
font-size: 13px;
}
/* =============== MATRIX HEATMAP =============== */
.matrix-wrap{
border-radius: var(--r-lg); padding: 24px;
background: linear-gradient(180deg, var(--bg-glass), rgba(14,20,36,0.2));
border: 1px solid var(--bd-hair);
backdrop-filter: blur(14px);
overflow-x: auto;
}
.matrix{
display: grid;
grid-template-columns: 220px repeat(4, 1fr);
gap: 6px;
min-width: 820px;
}
.mx-top{
display: contents;
}
.mx-top .mx-head{
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
color: var(--tx-3);
padding: 10px 6px;
border-bottom: 1px solid var(--bd-hair);
display: flex; align-items: center; gap: 8px;
}
.mx-top .mx-head:first-child{ color: var(--tx-1); }
.mx-top .mx-head .lv-dot{ width: 7px; height: 7px; border-radius: 2px; }
.mx-top .mx-head[data-level="strat"] .lv-dot{ background: var(--strat-1); }
.mx-top .mx-head[data-level="tact"] .lv-dot{ background: var(--tact-1); }
.mx-top .mx-head[data-level="op"] .lv-dot{ background: var(--op-1); }
.mx-top .mx-head[data-level="infra"] .lv-dot{ background: var(--infra-1); }
.mx-pillar-row{
grid-column: 1 / -1;
display: flex; align-items: center; gap: 10px;
padding: 14px 10px 6px;
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase;
color: var(--tx-3);
border-top: 1px solid var(--bd-hair);
margin-top: 4px;
}
.mx-pillar-row[data-pillar="wevia"]{ color: var(--p-wevia-1); }
.mx-pillar-row[data-pillar="product"]{ color: var(--p-product-1); }
.mx-pillar-row[data-pillar="biz"]{ color: var(--p-biz-1); }
.mx-pillar-row[data-pillar="infra"]{ color: #94a3b8; }
.mx-pillar-row .line{
flex: 1; height: 1px;
background: linear-gradient(90deg, currentColor, transparent);
opacity: 0.4;
}
.dept-name{
font-family: var(--ff-display);
font-weight: 500; font-size: 13px;
padding: 14px 6px;
color: var(--tx-2);
display: flex; flex-direction: column; gap: 3px;
}
.dept-name .system-badge{
font-family: var(--ff-mono);
font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
padding: 2px 6px;
border-radius: 3px;
width: fit-content;
border: 1px solid var(--bd-hair);
}
.dept-name .system-badge[data-tax="wevia"] { color: var(--tax-wevia); border-color: rgba(168,85,247,0.3); background: rgba(168,85,247,0.08); }
.dept-name .system-badge[data-tax="native"] { color: var(--tax-native); border-color: rgba(20,184,166,0.3); background: rgba(20,184,166,0.08); }
.dept-name .system-badge[data-tax="sap"] { color: var(--tax-sap); border-color: rgba(59,130,246,0.3); background: rgba(59,130,246,0.08); }
.dept-name .system-badge[data-tax="hybrid"] { color: var(--tax-hybrid); border-color: rgba(245,158,11,0.3); background: rgba(245,158,11,0.08); }
.dept-name .system-badge[data-tax="partner"]{ color: var(--tax-partner); border-color: rgba(236,72,153,0.3); background: rgba(236,72,153,0.08); }
.dept-name .system-badge[data-tax="infra"] { color: var(--tax-infra); border-color: rgba(100,116,139,0.35); background: rgba(100,116,139,0.10); }
.cell{
position: relative;
padding: 12px 10px; border-radius: 8px;
background: var(--bg-base);
border: 1px solid var(--bd-hair);
display: flex; flex-direction: column; gap: 6px;
cursor: pointer;
transition: all .25s var(--ease);
min-height: 72px;
}
.cell:hover{
transform: translateY(-2px);
border-color: var(--bd-mid);
z-index: 2;
box-shadow: 0 10px 30px -10px rgba(0,0,0,0.6);
}
.cell .kpi{
font-family: var(--ff-mono);
font-size: 10px; color: var(--tx-4);
letter-spacing: 0.06em; text-transform: uppercase;
}
.cell .val{
font-family: var(--ff-mono);
font-size: 16px; font-weight: 600;
color: var(--tx-1); line-height: 1;
}
.cell .val small{ font-size: 11px; color: var(--tx-3); font-weight: 500; margin-left: 3px; }
.cell .delta{
font-family: var(--ff-mono);
font-size: 10px;
display: inline-flex; align-items: center; gap: 4px;
margin-top: auto;
}
.cell .delta.up{ color: var(--good); }
.cell .delta.down{ color: var(--bad); }
.cell .delta.flat{ color: var(--neutral); }
.cell .heat{
position: absolute; inset: 0;
border-radius: inherit;
opacity: 0.10; pointer-events: none;
transition: opacity .25s var(--ease);
}
.cell:hover .heat{ opacity: 0.20; }
.cell[data-level="strat"] .heat{ background: linear-gradient(135deg, var(--strat-1), var(--strat-2)); }
.cell[data-level="tact"] .heat{ background: linear-gradient(135deg, var(--tact-1), var(--tact-2)); }
.cell[data-level="op"] .heat{ background: linear-gradient(135deg, var(--op-1), var(--op-2)); }
.cell[data-level="infra"] .heat{ background: linear-gradient(135deg, var(--infra-1), var(--infra-2)); }
.cell .src-badge{
position: absolute; top: 6px; right: 7px;
font-family: var(--ff-mono);
font-size: 8px; letter-spacing: 0.08em; text-transform: uppercase;
padding: 2px 5px; border-radius: 3px;
background: rgba(0,0,0,0.4);
border: 1px solid var(--bd-hair);
color: var(--tx-3);
}
.cell .src-badge[data-src="live"]{ color: var(--good); border-color: rgba(52,211,153,0.3); }
.cell .src-badge[data-src="trend"]{ color: var(--tact-1); border-color: rgba(34,211,238,0.3); }
.cell .src-badge[data-src="forecast"]{ color: var(--strat-1); border-color: rgba(217,70,239,0.3); }
.cell .src-badge[data-src="todo"]{ color: var(--warn); border-color: rgba(251,191,36,0.3); }
/* =============== DEPT CARDS =============== */
.deptgrid{
display: grid;
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
gap: 14px;
margin-bottom: 8px;
}
.dcard{
padding: 18px;
border-radius: var(--r-md);
background: linear-gradient(180deg, var(--bg-glass), rgba(14,20,36,0.3));
border: 1px solid var(--bd-hair);
backdrop-filter: blur(12px);
display: flex; flex-direction: column; gap: 12px;
transition: all .3s var(--ease);
position: relative; overflow: hidden;
}
.dcard:hover{
transform: translateY(-3px);
border-color: var(--bd-mid);
}
.dcard::before{
content:"";
position: absolute; top: 0; left: 0; right: 0; height: 2px;
background: linear-gradient(90deg, var(--strat-1), var(--tact-1), var(--op-1), var(--infra-1));
opacity: 0.6;
}
.dcard-head{
display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.dcard-head .dname{
font-family: var(--ff-display); font-weight: 500;
font-size: 15px; color: var(--tx-1);
display: flex; flex-direction: column; gap: 4px;
min-width: 0;
}
.dcard-head .dname .nm{
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dcard-head .dname .system-badge{
font-family: var(--ff-mono);
font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
padding: 2px 6px; border-radius: 3px;
width: fit-content;
}
.dcard-head .dname .system-badge[data-tax="wevia"] { color: var(--tax-wevia); border: 1px solid rgba(168,85,247,0.3); background: rgba(168,85,247,0.08); }
.dcard-head .dname .system-badge[data-tax="native"] { color: var(--tax-native); border: 1px solid rgba(20,184,166,0.3); background: rgba(20,184,166,0.08); }
.dcard-head .dname .system-badge[data-tax="sap"] { color: var(--tax-sap); border: 1px solid rgba(59,130,246,0.3); background: rgba(59,130,246,0.08); }
.dcard-head .dname .system-badge[data-tax="hybrid"] { color: var(--tax-hybrid); border: 1px solid rgba(245,158,11,0.3); background: rgba(245,158,11,0.08); }
.dcard-head .dname .system-badge[data-tax="partner"]{ color: var(--tax-partner); border: 1px solid rgba(236,72,153,0.3); background: rgba(236,72,153,0.08); }
.dcard-head .dname .system-badge[data-tax="infra"] { color: var(--tax-infra); border: 1px solid rgba(100,116,139,0.35); background: rgba(100,116,139,0.10); }
.dcard-head .status{
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.1em;
padding: 3px 8px; border-radius: 999px;
background: rgba(52,211,153,0.1); color: var(--good);
border: 1px solid rgba(52,211,153,0.2);
white-space: nowrap; flex-shrink: 0;
}
.dcard-head .status.warn{ background: rgba(251,191,36,0.1); color: var(--warn); border-color: rgba(251,191,36,0.2); }
.dcard-head .status.bad{ background: rgba(248,113,113,0.1); color: var(--bad); border-color: rgba(248,113,113,0.2); }
.dcard-spark{ height: 52px; position: relative; }
.dcard-spark svg{ width: 100%; height: 100%; display: block; }
.dcard-preds{
display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px;
}
.pred{
padding: 10px; border-radius: 8px;
background: rgba(5,7,14,0.5);
border: 1px solid var(--bd-hair);
display: flex; flex-direction: column; gap: 4px;
}
.pred-head{
display: flex; align-items: center; justify-content: space-between;
font-family: var(--ff-mono);
font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase;
}
.pred-head .lv{ display: inline-flex; align-items: center; gap: 5px; color: var(--tx-3); }
.pred-head .lv .d{ width: 6px; height: 6px; border-radius: 2px; }
.pred[data-level="strat"] .lv .d{ background: var(--strat-1); }
.pred[data-level="tact"] .lv .d{ background: var(--tact-1); }
.pred[data-level="op"] .lv .d{ background: var(--op-1); }
.pred[data-level="infra"] .lv .d{ background: var(--infra-1); }
.pred-head .src{ font-size: 8px; color: var(--tx-4); }
.pred-head .src.live{ color: var(--good); }
.pred-head .src.trend{ color: var(--tact-1); }
.pred-head .src.forecast{ color: var(--strat-1); }
.pred-head .src.todo{ color: var(--warn); }
.pred-val{
font-family: var(--ff-mono);
font-size: 16px; font-weight: 600;
color: var(--tx-1); line-height: 1;
}
.pred-val small{ font-size: 10px; color: var(--tx-3); font-weight: 500; margin-left: 3px; }
.pred-kpi{ font-size: 10px; color: var(--tx-3); }
.pred-bullet{
margin-top: 4px; height: 4px; border-radius: 2px;
background: var(--bg-void);
position: relative; overflow: hidden;
}
.pred-bullet .fill{
position: absolute; left: 0; top: 0; bottom: 0;
border-radius: 2px;
}
.pred[data-level="strat"] .pred-bullet .fill{ background: linear-gradient(90deg, var(--strat-1), var(--strat-2)); }
.pred[data-level="tact"] .pred-bullet .fill{ background: linear-gradient(90deg, var(--tact-1), var(--tact-2)); }
.pred[data-level="op"] .pred-bullet .fill{ background: linear-gradient(90deg, var(--op-1), var(--op-2)); }
.pred[data-level="infra"] .pred-bullet .fill{ background: linear-gradient(90deg, var(--infra-1), var(--infra-2)); }
.pred-bullet .target{
position: absolute; top: -2px; bottom: -2px; width: 2px;
background: var(--tx-1); opacity: 0.5;
}
/* =============== LEVEL BANDS =============== */
.bands{ display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.band{
padding: 22px; border-radius: var(--r-md);
background: linear-gradient(180deg, var(--bg-glass), rgba(14,20,36,0.2));
border: 1px solid var(--bd-hair);
position: relative; overflow: hidden;
}
.band::after{
content:""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
background: linear-gradient(90deg, var(--b-c1), var(--b-c2));
}
.band[data-level="strat"]{ --b-c1: var(--strat-1); --b-c2: var(--strat-2); }
.band[data-level="tact"]{ --b-c1: var(--tact-1); --b-c2: var(--tact-2); }
.band[data-level="op"]{ --b-c1: var(--op-1); --b-c2: var(--op-2); }
.band[data-level="infra"]{ --b-c1: var(--infra-1); --b-c2: var(--infra-2); }
.band-name{
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.22em; text-transform: uppercase;
color: var(--tx-3); margin-bottom: 6px;
}
.band-title{
font-family: var(--ff-display); font-weight: 500;
font-size: 18px; color: var(--tx-1); margin-bottom: 14px;
}
.band-metric{
font-family: var(--ff-mono);
font-size: 32px; font-weight: 600; line-height: 1;
background: linear-gradient(110deg, var(--b-c1), var(--b-c2));
-webkit-background-clip: text; background-clip: text; color: transparent;
margin-bottom: 10px;
}
.band-chart{ height: 70px; margin: 10px 0; }
.band-chart svg{ width: 100%; height: 100%; display: block; }
.band-bullets{ display: flex; flex-direction: column; gap: 6px; font-size: 12px; color: var(--tx-2); padding: 0; margin: 0; }
.band-bullets li{ display: flex; align-items: flex-start; gap: 8px; list-style: none; }
.band-bullets li::before{
content: ""; width: 6px; height: 6px; border-radius: 2px;
background: linear-gradient(135deg, var(--b-c1), var(--b-c2));
margin-top: 6px; flex-shrink: 0;
}
/* =============== SOURCES =============== */
.sources-card{
margin-top: 28px; padding: 24px;
border-radius: var(--r-md);
background: linear-gradient(180deg, rgba(14,20,36,0.4), rgba(5,7,14,0.3));
border: 1px solid var(--bd-hair);
display: grid; grid-template-columns: 1.5fr 3fr;
gap: 32px; align-items: start;
}
.sources-card h3{
font-family: var(--ff-display); font-weight: 500;
font-size: 18px; margin: 0 0 8px; color: var(--tx-1);
}
.sources-card p{ font-size: 13px; color: var(--tx-3); margin: 0 0 16px; line-height: 1.6; }
.src-pills{ display: flex; flex-wrap: wrap; gap: 8px; }
.src-pill{
padding: 6px 12px; border-radius: 999px;
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.08em;
background: var(--bg-base);
border: 1px solid var(--bd-soft);
color: var(--tx-2);
display: inline-flex; align-items: center; gap: 6px;
}
.src-pill.live{ color: var(--good); border-color: rgba(52,211,153,0.3); }
.src-pill.trend{ color: var(--tact-1); border-color: rgba(34,211,238,0.3); }
.src-pill.forecast{ color: var(--strat-1); border-color: rgba(217,70,239,0.3); }
.src-pill.todo{ color: var(--warn); border-color: rgba(251,191,36,0.3); }
.src-pill .count{ color: var(--tx-1); font-weight: 600; }
.tax-legend{
display: flex; flex-wrap: wrap; gap: 10px;
margin-top: 16px; padding-top: 16px;
border-top: 1px dashed var(--bd-hair);
}
.tax-legend .tx-pill{
padding: 5px 10px; border-radius: 4px;
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.08em;
display: inline-flex; align-items: center; gap: 6px;
}
.tax-legend .tx-pill .sw{ width: 10px; height: 10px; border-radius: 2px; }
.tax-legend .tx-pill[data-tax="wevia"] { color: var(--tax-wevia); background: rgba(168,85,247,0.08); border: 1px solid rgba(168,85,247,0.3); }
.tax-legend .tx-pill[data-tax="native"] { color: var(--tax-native); background: rgba(20,184,166,0.08); border: 1px solid rgba(20,184,166,0.3); }
.tax-legend .tx-pill[data-tax="sap"] { color: var(--tax-sap); background: rgba(59,130,246,0.08); border: 1px solid rgba(59,130,246,0.3); }
.tax-legend .tx-pill[data-tax="hybrid"] { color: var(--tax-hybrid); background: rgba(245,158,11,0.08); border: 1px solid rgba(245,158,11,0.3); }
.tax-legend .tx-pill[data-tax="partner"]{ color: var(--tax-partner); background: rgba(236,72,153,0.08); border: 1px solid rgba(236,72,153,0.3); }
.tax-legend .tx-pill[data-tax="infra"] { color: var(--tax-infra); background: rgba(100,116,139,0.10); border: 1px solid rgba(100,116,139,0.35); }
.tax-legend .tx-pill .sw[data-tax="wevia"] { background: var(--tax-wevia); }
.tax-legend .tx-pill .sw[data-tax="native"] { background: var(--tax-native); }
.tax-legend .tx-pill .sw[data-tax="sap"] { background: var(--tax-sap); }
.tax-legend .tx-pill .sw[data-tax="hybrid"] { background: var(--tax-hybrid); }
.tax-legend .tx-pill .sw[data-tax="partner"]{ background: var(--tax-partner); }
.tax-legend .tx-pill .sw[data-tax="infra"] { background: var(--tax-infra); }
.tax-legend .tx-pill .count{ color: var(--tx-1); font-weight: 600; }
/* =============== MIROFISH CTA =============== */
.engine-card{
margin-top: 28px; padding: 32px;
border-radius: var(--r-lg);
background:
radial-gradient(600px 300px at 100% 0%, rgba(168,85,247,0.12), transparent 60%),
radial-gradient(500px 280px at 0% 100%, rgba(34,211,238,0.1), transparent 55%),
linear-gradient(180deg, var(--bg-glass-strong), var(--bg-base));
border: 1px solid var(--bd-soft);
display: grid; grid-template-columns: 1fr auto; gap: 24px; align-items: center;
}
.engine-card .tag{
font-family: var(--ff-mono);
font-size: 10px; letter-spacing: 0.22em; text-transform: uppercase;
color: var(--tx-3);
margin-bottom: 8px;
display: inline-flex; align-items: center; gap: 8px;
}
.engine-card .tag::before{
content:""; width: 5px; height: 5px; border-radius: 50%;
background: var(--strat-1); box-shadow: 0 0 10px var(--strat-1);
}
.engine-card h3{
font-family: var(--ff-display); font-weight: 500;
font-size: 24px; margin: 0 0 10px; color: var(--tx-1);
}
.engine-card p{ color: var(--tx-3); font-size: 13px; margin: 0; max-width: 680px; line-height: 1.6; }
.engine-cta{
display: inline-flex; align-items: center; gap: 10px;
padding: 14px 22px; border-radius: 999px;
background: linear-gradient(135deg, var(--strat-1), var(--tact-2));
color: white;
font-family: var(--ff-mono);
font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase;
font-weight: 600;
transition: all .3s var(--ease);
box-shadow: 0 10px 30px -10px var(--strat-glow);
white-space: nowrap;
}
.engine-cta:hover{ transform: translateY(-2px); box-shadow: 0 14px 36px -10px var(--strat-glow); }
/* =============== FOOTER =============== */
footer.eco{
margin-top: 60px; padding: 16px 28px;
border-top: 1px solid var(--bd-hair);
background: linear-gradient(0deg, rgba(10,14,26,0.9), rgba(10,14,26,0.5));
backdrop-filter: blur(14px);
font-family: var(--ff-mono);
font-size: 11px; color: var(--tx-3);
display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center;
gap: 14px;
}
footer.eco .items{ display: flex; flex-wrap: wrap; gap: 18px; align-items: center; }
footer.eco .items span{ display: inline-flex; align-items: center; gap: 6px; }
footer.eco .items .v{ color: var(--tx-1); font-weight: 600; }
footer.eco .items .ok{ color: var(--good); }
footer.eco .sep{ color: var(--tx-dim); }
footer.eco .truth-link{
color: var(--tact-1);
padding: 4px 10px; border: 1px solid rgba(34,211,238,0.2);
border-radius: 4px; transition: all .2s var(--ease);
}
footer.eco .truth-link:hover{ background: rgba(34,211,238,0.08); border-color: rgba(34,211,238,0.5); }
/* =============== RESPONSIVE =============== */
@media (max-width: 1100px){
.pillars-hero{ grid-template-columns: repeat(2,1fr); }
.gauges{ grid-template-columns: repeat(2,1fr); }
.bands{ grid-template-columns: repeat(2,1fr); }
.sources-card{ grid-template-columns: 1fr; }
.engine-card{ grid-template-columns: 1fr; }
.hero-head{ grid-template-columns: 1fr; }
.hero-meta{ align-items: flex-start; }
}
@media (max-width: 640px){
.hero{ padding: 32px 18px 18px; }
.section{ padding: 32px 18px 0; }
.pillars-hero{ grid-template-columns: 1fr; }
.gauges{ grid-template-columns: 1fr; }
.bands{ grid-template-columns: 1fr; }
.deptgrid{ grid-template-columns: 1fr; }
.xnav{ padding: 12px 16px; }
}
.reveal{ opacity: 0; transform: translateY(12px); animation: reveal .7s var(--ease) forwards; }
@keyframes reveal{ to{ opacity: 1; transform: none; } }
.reveal:nth-child(1){ animation-delay: .05s; }
.reveal:nth-child(2){ animation-delay: .15s; }
.reveal:nth-child(3){ animation-delay: .25s; }
.reveal:nth-child(4){ animation-delay: .35s; }
.reveal:nth-child(5){ animation-delay: .45s; }
:focus-visible{ outline: 2px solid var(--tact-1); outline-offset: 3px; border-radius: 6px; }
</style>
<!-- DOCTRINE-60-UX-ENRICH direct-inject-20260424-143816 -->
<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>
<nav class="xnav" aria-label="Pivot ecosystem">
<a href="/weval-technology-platform.html">← WTP</a>
<span class="sep">/</span>
<a href="/all-ia-hub.html">All-IA</a>
<span class="sep">/</span>
<a href="/weval-arena.html">Arena</a>
<span class="sep">/</span>
<a href="/wevia-master.html">WEVIA Master</a>
<span class="sep">/</span>
<a href="/wevia-orchestrator.html">Orchestrator</a>
<span class="sep">/</span>
<a href="/wevia-unified-hub.html">Truth Hub</a>
<span class="sep">·</span>
<a href="#" class="current">WePredict Cockpit</a>
</nav>
<header class="hero">
<div class="hero-head">
<div class="reveal">
<div class="eyebrow"><span class="dot"></span> Couverture WEVAL complète · 4 piliers × 4 domaines · 64 prédictions</div>
<h1>WePredict <em>Cockpit</em></h1>
<p class="hero-sub">Plateforme prédictive pour <strong>tout l'écosystème WEVAL</strong> — pas seulement SAP. Source unique <strong>Truth Registry</strong> (906 agents · 1263 intents · 15 providers · 15509 skills). Quatre piliers : <strong>WEVIA</strong> (IA souveraine), <strong>Produits natifs</strong> (WEVADS/Ethica/Paperclip/Arsenal), <strong>Business</strong> (SAP + sales + gouvernance), <strong>Cloud & Infra</strong> (S204/S95/DevOps/Sécurité). Chaque domaine affiche son vrai système — pas de SAP-washing.</p>
</div>
<div class="hero-meta reveal">
<span class="ver">V146 · Truth Registry aligned</span>
<span>Auto-refresh <strong>30s</strong></span>
<span class="ts" id="ts-now"></span>
</div>
</div>
<!-- 4 PILLAR HERO CARDS -->
<div class="pillars-hero">
<article class="phero reveal" data-pillar="wevia">
<div class="phero-tag">Pilier I · Sovereign AI</div>
<h3>WEVIA — IA souveraine 0€</h3>
<div class="phero-score">
<span class="v">87</span><span class="u">/100</span>
<span class="d">▲ +3.2pt</span>
</div>
<div class="phero-dots">
<span>Master</span><span>Enterprise</span><span>Arena</span><span>LIFE</span>
</div>
</article>
<article class="phero reveal" data-pillar="product">
<div class="phero-tag">Pilier II · Native Products</div>
<h3>WEVAL — produits propriétaires</h3>
<div class="phero-score">
<span class="v">82</span><span class="u">/100</span>
<span class="d">▲ +2.1pt</span>
</div>
<div class="phero-dots">
<span>WEVADS</span><span>Ethica</span><span>Paperclip</span><span>Arsenal</span>
</div>
</article>
<article class="phero reveal" data-pillar="biz">
<div class="phero-tag">Pilier III · Business</div>
<h3>SAP + Sales + Gouvernance</h3>
<div class="phero-score">
<span class="v">79</span><span class="u">/100</span>
<span class="d">▲ +1.4pt</span>
</div>
<div class="phero-dots">
<span>Finance</span><span>Sales</span><span>Supply</span><span>DG</span>
</div>
</article>
<article class="phero reveal" data-pillar="infra">
<div class="phero-tag">Pilier IV · Cloud & Infra</div>
<h3>Souveraineté technique</h3>
<div class="phero-score">
<span class="v">94</span><span class="u">/100</span>
<span class="d">▲ +0.3pt</span>
</div>
<div class="phero-dots">
<span>S204</span><span>S95</span><span>DevOps</span><span>Sec</span>
</div>
</article>
</div>
<!-- 4 LEVEL GAUGES -->
<div class="gauges-sep">
<span class="gauges-sep-line"></span>
<span class="gauges-sep-txt">◆ 4 niveaux décisionnels transverses aux 16 domaines</span>
<span class="gauges-sep-line"></span>
</div>
<div class="gauges">
<article class="gauge-card reveal" data-level="strat">
<div class="gauge-head"><span class="gauge-label">◆ Stratégique</span><span class="gauge-chip">90-180j · Board</span></div>
<div class="gauge-body">
<svg viewBox="0 0 96 96" width="96" height="96">
<defs><linearGradient id="gS" x1="0" x2="1"><stop offset="0%" stop-color="#d946ef"/><stop offset="100%" stop-color="#a855f7"/></linearGradient></defs>
<circle cx="48" cy="48" r="38" fill="none" stroke="rgba(255,255,255,0.06)" stroke-width="7"/>
<circle cx="48" cy="48" r="38" fill="none" stroke="url(#gS)" stroke-width="7" stroke-linecap="round" stroke-dasharray="239" stroke-dashoffset="50" transform="rotate(-90 48 48)"/>
<text x="48" y="52" text-anchor="middle" font-family="JetBrains Mono" font-size="20" font-weight="700" fill="#eef2ff">79</text>
<text x="48" y="66" text-anchor="middle" font-family="JetBrains Mono" font-size="7" fill="#8591af" letter-spacing="1">CONFIDENCE</text>
</svg>
<div class="gauge-stats">
<div class="val">16<small>/16 dom.</small></div>
<div class="sub">Board · M&A · ARR · Risk · Roadmap</div>
</div>
</div>
<div class="gauge-trend"><span class="delta">▲ +2.4pt</span><span>horizon 90j</span></div>
</article>
<article class="gauge-card reveal" data-level="tact">
<div class="gauge-head"><span class="gauge-label">◆ Tactique</span><span class="gauge-chip">30-90j · Mgmt</span></div>
<div class="gauge-body">
<svg viewBox="0 0 96 96" width="96" height="96">
<defs><linearGradient id="gT" x1="0" x2="1"><stop offset="0%" stop-color="#22d3ee"/><stop offset="100%" stop-color="#3b82f6"/></linearGradient></defs>
<circle cx="48" cy="48" r="38" fill="none" stroke="rgba(255,255,255,0.06)" stroke-width="7"/>
<circle cx="48" cy="48" r="38" fill="none" stroke="url(#gT)" stroke-width="7" stroke-linecap="round" stroke-dasharray="239" stroke-dashoffset="36" transform="rotate(-90 48 48)"/>
<text x="48" y="52" text-anchor="middle" font-family="JetBrains Mono" font-size="20" font-weight="700" fill="#eef2ff">85</text>
<text x="48" y="66" text-anchor="middle" font-family="JetBrains Mono" font-size="7" fill="#8591af" letter-spacing="1">CONFIDENCE</text>
</svg>
<div class="gauge-stats">
<div class="val">16<small>/16 dom.</small></div>
<div class="sub">OKR · Pipeline · Capacity · Velocity</div>
</div>
</div>
<div class="gauge-trend"><span class="delta">▲ +4.1pt</span><span>horizon 30j</span></div>
</article>
<article class="gauge-card reveal" data-level="op">
<div class="gauge-head"><span class="gauge-label">◆ Opérationnel</span><span class="gauge-chip">1-7j · Terrain</span></div>
<div class="gauge-body">
<svg viewBox="0 0 96 96" width="96" height="96">
<defs><linearGradient id="gO" x1="0" x2="1"><stop offset="0%" stop-color="#84cc16"/><stop offset="100%" stop-color="#10b981"/></linearGradient></defs>
<circle cx="48" cy="48" r="38" fill="none" stroke="rgba(255,255,255,0.06)" stroke-width="7"/>
<circle cx="48" cy="48" r="38" fill="none" stroke="url(#gO)" stroke-width="7" stroke-linecap="round" stroke-dasharray="239" stroke-dashoffset="22" transform="rotate(-90 48 48)"/>
<text x="48" y="52" text-anchor="middle" font-family="JetBrains Mono" font-size="20" font-weight="700" fill="#eef2ff">91</text>
<text x="48" y="66" text-anchor="middle" font-family="JetBrains Mono" font-size="7" fill="#8591af" letter-spacing="1">CONFIDENCE</text>
</svg>
<div class="gauge-stats">
<div class="val">16<small>/16 dom.</small></div>
<div class="sub">SLA · Leads · Incidents · Throughput</div>
</div>
</div>
<div class="gauge-trend"><span class="delta">▲ +1.8pt</span><span>horizon 7j</span></div>
</article>
<article class="gauge-card reveal" data-level="infra">
<div class="gauge-head"><span class="gauge-label">◆ Infrastructure</span><span class="gauge-chip">Live · Système</span></div>
<div class="gauge-body">
<svg viewBox="0 0 96 96" width="96" height="96">
<defs><linearGradient id="gI" x1="0" x2="1"><stop offset="0%" stop-color="#f59e0b"/><stop offset="100%" stop-color="#ef4444"/></linearGradient></defs>
<circle cx="48" cy="48" r="38" fill="none" stroke="rgba(255,255,255,0.06)" stroke-width="7"/>
<circle cx="48" cy="48" r="38" fill="none" stroke="url(#gI)" stroke-width="7" stroke-linecap="round" stroke-dasharray="239" stroke-dashoffset="15" transform="rotate(-90 48 48)"/>
<text x="48" y="52" text-anchor="middle" font-family="JetBrains Mono" font-size="20" font-weight="700" fill="#eef2ff">94</text>
<text x="48" y="66" text-anchor="middle" font-family="JetBrains Mono" font-size="7" fill="#8591af" letter-spacing="1">CONFIDENCE</text>
</svg>
<div class="gauge-stats">
<div class="val">16<small>/16 dom.</small></div>
<div class="sub">CPU · RAM · Disk · Latency · Uptime</div>
</div>
</div>
<div class="gauge-trend"><span class="delta">▲ +0.3pt</span><span>horizon 24h</span></div>
</article>
</div>
<div class="ticker reveal">
<span class="ticker-label"><span class="dot"></span> Live signals</span>
<div class="ticker-stream">
<span class="item"><span class="k">L99 combined</span> <span class="up">201/201</span></span>
<span class="item"><span class="k">legacy</span> <span class="up">153/153</span></span>
<span class="item"><span class="k">Master</span> <span class="up">72/72</span></span>
<span class="item"><span class="k">Opus</span> <span class="up">129/129</span></span>
<span class="item"><span class="k">Tools</span> 158</span>
<span class="item"><span class="k">Docker</span> 19 up</span>
<span class="item"><span class="k">Providers</span> <span class="up">15/15</span></span>
<span class="item"><span class="k">Qdrant</span> 14 368 vect</span>
<span class="item"><span class="k">Ollama</span> 7 models</span>
<span class="item"><span class="k">Arena</span> 409 opts</span>
<span class="item"><span class="k">Agents</span> <span class="up">906</span> <span style="color:var(--tx-4);font-size:9px">dedup 1042 overlaps</span></span>
<span class="item"><span class="k">Intents</span> <span class="up">1263</span> <span style="color:var(--tx-4);font-size:9px">truth registry</span></span>
<span class="item"><span class="k">WEVADS</span> 646 configs</span>
<span class="item"><span class="k">HCP</span> 161 733</span>
<span class="item"><span class="k">Doctrines</span> 19</span>
</div>
<a class="ticker-cta" href="/wevia-unified-hub.html">Truth Registry →</a>
</div>
</header>
<!-- ========== MATRIX HEATMAP GROUPED BY PILLAR ========== -->
<section class="section">
<div class="section-head">
<div>
<div class="tag">Matrix · 4 piliers × 4 domaines × 4 niveaux = 64 prédictions</div>
<h2>Grille prédictive WEVAL</h2>
<p>Taxonomie honnête : chaque domaine porte son vrai système (WEVIA / WEVAL Native / SAP / Hybrid / Infra / Partner) — pas de forçage SAP-washing.</p>
</div>
<div style="display:flex; gap:10px; align-items:center; font-family: var(--ff-mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--tx-3);">
<span style="display:inline-flex;align-items:center;gap:6px"><span style="width:8px;height:8px;background:var(--good);border-radius:2px"></span>↑ Up</span>
<span style="display:inline-flex;align-items:center;gap:6px"><span style="width:8px;height:8px;background:var(--bad);border-radius:2px"></span>↓ Down</span>
</div>
</div>
<div class="matrix-wrap">
<div class="matrix" id="matrix">
<div class="mx-top">
<div class="mx-head">Domaine WEVAL · Système</div>
<div class="mx-head" data-level="strat"><span class="lv-dot"></span>Stratégique</div>
<div class="mx-head" data-level="tact"><span class="lv-dot"></span>Tactique</div>
<div class="mx-head" data-level="op"><span class="lv-dot"></span>Opérationnel</div>
<div class="mx-head" data-level="infra"><span class="lv-dot"></span>Infrastructure</div>
</div>
<!-- rows injected by JS, grouped by pillar -->
</div>
</div>
</section>
<!-- ========== DOMAIN CARDS GROUPED BY PILLAR ========== -->
<section class="section">
<div class="section-head">
<div>
<div class="tag">Drill-down · 16 cockpits WEVAL</div>
<h2>Prévisions par domaine</h2>
<p>Tendance 30j (sparkline) et progression vs target (bullet chart) pour chacun des 16 domaines, regroupés par pilier.</p>
</div>
</div>
<div id="deptgroups"><!-- pillar-grouped dcards injected by JS --></div>
</section>
<!-- ========== LEVEL BANDS ========== -->
<section class="section">
<div class="section-head">
<div>
<div class="tag">Deep-dive · 4 horizons décisionnels transverses</div>
<h2>Tendances par niveau</h2>
<p>Agrégation des 16 domaines WEVAL par horizon de décision.</p>
</div>
</div>
<div class="bands">
<article class="band reveal" data-level="strat">
<div class="band-name">◆ Stratégique</div>
<div class="band-title">Board · 90-180 jours</div>
<div class="band-metric">79<span style="font-size:16px;color:var(--tx-3);margin-left:4px">/100</span></div>
<div class="band-chart">
<svg viewBox="0 0 300 70" preserveAspectRatio="none">
<defs><linearGradient id="bgS" x1="0" x2="0" y1="0" y2="1"><stop offset="0%" stop-color="#d946ef" stop-opacity="0.4"/><stop offset="100%" stop-color="#d946ef" stop-opacity="0"/></linearGradient></defs>
<path d="M0,50 L30,48 L60,42 L90,38 L120,35 L150,30 L180,28 L210,25 L240,22 L270,18 L300,15 L300,70 L0,70 Z" fill="url(#bgS)"/>
<path d="M0,50 L30,48 L60,42 L90,38 L120,35 L150,30 L180,28 L210,25 L240,22 L270,18 L300,15" fill="none" stroke="#d946ef" stroke-width="2" stroke-linejoin="round"/>
<circle cx="300" cy="15" r="3" fill="#d946ef"/>
</svg>
</div>
<ul class="band-bullets">
<li>ARR WEVIA Enterprise · forecast Q+1 positif</li>
<li>Pipeline Cosumar · Carrefour · advancing</li>
<li>Ethica Groupe · pharma MENA expansion</li>
</ul>
</article>
<article class="band reveal" data-level="tact">
<div class="band-name">◆ Tactique</div>
<div class="band-title">Management · 30-90 jours</div>
<div class="band-metric">85<span style="font-size:16px;color:var(--tx-3);margin-left:4px">/100</span></div>
<div class="band-chart">
<svg viewBox="0 0 300 70" preserveAspectRatio="none">
<defs><linearGradient id="bgT" x1="0" x2="0" y1="0" y2="1"><stop offset="0%" stop-color="#22d3ee" stop-opacity="0.4"/><stop offset="100%" stop-color="#22d3ee" stop-opacity="0"/></linearGradient></defs>
<path d="M0,45 L25,40 L50,38 L75,32 L100,35 L125,28 L150,22 L175,25 L200,18 L225,14 L250,12 L275,10 L300,8 L300,70 L0,70 Z" fill="url(#bgT)"/>
<path d="M0,45 L25,40 L50,38 L75,32 L100,35 L125,28 L150,22 L175,25 L200,18 L225,14 L250,12 L275,10 L300,8" fill="none" stroke="#22d3ee" stroke-width="2" stroke-linejoin="round"/>
<circle cx="300" cy="8" r="3" fill="#22d3ee"/>
</svg>
</div>
<ul class="band-bullets">
<li>OKR Q1 · 85% atteints · retard RH staffing</li>
<li>WEVADS 9 winners SACRED · brain stable</li>
<li>Arena 409 opts · leaderboard actif</li>
</ul>
</article>
<article class="band reveal" data-level="op">
<div class="band-name">◆ Opérationnel</div>
<div class="band-title">Terrain · 1-7 jours</div>
<div class="band-metric">91<span style="font-size:16px;color:var(--tx-3);margin-left:4px">/100</span></div>
<div class="band-chart">
<svg viewBox="0 0 300 70" preserveAspectRatio="none">
<defs><linearGradient id="bgO" x1="0" x2="0" y1="0" y2="1"><stop offset="0%" stop-color="#84cc16" stop-opacity="0.4"/><stop offset="100%" stop-color="#84cc16" stop-opacity="0"/></linearGradient></defs>
<path d="M0,20 L20,22 L40,18 L60,25 L80,20 L100,15 L120,12 L140,18 L160,14 L180,10 L200,12 L220,8 L240,9 L260,6 L280,8 L300,5 L300,70 L0,70 Z" fill="url(#bgO)"/>
<path d="M0,20 L20,22 L40,18 L60,25 L80,20 L100,15 L120,12 L140,18 L160,14 L180,10 L200,12 L220,8 L240,9 L260,6 L280,8 L300,5" fill="none" stroke="#84cc16" stroke-width="2" stroke-linejoin="round"/>
<circle cx="300" cy="5" r="3" fill="#84cc16"/>
</svg>
</div>
<ul class="band-bullets">
<li>L99 304/304 · SLA respecté J+7</li>
<li>WEVIA LIFE · 2 077 emails classifiés</li>
<li>Paperclip · 848 agents actifs · 6 projets</li>
</ul>
</article>
<article class="band reveal" data-level="infra">
<div class="band-name">◆ Infrastructure</div>
<div class="band-title">Système · Temps réel</div>
<div class="band-metric">94<span style="font-size:16px;color:var(--tx-3);margin-left:4px">/100</span></div>
<div class="band-chart">
<svg viewBox="0 0 300 70" preserveAspectRatio="none">
<defs><linearGradient id="bgI" x1="0" x2="0" y1="0" y2="1"><stop offset="0%" stop-color="#f59e0b" stop-opacity="0.4"/><stop offset="100%" stop-color="#f59e0b" stop-opacity="0"/></linearGradient></defs>
<path d="M0,15 L15,12 L30,18 L45,14 L60,10 L75,13 L90,8 L105,11 L120,6 L135,9 L150,5 L165,8 L180,4 L195,6 L210,3 L225,5 L240,2 L255,4 L270,2 L285,3 L300,2 L300,70 L0,70 Z" fill="url(#bgI)"/>
<path d="M0,15 L15,12 L30,18 L45,14 L60,10 L75,13 L90,8 L105,11 L120,6 L135,9 L150,5 L165,8 L180,4 L195,6 L210,3 L225,5 L240,2 L255,4 L270,2 L285,3 L300,2" fill="none" stroke="#f59e0b" stroke-width="2" stroke-linejoin="round"/>
<circle cx="300" cy="2" r="3" fill="#f59e0b"/>
</svg>
</div>
<ul class="band-bullets">
<li>S204 · CPU 35% · 17 Docker · 88% disk</li>
<li>S95 Arsenal · PostgreSQL · 38 crons</li>
<li>Uptime 99.97% · CrowdSec ARMED</li>
</ul>
</article>
</div>
</section>
<!-- ========== SOURCES & TAXONOMY ========== -->
<section class="section">
<div class="sources-card">
<div>
<h3>Sources & taxonomie</h3>
<p>Chaque cellule affiche sa source (live/trend/forecast/todo) ET sa taxonomie (wevia/native/sap/hybrid/partner/infra). Pas de SAP-washing : un domaine WEVIA est étiqueté WEVIA, pas "SAP AI Core equivalent".</p>
</div>
<div>
<div class="src-pills">
<span class="src-pill live">● LIVE <span class="count" id="cnt-live"></span></span>
<span class="src-pill trend">◐ TREND <span class="count" id="cnt-trend"></span></span>
<span class="src-pill forecast">◑ FORECAST <span class="count" id="cnt-forecast"></span></span>
<span class="src-pill todo">○ TODO <span class="count" id="cnt-todo"></span></span>
</div>
<div class="tax-legend">
<span class="tx-pill" data-tax="wevia"><span class="sw" data-tax="wevia"></span>WEVIA <span class="count" id="tax-wevia"></span></span>
<span class="tx-pill" data-tax="native"><span class="sw" data-tax="native"></span>WEVAL Native <span class="count" id="tax-native"></span></span>
<span class="tx-pill" data-tax="sap"><span class="sw" data-tax="sap"></span>SAP <span class="count" id="tax-sap"></span></span>
<span class="tx-pill" data-tax="hybrid"><span class="sw" data-tax="hybrid"></span>Hybrid <span class="count" id="tax-hybrid"></span></span>
<span class="tx-pill" data-tax="partner"><span class="sw" data-tax="partner"></span>Partner <span class="count" id="tax-partner"></span></span>
<span class="tx-pill" data-tax="infra"><span class="sw" data-tax="infra"></span>Infra <span class="count" id="tax-infra"></span></span>
</div>
<div style="margin-top:18px; font-family: var(--ff-mono); font-size: 11px; color: var(--tx-3); line-height:1.8;">
APIs · /api/dsh-predict-api.php · /api/l99-health.php · /api/truth-registry.php<br>
/api/ecosystem-health.php · /api/wevia-autonomous.php · /api/paperclip-dashboard.json · /api/wevads-brain.php
</div>
</div>
</div>
</section>
<!-- ========== MIROFISH CTA ========== -->
<section class="section">
<div class="engine-card">
<div>
<div class="tag">Moteur ad-hoc préservé · doctrine #108</div>
<h3>Simulation personnalisée → Mirofish v0.1-Preview</h3>
<p>Ce cockpit est la vue permanente (live platform). Pour une prédiction sur un rapport uploadé ou une simulation scénarisée custom, bascule vers le moteur ad-hoc Mirofish — non écrasé, complémentaire.</p>
</div>
<a class="engine-cta" href="https://mirofish.weval-consulting.com" target="_blank" rel="noopener">
Upload rapport →
</a>
</div>
</section>
<footer class="eco">
<div class="items">
<span class="v ok">A+ 100%</span>
<span class="sep">·</span>
<span><span class="v">L99</span> 201/201 <span style="color:var(--tx-4);font-size:9px">combined</span></span>
<span class="sep">·</span>
<span><span class="v">nonreg-api</span> 153/153</span>
<span class="sep">·</span>
<span><span class="v">l99-api</span> 338/338</span>
<span class="sep">·</span>
<span><span class="v">Tools</span> 158</span>
<span class="sep">·</span>
<span><span class="v">Docker</span> 19</span>
<span class="sep">·</span>
<span><span class="v">Providers</span> 15</span>
<span class="sep">·</span>
<span><span class="v">Qdrant</span> 14 368</span>
<span class="sep">·</span>
<span><span class="v">Ollama</span> 7</span>
<span class="sep">·</span>
<span><span class="v">Agents</span> 906</span>
</div>
<a class="truth-link" href="/wevia-unified-hub.html">Truth Registry →</a>
</footer>
<script>
/* =============================================================
WePredict V145 — WEVAL ecosystem model
4 pillars × 4 domains × 4 levels = 64 predictions.
Each domain carries honest taxonomy (tax):
wevia — WEVIA sovereign AI core products
native — WEVAL native products (WEVADS, Ethica, Paperclip, Arsenal)
sap — Pure SAP modules
hybrid — SAP + WEVAL layer combined
partner — External partner ecosystem
infra — Cloud/infrastructure
============================================================= */
const PILLARS = [
{ id:'wevia', label:'WEVIA — IA souveraine', desc:'Orchestration autonome · 0€ inference cost · Master/EM/Arena/LIFE',
domains:[
{ id:'master', name:'WEVIA Master', system:'WEVIA CORE', tax:'wevia',
preds:{
strat:{kpi:'Autonomy level', val:'100', unit:'%', d:+5, src:'forecast', target:88},
tact: {kpi:'Wave intents', val:'1263', unit:'', d:+42, src:'trend', target:82},
op: {kpi:'Exec intents', val:'21', unit:'', d:0, src:'live', target:94},
infra:{kpi:'Resolver tools', val:'269', unit:'', d:+12, src:'live', target:97}
}},
{ id:'em', name:'WEVIA Enterprise (EM)', system:'WEVIA EM', tax:'wevia',
preds:{
strat:{kpi:'ARR pipeline', val:'+28', unit:'%', d:+6, src:'forecast', target:82},
tact: {kpi:'Agents actifs', val:'930', unit:'', d:+24, src:'trend', target:86},
op: {kpi:'Value chain', val:'9/9', unit:'mét',d:0, src:'live', target:92},
infra:{kpi:'Dépôts git', val:'15', unit:'', d:0, src:'live', target:96}
}},
{ id:'arena', name:'WEVIA Arena', system:'WEVIA ARENA', tax:'wevia',
preds:{
strat:{kpi:'Model mix', val:'409', unit:'opt',d:+12, src:'forecast', target:78},
tact: {kpi:'Win-rate Trinity', val:'87', unit:'%', d:+3, src:'trend', target:84},
op: {kpi:'Daily calls', val:'12.4k',unit:'', d:+820, src:'live', target:91},
infra:{kpi:'Hierarchy links', val:'25', unit:'', d:0, src:'live', target:95}
}},
{ id:'life', name:'WEVIA LIFE', system:'WEVIA LIFE', tax:'wevia',
preds:{
strat:{kpi:'Intel coverage', val:'+14', unit:'%', d:+2, src:'forecast', target:74},
tact: {kpi:'Emails classified', val:'2077', unit:'', d:+38, src:'trend', target:83},
op: {kpi:'Actions / opps', val:'1119', unit:'', d:+24, src:'live', target:90},
infra:{kpi:'Cron 30m', val:'OK', unit:'', d:0, src:'live', target:98}
}}
]},
{ id:'product', label:'WEVAL — produits natifs', desc:'WEVADS email platform · Ethica pharma · Paperclip PM · Arsenal ops',
domains:[
{ id:'wevads', name:'WEVADS Platform', system:'WEVAL NATIVE', tax:'native',
preds:{
strat:{kpi:'Sender rep.', val:'A+', unit:'', d:0, src:'forecast', target:77},
tact: {kpi:'Brain configs', val:'646', unit:'', d:+14, src:'trend', target:85},
op: {kpi:'Winners SACRED', val:'9', unit:'', d:0, src:'live', target:92},
infra:{kpi:'PMTA/Kumo/Postfix', val:'UP', unit:'', d:0, src:'live', target:99}
}},
{ id:'ethica', name:'Ethica / ReachHCP', system:'WEVAL PHARMA', tax:'native',
preds:{
strat:{kpi:'MENA expansion', val:'+4.1', unit:'%', d:+1.2, src:'forecast', target:73},
tact: {kpi:'Consent rate', val:'68', unit:'%', d:+3, src:'trend', target:82},
op: {kpi:'HCPs enriched', val:'161k', unit:'', d:+2.4, src:'live', target:91},
infra:{kpi:'ecm.py + pipeline', val:'v5', unit:'', d:0, src:'live', target:96}
}},
{ id:'paperclip', name:'Paperclip PM', system:'WEVAL PM', tax:'native',
preds:{
strat:{kpi:'Projets actifs', val:'6', unit:'', d:0, src:'forecast', target:75},
tact: {kpi:'Agents total', val:'848', unit:'', d:+16, src:'trend', target:84},
op: {kpi:'Goals tracked', val:'9', unit:'', d:0, src:'live', target:88},
infra:{kpi:'PG paperclip', val:'OK', unit:'', d:0, src:'live', target:97}
}},
{ id:'arsenal', name:'Arsenal Ops', system:'WEVAL OPS', tax:'native',
preds:{
strat:{kpi:'Screens catalog', val:'150+', unit:'', d:+6, src:'forecast', target:72},
tact: {kpi:'arsenal-common.js', val:'25KB', unit:'', d:0, src:'trend', target:79},
op: {kpi:'Port 5890', val:'UP', unit:'', d:0, src:'live', target:93},
infra:{kpi:'S95 sentinel', val:'ARMED',unit:'', d:0, src:'live', target:98}
}}
]},
{ id:'biz', label:'Business — SAP + Sales + DG', desc:'Finance FI · Sales SD+Vistex · Supply MM/PP · Gouvernance',
domains:[
{ id:'finance', name:'Finance & Compta', system:'SAP FI', tax:'sap',
preds:{
strat:{kpi:'EBITDA 90j', val:'+4.2', unit:'%', d:+2.1, src:'forecast', target:75},
tact: {kpi:'Cash-flow Q', val:'2.1', unit:'M€', d:+8.3, src:'trend', target:82},
op: {kpi:'DSO', val:'38', unit:'j', d:-3.2, src:'live', target:91},
infra:{kpi:'ERP FI uptime', val:'99.9', unit:'%', d:+0.1, src:'live', target:97}
}},
{ id:'sales', name:'Sales & CRM', system:'SAP SD + CRM', tax:'hybrid',
preds:{
strat:{kpi:'Pipeline Cosumar', val:'advancing', unit:'', d:+1, src:'forecast', target:76},
tact: {kpi:'Deals closing', val:'12', unit:'', d:+3, src:'trend', target:84},
op: {kpi:'Twenty CRM sync', val:'100', unit:'%', d:0, src:'live', target:95},
infra:{kpi:'Vistex portal', val:'todo', unit:'', d:0, src:'todo', target:70}
}},
{ id:'supply', name:'Supply & Manuf', system:'SAP MM + PP', tax:'sap',
preds:{
strat:{kpi:'Capacity plan', val:'+8', unit:'%', d:+1.4, src:'forecast', target:74},
tact: {kpi:'OEE', val:'82', unit:'%', d:+1.8, src:'trend', target:86},
op: {kpi:'OTD rate', val:'94.3', unit:'%', d:+1.2, src:'live', target:91},
infra:{kpi:'EDI / MES', val:'99.7', unit:'%', d:+0.1, src:'live', target:96}
}},
{ id:'dg', name:'Direction Générale', system:'GOUVERNANCE', tax:'hybrid',
preds:{
strat:{kpi:'Doctrine #0', val:'ACTIVE',unit:'', d:0, src:'forecast', target:88},
tact: {kpi:'Arbitrages ouv.', val:'14', unit:'', d:-4, src:'trend', target:81},
op: {kpi:'Weekly brief', val:'4/4', unit:'', d:0, src:'live', target:95},
infra:{kpi:'Cockpit live', val:'WTP', unit:'', d:0, src:'live', target:99}
}}
]},
{ id:'infra', label:'Cloud & Infra — souveraineté', desc:'S204 primary · S95 legacy · DevOps quality · Security & partners',
domains:[
{ id:'s204', name:'S204 Core (primary)', system:'INFRA PRIMARY', tax:'infra',
preds:{
strat:{kpi:'Capacity plan', val:'+24', unit:'%', d:+3, src:'forecast', target:78},
tact: {kpi:'Docker stack', val:'17', unit:'up', d:0, src:'trend', target:89},
op: {kpi:'Disk usage', val:'88', unit:'%', d:+1, src:'live', target:72},
infra:{kpi:'Ollama/Qdrant', val:'UP', unit:'', d:0, src:'live', target:98}
}},
{ id:'s95', name:'S95 Legacy', system:'INFRA LEGACY', tax:'infra',
preds:{
strat:{kpi:'Decomm plan', val:'none', unit:'', d:0, src:'forecast', target:70},
tact: {kpi:'Cron actifs', val:'38', unit:'', d:+1, src:'trend', target:82},
op: {kpi:'PostgreSQL', val:'5432', unit:'', d:0, src:'live', target:94},
infra:{kpi:'Sentinel-lite', val:'ARMED',unit:'', d:0, src:'live', target:97}
}},
{ id:'devops', name:'DevOps & Quality', system:'QUALITY', tax:'infra',
preds:{
strat:{kpi:'DORA élite', val:'95', unit:'%', d:+1.8, src:'forecast', target:85},
tact: {kpi:'Deploy freq.', val:'8/d', unit:'', d:+1, src:'trend', target:89},
op: {kpi:'L99 / NonReg', val:'304/200',unit:'', d:0, src:'live', target:93},
infra:{kpi:'Git + Gitea sync', val:'OK', unit:'', d:0, src:'live', target:97}
}},
{ id:'secpart', name:'Security & Partners', system:'SEC + PARTNERS', tax:'partner',
preds:{
strat:{kpi:'Partners 6', val:'6', unit:'act',d:0, src:'forecast', target:79},
tact: {kpi:'Vuln. patch', val:'92', unit:'%', d:+1.4, src:'trend', target:87},
op: {kpi:'CrowdSec bans', val:'0', unit:'wl', d:0, src:'live', target:94},
infra:{kpi:'SSL validity', val:'100', unit:'%', d:0, src:'live', target:99}
}}
]}
];
const LEVELS = ['strat','tact','op','infra'];
function deltaHTML(d){
if(d === 0 || d === '0') return `<span class="delta flat">▬ 0</span>`;
const n = typeof d === 'string' ? d : (d>0?`+${d}`:`${d}`);
const sign = (typeof d === 'number' ? d : parseFloat(d)) || 0;
if(sign > 0) return `<span class="delta up">▲ ${n}</span>`;
if(sign < 0) return `<span class="delta down">▼ ${n}</span>`;
return `<span class="delta flat">▬ ${n}</span>`;
}
/* === Matrix render (grouped by pillar) === */
function renderMatrix(){
const m = document.getElementById('matrix');
PILLARS.forEach(pillar => {
const sep = document.createElement('div');
sep.className = 'mx-pillar-row';
sep.dataset.pillar = pillar.id;
sep.innerHTML = `<span>${pillar.label}</span><span class="line"></span><span style="color:var(--tx-4);font-size:9px">${pillar.domains.length} dom</span>`;
m.appendChild(sep);
pillar.domains.forEach(d => {
const name = document.createElement('div');
name.className = 'dept-name';
name.innerHTML = `<span>${d.name}</span><span class="system-badge" data-tax="${d.tax}">${d.system}</span>`;
m.appendChild(name);
LEVELS.forEach(lv => {
const p = d.preds[lv];
const cell = document.createElement('div');
cell.className = 'cell';
cell.dataset.level = lv;
cell.dataset.dept = d.id;
cell.setAttribute('role','button');
cell.setAttribute('tabindex','0');
cell.setAttribute('aria-label', `${d.name} · ${lv} · ${p.kpi} ${p.val}${p.unit}`);
cell.innerHTML = `
<div class="heat"></div>
<span class="src-badge" data-src="${p.src}">${p.src}</span>
<div class="kpi">${p.kpi}</div>
<div class="val">${p.val}${p.unit?`<small>${p.unit}</small>`:''}</div>
${deltaHTML(p.d)}
`;
m.appendChild(cell);
});
});
});
}
/* === Sparkline generator === */
function seedRand(str){
let h = 2166136261;
for(let i=0;i<str.length;i++){ h ^= str.charCodeAt(i); h = (h*16777619) >>> 0; }
return () => { h = (h*48271) % 0x7fffffff; return (h & 0xffffff) / 0xffffff; };
}
function sparkPath(id, w=280, h=48, points=24, trend='up'){
const rnd = seedRand(id);
const pts = [];
let v = 0.5 + rnd()*0.2;
for(let i=0;i<points;i++){
const drift = (trend==='up' ? 0.02 : trend==='down' ? -0.02 : 0);
v = Math.max(0.08, Math.min(0.92, v + drift + (rnd()-0.5)*0.15));
pts.push(v);
}
const xs = pts.map((_,i) => (i/(points-1)) * w);
const ys = pts.map(p => h - p*h*0.85 - h*0.07);
const linePath = xs.map((x,i)=>`${i===0?'M':'L'}${x.toFixed(1)},${ys[i].toFixed(1)}`).join(' ');
const areaPath = linePath + ` L${w},${h} L0,${h} Z`;
return { linePath, areaPath, lastX: xs[xs.length-1], lastY: ys[ys.length-1] };
}
/* === Dept cards grouped by pillar === */
function renderDeptCards(){
const root = document.getElementById('deptgroups');
PILLARS.forEach(pillar => {
const group = document.createElement('div');
group.className = 'pgroup';
group.dataset.pillar = pillar.id;
// pillar aggregate score from its 4 domains
let agg = 0, total = 0;
pillar.domains.forEach(d => LEVELS.forEach(lv => { agg += d.preds[lv].target||80; total++; }));
const pScore = Math.round(agg/total);
group.innerHTML = `
<div class="pgroup-head">
<span class="num">${PILLARS.indexOf(pillar)+1}</span>
<span class="lbl">${pillar.label}</span>
<span class="desc">${pillar.desc}</span>
<span class="score"><span>score</span><b>${pScore}/100</b></span>
</div>
<div class="deptgrid"></div>
`;
const grid = group.querySelector('.deptgrid');
pillar.domains.forEach(d => {
const avgDelta = LEVELS.reduce((s,lv) => {
const val = d.preds[lv].d;
const n = typeof val === 'number' ? val : parseFloat(val) || 0;
return s + (n>0?1:n<0?-1:0);
}, 0);
const statusClass = avgDelta >= 2 ? '' : avgDelta <= -2 ? 'bad' : 'warn';
const statusTxt = avgDelta >= 2 ? 'STABLE' : avgDelta <= -2 ? 'RISK' : 'WATCH';
const sp = sparkPath(d.id, 320, 50, 26, avgDelta>=0?'up':'down');
const gradId = `gsp-${d.id}`;
const card = document.createElement('article');
card.className = 'dcard reveal';
card.innerHTML = `
<div class="dcard-head">
<div class="dname">
<span class="nm">${d.name}</span>
<span class="system-badge" data-tax="${d.tax}">${d.system}</span>
</div>
<span class="status ${statusClass}">${statusTxt}</span>
</div>
<div class="dcard-spark">
<svg viewBox="0 0 320 50" preserveAspectRatio="none">
<defs>
<linearGradient id="${gradId}" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stop-color="#22d3ee" stop-opacity="0.35"/>
<stop offset="100%" stop-color="#22d3ee" stop-opacity="0"/>
</linearGradient>
</defs>
<path d="${sp.areaPath}" fill="url(#${gradId})"/>
<path d="${sp.linePath}" fill="none" stroke="#22d3ee" stroke-width="1.5" stroke-linejoin="round"/>
<circle cx="${sp.lastX}" cy="${sp.lastY}" r="2.5" fill="#22d3ee"/>
</svg>
</div>
<div class="dcard-preds">
${LEVELS.map(lv => {
const p = d.preds[lv];
const lvName = {strat:'Strat', tact:'Tact', op:'Op', infra:'Infra'}[lv];
const pct = Math.max(8, Math.min(98, p.target));
return `
<div class="pred" data-level="${lv}">
<div class="pred-head">
<span class="lv"><span class="d"></span>${lvName}</span>
<span class="src ${p.src}">${p.src}</span>
</div>
<div class="pred-kpi">${p.kpi}</div>
<div class="pred-val">${p.val}${p.unit?`<small>${p.unit}</small>`:''}</div>
<div class="pred-bullet" title="vs. target: ${pct}%">
<div class="fill" style="width:${pct}%"></div>
<div class="target" style="left:${pct}%"></div>
</div>
</div>`;
}).join('')}
</div>
`;
grid.appendChild(card);
});
root.appendChild(group);
});
}
/* === Counters === */
function renderCounters(){
const src = { live:0, trend:0, forecast:0, todo:0 };
const tax = { wevia:0, native:0, sap:0, hybrid:0, partner:0, infra:0 };
PILLARS.forEach(p => p.domains.forEach(d => {
tax[d.tax] = (tax[d.tax]||0) + 4; // 4 cells per domain carry the domain tax
LEVELS.forEach(lv => { src[d.preds[lv].src]++; });
}));
document.getElementById('cnt-live').textContent = src.live;
document.getElementById('cnt-trend').textContent = src.trend;
document.getElementById('cnt-forecast').textContent = src.forecast;
document.getElementById('cnt-todo').textContent = src.todo;
document.getElementById('tax-wevia').textContent = tax.wevia;
document.getElementById('tax-native').textContent = tax.native;
document.getElementById('tax-sap').textContent = tax.sap;
document.getElementById('tax-hybrid').textContent = tax.hybrid;
document.getElementById('tax-partner').textContent = tax.partner;
document.getElementById('tax-infra').textContent = tax.infra;
}
function renderTS(){
const now = new Date();
const fmt = now.toISOString().replace('T',' ').slice(0,19) + ' UTC';
document.getElementById('ts-now').textContent = fmt;
}
async function safeFetch(url, timeoutMs=2500){
try{
const c = new AbortController();
const t = setTimeout(()=>c.abort(), timeoutMs);
const r = await fetch(url, { signal: c.signal });
clearTimeout(t);
if(!r.ok) return null;
return await r.json();
}catch(e){ return null; }
}
async function refreshLive(){
const endpoints = [
'/api/dsh-predict-api.php',
'/api/l99-health.php',
'/api/ecosystem-health.php',
'/api/wevads-brain.php'
];
for(const ep of endpoints){
const data = await safeFetch(ep);
if(data && Array.isArray(data.predictions)){
data.predictions.forEach(p => {
PILLARS.forEach(pl => pl.domains.forEach(d => {
if(d.id === p.dept && d.preds[p.level]){
Object.assign(d.preds[p.level], p);
}
}));
});
}
}
renderTS();
}
document.addEventListener('DOMContentLoaded', () => {
renderMatrix();
renderDeptCards();
renderCounters();
renderTS();
refreshLive();
setInterval(() => { renderTS(); refreshLive(); }, 30000);
});
</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>