/* =====================================================================
   FS - Componentes
   Lo que se repite en todas las pantallas: pestanas, tablas, botones, formularios.

   Parte de la hoja de estilos de FS, que se sirve en varios archivos
   enlazados en orden desde src/views/_estilos.php. El orden importa:
   la cascada es la concatenacion de todos ellos.
   ===================================================================== */
/* --------------------------------------------------------------------
   Pestañas de sección (Ajustes)
   -------------------------------------------------------------------- */
.tabs {
  display: flex;
  gap: 2px;
  flex-wrap: wrap;
  margin-bottom: 18px;
  border-bottom: 2px solid var(--borde);
}

/* Lo que se pega arriba mientras se hace scroll. Un contenedor sticky que
   envuelve la parte de navegación/filtro de cada listado, para no volver al
   tope al recorrer una lista larga:

     - Reparaciones: el título + las pestañas de estado.
     - Base Slots:   los chips (filtros rápidos) + el panel de búsqueda.

   Va todo en UN solo contenedor a propósito: si cada pieza se pegara por su
   cuenta, dos o tres sticky pelearían por el mismo borde superior. El fondo
   es obligatorio —un sticky transparente deja ver el contenido pasar por
   atrás—, y el z-index lo deja por encima de la tabla. */
.cabecera-pegajosa {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--fondo);
  padding-top: 10px;
}
.cabecera-pegajosa .titulo-pagina { margin-bottom: 10px; }
/* Adentro, las pestañas no se pegan por su cuenta (el contenedor ya lo hace);
   los chips se juntan un poco al panel de filtros que va debajo. */
.cabecera-pegajosa .tabs  { position: static; }
.cabecera-pegajosa .chips { margin-bottom: 12px; }

.tabs .tab {
  padding: 9px 16px;
  font-size: .92rem;
  font-weight: 550;
  text-transform: uppercase;
  color: var(--texto-suave);
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  white-space: nowrap;
}

.tabs .tab:hover {
  color: var(--texto);
  background: var(--fondo-hover);
  text-decoration: none;
  border-radius: var(--radio-chico) var(--radio-chico) 0 0;
}

/* Cada estado conserva su color semantico. Las pestañas inactivas quedan
   neutras; estas variables aparecen al seleccionar una. */
.tabs .tab-en_reparacion  { --tab-color: var(--ambar);       --tab-bg: var(--ambar-bg); }
.tabs .tab-pendiente      { --tab-color: var(--violeta);     --tab-bg: var(--violeta-bg); }
/* Las vistas por ubicacion no estan aca: no son pestañas sino los chips de
   adentro de cada estado abierto, y los chips llevan su propio estilo. */
/* TOTAL FS suma en_reparacion y pendiente: las maquinas que hoy no dan plata,
   asi que va en rojo. Su destaque completo esta mas abajo. */
.tabs .tab-total_fs       { --tab-color: var(--rojo);        --tab-bg: var(--rojo-bg); }
/* El paso intermedio va en azul: no es trabajo del taller -ya terminó- ni una
   máquina andando. Es el traslado, el mismo color con el que se marca el viaje
   de la pieza en la ficha (.etq-envio-lab, .etq-recibido-sala). */
.tabs .tab-rep_sin_recibir { --tab-color: var(--acento);   --tab-bg: var(--acento-suave); }
.tabs .tab-en_servicio    { --tab-color: var(--verde);       --tab-bg: var(--verde-bg); }
.tabs .tab-retirada       { --tab-color: var(--texto-suave); --tab-bg: var(--gris-bg); }
.tabs .tab-todas          { --tab-color: var(--acento);    --tab-bg: var(--acento-suave); }

.tabs .tab.activa {
  color: var(--tab-color, var(--acento));
  background: var(--tab-bg, var(--acento-suave));
  border-bottom-color: var(--tab-color, var(--acento));
  border-radius: var(--radio-chico) var(--radio-chico) 0 0;
  font-weight: 700;
}

/* Contador al lado del nombre de la pestaña. */
.tab-num {
  display: inline-block;
  margin-left: 6px;
  font-family: var(--fuente-mono);
  font-size: .82rem;
  padding: 1px 6px;
  border-radius: 10px;
  background: var(--gris-bg);
  color: var(--texto-suave);
}

.tabs .tab.activa .tab-num {
  background: var(--fondo-panel);
  color: var(--tab-color, var(--acento));
}

/* ---------------------------------------------------------------------
   TOTAL FS: la primera pestaña, y la unica encendida sin estar elegida.

   El resto de las pestañas quedan neutras hasta que se las abre; esta no,
   porque su numero es el dato que se viene a mirar: cuantos slots no estan
   en sala ahora mismo. Si hubiera que buscarla entre cinco pestañas grises
   dejaria de ser un total y seria una pestaña mas.

   Los colores salen de las variables del tema, asi que el oscuro se acomoda
   solo. --fondo-panel hace de "color sobre rojo": blanco en el tema claro y
   casi negro en el oscuro, que es justo lo que necesita cada uno para leerse
   contra su propio rojo.
   --------------------------------------------------------------------- */
.tabs .tab-total_fs {
  color: var(--rojo);
  background: var(--rojo-bg);
  border: 1px solid var(--rojo);
  border-bottom: 2px solid var(--rojo);
  border-radius: var(--radio-chico) var(--radio-chico) 0 0;
  font-weight: 750;
  letter-spacing: .02em;
  /* Separada de las dos que la desglosan: primero el total, despues el
     detalle. El gap de 2px del resto no alcanza para leerlo como un corte. */
  margin-right: 12px;
}

.tabs .tab-total_fs:hover {
  color: var(--rojo);
  background: var(--rojo-bg);
  filter: brightness(.97);
}

/* El contador es el dato, no una etiqueta: va en rojo lleno. Esta regla cae
   despues de la de .tab.activa .tab-num a proposito, para que el numero se
   vea igual de fuerte con la pestaña abierta o cerrada. */
.tabs .tab-total_fs .tab-num {
  background: var(--rojo);
  color: var(--fondo-panel);
  font-weight: 700;
}

/* Abierta, se invierte: el rojo pasa al fondo. */
.tabs .tab-total_fs.activa {
  color: var(--fondo-panel);
  background: var(--rojo);
}

.tabs .tab-total_fs.activa .tab-num {
  background: var(--fondo-panel);
  color: var(--rojo);
}

/* ---------------------------------------------------------------------
   El grupo "Más" de las pestañas

   En la pantalla grande no existe: el <details> y su panel se vuelven
   transparentes con display: contents, asi que sus enlaces son hijos
   directos de .tabs y quedan en la misma fila que los demas, en el mismo
   orden de siempre. El boton que lo abre no se muestra.

   En el telefono (mas abajo, con la clase js) el mismo markup se convierte
   en un desplegable. Sin JavaScript se queda como en la pantalla grande:
   todo a la vista, que es el fallback razonable.
   --------------------------------------------------------------------- */
.tabs-mas,
.tabs-mas-panel { display: contents; }
.tabs-mas > summary { display: none; }

/* Chrome envuelve el contenido del <details> en una caja propia,
   ::details-content, que el display: contents del <div> de adentro no hace
   desaparecer. Las pestañas plegadas quedaban dentro de esa caja: en vez de
   ser items del flex de .tabs eran inline dentro de un item, y se dibujaban
   8px mas arriba que las otras cuatro. Se vuelve transparente tambien. */
.tabs-mas::details-content { display: contents; }
.tab-mas-flecha { margin-left: 6px; font-size: .68rem; line-height: 1; }

/* En el telefono las siete pestañas ocupaban cuatro renglones -176px- y todo
   eso viajaba pegado arriba mientras se scrolea la tabla. Quedan las tres del
   piso y el resto entra acá. */
@media (max-width: 700px) {
  html.js .tabs-mas {
    display: block;
    /* El panel se cuelga de este elemento, no de la barra: asi cae debajo del
       boton y no del primer borde de la pantalla. */
    position: relative;
  }

  /* El boton se dibuja como un control y no como una pestaña apagada: con el
     estilo de las otras se perdia entre ellas, y es el unico de la barra que
     esconde algo detras. Contorno entero, fondo propio y el texto en el gris
     fuerte: se lee "esto se abre" sin tener que probarlo. */
  html.js .tabs-mas > summary {
    display: inline-flex;
    align-items: center;
    list-style: none;
    cursor: pointer;
    color: var(--texto);
    background: var(--gris-bg);
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio-chico);
    font-weight: 650;
  }

  html.js .tabs-mas > summary::-webkit-details-marker { display: none; }

  /* Acá el <details> vuelve a ser un desplegable de verdad, asi que su caja
     vuelve a ser una caja: con display: contents el navegador no puede
     ocultarle el contenido cuando esta cerrado. */
  html.js .tabs-mas::details-content { display: block; }

  /* Abierto se marca en azul, como cualquier control en uso, y el triangulito
     se da vuelta: el boton dice si el menu esta desplegado o no. */
  html.js .tabs-mas[open] > summary {
    color: var(--acento);
    border-color: var(--acento);
    background: var(--acento-suave);
  }

  /* El triangulito, separado por una linea: es la parte que promete el menu,
     igual que en un selector del sistema.

     Se da vuelta con scaleY y no con rotate: rotar 180 grados le pasaria la
     linea separadora al otro lado del triangulito. */
  .tab-mas-flecha {
    /* Estirado a lo alto del boton, para que la linea sea una separacion y no
       una rayita del tamaño del triangulito. */
    display: flex;
    align-items: center;
    align-self: stretch;
    margin-left: 8px;
    padding-left: 8px;
    font-size: .8rem;
    border-left: 1px solid var(--borde-fuerte);
  }

  html.js .tabs-mas[open] > summary .tab-mas-flecha {
    transform: scaleY(-1);
    border-left-color: var(--acento);
  }

  /* Flota sobre la tabla en vez de empujarla: abrir el menu no puede mover de
     lugar la fila que estabas mirando. */
  html.js .tabs-mas-panel {
    display: flex;
    flex-direction: column;
    gap: 2px;
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    z-index: 25;
    min-width: 210px;
    padding: 5px;
    background: var(--fondo-panel);
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio);
    box-shadow: var(--sombra);
  }

  /* Adentro del panel dejan de ser pestañas y pasan a ser renglones de menu:
     el nombre a la izquierda, el numero a la derecha, y el dedo tiene toda la
     fila para acertar. */
  html.js .tabs-mas-panel .tab {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 11px 12px;
    margin-bottom: 0;
    border: 0;
    border-radius: var(--radio-chico);
  }
}

/* La pastilla ".etq-requis" se fue: la columna REQUI del listado ya no muestra
   un numero mas una etiqueta, sino solamente cuantas requisiciones tiene el
   caso. Los numeros se leen en la ficha, agrupando las partes. */

/* Los otros equipos que entraron con la misma requisicion, en el historial de
   REQUIs de una maquina. Va debajo del UID y en chico: el dato principal de la
   fila es el pedido de ESTE equipo; esto avisa que el pedido sigue en otro. */
.requi-otros-uid {
  display: block;
  margin-top: 3px;
  color: var(--texto-suave);
  font-size: .78rem;
}

/* Prioridad operativa en el listado de reparaciones. */
.etq-prioridad {
  display: inline-block;
  width: fit-content;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: .72rem;
  font-weight: 750;
  line-height: 1.25;
}
.etq-prioridad-normal { color: var(--acento); background: var(--acento-suave); }
.etq-prioridad-alta   { color: var(--rojo);     background: var(--rojo-bg); }

/* .tabs-resto y .tab-suave se sacaron: Retiradas y Todas iban al otro extremo
   de la barra y en chico, marcadas como "no son del trabajo diario". Para
   Todas eso probablemente no era cierto -es la vista sin filtro de estado, y
   adonde se va a buscar cuando no se sabe en que estado quedo algo-, y
   achicarlas era la interfaz decidiendo por el operador cual le importa. Ahora
   son todas iguales: el orden dice que va primero y el contador de cada una
   dice si tiene algo adentro. */

/* --------------------------------------------------------------------
   Días acumulados de una pestaña
   -------------------------------------------------------------------- */
.resumen-dias {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px 22px;
  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: 11px 16px;
  margin-bottom: 14px;
}

/* Hay máquinas afuera: el número es una cuenta que corre, no un dato
   cerrado, así que va en ámbar. Sin ninguna, en verde. */
.resumen-abierta { border-left-color: var(--ambar); }
.resumen-abierta .resumen-num { color: var(--ambar); }
.resumen-ok { border-left-color: var(--verde); }
.resumen-ok .resumen-num { color: var(--verde); }

.resumen-cifra { display: flex; align-items: center; gap: 11px; }

.resumen-num {
  /* Es el numero que se viene a mirar: cuantas maquinas hay en la pestaña que
     esta abierta. Estaba en 2.1rem, apenas mas grande que un titulo. */
  font-size: 2.8rem;
  font-weight: 700;
  line-height: 1;
  color: var(--texto);
  font-variant-numeric: tabular-nums;
}

/* El rotulo y su desglose son lo que explica el numero grande: iban en .85 y
   .82rem, un tamaño de nota al pie para la linea que se lee primero. */
.resumen-rot {
  font-size: 1rem;
  color: var(--texto);
  display: flex;
  flex-direction: column;
  line-height: 1.4;
}

/* Cada parte del desglose lleva a su pestaña, asi que se ven como lo que son:
   enlaces. El punto que las separa no. */
.resumen-desglose {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 2px 4px;
  margin-top: 3px;
  font-size: .95rem;
  color: var(--texto-suave);
}

.resumen-desglose a {
  font-weight: 600;
  /* Cada parte se parte por entero al renglon siguiente y nunca por la mitad:
     en el telefono, "7 en reparación" comprimido salia en tres lineas de una
     palabra cada una. */
  white-space: nowrap;
  /* El margen negativo compensa el relleno: el area para el dedo crece sin
     mover de lugar el renglon. */
  padding: 4px 7px;
  margin: -4px 0;
  border-radius: var(--radio-chico);
}

.resumen-desglose a:hover {
  background: var(--acento-suave);
  text-decoration: none;
}

.resumen-punto { color: var(--texto-tenue); }

/* En el telefono el desglose se toca con el dedo: mismo texto, mas blanco
   alrededor para no errarle. */
@media (max-width: 700px) {
  /* El corrimiento a la izquierda alinea el texto del primer enlace con el
     rotulo de arriba, que no tiene relleno. */
  .resumen-desglose { font-size: 1rem; gap: 4px 6px; margin-left: -10px; }

  /* Sin margen negativo arriba y abajo: con el, dos partes en renglones
     seguidos se pisaban las areas de toque y el dedo podia caer en la de al
     lado. Aca el relleno empuja el renglon, que es lo que corresponde. */
  .resumen-desglose a { padding: 8px 10px; margin: 0; }
}

/* La peor es el dato accionable de la barra: se separa del resto. */
.resumen-peor {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-weight: 600;
  color: var(--texto);
}

.resumen-peor a { font-weight: 700; }

/* Las piezas que esperan a Logistica, al lado de la mayor demora. Ambar y no
   rojo: no es una maquina caida sino algo que espera a alguien, el mismo
   criterio que las pastillas de la ficha. */
.resumen-cola {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-weight: 600;
  color: var(--texto-suave);
}
.resumen-cola:hover { color: var(--texto); }
.resumen-cola-n {
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--ambar);
}

.resumen-detalle {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 16px;
  font-size: .88rem;
  color: var(--texto-suave);
}

/* --------------------------------------------------------------------
   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; }

.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; }

/* .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); }

.aviso-sin-reparacion {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--rojo-bg);
  border: 2px solid var(--rojo);
  color: var(--rojo);
  font-weight: 700;
  font-size: 1rem;
  padding: 12px 16px;
  border-radius: var(--radio);
  margin-bottom: 16px;
}
.aviso-sin-reparacion-icono {
  font-size: 1.25rem;
  flex: 0 0 auto;
}

.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. */
.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: 10px;
  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: 10px;
  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 taller, 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); }
.etq-envio-lab     { background: var(--acento-suave); color: var(--acento); }
/* Los hitos del viaje comparten el azul: el mismo dato -donde esta la pieza-
   contado en la ida, en la vuelta y en el despacho del repuesto. */
.etq-recibido-sala { background: var(--acento-suave); color: var(--acento); }
.etq-envio-sala    { background: var(--acento-suave); color: var(--acento); }
/* Lo que falta es de Logistica y no de Sala: ambar, como todo lo que esta
   esperando a alguien. */
.etq-espera-envio  { background: var(--ambar-bg); color: var(--ambar); }
/* Los dos tramos que abre el REQUI, del mismo lado de la espera y por eso del
   mismo color: la pieza que sigue en el salon esperando que la pasen a buscar,
   y la que espera un repuesto que nadie empezo a comprar. */
.etq-espera-recepcion { background: var(--ambar-bg); color: var(--ambar); }
.etq-espera-compra { background: var(--ambar-bg); color: var(--ambar); }
/* Y el hito que las saca de ahi: alguien esta gestionando la compra. Azul como
   el resto de los hitos ocurridos. */
.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;
}

.partes-reparacion li {
  padding: 12px 0;
  border-bottom: 1px solid var(--borde);
}

.partes-reparacion li:last-child { border-bottom: none; }

/* --------------------------------------------------------------------
   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; }

/* --------------------------------------------------------------------
   Novedades (el changelog, desde el numero de version del pie)

   El modal es mas alto que ancho: son entradas de texto una abajo de la
   otra, no un formulario. El titulo y el boton de cerrar quedan fijos y
   lo unico que se desplaza es la lista, para que cerrar no obligue a
   volver arriba del todo.
   -------------------------------------------------------------------- */
.pie-version {
  color: var(--texto-tenue);
  text-decoration: none;
  border-bottom: 1px dotted var(--borde-fuerte);
}
.pie-version:hover,
.pie-version:focus-visible { color: var(--texto); }

.modal-alto { width: min(760px, calc(100vw - 32px)); }

.modal-scroll {
  max-height: min(58vh, 520px);
  overflow-y: auto;
  padding: 14px 16px;
  margin-bottom: 14px;
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  background: var(--fondo);
}

.changelog-entrada + .changelog-entrada {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--borde);
}

.changelog-cab {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}

.changelog-version {
  padding: 1px 7px;
  border-radius: var(--radio-chico);
  background: var(--acento-suave);
  color: var(--acento-fuerte);
  font-size: .78rem;
}

.changelog-titulo { margin: 0; font-size: 1rem; }
.changelog-fecha  { margin-left: auto; font-size: .8rem; }

.changelog-cuerpo p  { margin: 8px 0; }
.changelog-cuerpo ul { margin: 8px 0; padding-left: 20px; }
.changelog-cuerpo li { margin: 3px 0; }
.changelog-cuerpo code {
  padding: 1px 4px;
  border-radius: var(--radio-chico);
  background: var(--fondo-hover);
  font-size: .86em;
}

.changelog-dentro > summary {
  cursor: pointer;
  color: var(--texto-suave);
  font-size: .82rem;
}
.changelog-dentro[open] > summary { margin-bottom: 2px; }
.changelog-dentro .changelog-cuerpo {
  padding-left: 12px;
  border-left: 2px solid var(--borde);
  color: var(--texto-suave);
  font-size: .88rem;
}

/* --------------------------------------------------------------------
   Entrada señuelo

   Un boton con el aspecto del campo de texto que reemplaza: se toca
   donde uno ya iba a tocar, pero lo que abre es el modal. Va como
   <button> y no como <input readonly> para que un lector de pantalla
   anuncie que es algo que se acciona y no un campo que no deja escribir.
   -------------------------------------------------------------------- */
.entrada-senuelo {
  font-family: inherit;
  font-size: .92rem;
  text-align: left;
  color: var(--texto-tenue);
  background: var(--fondo-panel);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-chico);
  padding: 7px 9px;
  width: 100%;
  cursor: text;
}

.entrada-senuelo:hover { border-color: var(--acento); }

.entrada-senuelo:focus-visible {
  outline: 2px solid var(--acento);
  outline-offset: -1px;
  border-color: var(--acento);
}

.campo-novedad { margin-top: 14px; }

.parte-estado-editor { margin-top: 10px; }
.parte-estado-editor > summary { display: inline-flex; list-style: none; }
.parte-estado-editor > summary::-webkit-details-marker { display: none; }

/* Los dos desplegables de una parte, "Marcar enviada a LAB" y "Cambiar estado",
   en el mismo renglon: son dos botones chicos y uno debajo del otro dejaba media
   ficha vacia.
   Al abrirse, flex-basis 100% le da el renglon entero al que se abrio y empuja
   al otro boton al siguiente: el formulario de estado tiene tres campos mas el
   motivo y en la mitad del ancho quedaba ilegible. El margin-top de cada
   details se anula porque ahora lo pone el contenedor, y sumados dejaban los
   renglones desparejos. */
.parte-acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 8px;
  margin-top: 10px;
}

.parte-acciones > details { margin-top: 0; }
.parte-acciones > details[open] { flex: 1 0 100%; }

.form-estado-parte {
  margin-top: 10px;
  padding: 12px;
  border: 1px solid var(--borde);
  border-radius: var(--radio-chico);
  background: var(--fondo-suave);
}

.form-agregar-parte {
  display: flex;
  align-items: end;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--borde);
}

.form-agregar-parte .campo { flex: 1; margin: 0; }

/* El buscador se lleva una fila entera: filtra un catalogo de casi 900 piezas
   y compartir el ancho con el comentario lo dejaba en un tercio de la linea,
   demasiado angosto para leer el nombre que se esta eligiendo. El comentario y
   el boton entran juntos en la fila de abajo. */
.form-agregar-parte .campo[data-autocompletar-parte] { flex: 1 1 100%; }

.autocompletar-parte-caja { position: relative; }

.autocompletar-parte-lista {
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  overflow: hidden;
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-chico);
  background: var(--fondo-panel);
  box-shadow: var(--sombra);
}

.autocompletar-parte-lista[hidden] { display: none; }

.autocompletar-parte-opcion {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-bottom: 1px solid var(--borde);
  border-radius: 0;
  background: var(--fondo-panel);
  color: var(--texto);
  text-align: left;
  font: inherit;
  cursor: pointer;
}

.autocompletar-parte-opcion:last-of-type { border-bottom: 0; }
.autocompletar-parte-opcion:hover,
.autocompletar-parte-opcion.activa { background: var(--fondo-hover); }
.autocompletar-parte-opcion.seleccionada {
  background: var(--acento-suave);
  color: var(--acento);
}
.autocompletar-parte-opcion code { color: var(--texto-tenue); }
.autocompletar-parte-opcion[hidden] { display: none; }
.autocompletar-parte-vacio { margin: 0; padding: 9px 10px; color: var(--texto-suave); }

.partes-seleccionadas {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.parte-seleccionada {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  max-width: 100%;
  padding: 5px 8px;
  border: 1px solid var(--borde-fuerte);
  border-radius: 999px;
  background: var(--acento-suave);
  color: var(--acento);
  font: inherit;
  font-size: .82rem;
  cursor: pointer;
}

.parte-seleccionada span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.parte-seleccionada:hover { border-color: var(--acento); }
.parte-seleccionada[hidden] { display: none; }

.campo-boton { justify-content: flex-end; }
.campo-boton .btn { margin-bottom: 1px; }

.fila-campos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  gap: 0 14px;
  align-items: start;
}

.fila-campos .campo-ancho { grid-column: span 2; }
.fila-accion { align-items: end; }

/* Barra de una sola línea: un par de campos y el botón, todo en el mismo
   renglón. No usa la grilla de .fila-campos porque su mínimo de 210px por
   columna, en una columna angosta, deja solo dos columnas: ahí un
   .campo-ancho ocupa las dos y empuja el botón a un tercer renglón. */
.fila-linea {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 0 10px;
}

/* Fila con una nota de ayuda debajo de un campo.
   .fila-accion y .fila-linea alinean al pie (align-items: end) para que los
   controles queden parejos aunque un rotulo ocupe dos renglones. Con una nota
   debajo, esa columna crece hacia abajo y el pie comun le levanta el input por
   encima de los vecinos: los rotulos quedan a distinta altura. Alineando arriba
   vuelven a la misma linea y la nota queda colgando al pie, que es su lugar.
   Es una clase y no algo automatico: si se le agrega una nota a otra fila, hay
   que ponersela. */
.fila-campos.fila-con-nota,
.fila-linea.fila-con-nota { align-items: start; }

.fila-linea .campo        { flex: 1 1 150px; }
.fila-linea .campo-chico  { flex: 1 1 130px; }
.fila-linea .campo-ancho  { flex: 3 1 190px; }
.fila-linea .campo-boton  { flex: 0 0 auto; }

.error-campo {
  color: var(--rojo);
  font-size: .8rem;
  margin: 4px 0 0;
  font-weight: 500;
}

.ayuda {
  font-size: .8rem;
  color: var(--texto-tenue);
  margin: 4px 0 0;
  line-height: 1.4;
}

.ayuda-bloque {
  background: var(--fondo-suave);
  border-left: 3px solid var(--acento);
  border-radius: var(--radio-chico);
  padding: 10px 14px;
  margin: 0 0 16px;
  font-size: .86rem;
  color: var(--texto-suave);
}

.ayuda-uid { font-weight: 600; color: var(--verde); }
.ayuda-uid[data-nueva] { color: var(--ambar); }

/* Aviso de duplicado bajo el UID: caja de advertencia, para que se note apenas
   se tipea el UID y no pase por alto. */
.aviso-uid-abierta {
  margin-top: 4px;
  padding: 10px 14px;
  border-radius: var(--radio-chico);
  border-left: 4px solid var(--ambar);
  background: var(--ambar-bg);
  color: var(--ambar);
  font-size: .9rem;
  line-height: 1.4;
}
.aviso-uid-abierta a { color: var(--ambar); font-weight: 700; text-decoration: underline; }

/* --------------------------------------------------------------------
   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; }

/* --------------------------------------------------------------------
   Bitacora
   -------------------------------------------------------------------- */
.bitacora { list-style: none; margin: 0; padding: 0; }

.bitacora li {
  border: 1px solid var(--borde);
  border-left: 4px solid var(--acento);
  background: var(--fondo-panel);
  border-radius: var(--radio-chico);
  padding: 11px 14px 12px;
  margin-bottom: 12px;
  box-shadow: var(--sombra);
}

/* El color lateral permite reconocer rápido de qué área vino cada comentario,
   incluso antes de leer la etiqueta del autor. */
.bitacora li[data-categoria="sala"]        { border-left-color: var(--acento); }
.bitacora li[data-categoria="logistica"]   { border-left-color: var(--ambar); }
.bitacora li[data-categoria="laboratorio"] { border-left-color: var(--verde); }
.bitacora li[data-categoria="otros"]       { border-left-color: var(--texto-suave); }

/* Hitos que enmarcan la bitácora como una línea de tiempo: la salida de
   servicio al inicio y el cierre (volvió / retirada) al final. Se distinguen de
   las novedades con un punto y un color más fuerte. */
.bit-hito {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 8px 12px;
  margin-bottom: 8px;
  font-weight: 600;
  border-left: 3px solid var(--texto-suave);
  background: var(--gris-bg);
  border-radius: 0 var(--radio-chico) var(--radio-chico) 0;
}
.bit-hito .mono { font-weight: 700; }
.bit-hito-inicio { border-left-color: var(--ambar); }
.bit-hito-fin { border-left-color: var(--verde); margin-top: 8px; }
.bit-hito-fin.sem-cerrada { border-left-color: var(--verde); }

.bit-cab {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding-bottom: 8px;
  margin-bottom: 9px;
  border-bottom: 1px solid var(--borde);
  font-size: .85rem;
}
.bit-cab form { margin: 0 0 0 auto; }
.bit-cab > strong {
  padding: 2px 6px;
  border-radius: var(--radio-chico);
  background: var(--gris-bg);
  color: var(--texto);
}

/* Quien escribio la novedad. Estaba en el gris de los metadatos y se perdia
   entre el sello y la etiqueta de area; al recorrer una bitacora larga el
   nombre es lo que se busca, asi que lleva el color de texto pleno (casi negro
   en claro, casi blanco en oscuro) y un poco mas de peso. */
.bit-cab .bit-autor {
  color: var(--texto);
  font-weight: 600;
}

.bitacora p {
  margin: 0;
  color: var(--texto);
  font-size: .94rem;
  line-height: 1.55;
}

/* "Sin reparación" dentro de una entrada: es lo que se busca al recorrer una
   bitácora larga, así que va en rojo y en negrita, el mismo rojo de la
   etiqueta de estado. */
.bit-sin-rep {
  color: var(--rojo);
  font-weight: 700;
}

/* Corregir una novedad: plegado, para que no compita con leerla. */
.bit-editar { margin-top: 6px; }

/* El disparador del modal se ve igual que el <summary> "Corregir" que
   reemplaza, para que la entrada no cambie de aspecto. */
.bit-editar-abrir {
  margin-top: 6px;
  font-size: .82rem;
  color: var(--texto-tenue);
}

.bit-editar-abrir:hover { color: var(--acento); }

.bit-editar > summary {
  font-size: .82rem;
  color: var(--texto-tenue);
  cursor: pointer;
  width: fit-content;
}

.bit-editar > summary:hover { color: var(--acento); }
.bit-editar[open] > summary { margin-bottom: 6px; color: var(--texto-suave); }
.bit-editar .campo { margin-bottom: 8px; }

/* Las novedades anteriores a las tres ultimas, plegadas.
   El summary se ve como un enlace y no como un boton: es para ir a buscar
   historia, no una accion del trabajo diario. */
.bit-anteriores > summary {
  font-size: .85rem;
  color: var(--texto-suave);
  cursor: pointer;
  padding: 6px 0;
  width: fit-content;
}

.bit-anteriores > summary:hover { color: var(--acento); }
.bit-anteriores[open] > summary { margin-bottom: 8px; }

/* Al abrirlo, lo viejo se distingue de las tres ultimas sin gritar: una linea
   al costado agrupa el bloque, mientras cada entrada conserva el color del
   area que la escribio. */
.bit-anteriores[open] {
  border-left: 1px dashed var(--borde);
  padding-left: 10px;
  margin-bottom: 10px;
}

/* Al imprimir no hay donde hacer clic, asi que el desplegable se abre solo
   (lo hace fs.js en beforeprint) y su titulo sobra. */
@media print {
  .bit-anteriores > summary { display: none; }
  .bit-anteriores[open]     { border-left: 0; padding-left: 0; }
}


/* --------------------------------------------------------------------
   Bitacora: etiquetas de area, tipos de entrada y filtros
   Estaban al final del archivo, lejos de la seccion Bitacora.
   -------------------------------------------------------------------- */
/* Etiqueta del área, con un color por área. Usa la base .etq. */
.etq-cat { font-weight: 600; }
.etq-cat-sala        { background: var(--acento-suave); color: var(--acento); }
.etq-cat-logistica   { background: var(--ambar-bg); color: var(--ambar); }
.etq-cat-laboratorio { background: var(--verde-bg); color: var(--verde); }
.etq-cat-otros       { background: var(--gris-bg);  color: var(--texto-suave); }

/* En la bitácora la etiqueta va chica, al lado del autor. */
.bit-cab .etq-cat { font-size: .72rem; padding: 1px 7px; }

/* Qué clase de entrada es: novedad escrita a mano, cambio de estado, movimiento
   de una parte.

   El chip va contorneado y en gris, con el color SOLO en el glifo, y no relleno
   como la etiqueta de área. No es capricho: el área ya usa azul, ámbar y verde
   rellenos, y los dos chips viven en el mismo renglón. Dos rellenos del mismo
   color al lado se leen como lo mismo, y esto aparece en todas las entradas de
   la bitácora, así que tiene que ser tranquilo. El color del glifo alcanza para
   barrer la columna con la vista. */
.bit-tipo {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: .72rem;
  font-weight: 600;
  padding: 1px 8px 1px 4px;
  border: 1px solid var(--borde);
  border-radius: 20px;
  color: var(--texto-suave);
  white-space: nowrap;
}

.bit-tipo-icono {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  font-size: .7rem;
  font-weight: 700;
  line-height: 1;
}

.bit-tipo-manual         .bit-tipo-icono { background: var(--ambar-bg);   color: var(--ambar); }
.bit-tipo-estado         .bit-tipo-icono { background: var(--violeta-bg); color: var(--violeta); }
.bit-tipo-parte_estado   .bit-tipo-icono { background: var(--violeta-bg); color: var(--violeta); }
.bit-tipo-parte_agregada .bit-tipo-icono { background: var(--verde-bg);   color: var(--verde); }
.bit-tipo-parte_quitada  .bit-tipo-icono { background: var(--rojo-bg);    color: var(--rojo); }
.bit-tipo-envio_lab      .bit-tipo-icono { background: var(--acento-suave);   color: var(--acento); }
.bit-tipo-adjunto        .bit-tipo-icono { background: var(--acento-suave);   color: var(--acento); }

/* Barra de chips para filtrar las novedades por área. */
.bit-filtros {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin: 2px 0 14px;
}
.bit-filtros-lbl { margin-right: 2px; }
.bit-chip {
  font-size: .82rem;
  font-weight: 600;
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid var(--borde-fuerte);
  background: var(--fondo-suave);
  color: var(--texto-suave);
  line-height: 1.4;
  cursor: pointer;
}
.bit-chip:hover { border-color: var(--acento); color: var(--texto); }
.bit-chip-activo,
.bit-chip-activo:hover {
  background: var(--acento-fuerte);
  border-color: var(--acento-fuerte);
  color: #fff;
}

/* Al filtrar, las novedades que no son del área elegida se ocultan. El
   selector con [hidden] gana en especificidad a cualquier display de .bitacora li. */
.bitacora li[hidden] { display: none; }

/* --------------------------------------------------------------------
   Adjuntos
   -------------------------------------------------------------------- */
.adjuntos { list-style: none; margin: 0; padding: 0; }

.adjuntos li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--borde);
}
.adjuntos li:last-child { border-bottom: none; }

.adjuntos img {
  width: 62px;
  height: 46px;
  object-fit: cover;
  border-radius: var(--radio-chico);
  border: 1px solid var(--borde);
  display: block;
}

.adj-doc {
  width: 62px;
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--rojo-bg);
  color: var(--rojo);
  font-weight: 700;
  font-size: .82rem;
  border-radius: var(--radio-chico);
  border: 1px solid var(--borde);
}
.adj-doc:hover { text-decoration: none; }

.adj-info { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.adj-info > a { font-size: .88rem; word-break: break-word; }

.adjuntos li > form { margin: 0; }
.progreso-subida { margin-top: 10px; display: grid; gap: 5px; font-size: .86rem; color: var(--texto-suave); }
.progreso-subida[hidden] { display: none; }
.progreso-subida span { display: block; height: 7px; border-radius: 999px; background: linear-gradient(90deg, var(--acento) var(--progreso, 0%), var(--borde) var(--progreso, 0%)); }
.progreso-subida em { font-style: normal; }
.aviso-vivo { margin-bottom: 14px; padding: 9px 12px; border-left: 3px solid var(--acento); border-radius: var(--radio-chico); background: var(--acento-suave); color: var(--texto); }

@keyframes fila-actualizada {
  0%, 100% { background-color: transparent; }
  50% { background-color: var(--acento-suave); }
}

tr.es-actualizada > td {
  animation: fila-actualizada 0.8s ease-in-out 3;
  background-color: var(--acento-suave);
}

@media (prefers-reduced-motion: reduce) {
  tr.es-actualizada > td {
    animation: none;
    background-color: var(--acento-suave);
  }
}

.titulo-pagina-con-accion {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 14px;
  flex-wrap: wrap;
}

.btn-nueva-flotante { position: static; box-shadow: none; }

@media (max-width: 700px) {
  .btn-nueva-flotante {
    position: fixed;
    right: 22px;
    bottom: 22px;
    z-index: 30;
    box-shadow: var(--sombra);
  }
}


/* --------------------------------------------------------------------
   Visor de adjuntos (lightbox)
   Estaba al final de fs.css, sin encabezado.
   -------------------------------------------------------------------- */
.sin-scroll { overflow: hidden; }

html.js .adjuntos [data-adj-abrir] img { cursor: zoom-in; }

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  background: rgba(8, 12, 18, .93);
}
.lightbox[hidden] { display: none; }

.lightbox-vis {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 58px 18px 74px;      /* deja aire para la cruz arriba y la barra abajo */
  min-height: 0;
  min-width: 0;
}
.lightbox-vis img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 4px;
  box-shadow: 0 10px 44px rgba(0, 0, 0, .55);
}
.lightbox-vis iframe { width: min(100%, 980px); height: 100%; border: 0; border-radius: 4px; background: #fff; }
.lightbox-doc { color: #fff; text-align: center; }
.lightbox-doc-icono {
  display: inline-block;
  font-size: 1.9rem;
  font-weight: 700;
  letter-spacing: 1px;
  border: 2px solid rgba(255, 255, 255, .5);
  border-radius: 8px;
  padding: 18px 24px;
  margin-bottom: 12px;
}

.lightbox-cerrar {
  position: absolute;
  top: 10px;
  right: 14px;
  z-index: 2;
  width: 42px;
  height: 42px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, .12);
  color: #fff;
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
}
.lightbox-cerrar:hover { background: rgba(255, 255, 255, .22); }

.lightbox-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 48px;
  height: 64px;
  border: none;
  border-radius: 8px;
  background: rgba(255, 255, 255, .1);
  color: #fff;
  font-size: 2rem;
  line-height: 1;
  cursor: pointer;
}
.lightbox-nav:hover { background: rgba(255, 255, 255, .2); }
.lightbox-nav[hidden] { display: none; }
.lightbox-nav.prev { left: 10px; }
.lightbox-nav.next { right: 10px; }

.lightbox-barra {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  gap: 14px;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  padding: 14px;
  background: linear-gradient(transparent, rgba(0, 0, 0, .55));
  color: #fff;
}
.lightbox-contador { font-variant-numeric: tabular-nums; opacity: .9; }
.lightbox-boton {
  border: 1px solid rgba(255, 255, 255, .4);
  background: rgba(255, 255, 255, .1);
  color: #fff;
  padding: 8px 14px;
  border-radius: 6px;
  font-size: .9rem;
  line-height: 1;
  cursor: pointer;
  text-decoration: none;
}
.lightbox-boton:hover { background: rgba(255, 255, 255, .2); color: #fff; }
.lightbox-eliminar { border-color: rgba(242, 139, 131, .6); color: #ffd9d5; }
.lightbox-eliminar:hover { background: rgba(179, 38, 30, .45); }
.lightbox-eliminar[hidden] { display: none; }

@media (max-width: 600px) {
  .lightbox-nav { width: 40px; height: 52px; font-size: 1.6rem; }
  .lightbox-vis { padding: 54px 6px 78px; }
}

/* ====================================================================
   Categoría (área) del usuario y filtro de la bitácora por área
   ==================================================================== */

/* --------------------------------------------------------------------
   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; }
