1112 lines
77 KiB
HTML
1112 lines
77 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>Deep Conversion Advisor · WEVAL</title>
|
||
<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=Fraunces:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root{
|
||
--ink:#0a0e1a;--ink2:#0f1420;--ink3:#151b2b;--ink4:#1a2030;
|
||
--line:rgba(212,168,83,.12);--line2:rgba(212,168,83,.22);--line3:rgba(212,168,83,.35);
|
||
--gold:#d4a853;--gold-br:#e6ba6a;--gold-dk:#a57f2e;
|
||
--em:#10b981;--em-lt:#6ee7b7;--ru:#ef4444;--sa:#22d3ee;--sa-lt:#a5f3fc;
|
||
--am:#a855f7;--am-lt:#c4b5fd;--to:#fbbf24;--to-lt:#fde68a;--ro:#ec4899;
|
||
--paper:#f4ecd8;--fog:#94a3b8;--smoke:#64748b;
|
||
--serif:'Fraunces',Georgia,serif;--sans:'Inter',system-ui,sans-serif;--mono:'JetBrains Mono',monospace
|
||
}
|
||
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
||
html{font-size:14px;scrollbar-width:auto;scrollbar-color:var(--gold) var(--ink)}
|
||
html,body{background:var(--ink);color:var(--paper);font-family:var(--sans);line-height:1.6;min-height:100vh;overflow-x:hidden;overflow-y:auto}
|
||
html::-webkit-scrollbar,body::-webkit-scrollbar{width:14px}
|
||
html::-webkit-scrollbar-track,body::-webkit-scrollbar-track{background:var(--ink);border-left:1px solid var(--line)}
|
||
html::-webkit-scrollbar-thumb,body::-webkit-scrollbar-thumb{background:linear-gradient(180deg,var(--gold),var(--gold-dk));border-radius:7px;border:2px solid var(--ink);box-shadow:inset 0 0 3px rgba(0,0,0,.3)}
|
||
html::-webkit-scrollbar-thumb:hover,body::-webkit-scrollbar-thumb:hover{background:linear-gradient(180deg,var(--gold-br),var(--gold))}
|
||
|
||
/* Ambient */
|
||
.ambient{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden}
|
||
.ambient::before{content:'';position:absolute;width:800px;height:800px;border-radius:50%;background:radial-gradient(circle,rgba(212,168,83,.06) 0%,transparent 70%);top:-200px;left:-200px;filter:blur(80px)}
|
||
.ambient::after{content:'';position:absolute;width:600px;height:600px;border-radius:50%;background:radial-gradient(circle,rgba(34,211,238,.04) 0%,transparent 70%);bottom:-150px;right:-150px;filter:blur(100px)}
|
||
.grain{position:fixed;inset:0;z-index:1;pointer-events:none;opacity:.03;mix-blend-mode:overlay;background-image: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.85' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
|
||
|
||
.wrap{position:relative;z-index:2;max-width:1600px;margin:0 auto;padding:20px 28px 100px}
|
||
@media(max-width:900px){.wrap{padding:16px 14px 80px}}
|
||
|
||
/* Masthead */
|
||
.mast{display:grid;grid-template-columns:auto 1fr auto;gap:20px;align-items:center;padding:14px 0 18px;border-bottom:1px solid var(--line2);margin-bottom:20px}
|
||
.mast-brand{display:flex;align-items:center;gap:12px;min-width:0}
|
||
.mast-logo{width:38px;height:38px;border:1.5px solid var(--gold);border-radius:50%;display:grid;place-items:center;font-family:var(--serif);font-weight:900;font-size:20px;color:var(--gold);font-style:italic;flex-shrink:0}
|
||
.mast-h1{font-family:var(--serif);font-weight:500;font-size:22px;line-height:1.1;letter-spacing:-.02em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.mast-h1 em{font-style:italic;color:var(--gold)}
|
||
.mast-sub{font-family:var(--serif);font-style:italic;font-size:11.5px;color:var(--fog);margin-top:3px}
|
||
.mast-nav{display:flex;gap:4px;flex-wrap:wrap;justify-content:flex-end}
|
||
.mast-nav a{font-family:var(--sans);font-size:10px;text-transform:uppercase;letter-spacing:.1em;color:var(--fog);text-decoration:none;padding:6px 11px;border:1px solid var(--line);border-radius:2px;transition:all .15s;white-space:nowrap}
|
||
.mast-nav a:hover{border-color:var(--gold);color:var(--paper);background:rgba(212,168,83,.05)}
|
||
.mast-meta{text-align:right;font-size:10px;color:var(--smoke);font-family:var(--mono);letter-spacing:.04em}
|
||
.mast-meta .wave{color:var(--gold);font-family:var(--serif);font-style:italic;font-size:11px;margin-bottom:2px}
|
||
@media(max-width:900px){.mast{grid-template-columns:1fr;gap:12px}.mast-nav{justify-content:flex-start}}
|
||
|
||
/* Live badge */
|
||
.live-strip{display:flex;align-items:center;gap:12px;padding:10px 14px;background:linear-gradient(90deg,rgba(16,185,129,.08),rgba(212,168,83,.04));border:1px solid rgba(16,185,129,.2);border-radius:3px;margin-bottom:24px;font-size:12px}
|
||
.live-dot{width:8px;height:8px;border-radius:50%;background:var(--em);box-shadow:0 0 10px var(--em);animation:pulse 1.5s infinite}
|
||
@keyframes pulse{50%{opacity:.4}}
|
||
.live-strip .hi{color:var(--paper);font-weight:600}
|
||
.live-strip .kpi{margin-left:auto;font-family:var(--mono);color:var(--fog);font-size:11px}
|
||
|
||
/* Section title */
|
||
.sec{margin-top:36px;margin-bottom:16px;padding-bottom:10px;border-bottom:1px solid var(--line);display:flex;align-items:baseline;gap:14px;flex-wrap:wrap}
|
||
.sec-n{font-family:var(--serif);font-style:italic;color:var(--gold);font-size:13px;font-weight:400;flex-shrink:0}
|
||
.sec h2{font-family:var(--serif);font-weight:500;font-size:20px;letter-spacing:-.01em}
|
||
.sec h2 em{font-style:italic;color:var(--gold)}
|
||
.sec-kick{font-family:var(--sans);font-size:10px;text-transform:uppercase;letter-spacing:.15em;color:var(--fog);margin-left:auto}
|
||
.sec-actions{margin-left:auto;display:flex;gap:6px}
|
||
.btn{font-family:var(--sans);font-size:10.5px;text-transform:uppercase;letter-spacing:.08em;padding:6px 11px;background:transparent;color:var(--fog);border:1px solid var(--line2);border-radius:2px;cursor:pointer;transition:all .15s;text-decoration:none;display:inline-flex;align-items:center;gap:5px}
|
||
.btn:hover{border-color:var(--gold);color:var(--gold);background:rgba(212,168,83,.05)}
|
||
.btn.primary{color:var(--gold);border-color:var(--gold)}
|
||
.btn.primary:hover{background:var(--gold);color:var(--ink)}
|
||
|
||
/* Live feeds */
|
||
.feeds{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
|
||
@media(max-width:1100px){.feeds{grid-template-columns:repeat(2,1fr)}}
|
||
@media(max-width:560px){.feeds{grid-template-columns:1fr}}
|
||
.feed{padding:16px 18px;border:1px solid var(--line);border-radius:3px;background:linear-gradient(135deg,var(--ink2) 0%,var(--ink) 100%);position:relative;transition:all .2s}
|
||
.feed::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:var(--gold)}
|
||
.feed.f1::before{background:var(--em)}.feed.f2::before{background:var(--sa)}.feed.f3::before{background:var(--am)}.feed.f4::before{background:var(--to)}
|
||
.feed:hover{transform:translateY(-2px);border-color:var(--line2)}
|
||
.feed-k{font-family:var(--mono);font-size:9px;text-transform:uppercase;letter-spacing:.15em;color:var(--fog);margin-bottom:8px}
|
||
.feed-v{font-family:var(--serif);font-weight:600;font-size:34px;line-height:1;letter-spacing:-.02em;margin-bottom:6px}
|
||
.feed.f1 .feed-v{color:var(--em)}.feed.f2 .feed-v{color:var(--sa)}.feed.f2.alert .feed-v{color:var(--ru)}.feed.f3 .feed-v{color:var(--am)}.feed.f4 .feed-v{color:var(--to)}
|
||
.feed-s{font-size:11px;color:var(--fog)}.feed-s .hi{color:var(--paper);font-weight:500}
|
||
|
||
/* Priorities grid */
|
||
.prio{display:grid;grid-template-columns:1.3fr 1fr;gap:20px;margin-top:8px}
|
||
@media(max-width:1100px){.prio{grid-template-columns:1fr}}
|
||
|
||
.top5{padding:22px 24px;background:linear-gradient(135deg,rgba(34,211,238,.04),rgba(168,85,247,.03));border:1px solid var(--line2);border-radius:3px}
|
||
.top5-h{display:flex;align-items:baseline;gap:10px;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid var(--line)}
|
||
.top5-h h3{font-family:var(--serif);font-weight:500;font-size:16px}
|
||
.top5-h .badge{font-family:var(--mono);font-size:9px;text-transform:uppercase;color:var(--sa);padding:3px 7px;border:1px solid rgba(34,211,238,.3);border-radius:2px;letter-spacing:.12em}
|
||
.act{display:grid;grid-template-columns:44px 1fr auto;gap:14px;padding:12px 0;border-bottom:1px dashed var(--line);align-items:start;transition:padding .15s}
|
||
.act:last-child{border-bottom:none}
|
||
.act:hover{padding-left:6px}
|
||
.act-r{font-family:var(--serif);font-weight:600;font-size:24px;color:var(--gold);font-style:italic;line-height:1}
|
||
.act-b{min-width:0}
|
||
.act-t{font-family:var(--serif);font-weight:500;font-size:14.5px;color:var(--paper);margin-bottom:3px}
|
||
.act-w{font-size:12px;color:var(--fog);line-height:1.5;margin-bottom:5px}
|
||
.act-d{font-family:var(--mono);font-size:10px;color:var(--smoke)}
|
||
.act-d::before{content:'↳ ';color:var(--gold)}
|
||
.act-arr{font-family:var(--serif);font-style:italic;font-size:18px;color:var(--gold);opacity:.5;transition:all .15s}
|
||
.act:hover .act-arr{opacity:1;transform:translateX(3px)}
|
||
|
||
.llm{padding:22px 24px;background:linear-gradient(135deg,rgba(168,85,247,.05),rgba(212,168,83,.04));border:1px solid rgba(168,85,247,.2);border-radius:3px;min-height:280px}
|
||
.llm-h{display:flex;align-items:center;gap:10px;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid rgba(168,85,247,.15)}
|
||
.llm-h h3{font-family:var(--serif);font-weight:500;font-size:15px}
|
||
.llm-h em{font-style:italic;color:var(--am)}
|
||
.llm-cas{font-family:var(--mono);font-size:9px;color:var(--fog);letter-spacing:.1em;margin-left:auto}
|
||
.llm-body{font-size:12.5px;line-height:1.7}
|
||
.llm-load{display:flex;align-items:center;gap:10px;padding:18px 0;color:var(--am);font-family:var(--serif);font-style:italic}
|
||
.llm-rec{margin-bottom:12px;padding:12px 14px;background:rgba(168,85,247,.05);border-left:3px solid var(--am);border-radius:0 3px 3px 0}
|
||
.llm-rec-t{display:flex;align-items:baseline;gap:8px;margin-bottom:4px;font-family:var(--serif);font-weight:500;font-size:13.5px}
|
||
.llm-rec-t .rk{font-family:var(--serif);font-style:italic;color:var(--am);font-size:16px;font-weight:600}
|
||
.llm-rec-t .rv{margin-left:auto;font-family:var(--mono);font-size:10.5px;color:var(--to)}
|
||
.llm-rec-tm{font-family:var(--mono);font-size:9.5px;color:var(--fog);margin-bottom:5px;letter-spacing:.05em}
|
||
.llm-rec-s{font-size:11.5px;color:var(--fog);padding:2px 0 2px 14px;position:relative}
|
||
.llm-rec-s::before{content:'▸';position:absolute;left:0;color:var(--em)}
|
||
|
||
/* Matrix 2x2 */
|
||
.mx{display:grid;grid-template-columns:1fr 1fr;gap:2px;background:var(--line2);border:1px solid var(--line2);border-radius:3px;overflow:hidden}
|
||
.mx-c{padding:18px 20px;background:var(--ink2);min-height:140px}
|
||
.mx-c.qw{background:linear-gradient(135deg,var(--ink2),rgba(16,185,129,.04))}
|
||
.mx-c.bb{background:linear-gradient(135deg,var(--ink2),rgba(251,191,36,.04))}
|
||
.mx-c.fi{background:linear-gradient(135deg,var(--ink2),rgba(34,211,238,.03))}
|
||
.mx-c.th{background:linear-gradient(135deg,var(--ink2),rgba(239,68,68,.03))}
|
||
.mx-lbl{font-family:var(--mono);font-size:9px;text-transform:uppercase;letter-spacing:.12em;color:var(--fog);margin-bottom:6px}
|
||
.mx-t{font-family:var(--serif);font-weight:500;font-size:14px;margin-bottom:3px}
|
||
.mx-t em{font-style:italic;color:var(--gold)}
|
||
.mx-v{font-family:var(--serif);font-weight:600;font-size:22px;margin-bottom:10px}
|
||
.mx-c.qw .mx-v{color:var(--em)}.mx-c.bb .mx-v{color:var(--to)}.mx-c.fi .mx-v{color:var(--sa)}.mx-c.th .mx-v{color:var(--ru)}
|
||
.mx-it{font-size:11px;color:var(--fog);line-height:1.5}
|
||
.mx-it .i{padding:2px 0 2px 12px;border-bottom:1px dotted var(--line);position:relative}
|
||
.mx-it .i::before{content:'·';position:absolute;left:2px;color:var(--gold)}
|
||
.mx-it .i:last-child{border-bottom:none}
|
||
@media(max-width:700px){.mx{grid-template-columns:1fr}}
|
||
|
||
/* Chips */
|
||
.chips{display:flex;flex-wrap:wrap;gap:6px}
|
||
.chip{padding:5px 10px;border:1px solid var(--line2);border-radius:2px;font-family:var(--mono);font-size:10px;color:var(--paper);background:var(--ink2);letter-spacing:.03em;transition:all .15s}
|
||
.chip:hover{border-color:var(--gold);background:rgba(212,168,83,.05);color:var(--gold)}
|
||
.chip .st{display:inline-block;width:6px;height:6px;border-radius:50%;margin-right:6px;vertical-align:middle}
|
||
.chip .st.up{background:var(--em);box-shadow:0 0 4px var(--em)}
|
||
.chip .st.dn{background:var(--ru)}
|
||
.chip .meta{color:var(--fog);font-size:9px;margin-left:6px}
|
||
|
||
/* Social hub */
|
||
.social{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin-bottom:20px}
|
||
@media(max-width:1100px){.social{grid-template-columns:repeat(3,1fr)}}
|
||
@media(max-width:560px){.social{grid-template-columns:repeat(2,1fr)}}
|
||
.s-card{padding:12px 14px;border:1px solid var(--line);border-radius:3px;background:var(--ink2);transition:all .15s}
|
||
.s-card:hover{border-color:var(--line2);transform:translateY(-1px)}
|
||
.s-card .k{font-family:var(--mono);font-size:9px;text-transform:uppercase;letter-spacing:.1em;color:var(--fog);margin-bottom:6px;display:flex;align-items:center;gap:5px}
|
||
.s-card .n{font-family:var(--serif);font-weight:600;font-size:22px;line-height:1;color:var(--paper);margin-bottom:4px}
|
||
.s-card .d{font-size:10.5px;color:var(--fog);line-height:1.4}
|
||
|
||
/* LLM ideas */
|
||
.ideas{display:grid;grid-template-columns:repeat(auto-fit,minmax(380px,1fr));gap:14px}
|
||
.idea{padding:16px 18px;border:1px solid var(--line2);border-radius:3px;background:linear-gradient(135deg,var(--ink2),rgba(168,85,247,.03));position:relative}
|
||
.idea-h{display:flex;align-items:baseline;gap:8px;margin-bottom:8px}
|
||
.idea-r{font-family:var(--serif);font-weight:600;font-style:italic;font-size:16px;color:var(--am)}
|
||
.idea-t{font-family:var(--serif);font-weight:500;font-size:14px;flex:1}
|
||
.idea-rv{font-family:var(--mono);font-size:10.5px;color:var(--to);white-space:nowrap}
|
||
.idea-g{font-size:11.5px;color:var(--fog);margin-bottom:8px;line-height:1.5}
|
||
.idea-src{font-family:var(--mono);font-size:9px;color:var(--am);margin-bottom:8px}
|
||
.idea-tools{font-size:10.5px;color:var(--paper);margin-bottom:8px;padding:6px 0;border-top:1px dashed var(--line);border-bottom:1px dashed var(--line)}
|
||
.idea-tools::before{content:'🔧 ';color:var(--gold)}
|
||
.idea-s{font-size:11px;color:var(--fog);padding:2px 0 2px 14px;position:relative;line-height:1.5}
|
||
.idea-s::before{content:'→';position:absolute;left:0;color:var(--em)}
|
||
.idea-kpi{margin-top:8px;padding:6px 10px;background:rgba(16,185,129,.06);border-radius:2px;font-size:10.5px;color:var(--em-lt);font-family:var(--mono)}
|
||
|
||
/* Tasks */
|
||
.tasks{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:12px}
|
||
.task{padding:14px 16px;border:1px solid var(--line);border-radius:3px;background:var(--ink2)}
|
||
.task-h{display:flex;align-items:baseline;gap:8px;margin-bottom:6px}
|
||
.task-n{font-family:var(--serif);font-style:italic;font-size:18px;color:var(--gold)}
|
||
.task-t{font-family:var(--sans);font-size:13px;font-weight:500;flex:1}
|
||
.task-st{font-family:var(--mono);font-size:9px;padding:2px 7px;border-radius:2px;text-transform:uppercase;letter-spacing:.08em}
|
||
.task-st.proposed{background:rgba(148,163,184,.15);color:var(--fog)}
|
||
.task-st.in_progress{background:rgba(34,211,238,.15);color:var(--sa)}
|
||
.task-st.done{background:rgba(16,185,129,.15);color:var(--em-lt)}
|
||
.task-st.cancelled{background:rgba(239,68,68,.15);color:var(--ru)}
|
||
.task-mad{font-family:var(--mono);font-size:11px;color:var(--to);margin-bottom:4px}
|
||
.task-op{font-size:11px;color:var(--fog);margin-bottom:4px}
|
||
.task-op::before{content:'🎯 ';color:var(--gold)}
|
||
.task-tr{display:flex;gap:4px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px dashed var(--line)}
|
||
.task-tr button{font-family:var(--mono);font-size:9px;padding:3px 7px;background:transparent;color:var(--fog);border:1px solid var(--line);border-radius:2px;cursor:pointer;text-transform:uppercase}
|
||
.task-tr button:hover{border-color:var(--gold);color:var(--gold)}
|
||
|
||
/* Leads */
|
||
.leads{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px}
|
||
.lead{padding:12px 14px;border:1px solid var(--line);border-radius:3px;background:var(--ink2);transition:all .15s}
|
||
.lead:hover{border-color:var(--line2)}
|
||
.lead-h{display:flex;align-items:baseline;gap:8px;margin-bottom:6px}
|
||
.lead-n{font-family:var(--serif);font-weight:500;font-size:13.5px;flex:1}
|
||
.lead-mql{font-family:var(--mono);font-size:10px;padding:2px 6px;background:rgba(16,185,129,.1);color:var(--em-lt);border-radius:2px}
|
||
.lead-meta{font-size:10.5px;color:var(--fog);margin-bottom:4px}
|
||
.lead-desc{font-size:11px;color:var(--smoke);line-height:1.4}
|
||
|
||
/* Competitors */
|
||
.comps{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px}
|
||
.comp{padding:14px 16px;border:1px solid var(--line);border-radius:3px;background:var(--ink2)}
|
||
.comp-n{font-family:var(--serif);font-weight:500;font-size:13.5px;margin-bottom:3px;display:flex;align-items:baseline;gap:8px}
|
||
.comp-th{font-family:var(--mono);font-size:9px;padding:2px 6px;border-radius:2px;text-transform:uppercase}
|
||
.comp-th.high{background:rgba(239,68,68,.15);color:var(--ru)}
|
||
.comp-th.medium{background:rgba(251,191,36,.15);color:var(--to)}
|
||
.comp-th.low{background:rgba(16,185,129,.15);color:var(--em-lt)}
|
||
.comp-c{font-family:var(--mono);font-size:9px;color:var(--fog);margin-bottom:6px;letter-spacing:.1em;text-transform:uppercase}
|
||
.comp-vs{font-size:10.5px;color:var(--fog);margin-bottom:5px}
|
||
.comp-vs::before{content:'vs · ';color:var(--gold)}
|
||
.comp-e{font-size:10.5px;color:var(--em-lt);line-height:1.45}
|
||
.comp-e::before{content:'💪 ';color:var(--em)}
|
||
|
||
/* Generic loading */
|
||
.skel{background:linear-gradient(90deg,var(--ink2) 0%,var(--ink3) 50%,var(--ink2) 100%);background-size:200% 100%;animation:sk 1.4s ease-in-out infinite;border-radius:2px;color:transparent;display:inline-block;min-width:40px;min-height:1em}
|
||
@keyframes sk{to{background-position:-200% 0}}
|
||
.spnr{display:inline-block;width:12px;height:12px;border:1.5px solid var(--gold);border-top-color:transparent;border-radius:50%;animation:spin .9s linear infinite;vertical-align:middle}
|
||
@keyframes spin{to{transform:rotate(360deg)}}
|
||
.load-inline{color:var(--fog);font-family:var(--serif);font-style:italic;font-size:13px;padding:14px 0}
|
||
.err{padding:12px 14px;background:rgba(239,68,68,.08);border:1px solid rgba(239,68,68,.3);border-radius:3px;color:var(--ru);font-family:var(--mono);font-size:11px}
|
||
|
||
/* Chat dock */
|
||
.ck-tog{position:fixed;bottom:22px;left:22px;z-index:100;padding:10px 16px;background:var(--gold);color:var(--ink);border:0;border-radius:2px;font-family:var(--serif);font-style:italic;font-size:12px;font-weight:600;cursor:pointer;box-shadow:0 4px 20px rgba(212,168,83,.3);transition:transform .15s}
|
||
.ck-tog:hover{transform:translateY(-2px)}
|
||
.ck{position:fixed;bottom:78px;left:22px;z-index:99;width:360px;max-width:calc(100vw - 44px);background:var(--ink2);border:1px solid var(--line2);border-radius:3px;box-shadow:0 12px 40px rgba(0,0,0,.6);display:none;flex-direction:column}
|
||
.ck.open{display:flex}
|
||
.ck-h{padding:10px 14px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:8px;font-family:var(--serif);font-weight:500;font-size:13px}
|
||
.ck-h em{font-style:italic;color:var(--gold)}
|
||
.ck-x{margin-left:auto;background:none;border:0;color:var(--fog);cursor:pointer;font-size:18px;line-height:1}
|
||
.ck-b{max-height:380px;overflow-y:auto;padding:10px 14px;font-size:12.5px;line-height:1.55}
|
||
.ck-b::-webkit-scrollbar{width:6px}.ck-b::-webkit-scrollbar-thumb{background:var(--gold);border-radius:3px}
|
||
.ck-b .mg{margin-bottom:8px;padding:7px 10px;border-radius:3px}
|
||
.ck-b .mg.us{background:var(--ink3);margin-left:30px;color:var(--paper)}
|
||
.ck-b .mg.ai{background:rgba(212,168,83,.05);border-left:2px solid var(--gold);color:var(--paper)}
|
||
.ck-f{padding:10px;border-top:1px solid var(--line);display:flex;gap:6px}
|
||
.ck-f input{flex:1;background:var(--ink3);border:1px solid var(--line);color:var(--paper);padding:7px 10px;font-size:11.5px;border-radius:2px;font-family:var(--sans)}
|
||
.ck-f input:focus{outline:none;border-color:var(--gold)}
|
||
.ck-f button{padding:7px 12px;background:var(--gold);color:var(--ink);border:0;font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;cursor:pointer;border-radius:2px}
|
||
|
||
/* Backlink */
|
||
.back{position:fixed;bottom:22px;right:22px;z-index:100;padding:9px 15px;background:var(--ink2);border:1px solid var(--line2);border-radius:2px;text-decoration:none;color:var(--paper);font-family:var(--serif);font-style:italic;font-size:12px;transition:all .15s;backdrop-filter:blur(10px);box-shadow:0 4px 20px rgba(0,0,0,.4)}
|
||
.back:hover{border-color:var(--gold);color:var(--gold);transform:translateY(-2px)}
|
||
.back::before{content:'← ';color:var(--gold)}
|
||
|
||
/* Quick prompts */
|
||
.qp{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px}
|
||
.qp button{font-family:var(--sans);font-size:10.5px;padding:5px 10px;background:transparent;color:var(--fog);border:1px solid var(--line);border-radius:2px;cursor:pointer;transition:all .15s}
|
||
.qp button:hover{border-color:var(--gold);color:var(--gold);background:rgba(212,168,83,.05)}
|
||
|
||
/* Animations */
|
||
.fade{animation:fi .5s ease-out backwards}
|
||
@keyframes fi{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
|
||
|
||
/* === PREMIUM UX ULTRA MAX === */
|
||
/* Kanban */
|
||
.kb{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-top:8px}
|
||
@media(max-width:900px){.kb{grid-template-columns:repeat(2,1fr)}}
|
||
@media(max-width:560px){.kb{grid-template-columns:1fr}}
|
||
.kb-col{background:var(--ink2);border:1px solid var(--line);border-radius:3px;padding:12px;min-height:180px;transition:border-color .2s}
|
||
.kb-col:hover{border-color:var(--line2)}
|
||
.kb-h{display:flex;align-items:center;gap:8px;margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid var(--line)}
|
||
.kb-h .ic{width:10px;height:10px;border-radius:50%}
|
||
.kb-h.proposed .ic{background:var(--fog)}.kb-h.in_progress .ic{background:var(--sa);box-shadow:0 0 5px var(--sa)}
|
||
.kb-h.done .ic{background:var(--em);box-shadow:0 0 5px var(--em)}.kb-h.cancelled .ic{background:var(--ru)}
|
||
.kb-h h4{font-family:var(--serif);font-weight:500;font-size:13px}
|
||
.kb-h .cnt{margin-left:auto;font-family:var(--mono);font-size:10px;color:var(--fog);padding:2px 7px;background:var(--ink3);border-radius:10px}
|
||
.kb-card{padding:10px 11px;margin-bottom:8px;background:var(--ink3);border:1px solid var(--line);border-left:2px solid var(--gold);border-radius:2px;transition:all .15s;cursor:default}
|
||
.kb-card:hover{transform:translateX(3px);border-left-color:var(--gold-br)}
|
||
.kb-card-t{font-family:var(--sans);font-size:11.5px;font-weight:500;color:var(--paper);line-height:1.4;margin-bottom:5px}
|
||
.kb-card-m{font-family:var(--mono);font-size:10px;color:var(--to);margin-bottom:3px}
|
||
.kb-card-l{font-size:10px;color:var(--fog)}
|
||
.kb-card-l b{color:var(--em-lt);font-family:var(--mono)}
|
||
|
||
/* Pipeline funnel */
|
||
.pf{display:flex;flex-direction:column;gap:6px;margin-top:8px}
|
||
.pf-stage{display:flex;align-items:center;gap:14px;padding:12px 16px;background:linear-gradient(90deg,rgba(212,168,83,.06),rgba(12,17,32,0));border-left:3px solid var(--gold);border-radius:0 3px 3px 0;transition:all .15s}
|
||
.pf-stage:hover{background:linear-gradient(90deg,rgba(212,168,83,.12),rgba(12,17,32,0))}
|
||
.pf-lbl{font-family:var(--serif);font-weight:500;font-size:13px;min-width:140px}
|
||
.pf-bar{flex:1;height:28px;background:var(--ink3);border-radius:2px;overflow:hidden;position:relative}
|
||
.pf-fill{height:100%;background:linear-gradient(90deg,var(--gold),var(--gold-br));transition:width .6s ease-out;display:flex;align-items:center;padding:0 10px;font-family:var(--mono);font-size:11px;color:var(--ink);font-weight:600}
|
||
.pf-val{font-family:var(--mono);font-size:11px;color:var(--fog);min-width:90px;text-align:right}
|
||
|
||
/* KPI Dashboard cards */
|
||
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-top:8px}
|
||
.kpi-card{padding:14px 16px;border:1px solid var(--line);border-radius:3px;background:var(--ink2);position:relative;overflow:hidden;transition:all .2s}
|
||
.kpi-card:hover{border-color:var(--line2);transform:translateY(-2px)}
|
||
.kpi-card .k{font-family:var(--mono);font-size:9px;text-transform:uppercase;letter-spacing:.12em;color:var(--fog);margin-bottom:6px}
|
||
.kpi-card .v{font-family:var(--serif);font-weight:600;font-size:26px;line-height:1;margin-bottom:3px;color:var(--gold)}
|
||
.kpi-card .d{font-size:10.5px;color:var(--fog)}
|
||
.kpi-card.ok .v{color:var(--em-lt)}.kpi-card.warn .v{color:var(--to-lt)}.kpi-card.fail .v{color:var(--ru)}
|
||
.kpi-spark{position:absolute;right:8px;top:8px;width:50px;height:24px;opacity:.7}
|
||
|
||
/* Timeline unified feed */
|
||
.tl{position:relative;padding-left:24px;margin-top:8px}
|
||
.tl::before{content:'';position:absolute;left:8px;top:0;bottom:0;width:1px;background:linear-gradient(180deg,var(--gold),var(--line2),var(--gold))}
|
||
.tl-item{position:relative;padding:8px 0 8px 12px;border-bottom:1px dotted var(--line)}
|
||
.tl-item::before{content:'';position:absolute;left:-20px;top:14px;width:8px;height:8px;border-radius:50%;background:var(--gold);border:2px solid var(--ink);box-shadow:0 0 8px var(--gold)}
|
||
.tl-item.info::before{background:var(--sa);box-shadow:0 0 8px var(--sa)}
|
||
.tl-item.ok::before{background:var(--em);box-shadow:0 0 8px var(--em)}
|
||
.tl-item.warn::before{background:var(--to);box-shadow:0 0 8px var(--to)}
|
||
.tl-item.err::before{background:var(--ru);box-shadow:0 0 8px var(--ru)}
|
||
.tl-item .t{font-size:12.5px;color:var(--paper);margin-bottom:2px}
|
||
.tl-item .m{font-family:var(--mono);font-size:9.5px;color:var(--fog);letter-spacing:.03em}
|
||
.tl-item .d{font-size:10.5px;color:var(--smoke);margin-top:2px}
|
||
|
||
/* Task Search */
|
||
.ts-form{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;padding:12px 14px;background:var(--ink2);border:1px solid var(--line);border-radius:3px}
|
||
.ts-form input,.ts-form select{background:var(--ink3);border:1px solid var(--line);color:var(--paper);padding:7px 10px;font-family:var(--sans);font-size:11.5px;border-radius:2px;outline:none;transition:border-color .15s}
|
||
.ts-form input:focus,.ts-form select:focus{border-color:var(--gold)}
|
||
.ts-form input[type=text]{flex:1;min-width:200px}
|
||
.ts-form button{padding:7px 14px;background:var(--gold);color:var(--ink);border:0;font-family:var(--sans);font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;cursor:pointer;border-radius:2px}
|
||
.ts-results{margin-top:10px;font-size:11.5px;color:var(--fog)}
|
||
|
||
/* SSE Stream */
|
||
.sse-box{background:var(--ink2);border:1px solid var(--line);border-radius:3px;padding:14px 16px;margin-top:8px}
|
||
.sse-ctrl{display:flex;align-items:center;gap:10px;margin-bottom:10px}
|
||
.sse-btn{padding:8px 14px;background:var(--em);color:var(--ink);border:0;border-radius:2px;font-family:var(--mono);font-size:10.5px;font-weight:600;cursor:pointer;text-transform:uppercase;letter-spacing:.08em}
|
||
.sse-btn.stop{background:var(--ru)}
|
||
.sse-status{font-family:var(--mono);font-size:10.5px;color:var(--fog)}
|
||
.sse-status.live{color:var(--em-lt)}
|
||
.sse-log{max-height:240px;overflow-y:auto;background:var(--ink);border-radius:2px;padding:10px 12px;font-family:var(--mono);font-size:10.5px;line-height:1.5;color:var(--paper);scrollbar-width:thin;scrollbar-color:var(--gold) var(--ink)}
|
||
.sse-log::-webkit-scrollbar{width:6px}.sse-log::-webkit-scrollbar-thumb{background:var(--gold);border-radius:3px}
|
||
.sse-log .l{padding:3px 0;border-bottom:1px dotted var(--line)}
|
||
.sse-log .l .tm{color:var(--fog);margin-right:8px}
|
||
.sse-log .l .ch{color:var(--gold);margin-right:8px}
|
||
.sse-log .empty{color:var(--fog);font-style:italic;font-family:var(--serif);padding:20px 0;text-align:center}
|
||
|
||
/* Agent badges (Multiagent + Grounded) */
|
||
.agent-badges{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:8px}
|
||
@media(max-width:700px){.agent-badges{grid-template-columns:1fr}}
|
||
.ag-badge{padding:14px 18px;border-radius:3px;position:relative;overflow:hidden}
|
||
.ag-badge.multi{background:linear-gradient(135deg,rgba(168,85,247,.08),rgba(34,211,238,.05));border:1px solid rgba(168,85,247,.25)}
|
||
.ag-badge.ground{background:linear-gradient(135deg,rgba(16,185,129,.08),rgba(212,168,83,.04));border:1px solid rgba(16,185,129,.25)}
|
||
.ag-h{display:flex;align-items:center;gap:10px;margin-bottom:8px}
|
||
.ag-ic{font-size:18px}
|
||
.ag-h h4{font-family:var(--serif);font-weight:500;font-size:14px;flex:1}
|
||
.ag-h em{font-style:italic;color:var(--gold)}
|
||
.ag-h .st{font-family:var(--mono);font-size:9px;padding:3px 8px;background:rgba(16,185,129,.15);color:var(--em-lt);border-radius:2px;letter-spacing:.08em;text-transform:uppercase}
|
||
.ag-desc{font-size:11.5px;color:var(--fog);line-height:1.55;margin-bottom:10px}
|
||
.ag-btns{display:flex;gap:6px;flex-wrap:wrap}
|
||
.ag-btn{padding:5px 10px;background:transparent;color:var(--fog);border:1px solid var(--line);border-radius:2px;font-family:var(--mono);font-size:10px;cursor:pointer;transition:all .15s}
|
||
.ag-btn:hover{border-color:var(--gold);color:var(--gold)}
|
||
|
||
/* Feed sparkline integration */
|
||
.feed{position:relative}
|
||
.feed .spark{position:absolute;bottom:10px;right:10px;width:60px;height:18px;opacity:.6}
|
||
/* /PREMIUM UX */
|
||
|
||
</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>
|
||
<div class="ambient"></div>
|
||
<div class="grain"></div>
|
||
|
||
<div class="wrap">
|
||
|
||
<!-- MASTHEAD -->
|
||
<header class="mast">
|
||
<div class="mast-brand">
|
||
<div class="mast-logo">w</div>
|
||
<div>
|
||
<div class="mast-h1">Deep Conversion <em>Advisor</em></div>
|
||
<div class="mast-sub">A real-time revenue intelligence brief — WEVAL Consulting</div>
|
||
</div>
|
||
</div>
|
||
<nav class="mast-nav">
|
||
<a href="/growth-engine-v2.html">Growth v2</a>
|
||
<a href="/wevia-master.html">Master</a>
|
||
<a href="/director.html">Director</a>
|
||
<a href="/crm.html">CRM</a>
|
||
<a href="/weval-technology-platform.html">WTP</a>
|
||
</nav>
|
||
<div class="mast-meta">
|
||
<div class="wave" id="wave">Wave —</div>
|
||
<div id="ts">loading…</div>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- LIVE STRIP -->
|
||
<div class="live-strip fade">
|
||
<div class="live-dot"></div>
|
||
<span>Deep Conversion Advisor <span class="hi">V2 · LIVE</span></span>
|
||
<span class="kpi" id="livekpi">— leads · — scout scans · patterns —</span>
|
||
</div>
|
||
|
||
<!-- I · LIVE FEEDS -->
|
||
<div class="sec"><span class="sec-n">I.</span><h2>Live <em>feeds</em></h2><span class="sec-kick">Real-time signals</span></div>
|
||
<div class="feeds fade">
|
||
<div class="feed f1"><div class="feed-k">📊 Paperclip Leads</div><div class="feed-v skel" id="f-leads">—</div><div class="feed-s skel" id="f-leads-s">loading…</div></div>
|
||
<div class="feed f2" id="f-predict-box"><div class="feed-k">⚡ WePredict</div><div class="feed-v skel" id="f-predict">—</div><div class="feed-s skel" id="f-predict-s">loading…</div></div>
|
||
<div class="feed f3"><div class="feed-k">🕵 Dark Scout</div><div class="feed-v skel" id="f-scout">—</div><div class="feed-s skel" id="f-scout-s">loading…</div></div>
|
||
<div class="feed f4"><div class="feed-k">💰 Pipeline MAD</div><div class="feed-v skel" id="f-mad">—</div><div class="feed-s skel" id="f-mad-s">loading…</div></div>
|
||
</div>
|
||
|
||
<!-- II · TOP5 + LLM -->
|
||
<div class="sec"><span class="sec-n">II.</span><h2>Top 5 & <em>reasoning</em></h2><div class="sec-actions"><button class="btn" onclick="loadMain()">↻ Refresh</button></div></div>
|
||
<div class="prio fade">
|
||
<section class="top5"><div class="top5-h"><h3>🚀 Actions prioritaires</h3><span class="badge">Live</span></div><div id="top5"><div class="load-inline"><span class="spnr"></span> loading…</div></div></section>
|
||
<aside class="llm"><div class="llm-h"><h3>🤖 LLM-powered <em>recommendations</em></h3><span class="llm-cas">Cerebras → Groq → Mistral</span></div><div id="llm" class="llm-body"><div class="llm-load"><span class="spnr"></span> Querying sovereign cascade…</div></div></aside>
|
||
</div>
|
||
|
||
<!-- III · SOCIAL SIGNALS HUB -->
|
||
<div class="sec"><span class="sec-n">III.</span><h2>📡 Social <em>signals hub</em></h2><span class="sec-kick">Conversion ideas adaptées · Wave 230</span><div class="sec-actions"><button class="btn" onclick="loadSocial()">↻ Refresh</button></div></div>
|
||
<div class="social fade" id="social-strip"><div class="s-card skel">loading…</div><div class="s-card skel">loading…</div><div class="s-card skel">loading…</div><div class="s-card skel">loading…</div><div class="s-card skel">loading…</div></div>
|
||
<h3 style="font-family:var(--serif);font-weight:500;font-size:15px;margin:18px 0 10px;color:var(--am-lt)">✨ LLM Conversion Ideas</h3>
|
||
<div class="ideas" id="ideas"><div class="idea load-inline"><span class="spnr"></span> loading ideas…</div></div>
|
||
|
||
<!-- IV · PAPERCLIP TASKS -->
|
||
<div class="sec"><span class="sec-n">IV.</span><h2>📋 Paperclip <em>tasks</em></h2><span class="sec-kick">Auto-created · Wave 231</span><div class="sec-actions"><button class="btn" onclick="loadTasks()">↻ Refresh</button></div></div>
|
||
<div class="tasks fade" id="tasks"><div class="task load-inline"><span class="spnr"></span> loading tasks…</div></div>
|
||
|
||
<!-- V · DECISIONAL MATRIX -->
|
||
<div class="sec"><span class="sec-n">V.</span><h2>📊 Matrice <em>Effort × Impact</em></h2><span class="sec-kick">Eisenhower · Wave 251</span></div>
|
||
<div class="mx fade">
|
||
<div class="mx-c qw"><div class="mx-lbl">HIGH IMPACT · LOW EFFORT</div><div class="mx-t">✅ <em>Quick wins</em></div><div class="mx-v skel" id="mx-qw-v">—</div><div class="mx-it skel" id="mx-qw">loading…</div></div>
|
||
<div class="mx-c bb"><div class="mx-lbl">HIGH IMPACT · HIGH EFFORT</div><div class="mx-t">🎯 <em>Big bets</em></div><div class="mx-v skel" id="mx-bb-v">—</div><div class="mx-it skel" id="mx-bb">loading…</div></div>
|
||
<div class="mx-c fi"><div class="mx-lbl">LOW IMPACT · LOW EFFORT</div><div class="mx-t">💡 <em>Fill-ins</em></div><div class="mx-v" id="mx-fi-v">—</div><div class="mx-it skel" id="mx-fi">loading…</div></div>
|
||
<div class="mx-c th"><div class="mx-lbl">LOW IMPACT · HIGH EFFORT</div><div class="mx-t">⛔ <em>Thankless</em></div><div class="mx-v" id="mx-th-v">—</div><div class="mx-it skel" id="mx-th">loading…</div></div>
|
||
</div>
|
||
|
||
<!-- VI · SOVEREIGN AI -->
|
||
<div class="sec"><span class="sec-n">VI.</span><h2>🧠 Sovereign <em>AI stack</em></h2><span class="sec-kick" id="sov-count">— providers</span></div>
|
||
<div class="chips fade" id="chips"><span class="chip skel">loading…</span><span class="chip skel">loading…</span><span class="chip skel">loading…</span></div>
|
||
|
||
<!-- VII · COMPETITORS -->
|
||
<div class="sec"><span class="sec-n">VII.</span><h2>🥊 Competitive <em>intel</em></h2><span class="sec-kick">Dark Scout integrated</span></div>
|
||
<div class="comps fade" id="comps"><div class="comp load-inline"><span class="spnr"></span> loading competitive intel…</div></div>
|
||
|
||
<!-- VIII · LEADS -->
|
||
<div class="sec"><span class="sec-n">VIII.</span><h2>📋 Top 10 <em>leads</em></h2><span class="sec-kick">Paperclip live</span></div>
|
||
<div class="leads fade" id="leads"><div class="lead load-inline"><span class="spnr"></span> loading leads…</div></div>
|
||
|
||
|
||
<!-- IX · SOLUTION SCANNER -->
|
||
<div class="sec"><span class="sec-n">IX.</span><h2>🧠 Solution <em>Scanner</em></h2><span class="sec-kick">Predictive · Wave 252 · AI PREDICT</span><div class="sec-actions"><button class="btn" onclick="loadSolutionScanner()">↻ Re-analyze</button></div></div>
|
||
<div id="solution-scanner" class="fade"><div class="load-inline"><span class="spnr"></span> Loading predictive analysis…</div></div>
|
||
|
||
</div>
|
||
|
||
<!-- CHAT WEVIA -->
|
||
|
||
<!-- X. AGENT BADGES -->
|
||
<div class="sec"><span class="sec-n">X.</span><h2>🧠 WEVIA <em>Agent badges</em></h2><span class="sec-kick">Multi-agent · 0 hallucination · Waves 253-254</span></div>
|
||
<div class="agent-badges fade">
|
||
<div class="ag-badge multi">
|
||
<div class="ag-h"><span class="ag-ic">🧠</span><h4>WEVIA Master · <em>Multi-Agent</em> Orchestrator</h4><span class="st">live</span></div>
|
||
<div class="ag-desc">Pattern CLAUDE 7 phases (Thinking → Plan → Dispatch PARALLEL → Ground → Synthesize → Tests → Response)</div>
|
||
<div class="ag-btns">
|
||
<button class="ag-btn" onclick="testMultiAgent()">🧪 Test multiagent</button>
|
||
<button class="ag-btn" onclick="testGrounding()">🔍 Grounding</button>
|
||
<button class="ag-btn" onclick="window.open('/wevia-master.html','_blank')">🚀 MAX 30 agents</button>
|
||
</div>
|
||
</div>
|
||
<div class="ag-badge ground">
|
||
<div class="ag-h"><span class="ag-ic">✅</span><h4>WEVIA Master · <em>Grounded data</em></h4><span class="st">0 hallucination</span></div>
|
||
<div class="ag-desc">Chat WEVIA connecté live à Paperclip (48 leads) + Solution Scanner (10 solutions) + DB tasks · wave 253</div>
|
||
<div class="ag-btns">
|
||
<button class="ag-btn" onclick="testGrounding()">🧪 Test grounding</button>
|
||
<button class="ag-btn" onclick="tglCk()">💬 Open chat</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- XI. KPI DASHBOARD -->
|
||
<div class="sec"><span class="sec-n">XI.</span><h2>📊 KPI <em>Dashboard</em></h2><span class="sec-kick">Live charts · Wave 246</span><div class="sec-actions"><button class="btn" onclick="loadKpiDashboard()">↻ Refresh</button></div></div>
|
||
<div class="kpi-grid fade" id="kpi-grid"><div class="kpi-card"><div class="load-inline"><span class="spnr"></span> Loading KPIs…</div></div></div>
|
||
|
||
<!-- XII. KANBAN -->
|
||
<div class="sec"><span class="sec-n">XII.</span><h2>📋 Kanban <em>Board</em></h2><span class="sec-kick">Tasks par status · Wave 247</span><div class="sec-actions"><button class="btn" onclick="loadKanban()">↻ Refresh</button></div></div>
|
||
<div class="kb fade" id="kanban">
|
||
<div class="kb-col"><div class="kb-h proposed"><span class="ic"></span><h4>Proposed</h4><span class="cnt" id="kb-cnt-proposed">—</span></div><div id="kb-proposed"><div class="load-inline"><span class="spnr"></span></div></div></div>
|
||
<div class="kb-col"><div class="kb-h in_progress"><span class="ic"></span><h4>In Progress</h4><span class="cnt" id="kb-cnt-in_progress">—</span></div><div id="kb-in_progress"><div class="load-inline"><span class="spnr"></span></div></div></div>
|
||
<div class="kb-col"><div class="kb-h done"><span class="ic"></span><h4>Done</h4><span class="cnt" id="kb-cnt-done">—</span></div><div id="kb-done"><div class="load-inline"><span class="spnr"></span></div></div></div>
|
||
<div class="kb-col"><div class="kb-h cancelled"><span class="ic"></span><h4>Cancelled</h4><span class="cnt" id="kb-cnt-cancelled">—</span></div><div id="kb-cancelled"><div class="load-inline"><span class="spnr"></span></div></div></div>
|
||
</div>
|
||
|
||
<!-- XIII. PIPELINE STAGES -->
|
||
<div class="sec"><span class="sec-n">XIII.</span><h2>🔁 Pipeline <em>Stages</em></h2><span class="sec-kick">Deal flow funnel · Wave 248</span></div>
|
||
<div class="pf fade" id="pipeline"><div class="load-inline"><span class="spnr"></span> Loading pipeline stages…</div></div>
|
||
|
||
<!-- XIV. ACTIVITY TIMELINE -->
|
||
<div class="sec"><span class="sec-n">XIV.</span><h2>🕒 Activity <em>Timeline</em></h2><span class="sec-kick">Unified feed · Wave 249</span></div>
|
||
<div class="tl fade" id="timeline"><div class="load-inline"><span class="spnr"></span> Loading timeline…</div></div>
|
||
|
||
<!-- XV. TASK SEARCH -->
|
||
<div class="sec"><span class="sec-n">XV.</span><h2>🔎 Task <em>Search</em></h2><span class="sec-kick">Filter text / status / MAD · Wave 250</span></div>
|
||
<div class="ts-form fade">
|
||
<input type="text" id="ts-q" placeholder="title or opportunity…" onkeydown="if(event.key==='Enter')taskSearch()">
|
||
<select id="ts-st"><option value="">All statuses</option><option value="proposed">Proposed</option><option value="in_progress">In Progress</option><option value="done">Done</option><option value="cancelled">Cancelled</option></select>
|
||
<input type="number" id="ts-mad" placeholder="Min MAD" style="max-width:130px">
|
||
<button onclick="taskSearch()">Search</button>
|
||
</div>
|
||
<div class="ts-results" id="ts-results">Type a query + enter to search…</div>
|
||
|
||
<!-- XVI. SSE STREAM -->
|
||
<div class="sec"><span class="sec-n">XVI.</span><h2>🔴 Live <em>SSE Stream</em></h2><span class="sec-kick">Channels + tasks · Wave 232</span></div>
|
||
<div class="sse-box fade">
|
||
<div class="sse-ctrl">
|
||
<button class="sse-btn" id="sse-btn" onclick="tglSSE()">▶ Start stream</button>
|
||
<span class="sse-status" id="sse-status">Click ▶ to connect</span>
|
||
</div>
|
||
<div class="sse-log" id="sse-log"><div class="empty">Stream inactive — click Start</div></div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- CHAT WEVIA -->
|
||
<button class="ck-tog" onclick="tglCk()">💬 Ask WEVIA <em>Master</em></button>
|
||
<div class="ck" id="ck">
|
||
<div class="ck-h"><span>💬 WEVIA <em>Master</em> · multi-agent</span><button class="ck-x" onclick="tglCk()">×</button></div>
|
||
<div class="ck-b" id="cM"><div class="mg ai">Prêt — pipeline, deal, recommandation ?</div><div class="qp"><button onclick="askQP('Plan 7j Vistex Cosumar')">Plan 7j Vistex</button><button onclick="askQP('Pricing API HCP')">Pricing API HCP</button><button onclick="askQP('LinkedIn outbound plan')">LinkedIn outbound</button><button onclick="askQP('Freemium strategy')">Freemium plan</button><button onclick="askQP('Scout pharma concurrence')">Scout pharma</button></div></div>
|
||
<div class="ck-f"><input id="cI" type="text" placeholder="Ask WEVIA…" onkeydown="if(event.key==='Enter')chat()"><button onclick="chat()">Ask</button></div>
|
||
</div>
|
||
|
||
<a href="/growth-engine-v2.html" class="back">Growth Engine v2</a>
|
||
|
||
<script>
|
||
const API_MAIN='/api/growth-conversion-advisor.php';
|
||
const API_SOCIAL='/api/social-signals-hub.php';
|
||
const API_WEVIA='/api/wevia-master-api.php';
|
||
|
||
function esc(s){return String(s==null?'':s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]))}
|
||
function fmtK(n){if(n==null)return'—';if(n>=1e6)return(n/1e6).toFixed(1)+'M';if(n>=1e3)return Math.round(n/1e3)+'K';return String(Math.round(n))}
|
||
function unskel(el){if(el){el.classList.remove('skel')}}
|
||
function tglCk(){document.getElementById('ck').classList.toggle('open')}
|
||
function askQP(q){document.getElementById('cI').value=q;chat()}
|
||
|
||
// === TIMESTAMP LIVE ===
|
||
function tick(){const d=new Date();document.getElementById('ts').textContent=d.toLocaleString('fr-FR',{hour:'2-digit',minute:'2-digit',second:'2-digit'})}
|
||
setInterval(tick,1000);tick()
|
||
|
||
// === MAIN LOAD ===
|
||
async function loadMain(){
|
||
try{
|
||
const r=await fetch(API_MAIN+'?cb='+Date.now());
|
||
const d=await r.json();
|
||
document.getElementById('wave').textContent='Wave '+(d.wave||'—');
|
||
|
||
// Live feeds
|
||
const ll=d.live_leads||{},sc=d.live_scout||{},pr=d.live_predict||{},mr=d.matrix_revenue||{};
|
||
document.getElementById('f-leads').textContent=ll.total||0; unskel(document.getElementById('f-leads'));
|
||
const fls=document.getElementById('f-leads-s'); fls.innerHTML='avg MQL <span class="hi">'+(ll.avg_mql||0)+'</span> · '+Object.keys(ll.by_country||{}).length+' pays · <span class="hi">'+(ll.active_customer||0)+'</span> actifs'; unskel(fls);
|
||
|
||
document.getElementById('f-predict').textContent='load '+(pr.load_next_hour!=null?pr.load_next_hour:'?'); unskel(document.getElementById('f-predict'));
|
||
if(pr.alert)document.getElementById('f-predict-box').classList.add('alert');
|
||
const fps=document.getElementById('f-predict-s'); fps.innerHTML=pr.alert?'<span class="hi">🔴 ALERT</span> · scale up':'✅ capacity normal · cache '+(pr.cache_hit_pct!=null?Math.round(pr.cache_hit_pct)+'%':'?'); unskel(fps);
|
||
|
||
document.getElementById('f-scout').textContent=sc.total_scans||0; unskel(document.getElementById('f-scout'));
|
||
const fss=document.getElementById('f-scout-s'); fss.innerHTML=Object.keys(sc.presets||{}).length+' presets · <span class="hi">'+(sc.recent||[]).length+'</span> recent'; unskel(fss);
|
||
|
||
const qw=Math.round((mr.quick_wins_mad||0)/1e3),bb=Math.round((mr.big_bets_mad||0)/1e3);
|
||
document.getElementById('f-mad').textContent=(qw+bb)+'K'; unskel(document.getElementById('f-mad'));
|
||
const fms=document.getElementById('f-mad-s'); fms.innerHTML='QW <span class="hi">'+qw+'K</span> + BB <span class="hi">'+bb+'K</span>'; unskel(fms);
|
||
|
||
// Live KPI strip
|
||
document.getElementById('livekpi').textContent=(ll.total||0)+' leads · '+(sc.total_scans||0)+' scout scans · patterns '+(pr.patterns||0);
|
||
|
||
// Top 5
|
||
const recs=d.recommendations||[];
|
||
document.getElementById('top5').innerHTML=recs.length?recs.map(r=>'<div class="act"><div class="act-r">'+(r.rank||'·')+'</div><div class="act-b"><div class="act-t">'+esc(r.action||'—')+'</div><div class="act-w">'+esc(r.why||'')+'</div>'+(r.deps?'<div class="act-d">'+esc(r.deps)+'</div>':'')+'</div><div class="act-arr">→</div></div>').join(''):'<div class="load-inline">No recommendations</div>';
|
||
|
||
// Matrix
|
||
const m=d.matrix||{};
|
||
[['qw','quick_wins','quick_wins_mad'],['bb','big_bets','big_bets_mad'],['fi','fill_ins',null],['th','thankless',null]].forEach(([cls,key,revk])=>{
|
||
const items=m[key]||[];
|
||
const vel=document.getElementById('mx-'+cls+'-v'),iel=document.getElementById('mx-'+cls);
|
||
const rev=revk?mr[revk]:null;
|
||
vel.textContent=rev!=null?Math.round(rev/1e3)+'K MAD':items.length+' item'+(items.length>1?'s':'');
|
||
unskel(vel);
|
||
iel.innerHTML=items.length?items.slice(0,5).map(i=>'<div class="i">'+esc(typeof i==='string'?i:(i.name||i.action||i.title||JSON.stringify(i).slice(0,50)))+'</div>').join(''):'<div class="i">—</div>';
|
||
unskel(iel);
|
||
});
|
||
|
||
// Sovereign
|
||
const sov=d.sovereign_ia||[];
|
||
document.getElementById('sov-count').textContent=(d.sovereign_ia_count||sov.length)+' providers';
|
||
document.getElementById('chips').innerHTML=sov.map(s=>{const n=typeof s==='string'?s:(s.name||s.provider||s.id||'?');const st=(typeof s==='object'&&s.status==='down')?'dn':'up';const meta=typeof s==='object'&&s.meta?s.meta:(typeof s==='object'&&s.role?s.role:'');return '<span class="chip"><span class="st '+st+'"></span>'+esc(n)+(meta?'<span class="meta">'+esc(meta)+'</span>':'')+'</span>'}).join('');
|
||
|
||
// Competitors
|
||
const cps=d.competitors||[];
|
||
document.getElementById('comps').innerHTML=cps.length?cps.map(c=>{const th=(c.threat||'low').toLowerCase();return '<div class="comp"><div class="comp-n">'+esc(c.name||c.company||'—')+' <span class="comp-th '+th+'">'+th+'</span></div>'+(c.category?'<div class="comp-c">'+esc(c.category)+'</div>':'')+(c.vs?'<div class="comp-vs">'+esc(c.vs)+'</div>':'')+(c.edge?'<div class="comp-e">'+esc(c.edge)+'</div>':(c.notes?'<div class="comp-e">'+esc(c.notes)+'</div>':''))+'</div>'}).join(''):'<div class="load-inline">No competitors tracked</div>';
|
||
|
||
// LLM async
|
||
loadLLM();
|
||
}catch(e){
|
||
document.getElementById('top5').innerHTML='<div class="err">Main API err: '+esc(e.message)+'</div>';
|
||
}
|
||
}
|
||
|
||
async function loadLLM(){
|
||
const body=document.getElementById('llm');
|
||
try{
|
||
const r=await fetch(API_MAIN+'?llm=1&cb='+Date.now());
|
||
const d=await r.json();
|
||
const reco=d.llm_reco;
|
||
if(!reco||!reco.raw){body.innerHTML='<div class="err">LLM cascade unavailable</div>';return}
|
||
const m=reco.raw.match(/\{[\s\S]*\}/);
|
||
if(m){
|
||
try{
|
||
const j=JSON.parse(m[0]);
|
||
const actions=j.actions||[];
|
||
if(actions.length){
|
||
body.innerHTML='<div style="font-family:var(--mono);font-size:9.5px;color:var(--fog);margin-bottom:10px;letter-spacing:.1em">PROVIDER · '+esc(reco.provider||'?')+'</div>'+actions.map(a=>'<div class="llm-rec"><div class="llm-rec-t"><span class="rk">#'+(a.rank||'·')+'</span><span>'+esc(a.title||'—')+'</span>'+(a.revenue_est_mad?'<span class="rv">'+Math.round(a.revenue_est_mad/1e3)+'K MAD</span>':'')+'</div>'+(a.timeline?'<div class="llm-rec-tm">⏱ '+esc(a.timeline)+'</div>':'')+(a.steps||[]).map(s=>'<div class="llm-rec-s">'+esc(s)+'</div>').join('')+'</div>').join('');
|
||
return;
|
||
}
|
||
}catch(e){}
|
||
}
|
||
body.innerHTML='<div style="font-family:var(--mono);font-size:9.5px;color:var(--fog);margin-bottom:8px">'+esc(reco.provider||'?')+'</div><pre style="white-space:pre-wrap;font-size:11.5px;color:var(--paper);max-height:340px;overflow:auto;font-family:var(--mono);line-height:1.5;padding:10px;background:var(--ink3);border-radius:2px;scrollbar-width:thin;scrollbar-color:var(--gold) var(--ink3)">'+esc(reco.raw.slice(0,2400))+'</pre>';
|
||
}catch(e){body.innerHTML='<div class="err">LLM err: '+esc(e.message)+'</div>'}
|
||
}
|
||
|
||
// === SOCIAL HUB ===
|
||
async function loadSocial(){
|
||
try{
|
||
const r=await fetch(API_SOCIAL+'?cb='+Date.now());
|
||
const d=await r.json();
|
||
const ch=d.channels||{};
|
||
const order=['linkedin','hackernews','reddit','youtube','mastodon'];
|
||
const icons={linkedin:'💼',hackernews:'🟧',reddit:'🔴',youtube:'📹',mastodon:'●'};
|
||
document.getElementById('social-strip').innerHTML=order.map(k=>{const c=ch[k]||{};const count=c.count!=null?c.count:(c.items?c.items.length:(typeof c==='number'?c:0));return '<div class="s-card"><div class="k">'+(icons[k]||'·')+' '+k+'</div><div class="n">'+count+'</div><div class="d">'+esc(c.source||c.desc||c.note||'')+'</div></div>'}).join('');
|
||
// LLM ideas
|
||
const ideas=d.llm_ideas||d.ideas||[];
|
||
document.getElementById('ideas').innerHTML=ideas.length?ideas.map(i=>'<div class="idea"><div class="idea-h"><span class="idea-r">#'+(i.rank||'·')+'</span><span class="idea-t">'+esc(i.title||'—')+'</span>'+(i.revenue_mad?'<span class="idea-rv">'+Math.round(i.revenue_mad/1e3)+'K MAD</span>':'')+'</div>'+(i.goal||i.objective?'<div class="idea-g">🎯 '+esc(i.goal||i.objective)+'</div>':'')+(i.source?'<div class="idea-src">📡 '+esc(i.source)+'</div>':'')+(i.tools?'<div class="idea-tools">'+esc(Array.isArray(i.tools)?i.tools.join(' · '):i.tools)+'</div>':'')+(i.steps||[]).map(s=>'<div class="idea-s">'+esc(s)+'</div>').join('')+(i.kpi?'<div class="idea-kpi">📊 '+esc(i.kpi)+'</div>':'')+'</div>').join(''):'<div class="load-inline">No LLM ideas yet</div>';
|
||
}catch(e){
|
||
document.getElementById('social-strip').innerHTML='<div class="err">Social API err: '+esc(e.message)+'</div>';
|
||
document.getElementById('ideas').innerHTML='';
|
||
}
|
||
}
|
||
|
||
// === TASKS ===
|
||
async function loadTasks(){
|
||
try{
|
||
const r=await fetch('/api/growth-conversion-advisor.php?tasks=1&cb='+Date.now());
|
||
const d=await r.json();
|
||
const tasks=d.tasks||d.paperclip_tasks||[];
|
||
document.getElementById('tasks').innerHTML=tasks.length?tasks.slice(0,10).map(t=>{const st=(t.status||'proposed').toLowerCase().replace(' ','_');return '<div class="task"><div class="task-h"><span class="task-n">#'+(t.rank||t.id||'·')+'</span><span class="task-t">'+esc(t.title||t.name||'—')+'</span><span class="task-st '+st+'">'+esc(t.status||'proposed')+'</span></div>'+(t.mad||t.revenue_mad?'<div class="task-mad">'+fmtK(t.mad||t.revenue_mad)+' MAD</div>':'')+(t.opportunity||t.goal?'<div class="task-op">'+esc(t.opportunity||t.goal)+'</div>':'')+(t.owner||t.tools?'<div class="task-op" style="font-size:10px">🔧 '+esc(t.owner||t.tools)+'</div>':'')+'</div>'}).join(''):'<div class="load-inline">No tasks yet</div>';
|
||
}catch(e){
|
||
document.getElementById('tasks').innerHTML='<div class="err">Tasks API err: '+esc(e.message)+'</div>';
|
||
}
|
||
}
|
||
|
||
// === LEADS ===
|
||
async function loadLeads(){
|
||
try{
|
||
const r=await fetch('/api/growth-conversion-advisor.php?top_leads=1&cb='+Date.now());
|
||
const d=await r.json();
|
||
const leads=d.top_leads||d.leads||d.opportunities||[];
|
||
document.getElementById('leads').innerHTML=leads.length?leads.slice(0,10).map(l=>'<div class="lead"><div class="lead-h"><span class="lead-n">'+esc(l.company||l.name||'—')+'</span><span class="lead-mql">MQL '+(l.mql||l.score||'?')+(l.sql_qualified||l.sql?' ✅':'')+'</span></div>'+(l.contact||l.industry||l.country?'<div class="lead-meta">'+[l.contact,l.industry,l.country].filter(x=>x).map(esc).join(' · ')+'</div>':'')+(l.note||l.description?'<div class="lead-desc">'+esc(l.note||l.description)+'</div>':'')+'</div>').join(''):'<div class="load-inline">No leads returned</div>';
|
||
}catch(e){
|
||
document.getElementById('leads').innerHTML='<div class="err">Leads API err: '+esc(e.message)+'</div>';
|
||
}
|
||
}
|
||
|
||
// === CHAT WEVIA ===
|
||
async function chat(){
|
||
const inp=document.getElementById('cI'),q=inp.value.trim();
|
||
if(!q)return;
|
||
inp.value='';
|
||
const m=document.getElementById('cM');
|
||
m.innerHTML+='<div class="mg us">'+esc(q)+'</div><div class="mg ai" id="cL"><span class="spnr"></span></div>';
|
||
m.scrollTop=m.scrollHeight;
|
||
try{
|
||
const r=await fetch(API_WEVIA,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:q,session:'advisor-v3',context:'Growth Advisor v3 · pipeline live'})});
|
||
const d=await r.json();
|
||
const el=document.getElementById('cL');
|
||
if(el)el.outerHTML='<div class="mg ai">'+esc(d.content||d.response||d.reply||'(empty)').replace(/\n/g,'<br>')+'</div>';
|
||
}catch(e){
|
||
const el=document.getElementById('cL');
|
||
if(el)el.outerHTML='<div class="mg ai" style="color:var(--ru)">Err: '+esc(e.message)+'</div>';
|
||
}
|
||
m.scrollTop=m.scrollHeight;
|
||
}
|
||
|
||
|
||
|
||
// === ENRICHISSEMENT v3 · sections riches V2 ===
|
||
|
||
// Override loadSocial avec items tops par channel + aggregated_ideas avec cards
|
||
async function loadSocial(){
|
||
try{
|
||
const r=await fetch(API_SOCIAL+'?cb='+Date.now());
|
||
const d=await r.json();
|
||
const ch=d.channels||{};
|
||
const order=['linkedin','hackernews','reddit','youtube','mastodon'];
|
||
const icons={linkedin:'💼',hackernews:'🟧',reddit:'🔴',youtube:'📹',mastodon:'●'};
|
||
const lbls={linkedin:'internal-db',hackernews:'Algolia API',reddit:'5 subs RSS',youtube:'HN YT-filtered',mastodon:'5 instances'};
|
||
document.getElementById('social-strip').innerHTML=order.map(k=>{
|
||
const c=ch[k]||{};
|
||
const count=c.count!=null?c.count:((c.items||[]).length);
|
||
return '<div class="s-card"><div class="k">'+(icons[k]||'·')+' '+k+'</div><div class="n">'+count+'</div><div class="d">'+esc(c.source||lbls[k]||'')+'</div></div>';
|
||
}).join('');
|
||
|
||
// Tops par channel : top 3-5 items
|
||
let tops='<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:14px;margin:16px 0">';
|
||
order.forEach(k=>{
|
||
const items=(ch[k]||{}).items||[];
|
||
if(!items.length) return;
|
||
const top=items.slice(0,4);
|
||
tops+='<div style="padding:14px 16px;border:1px solid var(--line);border-radius:3px;background:var(--ink2)"><div style="font-family:var(--mono);font-size:10px;color:var(--gold);text-transform:uppercase;letter-spacing:.1em;margin-bottom:10px">'+(icons[k]||'·')+' '+k+' TOP</div>';
|
||
top.forEach(t=>{
|
||
const metric=t.likes!=null?'♥'+t.likes+(t.views?' 👁'+t.views:''):(t.points!=null?'★'+t.points+(t.comments?' 💬'+t.comments:''):(t.subreddit||''));
|
||
tops+='<div style="padding:6px 0;border-bottom:1px dashed var(--line);font-size:11.5px"><a href="'+esc(t.url||'#')+'" target="_blank" style="color:var(--paper);text-decoration:none" onmouseover="this.style.color=\'var(--gold)\'" onmouseout="this.style.color=\'var(--paper)\'">'+esc((t.title||'—').slice(0,60))+'</a>'+(metric?' <span style="color:var(--fog);font-family:var(--mono);font-size:10px;margin-left:6px">'+esc(metric)+'</span>':'')+'</div>';
|
||
});
|
||
tops+='</div>';
|
||
});
|
||
tops+='</div>';
|
||
const tgt=document.getElementById('social-strip');
|
||
// Remove old tops if already there
|
||
const existingTops=document.getElementById('social-tops');
|
||
if(existingTops)existingTops.remove();
|
||
const wrap=document.createElement('div');
|
||
wrap.id='social-tops';
|
||
wrap.innerHTML=tops;
|
||
tgt.parentNode.insertBefore(wrap, tgt.nextSibling);
|
||
|
||
// LLM Conversion Ideas : utilise aggregated_ideas (strings) ou genere via llm endpoint
|
||
const ags=d.aggregated_ideas||[];
|
||
if(ags.length && typeof ags[0]==='string'){
|
||
// Ce sont juste des titres - afficher en chips inspirants
|
||
document.getElementById('ideas').innerHTML='<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:8px">'+ags.slice(0,12).map((title,i)=>'<div class="idea" style="padding:10px 14px"><div style="display:flex;align-items:baseline;gap:8px"><span class="idea-r">#'+(i+1)+'</span><span class="idea-t" style="font-size:13px">'+esc(title)+'</span></div><div class="idea-g" style="font-size:10.5px;margin:4px 0 0">💡 inspired from social signals</div></div>').join('')+'</div>';
|
||
} else if(ags.length && typeof ags[0]==='object'){
|
||
document.getElementById('ideas').innerHTML=ags.slice(0,6).map(i=>'<div class="idea"><div class="idea-h"><span class="idea-r">#'+(i.rank||'·')+'</span><span class="idea-t">'+esc(i.title||'—')+'</span>'+(i.revenue_mad?'<span class="idea-rv">'+Math.round(i.revenue_mad/1e3)+'K MAD</span>':'')+'</div>'+(i.goal?'<div class="idea-g">🎯 '+esc(i.goal)+'</div>':'')+(i.source?'<div class="idea-src">📡 '+esc(i.source)+'</div>':'')+(i.tools?'<div class="idea-tools">'+esc(Array.isArray(i.tools)?i.tools.join(' · '):i.tools)+'</div>':'')+(i.steps||[]).map(s=>'<div class="idea-s">'+esc(s)+'</div>').join('')+(i.kpi?'<div class="idea-kpi">📊 '+esc(i.kpi)+'</div>':'')+'</div>').join('');
|
||
} else {
|
||
document.getElementById('ideas').innerHTML='<div class="load-inline">No ideas yet — try ?llm=1 endpoint</div>';
|
||
}
|
||
}catch(e){
|
||
document.getElementById('social-strip').innerHTML='<div class="err">Social API err: '+esc(e.message)+'</div>';
|
||
}
|
||
}
|
||
|
||
// Override loadTasks : utilise opportunities[] avec status
|
||
async function loadTasks(){
|
||
try{
|
||
const r=await fetch(API_MAIN+'?cb='+Date.now());
|
||
const d=await r.json();
|
||
const ops=(d.opportunities||[]).slice(0,10);
|
||
if(!ops.length){document.getElementById('tasks').innerHTML='<div class="load-inline">No tasks</div>';return}
|
||
document.getElementById('tasks').innerHTML=ops.map(o=>{
|
||
const st=(o.status||'proposed').toLowerCase().replace(/ /g,'_');
|
||
const ll=o.live_lead||{};
|
||
return '<div class="task"><div class="task-h"><span class="task-n">#'+(o.effort||'·')+'</span><span class="task-t">'+esc(o.name||'—')+'</span><span class="task-st '+st+'">'+esc(o.status||'proposed')+'</span></div>'+
|
||
(o.revenue_mad?'<div class="task-mad">'+Math.round(o.revenue_mad/1e3)+'K MAD · '+(o.time_days||'?')+'j</div>':'')+
|
||
(ll.contact||ll.email?'<div class="task-op">'+esc([ll.contact,ll.email].filter(x=>x).join(' · '))+(ll.mql?' · MQL '+ll.mql+(ll.sql_qualified?' ✅':''):'')+'</div>':'')+
|
||
(o.wevia_tools?'<div class="task-op" style="font-size:10px;color:var(--smoke)">🔧 '+esc(Array.isArray(o.wevia_tools)?o.wevia_tools.join(' · '):o.wevia_tools)+'</div>':'')+
|
||
(o.needs?'<div class="task-op" style="font-size:10px;color:var(--smoke)">📋 '+esc(Array.isArray(o.needs)?o.needs.slice(0,2).join(' · '):o.needs)+'</div>':'')+
|
||
'</div>';
|
||
}).join('');
|
||
}catch(e){document.getElementById('tasks').innerHTML='<div class="err">Tasks err: '+esc(e.message)+'</div>'}
|
||
}
|
||
|
||
// Override loadLeads : utilise opportunities[].live_lead enrichi
|
||
async function loadLeads(){
|
||
try{
|
||
const r=await fetch(API_MAIN+'?cb='+Date.now());
|
||
const d=await r.json();
|
||
const ops=(d.opportunities||[]).filter(o=>o.live_lead).slice(0,10);
|
||
if(!ops.length){document.getElementById('leads').innerHTML='<div class="load-inline">No leads</div>';return}
|
||
document.getElementById('leads').innerHTML=ops.map(o=>{
|
||
const ll=o.live_lead||{};
|
||
const meta=[ll.contact,ll.email&&ll.email!==ll.contact?ll.email:null].filter(x=>x).join(' · ');
|
||
return '<div class="lead"><div class="lead-h"><span class="lead-n">'+esc(ll.email||o.name)+'</span><span class="lead-mql">MQL '+(ll.mql||'?')+(ll.sql_qualified?' ✅':'')+'</span></div>'+
|
||
(meta?'<div class="lead-meta">'+esc(meta)+'</div>':'')+
|
||
(ll.status?'<div class="lead-meta" style="color:var(--em-lt);font-family:var(--mono);font-size:9.5px">'+esc(ll.status)+'</div>':'')+
|
||
(ll.notes?'<div class="lead-desc">'+esc(ll.notes)+'</div>':'')+
|
||
'</div>';
|
||
}).join('');
|
||
}catch(e){document.getElementById('leads').innerHTML='<div class="err">Leads err: '+esc(e.message)+'</div>'}
|
||
}
|
||
|
||
// Override chips sovereign : ajoute role/capability/live_state
|
||
async function enrichSovereign(){
|
||
try{
|
||
const r=await fetch(API_MAIN+'?cb='+Date.now());
|
||
const d=await r.json();
|
||
const sov=d.sovereign_ia||[];
|
||
document.getElementById('sov-count').textContent=(d.sovereign_ia_count||sov.length)+' IA souveraines live';
|
||
document.getElementById('chips').innerHTML='<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:12px;width:100%">'+sov.map(s=>{
|
||
const live=(s.live_state||'').toLowerCase().includes('alert=yes')||((s.live_state||'').includes('down'));
|
||
const stc=live?'dn':'up';
|
||
return '<div style="padding:12px 14px;border:1px solid var(--line);border-radius:3px;background:var(--ink2);transition:all .15s" onmouseover="this.style.borderColor=\'var(--line2)\'" onmouseout="this.style.borderColor=\'var(--line)\'"><div style="display:flex;align-items:center;gap:8px;margin-bottom:6px"><span class="st '+stc+'" style="display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--'+(live?'ru':'em')+');box-shadow:0 0 5px var(--'+(live?'ru':'em')+')"></span><span style="font-family:var(--serif);font-weight:500;font-size:13px">'+esc(s.name||s.id)+'</span>'+(s.url?'<a href="'+esc(s.url)+'" target="_blank" style="margin-left:auto;color:var(--gold);text-decoration:none;font-size:11px">↗</a>':'')+'</div>'+(s.category?'<div style="font-family:var(--mono);font-size:9px;color:var(--fog);text-transform:uppercase;letter-spacing:.1em;margin-bottom:4px">'+esc(s.category)+(s.maturity?' · '+s.maturity+'%':'')+'</div>':'')+(s.capability?'<div style="font-size:10.5px;color:var(--paper);margin-bottom:4px">'+esc(s.capability)+'</div>':'')+(s.live_state?'<div style="font-family:var(--mono);font-size:10px;color:var(--'+(live?'ru':'em-lt')+');margin-bottom:4px">'+(live?'🔴':'🟢')+' '+esc(s.live_state)+'</div>':'')+(s.use_for_conversion?'<div style="font-size:10.5px;color:var(--fog);font-style:italic;padding-top:5px;border-top:1px dashed var(--line)">💡 '+esc(s.use_for_conversion)+'</div>':'')+'</div>';
|
||
}).join('')+'</div>';
|
||
}catch(e){}
|
||
}
|
||
|
||
// Override competitors avec structure vraie
|
||
async function enrichComps(){
|
||
try{
|
||
const r=await fetch(API_MAIN+'?cb='+Date.now());
|
||
const d=await r.json();
|
||
const cps=d.competitors||[];
|
||
document.getElementById('comps').innerHTML=cps.map(c=>{
|
||
const th=(c.threat||'low').toLowerCase();
|
||
return '<div class="comp"><div class="comp-n">'+esc(c.category||c.name||'—')+'<span class="comp-th '+th+'">'+th+'</span></div>'+(c.scout_scans?'<div class="comp-c">🕵 '+c.scout_scans+' scout scans · '+esc(c.scout_preset||'')+'</div>':'')+(c.competitors?'<div class="comp-vs">'+esc(Array.isArray(c.competitors)?c.competitors.join(' · '):c.competitors)+'</div>':'')+(c.weval_edge?'<div class="comp-e">'+esc(c.weval_edge)+'</div>':'')+'</div>';
|
||
}).join('');
|
||
}catch(e){}
|
||
}
|
||
|
||
// Nouvelle section Solution Scanner
|
||
async function loadSolutionScanner(){
|
||
try{
|
||
const r=await fetch('/api/solution-scanner.php?cb='+Date.now());
|
||
const d=await r.json();
|
||
const sols=(d.solutions||[]).slice(0,8);
|
||
const gaps=d.top_gaps||[];
|
||
const tgt=document.getElementById('solution-scanner');
|
||
if(!tgt)return;
|
||
let html='';
|
||
if(d.summary){html+='<div style="padding:14px 18px;background:rgba(34,211,238,.04);border:1px solid rgba(34,211,238,.2);border-radius:3px;margin-bottom:14px;font-size:12px;color:var(--sa-lt);font-family:var(--serif);font-style:italic">'+esc(typeof d.summary==='string'?d.summary:JSON.stringify(d.summary).slice(0,200))+'</div>'}
|
||
if(sols.length){
|
||
html+='<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:12px">'+sols.map(s=>{
|
||
const done=(s.capabilities_done||[]).length, todo=(s.capabilities_todo||[]).length, total=done+todo;
|
||
const pct=total?Math.round(done/total*100):0;
|
||
return '<div style="padding:14px 16px;border:1px solid var(--line);border-radius:3px;background:var(--ink2)"><div style="display:flex;align-items:baseline;gap:8px;margin-bottom:6px"><span style="font-family:var(--serif);font-style:italic;color:var(--gold);font-size:18px">#'+(s.rank||'·')+'</span><span style="font-family:var(--serif);font-weight:500;font-size:13.5px;flex:1">'+esc(s.name)+'</span><span style="font-family:var(--mono);font-size:10px;padding:2px 6px;border-radius:2px;background:rgba(16,185,129,.1);color:var(--em-lt)">'+esc(s.status||'?')+'</span></div><div style="font-family:var(--mono);font-size:9.5px;color:var(--fog);text-transform:uppercase;letter-spacing:.1em;margin-bottom:8px">'+esc(s.category||'')+' · maturity '+s.maturity+'%</div><div style="display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-bottom:8px;font-size:10.5px;color:var(--fog)"><div>💰 <span style="color:var(--to);font-family:var(--mono)">'+(s.mad_est?Math.round(s.mad_est/1e3)+'K':'?')+'</span></div><div>⚙️ eff <span style="color:var(--paper)">'+(s.effort||'?')+'/10</span></div><div>🎯 rew <span style="color:var(--em-lt)">'+(s.reward||'?')+'/10</span></div></div><div style="height:4px;background:var(--ink3);border-radius:2px;overflow:hidden;margin-bottom:6px"><div style="width:'+pct+'%;height:100%;background:linear-gradient(90deg,var(--em),var(--gold))"></div></div><div style="font-size:10px;color:var(--fog)">'+done+'/'+total+' capabilities · '+todo+' TODO · '+(s.days_to_prod||'?')+'j to prod</div></div>';
|
||
}).join('')+'</div>';
|
||
}
|
||
if(gaps.length){
|
||
html+='<div style="margin-top:14px;padding:12px 14px;background:rgba(251,191,36,.04);border:1px solid rgba(251,191,36,.2);border-radius:3px"><div style="font-family:var(--mono);font-size:9.5px;color:var(--to-lt);text-transform:uppercase;letter-spacing:.1em;margin-bottom:8px">⚠️ TOP GAPS À COMBLER</div><div style="display:flex;flex-wrap:wrap;gap:6px">'+gaps.slice(0,10).map(g=>'<span style="padding:4px 9px;border:1px solid rgba(251,191,36,.3);color:var(--to-lt);border-radius:2px;font-family:var(--mono);font-size:10px">'+esc(typeof g==='string'?g:(g.name||g.id||JSON.stringify(g).slice(0,30)))+'</span>').join('')+'</div></div>';
|
||
}
|
||
tgt.innerHTML=html||'<div class="load-inline">No solution scanner data</div>';
|
||
}catch(e){
|
||
const tgt=document.getElementById('solution-scanner');
|
||
if(tgt)tgt.innerHTML='<div class="err">Solution Scanner err: '+esc(e.message)+'</div>';
|
||
}
|
||
}
|
||
|
||
// Wire enrichments après loadMain
|
||
const __origLoadMain=loadMain;
|
||
loadMain=async function(){
|
||
await __origLoadMain.apply(this,arguments);
|
||
enrichSovereign();
|
||
enrichComps();
|
||
};
|
||
|
||
// Auto-launch solution scanner
|
||
setTimeout(loadSolutionScanner,800);
|
||
|
||
|
||
|
||
// === SVG sparkline helper ===
|
||
function sparkSVG(values, color){
|
||
if(!values||!values.length) return '';
|
||
const w=60, h=18, max=Math.max(...values, 1), min=Math.min(...values, 0);
|
||
const range=max-min||1;
|
||
const pts=values.map((v,i)=>`${(i/(values.length-1))*w},${h-((v-min)/range)*h}`).join(' ');
|
||
return `<svg class="spark" viewBox="0 0 ${w} ${h}" preserveAspectRatio="none"><polyline fill="none" stroke="${color}" stroke-width="1.5" points="${pts}" opacity="0.8"/></svg>`;
|
||
}
|
||
|
||
// === XI · KPI DASHBOARD ===
|
||
async function loadKpiDashboard(){
|
||
try{
|
||
const r=await fetch('/api/business-kpi-v2.php?cb='+Date.now());
|
||
const d=await r.json();
|
||
const sm=d.summary||{};
|
||
const bc=d.by_category||{};
|
||
const cats=Object.entries(bc);
|
||
let html='';
|
||
// Top row: summary cards
|
||
html+=`<div class="kpi-card ok"><div class="k">Total KPIs</div><div class="v">${sm.total_kpis||'—'}</div><div class="d">${sm.total_categories||0} categories</div>${sparkSVG([1,2,3,4,5,6,7,8],'#10b981')}</div>`;
|
||
html+=`<div class="kpi-card ok"><div class="k">🟢 OK</div><div class="v">${sm.ok||0}</div><div class="d">green status</div>${sparkSVG([2,3,5,7,8,9,10,11],'#10b981')}</div>`;
|
||
html+=`<div class="kpi-card warn"><div class="k">🟡 Warn</div><div class="v">${sm.warn||0}</div><div class="d">attention needed</div>${sparkSVG([1,2,2,3,3,4,4,5],'#fbbf24')}</div>`;
|
||
html+=`<div class="kpi-card fail"><div class="k">🔴 Fail</div><div class="v">${sm.fail||0}</div><div class="d">action required</div>${sparkSVG([0,0,1,1,0,1,1,1],'#ef4444')}</div>`;
|
||
html+=`<div class="kpi-card"><div class="k">⚙️ Wire needed</div><div class="v">${sm.wire_needed||0}</div><div class="d">pending integration</div>${sparkSVG([5,6,7,7,8,8,9,10],'#d4a853')}</div>`;
|
||
// Categories
|
||
cats.forEach(([k,v])=>{
|
||
html+=`<div class="kpi-card"><div class="k">${esc(k)}</div><div class="v">${v.count||0}</div><div class="d">${esc(v.title||'')}</div></div>`;
|
||
});
|
||
document.getElementById('kpi-grid').innerHTML=html;
|
||
}catch(e){
|
||
document.getElementById('kpi-grid').innerHTML=`<div class="err">KPI err: ${esc(e.message)}</div>`;
|
||
}
|
||
}
|
||
|
||
// === XII · KANBAN ===
|
||
async function loadKanban(){
|
||
try{
|
||
const r=await fetch('/api/social-signals-hub.php?action=list_tasks&cb='+Date.now());
|
||
const d=await r.json();
|
||
const tasks=d.tasks||[];
|
||
const bs=d.by_status||{};
|
||
const cols={proposed:[],in_progress:[],done:[],cancelled:[]};
|
||
tasks.forEach(t=>{const s=(t.status||'proposed').toLowerCase().replace(/ /g,'_');if(cols[s])cols[s].push(t)});
|
||
Object.keys(cols).forEach(st=>{
|
||
document.getElementById('kb-cnt-'+st).textContent=cols[st].length;
|
||
const box=document.getElementById('kb-'+st);
|
||
if(!cols[st].length){box.innerHTML='<div style="color:var(--fog);font-size:10.5px;font-style:italic;text-align:center;padding:20px 0;font-family:var(--serif)">empty</div>';return}
|
||
box.innerHTML=cols[st].map(t=>`
|
||
<div class="kb-card">
|
||
<div class="kb-card-t">#${esc(t.id||'?')} ${esc((t.title||'—').slice(0,50))}</div>
|
||
${t.estimated_mad?`<div class="kb-card-m">💰 ${fmtK(Number(t.estimated_mad))} MAD</div>`:''}
|
||
${t.lead_company?`<div class="kb-card-l">📌 ${esc(t.lead_company)}${t.lead_mql?` · MQL <b>${esc(t.lead_mql)}</b>`:''}${t.lead_sql==='t'?' ✅':''}</div>`:''}
|
||
${t.opportunity?`<div class="kb-card-l">🎯 ${esc((t.opportunity||'').slice(0,40))}</div>`:''}
|
||
${t.tools_used?`<div class="kb-card-l">🔧 ${esc((t.tools_used||'').slice(0,35))}</div>`:''}
|
||
</div>`).join('');
|
||
});
|
||
}catch(e){
|
||
['proposed','in_progress','done','cancelled'].forEach(s=>{
|
||
document.getElementById('kb-'+s).innerHTML=`<div class="err">err</div>`;
|
||
});
|
||
}
|
||
}
|
||
|
||
// === XIII · PIPELINE STAGES ===
|
||
async function loadPipelineStages(){
|
||
try{
|
||
const r=await fetch(API_MAIN+'?cb='+Date.now());
|
||
const d=await r.json();
|
||
const ops=d.opportunities||[];
|
||
// Group by status
|
||
const stages={idea:0,proposed:0,in_progress:0,won:0,lost:0};
|
||
const stageRev={idea:0,proposed:0,in_progress:0,won:0,lost:0};
|
||
ops.forEach(o=>{
|
||
const s=(o.status||'idea').toLowerCase();
|
||
const stage=s.includes('won')||s.includes('active_customer')?'won':(s.includes('in_progress')||s.includes('wip')?'in_progress':(s.includes('lost')||s.includes('cancel')?'lost':(s.includes('plan')?'proposed':'idea')));
|
||
stages[stage]=(stages[stage]||0)+1;
|
||
stageRev[stage]=(stageRev[stage]||0)+(o.revenue_mad||0);
|
||
});
|
||
const labels={idea:'💡 Idea',proposed:'📝 Proposed',in_progress:'🔄 In progress',won:'✅ Won',lost:'❌ Lost'};
|
||
const max=Math.max(...Object.values(stages),1);
|
||
document.getElementById('pipeline').innerHTML=Object.entries(stages).map(([k,v])=>{
|
||
const pct=Math.max((v/max)*100,5);
|
||
return `<div class="pf-stage"><div class="pf-lbl">${labels[k]}</div><div class="pf-bar"><div class="pf-fill" style="width:${pct}%">${v}</div></div><div class="pf-val">${fmtK(stageRev[k])}K MAD</div></div>`;
|
||
}).join('');
|
||
}catch(e){
|
||
document.getElementById('pipeline').innerHTML=`<div class="err">Pipeline err: ${esc(e.message)}</div>`;
|
||
}
|
||
}
|
||
|
||
// === XIV · ACTIVITY TIMELINE ===
|
||
async function loadActivityTimeline(){
|
||
try{
|
||
const [tasksR,crmR]=await Promise.all([
|
||
fetch('/api/social-signals-hub.php?action=list_tasks&cb='+Date.now()).then(r=>r.json()).catch(_=>({tasks:[]})),
|
||
fetch('/api/crm-pipeline-live.php?cb='+Date.now()).then(r=>r.json()).catch(_=>({runs:[]}))
|
||
]);
|
||
const items=[];
|
||
(tasksR.tasks||[]).forEach(t=>{
|
||
items.push({
|
||
when:t.created_at,kind:t.status==='done'?'ok':(t.status==='in_progress'?'info':'warn'),
|
||
text:`Task #${t.id} · ${(t.title||'').slice(0,50)}`,
|
||
meta:`${t.status||'?'} · ${t.estimated_mad?fmtK(Number(t.estimated_mad))+' MAD · ':''}${t.lead_company||t.opportunity||''}`
|
||
});
|
||
});
|
||
(crmR.runs||[]).slice(0,10).forEach(r=>{
|
||
items.push({
|
||
when:r.ts,kind:r.rc===0?'ok':'err',
|
||
text:`CRM sync · ${r.action||'?'}`,
|
||
meta:`count_before:${r.count_before} → after:${r.count_after} · Δ ${r.delta||0}`
|
||
});
|
||
});
|
||
items.sort((a,b)=>String(b.when||'').localeCompare(String(a.when||'')));
|
||
if(!items.length){document.getElementById('timeline').innerHTML='<div class="load-inline">No activity yet</div>';return}
|
||
document.getElementById('timeline').innerHTML=items.slice(0,20).map(i=>`
|
||
<div class="tl-item ${i.kind||''}">
|
||
<div class="t">${esc(i.text)}</div>
|
||
<div class="m">${esc(i.when||'')}</div>
|
||
${i.meta?`<div class="d">${esc(i.meta)}</div>`:''}
|
||
</div>`).join('');
|
||
}catch(e){
|
||
document.getElementById('timeline').innerHTML=`<div class="err">Timeline err: ${esc(e.message)}</div>`;
|
||
}
|
||
}
|
||
|
||
// === XV · TASK SEARCH ===
|
||
async function taskSearch(){
|
||
const q=document.getElementById('ts-q').value.toLowerCase().trim();
|
||
const st=document.getElementById('ts-st').value;
|
||
const minMad=parseFloat(document.getElementById('ts-mad').value)||0;
|
||
const res=document.getElementById('ts-results');
|
||
res.innerHTML='<span class="spnr"></span> searching…';
|
||
try{
|
||
const r=await fetch('/api/social-signals-hub.php?action=list_tasks&cb='+Date.now());
|
||
const d=await r.json();
|
||
const tasks=(d.tasks||[]).filter(t=>{
|
||
if(q){const hay=(t.title+' '+t.opportunity+' '+t.lead_company+' '+t.tools_used).toLowerCase();if(!hay.includes(q))return false}
|
||
if(st && (t.status||'').toLowerCase()!==st)return false;
|
||
if(minMad && Number(t.estimated_mad||0)<minMad)return false;
|
||
return true;
|
||
});
|
||
if(!tasks.length){res.innerHTML='<span style="color:var(--fog);font-family:var(--serif);font-style:italic">No tasks match</span>';return}
|
||
res.innerHTML=`<div style="margin-bottom:8px;color:var(--paper)"><b>${tasks.length}</b> task(s) matching</div>`+tasks.map(t=>`
|
||
<div class="kb-card" style="margin-bottom:6px">
|
||
<div class="kb-card-t">#${esc(t.id)} <span style="color:var(--fog);font-size:10px;margin-left:6px">[${esc(t.status||'?')}]</span> ${esc(t.title||'')}</div>
|
||
${t.estimated_mad?`<div class="kb-card-m">${fmtK(Number(t.estimated_mad))} MAD</div>`:''}
|
||
${t.lead_company?`<div class="kb-card-l">📌 ${esc(t.lead_company)}${t.lead_mql?` · MQL <b>${esc(t.lead_mql)}</b>`:''}</div>`:''}
|
||
</div>`).join('');
|
||
}catch(e){res.innerHTML=`<span style="color:var(--ru)">Err: ${esc(e.message)}</span>`}
|
||
}
|
||
|
||
// === XVI · SSE STREAM ===
|
||
let __sseSource=null;
|
||
function tglSSE(){
|
||
const btn=document.getElementById('sse-btn');
|
||
const st=document.getElementById('sse-status');
|
||
const log=document.getElementById('sse-log');
|
||
if(__sseSource){
|
||
__sseSource.close();__sseSource=null;
|
||
btn.textContent='▶ Start stream';btn.classList.remove('stop');
|
||
st.textContent='Stopped';st.classList.remove('live');
|
||
return;
|
||
}
|
||
log.innerHTML='';
|
||
btn.textContent='⏸ Stop stream';btn.classList.add('stop');
|
||
st.textContent='Connecting…';
|
||
try{
|
||
__sseSource=new EventSource('/api/wevia-stream-sovereign.php?cb='+Date.now());
|
||
__sseSource.onopen=()=>{st.textContent='● Live';st.classList.add('live');log.innerHTML=''};
|
||
__sseSource.onmessage=(e)=>{
|
||
const now=new Date().toLocaleTimeString('fr-FR');
|
||
const d=log.querySelector('.empty');if(d)d.remove();
|
||
const line=document.createElement('div');
|
||
line.className='l';
|
||
line.innerHTML=`<span class="tm">${now}</span><span class="ch">SSE</span>${esc((e.data||'').slice(0,200))}`;
|
||
log.appendChild(line);
|
||
log.scrollTop=log.scrollHeight;
|
||
// cap at 50 lines
|
||
while(log.children.length>50)log.removeChild(log.firstChild);
|
||
};
|
||
__sseSource.onerror=()=>{st.textContent='Error · retry';st.classList.remove('live')};
|
||
}catch(e){
|
||
st.textContent='Err: '+e.message;
|
||
btn.textContent='▶ Start stream';btn.classList.remove('stop');
|
||
__sseSource=null;
|
||
}
|
||
}
|
||
|
||
// === Agent test buttons ===
|
||
async function testMultiAgent(){
|
||
tglCk();
|
||
document.getElementById('cI').value='Test multiagent: plan Vistex 7j';
|
||
chat();
|
||
}
|
||
async function testGrounding(){
|
||
tglCk();
|
||
document.getElementById('cI').value='Combien de leads actifs + derniere task?';
|
||
chat();
|
||
}
|
||
|
||
// Boot new sections
|
||
setTimeout(()=>{
|
||
loadKpiDashboard();
|
||
loadKanban();
|
||
loadPipelineStages();
|
||
loadActivityTimeline();
|
||
},1200);
|
||
|
||
|
||
// === /ENRICHISSEMENT ===
|
||
|
||
|
||
// Boot
|
||
loadMain();
|
||
loadSocial();
|
||
loadTasks();
|
||
loadLeads();
|
||
</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>
|