/* style.css — CSS simple, mobile-first, sin frameworks. */

:root {
  --color-bg: #f5f6f8;
  --color-text: #1f2430;
  --color-primary: #1d4ed8;
  --color-primary-dark: #1739a6;
  --color-border: #d5d9e0;
  --color-danger: #b91c1c;
  --color-danger-bg: #fde8e8;
  --color-warning-bg: #fff4d6;
  --color-warning-text: #7a5b00;
  --color-success-bg: #e3f6e5;
  --color-success-text: #14532d;
  --radius: 10px;
  /* Alto fijo de .app-topbar, en su propia variable para que el menú
     lateral sticky (.app-sidebar, ver más abajo) sepa exactamente cuánto
     espacio dejarle arriba sin superponerse — una sola fuente de verdad
     en vez de adivinar el alto real del topbar en 2 lugares distintos. */
  --topbar-h: 3.3rem;
  font-size: 16px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  line-height: 1.45;
}

.wrap {
  max-width: 640px;
  margin: 0 auto;
  padding: 1rem 1rem 3rem;
}

/* Cualquier usuario que no esté en ADMIN_WRITE_USERS (ver inc/helpers.php
   is_read_only_user()/block_write_if_read_only()): oculta CUALQUIER
   formulario de escritura de una sola vez, en vez de tocar cada botón de
   guardar/borrar/actualizar de cada página una por una — todo formulario
   de escritura en esta app ya usa method="post" (los de solo filtrar/
   buscar son siempre method="get"), así que esta única regla cubre lo
   que existe hoy Y lo que se agregue después, sin mantenimiento extra.
   El bloqueo real (que nadie pueda escribir aunque fuerce el POST a
   mano) vive en el servidor, no acá — ver block_write_if_read_only().
   Excepción explícita [data-readonly-visible] (Ana, 2026-08-16, segunda
   vuelta: en el formulario de campo pidió dejar TODO visible, incluidos
   los campos, y deshabilitar solo el botón de guardar — no ocultar el
   formulario entero como acá) — ver campo/sede.php, el botón mismo se
   deshabilita aparte con el atributo disabled en PHP. */
/* !important a propósito: varios formularios de escritura ya traen su
   propio style="display:flex" inline (layout de la fila, ej.
   admin/sites.php) que sin esto le gana a esta regla — probado en vivo,
   sin !important 50 formularios de sites.php quedaban "ocultos" en la
   hoja de estilos pero visibles en pantalla. Es el único !important de
   todo el proyecto, y es intencional: esto tiene que ganar siempre. */
body.role-readonly form[method="post"]:not([data-readonly-visible]) { display: none !important; }

/* Mismo criterio: cualquier link que apunte a las 2 páginas bloqueadas
   por Apache para un usuario de solo lectura (admin/.htaccess) queda
   inerte, en vez de llevar a una página que da 403. "psicosocial.php"
   queda SIN bloquear (sí debe aparecer el diagnóstico psicosocial, solo
   muestra agregados por sede, nunca nombres) — lo bloqueado son los 2
   IMPORTADORES de Excel
   (import.php / import_psicosocial.php), por eso hacen falta 2
   selectores explícitos en vez del truco de un solo substring de antes
   (import.php no es substring de import_psicosocial.php ni viceversa). */
body.role-readonly a[href*="/import.php"],
body.role-readonly a[href*="/import_psicosocial.php"] {
  pointer-events: none; cursor: default; text-decoration: none; color: inherit;
}

.page-header {
  padding: 1.25rem 0 0.5rem;
}

.page-header h1 {
  font-size: 1.4rem;
  margin: 0 0 0.4rem;
}

.page-header p {
  margin: 0;
  color: #4b5262;
  font-size: 0.95rem;
}

fieldset {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 0.9rem 1rem 1.1rem;
  margin: 0 0 1rem;
  background: #fff;
}

legend {
  font-weight: 600;
  padding: 0 0.4rem;
  font-size: 0.95rem;
}

label {
  display: block;
  font-weight: 500;
  margin: 0.7rem 0 0.3rem;
  font-size: 0.92rem;
}

label.checkbox {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 400;
  margin: 0.5rem 0;
}

label.checkbox input { width: auto; }

input[type="text"],
input[type="tel"],
select,
textarea {
  width: 100%;
  padding: 0.65rem 0.7rem;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  font-size: 1rem;
  font-family: inherit;
  background: #fff;
  color: var(--color-text);
}

input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

.hint {
  color: #6b7280;
  font-size: 0.82rem;
  margin: 0.3rem 0 0;
}

.pending-hint {
  color: var(--color-warning-text);
  font-weight: 600;
}

details.hint {
  margin-top: 0.5rem;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  padding: 0.5rem 0.7rem;
}
details.hint summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--color-text);
}
details.hint dl { margin: 0.6rem 0 0.2rem; }
details.hint dt { color: var(--color-text); margin-top: 0.5rem; }
details.hint dd { margin: 0.15rem 0 0; }

button[type="submit"] {
  width: 100%;
  padding: 0.9rem;
  font-size: 1.05rem;
  font-weight: 600;
  color: #fff;
  background: var(--color-primary);
  border: none;
  border-radius: var(--radius);
  cursor: pointer;
  margin-top: 0.3rem;
}

button[type="submit"]:active { background: var(--color-primary-dark); }
button[type="submit"]:disabled { opacity: 0.6; cursor: not-allowed; }

.banner {
  padding: 0.8rem 1rem;
  border-radius: var(--radius);
  margin-bottom: 1rem;
  font-size: 0.92rem;
}

.banner-warning {
  background: var(--color-warning-bg);
  color: var(--color-warning-text);
}

.banner-success {
  background: var(--color-success-bg);
  color: var(--color-success-text);
}

.banner-error {
  background: var(--color-danger-bg);
  color: var(--color-danger);
}

/* Confirmación de guardado en public/campo/sede.php — más grande y con
   acento a la izquierda a propósito: en celular, después de llenar un
   formulario largo, el equipo de campo necesita ver de un vistazo que sí
   quedó guardado, no un aviso chico que se pierde entre el resto. */
.banner-save-confirm {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 1rem 1.1rem;
  font-size: 1rem;
  border-left: 4px solid var(--color-success-text);
}
.banner-save-confirm strong { font-size: 1.05rem; }
.banner-save-confirm span { font-size: 0.85rem; opacity: 0.9; }
.banner-save-confirm-close {
  display: inline-block;
  margin-top: 0.5rem;
  font-weight: 600;
  font-size: 0.88rem;
  color: var(--color-success-text);
  text-decoration: underline;
}

/* Aviso de "no se guardó" junto al botón Guardar (campo/sede.php,
   incidente 2026-08-20) — mismo tratamiento grande/con acento que
   .banner-save-confirm arriba, en rojo, para que un error de validación
   pese lo mismo visualmente que una confirmación de éxito y no se
   confunda con el resto de texto de ayuda de la página. */
.banner-save-alert {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 1rem 1.1rem;
  font-size: 1rem;
  border-left: 4px solid var(--color-danger);
}
.banner-save-alert strong { font-size: 1.05rem; }
.banner-save-alert span { font-size: 0.85rem; opacity: 0.9; }

/* ---- Dashboard admin ---- */
/* Los paneles de /admin usan casi todo el ancho de pantallas grandes
   (a diferencia de .wrap, pensado mobile-first para el formulario
   público) — así las tablas anchas no dependen tanto del scroll interno. */

.admin-wrap {
  max-width: 1800px;
  padding-left: 1.5rem;
  padding-right: 1.5rem;
}

@media (max-width: 700px) {
  .admin-wrap {
    padding-left: 0.75rem;
    padding-right: 0.75rem;
  }
}

.counters {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.7rem;
  margin: 1rem 0;
}

@media (min-width: 700px) {
  .counters { grid-template-columns: repeat(4, 1fr); }
}

.counter-card {
  background: #fff;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 0.8rem;
  text-align: center;
}

.counter-card .num {
  font-size: 1.6rem;
  font-weight: 700;
  display: block;
}

.counter-card .label {
  font-size: 0.78rem;
  color: #6b7280;
}

.counter-card.alert .num { color: var(--color-danger); }

/* ---- Franja de 6 categorías del MEN (panorama ejecutivo compartido por
   admin/index.php y admin/summary.php) — ver render_structural_status_strip()
   en inc/charts.php. Cada caja es un enlace: el color superior es la única
   señal de severidad (nunca "alerta sí/no" binario) y coincide exacto con
   los colores que ya usa el Excel de la SEM. ---- */
.status-strip {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.6rem;
  margin: 1rem 0 1.4rem;
}
@media (min-width: 700px) {
  /* auto-fit en vez de repeat(6, 1fr) fijo — la 7ª caja opcional "Sin
     evaluar" (sedes sin visita, ver render_structural_status_strip() en
     charts.php) quedaba sola en su propia fila cuando aparecía (6 no
     divide 7), como una tarjeta huérfana desalineada. Con auto-fit la
     grilla se acomoda sola a 6 o 7 columnas parejas según cuántas cajas
     traiga cada página — Ana lo notó en admin/sites.php, 2026-08-16. */
  .status-strip { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
}
.status-strip-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  background: #fff;
  border: 1px solid var(--color-border);
  border-top: 4px solid;
  border-radius: var(--radius);
  padding: 0.7rem 0.5rem;
  text-align: center;
  text-decoration: none;
  transition: box-shadow 0.15s;
}
.status-strip-item:hover {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.status-strip-item-active {
  background: #f0f1f4;
  border-color: #b8bcc4;
  box-shadow: inset 0 0 0 1px currentColor;
}
.status-strip-num {
  font-size: 1.7rem;
  font-weight: 700;
  line-height: 1.1;
}
.status-strip-label {
  font-size: 0.74rem;
  color: var(--color-text);
  line-height: 1.15;
}

/* ---- Gráficos del resumen ejecutivo (admin/summary.php) ---- */
/* Cada gráfico va en una tarjeta de ancho acotado: el SVG interno usa un
   viewBox fijo, así que sin un límite de ancho aquí se estira al tamaño
   del panel (hasta 1800px) y todo — texto incluido — se ve gigante. */

.section-title {
  font-size: 1.05rem;
  font-weight: 700;
  margin: 1.6rem 0 0.6rem;
}

.chart-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 0.9rem;
  margin: 0 0 1.6rem;
  align-items: start;
}

/* Como .chart-grid, pero cada celda trae su propio título+descripción
   (.dash-block-head) arriba de la tarjeta, no solo el <h3> corto que
   usa .chart-grid — admin/psicosocial.php, "Alertas más frecuentes" +
   "Personal afectado por rol" lado a lado (Ana, 2026-08-16). Mínimo más
   ancho que .chart-grid porque estos 2 gráficos necesitan más espacio
   para nombres de institución largos. */
.psico-chart-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
  gap: 0.4rem 1.4rem;
  align-items: start;
}

.chart-card {
  background: #fff;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 0.9rem 1.1rem 1rem;
  max-width: 460px;
}

.chart-card.chart-card-wide {
  max-width: 620px;
}

.chart-card h3 {
  margin: 0 0 0.6rem;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--color-text);
}

/* Grid en vez de flex-wrap (Ana, 2026-08-16, admin/sites.php: con 7+
   campos el botón "Filtrar" y "Limpiar filtros" quedaban cada uno solo
   en su propia fila, pegados a la izquierda, y un campo se desalineaba
   verticalmente unos px del resto) — con grid cada fila se reparte
   pareja sola (tantas "líneas" como hagan falta, se acomoda solo) y
   todos los campos alinean por su base de forma consistente.
   minmax(160px, 220px) — NO minmax(160px, 1fr) — a propósito: con 1fr,
   cuando hay pocos campos (ej. el filtro de Sector de admin/dashboard.php,
   uno solo) esa única columna se estira a TODO el ancho sobrante de la
   fila, quedando gigante y "sin estilo" (Ana, 2026-08-16). Con un tope
   fijo cada campo queda del mismo ancho razonable haya 1 o 9 campos, y
   el espacio sobrante simplemente queda vacío a la derecha (normal en
   una barra de filtros corta). */
.filters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 220px));
  gap: 0.8rem 0.7rem;
  margin: 1rem 0;
  align-items: end;
}

.filters label {
  font-size: 0.8rem;
  margin: 0 0 0.2rem;
}

.filters select {
  padding: 0.4rem 0.5rem;
}

/* El botón[type=submit] global (button[type="submit"] { width:100%;
   padding:0.9rem; font-size:1.05rem; ...}) está pensado para el CTA
   grande de los formularios públicos de una sola pregunta — dentro de
   .filters ahora es una celda de grid de ~160px+ (antes, con flex, el
   div se achicaba al contenido y "width:100%" no se notaba tanto), así
   que se veía desproporcionadamente grande al lado de selects/inputs
   chicos (Ana, 2026-08-16, "quedaron muy grandes"). Tamaño a la par del
   resto de los controles del filtro, ancho natural (no estirado). */
.filters button[type="submit"] {
  width: auto;
  padding: 0.5rem 1.1rem;
  font-size: 0.88rem;
}

.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  margin: 0.8rem 0 1.6rem;
  font-size: 0.85rem;
}

.pagination-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  align-items: center;
}

.pagination-links a,
.pagination-links strong {
  display: inline-block;
  min-width: 1.8rem;
  text-align: center;
  padding: 0.3rem 0.5rem;
  border-radius: 6px;
  text-decoration: none;
  color: var(--color-primary);
}

.pagination-links strong {
  background: var(--color-primary);
  color: #fff;
}

.pagination-links a:hover { background: #eef2ff; }

.pagination-ellipsis { color: #6b7280; padding: 0 0.2rem; }

/* Paginación repetida arriba de una tabla larga (además de la de abajo) —
   Ana, 2026-08-16, admin/psicosocial.php "Detalle por sede": para no tener
   que bajar hasta el final solo para pasar de página. Misma <nav> que
   abajo, solo que acá se empuja a la esquina superior derecha de la tabla
   en vez de ocupar todo el ancho con "Página X de Y" a la izquierda. */
.pagination-top {
  display: flex;
  justify-content: flex-end;
}
.pagination-top .pagination {
  margin: 0 0 0.5rem;
}

/* "Sombra de scroll" — Ana, 2026-08-16 (admin/sites.php, tabla de 18
   columnas): con overflow-x:auto la tabla YA se desplazaba bien
   contenida (fix de .app-content min-width:0 más arriba en este mismo
   archivo), pero sin ninguna señal visual de que hay más a la derecha
   se seguía viendo "cortada" — el borde derecho de la caja no se
   distingue de "acá se termina el dato". Truco 100% CSS (sin JS): dos
   gradientes blancos que se desplazan CON el contenido (tapan la sombra
   cuando ya se ve el final de esa columna) más dos gradientes de sombra
   fijos respecto al viewport — el resultado es una sombra que aparece
   sola en el borde que todavía tiene contenido oculto, y desaparece
   sola cuando ya se llegó ahí. Mismo mecanismo en cualquier tabla ancha
   del panel (esta clase es compartida). */
.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background-color: #fff;
  background-repeat: no-repeat;
  background-size: 24px 100%, 24px 100%, 10px 100%, 10px 100%;
  background-position: left center, right center, left center, right center;
  background-image:
    linear-gradient(to right, #fff, rgba(255,255,255,0)),
    linear-gradient(to left, #fff, rgba(255,255,255,0)),
    linear-gradient(to right, rgba(0,0,0,0.12), rgba(0,0,0,0)),
    linear-gradient(to left, rgba(0,0,0,0.12), rgba(0,0,0,0));
  background-attachment: local, local, scroll, scroll;
}

table {
  border-collapse: collapse;
  width: 100%;
  min-width: 900px;
  font-size: 0.85rem;
}

th, td {
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--color-border);
  text-align: left;
}

th { white-space: nowrap; }
/* Las celdas de texto largo (descripción, comentario) sí pueden partirse en
   varias líneas — evita que una sola columna estire toda la tabla. */
td { white-space: normal; max-width: 320px; }

th { background: #f0f1f4; position: sticky; top: 0; }

/* .dash-table/.dash-table-wrap (psicosocial.php, …) nunca habían tenido
   CSS propio: heredaban `table { min-width: 900px }` y
   `th { white-space: nowrap }` de arriba sin ningún `overflow-x` en el
   wrapper que lo compensara. Adentro de una tarjeta angosta (.chart-card,
   ~460px) el encabezado sin poder partirse en 2 líneas ("% de la
   muestra") obliga a la tabla a crecer más allá de su contenedor, y las
   columnas de la derecha quedan pintadas fuera de la tarjeta, superpuestas
   con lo que sigue al lado.
   `table-layout: fixed` se probó primero pero rompía las tablas anchas de
   verdad (ej. el detalle de psicosocial.php, 12 columnas): igualaba todas
   las columnas a un ancho parejo minúsculo en vez de dejar que el
   contenido mande. La solución real es 2 cosas MÁS chicas: dejar que el
   encabezado se parta en líneas (`white-space: normal`, en vez de
   heredar el nowrap de arriba) para que las tablas angostas ya quepan
   solas, y `overflow-x: auto` en el wrapper como resguardo para las
   tablas que de verdad son más anchas que su tarjeta (scroll horizontal
   propio, nunca se desborda sobre el vecino). */
.dash-table-wrap { overflow-x: auto; }
.dash-table th, .dash-table td { overflow-wrap: break-word; word-break: break-word; white-space: normal; }

tr.status-danger td { background: var(--color-danger-bg); }
tr.status-stale td { background: var(--color-warning-bg); }

.badge {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
}

.badge-ok { background: var(--color-success-bg); color: var(--color-success-text); }
.badge-warn { background: var(--color-warning-bg); color: var(--color-warning-text); }
.badge-danger { background: var(--color-danger-bg); color: var(--color-danger); }

.export-btn {
  display: inline-block;
  padding: 0.55rem 1rem;
  background: var(--color-primary);
  color: #fff;
  text-decoration: none;
  border-radius: 8px;
  font-weight: 600;
  font-size: 0.9rem;
}

/* ---- Layout de /admin: barra superior + menú lateral ---- */
/* Colapsa a overlay en móvil con un checkbox oculto + CSS puro (sin JS).
   inc/admin_header.php arma el HTML; esto es solo la presentación. */

.nav-toggle-checkbox { display: none; }
.nav-toggle-btn { display: none; }

.app-shell {
  display: grid;
  grid-template-columns: 230px 1fr;
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "topbar topbar"
    "sidebar content";
  min-height: 100vh;
}

.app-topbar {
  grid-area: topbar;
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0.7rem 1.2rem;
  min-height: var(--topbar-h);
  background: #fff;
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: 30;
}

.app-topbar-title { font-weight: 700; }
.app-topbar-page { color: #6b7280; font-size: 0.9rem; }
.app-topbar-export {
  margin-left: auto;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: none;
  white-space: nowrap;
}
.app-topbar-export:hover { text-decoration: underline; }

/* Antes se desplazaba junto con el contenido — en páginas largas (Detalle
   por sede, Diagnóstico psicosocial) el menú y el botón "Salir" quedaban
   fuera de vista al bajar. Ana, 2026-08-20: "dejar el menú permanente en
   la visualización" — sticky + su propio alto/scroll interno, mismo
   truco que ya usa .app-topbar (position:sticky; top:0) más arriba. Solo
   en escritorio: en móvil el menú ya es un overlay aparte (ver
   @media max-width:900px más abajo), no debe llevar sticky ahí. */
.app-sidebar {
  grid-area: sidebar;
  background: #fff;
  border-right: 1px solid var(--color-border);
  padding: 1rem 0.7rem;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  position: sticky;
  top: var(--topbar-h);
  height: calc(100vh - var(--topbar-h));
  overflow-y: auto;
}

.app-sidebar a {
  display: block;
  padding: 0.6rem 0.8rem;
  border-radius: 8px;
  text-decoration: none;
  color: var(--color-text);
  font-size: 0.92rem;
  font-weight: 500;
}

.app-sidebar a:hover { background: #eef2ff; }
.app-sidebar a.active { background: var(--color-primary); color: #fff; }

/* Etiqueta de grupo del menú ("General" / "Censo psicosocial") — Ana,
   2026-08-16: agrupar visualmente el módulo psicosocial (+ Casos de
   comunidad, que pidió mover ahí) separado del censo estructural de
   siempre. Mismo tratamiento tipográfico (mayúscula, letter-spacing) que
   ya usa .dash-block-head h3 en los dosieres, para que se sienta la
   misma convención de "encabezado de sección" en todo el panel. */
.app-sidebar-group-label {
  display: block;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #7d848c;
  padding: 0.9rem 0.8rem 0.3rem;
}
.app-sidebar-group-label:first-child { padding-top: 0.3rem; }
/* El texto solo no bastaba como separación (Ana, 2026-08-16) — se suma
   una línea divisoria arriba de cada grupo (menos el primero) y un
   acento del mismo morado/ciruela que ya identifica el módulo
   psicosocial en el resto del panel (dash-dossier.dash-psico, la tarjeta
   resumen del Dashboard), para que el segundo grupo se sienta
   claramente "su propia sección" y no solo un subtítulo more. */
.app-sidebar-group-label:not(:first-child) {
  margin-top: 0.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--color-border);
}
.app-sidebar-group-label.psico { color: #6b3f6b; }
.app-sidebar a.psico-link.active { background: #6b3f6b; }
.app-sidebar-group-label.retorno { color: #2a4d8f; }
.app-sidebar a.retorno-link.active { background: #2a4d8f; }
/* Primera infancia (Ana, 2026-08-25: "que en el menú destaque un poco
   más") — mismo tratamiento de color que psico/retorno arriba, más una
   etiqueta "Nuevo" (módulo recién agregado) para que salte a la vista sin
   depender solo del color. Verde/turquesa a propósito: ni el morado de
   psico ni el azul de retorno, para que las 3 secciones se distingan entre
   sí de un vistazo. */
.app-sidebar-group-label.pi { color: #1f7a5c; }
.app-sidebar a.pi-link.active { background: #1f7a5c; }
.nav-badge-new {
  display: inline-block; font-size: 0.6rem; font-weight: 800; letter-spacing: 0.03em;
  color: #fff; background: #1f7a5c; padding: 0.08rem 0.4rem; border-radius: 999px;
  margin-left: 0.3rem; text-transform: none; vertical-align: middle;
}

.app-sidebar-footer {
  margin-top: auto;
  padding-top: 0.8rem;
  border-top: 1px solid var(--color-border);
}
/* Botón "Salir" — Ana, 2026-08-20: el link de cerrar sesión quedaba muy
   discreto/perdido al final de un menú largo. Rojo se veía como una
   alerta/error (no lo es, es una acción normal) — se cambió a azul,
   el mismo --color-primary que ya usan todos los botones de acción del
   resto del panel, para que se lea como "un botón más", solo que
   siempre visible al fondo del menú. Selector .app-sidebar
   a.app-sidebar-logout (no solo .app-sidebar-logout) a propósito:
   necesita más especificidad que .app-sidebar a de arriba para ganarle
   el color/padding/peso sin recurrir a !important (único !important
   intencional del proyecto es otro, ver la nota de body.role-readonly
   más arriba). */
.app-sidebar a.app-sidebar-logout {
  display: block;
  text-align: center;
  margin: 0 0.1rem;
  padding: 0.65rem 0.8rem;
  border-radius: 8px;
  background: var(--color-primary);
  color: #fff;
  font-weight: 700;
  font-size: 0.88rem;
  letter-spacing: 0.01em;
}
.app-sidebar a.app-sidebar-logout:hover { background: var(--color-primary-dark); }

.app-sidebar-backdrop { display: none; }

.app-content {
  grid-area: content;
  max-width: 1800px;
  width: 100%;
  /* Bug real encontrado 2026-08-16 (Ana, en admin/sites.php: "la tabla se
     corta"): una celda de CSS Grid con "1fr" no se achica por debajo del
     ancho mínimo de su contenido salvo que se le diga explícitamente —
     una tabla ancha (admin/sites.php tiene 18 columnas, más de 2000px)
     empujaba TODA la página a desplazarse de lado (arrastrando el menú y
     los filtros con ella) en vez de que solo la tabla tuviera su propio
     scroll horizontal contenido (.table-scroll ya trae overflow-x:auto,
     pero nunca llegaba a activarse porque la página entera ya se había
     estirado antes). min-width:0 deja que esta celda se achique al
     espacio real disponible, y ahí sí manda el overflow-x de cada tabla. */
  min-width: 0;
  padding: 1.3rem 1.5rem 3rem;
  margin: 0 auto;
}

@media (max-width: 900px) {
  .app-shell {
    grid-template-columns: 1fr;
    grid-template-areas:
      "topbar"
      "content";
  }
  .nav-toggle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.2rem;
    height: 2.2rem;
    font-size: 1.2rem;
    cursor: pointer;
    border-radius: 8px;
  }
  .nav-toggle-btn:hover { background: #eef2ff; }
  .app-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    /* Restablece el height:calc(...) del sticky de escritorio — acá el
       overlay móvil ya define el alto con top:0 + bottom:0 (pantalla
       completa), un height explícito de por medio los pisa y lo deja
       corto. */
    height: auto;
    width: 260px;
    transform: translateX(-100%);
    transition: transform 0.2s ease;
    z-index: 50;
    overflow-y: auto;
  }
  .nav-toggle-checkbox:checked ~ .app-shell .app-sidebar {
    transform: translateX(0);
  }
  .app-sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(11, 11, 11, 0.4);
    z-index: 40;
  }
  .nav-toggle-checkbox:checked ~ .app-shell .app-sidebar-backdrop {
    display: block;
  }
}

/* ---- Header simple compartido por el formulario público y cases.php ---- */

.public-topbar {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 0.8rem 1rem;
  background: #fff;
  border-bottom: 1px solid var(--color-border);
  margin: -1rem -1rem 1rem;
}

.public-topbar-title {
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--color-text);
  text-decoration: none;
}

.public-topbar nav { display: flex; gap: 0.9rem; margin-left: auto; }
.public-topbar nav a {
  font-size: 0.85rem;
  color: var(--color-primary);
  text-decoration: none;
  font-weight: 600;
}
.public-topbar nav a.active { color: var(--color-text); text-decoration: underline; }

/* ---- Popup/tooltip del mapa de afectaciones (admin/summary.php) ---- */
.map-point-popup { font-size: 0.85rem; line-height: 1.4; max-width: 230px; }
.map-point-list {
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0;
  max-height: 160px;
  overflow-y: auto;
  border-top: 1px solid var(--color-border);
  padding-top: 0.3rem;
}
.map-point-list li { padding: 0.1rem 0; }
.map-point-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 4px;
}

/* ---- Componentes de "dosier" reutilizables (admin/dashboard.php y
   admin/psicosocial.php) — movidos acá desde el <style> propio de
   dashboard.php el 2026-08-16, al construir el módulo psicosocial, para
   que ambas páginas los compartan sin duplicar la definición. Lo que es
   específico de un solo dominio (barra de severidad estructural, mapa,
   tablas de sedes, checklist de aliados de infraestructura) se queda en
   el <style> propio de cada página. ---- */

.dash-dossier {
  background: #fff; border: 1px solid var(--color-border); border-radius: var(--radius);
  padding: 1.5rem 1.5rem 1.75rem; margin-bottom: 1.75rem; position: relative; overflow: hidden;
}
.dash-dossier::before { content: ""; position: absolute; top: 0; left: 0; bottom: 0; width: 5px; }
/* Acento del dosier psicosocial — morado/ciruela, mismo patrón de "una
   franja de color por dominio". */
.dash-dossier.dash-psico::before { background: #6b3f6b; }
/* Acento del dosier de retorno a clases (admin/dashboard_retorno.php) —
   índigo, distinto del anterior. */
.dash-dossier.dash-retorno::before { background: #2a4d8f; }
.dash-dossier-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin-bottom: 0.9rem;
}
.dash-dossier-head h2 { margin: 0; font-size: 1.15rem; }
.dash-region-chip {
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  padding: 0.28rem 0.6rem; border-radius: 999px; background: var(--color-bg); color: #565f6b;
  white-space: nowrap;
}
/* Más de un chip junto al título de un dosier (ej. "749 personas" + "597
   docentes/directivos afectados" en psicosocial.php) — Ana, 2026-08-16. */
.dash-region-chips { display: flex; gap: 0.4rem; flex-wrap: wrap; }

.dash-stat-band {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
  background: var(--color-border); border: 1px solid var(--color-border);
  border-radius: var(--radius); overflow: hidden; margin-bottom: 2rem;
}
.dash-stat-tile { background: #fff; padding: 1.1rem 1.2rem; }
/* Una banda con 5 tarjetas (no 4 como el resto, ej. dashboard_retorno.php
   cuando hay sedes sin diagnóstico) — con la grilla base a 4 columnas la
   5ta quedaba sola en una fila nueva, con 3 columnas vacías mostrando el
   gris de fondo del grid. Esta clase sube la grilla a 5 columnas solo para
   esa banda. El media query de abajo la vuelve a bajar a 2 columnas en
   mobile igual que el resto (misma especificidad, gana por ir después en
   el archivo). */
.dash-stat-band-5 { grid-template-columns: repeat(5, 1fr); }
.dash-stat-tile .num { display: block; font-size: 1.5rem; font-weight: 800; line-height: 1; }
.dash-stat-tile .num small { font-size: 0.6em; font-weight: 700; color: #6b7280; }
/* Tarjeta de alerta dentro de un stat-band — mismo acento que .dash-mini-stat.warn. */
.dash-stat-tile.warn .num { color: #b5502a; }
.dash-stat-tile .lbl { font-size: 0.78rem; color: #565f6b; margin-top: 0.3rem; display: block; }
.dash-stat-tile .dash-stat-sub { font-size: 0.68rem; color: #7d848c; margin-top: 0.35rem; display: block; }
/* Variante clicable (tarjeta resumen psicosocial del Dashboard, cada
   valor lleva al detalle completo — Ana, 2026-08-16). */
a.dash-stat-tile { display: block; text-decoration: none; color: inherit; }
a.dash-stat-tile:hover { background: var(--color-bg); }
.dash-stat-tile .lbl-link { font-size: 0.66rem; color: var(--color-primary); margin-top: 0.15rem; display: block; text-decoration: underline; }

.dash-mini-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.9rem; margin-bottom: 1.75rem; }
/* Las 5 tarjetas de necesidad del módulo psicosocial (vivienda inhab.,
   daños severos, apoyo urgente, apoyo próx. días, lesionados graves) son
   textos cortos — con la grilla de 3 columnas de arriba (pensada para las
   otras .dash-mini-stats de dashboard.php, con oraciones largas) quedaban
   grandes y partidas en 2 filas (Ana, 2026-08-16, "quedaron en la misma
   línea"). auto-fit con un mínimo chico las deja en una sola fila en
   pantallas normales y las reacomoda solo si de verdad no entran. */
.dash-psico .dash-mini-stats,
.dash-psico-inline .dash-mini-stats {
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 0.6rem;
}
.dash-mini-stat { background: var(--color-bg); border-radius: 8px; padding: 0.8rem 0.9rem; }
.dash-mini-stat .n { display: block; font-size: 1.15rem; font-weight: 800; margin-bottom: 0.2rem; }
.dash-mini-stat.warn .n { color: #b5502a; }
.dash-mini-stat.crit .n { color: #d03b3b; }
.dash-mini-stat .l { font-size: 0.72rem; color: #565f6b; }
a.dash-mini-stat { display: block; text-decoration: none; color: inherit; border: 1px solid transparent; transition: border-color 0.1s; }
a.dash-mini-stat:hover { border-color: var(--color-primary); }
a.dash-mini-stat .l { color: #1d4ed8; text-decoration: underline; }

.dash-block-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.7rem; flex-wrap: wrap;
  margin: 2.25rem 0 0.7rem; padding-top: 1.75rem; border-top: 1px solid var(--color-border);
}
.dash-block-head h3 { margin: 0; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; color: #565f6b; }
.dash-block-count { font-size: 0.72rem; color: #7d848c; }
.dash-note { font-size: 0.75rem; color: #6b7280; margin: 0.3rem 0 1rem; line-height: 1.5; }
/* Aviso de transparencia de datos (ej. bucket "sin identificar" del
   censo psicosocial) — distinto de .dash-note plano para que resalte
   como una nota aparte, no como texto de apoyo cualquiera. */
.dash-note.dash-note-caveat {
  background: var(--color-bg); border: 1px dashed var(--color-border); border-radius: 8px;
  padding: 0.7rem 0.9rem; margin-top: 0.9rem;
}

.dash-priority-row { display: grid; grid-template-columns: 140px 1fr 40px; align-items: center; gap: 0.6rem; margin-bottom: 0.6rem; }
.dash-priority-label { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.76rem; color: #444; white-space: nowrap; }
.dash-priority-track { height: 11px; background: var(--color-bg); border: 1px solid var(--color-border); border-radius: 999px; overflow: hidden; }
.dash-priority-fill { height: 100%; border-radius: 999px 0 0 999px; }
.dash-priority-num { font-weight: 800; font-size: 0.82rem; text-align: right; }

details.more-inline { margin: -0.25rem 0 0.5rem; }
details.more-inline summary { cursor: pointer; font-size: 0.74rem; font-weight: 700; color: #1d4ed8; list-style: none; }
details.more-inline summary::-webkit-details-marker { display: none; }
details.more-inline summary::before { content: "▸ "; }
details.more-inline[open] summary::before { content: "▾ "; }

.dash-ally-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 0.7rem; }
.dash-ally-card { background: var(--color-bg); border: 1px solid var(--color-border); border-radius: 8px; padding: 0.75rem 0.85rem; }
.dash-ally-card h4 { margin: 0 0 0.2rem; font-size: 0.88rem; }
.dash-ally-card .n { font-size: 0.72rem; color: #565f6b; margin-bottom: 0.4rem; display: block; }
.dash-ally-card details summary { cursor: pointer; font-size: 0.74rem; font-weight: 700; color: #1d4ed8; list-style: none; }
.dash-ally-card details summary::-webkit-details-marker { display: none; }
.dash-ally-card details summary::before { content: "▸ "; }
.dash-ally-card details[open] summary::before { content: "▾ "; }
.dash-ally-card details ul { margin: 0.4rem 0 0; padding-left: 1.1rem; font-size: 0.76rem; color: #565f6b; }
.dash-ally-card details li { margin-bottom: 0.2rem; }

/* Titular destacado (ej. "18 instituciones sin programa · 89 personas") —
   tarjeta resumen psicosocial del Dashboard, 2026-08-16. */
.dash-headline {
  display: flex; align-items: center; justify-content: space-between; gap: 0.8rem; flex-wrap: wrap;
  background: #f3ecf3; border-radius: 8px; padding: 0.75rem 1rem; margin: 0 0 1.1rem;
}
.dash-headline p { margin: 0; font-size: 0.9rem; color: var(--color-text); }
.dash-headline strong { color: #6b3f6b; }
.dash-headline .dash-detail-cta { font-size: 0.83rem; white-space: nowrap; }

.dash-detail-cta { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.85rem; font-weight: 700; color: #6b3f6b; text-decoration: none; }
.dash-detail-cta:hover { text-decoration: underline; }

/* Panel resumen psicosocial INSERTADO dentro del dosier de Manizales (a
   pedido de Ana, 2026-08-16), justo después de "Sedes sanas que igual no
   dan clase" — "Personas que perdieron su vivienda" vive ADENTRO de este
   mismo panel (a pedido de Ana, mismo día: agrupa el impacto personal/
   familiar — vivienda + riesgo psicosocial — separado del impacto
   estructural del resto del dosier). Fondo de color propio para que se
   distinga a simple vista sin necesitar leer el título. Vive junto al
   resto del dosier de Manizales, así que hereda su mismo mostrar/ocultar
   con el toggle de región (no necesita su propia lógica de data-region).
   Margen superior más grande que el resto de los bloques del dosier — a
   propósito, para que se note que es un panel aparte, no una sección más
   de la lista. */
.dash-psico-inline {
  background: #f3ecf3; border: 1px solid #d9c6d9; border-radius: var(--radius);
  padding: 1.1rem 1.3rem 1.3rem; margin: 2.5rem 0 1.75rem;
}
.dash-psico-inline .dash-dossier-head { margin-bottom: 0.6rem; }
.dash-psico-inline .dash-headline { background: #fff; }

@media (max-width: 640px) {
  .dash-stat-band { grid-template-columns: repeat(2, 1fr); }
  .dash-mini-stats { grid-template-columns: 1fr; }
  .dash-priority-row { grid-template-columns: 105px 1fr 34px; }
}

/* ---- Diagnóstico de retorno a clases (public/campo/sede.php, agregado
   2026-08-18) — ver mockup_instrumento_retorno.html, diseño aprobado. ---- */

/* Checkboxes de "Grados que retornan" (13 opciones): en columna simple se
   vuelve una lista larguísima en pantallas anchas — grid compacto, mismo
   criterio que .status-strip/.dash-ally-grid más arriba. */
.check-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
  gap: 0.4rem 0.6rem;
  margin: 0.4rem 0 0.8rem;
}
.check-grid label.checkbox { margin: 0; }

/* Campo "Estudiantes sin atención definida" — el indicador de alerta
   principal del instrumento (KPI que se prioriza en el resumen), resaltado
   para que no se pierda entre el resto de campos numéricos del formulario. */
.campo-alerta {
  background: var(--color-warning-bg);
  border: 1px solid #e2932e;
  border-radius: 8px;
  padding: 0.7rem 0.9rem 0.9rem;
  margin: 0.9rem 0;
}
.campo-alerta label { color: #8a5300; }

/* Cada una de las 11 estrategias del checklist de flexibilización
   académica, con su descripción completa siempre visible debajo (a
   diferencia de details.hint, que la esconde) — el equipo de campo suele
   necesitar leerlas todas para decidir cuáles aplican, no solo la que ya
   conoce. */
.flex-check {
  border: 1px solid var(--color-border);
  border-radius: 8px;
  padding: 0.6rem 0.8rem;
  margin-bottom: 0.5rem;
  background: #fff;
}
.flex-check label.checkbox { align-items: flex-start; }
.flex-check input { margin-top: 0.2rem; }

/* Cada opción de "Jornada" con su horario propio al frente, para que quede
   asociado a esa jornada (Ana, 2026-08-18). Desde 2026-08-19 la sede puede
   marcar VARIAS jornadas a la vez (antes era un radio único) — cada una
   despliega su propio bloque de grados (.jornada-block/.jornada-grados)
   además de su horario, ver campo/sede.php. */
.jornada-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.35rem;
}
.jornada-row-label {
  margin: 0;
  flex: 0 0 auto;
  min-width: 130px;
}
.jornada-row-horario {
  flex: 1;
  min-width: 0;
}
@media (max-width: 480px) {
  .jornada-row { flex-wrap: wrap; }
  .jornada-row-horario { flex-basis: 100%; margin-left: 1.6rem; width: calc(100% - 1.6rem); }
}

/* Contenedor de una jornada completa (fila + su propio bloque de grados) —
   2026-08-19, ver comentario de .jornada-row arriba. */
.jornada-block {
  border: 1px solid var(--color-border);
  border-radius: 8px;
  padding: 0.6rem 0.8rem;
  margin-bottom: 0.6rem;
}
.jornada-block .jornada-row { margin-bottom: 0; }
.jornada-grados {
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px dashed var(--color-border);
}

/* Pestañas entre "Levantamiento de campo" (infraestructura) y
   "Diagnóstico de retorno a clases" en campo/sede.php — Ana, 2026-08-18:
   con los 2 formularios uno debajo del otro el botón "Guardar" del
   primero quedaba en la mitad de la página. CSS puro con el mismo truco
   de radios ocultos + selector de hermanos que ya usa
   .nav-toggle-checkbox más arriba (sin JS, cada pestaña sigue siendo un
   <form> completo e independiente, ninguno anidado dentro del otro). */
.tab-toggle {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.tab-bar {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.2rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--color-border);
}
/* Antes: solo una línea azul debajo de la pestaña activa (fácil de pasar
   por alto, ver incidente 2026-08-20: varios usuarios no encontraban la
   confirmación/error de "Diagnóstico de retorno" porque no notaban que
   había 2 pestañas). Ahora cada pestaña es una "píldora" con relleno de
   color propio siempre visible — no solo la activa — para que se note de
   entrada que hay 2 secciones distintas, y la activa además queda sólida
   con el color primario (mismo tratamiento que .app-sidebar a.active). */
.tab-label {
  display: inline-block;
  padding: 0.6rem 1rem;
  font-size: 0.9rem;
  font-weight: 600;
  border-radius: 999px;
  cursor: pointer;
  user-select: none;
  background: var(--color-bg);
  color: #565f6b;
  border: 1px solid var(--color-border);
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.tab-label:hover { border-color: var(--color-primary); }
.tab-label .badge { margin-left: 0.3rem; }
.tab-toggle:focus-visible ~ .tab-bar label { outline: 2px solid var(--color-primary); outline-offset: 2px; }
#tab-campo:checked ~ .tab-bar label[for="tab-campo"],
#tab-retorno:checked ~ .tab-bar label[for="tab-retorno"] {
  color: #fff;
  background: var(--color-primary);
  border-color: var(--color-primary);
}
.tab-panel { display: none; }
#tab-campo:checked ~ #panel-campo,
#tab-retorno:checked ~ #panel-retorno {
  display: block;
}
@media (max-width: 480px) {
  .tab-label { padding: 0.6rem 0.7rem; font-size: 0.82rem; }
}
