/* =========================================================
   Sala Situacional — estilos del dashboard.
   Usa las variables de tema definidas en style.css (claro/oscuro).
   ========================================================= */

/* ---- KPIs grid ---- */
.d-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 1rem;
  margin-bottom: 2rem;
}
.d-kpi {
  padding: 1.25rem 1.5rem;
  border-left: 3px solid var(--accent);
  border-radius: 12px;
  background: var(--soft-bg);
  border: 1px solid var(--panel-border);
  backdrop-filter: blur(8px);
}
.d-kpi.alert  { border-left-color: var(--danger); }
.d-kpi.alert .d-v { color: var(--danger); }
.d-kpi.warn   { border-left-color: var(--warning); }
.d-kpi.ok     { border-left-color: var(--success); }
.d-kpi.accent { border-left-color: #0d9488; }
.d-v { font-size: 2rem; font-weight: 800; line-height: 1; }
.d-l { font-size: 0.72rem; color: var(--text-muted); margin-top: 6px; text-transform: uppercase; letter-spacing: .3px; }

/* ---- Insights / Conclusiones ---- */
.insights-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 12px;
}
.insight {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 12px 14px;
  border-radius: 10px;
  background: var(--soft-bg);
  border: 1px solid var(--panel-border);
  border-left: 3px solid var(--accent);
}
.insight.alerta { border-left-color: var(--danger); }
.insight.warn   { border-left-color: var(--warning); }
.insight.ok     { border-left-color: var(--success); }
.insight.info   { border-left-color: var(--accent); }
.insight-icon    { font-size: 1.5rem; line-height: 1; flex-shrink: 0; }
.insight-titulo  { font-weight: 700; font-size: .9rem; margin-bottom: 3px; }
.insight-detalle { font-size: .78rem; color: var(--text-muted); line-height: 1.45; }

/* ---- Grid de paneles ---- */
.d-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
  margin-bottom: 1.5rem;
}
.d-panel {
  padding: 1.25rem 1.5rem;
  min-width: 0;
}
.d-panel-2  { grid-column: span 2; }
.d-panel-full { grid-column: span 3; }
.d-panel h3 {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text-main);
  margin: 0 0 1rem;
  padding-bottom: 0.65rem;
  border-bottom: 1px solid var(--panel-border);
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.d-panel h3 small {
  font-weight: 400;
  color: var(--text-muted);
  font-size: 0.74rem;
  flex: 1;
}
.d-chart-wrap { position: relative; height: 260px; }
.d-panel-2 .d-chart-wrap { height: 280px; }
.d-hint { font-size: 0.76rem; color: var(--text-muted); margin: 8px 0 0; }

/* ---- Panel full-width (mapa, tabla, etc.) ---- */
.d-full {
  margin-bottom: 1.5rem;
}

/* ---- Upload panel ---- */
.d-upload-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr auto;
  gap: 1rem;
  align-items: end;
  padding-top: 0.5rem;
}
.d-upload-item label {
  display: block;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 4px;
  text-transform: uppercase;
}
.d-upload-item input[type=file] {
  display: block;
  width: 100%;
  font-size: 0.82rem;
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  padding: 6px 8px;
  background: var(--input-bg);
  color: var(--text-main);
  cursor: pointer;
}
.d-upload-actions { display: flex; flex-direction: column; gap: 6px; }
/* Fecha de corte, junto al botón de procesar: es una decisión que se toma en ese momento,
   no un ajuste escondido. La etiqueta envuelve al campo para que se pueda pulsar el texto. */
.corte-label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: .76rem; font-weight: 600; color: var(--text-muted);
}
.corte-input { max-width: 190px; min-height: 34px; }
#corte-hint { margin-top: .4rem; }
.btn-process {
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 9px 18px;
  cursor: pointer;
  font-weight: 600;
  font-size: 0.88rem;
  white-space: nowrap;
  transition: background 0.2s;
}
.btn-process:hover    { background: var(--accent-hover); }
.btn-process:disabled { opacity: 0.5; cursor: not-allowed; }
/* Acción alterna junto a la principal (p. ej. «Por nombre» junto a «Buscar»). */
.btn-secundario       { background: transparent; color: var(--text-main);
                        border: 1px solid var(--panel-border); }
.btn-secundario:hover { background: var(--soft-bg); }
.proc-status { font-size: 0.78rem; color: var(--text-muted); }

/* ---- Stats list (integración/calidad) ---- */
.stats-list { display: flex; flex-direction: column; gap: 8px; }
.stat-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 7px 10px;
  border-radius: 8px;
  background: var(--soft-bg);
  font-size: 0.85rem;
  border: 1px solid var(--panel-border);
}
.stat-row b { font-size: 1rem; }
.stat-row.flag { background: rgba(239,68,68,0.12); color: var(--danger); border-color: rgba(239,68,68,0.25); }
.stat-row.good { background: rgba(16,185,129,0.12); color: var(--success); border-color: rgba(16,185,129,0.25); }

/* ---- Mapa ---- */
#mapa {
  height: 460px;
  border-radius: 10px;
  overflow: hidden;
  z-index: 1;
  border: 1px solid var(--panel-border);
}
.map-legend {
  background: var(--legend-bg);
  color: var(--text-main);
  padding: 8px 10px;
  border-radius: 8px;
  font-size: 0.74rem;
  line-height: 1.6;
  border: 1px solid var(--panel-border);
  box-shadow: var(--shadow);
}
.map-legend i {
  display: inline-block;
  width: 12px; height: 12px;
  border-radius: 2px;
  margin-right: 6px;
  vertical-align: middle;
}
.leaflet-popup-content-wrapper {
  background: var(--popup-bg);
  color: var(--text-main);
  border: 1px solid var(--panel-border);
  border-radius: 10px;
}
.leaflet-popup-tip { background: var(--popup-bg); }
.leaflet-popup-content { font-size: 0.8rem; line-height: 1.5; }

/* ---- Indicadores ---- */
.d-indicadores { display: flex; flex-direction: column; gap: 10px; }
.d-ind {
  padding: 10px 14px;
  border-radius: 10px;
  background: var(--soft-bg);
  border-left: 3px solid var(--accent);
  border: 1px solid var(--panel-border);
  border-left: 3px solid var(--accent);
}
.d-ind-v { font-size: 1.5rem; font-weight: 800; line-height: 1; }
.d-ind-l { font-size: 0.76rem; color: var(--text-muted); margin-top: 4px; }
.d-ind.alert { border-left-color: var(--danger); background: rgba(239,68,68,0.08); }
.d-ind.alert .d-ind-v { color: var(--danger); }
.d-ind.ok    { border-left-color: var(--success); }

/* ---- Tabla geográfica ---- */
.d-table-wrap { overflow: auto; max-height: 380px; }
.d-table-wrap table { width: 100%; border-collapse: collapse; font-size: 0.83rem; }
.d-table-wrap th, .d-table-wrap td {
  text-align: left;
  padding: 8px 12px;
  border-bottom: 1px solid var(--panel-border);
}
.d-table-wrap th {
  background: var(--hover-bg);
  color: var(--text-muted);
  font-weight: 600;
  position: sticky;
  top: 0;
}
.d-table-wrap td:not(:first-child),
.d-table-wrap th:not(:first-child) { text-align: right; }
.d-table-wrap tbody tr:hover { background: var(--soft-bg); }

/* ---- Tablas consolidadas (confirmados / en investigación / descartados) ---- */
.t-cons-scroll { max-height: 520px; }
/* la 2.a columna de la tabla distrital es Provincia: texto, no cifra */
#tablaDistritos td:nth-child(2), #tablaDistritos th:nth-child(2) { text-align: left; }

.t-cons-total { font-weight: 700; background: var(--soft-bg); }
.t-cons-total td { border-top: 2px solid var(--panel-border); }
.t-cons tfoot { position: sticky; bottom: 0; }
/* La fila TOTAL flota sobre el resto de la tabla, así que necesita DOS cosas que no tenía:
   1. el fondo en las CELDAS y no en la fila -- un `background` sobre un <tr> no se pinta
      cuando el tfoot es sticky;
   2. un color OPACO. `--hover-bg` es un blanco al 5 %, pensado para teñir una fila que ya
      está sobre el panel; usado aquí dejaba ver el último distrito a través del TOTAL, con
      las dos cifras impresas una encima de otra. `--popup-bg` es el color sólido con el que
      el tema pinta lo que se superpone al contenido.
   Se notaba poco mientras la tabla cabía en pantalla; por residencia son 74 distritos y
   desborda siempre. */
.t-cons tfoot .t-cons-total td { background: var(--popup-bg); }
.t-cons-vacio { text-align: center !important; color: var(--text-muted); padding: 18px 12px; }

.t-cons th.t-ord { cursor: pointer; user-select: none; white-space: nowrap; }
.t-cons th.t-ord:hover { color: var(--text-main); }
.t-cons th.t-ord::after { content: '\2195'; opacity: .25; margin-left: 5px; font-size: .8em; }
.t-cons th.t-ord-act { color: var(--accent); }
.t-cons th.t-ord-act[data-dir="asc"]::after  { content: '\2191'; opacity: .9; }
.t-cons th.t-ord-act[data-dir="desc"]::after { content: '\2193'; opacity: .9; }

.t-cons-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
.t-cons-bar .d-hint { margin: 0; }
.t-cons-buscar {
  flex: 1 1 220px;
  max-width: 340px;
  padding: 7px 11px;
  border-radius: 8px;
  border: 1px solid var(--panel-border);
  background: var(--soft-bg);
  color: var(--text-main);
  font-size: 0.82rem;
}
.t-cons-buscar:focus { outline: 2px solid var(--accent, #3b82f6); outline-offset: 1px; }

/* ---- Botón descarga ---- */
.btn-download {
  display: inline-block;
  font-size: 0.73rem;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 6px;
  background: var(--success);
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
  transition: opacity 0.2s;
}
.btn-download:hover { opacity: 0.8; }

/* ============================================================
   Alta de usuarios: la política de contraseña, en pantalla
   Se muestra ANTES de escribir y se marca en verde según se cumple. Antes solo había una
   línea de texto y el único aviso llegaba como error del servidor al pulsar Guardar.
   ============================================================ */
.nu-form{margin-bottom:1rem;padding:1rem;background:var(--soft-bg);border-radius:10px;
  border:1px solid var(--panel-border);}
/* auto-fit en vez de columnas fijas: el formulario se reordena solo en tablet y celular. */
.nu-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:1rem;}
.nu-ayuda{display:block;margin-top:4px;line-height:1.45;}
.nu-pw-row{display:flex;gap:5px;align-items:stretch;}
.nu-pw-row .d-input{flex:1 1 auto;min-width:0;}
.nu-pw-btn{flex:0 0 auto;width:36px;min-height:36px;border-radius:8px;cursor:pointer;
  border:1px solid var(--panel-border);background:var(--soft-bg);color:var(--text-main);
  font-size:.95rem;line-height:1;display:inline-flex;align-items:center;justify-content:center;}
.nu-pw-btn:hover{background:var(--hover-bg);}
.nu-pw-btn.activo{border-color:var(--accent);color:var(--accent);}
.nu-barra-fondo{height:6px;border-radius:4px;background:rgba(128,128,128,.25);margin-top:6px;
  overflow:hidden;}
.nu-barra{height:100%;width:0;transition:width .2s,background .2s;}
.nu-reqs{margin-top:6px;font-size:.74rem;line-height:1.75;color:var(--text-muted);}
.nu-req-ok{color:var(--success);}
.nu-acciones{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:1rem;}
.nu-acciones .proc-status{margin:0;}
/* Aviso posterior al alta: la contraseña no vuelve a mostrarse nunca, hay que entregarla ya. */
.nu-entrega{margin-top:.8rem;padding:.7rem .9rem;border-radius:10px;font-size:.82rem;
  border:1px solid var(--success);background:rgba(16,185,129,.10);line-height:1.6;}
.nu-entrega code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.86rem;
  padding:1px 6px;border-radius:5px;background:var(--input-bg);}

/* ============================================================
   Casos por distrito (vista secundaria)
   ============================================================ */
.dist-barra{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-bottom:.8rem;}
.dist-barra .d-input{flex:1 1 220px;max-width:340px;}
.dist-tot{display:flex;gap:.5rem;flex-wrap:wrap;margin-left:auto;}
.dist-tot span{font-size:.76rem;padding:3px 10px;border-radius:20px;background:var(--soft-bg);
  border:1px solid var(--panel-border);white-space:nowrap;}
.dist-tot b{color:var(--text-main);}
#tablaDistritoCasos tbody tr{cursor:pointer;}
#tablaDistritoCasos td.dist-nom{font-weight:700;color:var(--text-main);}
.dist-conf{color:var(--danger);font-weight:800;}
.dist-inv{color:var(--warning);font-weight:700;}
.dist-detalle{padding:0 !important;}
.dist-detalle-box{padding:.7rem .9rem;background:var(--soft-bg);border-left:3px solid var(--accent);}
.dist-detalle-tit{font-size:.82rem;font-weight:700;margin-bottom:.5rem;display:flex;gap:10px;
  align-items:center;flex-wrap:wrap;}
.dist-detalle-tit .btn-process{padding:3px 10px;font-size:.72rem;}
.dist-caso{display:grid;grid-template-columns:1fr auto;gap:4px 12px;padding:.35rem 0;
  border-bottom:1px solid var(--panel-border);font-size:.79rem;}
.dist-caso:last-child{border-bottom:none;}
.dist-caso-sub{grid-column:1/-1;color:var(--text-muted);font-size:.73rem;}

/* ---- Sidebar meta (corte/ambit) ---- */
.sidebar-meta {
  margin-bottom: 1.5rem;
  padding: 0.75rem;
  border-radius: 8px;
  background: var(--soft-bg);
  border: 1px solid var(--panel-border);
}
.sidebar-meta .meta-corte {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-main);
}
.sidebar-meta .meta-ambito {
  font-size: 0.72rem;
  color: var(--text-muted);
  margin-top: 3px;
}
.sidebar-meta .meta-fuentes {
  font-size: 0.68rem;
  color: var(--text-muted);
  margin-top: 4px;
  line-height: 1.5;
}

/* ---- Footer ---- */
.d-footer {
  margin-top: 2rem;
  padding: 1rem 0;
  border-top: 1px solid var(--panel-border);
  font-size: 0.74rem;
  color: var(--text-muted);
  line-height: 1.6;
}
.d-footer p { margin: 2px 0; }

/* ---- Filtros ---- */
.d-filtros-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr auto;
  gap: 1rem;
  align-items: end;
}
.d-filtro-item label {
  display: block;
  font-size: .78rem;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 4px;
  text-transform: uppercase;
}
.d-filtro-item select,
.d-input {
  display: block;
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  background: var(--input-bg);
  color: var(--text-main);
  font-size: .85rem;
  outline: none;
  transition: border-color .2s;
}
.d-filtro-item select:focus,
.d-input:focus { border-color: var(--accent); }
.d-filtro-actions { display: flex; flex-direction: column; gap: 6px; }

/* ---- Chips de filtros activos ---- */
.filtros-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; align-items: center; }
.filtro-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--accent); color: #fff;
  font-size: .75rem; padding: 3px 10px; border-radius: 999px;
}
.filtro-chip b { font-weight: 700; }
.filtro-chip-x { cursor: pointer; opacity: .8; font-weight: 700; }
.filtro-chip-x:hover { opacity: 1; }
.filtro-chip-vacio { font-size: .78rem; color: var(--text-muted); font-style: italic; }

/* ---- Insignia y nota del panel Rt (número reproductivo efectivo) ---- */
.rt-badge {
  display: inline-block; margin-left: 10px; padding: 3px 12px;
  border-radius: 999px; font-size: .82rem; font-weight: 700;
  vertical-align: middle; border: 1px solid transparent;
}
.rt-badge span { font-weight: 500; opacity: .85; }
.rt-badge.rt-red   { background: rgba(220,38,38,.16);  color: var(--danger);  border-color: rgba(220,38,38,.35); }
.rt-badge.rt-amber { background: rgba(217,119,6,.16);  color: var(--warning); border-color: rgba(217,119,6,.35); }
.rt-badge.rt-green { background: rgba(22,163,74,.16);  color: var(--success); border-color: rgba(22,163,74,.35); }
.rt-nota { margin: 2px 0 12px; font-size: .8rem; color: var(--text-muted); line-height: 1.4; max-width: 70ch; }

/* ---- Resumen de generaciones (curva por generaciones) ---- */
.gen-resumen { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 14px; }
.gen-chip {
  display: inline-flex; flex-direction: column; gap: 2px;
  background: var(--input-bg);
  border-left: 4px solid var(--accent);
  border-radius: 8px;
  padding: 7px 12px;
  font-size: .8rem;
  color: var(--text-main);
}
.gen-chip small { color: var(--text-muted); font-size: .68rem; }
.gen-prov { color: var(--warning); font-style: italic; }

/* ---- Reporte markdown ---- */
.reporte-md {
  font-size: .85rem;
  line-height: 1.7;
  color: var(--text-main);
  max-height: 600px;
  overflow: auto;
  padding: 1rem;
  background: var(--input-bg);
  border-radius: 10px;
  border: 1px solid var(--panel-border);
  white-space: pre-wrap;
  font-family: 'Courier New', monospace;
}
.reporte-md h1, .reporte-md h2, .reporte-md h3 { color: var(--accent); margin: 1rem 0 .4rem; }
.reporte-md table { border-collapse: collapse; width: 100%; margin: .5rem 0; }
.reporte-md th, .reporte-md td { border: 1px solid var(--panel-border); padding: 4px 8px; }
.reporte-md th { background: var(--hover-bg); }
.reporte-md hr  { border-color: var(--panel-border); margin: 1rem 0; }

/* ---- Toggle Distritos / Provincias ---- */
.map-toggle-group {
  display: inline-flex;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--panel-border);
  margin-left: auto;
}
.btn-map-toggle {
  background: var(--soft-bg);
  color: var(--text-muted);
  border: none;
  padding: 4px 14px;
  font-size: .78rem;
  font-weight: 600;
  cursor: pointer;
  transition: background .15s, color .15s;
  white-space: nowrap;
}
.btn-map-toggle:hover  { background: var(--hover-bg); color: var(--text-main); }
.btn-map-toggle.active { background: var(--accent); color: #fff; }

.map-metrica-sel {
  margin-left: auto;
  padding: 5px 10px;
  border-radius: 8px;
  border: 1px solid var(--panel-border);
  background: var(--input-bg);
  color: var(--text-main);
  font-size: .8rem;
  font-weight: 600;
  cursor: pointer;
  outline: none;
}
.map-metrica-sel:focus { border-color: var(--accent); }
/* cuando hay selector, el grupo de vistas ya no necesita empujar a la derecha */
.map-metrica-sel + .map-toggle-group { margin-left: 8px; }

/* ---- Conmutador de base geográfica (notificación ↔ residencia) ----
   Reusa el aspecto del conmutador del mapa, pero se ancla a la IZQUIERDA y arriba de la
   tabla: `.map-toggle-group` empuja con `margin-left:auto` porque allí comparte fila con
   el título, y aquí es lo primero que hay que leer antes de mirar las cifras. */
.base-toggle { margin: 0 0 .7rem 0; }
/* El estado activo no puede depender SOLO del color: en la pantalla de un puesto de salud
   -brillo alto, monitor viejo- los dos botones se ven casi iguales. El activo lleva además
   un peso distinto y una marca. */
.base-toggle .btn-map-toggle.active { font-weight: 800; }
.base-toggle .btn-map-toggle.active::before { content: "✓ "; }
.base-toggle .btn-map-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
/* Marca de la fila cuyo paciente reside fuera de la región: su T.I.A. queda en blanco a
   propósito y sin este rótulo parecería un dato que falta. */
.base-fuera {
  font-size: .68rem; font-weight: 600; text-transform: uppercase; letter-spacing: .03em;
  color: var(--warning); border: 1px solid var(--warning); border-radius: 10px;
  padding: 0 6px; margin-left: 6px; white-space: nowrap;
}
/* Distrito donde las dos bases NO cuentan lo mismo (San Miguel: 2 por notificación, 193 por
   residencia). Va en rojo y no en gris a propósito: no es una nota al pie, es un aviso de que
   la cifra de la fila no es la que el lector cree que está leyendo. */
.base-discorda {
  font-size: .68rem; font-weight: 700; letter-spacing: .02em;
  color: var(--danger); border: 1px solid var(--danger); border-radius: 10px;
  padding: 0 6px; margin-left: 6px; white-space: nowrap; cursor: help;
}
/* Guion de la T.I.A. que no aplica. Atenuado para que se lea como «no corresponde» y no como
   «falta el dato»; el pie de la tabla explica por qué. */
.tia-na { color: var(--text-muted); cursor: help; }

/* Reparto por establecimiento: el distrito que NO es el de su código va atenuado, para que de
   un vistazo se vea si el establecimiento atiende lo suyo o lo de al lado. */
.rie-chip.rep-ajeno {
  color: var(--text-muted);
  border-color: var(--panel-border);
  background: transparent;
}


/* ---- Control de difusión temporal ---- */
#difusion-control {
  background: var(--soft-bg);
  border: 1px solid var(--panel-border);
  border-radius: 10px;
  padding: 10px 14px;
}
#difusion-info { color: var(--text-main); }
#difusion-slider {
  accent-color: var(--danger);
  height: 6px;
  cursor: pointer;
}
#difusion-play { background: var(--soft-bg); color: var(--text-main); }
#difusion-play:hover { background: var(--hover-bg); }

/* ---- Responsive ---- */
@media (max-width: 1100px) {
  .d-grid { grid-template-columns: 1fr 1fr; }
  .d-panel-2 { grid-column: span 2; }
  .d-panel-full { grid-column: span 2; }
  .d-upload-grid { grid-template-columns: 1fr 1fr; }
  .d-filtros-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 720px) {
  .d-grid { grid-template-columns: 1fr; }
  .d-panel-2, .d-panel-full { grid-column: span 1; }
  .d-upload-grid { grid-template-columns: 1fr; }
  .d-kpis { grid-template-columns: repeat(2, 1fr); }
  .d-kpi { padding: .9rem 1rem; }
  .d-v { font-size: 1.6rem; }
  .d-panel { padding: 1rem .9rem; }
  /* Los filtros venían con cuatro columnas fijas también en el móvil: los desplegables de
     semana quedaban de 60 px y no se podía elegir nada. */
  .d-filtros-grid { grid-template-columns: 1fr; gap: .7rem; }
  .d-filtro-actions { display: flex; flex-direction: column; gap: 6px; }
  .d-filtro-actions .btn-process { margin-top: 0 !important; width: 100%; }
  /* Un gráfico de 260 px de alto en una pantalla de 640 se lleva media vista. */
  .d-chart-wrap, .d-panel-2 .d-chart-wrap { height: 220px; }
  /* Las tablas anchas se desplazan DENTRO de su panel. Sin `nowrap` el navegador
     comprime las columnas hasta partir cada palabra en vertical. */
  .d-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .d-table-wrap table { font-size: .78rem; }
  .d-table-wrap th, .d-table-wrap td { padding: 6px 8px; white-space: nowrap; }
  /* Objetivo táctil: los botones de acción de las tablas eran de 18 px de alto. */
  .btn-process, .pag-btn, .filtro-btns .fbtn { min-height: 34px; }
  .pag-controls { justify-content: center; }
  .t-cons-buscar { max-width: none; }
  /* El conmutador de base ocupa la fila entera y sus botones crecen al tamaño de un dedo:
     con los 4 px de padding del conmutador del mapa son imposibles de acertar.

     ESTA REGLA SE ESCRIBIÓ PARA DOS BOTONES Y SE ROMPIÓ AL LLEGAR EL TERCERO. Con
     `flex: 1 1 0` y el `white-space: nowrap` que heredan de `.btn-map-toggle`, los botones
     no pueden encoger por debajo del ancho de su rótulo: «Por lugar de infección» empujaba
     el grupo fuera de la pantalla a 360 y 390 px -- medido en el navegador--, así que en un
     celular el tercer botón quedaba inalcanzable. Se deja envolver y se permite que el
     rótulo parta de línea: así entran tres, o cinco el día que haya cinco. */
  .base-toggle { display: flex; width: 100%; flex-wrap: wrap; }
  .base-toggle .btn-map-toggle {
    flex: 1 1 auto; min-width: 45%; min-height: 38px;
    white-space: normal; line-height: 1.15; padding: 6px 10px;
  }
}
@media (max-width: 480px) {
  .d-kpis { grid-template-columns: 1fr; }
  .d-panel h3 { font-size: .85rem; }
  .d-panel h3 small { flex: 1 1 100%; }   /* el subtítulo baja de línea en vez de apretar */
}

/* ============================================================
   Consola de campo (perfil Operativo / Redes)  — buscador DNI
   ============================================================ */
.campo-search{display:flex;gap:10px;margin-bottom:1rem;flex-wrap:wrap;}
.campo-search .d-input{flex:1;min-width:220px;}
.campo-search .btn-process{white-space:nowrap;}
.campo-resultado{min-height:40px;}
.campo-vacio{padding:1rem;border-radius:10px;background:rgba(234,179,8,.12);
  border:1px solid var(--warning);}
.campo-header{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem;
  flex-wrap:wrap;padding:1rem 1.2rem;border-radius:12px;background:var(--soft-bg);
  border:1px solid var(--panel-border);margin-bottom:1rem;}
.campo-nombre{font-size:1.15rem;font-weight:800;color:var(--text-main);}
.campo-sub{color:var(--text-muted);font-size:.85rem;margin-top:2px;}
.campo-estado{text-align:right;}
.campo-badge{display:inline-block;padding:5px 12px;border-radius:20px;color:#fff;
  font-weight:800;font-size:.8rem;letter-spacing:.3px;}
.campo-badge-sm{padding:2px 8px;font-size:.68rem;}
.campo-estado-sub{font-size:.75rem;color:var(--text-muted);margin-top:5px;}
.campo-cards{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin-bottom:1rem;}
.campo-grid2{display:grid;grid-template-columns:1fr 1fr;gap:1rem;}
.campo-card{padding:1rem 1.1rem;border-radius:12px;background:var(--panel-bg);
  border:1px solid var(--panel-border);}
.campo-card h4{margin:0 0 .6rem;font-size:.9rem;color:var(--text-main);}
.campo-card h4 small{color:var(--text-muted);font-weight:400;margin-left:6px;}
.campo-card-warn{border-color:var(--warning);}
.campo-timeline{list-style:none;margin:0;padding:0;}
.campo-timeline .d-hint{padding-left:0;list-style:none;}
.campo-tl-item{position:relative;padding:6px 0 6px 20px;border-left:2px solid var(--panel-border);}
.campo-tl-item::before{content:'';position:absolute;left:-6px;top:11px;width:10px;height:10px;
  border-radius:50%;background:var(--accent);}
.campo-tl-laboratorio::before{background:var(--danger);}
.campo-tl-muestra::before{background:var(--warning);}
.campo-tl-grave::before{background:#b91c1c;}
.campo-tl-fecha{font-weight:700;font-size:.78rem;margin-right:8px;color:var(--text-main);}
.campo-tl-label{font-size:.85rem;color:var(--text-muted);}
.campo-tabla-mu{width:100%;font-size:.82rem;border-collapse:collapse;}
.campo-pend-filtros{display:flex;gap:14px;align-items:center;margin-bottom:.8rem;flex-wrap:wrap;}
.campo-pend-filtros .d-input{flex:1;min-width:240px;}
.campo-check{font-size:.82rem;color:var(--text-muted);display:flex;align-items:center;gap:6px;cursor:pointer;}
.campo-link{color:var(--accent);text-decoration:none;font-weight:700;}
.campo-link:hover{text-decoration:underline;}
/* «Línea de tiempo» se partía en tres renglones en la última columna de las listas de campo:
   la columna era más angosta que la frase. Solo esos dos enlaces; el resto de .campo-link
   (documentos, nombres) sí debe poder partirse. */
td > .campo-link.rec-tl, td > .campo-link.lug-tl { white-space: nowrap; }
@media(max-width:820px){.campo-cards,.campo-grid2{grid-template-columns:1fr;}}

/* Subtítulo de una segunda gráfica dentro del mismo panel. */
.sub-h4{margin:1.4rem 0 .5rem;font-size:.85rem;color:var(--text-main);
  padding-top:.9rem;border-top:1px solid var(--panel-border);}

/* --- Cobertura de fuentes: qué tiene el expediente y qué le falta --------- */
.cob-fuentes{display:grid;grid-template-columns:repeat(3,1fr);gap:.6rem;margin-bottom:.8rem;}
.cob-f{padding:.6rem .75rem;border-radius:10px;border:1px solid var(--panel-border);
  background:var(--panel-bg);}
.cob-f.cob-si{border-color:var(--success,#16a34a);background:rgba(22,163,74,.08);}
.cob-f.cob-no{border-color:var(--danger);background:rgba(220,38,38,.08);}
.cob-f-top{display:flex;align-items:center;gap:6px;font-weight:800;font-size:.85rem;
  color:var(--text-main);}
.cob-f-ico{font-size:.95rem;line-height:1;}
.cob-f-que{font-size:.68rem;color:var(--text-muted);text-transform:uppercase;
  letter-spacing:.4px;margin-top:1px;}
.cob-f-det{font-size:.78rem;color:var(--text-muted);margin-top:4px;}
.cob-avisos{display:flex;flex-direction:column;gap:.4rem;}
.cob-av{display:flex;gap:.55rem;align-items:flex-start;padding:.55rem .7rem;border-radius:9px;
  border-left:4px solid var(--text-muted);background:var(--soft-bg);font-size:.82rem;}
.cob-av-alta{border-left-color:var(--danger);background:rgba(220,38,38,.09);}
.cob-av-media{border-left-color:var(--warning);background:rgba(234,179,8,.10);}
.cob-av-info{border-left-color:var(--accent);background:rgba(59,130,246,.08);}
.cob-av-fuente{font-weight:800;font-size:.7rem;padding:1px 7px;border-radius:20px;
  background:var(--panel-bg);border:1px solid var(--panel-border);white-space:nowrap;
  color:var(--text-main);}
.cob-av-txt{color:var(--text-main);}
.cob-av-acc{display:block;color:var(--text-muted);font-size:.76rem;margin-top:2px;}
/* URGENTE: por encima de «alta». No es gravedad, es plazo — hay una ventana clínica que se
   cierra en días (inmunoglobulina post-exposición) y ese aviso no puede leerse igual que uno
   que describe el acumulado del brote. */
.cob-av-urgente{border-left-color:var(--danger);background:rgba(220,38,38,.16);
  box-shadow:inset 3px 0 0 rgba(220,38,38,.35);font-weight:600;}
.cob-ok{font-size:.82rem;color:var(--text-muted);}
.cob-sug{margin-top:.8rem;}
.cob-sug-item{display:flex;gap:.6rem;align-items:center;padding:.4rem .2rem;
  border-bottom:1px solid var(--panel-border);font-size:.83rem;}
.cob-sug-item:last-child{border-bottom:none;}
@media(max-width:820px){.cob-fuentes{grid-template-columns:1fr;}}

/* ============================================================
   Curvas por ámbito (región / red / provincia / distrito)
   ============================================================ */
.amb-barra{display:flex;flex-wrap:wrap;gap:.8rem;align-items:center;margin-bottom:.4rem;}
.amb-niveles{margin:0;}

/* ============================================================
   Mapa por mes: mapa + ranking de distritos al costado (la lámina)
   ============================================================ */
.mapa-con-ranking{display:flex;gap:1rem;align-items:stretch;}
.mapa-con-ranking > #mapa{flex:1 1 auto;min-width:0;}
.mes-ranking{flex:0 0 260px;overflow:auto;max-height:460px;padding:.6rem .7rem;
  border:1px solid var(--panel-border);border-radius:10px;background:var(--soft-bg);}
.mes-ranking-tit{font-weight:800;font-size:1rem;letter-spacing:.5px;margin-bottom:.6rem;
  color:var(--accent);}
.mes-rank-fila{margin-bottom:.5rem;}
.mes-rank-nom{font-size:.76rem;font-weight:700;color:var(--text-main);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.mes-rank-barra{display:flex;align-items:center;gap:6px;}
.mes-rank-barra span{display:block;height:12px;border-radius:3px;min-width:4px;}
.mes-rank-barra b{font-size:.76rem;color:var(--text-muted);}
.mes-rank-mas{font-size:.74rem;color:var(--text-muted);font-style:italic;margin-top:.4rem;}
#meses-slider{accent-color:var(--danger);height:6px;cursor:pointer;}
#meses-play{background:var(--soft-bg);color:var(--text-main);}
/* Bajo 900 px el ranking al costado deja el mapa en una franja inservible: va debajo. */
@media(max-width:900px){
  .mapa-con-ranking{flex-direction:column;}
  .mes-ranking{flex:1 1 auto;max-height:none;}
}

/* ============================================================
   Ventanas que se cierran (gestantes): lo accionable se ve distinto
   ============================================================ */
/* ============================================================
   Selector de NetLab: varios archivos o carpetas completas
   ============================================================ */
.d-upload-netlab{grid-column:1 / -1;}
.nl-drop{border:2px dashed var(--panel-border);border-radius:12px;padding:1rem;
  display:flex;flex-wrap:wrap;gap:.8rem;align-items:center;justify-content:space-between;
  background:var(--soft-bg);transition:border-color .15s, background .15s;}
.nl-drop-activa{border-color:var(--accent);background:rgba(13,148,136,.10);}
.nl-drop-txt{display:flex;flex-direction:column;gap:2px;font-size:.85rem;min-width:0;}
.nl-drop-txt span{color:var(--text-muted);font-size:.78rem;}
.nl-drop-btns{display:flex;gap:.4rem;flex-wrap:wrap;}
.nl-lista{margin-top:.7rem;}
.nl-resumen{font-size:.82rem;margin-bottom:.5rem;color:var(--text-main);}
.nl-grupo{margin-bottom:.6rem;}
.nl-grupo-tit{font-size:.76rem;font-weight:800;text-transform:uppercase;letter-spacing:.4px;
  color:var(--accent);margin-bottom:.25rem;}
.nl-grupo-tit span{color:var(--text-muted);font-weight:600;}
.nl-item{display:flex;align-items:center;gap:.6rem;padding:.25rem .5rem;border-radius:6px;
  font-size:.79rem;border-bottom:1px solid var(--panel-border);}
.nl-item:last-child{border-bottom:none;}
.nl-item-nom{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-variant-numeric:tabular-nums;}
.nl-item-kb{color:var(--text-muted);white-space:nowrap;}
.nl-quitar{background:none;border:none;color:var(--text-muted);cursor:pointer;
  font-size:.85rem;padding:0 4px;line-height:1;}
.nl-quitar:hover{color:var(--danger);}

/* ============================================================
   Guía de descarga dentro de la pantalla de carga
   Va aquí y no en un manual aparte porque es donde se comete el error.
   ============================================================ */
.guia{margin-top:1.2rem;border:1px solid var(--panel-border);border-radius:12px;
  background:var(--soft-bg);padding:.8rem 1rem;}
.guia summary{cursor:pointer;font-size:.95rem;list-style:none;}
.guia summary::-webkit-details-marker{display:none;}
.guia summary::before{content:'▸ ';color:var(--accent);font-weight:800;}
.guia[open] summary::before{content:'▾ ';}
.guia summary small{color:var(--text-muted);margin-left:.5rem;font-weight:400;}
.guia .sub-h4{margin:1rem 0 .35rem;}
.guia-alerta{margin:.8rem 0;padding:.7rem .9rem;border-radius:9px;font-size:.84rem;
  line-height:1.5;border-left:4px solid var(--warning);background:rgba(234,179,8,.10);}
.guia-tabla td{vertical-align:top;font-size:.82rem;line-height:1.45;}
.guia-code{margin:.4rem 0;padding:.6rem .8rem;border-radius:8px;font-size:.8rem;
  background:var(--panel-bg);border:1px solid var(--panel-border);
  color:var(--text-main);overflow-x:auto;white-space:pre;}
.guia-check{margin-top:1rem;padding:.7rem .9rem;border-radius:9px;font-size:.82rem;
  line-height:1.5;border-left:4px solid var(--success);background:rgba(16,185,129,.08);}
.guia-check ul{margin:.4rem 0 0 1.1rem;padding:0;}
.guia-check li{margin-bottom:.3rem;}

.fila-urgente{background:rgba(220,38,38,.10);}
/* Identidad en una lista de trabajo: nombre arriba, documento (que abre el expediente) y
   teléfono debajo. Apilado y no en tres columnas para que la tabla siga cabiendo. */
.ident-nom{font-weight:700;font-size:.8rem;color:var(--text-main);line-height:1.25;}
.ident-doc{font-size:.78rem;font-variant-numeric:tabular-nums;}
.ident-tel{font-size:.76rem;color:var(--text-muted);}
.ident-tel a{color:var(--text-muted);text-decoration:none;}
.ident-tel a:hover{color:var(--accent);text-decoration:underline;}
.ident-caso{font-size:.72rem;color:var(--text-muted);margin-top:2px;}
.tag-ventana{display:inline-block;font-size:.68rem;font-weight:800;padding:2px 8px;
  border-radius:20px;white-space:nowrap;letter-spacing:.3px;}
.tag-ig{background:rgba(220,38,38,.18);color:var(--danger);border:1px solid rgba(220,38,38,.4);}
.tag-seg{background:rgba(234,179,8,.16);color:var(--warning);border:1px solid rgba(234,179,8,.4);}
.tag-cerrada{background:var(--soft-bg);color:var(--text-muted);border:1px solid var(--panel-border);}

/* ── La causa común de los "confirmado sin respaldo en NetLab" ──────────────
   No es un aviso más: es la instrucción para la PRÓXIMA descarga. Por eso va
   destacado arriba del listado y no repetido dentro de cada fila. */
.cal-causas{margin:.2rem 0 1rem;padding:.75rem .95rem;border-radius:10px;
  border:1px solid rgba(234,179,8,.38);border-left:4px solid var(--warning);
  background:rgba(234,179,8,.09);}
.cal-causas summary{cursor:pointer;font-size:.88rem;list-style:none;line-height:1.45;}
.cal-causas summary::-webkit-details-marker{display:none;}
.cal-causas summary::before{content:'▸ ';color:var(--warning);font-weight:800;}
.cal-causas[open] summary::before{content:'▾ ';}
.cal-causas summary small{display:block;color:var(--text-muted);font-weight:400;
  font-size:.76rem;margin-top:2px;}
.cal-causas-lista{margin:0 0 0 1.1rem;padding:0;font-size:.82rem;line-height:1.55;}
.cal-causas-lista li{margin-bottom:.4rem;}

/* Estado de una muestra en NetLab. «Rechazada» y «en proceso» se veían igual (las dos como
   resultado vacío) y son acciones opuestas: una manda a esperar, la otra a volver a citar
   al paciente. El color es la diferencia que hace que no se confundan de un vistazo. */
.tag-mu{display:inline-block;font-size:.68rem;font-weight:800;padding:2px 8px;
  border-radius:20px;white-space:nowrap;letter-spacing:.2px;}
.tag-mu-rech{background:rgba(220,38,38,.16);color:var(--danger);
  border:1px solid rgba(220,38,38,.38);}
.tag-mu-proc{background:rgba(59,130,246,.14);color:var(--accent);
  border:1px solid rgba(59,130,246,.35);}
.tag-mu-ok{background:rgba(16,185,129,.14);color:var(--success);
  border:1px solid rgba(16,185,129,.35);}

/* ── Alertas de riesgo ──────────────────────────────────────────────────────
   Un caso suele traer varios factores a la vez (gestante + hospitalizada +
   viajó). Como chips se leen de un vistazo y se ve cuál acumula; como texto
   corrido se convierten en un párrafo que nadie termina. */
.rie-chip{display:inline-block;font-size:.68rem;font-weight:700;padding:2px 8px;
  border-radius:20px;margin:0 4px 4px 0;white-space:nowrap;
  background:var(--soft-bg);color:var(--text-main);border:1px solid var(--panel-border);}
.rie-contagio{font-size:.68rem;font-weight:800;color:var(--danger);margin-top:4px;
  letter-spacing:.2px;}
.rie-cat{border:1px solid var(--panel-border);border-radius:10px;padding:.6rem .9rem;
  background:var(--soft-bg);}
.rie-cat summary{cursor:pointer;font-size:.86rem;list-style:none;}
.rie-cat summary::-webkit-details-marker{display:none;}
.rie-cat summary::before{content:'▸ ';color:var(--accent);font-weight:800;}
.rie-cat[open] summary::before{content:'▾ ';}
.rie-cat summary small{color:var(--text-muted);margin-left:.5rem;font-weight:400;}
.rie-cat table{margin-top:.6rem;}
.rie-cat td{font-size:.79rem;line-height:1.45;vertical-align:top;}

/* Ámbito de la cuenta: una coordinadora ve 40 casos donde el equipo regional ve 557.
   Sin decirlo en pantalla, un tablero recortado se lee como un tablero roto. */
.amb-badge{display:inline-flex;align-items:center;gap:6px;padding:3px 11px;border-radius:20px;
  font-size:.72rem;font-weight:700;letter-spacing:.2px;
  background:rgba(59,130,246,.14);color:var(--accent);border:1px solid rgba(59,130,246,.35);}

/* ============================================================
   Shell SPA: topbar fija + sidebar agrupado por módulos
   ============================================================ */
.topbar{position:fixed;top:0;left:0;right:0;height:54px;z-index:1200;display:flex;
  align-items:center;justify-content:space-between;gap:1rem;padding:0 1.2rem;
  background:var(--panel-bg);border-bottom:1px solid var(--panel-border);}
.topbar-brand{display:flex;align-items:center;gap:10px;min-width:0;}
.topbar-brand .logo-icon{font-size:1rem;font-weight:800;color:#fff;background:var(--accent);
  border-radius:8px;padding:4px 9px;letter-spacing:.5px;}
.topbar-title{font-size:.92rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.topbar-user{display:flex;align-items:center;gap:10px;font-size:.85rem;white-space:nowrap;}
.topbar-user #userNameDisplay{font-weight:700;color:var(--text-main);}
.topbar-user .role-badge{margin-bottom:0;}
.topbar-user .btn-logout{width:auto;padding:.32rem .75rem;}
.topbar .theme-toggle{position:static;background:transparent;border:1px solid var(--panel-border);
  border-radius:8px;width:34px;height:34px;cursor:pointer;color:var(--text-main);font-size:1rem;}

/* el topbar fijo empuja todo el layout hacia abajo */
.dashboard-body{padding-top:54px;}
.sidebar{position:fixed;left:0;top:54px;height:calc(100vh - 54px);z-index:1000;overflow-y:auto;}
.main-content{padding-top:1.5rem;}

/* ---- La barra superior en pantallas estrechas ----
   Todo lo de la derecha (ámbito, usuario, rol, tema, salir) más el título completo no
   entra en 360 px: sin esto la barra se ensancha, empuja el documento de lado y el botón
   de salir se sale de la pantalla. Se va soltando lastre por orden de importancia; el
   nombre del usuario y su ámbito siguen visibles dentro del panel «Mi cuenta». */
@media (max-width: 900px){
  .topbar{padding:0 .7rem;gap:.6rem;}
  .topbar-title{font-size:.84rem;}
  .topbar-user{gap:7px;}
  .topbar-user .btn-logout{padding:.3rem .6rem;font-size:.8rem;}
}
@media (max-width: 700px){
  .topbar-title .tb-sub{display:none;}     /* queda «DIRESA Puno» */
  .topbar-brand .logo-marca-sm{display:none;}
}
@media (max-width: 520px){
  .topbar-user #userNameDisplay{display:none;}
  .topbar-user .amb-badge{display:none;}
  .topbar-user .role-badge{font-size:.68rem;padding:.15rem .4rem;}
}
@media (max-width: 400px){
  .topbar-user .btn-logout{font-size:0;padding:.34rem .5rem;}   /* solo el icono */
  .topbar-user .btn-logout::after{content:'\21AA';font-size:.95rem;}
}

/* sidebar: menú agrupado por módulos */
.sidebar-nav{flex:1;}
.nav-group{margin-bottom:1.1rem;}
.nav-group-title{font-size:.66rem;text-transform:uppercase;letter-spacing:.09em;font-weight:800;
  color:var(--text-muted);opacity:.75;padding:0 .9rem;margin-bottom:.35rem;}
.nav-item{display:flex;align-items:center;gap:9px;padding:.55rem .9rem;border-radius:8px;
  color:var(--text-muted);text-decoration:none;cursor:pointer;font-size:.88rem;transition:all .2s;}
.nav-item:hover{background:var(--hover-bg);color:var(--text-main);}
.nav-item.active{background:rgba(59,130,246,.16);color:var(--text-main);font-weight:700;}
.nav-item .nav-ico{width:20px;text-align:center;flex:none;}

/* buscador de campo: input más protagonista en su vista */
#panel-campo .campo-search .d-input{font-size:1.05rem;padding:.7rem 1rem;}

/* ===== Paginación de tablas (20/página) + botones-filtro ===== */
.pag-controls{display:flex;align-items:center;justify-content:flex-end;gap:12px;margin-top:.8rem;flex-wrap:wrap;}
.pag-btn{background:var(--soft-bg);border:1px solid var(--panel-border);color:var(--text-main);
  border-radius:8px;padding:.35rem .85rem;cursor:pointer;font-size:.82rem;transition:background .2s;}
.pag-btn:hover:not(:disabled){background:var(--hover-bg);}
.pag-btn:disabled{opacity:.4;cursor:default;}
.pag-info{font-size:.8rem;color:var(--text-muted);}
.filtro-btns{display:inline-flex;gap:3px;background:var(--soft-bg);border:1px solid var(--panel-border);
  border-radius:9px;padding:3px;}
.filtro-btns .fbtn{background:transparent;border:none;color:var(--text-muted);border-radius:6px;
  padding:.32rem .8rem;cursor:pointer;font-size:.8rem;transition:all .2s;}
.filtro-btns .fbtn.active{background:var(--accent);color:#fff;font-weight:700;}
#btnFiltrosAvanzados.active{background:var(--accent) !important;color:#fff !important;}

/* ============================================================
   Línea de tiempo epidemiológica (franjas de riesgo + eventos de campo)
   ============================================================ */
.tl-card{margin-bottom:1rem;}
.tl-epi{position:relative;height:74px;margin:.6rem 0 .2rem;}
.tl-axis{position:absolute;left:0;right:0;top:50px;height:2px;background:var(--panel-border);}
.tl-band{position:absolute;top:26px;height:24px;border-radius:4px;}
.tl-band-amarillo{background:rgba(234,179,8,.30);border:1px solid rgba(234,179,8,.7);}
.tl-band-rojo{background:rgba(178,34,34,.28);border:1px solid rgba(178,34,34,.75);}
.tl-band-gris{background:rgba(130,130,130,.22);border:1px solid rgba(130,130,130,.6);}
.tl-fie{position:absolute;top:18px;height:40px;width:2px;background:var(--text-main);}
.tl-fie-lbl{position:absolute;top:0;transform:translateX(-50%);font-size:.58rem;font-weight:800;
  line-height:1.05;text-align:center;color:var(--text-main);white-space:nowrap;}
.tl-caso{position:absolute;top:50px;width:11px;height:11px;border-radius:50%;background:var(--accent);
  border:2px solid var(--panel-bg);transform:translate(-50%,-50%);cursor:pointer;}
.tl-campo-flag{position:absolute;top:4px;transform:translateX(-50%);color:#0d9488;font-size:1.05rem;
  line-height:1;cursor:pointer;}
.tl-scale{display:flex;justify-content:space-between;font-size:.66rem;color:var(--text-muted);margin-bottom:.5rem;}
.tl-legend{display:flex;flex-wrap:wrap;gap:12px;font-size:.72rem;color:var(--text-muted);margin-bottom:.6rem;}
.tl-leg{display:inline-flex;align-items:center;gap:5px;}
.tl-leg small{opacity:.75;}
.tl-dot{width:12px;height:12px;border-radius:3px;display:inline-block;}
.tl-flagdot{background:#0d9488;border-radius:50%;}
.tl-campo-mod{border-top:1px solid var(--panel-border);padding-top:.7rem;margin-top:.3rem;}
.tl-campo-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem;}
.tl-ev-form{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:.7rem;align-items:center;}
.tl-ev-form #ev-desc{flex:1;min-width:200px;}
.tl-campo-list{display:flex;flex-direction:column;gap:5px;}
.tl-campo-item{display:flex;align-items:center;gap:10px;padding:.4rem .6rem;border-radius:8px;
  background:var(--panel-bg);border:1px solid var(--panel-border);font-size:.82rem;}
.tl-campo-fecha{font-weight:700;min-width:46px;}
.tl-campo-tipo{background:var(--soft-bg);border:1px solid var(--panel-border);border-radius:6px;
  padding:1px 8px;font-size:.7rem;color:var(--text-muted);}
.tl-campo-desc{flex:1;}
.tl-campo-del{background:transparent;border:none;color:var(--text-muted);cursor:pointer;font-size:.9rem;}
.tl-campo-del:hover{color:var(--danger);}

/* Marcadores de datos ya presentes en OSIRIS (contactos, bloqueo) sobre el timeline */
.tl-osiris{position:absolute;top:36px;transform:translateX(-50%);color:#a855f7;font-size:.85rem;line-height:1;cursor:pointer;}
.tl-osirisdot{background:#a855f7;border-radius:2px;}

/* ── INSTITUCIONES Y CONGLOMERADOS ─────────────────────────────────────────── */
/* Chips del catálogo: lugares que el propio brote repite (UNA PUNO, UPEU, CUARTEL…). */
.lug-chips { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:.7rem; }
.lug-chip {
  background:var(--soft-bg); border:1px solid var(--panel-border); color:var(--text-main);
  border-radius:999px; padding:.28rem .7rem; font-size:.76rem; cursor:pointer;
  transition:background .15s, border-color .15s;
}
.lug-chip:hover { background:var(--hover-bg); border-color:var(--accent); }
.lug-chip b { color:var(--danger); margin-left:2px; }

/* "Por qué coincide": el texto crudo de OSIRIS que disparó el match. */
.lug-match {
  display:inline-block; background:var(--soft-bg); border-radius:4px;
  padding:1px 5px; margin:1px 2px 1px 0; color:var(--text-muted);
}
.lug-match b { color:var(--text-main); font-weight:600; }

.niv-chip {
  display:inline-block; border:1px solid; border-radius:999px;
  padding:1px 8px; font-size:.7rem; font-weight:600; white-space:nowrap;
}
.niv-manual { font-size:.72rem; }

/* Tarjetas de conglomerado */
.cong-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(280px, 1fr)); gap:12px; }
.cong-card {
  background:var(--soft-bg); border:1px solid var(--panel-border); border-radius:10px;
  padding:.85rem 1rem; cursor:pointer; transition:border-color .15s, transform .1s;
}
.cong-card:hover { border-color:var(--accent); transform:translateY(-2px); }
.cong-card-head { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.cong-card-head h4 { margin:0; font-size:.95rem; flex:1; }
.cong-ico { font-size:1.15rem; }
.cong-badge { font-size:.66rem; border-radius:999px; padding:2px 8px; font-weight:600; }
.cong-badge.activo { background:rgba(220,38,38,.15); color:var(--danger); }
.cong-badge.cerrado { background:var(--hover-bg); color:var(--text-muted); }
.cong-card-cifras { display:flex; gap:1.2rem; margin:.7rem 0 .4rem; }
.cong-card-cifras div { display:flex; flex-direction:column; }
.cong-card-cifras b { font-size:1.3rem; line-height:1.1; }
.cong-card-cifras span { font-size:.68rem; color:var(--text-muted); text-transform:uppercase; letter-spacing:.3px; }
.cong-card-cifras .conf b { color:var(--danger); }
.cong-card-cifras .pend b { color:var(--warning); }
.cong-card-pie { font-size:.72rem; color:var(--text-muted); margin:0; line-height:1.4; }

/* Detalle */
.cong-detalle-head { display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:8px; margin-bottom:.6rem; }
.cong-acciones { display:flex; gap:6px; flex-wrap:wrap; }
.btn-peligro { background:var(--danger) !important; }
.btn-cong { background:var(--accent) !important; }
.cong-kpis { display:grid; grid-template-columns:repeat(auto-fit, minmax(130px,1fr)); gap:10px; margin:.6rem 0 1rem; }
.cong-kpi {
  background:var(--soft-bg); border:1px solid var(--panel-border); border-left:3px solid var(--panel-border);
  border-radius:8px; padding:.6rem .8rem; display:flex; flex-direction:column;
}
.cong-kpi span { font-size:1.5rem; font-weight:700; line-height:1.1; }
.cong-kpi small { font-size:.68rem; color:var(--text-muted); margin-top:3px; }
.cong-kpi.conf { border-left-color:var(--danger); }
.cong-kpi.conf span { color:var(--danger); }
.cong-kpi.pend { border-left-color:var(--warning); }
.cong-kpi.pend span { color:var(--warning); }
/* La cifra defendible en un informe: confirmados cuyo vínculo está probado. */
.cong-kpi.strong { border-left-color:var(--accent); background:var(--hover-bg); }
.cong-kpi.strong span { color:var(--accent); }

.cong-grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
@media (max-width: 900px) { .cong-grid-2 { grid-template-columns:1fr; } }
.d-panel-inner {
  background:var(--soft-bg); border:1px solid var(--panel-border);
  border-radius:10px; padding:.8rem 1rem;
}
.d-panel-inner h5 { margin:0 0 .6rem; font-size:.85rem; }
.d-panel-inner h5 small { font-weight:400; color:var(--text-muted); font-size:.72rem; margin-left:6px; }

.cong-niv-tabla { width:100%; border-collapse:collapse; font-size:.8rem; }
.cong-niv-tabla th, .cong-niv-tabla td { padding:.4rem .5rem; text-align:left; border-bottom:1px solid var(--panel-border); }
.cong-niv-tabla th { font-size:.7rem; color:var(--text-muted); text-transform:uppercase; letter-spacing:.3px; }
.cong-niv-tabla tr.niv-fuerte { background:var(--hover-bg); }

/* Modal de reglas */
/* Por encima de la barra superior (z-index 1200): con 1000 el diálogo se abría DEBAJO de
   ella y su encabezado quedaba tapado. */
.cong-modal {
  position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:1300;
  display:flex; align-items:center; justify-content:center; padding:1rem;
}
.cong-modal-box { max-width:640px; width:100%; max-height:88vh; overflow-y:auto; padding:1.4rem 1.6rem; }
.cong-lbl { display:block; font-size:.78rem; color:var(--text-muted); margin:.7rem 0 .2rem; font-weight:600; }
.cong-lbl .d-input { margin-top:.25rem; width:100%; }
.cong-pat-row { display:flex; gap:6px; margin-bottom:6px; align-items:center; }
.cong-pat-row .pat-txt { flex:1; }
.cong-pat-row .pat-niv { max-width:130px; }
.cong-modal-acciones { display:flex; justify-content:flex-end; gap:8px; margin-top:1.2rem; }

.cong-add{display:inline-flex;gap:6px;align-items:center;margin-left:auto;}

/* Rejilla de filtros de ambito del explorador (provincia -> distrito -> centro de salud). */
.lug-filtros{display:grid;grid-template-columns:2fr 1fr 1fr 1fr 1.4fr;gap:10px;margin-bottom:.8rem;}
@media (max-width:1100px){.lug-filtros{grid-template-columns:1fr 1fr;}}
@media (max-width:640px){.lug-filtros{grid-template-columns:1fr;}}
.lug-filtro{display:flex;flex-direction:column;}
.lug-filtro label{font-size:.7rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:.3px;margin-bottom:4px;}
.lug-filtro .d-input{width:100%;}

/* ── Curva del distrito (modal que abre el mapa) ───────────────────────── */
.cdist-box { max-width: 900px; }
.cdist-head { display:flex; justify-content:space-between; align-items:flex-start; gap:12px; }
.cdist-head h3 { margin:0 0 2px; }
.cdist-chart { height: 320px; margin-top: .9rem; }
.cdist-badge { display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin-top:.7rem; }
.cdist-chip { padding:4px 11px; border-radius:999px; font-size:.78rem; font-weight:600;
              border:1px solid currentColor; }
.cdist-chip.dato { color:var(--muted); border-color:var(--border); font-weight:500; }
.cdist-nota { margin-top:.8rem; font-size:.8rem; line-height:1.5; color:var(--muted); }
.cdist-nota b { color:var(--danger); }
.map-curva-btn { width:100%; padding:6px 10px; border-radius:7px; cursor:pointer;
                 border:1px solid #0891b2; background:#0891b2; color:#fff;
                 font-weight:600; font-size:.8rem; }
.map-curva-btn:hover { filter:brightness(1.12); }

/* ── KPI consolidado OSIRIS + NetLab ───────────────────────────────────────
   La brecha entre el conteo oficial y el real no es un dato: es una TAREA.
   Se destaca para que sea lo primero que se ve, y baje a cero. */
.d-kpi.kpi-consolidado { border: 1px solid #8e44ad; }
.d-kpi.kpi-brecha {
  border: 2px solid #8e44ad;
  background: linear-gradient(180deg, rgba(142,68,173,.14), rgba(142,68,173,.05));
  box-shadow: 0 0 0 1px rgba(142,68,173,.25);
}
.d-kpi.kpi-brecha .d-v { color: #c084fc; }
:root[data-theme="light"] .d-kpi.kpi-brecha .d-v { color: #7e22ce; }

/* Las notas de la brecha son la parte accionable de la tarjeta y estaban en .66rem con un
   lila (#e9b8ff) pensado solo para el fondo oscuro: en tema claro quedaban ilegibles justo
   los dos avisos que hay que leer. Ahora son chips, con contraste propio en cada tema. */
/* Ocupan el ancho de la tarjeta y se alinean a la izquierda: centradas y estrechas el texto
   se partía en cuatro líneas de dos palabras y el número dejaba de saltar a la vista. */
.kpi-notas-wrap { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; width: 100%; }
.kpi-nota {
  font-size: .72rem; font-weight: 700; line-height: 1.4; letter-spacing: .1px;
  padding: 5px 9px; border-radius: 7px; text-align: left; text-wrap: balance;
  background: rgba(234,179,8,.14); color: #fbbf24; border: 1px solid rgba(234,179,8,.32);
}
:root[data-theme="light"] .kpi-nota {
  background: rgba(217,119,6,.10); color: #92400e; border-color: rgba(217,119,6,.30);
}
.kpi-nota.kpi-ok {
  background: rgba(16,185,129,.14); color: var(--success); border-color: rgba(16,185,129,.32);
  font-weight: 600;
}
:root[data-theme="light"] .kpi-nota.kpi-ok { background: rgba(5,150,105,.10); color: #065f46; }
.d-kpi .d-l small { display: block; font-weight: 400; opacity: .75; font-size: .92em; }

/* ── Acciones pendientes: cada fuga es una TAREA, no una estadística ────────── */
.d-acciones { margin-bottom: 1.5rem; }
.acc-head h3 { margin: 0 0 .7rem; font-size: 1rem; }
.acc-head h3 small { font-weight: 400; color: var(--text-muted); margin-left: .5rem; font-size: .78rem; }
.acc-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(235px, 1fr)); }
.acc-card {
  position: relative; padding: 14px 16px 34px; border-radius: 11px; cursor: pointer;
  background: var(--soft-bg, rgba(255,255,255,.03));
  border: 1px solid var(--panel-border, rgba(255,255,255,.08));
  border-left-width: 4px; transition: transform .12s, box-shadow .12s;
}
.acc-card:hover { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(0,0,0,.28); }
.acc-critico { border-left-color: #dc2626; }
.acc-aviso   { border-left-color: #d97706; }
.acc-n { font-size: 1.9rem; font-weight: 800; line-height: 1; }
.acc-critico .acc-n { color: #f87171; }
.acc-aviso   .acc-n { color: #fbbf24; }
.acc-t { margin-top: 4px; font-weight: 700; font-size: .84rem; }
.acc-a { margin-top: 6px; font-size: .74rem; line-height: 1.45; color: var(--text-muted); }
.acc-dl {
  position: absolute; left: 16px; bottom: 10px; font-size: .68rem; font-weight: 700;
  color: var(--primary2, #0891b2); opacity: .75;
}
.acc-card:hover .acc-dl { opacity: 1; }
.acc-vacio {
  padding: 14px 18px; border-radius: 10px; font-weight: 600; font-size: .86rem;
  color: var(--ok, #16a34a); border: 1px solid rgba(22,163,74,.35);
  background: rgba(22,163,74,.08);
}

/* =========================================================================
   IMPRESIÓN (SALA SITUACIONAL)
   ========================================================================= */
@media print {
  /* Forzar colores e imágenes de fondo (Chrome/Edge/Safari) */
  * {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }

  /* Redefinir variables CSS para modo claro en impresión */
  :root {
    --bg: #ffffff;
    --panel: #f8fafc;
    --panel-border: #e2e8f0;
    --text: #0f172a;
    --text-muted: #475569;
  }

  /* Fondo blanco absoluto para la página y texto negro puro */
  body, .dashboard-body {
    background: #ffffff !important;
    color: #000000 !important;
    margin: 0 !important;
    padding: 0 !important;
  }

  /* Paneles sin sombras y con bordes definidos */
  .glass-panel, .d-panel, .d-hero {
    background: #ffffff !important;
    box-shadow: none !important;
    border: 1px solid #cccccc !important;
    page-break-inside: avoid;
    margin-bottom: 1rem !important;
  }

  /* Forzar altura de los mapas y contenedores de gráficos para que no colapsen */
  #mapa {
    height: 400px !important;
    width: 100% !important;
    page-break-inside: avoid;
  }
  
  .chart-container, .chart-wrapper {
    page-break-inside: avoid;
    width: 100% !important;
    height: 350px !important; /* Chart.js necesita una altura explícita para no encogerse */
  }

  /* Ocultar botones de descarga interactivos */
  .btn-process, .btn-download, button[id^="dl-"], #cdist-cerrar {
    display: none !important;
  }

  /* Eliminar scrollbars de tablas */
  .d-table-wrap {
    overflow: visible !important;
  }
  
  table {
    width: 100% !important;
    border-collapse: collapse !important;
  }

  th, td {
    color: #000000 !important;
    border-bottom: 1px solid #dddddd !important;
  }

  /* Textos mutados más legibles */
  .text-muted, small {
    color: #333333 !important;
  }

  /* Ocultar elementos no relevantes en impresión (ej. barras de navegación laterales) */
  .sidebar, .nav-menu {
    display: none !important;
  }
  
  /* Asegurar que el contenido ocupe todo el ancho si había sidebar */
  .main-content, .d-grid {
    width: 100% !important;
    margin: 0 !important;
    padding: 0 !important;
    grid-template-columns: 1fr !important;
  }
}

/* ══════════════════════════════════════════════════════════════════════════════
   PANORAMA — "¿cómo vamos?"
   Tarjetas con dirección y lectura, arriba de los KPIs acumulados. Son clicables:
   llevan a la vista donde se sustenta el número.
   ══════════════════════════════════════════════════════════════════════════════ */
.pano { margin-bottom: 1.6rem; }
.pano-head { display: flex; align-items: baseline; gap: .8rem; flex-wrap: wrap; margin-bottom: .8rem; }
.pano-head h3 { margin: 0; font-size: 1.05rem; }
.pano-head h3 small { font-weight: 400; color: var(--text-muted); margin-left: .45rem; font-size: .78rem; }
.pano-stale {
  font-size: .7rem; font-weight: 700; padding: 3px 9px; border-radius: 999px;
  color: #d97706; background: rgba(217,119,6,.12); border: 1px solid rgba(217,119,6,.35);
}
.pano-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(255px, 1fr)); }
.pano-card {
  position: relative; padding: 15px 17px 30px; border-radius: 12px; cursor: pointer;
  background: var(--soft-bg, rgba(255,255,255,.03));
  border: 1px solid var(--panel-border, rgba(255,255,255,.08));
  border-left-width: 4px; transition: transform .12s, box-shadow .12s;
}
.pano-card:hover { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(0,0,0,.28); }
.pano-alerta { border-left-color: #dc2626; }
.pano-aviso  { border-left-color: #d97706; }
.pano-ok     { border-left-color: #16a34a; }
.pano-neutro { border-left-color: var(--text-muted); }
.pano-t { font-size: .72rem; text-transform: uppercase; letter-spacing: .4px; color: var(--text-muted); }
.pano-v { display: flex; align-items: baseline; gap: .45rem; margin: 4px 0 2px; }
.pano-n { font-size: 2.1rem; font-weight: 800; line-height: 1; }
.pano-dir { font-size: 1rem; font-weight: 800; }
.pano-dir-sube { color: #dc2626; }
.pano-dir-baja { color: #16a34a; }
.pano-dir-estable, .pano-dir-nuevo { color: var(--text-muted); }
.pano-d { font-size: .78rem; font-weight: 700; opacity: .9; }
.pano-l { font-size: .73rem; line-height: 1.4; color: var(--text-muted); margin-top: 7px; }
.pano-ir {
  position: absolute; left: 17px; bottom: 10px; font-size: .68rem; font-weight: 700;
  color: var(--accent); opacity: .75;
}
.pano-card:hover .pano-ir { opacity: 1; }

/* ══════════════════════════════════════════════════════════════════════════════
   SEMÁFORO DE DISTRITOS
   3 colores (estado) + textura (certeza). El borde punteado es "sin transmisión pero
   por confirmar": la información NO se borró, se movió del color a la textura.
   ══════════════════════════════════════════════════════════════════════════════ */
.sem-resumen { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.sem-kpi {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 11px;
  background: var(--soft-bg, rgba(255,255,255,.03));
  border: 1px solid var(--panel-border, rgba(255,255,255,.08)); border-left-width: 4px;
}
.sem-kpi b { font-size: 1.9rem; font-weight: 800; line-height: 1; }
.sem-kpi span { font-size: .74rem; color: var(--text-muted); line-height: 1.3; }
.sem-kpi small { font-size: .66rem; opacity: .8; }
.sem-k-rojo   { border-left-color: #dc2626; } .sem-k-rojo b   { color: #dc2626; }
.sem-k-verde  { border-left-color: #16a34a; } .sem-k-verde b  { color: #16a34a; }
.sem-k-blanco { border-left-color: var(--text-muted); }
.sem-k-alerta { border-left-color: #d97706; } .sem-k-alerta b { color: #d97706; }

.sem-mosaico { display: grid; gap: 9px; grid-template-columns: repeat(auto-fill, minmax(178px, 1fr)); }
.sem-chip {
  display: flex; flex-direction: column; gap: 2px; text-align: left; cursor: pointer;
  padding: 9px 11px; border-radius: 9px; font: inherit; color: inherit;
  background: var(--soft-bg, rgba(255,255,255,.03));
  border: 2px solid var(--panel-border, rgba(255,255,255,.12));
  transition: transform .1s, box-shadow .1s;
}
.sem-chip:hover { transform: translateY(-2px); box-shadow: 0 5px 14px rgba(0,0,0,.3); }
.sem-rojo   { border-color: #dc2626; background: rgba(220,38,38,.10); }
.sem-verde  { border-color: #16a34a; background: rgba(22,163,74,.10); }
.sem-blanco { border-color: var(--panel-border); }
.sem-porconf { border-style: dashed; }
.sem-nom { font-size: .82rem; font-weight: 700; }
.sem-prov { font-size: .66rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: .3px; }
.sem-dato { font-size: .7rem; color: var(--text-muted); }
.sem-warn { color: #d97706; }
/* El semáforo por PROVINCIA reusa `.sem-chip`, pero sus celdas no se pulsan (no hay una
   curva provincial que abrir desde aquí): se les quita el cursor y el hover para que no
   prometan un clic que no existe. Y son 13 en vez de 111, así que caben más anchas. */
#sem-prov-mosaico { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
#sem-prov-mosaico .sem-chip { cursor: default; }
#sem-prov-mosaico .sem-chip:hover { transform: none; box-shadow: none; }

/* ── Aviso de datos ficticios ─────────────────────────────────────────────────
   Un despliegue de demostración es indistinguible del real a simple vista, y ese parecido
   es el riesgo: una captura reenviada por WhatsApp se lee como cifra oficial. La banda va
   arriba del todo, ocupa el ancho completo, no se puede cerrar y usa el color de peligro a
   propósito — tiene que interrumpir, no decorar.

   VA `fixed` Y NO `sticky`, y esto costó una pantalla rota: `body.dashboard-body` es un
   contenedor FLEX (barra lateral + contenido), así que un elemento en flujo normal se
   convierte en un ítem flex más y se estira a lo alto de todo el documento — 21 000 px de
   franja roja empujando el tablero a un tercio de la pantalla. Fuera del flujo, el layout
   ni se entera.

   El desplazamiento de la barra superior y de la lateral se aplica SOLO bajo
   `body.con-aviso-demo`, que el JS pone únicamente cuando el corte viene marcado como
   ficticio: en producción estas reglas no llegan a existir. */
.aviso-demo {
  position: fixed; top: 0; left: 0; right: 0; z-index: 2000;
  background: repeating-linear-gradient(45deg, #b91c1c, #b91c1c 14px, #991b1b 14px, #991b1b 28px);
  color: #fff; text-align: center; padding: .4rem 1rem;
  font-size: .8rem; line-height: 1.3; letter-spacing: .2px;
  box-shadow: 0 2px 10px rgba(0,0,0,.35);
}
.aviso-demo b { letter-spacing: 1px; margin-right: .5rem; }

/* Alto real de la banda; si cambia el padding o el tipo, se cambia aquí y todo lo demás
   se recoloca solo. */
:root { --aviso-demo-h: 30px; }

body.con-aviso-demo .topbar        { top: var(--aviso-demo-h); }
body.con-aviso-demo .sidebar       { top: calc(54px + var(--aviso-demo-h)); }
body.con-aviso-demo.dashboard-body { padding-top: calc(54px + var(--aviso-demo-h)); }
/* El tablero público no tiene barra lateral ni barra fija: solo hay que bajar el contenido. */
body.con-aviso-demo:not(.dashboard-body) { padding-top: var(--aviso-demo-h); }

@media print {
  /* En papel la advertencia importa MÁS, no menos: se imprime en el flujo, arriba. */
  .aviso-demo { position: static; }
  body.con-aviso-demo .topbar, body.con-aviso-demo .sidebar { top: 0; }
}

/* ── Pendientes de verdad ─────────────────────────────────────────────────────
   Una tarjeta por motivo de atasco. El borde lleva el color del nivel porque lo que
   distingue a estas tarjetas no es cuántas hay, sino qué hay que hacer con ellas. */
.pr-grid {
  display: grid; gap: 10px; margin-bottom: 1.2rem;
  grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
}
.pr-card {
  padding: .85rem 1rem; border-radius: 10px;
  background: var(--soft-bg, rgba(255,255,255,.03));
  border: 1px solid var(--panel-border, rgba(255,255,255,.12));
  border-left-width: 4px;
}
.pr-card.pr-critico { border-left-color: #dc2626; }
.pr-card.pr-aviso   { border-left-color: #d97706; }
.pr-card.pr-real    { border-left-color: #16a34a; }
.pr-n { font-size: 1.7rem; font-weight: 800; line-height: 1.1; }
.pr-n small { font-size: .72rem; font-weight: 600; color: var(--text-muted); margin-left: .35rem; }
.pr-tit { font-size: .86rem; font-weight: 700; margin: .15rem 0 .3rem; }
.pr-esp { font-size: .76rem; color: var(--text-muted); margin: 0 0 .35rem; }
.pr-acc { font-size: .76rem; line-height: 1.45; margin: 0; }
.pr-meta { font-size: .7rem; color: var(--text-muted); margin-top: .45rem; }
.pr-meta b { color: var(--danger, #dc2626); }

/* ── Extracción de informes ───────────────────────────────────────────────────
   Cuatro productos del mismo corte, cada uno con lo que es y para qué sirve. Antes
   eran cinco botones apretados en el título de un panel, distinguibles solo por su
   extensión: había que abrirlos para saber cuál iba a la reunión. */
.extraccion-grid {
  display: grid; gap: 12px; margin: .4rem 0 1.2rem;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.extraccion-card {
  display: flex; flex-direction: column; gap: .45rem;
  padding: .9rem 1rem; border-radius: 10px;
  background: var(--soft-bg, rgba(255,255,255,.03));
  border: 1px solid var(--panel-border, rgba(255,255,255,.12));
}
.extraccion-card h4 { margin: 0; font-size: .92rem; display: flex; flex-wrap: wrap; gap: .4rem; align-items: baseline; }
.extraccion-card h4 span {
  font-size: .68rem; font-weight: 600; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: .4px;
}
.extraccion-card p { margin: 0; font-size: .78rem; line-height: 1.5; color: var(--text-muted); flex: 1; }
.extraccion-lbl { font-size: .7rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: .3px; }
.extraccion-card .btn-download { align-self: flex-start; }

/* ── Aviso de fuentes no cargadas (módulo operativo) ──────────────────────────
   Una instalación recién hecha no trae los archivos de OSIRIS/NotiWeb/NetLab
   (contienen datos personales). Sin este aviso, las tablas del módulo operativo
   salen vacías y parecen una avería. */
.aviso-fuentes {
  margin: .8rem 0 1rem; padding: .9rem 1.1rem; border-radius: 10px;
  border: 1px solid #d97706; border-left-width: 4px;
  background: rgba(217, 119, 6, .09);
}
.aviso-fuentes b { color: #b45309; font-size: .95rem; }
.aviso-fuentes p { margin: .45rem 0 0; font-size: .86rem; line-height: 1.45; }
.aviso-fuentes-det { color: var(--text-muted); font-size: .8rem !important; }
.aviso-fuentes-btn { margin-top: .7rem; padding: .35rem .9rem; font-size: .82rem; }

/* ── Casos FUERA de Puno sobre el mapa ──────────────────────────────────────
   Arequipa y Cusco no tienen polígono en geo_puno.js, así que un caso contagiado o
   residente allí no tenía dónde dibujarse y desaparecía. Son pocos y son los que más
   dicen: un contagio fuera de la región es un caso IMPORTADO. Va como tarjeta flotante
   sobre el mapa, deliberadamente FUERA del territorio, para que se lea como lo que es. */
.mapa-envoltura {
  position: relative;
  /* DEJO EL MAPA EN BLANCO EN EL PANEL DEL ADMINISTRADOR. Al envolver `#mapa` en este div
     para colgarle la tarjeta de importados, `#mapa` dejo de ser hijo DIRECTO de
     `.mapa-con-ranking` y la regla que le daba ancho (`.mapa-con-ranking > #mapa`) dejo de
     aplicar. La envoltura no tenia medidas propias, asi que como item flex colapsaba a 2 px
     y Leaflet dibujaba dentro de una franja de 2 px: el mapa "no cargaba".
     Solo pasaba en el tablero autenticado -- en el publico la envoltura no vive dentro de
     un flex y ocupaba el ancho sola-- y por eso no salto en la revision. */
  flex: 1 1 auto;
  min-width: 0;
}
.mapa-externos {
  /* ARRIBA A LA DERECHA, no a la izquierda: ahi es donde Leaflet pone los botones de zoom
     y la tarjeta se los comia. La leyenda vive abajo a la derecha y la atribucion tambien,
     asi que esta es la unica esquina libre. */
  position: absolute; top: 12px; right: 12px; z-index: 500; max-width: 232px;
  background: var(--panel-bg); border: 1px solid var(--panel-border);
  border-radius: 10px; padding: .6rem .7rem; font-size: .78rem;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .28); backdrop-filter: blur(6px);
}
.mapa-externos .ext-cab { display: flex; gap: .5rem; align-items: flex-start; line-height: 1.25; }
.mapa-externos .ext-globo { font-size: 1.35rem; line-height: 1; }
.mapa-externos .ext-sub { color: var(--text-muted); font-size: .72rem; margin-top: 2px; }
.mapa-externos .ext-lista {
  margin: .5rem 0 .35rem; border-top: 1px solid var(--panel-border); padding-top: .35rem;
}
.mapa-externos .ext-fila { display: flex; justify-content: space-between; gap: .6rem; }
.mapa-externos .ext-pie { color: var(--text-muted); font-size: .7rem; }
@media (max-width: 640px) {
  .mapa-externos { position: static; max-width: none; margin: 0 0 .6rem; }
}

/* Aviso dentro de la leyenda: el usuario pidió incidencia y el mapa pinta confirmados. */
.map-legend-aviso {
  margin-top: .4rem; padding-top: .35rem; border-top: 1px solid rgba(255, 255, 255, .18);
  font-size: .68rem; line-height: 1.25; max-width: 190px; opacity: .95;
}


/* ── Sala con el pipeline corregido (OSIRIS + NetLab) ─────────────────────────
   Dos colores de texto para tablas: el numero que hay que ir a corregir y el que solo
   hay que vigilar. Usan las variables del tema, asi que el claro y el oscuro se resuelven
   solos -- un color fijo aqui se vuelve ilegible en cuanto alguien cambia de tema. */
.txt-alert { color: var(--danger); }
.txt-warn  { color: var(--warning); }

/* La banda de KPIs de la sala interna vive dentro de un panel, no a ancho de pagina:
   sin esto hereda el grid de #kpis y las tarjetas salen del recuadro en pantallas medias. */
#sala-lab-kpis { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
#sala-lab-kpis .d-kpi .d-l small { display: block; opacity: .75; font-weight: 400; }


/* ── Objetivo táctil: lo decide el PUNTERO, no el ancho ───────────────────────
   Los conmutadores medían 24 px de alto en una tablet de 768 px, porque la regla que los
   agranda cuelga de `max-width: 720px`. Una tablet es táctil aunque sea ancha, y el dedo
   no encoge con la pantalla. `pointer: coarse` pregunta lo que de verdad importa. */
@media (hover: none) and (pointer: coarse) {
  .btn-map-toggle { min-height: 36px; padding: 7px 14px; }
  .map-metrica-sel { min-height: 36px; }
}

/* =========================================================
   AVISO DE CARGA — «la pantalla no está rota, está trabajando»
   Dos piezas distintas para dos esperas distintas:

   · .cargando-barra  — hilo de 3 px arriba del todo. Sale sola con CUALQUIER llamada al
     servidor (la engancha api.js contando peticiones en vuelo). No bloquea nada: es para
     las esperas cortas —un panel, una descarga, un desplegable— donde un modal encima de
     la pantalla molestaría más de lo que informa.
   · .cargando-overlay — modal centrado. Solo para las tres esperas LARGAS en las que la
     pantalla se queda quieta o, peor, enseñando el corte anterior: el arranque, un filtro
     que re-agrega el corte entero en el servidor y el ETL. Ahí el usuario necesita saber
     que lo que ve todavía no es la respuesta.

   Ambas viven en el tema (var(--...)) para no repintarse al conmutar claro/oscuro.
   ========================================================= */
.cargando-barra {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 3px;
  z-index: 4000;
  background: linear-gradient(90deg,
      transparent 0%, var(--accent) 35%, #14b8a6 50%, var(--accent) 65%, transparent 100%);
  background-size: 220% 100%;
  animation: cargando-corre 1.1s linear infinite;
  pointer-events: none;
}
@keyframes cargando-corre {
  from { background-position: 120% 0; }
  to   { background-position: -120% 0; }
}
/* La banda de datos ficticios va fija arriba y empuja el resto: el hilo baja con ella. */
body.con-aviso-demo .cargando-barra { top: 34px; }

.cargando-overlay {
  position: fixed;
  inset: 0;
  z-index: 4100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: rgba(2, 6, 16, 0.55);
  backdrop-filter: blur(3px);
}
:root[data-theme="light"] .cargando-overlay { background: rgba(148, 163, 184, 0.35); }
.cargando-overlay[hidden] { display: none; }

.cargando-caja {
  background: var(--panel-bg);
  border: 1px solid var(--panel-border);
  border-radius: 14px;
  backdrop-filter: blur(14px);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .35);
  padding: 1.6rem 2rem;
  max-width: 380px;
  text-align: center;
}
.cargando-spin {
  width: 38px; height: 38px;
  margin: 0 auto .9rem;
  border-radius: 50%;
  border: 3px solid var(--panel-border);
  border-top-color: var(--accent);
  border-right-color: #14b8a6;
  animation: cargando-gira .8s linear infinite;
}
@keyframes cargando-gira { to { transform: rotate(360deg); } }

.cargando-tit {
  margin: 0;
  font-size: .95rem;
  font-weight: 700;
  color: var(--text-main);
}
.cargando-sub {
  margin: .35rem 0 0;
  font-size: .76rem;
  line-height: 1.45;
  color: var(--text-muted);
}
/* El paso concreto (subiendo NetLab 3 de 7, procesando…) cuando lo hay. */
.cargando-paso {
  margin: .7rem 0 0;
  font-size: .72rem;
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  color: var(--accent);
  min-height: 1em;
}

/* Marca de agua sobre un panel cuyo gráfico todavía se está dibujando. Se pone y se quita
   desde JS con la clase, así que no hace falta tocar el HTML de cada panel. */
.d-chart-wrap.esperando::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 10px;
  background: linear-gradient(100deg,
      transparent 20%, var(--soft-bg) 45%, transparent 70%);
  background-size: 260% 100%;
  animation: cargando-corre 1.3s linear infinite;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .cargando-barra, .cargando-spin, .d-chart-wrap.esperando::after { animation: none; }
  .cargando-spin { border-top-color: var(--accent); opacity: .8; }
}

/* =========================================================
   REZAGO DE VISIBILIDAD — «por qué la curva se sigue llenando»
   Los tramos van NUMERADOS y unidos por una línea porque aquí el número dice algo cierto:
   es un circuito, cada paso ocurre después del anterior y el reloj de uno no arranca hasta
   que el de antes para. Numerar un montón de tarjetas sueltas sería decoración; esto no.
   ========================================================= */
.rez-lectura {
  border-radius: 12px;
  border: 1px solid var(--panel-border);
  border-left: 4px solid var(--warning);
  background: var(--soft-bg);
  padding: 1rem 1.2rem;
  margin-bottom: 1.1rem;
}
.rez-lectura .rez-titular {
  font-size: 1.02rem;
  font-weight: 700;
  line-height: 1.45;
  margin: 0 0 .45rem;
  color: var(--text-main);
  text-wrap: balance;
}
.rez-lectura .rez-titular b { color: var(--warning); }
.rez-lectura p { font-size: .82rem; line-height: 1.55; color: var(--text-muted); margin: 0; }
.rez-lectura p + p { margin-top: .45rem; }

/* ---- el circuito, paso a paso ---- */
.rez-tramos { display: flex; flex-direction: column; gap: 0; margin: .3rem 0 .4rem; }
.rez-tramo {
  display: grid;
  grid-template-columns: 34px 1fr auto;
  gap: 0 .9rem;
  align-items: start;
  padding: .85rem 0;
  border-top: 1px solid var(--panel-border);
}
.rez-tramo:first-child { border-top: 0; }
.rez-num {
  grid-row: 1 / span 2;
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  font-size: .8rem; font-weight: 800;
  color: var(--text-main);
  background: var(--soft-bg);
  border: 1px solid var(--panel-border);
  position: relative;
}
/* Hilo que une un paso con el siguiente: es lo que convierte cinco tarjetas en un circuito. */
.rez-tramo:not(:last-child) .rez-num::after {
  content: "";
  position: absolute;
  top: 30px; left: 50%;
  width: 1px; height: calc(100% + 1.1rem);
  background: var(--panel-border);
}
.rez-tramo.ok    .rez-num { border-color: var(--success); color: var(--success); }
.rez-tramo.warn  .rez-num { border-color: var(--warning); color: var(--warning); }
.rez-tramo.alert .rez-num { border-color: var(--danger);  color: var(--danger); }

.rez-t-tit { font-size: .88rem; font-weight: 700; margin: .25rem 0 .2rem; }
.rez-t-det { font-size: .78rem; line-height: 1.5; color: var(--text-muted); margin: 0; }
.rez-t-det b { color: var(--text-main); }
/* El reloj del tramo, alineado a la derecha para poder compararlos de un vistazo. */
.rez-t-reloj {
  grid-row: 1 / span 2;
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  padding-top: .2rem;
}
.rez-t-dias { font-size: 1.35rem; font-weight: 800; line-height: 1; }
/* El color del RELOJ lo decide su propia medida contra su propia meta, no el estado de la
   fila. En el tramo del laboratorio apuntan al revés a propósito: la mediana es buenísima
   (1 d contra una meta de 4) y lo que está mal es la cola acumulada, que es lo que marca la
   fila. Colgando el color del estado de la fila, ese «1 d» salía en rojo. */
.rez-t-reloj.v-ok    .rez-t-dias { color: var(--success); }
.rez-t-reloj.v-warn  .rez-t-dias { color: var(--warning); }
.rez-t-reloj.v-alert .rez-t-dias { color: var(--danger); }
.rez-t-meta { font-size: .68rem; color: var(--text-muted); margin-top: 3px; }

@media (max-width: 620px) {
  .rez-tramo { grid-template-columns: 26px 1fr; }
  .rez-t-reloj { grid-row: auto; grid-column: 2; text-align: left; padding-top: .45rem; }
  .rez-t-dias { font-size: 1.1rem; }
}

/* Fila de la tabla día a día que cae dentro de la zona todavía ilegible. */
#tablaVisibilidad tr.rez-tibia td { background: rgba(217, 119, 6, .10); }
#tablaVisibilidad tr.rez-firme td { opacity: .72; }

/* =========================================================
   TESELAS DEL MAPA (OpenStreetMap)
   OSM se sirve en un solo estilo, colorido: verdes, amarillos y rosas que compiten con la
   escala amarillo-rojo del coroplético -el tramo más bajo, #fed976, casi desaparecía sobre
   el beige-. Se apaga en el tema claro y se invierte en el oscuro. El filtro va sobre la
   CAPA de teselas (clase que pone Leaflet vía `className`), no sobre el mapa: los
   polígonos y la leyenda van en otras capas y conservan sus colores exactos.
   Elegido simulando las funciones de filtro sobre una tesela real con los cinco tramos
   encima. Orden de izquierda a derecha, como los aplica el navegador.
   ========================================================= */
.teselas-osm { filter: saturate(.35) brightness(1.03); }
:root[data-theme="dark"] .teselas-osm {
  filter: invert(1) hue-rotate(180deg) brightness(.85) contrast(.9) saturate(.45);
}

/* =========================================================
   EXPOSICIÓN OFICIAL (Reporte epidemiológico)
   Va aparte de la rejilla de extracción y con otro peso visual a propósito: no es una
   descarga inmediata, necesita un insumo que se sube y tarda un minuto en generarse.
   ========================================================= */
.expo-oficial {
  margin-top: 1.1rem; padding: 1rem 1.1rem; border: 1px solid var(--panel-border);
  border-radius: 10px; display: flex; flex-direction: column; gap: .75rem;
}
.expo-oficial h4 { margin: 0; font-size: .95rem; display: flex; flex-wrap: wrap; gap: .4rem; align-items: baseline; }
.expo-oficial h4 span {
  font-size: .68rem; font-weight: 600; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: .3px;
}
.expo-intro { margin: 0; font-size: .8rem; line-height: 1.5; color: var(--text-muted); max-width: 72ch; }
.expo-insumos { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: .6rem; }
.expo-insumo {
  display: flex; flex-direction: column; gap: .25rem; padding: .55rem .65rem;
  border: 1px dashed var(--panel-border); border-radius: 8px; min-width: 0;
}
.expo-ins-lbl { font-size: .7rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: .3px; }
.expo-ins-lbl em { font-style: normal; text-transform: none; letter-spacing: 0; opacity: .8; }
.expo-ins-val { font-size: .8rem; overflow-wrap: anywhere; }
.expo-ins-val small { display: block; color: var(--text-muted); font-size: .72rem; }
.expo-subir {
  align-self: flex-start; font-size: .75rem; padding: 3px 10px; border-radius: 6px;
  border: 1px solid var(--panel-border); cursor: pointer;
}
.expo-subir:hover, .expo-subir:focus-within { border-color: var(--accent); color: var(--accent); }
.expo-acciones { display: flex; flex-wrap: wrap; gap: .6rem; align-items: center; }
.expo-resultado:empty { display: none; }
.expo-resultado { font-size: .8rem; line-height: 1.5; }
.expo-veredicto { font-weight: 700; }
.expo-veredicto.ok { color: var(--success); }
.expo-veredicto.alert { color: var(--danger); }
.expo-resultado ul { margin: .3rem 0 0; padding-left: 1.1rem; }
.expo-resultado details { margin-top: .4rem; }
.expo-resultado summary { cursor: pointer; color: var(--text-muted); }
