/* ==========================================================================
   Centinela 360 - Hoja de estilos propia (sin frameworks / sin Bootstrap)
   ========================================================================== */

/* ==========================================================================
   Rediseno "Centinela Aurora" (vidrio esmerilado + tablero bento).
   Los NOMBRES de variable existentes se conservan a proposito: todas las
   reglas de mas abajo ya consumian estos tokens, asi que retemizar aqui
   basta para actualizar las 53 vistas sin tocar cada archivo. Se agregan
   tokens nuevos (--grad, --color-teal-deep, --glass-*, --color-heading,
   --radius-lg, --shadow-glass, --font-display) para los componentes
   nuevos (capsula flotante, tarjetas bento, tipografia). Solo fuentes de
   sistema: sin Google Fonts ni ningun otro CDN (correccion pre-
   despliegue, ver comentario de --font/--font-display mas abajo).

   --color-heading existe aparte de --color-navy porque --color-navy se
   sigue usando como FONDO fijo (topbar, nav, boton primario) en ambos
   temas -es el "cromo" oscuro de la marca, no cambia con el tema-,
   mientras que --color-heading es el texto de titulos sobre tarjetas y
   SI debe invertirse en modo oscuro (si no, un titulo navy quedaria
   invisible sobre una tarjeta oscura). */
:root {
  /* Alto de la barra de navegacion inferior movil, sin contar la
     safe-area. Un solo lugar que declara este numero: lo consumen
     .app-bottom-nav (min-height) y el padding-bottom de .app-main, para
     que no puedan quedar desincronizados y volver a tapar el ultimo
     item de una lista. Ver PROBLEMA 1 en el bloque @media 640px. */
  --app-bottom-nav-h: 64px;
  --color-navy: #0b2a4a;
  --color-navy-dark: #081f38;
  /* ACENTO AZUL (antes turquesa #17a9c4). Los NOMBRES --color-teal* se
     conservan a proposito: 43 reglas de este archivo ya los consumen, y
     el modulo de Roles que se esta construyendo en paralelo tambien.
     Renombrarlos obligaria a tocar archivos de otra tarea. Cambia el
     valor, no el nombre.

     Un solo tono no sirve para los tres papeles del acento, porque el
     minimo de 4.5:1 tira en direcciones opuestas segun lo que va encima
     o debajo. De ahi los tres tokens (mismo criterio que ya justificaba
     --color-teal-deep):

       --color-teal        bordes, iconos, foco, texto GRANDE, rellenos
                           sin texto encima.  4.09:1 sobre blanco: basta
                           para bordes/iconos (>=3:1) y texto grande,
                           NO para texto de tamano normal.
       --color-teal-text   texto de tamano normal sobre superficie clara.
                           5.93:1 sobre blanco.
       --color-teal-deep   rellenos con texto BLANCO encima.  7.56:1.
       --color-teal-chrome acento sobre el cromo navy fijo (chip de nav
                           activo, marca del topbar), donde el texto que
                           va encima es --color-navy-dark.  7.76:1.
                           Fijo en ambos temas, igual que --color-navy,
                           porque el cromo no cambia con el tema. */
  --color-teal: #0284c7;
  --color-teal-text: #0369a1;
  --color-teal-deep: #075985;
  --color-teal-chrome: #38bdf8;
  --color-bg: #eef2f6;
  --color-surface: #ffffff;
  --color-border: #dde4ea;
  --color-text: #10141c;
  --color-text-muted: #5b6472;
  --color-heading: var(--color-navy);
  --color-danger: #c0392b;
  --color-danger-bg: #fdecea;
  /* Mismo caso que --color-warning: venia en 3.72:1 sobre su propio fondo
     tenue y 4.14:1 sobre blanco. Ajuste minimo a 4.80:1 y 5.35:1. */
  --color-success: #177a4c;
  --color-success-bg: #e8f6ee;
  /* Oscurecido desde #b06d0f (auditoria de contraste de esta rama): sobre
     --color-warning-bg daba 3.73:1 y sobre superficie blanca 4.17:1, ambos
     bajo 4.5:1. Este es el ajuste MINIMO que cumple en los dos fondos
     (4.68:1 y 5.23:1) sin saturar el tono. Falla preexistente, no
     introducida por el cambio de acento a azul. */
  --color-warning: #9a5f0c;
  --color-warning-bg: #fdf1de;
  --radius: 16px;
  --radius-lg: 22px;
  --shadow: 0 16px 36px -20px rgba(11, 42, 74, 0.22);
  --shadow-glass: 0 20px 45px -22px rgba(10, 15, 25, 0.35);
  --grad: linear-gradient(135deg, var(--color-teal-deep), var(--color-navy));
  /* Degradado del boton dominante de la pantalla del guardia ("Escanear
     documento"). En la maqueta aprobada este degradado es celeste
     (#38bdf8 -> #0ea5e9) con texto casi blanco encima; en modo CLARO eso
     da 4.09:1 y 2.77:1, bajo el minimo de 4.5:1. Ese boton lo toca un
     guardia de pie, al sol, en una reja: la legibilidad ahi no es
     estetica. Por eso en claro se profundiza a #075985 -> #0369a1
     (7.56:1 y 5.93:1 con blanco) y en OSCURO se respeta la maqueta tal
     cual, porque ahi si cumple (7.12:1 y 5.51:1 con el texto #04283d de
     la propia maqueta). Unico punto donde la implementacion se aparta
     del concepto, y solo en un tema. */
  --grad-escanear: linear-gradient(150deg, #075985, #0369a1);
  --color-escanear-texto: #ffffff;
  --glass-bg: rgba(255, 255, 255, 0.68);
  --glass-border: rgba(15, 20, 30, 0.08);
  /* Solo tipografias de sistema (sin Google Fonts ni ningun otro CDN: la
     app es una PWA offline-first y esto era la unica dependencia de red
     externa del proyecto). --font-display usa la palabra clave generica
     "ui-rounded" primero -Safari/iOS la resuelve a la variante redondeada
     del font de sistema (SF Pro Rounded)-, y cae al mismo stack robusto
     que --font en cualquier otro navegador; la distincion visual entre
     titulares y texto de interfaz queda dada por peso/tracking, no por
     una familia tipografica distinta. */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --font-display: ui-rounded, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  /* Monoespaciada de SISTEMA (sin Google Fonts, mismo criterio que
     --font/--font-display de arriba) para cifras tipo "lectura de
     instrumento" en el tablero del Inicio -- mismo rol que cumplia IBM
     Plex Mono en la referencia visual aprobada, sin la dependencia
     externa que la app ya no usa. */
  --font-mono-sys: ui-monospace, "SF Mono", "Cascadia Code", "Segoe UI Mono", Consolas, "Liberation Mono", monospace;
}

/* ==========================================================================
   MODO OSCURO -- dos puertas de entrada, una sola paleta
   ==========================================================================
   La app sigue siendo CLARA por defecto (:root de arriba). El oscuro se
   activa por dos caminos:

     1. Preferencia del sistema, como siempre        -> @media de abajo
     2. Eleccion manual del usuario en "Mas"         -> [data-theme]

   La eleccion manual GANA sobre el sistema. Por eso el @media excluye
   :root[data-theme="light"]: si el usuario pidio claro expresamente, un
   telefono en modo noche no puede contradecirlo.

   Los dos bloques declaran los MISMOS valores a proposito -no hay forma
   de compartir un bloque entre dentro y fuera de un @media sin recurrir
   a trucos ilegibles-. SI CAMBIAS UN VALOR ACA, CAMBIALO EN LOS DOS.

   --color-navy/--color-navy-dark NO se redefinen: siguen siendo el cromo
   oscuro fijo de topbar/nav/boton primario en ambos temas, y por el
   mismo motivo tampoco cambia --color-teal-chrome.
   -------------------------------------------------------------------- */

/* Puerta 1: preferencia del sistema, salvo que el usuario haya forzado claro */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --color-bg: #05070b;
    --color-surface: #101f30;
    --color-border: #223b52;
    --color-text: #eef2f5;
    --color-text-muted: #93a9ba;
    --color-heading: #eaf4f8;
    --color-teal: #38bdf8;
    --color-teal-text: #38bdf8;
    --color-danger: #ff5f72;
    --color-danger-bg: #2c0f14;
    --color-success: #35d18e;
    --color-success-bg: #0c2a1d;
    --color-warning: #eeae4f;
    --color-warning-bg: #2c2007;
    --shadow: 0 20px 45px -18px rgba(0, 0, 0, 0.6);
    --shadow-glass: 0 24px 55px -20px rgba(0, 0, 0, 0.75);
    --glass-bg: rgba(255, 255, 255, 0.055);
    --glass-border: rgba(255, 255, 255, 0.1);
    --grad-escanear: linear-gradient(150deg, #38bdf8, #0ea5e9);
    --color-escanear-texto: #04283d;
  }
}

/* Puerta 2: eleccion manual del usuario (gana sobre el sistema) */
:root[data-theme="dark"] {
  --color-bg: #05070b;
  --color-surface: #101f30;
  --color-border: #223b52;
  --color-text: #eef2f5;
  --color-text-muted: #93a9ba;
  --color-heading: #eaf4f8;
  --color-teal: #38bdf8;
  --color-teal-text: #38bdf8;
  --color-danger: #ff5f72;
  --color-danger-bg: #2c0f14;
  --color-success: #35d18e;
  --color-success-bg: #0c2a1d;
  --color-warning: #eeae4f;
  --color-warning-bg: #2c2007;
  --shadow: 0 20px 45px -18px rgba(0, 0, 0, 0.6);
  --shadow-glass: 0 24px 55px -20px rgba(0, 0, 0, 0.75);
  --glass-bg: rgba(255, 255, 255, 0.055);
  --glass-border: rgba(255, 255, 255, 0.1);
  --grad-escanear: linear-gradient(150deg, #38bdf8, #0ea5e9);
  --color-escanear-texto: #04283d;
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
}

/* CORRECCION MOVIL iPhone (barra inferior y encabezado que desaparecian
   al hacer scroll): el recorte horizontal que antes vivia en .app-shell
   se sube aqui, al elemento raiz. Motivo real (no preferencia de
   estilo): por especificacion CSS, cuando overflow-x vale "hidden" y
   overflow-y vale "visible", el eje declarado "visible" se COMPUTA como
   "auto" -- .app-shell se convertia en su propio contenedor de scroll
   con scrollHeight == clientHeight, y cualquier "position: sticky" en su
   interior perdia todo rango de desplazamiento, es decir se comportaba
   como estatico y se iba con el scroll. En <html> ese mismo par de
   valores es inofensivo: el scrollport del elemento raiz ES el viewport,
   asi que sticky/fixed siguen funcionando y se conserva el recorte
   horizontal de siempre (manchas ambientales, tablas anchas). */
html {
  overflow-x: hidden;
}

body {
  font-family: var(--font);
  background: var(--color-bg);
  color: var(--color-text);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--color-teal-text);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

img {
  max-width: 100%;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--color-heading);
  letter-spacing: -0.01em;
  margin: 0 0 12px;
}

p {
  margin: 0 0 12px;
}

/* ---------- Layout general (autenticado) ---------- */

.app-shell {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* CORRECCION MOVIL iPhone: aqui NO se declara ningun overflow. El
     intento anterior ("overflow-x: hidden" + "overflow-y: visible" a
     proposito) no evitaba el problema que describia su propio
     comentario: declarar "visible" explicitamente no cambia nada,
     porque la computacion a "auto" la hace la especificacion sobre el
     valor declarado. El resultado era que .app-shell si era un
     contenedor de scroll y el sticky del nav inferior no se pegaba
     nunca. El recorte horizontal se movio a la regla "html" de mas
     arriba, donde es seguro. */
}

/* Manchas ambientales fijas detras del contenido (no se desplazan con el
   scroll ni interfieren con clics): mismo recurso que .ambient-blob del
   shell de invitado, pero mas tenues para no competir con tablas densas. */
.app-ambient {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: -1;
}

.app-ambient .ambient-blob {
  opacity: 0.16;
}

.app-ambient .ambient-blob--a {
  top: -140px;
  left: -100px;
}

.app-ambient .ambient-blob--b {
  top: 40vh;
  right: -140px;
}

.app-topbar {
  position: relative;
  z-index: 1;
  background: var(--color-navy);
  color: #fff;
  /* Correccion calidad demo: el meta viewport ya declara
     "viewport-fit=cover" (necesario para que env(safe-area-inset-*)
     tenga algun valor no-cero), pero el encabezado nunca lo usaba -- en
     un telefono con notch/isla dinamica ejecutando la PWA a pantalla
     completa, "CENTINELA360" y el avatar quedaban parcialmente tapados
     por la barra de estado del sistema. Se SUMA al padding de siempre
     (nunca se reemplaza): en un navegador normal env() vale 0 y el
     padding queda identico al de antes. */
  padding: calc(14px + env(safe-area-inset-top, 0px)) 24px 14px;
}

/* Fila brand + user-box. En escritorio es el unico contenido del
   encabezado (mismo layout que antes, solo un nivel mas anidado para
   poder agregar el subtitulo movil de rol/seccion debajo sin tocar
   esta fila). */
.app-topbar-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.app-topbar .brand {
  font-weight: 700;
  font-size: 18px;
  letter-spacing: 0.5px;
}

.app-topbar .brand span {
  color: var(--color-teal-chrome);
}

.app-topbar .user-box {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 14px;
}

.app-topbar form {
  margin: 0;
}

/* Envoltorio del nombre+boton "Cerrar sesion" de escritorio: mismo
   layout en fila que tenian antes como hijos directos de .user-box
   (ver regla de arriba), solo que ahora anidados un nivel para poder
   ocultarlos como bloque en movil (ver Responsive) sin tocar su
   apariencia en escritorio. */
.app-user-desktop {
  display: flex;
  align-items: center;
  gap: 14px;
}

/* Avatar y subtitulo (rol . seccion) del encabezado compacto movil:
   ocultos por defecto (escritorio no cambia). Se muestran solo dentro
   de @media (max-width: 640px), ver Responsive. */
.app-avatar {
  display: none;
}

.app-topbar-subtitle {
  display: none;
}

.btn-link {
  background: none;
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: #fff;
  padding: 6px 14px;
  border-radius: var(--radius);
  cursor: pointer;
  font-size: 13px;
}

.btn-link:hover {
  background: rgba(255, 255, 255, 0.1);
}

.app-main {
  flex: 1;
  padding: 32px 24px;
  max-width: 1100px;
  width: 100%;
  margin: 0 auto;
}

/* ---------- Tarjetas / Cards ---------- */

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 26px;
  transition: box-shadow 180ms ease, transform 180ms ease;
}

/* ---------- Layout invitado (login / recuperar contraseña) ---------- */

.guest-shell {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(160deg, var(--color-navy) 0%, var(--color-navy-dark) 55%, #06172b 100%);
  padding: 24px;
  overflow: hidden;
}

/* Manchas de degradado suaves detras de la tarjeta de vidrio: mismo
   recurso ambiental que .app-ambient (mas abajo), reutilizado aqui para
   que login/recuperar-contraseña compartan el lenguaje visual. */
.ambient-blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.45;
  pointer-events: none;
  z-index: 0;
}

.ambient-blob--a {
  width: 340px;
  height: 340px;
  background: var(--color-teal);
  top: -120px;
  left: -80px;
}

.ambient-blob--b {
  width: 380px;
  height: 380px;
  background: var(--color-navy-dark);
  bottom: -140px;
  right: -80px;
}

@media (prefers-reduced-motion: no-preference) {
  .ambient-blob {
    animation: ambient-drift 20s ease-in-out infinite alternate;
  }

  .ambient-blob--b {
    animation-delay: -8s;
  }
}

@keyframes ambient-drift {
  from {
    transform: translate(0, 0) scale(1);
  }
  to {
    transform: translate(18px, -14px) scale(1.08);
  }
}

.guest-card {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 400px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-glass);
  padding: 36px 32px;
}

.guest-brand {
  text-align: center;
  margin-bottom: 24px;
}

.guest-brand .brand-title {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 700;
  color: var(--color-heading);
  letter-spacing: -0.01em;
}

.guest-brand .brand-title span {
  color: var(--color-teal);
}

.guest-brand .brand-subtitle {
  font-size: 13px;
  color: var(--color-text-muted);
  margin-top: 4px;
}

/* ---------- Formularios ---------- */

.form-group {
  margin-bottom: 18px;
}

label {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  margin-bottom: 7px;
  transition: color 160ms ease;
}

/* Toque tactil: mientras el input/select/textarea de un .form-group
   tiene foco, su label se resalta en el color de acento. Se apoya en
   :has() -ya usado en este archivo por .role-card:has(input:checked)-
   asi que no depende de reordenar label/input en ningun formulario. */
.form-group:has(input:focus, select:focus, textarea:focus) label {
  color: var(--color-teal-text);
}

/* CORRECCION VISUAL (controles HTML nativos): input[type="tel"] e
   input[type="time"] faltaban en este selector compartido -mismo defecto
   ya corregido antes para input[type="number"], ver comentario mas
   abajo- y por eso se veian con la apariencia nativa del navegador
   (views/usuarios/crear.php Telefono, views/turnos/crear.php y
   editar.php Hora inicio/termino). Se agregan tambien "search"/"url"/
   "month"/"week", sin uso actual en el proyecto, para que cualquier
   campo futuro de ese tipo quede estilizado por defecto sin depender de
   otra auditoria. */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
input[type="datetime-local"],
input[type="number"],
input[type="tel"],
input[type="time"],
input[type="search"],
input[type="url"],
input[type="month"],
input[type="week"],
select,
textarea {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  padding: 12px 14px;
  border: 1.5px solid var(--color-border);
  border-radius: calc(var(--radius) - 2px);
  font-size: 14.5px;
  font-family: var(--font);
  background: var(--color-bg);
  color: var(--color-text);
  transition: border-color 180ms ease, box-shadow 180ms ease, background 180ms ease;
}

/* CORREGIDO en la auditoria visual Aurora (Semana 5): input[type="number"]
   faltaba en el selector compartido de arriba -- el campo "Orden" de
   Configurar puntos de ronda (views/rondas/puntos.php) quedaba con la
   apariencia nativa del navegador (spinner incluido) en vez del estilo
   Aurora del resto de los campos. Los navegadores WebKit/Blink dibujan
   las flechas nativas de number encima del padding derecho; se reduce
   ese padding para que no queden pegadas al borde del campo. */
input[type="number"] {
  padding-right: 8px;
}

/* Corrección de formulario que desborda en iPhone (prueba móvil real:
   el mismo formulario se veía bien en Android y desbordaba en iOS). El
   control nativo de iOS Safari para type="date"/"time" dibuja su texto
   completo ("dd/mm/aaaa", "HH:MM a.m./p.m.") con más ancho interno del
   que necesita el mismo control en Android/Chrome; con el padding
   compartido (12px 14px) ese contenido nativo terminaba más ancho que
   la caja del campo, empujándola fuera de su columna. Se reduce el
   padding lateral SOLO en date/time, y SOLO dentro de
   @supports (-webkit-touch-callout: none) -- esa consulta de soporte
   únicamente es verdadera en WebKit de iOS (Safari y cualquier
   navegador en iOS, que por política de Apple usa el mismo motor);
   Chrome/Android es Blink y nunca la cumple, así que esta regla no
   puede alterar Android aunque se equivoque. */
/* CAUSA REAL DEL DESBORDE EN iPhone (cierre, validación móvil real
   post-despliegue, 2026-09-24): el bloque de abajo ya reducía el padding
   lateral, pero eso solo atacaba el síntoma. Medido con el DOM real
   renderizado (Chrome headless, 390px y 412px): la caja del campo cabe
   perfectamente -- 278-304px de ancho dentro de contenedores de ese
   mismo ancho, con 43-56px de margen libre a la derecha, sin ningún
   elemento desbordado (document.scrollWidth === clientWidth). Es decir,
   el modelo de caja (width/max-width/min-width/box-sizing, ya presentes
   arriba y en .form-grid/.filters-bar) NO es el problema: en Blink no
   hay desborde posible.

   Lo que faltaba es específico de WebKit: a `input[type="date"]` e
   `input[type="time"]` NO se les había aplicado nunca
   `-webkit-appearance: none` (en este archivo solo lo tenían
   input[type="checkbox"] y button.porteria-lista-item). Sin eso, iOS
   conserva el DIBUJO NATIVO del control, que mantiene su ancho
   intrínseco propio (el texto completo "dd/mm/aaaa" o "HH:MM a. m." con
   las cajas del sistema) y se pinta por encima del borde de la caja
   declarada, aunque la caja mida lo correcto -- exactamente el síntoma
   reportado: bien en Android/Chrome (Blink respeta la caja), desbordado
   en iPhone (cualquier navegador en iOS usa WebKit por política de
   Apple).

   Todo sigue encerrado en @supports (-webkit-touch-callout: none), que
   SOLO es verdadera en WebKit de iOS: escritorio y Android (Blink)
   nunca entran aquí, así que ni el dibujo nativo ni el icono de
   calendario de Chrome cambian. En iOS el control sigue abriendo el
   selector nativo al tocarlo -- appearance:none es dibujo, no
   funcionalidad (mismo criterio ya documentado arriba para los
   checkbox). */
@supports (-webkit-touch-callout: none) {
  input[type="date"],
  input[type="time"] {
    -webkit-appearance: none;
    appearance: none;
    /* Repetidos a propósito dentro del bloque de iOS: son las mismas
       reglas del selector compartido de arriba, pero declaradas junto a
       appearance:none para que ningún cambio futuro en aquel selector
       pueda dejar el control nativo de iOS sin límite de ancho. */
    width: 100%;
    max-width: 100%;
    min-width: 0;
    box-sizing: border-box;
    padding-left: 10px;
    padding-right: 6px;
  }
}

/* El contenedor plegable ("¿Turno nocturno?" en Crear/Editar turno, que
   envuelve el campo `fecha_termino`) era el único .form-group del
   proyecto con padding lateral propio y sin el mismo seguro de
   encogimiento que .form-grid > .form-group y .filters-bar .form-group
   ya tenían. Con el `* { box-sizing: border-box }` global no desbordaba
   en Blink (verificado: margen libre de 56px a 390px), pero se le
   declara igual para que el campo de fecha más anidado del sistema
   tenga exactamente las mismas garantías que el resto. */
.form-group-details .form-group {
  min-width: 0;
  max-width: 100%;
}

textarea {
  resize: vertical;
  height: 108px;
}

/* Revision de interfaz: input[type="file"] nunca tenia estilo propio en
   ningun formulario de evidencia (Novedades/Incidentes/Rondas) -- se
   veia como el selector de archivo nativo del navegador ("boton HTML
   basico"), inconsistente con el resto de los campos Aurora. El
   navegador no permite reemplazar el control nativo por completo, pero
   ::file-selector-button (soportado en todos los navegadores modernos)
   si permite darle el mismo lenguaje visual (boton solido + contenedor
   con borde) que ya usa el resto del formulario. */
input[type="file"] {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  padding: 10px 12px;
  border: 1.5px dashed var(--color-border);
  border-radius: calc(var(--radius) - 2px);
  font-size: 13px;
  font-family: var(--font);
  background: var(--color-bg);
  color: var(--color-text-muted);
  cursor: pointer;
  transition: border-color 180ms ease, background 180ms ease;
}

input[type="file"]:hover {
  border-color: var(--color-teal);
  background: var(--color-surface);
}

input[type="file"]::file-selector-button {
  margin-right: 10px;
  padding: 8px 14px;
  border: none;
  border-radius: calc(var(--radius) - 4px);
  background: var(--color-navy);
  color: #fff;
  font-size: 12.5px;
  font-weight: 600;
  font-family: var(--font);
  cursor: pointer;
  transition: background 160ms ease;
}

input[type="file"]::file-selector-button:hover {
  background: var(--color-navy-dark);
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--color-teal);
  background: var(--color-surface);
  box-shadow: 0 0 0 4px rgba(23, 169, 196, 0.16);
}

input::placeholder {
  color: var(--color-text-muted);
  opacity: 1;
}

select:disabled {
  color: var(--color-text-muted);
  background: var(--color-bg);
  cursor: not-allowed;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 46px;
  padding: 0 22px;
  background: var(--grad);
  color: #fff;
  border: none;
  border-radius: 100px;
  font-size: 14.5px;
  font-weight: 700;
  font-family: var(--font);
  cursor: pointer;
  text-align: center;
  box-shadow: 0 10px 22px -10px rgba(11, 42, 74, 0.45);
  transition: filter 160ms ease, box-shadow 160ms ease, transform 120ms ease;
}

.btn:hover {
  filter: brightness(1.06);
  box-shadow: 0 14px 28px -10px rgba(11, 42, 74, 0.5);
  text-decoration: none;
}

.btn:active {
  transform: scale(0.98);
}

.btn-with-icon {
  gap: 8px;
}

.btn-icon {
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
}

/* Iconos SVG inline (helper icon(), reemplaza los emojis usados como
   icono funcional/de estado -revision de interfaz-). Se dimensionan en
   "em" para heredar el font-size ya definido en cada contenedor
   (.btn-icon / .empty-state-icon / .porteria-tile-icon) sin duplicar
   valores de tamaño; el color siempre es currentColor, nunca un color
   fijo, para seguir el mismo texto/estado del elemento que envuelve al
   icono. */
.btn-icon svg,
.empty-state-icon svg,
.porteria-tile-icon svg,
.dash-quick-icon svg {
  width: 1em;
  height: 1em;
  display: inline-block;
  vertical-align: -0.125em;
}

/* Sprint 7 (correccion UX /asistencia): .btn-secondary se usaba en
   varias vistas (Turnos, Asignaciones, Asistencia) SIN combinarla nunca
   con .btn en el HTML (siempre class="btn-secondary" a secas, ver
   views/turnos/index.php, views/turnos/semana.php,
   views/asignaciones/index.php, views/asistencia/index.php). Como esta
   regla nunca definia su propia caja (altura/relleno/radio/tipografia/
   cursor), el boton quedaba con el tamaño y fuente por defecto del
   navegador: por eso se veia "HTML basico" y desalineado junto a un
   <select> que si recibe el tratamiento completo mas abajo. Se completa
   aqui la caja EXACTA de .btn (mismas medidas, para que ambas clases
   compartan alto/forma) conservando el color/fondo/borde propios de la
   variante secundaria; no se toco ningun archivo de vista para esto. */
.btn-secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 46px;
  padding: 0 22px;
  background: transparent;
  color: var(--color-heading);
  border: 1.5px solid var(--color-border);
  border-radius: 100px;
  font-size: 14.5px;
  font-weight: 700;
  font-family: var(--font);
  cursor: pointer;
  text-align: center;
  transition: background 180ms ease, border-color 180ms ease, transform 120ms ease;
}

.btn-secondary:hover {
  background: var(--color-bg);
  border-color: var(--color-teal);
}

.btn-secondary:active {
  transform: scale(0.98);
}

/* Variantes de tamaño completo de .btn para acciones destructivas/positivas
   a nivel de formulario (Sprint 6, modulo Turnos: "Cancelar" y acciones
   afirmativas no deben quedar con apariencia HTML basica). Mismo criterio
   de color que .btn-tiny-danger/.btn-tiny-success (mas abajo), aplicado
   aqui al tamaño completo de .btn en vez del tamaño compacto. */
.btn-danger {
  background: var(--color-danger);
  color: #fff;
}

.btn-danger:hover {
  filter: brightness(0.92);
}

.btn-success {
  background: var(--color-success);
  color: #fff;
}

.btn-success:hover {
  filter: brightness(0.92);
}

.form-links {
  text-align: center;
  margin-top: 18px;
  font-size: 13px;
}

/* ---------- Alertas ---------- */

.alert {
  border-radius: var(--radius);
  padding: 12px 14px;
  font-size: 13px;
  margin-bottom: 18px;
}

.alert-error {
  background: var(--color-danger-bg);
  color: var(--color-danger);
  border: 1px solid rgba(192, 57, 43, 0.25);
}

.alert-success {
  background: var(--color-success-bg);
  color: var(--color-success);
  border: 1px solid rgba(30, 142, 90, 0.25);
}

.alert ul {
  margin: 0;
  padding-left: 18px;
}

/* ---------- Navegacion ---------- */

.app-nav {
  background: var(--color-navy-dark);
  padding: 8px 20px;
  display: flex;
  align-items: center;
  gap: 3px;
  flex-wrap: wrap;
}

.app-nav a {
  color: rgba(255, 255, 255, 0.68);
  padding: 9px 16px;
  border-radius: 100px;
  font-size: 13px;
  font-weight: 600;
  transition: background 160ms ease, color 160ms ease;
}

.app-nav a:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.08);
  text-decoration: none;
}

.app-nav a.activo {
  color: var(--color-navy-dark);
  background: var(--color-teal-chrome);
}

/* Grupos desplegables del encabezado compacto (correccion post-QA):
   mismo <details>/<summary> nativo que ya usaba el panel "Mas" del nav
   movil (sin JS obligatorio: abre/cierra solo), llevado tambien al
   encabezado de escritorio para que Administracion/Operacion/Control de
   acceso no aparezcan como una fila larga de enlaces sueltos. */
.app-nav-drop {
  position: relative;
}

.app-nav-drop summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 5px;
  color: rgba(255, 255, 255, 0.68);
  padding: 9px 14px;
  border-radius: 100px;
  font-size: 13px;
  font-weight: 600;
  transition: background 160ms ease, color 160ms ease;
  user-select: none;
}

.app-nav-drop summary::-webkit-details-marker {
  display: none;
}

.app-nav-drop summary::after {
  /* Revision de interfaz: triangulo CSS puro (borde) en vez del
     caracter Unicode "\25BE" -sin fuente de iconos, sin glifo de
     texto-. */
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  opacity: 0.75;
}

.app-nav-drop summary:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.08);
}

.app-nav-drop summary.activo {
  color: var(--color-navy-dark);
  background: var(--color-teal-chrome);
}

.app-nav-drop[open] summary {
  color: #fff;
  background: rgba(255, 255, 255, 0.12);
}

.app-nav-drop-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 40;
  min-width: 200px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--color-surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-glass);
  padding: 8px;
}

.app-nav-drop-panel a {
  padding: 9px 12px;
  border-radius: 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text);
  text-decoration: none;
  transition: background 140ms ease;
}

.app-nav-drop-panel a:hover {
  background: var(--color-bg);
  text-decoration: none;
}

.app-nav-drop-panel a.activo {
  background: var(--glass-bg);
  color: var(--color-teal-text);
}

/* Barra de navegacion inferior movil: oculta por defecto (escritorio
   no cambia). Se muestra solo dentro de @media (max-width: 640px). */
.app-bottom-nav {
  display: none;
}

/* PROBLEMA 3 (el panel flotante no se cerraba al tocar fuera): fondo
   atenuado como ELEMENTO REAL del DOM (hermano de .app-bottom-nav, ver
   layouts/main.php) y no como pseudo-elemento ::before del <details>.
   Motivo real: un ::before pertenece a su elemento originante, asi que
   cualquier toque sobre ese fondo se reportaba con event.target =
   <details> del panel; el cierre "al pulsar fuera" de nav.js hacia
   detalle.contains(event.target), veia "true" y concluia que el toque
   habia sido DENTRO del panel. Resultado: el fondo se tragaba
   literalmente todos los toques de afuera y el panel solo se podia
   cerrar volviendo a tocar el mismo boton. Siendo un elemento hermano,
   el toque cae realmente fuera del <details> y cierra.
   Oculto por defecto: en escritorio no existe panel flotante. */
.app-sheet-backdrop {
  display: none;
}

/* PROBLEMA 4 (con el panel abierto, el fondo seguia desplazandose).
   Clase que nav.js pone y quita sobre <body> mientras el panel
   "Operación"/"Más" esta abierto.
   Se usa "position: fixed" y NO "overflow: hidden" porque iOS Safari
   ignora overflow:hidden en body/html para el scroll de la pagina (es
   la limitacion conocida de ese motor; en el iPhone del reporte no
   habria tenido ningun efecto).
   Fijar el body lo reposiciona en el tope del documento, asi que nav.js
   compensa con "top: -<scroll actual>px" y, al cerrar, devuelve el
   scroll a su valor exacto con window.scrollTo -- por eso la pagina no
   salta de posicion.
   width/left/right explicitos: un elemento fixed sin ancho declarado se
   encoge a su contenido; sin esto el body cambiaria de ancho al abrir
   el panel y el contenido se reacomodaria a la vista. */
body.app-scroll-bloqueado {
  position: fixed;
  left: 0;
  right: 0;
  width: 100%;
}

/* El menu hamburguesa + panel vertical (CORRECCION UX movil, version
   anterior) se retiro: la navegacion movil ahora es la barra inferior
   fija + panel "Mas" (IMPLEMENTACION UX movil tipo app, ver mas abajo
   y @media max-width: 640px). #app-nav (arriba) sigue siendo la
   navegacion real de escritorio, sin cambios.

   Encabezados de grupo (Administracion/Operacion/Usuarios): ocultos en
   escritorio, visibles solo dentro del panel "Mas" en movil (ver
   Responsive). Es la misma clase que ya usaba el panel anterior. */
.app-nav-group-label {
  display: none;
}

/* ---------- Encabezado de tarjeta (titulo + accion) ---------- */

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 18px;
  flex-wrap: wrap;
}

.card-header h1 {
  margin: 0;
}

.card-header .btn {
  width: auto;
}

/* Botones de accion agrupados en el encabezado (bloque E: "Configurar
   puntos" y "Programar ronda" deben quedar lado a lado). Sin este
   contenedor, dos <a class="btn-tiny"> sueltos dentro de .card-header
   quedan repartidos por justify-content:space-between junto con el <h1>
   -en pantallas angostas eso los separaba de forma inconsistente y, con
   textos largos, los hacia superponerse o quedar pegados al borde. Este
   wrapper los trata como UN solo item del header (con su propio ancho
   compartido en movil), asi el h1 queda siempre en su propia linea y los
   dos botones siempre juntos. */
.card-header-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* ---------- Contexto de navegacion jerarquica (Cliente -> Instalaciones
   -> Operacion): banda superior fuera de la tarjeta principal, mismo
   patron visual que .alert (misma superficie/borde), para no crear un
   componente ajeno al sistema Aurora existente. */

.context-banner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 16px;
  margin-bottom: 16px;
  padding: 10px 16px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

.context-banner-label {
  color: var(--color-text-muted);
  font-size: 14px;
}

.context-banner-label strong {
  color: var(--color-heading);
}

/* Fila de accesos rapidos a los demas modulos operativos de la misma
   instalacion (Turnos/Guardias/Puestos/Rondas/Novedades/Incidentes),
   dentro del mismo banner de contexto. Mismo criterio ya usado en
   .app-nav-drop-panel a.activo: fondo sutil + color teal para marcar el
   modulo actual, sin iconos. flex-wrap propio para que en movil la fila
   de accesos baje limpiamente en vez de desbordar. */
.context-banner-links {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  width: 100%;
}

.context-banner-link {
  padding: 6px 12px;
  border-radius: 100px;
  font-size: 12px;
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-bg);
  text-decoration: none;
  transition: background 140ms ease, color 140ms ease;
}

.context-banner-link:hover {
  background: var(--color-border);
  text-decoration: none;
}

.context-banner-link.activo {
  background: var(--glass-bg);
  color: var(--color-teal-text);
}

/* ---------- Filtros de listado ---------- */

.filters-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 14px;
  margin-bottom: 20px;
  padding: 14px 16px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  align-items: flex-end;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

/* CORREGIDO en la auditoria visual Aurora (Semana 5): sin min-width: 0
   un elemento flex nunca se encoge por debajo de su ancho de contenido
   minimo (min-width: auto es el valor por defecto de un flex item), asi
   que un <select> con nombres de instalacion largos podia forzar a la
   fila completa (Instalacion + Fecha, views/rondas/index.php y
   views/rondas/puntos.php) a salirse del margen de la tarjeta en
   pantallas reducidas, aun con flex-wrap: wrap. Mismo problema en
   Novedades/Incidentes (Buscar/Estado/Severidad). min-width: 0 permite
   que cada campo se encoja al ancho real disponible. */
.filters-bar .form-group {
  margin-bottom: 0;
  flex: 1 1 160px;
  min-width: 0;
  max-width: 100%;
}

.filters-bar .filters-actions {
  display: flex;
  gap: 8px;
  flex: 0 0 auto;
}

.filters-bar .btn,
.filters-bar .btn-secondary,
.filters-bar .btn-tiny {
  width: auto;
  flex: 0 0 auto;
}

/* ---------- Tablas ---------- */

.table-wrap {
  width: 100%;
  overflow-x: auto;
  /* Correccion (revision de interfaz: "corrige el recorte de la primera
     columna en las tablas"): overflow-x: auto por si solo deja
     overflow-y en su valor inicial (visible) en algunos motores, lo que
     vuelve ambigua/inconsistente la region de recorte de este
     contenedor contra su propio border-radius -el borde redondeado
     terminaba "mordiendo" la esquina superior/inferior de la primera
     columna, la mas visible por ser la primera en leerse-. Fijar
     overflow-y: hidden (nunca se quiso scroll vertical aqui, solo
     horizontal cuando la tabla no cabe) hace que ambos ejes queden en un
     estado de recorte explicito y consistente, y el radio se aplica
     limpio en las 4 esquinas de la tabla real sin recortar contenido de
     ninguna columna. */
  overflow-y: hidden;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

/* Sprint 4.2 (unificacion de tablas, sin cambios de logica): patron
   comun para TODOS los listados administrativos (Usuarios, Empresas,
   Clientes, Instalaciones, Guardias, Puestos). Antes cada tabla usaba
   table-layout: fixed (el ancho de columna sale solo del th de la
   primera fila; min-width en celdas se ignora) combinado con columnas
   en % y overflow-wrap: break-word en varias columnas -incluidos los
   propios encabezados-, lo que partia palabras a mitad ("INSTALAC/ION",
   "TELEFO/NO") o las truncaba con "...". Con table-layout: auto el
   ancho de cada columna respeta su min-width real, el encabezado nunca
   se comprime por debajo de su propio texto, y si la suma de anchos
   minimos supera el ancho disponible la tabla crece mas alla del 100%
   -.table-wrap ya tenia overflow-x: auto desde antes, sin cambios- en
   vez de aplastar columnas o partir palabras. Los modificadores
   .data-table--{usuarios,empresas,clientes,instalaciones,guardias,
   puestos} de mas abajo solo agregan anchos minimos especificos por
   columna; ya no necesitan repetir white-space/word-break porque ahora
   es responsabilidad de esta regla base compartida. */
table.data-table {
  width: 100%;
  table-layout: auto;
  border-collapse: collapse;
  font-size: 12.5px;
}

.data-table th,
.data-table td {
  text-align: left;
  padding: 18px 14px;
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}

.data-table th {
  background: var(--color-bg);
  color: var(--color-text-muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  font-weight: 700;
  /* Los encabezados NUNCA se parten ni se truncan, en ninguna tabla. */
  white-space: nowrap;
  overflow: visible;
  text-overflow: clip;
}

.data-table td {
  /* Por defecto las celdas pueden ocupar dos lineas naturales -en
     espacios, nunca a mitad de palabra-. Las columnas que deben
     quedar siempre en una sola linea (codigos, RUT, correo, telefono,
     fechas, estado, contadores, acciones) lo fuerzan explicitamente
     con white-space: nowrap en su modificador de columna, mas abajo. */
  white-space: normal;
  overflow-wrap: normal;
  word-break: normal;
  overflow: visible;
  text-overflow: clip;
}

.data-table tbody tr:last-child td {
  border-bottom: none;
}

.data-table tr:hover td {
  background: var(--color-bg);
}

/* Anchos por columna especificos del listado de Usuarios (8 columnas:
   Nombre, Correo, Estado, Empresa, Roles, Instalaciones, Creado,
   Acciones). Sprint 4.2: modificador propio (.data-table--usuarios),
   igual criterio que el resto de listados, para no depender de reglas
   .data-table sueltas sin calificar que antes se aplicaban a esta
   tabla por ser la unica sin modificador de clase. Correo no tiene
   espacios utiles para partir en dos lineas de forma legible, por eso
   se mantiene en una sola linea con min-width propio en vez de
   envolver. */
table.data-table.data-table--usuarios {
  min-width: 1220px;
}

table.data-table.data-table--usuarios th:nth-child(1),
table.data-table.data-table--usuarios td:nth-child(1) {
  width: 16%;
  min-width: 160px;
}

table.data-table.data-table--usuarios th:nth-child(2),
table.data-table.data-table--usuarios td:nth-child(2) {
  width: 20%;
  min-width: 200px;
}

table.data-table.data-table--usuarios td:nth-child(2) {
  white-space: nowrap;
}

table.data-table.data-table--usuarios th:nth-child(3),
table.data-table.data-table--usuarios td:nth-child(3) {
  width: 10%;
  min-width: 100px;
  text-align: center;
}

table.data-table.data-table--usuarios td:nth-child(3) {
  white-space: nowrap;
}

table.data-table.data-table--usuarios th:nth-child(4),
table.data-table.data-table--usuarios td:nth-child(4) {
  width: 15%;
  min-width: 150px;
}

table.data-table.data-table--usuarios th:nth-child(5),
table.data-table.data-table--usuarios td:nth-child(5) {
  width: 16%;
  min-width: 160px;
}

table.data-table.data-table--usuarios th:nth-child(6),
table.data-table.data-table--usuarios td:nth-child(6) {
  width: 16%;
  min-width: 160px;
}

table.data-table.data-table--usuarios th:nth-child(7),
table.data-table.data-table--usuarios td:nth-child(7) {
  width: 18%;
  min-width: 180px;
}

table.data-table.data-table--usuarios td:nth-child(7) {
  white-space: nowrap;
}

table.data-table.data-table--usuarios th:nth-child(8),
table.data-table.data-table--usuarios td:nth-child(8) {
  width: 104px;
  min-width: 104px;
  white-space: nowrap;
  overflow: visible;
}

/* Anchos por columna especificos del listado de Empresas (11 columnas:
   Razon social, Nombre comercial, RUT, Correo, Telefono, Estado,
   Usuarios, Clientes, Instalaciones, Creado, Acciones). Se usa un
   modificador propio (.data-table--empresas) para no reinterpretar las
   reglas nth-child de otros listados; sigue reutilizando la misma base
   .data-table (bordes, padding, hover, tipografia, table-layout: auto,
   white-space en th/td) definida mas arriba. */
table.data-table.data-table--empresas {
  min-width: 1450px;
}

table.data-table.data-table--empresas th:nth-child(1),
table.data-table.data-table--empresas td:nth-child(1) {
  width: 12%;
  min-width: 180px;
}

table.data-table.data-table--empresas th:nth-child(2),
table.data-table.data-table--empresas td:nth-child(2) {
  width: 11%;
  min-width: 160px;
}

table.data-table.data-table--empresas th:nth-child(3),
table.data-table.data-table--empresas td:nth-child(3) {
  width: 8%;
  min-width: 120px;
  white-space: nowrap;
}

table.data-table.data-table--empresas th:nth-child(4),
table.data-table.data-table--empresas td:nth-child(4) {
  width: 14%;
  min-width: 200px;
  white-space: nowrap;
}

table.data-table.data-table--empresas th:nth-child(5),
table.data-table.data-table--empresas td:nth-child(5) {
  width: 9%;
  min-width: 130px;
  white-space: nowrap;
}

table.data-table.data-table--empresas th:nth-child(6),
table.data-table.data-table--empresas td:nth-child(6) {
  width: 7%;
  min-width: 100px;
  white-space: nowrap;
  text-align: center;
}

table.data-table.data-table--empresas th:nth-child(7),
table.data-table.data-table--empresas td:nth-child(7),
table.data-table.data-table--empresas th:nth-child(8),
table.data-table.data-table--empresas td:nth-child(8),
table.data-table.data-table--empresas th:nth-child(9),
table.data-table.data-table--empresas td:nth-child(9) {
  width: 6%;
  min-width: 90px;
  white-space: nowrap;
  text-align: center;
}

table.data-table.data-table--empresas th:nth-child(10),
table.data-table.data-table--empresas td:nth-child(10) {
  width: 13%;
  min-width: 180px;
  white-space: nowrap;
}

table.data-table.data-table--empresas th:nth-child(11),
table.data-table.data-table--empresas td:nth-child(11) {
  width: 104px;
  min-width: 104px;
  white-space: nowrap;
  overflow: visible;
}

/* Anchos por columna especificos del listado de Clientes (9 columnas:
   Empresa, Nombre del cliente, RUT, Correo, Telefono, Estado,
   Instalaciones, Creado, Acciones). Mismo criterio que
   .data-table--empresas: modificador propio para no reinterpretar las
   reglas nth-child de otros listados; sigue reutilizando la misma base
   .data-table (bordes, padding, hover, tipografia, table-layout: auto,
   white-space en th/td) definida mas arriba. */
table.data-table.data-table--clientes {
  min-width: 1280px;
}

table.data-table.data-table--clientes th:nth-child(1),
table.data-table.data-table--clientes td:nth-child(1) {
  width: 15%;
  min-width: 160px;
}

table.data-table.data-table--clientes th:nth-child(2),
table.data-table.data-table--clientes td:nth-child(2) {
  width: 16%;
  min-width: 180px;
}

table.data-table.data-table--clientes th:nth-child(3),
table.data-table.data-table--clientes td:nth-child(3) {
  width: 11%;
  min-width: 120px;
  white-space: nowrap;
}

table.data-table.data-table--clientes th:nth-child(4),
table.data-table.data-table--clientes td:nth-child(4) {
  width: 18%;
  min-width: 200px;
  white-space: nowrap;
}

table.data-table.data-table--clientes th:nth-child(5),
table.data-table.data-table--clientes td:nth-child(5) {
  width: 11%;
  min-width: 130px;
  white-space: nowrap;
}

table.data-table.data-table--clientes th:nth-child(6),
table.data-table.data-table--clientes td:nth-child(6) {
  width: 8%;
  min-width: 100px;
  white-space: nowrap;
  text-align: center;
}

table.data-table.data-table--clientes th:nth-child(7),
table.data-table.data-table--clientes td:nth-child(7) {
  width: 8%;
  min-width: 100px;
  white-space: nowrap;
  text-align: center;
}

table.data-table.data-table--clientes th:nth-child(8),
table.data-table.data-table--clientes td:nth-child(8) {
  width: 13%;
  min-width: 180px;
  white-space: nowrap;
}

table.data-table.data-table--clientes th:nth-child(9),
table.data-table.data-table--clientes td:nth-child(9) {
  width: 104px;
  min-width: 104px;
  white-space: nowrap;
  overflow: visible;
}

/* Anchos por columna especificos del listado de Instalaciones (12
   columnas: Empresa, Cliente, Nombre, Codigo interno, Tipo, Direccion,
   Ciudad, Region, Estado, Usuarios, Creado, Acciones). Mismo criterio
   que .data-table--empresas / .data-table--clientes: modificador propio
   para no reinterpretar las reglas nth-child de otros listados; sigue
   reutilizando la misma base .data-table (bordes, padding, hover,
   tipografia, table-layout: auto, white-space en th/td) definida mas
   arriba. */
table.data-table.data-table--instalaciones {
  min-width: 1640px;
}

table.data-table.data-table--instalaciones th:nth-child(1),
table.data-table.data-table--instalaciones td:nth-child(1) {
  width: 9%;
  min-width: 150px;
}

table.data-table.data-table--instalaciones th:nth-child(2),
table.data-table.data-table--instalaciones td:nth-child(2) {
  width: 9%;
  min-width: 150px;
}

table.data-table.data-table--instalaciones th:nth-child(3),
table.data-table.data-table--instalaciones td:nth-child(3) {
  width: 10%;
  min-width: 160px;
}

table.data-table.data-table--instalaciones th:nth-child(4),
table.data-table.data-table--instalaciones td:nth-child(4) {
  width: 8%;
  min-width: 140px;
  white-space: nowrap;
}

table.data-table.data-table--instalaciones th:nth-child(5),
table.data-table.data-table--instalaciones td:nth-child(5) {
  width: 8%;
  min-width: 140px;
  white-space: nowrap;
}

table.data-table.data-table--instalaciones th:nth-child(6),
table.data-table.data-table--instalaciones td:nth-child(6) {
  width: 10%;
  min-width: 170px;
}

table.data-table.data-table--instalaciones th:nth-child(7),
table.data-table.data-table--instalaciones td:nth-child(7) {
  width: 8%;
  min-width: 130px;
  white-space: nowrap;
}

table.data-table.data-table--instalaciones th:nth-child(8),
table.data-table.data-table--instalaciones td:nth-child(8) {
  width: 7%;
  min-width: 120px;
  white-space: nowrap;
}

table.data-table.data-table--instalaciones th:nth-child(9),
table.data-table.data-table--instalaciones td:nth-child(9) {
  width: 6%;
  min-width: 100px;
  white-space: nowrap;
  text-align: center;
}

table.data-table.data-table--instalaciones th:nth-child(10),
table.data-table.data-table--instalaciones td:nth-child(10) {
  width: 6%;
  min-width: 90px;
  white-space: nowrap;
  text-align: center;
}

table.data-table.data-table--instalaciones th:nth-child(11),
table.data-table.data-table--instalaciones td:nth-child(11) {
  width: 11%;
  min-width: 180px;
  white-space: nowrap;
}

table.data-table.data-table--instalaciones th:nth-child(12),
table.data-table.data-table--instalaciones td:nth-child(12) {
  width: 104px;
  min-width: 104px;
  white-space: nowrap;
  overflow: visible;
}

/* Anchos por columna especificos del listado de Guardias (12 columnas:
   Empresa, Cliente, Instalacion, RUT, Nombre completo, Telefono,
   Correo, Cargo, Fecha de ingreso, Estado, Creado, Acciones).
   Sprint 4.2: se reemplazan los anchos en % + overflow-wrap: break-word
   (causa real de encabezados partidos como "INSTALAC/ION",
   "TELEFO/NO") por el mismo patron ya validado en Puestos: min-width
   por columna sobre table-layout: auto (regla base de mas arriba).
   Mismo criterio que .data-table--empresas/--clientes/--instalaciones/
   --puestos: modificador propio para no reinterpretar las reglas
   nth-child de otros listados. */
table.data-table.data-table--guardias {
  /* Suma real de los min-width por columna de mas abajo (150+150+160+
     120+180+130+200+150+150+100+180+104 = 1774px) mas un margen chico
     para bordes/redondeo de subpixeles. */
  min-width: 1780px;
}

table.data-table.data-table--guardias th:nth-child(1),
table.data-table.data-table--guardias td:nth-child(1) {
  width: 9%;
  min-width: 150px;
}

table.data-table.data-table--guardias th:nth-child(2),
table.data-table.data-table--guardias td:nth-child(2) {
  width: 9%;
  min-width: 150px;
}

table.data-table.data-table--guardias th:nth-child(3),
table.data-table.data-table--guardias td:nth-child(3) {
  width: 9%;
  min-width: 160px;
}

table.data-table.data-table--guardias th:nth-child(4),
table.data-table.data-table--guardias td:nth-child(4) {
  width: 7%;
  min-width: 120px;
  white-space: nowrap;
}

table.data-table.data-table--guardias th:nth-child(5),
table.data-table.data-table--guardias td:nth-child(5) {
  width: 10%;
  min-width: 180px;
}

table.data-table.data-table--guardias th:nth-child(6),
table.data-table.data-table--guardias td:nth-child(6) {
  width: 7%;
  min-width: 130px;
  white-space: nowrap;
}

table.data-table.data-table--guardias th:nth-child(7),
table.data-table.data-table--guardias td:nth-child(7) {
  width: 11%;
  min-width: 200px;
  white-space: nowrap;
}

table.data-table.data-table--guardias th:nth-child(8),
table.data-table.data-table--guardias td:nth-child(8) {
  width: 8%;
  min-width: 150px;
}

table.data-table.data-table--guardias th:nth-child(9),
table.data-table.data-table--guardias td:nth-child(9) {
  width: 8%;
  min-width: 150px;
  white-space: nowrap;
}

table.data-table.data-table--guardias th:nth-child(10),
table.data-table.data-table--guardias td:nth-child(10) {
  width: 6%;
  min-width: 100px;
  white-space: nowrap;
  text-align: center;
}

table.data-table.data-table--guardias th:nth-child(11),
table.data-table.data-table--guardias td:nth-child(11) {
  width: 10%;
  min-width: 180px;
  white-space: nowrap;
}

table.data-table.data-table--guardias th:nth-child(12),
table.data-table.data-table--guardias td:nth-child(12) {
  width: 104px;
  min-width: 104px;
  white-space: nowrap;
  overflow: visible;
}

/* Anchos por columna especificos del listado de Puestos de servicio
   (Sprint 4 - Entrega 1; 11 columnas: Empresa, Cliente, Instalacion,
   Nombre del puesto, Codigo interno, Tipo, Ubicacion, Estado, Guardias,
   Creado, Acciones). Mismo criterio que .data-table--empresas/
   --clientes/--instalaciones/--guardias: modificador propio para no
   reinterpretar las reglas nth-child de otros listados; sigue
   reutilizando la misma base .data-table (bordes, padding, hover,
   tipografia).

   Sprint 4.1 (pulido visual, sin cambios de logica): la tabla base usa
   table-layout: fixed (regla table.data-table de mas arriba, compartida
   por TODOS los listados y que no se toca aqui). Con layout fijo el
   ancho de cada columna se toma UNICAMENTE del th de la primera fila y
   segun la especificacion CSS min-width en celdas posteriores se
   ignora; por eso una columna en % terminaba mas angosta que su propio
   encabezado y el navegador partia la palabra para no desbordar (
   "EMPRES/A", "INSTALAC/ION") o la truncaba con puntos suspensivos (
   "Guardias" -> "G...", "Creado" -> "CRE..."). La correccion real -no
   un parche visual encima del sintoma- es usar table-layout: auto SOLO
   para este modificador (no se toca table.data-table global ni ningun
   otro modulo): con layout automatico, min-width por columna SI se
   respeta, el ancho final se calcula segun contenido y ninguna columna
   puede quedar mas angosta que su encabezado en una sola linea. Cuando
   la suma de anchos minimos supera el ancho disponible, la tabla crece
   mas alla del 100% y .table-wrap (ya tenia overflow-x: auto desde
   antes, sin cambios) habilita scroll horizontal en vez de comprimir
   columnas o partir palabras. */
table.data-table.data-table--puestos {
  table-layout: auto;
  /* Suma real de los min-width por columna de mas abajo (120+120+150+
     190+150+150+150+100+100+180+104 = 1514px) mas un margen chico para
     bordes/redondeo de subpixeles. */
  min-width: 1520px;
}

/* Los encabezados NUNCA se parten ni se truncan, en ninguna columna
   (incluidas Empresa/Cliente/Instalacion/Nombre/Ubicacion, cuyo
   CONTENIDO de fila -no su encabezado- si puede ocupar dos lineas mas
   abajo). overflow: visible + text-overflow: clip evita cualquier
   "..." residual si el navegador redondea el ancho automatico por
   subpixeles. */
table.data-table.data-table--puestos th {
  white-space: nowrap;
  overflow: visible;
  text-overflow: clip;
}

table.data-table.data-table--puestos th:nth-child(1),
table.data-table.data-table--puestos td:nth-child(1) {
  width: 10%;
  min-width: 120px;
}

table.data-table.data-table--puestos td:nth-child(1) {
  /* Empresa: el contenido de la celda (no el encabezado) puede
     ocupar dos lineas naturales -en espacios, nunca a mitad de
     palabra- ahora que min-width le da espacio real. */
  white-space: normal;
  overflow-wrap: normal;
  word-break: normal;
  overflow: visible;
  text-overflow: clip;
}

table.data-table.data-table--puestos th:nth-child(2),
table.data-table.data-table--puestos td:nth-child(2) {
  width: 10%;
  min-width: 120px;
}

table.data-table.data-table--puestos td:nth-child(2) {
  /* Cliente: mismo criterio que la columna 1. */
  white-space: normal;
  overflow-wrap: normal;
  word-break: normal;
  overflow: visible;
  text-overflow: clip;
}

table.data-table.data-table--puestos th:nth-child(3),
table.data-table.data-table--puestos td:nth-child(3) {
  width: 11%;
  min-width: 150px;
}

table.data-table.data-table--puestos td:nth-child(3) {
  /* Instalacion: mismo criterio que la columna 1. */
  white-space: normal;
  overflow-wrap: normal;
  word-break: normal;
  overflow: visible;
  text-overflow: clip;
}

table.data-table.data-table--puestos th:nth-child(4),
table.data-table.data-table--puestos td:nth-child(4) {
  width: 16%;
  min-width: 190px;
}

table.data-table.data-table--puestos td:nth-child(4) {
  /* Nombre del puesto: mismo criterio que la columna 1. */
  white-space: normal;
  overflow-wrap: normal;
  word-break: normal;
  overflow: visible;
  text-overflow: clip;
}

table.data-table.data-table--puestos th:nth-child(5),
table.data-table.data-table--puestos td:nth-child(5) {
  /* Codigo interno: siempre en una sola linea (regla de negocio de
     este ajuste), como pide el enunciado. */
  width: 10%;
  min-width: 150px;
  white-space: nowrap;
}

table.data-table.data-table--puestos th:nth-child(6),
table.data-table.data-table--puestos td:nth-child(6) {
  /* Tipo: catalogo de texto libre (ver PuestoController::TIPOS_SUGERIDOS),
     valores como "Acceso vehicular" necesitan mas ancho minimo que su
     encabezado para no forzar una segunda linea. */
  width: 11%;
  min-width: 150px;
  white-space: nowrap;
}

table.data-table.data-table--puestos th:nth-child(7),
table.data-table.data-table--puestos td:nth-child(7) {
  width: 12%;
  min-width: 150px;
}

table.data-table.data-table--puestos td:nth-child(7) {
  /* Ubicacion: texto libre opcional, mismo criterio que la columna 1. */
  white-space: normal;
  overflow-wrap: normal;
  word-break: normal;
  overflow: visible;
  text-overflow: clip;
}

table.data-table.data-table--puestos th:nth-child(8),
table.data-table.data-table--puestos td:nth-child(8) {
  /* Estado: badge, siempre en una sola linea. */
  width: 7%;
  min-width: 100px;
  white-space: nowrap;
  text-align: center;
}

table.data-table.data-table--puestos th:nth-child(9),
table.data-table.data-table--puestos td:nth-child(9) {
  /* Guardias: encabezado y valor siempre completos en una sola linea
     (era el caso truncado como "G..."). */
  width: 7%;
  min-width: 100px;
  white-space: nowrap;
  text-align: center;
}

table.data-table.data-table--puestos th:nth-child(10),
table.data-table.data-table--puestos td:nth-child(10) {
  /* Creado: fecha/hora completa en una sola linea (era el caso
     truncado como "CRE..."); el valor real es un DATETIME
     ("AAAA-MM-DD HH:MM:SS"), mas ancho que la palabra "Creado" sola. */
  width: 11%;
  min-width: 180px;
  white-space: nowrap;
}

table.data-table.data-table--puestos th:nth-child(11),
table.data-table.data-table--puestos td:nth-child(11) {
  /* Acciones: sin cambios de fondo, ya funcionaba bien (ancho fijo en
     px, botones apilados via .actions-cell). */
  width: 104px;
  min-width: 104px;
  white-space: nowrap;
  overflow: visible;
}

.actions-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}

.actions-cell a,
.actions-cell button {
  font-size: 12px;
}

.actions-cell form {
  margin: 0;
  display: block;
}

.btn-tiny {
  display: inline-block;
  padding: 7px 13px;
  border-radius: 100px;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-heading);
  cursor: pointer;
  font-weight: 700;
  font-family: var(--font);
  font-size: 12.5px;
  line-height: 1.2;
  transition: background 160ms ease, border-color 160ms ease, color 160ms ease, transform 120ms ease;
}

.btn-tiny:active {
  transform: scale(0.96);
}

.btn-tiny:hover {
  background: var(--color-bg);
  text-decoration: none;
}

.btn-tiny-danger {
  border-color: rgba(192, 57, 43, 0.3);
  color: var(--color-danger);
}

.btn-tiny-danger:hover {
  background: var(--color-danger-bg);
}

.btn-tiny-success {
  border-color: rgba(30, 142, 90, 0.35);
  color: var(--color-success);
}

.btn-tiny-success:hover {
  background: var(--color-success-bg);
}

/* ---------- Estados y roles (badges) ---------- */

.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.3px;
  white-space: nowrap;
  transition: background 180ms ease, color 180ms ease;
}

.badge-activo,
.badge-activa,
.badge-operativa {
  background: var(--color-success-bg);
  color: var(--color-success);
}

/* Incidentes: responsable asignado (M-8, auditoria visual 2026-09-08).
   Mismo tono "resuelto/en buen estado" que .badge-activo. */
.badge-asignado {
  background: var(--color-success-bg);
  color: var(--color-success);
}

.badge-suspendido,
.badge-suspendida,
.badge-dado_de_baja,
.badge-dada_de_baja,
.badge-inactivo,
.badge-inactiva {
  background: var(--color-danger-bg);
  color: var(--color-danger);
}

/* Instalaciones (Sprint 2 - Entrega 1): tercer estado propio de la
   tabla instalaciones, sin equivalente en usuarios/empresas/clientes
   (activo/inactivo son binarios). "En implementacion" no es exito ni
   error: es un estado intermedio, con su propio color neutro/amarillo
   para no confundirse visualmente con "operativa" (verde) ni
   "inactiva" (rojo). */
.badge-en_implementacion {
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

/* Estados de turno (Sprint 6). Reutilizan las mismas variables de color
   ya definidas arriba (success/danger/warning), sin introducir tonos
   nuevos: programado = pendiente (mismo tono que "en_implementacion"),
   confirmado = success, cancelado = danger, completado = neutral/muted
   (ni positivo ni negativo, solo "ya ocurrio"). */
.badge-programado {
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

.badge-confirmado {
  background: var(--color-success-bg);
  color: var(--color-success);
}

.badge-cancelado {
  background: var(--color-danger-bg);
  color: var(--color-danger);
}

.badge-completado {
  background: var(--color-bg);
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
}

/* Estados operacionales de Asistencia y Relevo (Sprint 7). Mismo
   criterio de color que Turnos, sin introducir tonos nuevos:
   pendiente = advertencia (aun no se marca), en_curso = success (guardia
   en el puesto), cerrado = neutral/muted (ya ocurrio, sin incidencias),
   cerrado_con_excepcion = danger (requiere atencion: cierre sin relevo
   formal), anulado = danger (correccion logica de un registro previo).
   'cancelado' (turno padre cancelado) reutiliza .badge-cancelado, ya
   definido arriba. */
.badge-pendiente {
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

.badge-en_curso {
  background: var(--color-success-bg);
  color: var(--color-success);
}

.badge-cerrado {
  background: var(--color-bg);
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
}

.badge-cerrado_con_excepcion {
  background: var(--color-danger-bg);
  color: var(--color-danger);
}

.badge-anulado {
  background: var(--color-danger-bg);
  color: var(--color-danger);
}

/* Severidad de Incidentes (Sprint Semana 5): 4 niveles propios, sin
   equivalente previo en el proyecto. Reutiliza las mismas 3 variables de
   color ya definidas (success/warning/danger) en vez de introducir tonos
   nuevos: baja = success, media = warning, alta = warning mas fuerte
   (mismo tono que warning, se distingue por texto), critica = danger. */
.badge-severidad-baja {
  background: var(--color-success-bg);
  color: var(--color-success);
}

.badge-severidad-media,
.badge-severidad-alta {
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

.badge-severidad-critica {
  background: var(--color-danger-bg);
  color: var(--color-danger);
}

.badge-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.badge-rol {
  display: inline-block;
  padding: 2px 12px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  color: var(--color-teal-text);
  white-space: nowrap;
  transition: background 180ms ease, color 180ms ease;
}

.text-muted {
  color: var(--color-text-muted);
}

/* ---------- Estado vacio ---------- */

.empty-state {
  text-align: center;
  padding: 48px 16px;
  color: var(--color-text-muted);
}

/* ---------- Paginacion ---------- */

.pagination {
  display: flex;
  gap: 6px;
  justify-content: center;
  margin-top: 20px;
  flex-wrap: wrap;
}

.pagination a,
.pagination span {
  padding: 7px 12px;
  border-radius: var(--radius);
  border: 1px solid var(--color-border);
  font-size: 13px;
  color: var(--color-heading);
}

.pagination span.activo {
  background: var(--color-navy);
  color: #fff;
  border-color: var(--color-navy);
}

.pagination a:hover {
  background: var(--color-bg);
  text-decoration: none;
}

/* ---------- Checkbox (control global, Aurora) ----------
   CORRECCION VISUAL (controles HTML nativos): antes solo .role-card
   input[type="checkbox"] tenia estilo propio (accent-color, que igual
   deja que cada sistema operativo dibuje su propia forma nativa de
   casilla -cuadrada en Windows, redondeada en macOS, distinta en cada
   navegador-); .checkbox-item input (usado en Instalaciones de
   Usuarios/Editar y en Guardias de views/asignaciones/puesto.php) no
   tenia ningun estilo, quedando con la casilla nativa sin integrar.
   appearance:none oculta el dibujo nativo del sistema operativo y lo
   reemplaza por un cuadro propio. Esto NO afecta la semantica real del
   checkbox: foco por teclado (Tab), alternar con Space, asociacion con
   su <label>, y el estado real checked/aria-checked que lee un lector
   de pantalla siguen siendo manejados por el navegador de forma nativa
   -appearance:none es solo dibujo visual, no quita funcionalidad-. Se
   aplica globalmente (no solo a .checkbox-item/.role-card) para que
   cualquier checkbox futuro del proyecto quede estilizado sin otra
   auditoria (Centralizar los estilos, sin duplicar).

   El relleno del estado marcado (fondo + marca de verificacion) se
   pinta con un ::before propio en vez de background-color/
   background-image directos sobre el input: se detecto en revision real
   que, en el estado :checked, algunos motores de renderizado conservan
   parte de la pintura nativa del control por encima del
   background-color/border-color declarados (appearance:none no la
   suprime del todo ahi, aunque si en el resto de estados), dejando el
   checkbox marcado sin verse relleno. Un pseudo-elemento no es parte del
   control nativo -es contenido de autor puro-, asi que no puede sufrir
   ese problema; es ademas la tecnica mas usada y probada para checkboxes
   personalizados multi-navegador. */

input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  box-sizing: border-box;
  width: 19px;
  height: 19px;
  flex-shrink: 0;
  margin: 0;
  border: 1.5px solid var(--color-border);
  border-radius: 5px;
  background-color: var(--color-surface);
  cursor: pointer;
  transition: border-color 160ms ease, box-shadow 160ms ease;
}

/* Relleno + marca de verificacion (SVG propio embebido como data-URI,
   sin CDN ni fuente de iconos -mismo trazo blanco sobre fondo de acento
   que ya usa .role-card::after). inset:-1.5px cubre tambien el borde
   propio del input, para que al marcar no se vea un borde delgado sin
   cubrir alrededor del relleno. Oculto por defecto via opacity+scale
   (mismo criterio de transicion que el resto de estados interactivos). */
input[type="checkbox"]::before {
  content: "";
  position: absolute;
  inset: -1.5px;
  border-radius: 5px;
  background-color: var(--color-teal-deep);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 13px 13px;
  opacity: 0;
  transform: scale(0.6);
  transition: opacity 140ms ease, transform 140ms ease;
}

/* Estado hover: igual criterio de acento que el resto de los controles
   (input:focus, .role-card:hover). Se omite si esta deshabilitado -un
   checkbox inactivo no debe insinuar que se puede interactuar con el-. */
input[type="checkbox"]:hover:not(:disabled) {
  border-color: var(--color-teal);
}

/* Estado foco (solo navegacion por teclado, :focus-visible -mismo
   criterio ya usado en .dash-quick-tile/.porteria-tile-, para no mostrar
   el anillo en un clic de mouse donde no aporta informacion nueva). */
input[type="checkbox"]:focus-visible {
  outline: none;
  border-color: var(--color-teal);
  box-shadow: 0 0 0 4px rgba(23, 169, 196, 0.16);
}

/* Estado seleccionado: el ::before de arriba pasa a visible; el input ya
   no necesita pintar su propio fondo/borde porque el overlay cubre toda
   el area (incluido el borde, ver inset:-1.5px). */
input[type="checkbox"]:checked::before {
  opacity: 1;
  transform: scale(1);
}

/* Estado deshabilitado: mismo checkbox visible (no desaparece, para no
   perder el contexto de que esa opcion existe pero no se puede tocar),
   opacidad reducida y cursor "not-allowed" -caso real:
   views/asignaciones/puesto.php deshabilita los checkboxes de guardias
   cuando el actuante no tiene asignaciones.gestionar-. Un deshabilitado
   Y marcado usa un gris neutro en vez del teal de acento, para no leerse
   como "seleccionable activo". */
input[type="checkbox"]:disabled {
  cursor: not-allowed;
  opacity: 0.55;
  background-color: var(--color-bg);
  border-color: var(--color-border);
}

input[type="checkbox"]:disabled::before {
  background-color: var(--color-text-muted);
}

/* ---------- Listas de checkboxes (roles / instalaciones) ---------- */

.checkbox-list {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 10px 14px;
  max-height: 220px;
  overflow-y: auto;
  background: var(--color-surface);
}

.checkbox-item {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 6px 0;
  font-size: 13.5px;
  cursor: pointer;
}

/* Alineacion fina contra la primera linea del texto (el checkbox global
   nace con margin:0); el tamano/apariencia real ya los define la regla
   compartida de arriba. */
.checkbox-item input {
  margin-top: 3px;
}

.checkbox-item:has(input:disabled) {
  cursor: not-allowed;
  color: var(--color-text-muted);
}

.checkbox-item .muted {
  color: var(--color-text-muted);
  font-size: 12px;
}

/* ---------- Estado vacio embebido (ej: instalaciones no disponibles) ---------- */

.empty-state-inline {
  text-align: center;
  padding: 14px 16px;
  color: var(--color-text-muted);
}

.empty-state .empty-state-icon,
.empty-state-inline .empty-state-icon {
  display: block;
  position: relative;
  top: 2px;
  font-size: 22px;
  margin-bottom: 6px;
}

.empty-state .empty-state-title,
.empty-state-inline .empty-state-title {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--color-heading);
  margin: 0 0 4px;
}

.empty-state .empty-state-desc,
.empty-state-inline .empty-state-desc {
  font-size: 12px;
  margin: 0;
  color: var(--color-text-muted);
}

.empty-state-actions {
  margin-top: 16px;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
}

.form-hint {
  font-size: 12px;
  color: var(--color-text-muted);
  margin-top: 4px;
}

/* Fin nocturno calculado y visible (bloque E): mismo tamaño que
   .form-hint, pero con el acento teal ya usado para datos derivados
   por el sistema (ver .form-section-title), para distinguirlo de una
   ayuda estática de texto fijo -- esto es un dato calculado en vivo. */
.form-hint-calculado {
  color: var(--color-teal-text);
  font-weight: 600;
  margin-top: 8px;
}

/* "Salida pendiente" (Dentro ahora): mismo criterio que
   .form-hint-calculado, tono de advertencia en vez de teal. */
.form-hint-alerta {
  color: var(--color-warning);
  font-weight: 600;
}

/* Utilidad generica: oculta visualmente sin sacar del arbol de
   accesibilidad (mismo patron ya usado en .app-bottom-nav-label). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Control de evidencia estilizado (auditoria visual: reemplaza el
   <input type="file"> nativo "Choose File / No file chosen", visible
   en views/novedades/crear.php, views/incidentes/crear.php y
   views/rondas/ver.php). El input real sigue en el DOM -mismo name,
   accept y comportamiento de envio multipart, ver .visually-hidden
   arriba-, solo queda fuera de la vista; el <label for="..."> hace de
   boton visual y activa el selector de archivos nativo sin JavaScript
   (progresion segura: si el JS de app.js no carga, el boton igual
   funciona, solo no se actualiza el nombre del archivo elegido). */
.file-input {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-top: 4px;
}

.file-input-trigger {
  flex-shrink: 0;
}

.file-input-filename {
  font-size: 13.5px;
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}

.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 18px;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

/* CORREGIDO en la auditoria visual Aurora (Semana 5): mismo problema que
   .filters-bar .form-group -- un item de grid tampoco se encoge por
   debajo de su ancho de contenido minimo por defecto (min-width: auto),
   asi que el campo "Orden" (views/rondas/puntos.php) o el nombre del
   punto podian forzar overflow horizontal dentro de .form-grid en
   pantallas reducidas. */
.form-grid > .form-group {
  min-width: 0;
  max-width: 100%;
}

/* ---------- Secciones de formulario ---------- */

/* Formulario compacto (bloque E, decision aprobada): 24px/22px dejaba
   demasiado aire entre secciones en formularios largos como Crear turno
   -en movil obligaba a demasiado scroll para llegar al boton "Crear
   turno". Reducido a un espaciado mas denso, sin perder la separacion
   visual entre secciones (el borde inferior se conserva). */
.form-section {
  margin-bottom: 16px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--color-border);
}

.form-section:last-of-type {
  border-bottom: none;
  padding-bottom: 0;
  margin-bottom: 0;
}

.form-section-title {
  font-size: 12.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--color-teal-text);
  margin: 0 0 10px;
}

.form-actions {
  margin-top: 4px;
  display: flex;
  justify-content: flex-end;
}

.form-actions .btn,
.form-actions .btn-secondary {
  width: auto;
  max-width: 220px;
}

/* ---------- Tarjetas de roles seleccionables ---------- */

.role-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 10px;
}

.role-card {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  border: 2px solid var(--color-border);
  border-radius: var(--radius);
  padding: 11px 13px;
  background: var(--color-surface);
  cursor: pointer;
  transition: border-color 200ms cubic-bezier(0.4, 0, 0.2, 1),
    background 200ms cubic-bezier(0.4, 0, 0.2, 1),
    box-shadow 200ms cubic-bezier(0.4, 0, 0.2, 1),
    transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* El borde ya nace en 2px (constante entre estado normal y seleccionado),
   asi el padding nunca cambia y la tarjeta no "salta" al marcarla. */
.role-card:hover {
  border-color: var(--color-teal);
  background: rgba(23, 169, 196, 0.025);
  box-shadow: 0 6px 16px rgba(11, 42, 74, 0.08);
  transform: translateY(-1px);
}

/* Tamano/apariencia/estados (normal, hover, foco, seleccionado,
   deshabilitado) ya los define la regla global input[type="checkbox"]
   de arriba (antes esta regla los duplicaba con accent-color, que aun
   asi dejaba una casilla con forma nativa del sistema operativo); aqui
   solo queda la alineacion fina contra la primera linea del nombre del
   rol dentro de la tarjeta. */
.role-card input[type="checkbox"] {
  margin-top: 2px;
}

.role-card:has(input:checked) {
  border-color: var(--color-teal);
  background: rgba(23, 169, 196, 0.08);
}

.role-card::after {
  /* Revision de interfaz: el "\2713" (caracter Unicode) se reemplaza por
     un SVG propio embebido como data-URI (sin CDN, sin fuente de
     iconos): un check de trazo blanco, mismo circulo insignia de
     siempre. content:"" + background-image en vez de un glifo de texto. */
  content: "";
  position: absolute;
  top: -6px;
  right: -6px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background-color: var(--color-navy);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 9px 9px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: scale(0.5);
  box-shadow: 0 1px 4px rgba(11, 42, 74, 0.22);
  transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1), transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
}

.role-card:has(input:checked)::after {
  opacity: 1;
  transform: scale(1);
}

.role-card-name {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--color-heading);
  display: block;
}

.role-card-desc {
  font-size: 12px;
  color: var(--color-text-muted);
  margin-top: 2px;
  display: block;
}

/* ---------- Tarjetas de puestos (modulo Asignaciones, Sprint 5) ----------
   Grid responsivo de tarjetas compactas para /asignaciones: reutiliza el
   mismo criterio de auto-fill/minmax ya usado en .role-cards (arriba)
   para que la cuadricula se reacomode sola en tablet/movil sin necesitar
   una regla aparte dentro de @media (max-width: 640px): con una sola
   columna disponible, auto-fill ya cae naturalmente a 1 columna. */

/* Tarjetas mas pequeñas (bloque E, decision aprobada): minmax de 220px a
   180px cabe una columna mas en tablet/desktop sin sentirse apretado, y
   el padding/gap se redujo en la misma proporcion que .form-section
   arriba -- misma corrida de compactacion, mismo criterio. Usado tanto
   por Turnos (tarjetas de puesto) como por Rondas (listado de rondas del
   dia): un solo cambio compacta las dos pantallas que pedia el bloque. */
.asignaciones-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 10px;
  margin-top: 18px;
}

.accesos-grupo-antiguo-titulo {
  margin-top: 20px;
  color: var(--color-warning);
}

.asignacion-card {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 12px;
  background: var(--color-surface);
  display: flex;
  flex-direction: column;
  gap: 5px;
}

/* "Dentro ahora" con salida pendiente real (investigado con datos
   reales: varios ingresos con 6-9 dias de antiguedad, ninguno por un
   calculo incorrecto -- ingresos que de verdad nunca registraron
   salida). Mismo tono de advertencia que .badge-pendiente, solo en el
   borde de la tarjeta para que se note sin tener que leer el texto. */
.asignacion-card--alerta {
  border-color: var(--color-warning);
}

.asignacion-card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.asignacion-card-header h3 {
  margin: 0;
  font-size: 14px;
  color: var(--color-heading);
  /* Bloque E: un item flex no se encoge por debajo de su ancho de
     contenido minimo por defecto -- con un nombre de guardia largo
     junto al badge de estado, el titulo podia empujar el badge fuera de
     la tarjeta en vez de partirse en dos lineas. Mismo criterio ya
     usado en .form-grid > .form-group. */
  min-width: 0;
  overflow-wrap: break-word;
}

.asignacion-card-tipo {
  margin: 0;
  font-size: 12px;
  color: var(--color-text-muted);
  overflow-wrap: break-word;
}

.asignacion-card-contador {
  margin: 4px 0 8px;
  font-size: 13px;
  color: var(--color-text);
}

.asignacion-card-contador strong {
  color: var(--color-heading);
  font-size: 16px;
}

.asignacion-card .btn-tiny {
  align-self: flex-start;
}

/* ---------- Turnos: filas de turno dentro de una tarjeta de puesto (Sprint 6) ----------
   Reutiliza .asignaciones-grid/.asignacion-card (arriba) para la
   cuadricula de tarjetas por puesto; esto solo agrega las filas de
   turno DENTRO de cada tarjeta, para no duplicar el grid ni el
   contenedor de tarjeta. */

.turno-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 0;
  border-top: 1px solid var(--color-border);
  font-size: 13px;
}

.turno-item:first-child {
  border-top: none;
}

.turno-item-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.turno-item-guardia {
  font-weight: 600;
  color: var(--color-heading);
}

.turno-item-horario {
  color: var(--color-text-muted);
  font-size: 12px;
}

.turno-item-acciones {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
  flex-wrap: wrap;
}

/* Cancelar turno (motivo obligatorio, prueba móvil real 2026-09-19):
   <details> compacto -- el botón "Cancelar" abre un mini-formulario en
   vez de un confirm() sin forma de explicar por qué. Cierra la fila
   cuando no está abierto; en 412px el formulario ocupa el ancho
   disponible sin desbordar. */
.turno-cancelar-detalle {
  position: relative;
}

.turno-cancelar-detalle summary {
  list-style: none;
  cursor: pointer;
}

.turno-cancelar-detalle summary::-webkit-details-marker {
  display: none;
}

.turno-cancelar-detalle[open] summary {
  display: none;
}

.turno-cancelar-form {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 180px;
  max-width: 100%;
  padding: 8px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

.turno-cancelar-form input[type="text"] {
  width: 100%;
  padding: 6px 8px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  font-size: 13px;
}

/* ---------- Vista semanal de turnos (Sprint 6) ----------
   Bloques simples agrupados por dia, con scroll VERTICAL de la pagina
   (nunca horizontal): cada dia es una tarjeta igual a .card, apiladas
   una debajo de otra. Deliberadamente NO es una grilla de 7 columnas
   tipo Excel (pedido explicito del enunciado). */

.semana-dia {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin-bottom: 12px;
  background: var(--color-surface);
}

.semana-dia-titulo {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: 13px;
  font-weight: 700;
  color: var(--color-heading);
  margin-bottom: 8px;
  text-transform: capitalize;
}

.semana-dia-titulo .muted {
  font-weight: 400;
  font-size: 12px;
  color: var(--color-text-muted);
  text-transform: none;
}

/* ---------- Filtros secundarios y campos opcionales colapsables (Sprint 6.1) ----------
   <details>/<summary> nativo (sin JS) para no exigir Guardia/Puesto ni
   Fecha de termino a simple vista, cumpliendo el pedido explicito de
   este sprint de "no bloquear la carga principal" y de compactar el
   formulario. Sin estos estilos, <details> se ve como un control basico
   del navegador (triangulo por defecto, sin tipografia ni fondo
   propios); se redisenya para que quede igual de integrado que
   btn-tiny/btn-secondary y el resto de la interfaz. */
.filters-secondary,
.form-group-details {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  margin-top: 6px;
}

.filters-secondary summary,
.form-group-details summary {
  list-style: none;
  cursor: pointer;
  padding: 9px 12px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--color-heading);
  display: flex;
  align-items: center;
  gap: 7px;
  user-select: none;
}

.filters-secondary summary::-webkit-details-marker,
.form-group-details summary::-webkit-details-marker {
  display: none;
}

.filters-secondary summary::before,
.form-group-details summary::before {
  /* Revision de interfaz: triangulo CSS puro (borde) en vez del
     caracter Unicode "\25B8". */
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  border-left: 5px solid var(--color-teal);
  transition: transform 180ms ease;
}

.filters-secondary[open] summary::before,
.form-group-details[open] summary::before {
  transform: rotate(90deg);
}

.filters-secondary summary:hover,
.form-group-details summary:hover {
  background: var(--color-bg);
}

.filters-secondary-body {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 14px;
  padding: 2px 12px 14px;
  align-items: flex-end;
  border-top: 1px solid var(--color-border);
}

.filters-secondary-body .form-group {
  flex: 1 1 160px;
  margin-bottom: 0;
  margin-top: 12px;
}

.filters-secondary-body .filters-actions {
  margin-top: 12px;
}

.form-group-details .form-group {
  padding: 2px 12px 14px;
  margin-bottom: 0;
  border-top: 1px solid var(--color-border);
}

/* Bloque (simplificación de Turnos/Supervisor): mismo criterio que
   .form-group-details .form-group arriba, para cuando el contenido
   plegable es una lista de .turno-item en vez de un campo de
   formulario -- el borde superior de .turno-item ya separa cada fila
   entre sí, este padding lateral solo evita que queden pegadas al
   borde del contenedor plegable. */
.form-group-details .turno-item {
  padding-left: 12px;
  padding-right: 12px;
}

/* Enlaces/acciones dentro de un estado vacio (ej: "sin guardias
   asignados" -> Ir a Asignaciones): separacion del texto descriptivo. */
.empty-state .btn-tiny,
.empty-state-inline .btn-tiny {
  margin-top: 8px;
}

/* ---------- Responsive ---------- */

@media (max-width: 640px) {
  /* PROBLEMA 2 (encabezado que se perdia al hacer scroll): el
     encabezado "CENTINELA360" + avatar de rol queda anclado arriba.
     Se usa "position: sticky" y NO "fixed" a proposito: sticky conserva
     el alto real del encabezado dentro del flujo del documento, asi que
     no hace falta compensar con padding-top en el contenido (con
     "fixed" habria que adivinar la altura exacta del encabezado, que
     varia segun si hay subtitulo de rol/seccion y si la fila se
     envuelve en pantallas muy angostas -- si esa altura se calcula mal,
     el encabezado tapa el primer titulo de cada pantalla).
     Funciona a partir de la correccion de overflow en .app-shell / html
     (ver arriba): antes de esa correccion, cualquier sticky dentro de
     .app-shell era ignorado por el navegador.
     El padding-top ya suma env(safe-area-inset-top) desde antes, asi
     que el notch / isla dinamica sigue respetado.
     z-index 15: por encima de todo el contenido de las vistas (que usa
     como maximo z-index 1) y por DEBAJO del fondo atenuado del panel
     flotante (19) y de la barra inferior (20), para que al abrir
     "Operación"/"Más" el encabezado tambien quede atenuado y se lea
     como inerte. */
  .app-topbar {
    position: sticky;
    top: 0;
    z-index: 15;
    padding: calc(12px + env(safe-area-inset-top, 0px)) 16px 10px;
  }

  .app-topbar-row {
    flex-wrap: wrap;
    gap: 10px;
  }

  /* IMPLEMENTACION UX movil tipo app: en escritorio #app-nav sigue
     siendo la navegacion real (sin cambios); en movil se reemplaza por
     la barra inferior fija + panel "Mas" de mas abajo, asi que aqui
     simplemente se oculta. */
  .app-nav {
    display: none;
  }

  /* Subtitulo del encabezado compacto (rol . seccion actual): oculto en
     escritorio, la cabecera de escritorio no se toca. */
  .app-topbar-subtitle {
    margin: 2px 0 0;
    font-size: 12px;
    color: rgba(255, 255, 255, 0.65);
  }

  /* En movil el nombre+boton "Cerrar sesion" de escritorio se
     reemplazan por el avatar (ver mas abajo); nada se elimina, solo se
     oculta uno u otro segun el ancho de pantalla. */
  .app-user-desktop {
    display: none;
  }

  .app-avatar {
    display: block;
    position: relative;
  }

  .app-avatar-trigger {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--grad);
    color: #fff;
    font-family: var(--font-display);
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
    list-style: none;
    transition: transform 120ms ease;
  }

  .app-avatar-trigger:active {
    transform: scale(0.92);
  }

  .app-avatar-trigger::-webkit-details-marker {
    display: none;
  }

  .app-avatar[open] .app-avatar-trigger {
    outline: 2px solid rgba(255, 255, 255, 0.5);
    outline-offset: 2px;
  }

  /* REDUCIDO Y REUBICADO (pedido explicito, prueba real en Motorola: el
     panel tapaba el nombre del guardia en la pagina de abajo).
     Confirmado con captura real a 412px: el panel abierto quedaba justo
     encima del encabezado con el nombre del guardia (primera linea de
     contenido, pegada al topbar), y su fondo traslucido con blur dejaba
     ver ese mismo texto de fondo mezclado con el del panel -dos nombres
     superpuestos, dificiles de leer-. Correccion real, no cosmetica:
     min-width y padding mas chicos para que el panel ocupe menos alto y
     menos ancho (menos superficie para tapar algo), y fondo SOLIDO (sin
     blur ni transparencia) para que, en el area que si cubre, se lea
     limpio en vez de mezclado con el contenido de atras. */
  .app-avatar-panel {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 30;
    width: 200px;
    max-width: calc(100vw - 32px);
    background: var(--color-surface);
    border: 1px solid var(--glass-border);
    color: var(--color-text);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-glass);
    padding: 10px;
  }

  /* Una sola linea, con "…" si no cabe (pedido explicito: reducir el
     panel para que no tape el nombre de abajo). El nombre completo
     largo (ej. "TEST BLOQUEO_696540 UsuarioGuardia") era justo lo que
     hacia crecer el panel a 3 lineas y lo empujaba a cubrir mas alto de
     lo necesario -- capado a una linea, la altura del panel queda fija y
     predecible sin importar cuan largo sea el nombre real. El nombre
     completo sigue disponible: title= lo muestra igual si el texto se
     corta. */
  .app-avatar-nombre {
    margin: 0;
    font-size: 14px;
    font-weight: 700;
    color: var(--color-heading);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .app-avatar-rol {
    margin: 2px 0 8px;
    font-size: 12px;
    color: var(--color-text-muted);
  }

  .app-avatar-logout {
    width: 100%;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 10px;
    font-weight: 600;
    color: var(--color-danger);
    cursor: pointer;
  }

  /* Encabezados de grupo dentro del panel "Mas" (reutiliza la misma
     clase que ya usaba el panel anterior). */
  .app-nav-group-label {
    display: block;
    width: 100%;
    text-align: left;
    color: rgba(255, 255, 255, 0.5);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.8px;
    padding: 14px 14px 6px;
    margin-top: 2px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
  }

  .app-nav-group-label:first-child {
    margin-top: 0;
    border-top: none;
  }

  /* ---------- Barra de navegacion inferior (IMPLEMENTACION UX app) ----------
     Fija, con hasta 4 pestanas segun permiso. "Mas" es un <details>
     nativo: abre/cierra sin JavaScript; nav.js solo agrega el cierre
     automatico al elegir un enlace, con Escape o al pulsar fuera. */
  /* REDISEÑO NAVEGACION (correccion "estilo Instagram" -- capsula
     enorme, circulo activo gigante deslizante, iconos desproporcionados,
     paneles que tapaban botones): barra COMPACTA, fondo solido (sin
     backdrop-filter: la barra inferior es visible en CADA pantalla, asi
     que es el elemento con mas impacto de rendimiento posible si usa
     blur -ver medicion real documentada en el informe de esta correccion-),
     sin la pastilla degradada que se deslizaba detras del item activo
     -el estado activo ahora es solo un cambio de color de icono/texto,
     sin geometria que animar ni JS de posicionamiento que ejecutar-.

     PROBLEMA 1 -- prueba en iPhone real (Safari), el mas importante:
     la barra desaparecia al hacer scroll y solo reaparecia arrastrando
     hacia abajo. La version anterior usaba "position: sticky" para
     reservar su propio alto en el flujo y no tapar contenido, pero ese
     sticky NUNCA se activaba: .app-shell era un contenedor de scroll
     sin rango de desplazamiento propio (ver correccion de overflow mas
     arriba), asi que la barra se comportaba como un elemento estatico
     al final del documento -- exactamente el sintoma reportado.
     Ahora es "position: fixed" anclada al borde inferior del viewport:
     no depende de ningun ancestro ni de que el sticky se active, asi
     que queda visible en TODAS las vistas y para todos los roles.
     Como "fixed" saca la barra del flujo (ya no reserva su alto), el
     contenido compensa con padding-bottom en .app-main -- ver
     --app-bottom-nav-h mas abajo: eso es lo que evita que el ultimo
     item de las listas largas (Guardias, Puestos, Novedades,
     Incidentes, Rondas, Asignaciones) quede tapado. */
  .app-bottom-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    margin: 0;
    z-index: 20;
    display: flex;
    align-items: stretch;
    gap: 0;
    min-height: var(--app-bottom-nav-h, 64px);
    padding: 4px 4px calc(4px + env(safe-area-inset-bottom, 0px));
    border-radius: 0;
    background: var(--color-surface);
    border: none;
    border-top: 1px solid var(--color-border);
    box-shadow: none;
  }

  .app-bottom-nav-item {
    position: relative;
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-height: 44px;
    padding: 5px 4px;
    border-radius: 0;
    color: var(--color-text-muted);
    text-decoration: none;
    cursor: pointer;
    list-style: none;
    transition: color 150ms ease;
  }

  /* Bug real encontrado en la validacion visual (correccion calidad
     demo): .app-more-panel/.app-operacion-panel son "position: fixed"
     Y viven DENTRO del <details> "Operacion"/"Mas" (.app-bottom-nav-more)
     -- un transform en CUALQUIER ancestro (incluido este scale() de
     "presionado") convierte a ese ancestro en el contenedor de
     posicionamiento del descendiente fixed en vez del viewport, y el
     panel desplegable aparecia encogido y mal ubicado en vez de cubrir
     el ancho de la pantalla. Se excluye a esos dos items del efecto de
     escala (siguen siendo <a> normales sin fixed descendiente, asi que
     conservan el feedback tactil de siempre). */
  .app-bottom-nav-item:not(.app-bottom-nav-more):active {
    transform: scale(0.92);
  }

  .app-bottom-nav-item::-webkit-details-marker {
    display: none;
  }

  /* Correccion adicional (auditoria visual, iconos "Operacion"/"Mas"):
     list-style/::-webkit-details-marker de arriba se aplicaban sobre el
     <details> (.app-bottom-nav-item), pero el triangulo nativo de
     apertura pertenece al <summary> hijo -por spec, es "summary" quien
     tiene display:list-item y el marker-, asi que nunca se ocultaba:
     quedaba un triangulo "▶" nativo del navegador flotando junto al
     icono SVG de cada uno, con la misma lectura ambigua de "reproducir"
     que motivo reemplazar esos iconos. Se suprime aqui, en el elemento
     correcto, sin tocar el resto del comportamiento nativo (abrir/cerrar
     sigue funcionando via el atributo [open], sin JavaScript). */
  .app-bottom-nav-item > summary {
    list-style: none;
  }

  .app-bottom-nav-item > summary::-webkit-details-marker {
    display: none;
  }

  .app-bottom-nav-item > summary::marker {
    content: "";
    display: none;
  }

  /* Estado activo: SOLO color turquesa + un indicador fino (barra de
     3px arriba del item) -- nunca un fondo/pastilla que se lea como
     circulo o capsula grande (correccion calidad demo: diseño
     operativo aprobado explicitamente pide "indicador fino", no una
     caja resaltada). */
  .app-bottom-nav-item.activo {
    color: var(--color-teal-text);
  }

  .app-bottom-nav-item.activo::before {
    content: "";
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 24px;
    height: 3px;
    border-radius: 0 0 3px 3px;
    background: var(--color-teal);
  }

  /* Etiqueta visible (no solo accesible para lectores de pantalla, ver
     correccion calidad demo anterior): texto pequeño bajo el icono. */
  .app-bottom-nav-label {
    font-size: 9.5px;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
    letter-spacing: 0.01em;
  }

  /* Iconos moderados (18px, antes 22px + geometria de circulo/triangulo
     dibujada a mano con CSS): TODOS los iconos del nav inferior -Inicio,
     Operación, Accesos, Más- son ahora SVG real del sistema icon()
     -unico origen de iconos del proyecto-, sin excepcion. */
  .app-bottom-nav-icon {
    display: inline-flex;
    width: 18px;
    height: 18px;
    flex: 0 0 18px;
  }

  .app-bottom-nav-icon svg {
    width: 100%;
    height: 100%;
    stroke-width: 2px;
  }

  /* Panel "Mas": sheet fijo sobre la barra inferior, oculto hasta que
     el <details> se abre (atributo nativo [open], sin JavaScript). */
  .app-more-panel {
    display: none;
  }

  /* Fondo atenuado detras del panel (mismo criterio visual que ya
     tenia: dejar claro que lo de abajo esta inerte mientras el panel
     esta abierto). Ahora es el elemento real #app-sheet-backdrop, ver
     PROBLEMA 3 mas arriba.
     Dos selectores a proposito:
       1) .app-bottom-nav:has(...) -- funciona SIN JavaScript, igual que
          el ::before anterior, para que abrir el panel siga atenuando
          el fondo aunque nav.js no cargue.
       2) .app-sheet-backdrop.visible -- la clase que pone nav.js. Es la
          que garantiza el mismo resultado en cualquier navegador que
          todavia no soporte :has().
     z-index 19: sobre el contenido y sobre el encabezado (15) y por
     debajo de la propia barra inferior (20) y del panel (20), asi que
     el fondo NO bloquea los toques de la barra inferior -- se puede
     pasar directo de "Operación" a "Inicio" con un solo toque. */
  .app-bottom-nav:has(.app-bottom-nav-more[open]) ~ .app-sheet-backdrop,
  .app-sheet-backdrop.visible {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.45);
    z-index: 19;
    /* iOS Safari no dispara "click" sobre elementos no interactivos sin
       una senal de que son pulsables; el manejador de nav.js se asigna
       directamente a este elemento (no delegado) y se declara cursor
       pointer para que el evento llegue siempre. */
    cursor: pointer;
    /* El toque cierra el panel: no debe interpretarse como intento de
       hacer scroll ni disparar el zoom por doble toque. */
    touch-action: manipulation;
  }

  .app-bottom-nav-more[open] .app-more-panel {
    display: flex;
    flex-direction: column;
    position: fixed;
    left: 16px;
    right: 16px;
    bottom: calc(88px + env(safe-area-inset-bottom, 0));
    z-index: 20;
    max-height: min(70vh, 480px);
    overflow-y: auto;
    background: var(--color-navy-dark);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-glass);
    padding-bottom: 8px;
  }

  .app-more-panel a {
    width: 100%;
    min-height: 46px;
    display: flex;
    align-items: center;
    text-align: left;
    padding: 0 16px;
    font-size: 15px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.75);
    text-decoration: none;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    border-left: 3px solid transparent;
  }

  .app-more-panel a:hover {
    color: #fff;
    background: rgba(255, 255, 255, 0.05);
  }

  .app-more-panel a.activo {
    background: rgba(255, 255, 255, 0.08);
    border-left-color: var(--color-teal);
    color: #fff;
  }

  .app-more-panel-footer {
    padding: 12px 16px 16px;
    display: flex;
    gap: 8px;
    align-items: center;
  }

  .app-more-panel-footer form {
    margin: 0;
  }

  .app-more-logout-form {
    margin-left: auto;
  }

  .app-more-accion-icono {
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 1px solid rgba(255, 255, 255, 0.35);
    border-radius: 50%;
    color: #fff;
    cursor: pointer;
    padding: 0;
  }

  .app-more-accion-icono:hover {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.5);
  }

  /* Area tactil real de 44px (minimo comodo con guantes y bajo lluvia),
     con el circulo visible de 40px centrado dentro. */
  .app-more-accion-icono {
    min-width: 44px;
    min-height: 44px;
  }

  .app-more-accion-icono svg {
    width: 20px;
    height: 20px;
    stroke-width: 2;
  }

  /* Los dos <span> que envuelven sol y luna dentro del boton de tema: no
     deben aportar caja propia ni desalinear el icono. Solo uno de los
     dos esta visible a la vez (lo decide assets/js/tema.js). */
  .app-more-accion-icono [data-tema-icono] {
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 0;
  }

  .app-more-accion-icono [data-tema-icono][hidden] {
    display: none;
  }

  /* PROBLEMA 1 (segunda mitad): con la barra inferior en "position:
     fixed" ya no reserva su alto en el flujo, asi que el contenido
     reserva el espacio equivalente por si mismo. 64px es el min-height
     real declarado en .app-bottom-nav de mas arriba; se le suma
     env(safe-area-inset-bottom) (barra de gestos / notch del iPhone) y
     se conserva el padding inferior de 20px que ya tenia el contenido,
     para que el ultimo elemento de cada listado quede completamente
     visible y sea tocable. Verificado contra las vistas largas con
     tabla: Guardias, Puestos, Novedades, Incidentes, Rondas y
     Asignaciones (todas renderizan dentro de .app-main). */
  .app-main {
    padding: 20px 16px calc(20px + var(--app-bottom-nav-h, 64px) + env(safe-area-inset-bottom, 0px));
  }

  .guest-card {
    padding: 28px 22px;
  }

  .form-grid {
    grid-template-columns: 1fr;
  }

  table.data-table {
    table-layout: auto;
  }

  .data-table th,
  .data-table td {
    white-space: normal;
    width: auto;
  }

  .card-header .btn {
    width: 100%;
  }

  /* Bloque E: en movil, "Configurar puntos" y "Programar ronda" (u otro
     par de acciones agrupadas) se reparten el ancho disponible en partes
     iguales, siempre en la misma fila mientras quepan -- si el texto
     fuera demasiado largo para eso, flex-wrap del contenedor los baja a
     una fila cada uno, nunca superpuestos ni cortados. */
  .card-header-actions {
    width: 100%;
  }

  .card-header-actions .btn-tiny {
    flex: 1 1 0;
    text-align: center;
  }

  .filters-bar {
    padding: 12px;
  }

  .filters-bar .form-group {
    flex: 1 1 100%;
  }

  .filters-bar .filters-actions {
    width: 100%;
  }

  .filters-bar .filters-actions .btn-secondary,
  .filters-bar .filters-actions .btn-tiny {
    flex: 1 1 auto;
    text-align: center;
  }

  .role-cards {
    grid-template-columns: 1fr;
  }

  .form-actions .btn,
  .form-actions .btn-secondary {
    width: 100%;
    max-width: none;
    min-width: 0;
  }

  /* Sprint 6.1: filtros secundarios y campos colapsables de Turnos,
     una sola columna tactil, igual criterio que .filters-bar arriba. */
  .filters-secondary-body .form-group {
    flex: 1 1 100%;
  }

  .filters-secondary-body .filters-actions .btn-tiny {
    width: 100%;
    text-align: center;
  }
}

/* CORREGIDO en la auditoria pre-despliegue: reemplaza el
   style="margin-bottom: 18px;" inline que tenia views/accesos/index.php
   (navegacion "Dia anterior / Hoy / Dia siguiente"). Alcance
   deliberadamente limitado a esa vista nueva de Accesos: no se toca
   Turnos ni Asistencia (aunque conserven el mismo patron inline, no
   forman parte de esta correccion). */
.accesos-nav-dia {
  margin-bottom: 18px;
}

/* ---------- Inicio: saludo + accesos directos (rediseño Aurora) ----------
   Reemplaza la tarjeta plana de bienvenida por un tablero tipo bento de
   accesos directos, generado en DashboardController con los mismos
   PermissionService::hasPermission('modulo','ver') que ya usaba
   layouts/main.php -sin cifras inventadas: el Centro de Comando con
   KPIs reales es trabajo aparte, todavia sin datos que mostrar-. */

.dash-quick-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 12px;
}

/* Interfaz "Centinela Roles": el Guardia/operador abre el Inicio sobre
   todo desde el celular en terreno, asi que sus tarjetas de acceso
   directo son mas grandes/tactiles (2 columnas fijas en vez de
   auto-fill) que las del resto de los roles. Mismo componente
   .dash-quick-tile, sin logica nueva. */
.dash-quick-grid--guardia {
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}

.dash-quick-grid--guardia .dash-quick-tile {
  padding: 22px 16px;
  align-items: center;
  text-align: center;
}

.dash-quick-grid--guardia .dash-quick-icon {
  width: 46px;
  height: 46px;
  font-size: 24px;
}

.dash-quick-grid--guardia .dash-quick-label {
  font-size: 15px;
}

/* ---------------------------------------------------------------
   SISTEMA VISUAL COMPARTIDO "Inicio" (aprobado sobre el diseño
   operativo del Guardia, extendido a los 4 roles): cabecera, resumen,
   secciones con accion primaria/secundaria, filas de navegacion.
   Fondos SOLIDOS, sin backdrop-filter en ninguna de estas clases -son
   las que un usuario real abre mas seguido de toda la app, asi que aqui
   es donde mas importa evitar el costo de composicion de blur() en
   hardware de gama baja-. Una unica arquitectura: estas clases
   ".pantalla-*" las usan por igual Guardia, Supervisor, Cliente y
   Superusuario en sus respectivos Inicio (ver views/dashboard/index.php);
   ningun rol tiene su propio juego de estilos paralelo. */

.pantalla-header {
  margin-bottom: 14px;
}

.pantalla-header h1 {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 700;
  color: var(--color-heading);
  margin: 0;
  line-height: 1.25;
}

.pantalla-header-sub {
  font-size: 12.5px;
  color: var(--color-text-muted);
  margin: 2px 0 0;
}

/* Variante para cabeceras de pantallas secundarias que llevan un boton
   (ej. "Volver") junto al titulo -- misma tipografia, layout en fila. */
.pantalla-header--fila {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  flex-wrap: wrap;
}

/* Resumen operativo: una unica superficie liviana (sin tarjetas
   separadas, sin sombra, sin fondo pesado) -- grid de hasta 3 columnas
   con un divisor sutil entre celdas (envuelve a una 2a fila si el rol
   tiene mas de 3 indicadores, ej. Superusuario), etiqueta arriba en
   gris tenue y numero grande abajo. Reemplaza el grid de tarjetas
   individuales con blur (.centro-metrica, retirado) que antes repetia
   el mismo fondo pesado una vez por indicador. */
.pantalla-resumen {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--color-border);
  margin-bottom: 16px;
}

.pantalla-resumen-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 4px;
  text-align: center;
  border-right: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
}

.pantalla-resumen-item:nth-child(3n),
.pantalla-resumen-item:last-child {
  border-right: none;
}

.pantalla-resumen-lbl {
  font-size: 12px;
  font-weight: 500;
  color: var(--color-text-muted);
}

.pantalla-resumen-num {
  font-family: var(--font-mono-sys);
  font-variant-numeric: tabular-nums;
  font-size: 24px;
  font-weight: 700;
  color: var(--color-heading);
}

.pantalla-resumen-sub {
  font-size: 10px;
  font-weight: 700;
  color: var(--color-warning);
}

/* Selector segmentado Ingreso/Salida: 2 radios reales (accesibles,
   funcionan sin JS), estilizados como pastillas -- ninguna dependencia
   de JS para que la seleccion "se vea" tomada, solo para que controle
   el href de los 4 tiles de abajo (ver assets/js/app.js). Especifico
   de Guardia (ningun otro rol tiene un modo Ingreso/Salida), por eso
   mantiene su nombre propio en vez de "pantalla-*". */
.guardia-modo {
  display: flex;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 100px;
  padding: 3px;
  margin-bottom: 14px;
}

.guardia-modo input[type="radio"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

.guardia-modo label {
  flex: 1;
  text-align: center;
  padding: 9px 0;
  margin: 0;
  border-radius: 100px;
  font-size: 13.5px;
  font-weight: 700;
  text-transform: none;
  letter-spacing: normal;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease;
}

.guardia-modo input[type="radio"]:checked + label {
  background: var(--grad);
  color: #fff;
}

.guardia-modo input[type="radio"]:focus-visible + label {
  outline: 2px solid var(--color-teal);
  outline-offset: 2px;
}

/* Seccion con titulo (ej. "Persona"/"Vehiculo" en Guardia): SIN
   tarjeta envolvente -- solo un titulo con icono, un divisor tenue, y
   debajo la accion primaria + la accion secundaria opcional. Reemplaza
   el patron de grid de celdas iguales (escanear/manual x persona/
   vehiculo se leian como 4 acciones del mismo peso). Reutilizable por
   cualquier rol que necesite el mismo patron "titulo + accion primaria
   + accion secundaria". */
.pantalla-seccion {
  margin-bottom: 18px;
}

.pantalla-seccion-titulo {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-bottom: 8px;
  margin-bottom: 10px;
  border-bottom: 1px solid var(--color-border);
}

.pantalla-seccion-icon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  color: var(--color-teal);
}

.pantalla-seccion-icon svg {
  width: 100%;
  height: 100%;
}

.pantalla-seccion-titulo h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 700;
  color: var(--color-heading);
}

.pantalla-seccion-acciones {
  display: flex;
  gap: 10px;
}

.pantalla-btn-primario {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  padding: 0 14px;
  background: var(--color-teal-deep);
  border: none;
  border-radius: var(--radius);
  color: #fff;
  text-decoration: none;
  font-size: 14.5px;
  font-weight: 700;
}

.pantalla-btn-primario:hover,
.pantalla-btn-primario:active {
  background: var(--color-teal-deep);
  text-decoration: none;
  color: #fff;
}

.pantalla-btn-icon {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
}

.pantalla-btn-icon svg {
  width: 100%;
  height: 100%;
}

.pantalla-btn-secundario {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 96px;
  min-height: 48px;
  padding: 0 16px;
  background: transparent;
  border: 1px solid var(--color-teal);
  border-radius: var(--radius);
  color: var(--color-teal-text);
  text-decoration: none;
  font-size: 14.5px;
  font-weight: 700;
}

.pantalla-btn-secundario:hover,
.pantalla-btn-secundario:active {
  background: var(--color-bg);
  text-decoration: none;
  color: var(--color-teal-text);
}

/* Fila de navegacion (ej. "Operación del turno" en Guardia): una unica
   fila liviana, sin borde pesado ni caja punteada -- solo icono +
   titulo/subtitulo + chevron. A proposito mucho menos prominente que
   una seccion con accion primaria. Reutilizable por cualquier rol para
   enlazar a una pantalla secundaria desde el Inicio (ej. Supervisor:
   Rondas/Novedades/Incidentes; Cliente: Visitantes/Autorizaciones). */
.pantalla-fila-nav {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 2px;
  margin-bottom: 4px;
  background: transparent;
  border: none;
  color: var(--color-text);
  text-decoration: none;
}

.pantalla-fila-nav:hover {
  text-decoration: none;
}

.pantalla-fila-nav-icon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  color: var(--color-text-muted);
}

.pantalla-fila-nav-icon svg {
  width: 100%;
  height: 100%;
}

.pantalla-fila-nav-texto {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.pantalla-fila-nav-titulo {
  font-size: 14.5px;
  font-weight: 700;
  color: var(--color-heading);
}

.pantalla-fila-nav-desc {
  font-size: 12px;
  font-weight: 400;
  color: var(--color-text-muted);
}

.pantalla-fila-nav-chevron {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin-left: auto;
  color: var(--color-text-muted);
}

.pantalla-fila-nav-chevron svg {
  width: 100%;
  height: 100%;
}

.pantalla-fila-nav-grupo {
  margin-bottom: 14px;
}

.dash-quick-tile {
  display: flex;
  flex-direction: column;
  gap: 14px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border-radius: var(--radius-lg);
  padding: 18px;
  box-shadow: var(--shadow);
  text-decoration: none;
  transition: transform 180ms ease, border-color 180ms ease, box-shadow 180ms ease;
}

.dash-quick-tile:hover,
.dash-quick-tile:focus-visible {
  transform: translateY(-3px);
  border-color: var(--color-teal);
  box-shadow: var(--shadow-glass);
  text-decoration: none;
}

.dash-quick-tile:active {
  transform: translateY(-1px) scale(0.99);
}

.dash-quick-icon {
  width: 38px;
  height: 38px;
  border-radius: 12px;
  background: var(--grad);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  /* CORRECCION VISUAL (consola movil del Guardia): antes mostraba la
     primera letra de la etiqueta como icono improvisado ("R", "B", "V");
     ahora es un SVG real (icon(), mismo helper que .porteria-tile-icon/
     .empty-state-icon), dimensionado via .dash-quick-icon svg de arriba.
     font-size pasa de 15px (calibrado para una letra de texto) a 20px:
     un trazo SVG a ese tamano de letra se veia perdido dentro del
     recuadro de 38px. */
  font-size: 20px;
}

.dash-quick-label {
  font-weight: 700;
  color: var(--color-heading);
  font-size: 14px;
}

/* ---------- Inicio: tablero real por rol (Fase 3, "Centro de Comando") ----------
   Datos reales de Services\CentroComandoService -sin cifras inventadas-;
   donde una celda no tiene una consulta real que la respalde, el HTML
   dice "Sin datos" en el mismo lugar visual.

   Correccion "referencia literal" (el Inicio de Supervisor/Cliente/
   Superusuario dejo de usar tarjetas -.centro-card/.centro-qa/.centro-list,
   retirados- y paso a la MISMA composicion plana del Guardia: cabecera,
   resumen de 3 columnas, secciones .pantalla-seccion con titulo+divisor,
   filas .pantalla-fila-nav dentro de .pantalla-lista). Sin fondo propio,
   sin sombra, sin blur, sin caja anidada en ningun nivel. */

.dash-empty-compact {
  padding: 10px 2px;
  margin-bottom: 14px;
  font-size: 12.5px;
  color: var(--color-text-muted);
}

.centro-section-count {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--color-teal-text);
  background: var(--color-bg);
  padding: 3px 9px;
  border-radius: 100px;
  white-space: nowrap;
  margin-left: auto;
}

/* Lista de filas planas dentro de una .pantalla-seccion (Instalaciones,
   Empresas, Actividad reciente, Pendientes, accesos rapidos por rol):
   cada item es un .pantalla-fila-nav, separados por un divisor fino en
   vez de estar cada uno en su propia tarjeta. */
.pantalla-lista {
  margin-bottom: 4px;
}

.pantalla-lista .pantalla-fila-nav {
  padding: 10px 2px;
  margin-bottom: 0;
  border-bottom: 1px solid var(--color-border);
}

.pantalla-lista .pantalla-fila-nav:last-child {
  border-bottom: none;
}

/* Slot derecho generico de una fila (badge de estado, hora, chevron, o
   una combinacion) -- reemplaza el badge/hora sueltos que antes vivian
   directo en .centro-list-item. */
.pantalla-fila-nav-derecha {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  flex-shrink: 0;
}

.pantalla-fila-nav-derecha .pantalla-fila-nav-chevron {
  margin-left: 0;
}

.pantalla-fila-nav-when {
  font-size: 11px;
  color: var(--color-text-muted);
  white-space: nowrap;
}

/* Estados abierto/abierta de incidentes y novedades: sin badge propio
   hasta ahora (solo existian los de asistencia/turnos, que ya usan
   'cerrado'). Se agregan aqui, sin tocar los badges existentes. */
.badge-abierto,
.badge-abierta {
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

.badge-cerrada {
  background: var(--color-bg);
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
}

/* ---------- Sprint 8 (extension operativa de porteria) ----------
   Pantalla operativa para Guardia/operador (views/accesos/porteria.php,
   views/accesos/porteria_rechazo.php), mobile-first por naturaleza (este
   flujo solo se muestra a quien no tiene permiso 'control_acceso.editar',
   nunca en el CRUD administrativo de Accesos/Visitantes, que conserva su
   propia presentacion sin tocar). Reutiliza variables/radios/sombras ya
   definidas arriba; no agrega colores nuevos. Sin camara, sin OCR: solo
   busqueda manual por texto (directiva vigente). */

.porteria-menu {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
  margin-top: 4px;
}

.porteria-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 120px;
  padding: 18px 12px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  text-align: center;
  text-decoration: none;
  transition: background 120ms ease, border-color 120ms ease;
}

.porteria-tile:hover,
.porteria-tile:focus-visible {
  background: var(--color-bg);
  border-color: var(--color-teal);
  text-decoration: none;
}

.porteria-tile:active {
  background: var(--color-bg);
}

.porteria-tile-icon {
  font-size: 34px;
  line-height: 1;
}

.porteria-tile-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--color-heading);
}

/* ---------- Puntos de una ronda en ejecucion ----------
   CORRECCION DE DENSIDAD (8-9-2026). Antes cada punto era un
   .porteria-tile dentro de .porteria-menu: una rejilla de dos columnas
   de 150px, pensada para tarjetas de un icono y una linea. Dentro de
   ella se metian nombre, estado, observacion, el desplegable de foto y
   dos botones, asi que en un telefono el nombre se partia en tres
   lineas, "Registrar" y "Omitir" se tocaban, y como .porteria-tile
   centra el texto ningun punto quedaba alineado con el siguiente.

   Ahora es una LISTA de una sola columna. Misma superficie, mismo
   borde, mismo radio y mismos badges del resto de la aplicacion -no se
   inventa un lenguaje visual nuevo-, pero con el espacio repartido en
   tres zonas que respiran: cabecera, observacion y acciones.

   Sin QR, sin GPS y sin hardware, como siempre; "Adjuntar foto" se
   conserva, porque Rondas SI usa evidencia fotografica. */
.ronda-puntos {
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.ronda-punto {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

/* Un punto ya marcado sigue visible y legible, solo deja de competir
   por la atencion con los que faltan. */
.ronda-punto--marcado {
  background: var(--color-bg);
}

.ronda-punto-cabecera {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.ronda-punto-icono {
  font-size: 20px;
  line-height: 0;
  color: var(--color-teal);
  flex: 0 0 auto;
}

.ronda-punto-icono svg {
  width: 1em;
  height: 1em;
  display: inline-block;
}

/* El nombre ocupa el ancho que sobra y empuja el badge al extremo, en
   vez de partirse en tres lineas dentro de media columna. */
.ronda-punto-nombre {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--color-heading);
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.ronda-punto-cabecera .badge {
  flex: 0 0 auto;
}

.ronda-punto-observacion {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--color-text-muted);
  /* Alineada con el nombre del punto (icono 20px + 10px de hueco), no
     con el borde de la tarjeta: la observacion pertenece al punto. */
  padding-left: 30px;
  overflow-wrap: anywhere;
}

.ronda-punto-form {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Distancia en vivo al punto (solo informativa, calculada en el
   navegador): mismos colores que badge-activo/badge-cancelado, sin
   introducir tonos nuevos. */
.ronda-punto-distancia {
  margin: 0 0 4px;
}

.ronda-punto-distancia--dentro {
  color: var(--color-success);
}

.ronda-punto-distancia--fuera {
  color: var(--color-danger);
}

/* "Adjuntar foto" pliega su contenido completo ARRIBA de los botones,
   nunca a su lado: comprimirlo en la misma fila era lo que hacia chocar
   Registrar con Omitir. */
.ronda-evidencia-toggle {
  margin: 0;
}

.ronda-evidencia-toggle .file-input {
  margin-top: 8px;
}

.ronda-evidencia-toggle .form-hint {
  margin: 6px 0 0;
}

.ronda-punto-acciones {
  display: flex;
  gap: 10px;
  width: 100%;
}

/* Area tactil comoda: se usa de pie, a veces con guantes. Los dos
   botones reparten el ancho en partes iguales y nunca se solapan. */
.ronda-punto-acciones button {
  flex: 1 1 0;
  min-width: 0;
  min-height: 44px;
}

/* En telefonos estrechos los dos botones pasan a apilarse antes que
   estrecharse hasta cortar su texto. */
@media (max-width: 360px) {
  .ronda-punto-acciones {
    flex-direction: column;
  }
}

.porteria-search .form-group {
  margin-bottom: 14px;
}

.porteria-search input[type="text"] {
  font-size: 16px;
}

.porteria-confirmacion {
  margin-bottom: 18px;
}

.porteria-confirmacion-nombre {
  margin: 0 0 2px;
  font-size: 20px;
  font-weight: 700;
  color: var(--color-heading);
}

.porteria-confirmacion-documento {
  margin: 0 0 12px;
  font-size: 13px;
  color: var(--color-text-muted);
  letter-spacing: 0.3px;
}

.porteria-confirmacion-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 10px;
}

.porteria-confirmacion-acciones {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 18px;
}

.porteria-confirmacion-acciones form {
  margin: 0;
}

.porteria-confirmacion-acciones .btn-secondary {
  width: 100%;
}

/* Mismo tratamiento visual que .filters-secondary/.form-group-details
   (definidos arriba): se declara aparte, sin tocar esos selectores, para
   no alterar Turnos ni ningun otro modulo cerrado. */
.porteria-mas-info {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  margin-top: 14px;
}

.porteria-mas-info summary {
  list-style: none;
  cursor: pointer;
  padding: 9px 12px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--color-heading);
  display: flex;
  align-items: center;
  gap: 6px;
}

.porteria-mas-info summary::-webkit-details-marker {
  display: none;
}

.porteria-mas-info summary::before {
  /* Revision de interfaz: triangulo CSS puro (borde) en vez del
     caracter Unicode "\25B8". */
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  border-left: 5px solid var(--color-teal);
  transition: transform 180ms ease;
}

.porteria-mas-info[open] summary::before {
  transform: rotate(90deg);
}

.porteria-mas-info summary:hover {
  background: var(--color-bg);
}

.porteria-mas-info .form-hint {
  padding: 0 12px 12px;
  margin-top: 0;
}

/* Campo de evidencia opcional dentro de "Mas informacion" (Rondas: ver
   views/rondas/ver.php) -- mismo contenedor .porteria-mas-info, solo se
   agrega el margen lateral que .form-hint ya tenia como padding, para
   que el input no quede pegado a los bordes del panel desplegable. */
.porteria-mas-info input[type="file"] {
  margin: 0 12px 12px;
  width: calc(100% - 24px);
}

/* ---------- Escaner de documento/patente (Fase 4, assets/js/scanner.js) ----------
   El input real de tipo file (que abre la camara en el celular via el
   atributo capture, ya puesto en el HTML) queda oculto: el boton visible
   es el <button data-scan-modo> que lo activa por script. Mismo criterio
   de "boton con texto + icono real" que el resto del proyecto -nunca un
   input file nativo sin estilizar a la vista-. */
.scanner-input-oculto {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

[data-scan-modo] {
  width: 100%;
  margin-top: 10px;
}

/* Los 2 botones de carnet ("Escanear carnet" + alternativa nativa
   "Tomar foto del documento" para iPhone) van uno junto al otro en
   pantallas con espacio, apilados en movil angosto -- ninguno de los 2
   pierde su margin-top de arriba en la fila. */
.scanner-botones-carnet {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-top: 10px;
}

.scanner-botones-carnet [data-scan-modo] {
  margin-top: 0;
}

@media (max-width: 480px) {
  .scanner-botones-carnet {
    grid-template-columns: 1fr;
  }
}

/* Rediseño Inicio del Guardia: cuando el Guardia toco "Escanear
   persona/vehiculo" desde el Inicio (en vez de "Registro manual"), el
   boton de escaneo llega resaltado a esta pantalla -- pura
   presentacion (borde de color), la opcion manual sigue ahi y sigue
   funcionando igual. */
.scanner-boton-enfatizado,
.scanner-botones-carnet--enfatizado [data-scan-modo] {
  border-color: var(--color-teal);
  box-shadow: 0 0 0 3px rgba(23, 169, 196, 0.14);
}

.scanner-estado {
  margin-top: 8px;
}

.scanner-estado-error {
  color: var(--color-danger);
}

.scanner-estado-ok {
  color: var(--color-success);
}

.scanner-boton-reverso {
  width: 100%;
  margin-top: 8px;
}

/* #scan-nombres-apellidos (views/accesos/porteria.php) usa class=
   "form-grid" (display:grid) Y el atributo HTML "hidden" a la vez: sin
   esta regla, .form-grid le gana en especificidad al [hidden] de la
   hoja de estilos del navegador y el bloque queda visible desde el
   primer render, antes de cualquier escaneo -bug real encontrado en la
   validacion visual de este rediseño, no solo teorico-. */
#scan-nombres-apellidos[hidden] {
  display: none;
}

/* Overlay de captura guiada (Rediseño Guardia: escaner con camara en
   vivo, marco-guia y captura automatica por estabilidad). Cubre toda la
   pantalla, por encima de cualquier otro elemento (nav inferior incluido
   -el z-index mas alto usado en el resto de la hoja es 40-). Fondo casi
   opaco: el video en vivo es lo unico realmente visible. */
.scanner-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: #000;
  overflow: hidden;
}

.scanner-overlay-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Marco-guia: proporcion de tarjeta (~1.586:1) para carnet, rectangulo
   mas ancho para patente. Solo referencia visual -la captura toma el
   frame completo, no recorta al marco-. */
.scanner-overlay-marco {
  position: relative;
  z-index: 1;
  border: 3px solid rgba(255, 255, 255, 0.9);
  border-radius: 14px;
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.45);
  pointer-events: none;
}

.scanner-overlay-marco--carnet {
  width: min(86vw, 420px);
  aspect-ratio: 1.586 / 1;
}

.scanner-overlay-marco--patente {
  width: min(78vw, 360px);
  aspect-ratio: 2.4 / 1;
}

.scanner-overlay-instruccion {
  position: relative;
  z-index: 1;
  margin: 18px 24px 0;
  padding: 10px 16px;
  max-width: 420px;
  text-align: center;
  color: #fff;
  background: rgba(0, 0, 0, 0.55);
  border-radius: 10px;
  font-size: 14px;
}

.scanner-overlay-acciones {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: min(90vw, 360px);
  margin-top: 22px;
  margin-bottom: max(22px, env(safe-area-inset-bottom));
}

.scanner-overlay-cancelar {
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.4);
}

.scanner-overlay-cancelar:hover,
.scanner-overlay-cancelar:focus-visible {
  background: rgba(255, 255, 255, 0.2);
}

/* Cierre pequeño y discreto (X) del overlay de captura de evidencia de
   Rondas (views/rondas/ver.php): reemplaza un boton grande "Cancelar"
   -un solo boton principal en pantalla, "Capturar"-. Mismo z-index/
   posicionamiento relativo que el resto del overlay. */
.scanner-overlay-cerrar {
  position: absolute;
  top: max(14px, env(safe-area-inset-top, 0px));
  right: 14px;
  z-index: 2;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

.scanner-overlay-cerrar:hover,
.scanner-overlay-cerrar:focus-visible {
  background: rgba(0, 0, 0, 0.65);
}

/* Overlay de captura de evidencia de Rondas (views/rondas/ver.php):
   ajustes propios, ENCIMA de las reglas compartidas .scanner-overlay-*
   de arriba (mismo z-index/estructura, solo se agregan estas clases
   extra) -- no se modifico ninguna regla compartida con el escaner de
   OCR/scanner.js, asi que ese flujo queda exactamente igual.
   El boton "Capturar" baja a la parte inferior del visor (respetando
   el area segura del telefono) y la instruccion sube arriba, dejando
   el centro de la camara limpio para encuadrar. */
.ronda-evidencia-overlay-instruccion {
  margin-top: max(14px, env(safe-area-inset-top, 0px));
  font-size: 13px;
}

/* Corrección real (séptima sesión, prueba móvil real): margin-top:auto
   dependia de que el contenedor flex .scanner-overlay calculara bien
   toda la altura del viewport, y en Safari/iOS con la barra de
   direccion dinamica eso no era confiable -el boton no quedaba fijo
   abajo-. Con position:absolute + bottom:0, anclado directo al
   propio overlay (position:fixed, inset:0), la posicion final NO
   depende del calculo de alto del flex ni de cuanto mida la
   instruccion o el resto del contenido: siempre es la parte inferior
   real del visor, respetando el area segura del telefono. */
.ronda-evidencia-overlay-acciones {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0 auto max(22px, env(safe-area-inset-bottom));
}

/* ---------- Modulo Roles y Permisos: marca de accion sensible ----------
   Unica regla visual nueva del modulo. Todo lo demas reutiliza
   componentes que ya existen (.card, .form-section, .checkbox-list,
   .checkbox-item, .data-table, .alert, .badge), para no abrir un
   sistema visual paralelo.
   Los colores salen de las variables del tema, asi que funciona igual en
   modo dia y en modo noche sin escribir la regla dos veces. */

.badge-sensible {
  background: var(--color-danger-bg);
  color: var(--color-danger);
  border: 1px solid rgba(192, 57, 43, 0.25);
}

/* ==========================================================================
   Control de tema (panel "Mas")
   ==========================================================================
   Tres opciones en fila. Se apoya en radios nativos ocultos visualmente
   pero NO removidos del arbol de accesibilidad (no se usa display:none,
   que los sacaria del orden de tabulacion): el foco del teclado se pinta
   sobre .tema-opcion-cara con :focus-visible.
   Todos los colores salen de las variables del tema, asi que el propio
   control se ve bien en los dos modos sin escribir la regla dos veces. */

.tema-selector {
  display: flex;
  gap: 8px;
  padding: 4px 0 10px;
}

.tema-opcion {
  flex: 1;
  cursor: pointer;
}

.tema-opcion input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* OJO con los colores de aca abajo: el panel "Mas" es cromo NAVY fijo en
   los dos temas (ver .app-nav-group-label, que pinta sus titulos con
   rgba blanco). Por eso este control NO usa --color-surface ni
   --color-text-muted -en modo dia serian una tarjeta blanca y un gris
   oscuro sobre fondo navy, ilegibles-, sino blancos con alfa y
   --color-teal-chrome, que es justamente el acento fijo para cromo. */
.tema-opcion-cara {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  min-height: 62px;
  padding: 8px 4px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.72);
  transition: border-color 160ms ease, color 160ms ease, background 160ms ease;
}

.tema-opcion-icono {
  display: block;
  width: 20px;
  height: 20px;
}

.tema-opcion-icono svg {
  width: 100%;
  height: 100%;
}

.tema-opcion-texto {
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: 0.2px;
}

/* Estado elegido. El borde es de 1px igual que en reposo -y no 2px- para
   que la tarjeta no cambie de tamano al marcarse y el trio no "salte". */
.tema-opcion input:checked + .tema-opcion-cara {
  border-color: var(--color-teal-chrome);
  color: var(--color-teal-chrome);
  background: rgba(56, 189, 248, 0.14);
}

.tema-opcion input:focus-visible + .tema-opcion-cara {
  outline: 2px solid var(--color-teal-chrome);
  outline-offset: 2px;
}

/* ==========================================================================
   Inicio del Guardia (concepto A, paso 1 "Turno activo")
   ==========================================================================
   Una accion domina; dos la acompanan. Las proporciones salen de la
   maqueta: el boton principal ocupa alto de bloque con icono grande,
   titulo y subtitulo; los dos secundarios son la mitad de ancho y
   bastante mas bajos. */

.guardia-inicio {
  padding: 4px 0 8px;
}

.guardia-turno {
  margin: 0;
  font-size: 12.5px;
  color: var(--color-text-muted);
}

.guardia-quien {
  margin: 2px 0 0;
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 650;
  letter-spacing: -0.01em;
  color: var(--color-heading);
}

/* La instalacion en color de acento, como en la maqueta. Va con
   --color-teal-text y no --color-teal porque es texto de tamano normal
   sobre superficie clara (13px): 5.93:1 contra 4.09:1. */
.guardia-puesto {
  margin: 1px 0 18px;
  font-size: 13px;
  font-weight: 550;
  color: var(--color-teal-text);
}

/* ---- Accion dominante ----
   El degradado y el color de texto vienen de --grad-escanear /
   --color-escanear-texto, que cambian con el tema. Ver el comentario de
   esas variables arriba: en modo dia se profundiza respecto de la
   maqueta para no bajar de 4.5:1 al sol. */
.guardia-accion-principal {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 132px;
  padding: 22px 16px;
  border-radius: var(--radius-lg);
  background: var(--grad-escanear);
  color: var(--color-escanear-texto);
  text-align: center;
  text-decoration: none;
  box-shadow: var(--shadow);
}

.guardia-accion-principal:hover,
.guardia-accion-principal:active {
  text-decoration: none;
  color: var(--color-escanear-texto);
  filter: brightness(1.04);
}

.guardia-accion-principal-icon {
  display: block;
  width: 38px;
  height: 38px;
  margin-bottom: 6px;
}

.guardia-accion-principal-icon svg {
  width: 100%;
  height: 100%;
}

.guardia-accion-principal-titulo {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* opacity .78 sobre el degradado deja el subtitulo en 5.4:1 en el punto
   mas claro del modo dia; se mantiene por encima del minimo de texto
   normal en los dos temas. */
.guardia-accion-principal-sub {
  font-size: 12px;
  font-weight: 550;
  opacity: 0.78;
}

/* ---- Dos acciones secundarias ---- */

.guardia-acciones-secundarias {
  display: flex;
  gap: 10px;
  margin-top: 10px;
}

.guardia-accion-sec {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 78px;
  padding: 14px 8px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  color: var(--color-text);
  text-decoration: none;
  transition: border-color 160ms ease;
}

.guardia-accion-sec:hover,
.guardia-accion-sec:active {
  border-color: var(--color-teal);
  text-decoration: none;
  color: var(--color-text);
}

.guardia-accion-sec-icon {
  display: block;
  width: 24px;
  height: 24px;
  color: var(--color-teal);
}

.guardia-accion-sec-icon svg {
  width: 100%;
  height: 100%;
}

.guardia-accion-sec-texto {
  font-size: 12.5px;
  font-weight: 600;
}

/* Pantallas anchas: la maqueta es de telefono, pero el guardia puede
   abrir la app en una tablet de porteria. Se limita el ancho para que el
   boton no se vuelva una franja gigante. */
@media (min-width: 641px) {
  .guardia-inicio {
    max-width: 460px;
  }
}

/* ==========================================================================
   Campo leido del documento (concepto A, paso 3 "Confirma el destino")
   ==========================================================================
   Lo que salio del carnet se muestra relleno y etiquetado, para que el
   guardia distinga de un vistazo lo que ya esta resuelto de lo que
   todavia tiene que completar. La etiqueta la pone assets/js/scanner.js
   al aplicar una lectura correcta. */

.form-group.campo-leido {
  position: relative;
}

.campo-leido-tag {
  position: absolute;
  top: 0;
  right: 0;
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--color-teal-deep);
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.6px;
  line-height: 1.6;
}

/* Borde de acento en el propio campo: refuerza la etiqueta sin depender
   solo del color (quien no distinga el azul igual ve el texto LEIDO). */
.form-group.campo-leido input {
  border-color: var(--color-teal);
}

/* ==========================================================================
   LENGUAJE VISUAL DE LA MAQUETA, COMPARTIDO POR LOS CUATRO ROLES
   ==========================================================================
   Referencia literal: ENTREGABLES/Centinela360_Concepto_Completo.html.
   Este bloque traduce las cinco primitivas de esa maqueta al sistema de
   tokens de la app -- no introduce una paleta paralela ni un juego de
   estilos por rol:

     .greet/.who/.post  ->  .pantalla-contexto*
     .kpis/.kpi/.kpi.al ->  .pantalla-resumen* (+ modificador --alerta)
     .sec               ->  .pantalla-sec
     .row + .lft        ->  .pantalla-fila-estado*
     .pill ok/wa/no     ->  .pantalla-pill--ok / --wa / --no

   Los colores de la maqueta se sustituyen por los tokens equivalentes de
   la app (--color-teal-text, --color-warning, --color-danger), que ya
   estan verificados a 4.5:1 en los dos temas. La maqueta usa #fbbf24 y
   #f87171 crudos, que en modo dia no llegan al minimo sobre fondo claro.

   ---- Cabecera de tres lineas: rol -> sujeto -> perimetro ---- */

.pantalla-contexto {
  margin: 0 0 17px;
}

.pantalla-contexto-rol {
  font-size: 12px;
  color: var(--color-text-muted);
  margin: 0 0 2px;
}

.pantalla-contexto-quien {
  font-family: var(--font-display);
  font-size: 21px;
  font-weight: 650;
  letter-spacing: -0.01em;
  color: var(--color-heading);
  margin: 0;
  line-height: 1.2;
}

/* Perimetro (instalaciones que cubre, empresas de la plataforma) en el
   color de acento, igual que la instalacion del guardia: es el dato que
   dice "esto es lo tuyo". */
.pantalla-contexto-perimetro {
  font-size: 12px;
  color: var(--color-teal-text);
  margin: 2px 0 0;
  line-height: 1.35;
}

/* ---- Tres indicadores (.kpis de la maqueta) ----
   Antes eran tres celdas de una rejilla con divisores, etiqueta arriba y
   numero abajo. La maqueta los dibuja como tres cajas separadas con el
   NUMERO primero y el rotulo en mayusculas debajo: el numero es lo que
   se lee de un vistazo. Estas reglas van despues de las originales a
   proposito y las sustituyen sin borrarlas, para no romper ninguna otra
   pantalla que consuma las mismas clases. */

.pantalla-resumen {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 7px;
  border-top: none;
  margin-bottom: 14px;
}

.pantalla-resumen-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 7px;
  text-align: center;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 10px;
}

.pantalla-resumen-num {
  font-family: var(--font-mono-sys);
  font-variant-numeric: tabular-nums;
  font-size: 21px;
  font-weight: 650;
  line-height: 1.15;
  color: var(--color-teal-text);
}

.pantalla-resumen-lbl {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* .kpi.al de la maqueta: el indicador que señala el problema. El borde
   ambar acompaña al color del numero para que la alerta no dependa solo
   del tono del texto. */
.pantalla-resumen-item--alerta {
  border-color: var(--color-warning);
  background: var(--color-warning-bg);
}

.pantalla-resumen-item--alerta .pantalla-resumen-num {
  color: var(--color-warning);
}

/* ---- Rotulo de seccion (.sec de la maqueta) ----
   Sustituye a .pantalla-seccion-titulo (icono + <h2>) en el Inicio: una
   linea de 9 px en mayusculas pesa mucho menos y deja el contenido como
   protagonista. .pantalla-seccion-titulo se conserva intacto porque lo
   usan otras pantallas. */
.pantalla-sec {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin: 16px 0 7px;
}

/* ---- Filas planas con pildora de estado (.row de la maqueta) ----
   Reemplazan a las tarjetas .asignacion-card en el Inicio: la misma
   informacion en la mitad del alto, que es lo que permite ver cuatro o
   cinco instalaciones sin desplazar. */
.pantalla-atencion {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.pantalla-fila-estado {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 11px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 9px;
  color: var(--color-text);
  text-decoration: none;
  /* Area tactil: se usa de pie y a veces con guantes. */
  min-height: 46px;
}

a.pantalla-fila-estado:hover,
a.pantalla-fila-estado:active {
  border-color: var(--color-teal);
  text-decoration: none;
  color: var(--color-text);
}

.pantalla-fila-estado-texto {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.pantalla-fila-estado-titulo {
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.3;
}

.pantalla-fila-estado-desc {
  font-size: 10.5px;
  color: var(--color-text-muted);
  line-height: 1.35;
}

.pantalla-pill {
  flex: 0 0 auto;
  font-size: 9.5px;
  font-weight: 650;
  letter-spacing: 0.03em;
  padding: 3px 9px;
  border-radius: 11px;
  white-space: nowrap;
}

.pantalla-pill--ok {
  background: var(--color-success-bg);
  color: var(--color-success);
}

.pantalla-pill--wa {
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

.pantalla-pill--no {
  background: var(--color-danger-bg);
  color: var(--color-danger);
}

.pantalla-atencion-vacio {
  font-size: 12.5px;
  color: var(--color-text-muted);
  margin: 0;
  padding: 11px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 9px;
}

/* ---- Adaptabilidad por rol ----
   Cada rol tiene su prioridad de dispositivo y la conserva:

     Guardia y Supervisor  -> telefono. Una columna siempre; en pantalla
                              ancha se limita el ancho para que la accion
                              principal no se convierta en una franja.
     Administrador         -> telefono Y escritorio.
     Superusuario          -> principalmente escritorio.

   Por eso en >= 900 px las filas de estado y las listas del Inicio pasan
   a dos columnas y los indicadores se ensanchan, en vez de dejar una
   columna estrecha centrada en un monitor. El Inicio del Guardia queda
   fuera de esta regla: su bloque .guardia-inicio ya limita el ancho a
   460 px mas arriba en este mismo archivo. */
@media (min-width: 900px) {
  .pantalla-resumen {
    gap: 12px;
  }

  .pantalla-resumen-num {
    font-size: 26px;
  }

  .pantalla-resumen-lbl {
    font-size: 10px;
  }

  .pantalla-contexto-quien {
    font-size: 26px;
  }

  /* Dos columnas de filas planas: es lo que convierte el listado de
     empresas del Superusuario y el de instalaciones del Administrador en
     una pantalla de escritorio y no en un telefono estirado. */
  .pantalla-atencion {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
  }
}

/* ==========================================================================
   Marco del escaner: cuatro esquinas en L (maqueta, paso 2)
   ==========================================================================
   La maqueta dibuja cuatro angulos de 2,5 px en las esquinas del area de
   encuadre, no un rectangulo cerrado: el borde continuo tapa los bordes
   del documento, que es justo lo que el guardia necesita ver para saber
   si esta encuadrando bien. Los cuatro <i> los inserta
   assets/js/scanner.js. */

.scanner-overlay-marco {
  border: none;
}

.scanner-overlay-esquina {
  position: absolute;
  width: 21px;
  height: 21px;
  border: 2.5px solid var(--color-teal-chrome);
}

.scanner-overlay-esquina:nth-child(1) {
  top: 0;
  left: 0;
  border-right: 0;
  border-bottom: 0;
  border-radius: 5px 0 0 0;
}

.scanner-overlay-esquina:nth-child(2) {
  top: 0;
  right: 0;
  border-left: 0;
  border-bottom: 0;
  border-radius: 0 5px 0 0;
}

.scanner-overlay-esquina:nth-child(3) {
  bottom: 0;
  left: 0;
  border-right: 0;
  border-top: 0;
  border-radius: 0 0 0 5px;
}

.scanner-overlay-esquina:nth-child(4) {
  bottom: 0;
  right: 0;
  border-left: 0;
  border-top: 0;
  border-radius: 0 0 5px 0;
}

/* ==========================================================================
   Porteria en modo escaneo (enfoque=scan) y comprobante final
   ========================================================================== */

/* Sin marco ni sombra: en modo escaneo la pantalla es la accion, no una
   ficha dentro de una pagina. */
.card--escaneo {
  background: transparent;
  border: none;
  box-shadow: none;
  padding-left: 0;
  padding-right: 0;
}

.porteria-search--escaneo {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Boton dominante de escaneo: mismo peso visual que "Escanear documento"
   del Inicio del guardia (mismo degradado profundo aprobado, misma
   altura), para que el paso 1 y el paso 2 se lean como la misma accion. */
.porteria-escanear {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  min-height: 132px;
  padding: 22px 14px;
  border: none;
  border-radius: var(--radius-lg);
  background: var(--grad-escanear);
  color: var(--color-escanear-texto);
  font-family: inherit;
  text-align: center;
  cursor: pointer;
}

.porteria-escanear-icon {
  display: block;
  width: 30px;
  height: 30px;
}

.porteria-escanear-icon svg {
  width: 100%;
  height: 100%;
}

.porteria-escanear-titulo {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.porteria-escanear-sub {
  font-size: 12px;
  font-weight: 550;
  opacity: 0.78;
}

/* Respaldo manual. NO es una funcion retirada: es la misma entrada de
   texto y el mismo boton "Buscar" de siempre, un nivel mas abajo en la
   jerarquia, porque deja de ser lo primero que ve el guardia. Se abre de
   un toque y funciona sin JavaScript (<details> nativo). */
.porteria-respaldo {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 0 13px;
  background: var(--color-surface);
}

.porteria-respaldo > summary {
  padding: 13px 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-teal-text);
  cursor: pointer;
  list-style: none;
}

.porteria-respaldo > summary::-webkit-details-marker {
  display: none;
}

.porteria-respaldo > summary::marker {
  content: '';
}

.porteria-respaldo[open] > summary {
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 13px;
}

.porteria-respaldo > *:last-child {
  margin-bottom: 13px;
}

/* ---- Etiqueta de turno del menu de porteria ----
   Existia en el marcado (views/accesos/porteria.php) sin ninguna regla
   propia. */
.porteria-turno {
  color: var(--color-teal-text);
  font-weight: 600;
}

/* ---- Lista de visitantes frecuentes ----
   Mismo caso: el marcado existia y no tenia estilos, asi que el panel
   "Frecuente" -- ahora enlazado de verdad desde el Inicio -- se veia
   como una lista con viñetas. */
.porteria-lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.porteria-lista-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 56px;
  justify-content: center;
  padding: 10px 12px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 9px;
  color: var(--color-text);
  text-decoration: none;
}

.porteria-lista-item:hover,
.porteria-lista-item:active {
  border-color: var(--color-teal);
  text-decoration: none;
  color: var(--color-text);
}

/* Correccion de privacidad: los items de "Frecuente" pasaron de <a> con
   el RUT en la URL a <button> dentro de un <form method="post">. Estos
   reinicios hacen que el boton se vea EXACTAMENTE igual que el enlace
   que reemplazo -no cambia el diseño aprobado, solo el transporte-. */
button.porteria-lista-item {
  width: 100%;
  text-align: left;
  font: inherit;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.porteria-lista-form {
  margin: 0;
}

.porteria-lista-titulo {
  font-size: 13.5px;
  font-weight: 600;
}

.porteria-lista-detalle {
  font-size: 11px;
  color: var(--color-text-muted);
}

/* ---- Comprobante "Ingreso registrado" (maqueta, paso 4) ----
   El marcado existia desde la integracion de la rama del guardia, pero
   ninguna de estas clases tenia regla: el comprobante se veia como una
   lista de definiciones sin formato dentro de una tarjeta. */
.porteria-listo {
  text-align: center;
  padding: 26px 4px 8px;
  max-width: 420px;
  margin: 0 auto;
}

.porteria-listo-tick {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 62px;
  height: 62px;
  margin: 0 auto 15px;
  border-radius: 50%;
  background: var(--grad-escanear);
  color: var(--color-escanear-texto);
}

.porteria-listo-tick svg {
  width: 30px;
  height: 30px;
  stroke-width: 2.5px;
}

.porteria-listo h1 {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 650;
  color: var(--color-heading);
  margin: 0 0 4px;
}

.porteria-listo-destino {
  font-size: 12.5px;
  color: var(--color-text-muted);
  margin: 0 0 16px;
}

/* Recibo: pares etiqueta/valor alineados a los bordes, como la maqueta
   (.rc/.rw). <dl> real, no una tabla dibujada: cada dato conserva su
   relacion semantica para lectores de pantalla. */
.porteria-listo-recibo {
  text-align: left;
  margin: 0 0 18px;
  padding: 11px 13px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 10px;
}

.porteria-listo-recibo > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 4px 0;
}

.porteria-listo-recibo dt {
  font-size: 11.5px;
  color: var(--color-text-muted);
  margin: 0;
}

.porteria-listo-recibo dd {
  font-size: 11.5px;
  font-weight: 600;
  text-align: right;
  margin: 0;
}

.porteria-listo-acciones {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.porteria-listo-acciones .btn,
.porteria-listo-acciones .btn-secondary {
  width: 100%;
  justify-content: center;
}

.porteria-listo-cuenta {
  font-size: 11.5px;
  color: var(--color-text-muted);
  margin: 12px 0 0;
}

/* Modal de confirmación de lectura OCR */
.scanner-modal-confirmacion {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.5);
  padding: 20px;
  /* CORRECCION (verificar que "Confirmar" complete el registro en
     iPhone): el modal de RUT/Nombres/Apellidos autoenfoca el primer
     campo (confirmarLecturaDirecta -> primerInput.focus()), lo que abre
     el teclado nativo. Safari/iOS -a diferencia de Chrome/Android, que
     sí redimensiona el viewport visual de forma fiable- puede mantener
     un elemento position:fixed centrado por el viewport de LAYOUT
     completo (el que incluye el area que el teclado tapa), dejando el
     boton "Confirmar" fuera del area visible y sin ninguna forma de
     desplazarse hasta el, sin overflow. overflow-y:auto no cambia nada
     cuando el contenido ya cabe (mismo aspecto en Android/desktop), y
     permite alcanzar el boton cuando no cabe. */
  overflow-y: auto;
}

.scanner-modal-titulo {
  font-size: 18px;
  font-weight: 600;
  margin: 0 0 16px;
  text-align: center;
}

.scanner-modal-contenido {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 18px;
  max-width: 100%;
}

.scanner-modal-grupo {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.scanner-modal-grupo label {
  font-size: 13px;
  font-weight: 500;
  color: var(--color-text);
}

.scanner-modal-input {
  padding: 10px 12px;
  font-size: 15px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: inherit;
}

.scanner-modal-input:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: -1px;
}

.scanner-modal-acciones {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
}

.scanner-modal-confirmar,
.scanner-modal-cancelar {
  padding: 11px 16px;
  font-size: 14px;
  border-radius: 6px;
  border: none;
  cursor: pointer;
  font-weight: 500;
}

.scanner-modal-confirmar {
  background: var(--color-primary);
  color: white;
}

.scanner-modal-confirmar:hover {
  opacity: 0.9;
}

.scanner-modal-cancelar {
  background: var(--color-border);
  color: var(--color-text);
}

.scanner-modal-cancelar:hover {
  background: var(--color-border-hover, var(--color-border));
}

/* Modal flotante de estado (mostrarModalProcesando/mostrarModalError en
   scanner.js): reemplaza el viejo <p> insertado despues del boton, que
   quedaba dentro del layout de Inicio y podia comprimir los botones de
   al lado. Reutiliza el mismo overlay .scanner-modal-confirmacion, sin
   introducir un sistema visual nuevo. */
.scanner-modal-procesando-texto,
.scanner-modal-error-texto {
  margin: 0;
  text-align: center;
  font-size: 14px;
  line-height: 1.5;
}

.scanner-modal-error-texto {
  margin-bottom: 4px;
}

.scanner-modal-spinner {
  width: 32px;
  height: 32px;
  margin: 0 auto 14px;
  border: 3px solid var(--color-border);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: scanner-modal-girar 800ms linear infinite;
}

@keyframes scanner-modal-girar {
  to { transform: rotate(360deg); }
}

/* Debug OCR Modal - Diagnóstico visual de captura y OCR */
.debug-ocr-overlay {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  z-index: 9999;
}

.debug-ocr-modal {
  width: 100%;
  max-width: 600px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  border-radius: 12px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
}

.debug-ocr-modal .porteria-modal-header {
  background: #ff9800;
  color: white;
  padding: 16px;
  border-radius: 12px 12px 0 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.debug-ocr-modal .porteria-modal-header h2 {
  margin: 0;
  font-size: 18px;
}

.debug-ocr-modal .porteria-modal-close {
  background: none;
  border: none;
  font-size: 28px;
  color: white;
  cursor: pointer;
  padding: 0;
  line-height: 1;
}

.debug-ocr-modal .porteria-modal-body {
  background: white;
  padding: 16px;
  flex: 1;
  overflow-y: auto;
}

.debug-ocr-modal .debug-frame-preview img {
  max-width: 100%;
  height: auto;
  display: block;
}

.debug-ocr-modal .porteria-modal-footer {
  background: white;
  border-top: 1px solid #e0e0e0;
  padding: 12px 16px;
  display: flex;
  gap: 8px;
  justify-content: center;
  border-radius: 0 0 12px 12px;
  flex-wrap: wrap;
}

.debug-close-btn,
.debug-skip-btn {
  padding: 10px 16px;
  font-size: 14px;
  border-radius: 6px;
  border: none;
  cursor: pointer;
  font-weight: 500;
}

.debug-close-btn {
  background: var(--color-primary);
  color: white;
}

.debug-close-btn:hover {
  opacity: 0.9;
}

.debug-skip-btn {
  background: #f0f0f0;
  color: var(--color-text);
}

.debug-skip-btn:hover {
  background: #e0e0e0;
}

/* Reportes con IA (piloto 1-10). Prosa del resumen: mismo ancho de
   lectura que el resto del proyecto, sin ningun ancho maximo especial. */
.reporte-ia-resumen {
  background: var(--color-surface-alt, var(--color-bg));
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 16px;
  margin: 10px 0;
}

.reporte-ia-resumen p {
  margin: 0 0 10px;
}

.reporte-ia-resumen p:last-child {
  margin-bottom: 0;
}

.reporte-ia-resumen h3 {
  margin: 14px 0 6px;
  font-size: 0.95rem;
}

.reporte-ia-resumen h3:first-child {
  margin-top: 0;
}

.reporte-ia-resumen ul {
  margin: 0 0 10px;
  padding-left: 20px;
}

.reporte-ia-resumen li {
  margin-bottom: 4px;
}

/* ==========================================================================
   Graficas esenciales del Inicio (Supervisor/Administrador/Superusuario)
   ==========================================================================
   Pedido explicito: "graficos simples, accesibles y compatibles con
   cPanel, preferiblemente HTML/CSS/SVG local -- sin npm, Composer, CDN ni
   servicios externos". Dos formas, ambas sin libreria:

     .pantalla-grafica-barras  -> lista de barras horizontales (ancho =
                                   proporcion real vs. el maximo de la
                                   propia lista) para conteos por categoria
                                   (rondas por estado, incidentes por
                                   severidad/instalacion, cobertura).
     .pantalla-grafica-7dias   -> <svg> con barras pareadas por dia
                                   (entradas/salidas), dibujado a mano con
                                   <rect>, sin ninguna libreria de charts.

   Mismos tokens de color de siempre (--color-teal/--color-success/
   --color-warning/--color-danger): ningun tono nuevo, funciona igual en
   los dos temas sin bloques @media adicionales. */
.pantalla-grafica {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 12px 13px 13px;
  margin-bottom: 10px;
}

.pantalla-grafica-titulo {
  font-size: 11.5px;
  font-weight: 650;
  color: var(--color-heading);
  margin: 0 0 2px;
}

.pantalla-grafica-nota {
  font-size: 10.5px;
  color: var(--color-text-muted);
  margin: 0 0 10px;
}

.pantalla-grafica-vacio {
  font-size: 11.5px;
  color: var(--color-text-muted);
  margin: 0;
  padding: 4px 0 2px;
}

.pantalla-grafica-barras {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.pantalla-grafica-fila {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 3px;
}

.pantalla-grafica-fila-cab {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: 11px;
}

.pantalla-grafica-fila-etq {
  color: var(--color-text);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pantalla-grafica-fila-num {
  font-family: var(--font-mono-sys);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
  flex: 0 0 auto;
}

.pantalla-grafica-pista {
  height: 8px;
  border-radius: 5px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  overflow: hidden;
}

.pantalla-grafica-relleno {
  height: 100%;
  border-radius: 5px 0 0 5px;
  background: var(--color-teal);
  min-width: 2px;
}

.pantalla-grafica-relleno--ok { background: var(--color-success); }
.pantalla-grafica-relleno--wa { background: var(--color-warning); }
.pantalla-grafica-relleno--no { background: var(--color-danger); }

/* Cobertura de turnos: barra apilada de 2 segmentos (iniciados/sin
   marcar) en una sola pista, en vez de 2 filas -- el total programado ya
   se dice aparte en texto, la barra solo reparte ese total. */
.pantalla-grafica-pista--apilada {
  display: flex;
  height: 10px;
}

.pantalla-grafica-pista--apilada .pantalla-grafica-relleno {
  border-radius: 0;
}

.pantalla-grafica-pista--apilada .pantalla-grafica-relleno:first-child {
  border-radius: 5px 0 0 5px;
}

.pantalla-grafica-pista--apilada .pantalla-grafica-relleno:last-child {
  border-radius: 0 5px 5px 0;
}

.pantalla-grafica-leyenda {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 8px;
  font-size: 10.5px;
  color: var(--color-text-muted);
}

.pantalla-grafica-leyenda-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.pantalla-grafica-leyenda-punto {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: 0 0 auto;
}

/* Grafica de 7 dias (entradas/salidas): SVG dibujado a mano, viewBox fijo
   en unidades propias para que el navegador lo escale sin JS -- se ve
   completo a 412px y tambien en escritorio, sin scroll horizontal. */
.pantalla-grafica-svg-wrap {
  width: 100%;
  overflow: visible;
}

.pantalla-grafica-svg-wrap svg {
  width: 100%;
  height: auto;
  display: block;
}

.pantalla-grafica-svg-barra-entrada { fill: var(--color-teal); }
.pantalla-grafica-svg-barra-salida { fill: var(--color-text-muted); opacity: 0.55; }

.pantalla-grafica-svg-eje {
  stroke: var(--color-border);
  stroke-width: 1;
}

.pantalla-grafica-svg-etq {
  fill: var(--color-text-muted);
  font-size: 7px;
  font-family: var(--font-mono-sys, monospace);
}

.pantalla-grafica-svg-num {
  fill: var(--color-heading);
  font-size: 6.5px;
  font-weight: 650;
  font-family: var(--font-mono-sys, monospace);
  text-anchor: middle;
}

@media (min-width: 900px) {
  .pantalla-graficas-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
  }

  .pantalla-graficas-grid .pantalla-grafica {
    margin-bottom: 0;
  }
}
