/* ===========================================================================
   Identidad visual de Agropecuaria Santamaria (Byron 2026-08-25)
   ---------------------------------------------------------------------------
   La paleta y la tipografia salen literales de la hoja de la web corporativa
   (`context/diseno_agroweb/css/styles.css`), no de valores inventados aqui:
   si manana cambia la web, este bloque es lo unico que hay que sincronizar.

   Montserrat es la UNICA familia de la marca -- el acento se consigue con
   peso e italica, no con una segunda fuente. Se sirve desde /static (no desde
   Google Fonts): TrackIT se usa en la finca, con senal irregular y a veces sin
   salida a internet, y una fuente que no carga deja la app con otra cara.
   =========================================================================== */
@font-face {
  font-family: 'Montserrat';
  src: url('fonts/Montserrat-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('fonts/Montserrat-Italic.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('fonts/Montserrat-Medium.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('fonts/Montserrat-SemiBold.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('fonts/Montserrat-Bold.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('fonts/Montserrat-ExtraBold.woff2') format('woff2');
  font-weight: 800; font-style: normal; font-display: swap;
}

:root {
  /* --- Paleta de marca, tal cual la define la web corporativa ------------ */
  --green-900: #0F2712;  /* Verde mas profundo (fondos de barra/overlay) */
  --green-800: #143318;  /* Verde selva (heroe, titulos) */
  --green-700: #1B4220;
  --green-600: #245126;  /* Verde palma -- EL verde de la marca */
  --green-500: #2E6431;
  --green-300: #7FA886;
  --amber:     #F89A28;  /* Naranja corporativo (acento/atencion) */
  --amber-600: #E5891B;
  --gold:      #FBB24E;  /* Tinte claro del naranja (texto sobre verde) */
  --earth-600: #653512;
  --ivory:     #FAF6EF;  /* Marfil -- el fondo de la marca, no un gris */
  --ivory-2:   #F1EBDD;
  --line:      #E4DCCB;
  --ink:       #17251A;
  --ink-soft:  #4B5A4F;

  /* Ambar legible sobre blanco: el --amber corporativo es un naranja claro y
     como TEXTO no llega al contraste minimo (queda en ~2.4:1). Este es el
     mismo tono llevado a la luminosidad que si se lee; el --amber se reserva
     para bordes y rellenos, donde el contraste de texto no aplica. */
  --ambar-texto: #8A5410;

  /* --- Los nombres que ya usaba TrackIT, apuntando ahora a la marca ------
     El CSS de la app usa estos 6 nombres en ~150 sitios: repuntarlos aqui es
     lo que propaga la paleta nueva a toda la aplicacion de una sola vez. */
  --verde: var(--green-600);
  --verde-oscuro: var(--green-800);
  --gris-fondo: var(--ivory);
  --gris-borde: var(--line);
  --texto: var(--ink);
  --texto-suave: var(--ink-soft);
  /* El rojo de error se queda: es senalizacion, no marca, y la web
     corporativa no define ninguno. */
  --rojo-error: #b3261e;
  --vinotinto: #7A1F2E;  /* Acta anulada: resaltada sin confundirse con error */

  --transicion: 150ms ease;
  --ease: cubic-bezier(.22, .61, .36, 1);

  /* Sombras: se conserva la FORMA aprobada en el mockup de 2026-08-18 (la
     que ya estaba calibrada para tarjetas de esta app) y solo se retinta al
     verde nuevo -- antes tiraban al 31,92,46 del verde viejo. */
  --sombra-tarjeta: 0 4px 16px -6px rgba(15, 39, 18, 0.22), 0 1px 3px rgba(15, 39, 18, 0.08);
  --sombra-tarjeta-hover: 0 10px 26px -8px rgba(15, 39, 18, 0.30), 0 2px 6px rgba(15, 39, 18, 0.10);
  --anillo-foco-input: 0 0 0 3px rgba(36, 81, 38, 0.18);
  --anillo-foco-boton: 0 0 0 3px rgba(36, 81, 38, 0.28);
}

* { box-sizing: border-box; }

/* Enlaces de contenido -- los de dentro de una tabla o de un parrafo, que no
   llevan clase propia. Se quedaban en el azul por defecto del navegador, el
   unico color de la aplicacion que no venia de la marca: en el listado de
   usuarios, tres nombres en azul electrico sobre marfil se llevaban la vista
   por delante de todo lo demas (visto en la captura de Byron, 2026-08-25).
   La regla va sin clase (especificidad 0,0,1), asi que cualquier componente
   que ya fije su propio color -- la barra, los chips, los botones -- le gana
   sin necesidad de tocar nada. El subrayado se QUEDA: dentro de una tabla es
   lo que distingue un nombre que se puede abrir de uno que no. */
a { color: var(--verde); }
a:hover { color: var(--amber-600); }

body {
  margin: 0;
  font-family: 'Montserrat', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--gris-fondo);
  color: var(--texto);
  -webkit-font-smoothing: antialiased;
}

.topbar {
  /* El mismo degradado que la cabecera de la web corporativa: verde selva a
     verde profundo, con un halo de verde palma arriba a la derecha. Es lo que
     distingue la barra de un rectangulo de color plano. */
  background:
    radial-gradient(120% 200% at 85% 0%, var(--green-600) 0%, transparent 60%),
    linear-gradient(180deg, var(--green-800), var(--green-900));
  color: #fff;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.75rem 1.25rem;
  flex-wrap: wrap;
  gap: 0.5rem;
  /* Siempre visible al desplazar (Byron 2026-08-25): en una tabla de actas
     larga, tener que subir hasta arriba para cambiar de seccion o para salir
     es el tipo de friccion que se paga en cada uso. */
  position: sticky;
  top: 0;
  z-index: 100;
  /* La sombra despega la barra del contenido que pasa por debajo: sin ella,
     al desplazar, las filas de la tabla parecen "chocar" contra el verde. */
  box-shadow: 0 8px 30px -12px rgba(0, 0, 0, 0.5);
}

.topbar-brand {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  font-size: 1.05rem;
  color: #fff;
  text-decoration: none;
}
.topbar-brand svg { flex-shrink: 0; }
/* Emblema de la marca (palma + engranaje). Va el emblema SOLO, no el logo
   horizontal completo: a la altura de una barra el texto del logo no se lee. */
.topbar-emblema { height: 34px; width: auto; display: block; flex-shrink: 0; }
.topbar-titulo { line-height: 1.15; }
.topbar-titulo b { font-weight: 700; display: block; }
/* "Palma" en ambar claro y espaciado: es lo que ata la barra al naranja
   corporativo sin meter un boton naranja en cada pantalla. */
.topbar-titulo .topbar-sub {
  display: block;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
}

.topbar-nav {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  flex: 1;
  margin-left: 1.5rem;
}
/* El subrayado ambar que crece de izquierda a derecha es el gesto propio de
   la web corporativa; sustituye al borde blanco que aparecia de golpe. */
.topbar-nav a {
  color: rgba(255, 255, 255, 0.86);
  text-decoration: none;
  font-size: 0.92rem;
  font-weight: 500;
  padding: 0.35rem 0;
  position: relative;
  transition: color 0.2s var(--ease);
}
.topbar-nav a::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  height: 2px; width: 0;
  background: var(--amber);
  transition: width 0.28s var(--ease);
}
.topbar-nav a:hover { color: #fff; }
.topbar-nav a:hover::after { width: 100%; }
.topbar-nav a:focus-visible { outline: 2px solid #fff; outline-offset: 2px; border-radius: 2px; }

/* ===========================================================================
   Los dos menus de la barra (Byron 2026-08-25)
   ---------------------------------------------------------------------------
   HAMBURGUESA -> navegacion principal, SOLO en movil. Se toma tal cual de la
   web corporativa: tres barras de 26x2.5px que giran hasta formar una X, con
   el mismo corte de 720px que usa el sitio.
   TRES PUNTOS -> acciones de cuenta, en PC Y en movil. No se esconde en PC a
   proposito: son las mismas dos acciones en los dos tamanos y se buscan en el
   mismo sitio.
   =========================================================================== */
.nav-toggle {
  display: none;   /* El @media de movil es el unico que lo enciende. */
  flex-direction: column;
  gap: 5px;
  background: none;
  border: 0;
  padding: 0.4rem;
  cursor: pointer;
  flex-shrink: 0;
}
.nav-toggle span {
  display: block;
  width: 26px;
  height: 2.5px;
  background: #fff;
  border-radius: 2px;
  transition: transform 0.3s var(--ease), opacity 0.3s var(--ease);
}
/* Las tres barras se convierten en X: la de arriba baja y gira, la de en medio
   se desvanece, la de abajo sube y gira al reves. */
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7.5px) rotate(-45deg); }
.nav-toggle:focus-visible { outline: 2px solid #fff; outline-offset: 2px; border-radius: 6px; }

.menu-cuenta { position: relative; flex-shrink: 0; }

/* Tres puntos HORIZONTALES. El area tactil es de 36px aunque el icono mida
   20: en un telefono en campo, un boton de 20px se falla. */
.btn-puntos {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.10);
  color: #fff;
  cursor: pointer;
  transition: background var(--transicion);
}
.btn-puntos:hover { background: rgba(255, 255, 255, 0.22); }
.btn-puntos[aria-expanded="true"] { background: rgba(255, 255, 255, 0.26); }
.btn-puntos:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

.menu-desplegable[hidden] { display: none; }
.menu-desplegable {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 120;
  min-width: 12rem;
  padding: 0.4rem;
  background: #fff;
  border: 1px solid var(--gris-borde);
  border-radius: var(--radius-sm, 12px);
  box-shadow: 0 18px 40px -16px rgba(15, 39, 18, 0.45), 0 2px 8px rgba(15, 39, 18, 0.10);
  /* La barra es verde oscuro; dentro del desplegable el fondo es blanco, asi
     que el texto vuelve a los colores normales de la app. */
  color: var(--texto);
  text-align: left;
}
.menu-cabecera {
  margin: 0.15rem 0.35rem 0.4rem;
  padding-bottom: 0.45rem;
  border-bottom: 1px solid var(--gris-borde);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--texto-suave);
  line-height: 1.3;
}
.menu-desplegable form { margin: 0; }

/* Los selectores llevan .topbar delante para ganarle en especificidad al
   verde por defecto de button[type=submit] y al blanco de .topbar .btn-link,
   sin recurrir a !important. */
.topbar .menu-desplegable .item-menu {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 0.55rem 0.7rem;
  border: none;
  border-radius: 8px;
  background: none;
  box-shadow: none;
  color: var(--texto);
  font: inherit;
  font-size: 0.9rem;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--transicion), color var(--transicion);
}
.topbar .menu-desplegable .item-menu:hover {
  background: var(--ivory-2);
  color: var(--verde-oscuro);
  transform: none;
  box-shadow: none;
}
.topbar .menu-desplegable .item-menu:focus-visible {
  outline: 2px solid var(--verde);
  outline-offset: -2px;
  box-shadow: none;
}
/* Salir se separa y se marca: es la unica accion de la que no se vuelve sola,
   y en un dispositivo compartido en campo tiene que encontrarse rapido. */
.topbar .menu-desplegable .item-menu-salir {
  margin-top: 0.2rem;
  border-top: 1px solid var(--gris-borde);
  border-radius: 0 0 8px 8px;
  color: var(--rojo-error);
  font-weight: 600;
}
.topbar .menu-desplegable .item-menu-salir:hover {
  background: #fdecea;
  color: var(--rojo-error);
}

.topbar-user {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.9rem;
}
/* Un nombre largo no debe empujar los tres puntos fuera de la barra: se corta
   con puntos suspensivos y el desplegable lo muestra entero. El tope de 12rem
   no es estetico -- es lo que mantiene el ancho del bloque de usuario acotado,
   y con el la fila cabe en una linea por encima del corte pase quien pase por
   la barra (el nombre mas largo de la BD hoy mide 185px). */
.topbar-nombre {
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.badge {
  background: rgba(248, 154, 40, 0.18);
  border: 1px solid var(--amber);
  color: var(--gold);
  padding: 0.1rem 0.65rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
}

/* "Cambiar rol" y "Salir" ya no van sueltos en la barra: viven dentro del
   desplegable de los tres puntos (.item-menu). Las reglas que los pintaban de
   blanco sobre el verde se retiraron al quedarse sin ningun elemento. */

.inline-form { display: inline; }

.container {
  max-width: 960px;
  margin: 0 auto;
  padding: 1.5rem 1rem;
}
/* Listados de datos (actas, usuarios): mas columnas que un formulario, asi
   que aprovechan el ancho real de la pantalla en vez de los 960px. El tope
   alto es para monitores muy anchos, donde una tabla de borde a borde se
   vuelve incomoda de seguir con la vista. Byron 2026-08-24: en PC no deberia
   aparecer barra de desplazamiento horizontal; en celular es inevitable y
   esta bien. */
.container.ancho { max-width: 2200px; }

.login-card {
  max-width: 360px;
  margin: 3rem auto;
  background: #fff;
  border: 1px solid var(--gris-borde);
  border-radius: 14px;
  padding: 2rem;
  text-align: center;
  box-shadow: var(--sombra-tarjeta);
  transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.login-card:hover {
  box-shadow: var(--sombra-tarjeta-hover);
  transform: translateY(-2px);
}

/* Pantalla de acceso partida (Byron 2026-09-17): foto a la izquierda, acceso a
   la derecha. El login no tiene barra superior, asi que ocupa la ventana
   entera; por eso suelta el ancho y el relleno del .container. Solo afecta a
   login.html (la verificacion 2FA sigue con la tarjeta centrada de siempre). */
.container.login-pantalla { max-width: none; padding: 0; }
.login-split { display: grid; grid-template-columns: 1fr 1fr; min-height: 100vh; min-height: 100dvh; }
.login-foto {
  position: relative;
  background-color: var(--green-800);  /* mientras carga la foto */
  background-size: cover;
  background-position: center;
}
/* Velo verde muy suave de abajo hacia arriba: integra la foto con la paleta y
   deja legible el credito sin tapar el cultivo. */
.login-foto::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(0deg, rgba(15, 39, 18, 0.55) 0%, rgba(15, 39, 18, 0) 35%);
  pointer-events: none;
}
.login-foto-credito {
  position: absolute; left: 1rem; bottom: 0.8rem; z-index: 1;
  font-size: 0.7rem; color: rgba(255, 255, 255, 0.8); text-decoration: none;
}
.login-foto-credito:hover { color: #fff; text-decoration: underline; }
.login-lado {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 2rem 1rem;
}
.login-logo { width: 240px; max-width: 70%; height: auto; display: block; margin-bottom: 1.75rem; }
.login-lado .login-card { width: 100%; margin: 0; }
/* En celular la foto pasa a ser una franja arriba: sigue dando la identidad
   sin empujar el formulario fuera de la pantalla. */
@media (max-width: 720px) {
  .login-split { grid-template-columns: 1fr; grid-template-rows: 160px 1fr; }
  .login-lado { justify-content: flex-start; padding: 1.75rem 1rem 2rem; }
  .login-logo { width: 190px; margin-bottom: 1.25rem; }
}

/* El emblema en la tarjeta de acceso: es la unica pantalla que ve alguien
   que aun no ha entrado, y hasta ahora no llevaba ninguna marca. */
.login-emblema { height: 56px; width: auto; display: block; margin: 0 auto 0.9rem; }
.login-card h1 { color: var(--verde-oscuro); margin-bottom: 0.25rem; font-size: 1.4rem; }
.subtitle { color: var(--texto-suave); margin-top: 0; margin-bottom: 1.5rem; font-size: 0.9rem; }

.login-card form { display: flex; flex-direction: column; gap: 0.75rem; text-align: left; }
.login-card label { font-size: 0.85rem; color: var(--texto-suave); }
.login-card input {
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--gris-borde);
  border-radius: 8px;
  font-size: 1rem;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.login-card input:focus-visible {
  border-color: var(--verde);
  box-shadow: var(--anillo-foco-input);
  outline: none;
}
.login-card button {
  margin-top: 0.5rem;
  padding: 0.7rem;
  background: var(--verde);
  color: #fff;
  border: none;
  border-radius: 8px;
  font-size: 1rem;
  cursor: pointer;
  box-shadow: 0 2px 8px -2px rgba(36, 81, 38, 0.45);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.login-card button:hover {
  background: var(--verde-oscuro);
  transform: translateY(-1px);
  box-shadow: 0 6px 16px -3px rgba(36, 81, 38, 0.5);
}
.login-card button:focus-visible {
  outline: none;
  box-shadow: var(--anillo-foco-boton);
}

.error {
  background: #fdecea;
  color: var(--rojo-error);
  padding: 0.6rem 0.8rem;
  border-radius: 8px;
  font-size: 0.9rem;
}

.muted { color: var(--texto-suave); font-size: 0.9rem; }

/* --- Campos de contrasena: ojito + error en linea (Byron 2026-08-24) -------
   En celular el usuario no tenia forma de ver lo que estaba escribiendo, y el
   "no coinciden" solo aparecia despues de enviar el formulario. El boton se
   apoya sobre el input (position:absolute) en vez de ir al lado, para no
   romper el ancho del campo en pantallas angostas; el padding-right reserva
   su espacio para que el texto no quede debajo del icono. */
.campo-password {
  position: relative;
  display: block;
  /* Mismo max-width que el input, para que el boton quede pegado al borde
     derecho del campo y no al del contenedor en pantallas anchas. */
  max-width: 420px;
}
.campo-password input[type="password"],
.campo-password input[type="text"] {
  width: 100%;
  padding-right: 2.9rem;
}
.btn-ojo {
  position: absolute;
  right: 0;
  /* El input trae margin-top: 0.2rem propio: el boton arranca donde arranca
     la caja, no donde arranca el hueco de arriba. */
  top: 0.2rem;
  bottom: 0;
  width: 2.8rem;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 0;
  color: var(--texto-suave);
  cursor: pointer;
  transition: color var(--transicion);
}
.btn-ojo:hover { color: var(--verde); }
.btn-ojo:focus-visible {
  outline: none;
  color: var(--verde);
  box-shadow: var(--anillo-foco-boton);
  border-radius: 8px;
}
.btn-ojo[aria-pressed="true"] { color: var(--verde); }

/* Texto de ayuda y error debajo de un campo. El error es pequeño y rojo, no
   el banner .error de arriba del formulario: ese es para lo que responde el
   servidor. */
.ayuda-campo { margin: 0.25rem 0 0; font-size: 0.78rem; color: var(--texto-suave); }
.error-campo {
  margin: 0.25rem 0 0;
  font-size: 0.78rem;
  color: var(--rojo-error);
}
input.campo-invalido { border-color: var(--rojo-error); }
input.campo-invalido:focus-visible {
  border-color: var(--rojo-error);
  box-shadow: 0 0 0 3px rgba(179, 38, 30, 0.18);
}

/* Verificacion en dos pasos (Byron 2026-08-19) -- misma tarjeta que
   .login-card, un poco mas ancha para que el QR quepa comodo. */
.login-card-2fa { max-width: 420px; text-align: left; }
.login-card-2fa h1 { text-align: center; }
.login-card-2fa .subtitle { text-align: center; }
.pasos-2fa { margin: 0 0 1rem; padding-left: 1.2rem; color: var(--texto-suave); font-size: 0.88rem; line-height: 1.5; }
.pasos-2fa li + li { margin-top: 0.3rem; }
.qr-2fa {
  display: block; margin: 0 auto 1rem; width: 220px; height: 220px;
  border: 1px solid var(--gris-borde); border-radius: 12px; padding: 0.8rem; background: #fff;
}
.clave-manual { margin-bottom: 1.2rem; font-size: 0.85rem; }
.clave-manual summary { color: var(--verde); cursor: pointer; }
.clave-manual-texto {
  display: block; margin-top: 0.4rem; padding: 0.6rem 0.7rem; background: var(--gris-fondo);
  border-radius: 8px; letter-spacing: 0.08em; word-break: break-all; font-size: 0.95rem;
}
.form-2fa-confirmar { border-top: 1px dashed var(--gris-borde); padding-top: 1.1rem; }
.form-2fa-confirmar input { text-align: center; letter-spacing: 0.3em; font-size: 1.2rem; }

/* --- Formularios de acta ------------------------------------------------ */

/* Titulos con el tratamiento de la web corporativa: verde selva (no el verde
   de marca, que sobre marfil pierde peso), Montserrat en negrita y el
   interletrado ligeramente cerrado que usa el sitio en sus encabezados. */
h1 {
  color: var(--verde-oscuro);
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
h2 {
  font-size: 1.1rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-top: 1.5rem;
}

label { display: block; font-size: 0.85rem; color: var(--texto-suave); margin-top: 0.6rem; }

input[type="text"], input[type="email"], input[type="password"], select, textarea {
  width: 100%;
  max-width: 420px;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--gris-borde);
  border-radius: 8px;
  font-size: 0.95rem;
  margin-top: 0.2rem;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
input[type="text"]:focus-visible, input[type="email"]:focus-visible,
input[type="password"]:focus-visible, select:focus-visible, textarea:focus-visible {
  border-color: var(--verde);
  box-shadow: var(--anillo-foco-input);
  outline: none;
}

textarea { max-width: 100%; font-family: inherit; }

fieldset {
  border: 1px solid var(--gris-borde);
  border-radius: 14px;
  padding: 0.8rem 1rem 1rem;
  margin-top: 1rem;
  box-shadow: var(--sombra-tarjeta);
  transition: box-shadow 0.2s ease, transform 0.2s ease;
}
fieldset:hover {
  box-shadow: var(--sombra-tarjeta-hover);
  transform: translateY(-2px);
}
legend { font-weight: 600; padding: 0 0.4rem; }

.acciones { margin-top: 1.2rem; }

/* ===========================================================================
   Cabecera de pantalla y navegacion de seccion (Byron 2026-08-25)
   ---------------------------------------------------------------------------
   El problema que resuelve: en /admin/usuarios convivian CINCO controles con
   la misma forma de boton -- "+ Nuevo usuario" y cuatro enlaces a las otras
   secciones -- en un solo parrafo. En un telefono se apilaban y la pantalla se
   leia como una pila de botones sin jerarquia.

   Pero solo UNO de los cinco era una accion; los otros cuatro eran
   navegacion. La solucion no es darles mas espacio: es dejar de pintarlos
   igual. Ahora hay tres bandas, cada una con una FORMA distinta para que no
   compitan ni se confundan al mirarlas de reojo:

     1. Cabecera .......... el titulo y LA accion de la pantalla (ambar)
     2. Riel de secciones . donde estoy dentro de Administracion (texto)
     3. Filtros ........... que subconjunto estoy viendo (pastillas)

   El subrayado ambar del riel es el MISMO gesto que la barra superior usa al
   pasar el raton. Aqui deja de ser un efecto de hover y pasa a ser un estado:
   el ambar marca "estas aqui" en cualquier navegacion de la app, arriba y en
   la seccion. Una sola idea contando toda la historia de navegacion.
   =========================================================================== */
.cabecera-pagina {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.7rem 1.2rem;
  margin-bottom: 0.9rem;
}
.cabecera-pagina h1 { margin: 0; }
/* El boton trae margin-top propio para cuando va suelto en un parrafo; aqui
   lo pone la rejilla. */
.cabecera-pagina .btn-primario-link,
.cabecera-pagina .btn-secundario { margin-top: 0; }

.secciones {
  display: flex;
  /* No es decorativo: fija el riel como ancestro posicionado para que el
     `offsetLeft` de la seccion actual se mida CONTRA EL RIEL. Sin esto la
     referencia es un ancestro cualquiera y la cuenta que la centra en movil
     (menus.js) sale desplazada por el margen del contenedor. */
  position: relative;
  gap: 1.4rem;
  margin: 0 0 1.3rem;
  border-bottom: 1px solid var(--gris-borde);
  /* En movil el riel se desplaza en horizontal en vez de partirse en tres
     lineas -- misma decision que ya se tomo para .filtros. */
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.secciones::-webkit-scrollbar { display: none; }

.seccion {
  position: relative;
  flex-shrink: 0;
  padding: 0.6rem 0.15rem;
  color: var(--texto-suave);
  font-size: 0.92rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.2s var(--ease);
}
.seccion::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.28s var(--ease);
}
.seccion:hover { color: var(--verde-oscuro); }
.seccion:hover::after { transform: scaleX(1); }
/* La seccion actual: no solo se subraya -- tambien cambia de peso y de color.
   El subrayado solo no sobrevive a una pantalla con reflejos al sol, que es
   donde se usa esto. */
.seccion.actual {
  color: var(--verde-oscuro);
  font-weight: 700;
}
.seccion.actual::after { transform: scaleX(1); }
.seccion:focus-visible {
  outline: 2px solid var(--verde);
  outline-offset: -2px;
  border-radius: 4px;
}

button[type="submit"], .btn-primario-link {
  background: var(--verde);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 0.6rem 1.2rem;
  font-size: 0.95rem;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
  box-shadow: 0 2px 8px -2px rgba(36, 81, 38, 0.45);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
button[type="submit"]:hover, .btn-primario-link:hover {
  background: var(--verde-oscuro);
  border-color: var(--verde-oscuro);
  transform: translateY(-1px);
  box-shadow: 0 6px 16px -3px rgba(36, 81, 38, 0.5);
}
button[type="submit"]:focus-visible, .btn-primario-link:focus-visible {
  outline: none;
  box-shadow: var(--anillo-foco-boton);
}

/* La accion PRINCIPAL de cada pantalla (Nueva acta, Nuevo mantenimiento, Ver
   PDF, Editar...) va en el naranja corporativo. Es el unico sitio donde la
   marca usa el ambar a relleno completo, y es lo que evita que la app se lea
   como un bloque verde uniforme -- en la web corporativa cumple exactamente
   este papel.

   Los <button type="submit"> (Guardar, Firmar, Eliminar) se quedan en VERDE a
   proposito: aqui el ambar significa "empieza algo", no "confirma algo". Que
   un boton de firmar o de borrar compartiera color con "Nueva acta" seria
   pedir un clic por inercia justo donde no conviene.

   El texto va en verde profundo, no en blanco: blanco sobre este naranja no
   alcanza el contraste minimo, verde oscuro sobre naranja si (>7:1). */
.btn-primario-link {
  background: var(--amber);
  color: var(--green-900);
  font-weight: 600;
  box-shadow: 0 8px 20px -8px rgba(248, 154, 40, 0.7);
}
.btn-primario-link:hover {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--green-900);
  transform: translateY(-2px);
  box-shadow: 0 12px 24px -8px rgba(248, 154, 40, 0.75);
}
.btn-primario-link:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 154, 40, 0.5);
}

/* `display:inline-block` NO es cosmetico: sin el, un <a class="btn-secundario">
   sigue siendo una caja INLINE, y el relleno vertical de una caja inline no
   cuenta para la altura de la linea. Con dos o mas botones que se parten en
   varias lineas -- cualquier telefono -- las cajas se montaban literalmente
   unas encima de otras (visto por Byron el 2026-08-25 en /admin/usuarios).
   Afecta a los 10 sitios donde .btn-secundario es un enlace, no solo a ese. */
.btn-secundario {
  display: inline-block;
  vertical-align: middle;
  background: #fff;
  border: 1px solid var(--verde);
  color: var(--verde);
  border-radius: 8px;
  padding: 0.4rem 0.9rem;
  cursor: pointer;
  margin-top: 0.6rem;
  text-decoration: none;
  transition: background-color var(--transicion), color var(--transicion);
}
.btn-secundario:hover { background: var(--ivory-2); }

/* Un <button type="submit"> con esta clase (ej. "Guardar borrador") debe
   quedar como accion secundaria, no con el relleno verde de submit por
   defecto -- de ahi el selector compuesto para ganarle en especificidad. */
button[type="submit"].btn-secundario {
  background: #fff;
  color: var(--verde);
  box-shadow: none;
}
button[type="submit"].btn-secundario:hover {
  background: var(--ivory-2);
  transform: none;
  box-shadow: none;
}

/* ===========================================================================
   Barra de acciones de un listado + menu de operaciones (Byron 2026-09-01)
   ---------------------------------------------------------------------------
   Sustituye a los dos botones sueltos que tenia /actas. Dos problemas de raiz:

   1. Se veian DESALINEADOS y no era casualidad: .btn-secundario trae
      `margin-top: .6rem` -- lo necesita cuando cuelga solo debajo de un
      formulario -- y .btn-primario-link no. Dentro del mismo <p> el segundo
      boton se sentaba 6px mas abajo que el primero. La barra los pone en un
      flex con `gap`, que es lo que hacia falta en vez de que cada boton
      arrastre su propio margen.
   2. Los dos pesaban visualmente igual y eso mentia: uno crea un acta de cero
      y el otro deriva de un acta que ya existe. Ahora hay UNA entrada y la
      diferencia se cuenta dentro del menu, agrupada.
   =========================================================================== */
.barra-acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  margin: 0.9rem 0 1.1rem;
}
/* Dentro de la barra el espaciado lo pone el `gap`, no cada boton por su
   cuenta: sin esto vuelve el desnivel del punto 1. */
.barra-acciones .btn-secundario { margin-top: 0; }

.menu-accion { position: relative; }

/* El chevron es la unica senal de que este boton DESPLIEGA en vez de navegar.
   Por eso se le quito el "+" que traia: dos simbolos de affordance en el mismo
   boton -- crear y desplegar -- se estorban, y el que ahora dice la verdad es
   el chevron. */
.btn-menu { display: inline-flex; align-items: center; gap: 0.45rem; }
.btn-menu-chevron {
  /* En `em` y no en px: el boton crece con la tipografia del sistema y en un
     telefono un chevron de 16px fijos queda raquitico al lado del texto. */
  width: 1.05em;
  height: 1.05em;
  flex-shrink: 0;
  transition: transform var(--transicion);
}
.btn-menu[aria-expanded="true"] .btn-menu-chevron { transform: rotate(180deg); }

/* Hereda de .menu-desplegable la caja entera (fondo, borde, sombra, z-index) y
   solo cambia lo que aqui es distinto: cuelga del borde IZQUIERDO, porque el
   boton vive al principio de la pagina y no en la esquina de la barra
   superior. El min() evita que en un telefono el panel se salga de pantalla. */
.menu-operaciones {
  right: auto;
  left: 0;
  min-width: min(21rem, calc(100vw - 2.5rem));
  padding: 0.5rem;
}
.menu-operaciones .menu-cabecera:not(:first-child) { margin-top: 0.65rem; }

/* Cada opcion dice QUE es y QUE consecuencia tiene: el tecnico elige la
   operacion una sola vez y sin abrir la pantalla para averiguarlo. */
.item-operacion {
  display: block;
  padding: 0.55rem 0.6rem;
  border-radius: 8px;
  color: var(--texto);
  text-decoration: none;
  transition: background-color var(--transicion);
}
.item-operacion strong {
  display: block;
  font-size: 0.95rem;
  font-weight: 600;
}
.item-operacion small {
  display: block;
  margin-top: 0.1rem;
  font-size: 0.8rem;
  line-height: 1.35;
  color: var(--texto-suave);
}
/* Operacion que todavia no existe: se ve, se lee y no se puede tocar. Hay que
   apagar el :hover heredado de .item-operacion -- si no, se ilumina al pasar
   por encima y parece que responde. */
.item-operacion-pronto {
  color: var(--texto-suave);
  cursor: default;
}
.item-operacion-pronto strong { display: flex; align-items: center; gap: 0.45rem; }
.item-operacion-pronto:hover { background: none; }

.item-operacion:hover { background: var(--ivory-2); }
.item-operacion:focus-visible {
  outline: none;
  background: var(--ivory-2);
  box-shadow: var(--anillo-foco-boton);
}
button[type="submit"].btn-secundario:focus-visible {
  box-shadow: var(--anillo-foco-boton);
}

.btn-link {
  background: none; border: none; color: var(--verde);
  text-decoration: underline; cursor: pointer; padding: 0.2rem 0; font-size: 0.85rem;
  transition: color var(--transicion);
}
.btn-link:hover { color: var(--verde-oscuro); }

/* Mismo motivo que button[type="submit"].btn-secundario arriba: un
   <button type="submit"> con esta clase (ej. "Desactivar"/"Reactivar" en la
   lista de usuarios) necesita el selector compuesto para no heredar el
   relleno verde de submit por defecto. */
button[type="submit"].btn-link {
  background: none; border: none; padding: 0.2rem 0; color: var(--verde);
  border-radius: 0; display: inline; font-size: 0.85rem; box-shadow: none;
}
button[type="submit"].btn-link:hover { background: none; color: var(--verde-oscuro); transform: none; box-shadow: none; }
button[type="submit"].btn-link:focus-visible { box-shadow: var(--anillo-foco-boton); border-radius: 4px; }

.seleccionado {
  background: rgba(36, 81, 38, 0.08); border: 1px solid var(--verde);
  border-radius: 8px; padding: 0.6rem 0.8rem; margin-top: 0.4rem;
}
/* Panel de creacion inline de colaborador -- campos a la izquierda, CTA
   grande a la derecha. El grid existe porque el contenedor del formulario
   (.container, 960px) es bastante mas ancho que los campos (max-width
   420px): sin esto quedaba un vacio muerto a la derecha del formulario
   (reportado por Byron 2026-08-18). */
.crear-inline {
  background: #fff; border: 1px solid var(--gris-borde);
  border-radius: 14px; padding: 1rem 1.2rem; margin-top: 0.4rem;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(200px, 260px);
  gap: 1.5rem; align-items: stretch;
  box-shadow: var(--sombra-tarjeta);
}
.crear-campos label:first-of-type { margin-top: 0; }
.campo-ayuda { margin-top: 0.15rem; font-size: 0.8rem; }

.crear-cta {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.6rem; text-align: center;
  background: radial-gradient(circle at 50% 0%, rgba(36, 81, 38, 0.10), rgba(36, 81, 38, 0.03) 70%);
  border: 1px solid rgba(36, 81, 38, 0.16);
  border-radius: 12px; padding: 1.5rem 1rem;
}
.crear-cta-icono {
  width: 64px; height: 64px; border-radius: 999px; flex-shrink: 0;
  background: linear-gradient(155deg, var(--verde), var(--verde-oscuro));
  color: #fff; display: flex; align-items: center; justify-content: center;
  box-shadow: 0 6px 18px -6px rgba(36, 81, 38, 0.55);
}
.crear-cta-icono svg { width: 32px; height: 32px; }
.crear-cta-texto { margin: 0; font-size: 0.85rem; color: var(--texto-suave); }
.btn-crear-cta {
  background: var(--verde); color: #fff; border: none; border-radius: 8px;
  padding: 0.65rem 1.4rem; font-size: 0.95rem; font-weight: 600; cursor: pointer;
  box-shadow: 0 4px 12px -3px rgba(36, 81, 38, 0.5);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.btn-crear-cta:hover { background: var(--verde-oscuro); transform: translateY(-1px); box-shadow: 0 8px 18px -4px rgba(36, 81, 38, 0.55); }
.btn-crear-cta:focus-visible { outline: none; box-shadow: var(--anillo-foco-boton); }

/* Ficha de solo lectura para datos que vienen de GLPI (alimentados por el
   agente del equipo/celular) -- Byron 2026-08-18: si TrackIT dejara editar
   estos campos, un valor distinto al que el agente reporta crearia un
   conflicto de integridad con GLPI. Se muestran, no se editan; solo se
   pueden CONFIRMAR. */
.ficha-glpi {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.7rem 1rem; margin: 0.6rem 0 0.8rem;
  background: var(--gris-fondo); border: 1px solid var(--gris-borde);
  border-radius: 10px; padding: 0.8rem 0.9rem;
}
.ficha-glpi dt { font-size: 0.75rem; color: var(--texto-suave); text-transform: uppercase; letter-spacing: 0.03em; }
.ficha-glpi dd { margin: 0.1rem 0 0; font-size: 0.95rem; font-weight: 600; }

/* --- Base para portatil (Byron 2026-08-25) --------------------------------
   Mismo idioma visual que .ficha-glpi -- es el mismo tipo de dato: viene de
   GLPI y no se edita aqui -- pero con su propia caja para que se lea como un
   bloque aparte y no como tres campos mas del equipo. */
.ficha-base {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.7rem 1rem;
  margin: 0.6rem 0 0.3rem;
  padding: 0.7rem 0.9rem;
  background: #fff;
  border: 1px solid var(--gris-borde);
  border-left: 3px solid var(--verde);
  border-radius: 10px;
}
.ficha-base dt {
  font-size: 0.75rem; color: var(--texto-suave);
  text-transform: uppercase; letter-spacing: 0.03em;
}
.ficha-base dd { margin: 0.2rem 0 0; font-size: 0.95rem; font-weight: 600; }

/* "Sin consultar" NO se pinta como un estado mas: es la ausencia de dato, y
   darle color de pastilla lo haria parecer una respuesta. */
.dato-sin-consultar {
  font-weight: 500;
  font-style: italic;
  color: var(--texto-suave);
}

.nota-origen { margin: 0.15rem 0 0; font-size: 0.78rem; }

/* --- Tablero del Admin (Byron 2026-09-17) --------------------------------- */
.tablero-cabecera {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: 0.8rem; margin-bottom: 1.1rem;
}
.tablero-cabecera h1 { margin: 0 0 0.15rem; }
.tablero-cabecera .muted { margin: 0; }
.tablero-totales { display: flex; flex-wrap: wrap; gap: 0.4rem 1.1rem; font-size: 0.86rem; color: var(--texto-suave); }
.tablero-totales strong { color: var(--verde); font-size: 1.05rem; }

/* El bloque de "te espera a ti" se resalta SOLO cuando de verdad hay algo
   detenido: un marco permanente deja de significar nada a la semana. */
.kpi-bloque.bloque-atencion {
  padding: 0.9rem 1rem 0.2rem;
  border: 1px solid var(--amber);
  border-left-width: 4px;
  border-radius: 12px;
  background: rgba(248, 154, 40, 0.06);
}

/* Tarjeta que ademas es enlace: mismo aspecto, con el gesto de que se puede
   pulsar. El Admin entra al tablero para ir a otro sitio. */
a.tarjeta-enlace { text-decoration: none; color: inherit; transition: transform 140ms var(--ease, ease), box-shadow 140ms var(--ease, ease); }
a.tarjeta-enlace:hover { transform: translateY(-2px); box-shadow: 0 8px 20px -10px rgba(0, 0, 0, 0.35); }
a.tarjeta-enlace:focus-visible { outline: none; box-shadow: var(--anillo-foco-boton); }

/* Variacion contra el mes pasado. */
.delta { font-size: 0.8rem; font-weight: 700; margin-left: 0.35rem; vertical-align: middle; }
.delta.sube { color: var(--verde); }
.delta.baja { color: var(--rojo-error); }

/* Ranking de tecnicos: una barra por fila, sin libreria de graficas. */
.ranking { list-style: none; margin: 0.2rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.55rem; }
.ranking li {
  display: grid; grid-template-columns: minmax(0, 1fr) 90px 34px; align-items: center;
  gap: 0.5rem; font-size: 0.9rem;
}
.ranking-nombre { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ranking-barra { height: 8px; border-radius: 999px; background: var(--gris-borde); overflow: hidden; }
.ranking-barra > span { display: block; height: 100%; background: var(--verde); border-radius: 999px; }
.ranking-cifra { text-align: right; font-weight: 700; color: var(--verde); }
.ranking-sub { grid-column: 1 / -1; margin-top: -0.35rem; font-size: 0.76rem; color: var(--texto-suave); }

@media (max-width: 640px) {
  .ranking li { grid-template-columns: minmax(0, 1fr) 60px 30px; }
}

/* ===========================================================================
   Sidebar del rol Admin (Byron 2026-09-17)
   ---------------------------------------------------------------------------
   "Como funciona en el correo": plegado deja iconos, desplegado muestra el
   icono con su etiqueta. El ancho se anima; lo que NO se anima es la
   aparicion del texto -- se corta con overflow y se desvanece, porque animar
   el tamano de la letra se ve barato y ademas obliga al navegador a
   recalcular el texto en cada fotograma.

   El estado plegado llega del servidor (.plegado-inicial, leida de la cookie)
   y despues lo maneja el JS con .plegado sobre el propio aside. Las dos
   clases valen: sin eso, la pagina se pinta ancha y se encoge de golpe al
   arrancar el JS.
   =========================================================================== */
.con-sidebar { display: flex; align-items: flex-start; gap: 0; }
.con-sidebar > .container { flex: 1; min-width: 0; }

.sidebar {
  position: sticky;
  top: 0;
  flex: none;
  width: 232px;
  align-self: stretch;
  min-height: calc(100vh - var(--alto-barra, 60px));
  padding: 1.1rem 0.7rem 1.5rem;
  border-right: 1px solid var(--gris-borde);
  background: var(--ivory-2, #F3EEE4);
  transition: width 180ms var(--ease, ease);
}
.con-sidebar.plegado-inicial .sidebar,
.sidebar.plegado { width: 64px; }

/* El tirador: la pestanita para plegar y desplegar. */
.sidebar-tirador {
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; margin: 0 0 0.9rem auto;
  padding: 0; border: 1px solid var(--gris-borde); border-radius: 50%;
  background: #fff; color: var(--verde); cursor: pointer;
  transition: background-color var(--transicion), transform 180ms var(--ease, ease);
}
.sidebar-tirador svg { width: 17px; height: 17px; }
.sidebar-tirador:hover { background: var(--ivory, #FAF6EF); }
.sidebar-tirador:focus-visible { outline: none; box-shadow: var(--anillo-foco-boton); }
.con-sidebar.plegado-inicial .sidebar-tirador,
.sidebar.plegado .sidebar-tirador { transform: rotate(180deg); margin-right: auto; margin-left: auto; }

.sidebar-grupo { display: flex; flex-direction: column; gap: 0.15rem; }

.sidebar-item {
  position: relative;
  display: flex; align-items: center; gap: 0.7rem;
  padding: 0.55rem 0.7rem;
  border-radius: 999px;
  color: var(--texto, #1b1b18);
  text-decoration: none;
  font-size: 0.92rem;
  white-space: nowrap;
  transition: background-color var(--transicion), color var(--transicion);
}
.sidebar-item:hover { background: rgba(36, 81, 38, 0.08); }
.sidebar-item.actual { background: var(--verde); color: #fff; font-weight: 600; }
.sidebar-item.actual .nav-icono { color: #fff; }
.sidebar-item:focus-visible { outline: none; box-shadow: var(--anillo-foco-boton); }
.nav-icono { width: 21px; height: 21px; flex: none; color: var(--verde); }

.sidebar-titulo {
  display: flex; align-items: center; gap: 0.5rem;
  margin: 1.1rem 0 0.45rem; padding: 0 0.7rem;
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--texto-suave);
}
.sidebar-raya { display: none; flex: 1; height: 1px; background: var(--gris-borde); }

/* El numerito de lo que espera al Admin (anulaciones / actualizaciones). */
.sidebar-pendiente {
  margin-left: auto;
  min-width: 20px; padding: 0 6px;
  border-radius: 999px;
  background: var(--amber); color: #3a2a06;
  font-size: 0.74rem; font-weight: 700; line-height: 19px; text-align: center;
}
.sidebar-item.actual .sidebar-pendiente { background: #fff; color: var(--verde); }

/* --- Plegado: solo iconos ------------------------------------------------- */
.con-sidebar.plegado-inicial .sidebar-texto,
.sidebar.plegado .sidebar-texto { display: none; }
.con-sidebar.plegado-inicial .sidebar-item,
.sidebar.plegado .sidebar-item { justify-content: center; padding-left: 0; padding-right: 0; }
.con-sidebar.plegado-inicial .sidebar-titulo,
.sidebar.plegado .sidebar-titulo { padding: 0; margin: 0.9rem 0 0.5rem; }
.con-sidebar.plegado-inicial .sidebar-raya,
.sidebar.plegado .sidebar-raya { display: block; }
/* Plegado, el numerito no cabe al lado: se vuelve un punto sobre el icono. */
.con-sidebar.plegado-inicial .sidebar-pendiente,
.sidebar.plegado .sidebar-pendiente {
  position: absolute; top: 4px; right: 8px; margin: 0;
  min-width: 17px; padding: 0 4px; font-size: 0.68rem; line-height: 16px;
}

/* Plegado, el nombre aparece al pasar el raton: sin esto hay que adivinar que
   es cada icono. Es CSS puro (::after sobre data-titulo), no un tooltip de JS. */
.sidebar.plegado .sidebar-item::after,
.con-sidebar.plegado-inicial .sidebar-item::after {
  content: attr(data-titulo);
  position: absolute; left: calc(100% + 10px); top: 50%; transform: translateY(-50%);
  padding: 0.3rem 0.6rem; border-radius: 7px;
  background: var(--verde-oscuro, #163218); color: #fff;
  font-size: 0.82rem; font-weight: 500; white-space: nowrap;
  opacity: 0; pointer-events: none;
  transition: opacity 120ms var(--ease, ease);
  z-index: 40;
}
.sidebar.plegado .sidebar-item:hover::after,
.sidebar.plegado .sidebar-item:focus-visible::after,
.con-sidebar.plegado-inicial .sidebar-item:hover::after,
.con-sidebar.plegado-inicial .sidebar-item:focus-visible::after { opacity: 1; }

/* Solo para lectores de pantalla. */
.sr-solo {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --- Movil: el menu no se pliega, se esconde ------------------------------ */
@media (max-width: 900px) {
  .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0; z-index: 60;
    width: 232px !important; min-height: 100vh;
    transform: translateX(-100%);
    transition: transform 200ms var(--ease, ease);
    box-shadow: 0 0 30px rgba(0, 0, 0, 0.25);
    overflow-y: auto;
  }
  body.sidebar-abierto .sidebar { transform: none; }
  .sidebar .sidebar-texto { display: inline !important; }
  .sidebar .sidebar-item { justify-content: flex-start !important; padding: 0.55rem 0.7rem !important; }
  .sidebar .sidebar-item::after { content: none; }
  /* El tirador se queda a la vista, pegado al borde, para poder abrirlo. */
  .sidebar-tirador {
    position: fixed; left: 10px; top: 72px; z-index: 61;
    transform: rotate(180deg); margin: 0;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
  }
  body.sidebar-abierto .sidebar-tirador { left: 244px; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .sidebar, .sidebar-tirador, .sidebar-item::after { transition: none; }
}

/* ===========================================================================
   Indicador de busqueda en curso -- las hojitas (Byron 2026-09-17)
   ---------------------------------------------------------------------------
   Con datos moviles la busqueda por serial tarda hasta ~20 s y la pantalla se
   veia congelada. Lo enciende HTMX con la clase `htmx-request` (ver
   _cargando_busqueda.html); aqui solo esta el aspecto.

   Se usa display y no opacity a proposito: con opacity el hueco del
   indicador ocupa sitio siempre y la lista de resultados aparece 30px mas
   abajo de donde el ojo la esperaba. Y NO se usa la clase `htmx-indicator`
   (la que HTMX trae de serie) porque esa viene con su propio `opacity: 0`
   desde la hoja que HTMX inyecta, y pelearia con esto.
   =========================================================================== */
.cargando-busqueda { display: none; align-items: center; gap: 0.55rem; margin: 0.55rem 0 0.15rem; }
.cargando-busqueda.htmx-request { display: flex; }
.cargando-hojitas { width: 30px; height: 30px; flex: none; }
.cargando-hojitas use {
  fill: var(--verde);
  animation: cargando-hojita 1.2s linear infinite;
}
@keyframes cargando-hojita {
  0% { opacity: 1; }
  100% { opacity: 0.12; }
}
.cargando-texto { font-size: 0.88rem; color: var(--texto-suave); }

/* Sin movimiento: el anillo se queda quieto y quien avisa es el texto. */
@media (prefers-reduced-motion: reduce) {
  .cargando-hojitas use { animation: none; opacity: 0.45; }
}

/* Buscador escondido cuando ya hay algo elegido -- equipo o colaborador
   (Byron 2026-09-17). Clase propia y no [hidden]: ver buscadores.js. */
.buscador-plegable.oculto { display: none; }

/* Serial que no aparece ni en TrackIT ni en GLPI (Byron 2026-09-17). Ambar,
   no rojo: la app no esta rota ni el tecnico hizo nada mal -- es "esto hay que
   averiguarlo antes de seguir". El rojo sigue reservado para los errores. */
.aviso-no-encontrado {
  margin: 0.4rem 0 0;
  padding: 0.8rem 0.95rem;
  background: rgba(248, 154, 40, 0.12);
  border: 1px solid var(--amber);
  border-radius: 10px;
  font-size: 0.88rem;
  color: var(--ambar-texto);
}
.aviso-no-encontrado p { margin: 0.5rem 0 0; }
.aviso-no-encontrado p:first-child { margin-top: 0; }
.aviso-no-encontrado-titulo { font-weight: 600; }
.aviso-no-encontrado-pie { font-size: 0.82rem; opacity: 0.85; }

/* Aviso de dato duplicado en la pantalla de firma. Ambar, no rojo: no impide
   firmar ni hay nada roto -- es "mira esto antes de seguir". El rojo de la app
   esta reservado para lo que si es un error. */
.aviso-duplicado {
  margin: 0.8rem 0 0;
  padding: 0.7rem 0.9rem;
  background: rgba(248, 154, 40, 0.12);
  border: 1px solid var(--amber);
  border-radius: 10px;
  font-size: 0.88rem;
  color: var(--ambar-texto);
}

@media (max-width: 640px) {
  .crear-inline { grid-template-columns: 1fr; }
}

/* Texto en mayuscula mientras se escribe (Byron 2026-08-18) -- solo visual,
   el valor real que llega al servidor no cambia; el backend ya normaliza a
   mayuscula al guardar (colaboradores.py). */
input.mayusculas { text-transform: uppercase; }
input.mayusculas::placeholder { text-transform: none; }

.resultados-busqueda {
  border: 1px solid var(--gris-borde); border-radius: 8px;
  margin-top: 0.4rem; overflow: hidden;
}
.resultado-item {
  padding: 0.5rem 0.8rem; cursor: pointer; border-bottom: 1px solid var(--gris-borde);
  font-size: 0.9rem;
  transition: background-color var(--transicion);
}
.resultado-item:last-of-type { border-bottom: none; }
.resultado-item:hover { background: var(--ivory-2); }
.resultados-busqueda p.muted { padding: 0.5rem 0.8rem; margin: 0; border-top: 1px solid var(--gris-borde); }

.chk-inline {
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-size: 0.9rem; margin-right: 1rem; margin-top: 0.4rem;
}
.chk-inline input { width: auto; margin: 0; }

/* --- Tipo de acta (Byron 2026-08-25) --------------------------------------
   Es la primera decision del acta y la que cambia QUE documento es: sale
   impresa en el PDF, en el nombre del archivo y en la categoria del documento
   en GLPI. Por eso va como opciones a la vista y no en un desplegable, donde
   el tecnico se la encontraria ya elegida sin haberla mirado.

   Cada opcion lleva su explicacion debajo: "Entrega" y "Prestamo" no se
   distinguen solos, y el que diligencia el acta en campo no tiene por que
   adivinar cual corresponde. */
.tipo-acta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  margin-top: 0;
}
.tipo-acta legend { font-weight: 600; padding: 0 0.4rem; }

.opcion-tipo {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  flex: 1 1 15rem;
  margin: 0;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--gris-borde);
  border-radius: var(--radius-sm, 12px);
  background: #fff;
  cursor: pointer;
  transition: border-color var(--transicion), box-shadow var(--transicion),
              background var(--transicion);
}
.opcion-tipo:hover { border-color: var(--green-300); }
.opcion-tipo input { width: auto; margin: 0.15rem 0 0; flex-shrink: 0; accent-color: var(--verde); }
.opcion-tipo-texto { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.opcion-tipo-texto strong { font-size: 0.98rem; color: var(--texto); }
.opcion-tipo-texto small { font-size: 0.8rem; color: var(--texto-suave); line-height: 1.35; }

/* La elegida se marca con el verde de marca en el borde y un tinte suave: en
   un formulario largo hay que poder volver la vista arriba y ver que se
   escogio sin tener que buscar cual radio esta relleno. */
.opcion-tipo:has(input:checked) {
  border-color: var(--verde);
  background: rgba(36, 81, 38, 0.05);
  box-shadow: var(--sombra-tarjeta);
}
.opcion-tipo:has(input:checked) .opcion-tipo-texto strong { color: var(--verde-oscuro); }
.opcion-tipo:focus-within {
  outline: 2px solid var(--verde);
  outline-offset: 2px;
}

/* Modalidad del acta: solo PC / PC con celular / solo celular (Byron
   2026-09-16). Pidio algo "grande, bonito y llamativo": es la decision que
   cambia que equipo pide la pantalla, asi que va en tarjetas con icono y la
   elegida se llena de verde de marca. */
.modalidad, .bloque-modalidad { border: 0; padding: 0; box-shadow: none; min-width: 0; }
.modalidad { margin: 1.2rem 0 1.1rem; }
.bloque-modalidad { margin: 0; }
.modalidad:hover, .bloque-modalidad:hover { box-shadow: none; transform: none; }
.modalidad legend {
  font-size: 1.15rem; font-weight: 700; color: var(--verde-oscuro);
  padding: 0; margin-bottom: 0.7rem;
}
.modalidad-opciones {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 0.9rem;
}
.modalidad-opcion {
  position: relative;
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 0.55rem;
  margin: 0;
  padding: 1.3rem 1rem 1.1rem;
  border: 2px solid var(--gris-borde);
  border-radius: 16px;
  background: #fff;
  cursor: pointer;
  transition: border-color var(--transicion), box-shadow var(--transicion),
              background var(--transicion), transform var(--transicion);
}
.modalidad-opcion:hover { border-color: var(--green-300); box-shadow: var(--sombra-tarjeta); transform: translateY(-2px); }
.modalidad-opcion input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.modalidad-icono {
  display: flex; align-items: flex-end; justify-content: center; gap: 0.35rem;
  height: 4.2rem; width: 100%;
  color: var(--verde);
}
.modalidad-icono svg {
  fill: rgba(36, 81, 38, 0.08); stroke: currentColor; stroke-width: 3;
  stroke-linecap: round; stroke-linejoin: round;
}
.modalidad-icono .ico-pc { height: 4rem; }
.modalidad-icono .ico-celular { height: 3.2rem; }
.modalidad-icono .ico-pc + .ico-celular { height: 2.6rem; margin-left: -0.9rem; fill: #fff; }
.modalidad-texto { display: flex; flex-direction: column; gap: 0.2rem; }
.modalidad-texto strong { font-size: 1.12rem; font-weight: 700; color: var(--texto); }
.modalidad-texto small { font-size: 0.82rem; color: var(--texto-suave); line-height: 1.35; }
.modalidad-check {
  position: absolute; top: 0.7rem; right: 0.7rem;
  width: 1.6rem; height: 1.6rem; border-radius: 50%;
  border: 2px solid var(--gris-borde); background: #fff;
  display: flex; align-items: center; justify-content: center;
  transition: background var(--transicion), border-color var(--transicion);
}
.modalidad-check svg { width: 1rem; height: 1rem; fill: none; stroke: #fff; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.modalidad-opcion:has(input:checked) {
  border-color: var(--verde);
  background: linear-gradient(160deg, rgba(36, 81, 38, 0.10), rgba(36, 81, 38, 0.02));
  box-shadow: var(--sombra-tarjeta-hover);
}
.modalidad-opcion:has(input:checked) .modalidad-icono svg { fill: rgba(36, 81, 38, 0.18); }
.modalidad-opcion:has(input:checked) .modalidad-icono .ico-pc + .ico-celular { fill: #fff; }
.modalidad-opcion:has(input:checked) .modalidad-texto strong { color: var(--verde-oscuro); }
.modalidad-opcion:has(input:checked) .modalidad-check { background: var(--verde); border-color: var(--verde); }
.modalidad-opcion:has(input:focus-visible) { outline: 3px solid var(--amber); outline-offset: 2px; }
/* Aviso cuando se intenta seguir sin elegir: la seccion entera pulsa en ambar. */
.modalidad.modalidad-falta .modalidad-opcion { border-color: var(--amber); }
/* Los bloques que no tocan a la modalidad se ocultan con `hidden`; TrackIT no
   tiene regla global para [hidden] y fieldset/div pueden traer display propio. */
[data-bloque-modalidad][hidden] { display: none !important; }
.sin-correo {
  display: flex; align-items: flex-start; gap: 0.7rem;
  margin: 1rem 0 0; padding: 0.9rem 1rem;
  border: 2px solid var(--amber); border-radius: 14px; background: #FFF8EE;
  cursor: pointer;
}
.sin-correo input { width: 1.3rem; height: 1.3rem; margin: 0.1rem 0 0; flex-shrink: 0; accent-color: var(--verde); }
.sin-correo span { display: flex; flex-direction: column; gap: 0.25rem; }
.sin-correo strong { color: var(--texto); }
.sin-correo small { color: var(--texto-suave); font-size: 0.82rem; line-height: 1.4; }
.constancia-sin-correo {
  color: #C00000; font-weight: 700; line-height: 1.45;
  border-left: 4px solid #C00000; padding: 0.4rem 0 0.4rem 0.8rem; margin: 0.4rem 0 0.8rem;
}
.modalidad-pendiente { margin: 0.8rem 0 0; }
@media (max-width: 600px) {
  .modalidad-opciones { grid-template-columns: 1fr; gap: 0.6rem; }
  .modalidad-opcion {
    flex-direction: row; text-align: left; padding: 0.9rem 3rem 0.9rem 0.9rem; gap: 0.8rem;
  }
  .modalidad-icono { width: 4.4rem; height: 3rem; flex-shrink: 0; }
  .modalidad-icono .ico-pc { height: 2.9rem; }
  .modalidad-icono .ico-celular { height: 2.5rem; }
  .modalidad-icono .ico-pc + .ico-celular { height: 1.9rem; margin-left: -0.7rem; }
  .modalidad-check { top: 50%; transform: translateY(-50%); }
}

.badge-rol {
  display: inline-block; background: rgba(36, 81, 38, 0.10); color: var(--verde-oscuro);
  border: 1px solid var(--verde); border-radius: 999px;
  padding: 0.1rem 0.55rem; font-size: 0.78rem; margin-right: 0.3rem;
}

.tabla-scroll {
  overflow-x: auto;
  margin-top: 0.6rem;
  border-radius: 14px;
  box-shadow: var(--sombra-tarjeta);
}
/* El "levantamiento" al pasar el cursor va en la FILA, no en toda la tabla
   (Byron 2026-09-11): antes .tabla-scroll:hover elevaba el contenedor entero,
   lo que hacia flotar la tabla completa aunque el cursor estuviera sobre una
   sola fila. Ahora solo se eleva la fila bajo el cursor -- ver
   .tabla-actas tbody tr:hover mas abajo. */

/* Pills de estado (ej. columna "Estado" en una tabla) -- valores exactos
   del mockup aprobado 2026-08-18. Definidas pero sin aplicar todavia a
   ninguna columna real: no hay un lugar en el codigo actual con exactamente
   el significado "Vinculado/Pendiente" -- confirmar con Byron donde usarlas. */
.pill {
  border-radius: 999px; padding: 3px 10px; font-size: 11px;
  font-weight: 600; display: inline-flex;
}
.pill.ok { background: rgba(36, 81, 38, 0.12); color: var(--verde); }
.pill.pending { background: rgba(75, 90, 79, 0.12); color: var(--texto-suave); }
/* Alertas de borrador inactivo (Byron 2026-08-18): "pending" = 3-4 dias,
   "alerta" = 5+ dias (se auto-elimina a los 9, ver scheduler.py). */
.pill.alerta { background: rgba(179, 38, 30, 0.12); color: var(--rojo-error); }

/* --- Estado de un acta, como pastilla (Byron 2026-08-25) ------------------
   Era texto plano en una columna de texto plano: para saber si un acta estaba
   firmada habia que LEER la palabra, fila por fila. La pastilla se reconoce
   por color antes de leerla, que es como se recorre una tabla de 23 filas.

   Los cuatro estados que permite el CHECK del esquema, cada uno con un color
   que significa algo y no solo decora:
     Firmada             verde   -> terminado y correcto
     Borrador            ambar   -> te esta esperando a ti
     Anulacion pendiente ambar+  -> espera a OTRO (el Admin); borde marcado
     Anulada             vinotinto -> cerrado sin efecto; debe saltar a la vista

   Anulada iba en gris; Byron (2026-09-14) pidio resaltarla para que un acta
   anulada no pase por vigente al recorrer el listado. Va en vinotinto y NO en
   el rojo de error ni en el ambar: el ambar ya lo usan Borrador y Pendiente,
   y el rojo sigue reservado para lo que esta mal. */
.estado-pill {
  display: inline-block;
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
  font-size: 0.76rem;
  font-weight: 600;
  white-space: nowrap;
  letter-spacing: 0.01em;
}
.estado-firmada   { background: rgba(36, 81, 38, 0.12);  color: var(--verde); }
.estado-borrador  { background: rgba(248, 154, 40, 0.16); color: var(--ambar-texto); }
.estado-pendiente { background: rgba(248, 154, 40, 0.16); color: var(--ambar-texto); border: 1px solid var(--amber); }
.estado-anulada   { background: rgba(122, 31, 46, 0.10); color: var(--vinotinto); border: 1px solid rgba(122, 31, 46, 0.45); }
/* Solo para una solicitud RECHAZADA: es la unica pastilla de la app que
   comunica una negativa, y ahi el rojo si esta ganado. Un acta anulada, en
   cambio, es un desenlace normal y va en gris. */
.estado-rechazada { background: rgba(179, 38, 30, 0.12); color: var(--rojo-error); }

/* El aviso de borrador inactivo pasa de pastilla a linea de texto pequena
   debajo del estado. Antes eran DOS pastillas en la misma celda peleandose
   por la atencion; ahora la pastilla dice QUE es y la linea dice que le pasa.
   Es el tratamiento del ejemplo aprobado (.aviso). */
.aviso-fila {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.75rem;
  line-height: 1.3;
  color: var(--ambar-texto);
}
.aviso-fila.urgente { color: var(--rojo-error); font-weight: 600; }

/* El consecutivo es la matricula del acta: se busca por el, asi que se le da
   peso y cifras de ancho fijo (tabular-nums) para que las columnas de digitos
   queden alineadas y se puedan comparar de un vistazo. */
.consec {
  font-weight: 700;
  color: var(--verde-oscuro);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}
.consec-sin {
  font-weight: 500;
  font-style: italic;
  color: var(--texto-suave);
}

/* Las acciones de una fila necesitan separacion REAL: "Editar" y "Eliminar"
   son un enlace y un boton dentro de un form, y sin esto quedaban pegados
   ("EditarEliminar") porque el navegador colapsa el espacio entre ellos. */
.acciones-fila {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  white-space: nowrap;
}
.acciones-fila form { display: inline; margin: 0; }

/* Mismo motivo que .btn-secundario/.btn-link mas arriba: un <button
   type="submit"> necesita el selector compuesto para ganarle en
   especificidad al verde por defecto de button[type=submit]. */
.btn-peligro, button[type="submit"].btn-peligro { color: var(--rojo-error); }
.btn-peligro:hover, button[type="submit"].btn-peligro:hover { color: #7a1a15; background: none; }

/* Eliminar borrador (Byron 2026-08-18) -- separado visualmente del resto de
   acciones para que no se confunda ni se toque por accidente con "Guardar"
   o "Continuar a firma". */
.zona-peligro {
  margin-top: 1.5rem; padding-top: 1rem; border-top: 1px dashed var(--gris-borde);
}
.btn-peligro-outline, button[type="submit"].btn-peligro-outline {
  background: #fff; border: 1px solid var(--rojo-error); color: var(--rojo-error);
  border-radius: 8px; padding: 0.5rem 1rem; cursor: pointer; box-shadow: none;
  transition: background-color var(--transicion);
}
.btn-peligro-outline:hover, button[type="submit"].btn-peligro-outline:hover {
  background: #fdecea; transform: none; box-shadow: none;
}
.btn-peligro-outline:focus-visible, button[type="submit"].btn-peligro-outline:focus-visible {
  outline: none; box-shadow: 0 0 0 3px rgba(179, 38, 30, 0.25);
}

/* Barra de acciones del detalle de un acta (Byron 2026-09-11): las acciones
   normales (ver PDF, generar actualizacion) en una sola fila, con UNA sola
   con color (la primaria) para que no compitan. La accion destructiva
   (anular) NO va aqui -- vive aparte en .zona-peligro, lejos del enlace de
   volver, para que no se toque por accidente. */
.acciones-detalle { display: flex; flex-wrap: wrap; gap: .7rem; align-items: center; margin: 1.1rem 0 .4rem; }
.acciones-detalle .inline-form { margin: 0; }
.acciones-detalle .btn-primario-link, .acciones-detalle .btn-secundario { margin-top: 0; }
/* Enlace de volver arriba del titulo -- saca la navegacion de la vecindad de
   la accion destructiva del pie. */
.volver-detalle { margin: 0 0 .5rem; font-size: .9rem; }

.tabla-perifericos, .tabla-actas {
  width: 100%;
  min-width: 600px;
  border-collapse: collapse;
  font-size: 0.9rem;
}
.tabla-perifericos th, .tabla-perifericos td,
.tabla-actas th, .tabla-actas td {
  border: 1px solid var(--gris-borde);
  padding: 0.4rem;
  text-align: left;
}
.tabla-perifericos input { max-width: none; margin: 0; padding: 0.3rem; }
/* Encabezado de tabla al estilo de la web: versalita ancha sobre marfil, en
   verde selva. Al ir en un cuerpo MAS pequeno que el de las celdas, la
   mayuscula no ensancha la tabla (medido antes de desplegar). */
.tabla-actas th {
  background: var(--ivory-2);
  color: var(--verde-oscuro);
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

/* Un correo o un hostname largo no debe obligar a toda la tabla a crecer:
   sin esto, el ancho minimo de la tabla es el de su palabra mas larga sin
   cortar, y aparece la barra horizontal aunque sobre espacio en las demas
   columnas. "anywhere" (no "break-word") es el que si reduce ese minimo. */
.tabla-actas td, .tabla-actas th { overflow-wrap: anywhere; }

/* ...pero "anywhere" tambien parte palabras CORTAS cuando la ventana se
   estrecha, y la tabla quedaba con "Entreg/a", "Firmad/a" y hasta "Ve/r"
   partidos en dos lineas (Byron 2026-08-25, visto en una pantalla de 1280px).
   Se corrige por partes en vez de quitar el "anywhere", que sigue haciendo
   falta para los correos y hostnames largos:

   1. La tabla no baja de un ancho legible; por debajo de eso, el contenedor
      .tabla-scroll hace lo que ya sabe hacer -- desplazarse -- en vez de
      apretujar las columnas.
   2. Las columnas de dato corto (estado, fechas, tipo, el enlace "Ver")
      nunca se parten. */
.tabla-actas { min-width: 62rem; }

/* ...salvo cuando la tabla vive dentro de una rejilla de dos columnas (el
   panel de seguridad). Ahi el min-width la desbordaba sobre la tabla vecina y
   el texto quedaba SUPERPUESTO e ilegible -- visto al revisar el panel el
   2026-08-25. En dos columnas manda el ancho de la columna. */
.columnas-dos .tabla-actas { min-width: 0; }
.tabla-actas td.no-partir,
.tabla-actas th.no-partir,
.tabla-actas .pill,
.tabla-actas .badge-rol,
.tabla-actas .badge-info,
.tabla-actas .badge-alerta,
.tabla-actas .badge-critico { overflow-wrap: normal; white-space: nowrap; }

/* La ultima columna son las acciones (Ver / Editar / Eliminar): son verbos
   cortos y partirlos ("Ve/r") se ve descuidado. Vale para todas las tablas
   sin tener que marcar celda por celda en cada plantilla. */
.tabla-actas td:last-child, .tabla-actas th:last-child { overflow-wrap: normal; white-space: nowrap; }

/* Columnas de NOMBRE PROPIO -- nucleo, tecnico, colaborador, cargo, area,
   empresa. No se parten por DENTRO de la palabra, pero la celda si puede
   envolver entre palabras: "CAUDA/L" se ve roto (Byron 2026-09-01) y
   "PUERTO / RICO" esta perfecto.

   Por que no vale `no-partir` aqui: ese ademas prohibe envolver, y un nombre
   de tres palabras ensancharia la columna entera. Y por que no se quita el
   `overflow-wrap: anywhere` de la tabla: sigue haciendo falta para lo que de
   verdad no tiene espacios -- correos, hostnames y seriales largos. Justo por
   eso la columna Correo de /admin/colaboradores NO lleva esta clase. */
.tabla-actas td.palabras-enteras { overflow-wrap: normal; }

/* Encabezados que ordenan la columna al hacer clic (A-Z / Z-A), con la flecha
   indicadora a la derecha. Centralizado 2026-09-11: lo usan el inventario de
   PC y el listado de actas/mantenimientos. */
.tabla-actas th.ordenable { cursor: pointer; user-select: none; white-space: nowrap; }
.tabla-actas th.ordenable::after { content: "\2195"; opacity: .3; margin-left: .35rem; font-size: .8em; }
.tabla-actas th.orden-asc::after { content: "\2191"; opacity: .95; }
.tabla-actas th.orden-desc::after { content: "\2193"; opacity: .95; }

/* Buscador multi-criterio en cliente (inventario de PC y listado de actas):
   filas de input que filtran las filas de la tabla. Centralizado 2026-09-11
   -- antes vivia inline y por ID en cada plantilla. */
.criterio-fila { display: flex; gap: .5rem; align-items: center; margin-bottom: .4rem; max-width: 34rem; }
.criterio-fila input.criterio { flex: 1; margin: 0; }
.quitar-criterio { border: none; background: transparent; font-size: 1.3rem; line-height: 1; cursor: pointer; color: var(--texto-suave); padding: 0 .3rem; }
.quitar-criterio:hover { color: var(--rojo-error); }
.btn-agregar-criterio { margin: .1rem 0 1rem; }

/* Ficha de datos en rejilla (detalle de un acta, 2026-09-11): pares
   etiqueta/valor que se acomodan en varias columnas segun el ancho. Mismo
   lenguaje visual que la hoja de vida del colaborador. */
.ficha-datos { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: .9rem 1.4rem; margin: 1rem 0 1.4rem; }
.ficha-datos > div { min-width: 0; }
.ficha-datos .ancho { grid-column: 1 / -1; }
.ficha-et { display: block; font-size: .72rem; font-weight: 700; color: var(--texto-suave); text-transform: uppercase; letter-spacing: .06em; margin-bottom: .15rem; }
.ficha-val { display: block; font-size: .98rem; overflow-wrap: anywhere; }
.ficha-val.suave { color: var(--texto-suave); }

/* Los ENCABEZADOS nunca se parten. Son etiquetas de una o dos palabras y
   cortarlas ("Firm/adas", "Crea/do") deja la tabla con aspecto de rota. Si por
   eso la tabla no cabe, prefiero que .tabla-scroll se desplace: un encabezado
   ilegible confunde mas que una barra de desplazamiento. */
.tabla-actas th { overflow-wrap: normal; white-space: nowrap; }

/* Segunda linea dentro de una celda: el dato de apoyo (documento del
   colaborador, hostname del equipo, colaborador de un acta) va debajo del
   dato principal, mas pequeño y suave, para que la tabla siga escaneandose
   por la primera linea. Byron 2026-08-24. */
.celda-sub {
  display: block;
  font-size: 0.78rem;
  color: var(--texto-suave);
  line-height: 1.3;
}
.celda-lista { margin: 0; padding: 0; list-style: none; }
.celda-lista li + li { margin-top: 0.35rem; padding-top: 0.35rem; border-top: 1px dashed var(--gris-borde); }

.tabla-perifericos tbody tr, .tabla-actas tbody tr {
  transition: background 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
/* La fila bajo el cursor se oscurece Y se eleva un poco (el efecto que antes
   hacia toda la tabla, Byron 2026-09-11). position/z-index para que la sombra
   y el desplazamiento se dibujen por encima de las filas vecinas. */
.tabla-perifericos tbody tr:hover, .tabla-actas tbody tr:hover {
  background: rgba(36, 81, 38, 0.06);
  transform: translateY(-2px);
  box-shadow: 0 8px 20px -10px rgba(15, 39, 18, 0.35);
  position: relative;
  z-index: 1;
}
/* Fila que abre su detalle al hacer clic (listado de actas / mantenimientos):
   el cursor lo anuncia. Los enlaces/botones de dentro (Editar, Eliminar)
   conservan su propio cursor y no disparan la navegacion de la fila. */
.tabla-actas tbody tr.fila-clic { cursor: pointer; }

/* Perifericos: acordeon de tarjetas, una editable a la vez (Byron
   2026-08-18 -- en celular la tabla vieja mostraba todos los campos de
   todas las filas editables al mismo tiempo, facil tocar el campo de la
   fila equivocada; en PC no molestaba porque hay espacio de sobra, pero se
   unifico un solo componente para no mantener dos disenos distintos). El
   grid de .periferico-cuerpo hace la adaptacion responsive sola: una
   columna en movil, varias en pantallas anchas, sin media queries. */
.perifericos-lista { margin-top: 0.6rem; }
.periferico-vacio { margin-top: 0.6rem; }

.periferico-card {
  background: #fff; border: 1px solid var(--gris-borde); border-radius: 14px;
  margin-top: 0.7rem; box-shadow: var(--sombra-tarjeta); overflow: hidden;
  transition: box-shadow 0.2s ease;
}
.periferico-card:hover { box-shadow: var(--sombra-tarjeta-hover); }

.periferico-header {
  display: flex; align-items: center; gap: 0.75rem; width: 100%;
  padding: 0.75rem 1rem; background: none; border: none; cursor: pointer;
  text-align: left; font: inherit; color: inherit;
}
.periferico-header:focus-visible { outline: 2px solid var(--verde); outline-offset: -2px; border-radius: 12px; }

.periferico-icono {
  width: 38px; height: 38px; border-radius: 999px; flex-shrink: 0;
  background: rgba(36, 81, 38, 0.10); color: var(--verde);
  display: flex; align-items: center; justify-content: center;
}
.periferico-resumen { flex: 1; min-width: 0; }
.periferico-resumen-texto {
  display: block; font-weight: 600; font-size: 0.92rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.periferico-resumen-sub {
  display: block; font-size: 0.8rem; color: var(--texto-suave); margin-top: 0.1rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.periferico-estado-pill { flex-shrink: 0; }
.periferico-chevron { flex-shrink: 0; color: var(--texto-suave); transition: transform 0.2s ease; }
.periferico-card.abierta .periferico-chevron { transform: rotate(180deg); }

.periferico-cuerpo {
  display: none;
  padding: 0.2rem 1rem 1rem; border-top: 1px solid var(--gris-borde);
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 0.2rem 1rem;
}
.periferico-card.abierta .periferico-cuerpo { display: grid; }
.periferico-campo-ancho { grid-column: 1 / -1; }
.periferico-tipo-otro { margin-top: 0.4rem; }

.periferico-pie {
  grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 0.6rem;
  margin-top: 0.6rem; padding-top: 0.7rem; border-top: 1px dashed var(--gris-borde);
}

/* Aviso de "este periferico se desvinculara al firmar" (Byron 2026-08-19) --
   sustituye al checkbox "Ya no esta" de antes: aparece entre el header y el
   cuerpo de la tarjeta (fuera del <button> del acordeon) apenas se confirma
   un motivo en el modal, visible aunque la tarjeta este cerrada. */
.periferico-quitado-banner[hidden] { display: none; }
.periferico-quitado-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; flex-wrap: wrap;
  margin: 0 1rem 0.75rem; padding: 0.6rem 0.8rem;
  background: #fdecea; border: 1px solid rgba(179, 38, 30, 0.35); border-radius: 10px;
  font-size: 0.85rem; color: var(--rojo-error);
}
.periferico-quitado-texto { flex: 1; min-width: 0; }

/* Modal de motivo al quitar un periferico que ya venia de GLPI (Byron
   2026-08-19) -- mismo idioma visual que .overlay-firma (tarjeta blanca
   centrada, fondo oscuro), pero con z-index mas alto porque puede abrirse
   con una tarjeta de periferico ya desplegada detras. */
.overlay-motivo[hidden] { display: none; }
.overlay-motivo {
  position: fixed; inset: 0; z-index: 1002;
  display: flex; align-items: center; justify-content: center;
  padding: 1.5rem;
  background: rgba(15, 39, 18, 0.55);
}
.overlay-motivo-card {
  max-width: 30rem; width: 100%; max-height: 90vh; overflow-y: auto;
  background: #fff; border-radius: 16px; padding: 1.75rem;
  box-shadow: 0 20px 45px -18px rgba(0, 0, 0, 0.55);
}
.overlay-motivo-card h2 { margin: 0 0 0.4rem; color: var(--verde); font-size: 1.15rem; }
.overlay-motivo-opciones { display: flex; flex-direction: column; gap: 0.55rem; margin: 0.9rem 0; }
.chk-inline-bloque { display: flex; align-items: flex-start; gap: 0.5rem; font-size: 0.9rem; cursor: pointer; }
.chk-inline-bloque input { margin-top: 0.2rem; width: auto; }
#modal-motivo-otro { margin-top: 0.3rem; }
.overlay-motivo-acciones { display: flex; gap: 0.6rem; margin-top: 1rem; }
.overlay-motivo-acciones .btn-plano { flex: 1; }

.firma-bloque { margin-top: 1rem; }
.firma-canvas {
  border: 1px solid var(--gris-borde);
  border-radius: 8px;
  background: #fff;
  touch-action: none;
  display: block;
  max-width: 100%;
}
.firma-preview {
  max-width: 250px; display: block; margin: 0.3rem 0 0.6rem;
  border: 1px solid var(--gris-borde); border-radius: 8px; background: #fff; padding: 0.3rem;
}

/* Firma del colaborador en celular (Byron 2026-08-19): el lienzo chico
   embebido obligaba a girar el telefono para tener mas espacio. En
   viewport angosto se reemplaza por un boton que abre un lienzo a pantalla
   completa (.overlay-firma-movil mas abajo); en escritorio/pantalla no
   tactil se deja el lienzo inline de siempre (.firma-escritorio). Los dos
   bloques conviven en el DOM, el @media decide cual se ve -- el JS de
   actas_firmar.html pregunta por ese mismo estado calculado en vez de
   duplicar el breakpoint. */
.firma-cta-movil { display: none; }

.btn-abrir-firma {
  width: 100%; display: flex; align-items: center; gap: 0.9rem; text-align: left;
  background: #fff; border: 1px solid rgba(36, 81, 38, 0.18); border-radius: 14px;
  padding: 0.9rem 1.1rem; cursor: pointer;
  box-shadow: var(--sombra-tarjeta);
  transition: box-shadow var(--transicion), transform var(--transicion), border-color var(--transicion);
}
.btn-abrir-firma:hover { box-shadow: var(--sombra-tarjeta-hover); transform: translateY(-1px); }
.btn-abrir-firma:focus-visible { outline: none; box-shadow: var(--anillo-foco-boton); }
.btn-abrir-firma-icono {
  flex-shrink: 0; width: 46px; height: 46px; border-radius: 999px;
  background: linear-gradient(155deg, var(--verde), var(--verde-oscuro));
  color: #fff; display: flex; align-items: center; justify-content: center;
  box-shadow: 0 6px 14px -5px rgba(36, 81, 38, 0.55);
  transition: background var(--transicion);
}
.btn-abrir-firma-icono svg { width: 22px; height: 22px; }
/* SVG raiz con el atributo `hidden` no siempre respeta la regla por
   defecto del navegador para elementos HTML normales -- se refuerza aca en
   vez de confiar en eso (encontrado probando visualmente 2026-08-19: los
   dos iconos, lapiz y check, se veian juntos). */
.btn-abrir-firma-icono svg[hidden] { display: none; }
.btn-abrir-firma-texto { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.btn-abrir-firma-texto strong { font-size: 0.98rem; color: var(--texto); }
.btn-abrir-firma-texto small { color: var(--texto-suave); font-size: 0.82rem; line-height: 1.35; }
/* Estado "ya firmado": insignia pasa a verde solido con el check, borde con
   mas presencia -- misma logica de color que .pill.ok en el resto de la app. */
.btn-abrir-firma.firma-lista { border-color: var(--verde); background: rgba(36, 81, 38, 0.06); }
.btn-abrir-firma.firma-lista .btn-abrir-firma-icono { background: var(--verde); }

@media (max-width: 640px) {
  .firma-escritorio { display: none; }
  .firma-cta-movil { display: block; margin-top: 0.3rem; }
}

/* Lienzo de firma a pantalla completa -- pensado como una hoja en blanco:
   fondo blanco puro (no el overlay oscuro de "guardando", que es para
   ESPERAR, no para escribir), una guia de firma dibujada en el propio
   canvas (X + linea, como en un acta de papel real) y dos botones planos de
   ancho completo abajo, aprovechando todo el alto disponible del celular en
   cualquier orientacion -- ya no hace falta girarlo a mano. */
.overlay-firma-movil[hidden] { display: none; }
.overlay-firma-movil {
  position: fixed; inset: 0; z-index: 1001;
  background: #fff;
  /* El marco de adentro puede quedar mas ancho que el viewport al rotarse:
     aca se recorta para que no aparezcan barras de desplazamiento. */
  overflow: hidden;
}
.overlay-firma-movil-marco {
  position: absolute; top: 0; left: 0; width: 100%; height: 100%;
  background: #fff;
  display: flex; flex-direction: column;
  padding: env(safe-area-inset-top, 0) env(safe-area-inset-right, 0) env(safe-area-inset-bottom, 0) env(safe-area-inset-left, 0);
}
/* Horizontal forzado (Byron 2026-08-20): con el celular en vertical se gira
   el marco entero 90deg para que la pantalla de firma se vea apaisada, sin
   depender de screen.orientation.lock() (no existe en iOS y en Android solo
   funciona en pantalla completa). El ancho/alto intercambiados los pone el JS
   en px reales -- ver aplicarOrientacionFirma() en actas_firmar.html. */
.overlay-firma-movil.rotado .overlay-firma-movil-marco {
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) rotate(90deg);
  /* Los safe-area del sistema siguen refiriendose a los bordes FISICOS de la
     pantalla, asi que al rotar 90deg hay que permutarlos: el borde superior
     del marco cae sobre el borde derecho del telefono, el izquierdo sobre el
     superior, y asi. */
  padding: env(safe-area-inset-right, 0) env(safe-area-inset-bottom, 0) env(safe-area-inset-left, 0) env(safe-area-inset-top, 0);
}
.overlay-firma-movil-cerrar {
  position: absolute; top: 0.6rem; right: 0.6rem;
  width: 40px; height: 40px; border-radius: 999px;
  background: var(--gris-fondo); border: none; color: var(--texto-suave);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: background var(--transicion), color var(--transicion);
}
.overlay-firma-movil-cerrar:hover { background: var(--gris-borde); color: var(--texto); }
.overlay-firma-movil-cerrar svg { width: 20px; height: 20px; }
.overlay-firma-movil-titulo {
  margin: 0.8rem 3.2rem 0.3rem 1rem; text-align: center;
  font-size: 0.92rem; font-weight: 600; color: var(--verde);
}
.firma-canvas-movil-envoltorio {
  position: relative; flex: 1 1 auto; min-height: 0; background: #fff;
}
.firma-canvas-movil-capa {
  position: absolute; inset: 0; width: 100%; height: 100%;
  touch-action: none; display: block;
}
#canvas-guia-movil { pointer-events: none; }
.overlay-firma-movil-aviso {
  margin: 0 1rem 0.4rem; text-align: center; color: var(--rojo-error); font-size: 0.85rem;
}
.overlay-firma-movil-acciones {
  flex-shrink: 0; display: flex; gap: 0.6rem;
  padding: 0.7rem 0.8rem calc(0.7rem + env(safe-area-inset-bottom, 0));
  border-top: 1px solid var(--gris-borde);
}
.btn-plano {
  flex: 1; border-radius: 10px; padding: 0.85rem 0.6rem;
  font-size: 0.95rem; font-weight: 600; cursor: pointer; border: none;
  transition: background var(--transicion), transform var(--transicion);
}
.btn-plano:active { transform: scale(0.98); }
.btn-plano-borrar { background: var(--gris-fondo); color: var(--texto-suave); }
.btn-plano-borrar:hover { background: var(--gris-borde); }
.btn-plano-ok { background: var(--verde); color: #fff; box-shadow: 0 4px 12px -3px rgba(36, 81, 38, 0.5); }
.btn-plano-ok:hover { background: var(--verde-oscuro); }

/* "Listo" del pie de cada periferico (Byron 2026-09-08). Usa el verde de
   .btn-plano pero SIN su `flex: 1`: dentro de .periferico-pie, que es un
   space-between, estirarse se comeria toda la fila y dejaria un boton verde
   del ancho de la tarjeta al lado de un enlace de texto. */
.periferico-pie .periferico-listo {
  flex: 0 0 auto; padding: 0.55rem 1.4rem; font-size: 0.9rem;
}

/* Overlay de "guardando firma" (Byron 2026-08-18): pensado para conexiones
   moviles lentas/inestables en campo -- el envio puede tardar bastante
   (varias llamadas a GLPI con reintentos, ver glpi.py) y se prefiere dejarlo
   muy claro que sigue trabajando en vez de que parezca colgado. */
.overlay-firma[hidden] { display: none; }
.overlay-firma {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  padding: 1.5rem;
  background:
    radial-gradient(50rem 38rem at 85% 85%, rgba(36, 81, 38, 0.35), transparent 60%),
    linear-gradient(155deg, rgba(15, 39, 18, 0.94) 0%, rgba(20, 51, 24, 0.94) 60%, rgba(27, 66, 32, 0.94) 100%);
}
.overlay-firma-card {
  max-width: 26rem; width: 100%;
  background: #fff; border-radius: 16px; padding: 2rem 1.75rem;
  text-align: center; box-shadow: 0 20px 45px -18px rgba(0, 0, 0, 0.55);
}
.overlay-firma-spinner {
  width: 56px; height: 56px; margin: 0 auto 1.1rem;
  border-radius: 999px; border: 5px solid var(--gris-borde); border-top-color: var(--verde);
  animation: overlay-firma-girar 0.9s linear infinite;
}
@keyframes overlay-firma-girar { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .overlay-firma-spinner { animation: none; border-top-color: var(--gris-borde); }
}
.overlay-firma-card h2 { margin: 0 0 0.5rem; color: var(--verde); font-size: 1.2rem; }
.overlay-firma-card p { margin: 0; color: var(--texto-suave); font-size: 0.92rem; line-height: 1.5; }
.overlay-firma-espera { margin-top: 0.8rem; }
.overlay-firma-reintento { margin-top: 0.5rem; }
.overlay-firma-reintento .error { text-align: left; margin-bottom: 1rem; }
.overlay-firma-reintento button { width: 100%; margin-top: 0.5rem; }

/* Overlay breve de confirmacion "Guardado" (Byron 2026-08-19): a diferencia
   de .overlay-firma (opaco a proposito, para envios largos que no se deben
   interrumpir), este es translucido -- dura ~1.5s y solo confirma, luego el
   JS que lo acompana redirige solo de vuelta al listado. */
.overlay-guardado[hidden] { display: none; }
.overlay-guardado {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  padding: 1.5rem;
  background: rgba(15, 39, 18, 0.45);
  backdrop-filter: blur(3px);
  animation: overlay-guardado-fondo 1.5s ease forwards;
}
.overlay-guardado-card {
  background: #fff; border-radius: 16px; padding: 2.2rem 2.75rem;
  text-align: center; box-shadow: 0 20px 45px -18px rgba(0, 0, 0, 0.55);
  animation: overlay-guardado-entrada 0.35s ease;
}
.overlay-guardado-icono {
  width: 64px; height: 64px; margin: 0 auto 1rem;
  border-radius: 999px; background: linear-gradient(155deg, var(--verde), var(--verde-oscuro));
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 8px 18px -4px rgba(36, 81, 38, 0.55);
}
.overlay-guardado-icono svg { width: 32px; height: 32px; color: #fff; }
.overlay-guardado-card h2 { margin: 0; color: var(--verde); font-size: 1.6rem; }
@keyframes overlay-guardado-entrada {
  from { opacity: 0; transform: scale(0.9) translateY(6px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes overlay-guardado-fondo {
  0%, 82% { opacity: 1; }
  100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .overlay-guardado, .overlay-guardado-card { animation: none; }
}

.filtro-estado { margin: 0.8rem 0; }
.filtro-estado select { max-width: 260px; }

.resumen { background: var(--ivory-2); border-radius: 8px; padding: 0.8rem 1rem; margin-bottom: 1rem; }

/* Foco de teclado con el verde de marca en vez del azul por defecto del
   navegador. Se usa :focus-visible (no :focus) para no mostrar el anillo
   en clics de mouse/touch, solo en navegacion por teclado. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--verde);
  outline-offset: 2px;
  border-radius: 4px;
}

@media (max-width: 480px) {
  .login-card { margin: 1.5rem 1rem; padding: 1.5rem; }
  /* La barra ya NO se apila en vertical en pantallas muy estrechas: con la
     hamburguesa y los tres puntos, todo cabe en una sola fila y la navegacion
     baja a su panel solo cuando se pide. Apilarla aqui devolvia las tres
     lineas que justamente se querian quitar. */
}

/* Por debajo de ~400px (Galaxy S y iPhone mini) el nombre COMPLETO ya no cabe:
   medido, empujaba el bloque de usuario a una segunda linea y la barra volvia
   a 88px. En vez de recortarlo a "BYRON M..." -- que no dice mas que nada y
   encima se ve descuidado -- se muestra solo el nombre de pila, entero. El
   apellido sigue estando: el desplegable de los tres puntos lo trae completo. */
.topbar-nombre-corto { display: none; }
@media (max-width: 400px) {
  .topbar-nombre { display: none; }
  .topbar-nombre-corto { display: block; }
}

/* La barra en el celular (Byron 2026-08-25).
   Historia corta: al fijarla arriba se comia TRES lineas -- casi el 40% de la
   pantalla -- porque los cuatro enlaces de navegacion no caben al lado de la
   marca y del usuario. Primero se intento comprimir (fuente mas chica, la nav
   con desplazamiento horizontal); seguian siendo tres lineas.

   La solucion de verdad es la de la web corporativa: por debajo del corte la
   navegacion deja de estar a la vista y se recoge en la hamburguesa. Asi la
   barra queda en UNA sola fila -- hamburguesa, marca, nombre, rol y los tres
   puntos -- y los enlaces bajan en un panel solo cuando se piden.

   El GESTO es el del sitio; el CORTE no. La web lo pone en 720px, pero su
   cabecera solo lleva logo y enlaces. La de TrackIT arrastra ademas el bloque
   de usuario (nombre + rol + los tres puntos). Medido pieza a pieza: 40 de
   padding + 107 de marca + 24 de margen + 372 que pide la navegacion + 8 de
   hueco + 311 del bloque de usuario = 862px para que la fila NO se parta.
   De ahi los 900px: el numero sale de donde deja de caber (mas un margen),
   no de una talla redonda. Con 860 se partia por un pixel. */
@media (max-width: 900px) {
  .nav-toggle { display: flex; }

  .topbar-nav {
    /* order alto = ultimo elemento de la barra; base del 100% = linea propia.
       Con esto el panel cae DEBAJO de la fila sin position:absolute, asi que
       no hace falta clavar a mano la altura de la barra (que cambia entre
       tamanos) ni preocuparse de que tape el contenido. */
    order: 10;
    flex-basis: 100%;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin: 0.35rem -0.9rem -0.5rem;
    padding: 0.25rem 0.9rem 0.6rem;
    background: rgba(15, 39, 18, 0.35);
  }
  .topbar.nav-abierta .topbar-nav { display: flex; }
  .topbar-nav a {
    font-size: 0.95rem;
    font-weight: 500;
    padding: 0.75rem 0.25rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.10);
  }
  .topbar-nav a:last-child { border-bottom: none; }
  /* El subrayado ambar que crece es un gesto de raton; en tactil no hay hover,
     y ademas aqui cada enlace ocupa su propia fila. */
  .topbar-nav a::after { display: none; }

  .topbar { padding: 0.5rem 0.9rem; gap: 0.5rem; row-gap: 0.35rem; }
  /* La marca NO se encoge. Con `flex:1; min-width:0` se quedaba en 77px con
     95px de contenido y "TrackIT" se metia por debajo del nombre del usuario
     (visto midiendo a 390px, no a ojo). Quien cede el sitio cuando falta es el
     nombre, que para eso lleva los puntos suspensivos. */
  .topbar-brand { font-size: 1rem; gap: 0.5rem; flex: 0 0 auto; }
  .topbar-emblema { height: 28px; }
  .topbar-user {
    flex: 1 1 auto;
    min-width: 0;
    justify-content: flex-end;
    gap: 0.5rem;
    font-size: 0.85rem;
  }
  /* El nombre se QUEDA (antes se ocultaba entero por falta de sitio): cabe
     recortado, y el desplegable de los tres puntos lo repite completo. */
  .topbar-nombre { flex: 0 1 auto; min-width: 0; max-width: 7rem; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
  .login-card:hover, fieldset:hover,
  .tabla-perifericos tbody tr:hover, .tabla-actas tbody tr:hover,
  button[type="submit"]:hover, .btn-primario-link:hover, .login-card button:hover {
    transform: none !important;
  }
}

/* --- Sync/completar de colaboradores (Byron 2026-08-24) --------------------
   Colaboradores importados de la API nacen incompletos; se completan inline en
   el acta (.completar-colaborador) o desde el panel. */
.exito { color: var(--verde); font-weight: 600; }
.acciones-colaboradores { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; margin: 0.6rem 0; }
.completar-colaborador {
  margin-top: 0.7rem; padding: 0.7rem 0.8rem; border: 1px solid rgba(179, 38, 30, 0.35);
  border-radius: 8px; background: rgba(179, 38, 30, 0.05);
}
.completar-colaborador label { display: block; margin-top: 0.5rem; font-size: 13px; }
.aviso-incompleto { margin: 0 0 0.4rem; font-size: 13px; color: var(--rojo-error); }

/* Marca del cargo escrito a mano: el sync no lo sobrescribe (Byron
   2026-08-27). Discreta a proposito -- aparece en cada fila del listado de
   colaboradores y no debe competir con las pastillas de estado. */
.marca-manual {
  margin-left: 0.35rem; color: var(--verde); font-size: 0.85em;
  vertical-align: baseline; cursor: help;
}

/* ===========================================================================
   Panel de seguridad (/admin/seguridad) -- Byron 2026-08-25
   Reusa la paleta y la sombra de tarjeta ya aprobadas; solo agrega el rojo/
   ambar de severidad, que no existian porque hasta ahora nada en la app
   necesitaba distinguir "esto es un ataque" de "esto es informativo".
   =========================================================================== */
.tarjetas-resumen {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 0.9rem;
  margin: 1rem 0 1.6rem;
}
.tarjeta {
  background: #fff; border: 1px solid var(--gris-borde); border-radius: 14px;
  padding: 0.9rem 1rem; box-shadow: var(--sombra-tarjeta);
  display: flex; flex-direction: column; gap: 0.15rem;
}
.tarjeta-numero { font-size: 2rem; font-weight: 700; line-height: 1.1; color: var(--verde-oscuro); }
.tarjeta-titulo { font-weight: 600; font-size: 0.92rem; }
.tarjeta-sub { color: var(--texto-suave); font-size: 0.82rem; }
.tarjeta-alerta { border-color: var(--amber); }
.tarjeta-alerta .tarjeta-numero { color: var(--ambar-texto); }
.tarjeta-critica { border-color: var(--rojo-error); }
.tarjeta-critica .tarjeta-numero { color: var(--rojo-error); }

.columnas-dos {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 1.4rem; align-items: start;
}

.badge-info, .badge-alerta, .badge-critico {
  display: inline-block; border-radius: 999px;
  padding: 0.1rem 0.55rem; font-size: 0.78rem; white-space: nowrap;
}
.badge-info    { background: rgba(36, 81, 38, 0.10); color: var(--verde-oscuro); border: 1px solid var(--verde); }
.badge-alerta  { background: rgba(248, 154, 40, 0.16); color: var(--ambar-texto); border: 1px solid var(--amber); }
.badge-critico { background: #fdecea; color: var(--rojo-error); border: 1px solid var(--rojo-error); }

/* Una franja de color a la izquierda de la fila: se lee el nivel de gravedad
   recorriendo la tabla con la vista, sin tener que leer cada badge. */
.fila-alerta  td:first-child { box-shadow: inset 3px 0 0 var(--amber); }
.fila-critico td:first-child { box-shadow: inset 3px 0 0 var(--rojo-error); }

/* ===========================================================================
   Filtros de listado (Byron 2026-08-25)
   ---------------------------------------------------------------------------
   Reemplazan a los <select> de "Filtrar por estado" / "Mostrar". Tres motivos,
   todos de uso y no de estetica:

   1. UN clic en vez de tres. Un <select> obliga a abrir, leer y elegir; aqui
      todas las opciones estan a la vista y se cambia de una.
   2. El CONTEO. Es lo que convierte un filtro en informacion: se ve cuantas
      hay en cada estado ANTES de entrar. "Borrador 3" dice algo que el select
      nunca dijo.
   3. Se ve donde estas parado sin tener que leer el control.

   Siguen siendo enlaces normales (GET con query param), igual que el <select>
   con onchange que reemplazan: funcionan sin JS, se pueden abrir en otra
   pestana, y el boton "atras" del navegador se comporta como se espera.
   =========================================================================== */
.filtros {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.9rem 0 1.1rem;
}

.filtro-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.4rem 0.85rem;
  border: 1px solid var(--gris-borde);
  border-radius: 999px;
  background: #fff;
  color: var(--texto);
  font-size: 0.92rem;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color var(--transicion), background var(--transicion),
              color var(--transicion), box-shadow var(--transicion);
}
.filtro-chip:hover {
  border-color: var(--verde);
  box-shadow: var(--sombra-tarjeta);
}

/* El activo se marca con el verde de marca, no con un gris: en una fila de
   seis opciones el estado seleccionado tiene que leerse de un vistazo. */
.filtro-chip.activo {
  background: var(--verde);
  border-color: var(--verde);
  color: #fff;
  font-weight: 600;
}
.filtro-chip.activo:hover { background: var(--verde-oscuro); border-color: var(--verde-oscuro); }

.filtro-conteo {
  display: inline-block;
  min-width: 1.5rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: rgba(36, 81, 38, 0.10);
  color: var(--verde-oscuro);
  font-size: 0.8rem;
  font-weight: 600;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.filtro-chip.activo .filtro-conteo { background: rgba(255, 255, 255, 0.22); color: #fff; }

/* Un cero no es lo mismo que un numero: se atenua para que la vista se vaya
   sola a los estados que SI tienen algo esperando. */
.filtro-conteo.vacio { background: rgba(75, 90, 79, 0.10); color: var(--texto-suave); }
.filtro-chip.activo .filtro-conteo.vacio { background: rgba(255, 255, 255, 0.18); color: #fff; }

/* Chip que avisa: se usa cuando lo que hay detras necesita atencion (actas a
   punto de eliminarse, solicitudes pendientes, eventos criticos). El color
   solo aparece cuando el conteo es > 0 -- si no, seria una alarma permanente
   que se deja de mirar. */
.filtro-chip.urgente:not(.activo) { border-color: var(--rojo-error); }
.filtro-chip.urgente:not(.activo) .filtro-conteo { background: rgba(179, 38, 30, 0.12); color: var(--rojo-error); }

.filtros-titulo {
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--texto-suave);
  margin: 1rem 0 0.1rem;
}

@media (max-width: 640px) {
  /* En movil la fila se convierte en un carrusel horizontal en vez de
     apilarse en cuatro lineas y empujar la tabla fuera de la pantalla. */
  .filtros {
    flex-wrap: nowrap;
    overflow-x: auto;
    padding-bottom: 0.3rem;
    scrollbar-width: thin;
  }
  .filtro-chip { flex-shrink: 0; }
}


/* Barra de filtros en linea (Byron 2026-08-25). Reemplaza a los controles
   apilados uno debajo de otro, que en el panel de seguridad empujaban el
   contenido util media pantalla hacia abajo antes de que se viera nada. */
.barra-filtros {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem 1rem;
  padding: 0.85rem 1rem;
  background: #fff;
  border: 1px solid var(--gris-borde);
  border-radius: 14px;
  box-shadow: var(--sombra-tarjeta);
  margin-bottom: 1.2rem;
}
.barra-filtros .campo {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 0;
}
.barra-filtros label {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--texto-suave);
  margin: 0;
}
.barra-filtros select,
.barra-filtros input {
  margin: 0;
  min-width: 12rem;
  /* Un <select> crece hasta su opcion mas larga: el de "Tipo" tiene etiquetas
     de una frase entera y se comia media barra. Se acota y el texto largo se
     recorta con puntos suspensivos. */
  max-width: 18rem;
  text-overflow: ellipsis;
}
.barra-filtros .campo-ancho input { min-width: 16rem; }
.barra-filtros button { margin: 0; }

@media (max-width: 640px) {
  .barra-filtros { flex-direction: column; align-items: stretch; }
  .barra-filtros select, .barra-filtros input { min-width: 0; width: 100%; }
}

/* ===========================================================================
   Aviso de guardado -- toast superpuesto (Byron 2026-08-27)
   ---------------------------------------------------------------------------
   El problema que resuelve, con sus palabras: "le doy en el boton y la funcion
   si se cumple, pero porque yo se como funciona; otra persona que usa la
   plataforma no queda confiada que haya guardado algo". Guardar el borrador
   redirige a la misma pantalla, asi que el resultado visible de pulsar el
   boton era... nada. La accion se confirma, no se supone.

   Va ARRIBA y no abajo (que es donde la costumbre pone los toast) por una
   razon concreta de este flujo: guardar hace POST-redirect-GET, el navegador
   recarga la pantalla desplazada al tope, y el ojo del tecnico queda ahi. Un
   aviso abajo apareceria fuera de la vista justo en el momento en que hay que
   verlo. Se cuelga debajo de la barra fija midiendola en JS (--alto-topbar):
   la barra envuelve a dos lineas en pantallas angostas, asi que una distancia
   fija en el CSS la taparia en unos anchos y dejaria un hueco en otros.

   Verde profundo de la marca sobre marfil: el unico bloque de color oscuro
   que aparece sobre el contenido, imposible de confundir con .error (rojo) o
   con una tarjeta normal (blanca). El chulo se DIBUJA una vez -- es el gesto
   de sellar un documento, que es exactamente lo que acaba de pasar. */
.aviso-guardado[hidden] { display: none; }
.aviso-guardado {
  position: fixed;
  top: calc(var(--alto-topbar, 4.5rem) + 0.75rem);
  left: 50%;
  transform: translateX(-50%);
  z-index: 130;  /* sobre el menu de cuenta (120), debajo de los overlay */
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  max-width: min(28rem, calc(100vw - 1.5rem));
  padding: 0.8rem 0.9rem;
  background: var(--green-800);
  color: var(--ivory);
  border: 1px solid rgba(251, 178, 78, 0.35);
  border-radius: 12px;
  box-shadow: 0 18px 40px -14px rgba(15, 39, 18, 0.55), 0 2px 8px rgba(15, 39, 18, 0.20);
}

.aviso-guardado-icono { flex: none; width: 22px; height: 22px; margin-top: 1px; color: var(--gold); }
.aviso-guardado-icono circle { opacity: 0.45; }
.aviso-guardado-texto { min-width: 0; }
.aviso-guardado-titulo {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: 0.01em;
}
.aviso-guardado-detalle {
  margin: 0.15rem 0 0;
  font-size: 0.82rem;
  line-height: 1.4;
  color: rgba(250, 246, 239, 0.78);
}
.aviso-guardado-cerrar {
  flex: none;
  margin: -0.2rem -0.2rem 0 0;
  padding: 0.25rem;
  background: none;
  border: none;
  border-radius: 6px;
  color: rgba(250, 246, 239, 0.70);
  line-height: 0;
  box-shadow: none;
}
.aviso-guardado-cerrar:hover {
  background: rgba(250, 246, 239, 0.12);
  color: var(--ivory);
  transform: none;
  box-shadow: none;
}
.aviso-guardado-cerrar:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 1px;
}
.aviso-guardado-cerrar svg { width: 16px; height: 16px; }

/* Entrada: baja desde la barra, como si la barra misma lo soltara.
   Salida: la misma animacion al reves, disparada con la clase .saliendo. */
@keyframes aviso-guardado-entra {
  from { opacity: 0; transform: translate(-50%, -0.6rem); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
@keyframes aviso-guardado-sale {
  from { opacity: 1; transform: translate(-50%, 0); }
  to   { opacity: 0; transform: translate(-50%, -0.6rem); }
}
.aviso-guardado { animation: aviso-guardado-entra 260ms var(--ease) both; }
.aviso-guardado.saliendo { animation: aviso-guardado-sale 240ms var(--ease) both; }

/* El chulo se traza en vez de aparecer hecho: 34 es la longitud del path. */
@keyframes aviso-guardado-traza { from { stroke-dashoffset: 34; } to { stroke-dashoffset: 0; } }
.aviso-guardado-chulo {
  stroke-dasharray: 34;
  animation: aviso-guardado-traza 420ms var(--ease) 120ms both;
}

@media (prefers-reduced-motion: reduce) {
  .aviso-guardado,
  .aviso-guardado.saliendo { animation-duration: 1ms; }
  .aviso-guardado-chulo { animation: none; stroke-dashoffset: 0; }
}

@media (max-width: 640px) {
  .aviso-guardado {
    left: 0.75rem;
    right: 0.75rem;
    max-width: none;
    transform: none;
  }
  /* En un telefono la X medida daba 24 px de lado: se falla con el pulgar.
     El icono se queda del mismo tamano y lo que crece es el area que
     responde, centrada en la tarjeta -- que mide bastante mas de 44 px de
     alto, asi que no la deforma. */
  .aviso-guardado-cerrar {
    min-width: 44px;
    min-height: 44px;
    margin: -0.35rem -0.35rem 0 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  /* Sin centrado horizontal que compensar, las animaciones no llevan el
     translateX(-50%) -- si lo llevaran, el aviso se saldria de la pantalla. */
  @keyframes aviso-guardado-entra {
    from { opacity: 0; transform: translateY(-0.6rem); }
    to   { opacity: 1; transform: translateY(0); }
  }
  @keyframes aviso-guardado-sale {
    from { opacity: 1; transform: translateY(0); }
    to   { opacity: 0; transform: translateY(-0.6rem); }
  }
}

/* Se guardo, pero hay algo que saber. Cambia el icono y su color; el resto
   del aviso se queda igual porque el hecho principal -- se guardo -- es el
   mismo. Un segundo componente rojo aqui diria "fallo", que seria mentira. */
.aviso-guardado.atencion { border-color: rgba(248, 154, 40, 0.55); }
.aviso-guardado.atencion .aviso-guardado-icono { color: var(--amber); }
.aviso-guardado.atencion .aviso-guardado-icono circle { opacity: 0.6; }

/* Grupos de mantenimiento (2026-09-14): "Cambiar nombre o jefe de area"
   plegado para que el detalle arranque por los PC, que es a lo que se entra. */
.bloque-editar { margin: 0 0 1.4rem; }
.bloque-editar > summary { display: inline-block; cursor: pointer; margin-bottom: .4rem; }
.bloque-editar[open] { background: var(--ivory-2); border-radius: 8px; padding: .8rem 1rem; }
/* Con ~75 PC en la lista, el boton quedaba al fondo: se queda pegado abajo. */
.form-pc .acciones { position: sticky; bottom: 0; z-index: 2; background: var(--ivory); padding: .6rem 0; margin-top: .4rem; }

/* Calendario de mantenimiento (2026-09-14). */
.barra-ciclo { display: flex; flex-wrap: wrap; gap: .4rem 1.2rem; align-items: center; margin: .6rem 0 1rem; }
.barra-ciclo strong { font-size: 1.1rem; }
.tabla-calendario td { vertical-align: top; }
.tabla-calendario tr.semana-actual td { background: var(--ivory-2); }
.tabla-calendario tr.semana-pasada td:first-child { color: var(--texto-suave); }
.prog-tarjeta { display: block; margin: .2rem 0 .35rem; padding: .35rem .65rem; border-left: 4px solid var(--texto-suave);
  border-radius: 6px; background: #fff; color: inherit; text-decoration: none; box-shadow: 0 1px 2px rgba(0,0,0,.07); }
.prog-tarjeta:hover { background: var(--ivory); }
.prog-tarjeta.ok { border-left-color: var(--verde); }
.prog-tarjeta.alerta { border-left-color: var(--rojo-error); }
.resumen-ciclo { display: flex; flex-wrap: wrap; gap: .4rem; margin: .2rem 0 1rem; }
.tabla-calendario .celda-semana { width: 11rem; }
@media (max-width: 600px) { .tabla-calendario .celda-semana { width: 6.5rem; } }

/* Inicio del tecnico: indicadores (2026-09-16). Reusa .tarjeta del panel de
   seguridad; el medidor es verde sobre un tinte del mismo verde. */
.kpi-bloque { margin: 1.2rem 0 1.8rem; }
.kpi-cabecera { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .3rem 1rem; }
.kpi-cabecera h2 { margin: 0; }
.kpi-bloque .tarjetas-resumen { margin: .7rem 0 .9rem; }
.kpi-medidor { height: 8px; border-radius: 4px; background: rgba(36, 81, 38, 0.14); overflow: hidden; margin: .3rem 0 .15rem; }
.kpi-medidor > span { display: block; height: 100%; border-radius: 4px; background: var(--verde); }
.kpi-lista { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: .2rem .9rem; }
.kpi-lista .pill { margin-top: .25rem; }
.kpi-marca { font-size: .78rem; color: var(--ambar-texto); font-weight: 600; }
.kpi-vacio { color: var(--texto-suave); font-size: .9rem; margin: .4rem 0; }

/* ===========================================================================
   Submenu "Inventario" de la barra (Byron 2026-09-16)
   ---------------------------------------------------------------------------
   El boton no navega, solo abre. En PC: tarjeta blanca flotante que baja,
   crece y se desvanece a la vez, con los dos items entrando escalonados y la
   flecha girando. En movil (dentro de la hamburguesa): acordeon que se
   despliega con grid-template-rows 0fr -> 1fr, sin alturas fijas.
   Todo lo dispara aria-expanded / .abierto; el JS no anima nada.
   =========================================================================== */
.nav-sub { position: relative; display: flex; }
.nav-sub-boton {
  display: inline-flex; align-items: center; gap: .3rem;
  background: none; border: 0; padding: .35rem 0; margin: 0; cursor: pointer;
  color: rgba(255, 255, 255, 0.86); font: inherit; font-size: 0.92rem; font-weight: 500;
  position: relative; transition: color .2s var(--ease);
}
.nav-sub-boton::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 2px; width: 0;
  background: var(--amber); transition: width .28s var(--ease);
}
.nav-sub-boton:hover, .nav-sub.abierto .nav-sub-boton { color: #fff; }
.nav-sub-boton:hover::after, .nav-sub.abierto .nav-sub-boton::after { width: 100%; }
.nav-sub-boton:focus-visible { outline: 2px solid #fff; outline-offset: 2px; border-radius: 2px; }
.nav-sub-flecha { transition: transform .32s var(--ease); }
.nav-sub.abierto .nav-sub-flecha { transform: rotate(180deg); color: var(--gold); }

.nav-sub-panel {
  position: absolute; top: calc(100% + .75rem); left: 50%; z-index: 130;
  min-width: 13rem; padding: .45rem;
  background: #fff; border: 1px solid var(--gris-borde); border-radius: 14px;
  box-shadow: 0 22px 44px -18px rgba(15, 39, 18, .5), 0 3px 10px rgba(15, 39, 18, .12);
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translate(-50%, -10px) scale(.95); transform-origin: top center;
  transition: opacity .22s var(--ease), transform .32s var(--ease), visibility 0s linear .32s;
}
/* Piquito que apunta al boton. */
.nav-sub-panel::before {
  content: ""; position: absolute; top: -6px; left: 50%; width: 12px; height: 12px;
  background: #fff; border-left: 1px solid var(--gris-borde); border-top: 1px solid var(--gris-borde);
  transform: translateX(-50%) rotate(45deg); border-radius: 3px 0 0 0;
}
.nav-sub.abierto .nav-sub-panel {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translate(-50%, 0) scale(1);
  transition: opacity .22s var(--ease), transform .32s var(--ease), visibility 0s;
}
.nav-sub-lista { display: flex; flex-direction: column; gap: .15rem; min-height: 0; }
.topbar-nav .nav-sub-item {
  display: flex; align-items: center; gap: .65rem;
  padding: .6rem .75rem; border-radius: 9px; border: 0;
  color: var(--texto); font-size: .92rem; font-weight: 500; text-decoration: none;
  opacity: 0; transform: translateY(-6px);
  transition: opacity .2s var(--ease), transform .3s var(--ease), background .15s, color .15s;
}
.topbar-nav .nav-sub-item::after { display: none; }
.topbar-nav .nav-sub-item svg { color: var(--green-500); flex-shrink: 0; transition: transform .25s var(--ease); }
.topbar-nav .nav-sub-item:hover { background: var(--ivory-2); color: var(--verde-oscuro); }
.topbar-nav .nav-sub-item:hover svg { transform: scale(1.12); color: var(--amber); }
.topbar-nav .nav-sub-item:focus-visible { outline: 2px solid var(--verde); outline-offset: -2px; }
.nav-sub.abierto .nav-sub-item { opacity: 1; transform: none; }
.nav-sub.abierto .nav-sub-item:nth-child(1) { transition-delay: .06s, .06s, 0s, 0s; }
.nav-sub.abierto .nav-sub-item:nth-child(2) { transition-delay: .12s, .12s, 0s, 0s; }

@media (max-width: 900px) {
  .nav-sub { flex-direction: column; border-bottom: 1px solid rgba(255, 255, 255, 0.10); }
  .nav-sub-boton { justify-content: space-between; width: 100%; padding: .75rem .25rem; font-size: .95rem; }
  .nav-sub-boton::after { display: none; }
  .nav-sub-panel, .nav-sub.abierto .nav-sub-panel {
    position: static; transform: none; min-width: 0; padding: 0;
    background: none; border: 0; border-radius: 0; box-shadow: none;
    visibility: visible; pointer-events: auto; opacity: 1;
    display: grid; grid-template-rows: 0fr; transition: grid-template-rows .32s var(--ease);
  }
  .nav-sub-panel::before { display: none; }
  .nav-sub.abierto .nav-sub-panel { grid-template-rows: 1fr; }
  .nav-sub-lista { overflow: hidden; }
  .nav-sub:not(.abierto) .nav-sub-item { visibility: hidden; }
  .topbar-nav .nav-sub-item {
    color: rgba(255, 255, 255, .9); padding: .65rem .25rem .65rem 1.1rem; border-radius: 8px;
    border-bottom: 0;
  }
  .topbar-nav .nav-sub-item:last-child { margin-bottom: .45rem; }
  .topbar-nav .nav-sub-item svg { color: var(--gold); }
  .topbar-nav .nav-sub-item:hover { background: rgba(255, 255, 255, .08); color: #fff; }
}

/* Inventario del tecnico (2026-09-16): fila vinotinto tenue = sin acta de
   asignacion; ultima columna = equipo vinculado segun GLPI. */
.tabla-actas tbody tr.fila-sin-acta td { background: rgba(122, 31, 46, 0.065); }
.tabla-actas tbody tr.fila-sin-acta:hover td { background: rgba(122, 31, 46, 0.11); }
.pill.inv-sin-acta { background: rgba(122, 31, 46, 0.12); color: var(--vinotinto); }
.inv-leyenda { display: inline-flex; align-items: center; gap: .35rem; }
.inv-muestra { display: inline-block; width: .95rem; height: .95rem; border-radius: 4px;
  background: rgba(122, 31, 46, 0.14); border: 1px solid rgba(122, 31, 46, 0.35); }
/* Sin nowrap general: el modelo ("HP 245 14 INCH G9 NOTEBOOK PC") estiraba la
   tabla y dejaba la columna del vinculado fuera de la pantalla a 1366px. */
.tabla-inventario td:first-child, .tabla-inventario td:nth-last-child(2) { white-space: nowrap; }
.tabla-inventario td.palabras-enteras { min-width: 9rem; }
/* Un modelo o un numero partido a mitad ("24049RN28 / L") ya no se lee. */
.tabla-actas.tabla-inventario td.inv-entero { overflow-wrap: normal; }
.inv-vinculo { display: flex; flex-direction: column; line-height: 1.25; }
.inv-vinculo + .inv-vinculo { margin-top: .35rem; }
.inv-vinculo .muted { font-size: .82em; }

/* ===========================================================================
   Inicio del tecnico como tablero (Byron 2026-09-16): mas ancho, dos columnas
   arriba y el explorador de inventario con filtro cruzado (explorador.js).
   Colores de las graficas: verde = bien, vino = falta, ambar = pendiente,
   gris = sin dato. Siempre con leyenda y numero al lado, nunca solo color.
   =========================================================================== */
.container.tablero { max-width: 2200px; }
.tablero-dos { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 520px), 1fr)); gap: 0 2rem; }
.kpi-subtitulo { display: flex; align-items: baseline; gap: .8rem; font-size: 1rem; margin: 1rem 0 0; }
.kpi-subtitulo a { font-size: .85rem; font-weight: 500; }
h3.kpi-subtitulo { margin-top: .6rem; }

.explorador { border-top: 1px solid var(--gris-borde); padding-top: 1.2rem; }
.exp-controles { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1rem; margin: .8rem 0 .2rem; }
.exp-segmentado { display: inline-flex; padding: 3px; background: var(--ivory-2); border: 1px solid var(--gris-borde); border-radius: 999px; }
.exp-segmentado button {
  border: 0; background: none; font: inherit; font-size: .92rem; font-weight: 600; color: var(--texto-suave);
  padding: .4rem 1.1rem; border-radius: 999px; cursor: pointer; transition: background .2s var(--ease), color .2s var(--ease), box-shadow .2s;
}
.exp-segmentado button[aria-pressed="true"] { background: var(--verde); color: #fff; box-shadow: 0 2px 6px rgba(15, 39, 18, .25); }
.exp-segmentado button:focus-visible { outline: 2px solid var(--verde); outline-offset: 2px; }
.exp-filtros { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.exp-pildora {
  display: inline-flex; align-items: center; gap: .35rem; font: inherit; font-size: .85rem; cursor: pointer;
  padding: .3rem .4rem .3rem .75rem; border-radius: 999px; border: 1px solid var(--amber);
  background: rgba(248, 154, 40, .12); color: var(--ambar-texto); animation: exp-entra .25s var(--ease);
}
.exp-pildora-dim { font-weight: 600; }
.exp-pildora-x { display: inline-grid; place-items: center; width: 1.2rem; height: 1.2rem; border-radius: 50%; background: rgba(138, 84, 16, .15); font-weight: 700; }
.exp-pildora:hover .exp-pildora-x { background: var(--ambar-texto); color: #fff; }
.exp-limpiar { font-size: .85rem; }
@keyframes exp-entra { from { opacity: 0; transform: scale(.9); } to { opacity: 1; transform: none; } }

.exp-tarjetas { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.exp-graficas { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr)); gap: 1rem; margin-bottom: 1.4rem; }
.exp-grafica {
  background: #fff; border: 1px solid var(--gris-borde); border-radius: 14px; box-shadow: var(--sombra-tarjeta);
  padding: .9rem 1rem 1rem; min-width: 0; transition: border-color .2s, box-shadow .2s;
}
.exp-grafica.filtrada { border-color: var(--amber); box-shadow: 0 0 0 1px var(--amber), var(--sombra-tarjeta); }
.exp-grafica-dona { grid-column: span 1; }
.exp-grafica-cab { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; margin-bottom: .6rem; }
.exp-grafica-cab h3 { margin: 0; font-size: .95rem; }
.exp-quitar { font-size: .8rem; }

.exp-dona { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.exp-dona-anillo { position: relative; width: 128px; height: 128px; flex-shrink: 0; }
.exp-dona-svg { width: 100%; height: 100%; transform: rotate(-90deg); overflow: visible; }
.exp-dona-fondo { fill: none; stroke: var(--ivory-2); stroke-width: 22; }
.exp-arco { fill: none; stroke-width: 22; cursor: pointer; transition: opacity .2s, stroke-width .2s var(--ease); outline: none; }
.exp-arco:hover, .exp-arco:focus-visible, .exp-arco.elegido { stroke-width: 28; }
.exp-arco.atenuado, .atenuado { opacity: .32; }
.exp-dona-centro { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; pointer-events: none; }
.exp-dona-centro strong { font-size: 1.5rem; line-height: 1; color: var(--verde-oscuro); }
.exp-dona-centro span { font-size: .78rem; color: var(--texto-suave); }
.exp-leyenda { list-style: none; margin: 0; padding: 0; flex: 1 1 175px; min-width: 0; }
.exp-leyenda-fila, .exp-barra {
  display: grid; align-items: center; width: 100%; border: 0; background: none; font: inherit; color: var(--texto);
  text-align: left; cursor: pointer; border-radius: 8px; transition: background .15s, opacity .2s;
}
.exp-leyenda-fila { grid-template-columns: .75rem minmax(0, 1fr) auto auto; gap: .45rem; padding: .35rem .3rem; font-size: .84rem; }
.exp-leyenda-fila:hover, .exp-barra:hover { background: var(--ivory); }
.exp-leyenda-fila:focus-visible, .exp-barra:focus-visible { outline: 2px solid var(--verde); outline-offset: -2px; }
.exp-leyenda-fila.elegido, .exp-barra.elegido { background: rgba(248, 154, 40, .12); }
.exp-muestra { width: .8rem; height: .8rem; border-radius: 3px; }
.exp-leyenda-pct { color: var(--texto-suave); font-size: .8rem; text-align: right; }

.exp-barras { list-style: none; margin: 0; padding: 0; }
.exp-barra { grid-template-columns: minmax(6rem, 46%) 1fr 2.4rem; gap: .6rem; padding: .28rem .4rem; font-size: .84rem; }
.exp-barra-etiqueta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.exp-barra-pista { height: 12px; border-radius: 0 4px 4px 0; background: var(--ivory-2); overflow: hidden; }
.exp-barra-relleno { display: block; height: 100%; background: #3E7F42; border-radius: 0 4px 4px 0; transition: width .45s var(--ease); }
.exp-barra.elegido .exp-barra-relleno { background: var(--green-800); }
.exp-barra-valor { text-align: right; font-variant-numeric: tabular-nums; }
.exp-barra-otros { cursor: default; color: var(--texto-suave); }
.exp-barra-otros:hover { background: none; }
.exp-barra-otros .exp-barra-relleno { background: #9aa39c; }

.exp-tip {
  position: fixed; z-index: 300; pointer-events: none; display: flex; flex-direction: column; gap: .1rem;
  background: var(--green-900); color: #fff; padding: .45rem .65rem; border-radius: 8px; font-size: .82rem;
  box-shadow: 0 8px 20px -8px rgba(0, 0, 0, .45); max-width: 18rem;
}
/* Sin esto el display:flex de arriba le gana al atributo hidden y el cuadro
   nunca se oculta: se queda pegado en la ultima barra (Byron 2026-09-16). */
.exp-tip[hidden] { display: none; }
.exp-tip strong { font-size: .95rem; }
.exp-tip span { color: rgba(255, 255, 255, .8); }
.exp-ver-mas { margin-top: .6rem; }
@media (max-width: 600px) {
  .exp-tarjetas { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .6rem; }
  .exp-tarjetas .tarjeta { padding: .7rem .75rem; }
  .exp-tarjetas .tarjeta-numero { font-size: 1.6rem; }
  .exp-dona-anillo { width: 112px; height: 112px; }
  .exp-dona-centro strong { font-size: 1.35rem; }
  .exp-dona { gap: .6rem; }
}

/* Firma a mano con PDF escaneado (Byron 2026-10-23): plegada debajo de la
   firma en pantalla, que sigue siendo el camino normal. */
.firma-manual {
  margin-top: 1.6rem; padding: 0.9rem 1rem;
  border: 1px solid var(--gris-borde); border-radius: 10px;
}
.firma-manual > summary { cursor: pointer; font-weight: 600; color: var(--verde); }
.firma-manual[open] > summary { margin-bottom: 0.6rem; }
.firma-manual input[type="file"] { display: block; margin: 0.4rem 0; max-width: 100%; }
.lista-movimientos { list-style: none; padding: 0; margin: 0.4rem 0 1rem; }
.lista-movimientos li { padding: 0.5rem 0; border-bottom: 1px solid var(--gris-borde); font-size: 0.9rem; }
.lista-movimientos .celda-sub { display: block; }

/* --- Modulo de radios (Byron 2026-11-06) ------------------------------------ */
.tabla-actas tr.fila-inactiva td { color: var(--texto-suave); }
.radio-resultados { list-style: none; padding: 0; margin: .4rem 0 .8rem; display: grid; gap: .35rem; }
.radio-resultados .btn-secundario { width: 100%; text-align: left; margin: 0; white-space: normal; }
.radio-resultados .inline-form { margin: 0; }
.radio-responsable-actual { margin: .2rem 0 .3rem; }
.radio-sugerencias { margin: 1.2rem 0; padding: .9rem 1rem; border: 1px solid var(--gris-borde); border-radius: 10px; background: #fff; }
.radio-sugerencias h2 { margin-top: 0; font-size: 1.05rem; }
.radio-acciones-rapidas { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: .9rem; margin: 1.2rem 0 1.6rem; }
.radio-tarjeta-accion { border: 1px solid var(--gris-borde); border-radius: 10px; padding: .8rem .9rem; background: #fff; display: flex; flex-direction: column; gap: .35rem; min-width: 0; }
.radio-tarjeta-accion textarea, .radio-tarjeta-accion select { width: 100%; box-sizing: border-box; }
.radio-tarjeta-accion .btn-secundario { align-self: flex-start; }
.radio-hoja-opciones { display: flex; flex-wrap: wrap; gap: .6rem 1.2rem; align-items: flex-end; margin: .4rem 0 .8rem; }
.radio-hoja-opciones > div { min-width: 200px; }
.radio-fila-rechazada td { background: rgba(179, 38, 30, 0.04); }
.radio-modelo-nuevo { margin: .3rem 0 .6rem; font-size: .92rem; }
.radio-modelo-nuevo summary { cursor: pointer; color: var(--texto-suave); }
.aviso-confirmar { color: var(--ambar-texto); font-weight: 600; }
.radio-fotos { margin: 1.4rem 0; }
.radio-fotos-grilla { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: .9rem; margin: .6rem 0 1rem; }
.radio-foto { margin: 0; border: 1px solid var(--gris-borde); border-radius: 10px; background: #fff; padding: .5rem; min-width: 0; }
.radio-foto img { display: block; width: 100%; height: 190px; object-fit: cover; border-radius: 6px; background: var(--ivory-2); }
.radio-foto figcaption { font-size: .85rem; margin-top: .4rem; overflow-wrap: anywhere; }
.radio-foto.retirada img { opacity: .75; }
.radio-foto-acciones { margin-top: .4rem; font-size: .85rem; }
.radio-foto-acciones summary { cursor: pointer; color: var(--texto-suave); }
.radio-foto-acciones form { display: flex; flex-direction: column; gap: .3rem; margin: .5rem 0; }
.radio-foto-acciones input[type="file"], .radio-foto-nueva input[type="file"] { max-width: 100%; }
.radio-foto-nueva { max-width: 520px; }
.radio-fotos-retiradas summary { cursor: pointer; color: var(--texto-suave); }
/* En las tarjetas de accion del radio el boton secundario necesita su borde:
   sin el, sobre fondo blanco se lee como texto suelto. */
.radio-tarjeta-accion button[type="submit"].btn-secundario,
.radio-foto-acciones button[type="submit"].btn-secundario,
.radio-sugerencias button[type="submit"].btn-secundario,
.radio-hoja + .acciones button[type="submit"].btn-secundario,
.acciones-colaboradores button[type="submit"].btn-secundario { border: 1px solid var(--verde); }
.acciones-colaboradores .btn-primario-link { margin-top: .6rem; }
.radio-catalogo-nuevo { display: flex; flex-wrap: wrap; gap: .5rem 1rem; align-items: flex-end; margin: .5rem 0 1rem; }
.radio-catalogo-nuevo > div { min-width: 180px; }
.radio-catalogo-nuevo button[type="submit"].btn-secundario,
.radio-catalogo-fila button[type="submit"].btn-secundario { border: 1px solid var(--verde); margin-top: 0; }
.radio-catalogo-fila { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; margin: 0; }
.radio-catalogo-fila input[type="text"] { width: auto; flex: 1 1 140px; min-width: 120px; margin: 0; }
.radio-rol { border: 1px solid var(--gris-borde); border-radius: 10px; background: #fff; padding: .7rem .9rem; margin: .7rem 0; }
.radio-rol > summary { cursor: pointer; }
.radio-rol.inactivo { opacity: .8; }
.radio-rol form { margin-top: .7rem; }
.radio-matriz td:not(:first-child), .radio-matriz th:not(:first-child) { text-align: center; width: 8.5rem; }
.radio-matriz input[type="radio"] { width: 1.15rem; height: 1.15rem; }
.radio-rol .acciones-colaboradores button[type="submit"]:not(.btn-link) { margin-top: 0; }
.radios-cabecera { align-items: center; margin: .2rem 0 .6rem; }
.radios-resumen-linea { margin: 0; }
.radios-cabecera .acciones-colaboradores { margin: 0; }
.radios-filtros-extra { margin: .2rem 0 .8rem; }
.radios-filtros-extra a.exp-pildora { text-decoration: none; }
.radios-pendientes { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: .9rem; margin-top: .6rem; }
.radios-pend-lista { list-style: none; padding: 0; margin: .4rem 0 0; }
.radios-pend-lista li a, .radios-pend-lista li > span { display: flex; justify-content: space-between; gap: .8rem; padding: .45rem .2rem; border-bottom: 1px solid var(--gris-borde); text-decoration: none; color: inherit; }
.radios-pend-lista li a:hover { background: var(--ivory-2); }
.radios-pend-lista strong { white-space: nowrap; }
.radio-plantilla { max-width: 900px; margin: .8rem 0; }
.radio-plantilla .btn-secundario, .radio-plantilla button[type="submit"] { align-self: flex-start; margin-top: .2rem; }

/* --- Tablero de radios, segunda tanda (2026-11-09): torta, apiladas, columnas --- */
.exp-grafica-ancha { grid-column: 1 / -1; }
.exp-nota { margin: -.3rem 0 .6rem; font-size: .78rem; color: var(--texto-suave); }
.exp-torta-svg { width: 100%; height: 100%; overflow: visible; }
.exp-trozo { cursor: pointer; stroke: var(--surface, #fff); stroke-width: 1.5; transition: opacity .2s, transform .25s var(--ease); outline: none; }
.exp-trozo:hover, .exp-trozo:focus-visible { opacity: .85; }
.exp-apilada { display: grid; grid-template-columns: minmax(6rem, 38%) 1fr 2.4rem; gap: .6rem; align-items: center; padding: .28rem .4rem; font-size: .84rem; }
.exp-apilada-nombre { background: none; border: 0; padding: 0; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.exp-apilada-nombre:hover { text-decoration: underline; }
.exp-apilada-pista { height: 16px; border-radius: 0 4px 4px 0; }
.exp-apilada-total { display: flex; height: 100%; transition: width .45s var(--ease); }
.exp-segmento { display: block; height: 100%; cursor: pointer; transition: opacity .2s, filter .2s; outline: none; }
.exp-segmento + .exp-segmento { box-shadow: inset 1.5px 0 0 var(--surface, #fff); }
.exp-segmento:hover, .exp-segmento:focus-visible, .exp-segmento.elegido { filter: brightness(1.12) saturate(1.1); }
.exp-segmento:focus-visible { outline: 2px solid var(--verde); outline-offset: 1px; }
.exp-leyenda-linea { display: flex; flex-wrap: wrap; gap: .35rem .5rem; margin-top: .7rem; }
.exp-chip { display: inline-flex; align-items: center; gap: .35rem; padding: .2rem .55rem; border: 1px solid var(--gris-borde); border-radius: 999px; background: none; font: inherit; font-size: .78rem; color: inherit; cursor: pointer; }
.exp-chip.elegido { background: rgba(248, 154, 40, .12); border-color: var(--amber); }
.exp-chip-fijo { cursor: default; }
.exp-columnas { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: .4rem; align-items: end; height: 190px; }
.exp-columna { display: flex; flex-direction: column; align-items: center; height: 100%; cursor: pointer; border-radius: 6px; padding: 0 .1rem; outline: none; }
.exp-columna.vacia { cursor: default; }
.exp-columna:not(.vacia):hover, .exp-columna:focus-visible { background: var(--ivory); }
.exp-columna:focus-visible { outline: 2px solid var(--verde); outline-offset: -2px; }
.exp-columna.elegido { background: rgba(248, 154, 40, .12); }
.exp-columna-valor { font-size: .72rem; font-weight: 700; min-height: 1rem; font-variant-numeric: tabular-nums; }
.exp-columna-area { flex: 1; width: 100%; display: flex; align-items: flex-end; justify-content: center; }
.exp-columna-pila { width: min(100%, 34px); display: flex; flex-direction: column; gap: 2px; transition: height .45s var(--ease); }
.exp-columna-bloque { display: block; min-height: 3px; border-radius: 3px; }
.exp-columna-etiqueta { font-size: .68rem; color: var(--texto-suave); margin-top: .3rem; white-space: nowrap; }
@media (max-width: 640px) {
  .exp-columnas { gap: .15rem; height: 160px; }
  .exp-columna-etiqueta { font-size: .58rem; writing-mode: vertical-rl; transform: rotate(180deg); }
  .exp-apilada { grid-template-columns: minmax(5rem, 34%) 1fr 2rem; }
}
.exp-leyenda-sub { display: block; font-size: .72rem; color: var(--texto-suave); margin-top: .1rem; }

/* --- Selector de vista de las graficas (Byron 2026-11-09) ---------------------
   Una pildora con 4 iconos (torta, dona, barras acostadas, barras de pie) en la
   cabecera de cada grafica, y una general arriba con texto. La de cada grafica
   es discreta (no compite con el dato); la general usa el verde del segmentado. */
.exp-grafica-cab { align-items: center; }
.exp-grafica-acciones { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; justify-content: flex-end; }
.exp-vistas { display: inline-flex; gap: 2px; padding: 2px; background: var(--ivory-2); border: 1px solid var(--gris-borde); border-radius: 999px; flex-shrink: 0; }
.exp-vista {
  display: inline-flex; align-items: center; justify-content: center; gap: .35rem;
  min-width: 30px; height: 26px; padding: 0 .4rem; border: 0; border-radius: 999px; background: transparent;
  color: var(--texto-suave); cursor: pointer; font: inherit; font-size: .78rem; font-weight: 600;
  transition: background .2s var(--ease), color .2s, box-shadow .2s, transform .15s;
}
.exp-vista-ico { width: 15px; height: 15px; }
.exp-vista:hover:not(:disabled) { color: var(--verde-oscuro); background: rgba(255, 255, 255, .6); }
.exp-vista:active:not(:disabled) { transform: scale(.92); }
.exp-vista[aria-checked="true"] { background: #fff; color: var(--verde); box-shadow: 0 1px 4px rgba(15, 39, 18, .18); }
.exp-vista:focus-visible { outline: 2px solid var(--verde); outline-offset: 1px; }
.exp-vista:disabled { opacity: .3; cursor: not-allowed; }
.exp-vista-auto { font-size: .74rem; letter-spacing: .02em; }
/* General: mismo lenguaje que el segmentado PC/telefonos (activo en verde). */
.exp-vista-general { display: flex; align-items: center; gap: .55rem; flex-wrap: wrap; }
.exp-vista-general-et { font-size: .82rem; font-weight: 600; color: var(--texto-suave); }
.exp-vistas-global { padding: 3px; }
.exp-vistas-global .exp-vista { height: 32px; padding: 0 .7rem; }
.exp-vistas-global .exp-vista[aria-checked="true"] { background: var(--verde); color: #fff; box-shadow: 0 2px 6px rgba(15, 39, 18, .25); }
.exp-vista-texto:empty { display: none; }
/* Al cambiar de vista la grafica entra con un fundido corto. */
.exp-cuerpo { animation: exp-aparecer .28s var(--ease) both; }
@keyframes exp-aparecer { from { opacity: 0; transform: translateY(4px) scale(.985); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .exp-cuerpo { animation: none; } .exp-vista { transition: none; } }
/* Barras de pie */
.exp-verticales { display: grid; grid-template-columns: repeat(var(--n, 4), minmax(0, 1fr)); gap: .5rem; align-items: end; height: 190px; }
.exp-vertical { display: flex; flex-direction: column; align-items: center; height: 100%; min-width: 0; padding: 0 .1rem; border: 0; border-radius: 8px; background: none; font: inherit; color: inherit; cursor: pointer; }
.exp-vertical:hover { background: var(--ivory); }
.exp-vertical:focus-visible { outline: 2px solid var(--verde); outline-offset: -2px; }
.exp-vertical.elegido { background: rgba(248, 154, 40, .12); }
.exp-vertical-valor { font-size: .82rem; font-variant-numeric: tabular-nums; min-height: 1.1rem; }
.exp-vertical-area { flex: 1; width: 100%; display: flex; align-items: flex-end; justify-content: center; }
.exp-vertical-barra { display: block; width: min(70%, 46px); border-radius: 5px 5px 0 0; transition: height .45s var(--ease); }
.exp-vertical-etiqueta { margin-top: .35rem; font-size: .72rem; line-height: 1.15; text-align: center; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; word-break: break-word; min-height: 2.3em; }
@media (max-width: 640px) {
  .exp-vistas-global .exp-vista-texto { display: none; }
  .exp-vistas-global .exp-vista { padding: 0 .55rem; }
  .exp-grafica-cab { flex-wrap: wrap; }
  .exp-verticales { gap: .2rem; }
}
