/* =====================================================================
   Laboratorio - Componentes
   Secciones genéricas tomadas de componentes.css de FS: chips, paneles,
   títulos, KPIs, tablas, encabezados que ordenan, etiquetas de estado,
   botones, formularios, modales, filtros, listas de definiciones,
   paginación y gráficos. Lo propio de FS (la vía de una parte, REQUI,
   pared) no se trajo: si una pantalla lo necesita, se agrega acá.
   ===================================================================== */


/* --------------------------------------------------------------------
   Chips de filtro rápido

   Las reglas van atadas a .chips y no sueltas en .chip: mas abajo hay otro
   componente -las fichitas de "filtrando por", con su ✕- que tambien se llama
   .chip. Con las dos sueltas ganaba la de abajo por posicion, y los filtros de
   Base Slots terminaban con la forma de la fichita y poniendose rojos al pasar
   el mouse. Las sub-pestañas de aca abajo no lo sufrian porque ya lo
   deshacian a mano, regla por regla.
   -------------------------------------------------------------------- */
.chips {
  display: flex;
  gap: 7px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.chips .chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  font-size: .85rem;
  font-weight: 550;
  color: var(--texto-suave);
  background: var(--fondo-panel);
  border: 1px solid var(--borde-fuerte);
  border-radius: 20px;
  white-space: nowrap;
}

.chips .chip:hover { background: var(--fondo-hover); color: var(--texto); text-decoration: none; }

.chips .chip.activo {
  background: var(--acento-fuerte);
  border-color: var(--acento-fuerte);
  color: #fff;
}

.chips .chip-num {
  font-family: var(--fuente-mono);
  font-size: .82rem;
  padding: 1px 6px;
  border-radius: 10px;
  background: var(--gris-bg);
  color: var(--texto-suave);
}

.chips .chip.activo .chip-num { background: rgba(255, 255, 255, .22); color: #fff; }

/* Sub-pestañas de una pestaña de estado: van pegadas debajo de la barra, para
   que se lean como el adentro de la pestaña abierta y no como un filtro
   independiente. La barra deja 18px de aire y aca alcanza con la mitad.

   Y no van redondeadas como los filtros rapidos de Base Slots, que es de donde
   sale la clase: una pildora se lee como "un filtro mas", y esto es navegacion.
   Con la barra de pestañas justo arriba en angulos rectos, el mismo radio chico
   las emparenta con ella. Un punto mas de tamaño por lo mismo: se eligen tanto
   como una pestaña.

   Solo aca: .chips .chip sigue siendo la pildora de Base Slots. */
.chips-sub { margin-top: -8px; }

.chips-sub .chip {
  padding: 7px 15px;
  font-size: .9rem;
  border-radius: var(--radio-chico);
  /* Estas dos las venia heredando de la fichita de "filtrando por", que hasta
     ahora le ganaba por posicion. Escritas aca, la sub-pestaña se dibuja igual
     que siempre: sin ellas tomaba el gap de 7px y la interlinea de 1.5 de
     .chips .chip. Es un pelo de diferencia, pero es una diferencia que nadie
     pidio, y este commit arregla un choque de nombres, no rediseña nada. */
  gap: 6px;
  line-height: 1.6;
}

.chips-sub .chip-num { border-radius: var(--radio-chico); }

/* El hover propio: las sub-pestañas navegan, no sacan nada, asi que se pintan
   con el azul de la app y no con el gris de .chips .chip, que es el hover de un
   filtro que se pone y se saca. El rojo que usan las fichitas de "filtrando
   por" no entra aca: ahi anuncia que ese clic quita el filtro. */
.chips-sub .chip:not(.activo):hover {
  border-color: var(--acento);
  background: var(--fondo-hover);
  color: var(--acento);
}
.chips-sub .chip.activo:hover {
  border-color: var(--acento-fuerte);
  background: var(--acento-fuerte);
  color: #fff;
}

/* Los chips que se pintan, mientras tengan algo adentro: el rojo de lo que
   nadie movio y el verde de lo que ya esta en la sala, esperando que lo
   pongan. El del medio -lo que viaja- queda gris a proposito: no es un
   problema ni es una tarea, es un estado de transito, y tres colores en una
   fila de cuatro no se leen como un semaforo sino como una calcomania.

   Van despues de los tres bloques de arriba porque los pisan a todos: con la
   misma especificidad gana el ultimo, y ademas suman su clase.

   No llevan fondo lleno sino el par borde+texto sobre el fondo suave, que es
   como el resto de la app marca lo que urge -los numeros del encabezado, las
   pastillas de estado-: el color pleno es para los botones que borran.

   Cada clase define el par y las reglas lo usan: son las mismas reglas para
   los dos colores, y agregar un tercero es una linea. Las variables se
   redefinen en el tema oscuro -ahi --rojo y --verde son claros y sus fondos
   oscuros-, asi que el par funciona en los dos sin escribirlo dos veces. */
.chips-sub .chip-alerta { --chip-color: var(--rojo);  --chip-bg: var(--rojo-bg); }
.chips-sub .chip-listo  { --chip-color: var(--verde); --chip-bg: var(--verde-bg); }

.chips-sub .chip.chip-alerta:not(.activo),
.chips-sub .chip.chip-listo:not(.activo) {
  border-color: var(--chip-color);
  color: var(--chip-color);
}
.chips-sub .chip.chip-alerta:not(.activo) .chip-num,
.chips-sub .chip.chip-listo:not(.activo) .chip-num {
  background: var(--chip-bg);
  color: var(--chip-color);
}
.chips-sub .chip.chip-alerta:not(.activo):hover,
.chips-sub .chip.chip-listo:not(.activo):hover {
  border-color: var(--chip-color);
  background: var(--chip-bg);
  color: var(--chip-color);
}

/* Elegido: el mismo color, con el borde mas grueso y el numero invertido para
   que se lea como "estoy parado aca" y no como uno mas de la fila. El grosor
   va por box-shadow y no por border-width: cambiar el borde corre un pixel el
   contenido y los chips de al lado bailan. El numero se invierte contra
   --fondo-panel y no contra blanco fijo, que se perderia en el tema claro. */
.chips-sub .chip.chip-alerta.activo,
.chips-sub .chip.chip-alerta.activo:hover,
.chips-sub .chip.chip-listo.activo,
.chips-sub .chip.chip-listo.activo:hover {
  background: var(--chip-bg);
  border-color: var(--chip-color);
  color: var(--chip-color);
  box-shadow: inset 0 0 0 1px var(--chip-color);
}
.chips-sub .chip.chip-alerta.activo .chip-num,
.chips-sub .chip.chip-listo.activo .chip-num {
  background: var(--chip-color);
  color: var(--fondo-panel);
}

@media (max-width: 700px) {
  /* En el telefono se reparten el ancho del renglon y quedan como una barra de
     segmentos: mas superficie para el pulgar y mas presencia, que es lo que se
     necesita eligiendo parado frente a la maquina. Siguen envolviendo si no
     entran -el nombre mas largo es "En el laboratorio"-, y al envolver cada
     renglon se reparte solo. */
  .chips-sub { gap: 6px; }

  .chips-sub .chip {
    flex: 1 1 auto;
    justify-content: center;
    padding: 9px 10px;
    font-weight: 600;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .07);
  }
}

/* --------------------------------------------------------------------
   Selección múltiple en tablas
   -------------------------------------------------------------------- */
.col-check { width: 34px; text-align: center; }
.col-check input { cursor: pointer; }

.tabla tr.fila-elegida { background: var(--acento-suave); }
.tabla tr.fila-elegida:hover { background: var(--acento-suave); }

/* La barra de acciones se pega abajo mientras se elige, para no tener que
   volver al pie de una lista larga. */
.barra-seleccion {
  position: sticky;
  bottom: 12px;
  z-index: 5;
  box-shadow: 0 -2px 14px rgba(20, 35, 58, .14);
}

.barra-seleccion[hidden] { display: none; }

/* Elegir sobre qué actúa la acción: los tildados o todo el filtro. */
.campo-check.ambito { margin-bottom: 6px; }
.campo-check.ambito label { font-size: .88rem; }
.campo-check.ambito strong { font-family: var(--fuente-mono); }

/* --------------------------------------------------------------------
   Paneles
   -------------------------------------------------------------------- */
.panel {
  background: var(--fondo-panel);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  box-shadow: var(--sombra);
  padding: 16px 18px;
  margin-bottom: 16px;
}

.panel-cab {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

/* Panel que se pliega en el telefono. En pantalla ancha no se pliega y el
   encabezado se ve igual que el de cualquier otro panel: es un <summary> con
   la misma clase, sin el triangulito del navegador y sin el propio. Que quede
   siempre abierto lo resuelve fs.js. */
.panel-plegable > summary { list-style: none; }
.panel-plegable > summary::-webkit-details-marker { display: none; }
.panel-flecha { display: none; }

/* El "N sin reparación" que acompaña al conteo de partes: viaja dentro del
   span tenue del encabezado, así que le devuelve el rojo y el peso. */
.panel-cab-sin-rep { color: var(--rojo); font-weight: 700; }

/* --------------------------------------------------------------------
   Titulos de seccion, en mayuscula

   Es la ultima pieza tipografica de la direccion C: el titulo de la
   pantalla y el de cada panel se leen como el cartel de un pasillo.

   LA REGLA ES DONDE ESTA PARADO EL TITULO, NO QUE ETIQUETA USA
   ------------------------------------------------------------
   Va en mayuscula lo que NOMBRA UN LUGAR: "PANEL", "LOGISTICA",
   "ADJUNTOS", "HISTORIAL DE REPARACIONES". Por eso los selectores piden
   .titulo-pagina y .panel, que es donde viven los nombres de seccion, y
   no `h1, h2` a secas.

   Lo que queda afuera, y no por olvido:

     - Los titulos de los cuadros de confirmacion (.modal-titulo) y sus
       gemelos sin JavaScript (.titulo-pregunta). Muchos son preguntas
       -"¿Pasas la reparacion a Pendiente?"- y una pregunta en mayuscula
       se lee como un grito. Ademas no son un lugar donde uno esta: son
       algo que hay que contestar.
     - Los titulos de las novedades (.changelog-titulo), que son frases
       enteras.
     - Las dos pantallas de error, que tampoco son frases cortas: "No
       encontramos esa pagina" dicho a los gritos es peor noticia. Su h1
       vive en un .panel-centrado, fuera de .titulo-pagina, asi que queda
       afuera solo.
     - El ingreso, la subida por el telefono y la pared, que son
       documentos autonomos y no tienen .titulo-pagina.

   EL ESPACIADO
   ------------
   La mayuscula necesita mas aire que la minuscula, y cuanto mas chica la
   letra, mas: el h1 va con .04em y el h2, que es casi la mitad de grande,
   con .06em. El titulo de la ficha se queda con el suyo (.02em, ver
   pantallas.css): ya venia en mayuscula, y a 1.85rem y peso 800 un
   espaciado grande lo desarma en vez de ordenarlo. Por eso el :not().
   -------------------------------------------------------------------- */
.titulo-pagina h1:not(.ficha-titulo) {
  text-transform: uppercase;
  letter-spacing: .04em;
}

.panel > h2,
.panel-cab > h2 {
  text-transform: uppercase;
  letter-spacing: .06em;
}

/* La pregunta se queda como esta escrita. Va con .panel-cab adelante para
   ganarle en especificidad a la regla de arriba y no depender del orden. */
.panel-cab h2.titulo-pregunta {
  text-transform: none;
  letter-spacing: .01em;
}

.panel-acciones { display: flex; gap: 7px; flex-wrap: wrap; }

/* La lista de partes del <noscript>, en el alta. Es el unico lugar donde el
   catalogo entero sigue viajando: sin JavaScript no hay a quien preguntarle.
   Como <select multiple> son unos 40 KB y un solo control, contra los 600 KB
   y las 2.600 casillas que habia antes. */
.selector-partes-ns {
  width: 100%;
  margin-top: 6px;
  font-family: inherit;
  font-size: .9rem;
}

.panel-centrado { max-width: 560px; margin: 40px auto; text-align: center; }

/* Paso intermedio al cerrar con piezas SIN REPARACIÓN. Es una pregunta, no un
   error: el panel se queda con el ámbar del aviso y no con el rojo, que en el
   resto de la aplicación significa "esto no se puede". */
.panel-confirmar {
  max-width: 620px;
  text-align: left;
  border-left: 4px solid var(--ambar);
}
.panel-confirmar h1 { font-size: 1.15rem; margin: 0 0 10px; line-height: 1.35; }
.confirmar-icono { margin-right: 6px; }
.confirmar-uid { margin: 0 0 14px; display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.confirmar-lista {
  margin: 0 0 16px;
  padding: 10px 14px;
  list-style: none;
  background: var(--ambar-bg);
  border-radius: var(--radio-chico);
}
.confirmar-lista li {
  display: flex;
  gap: 8px;
  align-items: baseline;
  flex-wrap: wrap;
  padding: 3px 0;
  font-weight: 600;
  color: var(--texto);
}
.panel-accion { background: var(--acento-suave); border-color: var(--borde-fuerte); }

.panel-peligro { border-color: var(--rojo); }
.panel-peligro h2 { color: var(--rojo); }

.vacio {
  color: var(--texto-tenue);
  background: var(--fondo-suave);
  border: 1px dashed var(--borde);
  border-radius: var(--radio-chico);
  padding: 18px;
  text-align: center;
  margin: 0;
}

/* --------------------------------------------------------------------
   KPIs
   -------------------------------------------------------------------- */
.kpis {
  display: grid;
  /* Cuatro por fila: con siete KPI el tablero cierra en 4 + 3 y ninguna
     queda suelta al final de una fila de seis. */
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: 18px;
  /* Que cada tarjeta ocupe su alto y no el de la mas alta de su fila:
     la de pendientes lleva el desglose por motivo y, sin esto, las
     vecinas se estiraban con un hueco vacio abajo. */
  align-items: start;
}
@media (max-width: 1000px) { .kpis { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 700px)  { .kpis { grid-template-columns: 1fr; } }

.kpi {
  background: var(--fondo-panel);
  border: 1px solid var(--borde);
  border-left: 4px solid var(--borde-fuerte);
  border-radius: var(--radio);
  box-shadow: var(--sombra);
  padding: 9px 13px;
  display: flex;
  /* El numero y su rotulo, en un renglon, y todas las tarjetas del mismo
     alto. Lo que no entra en esa linea va al title: es el caso del
     desglose por motivo de los pendientes, en el tablero. */
  flex-direction: row;
  align-items: baseline;
  gap: 8px;
  color: var(--texto);
}
a.kpi:hover { text-decoration: none; background: var(--fondo-hover); }

.kpi-num { font-size: 1.5rem; font-weight: 700; line-height: 1.05; }
.kpi-rot { font-size: .8rem; color: var(--texto-suave); }
/* Desglose chico del KPI (ej: pendientes por motivo). Va en la misma
   linea que el rotulo; si no entra, baja y crece solo esa tarjeta. */
.kpi-detalle { font-size: .78rem; color: var(--texto-tenue); }

.kpi-reparacion { border-left-color: var(--ambar); }
.kpi-reparacion .kpi-num { color: var(--ambar); }
.kpi-pendiente  { border-left-color: var(--rojo); }
.kpi-pendiente .kpi-num { color: var(--rojo); }
/* El traslado, en el mismo azul que los hitos del viaje de la pieza. */
.kpi-sin-recibir { border-left-color: var(--acento); }
.kpi-sin-recibir .kpi-num { color: var(--acento); }
.kpi-reparada   { border-left-color: var(--verde); }
.kpi-reparada .kpi-num { color: var(--verde); }
.kpi-sin-reparacion { border-left-color: var(--rojo); }
.kpi-sin-reparacion .kpi-num { color: var(--rojo); }
.kpi-retirada   { border-left-color: var(--texto-tenue); }
.kpi-promedio   { border-left-color: var(--acento); }
.kpi-promedio .kpi-num { color: var(--acento); }

/* --------------------------------------------------------------------
   Tablas
   -------------------------------------------------------------------- */
.tabla-scroll { overflow-x: auto; margin: 0 -18px; padding: 0 18px; }

/* Base Slots: copia visible del titulo y de los nombres de columna al bajar
   por la tabla. Va debajo de los filtros pegajosos y sigue su scroll horizontal. */
.slots-encabezado-flotante {
  position: fixed;
  z-index: 19;
  margin: 0;
  padding-bottom: 0;
  border-bottom: 2px solid var(--borde-fuerte);
  box-shadow: 0 6px 14px rgba(20, 35, 58, .16);
}
.slots-encabezado-flotante[hidden] { display: none; }
.slots-encabezado-flotante .tabla-scroll { overflow: hidden; }

@media (max-width: 700px) {
  .slots-encabezado-flotante { padding: 14px 14px 0; }
}

/* .95rem y no .88: esto se lee parado frente a una maquina, con la luz que
   haya. Un cuerpo comodo en el piso de sala no molesta en la oficina; al reves
   si. Misma razon detras del resto de los tamaños de este archivo: nada por
   debajo de .8rem. */
.tabla {
  width: 100%;
  border-collapse: collapse;
  font-size: .95rem;
}

.tabla th {
  text-align: left;
  font-size: .8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--texto-suave);
  padding: 8px 9px;
  border-bottom: 2px solid var(--borde-fuerte);
  white-space: nowrap;
}

.tabla td {
  padding: 8px 9px;
  border-bottom: 1px solid var(--borde);
  vertical-align: middle;
}

.tabla tbody tr:hover { background: var(--fondo-hover); }
.tabla tbody tr:last-child td { border-bottom: none; }

/* La cabecera separa los nombres de columna de los datos sin sumar cajas ni
   colores de estado: una sola banda gris azulada y una línea superior bastan
   para orientar la lectura horizontal. */
.tabla-reparaciones thead th {
  color: var(--texto-suave);
  background: var(--fondo-suave);
  border-top: 1px solid var(--borde-fuerte);
  text-transform: uppercase;
}

.tabla-reparaciones thead th.th-activa { background: var(--acento-suave); }

/* El número de orden sirve para ubicar una fila cuando se habla entre dos
   personas. Se destaca con una franja gris-azulada, sobria y consistente en
   ambos temas, sin usar los colores del semáforo que describen el estado. */
.tabla-reparaciones .columna-orden,
.tabla-reparaciones .celda-orden {
  background: var(--gris-bg);
  text-align: center;
  width: 2.4rem;
  padding-right: 6px;
  padding-left: 6px;
}

.tabla-reparaciones .columna-orden {
  color: var(--texto-suave);
}

.tabla-reparaciones .celda-orden {
  color: var(--texto);
  font-family: var(--fuente-mono);
  font-size: 1rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.tabla-reparaciones tbody tr:hover .celda-orden { background: var(--acento-suave); }

.fila-inactiva { opacity: .55; }

/* Fila de una importación que no se va a cargar. Se muestra igual, marcada:
   esconderla dejaría al operador sin saber qué pasó con esa línea del archivo. */
.fila-error { background: var(--rojo-bg); }
.fila-error:hover { background: var(--rojo-bg); }

.tabla-permisos td:first-child { width: 45%; }
.tabla-permisos .si { color: var(--verde); font-weight: 650; }
.tabla-permisos .no { color: var(--texto-tenue); }

/* --------------------------------------------------------------------
   Contador de dias con semaforo
   -------------------------------------------------------------------- */
.dias {
  display: inline-block;
  min-width: 2.4em;
  text-align: center;
  font-family: var(--fuente-mono);
  font-weight: 700;
  font-size: .86rem;
  padding: 2px 7px;
  border-radius: var(--radio-chico);
  background: var(--gris-bg);
  color: var(--texto-suave);
}

.dias-grande { font-size: 1.15rem; padding: 5px 12px; }

/* El UID es por donde se busca una fila en el listado: se lee antes que el
   resto de la tabla, que va en .88rem. */
.tabla .uid-fuerte {
  font-family: var(--fuente-mono);
  font-weight: 700;
  font-size: 1.02rem;
  color: var(--texto);
  white-space: nowrap;
}

/* El UID es el enlace a la ficha, pero no se pinta de azul: en una tabla de
   doce columnas, una columna entera de links de color compite con el semaforo,
   que es lo que hay que ver primero. Se subraya al pasar por encima, que
   alcanza para saber que se puede clickear. */
.tabla .uid-fuerte a { color: inherit; }
.tabla .uid-fuerte a:hover { color: var(--acento); text-decoration: underline; }

/* El motivo llega hasta 255 caracteres. Suelto, estira el alto de la fila y
   descoloca la lectura de toda la tabla: se recorta a una linea. El texto
   entero esta en la ficha, a un clic del UID.

   max-width en una celda de tabla necesita table-layout fijo para respetarse
   del todo; con auto, el navegador lo toma como sugerencia, que es justo lo
   que se quiere aca: si sobra espacio lo usa, y si no, corta. */
.tabla .celda-motivo {
  max-width: 22ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --------------------------------------------------------------------
   Atajos de rango de fechas
   -------------------------------------------------------------------- */
.rangos { display: flex; flex-wrap: wrap; gap: 4px; }

.rango {
  padding: 4px 8px;
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-chico);
  background: var(--fondo-panel);
  color: var(--texto-suave);
  font-size: .82rem;
  line-height: 1.4;
  white-space: nowrap;
}

.rango:hover { background: var(--fondo-hover); color: var(--texto); text-decoration: none; }

.rango-activo {
  background: var(--acento-suave);
  border-color: var(--acento);
  color: var(--acento);
  font-weight: 600;
}

/* La leyenda de los marcadores, en la cabecera del panel de resultados. Las
   pastillas de muestra no son enlaces: solo dicen que significa cada una. */
.leyenda-marcadores { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.leyenda-marcadores .reincide,
.leyenda-marcadores .nuevo { margin-left: 0; cursor: default; }

/* --------------------------------------------------------------------
   Donde encontro la busqueda

   <mark> trae su propio amarillo del navegador, que sobre el tema oscuro
   queda ilegible: texto oscuro sobre amarillo brillante. Se redefine con las
   variables del tema, como todo el resto de la hoja.
   -------------------------------------------------------------------- */
mark {
  background: var(--ambar-bg);
  color: var(--texto);
  padding: 0 2px;
  border-radius: 2px;
  font-weight: 600;
}

/* La busqueda cubre siete campos y solo cuatro son columnas del listado. Si
   coincidio en uno de los otros tres, se dice cual: si no, la fila aparece sin
   una sola marca y no hay forma de saber por que esta ahi. */
.coincide-en {
  display: inline-block;
  margin-left: 6px;
  font-family: var(--fuente);
  font-weight: 400;
  font-size: .8rem;
  color: var(--texto-tenue);
}

/* Paneles que requieren atención. */
.panel-atencion { border-left: 4px solid var(--ambar); }

/* Un boton de exportar que esta trabajando: no se puede volver a apretar. */
[aria-busy="true"] {
  opacity: .6;
  pointer-events: none;
  cursor: progress;
}

/* --------------------------------------------------------------------
   Encabezados que ordenan

   Son enlaces: andan con el clic del medio, se guardan en favoritos y el
   navegador muestra el destino antes de apretar. La flecha dice como esta
   ordenado AHORA, no que va a hacer el clic.
   -------------------------------------------------------------------- */
.tabla th.th-orden { padding: 0; }

.tabla th.th-orden > a {
  display: block;
  padding: 8px 9px;
  color: inherit;
  white-space: nowrap;
}

.tabla th.th-orden > a:hover {
  color: var(--acento);
  background: var(--fondo-suave);
  text-decoration: none;
}

.tabla th.th-activa > a { color: var(--acento); }
.th-flecha { font-weight: 400; }

/* Al pasar el mouse por una columna sin ordenar, una flecha tenue avisa que
   se puede: sin esto no hay nada que diga que el encabezado es clickeable. */
.tabla th.th-orden:not(.th-activa) > a:hover .th-flecha::after {
  content: ' ↓';
  opacity: .45;
}

/* --------------------------------------------------------------------
   Fichitas de filtro activo

   Atadas a .chips-filtro por lo mismo que las de arriba: .chip es tambien el
   nombre de los filtros rapidos de Base Slots. Los dos componentes comparten
   el nombre y no hay por que unificarlos -uno navega, el otro saca un
   filtro-, pero cada uno manda solo adentro de su contenedor.
   -------------------------------------------------------------------- */
.chips-filtro {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: -6px 0 14px;
  font-size: .82rem;
}

.chips-filtro .chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 6px 3px 10px;
  border: 1px solid var(--borde-fuerte);
  border-radius: 999px;
  background: var(--fondo-suave);
  color: var(--texto-suave);
  line-height: 1.6;
  /* Estas tres las venia heredando del otro .chip, el de Base Slots, de puro
     rebote: eran las unicas que aquel bloque declaraba y este no. Escritas
     aca, la fichita se dibuja igual que siempre y deja de depender de un
     componente con el que no tiene nada que ver.

     El font-size gana igual al .82rem del contenedor, que nunca llego a
     aplicarse a la fichita. Si alguna vez se quiere el .82rem de verdad, se
     borra esta linea; es una decision de diseño, no un arreglo. */
  font-size: .85rem;
  font-weight: 550;
  white-space: nowrap;
}

.chips-filtro .chip:hover {
  border-color: var(--rojo);
  color: var(--rojo);
  text-decoration: none;
}

.chips-filtro .chip-x { font-size: .8rem; opacity: .6; }
.chips-filtro .chip:hover .chip-x { opacity: 1; }

/* Máquina que ya salió de servicio antes. Va pegada al UID y en ámbar: no es
   un error, es una señal de que conviene mirar el equipo de fondo. */
/* El marcador de reincidencia y su gemelo de novedades. Eran dos pastillas
   de 10px de radio: a ese tamanio se leen como una capsula, que es la forma
   con la que esta app decia "estado" y ya no dice -ver la cabecera de la
   ficha en pantallas.css, donde el estado paso a ser texto-. Ahora llevan
   el radio de la casa, el mismo de los botones y los paneles, asi que son
   una placa chica y no una pastilla.

   Se cambian los dos juntos porque son el mismo marcador con dos colores, y
   uno redondo al lado de otro cuadrado se lee como dos cosas distintas.
   Aparecen en cinco pantallas: el listado, el panel, avisos, el perfil y
   esta ficha. */
.reincide {
  display: inline-block;
  margin-left: 5px;
  vertical-align: 2px;
  font-family: var(--fuente-mono);
  font-size: .8rem;
  font-weight: 700;
  line-height: 1;
  padding: 3px 6px;
  border-radius: var(--radio-chico);
  background: var(--ambar-bg);
  color: var(--ambar);
}

.reincide:hover {
  background: var(--ambar);
  color: #fff;
  text-decoration: none;
}

/* Novedades o archivos que cargo otro y este usuario todavia no vio.
   Misma pastilla que .reincide para no inventar una forma nueva, pero en azul:
   el ambar de reincidencia avisa de un problema del equipo, esto es solo
   trabajo de otro sin leer. Y como la celda entera es .tenue, el color hace
   falta para que se despegue del gris de alrededor. */
.nuevo {
  display: inline-block;
  margin-left: 5px;
  vertical-align: 2px;
  font-family: var(--fuente-mono);
  font-size: .8rem;
  font-weight: 700;
  line-height: 1;
  padding: 3px 6px;
  border-radius: var(--radio-chico);
  background: var(--acento-suave);
  color: var(--acento);
  cursor: help;
}

.sem-verde { background: var(--verde-bg); color: var(--verde); }
.sem-ambar { background: var(--ambar-bg); color: var(--ambar); }
.sem-rojo  { background: var(--rojo-bg);  color: var(--rojo); }
.sem-cerrada { background: var(--gris-bg); color: var(--texto-suave); }

/* --------------------------------------------------------------------
   Etiquetas de estado
   -------------------------------------------------------------------- */
.etq {
  display: inline-block;
  font-size: .8rem;
  font-weight: 650;
  padding: 2px 8px;
  border-radius: 20px;
  white-space: nowrap;
  background: var(--gris-bg);
  color: var(--texto-suave);
}

.etq-grande { font-size: .86rem; padding: 4px 12px; }

/* El porqué del pendiente, ahora al lado del badge: es parte del estado, no
   un dato de las piezas, y en su propio renglón empujaba a los contadores a un
   tercero. */
.etq-motivo {
  margin-left: 5px;
  font-size: .78rem;
  color: var(--texto-tenue);
}

/* Cómo van las piezas del caso, en una sola línea de contadores.

   Antes cada dato traía su propio renglón —"N P. Reparadas", "N P. Sin
   reparación", y el "EN LAB" tres columnas más allá— y una fila cerrada con
   partes llegaba a cuatro renglones de alto. Como chips entran los tres en uno,
   y el color hace de leyenda: azul lo que está en el laboratorio, verde lo resuelto,
   rojo lo que no tiene arreglo. */
.cuentas-partes {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 4px;
}
.cuenta {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 999px;
  font-size: .74rem;
  font-weight: 700;
  line-height: 1.5;
  white-space: nowrap;
  cursor: default;
}
.cuenta-lab { background: var(--acento-suave);   color: var(--acento); }
.cuenta-ok  { background: var(--verde-bg);   color: var(--verde); }
.cuenta-sin { background: var(--rojo-bg);    color: var(--rojo); }

.etq-en_reparacion { background: var(--ambar-bg); color: var(--ambar); }
.etq-reparada_lab  { background: var(--violeta-bg); color: var(--violeta); }
/* Verde como EN SERVICIO: es Sala diciendo que la pieza quedo operativa. */
.etq-reparada_sala { background: var(--verde-bg);   color: var(--verde); }
/* Violeta como REP. POR LAB: las dos son la pieza que ya no tiene trabajo
   pendiente y espera su vuelta al slot. */
.etq-reemplazada   { background: var(--violeta-bg); color: var(--violeta); }
/* Las seis etiquetas del viaje de la pieza -RECIBIDO DE SALA, ESPERA
   RECEPCION, NO ENVIADO POR LOG, EN CAMINO A SALA, REPUESTO ENVIADO,
   RECIBIDO DEL LAB- vivian aca y se fueron con la pila: ahora eso lo dibuja
   la via, mas abajo en este archivo. Se borran sus reglas en el mismo
   cambio que las dejo sin uso, que es la unica forma de que el CSS muerto no
   se acumule.

   .etq-compra se queda: la sigue usando la pantalla de Logistica, que no
   tiene via. Azul como los hitos ocurridos: alguien esta gestionando la
   compra. */
.etq-compra        { background: var(--acento-suave); color: var(--acento); }
/* La pieza que rebota. Ambar y no rojo: no es una falla nueva sino un arreglo
   que no aguanto, y la fila ya tiene su estado al lado. */
.etq-vueltas       { background: var(--ambar-bg); color: var(--ambar); }
/* La pastilla del paso intermedio, del mismo color que su pestaña. */
.etq-rep_sin_recibir { background: var(--acento-suave); color: var(--acento); }
.etq-pendiente     { background: var(--rojo-bg);  color: var(--rojo); }
.etq-reparada      { background: var(--verde-bg); color: var(--verde); }
.etq-en_servicio   { background: var(--verde-bg); color: var(--verde); }
.etq-sin_reparacion{ background: var(--rojo-bg);   color: var(--rojo); }
.etq-retirada      { background: var(--gris-bg);  color: var(--texto-suave); }

/* Punto de color con el estado, para las fichas recientes: dice de un vistazo
   en qué anda cada una sin ocupar el espacio de una etiqueta entera. */
.etq-punto {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  vertical-align: middle;
}
.etq-punto.etq-en_reparacion { background: var(--ambar); }
.etq-punto.etq-reparada_lab  { background: var(--violeta); }
.etq-punto.etq-reparada_sala { background: var(--verde); }
.etq-punto.etq-reemplazada   { background: var(--violeta); }
.etq-punto.etq-pendiente     { background: var(--rojo); }
.etq-punto.etq-reparada      { background: var(--verde); }
.etq-punto.etq-en_servicio   { background: var(--verde); }
.etq-punto.etq-sin_reparacion{ background: var(--rojo); }
.etq-punto.etq-retirada      { background: var(--texto-tenue); }

/* --------------------------------------------------------------------
   "Seguir con": las últimas fichas que abriste, en una tira de pastillas.
   -------------------------------------------------------------------- */
.recientes {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 16px;
}
.recientes-rot { font-size: .82rem; color: var(--texto-tenue); }

.reciente {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border: 1px solid var(--borde);
  border-radius: 999px;
  background: var(--fondo-panel);
  color: var(--texto);
  font-size: .88rem;
}
.reciente:hover { background: var(--fondo-hover); text-decoration: none; border-color: var(--borde-fuerte); }
.etq-rol           { background: var(--acento-suave); color: var(--acento); }
/* Cada rol tiene su propia señal visual. Los pares usan variables del tema,
   para conservar el contraste también en modo oscuro. */
.etq-rol-admin      { background: var(--violeta-bg); color: var(--violeta); }
.etq-rol-encargado  { background: var(--verde-bg);   color: var(--verde); }
.etq-rol-supervisor { background: var(--acento-suave);   color: var(--acento); }
.etq-rol-tecnico    { background: var(--gris-bg);    color: var(--texto-suave); }
.etq-rol-lectura    { background: var(--ambar-bg);   color: var(--ambar); }
/* En tema claro las superficies suaves se parecían demasiado entre sí. Estos
   tonos y bordes hacen que el rol se reconozca sin leerlo; en oscuro se
   conservan los colores definidos arriba, que ya tienen buen contraste. */
:root:not([data-tema="oscuro"]) .etq-rol-admin {
  background: #ead7fa; color: #54168a; box-shadow: inset 0 0 0 1px #d4b8ed;
}
:root:not([data-tema="oscuro"]) .etq-rol-encargado {
  background: #d4f0df; color: #12683b; box-shadow: inset 0 0 0 1px #addfc2;
}
:root:not([data-tema="oscuro"]) .etq-rol-supervisor {
  background: #d7e8fa; color: #204e85; box-shadow: inset 0 0 0 1px #b6d2ef;
}
:root:not([data-tema="oscuro"]) .etq-rol-tecnico {
  background: #e1e5ea; color: #3f4b59; box-shadow: inset 0 0 0 1px #c9d0d8;
}
:root:not([data-tema="oscuro"]) .etq-rol-lectura {
  background: #fae6b8; color: #7a4b00; box-shadow: inset 0 0 0 1px #eccb81;
}
.etq-accion        { background: var(--acento-suave); color: var(--acento); font-family: var(--fuente-mono); }

/* --------------------------------------------------------------------
   Botones
   -------------------------------------------------------------------- */
.btn {
  display: inline-block;
  font-family: inherit;
  font-size: .88rem;
  font-weight: 550;
  line-height: 1.4;
  padding: 7px 14px;
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-chico);
  background: var(--fondo-panel);
  color: var(--texto);
  cursor: pointer;
  text-align: center;
  white-space: nowrap;
}
.btn:hover { background: var(--fondo-hover); text-decoration: none; }
.btn:active { transform: translateY(1px); }

.btn-primario {
  background: var(--acento-fuerte);
  border-color: var(--acento-fuerte);
  color: #fff;
}
.btn-primario:hover { background: var(--acento-hover); border-color: var(--acento-hover); }

.btn-peligro { background: var(--rojo); border-color: var(--rojo); color: #fff; }
.btn-peligro:hover { background: #92201a; border-color: #92201a; }

/* Boton que se muestra pero no se puede usar: dice que la accion existe y en
   que estado esta, sin ofrecerla a quien no le corresponde.

   Hace falta escribirlo: un <button disabled> al que el CSS ya le dio fondo y
   color propios NO lo grisa el navegador, y quedaba identico a uno activo, con
   la unica pista de que al hacer clic no pasaba nada. */
.btn:disabled,
.btn-deshabilitado {
  background: var(--gris-bg);
  border-color: var(--borde);
  color: var(--texto-tenue);
  cursor: not-allowed;
}
.btn:disabled:hover,
.btn-deshabilitado:hover { background: var(--gris-bg); }
.btn:disabled:active,
.btn-deshabilitado:active { transform: none; }

.btn-chico { font-size: .8rem; padding: 4px 10px; }
.btn-ancho { width: 100%; padding: 10px; font-size: .95rem; }

.btn-enlace {
  background: none;
  border: none;
  color: var(--texto-tenue);
  cursor: pointer;
  font-size: .95rem;
  padding: 0 4px;
  line-height: 1;
}
.btn-enlace:hover { color: var(--rojo); }

.acciones-pie, .acciones-form {
  display: flex;
  gap: 9px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.acciones-form { margin: 14px 0 0; }
.acciones-form-superiores { margin: 0 0 14px; }

/* --------------------------------------------------------------------
   Formularios
   -------------------------------------------------------------------- */
.formulario fieldset {
  border: 1px solid var(--borde);
  border-radius: var(--radio-chico);
  padding: 12px 14px 14px;
  margin: 0 0 14px;
}

.formulario legend {
  font-size: .82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--texto-suave);
  padding: 0 6px;
}

.formulario-angosto { max-width: 620px; }

/* Ancho intermedio, para los formularios largos. Sin esto ocupan los 1500px
   del contenido y los campos quedan desparramados de punta a punta: con el
   tope, la fila de campos se acomoda en tres columnas legibles. */
.formulario-medio { max-width: 900px; }

/* La ficha es más ancha que el alta porque son dos columnas y no una: a 900px
   cada columna quedaría en 440 y los campos del formulario, apilados de a uno.
   Acá el ancho no se desperdicia, lo llena el contenido. */
.pagina-angosta { max-width: 1180px; }

/* Izquierda los datos, derecha lo que se va agregando. La izquierda un poco
   más ancha porque lleva el formulario; la derecha, listas. */
.ficha-dos-columnas {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}

/* Apiladas, el orden se mantiene: primero los datos, después las novedades. */
@media (max-width: 980px) {
  .ficha-dos-columnas { grid-template-columns: 1fr; }
}

/* Cada columna apila sus paneles y come el margen del último, para que las dos
   terminen a la misma altura visual. */
.ficha-col > .panel:last-child { margin-bottom: 0; }

/* Lo que viene después de las columnas es la zona de borrado. Con el margen
   normal de 16px queda pegada a "Equipo" y se lee como un panel más de la
   ficha, cuando es lo contrario: hay que verla aparte. */
.ficha-dos-columnas { margin-bottom: 30px; }

/* Panel que se encoge a lo que ocupa su contenido en vez de estirarse a todo
   el ancho. Para la zona de borrado: un recuadro rojo de punta a punta pesa
   más de lo que el botón merece. max-width lo devuelve al ancho disponible
   cuando la pantalla es angosta. */
.panel-encogido {
  width: fit-content;
  max-width: 100%;
}

/* Segundo bloque de datos dentro de un panel que ya trae un formulario. */
.datos-extra { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--borde); }
.formulario-compacto { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--borde); }

.campo { margin-bottom: 12px; display: flex; flex-direction: column; }

.campo label {
  font-size: .85rem;
  font-weight: 600;
  color: var(--texto-suave);
  margin-bottom: 4px;
}

.req { color: var(--rojo); }

.campo input[type="text"],
.campo input[type="search"],
.campo input[type="password"],
.campo input[type="email"],
.campo input[type="number"],
.campo input[type="date"],
.campo input[type="file"],
.campo select,
.campo textarea,
.caja-login input {
  font-family: inherit;
  font-size: .92rem;
  color: var(--texto);
  background: var(--fondo-panel);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-chico);
  padding: 7px 9px;
  width: 100%;
  min-width: 0;
}

.campo textarea { resize: vertical; }

/* Va DESPUES del bloque de arriba y no junto a .visualmente-oculto: ahi tenia
   la misma especificidad que ".campo input[type=file]" y perdia por orden.
   Estando absoluto y con width 100%, el input de "Tomar Foto" de la ficha medía
   375px arrancando corrido y la pagina entera se desplazaba 29px al costado en
   el telefono. La regla va por clase para que no vuelva a pasar con el proximo
   control que se esconda dentro de un .campo. */
.campo input.visualmente-oculto,
.campo select.visualmente-oculto,
.campo textarea.visualmente-oculto {
  width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
}

.campo input:focus, .campo select:focus, .campo textarea:focus,
.caja-login input:focus {
  outline: 2px solid var(--acento);
  outline-offset: -1px;
  border-color: var(--acento);
}

.campo input.mono { font-family: var(--fuente-mono); }

/* Campo que el rol actual no puede editar: se muestra el valor, apagado, en
   vez de esconderlo. Así el operador ve el dato con el que se va a guardar. */
.campo input[readonly],
.campo input[disabled],
.campo select[disabled] {
  background: var(--fondo-suave);
  color: var(--texto-suave);
  cursor: not-allowed;
  border-style: dashed;
}

/* Campo con un prefijo fijo pegado adelante (el UID de máquina).
   El prefijo lo decide la sala, así que se muestra como etiqueta y no como
   texto editable: el operador solo escribe el número. */
.grupo-prefijo {
  display: flex;
  align-items: stretch;
}

.grupo-prefijo .prefijo-fijo {
  display: flex;
  align-items: center;
  padding: 0 8px;
  background: var(--gris-bg);
  color: var(--texto-suave);
  border: 1px solid var(--borde-fuerte);
  border-right: none;
  border-radius: var(--radio-chico) 0 0 var(--radio-chico);
  font-weight: 650;
  white-space: nowrap;
  user-select: none;
}

.grupo-prefijo .prefijo-fijo[hidden] { display: none; }

.grupo-prefijo input {
  border-radius: 0 var(--radio-chico) var(--radio-chico) 0;
  flex: 1;
  min-width: 0;
}

/* Sin prefijo (sala sin configurar): el input ocupa todo y recupera sus esquinas. */
.grupo-prefijo .prefijo-fijo[hidden] + input {
  border-radius: var(--radio-chico);
}

/* Valor que no es un input porque no se puede cambiar (el estado en el alta). */
.valor-fijo {
  margin: 0;
  padding: 6px 0 1px;
  display: flex;
  align-items: center;
  min-height: 34px;
}

.campo-check { flex-direction: row; align-items: center; }
.campo-check label {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  font-weight: 500;
  color: var(--texto);
  font-size: .9rem;
  cursor: pointer;
}
.campo-check input { width: auto; }

.filtro-partes { max-width: 520px; margin-bottom: 14px; }

/* En escritorio el catálogo puede tener cientos de filas. Los indicadores,
   acciones y buscador quedan a la vista; solo la tabla se desplaza. */
@media (min-width: 701px) {
  .tabla-partes-scroll {
    max-height: max(300px, calc(100vh - 390px));
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-gutter: stable;
  }

  .tabla-partes-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--fondo-panel);
    box-shadow: 0 1px 0 var(--borde-fuerte);
  }
}

.partes-reparacion {
  list-style: none;
  margin: 0;
  padding: 0;
}


/* --------------------------------------------------------------------
   Modales (<dialog> nativo)

   El navegador ya se encarga del foco, del fondo oscuro y de Escape;
   aca solo va el aspecto del panel para que sea el mismo de la app.
   -------------------------------------------------------------------- */
.modal {
  width: min(440px, calc(100vw - 32px));
  padding: 0;
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  background: var(--fondo-panel);
  color: var(--texto);
  box-shadow: 0 8px 32px rgba(0, 0, 0, .28);
}

.modal::backdrop { background: rgba(10, 16, 26, .55); }

/* Un modal que muestra una TABLA y no un formulario.

   Mas ancho, porque 440px alcanzan para cuatro casillas pero no para seis
   columnas; y con relleno propio, porque el del modal comun vive en
   `.modal .formulario` y aca adentro no hay ninguno. */
.modal-ancho  { width: min(860px, calc(100vw - 32px)); }
.modal-cuerpo { padding: 18px; }

/* Los modales de Personal, sin JavaScript.

   Un <dialog> cerrado lo esconde el navegador, y el boton que lo abriria no
   hace nada: la cuenta de reparaciones de cada persona quedaria sin forma de
   mirarse. Sin JS se muestran todos en linea, uno abajo del otro, y se
   esconden los botones que no sirven. Asi la informacion esta entera sin
   repetir el listado en un <noscript>.

   Va por `html:not(.js)` y no por <noscript> porque cubre ademas el caso en
   que el JavaScript esta habilitado pero no llego a cargar. Y va acotado a
   .modal-personal a proposito: los modales de Avisos ya traen su propio
   respaldo en <noscript>, y aplicarlo a todos los mostraria dos veces. */
html:not(.js) .modal-personal {
  display: block;
  position: static;
  width: auto;
  margin: 0 0 14px;
}
html:not(.js) [data-abrir-modal^="modal-personal-"],
html:not(.js) .modal-personal [data-cerrar-modal] { display: none; }


.modal .formulario { margin: 0; padding: 18px; }

.modal-titulo { margin: 0 0 6px; font-size: 1.05rem; }

.modal-texto { margin: 0 0 14px; color: var(--texto-suave); font-size: .9rem; }

.modal-acciones { justify-content: flex-end; margin-top: 4px; }

/* --------------------------------------------------------------------
   Filtros
   -------------------------------------------------------------------- */
.filtros {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr));
  gap: 0 14px;
  align-items: end;
}

/* Pantalla mediana: cuatro columnas fijas. Los tres checks y las acciones van
   juntos en el pie, fuera de estas columnas.

   Cuatro FIJAS y no `auto-fit`: auto-fit cuenta cuantas columnas entran segun
   el ancho, asi que el mismo panel salia en dos filas en un monitor y en tres
   en otro. Con un numero fijo se ve igual en todas las maquinas de la sala. */
@media (min-width: 900px) {
  .filtros {
    grid-template-columns: repeat(4, minmax(170px, 230px));
    justify-content: start;
  }
}

/* Pantalla ancha: los controles principales en una sola fila.

   Las columnas NO son iguales, porque los campos no necesitan lo mismo: el
   rango junta dos fechas y el buscador acepta "UID, modelo, serie, juego,
   motivo, tecnico". Repartir el ancho en partes iguales comprime a los dos.

   Rangos rápidos va en `max-content`: mide lo que miden sus pastillas, ni un
   pixel más. El sobrante se lo queda el buscador, que es el `1fr`.

   Desde 1350px y no antes, para que los campos conserven un ancho cómodo.

   El sobrante se lo queda entero el buscador, sin tope. Es lo contrario de lo
   que hicimos con el resto -donde estirar los campos dejaba el panel con aire de
   formulario a medio llenar- y es a proposito: el buscador es el unico campo que
   aprovecha el ancho, porque acepta texto largo, y darselo a el evita que quede
   un bloque muerto a la derecha. */
@media (min-width: 1350px) {
  .filtros {
    grid-template-columns:
      minmax(190px, 1fr)      /* Buscar: se queda con el sobrante */
      minmax(150px, 210px)    /* Vendor */
      320px                   /* Rango de fechas */
      max-content;            /* Rangos rápidos */
    justify-content: stretch;
  }
}

/* Entre 1350 y 1499px el usuario multisala conserva las cuatro columnas de la
   vista mediana. */
@media (min-width: 1350px) and (max-width: 1499px) {
  .filtros.filtros-con-sala {
    grid-template-columns: repeat(4, minmax(170px, 230px));
    justify-content: start;
  }
}

/* Con lugar suficiente, Sala se ubica al lado de Vendor y los cinco controles
   principales vuelven a quedar en una sola línea. */
@media (min-width: 1500px) {
  .filtros.filtros-con-sala {
    grid-template-columns:
      minmax(190px, 1fr)      /* Buscar */
      minmax(145px, 200px)    /* Vendor */
      minmax(135px, 190px)    /* Sala */
      320px                   /* Rango de fechas */
      max-content;            /* Rangos rápidos */
    justify-content: stretch;
  }
}

.filtros .campo { margin-bottom: 12px; }

/* Los filtros booleanos forman una sola franja al pie de la tarjeta. El pie es
   un único hijo de la grilla, así que no se separan entre las columnas de arriba. */
.filtros-pie {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 28px;
}

.filtros-checks {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 28px;
}

.filtros .filtros-checks .campo { margin-bottom: 12px; }

/* Sin JavaScript quedan los dos calendarios nativos. fs.js los reemplaza por
   el selector de rango, pero los mismos inputs siguen siendo los que viajan
   en el GET. */
.campo .campo-rotulo {
  font-size: .85rem;
  font-weight: 600;
  color: var(--texto-suave);
  margin-bottom: 4px;
}

.rango-fechas-nativo {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

/* El navegador define [hidden] antes que esta regla; se reafirma para que el
   respaldo desaparezca al inicializar el selector con JavaScript. */
.rango-fechas-nativo[hidden] { display: none; }

.campo .rango-fechas-nativo label {
  margin: 0;
  font-weight: 500;
}

.rango-fechas-nativo label > span {
  display: block;
  margin-bottom: 3px;
  color: var(--texto-tenue);
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .04em;
}

.rango-fechas-widget { position: relative; }

.rango-fechas-disparador {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  min-height: 36px;
  padding: 7px 9px;
  color: var(--texto);
  background: var(--fondo-panel);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-chico);
  font: inherit;
  font-size: .92rem;
  text-align: left;
  cursor: pointer;
}

.rango-fechas-disparador:hover { background: var(--fondo-hover); }
.rango-fechas-disparador:focus-visible { outline: 2px solid var(--acento); outline-offset: -1px; }

.rango-fechas-icono {
  position: relative;
  width: 15px;
  height: 15px;
  flex: 0 0 15px;
  border: 1.5px solid currentColor;
  border-radius: 2px;
}
.rango-fechas-icono::before {
  position: absolute;
  top: 3px;
  right: 0;
  left: 0;
  height: 1.5px;
  content: '';
  background: currentColor;
}
.rango-fechas-icono::after {
  position: absolute;
  top: -2px;
  left: 3px;
  width: 2px;
  height: 4px;
  content: '';
  background: var(--fondo-panel);
  border-right: 1.5px solid currentColor;
  border-left: 1.5px solid currentColor;
}

.rango-fechas-popover {
  position: absolute;
  z-index: 30;
  top: calc(100% + 6px);
  left: 0;
  width: min(630px, calc(100vw - 42px));
  padding: 12px;
  color: var(--texto);
  background: var(--fondo-panel);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio);
  box-shadow: 0 12px 28px rgba(20, 35, 58, .22);
}

.rango-fechas-cab,
.rango-fechas-pie {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.rango-fechas-cab { margin-bottom: 8px; font-size: .88rem; font-weight: 700; }
.rango-fechas-pie { margin-top: 10px; color: var(--texto-suave); font-size: .8rem; }

.rango-fechas-nav {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  color: var(--texto);
  background: transparent;
  border: 1px solid var(--borde);
  border-radius: var(--radio-chico);
  font: inherit;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}
.rango-fechas-nav:hover { background: var(--fondo-hover); }
.rango-fechas-nav:focus-visible { outline: 2px solid var(--acento); outline-offset: 1px; }

.rango-calendarios { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
.rango-calendario { min-width: 0; }
.rango-calendario-titulo { margin: 0 0 7px; text-align: center; font-size: .88rem; font-weight: 700; }
.rango-calendario-semana,
.rango-calendario-dias { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.rango-calendario-semana span { padding-bottom: 3px; color: var(--texto-suave); font-size: .7rem; font-weight: 700; text-align: center; }

.rango-dia {
  min-width: 0;
  height: 31px;
  padding: 0;
  color: var(--texto);
  background: transparent;
  border: 0;
  border-radius: 4px;
  font: inherit;
  font-size: .8rem;
  cursor: pointer;
}
.rango-dia:hover { background: var(--fondo-hover); }
.rango-dia:focus-visible { outline: 2px solid var(--acento); outline-offset: -2px; }
.rango-dia.es-hoy { box-shadow: inset 0 0 0 1px var(--acento); }
.rango-dia.en-rango { background: var(--acento-suave); border-radius: 0; }
.rango-dia.es-inicio,
.rango-dia.es-fin { color: #fff; background: var(--acento-fuerte); border-radius: 4px; font-weight: 700; }
.rango-dia.vacio { cursor: default; pointer-events: none; }

@media (max-width: 650px) {
  .rango-fechas-popover { width: min(340px, calc(100vw - 34px)); }
  .rango-calendarios { grid-template-columns: 1fr; }
  .rango-calendario:nth-child(2) { display: none; }
}

/* Los atajos de rango no entran en una columna: las tres pastillas necesitan
   mas de 170px y se partian en dos renglones. Van con la etiqueta al lado en
   vez de arriba, que es como se lee una barra de atajos, y ocupando dos
   columnas.

   DOS columnas y no todas (`1 / -1`), que fue el primer intento y salio mal:
   si un elemento ocupa todas, ninguna columna queda vacia, y `auto-fit` solo
   colapsa las que nadie usa. La grilla se quedaba con ocho columnas de las que
   se llenaban cuatro, y sobraban 800px a la derecha.

   El span va detras de una consulta de ancho minimo: abajo de 640px la grilla
   queda en una sola columna, y ahi pedir dos crearia una columna implicita que
   desborda de costado. */
/* Los atajos de rango entran en una columna con la etiqueta arriba, como
   cualquier otro campo: las tres pastillas juntas miden unos 210px. Con la
   etiqueta al lado -que fue un intento anterior- la celda se iba a 330px y ya
   no entraba en una fila con el resto. */
.filtros .campo-rangos { justify-content: flex-end; }

/* En el teléfono no se muestran los atajos de rango: ocupan lugar y el selector
   de fecha nativo del teléfono ya hace el trabajo con Desde y Hasta. */
@media (max-width: 700px) {
  .filtros .campo-rangos { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .actividad-panel { transition: none; }
}

.filtros-acciones {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
  align-items: flex-end;
}

.filtros.filtros-rapidos {
  grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 220px));
  justify-content: start;
}

/* --------------------------------------------------------------------
   Listas de definiciones
   -------------------------------------------------------------------- */
.datos {
  display: grid;
  grid-template-columns: minmax(140px, max-content) 1fr;
  gap: 6px 18px;
  margin: 0;
  font-size: .9rem;
}

.datos dt { font-weight: 600; color: var(--texto-suave); }
.datos dd { margin: 0; }


/* --------------------------------------------------------------------
   Paginacion
   -------------------------------------------------------------------- */
.paginacion {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--borde);
}

/* --------------------------------------------------------------------
   Mensajes flash
   -------------------------------------------------------------------- */
.flashes { margin-bottom: 16px; }

.flash {
  padding: 10px 14px;
  border-radius: var(--radio-chico);
  border-left: 4px solid;
  margin-bottom: 8px;
  font-size: .9rem;
}

.flash-ok    { background: var(--verde-bg); border-color: var(--verde); color: var(--verde); }
.flash-error { background: var(--rojo-bg);  border-color: var(--rojo);  color: var(--rojo); }
.flash-aviso { background: var(--ambar-bg); border-color: var(--ambar); color: var(--ambar); }

/* Los de exito y aviso se van solos a los pocos segundos (lo hace fs.js). El
   desvanecido: primero baja la opacidad, despues colapsa el alto, para que los
   flashes de abajo suban suave en vez de saltar. */
.flash-yendose {
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity .4s ease, transform .4s ease;
}

/* Varios botones en la misma celda de una tabla, cada uno con su form. */
.acciones-fila { display: flex; gap: 6px; flex-wrap: wrap; }
.acciones-fila form { margin: 0; }

/* Las preferencias se editan en un modal; cada opción ocupa su propia línea
   para que no parezcan un texto corrido. */
.opciones-avisos { display: grid; gap: 8px; }
.formulario fieldset.campo .opcion {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: .85rem;
  font-weight: 400;
  color: var(--texto);
}
.opciones-avisos label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: .9rem;
  font-weight: 400;
  color: var(--texto);
}

/* Con la explicacion al lado el rotulo pasa a ocupar dos renglones en un
   telefono, y centrado vertical la casilla queda flotando en el medio del
   texto. Arriba y alineada con la primera linea, que es donde esta el nombre
   del aviso. */
.opciones-avisos label:has(.tenue) { align-items: flex-start; }
.opciones-avisos label:has(.tenue) input { margin-top: .2em; }
.opciones-avisos .tenue { font-size: .85em; }

/* --------------------------------------------------------------------
   Graficos SVG generados en el servidor
   -------------------------------------------------------------------- */
.grafico { width: 100%; height: auto; display: block; overflow: visible; }
.grafico .g-barra { fill: var(--acento); }
.grafico .g-etiqueta { fill: var(--texto-suave); font-size: 11px; font-family: var(--fuente); }
.grafico .g-valor { fill: var(--texto-tenue); font-size: 10px; font-family: var(--fuente-mono); }
.grafico .g-guia { stroke: var(--borde); stroke-width: 1; }
