{"id":3110,"date":"2026-08-04T14:43:08","date_gmt":"2026-08-04T14:43:08","guid":{"rendered":"https:\/\/bl.blcorporations.com\/?page_id=3110"},"modified":"2026-08-04T20:49:12","modified_gmt":"2026-08-04T20:49:12","slug":"prueba-bl-ranking","status":"publish","type":"page","link":"https:\/\/bl.blcorporations.com\/?page_id=3110","title":{"rendered":"prueba bl ranking"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"3110\" class=\"elementor elementor-3110\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fbf8b58 e-flex e-con-boxed e-con e-parent\" data-id=\"fbf8b58\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f5d1f93 elementor-widget elementor-widget-shortcode\" data-id=\"f5d1f93\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">    <div id=\"bl-core-app\" class=\"bl-core-app\" data-ajax-url=\"https:\/\/bl.blcorporations.com\/wp-admin\/admin-ajax.php\" data-nonce=\"f0a2ec9e8b\">\r\n\r\n        <nav class=\"bl-nav\">\r\n            <div class=\"bl-nav-brand\">BL Corporations<\/div>\r\n            <div class=\"bl-nav-tabs\">\r\n                <button class=\"bl-nav-tab is-active\" data-module=\"buscador\">\ud83d\udd0d Buscador<\/button>\r\n                <button class=\"bl-nav-tab\" data-module=\"agentes\">\ud83d\udccb Agentes<\/button>\r\n                <button class=\"bl-nav-tab\" data-module=\"dashboard\">\ud83d\udcca Dashboard<\/button>\r\n            <\/div>\r\n        <\/nav>\r\n\r\n        <!-- ============ M\u00d3DULO 1: BUSCADOR ============ -->\r\n        <section class=\"bl-module bl-module-buscador is-active\" data-module-panel=\"buscador\">\r\n            <div class=\"bl-buscador-grid\">\r\n\r\n                <div class=\"bl-col bl-col-form\">\r\n                    <h3>Par\u00e1metros del pedido<\/h3>\r\n\r\n                    <label>Modalidad<\/label>\r\n                    <select id=\"bl-f-modalidad\">\r\n                        <option value=\"A\u00e9rea\">A\u00e9rea<\/option>\r\n                        <option value=\"FCL\">FCL<\/option>\r\n                        <option value=\"LCL\">LCL<\/option>\r\n                        <option value=\"Terrestre\">Terrestre<\/option>\r\n                        <option value=\"Courier\">Courier<\/option>\r\n                    <\/select>\r\n\r\n                    <label>Origen<\/label>\r\n                    <div class=\"bl-autocomplete-wrap\">\r\n                        <input type=\"text\" id=\"bl-f-origen\" placeholder=\"Escribe o elige un pa\u00eds...\" autocomplete=\"off\" \/>\r\n                        <div class=\"bl-autocomplete-dropdown\" id=\"bl-f-origen-dropdown\"><\/div>\r\n                    <\/div>\r\n\r\n                    <label>Destino<\/label>\r\n                    <div class=\"bl-autocomplete-wrap\">\r\n                        <input type=\"text\" id=\"bl-f-destino\" placeholder=\"Escribe o elige un pa\u00eds...\" autocomplete=\"off\" \/>\r\n                        <div class=\"bl-autocomplete-dropdown\" id=\"bl-f-destino-dropdown\"><\/div>\r\n                    <\/div>\r\n\r\n                    <label>Peso total<\/label>\r\n                    <div class=\"bl-inline-fields\">\r\n                        <input type=\"number\" id=\"bl-f-peso\" min=\"0\" step=\"0.01\" placeholder=\"0.00\" \/>\r\n                        <select id=\"bl-f-unidad-peso\">\r\n                            <option value=\"KG\">KG<\/option>\r\n                            <option value=\"TON\">TON (m\u00e9trica)<\/option>\r\n                            <option value=\"LB\">LB (libras)<\/option>\r\n                            <option value=\"OZ\">OZ (onzas)<\/option>\r\n                            <option value=\"ST\">ST (ton. corta)<\/option>\r\n                            <option value=\"LT\">LT (ton. larga)<\/option>\r\n                        <\/select>\r\n                    <\/div>\r\n\r\n                    <label class=\"bl-check-label\">\r\n                        <input type=\"checkbox\" id=\"bl-f-toggle-volumen\" \/> Agregar volumen \/ contenedor\r\n                    <\/label>\r\n                    <div class=\"bl-inline-fields bl-campo-volumen\" id=\"bl-campo-volumen\" hidden>\r\n                        <input type=\"number\" id=\"bl-f-volumen\" min=\"0\" step=\"0.01\" placeholder=\"0.00\" \/>\r\n                        <select id=\"bl-f-unidad-volumen\">\r\n                            <option value=\"CBM\">CBM (m\u00b3)<\/option>\r\n                            <option value=\"TEU\">TEU<\/option>\r\n                            <option value=\"FEU\">FEU<\/option>\r\n                        <\/select>\r\n                    <\/div>\r\n\r\n                    <label>Tipo de carga<\/label>\r\n                    <div class=\"bl-autocomplete-wrap\">\r\n                        <input type=\"text\" id=\"bl-f-tipo-carga\" placeholder=\"Escribe y selecciona (varios)...\" autocomplete=\"off\" \/>\r\n                        <div class=\"bl-autocomplete-dropdown\" id=\"bl-f-tipo-carga-dropdown\"><\/div>\r\n                    <\/div>\r\n                    <div class=\"bl-tags-wrap\" id=\"bl-f-tipo-carga-tags\"><\/div>\r\n\r\n                    <button id=\"bl-btn-ejecutar\" class=\"bl-btn bl-btn-primary\">Ejecutar Recomendaci\u00f3n<\/button>\r\n                <\/div>\r\n\r\n                <div class=\"bl-col bl-col-resultados\">\r\n                    <div class=\"bl-resultados-header\">\r\n                        <div class=\"bl-contadores\">\r\n                            <span id=\"bl-count-sugeridos\">MOSTRANDO 0 SUGERIDOS<\/span>\r\n                            <span id=\"bl-count-seleccionados\">0 AGENTES SELECCIONADOS<\/span>\r\n                        <\/div>\r\n                        <div class=\"bl-resultados-acciones\">\r\n                            <button id=\"bl-btn-seleccionar-todos\" class=\"bl-btn bl-btn-secondary\">Seleccionar Todos<\/button>\r\n                            <button id=\"bl-btn-exportar\" class=\"bl-btn bl-btn-secondary\" disabled title=\"Pr\u00f3ximamente\">Exportar Excel<\/button>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <table class=\"bl-tabla-resultados\">\r\n                        <thead>\r\n                            <tr>\r\n                                <th>Prioridad<\/th>\r\n                                <th>ID Agente<\/th>\r\n                                <th>Nombre<\/th>\r\n                                <th>Score<\/th>\r\n                                <th>Nro. Contratos<\/th>\r\n                                <th>Acci\u00f3n<\/th>\r\n                            <\/tr>\r\n                        <\/thead>\r\n                        <tbody id=\"bl-resultados-body\">\r\n                            <tr class=\"bl-empty-row\"><td colspan=\"6\">Ejecuta una recomendaci\u00f3n para ver los agentes sugeridos.<\/td><\/tr>\r\n                        <\/tbody>\r\n                    <\/table>\r\n                <\/div>\r\n\r\n                <div class=\"bl-col bl-col-mapa\">\r\n                    <h3>Ruta seleccionada<\/h3>\r\n                    <div class=\"bl-mapa-placeholder\">\r\n                        <div class=\"bl-mapa-punto bl-mapa-origen\">\r\n                            <span class=\"bl-mapa-label\">ORIGEN<\/span>\r\n                            <span class=\"bl-mapa-valor\" id=\"bl-mapa-origen-valor\">\u2014<\/span>\r\n                        <\/div>\r\n                        <div class=\"bl-mapa-linea\">\u2708 \u21e2 \ud83d\udea2<\/div>\r\n                        <div class=\"bl-mapa-punto bl-mapa-destino\">\r\n                            <span class=\"bl-mapa-label\">DESTINO<\/span>\r\n                            <span class=\"bl-mapa-valor\" id=\"bl-mapa-destino-valor\">\u2014<\/span>\r\n                        <\/div>\r\n                        <p class=\"bl-mapa-nota\">Vista simplificada. Mapa mundi gr\u00e1fico interactivo: pendiente para una pr\u00f3xima iteraci\u00f3n.<\/p>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n            <\/div>\r\n        <\/section>\r\n\r\n        <!-- ============ M\u00d3DULO 2: AGENTES (Directorio) ============ -->\r\n        <section class=\"bl-module bl-module-agentes\" data-module-panel=\"agentes\">\r\n            <div class=\"bl-agentes-header\">\r\n                <input type=\"text\" id=\"bl-agentes-buscar\" placeholder=\"Buscar por nombre, pa\u00eds o ciudad...\" \/>\r\n                <button id=\"bl-btn-filtros-avanzados\" class=\"bl-btn bl-btn-secondary\">Filtros Avanzados<\/button>\r\n                <div class=\"bl-vista-switch\">\r\n                    <button class=\"bl-btn bl-btn-secondary is-active\" data-vista=\"tabla\">Tabla<\/button>\r\n                    <button class=\"bl-btn bl-btn-secondary\" data-vista=\"bloques\">Bloques<\/button>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <div class=\"bl-filtros-avanzados-panel\" id=\"bl-filtros-avanzados-panel\">\r\n                <div class=\"bl-filtro-campo\">\r\n                    <label>Pa\u00eds Origen<\/label>\r\n                    <div class=\"bl-autocomplete-wrap\">\r\n                        <input type=\"text\" id=\"bl-filtro-pais-origen\" placeholder=\"Ej: China\" autocomplete=\"off\" \/>\r\n                        <div class=\"bl-autocomplete-dropdown\" id=\"bl-filtro-pais-origen-dropdown\"><\/div>\r\n                    <\/div>\r\n                <\/div>\r\n                <div class=\"bl-filtro-campo\">\r\n                    <label>Servicios<\/label>\r\n                    <div class=\"bl-autocomplete-wrap\">\r\n                        <input type=\"text\" id=\"bl-filtro-servicios\" placeholder=\"Ej: FCL\" autocomplete=\"off\" \/>\r\n                        <div class=\"bl-autocomplete-dropdown\" id=\"bl-filtro-servicios-dropdown\"><\/div>\r\n                    <\/div>\r\n                <\/div>\r\n                <div class=\"bl-filtro-campo\">\r\n                    <label>L\u00edmite Cr\u00e9dito<\/label>\r\n                    <div class=\"bl-autocomplete-wrap\">\r\n                        <input type=\"text\" id=\"bl-filtro-limite-credito\" placeholder=\"Ej: 5.000 - 20.000 USD\" autocomplete=\"off\" \/>\r\n                        <div class=\"bl-autocomplete-dropdown\" id=\"bl-filtro-limite-credito-dropdown\"><\/div>\r\n                    <\/div>\r\n                <\/div>\r\n                <div class=\"bl-filtro-campo\">\r\n                    <label>Ranking M\u00ednimo<\/label>\r\n                    <div class=\"bl-autocomplete-wrap\">\r\n                        <input type=\"text\" id=\"bl-filtro-ranking-minimo\" placeholder=\"Ej: 80 o m\u00e1s\" autocomplete=\"off\" \/>\r\n                        <div class=\"bl-autocomplete-dropdown\" id=\"bl-filtro-ranking-minimo-dropdown\"><\/div>\r\n                    <\/div>\r\n                <\/div>\r\n                <div class=\"bl-filtro-campo\">\r\n                    <label>Red Log\u00edstica<\/label>\r\n                    <div class=\"bl-autocomplete-wrap\">\r\n                        <input type=\"text\" id=\"bl-filtro-red-logistica\" placeholder=\"Ej: WCA\" autocomplete=\"off\" \/>\r\n                        <div class=\"bl-autocomplete-dropdown\" id=\"bl-filtro-red-logistica-dropdown\"><\/div>\r\n                    <\/div>\r\n                <\/div>\r\n                <div class=\"bl-filtro-campo\">\r\n                    <label>Estado<\/label>\r\n                    <div class=\"bl-autocomplete-wrap\">\r\n                        <input type=\"text\" id=\"bl-filtro-estado\" placeholder=\"Ej: Nuevo\" autocomplete=\"off\" \/>\r\n                        <div class=\"bl-autocomplete-dropdown\" id=\"bl-filtro-estado-dropdown\"><\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <div class=\"bl-agentes-acciones\">\r\n                <button id=\"bl-btn-buscar-agentes\" class=\"bl-btn bl-btn-primary\">Buscar Agentes<\/button>\r\n                <button id=\"bl-btn-limpiar-filtros\" class=\"bl-btn bl-btn-secondary\">Limpiar Filtros<\/button>\r\n                <button id=\"bl-btn-exportar-agentes\" class=\"bl-btn bl-btn-secondary\" disabled title=\"Pr\u00f3ximamente\">Exportar a Excel<\/button>\r\n                <button id=\"bl-btn-nuevo-agente\" class=\"bl-btn bl-btn-secondary\">+ Agente<\/button>\r\n            <\/div>\r\n\r\n            <p class=\"bl-resultado-busqueda-texto\" id=\"bl-resultado-busqueda-texto\">Resultado de B\u00fasqueda (0 Resultados Encontrados)<\/p>\r\n\r\n            <div id=\"bl-agentes-contenido\">\r\n                <p class=\"bl-loading\">Cargando directorio de agentes\u2026<\/p>\r\n            <\/div>\r\n        <\/section>\r\n\r\n        <!-- ============ M\u00d3DULO 3: DASHBOARD ============ -->\r\n        <section class=\"bl-module bl-module-dashboard\" data-module-panel=\"dashboard\">\r\n            <div id=\"bl-dashboard-contenido\">\r\n                <p class=\"bl-loading\">Cargando estad\u00edsticas\u2026<\/p>\r\n            <\/div>\r\n        <\/section>\r\n\r\n        <!-- ============ M\u00d3DULO 4 (oculto de la nav): FICHA DE REGISTRO Y EDICI\u00d3N DE AGENTE ============ -->\r\n        <section class=\"bl-module bl-module-editar\" data-module-panel=\"editar\">\r\n            <a href=\"#\" id=\"bl-editar-volver\" class=\"bl-editar-volver\">\u2190 Volver<\/a>\r\n            <h2 class=\"bl-editar-titulo\">Ficha de Registro y Edici\u00f3n de Agente<\/h2>\r\n            <p class=\"bl-editar-subtitulo\">Complete los bloques de informaci\u00f3n para el maestro de partners log\u00edsticos globales.<\/p>\r\n\r\n            <form id=\"bl-form-agente\">\r\n                <!-- ---------- BLOQUE 1 ---------- -->\r\n                <div class=\"bl-bloque-editar\">\r\n                    <div class=\"bl-bloque-header\"><span class=\"bl-bloque-tag\">BLOQUE 01<\/span> INFORMACI\u00d3N CORPORATIVA Y CONTACTO<\/div>\r\n\r\n                    <div class=\"bl-form-grid\">\r\n                        <div class=\"bl-campo\"><label>C\u00f3digo Agente (UUID)<\/label><input type=\"text\" id=\"bl-e-id\" readonly \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Nombre Comercial *<\/label><input type=\"text\" id=\"bl-e-nombre-comercial\" placeholder=\"Ej: SAMEDAYLOGISTICS\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Raz\u00f3n Social *<\/label><input type=\"text\" id=\"bl-e-razon-social\" placeholder=\"Ej: SAMEDAYLOGISTICS ROMANIA SRL\" \/><\/div>\r\n                        <div class=\"bl-campo\">\r\n                            <label>Estado Operativo<\/label>\r\n                            <select id=\"bl-e-estado\">\r\n                                <option value=\"Nuevo\">Nuevo<\/option>\r\n                                <option value=\"Activo\">Activo<\/option>\r\n                                <option value=\"Pasivo\">Pasivo<\/option>\r\n                                <option value=\"Inactivo\">Inactivo<\/option>\r\n                            <\/select>\r\n                        <\/div>\r\n                        <div class=\"bl-campo bl-autocomplete-wrap\"><label>Pa\u00eds<\/label><input type=\"text\" id=\"bl-e-pais\" placeholder=\"Ej: Ruman\u00eda\" autocomplete=\"off\" \/><div class=\"bl-autocomplete-dropdown\" id=\"bl-e-pais-dropdown\"><\/div><\/div>\r\n                        <div class=\"bl-campo bl-autocomplete-wrap\"><label>Ciudad<\/label><input type=\"text\" id=\"bl-e-ciudad\" placeholder=\"Ej: Bucarest\" autocomplete=\"off\" \/><div class=\"bl-autocomplete-dropdown\" id=\"bl-e-ciudad-dropdown\"><\/div><\/div>\r\n                        <div class=\"bl-campo\"><label>P\u00e1gina Web<\/label><input type=\"text\" id=\"bl-e-web\" placeholder=\"https:\/\/www.agente.com\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Responsable Asignado<\/label><input type=\"text\" id=\"bl-e-responsable\" placeholder=\"Ej: Juan P\u00e9rez (BL)\" \/><\/div>\r\n                        <div class=\"bl-campo bl-campo-ancho\"><label>Direcci\u00f3n Matriz<\/label><input type=\"text\" id=\"bl-e-direccion\" placeholder=\"Av. Principal #123, Of 402\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Fecha Actualizaci\u00f3n<\/label><input type=\"text\" id=\"bl-e-fecha-actualizacion\" readonly \/><\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"bl-bloque-subtitulo\">\ud83d\udc64 Datos de Contacto<\/div>\r\n                    <div class=\"bl-bloque2-grid\">\r\n                    <div class=\"bl-bloque2-izq\">\r\n                    <div class=\"bl-contacto-selector\">\r\n                        <div class=\"bl-autocomplete-wrap\" style=\"flex:1\">\r\n                            <input type=\"text\" id=\"bl-e-contacto-nombre\" placeholder=\"Ej: Elena Popescu (escribe o elige uno existente)\" autocomplete=\"off\" \/>\r\n                            <div class=\"bl-autocomplete-dropdown\" id=\"bl-e-contacto-nombre-dropdown\"><\/div>\r\n                        <\/div>\r\n                        <button type=\"button\" id=\"bl-btn-nuevo-contacto\" class=\"bl-btn bl-btn-secondary\">+ Nuevo Contacto<\/button>\r\n                        <button type=\"button\" id=\"bl-btn-guardar-contacto\" class=\"bl-btn bl-btn-secondary\" disabled title=\"Primero guarda el agente\">Guardar Contacto<\/button>\r\n                    <\/div>\r\n                    <div class=\"bl-form-grid\">\r\n                        <div class=\"bl-campo\"><label>ID Contacto (UUID)<\/label><input type=\"text\" id=\"bl-e-c-id\" readonly \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Cargo<\/label><input type=\"text\" id=\"bl-e-c-cargo\" placeholder=\"Pricing Manager\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>\u00c1rea<\/label><input type=\"text\" id=\"bl-e-c-area\" placeholder=\"Operaciones \/ Pricing\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Tel\u00e9fono Directo<\/label><input type=\"text\" id=\"bl-e-c-telefono\" placeholder=\"+40 21 123 4567\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Correo Electr\u00f3nico<\/label><input type=\"email\" id=\"bl-e-c-correo\" placeholder=\"elena@sameday.ro\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Mensajer\u00eda \/ Skype \/ Teams<\/label><input type=\"text\" id=\"bl-e-c-mensajeria\" placeholder=\"live:elena_sameday\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Otros Medios<\/label><input type=\"text\" id=\"bl-e-c-otros\" placeholder=\"WhatsApp: +40 700 000\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Idioma Preferente<\/label><input type=\"text\" id=\"bl-e-c-idioma\" placeholder=\"Ingl\u00e9s \/ Espa\u00f1ol\" \/><\/div>\r\n                        <div class=\"bl-campo\">\r\n                            <label>Estado Contacto<\/label>\r\n                            <select id=\"bl-e-c-estado\">\r\n                                <option value=\"Pendiente de Validaci\u00f3n\">Pendiente de Validaci\u00f3n<\/option>\r\n                                <option value=\"Validado\">Validado<\/option>\r\n                            <\/select>\r\n                        <\/div>\r\n                        <div class=\"bl-campo\"><label>Fecha Validaci\u00f3n<\/label><input type=\"text\" id=\"bl-e-c-fecha-validacion\" readonly \/><\/div>\r\n                    <\/div>\r\n                    <button type=\"button\" id=\"bl-btn-agregar-contacto\" class=\"bl-btn bl-btn-secondary\">+ Agregar a la Lista<\/button>\r\n                    <\/div>\r\n                    <div class=\"bl-bloque2-der\">\r\n                        <div class=\"bl-bloque-subtitulo\" style=\"margin-top:0\">\ud83d\udcc7 Contactos Ingresados<\/div>\r\n                        <div id=\"bl-contactos-lista\" class=\"bl-rutas-lista\">\r\n                            <p class=\"bl-loading\">Sin contactos agregados.<\/p>\r\n                        <\/div>\r\n                    <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <!-- ---------- BLOQUE 2 ---------- -->\r\n                <div class=\"bl-bloque-editar\">\r\n                    <div class=\"bl-bloque-header\"><span class=\"bl-bloque-tag\">BLOQUE 02<\/span> COBERTURA OPERATIVA, NODOS Y SERVICIOS HABILITADOS<\/div>\r\n\r\n                    <div class=\"bl-form-grid\">\r\n                        <div class=\"bl-campo\"><label>C\u00f3digo de Cobertura (RUTA-UUID)<\/label><input type=\"text\" id=\"bl-e-id-ruta\" readonly \/><\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"bl-bloque2-grid\">\r\n                        <div class=\"bl-bloque2-izq\">\r\n                            <div class=\"bl-form-grid\">\r\n                                <div class=\"bl-campo\"><label>Pa\u00eds de Origen Base<\/label><input type=\"text\" id=\"bl-e-pais-origen-base\" readonly \/><\/div>\r\n                                <div class=\"bl-campo bl-campo-ancho\">\r\n                                    <label>Pa\u00eds Cobertura<\/label>\r\n                                    <div class=\"bl-autocomplete-wrap\"><input type=\"text\" id=\"bl-e-pais-cobertura\" placeholder=\"Escribe y selecciona (varios)...\" autocomplete=\"off\" \/><div class=\"bl-autocomplete-dropdown\" id=\"bl-e-pais-cobertura-dropdown\"><\/div><\/div>\r\n                                    <div class=\"bl-tags-wrap\" id=\"bl-e-pais-cobertura-tags\"><\/div>\r\n                                <\/div>\r\n                                <div class=\"bl-campo bl-campo-ancho\">\r\n                                    <label>Ciudad Cobertura<\/label>\r\n                                    <div class=\"bl-autocomplete-wrap\"><input type=\"text\" id=\"bl-e-ciudad-cobertura\" placeholder=\"Escribe y selecciona (varias)...\" autocomplete=\"off\" \/><div class=\"bl-autocomplete-dropdown\" id=\"bl-e-ciudad-cobertura-dropdown\"><\/div><\/div>\r\n                                    <div class=\"bl-tags-wrap\" id=\"bl-e-ciudad-cobertura-tags\"><\/div>\r\n                                <\/div>\r\n                                <div class=\"bl-campo bl-campo-ancho\">\r\n                                    <label>Aeropuertos Operativos<\/label>\r\n                                    <input type=\"text\" id=\"bl-e-aeropuertos\" placeholder=\"Escribe un c\u00f3digo y presiona Enter (ej: SCL)\" \/>\r\n                                    <div class=\"bl-tags-wrap\" id=\"bl-e-aeropuertos-tags\"><\/div>\r\n                                <\/div>\r\n                                <div class=\"bl-campo bl-campo-ancho\">\r\n                                    <label>Puertos Operativos<\/label>\r\n                                    <input type=\"text\" id=\"bl-e-puertos\" placeholder=\"Escribe un c\u00f3digo y presiona Enter (ej: VAP)\" \/>\r\n                                    <div class=\"bl-tags-wrap\" id=\"bl-e-puertos-tags\"><\/div>\r\n                                <\/div>\r\n                                <div class=\"bl-campo bl-campo-ancho\"><label>Especialidad Geogr\u00e1fica<\/label><input type=\"text\" id=\"bl-e-especialidad\" placeholder=\"Ej: Europa del Este & Am\u00e9rica Latina Express\" \/><\/div>\r\n                                <div class=\"bl-campo bl-campo-ancho\">\r\n                                    <label>Rutas Principales (C\u00f3digos)<\/label>\r\n                                    <input type=\"text\" id=\"bl-e-rutas-codigos\" readonly placeholder=\"Se completa solo al marcar servicios en la matriz de abajo\" \/>\r\n                                <\/div>\r\n                                <div class=\"bl-campo\"><label>Exp. en Destino (N\u00b0 Operaciones)<\/label><input type=\"number\" min=\"0\" id=\"bl-e-exp-destino\" placeholder=\"0\" \/><\/div>\r\n                                <div class=\"bl-campo\" style=\"align-self:flex-end\">\r\n                                    <button type=\"button\" id=\"bl-btn-agregar-ruta\" class=\"bl-btn bl-btn-secondary\" style=\"width:100%\">Agregar<\/button>\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"bl-bloque-subtitulo\">\ud83d\udee0 Matriz de Servicios Registrados<\/div>\r\n                            <div class=\"bl-servicios-checklist\" id=\"bl-e-servicios-matriz\">\r\n                                <label><input type=\"checkbox\" data-servicio=\"carga_aerea\" \/> Carga A\u00e9rea<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"carga_maritima_fcl\" \/> Carga Mar\u00edtima FCL<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"carga_maritima_lcl\" \/> Carga Mar\u00edtima LCL<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"carga_terrestre\" \/> Carga Terrestre<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"courier\" \/> Courier<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"retiro_origen\" \/> Retiro en Origen<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"aduana_origen\" \/> Aduana en Origen<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"consolidacion\" \/> Consolidaci\u00f3n<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"almacenaje\" \/> Almacenaje<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"carga_peligrosa\" \/> Carga Peligrosa (IMO)<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"perecibles\" \/> Perecibles<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"carga_sobredimensionada\" \/> Carga Sobredimensionada<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"proyectos_especiales\" \/> Proyectos Especiales<\/label>\r\n                                <label><input type=\"checkbox\" data-servicio=\"servicio_puerta_puerta\" \/> Servicio Puerta a Puerta<\/label>\r\n                            <\/div>\r\n                            <div class=\"bl-campo bl-campo-ancho\" style=\"margin-top:10px\">\r\n                                <label>Otros Servicios<\/label>\r\n                                <input type=\"text\" id=\"bl-e-otros-servicios\" placeholder=\"Describe cualquier servicio adicional no listado arriba\" \/>\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <div class=\"bl-bloque2-der\">\r\n                            <div class=\"bl-bloque-subtitulo\">\ud83d\uddfa Rutas Ingresadas<\/div>\r\n                            <div id=\"bl-rutas-lista\" class=\"bl-rutas-lista\">\r\n                                <p class=\"bl-loading\">Sin rutas agregadas.<\/p>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <!-- ---------- BLOQUE 3 ---------- -->\r\n                <div class=\"bl-bloque-editar\">\r\n                    <div class=\"bl-bloque-header\"><span class=\"bl-bloque-tag\">BLOQUE 03<\/span> INFORMACI\u00d3N COMERCIAL, CR\u00c9DITO Y REDES LOG\u00cdSTICAS<\/div>\r\n                    <div class=\"bl-form-grid\">\r\n                        <div class=\"bl-campo\">\r\n                            <label>\u00bfPosee Cr\u00e9dito?<\/label>\r\n                            <select id=\"bl-e-hay-credito\"><option value=\"NO\">NO<\/option><option value=\"S\u00cd\">S\u00cd<\/option><\/select>\r\n                        <\/div>\r\n                        <div class=\"bl-campo\"><label>L\u00edmite Cr\u00e9dito<\/label><input type=\"number\" min=\"0\" step=\"0.01\" id=\"bl-e-limite-credito\" placeholder=\"0.00\" \/><\/div>\r\n                        <div class=\"bl-campo\">\r\n                            <label>Moneda Cr\u00e9dito<\/label>\r\n                            <select id=\"bl-e-moneda\"><option value=\"EUR\">EUR (\u20ac)<\/option><option value=\"USD\">USD ($)<\/option><option value=\"CLP\">CLP ($)<\/option><\/select>\r\n                        <\/div>\r\n                        <div class=\"bl-campo\"><label>D\u00edas Cr\u00e9dito<\/label><input type=\"number\" min=\"0\" id=\"bl-e-dias-credito\" placeholder=\"0\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Cr\u00e9dito Disponible<\/label><input type=\"number\" min=\"0\" step=\"0.01\" id=\"bl-e-credito-disponible\" placeholder=\"0.00\" \/><\/div>\r\n                        <div class=\"bl-campo\">\r\n                            <label>Cr\u00e9dito Suspendido<\/label>\r\n                            <select id=\"bl-e-credito-suspendido\"><option value=\"NO\">NO<\/option><option value=\"S\u00cd\">S\u00cd<\/option><\/select>\r\n                        <\/div>\r\n                        <div class=\"bl-campo\"><label>Facturas Vencidas<\/label><input type=\"number\" min=\"0\" id=\"bl-e-facturas-vencidas\" placeholder=\"0\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>KPI Cr\u00e9dito (Puntaje)<\/label><input type=\"text\" id=\"bl-e-kpi-credito\" placeholder=\"Ej: A \/ B+ \/ 85\" \/><\/div>\r\n                        <div class=\"bl-campo\">\r\n                            <label>Red Principal<\/label>\r\n                            <select id=\"bl-e-red\">\r\n                                <option value=\"\">\u2014 Sin red \u2014<\/option>\r\n                                <option value=\"WCA World\">WCA World<\/option>\r\n                                <option value=\"JCtrans Network\">JCtrans Network<\/option>\r\n                                <option value=\"IATA Certified\">IATA Certified<\/option>\r\n                                <option value=\"Independiente\">Independiente<\/option>\r\n                            <\/select>\r\n                        <\/div>\r\n                        <div class=\"bl-campo\"><label>Vigencia Membres\u00eda<\/label><input type=\"date\" id=\"bl-e-vigencia-membresia\" \/><\/div>\r\n                        <div class=\"bl-campo\"><label>Garant\u00eda Red ($ USD)<\/label><input type=\"number\" min=\"0\" step=\"0.01\" id=\"bl-e-garantia-red\" placeholder=\"0.00\" title=\"A\u00fan no se persiste en BD \u2014 ver nota en el c\u00f3digo\" \/><\/div>\r\n                        <div class=\"bl-campo\">\r\n                            <label>Acuerdo Bilateral Firmado<\/label>\r\n                            <select id=\"bl-e-acuerdo-bilateral\" title=\"A\u00fan no se persiste en BD \u2014 ver nota en el c\u00f3digo\">\r\n                                <option value=\"NO\">NO<\/option>\r\n                                <option value=\"S\u00cd (Vigente)\">S\u00cd (Vigente)<\/option>\r\n                                <option value=\"En Negociaci\u00f3n\">En Negociaci\u00f3n<\/option>\r\n                            <\/select>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"bl-editar-acciones\">\r\n                    <button type=\"button\" id=\"bl-btn-cancelar-agente\" class=\"bl-btn bl-btn-secondary\">Cancelar<\/button>\r\n                    <button type=\"button\" id=\"bl-btn-guardar-agente\" class=\"bl-btn bl-btn-primary bl-btn-guardar-agente\">Guardar Agente<\/button>\r\n                <\/div>\r\n            <\/form>\r\n        <\/section>\r\n\r\n        <!-- ============ MODAL FICHA DE AGENTE ============ -->\r\n        <div id=\"bl-modal-ficha\" class=\"bl-modal\">\r\n            <div class=\"bl-modal-content bl-modal-ficha-content\">\r\n                <button class=\"bl-modal-close\" id=\"bl-modal-close\">&times;<\/button>\r\n                <div class=\"bl-ficha-header\">\r\n                    <div>\r\n                        <h3 id=\"bl-ficha-titulo\">Agente<\/h3>\r\n                        <div id=\"bl-ficha-subtitulo\" class=\"bl-ficha-subtitulo\"><\/div>\r\n                    <\/div>\r\n                    <div class=\"bl-ficha-header-acciones\">\r\n                        <button type=\"button\" id=\"bl-btn-editar-ficha\" class=\"bl-btn bl-btn-secondary\">\u270e Editar Ficha<\/button>\r\n                        <div class=\"bl-export-wrap\">\r\n                            <button type=\"button\" id=\"bl-btn-exportar-ficha\" class=\"bl-btn bl-btn-secondary\">\u2b07 Exportar<\/button>\r\n                            <div class=\"bl-export-menu\" id=\"bl-export-menu\">\r\n                                <button type=\"button\" disabled title=\"Pr\u00f3ximamente\">PDF<\/button>\r\n                                <button type=\"button\" disabled title=\"Pr\u00f3ximamente\">Excel<\/button>\r\n                                <button type=\"button\" disabled title=\"Pr\u00f3ximamente\">PowerPoint<\/button>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n                <div class=\"bl-ficha-tabs\">\r\n                    <button class=\"bl-ficha-tab is-active\" data-ficha-tab=\"generales\">Datos Generales y Contactos<\/button>\r\n                    <button class=\"bl-ficha-tab\" data-ficha-tab=\"cobertura\">Cobertura, Rutas y Servicios<\/button>\r\n                    <button class=\"bl-ficha-tab\" data-ficha-tab=\"comercial\">Info Comercial y Cr\u00e9dito<\/button>\r\n                    <button class=\"bl-ficha-tab\" data-ficha-tab=\"evaluacion\">Evaluaci\u00f3n y Ranking<\/button>\r\n                    <button class=\"bl-ficha-tab\" data-ficha-tab=\"auditoria\">Auditor\u00eda y Logs<\/button>\r\n                <\/div>\r\n                <div id=\"bl-modal-body\"><p class=\"bl-loading\">Cargando ficha\u2026<\/p><\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n    <\/div>\r\n\r\n    <style>\r\n        .bl-core-app { font-family: -apple-system, \"Segoe UI\", Roboto, Arial, sans-serif; color: #1f2937; max-width: 1400px; margin: 0 auto; }\r\n        .bl-core-app * { box-sizing: border-box; }\r\n\r\n        .bl-nav { display: flex; align-items: center; justify-content: space-between; background: #0f2c4c; color: #fff; padding: 14px 20px; border-radius: 8px 8px 0 0; flex-wrap: wrap; gap: 10px; }\r\n        .bl-nav-brand { font-weight: 700; font-size: 18px; letter-spacing: .3px; }\r\n        .bl-nav-tabs { display: flex; gap: 6px; }\r\n        .bl-nav-tab { background: transparent; border: 1px solid rgba(255,255,255,.25); color: #fff; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 14px; transition: background .15s ease; }\r\n        .bl-nav-tab:hover { background: rgba(255,255,255,.12); }\r\n        .bl-nav-tab.is-active { background: #2563eb; border-color: #2563eb; }\r\n\r\n        .bl-module { display: none; padding: 20px; border: 1px solid #e5e7eb; border-top: none; border-radius: 0 0 8px 8px; background: #f9fafb; }\r\n        .bl-module.is-active { display: block; }\r\n\r\n        .bl-buscador-grid { display: grid; grid-template-columns: 260px 1fr 260px; gap: 18px; align-items: start; }\r\n        @media (max-width: 1000px) { .bl-buscador-grid { grid-template-columns: 1fr; } }\r\n\r\n        .bl-col { background: #fff; border: 1px solid #e5e7eb; border-radius: 8px; padding: 16px; }\r\n        .bl-col h3 { margin-top: 0; font-size: 15px; color: #0f2c4c; }\r\n        .bl-col-form label { display: block; font-size: 12px; font-weight: 600; color: #6b7280; margin: 12px 0 4px; }\r\n        .bl-col-form input, .bl-col-form select { width: 100%; padding: 8px 10px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; }\r\n        .bl-inline-fields { display: flex; gap: 8px; }\r\n        .bl-inline-fields select { max-width: 110px; }\r\n        .bl-campo-volumen { margin-top: 8px; }\r\n\r\n        .bl-check-label { display: flex !important; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: #6b7280; margin: 12px 0 4px; cursor: pointer; }\r\n        .bl-check-label input { width: auto !important; }\r\n\r\n        .bl-autocomplete-wrap { position: relative; }\r\n        .bl-autocomplete-dropdown { position: absolute; top: calc(100% + 2px); left: 0; right: 0; background: #fff; border: 1px solid #d1d5db; border-radius: 6px; max-height: 190px; overflow-y: auto; z-index: 60; display: none; box-shadow: 0 6px 16px rgba(15,44,76,.12); }\r\n        .bl-autocomplete-dropdown.is-open { display: block; }\r\n        .bl-autocomplete-item { padding: 7px 10px; font-size: 13px; cursor: pointer; }\r\n        .bl-autocomplete-item:hover, .bl-autocomplete-item.is-highlighted { background: #eef2f7; }\r\n        .bl-autocomplete-empty { padding: 8px 10px; font-size: 12px; color: #9ca3af; }\r\n\r\n        .bl-tags-wrap { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }\r\n        .bl-tag { background: #dbeafe; color: #1e3a8a; padding: 4px 8px; border-radius: 999px; font-size: 12px; display: flex; align-items: center; gap: 6px; font-weight: 600; }\r\n        .bl-tag button { background: none; border: none; cursor: pointer; color: #1e3a8a; font-weight: 800; font-size: 13px; line-height: 1; padding: 0; }\r\n\r\n        .bl-btn { border: none; border-radius: 6px; padding: 9px 16px; font-size: 13px; cursor: pointer; font-weight: 600; }\r\n        .bl-btn-primary { background: #2563eb; color: #fff; width: 100%; margin-top: 16px; }\r\n        .bl-btn-primary:hover { background: #1d4ed8; }\r\n        .bl-btn-secondary { background: #eef2f7; color: #1f2937; border: 1px solid #d1d5db; }\r\n        .bl-btn-secondary.is-active { background: #2563eb; color: #fff; border-color: #2563eb; }\r\n        .bl-btn:disabled { opacity: .5; cursor: not-allowed; }\r\n\r\n        .bl-resultados-header { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }\r\n        .bl-contadores { display: flex; gap: 14px; font-size: 12px; font-weight: 700; color: #0f2c4c; }\r\n        .bl-resultados-acciones { display: flex; gap: 8px; }\r\n\r\n        .bl-tabla-resultados { width: 100%; border-collapse: collapse; font-size: 13px; }\r\n        .bl-tabla-resultados th { text-align: left; background: #eef2f7; padding: 8px; font-size: 11px; text-transform: uppercase; color: #6b7280; }\r\n        .bl-tabla-resultados td { padding: 8px; border-bottom: 1px solid #f0f0f0; vertical-align: middle; }\r\n        .bl-empty-row td { text-align: center; color: #9ca3af; padding: 30px 8px; }\r\n        .bl-score-pill { display: inline-block; background: #dcfce7; color: #166534; font-weight: 700; padding: 3px 8px; border-radius: 999px; font-size: 12px; }\r\n        .bl-fila-acciones { display: flex; gap: 6px; }\r\n        .bl-fila-acciones button { padding: 5px 9px; font-size: 12px; }\r\n\r\n        .bl-mapa-placeholder { display: flex; flex-direction: column; gap: 12px; align-items: center; text-align: center; }\r\n        .bl-mapa-punto { width: 100%; background: #eef2f7; border-radius: 8px; padding: 10px; }\r\n        .bl-mapa-label { display: block; font-size: 10px; font-weight: 700; color: #6b7280; }\r\n        .bl-mapa-valor { display: block; font-size: 15px; font-weight: 700; color: #0f2c4c; margin-top: 3px; }\r\n        .bl-mapa-origen { border-left: 4px solid #2563eb; }\r\n        .bl-mapa-destino { border-left: 4px solid #16a34a; }\r\n        .bl-mapa-linea { font-size: 20px; }\r\n        .bl-mapa-nota { font-size: 11px; color: #9ca3af; margin-top: 8px; }\r\n\r\n        .bl-agentes-header { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }\r\n        .bl-agentes-header input { flex: 1; min-width: 220px; padding: 9px 12px; border: 1px solid #d1d5db; border-radius: 6px; }\r\n        .bl-vista-switch { display: flex; gap: 6px; }\r\n\r\n        .bl-filtros-avanzados-panel { display: none; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; background: #fff; border: 1px solid #e5e7eb; border-radius: 8px; padding: 14px; margin-bottom: 14px; }\r\n        .bl-filtros-avanzados-panel.is-open { display: grid; }\r\n        .bl-filtro-campo label { display: block; font-size: 11px; font-weight: 700; color: #6b7280; margin-bottom: 5px; text-transform: uppercase; }\r\n        .bl-filtro-campo input { width: 100%; padding: 8px 10px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 13px; }\r\n\r\n        .bl-agentes-acciones { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }\r\n        .bl-resultado-busqueda-texto { font-size: 13px; font-weight: 700; color: #0f2c4c; margin: 4px 0 14px; }\r\n\r\n        .bl-tabla-agentes { width: 100%; border-collapse: collapse; background: #fff; font-size: 13px; }\r\n        .bl-tabla-agentes th { text-align: left; background: #eef2f7; padding: 8px; font-size: 11px; text-transform: uppercase; color: #6b7280; }\r\n        .bl-tabla-agentes td { padding: 8px; border-bottom: 1px solid #f0f0f0; }\r\n\r\n        .bl-bloques-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }\r\n        .bl-bloque-agente { background: #fff; border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; }\r\n        .bl-bloque-agente h4 { margin: 0 0 6px; font-size: 14px; color: #0f2c4c; }\r\n        .bl-bloque-agente p { margin: 2px 0; font-size: 12px; color: #6b7280; }\r\n\r\n        .bl-kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px; margin-bottom: 20px; }\r\n        .bl-kpi-card { background: #fff; border: 1px solid #e5e7eb; border-radius: 8px; padding: 16px; }\r\n        .bl-kpi-card .bl-kpi-valor { font-size: 26px; font-weight: 800; color: #0f2c4c; }\r\n        .bl-kpi-card .bl-kpi-label { font-size: 12px; color: #6b7280; margin-top: 4px; }\r\n\r\n        .bl-dashboard-charts { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\r\n        @media (max-width: 900px) { .bl-dashboard-charts { grid-template-columns: 1fr; } }\r\n        .bl-chart-card { background: #fff; border: 1px solid #e5e7eb; border-radius: 8px; padding: 16px; }\r\n        .bl-chart-card h4 { margin-top: 0; font-size: 14px; color: #0f2c4c; }\r\n        .bl-bar-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 12px; }\r\n        .bl-bar-row .bl-bar-label { width: 110px; flex-shrink: 0; color: #374151; }\r\n        .bl-bar-row .bl-bar-track { flex: 1; background: #eef2f7; border-radius: 4px; overflow: hidden; height: 14px; }\r\n        .bl-bar-row .bl-bar-fill { background: #2563eb; height: 100%; }\r\n        .bl-bar-row .bl-bar-valor { width: 34px; text-align: right; font-weight: 700; color: #0f2c4c; }\r\n\r\n        .bl-loading { color: #9ca3af; font-size: 13px; padding: 20px 0; }\r\n\r\n        .bl-modal { display: none; position: fixed; inset: 0; background: rgba(15,44,76,.55); z-index: 9999; align-items: center; justify-content: center; }\r\n        .bl-modal.is-open { display: flex; }\r\n        .bl-modal-content { background: #fff; border-radius: 10px; width: min(560px, 92vw); max-height: 85vh; overflow-y: auto; padding: 22px; position: relative; }\r\n        .bl-modal-close { position: absolute; top: 10px; right: 14px; border: none; background: none; font-size: 22px; cursor: pointer; color: #6b7280; z-index: 5; }\r\n        .bl-ficha-info h3 { margin-top: 0; color: #0f2c4c; }\r\n        .bl-ficha-seccion { margin-top: 16px; }\r\n        .bl-ficha-seccion h4 { font-size: 12px; text-transform: uppercase; color: #6b7280; margin-bottom: 6px; }\r\n        .bl-ficha-seccion table { width: 100%; font-size: 13px; }\r\n        .bl-ficha-seccion td { padding: 3px 0; }\r\n\r\n        \/* ---------- FICHA: cabecera con acciones + pesta\u00f1as (v8.0) ---------- *\/\r\n        .bl-modal-ficha-content { width: min(900px, 94vw); padding: 22px 22px 26px; }\r\n        .bl-ficha-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; padding-right: 26px; flex-wrap: wrap; }\r\n        .bl-ficha-header h3 { margin: 0; color: #0f2c4c; font-size: 19px; }\r\n        .bl-ficha-subtitulo { font-size: 12px; color: #6b7280; margin-top: 3px; }\r\n        .bl-ficha-header-acciones { display: flex; gap: 8px; }\r\n        .bl-export-wrap { position: relative; }\r\n        .bl-export-menu { display: none; position: absolute; top: calc(100% + 4px); right: 0; background: #fff; border: 1px solid #d1d5db; border-radius: 6px; box-shadow: 0 6px 16px rgba(15,44,76,.15); z-index: 20; min-width: 140px; overflow: hidden; }\r\n        .bl-export-menu.is-open { display: block; }\r\n        .bl-export-menu button { display: block; width: 100%; text-align: left; padding: 8px 12px; border: none; background: #fff; font-size: 13px; cursor: not-allowed; color: #9ca3af; }\r\n        .bl-ficha-tabs { display: flex; gap: 4px; flex-wrap: wrap; border-bottom: 1px solid #e5e7eb; margin: 16px 0 14px; }\r\n        .bl-ficha-tab { background: transparent; border: none; border-bottom: 2px solid transparent; padding: 8px 10px; font-size: 12px; font-weight: 700; color: #6b7280; cursor: pointer; }\r\n        .bl-ficha-tab.is-active { color: #2563eb; border-bottom-color: #2563eb; }\r\n        .bl-ficha-panel { display: none; }\r\n        .bl-ficha-panel.is-active { display: block; }\r\n        .bl-contacto-card { border: 1px solid #f0f0f0; border-radius: 6px; padding: 10px; margin-bottom: 8px; }\r\n        .bl-contacto-card-acciones { display: flex; gap: 6px; margin-top: 6px; }\r\n        .bl-contacto-card-acciones a { font-size: 11px; padding: 4px 8px; border-radius: 5px; background: #eef2f7; color: #1f2937; text-decoration: none; font-weight: 600; }\r\n        .bl-contacto-card-acciones a:hover { background: #dbeafe; }\r\n        .bl-info-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 14px; }\r\n        .bl-info-card { background: #eef2f7; border-radius: 8px; padding: 10px 12px; border-left: 3px solid #2563eb; }\r\n        .bl-info-card .bl-info-card-label { font-size: 10px; font-weight: 700; text-transform: uppercase; color: #6b7280; }\r\n        .bl-info-card .bl-info-card-valor { font-size: 14px; font-weight: 700; color: #0f2c4c; margin-top: 2px; }\r\n\r\n        \/* ---------- FICHA DE REGISTRO Y EDICI\u00d3N (v8.0) ---------- *\/\r\n        .bl-module-editar .bl-editar-volver { display: inline-block; margin-bottom: 10px; font-size: 13px; color: #2563eb; text-decoration: none; font-weight: 600; }\r\n        .bl-editar-titulo { margin: 4px 0 2px; color: #0f2c4c; font-size: 22px; }\r\n        .bl-editar-subtitulo { margin: 0 0 18px; font-size: 13px; color: #6b7280; }\r\n        .bl-bloque-editar { background: #fff; border: 1px solid #e5e7eb; border-radius: 8px; padding: 18px; margin-bottom: 18px; }\r\n        .bl-bloque-header { font-size: 14px; font-weight: 700; color: #0f2c4c; display: flex; align-items: center; gap: 10px; padding-bottom: 12px; margin-bottom: 14px; border-bottom: 1px solid #f0f0f0; }\r\n        .bl-bloque-tag { background: #0f2c4c; color: #fff; font-size: 10px; padding: 3px 8px; border-radius: 4px; letter-spacing: .4px; }\r\n        .bl-bloque-subtitulo { font-size: 12px; font-weight: 700; color: #6b7280; text-transform: uppercase; margin: 18px 0 10px; padding-top: 12px; border-top: 1px dashed #e5e7eb; }\r\n        .bl-form-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }\r\n        @media (max-width: 1100px) { .bl-form-grid { grid-template-columns: repeat(2, 1fr); } }\r\n        .bl-campo label { display: block; font-size: 11px; font-weight: 700; color: #6b7280; text-transform: uppercase; margin-bottom: 5px; }\r\n        .bl-campo input, .bl-campo select { width: 100%; padding: 8px 10px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 13px; background: #fff; }\r\n        .bl-campo input[readonly] { background: #f3f4f6; color: #6b7280; }\r\n        .bl-campo-ancho { grid-column: span 2; }\r\n        .bl-contacto-selector { display: flex; gap: 8px; align-items: flex-start; margin-bottom: 14px; flex-wrap: wrap; }\r\n        .bl-bloque2-grid { display: grid; grid-template-columns: 3fr 1fr; gap: 18px; align-items: start; }\r\n        @media (max-width: 1000px) { .bl-bloque2-grid { grid-template-columns: 1fr; } }\r\n        .bl-servicios-checklist { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }\r\n        @media (max-width: 700px) { .bl-servicios-checklist { grid-template-columns: repeat(2, 1fr); } }\r\n        .bl-servicios-checklist label { display: flex; align-items: center; gap: 6px; font-size: 12px; background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 6px; padding: 7px 9px; cursor: pointer; }\r\n        .bl-servicios-checklist input { width: auto; }\r\n        .bl-ruta-form { margin-bottom: 12px; }\r\n        .bl-rutas-lista { max-height: 420px; overflow-y: auto; }\r\n        .bl-ruta-card { background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; padding: 10px; margin-bottom: 10px; font-size: 12px; }\r\n        .bl-ruta-card .bl-ruta-codigo { font-weight: 700; color: #0f2c4c; font-size: 12px; background: #dbeafe; display: inline-block; padding: 2px 7px; border-radius: 4px; margin-bottom: 5px; }\r\n        .bl-ruta-card .bl-ruta-trayecto { font-weight: 600; margin: 4px 0; }\r\n        .bl-ruta-card .bl-ruta-servicios { color: #6b7280; }\r\n        .bl-ruta-card button { margin-top: 6px; margin-right: 6px; background: #fee2e2; color: #991b1b; border: none; border-radius: 5px; padding: 4px 8px; font-size: 11px; cursor: pointer; font-weight: 600; }\r\n        .bl-ruta-card button.bl-contacto-editar { background: #dbeafe; color: #1e40af; }\r\n        .bl-editar-acciones { display: flex; justify-content: flex-end; gap: 10px; margin-top: 6px; }\r\n        .bl-editar-acciones .bl-btn { padding: 11px 22px; }\r\n    <\/style>\r\n\r\n    <script>\r\n    (function () {\r\n        var app = document.getElementById('bl-core-app');\r\n        if (!app) return;\r\n\r\n        var AJAX_URL = app.getAttribute('data-ajax-url');\r\n        var NONCE = app.getAttribute('data-nonce');\r\n        var seleccionadosSet = new Set();\r\n        var ultimosResultados = [];\r\n\r\n        function postAjax(action, params) {\r\n            var body = new URLSearchParams(Object.assign({ action: action, nonce: NONCE }, params || {}));\r\n            return fetch(AJAX_URL, {\r\n                method: 'POST',\r\n                headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n                body: body.toString()\r\n            }).then(function (r) { return r.json(); });\r\n        }\r\n\r\n        \/* ---------- COMPONENTE GEN\u00c9RICO: COMBO AUTOCOMPLETABLE (nuevo v7.0) ----------\r\n         * Se usa en Origen \/ Destino \/ Tipo de Carga (Buscador) y en los 6 filtros\r\n         * avanzados del Directorio de Agentes. El usuario puede escribir libremente\r\n         * (texto libre) o elegir de la lista desplegable, que se filtra en vivo a\r\n         * medida que escribe. Fuente de datos: AJAX real (bl_autocomplete_valores)\r\n         * o una lista est\u00e1tica en el propio JS, seg\u00fan el campo. *\/\r\n        function normalizarOpcion(o) {\r\n            return (typeof o === 'string') ? { label: o, valor: o } : o;\r\n        }\r\n\r\n        function crearAutocomplete(input, dropdown, config) {\r\n            config = config || {};\r\n            var timer;\r\n\r\n            function pintarLista(opciones) {\r\n                var lista = (opciones || []).map(normalizarOpcion);\r\n                if (!lista.length) {\r\n                    dropdown.innerHTML = '<div class=\"bl-autocomplete-empty\">Sin coincidencias<\/div>';\r\n                    dropdown.classList.add('is-open');\r\n                    return;\r\n                }\r\n                dropdown.innerHTML = lista.map(function (o) {\r\n                    return '<div class=\"bl-autocomplete-item\" data-valor=\"' + o.valor + '\" data-label=\"' + o.label + '\">' + o.label + '<\/div>';\r\n                }).join('');\r\n                dropdown.classList.add('is-open');\r\n                dropdown.querySelectorAll('.bl-autocomplete-item').forEach(function (item) {\r\n                    item.addEventListener('mousedown', function (e) {\r\n                        e.preventDefault();\r\n                        var valor = item.getAttribute('data-valor');\r\n                        var label = item.getAttribute('data-label');\r\n                        input.value = label;\r\n                        input.dataset.valor = valor;\r\n                        dropdown.classList.remove('is-open');\r\n                        if (config.onSelect) config.onSelect(valor, label);\r\n                    });\r\n                });\r\n            }\r\n\r\n            function buscar() {\r\n                var texto = input.value.trim();\r\n                if (config.ajaxCampo) {\r\n                    postAjax('bl_autocomplete_valores', { campo: config.ajaxCampo, texto: texto }).then(function (res) {\r\n                        pintarLista(res.success ? res.data.valores : []);\r\n                    });\r\n                } else if (config.valoresEstaticos) {\r\n                    var textoLower = texto.toLowerCase();\r\n                    var filtrados = config.valoresEstaticos.map(normalizarOpcion).filter(function (o) {\r\n                        return o.label.toLowerCase().indexOf(textoLower) !== -1;\r\n                    });\r\n                    pintarLista(filtrados);\r\n                }\r\n            }\r\n\r\n            input.addEventListener('input', function () {\r\n                delete input.dataset.valor;\r\n                clearTimeout(timer);\r\n                timer = setTimeout(buscar, 220);\r\n                if (config.onInput) config.onInput(input.value);\r\n            });\r\n            input.addEventListener('focus', buscar);\r\n            document.addEventListener('click', function (e) {\r\n                if (e.target !== input && !dropdown.contains(e.target)) {\r\n                    dropdown.classList.remove('is-open');\r\n                }\r\n            });\r\n        }\r\n\r\n        var TIPOS_CARGA_SUGERIDOS = ['General', 'Refrigerada', 'Peligrosa (IMO\/DGR)', 'Perecedera', 'Carga Suelta', 'Sobredimensionada', 'L\u00edquidos a Granel', 'Alto Valor', 'Textil', 'Electr\u00f3nica'];\r\n        var SERVICIOS_SUGERIDOS = ['A\u00e9reo Expr\u00e9s', 'FCL', 'LCL', 'Almacenaje', 'Agenciamiento Aduanero', '\u00daltima Milla', 'Carga Refrigerada', 'Carga Peligrosa'];\r\n        var LIMITE_CREDITO_OPCIONES = [\r\n            { label: 'Menor a 5.000 USD', valor: 'lt5000' },\r\n            { label: '5.000 - 20.000 USD', valor: 'e5000_20000' },\r\n            { label: '20.000 - 50.000 USD', valor: 'e20000_50000' },\r\n            { label: 'Mayor a 50.000 USD', valor: 'gt50000' }\r\n        ];\r\n        var RANKING_MINIMO_OPCIONES = [\r\n            { label: '60 o m\u00e1s', valor: '60' },\r\n            { label: '70 o m\u00e1s', valor: '70' },\r\n            { label: '80 o m\u00e1s', valor: '80' },\r\n            { label: '90 o m\u00e1s', valor: '90' }\r\n        ];\r\n\r\n        \/* ---------- NAV TABS ---------- *\/\r\n        var tabs = app.querySelectorAll('.bl-nav-tab');\r\n        var ultimoModuloVisible = 'buscador';\r\n\r\n        \/\/ Funci\u00f3n gen\u00e9rica de cambio de m\u00f3dulo (nueva v8.0): la usan tanto los tabs\r\n        \/\/ superiores como \"Editar Ficha\" \/ \"+ Agente\" \/ \"Volver\" \/ \"Cancelar\" para\r\n        \/\/ abrir el panel oculto de Ficha de Registro y Edici\u00f3n de Agente.\r\n        function mostrarModulo(nombre) {\r\n            tabs.forEach(function (t) { t.classList.toggle('is-active', t.getAttribute('data-module') === nombre); });\r\n            app.querySelectorAll('.bl-module').forEach(function (panel) {\r\n                panel.classList.toggle('is-active', panel.getAttribute('data-module-panel') === nombre);\r\n            });\r\n            if (nombre !== 'editar') { ultimoModuloVisible = nombre; }\r\n            if (nombre === 'agentes' && !app.dataset.agentesCargado) { cargarAgentes(); }\r\n            if (nombre === 'dashboard' && !app.dataset.dashboardCargado) { cargarDashboard(); }\r\n        }\r\n\r\n        tabs.forEach(function (tab) {\r\n            tab.addEventListener('click', function () {\r\n                mostrarModulo(tab.getAttribute('data-module'));\r\n            });\r\n        });\r\n\r\n        \/* ---------- M\u00d3DULO BUSCADOR ---------- *\/\r\n        var btnEjecutar = document.getElementById('bl-btn-ejecutar');\r\n        var tbody = document.getElementById('bl-resultados-body');\r\n        var countSugeridos = document.getElementById('bl-count-sugeridos');\r\n        var countSeleccionados = document.getElementById('bl-count-seleccionados');\r\n        var btnSeleccionarTodos = document.getElementById('bl-btn-seleccionar-todos');\r\n\r\n        \/\/ Origen \/ Destino: combo autocompletable con datos reales (distinct de agentes.pais).\r\n        crearAutocomplete(document.getElementById('bl-f-origen'), document.getElementById('bl-f-origen-dropdown'), { ajaxCampo: 'pais' });\r\n        crearAutocomplete(document.getElementById('bl-f-destino'), document.getElementById('bl-f-destino-dropdown'), { ajaxCampo: 'pais' });\r\n\r\n        \/\/ Volumen\/Contenedor: campo opcional, se muestra al marcar el checkbox.\r\n        var chkVolumen = document.getElementById('bl-f-toggle-volumen');\r\n        var campoVolumen = document.getElementById('bl-campo-volumen');\r\n        chkVolumen.addEventListener('change', function () {\r\n            campoVolumen.hidden = !chkVolumen.checked;\r\n        });\r\n\r\n        \/\/ Tipo de Carga: combo autocompletable + selecci\u00f3n M\u00daLTIPLE en forma de tags.\r\n        var tiposCargaSeleccionados = [];\r\n        var tipoCargaInput = document.getElementById('bl-f-tipo-carga');\r\n        var tipoCargaTagsWrap = document.getElementById('bl-f-tipo-carga-tags');\r\n\r\n        function pintarTagsTipoCarga() {\r\n            tipoCargaTagsWrap.innerHTML = tiposCargaSeleccionados.map(function (t) {\r\n                return '<span class=\"bl-tag\">' + t + '<button type=\"button\" data-tag=\"' + t + '\">&times;<\/button><\/span>';\r\n            }).join('');\r\n            tipoCargaTagsWrap.querySelectorAll('button').forEach(function (btn) {\r\n                btn.addEventListener('click', function () {\r\n                    var tag = btn.getAttribute('data-tag');\r\n                    tiposCargaSeleccionados = tiposCargaSeleccionados.filter(function (t) { return t !== tag; });\r\n                    pintarTagsTipoCarga();\r\n                });\r\n            });\r\n        }\r\n\r\n        function agregarTipoCarga(valor) {\r\n            var v = (valor || '').trim();\r\n            if (v === '' || tiposCargaSeleccionados.indexOf(v) !== -1) return;\r\n            tiposCargaSeleccionados.push(v);\r\n            pintarTagsTipoCarga();\r\n            tipoCargaInput.value = '';\r\n        }\r\n\r\n        crearAutocomplete(tipoCargaInput, document.getElementById('bl-f-tipo-carga-dropdown'), {\r\n            valoresEstaticos: TIPOS_CARGA_SUGERIDOS,\r\n            onSelect: function (valor) { agregarTipoCarga(valor); }\r\n        });\r\n        tipoCargaInput.addEventListener('keydown', function (e) {\r\n            if (e.key === 'Enter') { e.preventDefault(); agregarTipoCarga(tipoCargaInput.value); }\r\n        });\r\n\r\n        function actualizarContadores() {\r\n            countSeleccionados.textContent = seleccionadosSet.size + ' AGENTES SELECCIONADOS';\r\n        }\r\n\r\n        function marcarBotonFila(btn, activo) {\r\n            btn.classList.toggle('is-active', activo);\r\n            btn.textContent = activo ? 'Seleccionado' : 'Seleccionar';\r\n        }\r\n\r\n        function marcarBotonMaster(activo) {\r\n            btnSeleccionarTodos.classList.toggle('is-active', activo);\r\n            btnSeleccionarTodos.textContent = activo ? 'Todos Seleccionados' : 'Seleccionar Todos';\r\n        }\r\n\r\n        function sincronizarBotonMaster() {\r\n            var total = ultimosResultados.length;\r\n            marcarBotonMaster(total > 0 && seleccionadosSet.size === total);\r\n        }\r\n\r\n        function pintarResultados(agentes) {\r\n            ultimosResultados = agentes;\r\n            seleccionadosSet = new Set();\r\n            countSugeridos.textContent = 'MOSTRANDO ' + agentes.length + ' SUGERIDOS';\r\n            actualizarContadores();\r\n            marcarBotonMaster(false);\r\n\r\n            if (!agentes.length) {\r\n                tbody.innerHTML = '<tr class=\"bl-empty-row\"><td colspan=\"6\">No se encontraron agentes para los par\u00e1metros ingresados.<\/td><\/tr>';\r\n                return;\r\n            }\r\n\r\n            tbody.innerHTML = agentes.map(function (a, idx) {\r\n                return '' +\r\n                    '<tr>' +\r\n                        '<td>' + (idx + 1) + '<\/td>' +\r\n                        '<td><code>' + a.id + '<\/code><\/td>' +\r\n                        '<td>' + (a.nombre || '\u2014') + '<\/td>' +\r\n                        '<td><span class=\"bl-score-pill\">' + a.score + '<\/span><\/td>' +\r\n                        '<td>' + a.contratos + '<\/td>' +\r\n                        '<td class=\"bl-fila-acciones\">' +\r\n                            '<button class=\"bl-btn bl-btn-secondary bl-btn-seleccionar\" data-id=\"' + a.id + '\">Seleccionar<\/button>' +\r\n                            '<button class=\"bl-btn bl-btn-secondary bl-btn-ficha\" data-id=\"' + a.id + '\">Ver Ficha<\/button>' +\r\n                        '<\/td>' +\r\n                    '<\/tr>';\r\n            }).join('');\r\n\r\n            tbody.querySelectorAll('.bl-btn-seleccionar').forEach(function (btn) {\r\n                btn.addEventListener('click', function () {\r\n                    var id = btn.getAttribute('data-id');\r\n                    var yaSeleccionado = btn.classList.contains('is-active');\r\n                    if (yaSeleccionado) { seleccionadosSet.delete(id); } else { seleccionadosSet.add(id); }\r\n                    marcarBotonFila(btn, !yaSeleccionado);\r\n                    actualizarContadores();\r\n                    sincronizarBotonMaster();\r\n                });\r\n            });\r\n            tbody.querySelectorAll('.bl-btn-ficha').forEach(function (btn) {\r\n                btn.addEventListener('click', function () {\r\n                    abrirFicha(btn.getAttribute('data-id'));\r\n                });\r\n            });\r\n        }\r\n\r\n        btnEjecutar.addEventListener('click', function () {\r\n            var origen = document.getElementById('bl-f-origen').value.trim();\r\n            var destino = document.getElementById('bl-f-destino').value.trim();\r\n\r\n            document.getElementById('bl-mapa-origen-valor').textContent = origen || '\u2014';\r\n            document.getElementById('bl-mapa-destino-valor').textContent = destino || '\u2014';\r\n\r\n            tbody.innerHTML = '<tr class=\"bl-empty-row\"><td colspan=\"6\">Buscando agentes recomendados\u2026<\/td><\/tr>';\r\n\r\n            postAjax('bl_buscar_agentes', {\r\n                origen: origen,\r\n                destino: destino,\r\n                modalidad: document.getElementById('bl-f-modalidad').value,\r\n                peso: document.getElementById('bl-f-peso').value,\r\n                unidad_peso: document.getElementById('bl-f-unidad-peso').value,\r\n                volumen: chkVolumen.checked ? document.getElementById('bl-f-volumen').value : '',\r\n                unidad_volumen: chkVolumen.checked ? document.getElementById('bl-f-unidad-volumen').value : '',\r\n                tipo_carga: tiposCargaSeleccionados.join(',')\r\n            }).then(function (res) {\r\n                if (res.success) {\r\n                    pintarResultados(res.data.agentes);\r\n                } else {\r\n                    tbody.innerHTML = '<tr class=\"bl-empty-row\"><td colspan=\"6\">Ocurri\u00f3 un error al buscar agentes.<\/td><\/tr>';\r\n                }\r\n            }).catch(function () {\r\n                tbody.innerHTML = '<tr class=\"bl-empty-row\"><td colspan=\"6\">Error de conexi\u00f3n.<\/td><\/tr>';\r\n            });\r\n        });\r\n\r\n        btnSeleccionarTodos.addEventListener('click', function () {\r\n            var estaTodoSeleccionado = btnSeleccionarTodos.classList.contains('is-active');\r\n            if (!estaTodoSeleccionado) {\r\n                ultimosResultados.forEach(function (a) { seleccionadosSet.add(a.id); });\r\n                tbody.querySelectorAll('.bl-btn-seleccionar').forEach(function (btn) { marcarBotonFila(btn, true); });\r\n                marcarBotonMaster(true);\r\n            } else {\r\n                seleccionadosSet.clear();\r\n                tbody.querySelectorAll('.bl-btn-seleccionar').forEach(function (btn) { marcarBotonFila(btn, false); });\r\n                marcarBotonMaster(false);\r\n            }\r\n            actualizarContadores();\r\n        });\r\n\r\n        \/* ---------- FICHA (MODAL) \u2014 con pesta\u00f1as, Editar Ficha y Exportar (v8.0) ---------- *\/\r\n        var modal = document.getElementById('bl-modal-ficha');\r\n        var modalBody = document.getElementById('bl-modal-body');\r\n        var fichaTituloEl = document.getElementById('bl-ficha-titulo');\r\n        var fichaSubtituloEl = document.getElementById('bl-ficha-subtitulo');\r\n        var fichaIdActual = null;\r\n\r\n        document.getElementById('bl-modal-close').addEventListener('click', function () {\r\n            modal.classList.remove('is-open');\r\n        });\r\n        modal.addEventListener('click', function (e) {\r\n            if (e.target === modal) modal.classList.remove('is-open');\r\n        });\r\n\r\n        \/\/ Men\u00fa \"Exportar\" (PDF\/Excel\/PowerPoint deshabilitados por ahora \u2014 solo la interfaz).\r\n        var exportBtn = document.getElementById('bl-btn-exportar-ficha');\r\n        var exportMenu = document.getElementById('bl-export-menu');\r\n        exportBtn.addEventListener('click', function (e) {\r\n            e.stopPropagation();\r\n            exportMenu.classList.toggle('is-open');\r\n        });\r\n        document.addEventListener('click', function () { exportMenu.classList.remove('is-open'); });\r\n\r\n        document.getElementById('bl-btn-editar-ficha').addEventListener('click', function () {\r\n            if (!fichaIdActual) return;\r\n            modal.classList.remove('is-open');\r\n            abrirFormularioEdicion(fichaIdActual);\r\n        });\r\n\r\n        function whatsappHref(telefono) {\r\n            var limpio = (telefono || '').replace(\/[^\\d+]\/g, '');\r\n            return limpio ? ('https:\/\/wa.me\/' + limpio.replace('+', '')) : '';\r\n        }\r\n\r\n        function renderTabGenerales(d) {\r\n            var html = '<div class=\"bl-ficha-seccion\"><h4>Contactos (' + (d.contactos ? d.contactos.length : 0) + ')<\/h4>';\r\n            if (!d.contactos || !d.contactos.length) {\r\n                html += '<p class=\"bl-loading\">Sin contactos registrados.<\/p>';\r\n            }\r\n            (d.contactos || []).forEach(function (c) {\r\n                html += '<div class=\"bl-contacto-card\">' +\r\n                    '<strong>' + (c.Nombre_Contacto || '\u2014') + '<\/strong> \u2014 ' + (c.cargo || '') +\r\n                    '<div>' + (c.area || '') + '<\/div>' +\r\n                    '<div>' + (c.telefono || '') + ' \u00b7 ' + (c.correo || '') + '<\/div>' +\r\n                    '<div class=\"bl-contacto-card-acciones\">' +\r\n                        (c.correo ? '<a href=\"mailto:' + c.correo + '\">\u2709 Enviar Correo<\/a>' : '') +\r\n                        (whatsappHref(c.telefono) ? '<a href=\"' + whatsappHref(c.telefono) + '\" target=\"_blank\" rel=\"noopener\">\ud83d\udcac WhatsApp<\/a>' : '') +\r\n                    '<\/div>' +\r\n                '<\/div>';\r\n            });\r\n            html += '<\/div>';\r\n            return html;\r\n        }\r\n\r\n        var SERVICIOS_LABELS = {\r\n            carga_aerea: 'Carga A\u00e9rea', carga_maritima_fcl: 'Carga Mar\u00edtima FCL', carga_maritima_lcl: 'Carga Mar\u00edtima LCL',\r\n            carga_terrestre: 'Carga Terrestre', courier: 'Courier', retiro_origen: 'Retiro en Origen',\r\n            aduana_origen: 'Aduana en Origen', consolidacion: 'Consolidaci\u00f3n', almacenaje: 'Almacenaje',\r\n            carga_peligrosa: 'Carga Peligrosa (IMO)', perecibles: 'Perecibles', carga_sobredimensionada: 'Carga Sobredimensionada',\r\n            proyectos_especiales: 'Proyectos Especiales', servicio_puerta_puerta: 'Servicio Puerta a Puerta'\r\n        };\r\n\r\n        function renderTabCobertura(d) {\r\n            var info = d.info || {};\r\n            var cob = d.cobertura || {};\r\n            var serv = d.servicios || {};\r\n            var html = '<div class=\"bl-info-cards\">' +\r\n                '<div class=\"bl-info-card\"><div class=\"bl-info-card-label\">Pa\u00eds<\/div><div class=\"bl-info-card-valor\">' + (info.pais || '\u2014') + '<\/div><\/div>' +\r\n                '<div class=\"bl-info-card\"><div class=\"bl-info-card-label\">Ciudad<\/div><div class=\"bl-info-card-valor\">' + (info.ciudad || '\u2014') + '<\/div><\/div>' +\r\n                '<\/div>';\r\n            html += '<div class=\"bl-ficha-seccion\"><h4>Cobertura Operativa<\/h4>';\r\n            if (!d.cobertura) {\r\n                html += '<p class=\"bl-loading\">Sin cobertura registrada todav\u00eda.<\/p>';\r\n            } else {\r\n                html += '<div class=\"bl-ruta-card\">' +\r\n                    '<span class=\"bl-ruta-codigo\">' + (cob.id_ruta || '\u2014') + '<\/span>' +\r\n                    '<div class=\"bl-ruta-trayecto\">Pa\u00eds Origen: ' + (cob.pais_origen || '\u2014') + '<\/div>' +\r\n                    '<div class=\"bl-ruta-trayecto\">Cobertura: ' + (cob.pais_cobertura || '\u2014') + (cob.ciudad_cobertura ? ' (' + cob.ciudad_cobertura + ')' : '') + '<\/div>' +\r\n                    '<div class=\"bl-ruta-trayecto\">Aeropuertos: ' + (cob.aeropuertos || '\u2014') + '<\/div>' +\r\n                    '<div class=\"bl-ruta-trayecto\">Puertos: ' + (cob.puertos || '\u2014') + '<\/div>' +\r\n                    '<div class=\"bl-ruta-trayecto\">Especialidad Geogr\u00e1fica: ' + (cob.especialidad_geo || '\u2014') + '<\/div>' +\r\n                    '<div class=\"bl-ruta-trayecto\">Rutas Principales: ' + (cob.rutas_principal || '\u2014') + '<\/div>' +\r\n                    '<div class=\"bl-ruta-trayecto\">Experiencia en Destinos: ' + (cob.destinos_exp || '\u2014') + '<\/div>' +\r\n                '<\/div>';\r\n            }\r\n            html += '<\/div>';\r\n            html += '<div class=\"bl-ficha-seccion\"><h4>Servicios Habilitados<\/h4>';\r\n            var activos = Object.keys(SERVICIOS_LABELS).filter(function (k) { return !!serv[k]; }).map(function (k) { return SERVICIOS_LABELS[k]; });\r\n            html += '<div class=\"bl-ruta-servicios\">' + (activos.length ? activos.join(', ') : 'Sin servicios marcados.') + '<\/div>';\r\n            if (serv.otros_servicios) {\r\n                html += '<div class=\"bl-ruta-servicios\">Otros: ' + serv.otros_servicios + '<\/div>';\r\n            }\r\n            html += '<\/div>';\r\n            return html;\r\n        }\r\n\r\n        function renderTabComercial(d) {\r\n            var c = d.credito || {};\r\n            var html = '<div class=\"bl-info-cards\">' +\r\n                '<div class=\"bl-info-card\"><div class=\"bl-info-card-label\">\u00bfPosee Cr\u00e9dito?<\/div><div class=\"bl-info-card-valor\">' + (c.hay_credito || '\u2014') + '<\/div><\/div>' +\r\n                '<div class=\"bl-info-card\"><div class=\"bl-info-card-label\">L\u00edmite Cr\u00e9dito<\/div><div class=\"bl-info-card-valor\">' + (c.limite_credito || '\u2014') + ' ' + (c.moneda || '') + '<\/div><\/div>' +\r\n                '<div class=\"bl-info-card\"><div class=\"bl-info-card-label\">Cr\u00e9dito Disponible<\/div><div class=\"bl-info-card-valor\">' + (c.credito_disponible || '\u2014') + '<\/div><\/div>' +\r\n                '<div class=\"bl-info-card\"><div class=\"bl-info-card-label\">D\u00edas Cr\u00e9dito<\/div><div class=\"bl-info-card-valor\">' + (c.dias_credito || '\u2014') + '<\/div><\/div>' +\r\n                '<div class=\"bl-info-card\"><div class=\"bl-info-card-label\">Cr\u00e9dito Suspendido<\/div><div class=\"bl-info-card-valor\">' + (c.credito_suspendido || 'NO') + '<\/div><\/div>' +\r\n                '<div class=\"bl-info-card\"><div class=\"bl-info-card-label\">Facturas Vencidas<\/div><div class=\"bl-info-card-valor\">' + (c.facturas_vencidas || 0) + '<\/div><\/div>' +\r\n                '<div class=\"bl-info-card\"><div class=\"bl-info-card-label\">Red Log\u00edstica<\/div><div class=\"bl-info-card-valor\">' + (c.red || '\u2014') + '<\/div><\/div>' +\r\n                '<div class=\"bl-info-card\"><div class=\"bl-info-card-label\">Vigencia Membres\u00eda<\/div><div class=\"bl-info-card-valor\">' + (c.vigencia_membresia || '\u2014') + '<\/div><\/div>' +\r\n                '<\/div>';\r\n            return html;\r\n        }\r\n\r\n        function renderTabEvaluacion(d) {\r\n            return '<p class=\"bl-loading\">Sin datos de evaluaci\u00f3n\/ranking todav\u00eda \u2014 se incorporar\u00e1 en una pr\u00f3xima actualizaci\u00f3n (ver prompt de respaldo).<\/p>';\r\n        }\r\n\r\n        function renderTabAuditoria(d) {\r\n            return '<p class=\"bl-loading\">Sin historial de auditor\u00eda todav\u00eda \u2014 la tabla de logs se incorporar\u00e1 en una pr\u00f3xima actualizaci\u00f3n.<\/p>';\r\n        }\r\n\r\n        function abrirFicha(id) {\r\n            fichaIdActual = id;\r\n            modal.classList.add('is-open');\r\n            modalBody.innerHTML = '<p class=\"bl-loading\">Cargando ficha\u2026<\/p>';\r\n            modal.querySelectorAll('.bl-ficha-tab').forEach(function (t) { t.classList.toggle('is-active', t.getAttribute('data-ficha-tab') === 'generales'); });\r\n\r\n            postAjax('bl_get_ficha_agente', { id: id }).then(function (res) {\r\n                if (!res.success) {\r\n                    modalBody.innerHTML = '<p>No se pudo cargar la ficha del agente.<\/p>';\r\n                    return;\r\n                }\r\n                var d = res.data;\r\n                var info = d.info || {};\r\n                fichaTituloEl.textContent = info.nombre_comercial || 'Agente';\r\n                fichaSubtituloEl.textContent = (info.razon_social || '') + ' \u00b7 ' + (info.pais || '') + (info.ciudad ? ', ' + info.ciudad : '');\r\n\r\n                var paneles = {\r\n                    generales: renderTabGenerales(d),\r\n                    cobertura: renderTabCobertura(d),\r\n                    comercial: renderTabComercial(d),\r\n                    evaluacion: renderTabEvaluacion(d),\r\n                    auditoria: renderTabAuditoria(d)\r\n                };\r\n\r\n                modalBody.innerHTML = Object.keys(paneles).map(function (key) {\r\n                    return '<div class=\"bl-ficha-panel' + (key === 'generales' ? ' is-active' : '') + '\" data-ficha-panel=\"' + key + '\">' + paneles[key] + '<\/div>';\r\n                }).join('');\r\n            }).catch(function () {\r\n                modalBody.innerHTML = '<p>Error de conexi\u00f3n al cargar la ficha.<\/p>';\r\n            });\r\n        }\r\n\r\n        modal.querySelectorAll('.bl-ficha-tab').forEach(function (tab) {\r\n            tab.addEventListener('click', function () {\r\n                var key = tab.getAttribute('data-ficha-tab');\r\n                modal.querySelectorAll('.bl-ficha-tab').forEach(function (t) { t.classList.remove('is-active'); });\r\n                tab.classList.add('is-active');\r\n                modalBody.querySelectorAll('.bl-ficha-panel').forEach(function (p) {\r\n                    p.classList.toggle('is-active', p.getAttribute('data-ficha-panel') === key);\r\n                });\r\n            });\r\n        });\r\n\r\n        \/* ---------- M\u00d3DULO AGENTES (DIRECTORIO) ---------- *\/\r\n        var agentesContenido = document.getElementById('bl-agentes-contenido');\r\n        var resultadoBusquedaTexto = document.getElementById('bl-resultado-busqueda-texto');\r\n        var vistaActual = 'tabla';\r\n        var agentesDataCache = [];\r\n\r\n        \/\/ Placeholder de credito: mientras `creditos_carga`\/`limite_credito` no tenga datos reales\r\n        \/\/ cargados de forma masiva, se muestra el valor real si existe o un gui\u00f3n si est\u00e1 NULL.\r\n        function formatoCredito(a) {\r\n            if (!a.limite_credito) return '\u2014';\r\n            var moneda = a.moneda ? (' ' + a.moneda) : '';\r\n            return Number(a.limite_credito).toLocaleString('es-CL') + moneda;\r\n        }\r\n\r\n        function renderAgentesTabla(agentes) {\r\n            var html = '<table class=\"bl-tabla-agentes\"><thead><tr>' +\r\n                '<th>Nombre<\/th><th>Pa\u00eds<\/th><th>Ciudad<\/th><th>Servicios Destacados<\/th><th>Score<\/th><th>Cr\u00e9dito<\/th><th>Estado<\/th><th>Contactos<\/th><th>Acci\u00f3n<\/th>' +\r\n                '<\/tr><\/thead><tbody>';\r\n            agentes.forEach(function (a) {\r\n                html += '<tr><td>' + (a.nombre_comercial || '') + '<\/td><td>' + (a.pais || '') + '<\/td><td>' + (a.ciudad || '') + '<\/td>' +\r\n                    '<td>\u2014<\/td><td>\u2014<\/td><td>' + formatoCredito(a) + '<\/td>' +\r\n                    '<td>' + (a.estado || '') + '<\/td><td>' + (a.total_contactos || 0) + '<\/td>' +\r\n                    '<td><button class=\"bl-btn bl-btn-secondary bl-btn-ficha-dir\" data-id=\"' + a.id + '\">Ver Ficha<\/button><\/td><\/tr>';\r\n            });\r\n            html += '<\/tbody><\/table>';\r\n            agentesContenido.innerHTML = html;\r\n            agentesContenido.querySelectorAll('.bl-btn-ficha-dir').forEach(function (btn) {\r\n                btn.addEventListener('click', function () { abrirFicha(btn.getAttribute('data-id')); });\r\n            });\r\n        }\r\n\r\n        function renderAgentesBloques(agentes) {\r\n            var html = '<div class=\"bl-bloques-grid\">';\r\n            agentes.forEach(function (a) {\r\n                html += '<div class=\"bl-bloque-agente\">' +\r\n                    '<h4>' + (a.nombre_comercial || '') + '<\/h4>' +\r\n                    '<p>' + (a.pais || '') + (a.ciudad ? ', ' + a.ciudad : '') + '<\/p>' +\r\n                    '<p>Servicios Destacados: \u2014<\/p>' +\r\n                    '<p>Score: \u2014<\/p>' +\r\n                    '<p>Cr\u00e9dito: ' + formatoCredito(a) + '<\/p>' +\r\n                    '<p>Estado: ' + (a.estado || '\u2014') + '<\/p>' +\r\n                    '<p>Contactos: ' + (a.total_contactos || 0) + '<\/p>' +\r\n                    '<button class=\"bl-btn bl-btn-secondary bl-btn-ficha-dir\" data-id=\"' + a.id + '\">Ver Ficha<\/button>' +\r\n                    '<\/div>';\r\n            });\r\n            html += '<\/div>';\r\n            agentesContenido.innerHTML = html;\r\n            agentesContenido.querySelectorAll('.bl-btn-ficha-dir').forEach(function (btn) {\r\n                btn.addEventListener('click', function () { abrirFicha(btn.getAttribute('data-id')); });\r\n            });\r\n        }\r\n\r\n        function pintarAgentes() {\r\n            if (vistaActual === 'tabla') renderAgentesTabla(agentesDataCache);\r\n            else renderAgentesBloques(agentesDataCache);\r\n        }\r\n\r\n        function cargarAgentes(filtros) {\r\n            app.dataset.agentesCargado = '1';\r\n            agentesContenido.innerHTML = '<p class=\"bl-loading\">Cargando directorio de agentes\u2026<\/p>';\r\n            postAjax('bl_listar_agentes', filtros || {}).then(function (res) {\r\n                if (res.success) {\r\n                    agentesDataCache = res.data.agentes || [];\r\n                    pintarAgentes();\r\n                    resultadoBusquedaTexto.textContent = 'Resultado de B\u00fasqueda (' + (res.data.total || 0) + ' Resultados Encontrados)';\r\n                } else {\r\n                    agentesContenido.innerHTML = '<p>Error al cargar agentes.<\/p>';\r\n                }\r\n            });\r\n        }\r\n\r\n        \/\/ B\u00fasqueda r\u00e1pida (solo texto libre, sin filtros avanzados) con filtrado en vivo.\r\n        document.getElementById('bl-agentes-buscar').addEventListener('input', function (e) {\r\n            clearTimeout(app._blSearchTimer);\r\n            var val = e.target.value;\r\n            app._blSearchTimer = setTimeout(function () { cargarAgentes({ busqueda: val }); }, 350);\r\n        });\r\n\r\n        app.querySelectorAll('.bl-vista-switch button').forEach(function (btn) {\r\n            btn.addEventListener('click', function () {\r\n                app.querySelectorAll('.bl-vista-switch button').forEach(function (b) { b.classList.remove('is-active'); });\r\n                btn.classList.add('is-active');\r\n                vistaActual = btn.getAttribute('data-vista');\r\n                pintarAgentes();\r\n            });\r\n        });\r\n\r\n        \/* ---------- FILTROS AVANZADOS (nuevo v7.0) ---------- *\/\r\n        var panelFiltros = document.getElementById('bl-filtros-avanzados-panel');\r\n        document.getElementById('bl-btn-filtros-avanzados').addEventListener('click', function () {\r\n            panelFiltros.classList.toggle('is-open');\r\n        });\r\n\r\n        var filtroPaisOrigen = document.getElementById('bl-filtro-pais-origen');\r\n        var filtroServicios = document.getElementById('bl-filtro-servicios');\r\n        var filtroLimiteCredito = document.getElementById('bl-filtro-limite-credito');\r\n        var filtroRankingMinimo = document.getElementById('bl-filtro-ranking-minimo');\r\n        var filtroRedLogistica = document.getElementById('bl-filtro-red-logistica');\r\n        var filtroEstado = document.getElementById('bl-filtro-estado');\r\n\r\n        \/\/ Pa\u00eds Origen, Red Log\u00edstica y Estado: datos reales v\u00eda AJAX (distinct de la BD).\r\n        crearAutocomplete(filtroPaisOrigen, document.getElementById('bl-filtro-pais-origen-dropdown'), { ajaxCampo: 'pais' });\r\n        crearAutocomplete(filtroRedLogistica, document.getElementById('bl-filtro-red-logistica-dropdown'), { ajaxCampo: 'red' });\r\n        crearAutocomplete(filtroEstado, document.getElementById('bl-filtro-estado-dropdown'), { ajaxCampo: 'estado' });\r\n        \/\/ Servicios, L\u00edmite Cr\u00e9dito y Ranking M\u00ednimo: sin fuente de datos real todav\u00eda\r\n        \/\/ (ver comentario en bl_ajax_listar_agentes en el PHP) \u2014 combos con listas de ejemplo.\r\n        crearAutocomplete(filtroServicios, document.getElementById('bl-filtro-servicios-dropdown'), { valoresEstaticos: SERVICIOS_SUGERIDOS });\r\n        crearAutocomplete(filtroLimiteCredito, document.getElementById('bl-filtro-limite-credito-dropdown'), { valoresEstaticos: LIMITE_CREDITO_OPCIONES });\r\n        crearAutocomplete(filtroRankingMinimo, document.getElementById('bl-filtro-ranking-minimo-dropdown'), { valoresEstaticos: RANKING_MINIMO_OPCIONES });\r\n\r\n        function valorFiltro(input) {\r\n            \/\/ Si el usuario eligi\u00f3 de la lista, dataset.valor trae el c\u00f3digo real (ej. bucket de cr\u00e9dito).\r\n            \/\/ Si escribi\u00f3 libremente, se env\u00eda el texto tal cual.\r\n            return input.dataset.valor || input.value.trim();\r\n        }\r\n\r\n        function recolectarFiltros() {\r\n            return {\r\n                busqueda: document.getElementById('bl-agentes-buscar').value.trim(),\r\n                pais_origen: valorFiltro(filtroPaisOrigen),\r\n                servicios: valorFiltro(filtroServicios),\r\n                limite_credito: valorFiltro(filtroLimiteCredito),\r\n                ranking_minimo: valorFiltro(filtroRankingMinimo),\r\n                red_logistica: valorFiltro(filtroRedLogistica),\r\n                estado_filtro: valorFiltro(filtroEstado)\r\n            };\r\n        }\r\n\r\n        document.getElementById('bl-btn-buscar-agentes').addEventListener('click', function () {\r\n            cargarAgentes(recolectarFiltros());\r\n        });\r\n\r\n        document.getElementById('bl-btn-limpiar-filtros').addEventListener('click', function () {\r\n            document.getElementById('bl-agentes-buscar').value = '';\r\n            [filtroPaisOrigen, filtroServicios, filtroLimiteCredito, filtroRankingMinimo, filtroRedLogistica, filtroEstado].forEach(function (input) {\r\n                input.value = '';\r\n                delete input.dataset.valor;\r\n            });\r\n            cargarAgentes({});\r\n        });\r\n\r\n        document.getElementById('bl-btn-nuevo-agente').addEventListener('click', function () {\r\n            abrirFormularioEdicion(null);\r\n        });\r\n\r\n        \/* =====================================================================\r\n         * FICHA DE REGISTRO Y EDICI\u00d3N DE AGENTE (nuevo v8.0)\r\n         * ===================================================================== *\/\r\n        var contactosCache = [];\r\n        var contactoIndexActual = null; \/\/ \u00edndice en contactosCache que est\u00e1 cargado en el sub-bloque, o null = contacto nuevo sin guardar\r\n        var rutasCache = [];\r\n        var tagsPaisCobertura = [];\r\n        var tagsCiudadCobertura = [];\r\n        var tagsAeropuertos = [];\r\n        var tagsPuertos = [];\r\n        var agenteGuardadoEnBD = false; \/\/ controla si \"Guardar Contacto\" ya puede usarse\r\n\r\n        function hoyISO() {\r\n            var d = new Date();\r\n            return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0');\r\n        }\r\n\r\n        \/\/ ---- Combos multi-tag gen\u00e9ricos (Pa\u00eds Cobertura \/ Ciudad Cobertura \/ Aeropuertos \/ Puertos) ----\r\n        function crearComboMultiTag(input, dropdown, tagsWrap, destino, config) {\r\n            function pintar() {\r\n                tagsWrap.innerHTML = destino.map(function (t) {\r\n                    return '<span class=\"bl-tag\">' + t + '<button type=\"button\" data-tag=\"' + t + '\">&times;<\/button><\/span>';\r\n                }).join('');\r\n                tagsWrap.querySelectorAll('button').forEach(function (btn) {\r\n                    btn.addEventListener('click', function () {\r\n                        var i = destino.indexOf(btn.getAttribute('data-tag'));\r\n                        if (i !== -1) destino.splice(i, 1);\r\n                        pintar();\r\n                        sincronizarRutasCodigos();\r\n                    });\r\n                });\r\n            }\r\n            function agregar(valor) {\r\n                var v = (valor || '').trim();\r\n                if (v === '' || destino.indexOf(v) !== -1) return;\r\n                destino.push(v);\r\n                pintar();\r\n                input.value = '';\r\n            }\r\n            if (config && config.conAutocomplete) {\r\n                crearAutocomplete(input, dropdown, { ajaxCampo: config.ajaxCampo, onSelect: function (valor) { agregar(valor); } });\r\n            }\r\n            input.addEventListener('keydown', function (e) {\r\n                if (e.key === 'Enter') { e.preventDefault(); agregar(input.value); }\r\n            });\r\n            return { pintar: pintar, reset: function () { destino.length = 0; pintar(); } };\r\n        }\r\n\r\n        var comboPaisCobertura = crearComboMultiTag(document.getElementById('bl-e-pais-cobertura'), document.getElementById('bl-e-pais-cobertura-dropdown'), document.getElementById('bl-e-pais-cobertura-tags'), tagsPaisCobertura, { conAutocomplete: true, ajaxCampo: 'pais' });\r\n        var comboCiudadCobertura = crearComboMultiTag(document.getElementById('bl-e-ciudad-cobertura'), document.getElementById('bl-e-ciudad-cobertura-dropdown'), document.getElementById('bl-e-ciudad-cobertura-tags'), tagsCiudadCobertura, { conAutocomplete: true, ajaxCampo: 'ciudad' });\r\n        var comboAeropuertos = crearComboMultiTag(document.getElementById('bl-e-aeropuertos'), null, document.getElementById('bl-e-aeropuertos-tags'), tagsAeropuertos, {});\r\n        var comboPuertos = crearComboMultiTag(document.getElementById('bl-e-puertos'), null, document.getElementById('bl-e-puertos-tags'), tagsPuertos, {});\r\n\r\n        \/\/ Pa\u00eds y Ciudad del Bloque 1 (con datos reales de la BD).\r\n        crearAutocomplete(document.getElementById('bl-e-pais'), document.getElementById('bl-e-pais-dropdown'), {\r\n            ajaxCampo: 'pais',\r\n            onSelect: function (valor) { document.getElementById('bl-e-pais-origen-base').value = valor; }\r\n        });\r\n        document.getElementById('bl-e-pais').addEventListener('input', function (e) {\r\n            document.getElementById('bl-e-pais-origen-base').value = e.target.value;\r\n        });\r\n        crearAutocomplete(document.getElementById('bl-e-ciudad'), document.getElementById('bl-e-ciudad-dropdown'), { ajaxCampo: 'ciudad' });\r\n\r\n        \/\/ ---- Generaci\u00f3n inmediata de c\u00f3digos UUID (contacto \/ cobertura) ----\r\n        \/\/ Nota: los tres endpoints (agente, contacto, ruta) responden con la clave 'id' \u2014\r\n        \/\/ antes se le\u00eda 'id_contacto' \/ 'id_ruta' (que no existen en la respuesta), por eso\r\n        \/\/ los campos quedaban en blanco o mostraban el texto \"undefined\". Corregido en v8.2.\r\n        function generarCodigoContacto() {\r\n            document.getElementById('bl-e-c-id').value = 'Generando\u2026';\r\n            return postAjax('bl_generar_codigo_contacto', {}).then(function (res) {\r\n                var codigo = (res && res.success && res.data && res.data.id) ? res.data.id : '';\r\n                document.getElementById('bl-e-c-id').value = codigo;\r\n                return codigo;\r\n            }).catch(function () {\r\n                document.getElementById('bl-e-c-id').value = '';\r\n                return '';\r\n            });\r\n        }\r\n\r\n        function generarCodigoRuta() {\r\n            document.getElementById('bl-e-id-ruta').value = 'Generando\u2026';\r\n            return postAjax('bl_generar_codigo_ruta', {}).then(function (res) {\r\n                var codigo = (res && res.success && res.data && res.data.id) ? res.data.id : '';\r\n                document.getElementById('bl-e-id-ruta').value = codigo;\r\n                return codigo;\r\n            }).catch(function () {\r\n                document.getElementById('bl-e-id-ruta').value = '';\r\n                return '';\r\n            });\r\n        }\r\n\r\n        \/\/ ---- Sub-bloque de contacto: selector + guardado individual ----\r\n        function limpiarCamposContacto() {\r\n            ['bl-e-contacto-nombre', 'bl-e-c-cargo', 'bl-e-c-area', 'bl-e-c-telefono', 'bl-e-c-correo', 'bl-e-c-mensajeria', 'bl-e-c-otros', 'bl-e-c-idioma'].forEach(function (id) {\r\n                document.getElementById(id).value = '';\r\n            });\r\n            document.getElementById('bl-e-c-estado').value = 'Pendiente de Validaci\u00f3n';\r\n            document.getElementById('bl-e-c-fecha-validacion').value = hoyISO();\r\n            contactoIndexActual = null;\r\n            generarCodigoContacto();\r\n        }\r\n\r\n        function cargarContactoEnCampos(c) {\r\n            document.getElementById('bl-e-c-id').value = c.id_contacto || '';\r\n            document.getElementById('bl-e-contacto-nombre').value = c.nombre_contacto || '';\r\n            document.getElementById('bl-e-c-cargo').value = c.cargo || '';\r\n            document.getElementById('bl-e-c-area').value = c.area || '';\r\n            document.getElementById('bl-e-c-telefono').value = c.telefono || '';\r\n            document.getElementById('bl-e-c-correo').value = c.correo || '';\r\n            document.getElementById('bl-e-c-mensajeria').value = c.mensajeria || '';\r\n            document.getElementById('bl-e-c-otros').value = c.otros_medios || '';\r\n            document.getElementById('bl-e-c-idioma').value = c.idioma || '';\r\n            document.getElementById('bl-e-c-estado').value = c.estado_contacto || 'Pendiente de Validaci\u00f3n';\r\n            document.getElementById('bl-e-c-fecha-validacion').value = c.fecha_validacion || hoyISO();\r\n        }\r\n\r\n        function leerContactoDesdeCampos() {\r\n            var idExistente = (contactoIndexActual !== null && contactosCache[contactoIndexActual]) ? contactosCache[contactoIndexActual].id_contacto : '';\r\n            var idCampo = document.getElementById('bl-e-c-id').value.trim();\r\n            return {\r\n                id_contacto: idExistente || (idCampo && idCampo !== 'Generando\u2026' ? idCampo : ''),\r\n                nombre_contacto: document.getElementById('bl-e-contacto-nombre').value.trim(),\r\n                cargo: document.getElementById('bl-e-c-cargo').value.trim(),\r\n                area: document.getElementById('bl-e-c-area').value.trim(),\r\n                telefono: document.getElementById('bl-e-c-telefono').value.trim(),\r\n                correo: document.getElementById('bl-e-c-correo').value.trim(),\r\n                mensajeria: document.getElementById('bl-e-c-mensajeria').value.trim(),\r\n                otros_medios: document.getElementById('bl-e-c-otros').value.trim(),\r\n                idioma: document.getElementById('bl-e-c-idioma').value.trim(),\r\n                estado_contacto: document.getElementById('bl-e-c-estado').value,\r\n                fecha_validacion: document.getElementById('bl-e-c-fecha-validacion').value || hoyISO()\r\n            };\r\n        }\r\n\r\n        \/\/ Sincroniza lo escrito en el sub-bloque hacia contactosCache (sin llamar a la BD).\r\n        function sincronizarContactoActual() {\r\n            var actual = leerContactoDesdeCampos();\r\n            if (actual.nombre_contacto === '') return;\r\n            if (contactoIndexActual !== null && contactosCache[contactoIndexActual]) {\r\n                contactosCache[contactoIndexActual] = actual;\r\n            } else {\r\n                contactosCache.push(actual);\r\n                contactoIndexActual = contactosCache.length - 1;\r\n            }\r\n            pintarContactos();\r\n        }\r\n\r\n        \/\/ ---- Lista \"Contactos Ingresados\" (derecha del sub-bloque de contacto) ----\r\n        var contactosListaEl = document.getElementById('bl-contactos-lista');\r\n        function pintarContactos() {\r\n            if (!contactosCache.length) {\r\n                contactosListaEl.innerHTML = '<p class=\"bl-loading\">Sin contactos agregados.<\/p>';\r\n                return;\r\n            }\r\n            contactosListaEl.innerHTML = contactosCache.map(function (c, idx) {\r\n                return '<div class=\"bl-ruta-card\" data-idx=\"' + idx + '\">' +\r\n                    '<span class=\"bl-ruta-codigo\">' + (c.id_contacto || '\u2014') + '<\/span>' +\r\n                    '<div class=\"bl-ruta-trayecto\">' + (c.nombre_contacto || '\u2014') + (c.cargo ? ' \u2014 ' + c.cargo : '') + '<\/div>' +\r\n                    '<div class=\"bl-ruta-servicios\">' + (c.telefono || '') + (c.correo ? ' \u00b7 ' + c.correo : '') + '<\/div>' +\r\n                    '<button type=\"button\" class=\"bl-contacto-editar\" data-idx=\"' + idx + '\">Editar<\/button>' +\r\n                    '<button type=\"button\" class=\"bl-contacto-quitar\" data-idx=\"' + idx + '\">Quitar<\/button>' +\r\n                '<\/div>';\r\n            }).join('');\r\n            contactosListaEl.querySelectorAll('.bl-contacto-editar').forEach(function (btn) {\r\n                btn.addEventListener('click', function () {\r\n                    contactoIndexActual = parseInt(btn.getAttribute('data-idx'), 10);\r\n                    cargarContactoEnCampos(contactosCache[contactoIndexActual]);\r\n                });\r\n            });\r\n            contactosListaEl.querySelectorAll('.bl-contacto-quitar').forEach(function (btn) {\r\n                btn.addEventListener('click', function () {\r\n                    var idx = parseInt(btn.getAttribute('data-idx'), 10);\r\n                    contactosCache.splice(idx, 1);\r\n                    if (contactoIndexActual === idx) { contactoIndexActual = null; limpiarCamposContacto(); }\r\n                    pintarContactos();\r\n                    refrescarAutocompleteContactos();\r\n                });\r\n            });\r\n        }\r\n\r\n        document.getElementById('bl-btn-agregar-contacto').addEventListener('click', function () {\r\n            var c = leerContactoDesdeCampos();\r\n            if (c.nombre_contacto === '') { alert('Ingresa al menos el Nombre del Contacto.'); return; }\r\n            if (contactoIndexActual !== null && contactosCache[contactoIndexActual]) {\r\n                contactosCache[contactoIndexActual] = c;\r\n            } else {\r\n                contactosCache.push(c);\r\n            }\r\n            pintarContactos();\r\n            refrescarAutocompleteContactos();\r\n            limpiarCamposContacto();\r\n        });\r\n\r\n        var dropdownContacto = document.getElementById('bl-e-contacto-nombre-dropdown');\r\n        function refrescarAutocompleteContactos() {\r\n            crearAutocomplete(document.getElementById('bl-e-contacto-nombre'), dropdownContacto, {\r\n                valoresEstaticos: contactosCache.map(function (c, i) { return { label: c.nombre_contacto, valor: String(i) }; }),\r\n                onSelect: function (indice) {\r\n                    contactoIndexActual = parseInt(indice, 10);\r\n                    cargarContactoEnCampos(contactosCache[contactoIndexActual]);\r\n                }\r\n            });\r\n        }\r\n        refrescarAutocompleteContactos();\r\n\r\n        document.getElementById('bl-btn-nuevo-contacto').addEventListener('click', function () {\r\n            sincronizarContactoActual();\r\n            limpiarCamposContacto();\r\n            refrescarAutocompleteContactos();\r\n        });\r\n\r\n        document.getElementById('bl-btn-guardar-contacto').addEventListener('click', function () {\r\n            if (!agenteGuardadoEnBD) return;\r\n            var c = leerContactoDesdeCampos();\r\n            if (c.nombre_contacto === '') { alert('Ingresa al menos el Nombre del Contacto.'); return; }\r\n            postAjax('bl_guardar_contacto', {\r\n                id_agente: document.getElementById('bl-e-id').value,\r\n                id_contacto: c.id_contacto,\r\n                nombre_contacto: c.nombre_contacto,\r\n                cargo: c.cargo, area: c.area, telefono: c.telefono, correo: c.correo,\r\n                mensajeria: c.mensajeria, otros_medios: c.otros_medios, idioma: c.idioma,\r\n                estado_contacto: c.estado_contacto\r\n            }).then(function (res) {\r\n                if (!res.success) { alert(res.data && res.data.message ? res.data.message : 'No se pudo guardar el contacto.'); return; }\r\n                c.id_contacto = res.data.id_contacto;\r\n                if (contactoIndexActual !== null && contactosCache[contactoIndexActual]) {\r\n                    contactosCache[contactoIndexActual] = c;\r\n                } else {\r\n                    contactosCache.push(c);\r\n                    contactoIndexActual = contactosCache.length - 1;\r\n                }\r\n                pintarContactos();\r\n                refrescarAutocompleteContactos();\r\n                alert('Contacto guardado correctamente.');\r\n            });\r\n        });\r\n\r\n        \/\/ ---- Rutas (Bloque 2, v8.2): \"Rutas Principales (C\u00f3digos)\" ya NO se escribe a mano \u2014 es de\r\n        \/\/ solo lectura y se autocompleta con los nombres de los servicios marcados en la \"Matriz de\r\n        \/\/ Servicios Registrados\" de m\u00e1s abajo, para que el usuario vea de inmediato qu\u00e9 servicios\r\n        \/\/ quedaron marcados. El bot\u00f3n \"Agregar\" toma esa foto actual (servicios marcados + Exp. en\r\n        \/\/ Destino) y la agrega a la lista \"Rutas Ingresadas\"; esa lista arma lo que se guarda en\r\n        \/\/ `rutas.rutas_principal` \/ `rutas.destinos_exp` (una sola fila por agente) al Guardar Agente. ----\r\n        var rutasListaEl = document.getElementById('bl-rutas-lista');\r\n        var rutasCodigosEl = document.getElementById('bl-e-rutas-codigos');\r\n        var expDestinoEl = document.getElementById('bl-e-exp-destino');\r\n\r\n        \/\/ Recalcula \"Rutas Principales (C\u00f3digos)\" a partir de los checkboxes marcados en la matriz de servicios.\r\n        function actualizarRutasPrincipalesDesdeServicios() {\r\n            var marcados = Object.keys(SERVICIOS_LABELS).filter(function (k) {\r\n                var chk = document.querySelector('#bl-e-servicios-matriz input[data-servicio=\"' + k + '\"]');\r\n                return chk && chk.checked;\r\n            }).map(function (k) { return SERVICIOS_LABELS[k]; });\r\n            rutasCodigosEl.value = marcados.join(', ');\r\n        }\r\n        document.querySelectorAll('#bl-e-servicios-matriz input[data-servicio]').forEach(function (chk) {\r\n            chk.addEventListener('change', actualizarRutasPrincipalesDesdeServicios);\r\n        });\r\n\r\n        \/\/ Se conserva por compatibilidad con otras llamadas existentes.\r\n        function sincronizarRutasCodigos() {\r\n            actualizarRutasPrincipalesDesdeServicios();\r\n            pintarRutas();\r\n        }\r\n\r\n        \/\/ Arma el texto que se guardar\u00e1 en rutas.rutas_principal\r\n        function textoRutasPrincipal() {\r\n            return rutasCache.map(function (r) { return r.codigo_ruta; }).filter(Boolean).join(' | ');\r\n        }\r\n\r\n        \/\/ Arma el texto que se guardar\u00e1 en rutas.destinos_exp\r\n        function textoDestinosExp() {\r\n            return rutasCache.map(function (r) {\r\n                return r.codigo_ruta + (r.experiencia_operaciones ? ' \u2014 ' + r.experiencia_operaciones + ' Ops' : '');\r\n            }).filter(Boolean).join(' | ');\r\n        }\r\n\r\n        function pintarRutas() {\r\n            if (!rutasCache.length) {\r\n                rutasListaEl.innerHTML = '<p class=\"bl-loading\">Sin rutas agregadas.<\/p>';\r\n                return;\r\n            }\r\n            rutasListaEl.innerHTML = rutasCache.map(function (r, idx) {\r\n                return '<div class=\"bl-ruta-card\">' +\r\n                    '<span class=\"bl-ruta-codigo\">Servicios<\/span>' +\r\n                    '<div class=\"bl-ruta-trayecto\">' + (r.codigo_ruta || '\u2014') + '<\/div>' +\r\n                    '<div class=\"bl-ruta-servicios\">Exp. en Destino: ' + (r.experiencia_operaciones || 0) + ' Ops<\/div>' +\r\n                    '<button type=\"button\" data-idx=\"' + idx + '\">Quitar<\/button>' +\r\n                '<\/div>';\r\n            }).join('');\r\n            rutasListaEl.querySelectorAll('button').forEach(function (btn) {\r\n                btn.addEventListener('click', function () {\r\n                    rutasCache.splice(parseInt(btn.getAttribute('data-idx'), 10), 1);\r\n                    pintarRutas();\r\n                });\r\n            });\r\n        }\r\n\r\n        document.getElementById('bl-btn-agregar-ruta').addEventListener('click', function () {\r\n            var codigo = rutasCodigosEl.value.trim();\r\n            if (codigo === '') {\r\n                alert('Marca al menos un servicio en la \"Matriz de Servicios Registrados\" antes de agregar.');\r\n                return;\r\n            }\r\n            rutasCache.push({\r\n                codigo_ruta: codigo,\r\n                experiencia_operaciones: parseInt(expDestinoEl.value, 10) || 0\r\n            });\r\n            expDestinoEl.value = '';\r\n            pintarRutas();\r\n        });\r\n\r\n        \/\/ ---- Abrir el formulario (crear o editar) ----\r\n        function resetearFormularioAgente() {\r\n            formAgente.reset();\r\n            contactosCache = [];\r\n            contactoIndexActual = null;\r\n            rutasCache = [];\r\n            tagsPaisCobertura.length = 0; tagsCiudadCobertura.length = 0; tagsAeropuertos.length = 0; tagsPuertos.length = 0;\r\n            comboPaisCobertura.pintar(); comboCiudadCobertura.pintar(); comboAeropuertos.pintar(); comboPuertos.pintar();\r\n            document.querySelectorAll('#bl-e-servicios-matriz input').forEach(function (c) { c.checked = false; });\r\n            document.getElementById('bl-e-otros-servicios').value = '';\r\n            document.getElementById('bl-e-especialidad').value = '';\r\n            pintarRutas();\r\n            pintarContactos();\r\n            sincronizarRutasCodigos();\r\n            limpiarCamposContacto();\r\n            refrescarAutocompleteContactos();\r\n            \/\/ Fecha Actualizaci\u00f3n: siempre se autocompleta con la fecha de hoy, nunca queda en blanco.\r\n            document.getElementById('bl-e-fecha-actualizacion').value = hoyISO();\r\n        }\r\n\r\n        function abrirFormularioEdicion(id) {\r\n            mostrarModulo('editar');\r\n            resetearFormularioAgente();\r\n\r\n            if (!id) {\r\n                \/\/ Modo creaci\u00f3n: se piden UUID nuevos garantizados sin colisi\u00f3n con la BD,\r\n                \/\/ y se muestran de inmediato (agente, cobertura y primer contacto).\r\n                agenteGuardadoEnBD = false;\r\n                document.getElementById('bl-btn-guardar-contacto').disabled = true;\r\n                document.getElementById('bl-e-id').value = 'Generando\u2026';\r\n                postAjax('bl_generar_codigo_agente', {}).then(function (res) {\r\n                    document.getElementById('bl-e-id').value = (res && res.success && res.data && res.data.id) ? res.data.id : '';\r\n                }).catch(function () {\r\n                    document.getElementById('bl-e-id').value = '';\r\n                });\r\n                generarCodigoRuta();\r\n                \/\/ El c\u00f3digo de contacto ya se gener\u00f3 en resetearFormularioAgente() -> limpiarCamposContacto().\r\n                document.getElementById('bl-e-fecha-actualizacion').value = hoyISO();\r\n                return;\r\n            }\r\n\r\n            agenteGuardadoEnBD = false;\r\n            document.getElementById('bl-btn-guardar-contacto').disabled = true;\r\n            document.getElementById('bl-e-id').value = 'Cargando\u2026';\r\n            postAjax('bl_obtener_agente_editar', { id: id }).then(function (res) {\r\n                if (!res.success) { alert('No se pudo cargar el agente para editar.'); return; }\r\n                agenteGuardadoEnBD = true;\r\n                document.getElementById('bl-btn-guardar-contacto').disabled = false;\r\n                var d = res.data;\r\n                var info = d.info || {};\r\n\r\n                \/\/ C\u00f3digo Agente (UUID): se muestra siempre, pero no es editable (es \u00fanico por empresa).\r\n                document.getElementById('bl-e-id').value = info.id || id;\r\n                document.getElementById('bl-e-nombre-comercial').value = info.nombre_comercial || '';\r\n                document.getElementById('bl-e-razon-social').value = info.razon_social || '';\r\n                document.getElementById('bl-e-estado').value = info.estado || 'Nuevo';\r\n                document.getElementById('bl-e-pais').value = info.pais || '';\r\n                document.getElementById('bl-e-pais-origen-base').value = info.pais || '';\r\n                document.getElementById('bl-e-ciudad').value = info.ciudad || '';\r\n                document.getElementById('bl-e-web').value = info.pagina_web || '';\r\n                document.getElementById('bl-e-responsable').value = info.responsable || '';\r\n                document.getElementById('bl-e-direccion').value = info.direccion || '';\r\n                \/\/ Fecha Actualizaci\u00f3n: si la BD no trae una fecha (nunca deber\u00eda quedar en blanco), se usa la de hoy.\r\n                document.getElementById('bl-e-fecha-actualizacion').value = info.fecha_actualizacion || hoyISO();\r\n\r\n                contactosCache = (d.contactos || []).map(function (c) {\r\n                    return {\r\n                        id_contacto: c.id_contacto, nombre_contacto: c.Nombre_Contacto, cargo: c.cargo, area: c.area,\r\n                        telefono: c.telefono, correo: c.correo, mensajeria: c.mensajeria, otros_medios: c.otros_medios,\r\n                        idioma: c.idioma, estado_contacto: c.estado_contacto, fecha_validacion: c.fecha_validacion\r\n                    };\r\n                });\r\n                if (contactosCache.length) {\r\n                    contactoIndexActual = 0;\r\n                    cargarContactoEnCampos(contactosCache[0]);\r\n                } else {\r\n                    generarCodigoContacto();\r\n                }\r\n                pintarContactos();\r\n                refrescarAutocompleteContactos();\r\n\r\n                var cr = d.credito || {};\r\n                document.getElementById('bl-e-hay-credito').value = cr.hay_credito || 'NO';\r\n                document.getElementById('bl-e-limite-credito').value = cr.limite_credito || '';\r\n                document.getElementById('bl-e-moneda').value = cr.moneda || 'EUR';\r\n                document.getElementById('bl-e-dias-credito').value = cr.dias_credito || '';\r\n                document.getElementById('bl-e-credito-disponible').value = cr.credito_disponible || '';\r\n                document.getElementById('bl-e-credito-suspendido').value = cr.credito_suspendido || 'NO';\r\n                document.getElementById('bl-e-facturas-vencidas').value = cr.facturas_vencidas || '';\r\n                document.getElementById('bl-e-kpi-credito').value = cr.kpi_credito || '';\r\n                document.getElementById('bl-e-red').value = cr.red || '';\r\n                document.getElementById('bl-e-vigencia-membresia').value = cr.vigencia_membresia || '';\r\n\r\n                \/\/ Cobertura (Bloque 2): fila \u00fanica por agente (rutas + servicios_ruta).\r\n                var cob = d.cobertura || {};\r\n                var serv = d.servicios || {};\r\n                document.getElementById('bl-e-id-ruta').value = cob.id_ruta || '';\r\n                if (!cob.id_ruta) { generarCodigoRuta(); }\r\n                document.getElementById('bl-e-especialidad').value = cob.especialidad_geo || '';\r\n\r\n                function textoATags(destino, texto) {\r\n                    destino.length = 0;\r\n                    (texto || '').split(',').map(function (v) { return v.trim(); }).filter(Boolean).forEach(function (v) {\r\n                        if (destino.indexOf(v) === -1) destino.push(v);\r\n                    });\r\n                }\r\n                textoATags(tagsPaisCobertura, cob.pais_cobertura);\r\n                textoATags(tagsCiudadCobertura, cob.ciudad_cobertura);\r\n                textoATags(tagsAeropuertos, cob.aeropuertos);\r\n                textoATags(tagsPuertos, cob.puertos);\r\n                comboPaisCobertura.pintar(); comboCiudadCobertura.pintar(); comboAeropuertos.pintar(); comboPuertos.pintar();\r\n\r\n                document.querySelectorAll('#bl-e-servicios-matriz input[data-servicio]').forEach(function (chk) {\r\n                    chk.checked = !!serv[chk.getAttribute('data-servicio')];\r\n                });\r\n                document.getElementById('bl-e-otros-servicios').value = serv.otros_servicios || '';\r\n                \/\/ \"Rutas Principales (C\u00f3digos)\" se recalcula desde los checkboxes que se acaban de marcar\r\n                \/\/ (no desde el texto libre guardado), para que siempre muestre exactamente qu\u00e9 est\u00e1 marcado.\r\n                actualizarRutasPrincipalesDesdeServicios();\r\n\r\n                \/\/ Las entradas de \"Agregar Ruta\" no se pueden reconstruir de forma exacta a partir del\r\n                \/\/ texto libre guardado (rutas_principal \/ destinos_exp); se dejan vac\u00edas para nuevas adiciones.\r\n                rutasCache = [];\r\n                pintarRutas();\r\n            });\r\n        }\r\n\r\n        document.getElementById('bl-editar-volver').addEventListener('click', function (e) {\r\n            e.preventDefault();\r\n            mostrarModulo(ultimoModuloVisible);\r\n        });\r\n        document.getElementById('bl-btn-cancelar-agente').addEventListener('click', function () {\r\n            mostrarModulo(ultimoModuloVisible);\r\n        });\r\n\r\n        document.getElementById('bl-btn-guardar-agente').addEventListener('click', function () {\r\n            sincronizarContactoActual();\r\n\r\n            var nombreComercial = document.getElementById('bl-e-nombre-comercial').value.trim();\r\n            var razonSocial = document.getElementById('bl-e-razon-social').value.trim();\r\n            if (nombreComercial === '' || razonSocial === '') {\r\n                alert('Nombre Comercial y Raz\u00f3n Social son obligatorios (Bloque 1).');\r\n                return;\r\n            }\r\n\r\n            var payload = {\r\n                agente: {\r\n                    id: document.getElementById('bl-e-id').value,\r\n                    nombre_comercial: nombreComercial,\r\n                    razon_social: razonSocial,\r\n                    estado: document.getElementById('bl-e-estado').value,\r\n                    pais: document.getElementById('bl-e-pais').value.trim(),\r\n                    ciudad: document.getElementById('bl-e-ciudad').value.trim(),\r\n                    pagina_web: document.getElementById('bl-e-web').value.trim(),\r\n                    responsable: document.getElementById('bl-e-responsable').value.trim(),\r\n                    direccion: document.getElementById('bl-e-direccion').value.trim()\r\n                },\r\n                credito: {\r\n                    hay_credito: document.getElementById('bl-e-hay-credito').value,\r\n                    limite_credito: document.getElementById('bl-e-limite-credito').value,\r\n                    moneda: document.getElementById('bl-e-moneda').value,\r\n                    dias_credito: document.getElementById('bl-e-dias-credito').value,\r\n                    credito_disponible: document.getElementById('bl-e-credito-disponible').value,\r\n                    credito_suspendido: document.getElementById('bl-e-credito-suspendido').value,\r\n                    facturas_vencidas: document.getElementById('bl-e-facturas-vencidas').value,\r\n                    kpi_credito: document.getElementById('bl-e-kpi-credito').value,\r\n                    red: document.getElementById('bl-e-red').value,\r\n                    vigencia_membresia: document.getElementById('bl-e-vigencia-membresia').value\r\n                    \/\/ 'garantia_red' y 'acuerdo_bilateral' no se env\u00edan: no hay columna en creditos_carga todav\u00eda.\r\n                },\r\n                contactos: contactosCache,\r\n                cobertura: {\r\n                    id_ruta: document.getElementById('bl-e-id-ruta').value.trim(),\r\n                    pais_origen: document.getElementById('bl-e-pais-origen-base').value.trim(),\r\n                    pais_cobertura: tagsPaisCobertura.join(', '),\r\n                    ciudad_cobertura: tagsCiudadCobertura.join(', '),\r\n                    aeropuertos: tagsAeropuertos.join(', '),\r\n                    puertos: tagsPuertos.join(', '),\r\n                    destinos_exp: textoDestinosExp(),\r\n                    rutas_principal: textoRutasPrincipal() || document.getElementById('bl-e-rutas-codigos').value.trim(),\r\n                    especialidad_geo: document.getElementById('bl-e-especialidad').value.trim()\r\n                },\r\n                servicios: (function () {\r\n                    var s = {};\r\n                    document.querySelectorAll('#bl-e-servicios-matriz input[data-servicio]').forEach(function (chk) {\r\n                        s[chk.getAttribute('data-servicio')] = chk.checked ? 1 : 0;\r\n                    });\r\n                    s.otros_servicios = document.getElementById('bl-e-otros-servicios').value.trim();\r\n                    return s;\r\n                })()\r\n            };\r\n\r\n            var btnGuardar = document.getElementById('bl-btn-guardar-agente');\r\n            btnGuardar.disabled = true;\r\n            btnGuardar.textContent = 'Guardando\u2026';\r\n\r\n            postAjax('bl_guardar_agente', { payload: JSON.stringify(payload) }).then(function (res) {\r\n                btnGuardar.disabled = false;\r\n                btnGuardar.textContent = 'Guardar Agente';\r\n                if (!res.success) {\r\n                    alert('No se pudo guardar: ' + (res.data && res.data.message ? res.data.message : 'error desconocido.'));\r\n                    return;\r\n                }\r\n                agenteGuardadoEnBD = true;\r\n                document.getElementById('bl-btn-guardar-contacto').disabled = false;\r\n                document.getElementById('bl-e-id').value = res.data.id;\r\n                alert('Agente guardado correctamente.');\r\n                app.dataset.agentesCargado = ''; \/\/ fuerza recarga del directorio la pr\u00f3xima vez que se visite\r\n                mostrarModulo('agentes');\r\n            });\r\n        });\r\n\r\n        \/* ---------- M\u00d3DULO DASHBOARD ---------- *\/\r\n        var dashboardContenido = document.getElementById('bl-dashboard-contenido');\r\n\r\n        function barrasHtml(rows, labelKey, valueKey) {\r\n            if (!rows || !rows.length) return '<p class=\"bl-loading\">Sin datos disponibles.<\/p>';\r\n            var max = Math.max.apply(null, rows.map(function (r) { return parseInt(r[valueKey], 10) || 0; }));\r\n            return rows.map(function (r) {\r\n                var val = parseInt(r[valueKey], 10) || 0;\r\n                var pct = max ? Math.round((val \/ max) * 100) : 0;\r\n                return '<div class=\"bl-bar-row\">' +\r\n                    '<div class=\"bl-bar-label\">' + (r[labelKey] || '\u2014') + '<\/div>' +\r\n                    '<div class=\"bl-bar-track\"><div class=\"bl-bar-fill\" style=\"width:' + pct + '%\"><\/div><\/div>' +\r\n                    '<div class=\"bl-bar-valor\">' + val + '<\/div>' +\r\n                    '<\/div>';\r\n            }).join('');\r\n        }\r\n\r\n        function cargarDashboard() {\r\n            app.dataset.dashboardCargado = '1';\r\n            dashboardContenido.innerHTML = '<p class=\"bl-loading\">Cargando estad\u00edsticas\u2026<\/p>';\r\n            postAjax('bl_dashboard_stats', {}).then(function (res) {\r\n                if (!res.success) {\r\n                    dashboardContenido.innerHTML = '<p>Error al cargar el dashboard.<\/p>';\r\n                    return;\r\n                }\r\n                var d = res.data;\r\n                var html = '<div class=\"bl-kpi-grid\">' +\r\n                    kpi(d.total_agentes, 'Agentes registrados') +\r\n                    kpi(d.total_contactos, 'Contactos totales') +\r\n                    kpi(d.total_rutas, 'Rutas cargadas') +\r\n                    kpi(d.con_credito, 'Agentes con cr\u00e9dito') +\r\n                    '<\/div>';\r\n                html += '<div class=\"bl-dashboard-charts\">' +\r\n                    '<div class=\"bl-chart-card\"><h4>Agentes por pa\u00eds (Top 10)<\/h4>' + barrasHtml(d.por_pais, 'pais', 'total') + '<\/div>' +\r\n                    '<div class=\"bl-chart-card\"><h4>Agentes por estado<\/h4>' + barrasHtml(d.por_estado, 'estado', 'total') + '<\/div>' +\r\n                    '<\/div>';\r\n                dashboardContenido.innerHTML = html;\r\n            });\r\n        }\r\n\r\n        function kpi(valor, label) {\r\n            return '<div class=\"bl-kpi-card\"><div class=\"bl-kpi-valor\">' + (valor || 0) + '<\/div><div class=\"bl-kpi-label\">' + label + '<\/div><\/div>';\r\n        }\r\n    })();\r\n    <\/script>\r\n    <\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-3110","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/bl.blcorporations.com\/index.php?rest_route=\/wp\/v2\/pages\/3110","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bl.blcorporations.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/bl.blcorporations.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/bl.blcorporations.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bl.blcorporations.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3110"}],"version-history":[{"count":24,"href":"https:\/\/bl.blcorporations.com\/index.php?rest_route=\/wp\/v2\/pages\/3110\/revisions"}],"predecessor-version":[{"id":3138,"href":"https:\/\/bl.blcorporations.com\/index.php?rest_route=\/wp\/v2\/pages\/3110\/revisions\/3138"}],"wp:attachment":[{"href":"https:\/\/bl.blcorporations.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3110"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}