/* ═══════════════════════════════════════════════════════════════════════════
   portal.css — la piel del portal, encima de `tokens.css`

   AQUÍ NO SE DEFINE UN SOLO COLOR NUEVO
   Todo sale de los tokens que ya usa inefam.com. Es literalmente el requisito
   del encargo: el cliente tiene que sentir UN solo INEFAM entre el sitio
   público y el portal. Un guinda "parecido" pero distinto se nota, y lo que se
   nota es que son dos sistemas.

   LAS DOS REGLAS DE COLOR QUE NO SE NEGOCIAN
   · #711D1D sobre fondo oscuro da 1.77:1 — NO puede portar texto. Por eso el
     acento se toma siempre de `--acento`, que en claro es el guinda puro
     (10.48:1 sobre papel) y en oscuro es un tinte claro de la rampa. Nunca se
     escribe `#711D1D` a mano para texto.
   · El guinda puro sí sirve como RELLENO con texto blanco encima: eso es
     `--campo` / `--campo-texto`, y así está pintado el botón primario.

   CIFRAS
   `tabular-nums` en todo lo que sea número, para que una columna de importes
   no baile al cambiar de renglón. La clase `.cifra` de tokens.css ya lo trae.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ═══ Estructura ══════════════════════════════════════════════════════════ */

/* ═══ La página NUNCA se desplaza a lo ancho ══════════════════════════════
   `body` ya lo declaraba, y no bastaba. Los encabezados pegajosos de la tabla
   de detalle son `position: sticky` dentro de la caja que sí se desplaza, pero
   su caja mide lo que mide la TABLA —1,182 px medidos a 390 de ventana— y un
   elemento pegajoso escapa al recorte del cuerpo. Resultado: el documento
   medía 458 contra 390 y la página se deslizaba de lado en el teléfono, aunque
   ningún elemento visible estuviera fuera de su contenedor.

   Se declara también en la raíz. No es tapar el síntoma: que la página no se
   desplace en horizontal es la regla, y aquí se hace cumplir donde de verdad
   se decide. La tabla sigue desplazándose dentro de su propia caja, que es lo
   que se quiere. */
html { overflow-x: clip; }

body {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.saltar {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--campo);
  color: var(--campo-texto);
  padding: 0.75rem 1.25rem;
}
.saltar:focus { left: 0; }

.cabecera {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--linea);
}

.barra {
  width: min(100% - 2.5rem, var(--w-ancho));
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: clamp(0.6rem, 1.8vw, 1.5rem);
  /* La barra la dimensiona EL LOGOTIPO, no al revés. Con el bajo-firma
     institucional dentro, el logotipo mide 88 px de alto a su tamaño máximo;
     10 px de holgura por lado dan 108 px = 6.75rem. */
  min-height: 6.75rem;
}

/* El logotipo se pinta con máscara para que tome `--acento` del tema, igual
   que el `currentColor` del SVG en línea del sitio público, pero servido como
   archivo aparte y cacheado en vez de repetido en cada página. */
.marca { flex: none; display: block; text-decoration: none; }

/* El menú de producto es la parte ELÁSTICA de la cabecera. Todo lo demás
   —logo, empresa activa, tema, salir— tiene tamaño propio y no debe encogerse;
   el menú sí, y se desliza dentro de sí mismo antes que desbordar la página.
   `min-width: 0` es obligatorio: un elemento flex trae `min-width: auto` y se
   niega a encogerse por debajo de su contenido, así que sin esto el
   `overflow-x` de la lista no contiene nada y quien se desplaza es el
   documento. Medido a 1024 px: 1,141 de ancho contra 1,024 de ventana.
   Va en la cascada base y no en una consulta de medios a propósito: el
   catálogo crece —hoy 4 familias, mañana 6— y cualquier umbral fijo se queda
   corto en la siguiente. */
.nav-producto {
  flex: 1 1 auto;
  min-width: 0;
}
/* ⛔ LA REGLA DE ARRIBA ESTABA ESCRITA Y NO ESTABA APLICADA.
   El comentario dice «todo lo demas no debe encogerse», pero solo `.marca`
   tenia `flex: none`. `.empresa` heredaba el `flex-shrink: 1` de fabrica, se
   comprimia por debajo de su texto, y «EMPRESA ACTIVA / INEFAM - Interno`
   terminaba pintado ENCIMA de los ultimos renglones del menu. Se veia a
   1600 px, o sea en cualquier pantalla. */
.barra > *:not(.nav-producto) { flex: none; }
/* ⛔ EL LOGOTIPO DE INEFAM ES EL COMPLETO. NO SE RECORTA.
   Incluye la banda institucional —«Instituto Farmacéutico México» / «INEFAM do
   Brasil LTDA»—: no es un pie opcional, es parte de la marca. Aquí se usaba un
   recorte propio (`inefam-simbolo.svg`, 750×323) que se comía esa banda, y por
   eso el logotipo «salía cortado» aunque ningún elemento lo recortara: lo que
   faltaba no lo quitaba la maqueta, lo quitaba el archivo.

   El tamaño lo manda la LEGIBILIDAD DE LA BANDA, no el hueco disponible. Se
   midió a 110, 130, 150, 170 y 190 px de ancho: por debajo de 150 px el
   renglón «Instituto Farmacéutico México» baja de 5 px de altura de letra y
   deja de leerse. A 150 px el logotipo mide 88 px de alto, y la barra se
   dimensiona para alojarlo con holgura — ver `.barra`.

   El favicon SÍ sigue usando el símbolo recortado: a 32 px la banda es una
   mancha, y una pestaña del navegador es el único sitio donde el recorte
   comunica más que el logotipo entero. */
.marca-logo {
  display: block;
  width: clamp(120px, 11vw, 150px);
  aspect-ratio: 750 / 440;
  background-color: var(--acento);
  -webkit-mask: url("./marca/inefam-logo.svg") no-repeat center / contain;
  mask: url("./marca/inefam-logo.svg") no-repeat center / contain;
}

/* ⛔ EN TEMA OSCURO EL LOGOTIPO VA BLANCO, NO EN EL ACENTO.
   `--acento` en oscuro es un tinte claro de la rampa (`--brand-200`, #FECCC6)
   porque el guinda puro da 1.77:1 sobre negro y no puede portar texto. Ese
   tinte funciona como acento de interfaz, pero sobre el logotipo se lee ROSA,
   y la banda institucional lleva texto en negativo que queda todavía más
   desvaído.

   Un logotipo no es una marca de dato: no codifica magnitud ni identidad
   dentro de una gráfica, así que la regla de la rampa no lo alcanza. En
   negativo, la versión correcta de esta marca es la blanca — es la que existe
   en `marca/` como `inefam-logo-blanco` para impresión. */
[data-tema="oscuro"] .marca-logo { background-color: #FFFFFF; }

/* ── El menú del producto ────────────────────────────────────────────────
   Barra superior con submenú por familia. La columna izquierda queda LIBRE
   para los filtros del tablero: es la razón por la que el menú vive arriba y
   no a un lado.

   El desplegable es `<details>`/`<summary>`, o sea abre sin JavaScript. Lo
   único que hace falta en CSS es quitarle el triángulo del sistema —que en
   cada navegador se ve distinto— y poner el nuestro.                        */
.nav-producto__familias,
.nav-familia__lista {
  display: flex;
  list-style: none;
  padding: 0;
  margin: 0;
}
.nav-producto__familias {
  gap: clamp(0.35rem, 1vw, 0.9rem);
  align-items: center;
  /* ⛔ ENVUELVE, NO SE DESBORDA — Y NO PUEDE SER `overflow-x` (ver abajo).
     Con `nowrap` y `overflow: visible`, un catalogo que no cabe no se recorta
     ni se desliza: se PINTA ENCIMA de lo que sigue. Y el rectangulo del
     contenedor ni siquiera crece, asi que una medicion de cajas dice que todo
     esta bien mientras la pantalla muestra el texto montado.
     La medicion original —«a 1024 px la ultima familia termina en 811»— era
     cierta con CUATRO familias. Hoy son ocho. Cualquier umbral fijo se queda
     corto en la siguiente auditoria; envolver no. */
  flex-wrap: wrap;
  row-gap: 0.3rem;
  min-width: 0;
  max-width: 100%;
  padding-bottom: 2px;
  /* ⛔ AQUÍ NO VA `overflow-x: auto`, Y COSTÓ ENCONTRARLO.
     Lo tenía, para que el renglón de familias se deslizara a cualquier ancho.
     Pero un contenedor con `overflow` distinto de `visible` RECORTA a sus
     descendientes posicionados: desde que el panel cuelga de su propia familia
     —que es lo que hace legible qué menú salió de qué botón— quedaba dentro
     del recorte y no se pintaba. Se medía 304×281 px, opacidad 1, y no se veía
     nada.
     El deslizamiento sigue existiendo donde hace falta: la consulta de medios
     compacta (≤56rem) lo reactiva Y ahí el panel vuelve a colgar de la
     cabecera, o sea fuera del deslizador. Arriba de ese ancho las familias
     caben —medido a 1024 px: la última termina en 811 de 1024—. */
  overflow: visible;
}
.nav-producto__familias::-webkit-scrollbar { display: none; }

/* Los tres registros del primer nivel comparten caja: enlace (Panel, Consola),
   disparador de familia y familia sin nada que desplegar. Que midan lo mismo
   es lo que hace que la fila se lea como una fila. */
.nav-producto__enlace,
.nav-familia__disparador {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--texto-2);
  text-decoration: none;
  white-space: nowrap;
  padding: 0.45rem 0.5rem;
  border-bottom: 2px solid transparent;
  transition: color var(--d-micro), border-color var(--d-micro);
}
.nav-producto__enlace:hover,
.nav-familia__disparador:hover {
  color: var(--texto);
  border-bottom-color: var(--acento);
}
.nav-producto__enlace[aria-current="page"],
.nav-familia--actual .nav-familia__disparador {
  color: var(--texto);
  border-bottom-color: var(--acento);
}

/* Deshabilitado: se ve, se lee y no responde. No es un enlace muerto —eso
   promete una navegación que no existe— sino un `<span>` que lo dice. */
.nav-producto__enlace--cerrado {
  color: var(--texto-3);
  cursor: default;
}
.nav-producto__enlace--cerrado:hover { border-bottom-color: transparent; }

/* ═══ El panel cuelga de SU PROPIA FAMILIA ══════════════════════════════
   Colgaba de la cabecera, a ancho completo, y por eso TODOS los menús abrían
   pegados al borde izquierdo sin importar de qué familia salieran: se perdía
   la relación entre lo que se aprieta y lo que aparece.

   Anclarlo al disparador tiene un riesgo conocido —un panel de 22rem colgado
   de una familia que está a la derecha se sale de la pantalla; medido a
   1024 px, LATAM llegaba a 1,075— y por eso `portal.js` mide al abrir y
   escribe `--nav-desliz`: el corrimiento justo para que el panel quepa, con
   8 px de margen. El respaldo sin JavaScript es 0, que es exactamente el
   comportamiento anclado a la izquierda de su disparador.

   `.cabecera` tiene `backdrop-filter`, así que sería el bloque contenedor si
   la familia no declarara el suyo. Por eso el `position: relative` de abajo
   no es adorno: es lo que hace que `top: 100%` signifique «debajo de ESTA
   familia» y no «debajo de la barra». */
.nav-familia { position: relative; }
.nav-familia__caja { position: static; }

/* Un `<details>` cerrado no debe ocupar caja. Sin esto el panel se maqueta
   igual y suma al ancho del documento. */
.nav-familia__caja:not([open]) .nav-familia__panel { display: none; }
.nav-familia__disparador {
  cursor: pointer;
  /* El triángulo del sistema cambia de forma en cada navegador y no se puede
     colorear. Se apaga en los dos dialectos y se dibuja el nuestro. */
  list-style: none;
}
.nav-familia__disparador::-webkit-details-marker { display: none; }

/* Galón de 5px hecho con dos bordes. Gira al abrir. */
.nav-familia__flecha {
  width: 0.4rem;
  height: 0.4rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--d-micro) var(--e-cuarto);
}
[open] > .nav-familia__disparador .nav-familia__flecha {
  transform: translateY(1px) rotate(-135deg);
}

.nav-familia__panel {
  position: absolute;
  top: calc(100% + 0.35rem);
  left: 0;
  right: auto;
  translate: var(--nav-desliz, 0px) 0;
  z-index: 60;
  width: min(19rem, calc(100vw - 2.5rem));
  /* Una familia con diez países no cabe en pantallas bajas. Se desplaza dentro
     de su propia caja; la página nunca. */
  max-height: min(34rem, calc(100dvh - var(--alto-cabecera) - 2rem));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.5rem;
}

/* El menú se abre, no aparece. Es el único movimiento del encabezado y es lo
   que hace que la relación disparador→panel se lea de un vistazo. */
.nav-familia__caja[open] .nav-familia__panel {
  animation: nav-abre 170ms var(--e-salida) both;
}
@keyframes nav-abre {
  from { opacity: 0; transform: translateY(-6px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

.nav-familia__tagline {
  font-family: var(--f-mono);
  font-size: 0.62rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  line-height: 1.4;
  color: var(--texto-3);
  padding: 0 0.55rem 0.7rem;
  margin-bottom: 0.4rem;
  border-bottom: 1px solid var(--linea);
}

.nav-familia__lista { flex-direction: column; gap: 1px; }

/* Dos columnas: el nombre a la izquierda, el motivo pegado a la derecha, y la
   pregunta debajo cruzando las dos. Con el motivo en su propio renglón, las
   siete auditorías de medicamentos no cabían en pantalla y el menú se volvía
   una lista que hay que desplazar — que es justo lo que un menú no debe ser. */
.nav-entrada {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  column-gap: 0.6rem;
  row-gap: 0.1rem;
  padding: 0.45rem 0.55rem;
  border-radius: var(--radio-sm);
  text-decoration: none;
  color: var(--texto);
}
.nav-entrada__detalle { grid-column: 1 / -1; }
.nav-entrada--abierta { transition: background var(--d-micro); }
.nav-entrada--abierta:hover { background: var(--superficie-2); }
.nav-entrada--abierta[aria-current="page"] {
  background: var(--superficie-2);
  box-shadow: inset 2px 0 0 var(--acento);
}
.nav-entrada__nombre { font-size: var(--t-sm); font-weight: 600; }
.nav-entrada__detalle {
  font-size: var(--t-xs);
  line-height: 1.4;
  color: var(--texto-3);
}

/* Lo cerrado se distingue por ESTRUCTURA y no sólo por color: baja de
   contraste y además gana una etiqueta que dice por qué. Mismo criterio que
   el glifo ▲▼ de las gráficas — nada depende únicamente del matiz, porque en
   gobierno todo termina fotocopiado en blanco y negro. */
.nav-entrada--cerrada { cursor: default; }
.nav-entrada--cerrada .nav-entrada__nombre { color: var(--texto-3); }
.nav-entrada__motivo {
  grid-column: 2;
  white-space: nowrap;
  font-size: 0.6rem;
  color: var(--texto-3);
  border: 1px solid var(--linea);
  border-radius: 999px;
  padding: 0.05rem 0.45rem;
}

/* ── La empresa activa ───────────────────────────────────────────────────
   Empuja todo lo demás a la derecha y se lee antes que cualquier otra cosa del
   encabezado. Quien atiende a dos clientes tiene que saber en cuál está antes
   de leer una cifra. */
.empresa {
  margin-left: auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1.2;
  padding-inline: 0.9rem;
  border-left: 1px solid var(--linea);
}
.empresa__etiqueta {
  font-family: var(--f-mono);
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--texto-3);
}
.empresa__nombre {
  font-weight: 600;
  font-size: var(--t-sm);
  color: var(--texto);
  max-width: 22ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.salir { margin: 0; }

.suplantacion {
  width: min(100% - 2.5rem, var(--w-ancho));
  margin: 0 auto 0.75rem;
  padding: 0.6rem 0.9rem;
  border-radius: var(--radio-sm);
  border: 1px solid var(--linea-fuerte);
  background: var(--superficie-2);
  font-size: var(--t-sm);
  color: var(--texto-2);
}

/* ═══ Cuerpo ══════════════════════════════════════════════════════════════ */

main { flex: 1 0 auto; }

.pagina { padding-block: var(--pad-sm) var(--pad-md); }
.bloque { width: min(100% - 2.5rem, var(--w-ancho)); margin-inline: auto; }

.encabezado-pagina { margin-bottom: 2.5rem; }
.encabezado-pagina__cintillo { color: var(--texto-3); margin-bottom: 0.6rem; }
.encabezado-pagina__entrada {
  margin-top: 0.9rem;
  max-width: var(--w-texto);
  color: var(--texto-2);
  font-size: var(--t-lg);
}

.seccion { margin-top: 3rem; }
.seccion > h2 { margin-bottom: 1rem; }

.miga {
  display: flex;
  gap: 0.5rem;
  font-size: var(--t-sm);
  color: var(--texto-3);
  margin-bottom: 1.5rem;
}
.miga a { color: var(--texto-2); }

/* ═══ Acceso: una tarjeta centrada ════════════════════════════════════════ */

.acceso {
  display: grid;
  place-items: center;
  padding: clamp(2rem, 6vh, 5rem) 1.25rem;
}
.tarjeta-acceso {
  width: min(100%, 27rem);
  padding: clamp(1.75rem, 4vw, 2.5rem);
  background: var(--superficie);
}
.tarjeta-acceso h1 { margin-bottom: 0.75rem; }
.acceso__entrada { color: var(--texto-2); margin-bottom: 1.5rem; }
.acceso__pie {
  margin-top: 1.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--linea);
  font-size: var(--t-sm);
  color: var(--texto-3);
}
.acceso__pie a { color: var(--acento); }

/* ═══ Formularios ═════════════════════════════════════════════════════════ */

.formulario { display: grid; gap: 1.1rem; }
.campo { display: grid; gap: 0.4rem; }
.campo label {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--texto);
}
.campo input {
  font: inherit;
  color: var(--texto);
  background: var(--bg);
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio-sm);
  padding: 0.7rem 0.85rem;
  width: 100%;
  transition: border-color var(--d-micro), box-shadow var(--d-micro);
}
.campo input:hover { border-color: var(--texto-3); }
.campo input:focus-visible {
  border-color: var(--acento);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--acento) 22%, transparent);
}
.campo__codigo {
  font-family: var(--f-mono);
  font-size: 1.6rem;
  letter-spacing: 0.42em;
  text-align: center;
  padding-inline: 0.5rem;
}

.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  font: inherit;
  font-size: var(--t-sm);
  font-weight: 600;
  line-height: 1.2;
  padding: 0.62rem 1.1rem;
  border-radius: var(--radio-sm);
  border: 1px solid var(--linea-fuerte);
  background: none;
  color: var(--texto);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--d-micro), border-color var(--d-micro),
    color var(--d-micro);
}
.boton:hover { border-color: var(--acento); color: var(--acento); }
.boton--tenue { flex: none; white-space: nowrap; }
/* Relleno guinda con texto blanco encima: la única forma en que #711D1D puede
   convivir con texto en tema oscuro. */
.boton--primario {
  background: var(--campo);
  border-color: var(--campo);
  color: var(--campo-texto);
  padding-block: 0.78rem;
}
.boton--primario:hover {
  background: var(--brand-900);
  border-color: var(--brand-900);
  color: var(--campo-texto);
}
.boton--ancho { width: 100%; }

/* ═══ Avisos ══════════════════════════════════════════════════════════════ */

/* La región vive siempre en el árbol aunque esté vacía; sin contenido no debe
   ocupar espacio ni dibujar borde. */
.aviso-region:empty { display: none; }
.aviso {
  padding: 0.75rem 0.9rem;
  border-radius: var(--radio-sm);
  font-size: var(--t-sm);
  margin-bottom: 1.25rem;
}
/* El error NO se distingue sólo por color: lleva su propia barra a la
   izquierda y el texto lo dice. Mismo criterio que el glifo ▲▼ de las
   gráficas — nada depende únicamente del matiz. */
.aviso--error {
  background: var(--brand-50);
  border: 1px solid var(--brand-200);
  border-left: 4px solid var(--acento);
  color: var(--texto);
}
.aviso--info {
  background: var(--superficie-2);
  border: 1px solid var(--linea);
  border-left: 4px solid var(--linea-fuerte);
  color: var(--texto-2);
}
:root[data-tema="oscuro"] .aviso--error {
  background: color-mix(in srgb, var(--brand-800) 22%, transparent);
  border-color: color-mix(in srgb, var(--brand-300) 30%, transparent);
  border-left-color: var(--acento);
}

/* ═══ Elegir empresa ══════════════════════════════════════════════════════ */

/* Dentro de la tarjeta de acceso hereda su ancho; en la página de cambio se
   frena, porque un renglón de 84rem para leer dos palabras obliga a barrer
   la pantalla con la vista para nada. */
.lista-empresas {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 0.6rem;
  max-width: var(--w-texto);
}
.empresa-opcion {
  width: 100%;
  display: grid;
  gap: 0.15rem;
  text-align: left;
  font: inherit;
  padding: 0.9rem 1rem;
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio-sm);
  background: var(--superficie);
  color: var(--texto);
  cursor: pointer;
  transition: border-color var(--d-micro), background var(--d-micro);
}
.empresa-opcion:hover {
  border-color: var(--acento);
  background: var(--superficie-2);
}
.empresa-opcion__nombre { font-weight: 600; }
.empresa-opcion__clave { color: var(--texto-3); }
.empresa-opcion--activa { border-color: var(--acento); }
.empresa-opcion__marca {
  font-family: var(--f-mono);
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--acento);
}

/* ═══ Panel ═══════════════════════════════════════════════════════════════ */

.rejilla-vistas {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
  gap: 1.1rem;
}
.tarjeta-vista {
  display: grid;
  gap: 0.55rem;
  align-content: start;
  height: 100%;
  padding: 1.35rem;
  background: var(--superficie);
  text-decoration: none;
  color: var(--texto);
  transition: transform var(--d-ui) var(--e-salida), border-color var(--d-micro);
}
.tarjeta-vista:hover { transform: translateY(-2px); }
.tarjeta-vista__ramo { color: var(--texto-3); }
.tarjeta-vista__pregunta { color: var(--texto-2); font-size: var(--t-sm); }
.tarjeta-vista__ir {
  margin-top: 0.5rem;
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--acento);
}

.vacio {
  padding: 2rem;
  background: var(--superficie);
  color: var(--texto-2);
  max-width: var(--w-texto);
}
.vacio h2 { color: var(--texto); margin-bottom: 0.6rem; }

/* ── Cobertura: una línea por familia ────────────────────────────────────
   Deliberadamente NO son tarjetas. Seis tarjetas más debajo de las tarjetas
   de arriba convierten el panel en un mosaico donde nada pesa más que nada;
   un renglón por familia se barre con la vista en dos segundos y deja claro
   que lo importante de la página está arriba.                              */
.cobertura {
  list-style: none;
  padding: 0;
  margin: 0;
  border-top: 1px solid var(--linea);
}
.cobertura__fila {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.4rem 1.5rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--linea);
}
.cobertura__que {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.9rem;
  min-width: 0;
}
.cobertura__nombre { font-weight: 600; }
.cobertura__tagline { font-size: var(--t-sm); color: var(--texto-3); }
/* El estado de una familia contratada se lee en acento; el de una que no lo
   está, en tenue. La diferencia no es sólo el color: el texto lo dice. */
.cobertura__estado { color: var(--acento); white-space: nowrap; }
.cobertura__fila--sin .cobertura__estado { color: var(--texto-3); }

.ficha {
  margin-top: 2.5rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  gap: 1.25rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--linea);
}
.ficha dt {
  font-family: var(--f-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--texto-3);
  margin-bottom: 0.3rem;
}
.ficha dd { margin: 0; color: var(--texto); }

/* ═══ Tablas ══════════════════════════════════════════════════════════════ */

/* La tabla ancha se desplaza dentro de su propia caja: la página nunca se
   desplaza a lo ancho. `tabindex` lo pone el script para que la caja con
   desplazamiento sea alcanzable con el teclado. */
.tabla-envoltura {
  /* `contain: paint` hace de esta caja un bloque contenedor real, y con eso
     los encabezados PEGAJOSOS de la tabla dejan de escapar a su recorte.
     Sin esto, cada `th` sticky mide lo que mide la tabla —1,182 px medidos a
     390 de ventana— y arrastraba el ancho del documento: la página se
     deslizaba 68 px de lado en el teléfono aunque ningún elemento visible
     estuviera fuera de su contenedor. La tabla sigue desplazándose dentro de
     esta caja, que es lo que se quiere. */
  contain: paint;
  overflow-x: auto;
  border: 1px solid var(--linea);
  border-radius: var(--radio-sm);
  background: var(--superficie);
}
.tabla { width: 100%; border-collapse: collapse; font-size: var(--t-sm); }
.tabla th, .tabla td {
  text-align: left;
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--linea);
  vertical-align: top;
}
.tabla thead th {
  font-family: var(--f-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--texto-3);
  font-weight: 500;
  white-space: nowrap;
}
.tabla tbody tr:last-child th, .tabla tbody tr:last-child td { border-bottom: 0; }
.tabla tbody tr:hover { background: var(--superficie-2); }
.tabla tbody th { font-weight: 600; }
.tabla a { color: var(--acento); }

/* El estado se dice con la PALABRA. El color es refuerzo, nunca el dato: en
   blanco y negro —que en gobierno pasa todo el tiempo— tiene que seguir
   leyéndose. */
.estado {
  display: inline-block;
  font-family: var(--f-mono);
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.12rem 0.45rem;
  border-radius: 999px;
  border: 1px solid var(--linea-fuerte);
  color: var(--texto-2);
}
.estado--active { border-color: var(--acento); color: var(--acento); }
.estado--revoked, .estado--suspended, .estado--closed { color: var(--texto-3); }

/* ═══ Conmutador de tema ══════════════════════════════════════════════════ */

.tema {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.3rem;
  height: 2.3rem;
  padding: 0;
  border: 1px solid var(--linea-fuerte);
  border-radius: 999px;
  background: none;
  color: var(--texto-2);
  cursor: pointer;
  transition: color var(--d-micro), border-color var(--d-micro);
}
.tema:hover { color: var(--acento); border-color: var(--acento); }
.tema svg {
  grid-area: 1 / 1;
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
}
.g-luna { fill: currentColor; stroke: none; }
.g-sol { display: none; }
:root[data-tema="oscuro"] .g-sol { display: block; }
:root[data-tema="oscuro"] .g-luna { display: none; }

/* ═══ Pie ═════════════════════════════════════════════════════════════════ */

.pie {
  flex: none;
  margin-top: 4rem;
  border-top: 1px solid var(--linea);
  background: var(--superficie-2);
  padding-block: 1.5rem;
}
.pie__interior {
  width: min(100% - 2.5rem, var(--w-ancho));
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.5rem;
  font-size: var(--t-xs);
  color: var(--texto-3);
}

/* ═══ Compacto ════════════════════════════════════════════════════════════ */

/* ⛔ DESDE 86rem, NO DESDE 56rem.
   El menú de producto crece con el catálogo y a partir de cierto ancho su
   contenido se desbordaba SIN recortarse —el `overflow-x` vivía sólo en el
   bloque de 56rem— y se encimaba con «Empresa activa». Medido: por debajo de
   1,270 px el último enlace llegaba a 934 px y la empresa empezaba en 847.

   Aquí NO se envuelve la barra: se le devuelve al menú su propio deslizador y
   se saca el panel del deslizador. La cabecera sigue siendo de un renglón
   hasta 56rem, que es donde ya no cabe de ninguna forma.

   El umbral subió de 79rem a 86rem el día que el logotipo pasó a ser el
   COMPLETO —con su banda institucional es 42 px más ancho— y el menú volvió a
   encimarse a 1,280. Está medido a 1,150 · 1,280 · 1,376 · 1,440 · 1,750, no
   estimado: es el tipo de número que se queda corto en silencio. */
@media (max-width: 86rem) {
  /* ⛔ AQUI EL MENU BAJA A SU PROPIO RENGLON. NO SE DESLIZA.
     Antes, entre 56rem y 86rem, el renglon de familias era un deslizador
     horizontal SIN BARRA VISIBLE. Con cuatro familias casi nunca hacia falta;
     con ocho, a 1,300 px se veia asi:

         Panel  Medicamentos  Dispositivos medicos  Comercio exterior  Docur|

     «Documentos» cortado a media palabra, e «Insights» y «Consola» sin existir
     para quien mirara esa pantalla — y `Consola` es por donde el personal de
     INEFAM se cambia de empresa. Esconder navegacion sin decirlo es peor que
     una cabecera de dos renglones: lo segundo se ve, lo primero no.

     A lo ancho completo las ocho familias caben de sobra, y si algun dia no
     caben, envuelven (`flex-wrap: wrap` de la regla base). El panel sigue
     colgando de SU familia, que es lo que hace legible de que boton salio. */
  .barra { flex-wrap: wrap; row-gap: 0.5rem; }
  .nav-producto { order: 3; width: 100%; min-width: 0; }
}

/* Y en telefono el deslizador SI es lo correcto, por la razon de siempre:
   ocho familias envueltas hacen una cabecera pegajosa de tres renglones que se
   come un tercio de la pantalla. Ahi se prefiere deslizar —el gesto es natural
   con el dedo, a diferencia del raton— y el panel sale del deslizador. */
@media (max-width: 56rem) {
  .barra { padding-block: 0.6rem; }

  .nav-producto__familias {
    /* `min-width: 0` NO es adorno: un elemento flex trae `min-width: auto`,
       o sea se niega a encogerse por debajo de su contenido. Sin esto el
       `overflow-x` no contiene nada —el contenedor crece con los hijos— y
       quien termina desplazandose es la PAGINA. Medido a 390 px: 458 de ancho
       de documento contra 390 de ventana. */
    flex-wrap: nowrap;
    min-width: 0;
    max-width: 100%;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    /* Sitio para el subrayado de `aria-current`, que si no se recorta. */
    padding-bottom: 2px;
  }
  .nav-producto__familias::-webkit-scrollbar { display: none; }

  /* El panel deja de colgar de su familia y pasa a colgar de la cabecera: a
     lo ancho completo y, sobre todo, FUERA del renglon que se desliza. Un
     panel anclado dentro del deslizador se recortaria en cuanto sobresaliera.
     `.cabecera` es su bloque contenedor porque tiene `backdrop-filter`. */
  .nav-familia { position: static; }
  .nav-familia__panel {
    top: 100%;
    left: 0;
    right: 0;
    width: auto;
    border-radius: 0 0 var(--radio-lg) var(--radio-lg);
    max-height: calc(100dvh - var(--alto-cabecera) - 1rem);
  }

  .empresa {
    order: 2;
    align-items: flex-start;
    border-left: 0;
    padding-inline: 0;
  }
  .empresa__nombre { max-width: 100%; white-space: normal; }
}

/* ═══ Indicadores de HTMX ═════════════════════════════════════════════════
   Estas cuatro reglas las inyectaría HTMX solo, como una etiqueta <style> en
   línea. La política de contenido prohíbe el estilo en línea —`style-src
   'self'`— así que se le apaga con `<meta name="htmx-config">` y viven aquí,
   donde además se pueden leer y ajustar.
   ═════════════════════════════════════════════════════════════════════════ */
.htmx-indicator { opacity: 0; transition: opacity var(--d-ui) var(--e-cuarto); }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { opacity: 1; }

/* ═══════════════════════════════════════════════════════════════════════════
   BARRA LATERAL DE FILTROS Y FRANJA DEL CORTE
   Sólo se usa en `/vista/{id}`, pero vive aquí y no en `reporte.css` porque
   `reporte.css` es la piel de los BLOQUES del renderer y esto es el marco que
   los rodea. La frontera está donde está para que dos personas puedan tocar
   las dos mitades del tablero sin pisarse.

   AQUÍ NO SE DEFINE UN SOLO COLOR NUEVO
   Todo sale de `tokens.css`. El acento se toma siempre de `--acento` —guinda
   puro en claro, tinte claro en oscuro—, nunca se escribe #711D1D a mano para
   texto: sobre fondo oscuro da 1.77:1 y no puede portar ni una letra.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Alto de la cabecera pegajosa. Lo necesitan la barra lateral y la franja
   para pegarse justo debajo de ella y no atrás. Si cambia `.barra`, cambia
   este número: es el único acoplamiento y por eso está dicho una sola vez. */
/* RESPALDO. El valor de verdad lo mide `filtros.js` sobre la cabecera y lo
   escribe aquí mismo, porque la cabecera cambia de alto cuando el menú de
   familias envuelve —69 px en escritorio, 148 px en un teléfono— y un número
   fijo se queda corto en cuanto el menú crece: la franja se esconde detrás y
   nadie se entera. Estos dos son los medidos hoy, para que sin JavaScript
   quede cerca. */
:root { --alto-cabecera: 6.85rem; }
@media (max-width: 56rem) { :root { --alto-cabecera: 11.6rem; } }

/* ═══ La reja: filtros a la izquierda, tablero a la derecha ═══════════════ */

.tablero {
  display: grid;
  grid-template-columns: 17rem minmax(0, 1fr);
  gap: clamp(1.25rem, 2.4vw, 2.25rem);
  align-items: start;
}
/* `minmax(0, 1fr)` y `min-width: 0`: sin eso una tabla ancha estira su
   columna de la reja y empuja la página entera a desplazarse a lo largo. */
.tablero__cuerpo { min-width: 0; }

.tablero__lateral {
  position: sticky;
  top: calc(var(--alto-cabecera) + 0.75rem);
  /* Su propio desplazamiento: la lista de filtros es larga y el tablero es
     más largo todavía. Que la barra se quede quieta mientras el tablero corre
     es la mitad del valor de tenerla a un lado. */
  max-height: calc(100dvh - var(--alto-cabecera) - 1.5rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-right: 0.35rem;
}

/* ═══ El formulario de filtros ════════════════════════════════════════════ */

.filtros {
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  background: var(--superficie);
  padding: 0.9rem;
}

.filtros__cabeza {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--linea);
}
.filtros__titulo { color: var(--texto-3); margin: 0; font-weight: 500; }
.filtros__limpiar, .franja__limpiar {
  font-size: var(--t-sm);
  color: var(--acento);
  text-decoration: none;
  white-space: nowrap;
}
.filtros__limpiar:hover, .franja__limpiar:hover { text-decoration: underline; }

.filtros__fijos {
  margin-top: 0.9rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.6rem;
  font-size: var(--t-xs);
  color: var(--texto-3);
}
.filtros__fijo {
  border: 1px dashed var(--linea-fuerte);
  border-radius: 999px;
  padding: 0.1rem 0.55rem;
}

.filtros__acciones { margin-top: 1rem; }

/* ═══ Grupos plegables ════════════════════════════════════════════════════
   Es un `<details>`: el navegador ya sabe hacer acordeones y no se escribe
   uno. Un grupo con algo activo llega con `open` desde el servidor.
   ═════════════════════════════════════════════════════════════════════════ */

.grupo { border-bottom: 1px solid var(--linea); }
.grupo:last-of-type { border-bottom: 0; }

.grupo__resumen {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  padding: 0.7rem 0.1rem;
  list-style: none;
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--texto);
}
.grupo__resumen::-webkit-details-marker { display: none; }
.grupo__resumen::before {
  content: "▸";
  color: var(--texto-3);
  font-size: 0.75em;
  transition: transform var(--d-micro) var(--e-cuarto);
}
.grupo[open] > .grupo__resumen::before { transform: rotate(90deg); }
.grupo__resumen:hover { color: var(--acento); }
.grupo__titulo { flex: 1 1 auto; }
/* La cuenta de activos NO se distingue sólo por color: es un número. */
.grupo__cuenta {
  flex: none;
  color: var(--acento);
  border: 1px solid color-mix(in srgb, var(--acento) 35%, transparent);
  border-radius: 999px;
  padding: 0.05rem 0.45rem;
  line-height: 1.5;
}
.grupo__cuerpo { display: grid; gap: 0.9rem; padding: 0.15rem 0 0.9rem; }


/* ═══ El combobox ═════════════════════════════════════════════════════════
   Un combobox porta UN valor —eso dice el patrón de la W3C— y Enter agrega a
   la lista de chips que vive debajo, fuera del control. El listado va EN
   FLUJO y no flotando: la barra lateral tiene su propio desplazamiento, y un
   menú absoluto dentro de una caja con `overflow` se recorta a la mitad.
   ═════════════════════════════════════════════════════════════════════════ */

.combo { display: grid; gap: 0.3rem; min-width: 0; }
.combo__etq { color: var(--texto-3); }
/* El envoltorio de los campos ocultos existe para que el componente sepa dónde
   colgar uno nuevo. `display: contents` lo saca de la reja: si no, deja un
   renglón vacío de 0.3rem entre la etiqueta y el campo. Los `<input hidden>`
   de adentro se envían igual. */
.combo__ocultos { display: contents; }
.combo__campo {
  font: inherit;
  font-size: var(--t-sm);
  color: var(--texto);
  background: var(--bg);
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio-sm);
  padding: 0.45rem 0.6rem;
  width: 100%;
  min-width: 0;
  transition: border-color var(--d-micro), box-shadow var(--d-micro);
}
.combo__campo:hover { border-color: var(--texto-3); }
.combo__campo:focus-visible {
  border-color: var(--acento);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--acento) 22%, transparent);
}

.combo__lista {
  list-style: none;
  margin: 0;
  padding: 0.2rem;
  max-height: 15rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio-sm);
  background: var(--superficie-2);
}
/* Vacío o cerrado no ocupa espacio ni dibuja borde. `[hidden]` lleva
   `!important` porque el `display` de la lista lo ganaría. */
.combo__lista:empty { display: none; }
.combo__lista[hidden] { display: none !important; }

/* Cada sugerencia trae su PESO: «MAYPO — 12,481 líneas». Verlo antes de
   elegir es la mitad del valor de la lista.

   El peso va DEBAJO y no al lado: en una columna de 17rem, ponerlos en la
   misma línea recorta el nombre a «LABORATOR…» y elegir entre tres
   laboratorios recortados igual es imposible. Dos renglones y se lee entero. */
.sugerencia {
  display: grid;
  gap: 0.1rem;
  padding: 0.35rem 0.45rem;
  border-radius: var(--radio-sm);
  font-size: var(--t-sm);
  line-height: 1.3;
  cursor: pointer;
}
.sugerencia:hover { background: var(--superficie-3); }
/* La opción marcada con las flechas. El foco del DOM sigue en el campo, así
   que esto no puede ser `:focus`: es el reflejo de `aria-activedescendant`. */
.sugerencia--activa {
  background: var(--superficie-3);
  box-shadow: inset 2px 0 0 var(--acento);
}
/* Hasta dos renglones. Un nombre del padrón cabe en dos; el que no cabe se
   corta al final, donde está el «, S.A. DE C.V.» y no el nombre. */
.sugerencia__valor {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
  min-width: 0;
}
.sugerencia__peso { color: var(--texto-3); }
/* Los avisos no son elegibles y no lo parecen. */
.sugerencia--vacia, .sugerencia--aviso {
  cursor: default;
  color: var(--texto-2);
  background: none;
  display: block;
}
.sugerencia--vacia:hover, .sugerencia--aviso:hover { background: none; }
.sugerencia--aviso { border-bottom: 1px solid var(--linea); border-radius: 0; }
/* Un aviso se lee entero. El recorte a dos renglones es para los nombres del
   padrón, y aplicado aquí cortaba justo la parte que dice con qué se buscó
   —«las más cercanas a “pis”»—, que es la mitad del mensaje. */
.sugerencia--vacia .sugerencia__valor,
.sugerencia--aviso .sugerencia__valor {
  display: block;
  -webkit-line-clamp: none;
}

/* ═══ Chips ═══════════════════════════════════════════════════════════════
   Los mismos en la barra lateral y en la franja. Son enlaces normales, así
   que el teclado funciona solo: no hay un widget que atender.
   ═════════════════════════════════════════════════════════════════════════ */

.chips {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 0.5rem;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 2rem;
  max-width: 100%;
  padding: 0.15rem 0.25rem 0.15rem 0.6rem;
  font-size: var(--t-xs);
  border: 1px solid var(--linea-fuerte);
  border-radius: 999px;
  background: var(--superficie-2);
  color: var(--texto);
}
.chip__dim { color: var(--texto-3); flex: none; }
.chip__valor {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 18ch;
}
/* En la barra lateral el chip ya está debajo de su propio control: repetir
   el nombre del corte ahí es ruido. En la franja sí hace falta. */
.chips--lateral .chip__dim { display: none; }
.chips--lateral .chip__valor { max-width: 13ch; }

/* 44×44 px reales de área de clic aunque el glifo se vea chico. El
   pseudo-elemento estira el blanco sin estirar el dibujo, y el `gap` de
   0.75rem entre renglones evita que dos áreas se pisen. */
.chip__quitar {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: 1.55rem;
  height: 1.55rem;
  border-radius: 999px;
  color: var(--texto-3);
  text-decoration: none;
  line-height: 1;
}
.chip__quitar::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}
.chip__quitar:hover { color: var(--acento); background: var(--superficie-3); }

/* El chip que puso el sistema NO lleva ✕: el renderer volvería a poner el año
   en la siguiente petición y la ✕ sería un no-op reproducible, que es peor
   que no tener ✕. Lleva quién lo puso y cómo deshacerlo de verdad. */
.chip--sistema {
  border-style: dashed;
  padding-right: 0.6rem;
  flex-wrap: wrap;
}
.chip__nota {
  color: var(--texto-3);
  font-family: var(--f-mono);
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.chip__historico { color: var(--acento); white-space: nowrap; }

/* ═══ Franja pegajosa del corte ═══════════════════════════════════════════
   Los filtros se ven en los DOS lugares a propósito: al bajar al detalle la
   barra lateral queda fuera de vista y el usuario ya no sabe qué recorte está
   leyendo.
   ═════════════════════════════════════════════════════════════════════════ */

.franja {
  position: sticky;
  top: var(--alto-cabecera);
  z-index: 20;
  margin-bottom: 1.5rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(10px);
}

/* El alcance del contrato, siempre a la vista: es lo que evita que un «7.4 %
   del total» se repita en una junta como participación de mercado. */
.franja__alcance {
  margin: 0 0 0.5rem;
  padding-left: 0.55rem;
  border-left: 3px solid var(--acento);
  font-size: var(--t-sm);
  color: var(--texto-2);
}

.franja__corte {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem 0.9rem;
}
.franja__corte > .chips { flex: 1 1 20rem; }
.franja__sin { flex: 1 1 auto; margin: 0; font-size: var(--t-sm); color: var(--texto-3); }
.franja__conteo { flex: none; margin: 0; font-size: var(--t-sm); color: var(--texto-2); }
.franja__conteo strong { color: var(--texto); }
.franja__conteo--mudo { color: var(--texto-3); }
.franja__abrir { display: none; }

/* ═══ Diálogo de filtros (pantalla angosta) ═══════════════════════════════
   `showModal()` regala atrapado de foco, fondo inerte y `::backdrop` sin
   escribir una línea de accesibilidad. Nace vacío: `filtros.js` mueve dentro
   el MISMO formulario, para no tener dos copias con `id` repetidos.
   ═════════════════════════════════════════════════════════════════════════ */

.dialogo-filtros {
  width: min(23rem, 100%);
  max-width: 100%;
  height: 100dvh;
  max-height: 100dvh;
  margin: 0;
  padding: 0;
  border: 0;
  border-right: 1px solid var(--linea);
  background: var(--bg);
  color: var(--texto);
  flex-direction: column;
}
.dialogo-filtros[open] { display: flex; }
.dialogo-filtros::backdrop { background: rgba(0, 0, 0, 0.45); }
.dialogo-filtros__cabeza {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1rem;
  border-bottom: 1px solid var(--linea);
}
.dialogo-filtros__titulo { margin: 0; color: var(--texto-3); }
.dialogo-filtros__cuerpo { flex: 1 1 auto; overflow-y: auto; padding: 0.9rem 1rem 2rem; }
.dialogo-filtros__cuerpo .filtros { border: 0; padding: 0; background: none; }
/* El diálogo ya dice «Filtros» en su encabezado: el del formulario sobra y
   queda como un título repetido dos veces seguidas. */
.dialogo-filtros__cuerpo .filtros__titulo { display: none; }
.dialogo-filtros__cuerpo .filtros__cabeza { justify-content: flex-end; }

/* ═══ S8 · Llévatelo ══════════════════════════════════════════════════════
   El número de renglones se dice ANTES de pedir el archivo. Descubrirlo
   esperando una descarga de dos minutos es descubrirlo tarde.
   ═════════════════════════════════════════════════════════════════════════ */

.descarga {
  margin-top: 3rem;
  padding: clamp(1.25rem, 3vw, 1.9rem);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  background: var(--superficie);
}
.descarga__titulo { margin-bottom: 0.6rem; }
.descarga__conteo { color: var(--texto-2); max-width: var(--w-texto); }
.descarga__conteo strong { color: var(--texto); }

.descarga__form {
  margin-top: 1.35rem;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 1rem 1.5rem;
}
.descarga__formatos { border: 0; padding: 0; margin: 0; }
.descarga__formatos legend { color: var(--texto-3); padding: 0; margin-bottom: 0.45rem; }
.descarga__opcion {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin-right: 1.25rem;
  font-size: var(--t-sm);
  cursor: pointer;
}
.descarga__opcion input { accent-color: var(--acento); }

/* Un botón deshabilitado tiene que VERSE deshabilitado. Con el relleno guinda
   intacto, quien tiene un corte que no cabe lo aprieta, no pasa nada y
   concluye que la página está rota. Se apaga a superficie y texto tenue —no
   con opacidad sobre el guinda, que además hunde el contraste del texto— y el
   porqué se lee arriba, en el párrafo del conteo. */
.boton:disabled { cursor: not-allowed; }
.boton--primario:disabled,
.boton--primario:disabled:hover {
  background: var(--superficie-3);
  border-color: var(--linea-fuerte);
  color: var(--texto-3);
}

.descarga__estado {
  margin-top: 1rem;
  font-size: var(--t-sm);
  color: var(--texto-2);
  border-left: 3px solid var(--linea-fuerte);
  padding-left: 0.7rem;
}
.descarga__estado:empty { display: none; }
.descarga__liga { margin-top: 0.9rem; }
.descarga__nota {
  margin-top: 1.1rem;
  font-size: var(--t-xs);
  color: var(--texto-3);
  max-width: var(--w-texto);
}

/* ═══ Compacto: una columna, y los filtros en un diálogo ══════════════════
   La barra lateral sólo se esconde CUANDO HAY JAVASCRIPT, porque sólo
   entonces el botón «Filtrar» puede abrirla. Sin JavaScript se queda en su
   lugar, arriba del tablero, con sus grupos plegados: el respaldo tiene que
   ser un respaldo de verdad.
   ═════════════════════════════════════════════════════════════════════════ */

@media (max-width: 63.999rem) {
  .tablero { grid-template-columns: minmax(0, 1fr); }
  .tablero__lateral {
    position: static;
    max-height: none;
    overflow: visible;
    margin-bottom: 1.25rem;
  }
  .con-js .tablero__lateral { display: none; }
  .con-js .franja__abrir { display: inline-flex; }

  /* La franja pegajosa tiene que caber. En un teléfono, cabecera y franja se
     comen la pantalla: medido, 133 + 187 px son el 38 % de un iPhone. Se
     aprieta a dos renglones —alcance recortado y un carril de chips que se
     desplaza a lo ancho DENTRO de su caja— y baja a ~95 px. */
  .franja { padding: 0.55rem 0.7rem; }
  .franja__alcance {
    margin-bottom: 0.4rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* Dos renglones: arriba el botón y el conteo, abajo los chips con todo el
     ancho para ellos. En un solo renglón, el chip del año se parte a media
     palabra a los 150 px y el carril deja de leerse. */
  .franja__corte { flex-wrap: wrap; gap: 0.5rem 0.75rem; }
  .franja__abrir, .franja__conteo { order: 1; }
  .franja__conteo { margin-left: auto; }
  .chips--franja, .franja__sin { order: 2; flex: 1 0 100%; }
  .chips--franja {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding-bottom: 0.2rem;
    /* El desvanecido del borde derecho dice que hay más y que se desplaza. Sin
       él, un chip cortado a media palabra se lee como un defecto de pintado y
       nadie intenta arrastrarlo. */
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 1.75rem), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 1.75rem), transparent);
  }
  /* `max-width: none` a propósito: en el carril el chip se sale de la caja y
     se alcanza desplazando, en vez de comprimirse hasta partir su texto en
     tres renglones. */
  .chips--franja .chip { flex: none; max-width: none; }
  .chips--franja .chip--sistema { flex-wrap: nowrap; }
  .chips--franja .chip__valor { max-width: 12ch; }
  .franja__abrir, .franja__conteo, .franja__limpiar { flex: none; }
  /* «Quitar todos» ya está en la barra lateral como «Limpiar todo»: en el
     carril angosto se cae, y lo que no se cae es el conteo. */
  .franja__limpiar { display: none; }
}

/* ═══ Impreso ═════════════════════════════════════════════════════════════
   En papel no hay nada que filtrar ni que descargar: lo que tiene que salir
   es el corte, y cuál es el corte se lee en los chips. Por eso la franja SÍ
   se imprime y el formulario no.
   ═════════════════════════════════════════════════════════════════════════ */

@media print {
  .tablero { display: block; }
  .tablero__lateral, .descarga__form, .franja__abrir, .franja__limpiar {
    display: none;
  }
  .franja {
    position: static;
    backdrop-filter: none;
    border-color: #999;
  }
}
