Files
html/enterprise-management.html
2026-04-12 22:57:03 +02:00

234 lines
22 KiB
HTML

<!DOCTYPE html>
<html lang="en"><head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>WEVAL Enterprise Management — SaaS Platform</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@600;700;800;900&display=swap');
:root{--bg:#0a0e1a;--card:#111827;--border:#1e293b;--accent:#c96442;--green:#10b981;--blue:#3b82f6;--purple:#8b5cf6;--yellow:#f59e0b;--red:#ef4444;--cyan:#06b6d4;--text:#e2e8f0;--muted:#64748b;--font:'DM Sans',sans-serif;--mono:'JetBrains Mono',monospace}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--text);font-family:var(--font);overflow-x:hidden}
.topbar{display:flex;align-items:center;justify-content:space-between;padding:12px 24px;background:rgba(17,24,39,.95);border-bottom:1px solid var(--border);position:sticky;top:0;z-index:100;backdrop-filter:blur(12px)}
.logo{font-size:18px;font-weight:700;color:var(--accent)}.logo span{color:var(--text);font-weight:400}
.tabs{display:flex;gap:4px}
.tab{padding:8px 16px;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;color:var(--muted);transition:.2s}
.tab:hover,.tab.act{background:rgba(201,100,66,.15);color:var(--accent)}
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;padding:16px 24px}
.kpi{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:16px;text-align:center}
.kpi .v{font-size:28px;font-weight:700;font-family:var(--mono)}.kpi .l{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:1px;margin-top:4px}
.main{display:grid;grid-template-columns:1fr 1fr;gap:16px;padding:0 24px 24px}
.full{grid-column:1/-1}
.card{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:20px;overflow:hidden}
.card h3{font-size:14px;font-weight:600;margin-bottom:12px;display:flex;align-items:center;gap:8px}
.card h3 .badge{font-size:10px;background:rgba(201,100,66,.2);color:var(--accent);padding:2px 8px;border-radius:99px;font-weight:500}
/* Pipeline */
.pipeline{display:flex;gap:0;overflow-x:auto;padding:8px 0}
.pipe-stage{flex:1;min-width:140px;text-align:center;position:relative;padding:12px 8px}
.pipe-stage::after{content:'→';position:absolute;right:-8px;top:50%;transform:translateY(-50%);color:var(--muted);font-size:18px}
.pipe-stage:last-child::after{display:none}
.pipe-icon{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;margin:0 auto 8px;font-size:18px}
.pipe-name{font-size:12px;font-weight:600}.pipe-count{font-size:10px;color:var(--muted);margin-top:2px}
.pipe-bar{height:3px;border-radius:2px;margin-top:6px}
/* Agent grid */
.agent-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:8px}
.agent{background:rgba(255,255,255,.03);border:1px solid var(--border);border-radius:8px;padding:10px;text-align:center;font-size:11px;transition:.2s}
.agent:hover{border-color:var(--accent);transform:translateY(-2px)}
.agent .icon{font-size:22px;margin-bottom:4px}.agent .name{font-weight:600;font-size:11px}.agent .role{color:var(--muted);font-size:9px}
.agent .dot{width:6px;height:6px;border-radius:50%;display:inline-block;margin-right:4px}
/* n8n */
.n8n-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:8px}
.n8n-wf{background:rgba(59,130,246,.05);border:1px solid rgba(59,130,246,.2);border-radius:8px;padding:12px;font-size:12px}
.n8n-wf .wf-name{font-weight:600;margin-bottom:4px}.n8n-wf .wf-status{font-size:10px;color:var(--green)}
/* Dept sections */
.dept{border-left:3px solid var(--accent);padding-left:16px;margin-bottom:16px}
.dept-name{font-size:16px;font-weight:700;margin-bottom:4px}.dept-sub{font-size:11px;color:var(--muted)}
.view{display:none}.view.act{display:block}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
.card{animation:fadeIn .3s ease}
@media(max-width:768px){.main{grid-template-columns:1fr}.kpis{grid-template-columns:repeat(3,1fr)}}
</style></head><body style="padding-top:60px"><div style="position:fixed;top:0;left:0;right:0;height:28px;background:#ffffffee;z-index:100;display:flex;align-items:center;padding:0 14px;font-family:Nunito,sans-serif;font-size:.65rem;gap:12px;border-bottom:1px solid #e2e8f0;backdrop-filter:blur(8px)"><b style="color:#059669">WEVIA</b></div>
<div style="position:fixed;top:30px;left:0;right:0;display:flex;justify-content:center;gap:5px;padding:4px;z-index:100;background:#f8fafcee;backdrop-filter:blur(8px);font-family:Nunito,sans-serif">
<a href="/agents-archi.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Architecture</a>
<a href="/director-center.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Director</a>
<a href="/wevia-meeting-rooms.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Rooms</a>
<a href="/enterprise-model.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Enterprise</a>
<a href="/agents-ia.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Pyramid</a>
<a href="/director-chat.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Chat</a>
<a href="/l99-brain.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">L99</a>
</div>
<div class="topbar">
<div class="logo">WEVAL <span>Enterprise Management</span></div>
<div class="tabs" id="tabs">
<div class="tab act" onclick="showView('overview')">Overview</div>
<div class="tab" onclick="showView('pipelines')">Pipelines</div>
<div class="tab" onclick="showView('agents')">Agents</div>
<div class="tab" onclick="showView('n8n')">n8n Workflows</div>
<div class="tab" onclick="showView('infra')">Infrastructure</div>
<div class="tab" onclick="showView('saas')">SaaS Products</div>
</div>
<div style="font-family:var(--mono);font-size:12px;color:var(--green)">● LIVE <span id="clock"></span></div>
</div>
<div class="kpis" id="kpis"></div>
<!-- OVERVIEW -->
<div class="view act" id="v-overview"><div class="main" id="overview-content"></div></div>
<!-- PIPELINES -->
<div class="view" id="v-pipelines"><div class="main" id="pipelines-content"></div></div>
<!-- AGENTS -->
<div class="view" id="v-agents"><div class="main" id="agents-content"></div></div>
<!-- N8N -->
<div class="view" id="v-n8n"><div class="main" id="n8n-content"></div></div>
<!-- INFRA -->
<div class="view" id="v-infra"><div class="main" id="infra-content"></div></div>
<!-- SAAS -->
<div class="view" id="v-saas"><div class="main" id="saas-content"></div></div>
<script>
// === DATA ===
const DEPTS = [
{id:'ceo',name:'CEO Office',icon:'👔',color:'#c96442',agents:['CEO','Brain','Orch','TaskMgr','Intro'],pipeline:['Decision','Budget','Strategy','Hiring','Review'],kpi:'1 brief/day'},
{id:'prospect',name:'Prospect & Sales',icon:'🎯',color:'#f59e0b',agents:['Ethica','Analyst','Writer','Proposal','Contract'],pipeline:['Leads','Qualify','Outreach','Convert','Close'],kpi:'1052 leads'},
{id:'consult',name:'Consulting',icon:'🏗️',color:'#3b82f6',agents:['Architect','Planner','DeerFlow','Critic','Translate','Academy','ECC36','Persona6'],pipeline:['Analyse','Design','Propose','Deliver','Support'],kpi:'3 proposals'},
{id:'dev',name:'Dev Lab',icon:'⚡',color:'#8b5cf6',agents:['Executor','Debugger','Reviewer','Designer','WEDROID','Simplifier','Blueprint','DevForge'],pipeline:['Code','Review','Test','Deploy','Monitor'],kpi:'12 deploys/j'},
{id:'infra',name:'Infrastructure',icon:'🖥️',color:'#06b6d4',agents:['Watchdog','Guardian','Blade','GitMaster','Loki'],pipeline:['Monitor','Fix','Deploy','Verify','Report'],kpi:'99.9% uptime'},
{id:'security',name:'Security & Compliance',icon:'🔐',color:'#ef4444',agents:['Security','Verifier','Nuclei'],pipeline:['Scan','Detect','Assess','Remediate','Audit'],kpi:'Grade B (Nuclei+Trivy)'},
{id:'qa',name:'Quality Assurance',icon:'🧪',color:'#10b981',agents:['QA','TestEng','Tracer','Scientist'],pipeline:['Plan','Execute','Analyze','Report','Fix'],kpi:'153/153 NR + 450 L99'},
{id:'pharma',name:'Pharma & Ethica',icon:'💊',color:'#ec4899',agents:['Explore','DocSpec','MiroFish'],pipeline:['Scrape','Validate','Enrich','Campaign','Track'],kpi:'131K+ HCPs (DZ+MA+TN)'},
{id:'ai',name:'AI Engine',icon:'🧠',color:'#a855f7',agents:['Groq','Cerebras','Ollama','Sovereign','ClaudeCode','OpenWebUI','Flowise'],pipeline:['Ingest','Route','Infer','Validate','Deliver'],kpi:'247 AIs benchmarked'},
{id:'mta',name:'Email Infrastructure',icon:'📧',color:'#f97316',agents:['PMTA','KumoMTA','Postfix'],pipeline:['Compose','Route','Deliver','Track','Bounce'],kpi:'3M contacts (5582 standby)'},
{id:'cog',name:'Cognitive Modes',icon:'🎯',color:'#6366f1',agents:['Analysis','Codegen','Creative','Debug','Strategy','Research','Orchestration','TokenEff','BusinessPanel'],pipeline:['Perceive','Process','Generate','Validate','Output'],kpi:'9 modes'},
{id:'oss',name:'OSS Integration',icon:'🌐',color:'#14b8a6',agents:['BrowserUse','OpenClaw','Goose','AIOS','Dify','Mastra','EvoMaster','Activepieces','AEGIS','Prometheus','Flowise','OpenWebUI','CrewAI','LangChain','Scrapy','Supermemory'],pipeline:['Discover','Evaluate','Wire','Test','Deploy'],kpi:'685 tools'},
{id:'saas',name:'SaaS Products',icon:'📦',color:'#0ea5e9',agents:['LeadForge','OutreachAI','MailWarm','ProposalAI','WhatsAppAPI','WEVIA PUB','Manager'],pipeline:['Build','Launch','Sell','Support','Scale'],kpi:'38 tools'},
{id:'cron',name:'Automation',icon:'⏰',color:'#64748b',agents:['EthicaCron','B2BCron','NonRegCron','BackupCron','OSSChain','SkillSync','L99Auto','GuardCron'],pipeline:['Schedule','Execute','Validate','Alert','Log'],kpi:'30+ crons'},
];
const N8N_WORKFLOWS = [
{name:'Ethica HCP Enrichment',trigger:'Cron */6h',nodes:12,status:'active',desc:'Scrape → Validate → Enrich emails/phones → Store PG'},
{name:'B2B Lead Generation',trigger:'Cron */4h',nodes:8,status:'active',desc:'LinkedIn → Email pattern → Verify → CRM'},
{name:'NonReg Watchdog',trigger:'Cron 6h/18h',nodes:6,status:'active',desc:'Run 153 tests → Telegram alert → HTML report'},
{name:'Sovereign AI Router',trigger:'Webhook',nodes:5,status:'active',desc:'Request → Provider select → Inference → Cache → Return'},
{name:'WhatsApp Campaign',trigger:'Manual',nodes:7,status:'ready',desc:'Template → Audience → Send → Track → Report'},
{name:'Email Drip DZ+MA+TN',trigger:'Cron */5min',nodes:9,status:'active',desc:'Queue → Segment → Personalize → Send → Track'},
{name:'OSS Discovery Sync',trigger:'Cron */6h',nodes:6,status:'active',desc:'GitHub scan → Evaluate → Wire Paperclip → Alert'},
{name:'DeerFlow Research',trigger:'Webhook',nodes:8,status:'active',desc:'Query → Multi-source → Synthesize → Report → Store'},
{name:'Paperclip Agent Chain',trigger:'API',nodes:10,status:'active',desc:'Trigger → Select agent → Execute → Report → Learn'},
{name:'Azure AD O365 Sync',trigger:'Cron daily',nodes:5,status:'active',desc:'Check tenants → Sync accounts → Refresh tokens → Report'},
{name:'Guardian Auto-Heal',trigger:'Cron */5min',nodes:4,status:'active',desc:'Check services → Detect failure → Auto-restart → Alert'},
{name:'Stripe Billing',trigger:'Webhook',nodes:6,status:'ready',desc:'Event → Process payment → Update status → Invoice → Email'},
{name:'L99 Alive Monitor',trigger:'Cron */30min',nodes:7,status:'active',desc:'Scan → Playwright test → Screenshots → Infra check → Telegram'},
{name:'Backup & GOLD',trigger:'Cron daily 4am',nodes:5,status:'active',desc:'PG dump → GOLD snapshot → S3 upload → Verify → Clean old'},
{name:'IP Warmup Pipeline',trigger:'Cron daily',nodes:8,status:'active',desc:'Select IPs → Ramp volume → Monitor reputation → Adjust → Report'},
];
const INFRA = {
servers:[
{name:'S204',ip:'204.168.152.13',role:'Primary Web',disk:'83%',docker:20,services:['nginx','php-fpm','postgresql','ollama','sovereign','paperclip','deerflow']},
{name:'S95',ip:'95.216.167.89',role:'Email/Arsenal',disk:'65%',docker:4,services:['PMTA:25','KumoMTA:587','Postfix:2525','Sentinel:5890','PostgreSQL:5432']},
{name:'S151',ip:'151.80.235.110',role:'Tracking/Relay',disk:'45%',docker:2,services:['OpenClaw','Ollama','Tracking relay']},
{name:'Blade',ip:'Desktop',role:'Agent Desktop',disk:'N/A',docker:0,services:['Sentinel Agent','PowerShell','Claude Code']},
],
docker:['authentik-server','authentik-worker','authentik-db','plausible','plausible-events','plausible-db','uptime-kuma','mattermost','searxng','loki','twenty-redis','paperclip','openwebui','flowise','vaultwarden','n8n','qdrant','redis'],
ports:[9090,9443,8000,8001,3000,3100,3102,3033,5678,6333,6380,8222,8281,11435,4000]
};
const SAAS_PRODUCTS = [
{name:'WEVIA PUBLIC',desc:'AI Chat Widget + Command Center',modules:71,status:'live'},
{name:'WEVADS IA',desc:'Omnichannel Email Intelligence',pages:81,status:'live'},
{name:'Ethica HCP',desc:'Pharma Healthcare Professional Platform',hcps:'132K',status:'live'},
{name:'Sovereign Claude',desc:'Multi-provider AI Gateway',providers:6,status:'live'},
{name:'LeadForge',desc:'B2B Lead Generation Engine',leads:'1052',status:'live'},
{name:'MailWarm',desc:'IP Warmup & Reputation Manager',accounts:2036,status:'live'},
{name:'OutreachAI',desc:'AI-Powered Email Sequences',templates:50,status:'live'},
{name:'ProposalAI',desc:'Smart Proposal Generator',formats:3,status:'beta'},
{name:'Arsenal',desc:'192 Tools Security Platform',tools:192,status:'live'},
{name:'DeerFlow',desc:'Deep Research AI Agent',skills:528,status:'live'},
{name:'Paperclip',desc:'150-Agent AI Organization',agents:150,status:'live'},
{name:'WhatsApp API',desc:'Meta Business Messaging',mode:'LIVE',status:'live'},
];
// === RENDER ===
function renderKPIs(){
const kpis=[
{v:'150',l:'Agents',c:'var(--accent)'},{v:'25',l:'Departments',c:'var(--blue)'},
{v:'15',l:'n8n Workflows',c:'var(--purple)'},{v:'685',l:'OSS Tools',c:'var(--cyan)'},
{v:'3M',l:'Contacts',c:'var(--yellow)'},{v:'132K',l:'HCPs',c:'var(--green)'},
{v:'20',l:'Docker',c:'var(--red)'},{v:'93%',l:'L99 Score',c:'var(--accent)'},
{v:'12',l:'SaaS Products',c:'var(--blue)'},{v:'528',l:'Skills',c:'var(--purple)'}
];
document.getElementById('kpis').innerHTML=kpis.map(k=>`<div class="kpi"><div class="v" style="color:${k.c}">${k.v}</div><div class="l">${k.l}</div></div>`).join('');
}
function renderPipeline(stages,color){
return `<div class="pipeline">${stages.map((s,i)=>`<div class="pipe-stage"><div class="pipe-icon" style="background:${color}22;color:${color}">${i+1}</div><div class="pipe-name">${s}</div><div class="pipe-bar" style="background:linear-gradient(90deg,${color},${color}44);width:${70+Math.random()*30}%"></div></div>`).join('')}</div>`;
}
function renderOverview(){
let html='';
DEPTS.forEach(d=>{
html+=`<div class="card"><h3>${d.icon} ${d.name} <span class="badge">${d.agents.length} agents</span> <span class="badge" style="background:rgba(16,185,129,.2);color:var(--green)">${d.kpi}</span></h3>${renderPipeline(d.pipeline,d.color)}<div style="display:flex;flex-wrap:wrap;gap:4px;margin-top:8px">${d.agents.map(a=>`<span style="font-size:10px;background:${d.color}15;color:${d.color};padding:2px 8px;border-radius:4px">${a}</span>`).join('')}</div></div>`;
});
document.getElementById('overview-content').innerHTML=html;
}
function renderPipelines(){
let html=`<div class="card full"><h3>🔄 All Business Pipelines <span class="badge">${DEPTS.length} pipelines</span></h3>`;
DEPTS.forEach(d=>{
html+=`<div class="dept"><div class="dept-name">${d.icon} ${d.name}</div><div class="dept-sub">${d.agents.length} agents → ${d.kpi}</div>${renderPipeline(d.pipeline,d.color)}</div>`;
});
html+=`</div>`;
// n8n integration
html+=`<div class="card full"><h3>⚙️ n8n Workflow Pipelines <span class="badge">${N8N_WORKFLOWS.length} workflows</span></h3><div class="n8n-grid">${N8N_WORKFLOWS.map(w=>`<div class="n8n-wf"><div class="wf-name">⚙️ ${w.name}</div><div style="font-size:10px;color:var(--muted)">${w.trigger}${w.nodes} nodes</div><div class="wf-status">${w.status==='active'?'● Active':'○ Ready'}</div><div style="font-size:10px;color:var(--text);margin-top:4px;opacity:.7">${w.desc}</div></div>`).join('')}</div></div>`;
document.getElementById('pipelines-content').innerHTML=html;
}
function renderAgents(){
let html='';
DEPTS.forEach(d=>{
html+=`<div class="card"><h3>${d.icon} ${d.name} <span class="badge">${d.agents.length}</span></h3><div class="agent-grid">${d.agents.map(a=>`<div class="agent"><div class="icon">${d.icon}</div><div class="name">${a}</div><div class="role">${d.id}</div><div><span class="dot" style="background:var(--green)"></span><span style="font-size:9px;color:var(--green)">Active</span></div></div>`).join('')}</div></div>`;
});
document.getElementById('agents-content').innerHTML=html;
}
function renderN8N(){
let html=`<div class="card full"><h3>⚙️ n8n Automation Hub <span class="badge">${N8N_WORKFLOWS.length} workflows</span> <span class="badge" style="background:rgba(16,185,129,.2);color:var(--green)">${N8N_WORKFLOWS.filter(w=>w.status==='active').length} active</span></h3>`;
N8N_WORKFLOWS.forEach(w=>{
const color=w.status==='active'?'var(--green)':'var(--yellow)';
html+=`<div style="display:flex;align-items:center;gap:12px;padding:12px;border-bottom:1px solid var(--border)"><div style="width:8px;height:8px;border-radius:50%;background:${color}"></div><div style="flex:1"><div style="font-weight:600;font-size:13px">${w.name}</div><div style="font-size:11px;color:var(--muted)">${w.desc}</div></div><div style="text-align:right"><div style="font-family:var(--mono);font-size:11px;color:${color}">${w.status.toUpperCase()}</div><div style="font-size:10px;color:var(--muted)">${w.trigger}${w.nodes} nodes</div></div></div>`;
});
html+=`</div>`;
document.getElementById('n8n-content').innerHTML=html;
}
function renderInfra(){
let html=`<div class="card full"><h3>🖥️ Servers <span class="badge">${INFRA.servers.length}</span></h3><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:12px">${INFRA.servers.map(s=>`<div style="background:rgba(255,255,255,.02);border:1px solid var(--border);border-radius:10px;padding:16px"><div style="display:flex;justify-content:space-between;margin-bottom:8px"><span style="font-weight:700">${s.name}</span><span style="font-family:var(--mono);font-size:11px;color:var(--muted)">${s.ip}</span></div><div style="font-size:11px;color:var(--accent);margin-bottom:4px">${s.role}</div><div style="font-size:10px;color:var(--muted)">Disk: ${s.disk} | Docker: ${s.docker}</div><div style="display:flex;flex-wrap:wrap;gap:3px;margin-top:6px">${s.services.map(sv=>`<span style="font-size:9px;background:var(--green)15;color:var(--green);padding:1px 6px;border-radius:3px">${sv}</span>`).join('')}</div></div>`).join('')}</div></div>`;
html+=`<div class="card"><h3>🐳 Docker Containers <span class="badge">${INFRA.docker.length}</span></h3><div style="display:flex;flex-wrap:wrap;gap:6px">${INFRA.docker.map(d=>`<span style="font-size:11px;background:rgba(16,185,129,.1);color:var(--green);padding:4px 10px;border-radius:6px;border:1px solid rgba(16,185,129,.2)">● ${d}</span>`).join('')}</div></div>`;
html+=`<div class="card"><h3>🔌 Active Ports <span class="badge">${INFRA.ports.length}</span></h3><div style="display:flex;flex-wrap:wrap;gap:6px">${INFRA.ports.map(p=>`<span style="font-family:var(--mono);font-size:11px;background:rgba(59,130,246,.1);color:var(--blue);padding:4px 10px;border-radius:6px">:${p}</span>`).join('')}</div></div>`;
document.getElementById('infra-content').innerHTML=html;
}
function renderSaaS(){
let html=`<div class="card full"><h3>📦 SaaS Product Suite <span class="badge">${SAAS_PRODUCTS.length} products</span></h3><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px">${SAAS_PRODUCTS.map(p=>`<div style="background:rgba(255,255,255,.02);border:1px solid var(--border);border-radius:10px;padding:16px"><div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px"><span style="font-weight:700;font-size:14px">${p.name}</span><span style="font-size:10px;background:${p.status==='live'?'rgba(16,185,129,.2)':'rgba(245,158,11,.2)'};color:${p.status==='live'?'var(--green)':'var(--yellow)'};padding:2px 8px;border-radius:4px">${p.status.toUpperCase()}</span></div><div style="font-size:12px;color:var(--muted);margin-bottom:8px">${p.desc}</div><div style="font-size:11px;color:var(--accent)">${Object.entries(p).filter(([k])=>!['name','desc','status'].includes(k)).map(([k,v])=>`${k}: ${v}`).join(' • ')}</div></div>`).join('')}</div></div>`;
document.getElementById('saas-content').innerHTML=html;
}
function showView(id){
document.querySelectorAll('.view').forEach(v=>v.classList.remove('act'));
document.querySelectorAll('.tab').forEach(t=>t.classList.remove('act'));
document.getElementById('v-'+id).classList.add('act');
event.target.classList.add('act');
}
// Clock
setInterval(()=>{document.getElementById('clock').textContent=new Date().toLocaleTimeString()},1000);
// Init
renderKPIs();renderOverview();renderPipelines();renderAgents();renderN8N();renderInfra();renderSaaS();
</script>
</body></html>