Files
MP-Manager/templates/index.html
T
2026-05-30 14:31:19 -06:00

1112 lines
79 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MP Manager — Monte Providencia CRM & Control Center</title>
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
<!-- FontAwesome para Iconos -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Hojas de Estilo -->
<link rel="stylesheet" href="/static/css/style.css?v=1.0.11">
</head>
<body>
<div class="app-container">
<!-- SIDEBAR DE SUCURSALES -->
<aside class="sidebar">
<div class="sidebar-header">
<div class="brand-logo">
<i class="fa-solid fa-crown brand-icon"></i>
<h2>MP Manager</h2>
</div>
<p class="brand-subtitle">Monte Providencia</p>
</div>
<div class="search-box">
<i class="fa-solid fa-magnifying-glass"></i>
<input type="text" id="branch-search" placeholder="Buscar sucursal...">
</div>
<div class="branch-list-wrapper">
<div class="branch-section-title">Visión General</div>
<div id="global-overview-container" class="branch-list" style="margin-bottom: 12px;">
<!-- Consolidado Global va aquí -->
</div>
<div class="branch-section-title">Marca Principal</div>
<div id="brand-account-container">
<!-- Monte Providencia Marca va aquí -->
</div>
<div class="branch-section-title">Sucursales</div>
<div id="branches-container" class="branch-list">
<!-- Sucursales dinámicas van aquí -->
</div>
</div>
</aside>
<!-- CONTENIDO PRINCIPAL -->
<main class="main-content">
<!-- HEADER GLOBAL -->
<header class="global-header">
<div class="active-info">
<span class="active-badge"><i class="fa-solid fa-store"></i></span>
<div class="active-info-content">
<h1 id="active-branch-name">Cargando...</h1>
<p id="active-branch-owner" class="text-secondary">Monte Providencia</p>
<div id="active-branch-details" class="active-info-details">
<span>Cargando cuenta activa...</span>
</div>
</div>
</div>
<div class="header-actions">
<!-- TOGGLE GLOBAL DE MODO (Dry-Run / Live).
Universal: aplica a TODA la plataforma (Contactos, Comparativa, Kanban, Scripts).
Verde = Dry-Run (seguro, simulación). Rojo = Live (escribe en Bucéfalo). -->
<div id="global-mode-toggle" class="global-mode-toggle is-dryrun" title="Modo Simulación (Dry-Run): las acciones se simulan sin escribir en Bucéfalo.">
<span class="global-mode-icon">
<i class="fa-solid fa-shield-halved"></i>
</span>
<div class="global-mode-text">
<span class="global-mode-label">Modo</span>
<span class="global-mode-value" id="global-mode-value">Simulación</span>
</div>
<label class="toggle-switch global-mode-switch">
<input type="checkbox" id="global-mode-checkbox">
<span class="toggle-slider"></span>
</label>
</div>
<!-- Control de Sincronización Global -->
<div id="sync-status-bar" class="sync-status-bar hidden">
<div class="sync-progress-bar-wrapper">
<div id="sync-progress-fill" class="sync-progress-fill"></div>
</div>
<span id="sync-progress-text" class="sync-progress-text">Sync: 0/0 (sucursal)</span>
</div>
<div class="sync-dropdown">
<button id="btn-sync-global" class="btn btn-primary sync-main-btn">
<i class="fa-solid fa-rotate"></i> Sincronizar Todo
</button>
<button id="btn-sync-menu" class="btn btn-primary sync-menu-btn" aria-label="Opciones de sincronización">
<i class="fa-solid fa-chevron-down"></i>
</button>
<div id="sync-menu" class="sync-menu hidden">
<button id="btn-sync-metadata" class="sync-menu-item">
<i class="fa-solid fa-database"></i>
<span>Sincronizar Metadata</span>
</button>
</div>
</div>
<button id="btn-sync-active" class="btn btn-secondary">
<i class="fa-solid fa-arrows-rotate"></i> Sincronizar Sucursal
</button>
</div>
</header>
<!-- TABS DE NAVEGACIÓN -->
<nav class="navigation-tabs">
<button class="tab-link active" data-tab="tab-dashboard">
<i class="fa-solid fa-chart-pie"></i> Dashboard
</button>
<button class="tab-link" data-tab="tab-comparativa">
<i class="fa-solid fa-scale-balanced"></i> Comparativa Marca vs Sucursales
</button>
<button class="tab-link" data-tab="tab-contacts">
<i class="fa-solid fa-users"></i> Contactos
</button>
<button class="tab-link" data-tab="tab-opportunities">
<i class="fa-solid fa-clipboard-list"></i> Kanban Oportunidades
</button>
<button class="tab-link" data-tab="tab-workflows">
<i class="fa-solid fa-diagram-project"></i> Workflows GHL
</button>
<button class="tab-link" data-tab="tab-scripts">
<i class="fa-solid fa-terminal"></i> Scripts y Auditorías
</button>
</nav>
<!-- SECCIONES DE TABS -->
<div class="tab-content-wrapper">
<!-- 1. DASHBOARD TAB -->
<section id="tab-dashboard" class="tab-section active">
<div class="metrics-grid">
<div class="metric-card">
<div class="metric-icon primary"><i class="fa-solid fa-user-group"></i></div>
<div class="metric-details">
<h3 id="dash-contacts-count">0</h3>
<p>Contactos Sincronizados</p>
</div>
</div>
<div class="metric-card">
<div class="metric-icon success"><i class="fa-solid fa-hand-holding-dollar"></i></div>
<div class="metric-details">
<h3 id="dash-won-value">$0.00</h3>
<p>Oportunidades Ganadas</p>
<span class="sub-metric" id="dash-won-count">0 oportunidades</span>
</div>
</div>
<div class="metric-card">
<div class="metric-icon warning"><i class="fa-solid fa-business-time"></i></div>
<div class="metric-details">
<h3 id="dash-open-value">$0.00</h3>
<p>Oportunidades Abiertas</p>
<span class="sub-metric" id="dash-open-count">0 oportunidades</span>
</div>
</div>
<div class="metric-card">
<div class="metric-icon danger"><i class="fa-solid fa-thumbs-down"></i></div>
<div class="metric-details">
<h3 id="dash-lost-value">$0.00</h3>
<p>Oportunidades Perdidas</p>
<span class="sub-metric" id="dash-lost-count">0 oportunidades</span>
</div>
</div>
</div>
<!-- Panel de Detalles de Sucursal (Individual) -->
<div class="dashboard-details-grid" id="dashboard-details-grid">
<div class="card panel-card">
<div class="card-header">
<h3><i class="fa-solid fa-wave-square"></i> Distribución de Estado</h3>
</div>
<div class="card-body">
<div id="status-distribution-container" class="status-distribution-container">
<!-- Barras de distribución dinámicas -->
</div>
</div>
</div>
<div class="card panel-card">
<div class="card-header">
<h3><i class="fa-solid fa-diagram-project"></i> Pipelines y Etapas</h3>
</div>
<div class="card-body">
<div id="pipeline-overview-container" class="pipeline-overview-container">
<p class="text-secondary">Selecciona una cuenta para ver sus pipelines y etapas.</p>
</div>
</div>
</div>
</div>
<!-- Panel de Master de Sucursales (Global) -->
<div id="global-dashboard-details" class="hidden">
<div class="card panel-card" style="height: auto; min-height: 480px;">
<div class="card-header" style="flex-wrap: wrap; gap: 16px;">
<h3><i class="fa-solid fa-list-check"></i> Master de Sucursales (Overview Global)</h3>
<div class="search-box" style="margin: 0; width: 320px; position: relative;">
<i class="fa-solid fa-magnifying-glass" style="position: absolute; left: 14px; top: 50%; transform: translateY(-50%); color: var(--text-muted); font-size: 14px;"></i>
<input type="text" id="global-master-search" placeholder="Buscar sucursal..." style="width: 100%; background: rgba(255, 255, 255, 0.04); border: 1px solid var(--border-glass); border-radius: var(--radius-sm); padding: 10px 12px 10px 40px; font-size: 14px; outline: none; transition: var(--transition-fast);">
</div>
</div>
<div class="card-body" style="padding: 0;">
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">#</th>
<th>Sucursal</th>
<th>Contactos</th>
<th title="Contactos sin oportunidad asociada en esta sucursal. Clic para ver el listado.">Sin Opp <i class="fa-solid fa-circle-question" style="font-size: 11px; color: var(--text-muted);"></i></th>
<th>Oportunidades</th>
<th title="Total de pipelines disponibles en esta sucursal.">Pipelines</th>
<th>Ganado (Won)</th>
<th>Abierto (Open)</th>
<th>Última Sincronización</th>
<th style="text-align: center;">Acciones</th>
</tr>
</thead>
<tbody id="global-master-rows">
<tr>
<td colspan="10" class="text-center">Cargando catálogo consolidado...</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</section>
<!-- 2. COMPARATIVA MARCA vs SUCURSALES TAB -->
<section id="tab-comparativa" class="tab-section">
<div class="comparativa-header">
<div>
<h2 class="comparativa-title"><i class="fa-solid fa-scale-balanced"></i> Comparativa Marca vs Sucursales</h2>
<p class="text-secondary comparativa-subtitle">Conteo total de contactos y oportunidades de la cuenta de Marca contra la suma de todas las sucursales. Las cuentas demo se excluyen automáticamente.</p>
</div>
<div class="comparativa-actions">
<span id="comparativa-last-run" class="text-muted" style="font-size: 12px;"></span>
<button id="btn-comparativa-reload" class="btn btn-primary">
<i class="fa-solid fa-rotate"></i> Recalcular
</button>
</div>
</div>
<!-- Banner de estado: loading / error / vacio. Solo visible cuando aplica. -->
<div id="comparativa-status-banner" class="comparativa-status-banner" style="display: none;" role="status" aria-live="polite">
<div class="comparativa-status-icon"><i class="fa-solid fa-circle-notch fa-spin"></i></div>
<div class="comparativa-status-body">
<div class="comparativa-status-title" id="comparativa-status-title">Calculando comparativa…</div>
<div class="comparativa-status-msg" id="comparativa-status-msg">Esto puede tomar unos segundos en bases grandes.</div>
</div>
<button id="comparativa-status-retry" class="btn btn-secondary btn-sm" style="display: none;">
<i class="fa-solid fa-rotate"></i> Reintentar
</button>
</div>
<!-- Tarjetas de totales -->
<div class="comparativa-totals-grid">
<div class="card comparativa-total-card">
<div class="comparativa-total-label">Contactos en Marca</div>
<div class="comparativa-total-value" id="comp-brand-contacts"></div>
<div class="comparativa-total-sub" id="comp-brand-name">Cargando...</div>
</div>
<div class="card comparativa-total-card">
<div class="comparativa-total-label">Contactos en Sucursales (suma)</div>
<div class="comparativa-total-value" id="comp-branches-contacts"></div>
<div class="comparativa-total-sub" id="comp-branches-count"></div>
</div>
<div class="card comparativa-total-card comparativa-diff-card" id="comp-contacts-diff-card">
<div class="comparativa-total-label">Diferencia Contactos</div>
<div class="comparativa-total-value" id="comp-contacts-diff"></div>
<div class="comparativa-total-sub" id="comp-contacts-diff-status">Marca Sucursales</div>
</div>
<div class="card comparativa-total-card">
<div class="comparativa-total-label">Oportunidades en Marca</div>
<div class="comparativa-total-value" id="comp-brand-opps"></div>
<div class="comparativa-total-sub">&nbsp;</div>
</div>
<div class="card comparativa-total-card">
<div class="comparativa-total-label">Oportunidades en Sucursales (suma)</div>
<div class="comparativa-total-value" id="comp-branches-opps"></div>
<div class="comparativa-total-sub">&nbsp;</div>
</div>
<div class="card comparativa-total-card comparativa-diff-card" id="comp-opps-diff-card">
<div class="comparativa-total-label">Diferencia Oportunidades</div>
<div class="comparativa-total-value" id="comp-opps-diff"></div>
<div class="comparativa-total-sub" id="comp-opps-diff-status">Marca Sucursales</div>
</div>
</div>
<!-- Cuentas demo excluidas -->
<div class="card comparativa-info-card" id="comp-demos-card" style="display: none;">
<div class="card-header">
<h3><i class="fa-solid fa-eye-slash"></i> Cuentas demo excluidas</h3>
</div>
<div class="card-body">
<p class="text-secondary" style="margin: 0 0 8px 0; font-size: 13px;">Estas cuentas no participan en el conteo porque su nombre contiene "demo":</p>
<ul id="comp-demos-list" class="comparativa-demos-list"></ul>
</div>
</div>
<!-- Resumen de huecos -->
<div class="comparativa-buckets-grid">
<div class="card comparativa-bucket-card" data-bucket="missing_in_brand">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-user-large-slash"></i> Contactos en sucursal sin contraparte en Marca</h4>
<p class="text-secondary">Existen físicamente en una sucursal pero no se replicaron a Marca.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-missing_in_brand">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="missing_in_brand">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="missing_in_brand">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
<button id="btn-sync-missing-contacts" class="btn btn-primary btn-sm" type="button" title="Sincroniza estos contactos hacia la cuenta de Marca: double-check por teléfono → email → nombre. Si ya existe en Marca (falso positivo del audit), se omite. Si no, se crea con todos los datos y custom fields mapeados.">
<i class="fa-solid fa-user-plus"></i> Sincronizar a Marca
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-missing_in_brand" hidden></div>
</div>
<div class="card comparativa-bucket-card" data-bucket="missing_in_assigned_branch">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-map-pin"></i> Contactos en Marca ausentes de su sucursal asignada</h4>
<p class="text-secondary">El campo TIENDA del contacto apunta a una sucursal donde no aparece físicamente <strong>y tampoco existe en ninguna otra sucursal</strong>.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-missing_in_assigned_branch">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="missing_in_assigned_branch">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="missing_in_assigned_branch">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
<button id="btn-sync-missing-in-assigned-branch" class="btn btn-primary btn-sm" type="button" title="Selecciona los contactos del listado y crea sus duplicados en la sucursal asignada (resuelta por TIENDA + verificador). Antes de crear, doble-check por teléfono → email → nombre en la sucursal destino y globalmente.">
<i class="fa-solid fa-user-plus"></i> Crear seleccionados en sucursal
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-missing_in_assigned_branch" hidden></div>
</div>
<div class="card comparativa-bucket-card" data-bucket="present_in_other_branch_not_assigned">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-shuffle"></i> Contactos Marca en sucursal incorrecta</h4>
<p class="text-secondary">El campo TIENDA del contacto apunta a una sucursal, pero el contacto realmente está en OTRA. Usa el botón para corregir la TIENDA del contacto Marca.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-present_in_other_branch_not_assigned">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="present_in_other_branch_not_assigned">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="present_in_other_branch_not_assigned">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-present_in_other_branch_not_assigned" hidden></div>
</div>
<div class="card comparativa-bucket-card" data-bucket="probable_duplicate_in_brand">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-clone"></i> Probables duplicados en Marca</h4>
<p class="text-secondary">El contacto en Marca tiene teléfono/email, pero <strong>en la sucursal asignada existe un homónimo</strong> (mismo nombre) con teléfono/email distinto. Lo más probable: el bueno está en sucursal, el de Marca es un duplicado con otro número.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-probable_duplicate_in_brand">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="probable_duplicate_in_brand">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="probable_duplicate_in_brand">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-probable_duplicate_in_brand" hidden></div>
</div>
<div class="card comparativa-bucket-card" data-bucket="brand_not_in_any_branch">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-circle-question"></i> Contactos en Marca sin contraparte en NINGUNA sucursal</h4>
<p class="text-secondary">Leads de Marca (imports, formularios globales) que nunca se materializaron en una sucursal.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-brand_not_in_any_branch">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="brand_not_in_any_branch">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="brand_not_in_any_branch">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
<button id="btn-sync-brand-to-branch" class="btn btn-primary btn-sm" type="button" title="Crea el contacto en su sucursal correspondiente (resuelta por TIENDA + verificador). Solo procesa contactos con TIENDA poblada. Double-check en la sucursal por teléfono → email → nombre antes de crear.">
<i class="fa-solid fa-arrow-right-arrow-left"></i> Sincronizar a Sucursales
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-brand_not_in_any_branch" hidden></div>
</div>
<div class="card comparativa-bucket-card" data-bucket="brand_without_tienda">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-tag"></i> Contactos en Marca sin TIENDA poblada</h4>
<p class="text-secondary">El campo TIENDA está vacío, por lo que no se puede asignar a una sucursal.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-brand_without_tienda">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="brand_without_tienda">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="brand_without_tienda">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
<button id="btn-fix-tienda-from-sucursal" class="btn btn-primary btn-sm" type="button" title="Llena el campo TIENDA en Marca a partir del campo Sucursal (resuelto via verificador). Solo procesa contactos cuyo Sucursal mapea inequivocamente a una sucursal con TIENDA conocida.">
<i class="fa-solid fa-wand-magic-sparkles"></i> Llenar TIENDA desde Sucursal
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-brand_without_tienda" hidden></div>
</div>
<div class="card comparativa-bucket-card" data-bucket="brand_unknown_tienda">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-triangle-exclamation"></i> Contactos en Marca con TIENDA desconocida</h4>
<p class="text-secondary">El valor TIENDA no coincide con ninguna fila del verificador de sucursales.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-brand_unknown_tienda">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="brand_unknown_tienda">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="brand_unknown_tienda">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-brand_unknown_tienda" hidden></div>
</div>
<div class="card comparativa-bucket-card" data-bucket="missing_opps_in_brand">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-clipboard-question"></i> Oportunidades en sucursal sin réplica en Marca</h4>
<p class="text-secondary">Opps que existen en sucursal pero no se replicaron al contacto en Marca.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-missing_opps_in_brand">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="missing_opps_in_brand">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="missing_opps_in_brand">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
<button id="btn-sync-missing-opps" class="btn btn-primary btn-sm" type="button" title="Sincroniza estas oportunidades hacia la cuenta de Marca: busca el contacto por teléfono → email → nombre, crea el contacto si no existe, espera 10s y crea/actualiza la opp en Marca.">
<i class="fa-solid fa-rotate"></i> Sincronizar a Marca
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-missing_opps_in_brand" hidden></div>
</div>
<div class="card comparativa-bucket-card" data-bucket="contacts_missing_id_field">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-id-card"></i> Contactos sin ID Contacto Sucursal</h4>
<p class="text-secondary">Contactos cuyo campo de enlace está vacío o con id de longitud inválida (debe ser 20 caracteres). En sucursales se puede llenar automáticamente (= id nativo del contacto). En Marca aparece como aviso — su campo se resuelve por matcheo/sync.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-contacts_missing_id_field">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="contacts_missing_id_field">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="contacts_missing_id_field">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
<button id="btn-fill-contact-id-sucursal" class="btn btn-primary btn-sm" type="button" title="Llena el campo 'ID Contacto Sucursal' con el id nativo de cada contacto. SOLO sucursales (Marca queda intacta).">
<i class="fa-solid fa-wand-magic-sparkles"></i> Llenar campo (sucursales)
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-contacts_missing_id_field" hidden></div>
</div>
<div class="card comparativa-bucket-card" data-bucket="opps_missing_id_field">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-fingerprint"></i> Oportunidades sin ID Oportunidad Sucursal</h4>
<p class="text-secondary">Opps cuyo campo de enlace está vacío o con id de longitud inválida (debe ser 20 caracteres). En sucursales se puede llenar automáticamente (= id nativo de la opp). En Marca aparece como aviso — su campo se resuelve por matcheo/sync.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-opps_missing_id_field">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="opps_missing_id_field">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="opps_missing_id_field">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
<button id="btn-fill-opp-id-sucursal" class="btn btn-primary btn-sm" type="button" title="Llena el campo 'ID Oportunidad Sucursal' con el id nativo de cada opp. SOLO sucursales (Marca queda intacta).">
<i class="fa-solid fa-wand-magic-sparkles"></i> Llenar campo (sucursales)
</button>
<button id="btn-match-brand-opp-id-sucursal" class="btn btn-primary btn-sm" type="button" title="Matchea cada opp de Marca con su opp de sucursal y rellena el campo en Marca con el id de la opp de sucursal. SOLO Marca.">
<i class="fa-solid fa-arrows-left-right-to-line"></i> Matchear Marca con sucursales
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-opps_missing_id_field" hidden></div>
</div>
<div class="card comparativa-bucket-card" data-bucket="brand_duplicate_link_opps">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-clone"></i> Réplicas duplicadas en Marca (mismo ID Opp Sucursal)</h4>
<p class="text-secondary">Dos o más opps de Marca que apuntan a la MISMA opp de sucursal: réplicas duplicadas (causa típica del descuadre positivo Marca&gt;Sucursales). Se conserva la canónica y se eliminan las sobrantes. Reversible por run_id.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-brand_duplicate_link_opps">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="brand_duplicate_link_opps">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="brand_duplicate_link_opps">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
<button id="btn-cleanup-duplicate-opps" class="btn btn-primary btn-sm" type="button" title="Elimina las réplicas duplicadas sobrantes en Marca conservando la canónica (jerarquía: valor → status → más antigua). Default simulación; reversible por run_id.">
<i class="fa-solid fa-broom"></i> Limpiar duplicados
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-brand_duplicate_link_opps" hidden></div>
</div>
<div class="card comparativa-bucket-card" data-bucket="intra_brand_duplicates">
<div class="comparativa-bucket-header">
<div>
<h4><i class="fa-solid fa-people-arrows"></i> Duplicados intra-Marca (mismo nombre, sin teléfono ni email)</h4>
<p class="text-secondary">Grupos de contactos en Marca con el mismo nombre y sin identificadores fuertes. Imposibles de distinguir automáticamente — revísalos manualmente desde Bucéfalo y elimina los duplicados con el botón rojo.</p>
</div>
<span class="comparativa-bucket-badge" id="comp-bucket-intra_brand_duplicates">0</span>
</div>
<div class="comparativa-bucket-actions">
<button class="btn btn-secondary btn-sm btn-comparativa-toggle" data-bucket="intra_brand_duplicates">
<i class="fa-solid fa-list"></i> Ver listado
</button>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="intra_brand_duplicates">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
</div>
<div class="comparativa-bucket-body" id="comp-body-intra_brand_duplicates" hidden></div>
</div>
</div>
<!-- Modal de sync -->
<div id="sync-missing-opps-modal" class="modal-overlay" hidden>
<div class="modal-dialog">
<div class="modal-header">
<h3 id="sync-modal-title"><i class="fa-solid fa-rotate"></i> Sincronizar opps faltantes a Marca</h3>
<button class="modal-close" id="sync-modal-close" aria-label="Cerrar"><i class="fa-solid fa-xmark"></i></button>
</div>
<div class="modal-body" id="sync-modal-body">
<p class="text-secondary">Cargando plan...</p>
</div>
<div class="modal-footer" id="sync-modal-footer">
<button id="sync-modal-cancel" class="btn btn-secondary">Cancelar</button>
<button id="sync-modal-apply" class="btn btn-primary" hidden>
<i class="fa-solid fa-check"></i> Aplicar cambios en GHL
</button>
</div>
</div>
</div>
<!-- Desglose por sucursal -->
<div class="card comparativa-per-branch-card">
<div class="card-header">
<h3><i class="fa-solid fa-list-check"></i> Desglose por sucursal</h3>
<button class="btn btn-secondary btn-sm btn-comparativa-export" data-bucket="per_branch">
<i class="fa-solid fa-file-csv"></i> Exportar CSV
</button>
</div>
<div class="card-body" style="padding: 0;">
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">#</th>
<th>Sucursal</th>
<th style="text-align: right;">Contactos</th>
<th style="text-align: right;">Oportunidades</th>
</tr>
</thead>
<tbody id="comp-per-branch-rows">
<tr><td colspan="4" class="text-center">Cargando...</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</section>
<!-- 2. CONTACTOS TAB -->
<section id="tab-contacts" class="tab-section">
<div class="toolbar" style="gap: 12px; flex-wrap: wrap; align-items: center;">
<div class="search-box">
<i class="fa-solid fa-magnifying-glass"></i>
<input type="text" id="contact-table-search" placeholder="Filtrar contactos locales...">
</div>
<button id="btn-filter-without-opp" class="btn btn-secondary btn-sm" type="button" title="Mostrar solo contactos que no tienen oportunidad asociada en esta sucursal." aria-pressed="false">
<i class="fa-solid fa-user-slash"></i> Solo sin oportunidad
</button>
<button id="btn-bulk-create-opps" class="btn btn-primary btn-sm" type="button" style="display: none;" title="Crea oportunidades para todos los contactos sin oportunidad de esta sucursal en una sola operación. Cada cambio queda registrado en auditoría con un run_id reversible.">
<i class="fa-solid fa-layer-group"></i> Crear oportunidades para todos
</button>
<span id="contacts-filter-status" class="text-muted" style="font-size: 12px;"></span>
</div>
<div class="card table-card">
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>Nombre</th>
<th>Teléfono</th>
<th>Email</th>
<th title="Campo nativo de Bucéfalo (source): origen del contacto — formulario, Facebook, sucursal, etc.">Fuente</th>
<th>Etiquetas</th>
<th title="Custom field del contacto: Marca del Vehículo">Marca</th>
<th title="Custom field del contacto: Versión del Vehículo">Versión</th>
<th title="Custom field del contacto: Año del Vehículo">Año</th>
<th>Fecha Añadido</th>
<th id="contacts-action-header" class="contacts-action-col" style="display: none;">Acción</th>
</tr>
</thead>
<tbody id="contacts-table-rows">
<tr>
<td colspan="9" class="text-center">Selecciona una sucursal para ver los contactos.</td>
</tr>
</tbody>
</table>
</div>
<div class="pagination-bar">
<span id="pagination-info">Mostrando 0 - 0 de 0</span>
<div class="pagination-buttons">
<button id="btn-page-prev" class="btn btn-secondary btn-sm" disabled><i class="fa-solid fa-chevron-left"></i> Anterior</button>
<button id="btn-page-next" class="btn btn-secondary btn-sm" disabled>Siguiente <i class="fa-solid fa-chevron-right"></i></button>
</div>
</div>
</div>
</section>
<!-- 3. KANBAN TAB (OPORTUNIDADES) -->
<section id="tab-opportunities" class="tab-section">
<div class="toolbar">
<div class="pipeline-selector-wrapper">
<label for="pipeline-select"><i class="fa-solid fa-filter"></i> Seleccionar Pipeline:</label>
<select id="pipeline-select" class="form-control">
<option value="">-- Cargar pipelines --</option>
</select>
</div>
</div>
<div id="kanban-board" class="kanban-board">
<div class="board-empty-state">
<i class="fa-solid fa-folder-open"></i>
<p>No se encontraron pipelines ni oportunidades para esta cuenta.</p>
<span class="text-secondary">Asegúrate de sincronizar la sucursal para cargar sus datos desde GHL.</span>
</div>
</div>
</section>
<!-- 4. WORKFLOWS TAB -->
<section id="tab-workflows" class="tab-section">
<div class="toolbar" style="gap: 16px; flex-wrap: wrap;">
<div class="search-box">
<i class="fa-solid fa-magnifying-glass"></i>
<input type="text" id="workflow-table-search" placeholder="Buscar workflows por nombre, ID o trigger...">
</div>
<div class="pipeline-selector-wrapper" style="margin: 0;">
<label for="workflow-branch-select"><i class="fa-solid fa-store"></i> Cuenta/Sucursal:</label>
<select id="workflow-branch-select" class="form-control">
<option value="all">-- Todas las sucursales --</option>
</select>
</div>
<div class="pipeline-selector-wrapper" style="margin: 0;">
<label for="workflow-status-select"><i class="fa-solid fa-toggle-on"></i> Estado:</label>
<select id="workflow-status-select" class="form-control">
<option value="all">-- Todos los estados --</option>
<option value="active">Activo</option>
<option value="inactive">Pausado</option>
<option value="draft">Borrador</option>
</select>
</div>
<div class="pipeline-selector-wrapper" style="margin: 0;">
<label for="workflow-date-field"><i class="fa-solid fa-calendar-days"></i> Filtrar por:</label>
<select id="workflow-date-field" class="form-control">
<option value="created_at">Fecha de Creación</option>
<option value="updated_at">Fecha de Modificación</option>
</select>
</div>
<div class="pipeline-selector-wrapper" style="margin: 0;">
<label for="workflow-date-after"><i class="fa-solid fa-arrow-right"></i> Después de:</label>
<input type="datetime-local" id="workflow-date-after" class="form-control" step="60">
</div>
<div class="pipeline-selector-wrapper" style="margin: 0;">
<label for="workflow-date-before"><i class="fa-solid fa-arrow-left"></i> Antes de:</label>
<input type="datetime-local" id="workflow-date-before" class="form-control" step="60">
</div>
<button id="btn-workflow-clear-dates" class="btn btn-secondary" title="Limpiar filtros de fecha" style="padding: 6px 12px;">
<i class="fa-solid fa-xmark"></i> Limpiar fechas
</button>
<div style="margin-left: auto; display: flex; gap: 10px; flex-wrap: wrap; align-items: center;">
<span id="workflow-session-status" class="text-secondary" style="font-size: 12px;"></span>
<button id="btn-refresh-session" class="btn btn-secondary" title="Abre una ventana del navegador para renovar las cookies de Bucéfalo. Necesario para acciones de toggle / renombrar / eliminar workflows.">
<i class="fa-solid fa-key"></i> Renovar sesión Bucéfalo
</button>
<button id="btn-export-workflows" class="btn btn-secondary">
<i class="fa-solid fa-file-excel"></i> Exportar Excel
</button>
<button id="btn-sync-workflows" class="btn btn-secondary">
<i class="fa-solid fa-arrows-rotate"></i> Sincronizar Workflows
</button>
</div>
</div>
<div id="workflows-bulk-bar" class="hidden" style="padding:12px 16px; margin-bottom:8px; background: rgba(124, 58, 237, 0.08); border:1px solid rgba(124, 58, 237, 0.25); border-radius:8px;">
<div id="workflows-bulk-actions" style="display:flex; gap:12px; align-items:center;">
<span id="workflows-bulk-count" style="font-weight:bold;">0 seleccionados</span>
<button id="btn-bulk-publish" class="btn btn-secondary" title="Activar (Publicar) todos los seleccionados">
<i class="fa-solid fa-toggle-on" style="color:#34D399;"></i> Publicar
</button>
<button id="btn-bulk-draft" class="btn btn-secondary" title="Poner todos los seleccionados en Borrador">
<i class="fa-solid fa-toggle-off"></i> Poner en Borrador
</button>
<button id="btn-bulk-delete" class="btn btn-secondary" title="Eliminar todos los seleccionados (irreversible)" style="border-color: rgba(248, 113, 113, 0.4);">
<i class="fa-solid fa-trash-can" style="color:#F87171;"></i> Eliminar
</button>
<button id="btn-bulk-scan-anomalies" class="btn btn-secondary" title="Escanear anomalías en los nodos de los workflows seleccionados (read-only)">
<i class="fa-solid fa-stethoscope" style="color:#F59E0B;"></i> Escanear anomalías
</button>
<button id="btn-bulk-clear" class="btn btn-secondary" title="Limpiar selección">
<i class="fa-solid fa-xmark"></i> Limpiar selección
</button>
</div>
<div id="workflows-bulk-progress" class="hidden" style="display:flex; flex-direction:column; gap:8px;">
<div style="display:flex; justify-content:space-between; align-items:center; gap:12px;">
<span id="bulk-progress-title" style="font-weight:bold;">
<i class="fa-solid fa-spinner fa-spin"></i> Procesando...
</span>
<div style="display:flex; align-items:center; gap:10px;">
<span id="bulk-progress-counter" style="font-family:monospace;">0/0</span>
<button id="btn-bulk-cancel" class="btn btn-secondary hidden" title="Detener el escaneo en curso" style="padding:4px 10px; font-size:12px; border-color: rgba(248, 113, 113, 0.4);">
<i class="fa-solid fa-stop" style="color:#F87171;"></i> Cancelar
</button>
</div>
</div>
<div style="width:100%; height:8px; background: rgba(255,255,255,0.08); border-radius:4px; overflow:hidden;">
<div id="bulk-progress-fill" style="height:100%; width:0%; background: linear-gradient(90deg, #7C3AED, #60A5FA); transition: width 0.4s ease;"></div>
</div>
<div id="bulk-progress-current" style="font-size: 13px; color: var(--text-muted);">
Esperando logs del proceso...
</div>
<div id="bulk-progress-summary" class="hidden" style="display:flex; gap:16px; flex-wrap:wrap; align-items:center; font-size: 13px;">
<span id="bulk-progress-success-count" style="color:#34D399;"></span>
<span id="bulk-progress-skipped-count" style="color: var(--text-muted);"></span>
<span id="bulk-progress-failed-count" style="color:#F87171;"></span>
<span id="bulk-progress-anomalies-count" class="hidden" style="color:#F59E0B; font-weight:bold;"></span>
<button id="btn-bulk-retry-pending" class="btn btn-primary hidden" style="margin-left:auto;" title="Reintentar los workflows que no llegaron a procesarse">
<i class="fa-solid fa-rotate-right"></i> Reintentar pendientes (<span id="bulk-retry-count">0</span>)
</button>
<button id="btn-bulk-download-report" class="btn btn-secondary hidden" title="Descargar el CSV con los hallazgos">
<i class="fa-solid fa-file-csv"></i> Descargar CSV
</button>
<button id="btn-bulk-download-xlsx" class="btn btn-secondary hidden" title="Descargar Excel con los hallazgos coloreados por tipo">
<i class="fa-solid fa-file-excel" style="color:#34D399;"></i> Descargar Excel
</button>
<button id="btn-bulk-close-progress" class="btn btn-secondary">
<i class="fa-solid fa-check"></i> Cerrar
</button>
</div>
<div id="bulk-anomalies-panel" class="hidden" style="margin-top:8px; padding:12px; background: rgba(245, 158, 11, 0.08); border:1px solid rgba(245, 158, 11, 0.35); border-radius:8px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:8px;">
<i class="fa-solid fa-triangle-exclamation" style="color:#F59E0B;"></i>
<strong id="bulk-anomalies-title" style="color:#F59E0B;">Anomalías detectadas</strong>
<button id="btn-bulk-anomalies-toggle" class="btn btn-secondary" style="margin-left:auto; padding:2px 10px; font-size: 12px;" title="Mostrar/ocultar lista">
<i class="fa-solid fa-chevron-down"></i> <span id="bulk-anomalies-toggle-label">Ver detalle</span>
</button>
</div>
<div id="bulk-anomalies-list" class="hidden" style="max-height: 320px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px;"></div>
</div>
</div>
</div>
<div class="card table-card">
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width:36px; text-align:center;">
<input type="checkbox" id="workflows-select-all" title="Seleccionar todos los visibles">
</th>
<th class="workflow-sortable" data-sort-field="account_name">Cuenta/Sucursal <span class="sort-indicator"></span></th>
<th class="workflow-sortable" data-sort-field="id">ID Workflow <span class="sort-indicator"></span></th>
<th class="workflow-sortable" data-sort-field="name">Nombre del Workflow <span class="sort-indicator"></span></th>
<th class="workflow-sortable" data-sort-field="status">Estado <span class="sort-indicator"></span></th>
<th class="workflow-sortable" data-sort-field="trigger">Trigger <span class="sort-indicator"></span></th>
<th class="workflow-sortable" data-sort-field="created_at">Fecha de Creación <span class="sort-indicator"></span></th>
<th class="workflow-sortable" data-sort-field="updated_at">Fecha de Modificación <span class="sort-indicator"></span></th>
<th class="workflow-sortable" data-sort-field="synced_at">Sincronizado en Local <span class="sort-indicator"></span></th>
<th style="text-align: center;">Acciones</th>
</tr>
</thead>
<tbody id="workflows-table-rows">
<tr>
<td colspan="10" class="text-center">Cargando workflows...</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<!-- 5. SCRIPTS TAB (CENTRO DE SCRIPTS) -->
<section id="tab-scripts" class="tab-section">
<div class="scripts-layout-grid">
<!-- Columna Izquierda: Lista de Scripts -->
<div class="scripts-catalog-column">
<div class="card scripts-card">
<div class="card-header">
<h3><i class="fa-solid fa-cubes"></i> Scripts Disponibles</h3>
</div>
<div class="card-body">
<div class="script-search-box">
<i class="fa-solid fa-magnifying-glass"></i>
<input type="search" id="script-search-input" placeholder="Buscar por nombre, descripción, categoría o flag...">
</div>
<div class="script-category-tabs">
<button class="btn-category active" data-category="all">Todos</button>
<button class="btn-category" data-category="Búsqueda y Análisis">Búsqueda</button>
<button class="btn-category" data-category="Fix y Corrección">Fixes</button>
<button class="btn-category" data-category="Auditorías">Auditorías</button>
<button class="btn-category" data-category="Cron Jobs">Crons</button>
<button class="btn-category" data-category="Sin registrar">Sin registrar</button>
</div>
<div id="scripts-list" class="scripts-list">
<!-- Tarjetas de scripts dinámicas -->
</div>
</div>
</div>
</div>
<!-- Columna Derecha: Consola Terminal SSE -->
<div class="scripts-terminal-column">
<div class="card terminal-card">
<div class="card-header terminal-header">
<div class="terminal-title">
<span class="terminal-dot red"></span>
<span class="terminal-dot yellow"></span>
<span class="terminal-dot green"></span>
<h3><i class="fa-solid fa-code"></i> Terminal de Salida en Vivo</h3>
<span id="terminal-status-badge" class="terminal-status-badge idle">Listo</span>
</div>
<div class="terminal-actions">
<div class="universal-dryrun-toggle" id="universal-dryrun-wrapper" title="Modo Simulación (Dry-Run Seguro)">
<span class="toggle-label">Simular (Dry-Run)</span>
<label class="toggle-switch">
<input type="checkbox" id="universal-dryrun-checkbox" checked>
<span class="toggle-slider"></span>
</label>
</div>
<button id="btn-copy-terminal" class="btn btn-secondary btn-sm">
<i class="fa-solid fa-copy"></i> Copiar
</button>
<button id="btn-clear-terminal" class="btn btn-secondary btn-sm">
<i class="fa-solid fa-trash-can"></i> Limpiar
</button>
</div>
</div>
<nav class="terminal-tabs" id="terminal-tabs">
<button class="terminal-tab active" data-term-tab="output" type="button">
<i class="fa-solid fa-terminal"></i> Salida en Vivo
</button>
<button class="terminal-tab" data-term-tab="errors" type="button">
<i class="fa-solid fa-triangle-exclamation"></i> Errores
<span class="terminal-error-count" id="terminal-error-count">0</span>
</button>
</nav>
<!-- Barra sticky de controles del run activo. Vive fuera de #terminal-screen
para que no se mezcle con los logs ni se trunque por el cap del buffer. -->
<div class="terminal-run-bar hidden" id="terminal-run-bar">
<div class="terminal-run-bar-stats" id="terminal-run-stats" title="Líneas visibles · líneas descartadas">
<i class="fa-solid fa-list"></i>
<span id="terminal-run-counter">0 líneas</span>
</div>
<div class="terminal-run-bar-controls" id="terminal-run-controls" data-task-id="">
<!-- Botones Pausar / Reanudar / Detener / Revertir se insertan dinámicamente. -->
</div>
<div class="terminal-run-bar-actions">
<button id="btn-download-log" class="btn btn-secondary btn-sm hidden" title="Descargar log completo del run">
<i class="fa-solid fa-download"></i> Descargar log
</button>
</div>
</div>
<div class="terminal-body" id="terminal-screen" data-term-panel="output">
<div class="terminal-placeholder">
<i class="fa-solid fa-terminal"></i>
<p>Centro de Control de Scripts Python</p>
<span>Selecciona un script y haz clic en "Ejecutar" para ver la salida en tiempo real.</span>
</div>
</div>
<!-- Badge flotante que aparece cuando el usuario hizo scroll arriba durante un run. -->
<button id="terminal-resume-scroll" class="terminal-resume-scroll hidden" type="button" title="Volver al final del log">
<i class="fa-solid fa-arrow-down"></i> Volver al final
</button>
<div class="terminal-body terminal-errors-panel hidden" id="terminal-errors" data-term-panel="errors">
<div class="terminal-errors-summary" id="terminal-errors-summary">
<div class="terminal-errors-summary-main">
<strong id="terminal-errors-total">0</strong>
<span>errores registrados en esta sesión</span>
</div>
<div class="terminal-errors-summary-meta" id="terminal-errors-breakdown">
Sin scripts con fallos.
</div>
</div>
<div class="terminal-errors-list" id="terminal-errors-list">
<div class="terminal-placeholder">
<i class="fa-solid fa-shield-halved"></i>
<p>Sin errores registrados</p>
<span>Los errores detectados durante la ejecución aparecerán aquí con su script, Task ID y log.</span>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</main>
</div>
<!-- MODALES / NOTIFICACIONES TOAST -->
<div id="toast-container" class="toast-container"></div>
<!-- Modal de Información de Cuenta, Pipelines y Fases -->
<div id="modal-location-info" class="modal-backdrop hidden">
<div class="modal-card" style="width: 650px; max-width: 95%; max-height: 85vh; display: flex; flex-direction: column;">
<div class="modal-header">
<h3><i class="fa-solid fa-circle-info"></i> Detalles de la Cuenta y Pipelines</h3>
<button class="btn-close-modal" onclick="closeLocationInfoModal()">&times;</button>
</div>
<div class="modal-body" style="overflow-y: auto; flex: 1; padding: 24px; display: flex; flex-direction: column; gap: 20px;">
<!-- Loader -->
<div id="location-info-loader" class="text-center" style="padding: 40px 0;">
<i class="fa-solid fa-circle-notch fa-spin fa-2x" style="color: var(--color-primary);"></i>
<p style="margin-top: 12px; color: var(--text-muted);">Cargando detalles de la cuenta y pipelines...</p>
</div>
<!-- Contenido -->
<div id="location-info-content" class="hidden" style="display: flex; flex-direction: column; gap: 24px;">
<!-- Bloque de Metadata de Cuenta -->
<div>
<h4 style="color: var(--text-primary); margin-bottom: 12px; border-bottom: 1px solid var(--border-glass); padding-bottom: 8px; display: flex; align-items: center; gap: 8px;">
<i class="fa-solid fa-store" style="color: var(--color-primary-glow);"></i> Datos de GHL (Get Location)
</h4>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px; font-size: 14px;">
<div>
<span class="text-secondary" style="display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted);">Nombre Comercial</span>
<strong id="loc-info-name">-</strong>
</div>
<div>
<span class="text-secondary" style="display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted);">Location ID</span>
<code id="loc-info-id">-</code>
</div>
<div>
<span class="text-secondary" style="display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted);">Dueño de la Compañía</span>
<span id="loc-info-owner">-</span>
</div>
<div>
<span class="text-secondary" style="display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted);">Teléfono</span>
<span id="loc-info-phone">-</span>
</div>
<div>
<span class="text-secondary" style="display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted);">Email</span>
<span id="loc-info-email">-</span>
</div>
<div>
<span class="text-secondary" style="display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted);">Zona Horaria</span>
<span id="loc-info-timezone">-</span>
</div>
<div style="grid-column: span 2;">
<span class="text-secondary" style="display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted);">Dirección Completa</span>
<span id="loc-info-address">-</span>
</div>
</div>
</div>
<!-- Bloque de Pipelines y Fases -->
<div>
<h4 style="color: var(--text-primary); margin-bottom: 12px; border-bottom: 1px solid var(--border-glass); padding-bottom: 8px; display: flex; align-items: center; gap: 8px;">
<i class="fa-solid fa-diagram-project" style="color: var(--color-success-glow);"></i> Pipelines y Fases Existentes
</h4>
<div id="location-pipelines-container" style="display: flex; flex-direction: column; gap: 16px;">
<!-- Pipelines se renderizarán aquí -->
</div>
</div>
</div>
</div>
<div class="modal-footer" style="padding: 16px 24px; border-top: 1px solid var(--border-glass); display: flex; justify-content: flex-end;">
<button class="btn btn-secondary" onclick="closeLocationInfoModal()">Cerrar</button>
</div>
</div>
</div>
<!-- Modal de Renombrar Workflow -->
<div id="modal-rename-workflow" class="modal-backdrop hidden">
<div class="modal-card">
<div class="modal-header">
<h3><i class="fa-solid fa-pen-to-square"></i> Renombrar Workflow</h3>
<button class="btn-close-modal" onclick="closeRenameWorkflowModal()">&times;</button>
</div>
<div class="modal-body">
<input type="hidden" id="rename-wf-id">
<input type="hidden" id="rename-wf-location">
<div class="form-group" style="display: flex; flex-direction: column; gap: 8px;">
<label for="rename-wf-input">Nuevo Nombre del Workflow:</label>
<input type="text" id="rename-wf-input" class="form-control" placeholder="Escribe el nuevo nombre..." style="width: 100%; box-sizing: border-box;">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" onclick="closeRenameWorkflowModal()">Cancelar</button>
<button id="btn-save-rename-workflow" class="btn btn-primary" onclick="submitRenameWorkflow()">Guardar Cambios</button>
</div>
</div>
</div>
<!-- Modal de Metadata de Script -->
<div id="modal-script-metadata" class="modal-backdrop hidden">
<div class="modal-card script-editor-modal">
<div class="modal-header">
<h3><i class="fa-solid fa-tags"></i> Editar Metadata del Script</h3>
<button class="btn-close-modal" onclick="closeScriptMetadataModal()">&times;</button>
</div>
<div class="modal-body script-editor-body">
<input type="hidden" id="script-metadata-name">
<div class="script-form-grid">
<label>Título
<input type="text" id="script-meta-title" class="form-control">
</label>
<label>Categoría
<select id="script-meta-category" class="form-control">
<option value="Búsqueda y Análisis">Búsqueda y Análisis</option>
<option value="Fix y Corrección">Fix y Corrección</option>
<option value="Auditorías">Auditorías</option>
<option value="Cron Jobs">Cron Jobs</option>
<option value="Sin registrar">Sin registrar</option>
</select>
</label>
<label class="script-form-full">Descripción
<textarea id="script-meta-description" class="form-control" rows="4"></textarea>
</label>
<label>Placeholder de argumentos
<input type="text" id="script-meta-args" class="form-control">
</label>
<label>Modo dry-run
<select id="script-meta-dry-run-mode" class="form-control">
<option value="">Ninguno</option>
<option value="dry_run_flag">Usa --dry-run</option>
<option value="apply_flag">Usa --apply</option>
</select>
</label>
<label class="script-check-row"><input type="checkbox" id="script-meta-supports-locations"> Soporta sucursales</label>
<label class="script-check-row"><input type="checkbox" id="script-meta-mutator"> Modifica datos</label>
<label class="script-check-row"><input type="checkbox" id="script-meta-supports-audit"> Soporta auditoría</label>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" onclick="closeScriptMetadataModal()">Cancelar</button>
<button class="btn btn-primary" onclick="saveScriptMetadata()">Guardar Metadata</button>
</div>
</div>
</div>
<script src="/static/js/live_terminal.js?v=1.0.0" defer></script>
<script src="/static/js/app.js?v=1.0.13" defer></script>
</body>
</html>