Spaces:
Running
Running
Download index.html from fivetech/Core-Agentic-ERP: direct link, hf CLI and curl.
- Browser
- Download file 133 kB
-
https://huggingface.co/spaces/fivetech/Core-Agentic-ERP/resolve/main/index.html
- Command line
-
hf download hf://spaces/fivetech/Core-Agentic-ERP/index.html
-
curl -L -o index.html https://huggingface.co/spaces/fivetech/Core-Agentic-ERP/resolve/main/index.html
133 kB
| <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> | |
| ; | |
| 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=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[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> | |