/* =====================================================================
   Stock físico SSP · "romaneo de balanza"
   =====================================================================
   Ticket de balanza impreso sobre chapa de silo: base carbón cálido,
   tinta hueso, sello ámbar grano, filetes perforados, numeración de
   secciones, rayado de advertencia.

   Mobile-first de verdad: esto se usa parado frente a un silo, con una
   mano, con guantes y con mala señal. Todo lo tocable mide 44px o más.
   ===================================================================== */

:root {
  --fondo:        #121110;
  --superficie:   #1b1a17;
  --superficie-2: #242320;
  --borde:        #33312c;
  --borde-suave:  #232220;

  --tinta:      #efeae0;
  --tinta-2:    #98928a;
  --tinta-3:    #75706a;

  --ambar:      #eeb03e;
  --ambar-alto: #f7c66a;
  --azul:       #6b8ea5;
  --azul-alto:  #a8c4d4;
  --rojo:       #d4462f;
  --rojo-alto:  #f07158;
  --verde:      #7ba33f;

  --ancho: 1120px;
  --alto-nav: 58px;

  --mono: 'IBM Plex Mono', ui-monospace, 'Cascadia Mono', Menlo, monospace;
  --titulos: 'Oswald', 'Arial Narrow', 'Helvetica Neue', sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--fondo);
  color: var(--tinta);
  font-family: var(--titulos);
  -webkit-text-size-adjust: 100%;
  overflow-x: hidden;
}

body {
  /* Espacio para la navegación fija, respetando el notch. */
  padding-bottom: calc(var(--alto-nav) + 34px + env(safe-area-inset-bottom));
}

.mono { font-family: var(--mono); }
.tinta { color: var(--tinta); }
.oculto { display: none !important; }

.ancho { width: min(100%, var(--ancho)); margin: 0 auto; padding: 0 16px; }

/* Los números siempre tabulares: una columna de kilos que baila es
   ilegible de un vistazo, que es justo para lo que sirve. */
.cifra, .kg, .tabular { font-variant-numeric: tabular-nums; }

::selection { background: var(--ambar); color: var(--fondo); }
::-webkit-scrollbar { height: 8px; width: 8px; }
::-webkit-scrollbar-thumb { background: var(--borde); }


/* ------------------------------- Cabecera ------------------------------ */

.cabecera {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--fondo);
  border-bottom: 1px solid var(--borde);
}

.cabecera-fila {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  padding-top: 12px;
  padding-bottom: 10px;
}

/* El simbolo del logo al lado del titulo. Va alineado al pie del bloque de
   texto, no centrado: el titulo es lo que manda la linea de base. */
.cabecera-marca {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  min-width: 0;
}

/* El logo va sin fondo: el PNG ya viene con las siglas en color tinta y
   con transparencia, asi que apoya directo sobre el carbon. */
.cabecera-logo {
  height: 40px;
  width: auto;
  display: block;
  flex: 0 0 auto;
  background: transparent;
}

@media (max-width: 360px) {
  /* En pantallas muy angostas el titulo vale mas que el logo. */
  .cabecera-logo { height: 32px; }
}

.etiqueta-min {
  font-size: 10px;
  letter-spacing: 0.22em;
  color: var(--tinta-2);
  font-weight: 500;
}

.titulo-app {
  font-family: var(--titulos);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: 0.06em;
  line-height: 1.1;
  margin: 2px 0 0;
}

.cabecera-fecha {
  text-align: right;
  font-size: 10px;
  line-height: 1.5;
  color: var(--tinta-2);
}

/* Rotulo y valor de cada reloj. El rotulo apagado, el dato en tinta: se
   lee el dato primero y el rotulo solo si hace falta desambiguar. */
.cabecera-par { display: flex; gap: 6px; justify-content: flex-end; white-space: nowrap; }
.cabecera-rotulo { color: var(--tinta-3); letter-spacing: 0.1em; }

/* El filete perforado del ticket. */
.perforado {
  height: 5px;
  background: repeating-linear-gradient(90deg, var(--borde) 0 6px, transparent 6px 12px);
}


/* --------------------------- Aviso de frescura -------------------------- */
/* Un número viejo sin fecha es la trampa que ya costó cara: si la corrida
   tiene más de un día, la web lo dice arriba de todo y en rojo. */

.aviso-frescura {
  background: var(--rojo);
  color: var(--fondo);
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  line-height: 1.45;
  padding: 11px 16px;
  text-align: center;
}


/* Datos rezagados no es lo mismo que sistema roto: la planta no cargo. Se
   dice, pero en ambar y no en rojo, para que el rojo siga significando algo. */
.aviso-frescura.aviso-frescura-suave {
  background: var(--ambar);
  color: var(--fondo);
}


/* ------------------------------- Estados ------------------------------- */

.estado-carga, .estado-error {
  padding: 48px 0;
  text-align: center;
  font-size: 12px;
  letter-spacing: 0.16em;
  color: var(--tinta-3);
}

.estado-error {
  color: var(--rojo-alto);
  border: 1px solid var(--rojo);
  padding: 20px 16px;
  margin-top: 24px;
  font-family: var(--mono);
  letter-spacing: 0.06em;
  line-height: 1.6;
  text-align: left;
  /* El detalle tecnico del error trae la respuesta cruda de PostgREST, que
     puede ser un JSON largo sin un solo espacio. Sin esto no corta nunca y
     se derrama fuera de la pantalla del celular, justo cuando la persona
     necesita leer que paso. */
  overflow-wrap: anywhere;
}


/* -------------------------------- Héroes ------------------------------- */

.heroes {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  border-bottom: 1px solid var(--borde);
}

.heroe { padding: 26px 0 20px; }
.heroe + .heroe { border-top: 1px solid var(--borde-suave); }

@media (min-width: 720px) {
  .heroes { grid-template-columns: 1fr 1fr; gap: 0 40px; }
  .heroe + .heroe { border-top: none; }
}

.heroe-rotulo { display: flex; align-items: center; gap: 10px; }

.sello { width: 9px; height: 9px; background: var(--ambar); flex: 0 0 auto; }
.sello-azul { background: var(--azul); }

.heroe-num {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-top: 4px;
}

.cifra {
  font-family: var(--titulos);
  font-weight: 700;
  font-size: clamp(58px, 15vw, 104px);
  line-height: 0.82;
  letter-spacing: -0.035em;
  color: var(--tinta);
}

.heroe-unidad {
  font-family: var(--titulos);
  font-weight: 500;
  font-size: clamp(20px, 5vw, 32px);
  letter-spacing: 0.04em;
  color: var(--ambar);
}

.heroe-unidad-azul { color: var(--azul-alto); }

.heroe-pie {
  font-size: 11px;
  color: var(--tinta-2);
  letter-spacing: 0.06em;
  margin-top: 10px;
  line-height: 1.6;
}

.nota-no-sumar {
  font-size: 9px;
  letter-spacing: 0.16em;
  line-height: 1.7;
  color: var(--tinta-3);
  padding: 12px 0 4px;
  margin: 0;
  border-bottom: 1px solid var(--borde-suave);
}


/* ------------------------------ Secciones ------------------------------ */

.dos-columnas { display: flex; flex-wrap: wrap; gap: 0 40px; }
.columna { flex: 1 1 300px; min-width: 0; padding: 16px 0 2px; }
.bloque { padding: 20px 0 8px; }
.bloque-encabezado { padding: 18px 0 10px; }

/*
  Encabezado de seccion. Las secciones se separan por ESTRUCTURA, no por
  color: el color de esta pantalla ya significa algo —ambar es granel, azul
  es bolsones, rojo es negativo— y darle ademas un color a cada seccion
  haria que el mismo azul quisiera decir dos cosas distintas en la misma
  vista. Lo que separa una seccion de otra es el aire de arriba, el filete y
  el numero grande, que se leen igual de rapido y no le roban significado a
  nada.
*/
.seccion-titulo {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 12px;
  padding-top: 26px;
  border-top: 1px solid var(--borde);
}

/* La primera seccion de un bloque ya viene despues de un filete o del
   encabezado: no necesita otra linea encima. */
.bloque > .seccion-titulo:first-child { border-top: 0; padding-top: 18px; }

/* Apiladas (celular), la primera columna arranca pegada a la nota de arriba
   y no necesita filete. Lado a lado NO se le saca a ninguna: si se le quita
   solo a la izquierda, queda una linea suelta sobre la columna derecha y se
   lee como un error de alineacion, no como una separacion. */
@media (max-width: 699px) {
  .columna:first-child > .seccion-titulo { border-top: 0; padding-top: 18px; }
}

.num-seccion {
  font-family: var(--mono);
  font-size: 18px;
  font-weight: 600;
  color: var(--tinta-3);
  letter-spacing: 0.02em;
}

.seccion-nombre {
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 0.2em;
}

.seccion-nombre-grande {
  font-weight: 700;
  font-size: 20px;
  letter-spacing: 0.16em;
}

.seccion-nombre-med {
  font-weight: 600;
  font-size: 16px;
  letter-spacing: 0.1em;
}

.pista { font-size: 9px; color: var(--tinta-3); letter-spacing: 0.14em; }

.subtitulo {
  font-size: 10px;
  color: var(--tinta-2);
  letter-spacing: 0.14em;
  margin-top: 4px;
  line-height: 1.6;
}

.titulo-bloque {
  font-family: var(--titulos);
  font-weight: 700;
  font-size: 20px;
  letter-spacing: 0.05em;
  line-height: 1.1;
  margin: 0;
}

.subrayado-ambar {
  height: 2px;
  background: var(--ambar);
  width: 56px;
  margin: 12px 0 0;
}

.filete { height: 1px; background: var(--borde); margin-top: 18px; }

.pie-calculo {
  font-size: 9px;
  color: var(--tinta-3);
  letter-spacing: 0.16em;
  line-height: 1.8;
  padding: 10px 0 24px;
}


/* --------------------------- Filas con barra --------------------------- */

.fila-barra { padding: 7px 0; border-top: 1px solid var(--borde-suave); }

.fila-barra-datos {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}

.fila-barra-nombre {
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.1em;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fila-barra-valor {
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.unidad { color: var(--tinta-2); font-size: 11px; }

.barra {
  height: 5px;
  background: var(--superficie-2);
  margin-top: 6px;
  border-radius: 1px;
  overflow: hidden;
}

.barra > i {
  display: block;
  height: 100%;
  background: var(--ambar);
  transition: width 260ms cubic-bezier(.2,.8,.2,1);
}

.barra-azul > i { background: var(--azul); }


/* ------------------------------ Materiales ----------------------------- */

.material { border-top: 1px solid var(--borde-suave); }

.material-cabecera {
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  color: inherit;
  font: inherit;
  padding: 10px 0 9px;
  min-height: 52px;
  cursor: pointer;
  display: block;
  transition: background 120ms linear;
}

.material-cabecera:hover { background: var(--superficie); }
.material-cabecera:focus-visible { outline: 2px solid var(--ambar); outline-offset: -2px; }

.material-fila {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}

.material-nombre-caja {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}

.material-marca { font-family: var(--mono); font-size: 11px; color: var(--ambar); }

.material-nombre {
  font-weight: 500;
  font-size: 16px;
  letter-spacing: 0.09em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.material-valor {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.material-barra { height: 6px; }

.detalle {
  background: var(--superficie);
  border-left: 3px solid var(--ambar);
  padding: 4px 12px 10px;
  margin-bottom: 10px;
}

.detalle-titulo {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.2em;
  color: var(--tinta-2);
  padding: 8px 0 6px;
}

/* Dos columnas fijas, no `space-between`.
   Con flex y tres elementos, el del medio se corría según el largo del
   nombre y la columna de kilos quedaba dentada: la lista se leía sucia. En
   grilla, los kilos caen SIEMPRE en la misma vertical, que es lo que
   permite comparar de un vistazo sin leer número por número. */
.detalle-fila {
  display: grid;
  grid-template-columns: 1fr max-content;
  align-items: baseline;
  gap: 10px;
  padding: 5px 0;
  border-top: 1px dotted var(--borde);
  font-family: var(--mono);
  font-size: 12px;
}

.detalle-fila .cod {
  letter-spacing: 0.04em;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.detalle-fila .kg {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Encabezado de cada grupo (SILO, GALPON, CELDA…) con su subtotal: el
   número que uno viene a buscar ya sumado, en vez de sumarlo de a ojo. */
.grupo-encabezado {
  display: grid;
  grid-template-columns: 1fr max-content;
  align-items: baseline;
  gap: 10px;
  padding: 12px 0 4px;
  margin-top: 4px;
  border-bottom: 1px solid var(--borde);
}

.grupo-encabezado:first-of-type { padding-top: 4px; margin-top: 0; }

.grupo-nombre {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.2em;
  color: var(--ambar);
}

.grupo-total {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  color: var(--tinta-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.detalle-pie {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  color: var(--tinta-3);
  padding-top: 9px;
  margin-top: 6px;
  border-top: 1px solid var(--borde);
  line-height: 1.7;
}


/* ------------------------------- Filtros ------------------------------- */

.filtros {
  position: sticky;
  /* Justo debajo de la cabecera. */
  top: 62px;
  z-index: 30;
  background: var(--fondo);
  padding-bottom: 10px;
}

.buscador {
  display: flex;
  align-items: center;
  border: 1px solid var(--ambar);
  background: var(--superficie);
}

.buscador-flecha { font-size: 14px; color: var(--ambar); padding: 0 12px 0 14px; }

.buscador input {
  flex: 1;
  min-width: 0;
  height: 52px;
  background: transparent;
  border: none;
  color: var(--tinta);
  font-family: var(--mono);
  /* 16px o más: abajo de eso, iOS hace zoom al enfocar y descoloca todo. */
  font-size: 16px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.buscador input:focus { outline: none; }
.buscador input::placeholder { color: var(--tinta-3); }
.buscador input::-webkit-search-cancel-button { display: none; }

.buscador-limpiar {
  width: 52px;
  height: 52px;
  background: none;
  border: none;
  color: var(--tinta-2);
  font-family: var(--mono);
  font-size: 20px;
  cursor: pointer;
}

.chips { display: flex; gap: 6px; overflow-x: auto; padding-top: 8px; scrollbar-width: none; }
.chips::-webkit-scrollbar { display: none; }

.chip {
  flex: 0 0 auto;
  padding: 11px 14px;
  min-height: 44px;
  display: flex;
  align-items: center;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  border: 1px solid var(--borde);
  background: transparent;
  color: var(--tinta-2);
  border-radius: 2px;
  white-space: nowrap;
  transition: background 140ms linear, color 140ms linear;
}

.chip[aria-pressed="true"] {
  border-color: var(--ambar);
  background: var(--ambar);
  color: var(--fondo);
  font-weight: 600;
}


/* ------------------------- Lista de ubicaciones ------------------------ */

.tabla-encabezado {
  display: flex;
  justify-content: space-between;
  font-size: 9px;
  letter-spacing: 0.16em;
  color: var(--tinta-3);
  padding: 6px 0 0;
  border-bottom: 1px solid var(--borde);
}

.ubicacion { border-bottom: 1px solid var(--borde-suave); position: relative; }

/* Rayado de advertencia para lo anómalo: se ve de reojo, sin leer. */
.ubicacion.negativa::before,
.caja-anomalia::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.14;
  background: repeating-linear-gradient(45deg, var(--rojo) 0 8px, transparent 8px 18px);
}

.ubicacion-cabecera {
  position: relative;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  color: inherit;
  font: inherit;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  min-height: 56px;
  cursor: pointer;
  transition: background 120ms linear;
}

.ubicacion-cabecera:hover { background: var(--superficie); }
.ubicacion-cabecera:focus-visible { outline: 2px solid var(--ambar); outline-offset: -2px; }

.ubicacion-izq { min-width: 0; }

.ubicacion-cod-fila { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.ubicacion-cod {
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.06em;
}

.ubicacion-nombre {
  font-family: var(--titulos);
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--tinta-2);
  margin-top: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ubicacion-meta { display: flex; align-items: center; gap: 7px; margin-top: 5px; flex-wrap: wrap; }

.meta-planta { font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em; color: var(--tinta-2); }

.meta-tipo {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  color: var(--azul-alto);
  border: 1px solid var(--azul);
  padding: 1px 5px;
}

.chapa-anomalia {
  font-size: 9px;
  letter-spacing: 0.16em;
  background: var(--rojo);
  color: var(--fondo);
  padding: 3px 6px;
  font-weight: 600;
  border-radius: 2px;
  white-space: nowrap;
}

.chapa-sin-punto-cero {
  font-size: 9px;
  letter-spacing: 0.14em;
  border: 1px solid var(--tinta-3);
  color: var(--tinta-2);
  padding: 2px 5px;
  border-radius: 2px;
  white-space: nowrap;
  font-family: var(--mono);
}

.ubicacion-der { text-align: right; flex: 0 0 auto; }

.ubicacion-kg {
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.ubicacion-um { font-family: var(--mono); font-size: 10px; color: var(--tinta-3); margin-top: 4px; }

.rojo { color: var(--rojo-alto); }
.verde { color: var(--verde); }
.ambar { color: var(--ambar); }

/* --------------------- Estados de la lista ----------------------------- */
/* Cargando, sin resultados para el filtro, y sin conexion. Los tres viven
   en la misma caja y los distingue el texto (`pintarEstadoLista`), pero el
   de error ademas cambia de color: es el unico que pide una accion. */

.estado-lista {
  padding: 40px 12px;
  text-align: center;
  font-size: 12px;
  letter-spacing: 0.14em;
  color: var(--tinta-3);
}

.estado-lista-detalle {
  margin-top: 10px;
  font-size: 12px;
  letter-spacing: 0.02em;
  line-height: 1.5;
  color: var(--tinta-3);
  text-transform: none;   /* el detalle se lee como frase, no como rotulo */
  overflow-wrap: anywhere;   /* idem: puede traer el error crudo de la base */
}

.estado-lista-error { color: var(--rojo-alto); }
.estado-lista-error .estado-lista-detalle { color: var(--tinta-2); }

/* Se toca con guantes y a veces varias veces seguidas: 44px de alto minimo,
   igual que el resto de lo tocable del tablero. */
.boton-reintentar {
  margin-top: 16px;
  min-height: 44px;
  padding: 0 22px;
  background: transparent;
  border: 1px solid var(--rojo);
  color: var(--rojo-alto);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.16em;
  cursor: pointer;
}

.boton-reintentar:hover { background: rgba(212, 70, 47, 0.12); }
.boton-reintentar:active { transform: translateY(1px); }

.espacio-final { height: 24px; }

/* El porque de un guion. Sin esto un heroe en "—" se lee igual que un cero,
   que es la confusion que este tablero no puede permitirse. */
/* Un guion en cuerpo de titular se lee como una barra, no como un signo.
   Se achica para que parezca lo que es: un lugar donde falta un numero. */
.cifra-sin-dato {
  font-size: 0.45em;
  letter-spacing: 0.1em;
  color: var(--tinta-3);
  vertical-align: middle;
}

.heroe-sin-dato {
  color: var(--tinta-3);
  letter-spacing: 0.04em;
  line-height: 1.5;
  text-transform: none;
}


/* ------------------------------- Sistema ------------------------------- */

.aviso-ventana {
  border: 1px solid var(--ambar);
  background: var(--superficie);
  color: var(--ambar);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  line-height: 1.7;
  padding: 12px 14px;
  margin-bottom: 14px;
}

.kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  border: 1px solid var(--borde);
}

.kpi {
  padding: 14px 13px 13px;
  border-right: 1px solid var(--borde);
  border-bottom: 1px solid var(--borde);
}

.kpi-label {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.2em;
  color: var(--tinta-2);
  line-height: 1.5;
  min-height: 28px;
}

.kpi-valor { display: flex; align-items: baseline; gap: 5px; margin-top: 6px; }

.kpi-num {
  font-family: var(--titulos);
  font-weight: 700;
  font-size: 34px;
  line-height: 0.9;
  font-variant-numeric: tabular-nums;
}

.kpi-uni { font-family: var(--mono); font-size: 11px; color: var(--tinta-2); }

.advertencia {
  display: flex;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--borde-suave);
}

.advertencia-num { font-family: var(--mono); font-size: 11px; color: var(--ambar); flex: 0 0 auto; }

.advertencia-txt {
  font-family: var(--titulos);
  font-size: 15px;
  letter-spacing: 0.03em;
  line-height: 1.35;
  text-wrap: pretty;
}

.advertencia-dato {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  color: var(--tinta-2);
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
  line-height: 1.6;
}

.rotulo-anomalia { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-bottom: 10px; }

.caja-anomalia { position: relative; border: 1px solid var(--rojo); }

.anomalia-encabezado {
  position: relative;
  display: flex;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  color: var(--tinta-2);
  padding: 8px 12px;
  border-bottom: 1px solid var(--borde);
}

.anomalia-fila {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--borde-suave);
}

.anomalia-cod { font-family: var(--mono); font-size: 14px; font-weight: 600; letter-spacing: 0.04em; }

.anomalia-meta {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  color: var(--tinta-2);
  margin-top: 3px;
  line-height: 1.6;
}

.anomalia-kg {
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--rojo-alto);
  white-space: nowrap;
}

.anomalia-pie {
  position: relative;
  padding: 10px 12px;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--tinta-2);
  letter-spacing: 0.1em;
  line-height: 1.7;
}

.barra-semaforo { display: flex; height: 26px; margin-top: 12px; border: 1px solid var(--borde); }
.barra-semaforo > i { display: block; height: 100%; }

.semaforo-cajas {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  margin-top: 12px;
  border: 1px solid var(--borde);
}

.semaforo-caja { flex: 1 1 100px; padding: 11px 12px; border-right: 1px solid var(--borde); }

.semaforo-rotulo { display: flex; align-items: center; gap: 7px; }

.semaforo-punto { width: 9px; height: 9px; flex: 0 0 auto; }

.semaforo-label {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.2em;
  color: var(--tinta-2);
}

.semaforo-num {
  font-family: var(--titulos);
  font-weight: 700;
  font-size: 30px;
  line-height: 1;
  margin-top: 5px;
  font-variant-numeric: tabular-nums;
}


/* ------------------------------ Navegación ----------------------------- */

.navegacion {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 50;
  background: var(--fondo);
  border-top: 1px solid var(--borde);
  display: flex;
  width: 100%;
  padding-bottom: env(safe-area-inset-bottom);
}

.tab {
  flex: 1;
  min-height: var(--alto-nav);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
  background: none;
  border: none;
  border-right: 1px solid var(--borde-suave);
  border-top: 2px solid transparent;
  color: var(--tinta-2);
  transition: background 140ms linear, color 140ms linear;
}

.tab:last-child { border-right: none; }
.tab:focus-visible { outline: 2px solid var(--ambar); outline-offset: -2px; }

.tab-num { font-size: 11px; letter-spacing: 0.1em; color: var(--tinta-3); }

.tab-label {
  font-family: var(--titulos);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.14em;
}

.tab[aria-selected="true"] {
  border-top-color: var(--ambar);
  background: var(--superficie);
  color: var(--tinta);
}

.tab[aria-selected="true"] .tab-num { color: var(--ambar); }

/* Quien prefiera menos movimiento, que no lo tenga. */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}


/* ------------------------------ Preguntar ------------------------------ */

.buscador-enviar {
  width: 52px;
  height: 52px;
  background: var(--ambar);
  border: none;
  color: var(--fondo);
  font-size: 20px;
  font-weight: 600;
  cursor: pointer;
  flex: 0 0 auto;
}

.buscador-enviar:hover { background: var(--ambar-alto); }

.sugerencias { display: flex; flex-wrap: wrap; gap: 6px; padding: 4px 0 14px; }

.sugerencias-titulo {
  width: 100%;
  font-size: 9px;
  letter-spacing: 0.2em;
  color: var(--tinta-3);
  padding-bottom: 2px;
}

/* Las sugerencias van en minúscula y sin el estilo de filtro: son
   ejemplos para tocar, no un estado activo. */
.sugerencia { text-transform: none; letter-spacing: 0.04em; font-size: 12px; }

.respuesta {
  border: 1px solid var(--borde);
  border-left: 3px solid var(--ambar);
  background: var(--superficie);
  padding: 12px 14px 14px;
  margin-bottom: 12px;
}

.respuesta-sin-entender { border-left-color: var(--tinta-3); }

.respuesta-pregunta {
  font-family: var(--titulos);
  font-size: 15px;
  letter-spacing: 0.04em;
  color: var(--tinta-2);
  line-height: 1.35;
  padding-bottom: 8px;
  border-bottom: 1px dotted var(--borde);
  margin-bottom: 10px;
  text-wrap: pretty;
}

.respuesta-num { display: flex; align-items: baseline; gap: 4px; }

.cifra-resp {
  font-family: var(--titulos);
  font-weight: 700;
  font-size: clamp(34px, 9vw, 52px);
  line-height: 0.95;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.respuesta-num.rojo .cifra-resp { color: var(--rojo-alto); }

.respuesta-unidad {
  font-family: var(--titulos);
  font-weight: 500;
  font-size: 18px;
  color: var(--ambar);
}

.respuesta-titulo {
  font-family: var(--titulos);
  font-size: 17px;
  letter-spacing: 0.03em;
  line-height: 1.3;
}

.respuesta-sub {
  font-size: 11px;
  color: var(--tinta-2);
  letter-spacing: 0.08em;
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}

.respuesta-nota {
  font-size: 10px;
  color: var(--tinta-3);
  letter-spacing: 0.06em;
  line-height: 1.7;
  margin-top: 8px;
  text-wrap: pretty;
}

.respuesta-tabla { margin-top: 10px; }

/* Con cuatro pestañas el rótulo tiene que achicarse para que entre
   "UBICACIONES" sin cortarse en un teléfono angosto. */
@media (max-width: 460px) {
  .tab { gap: 4px; flex-direction: column; justify-content: center; }
  .tab-num { font-size: 9px; }
  .tab-label { font-size: 10px; letter-spacing: 0.06em; }
}

/* Copiar la respuesta para mandarla por chat. El que pide el stock casi
   nunca puede entrar al tablero: o se copia entero, o alguien lo transcribe
   a mano. */
.copiar-respuesta {
  margin-top: 12px;
  width: 100%;
  justify-content: center;
  letter-spacing: 0.12em;
  font-size: 11px;
  border-color: var(--ambar);
  color: var(--ambar);
}

.copiar-respuesta:active { transform: translateY(1px); }

.copiar-respuesta.copiado {
  background: var(--ambar);
  border-color: var(--ambar);
  color: var(--fondo);
  font-weight: 600;
}

/* Ultimo recurso: el navegador no dejo copiar, asi que se muestra el texto
   listo y seleccionado para copiarlo a mano. */
.texto-para-copiar {
  width: 100%;
  margin-top: 10px;
  padding: 10px;
  background: var(--fondo);
  color: var(--tinta-2);
  border: 1px solid var(--borde);
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.5;
  resize: vertical;
}

.ver-mas {
  margin-top: 10px;
  text-transform: none;
  letter-spacing: 0.06em;
  font-size: 11px;
  width: 100%;
  justify-content: center;
}


/* ============================== Acceso ================================= */
/* Pantalla de entrada. Mismo romaneo que el tablero: ticket sobre chapa.
   Tapa TODO hasta que hay sesión — no es un cartel arriba de los datos, es
   una puerta: mientras está, abajo no se pintó ningún número. */

.acceso {
  position: fixed;
  inset: 0;
  /* Por encima de la navegación inferior, que también es fixed y va DESPUÉS
     en el HTML: con el mismo z-index (50) la barra quedaba dibujada ARRIBA
     de la puerta y se podía tocar sin haber entrado. */
  z-index: 60;
  background: var(--fondo);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 16px calc(24px + env(safe-area-inset-bottom));
  overflow-y: auto;
}

.acceso-ticket {
  width: min(100%, 380px);
  background: var(--superficie);
  border: 1px solid var(--borde);
}

.acceso-cabecera {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 22px 20px 18px;
}

/* En la puerta el logo respira un poco mas: es lo primero que se ve. */
.acceso-cabecera .cabecera-logo { height: 46px; }

.acceso-cuerpo { padding: 4px 20px 22px; }

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

.acceso-campo label {
  display: block;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  color: var(--tinta-2);
  margin-bottom: 6px;
}

.acceso-campo input {
  width: 100%;
  height: 52px;               /* igual que el buscador: se toca con guantes */
  padding: 0 14px;
  background: var(--superficie-2);
  border: 1px solid var(--borde);
  color: var(--tinta);
  font-family: var(--mono);
  /* 16px o más: abajo de eso, iOS hace zoom al enfocar y descoloca todo. */
  font-size: 16px;
  letter-spacing: 0.06em;
}

/* El mail NO va en mayúsculas como el resto de la web: se escribe tal cual
   está dado de alta, y una mayúscula de más confunde a quien lo tipea. */
.acceso-campo input:focus { outline: none; border-color: var(--ambar); }

.acceso-boton {
  width: 100%;
  height: 54px;
  margin-top: 20px;
  background: var(--ambar);
  border: none;
  color: #1a1712;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.18em;
  cursor: pointer;
}

.acceso-boton:active { background: var(--ambar-alto); }

.acceso-boton[disabled] {
  background: var(--superficie-2);
  color: var(--tinta-3);
  cursor: default;
}

.acceso-error {
  margin-top: 14px;
  padding: 10px 12px;
  background: rgba(212, 70, 47, 0.12);
  border-left: 3px solid var(--rojo);
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.5;
  color: var(--rojo-alto);
}

.acceso-pie {
  padding: 14px 20px 18px;
  font-family: var(--mono);
  font-size: 10px;
  line-height: 1.6;
  letter-spacing: 0.1em;
  color: var(--tinta-3);
}

/* --------------------------- Salir de la sesión ------------------------- */

.cabecera-sesion {
  display: flex;
  align-items: center;
  gap: 10px;
  justify-content: flex-end;
  margin-top: 2px;
}

.sesion-mail {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--tinta-3);
  max-width: 42vw;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sesion-salir {
  min-height: 32px;
  padding: 0 10px;
  background: none;
  border: 1px solid var(--borde);
  color: var(--tinta-2);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  cursor: pointer;
}

.sesion-salir:active { border-color: var(--ambar); color: var(--ambar); }


/* ============================== Movimiento ============================= */
/*
  Criterio, porque acá es fácil pasarse: esto se usa parado frente a un silo,
  con guantes y con mala señal. Una animación que hace ESPERAR juega en
  contra — si tocás un material y la lista tarda, la web se siente lenta
  aunque sea más linda. Entonces:

    · nada arriba de 240ms;
    · el movimiento acompaña lo que ya pasó, nunca lo demora;
    · solo `transform` y `opacity`, que no recalculan el layout. Animar
      `width` o `height` en una lista de 156 ubicaciones hace tironear el
      scroll en un celular de planta;
    · lo que el usuario TOCA responde al instante (120ms); lo que aparece
      solo puede tomarse un poco más.
*/

:root {
  --mov-rapido: 120ms;
  --mov: 180ms;
  --mov-lento: 240ms;
  /* Arranca rápido y frena suave: se siente mecánico, como el papel que sale
     de una impresora de tickets, en vez de elástico. */
  --curva: cubic-bezier(0.16, 1, 0.3, 1);
}

/*
  Quien tiene activado "reducir movimiento" en su sistema lo tiene por algo:
  mareos, vértigo, migrañas. No se le achica la animación, se le apaga.
  Todo el contenido queda visible igual — ninguna animación de acá es la que
  hace aparecer algo.
*/
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ------------------------------ Entradas ------------------------------- */
/* `--i` es el índice de la fila: cada una entra un toque después que la
   anterior. El tope de 12 evita que la fila 90 de una lista larga entre dos
   segundos tarde — a partir de ahí entran todas juntas. */

@keyframes entrar {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

.entra {
  animation: entrar var(--mov-lento) var(--curva) backwards;
  animation-delay: calc(min(var(--i, 0), 12) * 28ms);
}

/* ------------------------------- Barras -------------------------------- */
/* La barra crece desde la izquierda. `scaleX` en vez de animar el `width`:
   el ancho real ya está puesto, lo que se anima es la escala, que la GPU
   resuelve sin tocar el layout de las 156 filas de al lado. */

@keyframes crecer {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.barra i {
  transform-origin: left center;
  animation: crecer var(--mov-lento) var(--curva) backwards;
  animation-delay: calc(min(var(--i, 0), 12) * 28ms + 60ms);
}

/* ------------------------- Cambio de pestaña --------------------------- */
/* Corte seco antes. Ahora la vista entra desde abajo, apenas. Da la
   sensación de que la pestaña nueva "sube", que es como se lee la barra de
   navegación de abajo. */

.vista:not(.oculto) {
  animation: entrar var(--mov) var(--curva);
}

/* --------------------------- Abrir y cerrar ---------------------------- */
/* Los detalles de material y de ubicación. No se anima la altura: se anima
   lo que hay adentro. La caja aparece de una (el layout se acomoda solo) y
   el contenido entra deslizándose. Cuesta cero y se siente igual. */

.detalle:not(.oculto) {
  animation: entrar var(--mov) var(--curva);
}

/* ------------------------- Respuesta al tacto -------------------------- */
/* Lo único que tiene que ser instantáneo. Con guantes y sin sonido, el
   hundido es la única confirmación de que el toque entró. */

.tab, .chip, .material-cabecera, .ubicacion-cabecera,
.acceso-boton, .buscador-enviar, .sesion-salir {
  transition: transform var(--mov-rapido) var(--curva),
              background-color var(--mov-rapido) var(--curva),
              border-color var(--mov-rapido) var(--curva),
              color var(--mov-rapido) var(--curva);
}

.tab:active, .chip:active, .material-cabecera:active, .ubicacion-cabecera:active,
.acceso-boton:active, .buscador-enviar:active, .sesion-salir:active {
  transform: scale(0.97);
}

/* La pestaña activa marca el cambio con el número, que es lo que distingue
   una sección de otra en este diseño. */
.tab[aria-selected="true"] .tab-num {
  transition: color var(--mov) var(--curva);
}

/* --------------------------- Avisos y estados -------------------------- */
/* El cartel de dato viejo y el de sesión caída aparecen deslizando desde
   arriba. Son lo único que puede aparecer DESPUÉS de que la pantalla ya se
   pintó, y si aparecieran de golpe se leerían como un salto de la página. */

@keyframes bajar {
  from { opacity: 0; transform: translateY(-100%); }
  to   { opacity: 1; transform: none; }
}

.aviso-frescura:not(.oculto) {
  animation: bajar var(--mov-lento) var(--curva);
}

/* La puerta de acceso entra con un fundido, sin deslizarse: es una pantalla
   completa, moverla entera marea. */
@keyframes aparecer {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.acceso:not(.oculto) { animation: aparecer var(--mov) ease-out; }

/* El ticket de adentro sí sube, apenas, para que la puerta no se sienta
   plana. */
.acceso-ticket { animation: entrar var(--mov-lento) var(--curva); }

/* ------------------------------ Esqueleto ------------------------------ */
/* Mientras se leen los datos. Late despacio: es "esperá", no "algo anda
   mal". A 1.6s no compite con la lectura. */

@keyframes latir {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

.estado-carga { animation: latir 1.6s ease-in-out infinite; }


/* ---------------------- Barras partidas por base ----------------------- */
/*
  Cada fila de POR PLANTA y POR TIPO muestra granel y bolsones SEPARADOS,
  nunca sumados (ver `agrupar` en app.js). Los colores son los mismos que
  los de los dos héroes de arriba: ámbar = granel, azul = bolsones. Así no
  hay que aprender un código nuevo, se lee el mismo de toda la pantalla.
*/

.barra-partida { display: flex; }

.barra-partida > i {
  display: block;
  height: 100%;
  transition: none;              /* el movimiento lo pone `crecer` */
}

/* OJO CON LA ESPECIFICIDAD ACA. Estos tramos van dentro de `.barra`, que
   tiene su propia regla `.barra > i { background: var(--ambar) }` mas
   arriba. `.barra > i` pesa (0,1,1) —clase + elemento— y `.tramo-bolsones`
   pesa (0,1,0), asi que la de arriba GANABA y TODOS los tramos salian
   ambar, bolsones incluidos. La pantalla quedaba de un solo color y la
   leyenda GRANEL/BOLSONES no distinguia nada: el galpon, que es 100%
   bolsones, se dibujaba igual que un silo. Por eso van calificados con
   `.barra > i`, que empata en especificidad y gana por orden. */
.barra > i.tramo-granel,
.leyenda-bases i.tramo-granel   { background: var(--ambar); }
.barra > i.tramo-bolsones,
.leyenda-bases i.tramo-bolsones { background: var(--azul); }
/* Ubicaciones cuyo tipo no clasifica en granel ni en bolsones. Casi nunca
   hay ninguna, pero si aparece no se esconde: se dibuja en gris y se
   nombra. Un dato que no encaja en las categorías es justamente el que hay
   que ver. */
.barra > i.tramo-otro,
.leyenda-bases i.tramo-otro     { background: var(--tinta-3); }

.tramo-negativo { background: var(--rojo); }

.fila-barra-valores {
  display: flex;
  align-items: baseline;
  gap: 6px;
  white-space: nowrap;
}

.fila-barra-sep { color: var(--tinta-3); }

/* El número toma el color de su base: si hay dos, se sabe cuál es cuál sin
   leer una leyenda. El rojo del negativo gana, porque es lo urgente. */
.fila-barra-valor.tramo-granel   { background: none; color: var(--ambar-alto); }
.fila-barra-valor.tramo-bolsones { background: none; color: var(--azul-alto); }
.fila-barra-valor.tramo-otro     { background: none; color: var(--tinta-2); }
.fila-barra-valor.rojo           { color: var(--rojo-alto); }

/* ------------------------------ Leyenda -------------------------------- */

/* Esta leyenda es la que explica QUE significa cada color. Si es demasiado
   chica no se lee, y sin leerla las barras son dos colores porque si. */
.leyenda-bases {
  display: flex;
  gap: 8px 18px;
  align-items: center;
  flex-wrap: wrap;
  margin: 2px 0 14px;
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--tinta-2);
}

.leyenda-bases span { display: flex; align-items: center; gap: 5px; }

.leyenda-bases i {
  width: 16px;
  height: 8px;
  display: block;
  border-radius: 1px;
  flex: 0 0 auto;
}
