Core-Agentic-ERP / index.html
fivetech's picture
Update index.html
6070a7b verified
Raw History Blame Contribute Delete
133 kB
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Core, el núcleo de un ERP Agéntico | Operaciones Inteligentes 2030</title>
<meta name="description" content="Core, el núcleo de un ERP Agéntico: demo local de operaciones con agentes ALPHA, BETA y GAMMA, cumplimiento por país y datos ficticios en SQLite.">
<meta property="og:title" content="Core, el núcleo de un ERP Agéntico | Operaciones Inteligentes 2030">
<meta property="og:description" content="Demo local con agentes de inventario, pedidos y proveedores; datos ficticios solo en tu navegador.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://fivetechsoft.github.io/Core/">
<script defer src="vendor/chart.js/4.4.8/chart.umd.js"></script>
<script src="vendor/sql.js/1.13.0/sql-wasm.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', system-ui, sans-serif;
background: #0a0e17;
color: #e0e6ed;
min-height: 100vh;
overflow-x: hidden;
background-image:
radial-gradient(ellipse at 70% 20%, rgba(30, 60, 120, 0.4) 0%, transparent 50%),
radial-gradient(ellipse at 20% 80%, rgba(20, 40, 80, 0.3) 0%, transparent 50%),
linear-gradient(180deg, #0a0e17 0%, #0d1525 100%);
}
.bg-city {
position: fixed;
inset: 0;
background:
radial-gradient(ellipse 65% 48% at 80% 8%, rgba(52, 82, 151, .23), transparent 74%),
radial-gradient(ellipse 50% 58% at 24% 82%, rgba(37, 80, 114, .14), transparent 72%),
linear-gradient(160deg, #090f1d 0%, #0c172b 54%, #080e19 100%);
z-index: 0;
pointer-events: none;
}
.container {
position: relative;
z-index: 1;
display: flex;
min-height: 100vh;
padding: 20px;
gap: 16px;
}
/* ===== SIDEBAR ===== */
.sidebar {
width: 220px;
background: rgba(12, 18, 32, 0.92);
border: 1px solid rgba(80, 140, 255, 0.25);
border-radius: 16px;
padding: 18px 12px;
display: flex;
flex-direction: column;
gap: 4px;
backdrop-filter: blur(12px);
box-shadow: 0 0 30px rgba(40, 100, 255, 0.15);
}
.logo {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px 18px;
border-bottom: 1px solid rgba(80, 140, 255, 0.2);
margin-bottom: 10px;
}
.logo-icon {
width: 36px;
height: 36px;
background: linear-gradient(135deg, #3b82f6, #8b5cf6);
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 14px;
color: white;
box-shadow: 0 0 15px rgba(99, 102, 241, 0.5);
}
.logo-text {
font-size: 18px;
font-weight: 700;
letter-spacing: 1px;
background: linear-gradient(90deg, #60a5fa, #a78bfa);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.nav-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-radius: 10px;
cursor: pointer;
font-size: 13.5px;
font-weight: 500;
color: #94a3b8;
transition: all 0.2s;
}
.nav-item:hover {
background: rgba(59, 130, 246, 0.12);
color: #e0e6ed;
}
.nav-item.active {
background: linear-gradient(90deg, rgba(59, 130, 246, 0.25), rgba(139, 92, 246, 0.15));
color: #60a5fa;
border: 1px solid rgba(96, 165, 250, 0.3);
}
.nav-item .icon {
width: 18px;
text-align: center;
font-size: 15px;
}
/* ===== MAIN PANEL ===== */
.main {
flex: 1;
display: flex;
flex-direction: column;
gap: 14px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
background: rgba(12, 18, 32, 0.9);
border: 1px solid rgba(80, 140, 255, 0.3);
border-radius: 14px;
padding: 12px 20px;
backdrop-filter: blur(10px);
}
.header-title h1 {
font-size: 18px;
font-weight: 600;
letter-spacing: 0.5px;
}
.header-title h1 {position:relative;display:inline-block;overflow:hidden}.header-title h1::after{content:'';position:absolute;inset:-5px auto -5px -60%;width:35%;background:linear-gradient(95deg,transparent,#effbff55,transparent);transform:skewX(-22deg);animation:ap-title-shimmer 13s ease-in-out infinite;pointer-events:none}@keyframes ap-title-shimmer{0%,45%,100%{left:-60%;opacity:0}49%{opacity:1}85%{left:135%;opacity:1}90%{opacity:0}}body[data-theme="light"] .header-title h1::after{background:linear-gradient(95deg,transparent,#548cd65e,transparent)}@media(prefers-reduced-motion:reduce){.header-title h1::after{animation:none;display:none}}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.header-right .notif {
width: 36px;
height: 36px;
border-radius: 50%;
background: rgba(59, 130, 246, 0.15);
border: 1px solid rgba(96, 165, 250, 0.3);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative;
}
.header-right .notif::after {
content: '';
position: absolute;
top: 6px;
right: 8px;
width: 8px;
height: 8px;
background: #ef4444;
border-radius: 50%;
border: 2px solid #0c1220;
}
.avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: linear-gradient(135deg, #6366f1, #a855f7);
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 14px;
}
.metrics {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
}
.metric-card {
background: rgba(12, 18, 32, 0.9);
border: 1px solid rgba(80, 140, 255, 0.25);
border-radius: 14px;
padding: 16px 18px;
backdrop-filter: blur(10px);
position: relative;
overflow: hidden;
}
.metric-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, #3b82f6, #8b5cf6);
}
.metric-label {
font-size: 12px;
color: #94a3b8;
margin-bottom: 6px;
font-weight: 500;
}
.metric-value {
font-size: 26px;
font-weight: 700;
letter-spacing: -0.5px;
}
.metric-change {
font-size: 12px;
margin-top: 4px;
display: flex;
align-items: center;
gap: 4px;
}
.metric-change.up { color: #22c55e; }
.metric-change.neutral { color: #60a5fa; }
.mid-row {
display: grid;
grid-template-columns: 280px 1fr;
gap: 12px;
}
.agents-card, .alerts-card {
background: rgba(12, 18, 32, 0.9);
border: 1px solid rgba(80, 140, 255, 0.25);
border-radius: 14px;
padding: 16px;
backdrop-filter: blur(10px);
}
.section-title {
font-size: 13px;
font-weight: 600;
color: #94a3b8;
margin-bottom: 12px;
text-transform: uppercase;
letter-spacing: 0.8px;
}
.agent-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-radius: 10px;
background: rgba(30, 41, 59, 0.5);
margin-bottom: 8px;
border: 1px solid rgba(80, 140, 255, 0.15);
}
.agent-badge {
width: 28px;
height: 28px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 12px;
color: white;
}
.agent-badge.a { background: linear-gradient(135deg, #3b82f6, #2563eb); }
.agent-badge.b { background: linear-gradient(135deg, #8b5cf6, #7c3aed); }
.agent-badge.g { background: linear-gradient(135deg, #06b6d4, #0891b2); }
.agent-info { flex: 1; }
.agent-name { font-size: 13px; font-weight: 600; }
.agent-role { font-size: 11px; color: #94a3b8; }
.agent-status {
font-size: 11px;
color: #22c55e;
font-weight: 500;
display: flex;
align-items: center;
gap: 4px;
}
.agent-status::before {
content: '';
width: 6px;
height: 6px;
background: #22c55e;
border-radius: 50%;
box-shadow: 0 0 6px #22c55e;
}
.alert-item {
display: flex;
gap: 10px;
padding: 10px 12px;
border-radius: 10px;
margin-bottom: 8px;
background: rgba(30, 41, 59, 0.4);
border-left: 3px solid;
}
.alert-item.low { border-color: #f59e0b; }
.alert-item.anomaly { border-color: #ef4444; }
.alert-item.risk { border-color: #22c55e; }
.alert-icon { font-size: 16px; margin-top: 2px; }
.alert-content { flex: 1; }
.alert-title { font-size: 13px; font-weight: 600; margin-bottom: 2px; }
.alert-desc { font-size: 12px; color: #94a3b8; line-height: 1.4; }
.alert-desc strong { color: #60a5fa; }
.charts-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.chart-card {
background: rgba(12, 18, 32, 0.9);
border: 1px solid rgba(80, 140, 255, 0.25);
border-radius: 14px;
padding: 16px;
backdrop-filter: blur(10px);
height: 260px;
}
.chart-card h3 {
font-size: 13px;
font-weight: 600;
color: #94a3b8;
margin-bottom: 10px;
text-transform: uppercase;
letter-spacing: 0.6px;
}
.chart-container {
height: calc(100% - 30px);
position: relative;
}
/* ===== CHAT WINDOW (MOVIBLE) ===== */
.chat-window {
position: fixed;
resize: both;
min-width: 320px;
min-height: 280px;
max-width: calc(100vw - 20px);
max-height: calc(100vh - 20px);
bottom: 30px;
left: 250px;
width: 380px;
background: rgba(12, 18, 32, 0.95);
border: 1px solid rgba(139, 92, 246, 0.4);
border-radius: 16px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5), 0 0 30px rgba(139, 92, 246, 0.2);
overflow: hidden;
z-index: 100;
backdrop-filter: blur(16px);
user-select: none; /* evita selección de texto mientras se arrastra */
}
.chat-header {
background: linear-gradient(90deg, rgba(99, 102, 241, 0.3), rgba(139, 92, 246, 0.2));
padding: 12px 16px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(139, 92, 246, 0.3);
cursor: grab; /* indica que se puede arrastrar */
}
.chat-header:active {
cursor: grabbing;
}
.chat-header h4 {
font-size: 13px;
font-weight: 600;
display: flex;
align-items: center;
gap: 8px;
}
.chat-header .close {
width: 24px;
height: 24px;
border-radius: 50%;
background: rgba(255,255,255,0.1);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 12px;
}
.chat-body {
padding: 14px;
display: flex;
flex-direction: column;
gap: 12px;
height: calc(100% - 150px);
min-height: 120px;
overflow-y: auto;
user-select: text; /* permite seleccionar texto en los mensajes */
}
.chat-msg {
max-width: 90%;
padding: 10px 14px;
border-radius: 12px;
font-size: 13px;
line-height: 1.45;
}
.chat-msg.user {
align-self: flex-end;
background: rgba(59, 130, 246, 0.25);
border: 1px solid rgba(96, 165, 250, 0.3);
border-bottom-right-radius: 4px;
}
.chat-msg.ai {
align-self: flex-start;
background: rgba(30, 41, 59, 0.8);
border: 1px solid rgba(139, 92, 246, 0.25);
border-bottom-left-radius: 4px;
}
.chat-msg p{margin:0 0 8px}.chat-msg p:last-child{margin-bottom:0}.chat-msg ul{margin:5px 0 8px 20px;padding:0}.chat-msg li{margin:3px 0}.chat-msg code{font:12px ui-monospace,SFMono-Regular,monospace;background:#34476655;border-radius:3px;padding:1px 3px;overflow-wrap:anywhere}.chat-msg pre{white-space:pre-wrap;overflow-wrap:anywhere;background:#0c172b;border-radius:7px;padding:8px;margin:7px 0}.chat-msg pre code{background:transparent;padding:0}.chat-msg strong{font-weight:700}.ap-demo-warning{color:#f8cc82;font-size:11px;line-height:1.45;margin:10px 0}.ap-demo-badge{display:block;color:#f8cc82;font-size:9px;letter-spacing:.04em;font-weight:700;margin-top:4px;line-height:1.3;overflow-wrap:anywhere}body[data-theme="light"] .ap-demo-warning,body[data-theme="light"] .ap-demo-badge{color:#85551c}
.chat-msg.ai .agent-tag {
color: #a78bfa;
font-weight: 600;
}
.chat-footer {
padding: 10px 14px 14px;
display: flex;
gap: 8px;
}
.chat-footer input {
flex: 1;
background: rgba(30, 41, 59, 0.6);
border: 1px solid rgba(80, 140, 255, 0.25);
border-radius: 10px;
padding: 10px 14px;
color: #e0e6ed;
font-size: 13px;
outline: none;
}
.chat-footer input::placeholder {
color: #64748b;
}
.chat-footer button.ap-mic.is-listening {background:#dc315c;box-shadow:0 0 0 4px rgba(220,49,92,.19);animation:ap-mic-pulse 1.3s ease-in-out infinite;}
@keyframes ap-mic-pulse {50%{box-shadow:0 0 0 9px rgba(220,49,92,.04)}}
@media(prefers-reduced-motion:reduce){.chat-footer button.ap-mic.is-listening{animation:none}}
.chat-footer button {
background: linear-gradient(135deg, #6366f1, #8b5cf6);
border: none;
border-radius: 10px;
width: 40px;
color: white;
cursor: pointer;
font-size: 16px;
}
.projector {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
width: 120px;
height: 20px;
background: radial-gradient(ellipse, rgba(59, 130, 246, 0.6), transparent 70%);
border-radius: 50%;
box-shadow: 0 0 40px rgba(59, 130, 246, 0.5);
z-index: 5;
}
@media (max-width: 1200px) {
.metrics { grid-template-columns: repeat(2, 1fr); }
.mid-row { grid-template-columns: 1fr; }
.charts-row { grid-template-columns: 1fr; }
.chat-window { left: 20px; width: 340px; }
}
.ap-human { border: 1px solid rgba(96,165,250,.4); background: rgba(59,130,246,.17); border-radius:50%; width:36px; height:36px; font-size:20px; cursor:pointer; color:#fff; }
.ap-human:hover { background:rgba(59,130,246,.38); }
.chat-window { height: 340px; }
#ap-chat-panel { height:calc(100% - 86px); display:flex; flex-direction:column; }
#ap-chat-panel .chat-body { flex:1; height:auto; min-height:80px; }
#ap-supervision-panel { height:calc(100% - 86px); }
.ap-model-bar { display:flex; align-items:center; gap:8px; padding:6px 10px; background:#17213a; border-bottom:1px solid #344361; font-size:.8em; }
.ap-model-bar button { background:#2b7fff; color:#fff; border:0; border-radius:6px; padding:5px 10px; cursor:pointer; font-size:.92em; }
.ap-model-bar button:disabled { opacity:.5; cursor:default; }
.ap-model-bar span { color:#9fb3d1; }
.ap-model-progress { height:6px; background:#0e1526; }
.ap-model-progress div { height:100%; width:0%; background:#2b7fff; transition:width .3s; }
body[data-theme="light"] .ap-model-bar { background:#eef3fb; border-color:#c9d6e8; }
body[data-theme="light"] .ap-model-bar span { color:#4a5f7d; }
body[data-theme="light"] .ap-model-progress { background:#dbe4f0; }
.ap-tabs { display:flex; border-bottom:1px solid #344361; }.ap-tabs button { flex:1; background:#17213a; color:#e0e6ed; border:0; padding:10px; cursor:pointer; }
[hidden] { display:none !important; }
#ap-supervision-panel { padding:12px; overflow:auto; user-select:text; }
.ap-panel-title { font-size:12px; text-transform:uppercase; font-weight:700; color:#a5b4fc; margin:10px 0; }
#ap-state { font-size:12px; margin:9px 0; color:#94a3b8; }
#ap-stock,#ap-orders { max-height:92px; overflow:auto; margin:8px 0; }
.ap-line { font-size:12px; padding:5px 0; border-bottom:1px solid #30415a; }
.ap-warn { color:#fbbf24; }
.ap-action,.ap-proposal button { background:#183d70; border:1px solid #4079be; color:#fff; border-radius:6px; padding:6px 10px; cursor:pointer; margin:4px 5px 4px 0; }
.ap-action:hover,.ap-proposal button:hover { background:#29508a; }
.ap-proposal { border-left:3px solid #4e95ec; padding:8px; margin:7px 0; background:#101e32; font-size:12px; line-height:1.5; }
.ap-proposal small { color:#aabbd0; }.ap-status { color:#fbbf24; }
@media (max-width: 800px) { .chat-window { max-width:calc(100vw - 20px); left:10px; } }
.ap-mode { padding:7px 10px; border:1px solid #4e75aa; background:#152743; color:#dbeafe; border-radius:10px; white-space:nowrap; cursor:pointer; font-size:12px; font-weight:600; }
.ap-mode[aria-pressed="true"] { border-color:#17a58a; background:#114237; color:#b8fce5; }
@media (max-width:800px) { .header-right { gap:5px; }.ap-mode { max-width:105px; overflow:hidden; text-overflow:ellipsis; } }
.ap-dialog { position:fixed; inset:0; z-index:999; background:rgba(4,8,17,.78); display:grid; place-items:center; padding:15px; }
.ap-dialog form { width:min(440px,100%); background:#15213a; border:1px solid #5471a1; border-radius:14px; padding:22px; box-shadow:0 20px 60px #0009; }
.ap-dialog h3 {font-size:17px; margin-bottom:9px;}.ap-dialog p {font-size:13px; color:#bdc8dc; line-height:1.5; margin-bottom:14px;}
.ap-dialog label {display:block; font-size:13px; margin:10px 0;}.ap-dialog input,.ap-dialog textarea {display:block; width:100%; padding:9px; margin-top:5px; background:#0c1428; border:1px solid #4e658b; color:#fff; border-radius:6px; font:inherit;}
.ap-dialog-buttons {display:flex; justify-content:flex-end; gap:8px; margin-top:15px;}.ap-dialog button {background:#24528e; color:white; border:1px solid #5780ba; border-radius:6px; padding:8px 12px; cursor:pointer;}
#ap-cycle { color:#8ba6c9; font-size:11px; margin:5px 0; }
#ap-feed { max-height:135px; overflow:auto; border-top:1px solid #30415a; }
.ap-feed-item { display:flex; align-items:baseline; gap:7px; border-bottom:1px solid #273952; padding:5px 1px; font-size:11px; }
.ap-feed-item time { color:#75a7ed; }.ap-feed-item strong { color:#c4b5fd; }.ap-feed-item small { color:#8199b8; margin-left:auto; }
.agent-status.ap-working::before { animation:ap-heartbeat 1s ease-in-out infinite; box-shadow:0 0 10px #52b8f8; }
@keyframes ap-heartbeat { 50% { transform:scale(1.65);opacity:.45; } }
@media (prefers-reduced-motion:reduce) { .agent-status.ap-working::before {animation:none;} }
#ap-bell {font-size:17px;color:inherit;flex:none;}#ap-bell-count {position:absolute;right:-5px;top:-7px;min-width:18px;padding:2px 4px;background:#e84257;border-radius:20px;color:white;font-size:10px;font-weight:700;border:1px solid white;}
#ap-bell::after {display:none;}
.ap-notices {position:absolute;z-index:20;right:87px;top:75px;width:min(390px,calc(100vw - 30px));max-height:390px;overflow:auto;background:#122039;border:1px solid #5471a1;border-radius:12px;padding:14px;box-shadow:0 20px 45px #0008;}
.ap-notices h3 {font-size:14px;margin-bottom:10px}.ap-notice {padding:10px 3px;border-top:1px solid #304565;font-size:12px;line-height:1.5}.ap-notice small {display:block;color:#aebbd0}.ap-notices button {margin-top:8px;padding:5px 8px;background:#24528e;border:1px solid #5780ba;color:white;border-radius:6px;cursor:pointer}.ap-notice em {color:#a5b4fc;font-style:normal;font-weight:600;}
body[data-theme="light"] .ap-notices {background:white;border-color:#c9d8ee;box-shadow:0 20px 45px #25416b30;}body[data-theme="light"] .ap-notice {border-color:#dae5f1}body[data-theme="light"] .ap-notice small {color:#536781}
.ap-headlines{position:fixed;z-index:24;bottom:68px;left:0;right:0;height:33px;background:#182d50ed;border-top:1px solid #4a86c0;color:#eaf3ff;display:flex;align-items:center;overflow:hidden;font-size:12px;letter-spacing:.02em}.ap-headlines-label{background:#d62d54;color:white;font-weight:800;letter-spacing:.1em;display:flex;align-items:center;white-space:nowrap;height:100%;padding:0 14px;z-index:2}.ap-headlines-clip{overflow:hidden;flex:1;white-space:nowrap}.ap-headlines-clip>div{display:inline-block;padding-left:100%;animation:ap-headline-roll 24s linear infinite}@keyframes ap-headline-roll{to{transform:translateX(-100%)}}body[data-theme="light"] .ap-headlines{background:#e3edf9;color:#213b5b}body:has(.ap-ticker[hidden]) .ap-headlines{bottom:0}body:has(.ap-ticker:not([hidden])){padding-bottom:101px}body:has(.ap-ticker[hidden]){padding-bottom:33px}@media(prefers-reduced-motion:reduce){.ap-headlines-clip>div{animation:none;padding-left:12px;overflow:hidden;text-overflow:ellipsis;max-width:100%}}
.ap-tv {position:fixed;inset:0;z-index:50;background:radial-gradient(circle at 50% 38%,#233b79 0%,#0a142a 44%,#07101f 100%);color:#e8f4ff;overflow:hidden;display:flex;flex-direction:column;font-family:Inter,system-ui,sans-serif}.ap-tv-top{display:flex;align-items:center;justify-content:space-between;padding:22px 36px;border-bottom:1px solid #44699b;background:#071126bb;letter-spacing:.16em;font-size:17px;font-weight:800}.ap-tv-top small{display:block;color:#66b7ff;font-size:10px;margin-top:5px}.ap-tv-top time{font-variant-numeric:tabular-nums;font-size:24px}.ap-tv-top button{padding:10px 15px;background:#1b3b67;color:#fff;border:1px solid #5a85b8;border-radius:8px;cursor:pointer}.ap-tv-stage{flex:1;display:flex;flex-direction:column;justify-content:center;text-align:center;padding:10px 45px;min-height:0}.ap-tv-head small{color:#6eceff;letter-spacing:.3em;font-weight:700}.ap-tv-head h1{font-size:clamp(30px,4.4vw,70px);letter-spacing:-.04em;line-height:1.1;margin:10px 0}.ap-tv-head p{color:#adc8e6;font-size:clamp(13px,1.5vw,20px)}.ap-tv-viz{height:min(38vh,310px);margin:auto 0}.ap-tv-viz svg{width:100%;height:100%;overflow:visible}.ap-tv-viz text{fill:#eaf6ff;font-size:24px;font-weight:800;letter-spacing:.1em}.ap-tv-viz .ap-tv-node-sub{font-size:11px;fill:#96bde5}.ap-tv-node{fill:#13274bbd;stroke:#7ab9fa;stroke-width:2;filter:drop-shadow(0 0 16px #4a8fee)}.ap-tv-path{animation:ap-dash 20s linear infinite}@keyframes ap-dash{to{stroke-dashoffset:-360}}.ap-tv-pulse{filter:drop-shadow(0 0 16px #89e5ff)}.ap-tv-cards{display:flex;gap:15px;justify-content:center;margin:0 auto 25px;max-width:1050px;width:100%}.ap-tv-cards div{background:#173259aa;border:1px solid #5c84af;border-radius:12px;padding:16px;flex:1;text-align:left}.ap-tv-cards small{display:block;color:#8abce9}.ap-tv-cards strong{font-size:clamp(18px,2.4vw,31px)}.ap-tv-lower{background:#172d56;border-top:2px solid #59b3ff;padding:14px 30px;display:flex;align-items:center;gap:22px;min-height:60px}.ap-tv-live{background:#e33159;color:white;padding:8px 12px;border-radius:3px;font-size:11px;font-weight:800;white-space:nowrap}.ap-tv-lower strong{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ap-tv-lower small{font-size:10px;color:#83aad2}.ap-tv:has(~ #ap-ticker:not([hidden])){bottom:101px}.ap-tv:has(~ #ap-ticker[hidden]){bottom:33px}.ap-tv~#ap-ticker{z-index:51}.ap-tv~#ap-ticker+.ap-dialog{z-index:999}body:has(.ap-tv:not([hidden])) .ap-headlines{z-index:52}body[data-theme="light"] .ap-tv{background:radial-gradient(circle at 50% 30%,#e5f2ff,#bfd8f4 65%,#a9c9ec);color:#123154}body[data-theme="light"] .ap-tv-top{background:#eaf4ffdd;border-color:#8bacce}body[data-theme="light"] .ap-tv-head p{color:#3e5d7c}body[data-theme="light"] .ap-tv-cards div{background:#f7fbffbd;border-color:#98bde2}body[data-theme="light"] .ap-tv-node{fill:#cfebff;stroke:#478bc9}body[data-theme="light"] .ap-tv-viz text{fill:#173d66}body[data-theme="light"] .ap-tv-viz .ap-tv-node-sub{fill:#3e648a}@media(max-width:700px){.ap-tv-top{padding:12px;font-size:12px}.ap-tv-top time{font-size:16px}.ap-tv-stage{padding:10px}.ap-tv-cards{gap:5px}.ap-tv-cards div{padding:8px}.ap-tv-viz{height:28vh}.ap-tv-lower{padding:8px;gap:8px}.ap-tv-lower small{display:none}}@media(prefers-reduced-motion:reduce){.ap-tv-path{animation:none}.ap-tv-pulse{display:none}}
.ap-live-dot{display:inline-block;width:7px;height:7px;background:#ff4268;border-radius:50%;box-shadow:0 0 10px #ff4268;animation:ap-onair 2s ease-in-out infinite}@keyframes ap-onair{50%{opacity:.4}}@media(prefers-reduced-motion:reduce){.ap-live-dot{animation:none}}#ap-broadcast-clock{display:block;margin-top:2px;font-variant-numeric:tabular-nums;color:#a9c8e6;font-size:11px;letter-spacing:.05em}body[data-theme="light"] #ap-broadcast-clock{color:#a9c8e6}.ap-spotlight strong{font-weight:800;letter-spacing:-.03em}.ap-spotlight:before{content:'ÚLTIMA HORA · OPERACIONES';display:block;color:#a5d8ff;font-size:10px;letter-spacing:.2em;margin-bottom:8px;font-weight:700}body[data-theme="light"] .ap-spotlight:before{color:#225ca2}
.ap-ticker {position:fixed;z-index:24;bottom:0;left:0;right:0;display:flex;align-items:center;height:68px;padding:5px 16px;gap:12px;background:#0c1828e8;border-top:1px solid #4e75aa;backdrop-filter:blur(16px);color:#dbeafe;box-shadow:0 -10px 40px #101c4348}.ap-ticker-label{font-weight:700;font-size:11px;letter-spacing:.1em;min-width:145px}.ap-ticker-label small{display:block;font-weight:400;letter-spacing:0;margin-top:3px;font-size:10px;color:#98a9bd}.ap-ticker-widget{flex:1;min-width:0;height:55px;overflow:hidden}.ap-tv-credit{font-size:10px;color:#9cc7ff;white-space:nowrap;text-decoration:none}body[data-theme="light"] .ap-ticker{background:#0c1828f2;color:#dbeafe;border-color:#4e75aa}body[data-theme="light"] .ap-ticker-label small{color:#98a9bd}@media(max-width:800px){.ap-ticker-label{min-width:74px}.ap-ticker-label small{display:none}.ap-tv-credit{display:none}}
.ap-focus {position:fixed;z-index:30;inset:0;pointer-events:none;--fx:50%;--fy:50%;background:radial-gradient(circle 110px at var(--fx) var(--fy),transparent 0,transparent 45%,#08132948 100%);transition:--fx .7s,--fy .7s;animation:focusFade 2.7s ease-in-out both;}@keyframes focusFade {0%,100%{opacity:0}30%,73%{opacity:1}}body[data-theme="light"] .ap-focus{background:radial-gradient(circle 110px at var(--fx) var(--fy),transparent 0,transparent 45%,#4a688833 100%)}@media(prefers-reduced-motion:reduce){.ap-focus{animation:none;display:none}}
.ap-spotlight {position:fixed;z-index:35;right:24px;top:100px;width:min(410px,calc(100vw - 40px));border-radius:20px;border:1px solid #9ec9ff9c;background:linear-gradient(135deg,#153c63d9,#262554c9);backdrop-filter:blur(24px);box-shadow:0 20px 60px #1c6fe677, inset 0 1px #ffffff55;color:white;text-align:left;padding:22px;cursor:pointer;animation:ap-spot-in .7s cubic-bezier(.2,.9,.2,1) both;}
.ap-spotlight small {display:block;color:#a5d8ff;font-weight:700;letter-spacing:.12em;text-transform:uppercase;margin-bottom:8px}.ap-spotlight strong {display:block;font-size:23px;line-height:1.2}.ap-spotlight span {display:block;font-size:13px;margin-top:10px;line-height:1.4}.ap-spotlight .ap-spotlight-hint {color:#a5d8ff;font-size:11px;text-transform:uppercase;letter-spacing:.08em}
@keyframes ap-spot-in {from{opacity:0;transform:translateX(110%) scale(.96)}to{opacity:1;transform:translateX(0) scale(1)}}
body[data-theme="light"] .ap-spotlight {background:linear-gradient(135deg,#eaf7ffeb,#e9e9ffdb);color:#18304b;box-shadow:0 20px 60px #4b78af48;border-color:#89baff}body[data-theme="light"] .ap-spotlight :is(small,.ap-spotlight-hint){color:#225ca2}
@media(prefers-reduced-motion:reduce){.ap-spotlight{animation:none}}@media(max-width:800px){.ap-spotlight{top:auto;bottom:15px;right:15px}}
.nav-item {border:0; width:100%; background:transparent; text-align:left; font:inherit; flex-shrink:0;}
.sidebar {max-height:calc(100vh - 40px); overflow-y:auto; position:sticky; top:20px;}
.ap-theme {width:36px;height:36px;flex:none;border:1px solid #4e75aa;background:#152743;color:#fff;border-radius:10px;cursor:pointer;font-size:17px;}
.ap-view {background:rgba(12,18,32,.92);border:1px solid rgba(80,140,255,.25);border-radius:14px;padding:22px;min-height:500px;}
.ap-view h2 {font-size:22px;margin:0 0 7px}.ap-view h3 {font-size:14px;color:#a5b4fc;margin:0 0 14px}
.ap-view-lead {color:#94a3b8;font-size:13px;margin-bottom:20px;line-height:1.5}
.ap-grid {display:grid;grid-template-columns:repeat(auto-fit,minmax(225px,1fr));gap:14px;margin:16px 0}
.ap-tile {background:#17243b;border:1px solid #304565;border-radius:12px;padding:17px;min-height:96px;line-height:1.5}
.ap-tile small {color:#aebbd0;display:block;font-size:11px}.ap-tile b {font-size:19px;display:block;margin-top:8px}
.ap-table-wrap {overflow:auto;border:1px solid #304565;border-radius:12px;margin-top:16px}
.ap-table {width:100%;border-collapse:collapse;text-align:left;font-size:12px;min-width:560px}
.ap-table th,.ap-table td {padding:12px;border-bottom:1px solid #304565;vertical-align:top}.ap-table th {color:#a5b4fc;background:#1b2a43}.ap-table tr:last-child td {border:0}
.ap-pill {color:#fbbf24;font-weight:600}.ap-tools {display:flex;gap:9px;flex-wrap:wrap;margin:14px 0}
.ap-view button {background:#24528e;border:1px solid #5780ba;border-radius:8px;color:#fff;padding:9px 12px;cursor:pointer}
.ap-view button:hover {background:#3069a8}button:disabled{opacity:.55;cursor:not-allowed!important}
body[data-theme="light"] {background:#f3f6fc;color:#17283f;background-image:radial-gradient(ellipse at 70% 20%,#e1edff 0%,transparent 55%),linear-gradient(#f7f9ff,#eaf1fb)}
body[data-theme="light"] .bg-city {background:radial-gradient(ellipse 60% 55% at 85% 5%,#dce9ff,transparent),linear-gradient(145deg,#f8faff,#eaf2fc)}
body[data-theme="light"] :is(.sidebar,.header,.metric-card,.agents-card,.alerts-card,.chart-card,.chat-window,.ap-view) {background:rgba(255,255,255,.94);border-color:#cad9ef;box-shadow:0 9px 30px #25416b13}
body[data-theme="light"] :is(.ap-tile,.agent-item,.ap-proposal,.chat-msg.ai) {background:#f1f6fd;border-color:#d2e0f1}
body[data-theme="light"] :is(.nav-item,.metric-label,.agent-role,.ap-view-lead,.ap-tile small) {color:#536781}
body[data-theme="light"] :is(.nav-item:hover,.nav-item.active) {color:#185db6;background:#e9f2ff}
body[data-theme="light"] :is(.ap-tabs button,.chat-footer input,.ap-dialog form,.ap-dialog input,.ap-dialog textarea,.ap-mode,.ap-theme) {background:#f0f6fe;color:#17283f;border-color:#bed0e9}
body[data-theme="light"] :is(.chat-body,.chat-footer,#ap-supervision-panel) {background:#fff;color:#17283f}
body[data-theme="light"] :is(.ap-line,.ap-feed-item,.ap-table th,.ap-table td) {border-color:#d8e3f1}
body[data-theme="light"] .ap-table th {background:#eaf2fd;color:#24549a}
body[data-theme="light"] :is(.ap-view h3,.ap-panel-title) {color:#395ab0}
body[data-theme="light"] :is(.ap-dialog p,.ap-proposal small) {color:#536781}
body[data-theme="light"] .chat-msg.user {color:#18314f;background:#d7e9fc}
body[data-theme="light"] #ap-cycle {color:#536781}
@media(max-width:800px){.sidebar{position:static;max-height:none}.ap-view{padding:14px}}
.agent-item{width:100%;text-align:left;color:#e6efff;font-family:inherit;cursor:pointer;transition:transform .2s,background .2s,border-color .2s,box-shadow .2s}.agent-item:hover{transform:translateX(3px);border-color:#7eafff}.agent-item:focus-visible{outline:2px solid #85c2ff;outline-offset:2px}.agent-item.is-selected{background:linear-gradient(110deg,rgba(46,107,200,.28),rgba(127,68,220,.19));border-color:#91baff;box-shadow:0 0 0 1px #587cbb88,0 14px 35px #335c9c35}.agent-item[aria-pressed=true] .agent-name{color:#cbe5ff}body[data-theme=light] .agent-item{color:#1b304f}body[data-theme=light] .agent-item.is-selected{background:linear-gradient(110deg,#dceafa,#efe9ff);border-color:#689fee}body[data-theme=light] .agent-item[aria-pressed=true] .agent-name{color:#1a4b86}.charts-row[hidden],.ap-agent-center[hidden]{display:none!important}.ap-agent-center:not([hidden]){display:flex;flex-direction:column;gap:18px;min-width:0;min-height:420px;padding:22px;border:1px solid #5b83ba88;border-radius:15px;background:radial-gradient(circle at 100% 0%,#263d7438,transparent 38%),#0b1425;box-shadow:0 20px 60px #09172f40}.ap-agent-hero{display:flex;align-items:center;gap:17px}.ap-agent-hero .agent-badge{width:58px;height:58px;font-size:27px;border-radius:15px;box-shadow:0 0 28px #5978e977}.ap-agent-hero h2{font-size:27px;margin:0}.ap-agent-hero p{color:#a8bfdc;font-size:12px;margin:3px 0}.ap-agent-back{margin-left:auto;background:#1c3c6e;color:#f3f8ff;border:1px solid #6990c8;border-radius:9px;padding:9px 12px;cursor:pointer}.ap-agent-story{color:#a9bdd8;font-size:13px;line-height:1.5;margin:0}.ap-agent-center .ap-grid{margin:0}.ap-agent-timeline{position:relative;padding-left:23px;border-left:1px solid #385b91;margin-left:8px;display:grid;gap:13px}.ap-agent-event{position:relative;padding:12px 14px;border:1px solid #355380;border-radius:10px;background:#13223b}.ap-agent-event:before{content:'';position:absolute;left:-30px;top:16px;width:10px;height:10px;border-radius:50%;background:#6ea5ff;box-shadow:0 0 12px #70acff}.ap-agent-event strong{display:block;font-size:13px}.ap-agent-event small{display:block;margin-top:5px;color:#a6bbd5;font-size:11px}.ap-agent-center h3{font-size:12px;letter-spacing:.1em;color:#9dc0ec;margin:0}.ap-agent-empty{padding:16px;color:#a9bdd8;background:#17253e;border-radius:9px;font-size:12px}body[data-theme=light] .ap-agent-center:not([hidden]){background:radial-gradient(circle at 100% 0%,#bed7ff88,transparent 40%),#fff;border-color:#bdcee5;color:#1b304f;box-shadow:0 12px 30px #2847721a}body[data-theme=light] :is(.ap-agent-hero p,.ap-agent-story,.ap-agent-event small){color:#526a87}body[data-theme=light] .ap-agent-event{background:#f5f9fe;border-color:#d3e1f0}body[data-theme=light] .ap-agent-empty{background:#f1f6fd;color:#526a87}@media(max-width:650px){.ap-agent-hero{flex-wrap:wrap}.ap-agent-back{margin-left:0}}
.header{box-shadow:0 0 0 1px #4477d144,0 12px 40px #256de226;animation:ap-header-glow 7s ease-in-out infinite}.header-title h1{text-shadow:0 0 18px #86aaff66,0 0 35px #618cf744}.header-title h1::after{width:48%;background:linear-gradient(95deg,transparent,#bce8ff12,#f5ffffbc,#91c6ff15,transparent);animation-duration:11s}.metric-card,.agents-card,.alerts-card,.chart-card,.ap-agent-center{transition:box-shadow .3s,border-color .3s}.metric-card:hover,.agents-card:hover,.alerts-card:hover,.chart-card:hover,.ap-agent-center:hover{border-color:#8bb7ff;box-shadow:0 0 0 1px #729ef766,0 18px 50px #397cf033}.agent-status:not(.ap-working)::before{animation:ap-beacon 2.4s ease-in-out infinite}.agent-badge{box-shadow:0 0 13px #5b82f477}.agent-item.is-selected{box-shadow:0 0 0 1px #6eb8ff,0 0 24px #409af16b}.ap-agent-hero .agent-badge{animation:ap-agent-orbit 4s ease-in-out infinite}@keyframes ap-header-glow{50%{box-shadow:0 0 0 1px #91c4ff77,0 12px 46px #627afb50}}@keyframes ap-beacon{50%{box-shadow:0 0 0 5px #24d48524,0 0 17px #39e99a;transform:scale(1.25)}}@keyframes ap-agent-orbit{50%{box-shadow:0 0 15px #7fd7ff,0 0 33px #6565ff99}}body[data-theme=light] .header{box-shadow:0 0 0 1px #8eb9fa,0 15px 40px #2b76d538}body[data-theme=light] .header-title h1{text-shadow:0 0 16px #519cf788}body[data-theme=light] .header-title h1::after{background:linear-gradient(95deg,transparent,#64aaff33,#1279eab8,#64aaff33,transparent)}body[data-theme=light] :is(.metric-card:hover,.agents-card:hover,.alerts-card:hover,.chart-card:hover){box-shadow:0 0 0 1px #6e9cde,0 15px 35px #3879d446}@media(prefers-reduced-motion:reduce){.header,.agent-status:not(.ap-working)::before,.ap-agent-hero .agent-badge{animation:none}.header-title h1::after{animation:none;display:none}}
.ap-compliance-hero{padding:24px;border-radius:16px;border:1px solid #5687cb;background:radial-gradient(circle at 50% 0%,#425ba044,transparent 60%),#101c33;box-shadow:0 0 32px #587cff2e;margin-bottom:20px}.ap-compliance-hero small{color:#a6c3ee;text-transform:uppercase;letter-spacing:.16em;font-size:10px}.ap-compliance-hero h2{font-size:26px;margin:8px 0}.ap-compliance-hero p{max-width:700px;color:#adc3df;font-size:13px;line-height:1.5}.ap-pyramid{display:grid;justify-items:center;gap:6px;margin:24px 0}.ap-pyramid-level{width:var(--width);max-width:100%;min-height:66px;display:flex;align-items:center;justify-content:space-between;gap:16px;padding:13px 11%;border:1px solid #91b7fb;border-radius:8px;color:#f7faff;background:linear-gradient(115deg,#264d9b,#4b388b);box-shadow:0 8px 25px #132c6470, inset 0 0 17px #9dc2ff1d;clip-path:polygon(6% 0,94% 0,100% 100%,0 100%)}.ap-pyramid-level b{font-size:14px}.ap-pyramid-level small{font-size:10px;color:#d4e5fc}.ap-pyramid-level:nth-child(2){background:linear-gradient(115deg,#235b9c,#3b468d)}.ap-pyramid-level:nth-child(3){background:linear-gradient(115deg,#1d6b9c,#315389)}.ap-pyramid-level:nth-child(4){background:linear-gradient(115deg,#167887,#2c5984)}.ap-pyramid-level:nth-child(5){background:linear-gradient(115deg,#28716e,#28577b)}.ap-compliance-note{font-size:12px;line-height:1.5;color:#a8bad5}.ap-compliance-pill{display:inline-block;padding:3px 7px;border-radius:5px;font-size:10px;font-weight:700;margin-left:6px}.ap-compliance-pill.review{background:#af671e33;color:#ffd49a;border:1px solid #ad722c}.ap-compliance-pill.pass{background:#236e573d;color:#8ff0c4;border:1px solid #3a9e79}.ap-compliance-pill.block{background:#b63d4933;color:#ffadb5;border:1px solid #cc5463}body[data-theme=light] .ap-compliance-hero{background:radial-gradient(circle at 50% 0%,#a8c9ff88,transparent 65%),#f4f8ff;border-color:#a9c8ed}body[data-theme=light] .ap-compliance-hero :is(h2,p,small),body[data-theme=light] .ap-compliance-note{color:#315075}body[data-theme=light] .ap-compliance-pill.review{color:#8b4c0e;background:#fff2df}body[data-theme=light] .ap-compliance-pill.pass{color:#165d42;background:#e1f6eb}body[data-theme=light] .ap-compliance-pill.block{color:#a62c3d;background:#fde9eb}@media(max-width:650px){.ap-pyramid-level{clip-path:none;width:100%!important}.ap-pyramid-level b{font-size:12px}}
.ap-law-list{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:12px;margin:16px 0 25px}.ap-law-card{border:1px solid #5277a8;background:#152540;border-radius:12px;padding:15px;box-shadow:0 8px 24px #12336255}.ap-law-card small{display:block;color:#9abce8;font-size:10px;letter-spacing:.08em}.ap-law-card strong{display:block;margin:7px 0;font-size:13px}.ap-law-card p{color:#a9bbd2;font-size:12px;line-height:1.4}.ap-law-card a{color:#8dc7ff;font-size:11px}.ap-payroll-form{display:flex;flex-wrap:wrap;gap:12px;align-items:end;padding:18px;border:1px solid #456d9d;border-radius:12px;background:#142440}.ap-payroll-form label{display:grid;gap:6px;color:#c7d8ec;font-size:12px}.ap-payroll-form input{padding:9px;border-radius:7px;border:1px solid #6995c6;background:#0b1728;color:#fff;max-width:220px}.ap-payroll-output{margin:12px 0;padding:15px;border-radius:9px;background:#272b45;color:#e8e4fd;font-size:13px;line-height:1.7}body[data-theme=light] .ap-law-card{background:#f5f9ff;color:#243d5f;border-color:#c5d9f2}body[data-theme=light] .ap-law-card :is(p,small){color:#526985}body[data-theme=light] .ap-law-card a{color:#12599d}body[data-theme=light] .ap-payroll-form{background:#eaf2ff;color:#1d3e65}body[data-theme=light] .ap-payroll-form label{color:#284b70}body[data-theme=light] .ap-payroll-form input{background:#fff;color:#152f4e}body[data-theme=light] .ap-payroll-output{background:#f4f0ff;color:#363057}
body[data-theme=light] .ap-compliance-hero .ap-pyramid-level small{color:#eff7ff;text-shadow:0 1px 4px #102e6188}
.ap-legal-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(245px,1fr));gap:14px;margin:16px 0 25px}.ap-legal-agent{padding:17px;border-radius:13px;border:1px solid #5077ab;background:linear-gradient(145deg,#162c4b,#111f36);box-shadow:0 9px 24px #0c203b44;min-width:0}.ap-legal-agent header{display:flex;gap:11px;align-items:flex-start;justify-content:space-between}.ap-legal-agent h3{font-size:17px;margin:0 0 6px}.ap-legal-agent small{font-size:10px;letter-spacing:.1em;color:#a9c8ee;text-transform:uppercase}.ap-legal-agent p,.ap-legal-agent li{font-size:12px;line-height:1.45;color:#c5d7ef}.ap-legal-agent ul{padding-left:17px;margin:8px 0 12px}.ap-legal-agent b{color:#e8f3ff}.ap-legal-status{font-size:10px;white-space:nowrap;padding:5px 7px;border-radius:20px;border:1px solid #b98c49;color:#ffdb9e;background:#925d2033}.ap-legal-agent .ap-legal-scope{margin-top:12px;padding-top:10px;border-top:1px solid #4a658b;color:#adcaec}.ap-legal-flow{border:1px solid #597ead;border-radius:12px;background:#10243c;padding:16px;margin:20px 0;color:#d9e9ff;font-size:12px;line-height:1.5}body[data-theme=light] .ap-legal-agent{background:linear-gradient(145deg,#f8fbff,#eaf2ff);border-color:#bdd2ed}body[data-theme=light] .ap-legal-agent :is(h3,b){color:#183857}body[data-theme=light] .ap-legal-agent :is(p,li,small,.ap-legal-scope){color:#435f7e}body[data-theme=light] .ap-legal-status{color:#81500c;background:#ffedca}body[data-theme=light] .ap-legal-flow{background:#f2f7ff;color:#28476e;border-color:#bfd4ee}
.ap-jurisdiction{display:flex;align-items:center;gap:12px;flex-wrap:wrap;border:1px solid #628bbd;border-radius:11px;padding:12px 16px;margin-bottom:19px;background:#18304d;color:#e8f2ff;font-size:12px}.ap-jurisdiction select,.ap-cost-form input,.ap-cost-form select{background:#0c1d33;color:#f0f7ff;border:1px solid #7098c7;border-radius:7px;padding:9px}.ap-cost-form{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px;padding:17px;border:1px solid #587eb0;border-radius:12px;background:#162943}.ap-cost-form label{font-size:12px;color:#d3e4fc;display:grid;gap:6px}.ap-cost-form button{align-self:end;border:1px solid #82b3ea;border-radius:8px;background:#305c94;color:#fff;padding:10px;cursor:pointer}.ap-cost-kpis{margin:18px 0}.ap-cost-kpis b{font-size:20px}.ap-cost-note{border-left:3px solid #d99b54;padding:9px 13px;background:#95601b2b;font-size:12px;line-height:1.5;margin:12px 0}body[data-theme=light] .ap-jurisdiction,body[data-theme=light] .ap-cost-form{background:#eef5ff;color:#28476b;border-color:#b9d0ec}body[data-theme=light] .ap-cost-form label{color:#375676}body[data-theme=light] .ap-jurisdiction select,body[data-theme=light] .ap-cost-form :is(input,select){background:#fff;color:#1e3958}body[data-theme=light] .ap-cost-note{background:#fff2da;color:#6a491d}
.ap-recruit-hero{padding:23px;border-radius:16px;border:1px solid #638ec1;background:radial-gradient(circle at 15% 0,#416bc066,transparent 45%),linear-gradient(135deg,#12243e,#162540 72%,#223458);margin-bottom:17px}.ap-recruit-hero small{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:#a8d2fa}.ap-recruit-hero h2{font-size:27px;margin:8px 0}.ap-recruit-hero p{max-width:760px;color:#c4d8f1;font-size:13px;line-height:1.5}.ap-recruit-categories{display:grid;grid-template-columns:repeat(auto-fit,minmax(155px,1fr));gap:10px;margin:15px 0}.ap-recruit-category{border:1px solid #5279a8;background:#152b49;border-radius:12px;padding:13px;min-width:0}.ap-recruit-category small{display:block;color:#a7c2e8;font-size:11px}.ap-recruit-category strong{font-size:19px;display:block;margin-top:6px;color:#eef6ff}.ap-recruit-radar{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:11px;margin:14px 0 25px}.ap-recruit-radar>div{border-radius:12px;border:1px solid #5277a2;background:linear-gradient(135deg,#142943,#162d4b);padding:14px}.ap-recruit-radar strong{display:block;font-size:13px;color:#e7f3ff}.ap-recruit-radar small{font-size:11px;color:#a9c4e2;line-height:1.5}.ap-recruit-form{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px;padding:15px;border:1px solid #6688b4;border-radius:12px;background:#162943;margin:15px 0}.ap-recruit-form label{font-size:11px;color:#d2e3f7;display:grid;gap:5px}.ap-recruit-form :is(input,select){border:1px solid #7198c3;background:#0d1e34;border-radius:7px;color:#fff;padding:9px;min-width:0}.ap-recruit-form button,.ap-recruit-move{border:1px solid #88b5e5;background:#2d598a;border-radius:7px;padding:9px;color:white;cursor:pointer}.ap-recruit-form button{align-self:end}.ap-recruit-board{display:grid;grid-template-columns:repeat(4,minmax(210px,1fr));gap:12px;overflow-x:auto;padding:2px 0 10px}.ap-recruit-column{border:1px solid #476c9c;border-radius:13px;background:#11243e;padding:12px;min-width:210px}.ap-recruit-column h3{font-size:13px;margin:2px 3px 13px}.ap-recruit-card{padding:12px;border:1px solid #668bb9;border-radius:10px;background:#1c3556;margin-bottom:10px;box-shadow:0 5px 15px #09172a44}.ap-recruit-card small{color:#acd0fb;font-size:10px;text-transform:uppercase;letter-spacing:.05em}.ap-recruit-card strong{display:block;margin:5px 0;font-size:12px;overflow-wrap:anywhere}.ap-recruit-card p{font-size:11px;color:#c7d8ed;line-height:1.4;overflow-wrap:anywhere}.ap-recruit-move{font-size:10px;padding:6px 8px}.ap-recruit-empty{color:#9cb6d4;font-size:11px;line-height:1.5;padding:9px}body[data-theme=light] .ap-recruit-hero,body[data-theme=light] .ap-recruit-category,body[data-theme=light] .ap-recruit-radar>div,body[data-theme=light] .ap-recruit-form,body[data-theme=light] .ap-recruit-column,body[data-theme=light] .ap-recruit-card{background:#f5f9ff;border-color:#b8d0eb;color:#254367}body[data-theme=light] .ap-recruit-hero :is(h2,p,small),body[data-theme=light] .ap-recruit-category :is(small,strong),body[data-theme=light] .ap-recruit-radar :is(small,strong),body[data-theme=light] .ap-recruit-form label,body[data-theme=light] .ap-recruit-card :is(small,p,strong),body[data-theme=light] .ap-recruit-empty{color:#365879}body[data-theme=light] .ap-recruit-form :is(input,select){background:white;color:#263f5a}@media(max-width:800px){.ap-recruit-radar{grid-template-columns:1fr}.ap-recruit-board{grid-template-columns:repeat(4,minmax(210px,1fr))}}
.ap-squad{border-radius:15px;border:1px solid #6395c3;background:radial-gradient(ellipse at 50% 20%,#367a6640,transparent 63%),#0d2b39;padding:18px;margin:20px 0}.ap-squad header{font-size:12px;font-weight:700;letter-spacing:.08em;color:#a9ecdb}.ap-squad-pitch{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:15px}.ap-squad-role{border:1px solid #4f9e8d;background:#163f46bd;border-radius:12px;text-align:center;padding:16px;min-width:0}.ap-squad-role span{display:block;font-size:22px;margin-bottom:5px}.ap-squad-role strong{display:block;color:#e0fff3;font-size:12px}.ap-squad-role small{font-size:10px;color:#b2decf}.ap-candidate-list{display:grid;grid-template-columns:repeat(auto-fit,minmax(245px,1fr));gap:12px;margin:15px 0}.ap-candidate-card{padding:15px;border:1px solid #5a80aa;border-radius:12px;background:#192d4a}.ap-candidate-card strong{font-size:14px;color:#e3f3ff}.ap-candidate-card p,.ap-candidate-card small{font-size:11px;color:#bad0ea;line-height:1.5}.ap-candidate-card button{border:1px solid #84b4ed;background:#315b8d;color:white;padding:8px;border-radius:7px;cursor:pointer;font-size:11px}.ap-candidate-card .ap-legal-status{display:inline-block;margin:8px 0}.ap-candidate-form{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;padding:15px;border:1px solid #5685b4;border-radius:12px;background:#162943}.ap-candidate-form label{display:grid;gap:5px;font-size:11px}.ap-candidate-form :is(input,select,textarea){background:#0e2038;border:1px solid #638db9;border-radius:7px;padding:9px;color:#fff;min-width:0}.ap-candidate-form textarea{min-height:74px}.ap-candidate-form button{align-self:end;padding:10px;border-radius:8px;border:1px solid #84b8ec;background:#315b92;color:#fff;cursor:pointer}body[data-theme=light] .ap-squad{background:#ecf8f1;border-color:#9bcbb6}body[data-theme=light] .ap-squad header{color:#24634d}body[data-theme=light] .ap-squad-role{background:#f7fffb;border-color:#b5d4c7}body[data-theme=light] .ap-squad-role :is(strong,small){color:#295647}body[data-theme=light] .ap-candidate-card,body[data-theme=light] .ap-candidate-form{background:#f5f9ff;border-color:#bfd3eb;color:#2e4c6d}body[data-theme=light] .ap-candidate-card :is(strong,p,small){color:#305475}body[data-theme=light] .ap-candidate-form :is(input,select,textarea){background:#fff;color:#274561}@media(max-width:650px){.ap-squad-pitch{grid-template-columns:1fr}}
.ap-activity-form{display:flex;gap:12px;flex-wrap:wrap;align-items:end;padding:15px;border:1px solid #5685b4;border-radius:12px;background:#162943;margin:16px 0}.ap-activity-form label{display:grid;gap:6px;font-size:12px;color:#d3e4fc}.ap-activity-form :is(input,select){background:#0e2038;border:1px solid #638db9;border-radius:7px;padding:9px;color:#fff;min-width:0}.ap-activity-form .ap-activity-search{flex:1 1 200px}.ap-activity-meta{color:#a9c4e2;font-size:12px;margin:12px 0 0}body[data-theme=light] .ap-activity-form{background:#eef5ff;border-color:#b9d0ec}body[data-theme=light] .ap-activity-form label{color:#28476b}body[data-theme=light] .ap-activity-form :is(input,select){background:#fff;color:#1e3958}body[data-theme=light] .ap-activity-meta{color:#435f7e}
/* Navegación táctil y shell adaptable */
.ap-menu-toggle,.ap-menu-close{display:none}.ap-menu-backdrop{position:fixed;inset:0;z-index:79;background:#061226b8;backdrop-filter:blur(3px)}
.container,.main,.header,.metrics,.mid-row,.charts-row,.ap-view{min-width:0}.main{min-width:0}.sidebar{flex:0 0 220px}.ap-table-wrap{max-width:100%}
:is(.nav-item,.ap-theme,.ap-mode,.ap-human,.notif,.ap-menu-toggle,.ap-menu-close):focus-visible{outline:3px solid #9ad0ff;outline-offset:2px}
@media(max-width:1050px){.container{padding:12px;gap:12px}.sidebar{flex-basis:190px;width:190px}.header{flex-wrap:wrap;gap:10px}.header-right{gap:7px;flex-wrap:wrap}.header-title h1{font-size:16px}.mid-row{grid-template-columns:minmax(0,1fr)}.charts-row{grid-template-columns:minmax(0,1fr)}}
@media(max-width:1050px) and (min-width:761px){.ap-mode{max-width:none!important}}
@media(max-width:760px){.ap-menu-toggle{position:fixed;z-index:90;top:10px;left:10px;display:inline-flex;align-items:center;gap:7px;min-height:44px;padding:7px 11px;border:1px solid #6f9dd5;border-radius:10px;background:#19375d;color:#fff;font:600 12px Inter,system-ui,sans-serif;box-shadow:0 6px 18px #020e25aa;cursor:pointer}.ap-menu-close{display:block;align-self:flex-end;border:1px solid #6f9dd5;border-radius:8px;background:#173259;color:white;min-height:40px;padding:7px 12px;cursor:pointer}.container{display:block;padding:10px;min-width:0;z-index:80;pointer-events:none}.container .sidebar,.container .main{pointer-events:auto}.container:has(.sidebar.is-open) .main{pointer-events:none}.main{position:relative;z-index:1}.main{width:100%;gap:10px}.sidebar{position:fixed!important;z-index:80;inset:0 auto 0 0;top:0!important;width:min(300px,85vw);max-width:min(300px,85vw);height:100dvh;max-height:100dvh!important;overflow-y:auto;transform:translateX(-105%);transition:transform .22s ease;box-shadow:0 15px 35px #020c20bb}.sidebar.is-open{transform:translateX(0);z-index:80!important}.header{padding:62px 12px 12px;display:block;min-width:0}.header-title h1{font-size:clamp(15px,4vw,19px);overflow-wrap:anywhere}.header-right{margin-top:12px;display:flex;gap:7px;flex-wrap:wrap}.header-right .ap-theme,.header-right .ap-human,.header-right .notif{width:44px;height:44px;min-width:44px}.header-right .ap-mode{min-height:44px;max-width:none}.metrics{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.metric-card{padding:12px;min-width:0}.metric-value{font-size:clamp(17px,5.5vw,24px);overflow-wrap:anywhere}.mid-row,.charts-row{grid-template-columns:minmax(0,1fr)}.chart-card{min-width:0;overflow:hidden}.chart-container{min-width:0;max-width:100%;overflow:hidden}.chart-container canvas{max-width:100%!important}.bg-city{width:100vw}.ap-view{padding:13px;min-width:0}.ap-headlines{bottom:55px;height:30px;max-width:100vw}.ap-headlines-label{font-size:9px;padding:0 8px}.ap-ticker{height:55px;max-width:100vw;padding:3px 8px;gap:6px}.ap-ticker-label{min-width:62px;font-size:9px}.ap-ticker-widget{height:48px}.ap-spotlight{bottom:92px!important;max-width:calc(100vw - 30px)}body:has(.ap-ticker:not([hidden])){padding-bottom:85px}body:has(.ap-ticker[hidden]){padding-bottom:30px}body[data-theme=light] .ap-menu-toggle{background:#eaf3ff;color:#21466c}}
@media(max-width:480px){.metrics{grid-template-columns:repeat(2,minmax(0,1fr))}.ap-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.ap-legal-grid,.ap-law-list,.ap-candidate-list{grid-template-columns:minmax(0,1fr)}.ap-recruit-categories{grid-template-columns:repeat(2,minmax(0,1fr))}.ap-recruit-board{grid-template-columns:repeat(4,minmax(230px,1fr))}.ap-cost-form,.ap-candidate-form,.ap-recruit-form{grid-template-columns:minmax(0,1fr)}.ap-candidate-form label[style]{grid-column:auto!important}.ap-squad-pitch{grid-template-columns:minmax(0,1fr)}.chat-window{position:fixed!important;inset:0!important;left:0!important;top:0!important;right:0!important;bottom:0!important;width:100vw!important;height:100dvh!important;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;border-radius:0!important;resize:none!important;z-index:110}.chat-header{cursor:default}.chat-footer input{min-width:0}.ap-notices{position:fixed;top:72px;left:10px;right:10px;width:auto;max-height:60vh}.ap-spotlight{display:none!important}}
@media(prefers-reduced-motion:reduce){.sidebar{transition:none}}
.agents-card{display:flex;flex-direction:column}.ap-news{margin-top:auto;padding-top:18px;border-top:1px solid #304565}.ap-news-head{font-size:10px;letter-spacing:.1em;font-weight:800;color:#e4f2ff}.ap-news-head small{display:block;color:#85a8ca;font-size:9px;margin-top:3px}.ap-video{position:relative;aspect-ratio:16/9;background:#070d18;margin-top:10px;border:1px solid #507eac;border-radius:9px;overflow:hidden}.ap-video iframe{width:100%;height:100%;border:0}.ap-video-error:not([hidden]){position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:9px;padding:18px;background:#07101ef5;color:#ecf4ff;text-align:center;font-size:12px;z-index:2}.ap-video-error a{color:#8fceff}.ap-news p{font-size:10px;color:#90a9c6;margin-top:8px}.ap-news a{color:#80c2ff}body[data-theme="light"] .ap-news{border-color:#d3e1f0}body[data-theme="light"] .ap-news-head{color:#2c4a70}body[data-theme="light"] .ap-news p{color:#536781}
</style>
</head>
<body>
<div class="bg-city"></div>
<button type="button" id="ap-menu-toggle" class="ap-menu-toggle" aria-label="Abrir menú de secciones" aria-controls="ap-sidebar" aria-expanded="false">☰ <span>Secciones</span></button>
<div id="ap-menu-backdrop" class="ap-menu-backdrop" hidden></div>
<div class="container">
<aside class="sidebar" id="ap-sidebar" aria-label="Secciones">
<button type="button" class="ap-menu-close" id="ap-menu-close" aria-label="Cerrar menú de secciones">Cerrar ✕</button>
<div class="logo">
<div class="logo-icon">IA</div>
<div class="logo-text">Core<small style="display:block;font-size:10px;font-weight:400;opacity:.7;line-height:1.2">Núcleo de un ERP Agéntico</small></div>
</div>
<button type="button" class="nav-item active" data-view="0"><span class="icon">📊</span> Dashboard</button>
<button type="button" class="nav-item" data-view="1"><span class="icon">💰</span> Finanzas</button>
<button type="button" class="nav-item" data-view="2"><span class="icon">📦</span> Suministro</button>
<button type="button" class="nav-item" data-view="3"><span class="icon">🚚</span> Logística IA</button>
<button type="button" class="nav-item" data-view="4"><span class="icon">📋</span> Gestión de Stock</button>
<button type="button" class="nav-item" data-view="5"><span class="icon">🛒</span> Ventas</button>
<button type="button" class="nav-item" data-view="6"><span class="icon">🎯</span> CRM Predictivo</button>
<button type="button" class="nav-item" data-view="7"><span class="icon">💲</span> Precios Dinámicos</button>
<button type="button" class="nav-item" data-view="8"><span class="icon">👥</span> RRHH</button>
<button type="button" class="nav-item" data-view="9"><span class="icon">🧠</span> Talento IA</button>
<button type="button" class="nav-item" data-view="10"><span class="icon">📅</span> Planificación</button>
<button type="button" class="nav-item" data-view="11"><span class="icon">🏭</span> Producción</button>
<button type="button" class="nav-item" data-view="12"><span class="icon">📈</span> Reportes Avanzados</button>
<button type="button" class="nav-item" data-view="13"><span class="icon">🤖</span> Agentes IA</button>
<button type="button" class="nav-item" data-view="21"><span class="icon">💬</span> Intervenciones</button>
<button type="button" class="nav-item" data-view="14"><span class="icon">⚖️</span> Cumplimiento</button>
<button type="button" class="nav-item" data-view="15"><span class="icon">🇨🇴</span> Nómina Colombia</button>
<button type="button" class="nav-item" data-view="16"><span class="icon">🧭</span> Subagentes jurídicos</button>
<button type="button" class="nav-item" data-view="17"><span class="icon">📊</span> Costes de mano de obra</button>
<button type="button" class="nav-item" data-view="18"><span class="icon">🌱</span> Reclutamiento y cambio</button>
<button type="button" class="nav-item" data-view="19"><span class="icon">⚽</span> Currícula · equipo</button>
<button type="button" class="nav-item" data-view="20"><span class="icon">🧾</span> Registro de actividad</button>
</aside>
<main class="main">
<header class="header">
<div class="header-title">
<h1>ERP | OPERACIONES INTELIGENTES 2030</h1>
</div>
<div class="header-right">
<button id="ap-tv-toggle" class="ap-theme" aria-label="Modo TV" title="Modo TV">📺</button>
<button id="ap-fullscreen" class="ap-theme" type="button" aria-label="Entrar en pantalla completa" title="Entrar en pantalla completa" aria-pressed="false">⛶</button>
<button id="ap-ticker-toggle" class="ap-theme" aria-label="Mostrar u ocultar mercados" title="Mostrar u ocultar mercados">📈</button>
<button id="ap-sound" class="ap-theme" aria-label="Silenciar efectos" title="Silenciar efectos">🔊</button>
<button id="ap-theme" class="ap-theme" aria-label="Cambiar tema" title="Cambiar tema">☀️</button>
<button id="ap-mode" class="ap-mode" aria-label="Cambiar modo del ERP">👤 Supervisado</button>
<button id="ap-agents" class="ap-mode" aria-label="Activar o detener el motor automático de agentes" aria-pressed="true">🤖 Agentes</button>
<button class="ap-human" title="Supervisión humana" aria-label="Supervisión humana" onclick="AP.tab('supervision')">👤</button>
<button type="button" id="ap-bell" class="notif" aria-label="Avisos" aria-expanded="false">🔔<span id="ap-bell-count" hidden></span></button>
<div class="avatar">U</div>
</div>
</header>
<aside id="ap-notices" class="ap-notices" hidden></aside>
<div id="ap-dashboard">
<section class="metrics">
<div class="metric-card">
<div class="metric-label">Valor de pedidos</div>
<div class="metric-value" id="ap-order-value">...</div>
<div class="metric-change neutral">Pedidos registrados</div>
</div>
<div class="metric-card">
<div class="metric-label">Unidades reservadas</div>
<div class="metric-value" id="ap-reservations">...</div>
<div class="metric-change neutral">Inventario</div>
</div>
<div class="metric-card">
<div class="metric-label">SKU sin alerta de stock</div>
<div class="metric-value" id="ap-stock-metric">...</div>
<div class="metric-change neutral">Estado de inventario</div>
</div>
<div class="metric-card">
<div class="metric-label">Decisiones pendientes</div>
<div class="metric-value" id="ap-pending-metric">...</div>
<div class="metric-change neutral">Supervisión humana</div>
</div>
</section>
<section class="mid-row">
<div class="agents-card">
<div class="section-title">Agentes</div>
<button type="button" class="agent-item" data-agent="ALPHA" aria-label="Ver actividad de ALPHA" aria-pressed="false">
<div class="agent-badge a">A</div>
<div class="agent-info">
<div class="agent-name">ALPHA</div>
<div class="agent-role">Inventario</div>
</div>
<div class="agent-status" id="ap-agent-alpha">Disponible</div>
</button>
<button type="button" class="agent-item" data-agent="BETA" aria-label="Ver actividad de BETA" aria-pressed="false">
<div class="agent-badge b">B</div>
<div class="agent-info">
<div class="agent-name">BETA</div>
<div class="agent-role">Ventas</div>
</div>
<div class="agent-status" id="ap-agent-beta">En espera</div>
</button>
<button type="button" class="agent-item" data-agent="GAMMA" aria-label="Ver actividad de GAMMA" aria-pressed="false">
<div class="agent-badge g">G</div>
<div class="agent-info">
<div class="agent-name">GAMMA</div>
<div class="agent-role">Logística</div>
</div>
<div class="agent-status" id="ap-agent-gamma">Proveedores</div>
</button>
<section class="ap-news"><div class="ap-news-head"><span class="ap-live-dot"></span> NOTICIAS INTERNACIONALES <small>FRANCE 24 · EN DIRECTO</small></div><div class="ap-video"><iframe id="ap-news-player" src="https://www.youtube-nocookie.com/embed/HvZt-nh9sGg?autoplay=1&mute=1&cc_load_policy=1&playsinline=1&enablejsapi=1" title="FRANCE 24 English en directo" allow="autoplay; encrypted-media; picture-in-picture" referrerpolicy="strict-origin-when-cross-origin" loading="lazy" allowfullscreen></iframe><div id="ap-video-error" class="ap-video-error" hidden><strong>No se pudo cargar la emisión.</strong><a href="https://www.youtube.com/watch?v=HvZt-nh9sGg" target="_blank" rel="noopener noreferrer">Abrir FRANCE 24 en YouTube ↗</a></div></div><p>Emisión oficial en silencio. Si el reproductor no carga, <a href="https://www.youtube.com/watch?v=HvZt-nh9sGg" target="_blank" rel="noopener noreferrer">ver el directo en YouTube ↗</a>.</p></section>
</div>
<section id="ap-agent-center" class="ap-agent-center" aria-live="polite" hidden></section>
<div class="alerts-card">
<div class="section-title">Inventario</div>
<div id="ap-state">Cargando datos...</div>
<div id="ap-stock"></div>
<button class="ap-action" id="ap-analyze">Analizar inventario con ALPHA</button>
<div class="section-title" style="margin-top:16px">Pedidos</div>
<div id="ap-orders"></div>
<div class="section-title" style="margin-top:12px">Actividad en vivo</div>
<div id="ap-cycle"></div>
<div id="ap-feed"></div>
</div>
</section>
<section class="charts-row">
<div class="chart-card">
<h3>Pronóstico de demanda T3/T4</h3>
<div class="chart-container">
<canvas id="demandChart"></canvas>
</div>
</div>
<div class="chart-card">
<h3>Costo de Operaciones</h3>
<div class="chart-container">
<canvas id="costChart"></canvas>
</div>
</div>
</section>
</div>
<section id="ap-view" class="ap-view" hidden></section>
</main>
</div>
<!-- CHAT WINDOW MOVIBLE -->
<div class="chat-window" id="chatWindow" hidden>
<div class="chat-header" id="chatHeader">
<h4>💬 CHAT CON CORE IA</h4>
<button type="button" class="close" onclick="AP.closeChat()" aria-label="Cerrar chat">✕</button>
</div>
<div class="ap-tabs"><button id="ap-tab-chat">Chat</button><button id="ap-tab-supervision">Supervisión <span id="ap-pending">0</span></button></div>
<div id="ap-chat-panel">
<div class="ap-model-bar">
<button id="ap-model-load" type="button">⬇️ Descargar MiMo 9B (~5,8 GB)</button>
<button id="ap-model-stop" type="button" hidden>⏹ Detener</button>
<span id="ap-model-state">Comprobando módulo del modelo…</span>
</div>
<div class="ap-model-progress" id="ap-model-progress" hidden><div></div></div>
<div class="chat-body" role="log" aria-label="Conversación con ALPHA" aria-live="polite" aria-relevant="additions"><div class="chat-msg ai">Consulta el inventario con ALPHA. El asistente usa un modelo MiMo 9B que se ejecuta en tu navegador: descárgalo con el botón de arriba la primera vez. Las propuestas requieren tu aprobación. Aviso: en las pruebas actuales este modelo falla al generar con el runtime probado (en investigación).</div></div>
<div class="chat-footer">
<button id="ap-websearch" class="ap-mic" type="button" aria-pressed="false">🔎</button>
<input type="text" placeholder="Escribe un mensaje..." id="chatInput" aria-label="Mensaje para ALPHA" autocomplete="off">
<button id="ap-mic" class="ap-mic" type="button" aria-label="Dictar mensaje" title="Dictar mensaje" aria-pressed="false">🎙️</button>
<button onclick="sendMessage()" aria-label="Enviar mensaje">➤</button>
</div>
</div>
<div id="ap-supervision-panel" hidden>
<div class="ap-panel-title">Propuestas de compra</div>
<div id="ap-queue"></div>
<div class="ap-panel-title">Actividad reciente</div>
<div id="ap-audit"></div>
<p class="ap-demo-warning">DEMO FICTICIA · Datos locales de julio de 2030. Los pedidos nuevos son simulados y no llegan de una tienda real.</p><button class="ap-action" id="ap-reset" type="button">Restablecer solo esta demo</button>
</div>
</div>
<div id="ap-headlines" class="ap-headlines"><span class="ap-headlines-label">EN PORTADA</span><div class="ap-headlines-clip"><div id="ap-headlines-text"></div></div></div>
<div id="ap-tv" class="ap-tv" hidden><div class="ap-tv-top"><div><span class="ap-live-dot"></span> CORE · EN DIRECTO <small>OPERACIONES INTELIGENTES</small></div><time id="ap-tv-clock"></time><button id="ap-tv-close" aria-label="Salir del modo TV">Salir ✕</button></div><div class="ap-tv-stage"><div class="ap-tv-head"><small id="ap-tv-kicker">INTELIGENCIA DE OPERACIONES</small><h1 id="ap-tv-title">El negocio, en movimiento</h1><p id="ap-tv-subtitle"></p></div><div id="ap-tv-viz" class="ap-tv-viz"><svg viewBox="0 0 900 330" aria-label="Flujo de agentes entre ventas, inventario y suministro" role="img"><defs><linearGradient id="ap-tv-line"><stop stop-color="#318ffb"/><stop offset=".5" stop-color="#a967ed"/><stop offset="1" stop-color="#39d8c2"/></linearGradient></defs><path d="M130 165 Q350 10 450 165 Q550 320 770 165" fill="none" stroke="url(#ap-tv-line)" stroke-width="3" stroke-dasharray="10 8" class="ap-tv-path"/><circle cx="130" cy="165" r="64" class="ap-tv-node"/><circle cx="450" cy="165" r="64" class="ap-tv-node"/><circle cx="770" cy="165" r="64" class="ap-tv-node"/><text x="130" y="157" text-anchor="middle">BETA</text><text x="450" y="157" text-anchor="middle">ALPHA</text><text x="770" y="157" text-anchor="middle">GAMMA</text><text x="130" y="184" text-anchor="middle" class="ap-tv-node-sub">VENTAS</text><text x="450" y="184" text-anchor="middle" class="ap-tv-node-sub">INVENTARIO</text><text x="770" y="184" text-anchor="middle" class="ap-tv-node-sub">SUMINISTRO</text><circle r="9" fill="#e4f8ff" class="ap-tv-pulse"><animateMotion dur="5s" repeatCount="indefinite" path="M130 165 Q350 10 450 165 Q550 320 770 165"/></circle></svg></div><div id="ap-tv-cards" class="ap-tv-cards"></div></div><div id="ap-tv-lower" class="ap-tv-lower"><span class="ap-tv-live">● EN VIVO</span><strong id="ap-tv-story"></strong><small>FIVETECH · DATOS LOCALES</small></div></div>
<div id="ap-ticker" class="ap-ticker" hidden><div class="ap-ticker-label"><span class="ap-live-dot"></span> MERCADOS <small>Datos según disponibilidad de cada bolsa</small><time id="ap-broadcast-clock"></time></div><div class="ap-ticker-widget tradingview-widget-container"><div class="tradingview-widget-container__widget"></div><script type="text/javascript" src="https://s3.tradingview.com/external-embedding/embed-widget-ticker-tape.js" async>{"symbols":[{"proName":"NASDAQ:AAPL","description":"Apple"},{"proName":"NASDAQ:MSFT","description":"Microsoft"},{"proName":"NASDAQ:NVDA","description":"Nvidia"},{"proName":"NASDAQ:AMZN","description":"Amazon"},{"proName":"NASDAQ:GOOGL","description":"Alphabet"},{"proName":"NASDAQ:TSLA","description":"Tesla"},{"proName":"FOREXCOM:SPXUSD","description":"S&P 500"}],"showSymbolLogo":true,"colorTheme":"dark","isTransparent":true,"displayMode":"adaptive","locale":"es"}</script></div><a href="https://www.tradingview.com/" target="_blank" rel="noopener noreferrer" class="ap-tv-credit">TradingView ↗</a></div>
<div id="ap-dialog" class="ap-dialog" role="dialog" aria-modal="true" aria-label="Confirmar acción" hidden></div>
<div id="ap-focus" class="ap-focus" hidden></div>
<button type="button" id="ap-spotlight" class="ap-spotlight" hidden aria-label="Abrir aviso destacado"><small id="ap-spotlight-agent"></small><strong id="ap-spotlight-title"></strong><span id="ap-spotlight-detail"></span><span class="ap-spotlight-hint">Ver detalles ↗</span></button>
<div class="projector"></div>
<script>
// ========== DRAG & DROP del chat ==========
const chatWindow = document.getElementById('chatWindow');
const chatHeader = document.getElementById('chatHeader');
let isDragging = false;
let offsetX = 0;
let offsetY = 0;
chatHeader.addEventListener('mousedown', (e) => {
// No iniciar drag si se hace clic en el botón de cerrar
if (e.target.classList.contains('close')) return;
isDragging = true;
const rect = chatWindow.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
chatWindow.style.transition = 'none'; // desactiva transiciones mientras se mueve
document.body.style.cursor = 'grabbing';
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
let newX = e.clientX - offsetX;
let newY = e.clientY - offsetY;
// Limitar para que no se salga de la pantalla
const maxX = window.innerWidth - chatWindow.offsetWidth;
const maxY = window.innerHeight - chatWindow.offsetHeight;
newX = Math.max(0, Math.min(newX, maxX));
newY = Math.max(0, Math.min(newY, maxY));
chatWindow.style.left = newX + 'px';
chatWindow.style.top = newY + 'px';
chatWindow.style.bottom = 'auto'; // importante para que top tenga prioridad
chatWindow.style.right = 'auto';
});
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
document.body.style.cursor = '';
chatWindow.style.transition = ''; // restaura transiciones
}
});
// ========== Charts ==========
const APChartsInit = () => { if (typeof Chart === 'undefined') return;
const demandCtx = document.getElementById('demandChart').getContext('2d');
new Chart(demandCtx, {
type: 'bar',
data: {
labels: ['T1', 'T2', 'T3', 'T4'],
datasets: [
{
type: 'line',
label: 'Pronóstico',
data: [320, 480, 620, 780],
borderColor: '#60a5fa',
backgroundColor: 'rgba(96, 165, 250, 0.1)',
borderWidth: 2,
tension: 0.3,
pointBackgroundColor: '#60a5fa',
pointRadius: 4,
fill: false
},
{
type: 'bar',
label: 'Real',
data: [280, 420, 580, 720],
backgroundColor: [
'rgba(59, 130, 246, 0.7)',
'rgba(99, 102, 241, 0.7)',
'rgba(139, 92, 246, 0.7)',
'rgba(168, 85, 247, 0.7)'
],
borderRadius: 6,
barPercentage: 0.6
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
x: { grid: { color: 'rgba(80, 140, 255, 0.08)' }, ticks: { color: '#94a3b8', font: { size: 11 } } },
y: { grid: { color: 'rgba(80, 140, 255, 0.08)' }, ticks: { color: '#94a3b8', font: { size: 11 } }, beginAtZero: true }
}
}
});
const costCtx = document.getElementById('costChart').getContext('2d');
new Chart(costCtx, {
type: 'line',
data: {
labels: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'],
datasets: [
{
label: 'Costo',
data: [2100, 2400, 2800, 3200, 3600, 4100, 3800, 4200, 4500, 3900, 3600, 3400],
borderColor: '#f59e0b',
backgroundColor: 'rgba(245, 158, 11, 0.15)',
borderWidth: 2.5,
tension: 0.35,
pointBackgroundColor: '#f59e0b',
pointRadius: 3,
fill: true
},
{
label: 'Presupuesto',
data: [2000, 2300, 2600, 3000, 3400, 3800, 3600, 4000, 4300, 3800, 3500, 3300],
borderColor: '#22c55e',
borderWidth: 1.5,
borderDash: [5, 5],
tension: 0.3,
pointRadius: 0,
fill: false
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
x: { grid: { color: 'rgba(80, 140, 255, 0.08)' }, ticks: { color: '#94a3b8', font: { size: 10 } } },
y: { grid: { color: 'rgba(80, 140, 255, 0.08)' }, ticks: { color: '#94a3b8', font: { size: 11 } }, beginAtZero: false }
}
}
});
if (typeof applyTheme === 'function') applyTheme();
};
if (typeof Chart !== 'undefined') APChartsInit();
else document.addEventListener('DOMContentLoaded', APChartsInit, { once: true });
document.querySelectorAll('.nav-item').forEach(item => {
item.addEventListener('click', () => {
document.querySelectorAll('.nav-item').forEach(i => i.classList.remove('active'));
item.classList.add('active');
});
});
</script>
<script>
'use strict';
const APCompliance={
// Didactic hierarchy, not a catalog of enacted law or a legal opinion.
levels:[['constitucion','Constitución',1,'Norma superior (ejemplo de jerarquía)'],['ley','Leyes',2,'Mandatos legales (sin texto jurídico cargado)'],['reglamento','Reglamentos',3,'Desarrollo reglamentario (sin fuente cargada)'],['sector','Normas sectoriales',4,'Dependen de jurisdicción y sector'],['interna','Políticas internas',5,'Reglas de operación de esta demo']],
colombia:[
['CO-CONST-25-53',1,'Constitución Política, arts. 25 y 53','Trabajo digno y remuneración mínima vital y móvil','https://www.suin-juriscol.gov.co/viewDocument.asp?ruta=Constitucion%2F1687988'],
['CO-CST',2,'Código Sustantivo del Trabajo','Salario, jornada, descansos y prestaciones; revisar artículos y reformas','https://www.funcionpublica.gov.co/eva/gestornormativo/norma.php?i=199983'],
['CO-LEY-2466-2025',2,'Ley 2466 de 2025','Reforma laboral; vigencia escalonada por disposición','https://www.funcionpublica.gov.co/eva/gestornormativo/norma.php?i=260676'],
['CO-DECRETO-159-2026',3,'Decreto 159 de 2026','Salario mínimo transitorio 2026; estado judicial requiere revisión','https://www.cancilleria.gov.co/normograma/compilacion/docs/decreto_0159_2026.htm'],
['CO-DECRETO-1470-2025',3,'Decreto 1470 de 2025','Auxilio de transporte 2026 y condiciones','https://cancilleria.gov.co/normograma/compilacion/docs/decreto_1470_2025.htm'],
['CO-CE-AUTO-2026',4,'Consejo de Estado: auto cautelar 2026','Suspensión provisional de Decreto 1469 y orden de acto sustituto; revisar providencias posteriores','https://www.alcaldiabogota.gov.co/sisjur/normas/Norma1.jsp?dt=S&i=192123'],
['CO-CC-C815-1999',4,'Corte Constitucional, C-815/99','Criterios constitucionales para fijar salario mínimo','https://www.corteconstitucional.gov.co/relatoria/1999/C-815-99.htm']
],
agents:[
['mercantil','Mercantil','Compras, proveedores, operaciones comerciales y sociedades','Propuestas de compra y contratos comerciales','Constitución → legislación mercantil → reglamentos aplicables → actos y decisiones → política interna','Sin fuentes ni reglas de jurisdicción cargadas'],
['laboral','Laboral','Vínculos de trabajo, jornada, remuneración y seguridad social','Alta y cambios de personal, nómina, jornada','Constitución → leyes y código laboral → reglamentos → jurisprudencia aplicable → política interna','Caso Colombia disponible solo como demo de fuentes; Venezuela sin fuentes laborales cargadas'],
['civil','Civil · contratación','Formación, ejecución, garantías y terminación de contratos civiles','Borradores de contrato, renovaciones y cláusulas','Constitución → legislación civil → reglamentos aplicables → jurisprudencia → cláusulas y política interna','Sin análisis de cláusulas implementado'],
['tributario-nacional','Tributario · nacional','IVA, ISLR, aportes parafiscales patronales y tributos sectoriales, según país','Operaciones gravadas, facturación, nómina patronal y declaraciones','Constitución → leyes tributarias → reglamentos → actos administrativos y jurisprudencia → control interno','País y régimen por definir; no se calcula ni declara'],
['tributario-regional','Tributario · regional','Tributos de región, estado o departamento según territorio aplicable','Operaciones, establecimientos e inmuebles con nexo regional','Constitución → ley nacional habilitante → norma regional → decisiones aplicables → control interno','Región y competencia por definir'],
['tributario-local','Tributario · local','Tributos municipales o distritales según domicilio y actividad','Establecimientos, actividades, inmuebles y permisos locales','Constitución → ley habilitante → ordenanza o acuerdo local → decisiones aplicables → control interno','Municipio y competencia por definir'],
['administrativo','Administrativo','Interacciones con entidades públicas y posibles faltas en la actuación de funcionarios, con revisión de hechos y competencia','Quejas o reclamos, peticiones, recursos frente a actos administrativos y eventual responsabilidad estatal','Constitución → procedimiento administrativo y leyes aplicables → reglamentos → acto y expediente → precedentes pertinentes','País, entidad, hechos, plazos y vía competente por verificar; no presenta escritos ni acusa a personas']
],
evaluate(ap,input){const layers=ap.query("SELECT * FROM compliance_norms WHERE id LIKE 'DEMO-%' ORDER BY level,id");if(!layers.length)return {status:'review',norm_id:null,reason:'Sin jerarquía de normas cargada'};const unknown=layers.find(x=>x.level<5&&!x.source_url);if(unknown)return {status:'review',norm_id:unknown.id,reason:'Faltan fuentes jurídicas vigentes para '+unknown.name+'; requiere evaluación humana'};return {status:'review',norm_id:'DEMO-interna-propuesta',reason:'Revisión humana requerida por política interna ilustrativa'};},
badge(ap,id){const c=ap.one('SELECT c.status,c.norm_id,c.reason FROM compliance_checks c WHERE c.proposal_id=?',[id]);const r=c||{status:'review',norm_id:'SIN-REVISAR',reason:'Propuesta anterior sin comprobación documentada'};return '<span class="ap-compliance-pill '+r.status+'" title="'+ap.esc(r.norm_id+' · '+r.reason)+'">'+(r.status==='pass'?'● Conforme':r.status==='block'?'● Bloqueado':'● Revisar')+' · '+ap.esc(r.norm_id)+'</span>'},
country(){return localStorage.getItem('ap-country')==='VE'?'VE':'CO'},
jurisdictionPicker(){const country=this.country();return '<div class="ap-jurisdiction"><label for="ap-country">País para la vista jurídica</label><select id="ap-country" aria-label="País para la vista jurídica"><option value="CO"'+(country==='CO'?' selected':'')+'>Colombia</option><option value="VE"'+(country==='VE'?' selected':'')+'>Venezuela</option></select><span>Selector de análisis local; no convierte normas de un país en reglas de otro.</span></div>'},
assessEvidence(text){const t=String(text).toLocaleLowerCase('es'),values=[['colaboración',/colabor|equipo|coordin/],['aprendizaje',/aprend|formaci[oó]n|mejor/],['responsabilidad',/responsab|entreg|seguim/]],hits=values.filter(x=>x[1].test(t)).map(x=>x[0]),specific=/\b(\d{1,3}%|\d+ (meses|años|proyectos|clientes|entregas)|resultado|ejemplo|proyecto|implement)\b/i.test(t),score=hits.length*20+(specific?20:0),explanation='Señales textuales encontradas: '+(hits.join(', ')||'ninguna')+'. '+(specific?'Incluye ejemplo o resultado específico.':'Falta un ejemplo o resultado específico; pide evidencia antes de avanzar.')+' Revisión humana necesaria: las palabras clave no prueban ajuste cultural.';return {score,explanation,status:score>=60?'review':'needs_evidence'}},
candidateView(){const ap=AP,esc=v=>ap.esc(v??''),rows=ap.query('SELECT * FROM candidate_screenings ORDER BY created_at DESC,id'),roles=[['⚙','Operaciones','Fabricación / servicio'],['🤝','Relaciones','Clientes y aliados'],['🔭','Exploración','Mercados y productos']];return '<div class="ap-recruit-hero"><small>RRHH · TRABAJO AGÉNTICO SEPARADO · DEMO SUPERVISADA</small><h2>Currícula y alineación cultural</h2><p>Las ofertas se muestran como posiciones de un equipo. Un cribado de texto explica señales observables de colaboración, aprendizaje y responsabilidad; no decide contrataciones ni sustituye entrevistas. Solo una persona puede aprobar el paso de un perfil al tablero de reclutamiento.</p></div><div class="ap-squad"><header>⚽ ALINEACIÓN · POSICIONES DE EJEMPLO, NO VACANTES PUBLICADAS</header><div class="ap-squad-pitch">'+roles.map(([icon,title,note])=>'<div class="ap-squad-role"><span>'+icon+'</span><strong>'+title+'</strong><small>'+note+'</small></div>').join('')+'</div></div><p class="ap-cost-note">Criterios definidos para esta demostración: evidencia relacionada con el puesto, colaboración, aprendizaje y responsabilidad. No se solicitan ni evalúan edad, género, origen, foto u otros atributos protegidos. La puntuación es un filtro de señales textuales, no una valoración de la persona o de su compatibilidad cultural real. Todo avance o rechazo requiere juicio humano.</p><h3>Analizar resumen voluntario de un perfil</h3><form id="ap-candidate-form" class="ap-candidate-form"><label>Alias (sin datos personales)<input name="alias" maxlength="60" required placeholder="Perfil A"></label><label>Posición<select name="role">'+roles.map(x=>'<option>'+esc(x[1])+'</option>').join('')+'</select></label><label style="grid-column:span 2">Evidencia laboral aportada<textarea name="evidence" maxlength="700" required placeholder="Ejemplos de trabajo en equipo, aprendizaje, responsabilidades y resultados, sin datos sensibles"></textarea></label><button type="submit">Analizar señales</button></form><p id="ap-candidate-feedback" class="ap-compliance-note" role="status">No pegues currículos con datos sensibles aquí. Ningún documento se sube ni se lee de forma autónoma.</p><h3>Revisión humana · '+rows.length+' perfiles locales</h3><div class="ap-candidate-list">'+(rows.length?rows.map(x=>'<article class="ap-candidate-card"><small>'+(x.demo?'PERFIL FICTICIO · DEMO':'PERFIL LOCAL')+' · '+esc(x.role)+'</small><br><strong>'+esc(x.alias)+'</strong><p>'+esc(x.evidence)+'</p><span class="ap-legal-status">'+(x.status==='approved'?'Avance aprobado por humano':x.status==='needs_evidence'?'Solicitar evidencia':'Revisión humana pendiente')+'</span><p><b>Señales '+x.score+'/80:</b> '+esc(x.explanation)+'</p>'+(x.status==='review'?'<button type="button" data-approve-candidate="'+esc(x.id)+'">Aprobar avance al reclutamiento</button>':'')+'</article>').join(''):'<p class="ap-recruit-empty">Sin perfiles. Introduce un escenario ficticio para probar el flujo.</p>')+'</div><p class="ap-compliance-note">La recomendación de avance exige 60/80 señales y una aprobación explícita de una persona. Un valor menor pide más evidencia, nunca rechazo automático. El proceso real necesita criterios aprobados, protección de datos, evaluación de sesgo y consentimiento.</p>'},
recruitmentView(){const ap=AP,esc=v=>ap.esc(v??''),kinds=['Colaboradores internos','Aliados','Productos','Clientes','Mercados'],stages=['Detectado','Exploración','Evaluación','Incorporación'],all=ap.query('SELECT * FROM recruitment_pipeline ORDER BY created_at DESC,id'),counts=kinds.map(k=>[k,all.filter(x=>x.kind===k).length]),cards=stages.map((stage,i)=>'<div class="ap-recruit-column"><h3>'+esc(stage)+' · '+all.filter(x=>x.stage===stage).length+'</h3>'+((items)=>items.length?items.map(x=>'<article class="ap-recruit-card"><small>'+esc(x.kind)+(x.demo?' · DEMO':' · REGISTRO LOCAL')+'</small><strong>'+esc(x.title)+'</strong>'+(x.note?'<p>'+esc(x.note)+'</p>':'')+(x.signal?'<p>Señal aportada: '+esc(x.signal)+'</p>':'')+(i<stages.length-1?'<button class="ap-recruit-move" type="button" data-recruit-id="'+esc(x.id)+'" data-next-stage="'+esc(stages[i+1])+'">Mover a '+esc(stages[i+1])+'</button>':'')+'</article>').join(''):'<p class="ap-recruit-empty">Sin registros en esta etapa.</p>')(all.filter(x=>x.stage===stage))+'</div>').join('');return '<div class="ap-recruit-hero"><small>RRHH · CAPTACIÓN · GESTIÓN DEL CAMBIO EXTERNO</small><h2>Radar de oportunidades</h2><p>Cinco flujos de captación para acompañar cambios del mercado, la regulación y el ambiente. Un registro en el tablero no equivale a contratación, alianza, lanzamiento ni venta.</p></div><div class="ap-recruit-categories">'+counts.map(([k,n])=>'<div class="ap-recruit-category"><small>'+esc(k)+'</small><strong>'+n+' <small>registros</small></strong></div>').join('')+'</div><h3>Radar externo</h3><div class="ap-recruit-radar"><div><strong>↗ Mercado</strong><small>Nuevos clientes, mercados, aliados y productos. Esperando señales aportadas por el equipo.</small></div><div><strong>⚖ Regulaciones</strong><small>Impactos jurídicos y laborales por país; ningún cambio normativo se monitoriza automáticamente.</small></div><div><strong>◌ Ambiente</strong><small>Riesgos y oportunidades ambientales. Sin datos externos conectados ni alertas en tiempo real.</small></div></div><h3>Registrar oportunidad o escenario</h3><form id="ap-recruit-form" class="ap-recruit-form"><label>Flujo<select name="kind">'+kinds.map(k=>'<option>'+esc(k)+'</option>').join('')+'</select></label><label>Nombre breve<input name="title" maxlength="100" required placeholder="Ej.: Perfil de mantenimiento"></label><label>Señal externa (opcional)<input name="signal" maxlength="160" placeholder="Origen verificado por el equipo"></label><label>Nota (opcional)<input name="note" maxlength="180" placeholder="Siguiente paso propuesto"></label><button type="submit">Guardar en Detectado</button></form><p class="ap-compliance-note" id="ap-recruit-feedback" role="status">Datos locales en este navegador. El radar no inventa vacantes, candidatos, aliados ni señales externas; alimenta el tablero solo con lo registrado aquí.</p><h3>Flujo de seguimiento</h3><div class="ap-recruit-board">'+cards+'</div><p class="ap-compliance-note">Colaboradores internos enlaza con RRHH/Laboral; aliados y productos con Suministro/Mercantil; clientes y mercados con CRM/Ventas. El enlace es organizativo, sin automatizar decisiones ni conectar expedientes externos.</p>'},
costView(){const ap=AP,esc=v=>ap.esc(v??''),country=this.country(),cur=country==='VE'?'VES':'COP',entries=ap.query('SELECT * FROM labor_cost_entries WHERE country=? ORDER BY period DESC,created_at DESC LIMIT 100',[country]),period=entries.length?entries[0].period:'',current=entries.filter(x=>x.period===period),operational=current.filter(x=>x.area==='Operativa'),support=current.filter(x=>x.area==='Soporte'),sum=a=>a.reduce((n,x)=>n+x.amount_cents,0),op=sum(operational),sup=sum(support),fmt=n=>new Intl.NumberFormat('es-ES',{minimumFractionDigits:2,maximumFractionDigits:2}).format(n/100)+' '+cur,groups=['Fabricación','Comercialización','Servicios'],rows=groups.map(name=>{const o=sum(operational.filter(x=>x.structure===name)),allocated=op?Math.round(sup*o/op):null;return [name,fmt(o),op?(o/op*100).toFixed(1)+' %':'Sin base',allocated===null?'Sin base operativa':fmt(allocated),'Solo MO operativa a coste; reparto de soporte solo analítico']});return this.jurisdictionPicker()+'<div class="ap-compliance-hero"><small>RRHH · LABORAL · ESTRUCTURA FINANCIERA</small><h2>Mano de obra por área</h2><p>Fabricación, Comercialización y Servicios. La MO operativa se presenta como coste; la MO de soporte administrativo como gasto no recuperable. Su reparto proporcional a la MO operativa sirve únicamente para análisis y proyección, nunca para capitalizar el gasto.</p></div><p class="ap-cost-note">Modelo de análisis definido por el usuario, no una regla contable universal ni una certificación ISO 9001. Valida el plan de cuentas y la política contable antes de registrar asientos o valorar inventario. No hay asientos automáticos.</p><form id="ap-cost-form" class="ap-cost-form"><label>Periodo (mes)<input name="period" type="month" required></label><label>Estructura<select name="structure"><option>Fabricación</option><option>Comercialización</option><option>Servicios</option></select></label><label>Área<select name="area"><option>Operativa</option><option>Soporte</option></select></label><label>MO del periodo ('+cur+')<input name="amount" type="number" min="0" step="0.01" required placeholder="Importe real o de escenario"></label><button type="submit">Guardar escenario local</button></form><p class="ap-compliance-note" id="ap-cost-feedback" role="status">Usa un periodo y datos propios. Cada entrada queda en SQLite local, separada por país.</p><div class="ap-cost-kpis">'+APViews.tiles([['Periodo analizado',period||'Sin datos'],['MO operativa · coste',fmt(op)],['MO soporte · gasto',fmt(sup)],['Soporte / MO operativa',op?(sup/op*100).toFixed(1)+' %':'Sin base operativa']])+'</div><h3>Proyección y reparto analítico'+(period?' · '+esc(period):'')+'</h3>'+APViews.table(['Estructura','MO operativa a coste','Peso en base operativa','Soporte imputado solo para análisis','Tratamiento'],rows)+'<p class="ap-compliance-note">Fórmula analítica: soporte total × (MO operativa de la estructura / MO operativa total). Si no hay MO operativa, no se reparte. El reparto no altera los importes de coste ni gasto guardados. Moneda '+cur+'; no mezcla países ni convierte divisas.</p><h3>Entradas locales</h3>'+APViews.table(['Periodo','Estructura','Área','Importe','Tratamiento'],entries.map(x=>[x.period,x.structure,x.area,fmt(x.amount_cents),x.area==='Operativa'?'Coste':'Gasto no recuperable']))},
agentsView(){const ap=AP,esc=v=>ap.esc(v??''),agents=ap.query('SELECT * FROM legal_subagents ORDER BY CASE id WHEN \u0027mercantil\u0027 THEN 1 WHEN \u0027laboral\u0027 THEN 2 WHEN \u0027civil\u0027 THEN 3 WHEN \u0027tributario-nacional\u0027 THEN 4 WHEN \u0027tributario-regional\u0027 THEN 5 WHEN \u0027tributario-local\u0027 THEN 6 ELSE 7 END'),proposals=ap.query('SELECT id,sku FROM purchase_proposals ORDER BY rowid DESC LIMIT 20');return this.jurisdictionPicker()+'<div class="ap-compliance-hero"><small>ORQUESTACIÓN JURÍDICA · DISEÑO LOCAL</small><h2>Subagentes jurídicos</h2><p>Siete ámbitos de revisión y un enrutamiento propuesto por tipo de operación. La jerarquía de cada ámbito es un esquema, no un conjunto de normas vigentes: sin país, territorio, sector y reglas verificadas, estos subagentes no emiten dictámenes ni aprueban propuestas.</p></div><div class="ap-legal-flow"><b>Ruta de una propuesta</b><br>Tipo de operación → país y territorio → ámbitos competentes → fuentes y vigencia → revisión humana → decisión registrada. Hoy solo existe el estado local de cumplimiento general; esta ruta jurídica no ejecuta revisiones automáticas ni envía declaraciones.</div><h3>Ámbitos y cobertura</h3><div class="ap-legal-grid">'+agents.map(x=>'<article class="ap-legal-agent"><header><div><small>SUBAGENTE · '+esc(x.id)+'</small><h3>'+esc(x.name)+'</h3></div><span class="ap-legal-status">'+(x.status==='demo'&&this.country()==='CO'?'Demo de fuentes':'Por configurar')+'</span></header><p>'+(x.id==='tributario-nacional'?'Tributos nacionales: IVA, '+(this.country()==='VE'?'ISLR':'renta')+', parafiscales patronales y sectoriales, sujetos al régimen aplicable.':esc(x.subject))+'</p><p><b>Revisaría:</b> '+esc(x.routing)+'</p><p><b>Pirámide de referencia:</b></p><ul>'+x.hierarchy.split(' → ').map(t=>'<li>'+esc(t)+'</li>').join('')+'</ul><p class="ap-legal-scope">'+esc(x.configuration_note)+'</p></article>').join('')+'</div><h3>Propuestas locales · ruta sugerida</h3><p class="ap-compliance-note">Las propuestas de compra del ERP son candidatas a revisión mercantil. Un análisis tributario dependerá del país, el territorio, el tipo de operación y el régimen fiscal; no se infiere la aplicabilidad de IVA, ISLR ni tributos regionales/locales. Esto es clasificación visual, no revisión efectuada.</p>'+APViews.table(['Propuesta','SKU','Ámbito candidato','Estado jurídico'],proposals.map(x=>[x.id,x.sku,'Mercantil · tributario por determinar','Sin revisión de subagentes']))+'<p class="ap-compliance-note">Administrativo ayuda a ordenar posibles reclamaciones ante entidades públicas; una queja, petición, recurso o acción exige identificar país, entidad, hechos, acto, plazos y cauce competente. No genera ni presenta denuncias, no atribuye faltas a funcionarios y no sustituye asesoría jurídica.</p><p class="ap-compliance-note">Civil y Laboral se activarán para contratos o actos de personal cuando existan documentos y datos con ámbito definido. No se han creado subagentes ejecutores ni obligaciones fiscales. Ninguna propuesta es aprobada por esta vista.</p>'},
payrollView(){const ap=AP,esc=v=>ap.esc(v??''),norms=ap.query("SELECT * FROM compliance_norms WHERE id LIKE 'CO-%' ORDER BY level,id"),rules=ap.query('SELECT * FROM payroll_rules ORDER BY id');return '<div class="ap-compliance-hero"><small>COLOMBIA · JURÍDICO-LABORAL · DEMO</small><h2>Nómina con trazabilidad normativa</h2><p>La cadena de fuentes recorre Constitución, código y leyes, decretos y providencias. Solo se listan normas verificadas en fuentes oficiales o institucionales. Una providencia posterior puede cambiar la regla aplicable: esta demo no emite nómina ni certifica cumplimiento.</p><div class="ap-pyramid">'+[['Constitución',55],['Leyes y Código Laboral',68],['Decretos salariales',80],['Providencias',92]].map((x,i)=>'<div class="ap-pyramid-level" style="--width:'+x[1]+'%"><b>'+x[0]+'</b><small>NIVEL '+(i+1)+'</small></div>').join('')+'</div></div><h3>Fuentes jurídicas enlazadas</h3><div class="ap-law-list">'+norms.map(x=>'<div class="ap-law-card"><small>NIVEL '+x.level+' · '+esc(x.id)+'</small><strong>'+esc(x.name)+'</strong><p>'+esc(x.scope)+'</p><a target="_blank" rel="noopener noreferrer" href="'+esc(x.source_url)+'">Consultar fuente ↗</a></div>').join('')+'</div><h3>Conceptos de nómina y reglas</h3>'+APViews.table(['Concepto','Regla / fuente','Valor orientativo','Estado'],rules.map(x=>[x.concept,x.norm_id+' · '+x.formula_note,x.value_text||'Por configurar',x.status==='requires_review'?'Revisión jurídica pendiente':'Sin parametrizar']))+'<h3>Simulador no liquidable</h3><p class="ap-compliance-note">Introduce salario base y días trabajados. Solo se prorratea el salario ordinario para visualizar la estructura; horas extra, recargos, prestaciones, aportes y auxilio se dejan pendientes. No uses este resultado para pagar, contratar ni declarar.</p><form id="ap-payroll-form" class="ap-payroll-form"><label>Salario mensual de ejemplo (COP)<input name="salary" type="number" min="0" step="1" placeholder="Salario de ejemplo" required></label><label>Días trabajados de ejemplo (0 a 30)<input name="days" type="number" min="0" max="30" step="1" value="30" required></label><button type="submit">Ver desglose ilustrativo</button></form><div id="ap-payroll-output" class="ap-payroll-output" role="status">Pendiente de datos de ejemplo. Ningún valor se guarda como nómina.</div><p class="ap-compliance-note">Importes de 2026 citados como referencia de los decretos indicados, no como vigencia definitiva: hubo medidas cautelares y deben comprobarse cambios posteriores. La jurisdicción, convenio, modalidad, periodo, jornada, IBC y topes deben validarse antes de habilitar un cálculo real.</p>'},
view(){const ap=AP,esc=v=>ap.esc(v??''),layers=ap.query("SELECT * FROM compliance_norms WHERE id LIKE 'DEMO-%' ORDER BY level,id"),checks=ap.query('SELECT p.id,p.sku,q.status AS decision,c.status AS check_status,c.norm_id,c.reason FROM purchase_proposals p JOIN approval_queue q ON q.proposal_id=p.id LEFT JOIN compliance_checks c ON c.proposal_id=p.id ORDER BY p.rowid DESC LIMIT 30');return this.jurisdictionPicker()+'<div class="ap-compliance-hero"><small>CAPA DE CUMPLIMIENTO · DEMOSTRACIÓN</small><h2>Jerarquía normativa</h2><p>Modelo visual inspirado en la pirámide de Kelsen. Las normas de este entorno son ejemplos, no normas jurídicas verificadas. Sin jurisdicción, sector y fuentes vigentes, ninguna propuesta obtiene una certificación legal ni se autoaprueba por esta capa.</p><div class="ap-pyramid">'+this.levels.map((x,i)=>'<div class="ap-pyramid-level" style="--width:'+(50+i*12)+'%"><b>'+esc(x[1])+'</b><small>NIVEL '+x[2]+'</small></div>').join('')+'</div><p class="ap-compliance-note">Se comprueban primero los niveles superiores; una ausencia de fuentes o conflicto requiere revisión humana. Esta demo solo trabaja sobre propuestas locales y no ejecuta compras, pagos o cambios de stock.</p></div><h3>Normas registradas · ejemplos</h3>'+APViews.table(['Nivel','Identificador','Alcance','Fuente'],layers.map(x=>[x.level,x.id,x.scope,x.source_url||'No aportada · ejemplo']))+'<h3>Propuestas y revisión</h3>'+APViews.table(['Propuesta','SKU','Decisión local','Semáforo','Norma / motivo'],checks.map(x=>[x.id,x.sku,x.decision,x.check_status==='pass'?'🟢 Conforme':x.check_status==='block'?'🔴 Bloqueado':'🟠 Revisión humana', (x.norm_id||'SIN-REVISAR')+' · '+(x.reason||'Sin comprobación documentada')]))+'<p class="ap-compliance-note">No es asesoramiento jurídico. Antes de activar reglas reales, indique jurisdicción, actividad, fuentes oficiales aplicables y responsable legal para validarlas.</p>'}
};
const APFormat={
// Model text stays inert: no HTML, URLs or browser actions are derived from it.
inline(parent,text){const re=/(\*\*([^*\n]{1,400})\*\*|`([^`\n]{1,400})`)/g;let from=0,m;while((m=re.exec(text))){parent.append(document.createTextNode(text.slice(from,m.index)));const el=document.createElement(m[2]?'strong':'code');el.textContent=m[2]||m[3];parent.append(el);from=re.lastIndex}parent.append(document.createTextNode(text.slice(from)))},
render(el,value){const text=String(value??'').slice(0,20000).replace(/\r\n?/g,'\n');let list=null,code=null;for(const line of text.split('\n')){if(/^\s*`{3}/.test(line)){if(code){el.append(code);code=null}else{list=null;code=document.createElement('pre')}continue}if(code){const span=document.createElement('code');span.textContent=line+'\n';code.append(span);continue}const bullet=line.match(/^\s*[-*]\s+(.+)$/);if(bullet){if(!list){list=document.createElement('ul');el.append(list)}const li=document.createElement('li');this.inline(li,bullet[1]);list.append(li);continue}list=null;if(!line.trim())continue;const p=document.createElement('p');this.inline(p,line.replace(/^#{1,4}\s+/,''));el.append(p)}if(code)el.append(code);if(!el.childNodes.length)el.textContent=text}
};
const AP = {
model: 'MiMo-V2.6-Distill-Qwen-9B (local en este navegador)',
models: null,
db: null, busy: false, store: null, cycleBusy:false, cycleTimer:null, cycleIntervalMs:30000, lastModelCycleAt:0, mode: localStorage.getItem('adaptapro-mode')==='autonomo'?'autonomo':'supervisado', agentsOn: localStorage.getItem('adaptapro-agents')!=='off',
money: n => 'USD '+new Intl.NumberFormat('en-US',{minimumFractionDigits:2,maximumFractionDigits:2}).format(n/100),
esc: s => String(s).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c])),
rows(...a){return APData.rows(...a);},
one(...a){return APData.one(...a);},
query(...a){return APData.query(...a);},
exec(...a){return APData.exec(...a);},
storage(...a){return APData.storage(...a);},
loadBytes(...a){return APData.loadBytes(...a);},
persist(...a){return APData.persist(...a);},
reset(...a){return APCommands.reset(...a);},
tx(...a){return APData.tx(...a);},
loadSeed(...a){return APData.loadSeed(...a);},
migrationPlan(...a){return APData.migrationPlan(...a);},
userVersion(...a){return APData.userVersion(...a);},
applyMigrations(...a){return APData.applyMigrations(...a);},
async init(){
try{
await new Promise((resolve,reject)=>{if(globalThis.__apCoreReady)return resolve();globalThis.addEventListener('ap-core-ready',resolve,{once:true});setTimeout(()=>reject(Error('Módulos del núcleo no cargados')),20000);});
const SQL=await initSqlJs({locateFile:f=>'vendor/sql.js/1.13.0/'+f});
this.store=await this.storage();const saved=await this.loadBytes();this.db=saved?new SQL.Database(saved):new SQL.Database();this.db.run('PRAGMA foreign_keys=ON');
const seed=await this.loadSeed();
await this.applyMigrations();
if(!saved){this.tx(()=>{for(const [table,items] of Object.entries(seed)){if(table==='meta')continue;for(const item of items){const keys=Object.keys(item);this.db.run(`INSERT INTO ${table} (${keys.join(',')}) VALUES (${keys.map(()=>'?').join(',')})`,keys.map(k=>item[k]));}}});}
else{this.tx(()=>{for(const table of ['workforce','production_jobs','planning_tasks'])for(const item of seed[table]||[]){const keys=Object.keys(item);this.db.run('INSERT OR IGNORE INTO '+table+' ('+keys.join(',')+') VALUES ('+keys.map(()=>'?').join(',')+')',keys.map(k=>item[k]));}});this.db.run("UPDATE purchase_proposals SET currency='USD' WHERE currency='EUR'");}
await this.persist();APPacks.load().catch(e=>console.warn('Registro de packs no disponible: '+e.message));this.render();this.updateMode();this.updateAgents();this.note('Demo local ficticia (semilla de julio de 2030). Modo '+this.mode+'.');this.startCycle();
}catch(e){this.note('No se pudieron cargar los datos: '+e.message,true);console.error(e);}
},
updateAgents(...a){return APCommands.updateAgents(...a);},
toggleAgents(...a){return APCommands.toggleAgents(...a);},
updateMode(...a){return APPolicy.updateMode(...a);},
toggleMode(...a){return APPolicy.toggleMode(...a);},
note(text,error=false){const e=document.getElementById('ap-state');if(e){e.textContent=text;e.style.color=error?'#fca5a5':'#94a3b8';}},
render(){
if(!this.db)return;
const stock=this.rows('SELECT * FROM stock_status ORDER BY sku');
const queue=this.rows(`SELECT q.*,p.sku,p.proposed_qty,p.unit_cost_cents,p.currency,p.rationale,p.supplier_id,p.agent_id,
s.name AS supplier FROM approval_queue q JOIN purchase_proposals p ON p.id=q.proposal_id JOIN suppliers s ON s.id=p.supplier_id ORDER BY p.created_at DESC`);
const pending=queue.filter(x=>x.status==='pendiente');
const stockEl=document.getElementById('ap-stock');
stockEl.innerHTML=stock.map(x=>`<div class="ap-line"><b>${this.esc(x.sku)}</b> ${this.esc(x.name)} · ${x.available} disponibles / ${x.on_hand} físicos ${x.needs_restock?'<span class="ap-warn">· Reposición necesaria</span>':''}</div>`).join('');
document.getElementById('ap-queue').innerHTML=queue.map(x=>`<div class="ap-proposal"><b>${this.esc(x.proposal_id)} · ${this.esc(x.sku)}</b> · ${x.proposed_qty} unidades · ${this.money(x.proposed_qty*x.unit_cost_cents)}<br><small>${this.esc(x.supplier)} · ${this.esc(x.rationale)}</small><br><span class="ap-status">${this.esc(x.status)}</span> ${APCompliance.badge(this,x.proposal_id)} ${x.status==='pendiente'?`<button data-decision="aprobada" data-id="${this.esc(x.proposal_id)}" title="Revisión humana necesaria; no certifica cumplimiento legal">Revisar y decidir</button><button data-decision="rechazada" data-id="${this.esc(x.proposal_id)}">Rechazar</button>`:''} ${x.status==='aprobada'&&!this.one('SELECT id FROM stock_movements WHERE proposal_id=?',[x.proposal_id])?`<button data-receive="${this.esc(x.proposal_id)}">Registrar recepción</button>`:''}</div>`).join('')||'<p>No hay propuestas.</p>';
document.getElementById('ap-pending').textContent=pending.length;
document.getElementById('ap-pending-metric').textContent=pending.length;
const total=this.one('SELECT coalesce(sum(quantity*unit_price_cents),0) AS n FROM sales_order_lines');
document.getElementById('ap-order-value').textContent=this.money(total.n);
const reservations=this.one('SELECT coalesce(sum(reserved),0) AS n FROM inventory');
document.getElementById('ap-reservations').textContent=reservations.n;
document.getElementById('ap-audit').innerHTML=this.rows('SELECT actor,action,entity_id,occurred_at FROM audit_log ORDER BY rowid DESC LIMIT 6').map(e=>`<div class="ap-line">${this.esc(e.actor)} · ${this.esc(e.action)} · ${this.esc(e.entity_id)}</div>`).join('');
const feed=document.getElementById('ap-feed');feed.innerHTML=this.rows('SELECT actor,action,entity_id,occurred_at FROM audit_log ORDER BY rowid DESC LIMIT 7').map(e=>`<div class="ap-feed-item"><time>${this.esc(new Date(e.occurred_at).toLocaleTimeString('es-ES',{hour:'2-digit',minute:'2-digit'}))}</time><strong>${this.esc(e.actor)}</strong> · ${this.esc(e.action.replaceAll('_',' '))}<small>${this.esc(e.entity_id)}</small></div>`).join('');
document.getElementById('ap-orders').innerHTML=this.rows('SELECT id,customer_name,region,status FROM sales_orders ORDER BY rowid DESC LIMIT 8').map(e=>`<div class="ap-line"><b>${this.esc(e.id)}</b> · ${this.esc(e.customer_name)} · ${this.esc(e.region)} · ${this.esc(e.status)}</div>`).join('');
document.querySelectorAll('[data-decision]').forEach(b=>b.onclick=()=>this.command({cmd:'propuesta_decidir',payload:{id:b.dataset.id,status:b.dataset.decision}}).catch(e=>this.note(e.message,true)));
document.querySelectorAll('[data-receive]').forEach(b=>b.onclick=()=>this.command({cmd:'recepcion_registrar',payload:{id:b.dataset.receive}}).catch(e=>this.note(e.message,true)));
const low=stock.filter(x=>x.needs_restock).length;
const metric=document.getElementById('ap-stock-metric');if(metric)metric.textContent=stock.length-low+'/'+stock.length;
},
decide(...a){return APCommands.decide(...a);},
receive(...a){return APCommands.receive(...a);},
command(...a){return APBus.command(...a);},
confirmAction(...a){return APPolicy.confirmAction(...a);},
decisionForm(...a){return APPolicy.decisionForm(...a);},
audit(...a){return APPolicy.audit(...a);},
context(...a){return APCommands.context(...a);},
propose(...a){return APCommands.propose(...a);},
modelCall(...a){return APCommands.modelCall(...a);},
closeChat(){const e=document.getElementById('chatWindow');e.hidden=true;e.style.display='none';localStorage.setItem('adaptapro-chat-open','false');},
tab(which){const e=document.getElementById('chatWindow');e.hidden=false;e.style.display='block';localStorage.setItem('adaptapro-chat-open','true');document.getElementById('ap-chat-panel').hidden=which!=='chat';document.getElementById('ap-supervision-panel').hidden=which!=='supervision';},
append(text,who){const el=document.createElement('div');el.className='chat-msg '+who;if(who==='ai')APFormat.render(el,text);else el.textContent=String(text);const body=document.querySelector('.chat-body');body.append(el);body.scrollTop=body.scrollHeight;},
appendStream(text){if(!text)return;const body=document.querySelector('.chat-body');if(!this._streamEl){const el=document.createElement('div');el.className='chat-msg ai';body.append(el);this._streamEl=el;}this._streamEl.textContent=text;body.scrollTop=body.scrollHeight;},
appendFinal(text){const el=this._streamEl;this._streamEl=null;if(el){if(text&&String(text).trim())APFormat.render(el,text);else el.remove();}else if(text&&String(text).trim())this.append(text,'ai');},
setAgentState(agent,label,working){const el=document.getElementById('ap-agent-'+agent);if(el){el.textContent=label;el.classList.toggle('ap-working',working);}},
startCycle(...a){return APCommands.startCycle(...a);},
cycle(...a){return APCommands.cycle(...a);},
ask(...a){return APCommands.ask(...a);},
};
window.AP=AP;
const APMic={button:document.getElementById('ap-mic'),recognition:null,active:false,start(){const Speech=window.SpeechRecognition||window.webkitSpeechRecognition;if(!Speech){this.button.disabled=true;this.button.title='Dictado no disponible en este navegador. Prueba Chrome.';this.button.setAttribute('aria-label',this.button.title);document.getElementById('chatInput').placeholder='Dictado no disponible aquí; escribe o prueba Chrome';return}if(this.active){this.recognition.stop();return}const input=document.getElementById('chatInput'),recognition=new Speech();this.recognition=recognition;recognition.lang='es-ES';recognition.continuous=false;recognition.interimResults=true;const prefix=input.value.trim();recognition.onstart=()=>{this.active=true;this.button.classList.add('is-listening');this.button.textContent='⏹';this.button.title='Detener dictado';this.button.setAttribute('aria-label','Detener dictado');this.button.setAttribute('aria-pressed','true')};recognition.onresult=e=>{let words='';for(let i=0;i<e.results.length;i++)words+=e.results[i][0].transcript;input.value=(prefix?prefix+' ':'')+words;input.focus()};recognition.onerror=e=>{if(e.error==='not-allowed'||e.error==='service-not-allowed')input.placeholder='Permite el micrófono en el navegador para dictar';else if(e.error!=='no-speech'&&e.error!=='aborted')input.placeholder='No se pudo dictar; puedes escribir el mensaje'};recognition.onend=()=>{this.active=false;this.button.classList.remove('is-listening');this.button.textContent='🎙️';this.button.title='Dictar mensaje';this.button.setAttribute('aria-label','Dictar mensaje');this.button.setAttribute('aria-pressed','false')};try{recognition.start()}catch(e){recognition.onend();input.placeholder='No se pudo iniciar el dictado; escribe el mensaje'}}};document.getElementById('ap-mic').addEventListener('click',()=>APMic.start());
const apWebBtn=document.getElementById('ap-websearch');function updateWebBtn(){const on=localStorage.getItem('adaptapro-web-search')==='true';apWebBtn.setAttribute('aria-pressed',String(on));apWebBtn.classList.toggle('is-listening',on);apWebBtn.style.opacity=on?'1':'0.5';apWebBtn.title=on?'Búsqueda web ACTIVADA: el texto que escribas se envía también a Tavily y Wikipedia (gratuito, con límites); no se añade automáticamente inventario ni auditoría. No incluyas información confidencial. Pulsa para desactivar.':'Búsqueda web desactivada. Si la activas, el texto que escribas se envía también a Tavily y Wikipedia para buscar contexto; no se añade automáticamente inventario ni auditoría. No incluyas información confidencial.';}
const apModelBtn=document.getElementById('ap-model-load'),apModelState=document.getElementById('ap-model-state'),apModelProg=document.getElementById('ap-model-progress'),apModelBar=apModelProg.querySelector('div'),apModelStop=document.getElementById('ap-model-stop');
apModelStop.addEventListener('click',()=>{if(globalThis.APLocalModel)APLocalModel.stop();});
setInterval(()=>{if(globalThis.APLocalModel){const gen=APLocalModel.state==='generating';apModelStop.hidden=!gen;if(gen)apModelUI();else if(apModelState.textContent==='Generando…')apModelUI();}},500);
function apModelUI(){if(!globalThis.APLocalModel){apModelState.textContent='Cargando módulo del modelo…';apModelBtn.disabled=true;return;}const st=APLocalModel.state;apModelBtn.disabled=st==='downloading';apModelBtn.hidden=st==='ready';if(st==='generating'){apModelState.textContent='Generando…';apModelProg.hidden=true;}else if(st==='ready'){apModelState.textContent='MiMo 9B descargado en este navegador (WASM/CPU). Aviso: en las pruebas actuales la generación falla con el runtime probado (en investigación); si te ocurre, el chat mostrará el error sin cambiar de modelo.';apModelProg.hidden=true;}else if(st==='downloading'){apModelProg.hidden=false;}else{apModelProg.hidden=true;apModelState.textContent=st==='error'?'Error al cargar: '+APLocalModel.error+'. Pulsa el botón para reintentar.':'Modelo local (WASM/CPU, sin aceleración garantizada). Descarga inicial aprox. 5,8 GB; se reutiliza mientras se conserve la caché de este navegador. Necesita memoria libre suficiente: en equipos justos puede ir lento o no cargar. Aviso: en las pruebas actuales este modelo se descarga pero falla al generar con el runtime de navegador probado; estamos investigándolo.';}}
apModelBtn.addEventListener('click',async()=>{apModelBtn.disabled=true;apModelProg.hidden=false;apModelState.textContent='Preparando descarga…';try{await APLocalModel.load((loaded,total)=>{const pct=Math.min(100,Math.round(loaded/total*100));apModelBar.style.width=pct+'%';apModelState.textContent='Descargando MiMo 9B… '+pct+'% ('+Math.round(loaded/1048576)+' MB de '+Math.round(total/1048576)+' MB)';});}catch(e){}apModelUI();});
if(globalThis.APLocalModel)apModelUI();else addEventListener('ap-core-ready',apModelUI,{once:true});
apWebBtn.addEventListener('click',()=>{const on=localStorage.getItem('adaptapro-web-search')!=='true';localStorage.setItem('adaptapro-web-search',String(on));updateWebBtn();AP.append(on?'🔎 Búsqueda web ACTIVADA. A partir de ahora, el texto que escribas se enviará también a Tavily y Wikipedia para buscar contexto (servicios externos, uso gratuito con límites). Las fuentes se citan tras cada respuesta. Se envía el texto que escribas; no se añade automáticamente inventario ni auditoría. No incluyas información confidencial.':'🔎 Búsqueda web desactivada. Tus mensajes ya no se envían a servicios de búsqueda.','ai');});updateWebBtn();
function sendMessage(){const input=document.getElementById('chatInput');const text=input.value.trim();if(!text)return;input.value='';AP.ask(text);}
document.getElementById('chatInput').addEventListener('keydown',e=>{if(e.key==='Enter')sendMessage();});
document.getElementById('ap-analyze').addEventListener('click',()=>AP.ask('Revisa el stock disponible y los pedidos. Si hay riesgo de rotura, crea una propuesta de reposición pendiente de supervisión.'));
document.getElementById('ap-reset').addEventListener('click',()=>AP.reset());
document.getElementById('ap-mode').addEventListener('click',()=>AP.toggleMode());
document.getElementById('ap-agents').addEventListener('click',()=>AP.toggleAgents());
const apChat=document.getElementById('chatWindow');if(localStorage.getItem('adaptapro-chat-open')==='true'){apChat.hidden=false;apChat.style.display='block'}try{const saved=JSON.parse(localStorage.getItem('adaptapro-chat-size')||'null');if(saved?.width&&saved?.height){apChat.style.width=Math.min(saved.width,innerWidth-20)+'px';apChat.style.height=Math.min(saved.height,innerHeight-20)+'px';}}catch(e){}
new ResizeObserver(()=>{localStorage.setItem('adaptapro-chat-size',JSON.stringify({width:apChat.offsetWidth,height:apChat.offsetHeight}));}).observe(apChat);
document.getElementById('ap-tab-chat').addEventListener('click',()=>AP.tab('chat'));
document.getElementById('ap-tab-supervision').addEventListener('click',()=>AP.tab('supervision'));
document.querySelector('.ap-human').addEventListener('click',()=>AP.tab('supervision'));
const APMenu={button:document.getElementById('ap-menu-toggle'),sidebar:document.getElementById('ap-sidebar'),backdrop:document.getElementById('ap-menu-backdrop'),close(){this.sidebar.classList.remove('is-open');this.backdrop.hidden=true;this.button.setAttribute('aria-expanded','false');this.button.setAttribute('aria-label','Abrir menú de secciones');if(this.button.dataset.wasOpen==='true')this.button.focus();delete this.button.dataset.wasOpen},open(){this.button.dataset.wasOpen='true';this.sidebar.classList.add('is-open');this.backdrop.hidden=false;this.button.setAttribute('aria-expanded','true');this.button.setAttribute('aria-label','Cerrar menú de secciones');document.getElementById('ap-menu-close').focus()}};APMenu.button.onclick=()=>APMenu.sidebar.classList.contains('is-open')?APMenu.close():APMenu.open();document.getElementById('ap-menu-close').onclick=()=>APMenu.close();APMenu.backdrop.onclick=()=>APMenu.close();document.addEventListener('keydown',e=>{if(e.key==='Escape')APMenu.close()});window.addEventListener('resize',()=>{if(innerWidth>760)APMenu.close()});
document.querySelectorAll('[data-view]').forEach(b=>b.addEventListener('click',()=>APViews.show(b.dataset.view)));
const APAgentCenter={selected:null,
show(agent){if(!['ALPHA','BETA','GAMMA'].includes(agent)||!AP.db)return;this.selected=agent;document.querySelectorAll('[data-agent]').forEach(b=>{const on=b.dataset.agent===agent;b.classList.toggle('is-selected',on);b.setAttribute('aria-pressed',String(on))});document.getElementById('ap-agent-center').hidden=false;document.querySelector('.alerts-card').hidden=true;document.querySelector('.charts-row').hidden=true;this.render();document.getElementById('ap-agent-center').scrollIntoView({block:'nearest',behavior:'smooth'})},
back(){this.selected=null;document.querySelectorAll('[data-agent]').forEach(b=>{b.classList.remove('is-selected');b.setAttribute('aria-pressed','false')});document.getElementById('ap-agent-center').hidden=true;document.querySelector('.alerts-card').hidden=false;document.querySelector('.charts-row').hidden=false},
render(){if(!this.selected||!AP.db)return;const a=this.selected,esc=v=>AP.esc(v??''),events=AP.query('SELECT occurred_at,action,entity_id,details_json FROM audit_log WHERE actor=? ORDER BY rowid DESC LIMIT 20',[a]),total=AP.one('SELECT count(*) AS n FROM audit_log WHERE actor=?',[a]).n,config={ALPHA:{icon:'A',badge:'a',role:'Inventario y propuestas',story:'Analiza el stock, detecta alertas y registra propuestas locales. Aprobar una propuesta no compra ni recibe mercancía.'},BETA:{icon:'B',badge:'b',role:'Ventas y demanda',story:'Registra pedidos del motor local y señala señales de demanda. Los pedidos aquí no prueban cobros ni entregas.'},GAMMA:{icon:'G',badge:'g',role:'Logística y proveedores',story:'Compara proveedores activos, costes y plazos antes de asociarlos a una propuesta local. No gestiona envíos reales.'}}[a],summary=a==='ALPHA'?[["SKU con alerta",AP.one('SELECT count(*) AS n FROM stock_status WHERE needs_restock=1').n],["Propuestas creadas",AP.one("SELECT count(*) AS n FROM purchase_proposals WHERE agent_id='ALPHA'").n],["Eventos registrados",total]]:a==='BETA'?[["Pedidos locales",AP.one('SELECT count(*) AS n FROM sales_orders').n],["Pendientes",AP.one("SELECT count(*) AS n FROM sales_orders WHERE status='pendiente'").n],["Eventos registrados",total]]:[["Proveedores activos",AP.one('SELECT count(*) AS n FROM suppliers WHERE active=1').n],["Selecciones registradas",AP.one("SELECT count(*) AS n FROM audit_log WHERE actor='GAMMA' AND action='proveedor_seleccionado'").n],["Eventos registrados",total]];
let related='';if(a==='ALPHA'){const rows=AP.query("SELECT p.id,p.sku,p.proposed_qty,a.status FROM purchase_proposals p JOIN approval_queue a ON a.proposal_id=p.id WHERE p.agent_id='ALPHA' ORDER BY p.rowid DESC LIMIT 8");related='<h3>PROPUESTAS LOCALES</h3>'+(rows.length?APViews.table(['Propuesta','SKU','Unidades','Estado'],rows.map(x=>[x.id,x.sku,x.proposed_qty,x.status])):'<p class="ap-agent-empty">Todavía no hay propuestas de ALPHA.</p>')}else if(a==='BETA'){const rows=AP.query('SELECT id,customer_name,status,placed_at FROM sales_orders ORDER BY rowid DESC LIMIT 8');related='<h3>PEDIDOS EN LA BASE LOCAL</h3>'+APViews.table(['Pedido','Cliente','Estado','Fecha'],rows.map(x=>[x.id,x.customer_name,x.status,x.placed_at.slice(0,10)]))}else{const rows=AP.query('SELECT s.name,sp.sku,s.lead_days FROM supplier_products sp JOIN suppliers s ON s.id=sp.supplier_id WHERE s.active=1 ORDER BY s.lead_days LIMIT 8');related='<h3>PROVEEDORES ACTIVOS</h3>'+APViews.table(['Proveedor','SKU','Plazo'],rows.map(x=>[x.name,x.sku,x.lead_days+' días']))}
const timeline=events.length?events.map(x=>'<div class="ap-agent-event"><strong>'+esc(x.action.replaceAll('_',' '))+'</strong><small>'+esc(x.entity_id)+' · '+esc(x.occurred_at.slice(0,19).replace('T',' '))+'</small></div>').join(''):'<p class="ap-agent-empty">Aún no hay eventos de '+a+' en la auditoría. La vista se actualizará cuando se registre actividad.</p>';
const box=document.getElementById('ap-agent-center');box.innerHTML='<div class="ap-agent-hero"><div class="agent-badge '+config.badge+'">'+config.icon+'</div><div><h2>'+a+'</h2><p>'+config.role+' · SQLite local</p></div><button class="ap-agent-back" type="button">← Volver al panel</button></div><p class="ap-agent-story">'+config.story+'</p>'+APViews.tiles(summary)+related+'<h3>HISTORIAL DE ACTIVIDAD · '+total+' EVENTOS</h3><div class="ap-agent-timeline">'+timeline+'</div>';box.querySelector('.ap-agent-back').onclick=()=>this.back();}
};document.querySelectorAll('[data-agent]').forEach(b=>b.addEventListener('click',()=>APAgentCenter.show(b.dataset.agent)));
function applyTheme(){const light=localStorage.getItem('adaptapro-theme')==='light';document.body.dataset.theme=light?'light':'dark';document.getElementById('ap-theme').textContent=light?'🌙':'☀️';document.getElementById('ap-theme').title=light?'Activar modo oscuro':'Activar modo claro';const color=light?'#536781':'#94a3b8';for(const chart of Object.values(typeof Chart!=='undefined'?Chart.instances:{})){for(const axis of Object.values(chart.options.scales||{})){axis.ticks.color=color;axis.grid.color=light?'#dde7f2':'rgba(80, 140, 255, 0.08)';}chart.update('none');}}
document.getElementById('ap-theme').addEventListener('click',()=>{localStorage.setItem('adaptapro-theme',document.body.dataset.theme==='light'?'dark':'light');applyTheme()});applyTheme();
const APFullscreen={button:document.getElementById('ap-fullscreen'),update(){const active=!!document.fullscreenElement;this.button.textContent=active?'⤡':'⛶';this.button.setAttribute('aria-pressed',String(active));this.button.setAttribute('aria-label',active?'Salir de pantalla completa':'Entrar en pantalla completa');this.button.title=active?'Salir de pantalla completa':'Entrar en pantalla completa'},async toggle(){try{if(document.fullscreenElement)await document.exitFullscreen();else await document.documentElement.requestFullscreen()}catch(e){this.button.title='Pantalla completa no disponible en este navegador'}this.update()}};APFullscreen.button.addEventListener('click',()=>APFullscreen.toggle());document.addEventListener('fullscreenchange',()=>APFullscreen.update());APFullscreen.update();
function updateTicker(){const shown=localStorage.getItem('adaptapro-ticker')!=='false';document.getElementById('ap-ticker').hidden=!shown;const b=document.getElementById('ap-ticker-toggle');b.title=shown?'Ocultar mercados':'Mostrar mercados';b.setAttribute('aria-label',b.title);b.setAttribute('aria-pressed',String(shown))};document.getElementById('ap-ticker-toggle').addEventListener('click',()=>{localStorage.setItem('adaptapro-ticker',String(document.getElementById('ap-ticker').hidden));updateTicker()});updateTicker();setInterval(()=>{const clock=document.getElementById('ap-broadcast-clock');if(clock)clock.textContent=new Date().toLocaleTimeString('es-ES',{hour:'2-digit',minute:'2-digit',second:'2-digit'})},1000);
const APHeadlines={update(){if(!AP.db)return;const notices=APNotices.items(),last=AP.one('SELECT actor,action,entity_id FROM audit_log ORDER BY rowid DESC LIMIT 1'),arr=[];for(const n of notices.slice(0,3))arr.push(n.agent+' · '+n.title+' · '+n.detail);if(last)arr.push(last.actor+' · '+last.action.replaceAll('_',' ')+' · '+last.entity_id);document.getElementById('ap-headlines-text').textContent=arr.join(' ◆ ')||'Operaciones en curso · sin alertas activas';}};
const APTV={active:false,index:0,lastRotate:0,
update(){if(!this.active||!AP.db)return;const titles=['El negocio, en movimiento','Ventas conectadas al inventario','La cadena de suministro responde','Decisiones con supervisión humana'];const subs=['Tres agentes colaboran sobre la misma base local','BETA registra pedidos; ALPHA vigila los umbrales','GAMMA compara proveedores y plazos','Autónomo propone; cumplimiento exige revisión humana'];const n=this.index%titles.length;document.getElementById('ap-tv-title').textContent=titles[n];document.getElementById('ap-tv-subtitle').textContent=subs[n];const count=AP.one('SELECT count(*) AS n FROM sales_orders').n,alerts=AP.one('SELECT count(*) AS n FROM stock_status WHERE needs_restock=1').n,pending=AP.one("SELECT count(*) AS n FROM approval_queue WHERE status='pendiente'").n;document.getElementById('ap-tv-cards').innerHTML=[['Pedidos',count],['SKU en alerta',alerts],['Decisiones pendientes',pending]].map(([k,v])=>'<div><small>'+k+'</small><strong>'+v+'</strong></div>').join('');const e=AP.one('SELECT actor,action,entity_id FROM audit_log ORDER BY rowid DESC LIMIT 1');document.getElementById('ap-tv-story').textContent=e?e.actor+' · '+e.action.replaceAll('_',' ')+' · '+e.entity_id:'Esperando actividad de agentes';document.getElementById('ap-tv-clock').textContent=new Date().toLocaleTimeString('es-ES',{hour:'2-digit',minute:'2-digit',second:'2-digit'});},
async toggle(force){this.active=force??!this.active;const el=document.getElementById('ap-tv');el.hidden=!this.active;document.getElementById('ap-tv-toggle').setAttribute('aria-pressed',String(this.active));if(this.active){this.index=0;this.update();try{await document.documentElement.requestFullscreen()}catch(e){}}else if(document.fullscreenElement){try{await document.exitFullscreen()}catch(e){}}},
tick(){if(!this.active)return;this.update();if(Date.now()-this.lastRotate>12000){this.index++;this.lastRotate=Date.now();this.update()}}
};document.getElementById('ap-tv-toggle').onclick=()=>APTV.toggle();document.getElementById('ap-tv-close').onclick=()=>APTV.toggle(false);document.addEventListener('keydown',e=>{if(e.key==='Escape'&&APTV.active)APTV.toggle(false)});document.addEventListener('fullscreenchange',()=>{if(!document.fullscreenElement&&APTV.active)APTV.toggle(false)});setInterval(()=>APTV.tick(),1000);
const APNotices={
read(){try{return new Set(JSON.parse(localStorage.getItem('adaptapro-notices-read')||'[]'))}catch{return new Set()}},
items(){if(!AP.db)return [];const rows=AP.rows.bind(AP),items=[];
for(const x of rows("SELECT p.id,p.sku FROM purchase_proposals p JOIN approval_queue a ON a.proposal_id=p.id WHERE a.status='pendiente'"))items.push({id:'pending:'+x.id,agent:'ALPHA',title:'Decisión pendiente',detail:x.id+' · '+x.sku,view:2});
for(const x of rows("SELECT p.id,p.sku FROM purchase_proposals p JOIN approval_queue a ON a.proposal_id=p.id WHERE a.status='aprobada' AND a.decided_by='modo_automatico'"))items.push({id:'auto:'+x.id,agent:'ALPHA',title:'Propuesta aprobada en Autónomo',detail:x.id+' · '+x.sku+' · revisar en Suministro. La aprobación local no compra ni recibe stock.',view:2});
for(const x of rows('SELECT sku,available,reorder_point FROM stock_status WHERE needs_restock=1'))items.push({id:'stock:'+x.sku,agent:'ALPHA',title:'Stock bajo',detail:x.sku+' · '+x.available+' disponibles, umbral '+x.reorder_point,view:4});
for(const x of rows("SELECT o.id,l.sku FROM sales_orders o JOIN sales_order_lines l ON l.order_id=o.id JOIN stock_status s ON s.sku=l.sku WHERE o.status='pendiente' AND s.needs_restock=1 ORDER BY o.placed_at DESC LIMIT 3"))items.push({id:'risk:'+x.id+':'+x.sku,agent:'BETA',title:'Pedido con riesgo de stock',detail:x.id+' · '+x.sku+' bajo umbral. No se dispone de fecha de entrega.',view:5});
const recent=rows("SELECT count(*) AS n FROM audit_log WHERE action='pedido_generado'")[0]?.n||0;if(recent>=4)items.push({id:'demand:'+Math.floor(recent/4),agent:'BETA',title:'Actividad de demanda',detail:recent+' pedidos añadidos por el motor local; revisar tendencia.',view:5});
return items;
},
render(){const items=this.items(),read=this.read(),unread=items.filter(x=>!read.has(x.id));const count=document.getElementById('ap-bell-count');count.hidden=!unread.length;count.textContent=unread.length>9?'9+':unread.length;const box=document.getElementById('ap-notices');box.innerHTML='<h3>Avisos · '+unread.length+' sin leer</h3>'+(!items.length?'<p class="ap-view-lead">Sin avisos activos.</p>':items.map(x=>'<div class="ap-notice"><em>'+AP.esc(x.agent)+'</em> · '+AP.esc(x.title)+(read.has(x.id)?' ✓':'')+'<small>'+AP.esc(x.detail)+'</small><button data-notice-view="'+x.view+'" data-notice-id="'+AP.esc(x.id)+'">Ver y marcar leído</button></div>').join(''));
box.querySelectorAll('[data-notice-id]').forEach(b=>b.onclick=()=>{const set=this.read();set.add(b.dataset.noticeId);localStorage.setItem('adaptapro-notices-read',JSON.stringify([...set]));APViews.show(b.dataset.noticeView);box.hidden=true;this.render()});
}
};
document.getElementById('ap-bell').onclick=()=>{const b=document.getElementById('ap-notices');b.hidden=!b.hidden;document.getElementById('ap-bell').setAttribute('aria-expanded',!b.hidden);APNotices.render()};
const APSpotlight={timer:null,lastKey:'',lastShown:0,
update(){if(document.hidden||!AP.db)return;const candidates=APNotices.items().filter(x=>x.id!==this.lastKey&&['auto:','stock:','risk:'].some(k=>x.id.startsWith(k)));if(!candidates.length||Date.now()-this.lastShown<180000)return;const x=candidates[0];this.lastKey=x.id;this.lastShown=Date.now();const b=document.getElementById('ap-spotlight');document.getElementById('ap-spotlight-agent').textContent=x.agent+' · FIVETECH';document.getElementById('ap-spotlight-title').textContent=x.title;document.getElementById('ap-spotlight-detail').textContent=x.detail;b.hidden=false;b.onclick=()=>{APViews.show(x.view);b.hidden=true;clearTimeout(this.timer)};clearTimeout(this.timer);APSound.play('chime');this.timer=setTimeout(()=>{b.hidden=true},8500);
}
};
const APSound={context:null,armed:false,muted:localStorage.getItem('adaptapro-muted')==='true',
play(kind){if(this.muted||!this.armed||document.hidden)return;try{const C=window.AudioContext||window.webkitAudioContext;if(!C)return;this.context||=new C();if(this.context.state!=='running')return;const now=this.context.currentTime,notes=kind==='approval'?[420,610]:kind==='autonomous'?[550,820,1050]:[660,880];notes.forEach((freq,i)=>{const osc=this.context.createOscillator(),gain=this.context.createGain(),start=now+i*.11;osc.type='sine';osc.frequency.setValueAtTime(freq,start);gain.gain.setValueAtTime(.0001,start);gain.gain.exponentialRampToValueAtTime(.035,start+.02);gain.gain.exponentialRampToValueAtTime(.0001,start+.32);osc.connect(gain).connect(this.context.destination);osc.start(start);osc.stop(start+.34)})}catch(e){}},
update(){const b=document.getElementById('ap-sound');b.textContent=this.muted?'🔇':'🔊';b.title=this.muted?'Activar sonidos':'Silenciar sonidos';b.setAttribute('aria-label',b.title)}
};
APSound.update();document.addEventListener('pointerdown',()=>{APSound.armed=true;try{const C=window.AudioContext||window.webkitAudioContext;if(C){APSound.context||=new C();APSound.context.resume().catch(()=>{})}}catch(e){}},{once:true});document.getElementById('ap-sound').onclick=()=>{APSound.muted=!APSound.muted;localStorage.setItem('adaptapro-muted',APSound.muted);APSound.update()};
const APFocus={last:0,seen:new Set(),show(){if(!AP.db||document.hidden||Date.now()-this.last<180000||matchMedia('(prefers-reduced-motion: reduce)').matches)return;const item=APNotices.items().find(x=>!this.seen.has(x.id)&&['pending:','stock:','auto:'].some(k=>x.id.startsWith(k)));if(!item)return;this.seen.add(item.id);this.last=Date.now();const target=item.id.startsWith('pending:')?document.getElementById('ap-mode'):item.id.startsWith('stock:')?document.getElementById('ap-stock-metric'):document.getElementById('ap-bell');if(!target)return;const r=target.getBoundingClientRect(),f=document.getElementById('ap-focus');f.style.setProperty('--fx',r.x+r.width/2+'px');f.style.setProperty('--fy',r.y+r.height/2+'px');f.hidden=false;setTimeout(()=>f.hidden=true,2750)}};
setInterval(()=>APFocus.show(),30000);
setInterval(()=>APSpotlight.update(),20000);
const oldRender=AP.render.bind(AP);AP.render=function(){oldRender();APNotices.render();APHeadlines.update();if(APViews.current)APViews.show(APViews.current);if(APAgentCenter.selected)APAgentCenter.render()};
AP.init();
window.onYouTubeIframeAPIReady=function(){try{new YT.Player('ap-news-player',{events:{onError:()=>{document.getElementById('ap-video-error').hidden=false}}})}catch(e){/* The direct stream link remains available. */}};
</script>
<script async src="https://www.youtube.com/iframe_api"></script>
<script async defer src="https://accounts.google.com/gsi/client"></script>
<script type="module" src="./core/index.mjs"></script>
<script type="module" src="./instinct-ui.mjs"></script>
</body>
</html>