/* ─── Tokens de diseño ───────────────────────────────────────────────────────
 * MIGRACIÓN A TEMA CLARO (2026-07-30): el dashboard pasa del kiosco oscuro
 * (dark-blue #0A248F + paneles "glass") al tema claro real que define
 * busport_guia_desarrollador.html. Las variables --db-* se mantienen como
 * nombres (para no reescribir cada regla del archivo) pero ahora apuntan a
 * los tokens claros oficiales de la guía en vez de a colores oscuros/glass.
 *
 * Histórico de tokens reemplazados (dark-blue kiosco, ya no se usa):
 * --db-bg:#080c14 / #0A248F, --db-panel-bg:rgba(255,255,255,0.05) "glass",
 * --db-text:#fff sobre fondo oscuro, --db-accent:#58BB25 verde Busport.
 * ──────────────────────────────────────────────────────────────────────────── */
:root{
  /* Tokens oficiales de la guía (busport_guia_desarrollador.html, sección Tokens CSS) */
  --canvas:#eef1f5;
  --surface:#fff;
  --surface-2:#f5f7fa;
  --ink:#192238;
  --muted:#68748a;
  --line:#dce2ea;
  --navy-950:#11182f;
  --navy-900:#192348;
  --navy-800:#273467;
  --green-700:#176b1d;
  --green-600:#1f7f24;
  --green-500:#31ad32;
  --amber-700:#965000;
  --amber-600:#b96300;
  --blue-600:#2468b2;
  --red-600:#d93d45;
  --radius-sm:8px;
  --radius-md:12px;
  --radius-lg:16px;
  --space-1:4px;
  --space-2:8px;
  --space-3:12px;
  --space-4:16px;

  /* Alias --db-* usados por el resto de este archivo: ahora resuelven a
     superficies neutras claras en vez de fondo oscuro/glass translúcido. */
  --db-bg:var(--canvas);
  --db-panel-bg:var(--surface);
  --db-panel-bg-soft:var(--surface-2);
  --db-border:var(--line);
  --db-border-soft:var(--line);
  --db-navy:var(--navy-800);
  --db-accent:var(--green-600);  /* acento primario: verde marca */
  --db-accent2:var(--green-500);                   /* variante clara para hovers */
  --db-danger:var(--red-600);
  --db-success:var(--green-700);
  --db-warning:var(--amber-600);
  --db-text:var(--ink);
  --db-text-body:var(--ink);
  --db-text-muted:var(--muted);
  --db-radius:var(--radius-lg);       /* esquinas de tarjeta: 16px */
  --db-radius-sm:var(--radius-sm);    /* esquinas de botón/badge: 8px */
  --db-gap:9px;
  --db-transition:0.15s ease;
  /* Tipografía real de la guía: cuerpo Trebuchet/Segoe UI, títulos Arial
     Black/Trebuchet. Las fuentes propias (Galano Grotesque / Harabara Mais)
     solo existen embebidas en base64 dentro del HTML de la guía; no se
     extraen acá — se usan los fallbacks de sistema que la guía define. */
  --db-font-body:'Trebuchet MS','Segoe UI',Arial,sans-serif;
  --db-font-display:'Arial Black','Trebuchet MS',Arial,sans-serif;
}
#home{background:var(--canvas) !important;color:var(--ink);width:100%;height:100%;overflow:hidden}
.db-wrap{display:flex;flex-direction:column;width:100%;height:100vh;padding:12px 16px;box-sizing:border-box;gap:var(--db-gap);font-family:var(--db-font-body);-webkit-font-smoothing:antialiased}
/* Kicker: etiqueta pequeña verde arriba de los títulos de panel (spec Busport) */
.db-kicker{display:block;font-size:9px;font-weight:700;letter-spacing:1.4px;color:var(--db-accent);text-transform:uppercase;margin-bottom:2px}
/* Topbar */
.db-topbar{display:flex;align-items:center;gap:16px;padding:8px 18px;background:var(--surface);border:1px solid var(--line);border-radius:var(--db-radius);flex-shrink:0;height:46px;box-sizing:border-box;box-shadow:0 1px 3px rgba(17,24,47,0.06)}
.db-title{font-size:18px;font-weight:700;color:var(--ink);letter-spacing:0.2px;flex:1;font-family:var(--db-font-display)}
/* Título grande de sección estilo Busport: display bold 900 48px, reservado
   para un título hero si se necesita en alguna vista (no se usa en la topbar
   compacta del dashboard, que necesita legibilidad rápida, no impacto editorial). */
.db-hero-ttl{font-family:var(--db-font-display);font-weight:900;font-size:48px;color:var(--ink);line-height:1.05;margin:0}
.db-hero-ttl .kw{color:var(--db-accent)}
.db-clock{font-size:24px;font-weight:300;color:var(--ink);font-variant-numeric:tabular-nums;letter-spacing:1.5px}
.db-date{font-size:11px;color:var(--db-text-muted)}
/* Badge de estado: no hay botones de acción reales en este dashboard, así que
   el badge "OPERACIÓN NORMAL" funciona como el elemento de mayor jerarquía
   visual de la topbar, con esquinas 8px y relleno sólido como pide la spec
   de botones. Color sólido reservado a este indicador de estado real, no
   como fondo decorativo. */
.db-badge{font-size:10px;font-weight:700;letter-spacing:1.2px;padding:6px 16px;border-radius:var(--db-radius-sm)}
.badge-ok{background:var(--green-600);color:#fff;border:1px solid var(--green-700)}
.badge-alert{background:#fbe9ea;color:var(--red-600);border:1px solid #f2b9bc;animation:dbBlink 1s infinite}
@keyframes dbBlink{0%,100%{opacity:1}50%{opacity:0.45}}
/* Destello de alerta: borde + sombra interior roja pulsante sobre todo el
   overlay, solo durante los primeros segundos tras un positivo. No cubre
   el contenido (pointer-events:none), así los datos siguen legibles. */
.db-flash-alert{position:relative}
.db-flash-alert::after{
  content:'';
  position:fixed;
  inset:0;
  z-index:9999;
  pointer-events:none;
  border:6px solid var(--db-danger);
  box-shadow:inset 0 0 80px 10px rgba(217,61,69,0.35);
  animation:dbFlashPulse 0.8s ease-in-out infinite;
}
@keyframes dbFlashPulse{0%,100%{opacity:1}50%{opacity:0.35}}
/* KPI */
.db-kpi-row{display:flex;gap:var(--db-gap);flex-shrink:0;height:74px}
.db-kpi{flex:1;position:relative;background:var(--surface);border:1px solid var(--line);border-radius:var(--db-radius);padding:11px 16px;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;transition:border-color var(--db-transition);overflow:hidden;box-shadow:0 1px 3px rgba(17,24,47,0.05)}
.kpi-danger{border-color:#f2b9bc;background:#fdf3f3}
/* El ícono queda como badge decorativo en la esquina, así el número+label
   ocupan todo el ancho de la tarjeta en vez de quedar apretados a la izquierda
   con un hueco vacío a la derecha */
.db-kpi-icon{position:absolute;top:10px;right:12px;width:30px;height:30px;border-radius:var(--db-radius-sm);display:flex;align-items:center;justify-content:center;flex-shrink:0;opacity:0.9}
.db-kpi-icon svg{width:16px;height:16px}
.ic-blue{background:var(--surface-2);color:var(--navy-800)}
.ic-red{background:#fbe9ea;color:var(--red-600)}
.ic-green{background:#e6f3e6;color:var(--green-700)}
.ic-yellow{background:#fdf0dc;color:var(--amber-700)}
.ic-blue2{background:#e8eef7;color:var(--blue-600)}
.db-kpi-body{display:flex;flex-direction:column;min-width:0;width:100%}
.db-kpi-val{font-size:32px;font-weight:600;color:var(--ink);line-height:1.1;letter-spacing:-0.5px;font-variant-numeric:tabular-nums}
.val-red{color:var(--db-danger)}.val-green{color:var(--db-success)}.val-yellow{color:var(--db-warning)}
.db-kpi-lbl{font-size:12px;font-weight:500;color:var(--db-text-body);margin-top:5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-transform:uppercase;letter-spacing:0.6px}
.db-kpi-sub{font-size:10px;color:var(--db-text-muted);margin-top:1px}
/* Semáforo de estado de conexión (arriba del KPI "Online") */
.conn-dot{position:absolute;top:11px;left:14px;width:8px;height:8px;border-radius:50%;background:var(--muted);box-shadow:0 0 0 3px rgba(104,116,138,0.15);transition:background-color var(--db-transition),box-shadow var(--db-transition)}
.conn-dot.conn-ok{background:var(--green-600);box-shadow:0 0 0 3px rgba(31,127,36,0.18)}
.conn-dot.conn-error{background:var(--db-danger);box-shadow:0 0 0 3px rgba(217,61,69,0.2);animation:dbBlink 1s infinite}
/* Layout */
/* .db-main ahora es una columna: fila superior (3 columnas) + fila inferior
   de gráficos (donuts + tendencia). Mantenemos el criterio de kiosco sin
   scroll salvo en la tabla de actividad reciente. */
.db-main{display:flex;flex-direction:column;gap:var(--db-gap);flex:1;min-height:0}
/* Grid (no flex) con el MISMO grid-template-columns que .db-bottom-row más
   abajo, así las 3 columnas quedan matemáticamente alineadas en px con la
   fila inferior — con flexbox puro dos filas independientes con "flex:1"
   pueden diferir en unos px según bordes/redondeo, con grid compartido no. */
.db-main-top{display:grid;grid-template-columns:22% 1fr 33%;gap:var(--db-gap);flex:1;min-height:0}
.db-col-l{display:flex;flex-direction:column;min-width:0;min-height:0}
/* flex-start (no "center") para que el panel arranque pegado arriba, igual
   que db-col-l y db-col-r — antes quedaba centrado verticalmente y el borde
   superior no coincidía con el resto de la fila. */
.db-col-c{display:flex;flex-direction:column;align-items:stretch;gap:var(--db-gap);min-width:0;min-height:0}
.db-col-r{display:flex;flex-direction:column;min-width:0;min-height:0}
/* Panels — tema claro real de la guía: tarjeta blanca sólida, borde sutil
   gris (--line) y esquinas de 16px, sin el efecto "glass" translúcido/blur
   del experimento dark-blue anterior (ese efecto no es parte del sistema de
   la guía). Sombra muy suave, apenas perceptible, solo para separar del
   fondo --canvas gris claro. */
.db-panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--db-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 1px 3px rgba(17,24,47,0.05)}
/* Panel que ocupa toda la altura de su columna (Último Positivo / Actividad
   Reciente ahora que cada uno vive solo en su columna) */
.db-panel-full{flex:1;min-height:0}
/* flex:1 (no alto fijo) para que ocupe toda la altura de la columna, igual
   que "Actividad Reciente" en db-col-r. El JS ya no fuerza un alto fijo con
   !important (ver buildUI() en dashboard.js) — esta es ahora la única fuente
   de verdad. min-width:0 evita que el contenido interno (foto fija de 280px
   + texto) desborde el ancho de la columna en vez de recortarse. */
.db-panel-face{flex:1;flex-direction:row !important;align-items:center;padding:14px 16px;gap:14px;width:100%;min-width:0;min-height:0;box-sizing:border-box}
.db-panel-table{min-height:0}
/* Fila inferior de gráficos: Dispositivos, Proporción Hoy y Tendencia Semanal
   agrupados como franja de apoyo, con altura fija compacta (no compiten en
   protagonismo con los paneles principales de arriba) */
/* Mismo grid-template-columns que .db-main-top (ver arriba) para alineación
   exacta en px: Dispositivos bajo "Último Positivo", Proporción Hoy bajo la
   foto/detalles, Tendencia Semanal bajo Actividad Reciente. */
.db-bottom-row{display:grid;grid-template-columns:22% 1fr 33%;gap:var(--db-gap);flex:0 0 158px}
.db-bottom-panel{min-height:0;min-width:0}
.db-panel-hdr{padding:8px 14px 6px;flex-shrink:0;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:8px}
.db-panel-ttl{font-size:12px;font-weight:700;color:var(--ink);text-transform:uppercase;letter-spacing:1.6px;font-family:var(--db-font-display)}
.db-panel-count{font-size:9px;color:var(--db-accent);margin-left:4px;font-weight:600}
.db-chart{flex:1;min-height:0;width:100%}
/* Face */
/* Responsiva de verdad: tamaño atado al contenedor real (flex-grow + height:100%)
   en vez de unidades de viewport (vw). "vw" depende de que el navegador
   realmente reporte un innerWidth más grande en la pantalla nueva — si el
   kiosco corre con zoom/escalado de Windows o una ventana de tamaño fijo,
   "vw" no cambia aunque el monitor sea físicamente más grande, y la foto se
   queda del mismo tamaño. flex-grow + height:100% en cambio siempre reflejan
   el tamaño real ya calculado del panel (que si es responsivo, vía el layout
   flex/grid del dashboard), así que la foto SIEMPRE ocupa el espacio real
   disponible sin importar de dónde salga ese espacio. flex:2 le da más
   proporción que a la columna de datos (flex:1). */
.db-face{flex:2 1 200px;min-width:200px;height:100%;border-radius:10px;object-fit:cover;border:1px solid var(--line);background:var(--surface-2)}
.db-face-info{flex:1 1 220px;display:flex;flex-direction:column;min-width:0}
.db-face-row{display:flex;flex-direction:column;padding:6px 0;border-bottom:1px solid var(--line)}
.db-face-row:last-child{border-bottom:none}
.db-face-lbl{font-size:14px;color:var(--db-text-muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:3px;font-weight:600}
.db-face-row span:last-child{font-size:20px;color:var(--ink);font-weight:500}
.alcohol-pos{color:var(--db-danger) !important;font-weight:700 !important}
.alcohol-neg{color:var(--db-success) !important;font-weight:600}
/* Records — NO scroll */
.db-records-body{flex:1;overflow:hidden;padding:4px 10px}
.db-rec-hdr,.db-rec-row{display:grid;grid-template-columns:64px minmax(0,1fr) 110px 90px;gap:8px;padding:5px 6px;font-size:11px;align-items:center}
.db-rec-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.db-rec-hdr{color:var(--db-text-muted);font-size:9px;text-transform:uppercase;letter-spacing:1px;font-weight:700;border-bottom:1px solid var(--line);margin-bottom:2px}
.db-rec-row{color:var(--db-text-body);border-bottom:1px solid var(--line);transition:background-color var(--db-transition)}
.db-rec-row:last-child{border-bottom:none}
.db-rec-row:hover{background-color:var(--surface-2)}
.row-alert{color:var(--red-600) !important}
.row-alert span{color:var(--red-600) !important}
.row-alert:hover{background-color:#fbe9ea}
/* Scrollbar sutil (por si algún panel llega a necesitar overflow) */
.db-panel ::-webkit-scrollbar{width:6px;height:6px}
.db-panel ::-webkit-scrollbar-thumb{background:var(--line);border-radius:3px}
.db-panel ::-webkit-scrollbar-track{background:transparent}
