jhernandez-vibecode

especialista-ebi

ESPECIALISTA EBI — Portal multi-póliza para Empresas Berthier EBI de Costa Rica S.A. (renovación 2025/2026), branding Seguros Digitales SDI (marca registrada y propiedad intelectual JC). HTML+CSS+JS vanilla en Netlify desde repo jhernandez-vibecode/ebi-polizas. 2 sub-páginas activas: Equipo Contratista (raíz `/`, acento dorado, 66 equipos, póliza madre EQG-0000183) e Incendio Multirriesgo (`/incendio-multirriesgo/`, acento verde teal, 4 zonas de riesgo con coaseguro 80%, póliza madre MRM-0000055). Cada sub-página tiene doble vista por `?modo=cliente`. Tipografía oficial SDI: Space Grotesk + Inter + JetBrains Mono. Iconos Lucide SVG inline. EBI es portafolio recurrente — el patrón establecido (carpeta dedicada por póliza + data.js específico + acento de color diferenciador + drawer adaptado al modelo de datos) debe servir para todos los futuros reportes a EBI. Usar este skill cuando JC pida cualquier cambio, nuevo reporte EBI, o ajuste al portal.

jhernandez-vibecode 0 Updated 2w ago

Resources

5
GitHub

Install

npx skillscat add jhernandez-vibecode/ebi-polizas

Install via the SkillsCat registry.

SKILL.md

Especialista EBI — Portal multi-póliza (marca SDI)

Contexto completo del proyecto para retomar sin perder hilo. Leer COMPLETO antes de tocar código.

Pólizas activas

Sub-página Ruta Póliza madre Acento Items Suma asegurada Prima
Equipo Contratista / EQG-0000183 Dorado SDI #C9A227 66 equipos ₡16.83B ₡33.14M
Incendio Multirriesgo /incendio-multirriesgo/ MRM-0000055 Verde teal SDI #0D9488 4 zonas de riesgo ₡3.59B (80%) · ₡4.42B (100%) ₡9.0M

Portal landing en /index.html — ACTIVO (desde 16 may 2026). Catálogo público con 2 cards (EQC dorado · IMR verde teal) que linkean a <sub-página>/?modo=cliente. Hero navy SDI + meta agente + footer legal. El cliente entra al portal y elige; el agente puede saltar directo a cada sub-página o usar el portal.

URL en producción: https://ebi-polizas.netlify.app/ · auto-deploy desde main (commit + push y Netlify deploya en 1-2 min).

Qué es

Portal web de pólizas para Empresas Berthier EBI de Costa Rica S.A. — renovación 2025/2026, marcado como producto de Seguros Digitales SDI (marca registrada y propiedad intelectual de Juan Carlos Hernández). El INS aparece como carrier (asegurador), no como marca de la app. Estructura de 3 niveles:

  • Portal landing público (/) — el cliente entra acá y elige qué póliza consultar. Hero SDI + cards por póliza con métricas + footer legal. Sin filtros ni interacciones complejas (solo navegación).
  • Sub-página por póliza (ej. /equipo-contratista/ o /incendio-multirriesgo/) — cada póliza es una mini-app independiente con doble modo controlado por ?modo=cliente:
    • Modo agente (/<sub-pagina>/) — uso interno de JC: tabla buscable, filtro, ordenamiento, drawer con detalle, botón "Copiar ruta" hacia OneDrive y CRUD localStorage.
    • Modo cliente (/<sub-pagina>/?modo=cliente) — link que JC comparte a EBI: reporte formal con logo SDI grande, composición visual, tabla sin filtros de edición, leyenda + nota de coberturas, footer institucional + botón "Exportar PDF" (window.print()).

El cliente NO tiene login. Sin backend, sin DB, sin auth. La doble vista por sub-página es el mismo patrón replicado entre Equipo Contratista e Incendio Multirriesgo.

Qué ve cada uno (matriz definitiva, ejemplo de Equipo Contratista)

Componente Agente (/equipo-contratista/) Cliente (/equipo-contratista/?modo=cliente)
Navbar SDI navy
Header reporte SDI grande
Share banner (link cliente con botones Copiar/Previsualizar)
Stats cards (66 · suma · prima · inclusiones)
Sección "Crecimiento del período" (2 insight cards: Inversión nueva · Prima incremental)
Sección "Documentos generales de la póliza" (3 cards: Generales · Especiales · Seguridad)
Composición de la Flota (9 cards por tipo)
Toolbar edición (+Agregar / Importar Excel / Exportar Excel / Exportar data.js / Resetear)
Filtros (search + tipo + counter)
Botón "Descargar Excel" al final de filtros
Tabla de 66 equipos con sort + columna Docs (pill dorado PDF siempre + pill teal Drive opcional)
Click en fila → drawer detalle
Drawer: detail-grid + suma/prima + Drive (si docs_url)
Drawer: CTA dorado "Descargar condiciones particulares" (PDF INS desde /docs/)
Drawer: "Carpeta del archivo digital" (ruta OneDrive interna)
Drawer: "Sin link de Drive vinculado" cuando docs_url está vacío
Drawer: botones Editar / Eliminar
Leyenda + nota coberturas
Footer legal SDI (marca registrada + licencia INS 08-1318 + carrier INS) ✓ navy ✓ cream

EBI es portafolio recurrente. Este es el primer reporte; vendrán más (otras pólizas, otras renovaciones). El patrón aquí (single file + data.js + dos modos + branding SDI) debe servir para todos los reportes futuros a EBI.

Stack técnico

  • Frontend: HTML5 + CSS3 + JS vanilla. Sin framework, sin bundler, sin npm install — igual que reclamos-SDI.
  • Tipografía oficial SDI: Space Grotesk (títulos), Inter (UI), JetBrains Mono (datos/pólizas/chasis) — vía Google Fonts. Tokens en assets/brand/sdi-tokens.css (importable). NO Playfair, no serif decorativas.
  • Iconos: SVG inline de Lucide en utils.js#ICONS — no font-awesome, no emoji estructural.
  • Datos: Hardcoded en js/data.js (const POLIZAS array + const BASE_PATH para la carpeta del archivo digital).
  • Documentación por póliza: Google Drive. Campo docs_url por equipo apuntando a carpeta pública Drive.
  • Hosting: Netlify (auto-deploy desde main).
  • Auth: ninguna. El reporte cliente es público por diseño (link directo + X-Robots-Tag: noindex,nofollow).

Estado actual (checkpoint 2026-05-16)

Día 4: incorporada la sub-página Incendio Multirriesgo en /incendio-multirriesgo/ y construido el portal landing en /index.html. Estructura final multi-página:

  • / → portal público con cards de pólizas (CSS /css/portal.css)
  • /equipo-contratista/ → sub-página EQC (migrada desde la raíz)
  • /incendio-multirriesgo/ → sub-página IMR
  • /assets/brand/ → assets SDI compartidos (favicon + logos + tokens)

Migración EQC ejecutada en bulk: index.html, css/, js/, docs/ movidos a /equipo-contratista/. Path del favicon ajustado a ../assets/brand/favicon.svg. Todo lo demás del HTML/CSS/JS de EQC sigue idéntico (no hay paths absolutos a /assets/... ni nada que se rompa con la migración).

Sub-página IMR desde cero: 4 zonas de riesgo en data.js con desglose de 6 rubros (Edificio/Mercadería/Otras Estructuras/Equipos/Mobiliario/Maquinaria) + 4 coberturas (T/C/D + IVA) + acreedor BAC opcional por zona. Coaseguro 80% con cálculo correcto de valor real al 100% (mercadería no aplica coaseguro). 4 PDFs INS + Adendum 001-2025 + Condiciones Generales V8 en /incendio-multirriesgo/docs/. CRUD agente con modal de 4 fieldsets. Acento verde teal vía override de tokens.

Portal landing con hero navy SDI + meta agente + 2 cards: EQC dorado (66 equipos · ₡16.83B · ₡33.1M) e IMR verde teal (4 zonas · ₡4.42B · ₡9.0M). Cada card linkea a <sub-página>/?modo=cliente. Footer legal SDI completo. Sin JS (CSS-only, links nativos). Mobile-first responsive.

Smoke test 3 vistas OK (portal · EQC cliente · IMR cliente).

Día 3 (15 may): descargadas 66 PDFs oficiales INS (condiciones particulares por póliza), renombradas al patrón corto 0101XXXXXXXXXXXX.pdf y servidas desde /docs/ del repo. Botón dorado "Descargar condiciones particulares" en el drawer (ambos modos) construye el URL determinísticamente desde el campo poliza vía pdfUrl(poliza). Cierra el último pendiente abierto. Cruzando los nombres reales de PDFs INS detectó que las 57 pólizas zonas 10-109 estaban en data.js con sufijo 00 (período anterior) cuando los PDFs vigentes son 01 — sufijos corregidos en bulk.

  • 6c9ef27 (15 may 2026): fix de nombres de coberturas en el drawer. El hardcode (Equipo · Lucro · Piezas) era INCORRECTO. Códigos oficiales INS para Equipo Contratista: E = Daño Directo · L = Responsabilidad Civil Extracontractual · F = Robo y Hurto · G = Riesgos Adicionales · P = Paquete F y G. Las 66 pólizas de EBI tienen E L P uniforme = Daño Directo + RC + Paquete F y G. Nuevo COBERTURAS_MAP + helper expandCoberturas(str) en utils.js. El drawer muestra ahora "E L P (Daño Directo · Responsabilidad Civil · Paquete F y G)".
  • d88caa2 (15 may 2026): sección "Crecimiento del período 2025/2026" entre stats y policy-docs, visible en ambos modos. 2 insight cards calculados dinámicamente desde state.rows: (a) Inversión nueva del período = suma asegurada de zonas >=102 → ₡4.76B (28.3% del valor total, 16 inclusiones); (b) Prima incremental por inclusiones = prima de zonas >=102 → ₡12.0M (36.2% de la prima anual). Util como argumento comercial al compartir el reporte con EBI. Nuevos paintInsights() en app.js (también en paintAll() para refresco tras CRUD) + iconos trendUp+coins en utils.js + .insight-card con gradient navy + icon dorado 56px + valor 32px Space Grotesk dorado. Print CSS adaptado.
  • a6217b3 (15 may 2026): pill dorado "PDF" en la columna Docs de la tabla (ambos modos). Siempre visible, deriva el URL desde pdfUrl(r.poliza). Si además hay docs_url cargado, se apila debajo una pill teal "Drive". Nueva .docs-cell flex-column con gap 4px. Estilo .docs-link--pdf con fondo dorado sólido + sombra dorada para distinguirlo del Drive (gold-soft con borde).
  • a45f96a (15 may 2026): sección Documentos generales de la póliza entre stats y composición de flota, visible en ambos modos. 3 PDFs hosted en docs/generales/ con nombres kebab-case (condiciones-generales.pdf 560KB, condiciones-especiales.pdf 81KB, medidas-de-seguridad.pdf 78KB) — el archivo de Generales es el oficial INS V9, los otros 2 son ejemplares tomados de Z-116 (texto idéntico para toda la cartera). Nueva const POLICY_DOCS en data.js + paintPolicyDocs() en app.js + grid 3-col responsive .policy-doc con gradient navy + borde dorado izquierdo + icon dorado 48px + título Space Grotesk dorado. Print CSS adaptado para PDF export del cliente.
  • d096c4f (15 may 2026): sistema de PDFs por póliza completo. (a) 66 PDFs INS renombrados de formato largo 0101XXX_014_141_Condiciones_..._YYYYMMDD_HHMMSS.pdf → corto 0101XXXXXXXXXXXX.pdf (16 chars + .pdf). (b) data.js sufijos 0001 para 57 pólizas zonas 10-109 (renovación 2025/2026 vigente; zonas 110-112 ya estaban en 01, zonas 113-117 mantienen 00 como inclusiones nuevas del período). (c) helpers pdfFileName(poliza) y pdfUrl(poliza) en utils.js. (d) bloque CTA .detail-pdf en openDrawer() con grid 3-col (icon dorado | título Space Grotesk + meta mono | chevron) + hover lift + sombra dorada — visible en agente y cliente.
  • 5876793 (15 may 2026): 66 vigencias actualizadas al listado oficial INS PMSPPP87. 50 zonas renovadas (zonas <=101) pasaron de "3/08/24 3/08/25" → "3/08/25 3/08/26". 11 inclusiones (zonas 102-112) renovadas a "3/08/25 3/08/26". 5 nuevas inclusiones del período (zonas 113-117) con formato oficial INS dd/mm/yy. Z-114 (EQC 0013789) fecha real cambió "30-01-2026" → "21/01/26" (9 días, dato oficial INS).
  • 8aa7d2f (15 may 2026): cruce de datos con Listado EQG183 oficial INS. 58 primas actualizadas al período vigente 2025/2026 (data.js tenía las del período anterior 2024/2025). Total prima ₡27,833,178 → ₡33,142,383 (+₡5,309,205, +19%). Zona 113 (EQC 0013715, Tractor Bulldozer Komatsu) suma corregida ₡289,840,000 → ₡389,840,000 (typo del data.js, +₡100M). Zona 102 (EQC 0013105, Excavadora Hyundai) equipo HV220S → HX220S. Suma total ₡16,733,858,785 → ₡16,833,858,785. Cruce y smoke test 8920 OK.
  • 4fc4c84 (14 may 2026): fix UX cliente — botón Descargar Excel sale del header y va al final de la fila de filtros (no más solapamiento con meta agente); max-width 1400 en cliente (tabla, header y footer); filtros con tarjeta cream + inputs blanco con focus dorado y chevron azul
  • 249ae20 (14 may 2026): cliente gana búsqueda + filtro tipo + drawer detalle (read-only). El drawer cliente NO muestra la "Carpeta del archivo digital" (ruta interna del agente), NI los botones Editar/Eliminar, NI el aviso "Sin link Drive" cuando docs_url está vacío. Botón "Exportar PDF" del cliente reemplazado por "Descargar Excel" (usa SheetJS, mismo handler que la toolbar del agente).
  • 4273aa8 (14 may 2026): share banner en agente — pill verde-teal arriba de la toolbar con el URL completo del cliente, botón "Copiar" al portapapeles y "Previsualizar" en pestaña nueva. Resuelve la fricción de armar el link ?modo=cliente a mano.
  • 8dc5d77 (13 may 2026): strings reales en POLIZA_INFO — numero_madre: "01-01-EQG-0000183" y licencia_ins: "08-1318".
  • 107d01f (13 may 2026): CRUD agente + Excel I/O + footer legal unificado + póliza madre en título — toolbar arriba de la tabla, modal editor, persistencia localStorage agente, dirty badge, import/export Excel (SheetJS), export data.js, footer legal en ambos modos con marca registrada + licencia INS.
  • 70c944f (13 may 2026): SDI rebrand + Drive docs por póliza.
  • 14f49a7 (13 may 2026): primer commit — release inicial con 66 equipos, dos modos, drawer detalle, exportar PDF, filtros y sort.

Próximos pasos (open)

  • PDFs en /docs/ ya cubren las condiciones particulares oficiales INS (66/66 EQC + 4/4 IMR). Falta opcional: si JC quiere agregar carpetas Drive con docs adicionales, poblar docs_url por zona/equipo.
  • Conectar repo a Netlify desde el dashboard ✅ Resuelto 16 may 2026 — site activo en https://ebi-polizas.netlify.app/ con auto-deploy desde main.
  • Cuando entren más pólizas EBI (RC, Riesgos del Trabajo, Flota Administrativa, etc.), agregar nueva sub-carpeta + card al portal con un acento de color libre (naranja SDI · azul SDI · etc.).

Repo: jhernandez-vibecode/ebi-polizas
Local clone: C:/Users/segur/ebi-polizas/
Preview local: http://localhost:8920 (entrada ebi-polizas en .claude/launch.json)

Estructura del repo

ebi-polizas/
├── index.html             # [PORTAL] Landing público con 2 cards de pólizas (EQC dorado · IMR verde)
├── css/
│   └── portal.css         # [PORTAL] Tokens SDI, hero navy, cards con --accent-color por variante (.poliza-card--gold / .poliza-card--teal), responsive
├── assets/
│   └── brand/             # ===== ASSETS SDI COMPARTIDOS (portal + sub-páginas) =====
│       ├── favicon.svg
│       ├── logo-header.svg     # Header con barras de color
│       ├── logo-negativo.svg   # SDI blanco para fondos oscuros
│       ├── logo-principal.svg  # SDI azul color para fondos claros
│       └── sdi-tokens.css      # Tokens oficiales SDI
│
├── equipo-contratista/    # ===== SUB-PÁGINA EQC (acento dorado #C9A227) =====
│   ├── index.html         # Markup completo (navbar + reportHeader + stats + toolbar + filters + table + drawer + modal editor + legal-footer)
│   ├── css/app.css        # ~1100 líneas — tokens SDI + paleta navy, dos modos, toolbar, modal, dirty badge, print CSS, responsive
│   ├── js/
│   │   ├── data.js        # POLIZA_INFO + POLIZAS (66 equipos con docs_url) + BASE_PATH
│   │   ├── utils.js       # formatCRC, tipoEquipo, folderName, pdfFileName, pdfUrl, expandCoberturas (+ COBERTURAS_MAP), isNew, escapeHtml, ICONS Lucide (~18 iconos)
│   │   └── app.js         # IIFE — routing modo, paint stats/table/fleet, drawer (con edit/delete), modal editor, CRUD localStorage `ebi_polizas_v1`, dirty flag, Excel I/O, data.js export
│   └── docs/              # 66 PDFs INS oficiales (formato corto `0101EQCXXXXXXXX.pdf`) + docs/generales/ (Generales V9 + Especiales + Seguridad)
│
├── incendio-multirriesgo/ # ===== SUB-PÁGINA IMR (acento verde teal #0D9488) =====
│   ├── index.html         # Markup adaptado (zona/rubros/coberturas/acreedor)
│   ├── css/app.css        # CSS heredado de EQC + override verde teal en tokens + componentes específicos (rubro-card, location-card, detail-rubros, detail-coberturas, detail-acreedor, modal-fieldset)
│   ├── js/
│   │   ├── data.js        # POLIZA_INFO + ZONAS (4 zonas con rubros) + POLICY_DOCS + COBERTURAS_BASICAS + RUBROS_INFO + BASE_PATH
│   │   ├── utils.js       # formatCRC, formatCRCcompact, sumRubros, valorReal100, folderName, pdfFileName, pdfUrl, escapeHtml, getMode, clienteUrl, ICONS Lucide (~28 iconos)
│   │   └── app.js         # IIFE — render stats/rubros/locations/table/drawer (con rubros+coberturas+acreedor)/modal con 4 fieldsets, CRUD localStorage `ebi_imr_v1`, Excel I/O con desglose, data.js export
│   └── docs/              # 4 PDFs INS de condiciones particulares (formato corto `0101IMRXXXXXXXX.pdf`) + docs/generales/ (Adendum 001-2025 + Condiciones Generales V8)
├── assets/
│   └── brand/             # Sistema de marca SDI sincronizado desde reclamos-SDI
│       ├── favicon.svg
│       ├── logo-header.svg     # Header con barras de color
│       ├── logo-negativo.svg   # SDI blanco para fondos oscuros (navbar, report-header, footer agente)
│       ├── logo-principal.svg  # SDI azul color para fondos claros (footer cliente)
│       └── sdi-tokens.css      # Tokens oficiales (paleta + tipografía + espaciado)
├── docs/                  # 66 PDFs oficiales INS de condiciones particulares — formato `0101XXXXXXXXXXXX.pdf` derivable desde el campo `poliza` con pdfUrl()
├── netlify.toml           # publish="." + redirect SPA + headers seguridad (noindex)
├── .gitignore
├── README.md
└── SKILL.md               # Este archivo (sync con user-level)

External CDN: SheetJS v0.20.3 (https://cdn.sheetjs.com/xlsx-0.20.3/...) cargado en index.html para Excel I/O.

Paleta y diseño (Marca SDI sobre navy formal)

Tokens SDI oficiales (de assets/brand/sdi-tokens.css):

--sdi-azul:    #0369A1   (identidad base · footer logo, accent secundario)
--sdi-verde:   #0D9488   (protección, estado vigente)
--sdi-naranja: #EA580C   (acción · disponible para CTAs)
--sdi-dorado:  #C9A227   (firma SDI · usado como acento primario en EBI)
--sdi-tinta:   #0F172A   (texto principal)

Escena navy (modo agente + report header cliente):

--color-dark:      #1A1A2E   (fondo navbar, header report)
--color-dark2:     #16213E   (gradient, cards backdrop)
--color-surface:   #21262D   (cards agente)
--color-text:      #E6EDF3   (texto principal sobre navy)

Escena cream (modo cliente body):

--color-bg:        #F8F4EF   (fondo cream)
--color-bg2:       #FFFFFF   (cards cliente)
--color-border-lt: #E8DCC8

Inclusiones nuevas (zona >= 102):

--color-new:       #FFF8E8
--color-new-bd:    var(--sdi-dorado)

Tipografía:

  • --font-display 'Space Grotesk' → h1, h2, h3, stat-card values, fleet-card counts
  • --font-body 'Inter' → body, párrafos, UI controls, botones
  • --font-mono 'JetBrains Mono' → datos numéricos (pólizas, chasis, montos, fechas, paths)

Principios ui-ux-pro-max aplicados: touch targets ≥44px, WCAG 4.5:1, animaciones 150-300ms ease-out, mobile-first 320/768/1280, sin emoji estructural, estados hover/focus/active, skeleton loader, @media print exhaustivo con -webkit-print-color-adjust: exact.

Modelo de datos

POLIZA_INFO — Identidad de la cartera y agente (js/data.js)

const POLIZA_INFO = {
  numero_madre: "01-01-EQG-0000183",
  cliente: "Empresas Berthier EBI de Costa Rica S.A.",
  periodo: "Renovación 2025/2026",
  producto: "Equipo Contratista",
  agente: "Juan Carlos Hernández",
  licencia_ins: "08-1318",
  carrier: "Instituto Nacional de Seguros (INS)"
};

Este bloque alimenta:

  • Navbar agente (subtítulo con póliza madre)
  • Report header cliente (eyebrow producto, badge póliza madre, meta agente y licencia)
  • Footer legal en ambos modos

POLIZAS — Lista de equipos

Campo Tipo Ejemplo
zona number 102
descripcion string "EXCAVADORA HYUNDAI 2024"
chasis string "HHKHK606EE0004518"
equipo string "HV220S" (código corto)
poliza string "EQC 0013105 01"
vigencia string "3/08/24 3/08/25" (formato libre)
suma_asegurada number 286000000 (en colones, sin formato)
prima number 640008
coberturas string "E L P" = Daño Directo + Responsabilidad Civil + Paquete F y G (ver COBERTURAS_MAP en utils.js)
docs_url string "https://drive.google.com/drive/folders/..." o "" si no hay link aún

Totales actuales: 66 equipos · ₡16,733,858,785 suma asegurada · ₡27,833,178 prima anual · 16 inclusiones (zona >= 102).

Documentación por póliza

Cada equipo tiene dos canales de documentación que coexisten:

1. PDF de condiciones particulares (oficial INS, hosted en repo)

Carpeta docs/ con 66 PDFs nombrados con el patrón corto 0101XXXXXXXXXXXX.pdf (16 chars + .pdf, sin espacios). El URL se construye determinísticamente desde el campo poliza con pdfUrl(poliza). El bloque CTA .detail-pdf del drawer (ambos modos) abre el PDF en pestaña nueva. Cuando JC descargue nuevos PDFs del INS:

  1. Descargar del INS el PDF (suele venir con sufijo largo _014_141_Condiciones_..._YYYYMMDD_HHMMSS.pdf).
  2. Renombrarlo a los primeros 16 chars + .pdf (script PS one-liner: Get-ChildItem *.pdf | %{ Rename-Item $_.FullName ($_.Name.Substring(0,16) + '.pdf') }).
  3. Pegar al directorio C:/Users/segur/ebi-polizas/docs/ y commitear.
  4. Si la póliza renovó (cambió sufijo 0001), también actualizar el campo poliza en data.js para que el URL coincida.

2. Carpeta Drive opcional (complementaria)

Cada equipo expone opcionalmente su carpeta pública de Drive vía el campo docs_url. El flujo es manual y bajo el control de JC:

  1. JC crea una carpeta pública en Google Drive por equipo (puede llamarse igual que la carpeta local Zona N- 0101NUMPOLIZA). Sube las condiciones, certificados, endosos, recibos.
  2. JC hace la carpeta accesible con link ("Cualquiera con el link · Lector"). Copia el URL.
  3. JC pega el URL en js/data.js en el campo docs_url del equipo correspondiente.
  4. Commit + push. Netlify deploya y aparece automáticamente:
    • En modo agente: bloque "Documentación digital (Google Drive)" en el drawer del equipo, con CTA "Abrir documentos en Drive".
    • En modo cliente: pill dorada "Ver" en la columna "Docs" de la tabla. Si está vacío, se muestra .

Importante:

  • Las carpetas DEBEN ser públicas ("cualquiera con el link") para que el cliente pueda abrirlas sin login. Sin embargo, NO indexables en buscadores (Drive las marca noindex por defecto).
  • Si una póliza tiene documentos confidenciales (ej. fotocopias de cédulas o información del agente), NO subirlos a esa carpeta pública. Filtrar manualmente antes de compartir.
  • El campo docs_url debe contener el URL completo, no solo el ID de la carpeta.

Helpers clave (js/utils.js)

Función Qué hace
formatCRC(n) n.toLocaleString('es-CR') con prefijo ₡
tipoEquipo(d) Mapea descripción → tipo (Excavadoras / Tractores / Compactadores / Camiones/Vagonetas / Cargadores / Montacargas / Retroexcavadoras / Mulas/Tractos / Trailers / Otros)
folderName(zona, poliza) "Zona {zona}- 0101{poliza sin espacios}" (prefijo 0101 + número compacto)
pdfFileName(poliza) "0101{poliza sin espacios}.pdf" (16 chars + .pdf)
pdfUrl(poliza) "docs/" + pdfFileName(poliza) — usado por el bloque .detail-pdf del drawer
expandCoberturas(str) Mapea "E L P""Daño Directo · Responsabilidad Civil · Paquete F y G" usando COBERTURAS_MAP
isNew(zona) zona >= 102 ⇒ marca como inclusión del período
escapeHtml(s) Sanitiza para evitar XSS al inyectar descripcion u otros campos
getMode() Lee ?modo=cliente del URL
ICONS SVG inline Lucide (shield, settings, search, x, copy, folder, etc.)

OneDrive del agente — estructura del archivo digital

BASE_PATH = C:\Users\segur\OneDrive\ARCHIVO DIGITAL\Equipo Contratista\E\Empresas Berthier Ebi de Costa Rica S.A

Reorganizada el 14 may 2026 (38 operaciones de filesystem en un solo script PS, 0 fails):

Empresas Berthier EBI/
├── 1. RECLAMOS                            ← intacta (carpeta de siniestros)
├── FOTOGRAFÍAS ANTIGUAS                   ← intacta
├── RENOVACIÓN 2019-2020 ... 2026-2027     ← 8 carpetas históricas anuales, intactas
│
├── Zona 75- 0101EQC001306500              ← 29 carpetas vigentes (formato unificado)
├── Zona 76- 0101EQC001306600              ← 26 fueron renombradas en la operación
├── ...                                    ← 3 (115/116/117) ya estaban bien
├── Zona 117- 0101EQC001389700
│
└── _Históricos/                           ← 11 carpetas de equipos dados de baja
    ├── Zona 40 - Cancelada
    ├── Zona 65 - Excluida
    ├── Zona 73 - Cancelada con devolución
    ├── Zona 82 - Cancelada
    ├── Zona 83 - Cancelada
    ├── Zona 88 - Cancelada
    ├── Zona 90 - Cancelada
    ├── Zona 92 - Cancelada
    ├── Zona 93 - Cancelada
    ├── Zona 94 - Cancelada con devolución
    └── Zona 95 - Cancelada con devolución

El formato unificado de las carpetas vigentes (Zona N- 0101<POLIZA_SIN_ESPACIOS>) coincide exactamente con folderName(zona, poliza) en js/utils.js. Esto significa que el botón "Copiar ruta" del drawer agente genera la ruta correcta para cada equipo de la cartera y JC puede pegarla directo en el Explorador de Windows.

Cuando entra un equipo nuevo a la cartera (incluido vía CRUD agente con zona ≥ próximo número), JC debe crear manualmente la carpeta correspondiente en OneDrive con el mismo formato antes de pegar docs_url. La app NO crea carpetas locales — solo apunta a ellas.

Compartir el reporte con EBI — share banner

El modo agente tiene un banner verde-teal arriba de la toolbar que muestra:

  • El URL completo del cliente de esa sub-página (ej. https://ebi-polizas.netlify.app/equipo-contratista/?modo=cliente)
  • Botón Copiar → al portapapeles, listo para WhatsApp/email
  • Botón Previsualizar → abre el reporte cliente en pestaña nueva para validar antes de enviar

Esto evita que JC arme el URL a mano cada vez (y se le olvide el ?modo=cliente, que es el gate que oculta toolbar/banner/edit). El banner se oculta automáticamente en modo cliente para que el EBI nunca lo vea.

CRUD agente + Excel I/O (workflow de cartera)

El modo agente tiene una toolbar arriba de la tabla con 5 acciones:

Botón Qué hace
+ Agregar equipo (primary dorado) Abre el modal editor con zona sugerida = max + 1
Importar Excel Reemplaza la lista entera desde un Excel/CSV. Headers flexibles (zona/Zona, descripcion/Descripción, etc.)
Exportar Excel Descarga EBI-Equipos-YYYY-MM-DD.xlsx con los equipos actuales
Exportar data.js (accent) Descarga data.js regenerado para pegar al repo y commitear
Resetear (ghost) Borra localStorage y vuelve a la lista del repo

Modal editor (mismo formulario para agregar y editar): zona, código, descripción, chasis, póliza, vigencia, suma_asegurada, prima, coberturas, docs_url. Validación de campos obligatorios + check de zona única.

Drawer de detalle (al click en una fila) agrega 2 botones abajo: Editar equipo (abre modal en modo edit) y Eliminar de la cartera (con confirm).

Persistencia

  • Agente: localStorage key ebi_polizas_v1. Si existe, la app carga de ahí; si no, usa POLIZAS del data.js como default. Cualquier cambio (agregar/editar/eliminar/importar Excel) se guarda automáticamente en localStorage.
  • Cliente: SIEMPRE lee de POLIZAS (data.js). NUNCA toca localStorage. El cliente solo ve lo que está en el repo.

Dirty badge

Cuando la lista en localStorage difiere del POLIZAS original del data.js, aparece un pill naranja "Cambios locales sin pushear" en la toolbar. Es el recordatorio visual de que hay que exportar el data.js y commitear para que el cliente vea los cambios.

Flujo de actualización de cartera

1. Agente edita en la app (agregar / editar / eliminar / importar Excel)
   → cambios persistidos en localStorage
   → dirty badge aparece

2. Cuando está listo:
   → click "Exportar data.js"
   → se descarga el archivo
   → JC lo pega en js/data.js del repo (o me lo pasa)
   → commit + push
   → Netlify deploya
   → cliente ve actualizado al recargar

3. Después del push:
   → si la lista local = lista del repo, dirty badge desaparece
   → si JC quiere descartar cambios locales, "Resetear"

Importante: el Excel maestro de JC debe mantenerse en OneDrive como source of truth para auditorías. La app es solo una herramienta de edición visual; el data.js del repo es lo que ve el cliente.

Lógica del drawer (ambos modos · cliente read-only)

Click en una fila → openDrawer(zona) arma un panel lateral. El contenido varía según MODE:

Siempre (agente + cliente):

  • Cabecera: badge ZONA + título descripcion + póliza hija
  • Grid 2 columnas: Código, Chasis, Vigencia, Coberturas (con expansión "Equipo · Lucro · Piezas"), N° Póliza, Estado
  • Bloque dorado: Suma Asegurada + Prima Anual destacadas
  • Bloque "Documentación digital" si docs_url está cargado: CTA "Abrir documentos en Drive" (target=_blank)

Solo agente:

  • Bloque "Documentación digital (Google Drive)" cuando docs_url está vacío: muestra "Sin link de Drive vinculado todavía" con hint para vincular
  • Bloque "Carpeta del archivo digital" (badge naranja "interno"): ruta completa BASE_PATH\Zona N- 0101POLIZA + botón "Copiar ruta" (usa navigator.clipboard con fallback a document.execCommand('copy'))
  • Acciones: Editar equipo (abre modal en modo edit) + Eliminar de la cartera (con confirm)

El cliente solo ve lo que es relevante para él: detalles de la póliza + Drive si hay documentación. Nunca ve la ruta del filesystem interno del agente, ni recordatorios de "falta cargar Drive", ni acciones de edición.

Branding SDI

El portal es producto de Seguros Digitales SDI (marca registrada y propiedad intelectual de Juan Carlos Hernández). El INS aparece como carrier (asegurador), no como marca de la app. Reglas:

  • Logo SDI siempre visible — variante logo-negativo.svg (blanco) sobre fondos navy (navbar agente, header report cliente), variante logo-principal.svg (azul color) sobre fondo cream (footer cliente).
  • Tagline "SEGUROS DIGITALES" aparece debajo del logo en versiones grandes (header cliente, footer).
  • Footer cliente (visible en pantalla y al imprimir PDF) cierra siempre con la línea legal:

    Servicio profesional de Seguros Digitales SDI · Marca registrada y propiedad intelectual de Juan Carlos Hernández.
    Pólizas suscritas con el Instituto Nacional de Seguros (INS) · Agente Juan Carlos Hernández. Documento confidencial para uso exclusivo del titular asegurado.

  • Favicon = assets/brand/favicon.svg (cuadrado azul SDI #0369A1 con barras).
  • Cuando se reutilice este patrón para otros clientes (no EBI), mantener SDI como marca y solo cambiar el cliente/cartera.

Exportar PDF (modo cliente)

Botón flotante arriba-derecha → window.print(). El @media print en app.css:

  • Oculta .no-print (botón, filtros, drawer, toast, navbar)
  • Fuerza fondos navy/dorado en headers/footers/tfoot con -webkit-print-color-adjust: exact
  • A4 landscape 12mm × 10mm
  • page-break-inside: avoid en stats, fleet cards, tabla rows
  • Tipografía a 9-10pt para que entre todo

Recursos externos

  • Carpeta de archivo digital: C:\Users\segur\OneDrive\ARCHIVO DIGITAL\Equipo Contratista\E\Empresas Berthier Ebi de Costa Rica S.A\ (estructura Zona N- 0101NUMPOLIZA)
  • Cliente: Empresas Berthier EBI de Costa Rica S.A. — operación de equipo contratista (recolección y manejo de residuos, expandido a otras líneas)
  • Carrier: INS — pólizas tipo Equipo Contratista (EQC)
  • Códigos de cobertura INS (póliza EQC): E = Daño Directo · L = Responsabilidad Civil Extracontractual · F = Robo y Hurto · G = Riesgos Adicionales · P = Paquete F y G (= F + G). Las 66 pólizas de EBI tienen "E L P" uniforme. Mapa en js/utils.js#COBERTURAS_MAP.

Cómo trabajar este proyecto

Para actualizar la cartera (incluir nuevo equipo / vencimiento)

  1. Editar js/data.js — agregar o modificar objeto en POLIZAS.
  2. Si el equipo es inclusión del período, asignarle zona >= 102 (la app lo marca automáticamente con badge "Nuevo" y borde dorado).
  3. Verificar local con http://localhost:8920 (entrada ebi-polizas en launch.json global).
  4. Commit + push a main → Netlify deploy 1-2 min.

Para cambios visuales o de copy

  • Tokens CSS en :root (app.css líneas iniciales) — cambiar paleta una sola vez ahí.
  • Iconos: agregar SVG nuevo a ICONS en utils.js (formato Lucide 24x24 currentColor).
  • Copy: la mayoría está en index.html (header reporte, footer, leyenda). Tabla y drawer se arman dinámicamente desde JS.

Para crear OTRO reporte EBI (póliza distinta)

Patrón establecido el 16 may 2026 con IMR: las nuevas pólizas se agregan como sub-carpeta del mismo repo ebi-polizas, NO como repo nuevo. Esto permite el portal landing futuro y mantiene branding/preview/deploy unificado.

  1. Crear sub-carpeta /<nombre-poliza>/ (ej. /responsabilidad-civil/, /flota-administrativa/).
  2. Replicar estructura interna: index.html + css/app.css + js/{data,utils,app}.js + docs/.
  3. CSS: copiar el CSS de IMR (o EQC) como base. Override --sdi-dorado y --sdi-dorado-lt para un nuevo acento de color que diferencie la póliza (cada póliza un color SDI distinto).
  4. data.js: ajustar POLIZA_INFO + colección principal (ZONAS, POLIZAS, etc.) según modelo del producto INS.
  5. index.html: ajustar título en navbar + report-header (mantener marca SDI). Ajustar columnas de la tabla según los campos del nuevo modelo.
  6. app.js: adaptar render de stats/tabla/drawer al modelo. Mantener: routing modo, share-banner, footer, dirty badge, Excel I/O, modal editor, drawer agente vs cliente.
  7. SKILL.md: agregar la nueva sub-página a la tabla "Pólizas activas" arriba.

Sub-página Incendio Multirriesgo (IMR)

Sub-página dedicada en /incendio-multirriesgo/ para la póliza madre 01-01-MRM-0000055-04 (Seguro de Incendio Multirriesgo INS, registro G06-69-A01-795 V8). 4 zonas de riesgo operativas:

Zona N° Póliza Hija Descripción Ubicación Suma Asegurada (80%) Prima Total Acreedor
1 IMR 0000318 04 Oficinas Centrales San José · La Uruca ₡491.421.221 ₡1.204.736 BAC ₡253.3M (Edificio)
2 IMR 0000319 04 Planta ACZARRI San José · Aserrí (El Huazo) ₡2.072.917.664 ₡5.236.263 BAC ₡179.0M (Equipo paneles solares)
3 IMR 0000320 04 Planta La Uruca San José · La Uruca ₡815.005.000 ₡2.031.316 BAC ₡168.8M (Maquinaria)
4 IMR 0000321 04 Planta El Tomatal Limón · Limón Centro ₡215.600.000 ₡531.303 — Libre —
Total ₡3.594.943.885 ₡9.003.618

Coaseguro 80% — el asegurado declara el 80% del valor real del bien. Cálculo del valor real al 100% (valorReal100(z) en utils.js):

  • Edificio, Equipos, Mobiliario, Maquinaria, Otras Estructuras → suma / 0.80
  • Mercadería NO aplica coaseguro (Coaseguro=N en condiciones) → se mantiene al 100%
  • Total al 100% = ₡4.417.918.606 (coincide con tabla del Adendum)

Modelo de datos IMR (incendio-multirriesgo/js/data.js)

A diferencia de EQC (un equipo = una fila con chasis/equipo/suma plana), IMR tiene una estructura jerárquica por zona:

{
  zona: 1,
  poliza: "IMR 0000318 04",        // hija (madre es MRM-0000055)
  descripcion: "Oficinas Centrales",
  provincia: "San José",
  canton: "San José",
  distrito: "La Uruca",
  direccion: "200 sur y 175 este del Puente Juan Pablo II",
  ocupacion: "Reciclaje desechos metálicos y no metálicos",
  folio_real: "1-682375-000",
  vigencia: "03/08/2025  03/08/2026",
  rubros: {                         // 6 partidas INS Multirriesgo (códigos 01/04/06/08/11/12)
    edificio: 413421221,            // 01 · base Reposición
    mercaderia: 0,                  // 04 · base Contable · NO aplica coaseguro
    otras_estructuras: 0,           // 06 · base Reposición
    equipos: 60800000,              // 08 · base Reposición
    mobiliario: 17200000,           // 11 · base Reposición
    maquinaria: 0                   // 12 · base Reposición
  },
  coberturas: {                     // 3 coberturas + IVA
    c_inundacion: 43147,            // C · Todo Riesgo Inundación/Deslizamiento/Vientos (5% mín ¢1M)
    d_convulsiones: 802933,         // D · Todo Riesgo Convulsiones de la Naturaleza (5% mín ¢1M)
    t_no_catastrofico: 220058,      // T · Todo Riesgo No Catastrófico (¢1M fijo)
    iva: 138598                     // Impuesto al Valor Agregado
  },
  prima_total: 1204736,             // suma de coberturas + IVA
  acreedor: {                       // o null si la zona está libre
    nombre: "BANCO BAC SAN JOSE SOCIEDAD ANONIMA",
    cedula: "3-101-012009",
    monto: 253250000,
    tipo: "Hipotecario",            // "Hipotecario" | "Prendario" | "Otro"
    rubro: "Edificio",
    observaciones: ""
  },
  docs_url: ""                      // Drive opcional
}

Helper clave: sumRubros(z) calcula la suma asegurada al 80%. valorReal100(z) reconstruye el valor real ajustando por el rubro de mercadería que no aplica coaseguro.

Documentos generales IMR

3 PDFs en incendio-multirriesgo/docs/generales/:

  1. Adendum 001-2025 (adendum-001-2025.pdf) — pieza maestra del producto. Consolida coaseguro 80%, sublímites (robo, rotura maquinaria, propiedades menores, etc.), gastos adicionales (alquiler 6 meses, demolición, escombros), cláusulas especiales (destrucción preventiva ¢150M, errores y omisiones, inclusión nuevos bienes), base de valoración, condiciones especiales, aseguramiento paneles solares, medidas de seguridad por zona.
  2. Condiciones Generales V8 (condiciones-generales.pdf) — documento oficial INS G06-69-A01-795 V8 del 03/05/2024, registrado ante SUGESE.
  3. (No hay PDF separado de "medidas de seguridad" porque están dentro del Adendum.)

CSS de IMR (acento verde teal · incendio-multirriesgo/css/app.css)

Base: copia íntegra del CSS de EQC. Override en :root que reasigna las variables de acento del CSS heredado:

:root {
  --sdi-dorado-real: #C9A227;       /* color SDI original, reservado para logos */
  --sdi-dorado:      #0D9488;       /* IMR override · verde teal acento UI */
  --sdi-dorado-lt:   #14B8A6;       /* IMR override · verde teal claro */
  --color-gold-soft: rgba(13, 148, 136, 0.12);  /* IMR */
  --color-new:       #ECFDF5;       /* IMR · verde muy pálido */
}

El acento --sdi-dorado (que internamente referencia el ID del token, no su valor visual) ahora apunta al verde teal. Todos los componentes heredados de EQC (stats, share-banner, modal-button-primary, hover de tabla, badge "Nuevo", policy-doc accent, drawer chevrons, detail-pdf gradient) automáticamente toman verde sin cambiar 150+ referencias en el CSS heredado. Los logos SDI tienen sus colores hardcoded inline en los <rect> SVG — no se ven afectados y mantienen la paleta tricolor SDI original (azul + verde + naranja + dorado real).

Componentes específicos de IMR agregados al final del CSS:

  • .coaseguro-badge — pill verde en navbar/header indicando "Coaseguro 80%"
  • .rubros-section + .rubro-card — 6 cards de composición por rubro (con icono, código, base de valoración y monto + %)
  • .locations-section + .location-card — 4 cards de zonas (solo cliente) con pin + provincia/cantón/distrito + dirección + suma
  • .detail-rubros + .detail-rubro — desglose por rubro en drawer (grid 2 col, monto por partida)
  • .detail-coberturas + .detail-cobertura — primas por cobertura con código tag + deducible
  • .detail-acreedor — card azul SDI con datos del banco acreedor
  • .detail-no-acreedor — banner verde "Libre de gravamen" cuando no hay acreedor
  • .modal-fieldset + .modal-grid-3 + .modal-grid-2 — fieldsets con leyenda dorada/verde para agrupar inputs del modal editor (datos · rubros · coberturas · acreedor)
  • .cell-ubicacion + .cell-acreedor — cells custom para tabla IMR

Modal editor IMR (4 fieldsets)

A diferencia de EQC (modal simple con 10 inputs en grid 2 col), IMR tiene 4 fieldsets agrupados visualmente:

  1. Identificación de la zona (11 inputs): zona, póliza, descripción, provincia, cantón, distrito, dirección, ocupación, folio real, vigencia, docs_url
  2. Rubros asegurados (6 inputs en grid 3-col): edificio · mercadería · otras estructuras · equipos · mobiliario · maquinaria
  3. Primas por cobertura (4 inputs en grid 2-col): C inundación · D convulsiones · T no catastrófico · IVA. La prima_total se calcula automáticamente al guardar.
  4. Acreedor (opcional) (6 inputs): nombre · cédula · monto · tipo (select Hipotecario/Prendario/Otro) · rubro · observaciones. Si nombre vacío → acreedor: null.

Validación: zona + póliza + descripción + provincia + cantón + dirección + vigencia obligatorios. Al menos un rubro > 0. Focus management: tras error, autofocus al primer campo inválido. Botón izquierdo dice "Salir" (convención SDI · solo destructivos usan "Cancelar").

Drawer IMR (más rico que EQC)

Click en fila → drawer con secciones en orden:

  1. Detail-grid (provincia/cantón, distrito, dirección, ocupación, folio real, vigencia, estado)
  2. Detail-money (suma asegurada 80% + prima total anual)
  3. Detail-rubros (desglose por rubro · 6 filas + suma)
  4. Detail-coberturas (4 filas con código tag + deducible + prima)
  5. Detail-acreedor (card azul con datos del banco) o detail-no-acreedor (banner verde)
  6. CTA "Descargar condiciones particulares" (PDF INS desde pdfUrl(r.poliza))
  7. Drive (si docs_url poblado) — ambos modos
  8. Solo agente: Carpeta del archivo digital interno (ruta OneDrive con botón copiar) + botones Editar/Eliminar zona

localStorage IMR

Key: ebi_imr_v1 (distinto de ebi_polizas_v1 que usa EQC). Cada sub-página mantiene su propia copia local — JC puede editar las 2 pólizas en paralelo sin colisión.

Excel I/O IMR

Export columnas (todas las que un agente necesita para auditar/respaldar):
zona · poliza · descripcion · provincia · canton · distrito · direccion · ocupacion · folio_real · vigencia · rubro_edificio · rubro_mercaderia · rubro_otras_estructuras · rubro_equipos · rubro_mobiliario · rubro_maquinaria · suma_asegurada (calc) · cob_c · cob_d · cob_t · cob_iva · prima_total · acreedor_nombre · acreedor_cedula · acreedor_monto · acreedor_tipo · acreedor_rubro · acreedor_observaciones · docs_url

Import acepta headers flexibles (lower/upper, con/sin tilde).

Acentos por póliza (para futuras sub-páginas)

Póliza Token de acento Color Hex
Equipo Contratista dorado SDI dorado #C9A227
Incendio Multirriesgo verde teal SDI verde #0D9488
(Siguiente póliza) sugerencia: naranja SDI #EA580C o azul SDI #0369A1

Si las pólizas son del MISMO cliente EBI pero distintos productos, consolidar en una sola app con selector de "póliza/sección" en navbar (el portal landing futuro cumple esta función). No duplicar en repos separados.

Reglas de oro

  1. Siempre verificar en preview local antes de pushear. Levantar ebi-polizas (puerto 8920) y probar las 3 vistas: portal (/), EQC (/equipo-contratista/ y /equipo-contratista/?modo=cliente), IMR (/incendio-multirriesgo/ y /incendio-multirriesgo/?modo=cliente).
  2. Datos sensibles: el reporte cliente es público por el link. No incluir CCSS, cédulas, teléfonos privados, montos de comisión del agente. Solo lo que JC le mostraría a EBI directamente.
  3. No agregar features no pedidas. JC quiere portal sobrio + reportes profesionales. Cualquier feature nueva (gráficas, export Excel, etc.) requiere decisión explícita.
  4. El campo vigencia viene del usuario en formato libre ("3/08/24 3/08/25", "21-10-24 03-08-26", "27/04/2026 03-08-2026"). NO normalizar a un parser de fechas — se rompería al cargar pólizas viejas con formatos distintos.
  5. Sync de SKILL.md en 2 ubicaciones obligatorio tras cambios: C:/Users/segur/.claude/skills/especialista-ebi/SKILL.md (user-level) y C:/Users/segur/ebi-polizas/SKILL.md (repo).
  6. NO usar el Claude Memory Engine para este proyecto — el engine se reorientó exclusivamente a SASINS (decisión JC 11 may 2026). Toda la memoria de EBI vive en este SKILL.md.

Entrega al cliente

JC tiene dos opciones para compartir con EBI:

Opción A — Portal completo (recomendado cuando EBI revisa varias pólizas):
https://ebi-polizas.netlify.app/
EBI ve el portal, selecciona la póliza que quiere consultar, y entra a la vista cliente de esa sub-página.

Opción B — Link directo a una póliza (cuando JC quiere mandar solo una):
https://ebi-polizas.netlify.app/equipo-contratista/?modo=cliente
https://ebi-polizas.netlify.app/incendio-multirriesgo/?modo=cliente

NUNCA compartir el link sin ?modo=cliente apuntando a una sub-página (expondría el drawer agente + filtros + ruta del archivo digital interno).