530 lines
38 KiB
HTML
530 lines
38 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>WEVAL Growth Engine</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif&family=Syne:wght@400;600;700;800&family=IBM+Plex+Mono:wght@400;600&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root{
|
|
--void:#05060a;--depth:#0a0c14;--surface:#0f1220;--elevated:#151a2e;--glass:rgba(18,22,42,0.6);
|
|
--text:#e8eaf6;--text2:#8892b8;--text3:#4a5278;
|
|
--gold:#e8b84b;--gold2:#d4a33a;--emerald:#34d399;--ruby:#f43f5e;--sapphire:#3b82f6;--amethyst:#a78bfa;--coral:#fb923c;--ice:#67e8f9;
|
|
--border:rgba(255,255,255,0.04);--glow:rgba(232,184,75,0.08);
|
|
--radius:16px;--radius-sm:10px;
|
|
}
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
body{background:var(--void);color:var(--text);font-family:'Syne',sans-serif;overflow-x:hidden;min-height:100vh}
|
|
::selection{background:var(--gold);color:var(--void)}
|
|
::-webkit-scrollbar{width:6px}
|
|
::-webkit-scrollbar-track{background:transparent}
|
|
::-webkit-scrollbar-thumb{background:var(--text3);border-radius:3px}
|
|
|
|
/* ═══ AMBIENT BACKGROUND ═══ */
|
|
.ambient{position:fixed;inset:0;pointer-events:none;z-index:0}
|
|
.ambient .orb{position:absolute;border-radius:50%;filter:blur(120px);opacity:0.15;animation:drift 20s ease-in-out infinite}
|
|
.ambient .orb:nth-child(1){width:600px;height:600px;background:var(--gold);top:-200px;right:-100px;animation-delay:0s}
|
|
.ambient .orb:nth-child(2){width:500px;height:500px;background:var(--sapphire);bottom:-150px;left:-100px;animation-delay:-7s}
|
|
.ambient .orb:nth-child(3){width:400px;height:400px;background:var(--amethyst);top:40%;left:50%;animation-delay:-14s}
|
|
@keyframes drift{0%,100%{transform:translate(0,0) scale(1)}33%{transform:translate(40px,-30px) scale(1.1)}66%{transform:translate(-20px,40px) scale(0.9)}}
|
|
.noise{position:fixed;inset:0;pointer-events:none;z-index:1;opacity:0.03;background:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
|
|
|
|
/* ═══ NAV ═══ */
|
|
.topbar{position:sticky;top:0;z-index:100;display:flex;align-items:center;padding:0 32px;height:56px;background:rgba(5,6,10,0.85);backdrop-filter:blur(20px) saturate(1.5);border-bottom:1px solid var(--border)}
|
|
.topbar .brand{font-family:'Instrument Serif',serif;font-size:1.4em;color:var(--gold);letter-spacing:-0.5px;margin-right:32px;white-space:nowrap}
|
|
.topbar .brand span{font-family:'Syne',sans-serif;font-size:0.5em;font-weight:700;color:var(--text3);text-transform:uppercase;letter-spacing:3px;vertical-align:middle;margin-left:8px}
|
|
.tabs{display:flex;gap:2px;flex:1}
|
|
.tab{padding:8px 18px;font-size:0.78em;font-weight:600;color:var(--text3);cursor:pointer;border-radius:8px;transition:all 0.25s;position:relative;letter-spacing:0.3px}
|
|
.tab:hover{color:var(--text2);background:rgba(255,255,255,0.03)}
|
|
.tab.active{color:var(--gold)}
|
|
.tab.active::after{content:'';position:absolute;bottom:-1px;left:20%;right:20%;height:2px;background:var(--gold);border-radius:2px}
|
|
.scan-btn{display:flex;align-items:center;gap:6px;padding:8px 20px;border:1px solid rgba(232,184,75,0.3);border-radius:100px;background:rgba(232,184,75,0.06);color:var(--gold);font-family:'Syne',sans-serif;font-size:0.75em;font-weight:700;cursor:pointer;transition:all 0.3s;letter-spacing:0.5px;text-transform:uppercase}
|
|
.scan-btn:hover{background:rgba(232,184,75,0.12);border-color:rgba(232,184,75,0.5);box-shadow:0 0 30px rgba(232,184,75,0.1)}
|
|
.scan-btn .ico{font-size:1.2em;transition:transform 0.6s}
|
|
.scan-btn:hover .ico{transform:rotate(180deg)}
|
|
|
|
/* ═══ LAYOUT ═══ */
|
|
.shell{display:flex;min-height:calc(100vh - 56px);position:relative;z-index:2}
|
|
.sidebar{width:260px;background:rgba(10,12,20,0.5);backdrop-filter:blur(10px);border-right:1px solid var(--border);padding:20px 0;overflow-y:auto;flex-shrink:0}
|
|
.main{flex:1;padding:28px 32px;overflow-y:auto;max-height:calc(100vh - 56px)}
|
|
|
|
/* ═══ SIDEBAR ═══ */
|
|
.sb-label{padding:0 20px;font-size:0.58em;text-transform:uppercase;letter-spacing:3px;color:var(--text3);font-weight:700;margin:20px 0 8px}
|
|
.sb-label:first-child{margin-top:0}
|
|
.sb-row{display:flex;align-items:center;gap:10px;padding:7px 20px;cursor:pointer;transition:all 0.2s;font-size:0.82em;color:var(--text2);position:relative}
|
|
.sb-row:hover{background:rgba(255,255,255,0.02);color:var(--text)}
|
|
.sb-row.active{color:var(--gold)}
|
|
.sb-row.active::before{content:'';position:absolute;left:0;top:4px;bottom:4px;width:2px;background:var(--gold);border-radius:0 2px 2px 0}
|
|
.sb-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}
|
|
.sb-rev{margin-left:auto;font-family:'IBM Plex Mono',monospace;font-size:0.72em;opacity:0.6}
|
|
.sb-divider{height:1px;background:var(--border);margin:12px 20px}
|
|
|
|
/* ═══ KPI ROW ═══ */
|
|
.kpis{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:28px}
|
|
.kpi{background:var(--glass);backdrop-filter:blur(12px);border:1px solid var(--border);border-radius:var(--radius-sm);padding:18px 16px;position:relative;overflow:hidden;transition:border-color 0.3s}
|
|
.kpi:hover{border-color:rgba(232,184,75,0.2)}
|
|
.kpi::before{content:'';position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,rgba(255,255,255,0.06),transparent)}
|
|
.kpi .val{font-family:'IBM Plex Mono',monospace;font-size:1.5em;font-weight:600;line-height:1.2}
|
|
.kpi .label{font-size:0.62em;text-transform:uppercase;letter-spacing:2px;color:var(--text3);margin-top:6px;font-weight:600}
|
|
.kpi .trend{font-size:0.68em;margin-top:4px;font-family:'IBM Plex Mono',monospace}
|
|
.up{color:var(--emerald)}.down{color:var(--ruby)}
|
|
|
|
/* ═══ GLASS CARDS ═══ */
|
|
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(380px,1fr));gap:16px;margin-bottom:28px}
|
|
.glass{background:var(--glass);backdrop-filter:blur(16px);border:1px solid var(--border);border-radius:var(--radius);padding:24px;position:relative;overflow:hidden;transition:all 0.35s;opacity:0;transform:translateY(20px);animation:reveal 0.6s ease forwards}
|
|
.glass:nth-child(1){animation-delay:0.05s}.glass:nth-child(2){animation-delay:0.1s}.glass:nth-child(3){animation-delay:0.15s}.glass:nth-child(4){animation-delay:0.2s}.glass:nth-child(5){animation-delay:0.25s}.glass:nth-child(6){animation-delay:0.3s}
|
|
@keyframes reveal{to{opacity:1;transform:translateY(0)}}
|
|
.glass:hover{border-color:rgba(232,184,75,0.15);transform:translateY(-3px);box-shadow:0 20px 60px rgba(0,0,0,0.3),0 0 40px var(--glow)}
|
|
.glass::before{content:'';position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,rgba(255,255,255,0.08),transparent)}
|
|
.glass .badge{position:absolute;top:18px;right:18px;font-size:0.58em;padding:4px 12px;border-radius:100px;font-weight:700;letter-spacing:1px;text-transform:uppercase}
|
|
.b-live{background:rgba(52,211,153,0.1);color:var(--emerald);border:1px solid rgba(52,211,153,0.2)}
|
|
.b-ready{background:rgba(59,130,246,0.1);color:var(--sapphire);border:1px solid rgba(59,130,246,0.2)}
|
|
.b-plan{background:rgba(232,184,75,0.1);color:var(--gold);border:1px solid rgba(232,184,75,0.2)}
|
|
.b-idea{background:rgba(167,139,250,0.1);color:var(--amethyst);border:1px solid rgba(167,139,250,0.2)}
|
|
.glass .g-icon{width:44px;height:44px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:1.4em;margin-bottom:14px}
|
|
.glass .g-title{font-size:1.05em;font-weight:700;margin-bottom:4px;letter-spacing:-0.3px}
|
|
.glass .g-sub{font-size:0.72em;color:var(--text3);margin-bottom:12px}
|
|
.glass .g-desc{font-size:0.8em;color:var(--text2);line-height:1.65;margin-bottom:16px}
|
|
.glass .g-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(70px,1fr));gap:8px;padding-top:14px;border-top:1px solid var(--border)}
|
|
.g-metric{text-align:center}
|
|
.g-metric .mv{font-family:'IBM Plex Mono',monospace;font-size:0.95em;font-weight:600}
|
|
.g-metric .ml{font-size:0.55em;text-transform:uppercase;letter-spacing:1.5px;color:var(--text3);margin-top:2px}
|
|
|
|
/* ═══ ACTIONS ═══ */
|
|
.act{display:flex;align-items:flex-start;gap:12px;padding:10px 14px;border-radius:var(--radius-sm);margin-bottom:4px;transition:all 0.2s;cursor:pointer;border:1px solid transparent}
|
|
.act:hover{background:rgba(255,255,255,0.02);border-color:var(--border)}
|
|
.act .ck{width:18px;height:18px;border:1.5px solid var(--text3);border-radius:5px;flex-shrink:0;display:flex;align-items:center;justify-content:center;transition:all 0.25s;margin-top:1px;font-size:0.7em}
|
|
.act .ck.done{background:var(--emerald);border-color:var(--emerald);color:var(--void)}
|
|
.act .at{flex:1;font-size:0.8em;color:var(--text2);line-height:1.5}
|
|
.act .aw{font-family:'IBM Plex Mono',monospace;font-size:0.6em;padding:3px 10px;border-radius:100px;white-space:nowrap}
|
|
|
|
/* ═══ CHAT ═══ */
|
|
.chat-box{background:var(--glass);backdrop-filter:blur(16px);border:1px solid var(--border);border-radius:var(--radius);margin-bottom:28px;overflow:hidden}
|
|
.chat-header{padding:14px 20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;font-size:0.85em;font-weight:700}
|
|
.chat-header .live{width:8px;height:8px;border-radius:50%;background:var(--emerald);animation:glow 2s infinite}
|
|
@keyframes glow{0%,100%{box-shadow:0 0 4px var(--emerald)}50%{box-shadow:0 0 12px var(--emerald),0 0 24px rgba(52,211,153,0.3)}}
|
|
.chat-body{max-height:320px;overflow-y:auto;padding:16px 20px}
|
|
.msg{padding:10px 16px;margin-bottom:8px;border-radius:12px;font-size:0.8em;line-height:1.6;max-width:85%;animation:msgIn 0.3s ease}
|
|
@keyframes msgIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
|
|
.msg.u{background:rgba(232,184,75,0.08);border:1px solid rgba(232,184,75,0.15);margin-left:auto;color:var(--gold)}
|
|
.msg.a{background:rgba(255,255,255,0.03);border:1px solid var(--border);color:var(--text2)}
|
|
.chat-input{display:flex;gap:8px;padding:12px 20px;border-top:1px solid var(--border);background:rgba(0,0,0,0.2)}
|
|
.chat-input input{flex:1;background:rgba(255,255,255,0.03);border:1px solid var(--border);border-radius:100px;padding:10px 18px;color:var(--text);font-family:'Syne',sans-serif;font-size:0.82em;transition:border-color 0.3s}
|
|
.chat-input input:focus{outline:none;border-color:rgba(232,184,75,0.4)}
|
|
.chat-input input::placeholder{color:var(--text3)}
|
|
.chat-input button{padding:10px 24px;border-radius:100px;background:var(--gold);color:var(--void);font-weight:700;border:none;cursor:pointer;font-family:'Syne',sans-serif;font-size:0.78em;letter-spacing:0.5px;transition:all 0.25s}
|
|
.chat-input button:hover{box-shadow:0 0 20px rgba(232,184,75,0.3);transform:scale(1.03)}
|
|
|
|
/* ═══ PIPELINE ═══ */
|
|
.pipe-row{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:28px}
|
|
.pipe-col{background:var(--glass);backdrop-filter:blur(12px);border:1px solid var(--border);border-radius:var(--radius-sm);padding:16px;min-height:200px}
|
|
.pipe-col .ph{font-size:0.6em;text-transform:uppercase;letter-spacing:2.5px;font-weight:700;margin-bottom:6px;display:flex;align-items:center;gap:6px}
|
|
.pipe-col .pn{font-family:'IBM Plex Mono',monospace;font-size:2em;font-weight:600;margin-bottom:10px;line-height:1}
|
|
.pipe-item{padding:8px 12px;background:rgba(255,255,255,0.02);border-radius:8px;font-size:0.78em;margin-bottom:4px;border-left:2px solid var(--text3);color:var(--text2);cursor:pointer;transition:all 0.2s}
|
|
.pipe-item:hover{background:rgba(255,255,255,0.04);border-left-color:var(--gold);color:var(--text)}
|
|
|
|
/* ═══ INTEL ═══ */
|
|
.intel{background:var(--glass);backdrop-filter:blur(12px);border:1px solid var(--border);border-radius:var(--radius-sm);padding:18px;position:relative;overflow:hidden}
|
|
.intel .it{position:absolute;top:14px;right:14px;font-size:0.55em;padding:3px 10px;border-radius:100px;font-weight:700;text-transform:uppercase;letter-spacing:1px}
|
|
.t-opp{background:rgba(52,211,153,0.08);color:var(--emerald);border:1px solid rgba(52,211,153,0.2)}
|
|
.t-thr{background:rgba(244,63,94,0.08);color:var(--ruby);border:1px solid rgba(244,63,94,0.2)}
|
|
.t-trd{background:rgba(103,232,249,0.08);color:var(--ice);border:1px solid rgba(103,232,249,0.2)}
|
|
.intel .ih{font-weight:700;font-size:0.88em;margin-bottom:6px;padding-right:80px;letter-spacing:-0.2px}
|
|
.intel .ib{font-size:0.76em;color:var(--text2);line-height:1.6}
|
|
.intel .id{font-family:'IBM Plex Mono',monospace;font-size:0.6em;color:var(--text3);margin-top:8px}
|
|
|
|
/* ═══ ASSETS ═══ */
|
|
.asset-section{margin-bottom:24px}
|
|
.asset-section .as-title{font-size:0.6em;text-transform:uppercase;letter-spacing:2.5px;color:var(--text3);font-weight:700;margin-bottom:10px}
|
|
.asset-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:6px}
|
|
.asset{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:8px;font-size:0.76em;color:var(--text2);background:rgba(255,255,255,0.015);border:1px solid transparent;transition:all 0.2s;cursor:pointer}
|
|
.asset:hover{background:rgba(255,255,255,0.03);border-color:var(--border);color:var(--text)}
|
|
.asset .ad{width:5px;height:5px;border-radius:50%;flex-shrink:0}
|
|
|
|
/* SECTION */
|
|
.stitle{font-family:'Instrument Serif',serif;font-size:1.6em;letter-spacing:-0.5px;margin-bottom:4px}
|
|
.ssub{font-size:0.78em;color:var(--text3);margin-bottom:24px}
|
|
|
|
/* WEEK HEADER */
|
|
.week-head{font-weight:700;font-size:0.88em;color:var(--gold);margin:20px 0 10px;padding-bottom:6px;border-bottom:1px solid var(--border);letter-spacing:-0.2px}
|
|
|
|
/* TABS */
|
|
.panel{display:none}.panel.on{display:block}
|
|
|
|
/* RESPONSIVE */
|
|
@media(max-width:1024px){.sidebar{display:none}.kpis{grid-template-columns:repeat(3,1fr)}.grid{grid-template-columns:1fr}.pipe-row{grid-template-columns:repeat(2,1fr)}}
|
|
@media(max-width:600px){.kpis{grid-template-columns:repeat(2,1fr)}.pipe-row{grid-template-columns:1fr}.tabs{display:none}}
|
|
|
|
/* === OPUS RESPONSIVE FIX v2 19avr — append-only, doctrine #14 === */
|
|
@media(max-width: 480px) {
|
|
html, body { overflow-x: hidden !important; max-width: 100vw; }
|
|
body, main, section, article { word-break: break-word; overflow-wrap: anywhere; }
|
|
img, video, iframe, canvas, svg, table, pre, code { max-width: 100% !important; }
|
|
pre, code { white-space: pre-wrap; word-break: break-all; }
|
|
table { display: block; overflow-x: auto; }
|
|
.container, [class*="container"], [class*="wrapper"] { max-width: 100vw !important; padding-left: 12px !important; padding-right: 12px !important; }
|
|
[class*="grid"], [class*="-grid"] { grid-template-columns: 1fr !important; gap: 10px !important; }
|
|
[class*="kpi"], [class*="stats"], [class*="-cards"] { grid-template-columns: 1fr !important; }
|
|
header, nav, footer { flex-wrap: wrap !important; }
|
|
header > *, nav > *, footer > * { max-width: 100%; }
|
|
h1 { font-size: 22px !important; word-break: break-word; }
|
|
h2 { font-size: 18px !important; }
|
|
.pitch, [class*="pitch"], [class*="hero"] { word-break: break-word; overflow-wrap: anywhere; }
|
|
}
|
|
/* === OPUS RESPONSIVE FIX v2 END === */
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="ambient"><div class="orb"></div><div class="orb"></div><div class="orb"></div></div>
|
|
<div class="noise"></div>
|
|
|
|
<nav class="topbar">
|
|
<div class="brand">Growth Engine <span>WEVAL</span></div>
|
|
<div class="tabs">
|
|
<div class="tab active" data-t="dashboard">Dashboard</div>
|
|
<div class="tab" data-t="opportunities">Opportunités</div>
|
|
<div class="tab" data-t="pipeline">Pipeline</div>
|
|
<div class="tab" data-t="actions">Plan 90J</div>
|
|
<div class="tab" data-t="assets">Assets</div>
|
|
<div class="tab" data-t="intel">Market Intel</div>
|
|
</div>
|
|
<button class="scan-btn" onclick="runScan()"><span class="ico">⟳</span> Scan & Propose</button>
|
|
</nav>
|
|
|
|
<div class="shell">
|
|
<aside class="sidebar">
|
|
<div class="sb-label">Opportunités Revenue</div>
|
|
<div class="sb-row active"><div class="sb-dot" style="background:var(--emerald)"></div>Ethica Pharma Email<div class="sb-rev" style="color:var(--emerald)">600K</div></div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--sapphire)"></div>API HCP Maghreb<div class="sb-rev">300K</div></div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--amethyst)"></div>WeviaAI SaaS<div class="sb-rev">200K</div></div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--gold)"></div>Consulting SAP/IA<div class="sb-rev">150K</div></div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--ice)"></div>White-label WEVIA<div class="sb-rev">80K</div></div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--coral)"></div>Formation IA PME<div class="sb-rev">60K</div></div>
|
|
<div class="sb-divider"></div>
|
|
<div class="sb-label">Écosystème connecté</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--emerald)"></div>WEVIA Master</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--emerald)"></div>WEVIA Arena</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--emerald)"></div>WEVADS Arsenal</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--emerald)"></div>Ethica B2B</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--emerald)"></div>Brain Engine</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--emerald)"></div>WeDroid Agent</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--emerald)"></div>WEVIA Life App</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--sapphire)"></div>Twenty CRM</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--sapphire)"></div>Plausible Analytics</div>
|
|
<div class="sb-divider"></div>
|
|
<div class="sb-label">IA Souveraine</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--emerald)"></div>Ollama 5 modèles</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--emerald)"></div>Cerebras 235B</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--emerald)"></div>Groq 70B</div>
|
|
<div class="sb-row"><div class="sb-dot" style="background:var(--sapphire)"></div>+4 providers free</div>
|
|
</aside>
|
|
|
|
<main class="main">
|
|
|
|
<!-- ═══ DASHBOARD ═══ -->
|
|
<div class="panel on" id="p-dashboard">
|
|
<div class="stitle">Growth Dashboard</div>
|
|
<div class="ssub">Vue consolidée · Enrichissement automatique · Propositions IA en continu</div>
|
|
|
|
<div class="kpis">
|
|
<div class="kpi"><div class="val" style="color:var(--gold)">0 <span style="font-size:0.5em">MAD</span></div><div class="label">Revenu mensuel</div><div class="trend down">Objectif 1.4M</div></div>
|
|
<div class="kpi"><div class="val" style="color:var(--emerald)">6</div><div class="label">Opportunités</div><div class="trend up">↑ +3 cette sem.</div></div>
|
|
<div class="kpi"><div class="val" style="color:var(--sapphire)" id="kAct">0/24</div><div class="label">Actions faites</div><div class="trend">Semaine 1</div></div>
|
|
<div class="kpi"><div class="val" style="color:var(--ice)">88</div><div class="label">Apps SaaS</div><div class="trend up">Catalogue actif</div></div>
|
|
<div class="kpi"><div class="val" style="color:var(--amethyst)">141K+</div><div class="label">HCP Maghreb</div><div class="trend up">↑ enrichi continu</div></div>
|
|
<div class="kpi"><div class="val" style="color:var(--coral)">12</div><div class="label">Providers IA</div><div class="trend">0€ coût API</div></div>
|
|
</div>
|
|
|
|
<div class="chat-box">
|
|
<div class="chat-header"><div class="live"></div>WEVIA Master — Growth Advisor</div>
|
|
<div class="chat-body" id="chatBody">
|
|
<div class="msg a">Connecté au Growth Engine. Je scanne vos 88 SaaS, 141K+ HCPs, 416 APIs et le marché pour proposer des actions de monétisation. Posez votre question stratégique.</div>
|
|
</div>
|
|
<div class="chat-input">
|
|
<input id="chatIn" placeholder="Analyse le marché, propose un pricing, plan commercial..." onkeydown="if(event.key==='Enter')sendChat()">
|
|
<button onclick="sendChat()">Envoyer</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="stitle" style="font-size:1.1em">Pipeline Commercial</div>
|
|
<div class="pipe-row">
|
|
<div class="pipe-col"><div class="ph" style="color:var(--amethyst)">◆ Idées</div><div class="pn">12</div><div class="pipe-item">Formation IA cliniques</div><div class="pipe-item">Newsletter HCP payante</div><div class="pipe-item">Marketplace plugins</div></div>
|
|
<div class="pipe-col"><div class="ph" style="color:var(--gold)">◆ Planifié</div><div class="pn">6</div><div class="pipe-item">API HCP Maghreb</div><div class="pipe-item">WeviaAI SaaS freemium</div><div class="pipe-item">White-label cabinets</div></div>
|
|
<div class="pipe-col"><div class="ph" style="color:var(--sapphire)">◆ En cours</div><div class="pn">3</div><div class="pipe-item">Ethica — 3 labos pilotes</div><div class="pipe-item">Consulting Vistex SAP</div><div class="pipe-item">Arrow/Scaleway</div></div>
|
|
<div class="pipe-col"><div class="ph" style="color:var(--emerald)">◆ Signé</div><div class="pn">0</div><div class="pipe-item" style="opacity:0.3;border-left-color:var(--text3)">En attente 1er contrat</div></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══ OPPORTUNITIES ═══ -->
|
|
<div class="panel" id="p-opportunities">
|
|
<div class="stitle">Opportunités de Monétisation</div>
|
|
<div class="ssub">Classées par revenu potentiel · Enrichies par WEVIA Master · Actions trackées</div>
|
|
<div class="grid" id="oppGrid"></div>
|
|
</div>
|
|
|
|
<!-- ═══ PIPELINE ═══ -->
|
|
<div class="panel" id="p-pipeline">
|
|
<div class="stitle">Pipeline Commercial</div>
|
|
<div class="ssub">Du sourcing au closing · Intégré Twenty CRM</div>
|
|
<div class="pipe-row" style="min-height:300px">
|
|
<div class="pipe-col"><div class="ph" style="color:var(--amethyst)">◆ Idées</div><div class="pn">12</div><div class="pipe-item">Formation IA cliniques</div><div class="pipe-item">Newsletter HCP payante</div><div class="pipe-item">Marketplace plugins IA</div><div class="pipe-item">Reseller programme</div><div class="pipe-item">Data as a Service</div></div>
|
|
<div class="pipe-col"><div class="ph" style="color:var(--gold)">◆ Planifié</div><div class="pn">6</div><div class="pipe-item">API HCP Maghreb</div><div class="pipe-item">WeviaAI SaaS</div><div class="pipe-item">White-label cabinets</div><div class="pipe-item">Landing WeviaAI.ma</div><div class="pipe-item">Webinaire PME</div></div>
|
|
<div class="pipe-col"><div class="ph" style="color:var(--sapphire)">◆ En cours</div><div class="pn">3</div><div class="pipe-item">Ethica — 3 labos pilotes</div><div class="pipe-item">Vistex SAP Morocco</div><div class="pipe-item">Arrow/Scaleway onboard</div></div>
|
|
<div class="pipe-col"><div class="ph" style="color:var(--emerald)">◆ Signé</div><div class="pn">0</div><div class="pipe-item" style="opacity:0.3">1er contrat en attente</div></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══ ACTIONS ═══ -->
|
|
<div class="panel" id="p-actions">
|
|
<div class="stitle">Plan d'Action — 90 Jours</div>
|
|
<div class="ssub">Semaine par semaine · Trackées · Connectées aux apps WEVAL</div>
|
|
<div id="actView"></div>
|
|
</div>
|
|
|
|
<!-- ═══ ASSETS ═══ -->
|
|
<div class="panel" id="p-assets">
|
|
<div class="stitle">Assets Map — Écosystème WEVAL</div>
|
|
<div class="ssub">88 apps SaaS · 417 APIs · 14 subdomains · 17 services · 12 providers IA</div>
|
|
<div id="assView"></div>
|
|
</div>
|
|
|
|
<!-- ═══ INTEL ═══ -->
|
|
<div class="panel" id="p-intel">
|
|
<div class="stitle">Market Intelligence</div>
|
|
<div class="ssub">Scan automatique quotidien · Tendances · Opportunités · Menaces</div>
|
|
<div class="grid" id="intGrid"></div>
|
|
</div>
|
|
|
|
</main>
|
|
</div>
|
|
|
|
<script>
|
|
const OPP=[
|
|
{id:1,n:"Ethica Pharma Email",ico:"💊",clr:"var(--emerald)",st:"live",rev:"600K MAD/mois",delay:"Immédiat",invest:"0 MAD",
|
|
desc:"Campagnes email ciblées pour laboratoires pharmaceutiques. 141K+ médecins Maghreb. Brain Engine auto-optimise. Concurrent: 3000€ / 15% open — nous visons 28-35%.",
|
|
m:{HCP:"141K+","Open Rate":"28-35%","Concurrent":"15%","Pricing":"2.5-8K€"},
|
|
acts:["Segmenter HCP: cardio, diabéto, dermo","Configurer 3 templates Starter/Pro/Premium","Contacter Kaouther — co-prospection TN/DZ","Appeler Biopharm, Centropharm, Sigma"],
|
|
apps:"WEVADS · Brain Engine · Ethica B2B · WEVIA Life · PowerMTA"},
|
|
{id:2,n:"API HCP Maghreb",ico:"🔌",clr:"var(--sapphire)",st:"ready",rev:"300K MAD/mois",delay:"4 semaines",invest:"20h dev",
|
|
desc:"API-as-a-Service: 141K+ médecins validés. Endpoints search/match/stats/export. Cibles: HealthTech, assurances, éditeurs médicaux.",
|
|
m:{Endpoints:"5","HCP":"141K+","Pricing":"0-499€",Distrib:"RapidAPI"},
|
|
acts:["Générer OpenAPI spec depuis ethica.medecins","Déployer api.weval.ma sur S204","Publier sur RapidAPI freemium","Contacter 5 HealthTech"],
|
|
apps:"Ethica B2B · API Gateway · Qdrant RAG"},
|
|
{id:3,n:"WeviaAI SaaS PME",ico:"🤖",clr:"var(--amethyst)",st:"plan",rev:"200K MAD/mois",delay:"8 semaines",invest:"40h dev",
|
|
desc:"IA souveraine en SaaS pour PME marocaines. Zero coût API. Chatbot 9 langues, PDF/PPT, RAG, code exec, vision OCR. Souveraineté données.",
|
|
m:{Models:"12",Langues:"9","Coût API":"0€","Pricing":"0-299 MAD"},
|
|
acts:["Landing page WeviaAI.ma","Chatbot WhatsApp Business","Webinaire gratuit PME","Packager Docker demo offline"],
|
|
apps:"WEVIA Arena · Ollama · Qdrant · SearXNG · WEVIA Life"},
|
|
{id:4,n:"Consulting SAP/IA",ico:"🏢",clr:"var(--gold)",st:"live",rev:"150K MAD/mois",delay:"En cours",invest:"Temps Yacine",
|
|
desc:"Missions consulting SAP S/4HANA, Cloud, IA. Partenariats Vistex, Huawei, Arrow/Scaleway. 16 ans d'expertise.",
|
|
m:{Partners:"4",Secteurs:"7",Pages:"359",Exp:"16 ans"},
|
|
acts:["Répondre Olga (Vistex) 3 conditions","Relancer Huawei quotas ECS","Finaliser Arrow/Scaleway","Publier 3 case studies"],
|
|
apps:"Site WEVAL · WEVIA Master · Twenty CRM"},
|
|
{id:5,n:"White-label WEVIA",ico:"🏥",clr:"var(--ice)",st:"plan",rev:"80K MAD/mois",delay:"6 semaines",invest:"30h packaging",
|
|
desc:"WEVIA IA personnalisée pour cabinets médicaux. Données 100% locales, RDV patients, souveraineté. 290€/mois/cabinet.",
|
|
m:{Cible:"Cabinets","Prix":"290€/mois",Deploy:"Docker",Data:"100% local"},
|
|
acts:["Packager WEVIA Life version cabinet","Script deploy-wevia-cabinet.sh","Contacter 20 cabinets engagés","Demo offline USB chiffrée"],
|
|
apps:"WEVIA Life · Docker · Ollama · CRM"},
|
|
{id:6,n:"Formation IA PME",ico:"🎓",clr:"var(--coral)",st:"idea",rev:"60K MAD/mois",delay:"3 semaines",invest:"20h contenu",
|
|
desc:"Formations en ligne + ateliers: IA pour gestion, rappels, documentation. Cliniques, cabinets comptables, PME export.",
|
|
m:{Prix:"490€/clinique",Cible:"12/mois",Format:"Online+atelier",Certif:"Oui"},
|
|
acts:["Extraire contenu IA des 359 pages","Module 'IA au quotidien'","Webinaire d'accroche gratuit","Parcours certification WEVIA"],
|
|
apps:"Academy · WEVIA Arena · Content Factory"}
|
|
];
|
|
|
|
const INTEL=[
|
|
{t:"Marché email pharma Maghreb +22% croissance",b:"Labos investissent massivement en digital post-COVID. Budget moyen: 50-200K€/an. 78% des HCP utilisent l'email professionnel.",tag:"opp",d:"Auto-scan — Avril 2026"},
|
|
{t:"DoctoLib lance au Maroc — concurrent indirect",b:"Offre RDV en ligne mais pas encore email/CRM pharma. Fenêtre d'opportunité pour WEVAL sur l'email marketing HCP.",tag:"thr",d:"Auto-scan — Avril 2026"},
|
|
{t:"IA souveraine — tendance forte Afrique 2026",b:"Gouvernements africains poussent solutions IA locales. Maroc stratégie IA 2030. WEVIA = first-mover.",tag:"trd",d:"Auto-scan — Avril 2026"},
|
|
{t:"API santé: 3.2B$ marché mondial 2026",b:"Croissance 18%/an. Peu de fournisseurs Afrique du Nord — marché sous-exploité. WEVAL positionné.",tag:"opp",d:"Auto-scan — Avril 2026"},
|
|
{t:"CNDP renforce souveraineté données santé",b:"Contraintes strictes données de santé. Solutions hébergées localement (WEVIA) = avantage compétitif décisif.",tag:"opp",d:"Auto-scan — Avril 2026"},
|
|
{t:"Freemium SaaS IA: conversion 3-8% → payant",b:"Avec 1000 utilisateurs free, objectif 50 Pro à 99 MAD/mois = 4950 MAD/mois récurrent.",tag:"trd",d:"Benchmark — Avril 2026"}
|
|
];
|
|
|
|
const WEEKS=[
|
|
{w:1,t:"Lancement",acts:[
|
|
{t:"Segmenter HCP par spécialité",o:"Ethica",c:"var(--emerald)"},
|
|
{t:"3 templates email Starter/Pro/Premium",o:"Ethica",c:"var(--emerald)"},
|
|
{t:"Contacter Kaouther co-prospection",o:"Ethica",c:"var(--emerald)"},
|
|
{t:"OpenAPI spec ethica.medecins",o:"API",c:"var(--sapphire)"},
|
|
{t:"Répondre Olga (Vistex) 3 conditions",o:"Consulting",c:"var(--gold)"},
|
|
{t:"Landing page WeviaAI.ma",o:"SaaS",c:"var(--amethyst)"}]},
|
|
{w:2,t:"Prospection",acts:[
|
|
{t:"100 emails personnalisés labos pharma",o:"Ethica",c:"var(--emerald)"},
|
|
{t:"Déployer api.weval.ma sur S204",o:"API",c:"var(--sapphire)"},
|
|
{t:"Publier RapidAPI pricing freemium",o:"API",c:"var(--sapphire)"},
|
|
{t:"Webinaire 'IA pour PME marocaines'",o:"SaaS",c:"var(--amethyst)"},
|
|
{t:"Relancer Huawei quotas ECS/EIP",o:"Consulting",c:"var(--gold)"}]},
|
|
{w:3,t:"Tests pilotes",acts:[
|
|
{t:"3 tests gratuits 2000 emails labos",o:"Ethica",c:"var(--emerald)"},
|
|
{t:"Contacter 5 HealthTech",o:"API",c:"var(--sapphire)"},
|
|
{t:"Chatbot WhatsApp Business WEVIA",o:"SaaS",c:"var(--amethyst)"},
|
|
{t:"Packager WEVIA cabinet Docker",o:"White-label",c:"var(--ice)"},
|
|
{t:"Review KPIs avec Kaouther",o:"Ethica",c:"var(--emerald)"}]},
|
|
{w:4,t:"Closing",acts:[
|
|
{t:"Clôturer 2 contrats Starter minimum",o:"Ethica",c:"var(--emerald)"},
|
|
{t:"1ère campagne payante Biopharm dermo",o:"Ethica",c:"var(--emerald)"},
|
|
{t:"Brain Engine mode réel J1→J7",o:"Ethica",c:"var(--emerald)"},
|
|
{t:"Offre annuelle 10 campagnes",o:"Ethica",c:"var(--emerald)"},
|
|
{t:"20 cabinets pour white-label",o:"White-label",c:"var(--ice)"},
|
|
{t:"3 case studies weval-consulting.com",o:"Consulting",c:"var(--gold)"}]}
|
|
];
|
|
|
|
const ASSETS={
|
|
"Apps SaaS (88)":["Academy","AI-SDR","AuditAI","BizPlan","BlacklistGuard","CanvasAI","CloudCost","Content Factory","CopyAI","CreativeFactory","DashboardAI","DataHarvest","DataInsight","DeliverAds","DeliverScore","DevForge","Email Platform","EmailVerify","E-Signature","Ethica B2B","FormBuilder","GPU Inference","Healthcare CRM","IA Arabe","InboxTest","ISP Monitor","LeadForge","Lean Six Sigma","LinkedIn Manager","MailForge","MailStream","MailWarm","MedReach","MedReach HCP","MeetingAI","NetworkGuard","NewsletterInsight","OutreachAI","Partner Program","PresentationAI","ProposalAI","ReputationAI","ROI Calculator","ScoutAI","Sentinel","SMSForge","Solution Finder","StoreAI","Technology Radar","TranslateAI","Trust Center","WEVADS IA","WEVAL CRM","WEVAL Mind","WEVIA Agency","WEVIA Enterprise","WEVIA Whitelabel","WEVIA Life App","Workspace","YouTube Factory"],
|
|
"Services Docker (17)":["n8n Workflows","Gitea (50 repos)","Mattermost Chat","SearXNG Search","Plausible Analytics","Uptime Kuma","Qdrant Vectors","Vaultwarden","Twenty CRM","Langfuse","Prometheus","Loki Logs"],
|
|
"IA Souveraine (12)":["Ollama qwen3:4b","Ollama gemma4:e4b","Ollama nomic-embed","Ollama all-minilm","Ollama glm-4:9b","Cerebras 235B","Groq 70B","SambaNova 70B","NVIDIA GLM-5","HuggingFace","Gemini","Mistral"],
|
|
"Agents IA (11)":["WEVIA Master (134)","WEVIA Autonomous","WEVIA Director","L99 Brain QA","WeDroid Terminal","Chatbot Public","Blade Razer","MiroFish","DeerFlow","Multi-Agent (6)","Turbo Fast-path"]
|
|
};
|
|
|
|
// ═══ RENDER ═══
|
|
function renderOpp(){
|
|
const g=document.getElementById('oppGrid');
|
|
g.innerHTML=OPP.map(o=>{
|
|
const stMap={live:'b-live',ready:'b-ready',plan:'b-plan',idea:'b-idea'};
|
|
return`<div class="glass">
|
|
<div class="badge ${stMap[o.st]}">${o.st}</div>
|
|
<div class="g-icon" style="background:${o.clr}15">${o.ico}</div>
|
|
<div class="g-title">${o.n}</div>
|
|
<div class="g-sub">${o.delay} · ${o.invest} · ${o.rev}</div>
|
|
<div class="g-desc">${o.desc}</div>
|
|
<div class="g-metrics">${Object.entries(o.m).map(([k,v])=>`<div class="g-metric"><div class="mv">${v}</div><div class="ml">${k}</div></div>`).join('')}</div>
|
|
<div style="margin-top:14px">${o.acts.map(a=>`<div class="act"><div class="ck" onclick="toggleCk(this)"></div><div class="at">${a}</div></div>`).join('')}</div>
|
|
<div style="margin-top:10px;font-size:0.65em;color:var(--text3)">${o.apps}</div>
|
|
</div>`}).join('');
|
|
}
|
|
|
|
function renderActs(){
|
|
document.getElementById('actView').innerHTML=WEEKS.map(w=>`
|
|
<div class="week-head">Semaine ${w.w} — ${w.t}</div>
|
|
${w.acts.map(a=>`<div class="act"><div class="ck" onclick="toggleCk(this)"></div><div class="at">${a.t}</div><div class="aw" style="background:${a.c}12;color:${a.c}">${a.o}</div></div>`).join('')}
|
|
`).join('');
|
|
}
|
|
|
|
function renderAssets(){
|
|
document.getElementById('assView').innerHTML=Object.entries(ASSETS).map(([cat,items])=>`
|
|
<div class="asset-section"><div class="as-title">${cat}</div>
|
|
<div class="asset-grid">${items.map(n=>`<div class="asset"><div class="ad" style="background:var(--emerald)"></div>${n}</div>`).join('')}</div></div>
|
|
`).join('');
|
|
}
|
|
|
|
function renderIntel(){
|
|
const tMap={opp:'t-opp',thr:'t-thr',trd:'t-trd'};
|
|
document.getElementById('intGrid').innerHTML=INTEL.map(i=>`
|
|
<div class="intel"><div class="it ${tMap[i.tag]}">${i.tag==='opp'?'Opportunity':i.tag==='thr'?'Threat':'Trend'}</div>
|
|
<div class="ih">${i.t}</div><div class="ib">${i.b}</div><div class="id">${i.d}</div></div>
|
|
`).join('');
|
|
}
|
|
|
|
// ═══ INTERACTIONS ═══
|
|
document.querySelectorAll('.tab').forEach(t=>t.addEventListener('click',function(){
|
|
document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active'));
|
|
document.querySelectorAll('.panel').forEach(p=>p.classList.remove('on'));
|
|
this.classList.add('active');
|
|
document.getElementById('p-'+this.dataset.t).classList.add('on');
|
|
}));
|
|
|
|
function toggleCk(el){el.classList.toggle('done');el.textContent=el.classList.contains('done')?'✓':'';
|
|
const d=document.querySelectorAll('.ck.done').length,t=document.querySelectorAll('.ck').length;
|
|
const k=document.getElementById('kAct');if(k)k.textContent=d+'/'+t;
|
|
}
|
|
|
|
async function sendChat(){
|
|
const inp=document.getElementById('chatIn'),msg=inp.value.trim();if(!msg)return;
|
|
const body=document.getElementById('chatBody');
|
|
body.innerHTML+=`<div class="msg u">${msg}</div>`;inp.value='';
|
|
const tid='t'+Date.now();
|
|
body.innerHTML+=`<div class="msg a" id="${tid}"><span style="opacity:0.5">⏳ WEVIA Master analyse...</span></div>`;
|
|
body.scrollTop=body.scrollHeight;
|
|
try{
|
|
const r=await fetch('/api/wevia-master-api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:msg,session:'ge-'+Date.now()})});
|
|
const d=await r.json();
|
|
document.getElementById(tid).innerHTML=(d.content||d.response||'—').replace(/\n/g,'<br>');
|
|
}catch(e){document.getElementById(tid).innerHTML='Erreur: '+e.message}
|
|
body.scrollTop=body.scrollHeight;
|
|
}
|
|
|
|
async function runScan(){
|
|
const btn=document.querySelector('.scan-btn');btn.innerHTML='<span class="ico" style="animation:spin 1s linear infinite">⟳</span> Scanning...';
|
|
const style=document.createElement('style');style.textContent='@keyframes spin{to{transform:rotate(360deg)}}';document.head.appendChild(style);
|
|
try{
|
|
const r=await fetch('/api/growth-engine-api.php?action=scan');const d=await r.json();
|
|
const body=document.getElementById('chatBody');
|
|
body.innerHTML+=`<div class="msg a"><strong>🔍 Scan terminé</strong><br>Pages: ${d.scan?.pages||'?'} · APIs: ${d.scan?.apis||'?'} · Products: ${d.scan?.products||'?'} · Docker: ${d.scan?.docker||'?'} · Disk: ${d.scan?.disk||'?'}<br><br>${(d.proposal||'Scan OK').replace(/\n/g,'<br>')}</div>`;
|
|
body.scrollTop=body.scrollHeight;
|
|
}catch(e){console.error(e)}
|
|
btn.innerHTML='<span class="ico">⟳</span> Scan & Propose';
|
|
}
|
|
|
|
// ═══ INIT ═══
|
|
renderOpp();renderActs();renderAssets();renderIntel();
|
|
</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 === -->
|
|
|
|
</body>
|
|
</html>
|