/* ==========================================================================
   La norma gráfica de los Monitores de DecideChile — monitor-ui, reference
   al 19-ago-2026. Perfil ESTÁTICO: "Opción A", variables CSS sin Tailwind.
   El sistema está escrito para funcionar con o sin Tailwind; esto es la
   misma norma que en Mercado Público (v4) y Municipios (v3), en CSS plano.

   Este archivo lo enlaza el generador UNA vez por página. No se inlinea
   repetido en cada página (son 11.253) ni se copia por proyecto: si mañana
   hay otro monitor estático, este archivo se comparte, no se duplica.

   Los comentarios que explican por qué una regla rara es así NO se borran.
   Cada uno es un bug que alguien ya peleó en uno de los dos repos
   publicados; sin el comentario, el siguiente los "limpia" y lo reintroduce.
   ========================================================================== */

/* El peso 500 es obligatorio: las píldoras del header usan font-weight 500 y
   sin la cara cargada el navegador cae al 400 o la sintetiza. Le pasa hoy a
   Mercado Público, que no lo pide. (§3.1) */
@import url('https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@200;300;400;500;600;800&family=JetBrains+Mono:wght@400..500&display=swap');

/* --------------------------------------------------------------------------
   §2 Tokens de color — paleta canónica, la misma del skill de dataviz
   -------------------------------------------------------------------------- */
:root {
  --primary: #266FE0;      /* acción, enlaces, acentos, eyebrow, serie 1 */
  --blue-dark: #184D9B;    /* hover de botón primario, serie 2 */
  --blue-light: #E7F0FF;   /* chips de ícono, activo del menú, hero */
  --ink: #171B21;          /* texto principal y títulos */

  /* muted = #626A78 y NO #6B7280. Mercado Público usa #6B7280, que da 4.43:1
     sobre #F5F5F5 — bajo el mínimo AA de 4.5:1. Municipios lo corrigió a
     #626A78, que sube a ~5:1 sin cambiar el tono. Es la norma. (§2.1) */
  --muted: #626A78;

  --line: #E5E7EB;         /* bordes y separadores */
  --bg: #F5F5F5;           /* fondo de página, th, hover de fila */
  --ok: #10B981;           /* éxito, variación positiva, serie 3 */
  --warn: #F59E0B;         /* advertencia, serie 4 */
  --err: #EF4444;          /* error, variación negativa, serie 5 */
  --violet: #8B5CF6;       /* serie 6 */
  --cyan: #06B6D4;         /* serie 7 */
  --footer-bg: #121212;    /* fondo del footer */

  /* Token y no un 64px literal repetido: si el header cambia de alto, el
     thead sticky y los anclajes se arreglan en un solo lugar. Municipios
     repite "top: 64px" a mano y por eso está en la lista de fixes. (§2.2) */
  --header-h: 64px;

  --page: 1100px;          /* ancho de página (§4) */
  --article: 720px;        /* ancho de lectura */
}

/* Registradas para que puedan ANIMARSE. Una custom property sin registrar no
   interpola: el difuminado de los carruseles aparecería de golpe al scrollear.
   Van acá y no en el override del panel porque las usan los dos carruseles: el
   de highlights (dentro del panel) y el de análisis (en la portada). */
@property --fade-izq { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --fade-der { syntax: '<length>'; inherits: false; initial-value: 0px; }

/* --------------------------------------------------------------------------
   §3 Tipografía — Hanken para texto, Mono para dato
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

/* Reserva el canal de la barra de scroll siempre. Sin esto, al bloquear el
   fondo con un modal abierto (regla de más abajo) la barra desaparece y la
   página salta su ancho hacia la derecha justo cuando se abre el modal. */
html { scrollbar-gutter: stable; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: 'Hanken Grotesk', system-ui, sans-serif;
  font-weight: 400;
  line-height: 1.5;
  /* Cifras tabulares en todo el sitio: sin esto una columna de números baila
     al cambiar de dígito. (§3) */
  font-feature-settings: 'tnum' 1;
  -webkit-font-smoothing: antialiased;
}

/* Nada de overflow-x en el body. Si algo desborda, se arregla la pieza —
   esconder el desborde esconde el bug y rompe el scroll horizontal legítimo
   de las tablas. (§6) */

/* --primary da 4.74:1 sobre blanco (pasa AA) pero 4.35:1 sobre --bg (no pasa).
   Como el fondo de página ES --bg, todo enlace que no viva dentro de una card
   blanca usa --blue-dark (7.48:1). Mismo token de §2, misma identidad. */
a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }
/* `:not(.btn)` y no `.hero a` a secas: los CTA del hero son <a>, y esta regla
   (0,1,1) le ganaba a `.btn-primary` (0,1,0). Resultado medido: los DOS botones
   salían con letras --blue-dark (24,77,155) — el azul con letras azul oscuro y
   el blanco también. Un botón no hereda color de enlace: lo define su variante. */
body > a, main > a, main > p > a, .estado a, .hero a:not(.btn) { color: var(--blue-dark); }

/* --------------------------------------------------------------------------
   §4 Layout
   -------------------------------------------------------------------------- */
.page { max-width: var(--page); margin: 0 auto; padding: 24px 16px; }
@media (min-width: 640px) { .page { padding: 40px 24px; } }

.article { max-width: var(--article); }

.card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 16px;
  margin-bottom: 22px;
}
@media (min-width: 768px) { .card { padding: 28px; } }

/* --------------------------------------------------------------------------
   §5.1–5.2 Header y menú
   -------------------------------------------------------------------------- */

/* Franja de contexto SOBRE el header — el patrón de Mercado Público: una banda
   oscura y angosta que dice en qué estado está el dato antes de mostrar nada.
   Va acá y no en el cuerpo porque es metadato del sitio, no del panel: la misma
   frescura vale para las 11.253 fichas, y dentro del cuerpo solo la veía quien
   llegaba al home.
   NO es sticky, el header sí: la frescura se lee una vez al llegar y después
   solo roba alto de viewport. Por eso va ANTES del .site-header en el flujo. */
/* `400..500` en el @import de arriba y no `400;500`: el texto de esta franja
   pide 440 —un 10% más que el 400 del resto— y con solo las dos instancias
   estáticas el navegador lo redondeaba a 500, o sea +25%. Con el rango variable
   el 440 es el 440. */
.topbar { background: var(--ink); color: #FAFAFA; }
.topbar .barra {
  max-width: var(--page);
  margin: 0 auto;
  /* Mismo padding lateral que .site-header .barra: si no coinciden, la franja
     y el wordmark quedan desalineados y se nota. */
  padding: 7px 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  /* En pantalla ancha las dos piezas caben en una línea. En angosta no —a 320px
     «Última revisión DT: …» + «último dictamen N°354/31 (07-ago-2026)» mide
     467px— y antes se resolvía con `flex-wrap: wrap`, que duplicaba el alto de
     la franja. Ahora se alternan: una sola línea que rota. Ver más abajo. */
  flex-wrap: nowrap;
  white-space: nowrap;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  line-height: 1.45;
}
@media (min-width: 640px) { .topbar .barra { padding: 7px 24px; } }
/* #C9CDD4 sobre --ink da 10.84:1; el blanco de los valores, 17.28:1. Ambos AA. */
.topbar b { color: #fff; font-weight: 600; }
.topbar .sep { color: #626A78; }
/* El ícono de IA. Sin filtro ni opacidad: el color (#FAFAFA) y el +10% de grosor
   viven en el propio assets/icono-ia.svg, porque un filtro sobre un <img> no
   puede dar un color exacto —`brightness(0) invert(1)` devuelve #fff— y el
   grosor de un ícono de trazo es su `stroke-width`, que desde afuera no se
   alcanza. */
.topbar .ia-icono { width: 15px; height: 15px; flex: none; }
.topbar .ia-txt { letter-spacing: 0.02em; font-weight: 440; }
/* El nombre de la casa, enlazado. Subrayado a propósito: en una franja de una
   sola línea, sin subrayado no se lee como enlace y nadie lo clickea. */
.topbar .ia-txt a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.topbar .ia-txt a:hover { text-decoration-thickness: 2px; }

.site-header {
  background: #fff;
  /* Sombra y NO border-bottom: con el borde el header mide 65px y el token
     --header-h dice 64, así que el thead sticky se pega 1px corrido. Los dos
     repos publicados usan sombra por esto mismo. */
  box-shadow: 0 1px 2px rgba(23, 27, 33, .06);
  position: sticky;
  top: 0;
  z-index: 20;
}
.site-header .barra {
  max-width: var(--page);
  margin: 0 auto;
  /* px-4 sm:px-6 y no px-6 fijo: con px-6 a 320px se van 48 de 320 en aire.
     Mercado Público usa px-6 fijo y está en la lista de fixes. (§4) */
  padding: 0 16px;
  height: var(--header-h);
  display: flex;
  align-items: center;
  gap: 16px;
}
@media (min-width: 640px) { .site-header .barra { padding: 0 24px; } }

/* min-height 44 y no solo el alto del wordmark: el link de la marca es un
   target táctil como cualquier otro y con el wordmark en texto medía 26px. (§6) */
/* `flex: none` y NO `min-width: 0`. Con `min-width: 0` la marca era lo único
   encogible de la barra —`.acciones` es `flex: none` y los `.pill` del nav son
   `nowrap`, así que ninguno cede—, y al traducir el nav a alemán (737px contra
   500 en español) el logo se comprimía a 0px de ancho. El SVG seguía pintándose
   sobre su caja vacía, así que en pantalla se veía el nav impreso encima del
   wordmark. La identidad del sitio no es lo que se sacrifica cuando falta lugar:
   lo que cede es el nav, y si no cabe está el menú de hamburguesa. */
.brand { display: flex; align-items: center; gap: 8px; flex: none; min-height: 44px; }
/* El icono va subido 20%: la marca lo tiene con aire abajo y sin esto no
   asienta con el wordmark. Los dos monitores publicados usan el mismo -20%. */
.brand-icon {
  height: 32px;
  width: 32px;
  flex-shrink: 0;
  transform: translateY(-20%);
  display: block;
}
/* El contenedor del Lottie: alto fijo ANTES de que cargue la animación, para
   que el header no salte cuando aparece. Si lottie-web no llega, queda un
   hueco de 32px y nada roto. */
.brand-icon[data-lottie] > svg { display: block; width: 100%; height: 100%; }
/* El wordmark escala en dos pasos y NUNCA se esconde: es la identidad. */
.brand-word { height: 34px; width: auto; }
@media (max-width: 360px) { .brand-word { height: 26px; } }
@media (min-width: 640px) { .brand-word { height: 46px; } }
/* Fallback tipográfico mientras no existan los SVG de marca: degradado, no
   roto. Se borra el día que estén los assets. */
span.brand-word {
  height: auto;
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--ink);
  white-space: nowrap;
}

/* El grupo de acciones (buscador + idioma) va SIEMPRE visible, también en
   móvil: antes vivía dentro de .nav-desk, que se esconde bajo 1024px, así que
   en el teléfono el header quedaba con la marca y la hamburguesa y nada más.
   `margin-left:auto` acá y no en .nav-desk: es este grupo el que empuja todo a
   la derecha cuando el nav está oculto. */
/* Puerta del nav con submenú. El <details> no puede ser `position: relative` y
   además `flex` en la fila del nav sin que el panel absoluto se cuelgue de él,
   así que el relative va acá y el panel se ancla a esta puerta, no a la barra. */
.pill-drop { position: relative; flex: none; display: flex; }
.pill-drop > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.pill-drop > summary::-webkit-details-marker { display: none; }
.pill-drop > summary .flecha { flex: none; transition: transform .15s; opacity: .55; }
.pill-drop[open] > summary .flecha { transform: rotate(180deg); opacity: 1; }
/* Abierto se ve como la puerta activa: es la sección en la que estás mirando. */
.pill-drop[open] > summary { background: var(--bg); color: var(--primary); }
.pill-drop > summary:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
/* El panel: mismos valores que el del selector de idioma —borde, radio, sombra,
   z-index— porque es el mismo componente con otro contenido. Se ancla a la
   IZQUIERDA de su puerta y no a la derecha: el nav se lee de izquierda a
   derecha y un panel que crece hacia adentro taparía las puertas siguientes. */
.pill-drop .panel {
  position: absolute;
  left: 0;
  top: 100%;
  margin-top: 8px;
  z-index: 46;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 10px 24px rgba(23, 27, 33, .12);
  padding: 6px 0;
  min-width: 190px;
}
.pill-drop .panel a {
  display: block;
  padding: 8px 16px;
  font-size: 13px;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
  transition: background .15s, color .15s;
}
.pill-drop .panel a:hover { background: #F6F8FB; color: var(--primary); }
.pill-drop .panel a:focus-visible { background: #F6F8FB; color: var(--primary); }
/* La vista vigente. La marca ui/menu.js y no el generador: estas vistas no
   tienen URL propia —son hashes sobre la misma página— así que el build no sabe
   en cuál estás. Mismo tratamiento que el ítem activo del selector de idioma. */
.pill-drop .panel a.activo { color: var(--primary); font-weight: 600; }

.acciones { margin-left: auto; display: flex; align-items: center; gap: 4px; flex: none; }

.nav-desk { display: none; gap: 4px; align-items: center; margin-left: auto; }
/* Breakpoint lg y no md: con etiquetas de más de una palabra, entre 768 y
   1024 el nav desborda. Regla operativa de la norma: si el nav mide más de
   ~420px, va en lg. (§5.1) */
@media (min-width: 1024px) { .nav-desk { display: flex; } }
/* Con el nav visible, el que separa es el nav; el grupo queda pegado a él. */
@media (min-width: 1024px) { .acciones { margin-left: 0; } }

/* TODAS las reglas del nav van bajo .site-header, no en `.pill` a secas.
   Motivo real, no estilístico: el <style> de dashboard.html define su propia
   `.pill` (JetBrains Mono 11px, fondo #F3F4F6) para los chips del panel, y en
   el home ese <style> se emite DESPUÉS de esta hoja. A igual especificidad
   gana el último, así que el menú del header salía en mono 11px —solo en el
   home; en las fichas se veía bien—. Con `.site-header .pill` (0,2,0) la norma
   gana sin tocar el panel.
   Hay 8 nombres compartidos entre las dos hojas: .pill .card .badge .kpi-card
   .kpi-grid .kpi-icon .kpi-label .kpi-value. Los otros 7 solo se usan dentro
   del panel, donde su look ES el correcto; si alguno llega al chrome, hay que
   scoparlo igual que este. */
.site-header .pill {
  /* inherit y no un stack propio: la marca es Hanken Grotesk y baja del body.
     Explícito porque es justo lo que el panel pisaba. */
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  border-radius: 6px;
  padding: 8px 12px;
  color: var(--muted);
  background: none;
  text-transform: none;
  letter-spacing: normal;
  white-space: nowrap;
  transition: color .15s, background .15s;
}
/* Los tres estados, con los mismos valores que HeaderNav.tsx de Mercado
   Público: inactivo `text-muted`, hover `text-primary` + `bg-bg`, activo
   `text-primary` + `bg-blue-light`.
   OJO con el contraste, que es un problema de la norma y no de este monitor:
   --primary sobre --blue-light da 4.13:1 y sobre --bg 4.35:1, los dos bajo el
   4.5:1 de AA para texto normal. Antes acá se usaba --blue-dark (7.11:1 y
   7.48:1), que pasaba AA pero se veía distinto a los monitores publicados. Se
   eligió la fidelidad a la referencia; el día que la norma corrija el par,
   esto ya está alineado. */
.site-header .pill:hover { color: var(--primary); background: var(--bg); text-decoration: none; }
.site-header .pill[aria-current="page"] { color: var(--primary); background: var(--blue-light); }

/* --------------------------------------------------------------------------
   Buscador del header — campo, no botón (§5.1)
   -------------------------------------------------------------------------- */

/* Un <form> GET normal: sin JS escribe ?q= y la página del buscador lo lee.
   Es lo que hace que funcione en un sitio estático servido desde S3. */
/* La lupa del header: un enlace a /buscador/, no un campo.
   Era un input de 240px siempre abierto —con su expansión a lupa bajo 1024px y
   su lista de sugerencias—. Se cambió por decisión de producto: había dos
   lugares donde buscar y el campo competía por el ancho del header, que con el
   nav traducido al alemán (547px) ya no tenía aire.
   Las reglas del input, de `.abierto` y de `.sug` se fueron con él; el IIFE que
   las manejaba en ui/menu.js queda inerte por su propio guard. */
.buscar-header {
  flex: none;
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  color: var(--muted);
  border-radius: 8px;
  transition: color .15s, background .15s;
}
.buscar-header:hover { color: var(--primary); background: var(--bg); }
.buscar-header:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  color: var(--primary);
}

/* --------------------------------------------------------------------------
   Selector de idioma — dropdown <details> (§5.2)
   -------------------------------------------------------------------------- */

/* Mismo patrón que el dropdown «Análisis avanzado» de Mercado Público:
   <details> nativo + panel absoluto. El <details> trae teclado y foco gratis;
   el cierre al clickear fuera lo pone ui/menu.js. */
.lang-drop { position: relative; flex: none; }
.lang-drop > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 4px;
  /* Mono 10px para el código del idioma: es un dato corto y en mayúsculas —ES,
     EN, 中— no una etiqueta de nav, y en el sitio eso va en JetBrains. A 14px en
     la fuente del cuerpo pesaba como una puerta más del header. */
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.06em;
  font-weight: 500;
  color: var(--muted);
  padding: 8px 10px;
  border-radius: 6px;
  white-space: nowrap;
  transition: color .15s, background .15s;
}
.lang-drop > summary::-webkit-details-marker { display: none; }
.lang-drop > summary:hover { color: var(--primary); background: var(--bg); }
/* Medidas en CSS y no solo en el atributo del SVG: el atributo es el tamaño
   intrínseco y el CSS es el que manda si algo hereda un font-size distinto. */
.lang-drop > summary .globo { flex: none; width: 12px; height: 12px; }
.lang-drop > summary .flecha { flex: none; width: 8px; height: 8px; transition: transform .15s; }
.lang-drop[open] > summary .flecha { transform: rotate(180deg); }
.lang-drop[open] > summary { color: var(--primary); background: var(--bg); }
.lang-drop .panel,
.filas-drop .panel {
  position: absolute;
  right: 0;
  top: 100%;
  margin-top: 8px;
  /* 46 y no 30: el botón «volver arriba» es `fixed` a la derecha con z-index 45,
     y el selector de filas también vive a la derecha del pie de tabla, así que
     en un teléfono el botón le tapaba la última opción del panel. Un popup que
     el usuario acaba de abrir gana contra un control flotante permanente. Queda
     por debajo del modal (50), que sí debe tapar todo. */
  z-index: 46;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 10px 24px rgba(23, 27, 33, .12);
  padding: 6px 0;
}
/* El ancho del selector de idioma: la mitad de los 190px que tenía.
   190 venía del `min-width: 150` de la referencia más un margen, y para seis
   nombres cortos —«English», «Deutsch», «Português»— sobraban unos 100px de
   panel vacío a la derecha de cada línea. Con tanto aire, una lista alineada a
   la izquierda no se lee como alineada: se lee como texto suelto en una caja.
   95px es ancho suficiente para el nombre más largo y deja el bloque pegado al
   texto, que es lo que hace evidente la alineación. Es `min-width`, no `width`:
   si un idioma con nombre más largo entra al config, el panel crece solo. */
.lang-drop .panel { min-width: 95px; }
/* El `min-width` sale de la regla compartida y pasa a cada dropdown, porque los
   dos quieren anchos distintos y ninguno quería 190: el selector de filas de las
   tablas ya declara el suyo —84px, para «10 / 15 / 25 / 50 / 100»— en
   `.tabla-pie .filas-drop .panel`, más abajo en esta hoja. */
/* El `#langbar` de adentro lo arma chrome.py, pero conserva esa clase —y por lo
   tanto hereda el `display:flex` en UNA FILA que el <style> de dashboard.html le
   pone, pensado para cuando la barra vivía al lado de las pestañas—. Sin esto
   los seis idiomas salen en fila y apretados dentro de un panel angosto.
   0,3,0 de especificidad para ganarle a `.langbar` del <style> del panel, que
   se emite después de esta hoja. */
.lang-drop .panel .langbar {
  display: flex;
  flex-direction: column;
  /* `stretch` explícito: el .langbar del <style> de dashboard.html trae
     `align-items:center`, que en una columna centra en el eje HORIZONTAL. Hoy no
     se nota porque los ítems llevan `width:100%`, pero es un empate frágil —el
     día que ese 100% cambie, los idiomas se centran— y el pedido es que queden
     alineados a la izquierda. Mejor decirlo. */
  align-items: stretch;
  gap: 0;
  padding: 0;
  margin: 0;
  border: 0;
  background: none;
}
/* El rótulo explica QUÉ se traduce. Sin él, un selector de idioma en el header
   promete un sitio en seis idiomas y el sitio está en español: lo que cambia
   son las explicaciones de las pestañas. */
/* El rótulo explica qué se traduce; va con el padding lateral de los ítems. */
.lang-drop .panel .lb-lbl {
  display: block;
  padding: 0 16px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
  margin: 4px 0 8px;
  white-space: normal;
  line-height: 1.5;
}
/* Ítems de la lista, con los valores del LangSwitch de Municipios:
   `block px-4 py-2 text-xs`, nombre nativo alineado a la izquierda, el activo
   en --primary y peso 600. El fondo del hover es el #f6f8fb de la referencia,
   más frío que --bg. */
/* `a` además de `button`: las opciones del selector de filas de los listados
   son ENLACES a la variante de ese tamaño —URLs reales, que funcionan sin JS—,
   no botones. Sin esto heredaban el `display:inline` de un <a> y los tres
   tamaños salían pegados en una fila («2550100»). */
.lang-drop .panel button,
.lang-drop .panel a,
.filas-drop .panel button,
.filas-drop .panel a {
  display: block;
  text-decoration: none;
  width: 100%;
  text-align: left;
  /* La familia va nombrada y no heredada. `inherit` tomaba la del contenedor, y
     en las rutas del panel el `.langbar` del <style> de dashboard.html le pone
     'JetBrains Mono': la misma lista salía monoespaciada en /dictamenes/ y con
     la fuente del cuerpo en la portada. */
  font-family: 'Hanken Grotesk', system-ui, sans-serif;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
  background: none;
  border: 0;
  border-radius: 0;
  padding: 8px 16px;
  cursor: pointer;
  transition: background .15s, color .15s;
}
.lang-drop .panel button:hover,
.lang-drop .panel a:hover,
.filas-drop .panel button:hover,
.filas-drop .panel a:hover { background: #F6F8FB; color: var(--primary); }
.lang-drop .panel button.active,
.lang-drop .panel a.active,
.filas-drop .panel button.active,
.filas-drop .panel a.active {
  color: var(--primary); font-weight: 600; background: none;
}

/* Menú móvil sobre <details> nativo: trae teclado, Esc y foco gratis. */
.menu-movil { margin-left: auto; }
@media (min-width: 1024px) { .menu-movil { display: none; } }
/* El orden en pantalla angosta es hamburguesa · lupa · globo, como en la
   referencia. `order` y no reordenar el markup: el DOM mantiene el orden
   lógico —buscador e idioma antes del menú— que es el que recorre el teclado. */
@media (max-width: 1023px) {
  .site-header .barra { gap: 2px; }
  /* La hamburguesa va última: `order: 2` a ella y `1` a las acciones. Con
     `order: -1` (primer intento) se iba delante de TODO, incluida la marca. */
  .acciones { order: 1; margin-left: auto; }
  .menu-movil { order: 2; margin-left: 0; }
}

.menu-movil > summary {
  list-style: none;
  cursor: pointer;
  /* ≥44px de target táctil (§6) */
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 8px;
  color: var(--ink);
}
.menu-movil > summary::-webkit-details-marker { display: none; }
.menu-movil > summary:hover { background: var(--bg); }

/* Con el <details> cerrado, un hijo `position:fixed` NO lo esconde el UA: el
   panel se sigue maquetando (colapsado a 12px de ancho) y sus 5 links quedan
   en el orden de tabulación, invisibles pero enfocables. Un usuario de teclado
   pasa por cinco links fantasma antes de llegar al contenido. El display:none
   explícito es lo que lo saca del layout y del foco. */
.menu-movil:not([open]) .menu-panel { display: none; }

.menu-panel {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: #fff;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  /* `inset: 0` deja el panel a ras del borde de la pantalla, y la `.barra` de
     adentro centra su contenido en `--header-h`: el logo, que es la pieza más
     alta de esa barra, quedaba tocando el canto de arriba. 12px lo despegan.
     Va en el panel y no en la barra para que el aire lo tenga TODO lo que
     empiece arriba, y para que el `border-bottom` de la barra siga marcando el
     final del encabezado y no un margen. */
  padding-top: 12px;
}
/* El panel del menú vive DENTRO de .site-header, así que su `.barra` heredaba
   `max-width: var(--page)` y `margin: 0 auto` de `.site-header .barra`. Y en un
   contenedor flex en columna, un margen lateral `auto` ANULA el stretch: la
   barra se encogía al ancho de su contenido (236px medidos en un viewport de
   500) y quedaba centrada, con el logo y la X pegados en el medio.
   Se resetean las dos propiedades. Con la barra a ancho completo, su
   `border-bottom` cruza la pantalla entera, que es lo que se quería. */
.menu-panel .barra {
  max-width: none;
  margin: 0;
  width: 100%;
  height: var(--header-h);
  padding: 0 16px;
  display: flex; align-items: center; justify-content: space-between;
  border-bottom: 1px solid var(--line);
}
.menu-panel .cerrar {
  margin-left: auto;
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; cursor: pointer; color: var(--ink);
  border-radius: 8px;
}
.menu-panel .cerrar:hover { background: var(--bg); }
/* Los valores son los del menú móvil de Mercado Público, medidos en su
   HeaderNav.tsx: `px-6 pt-4` en el nav, ítems `border-b border-line py-4` a
   17px, y los rótulos de grupo en `font-mono uppercase text-muted mt-6 mb-1` a
   10px con `letter-spacing: 0.14em`. */
.menu-panel nav { padding: 16px 24px 0; display: flex; flex-direction: column; flex: 1; }
.menu-panel nav a {
  display: block;
  font-size: 17px;
  padding: 16px 0;
  color: var(--ink);
  border-bottom: 1px solid var(--line);
}
/* Las puertas van en 500 y las vistas internas en 400 y sangradas: es lo que
   distingue una sección de una vista dentro de ella.
   El gancho es `data-sub`, que ui/chrome.py ya emitía para que ui/menu.js marque
   la vista vigente: los sub-ítems lo tienen —vacío en el primero de cada
   sección, que es la sección misma sin hash— y las puertas no, así que la
   presencia del atributo es exactamente la distinción que hace falta y no hay
   que inventar una clase que se pueda olvidar.
   Sangría sin guion: un guion delante de cada ítem se lee como viñeta de lista,
   no como jerarquía. 16px alcanzan para que el ojo agrupe. */
.menu-panel nav > a { font-weight: 500; }
.menu-panel nav > a[data-sub] { font-weight: 400; padding-left: 16px; }

/* Las puertas QUE TIENEN vistas debajo se pintan como rótulo de sección —mono,
   10px, versalitas, apagado— y no como una entrada más de 17px. Es el estilo que
   tenía el `<div class="grupo">` de la versión anterior, y hace el trabajo que ni
   el peso ni la sangría alcanzaban a hacer: decir que lo de abajo es DE ellas.
   Con «Dictámenes» a 17px como «Análisis», las cuatro vistas siguientes parecían
   hermanas suyas y no hijas.
   Se les saca el `border-bottom`: una línea entre el rótulo y su primera vista
   las separaría, que es justo lo contrario de lo que el rótulo viene a decir.
   `:not([data-sub]):has(+ a[data-sub])` —algo que NO es una vista y que va
   seguido de una vista— y no una clase emitida desde chrome.py: la condición ES
   estructural, «tiene hijos justo abajo», y leerla de la estructura evita que el
   día que una sección pierda sus vistas quede un rótulo huérfano que nadie se
   acordó de destildar.
   El `:not()` no es adorno: sin él la regla se come a los propios sub-ítems,
   porque cada vista va seguida de la siguiente. Quedaban «PANORAMA» y «DOCTRINA
   VIVA» en versalitas y solo la última de cada grupo con su estilo real.
   Siguen siendo enlaces y siguen llevando a su sección; que además el primer
   ítem de cada grupo («Panorama») apunte al mismo sitio es la red de seguridad
   de que el estilo de rótulo no esconda un destino. */
.menu-panel nav > a:not([data-sub]):has(+ a[data-sub]) {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
  padding: 24px 0 6px;
  border-bottom: 0;
}
.menu-panel nav a:hover { color: var(--primary); }
.menu-panel nav a[aria-current="page"] { color: var(--primary); font-weight: 600; }
/* La vista vigente dentro de una sección, marcada por ui/menu.js. */
.menu-panel nav a.activo { color: var(--primary); }
/* Pie del menú: rótulo chico y el sello centrado, como la referencia. */
.menu-panel .pie {
  margin-top: auto;
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 40px 24px;
}
.menu-panel .pie .rotulo {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
}
/* `brightness(0)` y no «sin filtro»: el sello está dibujado en BLANCO —viene
   hecho para el pie oscuro del sitio— así que sobre el panel blanco del menú
   desaparecía. brightness(0) lo pasa a negro conservando el alfa, y las letras
   caladas siguen caladas, así que se lee igual pero en negativo.
   No es `invert(1)`: invertir depende del color de origen y ataría este estilo a
   que el sello siga siendo blanco. brightness(0) da negro venga de donde venga. */
.menu-panel .pie img {
  height: 30px; width: auto; display: block;
  filter: brightness(0);
  opacity: .55;
}

/* Los dos keyframes son DISTINTOS a propósito y no es negociable: reusar el
   mismo animation-name no re-dispara la animación, el evento animationend
   nunca llega y el overlay queda pegado bloqueando todos los clicks de la
   página. Los dos repos publicados documentan este bug. (§5.2) */
@keyframes menu-pop     { from { opacity: 0; transform: translateX(10px); } to { opacity: 1; transform: translateX(0); } }
@keyframes menu-pop-out { to   { opacity: 0; transform: translateX(10px); } }
details[open] > .menu-pop { animation: menu-pop .25s cubic-bezier(.34, 1.4, .64, 1); }
details[open] > .menu-pop.menu-pop-out { animation: menu-pop-out .2s ease-in forwards; }
@media (prefers-reduced-motion: reduce) {
  details[open] > .menu-pop,
  details[open] > .menu-pop.menu-pop-out { animation: none; }
}

/* --------------------------------------------------------------------------
   §7 Accesibilidad
   -------------------------------------------------------------------------- */
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: #fff;
  color: var(--primary);
  padding: 10px 16px;
  border: 1px solid var(--line);
  border-radius: 0 0 8px 0;
  font-size: 14px;
  font-weight: 600;
}
.skip-link:focus { left: 0; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* --------------------------------------------------------------------------
   §5.3 Footer 5/4/3
   -------------------------------------------------------------------------- */
.site-footer {
  margin-top: 64px;
  background: var(--footer-bg);
  border-top: 1px solid rgba(255, 255, 255, .08);
  color: #fff;
}
.site-footer .cols {
  max-width: var(--page);
  margin: 0 auto;
  padding: 48px 16px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
}
@media (min-width: 640px) { .site-footer .cols { padding: 48px 24px; } }
@media (min-width: 768px) {
  /* 5/4/3 y no 5/3/4: «Explorar» necesita más aire que las fuentes. */
  .site-footer .cols { grid-template-columns: repeat(12, 1fr); }
  .site-footer .col-marca   { grid-column: span 5; }
  .site-footer .col-explora { grid-column: span 4; }
  .site-footer .col-fuentes { grid-column: span 3; }
}
.site-footer .col-titulo {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px;
  line-height: 14px;
  text-transform: uppercase;
  letter-spacing: .14em;
  color: rgba(255, 255, 255, .45);
  margin: 0 0 14px;
}
.site-footer .bajada {
  /* Arranca a la altura del SEGUNDO ítem de «Explorar» —62px desde el tope de
     la columna: 46 de la fila de marca + estos 16—, que es donde la columna de
     al lado tiene su segundo renglón. Va declarado y no heredado del margen por
     defecto del <p> (14px, que dejaba la bajada 2px arriba de «Ordinarios»):
     una alineación que depende del margen que traiga el navegador no es una
     alineación, es una coincidencia. */
  margin-top: 16px;
  font-size: 14px;
  font-weight: 300;
  color: rgba(255, 255, 255, .6);
  max-width: 24rem;
  line-height: 1.65;
}
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li { margin-bottom: 10px; }
.site-footer .col-explora a { font-size: 14px; color: rgba(255, 255, 255, .75); }
.site-footer .col-explora a:hover { color: var(--primary); }
.site-footer .col-fuentes a { font-size: 14px; color: rgba(255, 255, 255, .9); }
.site-footer .col-fuentes a:hover { color: var(--primary); }
/* 46px de alto, pedido explícito — el mismo valor que usa Mercado Público. */
.site-footer .wordmark-inv {
  height: 46px; width: auto;
  /* Invertir el logo en vez de mantener una segunda copia en blanco. */
  filter: brightness(0) invert(1);
}
/* Variante para un logo OPACO (JPG). `brightness(0) invert(1)` pinta todo el
   rectángulo de blanco: sirve para SVG/PNG con alfa, no para un JPG con fondo
   blanco. Con `invert(1)` a secas el fondo blanco se vuelve negro —casi el
   #121212 del footer— y la tipografía negra se vuelve blanca. Es lo mejor
   alcanzable sin una versión con transparencia. */
.site-footer .wordmark-inv.opaco { filter: invert(1); }

/* El ícono del footer: 32x32 y en blanco sólido. `brightness(0) invert(1)` es
   lo mismo que aplica la referencia al LogoEye en su footer — el trazo del
   Lottie es oscuro y sobre #121212 no se vería.
   El `-20%` de translate viene de .brand-icon y se mantiene: la marca trae aire
   abajo y sin eso el ícono no asienta con el wordmark. */
.site-footer .brand-icon {
  height: 32px; width: 32px;
  filter: brightness(0) invert(1);
}
/* El Lottie inyecta un <svg> que hereda el alto del contenedor, no lo trae. */
.site-footer .brand-icon svg { width: 100%; height: 100%; display: block; }
.site-footer .marca-txt {
  font-size: 18px; font-weight: 800; color: #fff; margin-bottom: 12px;
}
.site-footer .barra-baja {
  max-width: var(--page);
  margin: 0 auto;
  padding: 0 16px 40px;
}
@media (min-width: 640px) { .site-footer .barra-baja { padding: 0 24px 40px; } }
/* La fila de redes + «Powered by». El contacto va DEBAJO de esta fila y a
   ancho completo, que es el orden de Mercado Público: apilado y a la izquierda
   en móvil, en una línea a la derecha desde 768. */
.site-footer .fila {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}
@media (min-width: 768px) {
  .site-footer .fila { flex-direction: row; align-items: center; justify-content: space-between; }
}
.site-footer .redes { display: flex; gap: 10px; }
/* Las redes van bajas y suben al hover: son salidas del sitio, no la acción
   que el footer viene a proponer —esa es el mailto de la invitación—. La
   opacidad va en el <a> y no en el trazo para que el aro se atenúe con el
   ícono; separados, el aro quedaba más fuerte que lo que encierra. Mismo gesto
   que `.powered`, un paso más bajo. */
.site-footer .redes a {
  width: 36px; height: 36px;
  border: 1px solid rgba(255, 255, 255, .2);
  border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
  color: #fff;
  opacity: .6;
  transition: transform .15s, border-color .15s, opacity .15s;
}
.site-footer .redes a:hover {
  transform: translateY(-2px); border-color: var(--primary); opacity: 1;
}
/* El foco NO se atenúa: quien navega con teclado necesita ver dónde está. */
.site-footer .redes a:focus-visible { opacity: 1; }
/* La opacidad sale de una variable para que un sello con más cobertura de tinta
   pueda pedir menos —lo hace `assets.poweredByOpacidad`—. Va así y no como
   `opacity` inline porque inline le ganaría al :hover de abajo y el sello
   dejaría de aclararse al pasar el cursor. */
.site-footer .powered { opacity: var(--sello-op, .8); transition: opacity .15s; }
.site-footer .powered:hover { opacity: 1; }
/* El foco no se atenúa, igual que en .redes: quien navega con teclado necesita
   ver dónde está. */
.site-footer .powered:focus-visible { opacity: 1; }
/* Invitación a escribir, con los valores de Mercado Público medidos en su
   layout.tsx: `text-left md:text-right text-micro text-white/50 mt-6`, donde
   --text-micro es 10px/14px. Va al final del footer, después de la fila de
   redes y «Powered by», a ancho completo.
   Va en Hanken y no en mono: ese <p> no lleva `font-mono` en la referencia. En
   el footer el mono queda SOLO para las etiquetas de columna («Explorar»,
   «Fuentes de los datos»), que es lo que marca .col-titulo. */
.site-footer .contacto {
  font-size: 10px;
  line-height: 14px;
  color: rgba(255, 255, 255, .5);
  margin-top: 24px;
  text-align: left;
}
@media (min-width: 768px) { .site-footer .contacto { text-align: right; } }
.site-footer .contacto a { color: rgba(255, 255, 255, .7); text-decoration: underline; }
.site-footer .contacto a:hover { color: #fff; }

/* Con hero, las migas sobran: la banda ya dice en qué sección estás, y debajo
   de ella «Inicio › Dictámenes» repite el nombre de la página que se acaba de
   leer en 40px. Se ocultan solo donde hay hero — en una ficha, que no lo tiene,
   son la única señal de ubicación dentro de 11.253 documentos.
   display:none y no visibility: así también salen del árbol de accesibilidad y
   un lector de pantalla no las anuncia. Esto NO toca el BreadcrumbList del
   JSON-LD, que es lo que lee Google y se emite aparte, en el <head>. Ojo: hoy
   ese JSON-LD no sale en ninguna página porque `jsonld_breadcrumb` devuelve
   None sin dominio canónico —fail-closed, como toda URL absoluta—; aparece
   solo, en toda página, el día que se exporte MONITORDT_SITE_URL. */
.hero ~ #contenido .crumb { display: none; }

/* --------------------------------------------------------------------------
   §5.7 Hero — banda full-bleed FUERA del main.page
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  background: var(--blue-light);   /* respaldo si la foto no carga */
  border-bottom: 1px solid var(--line);
  overflow: hidden;
}
/* La foto en dos capas: grises abajo, velo blanco al 80% encima. Es lo que
   hace Municipios y por eso la compresión del JPEG no se nota. Foto y no
   video: el video obliga a CDN propio y se descarga en cada página con hero.
   La URL entra por --hero-img desde el config, no hardcodeada acá. (§5.7) */
.hero.con-foto::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: var(--hero-img);
  background-size: cover;
  background-position: center;
  filter: grayscale(1);
}
.hero.con-foto::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, .8);
}
/* El contenido va sobre las dos capas. Sin esto el velo lo tapa. */
.hero .interior { position: relative; z-index: 1; max-width: var(--page); margin: 0 auto; padding: 32px 16px; }
@media (min-width: 640px) { .hero .interior { padding: 48px 24px; } }
.hero h1 {
  font-size: clamp(26px, 3.2vw, 40px);
  line-height: 1.05;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0 0 12px;
}
/* Segunda línea del título, en azul. El quiebre lo pone un <br> dentro del
   mismo <h1>, así que el texto accesible sigue siendo la frase completa.
   --primary sobre el velo blanco del hero da 4.74:1 (pasa AA); sobre el
   --blue-light de respaldo, cuando la foto no carga, baja a 4.13:1. Es el
   mismo defecto de §2.2 que ya tiene el par primary/blue-light, y a 26–40px
   el mínimo aplicable es 3:1 (texto grande), así que acá pasa por tamaño. */
.hero h1 .l2 { color: var(--primary); }

/* #141414 es un literal pedido por el cliente, no un token de §2. Difiere de
   --ink (#171B21) en algo imperceptible —17.9:1 vs 16.4:1 sobre blanco— pero
   queda anotado como desvío: si se normaliza, es este solo lugar. */
.hero .bajada {
  font-size: 14px; font-weight: 300; color: #141414;
  max-width: 62ch; margin: 0;
}

/* Nota del hero: define un término que el visitante puede no manejar. Va bajo
   la bajada, un punto más chica y en gris, para que se lea como pie y no
   compita con el texto de entrada. */
.hero .hero-nota {
  font-size: 12.5px; font-weight: 300; line-height: 1.5;
  color: var(--muted); max-width: 62ch; margin: 10px 0 0;
}
.hero .hero-nota b { font-weight: 600; color: var(--ink); }

/* Etiqueta de ley en los resultados del buscador. El corpus nombra las leyes
   por su número y la gente por su nombre: la pastilla es el puente, y va junto
   a la materia para que se lea como una propiedad del documento. */
.et-ley {
  display: inline-block; margin-left: 8px; padding: 1px 8px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px; line-height: 16px; letter-spacing: .04em;
  color: var(--blue-dark); background: var(--blue-light);
  border-radius: 999px; vertical-align: 1px; white-space: nowrap;
}

/* Los dos CTA del hero. gap y no margin entre botones: con margin, el wrap a
   320px deja el segundo pegado al primero en la línea nueva. */
.hero-acciones { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 24px; }

/* --------------------------------------------------------------------------
   §5.6 Secciones, badges, botones, callouts, migas, ficha
   -------------------------------------------------------------------------- */
.section-tag {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px; line-height: 14px;
  text-transform: uppercase; letter-spacing: .14em;
  color: var(--primary);
  margin-bottom: 6px;
}
.section-title { font-size: 18px; font-weight: 600; margin: 0 0 4px; }
@media (min-width: 768px) { .section-title { font-size: 22px; } }
.section-desc { font-size: 13px; font-weight: 300; color: var(--muted); margin: 0 0 14px; }

.badge {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px; line-height: 14px;
  text-transform: uppercase; letter-spacing: .1em;
  padding: 4px 8px; border-radius: 6px;
  display: inline-flex; align-items: center;
}
.badge-primary { background: rgba(38, 111, 224, .1); color: var(--primary); }
.badge-ok      { background: rgba(16, 185, 129, .1); color: var(--ok); }
.badge-warn    { background: rgba(245, 158, 11, .1); color: var(--warn); }
.badge-err     { background: rgba(239, 68, 68, .1);  color: var(--err); }
.badge-violet  { background: rgba(139, 92, 246, .1); color: var(--violet); }
.badge-cyan    { background: rgba(6, 182, 212, .1);  color: var(--cyan); }
.badge-neutral { background: rgba(100, 116, 139, .12); color: #475569; }

.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 10px 16px;
  border-radius: 8px;
  font-weight: 600; font-size: 13px;
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
  /* ≥44px de alto efectivo con el padding de arriba (§6) */
}
.btn:hover { text-decoration: none; }
.btn-primary { background: var(--primary); color: #fff; border: 1px solid var(--primary); }
.btn-primary:hover { background: var(--blue-dark); border-color: var(--blue-dark); }
.btn-ghost { background: #fff; border: 1px solid var(--line); color: #141414; }
.btn-ghost:hover { background: var(--bg); }

/* Borde uniforme, sin barra lateral de color: es la forma de los dos repos. */
.callout { border: 1px solid var(--line); background: #fff; padding: 16px; border-radius: 12px; }

.crumb {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px; line-height: 16px;
  text-transform: uppercase; letter-spacing: .1em;
  color: var(--muted);
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  margin-bottom: 14px;
}
/* El link de las migas usa blue-dark y no primary a propósito: primary sobre
   bg da 4.35:1, bajo AA para texto normal. blue-dark da 7.48:1 y también es
   token de §2. (Hallazgo que va aguas arriba, a la norma: la combinación
   primary-sobre-bg es una trampa abierta para los ocho monitores.) */
.crumb a { color: var(--blue-dark); }
.crumb .sep { color: var(--line); }

.ficha-title { font-size: 22px; font-weight: 600; line-height: 1.2; color: var(--ink); margin: 0; }
.ficha-meta {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px; line-height: 14px;
  text-transform: uppercase; letter-spacing: .1em;
  color: var(--muted);
}

/* --------------------------------------------------------------------------
   §5.4 Tablas de dato
   -------------------------------------------------------------------------- */
/* Una sola regla y ninguna tabla queda sin envolver por olvido. Es de
   Municipios y es norma. Lo que NO se copia de ahí es el
   `.data-table{display:block}` bajo 640px: rompe la semántica de tabla para
   lectores de pantalla y este :has ya cubre el caso. (§5.4) */
:where(div, section, figure):has(> .data-table) { overflow-x: auto; }
.table-scroll { overflow-x: auto; }

.data-table { width: 100%; border-collapse: collapse; }
.data-table th {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px; line-height: 14px;
  text-transform: uppercase; letter-spacing: .1em;
  color: var(--muted);
  text-align: left;
  padding: 10px 6px;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
/* Deja ganar al override del caller y no al revés. */
.data-table th.text-center { text-align: center; }
.data-table th.text-right  { text-align: right; }
.data-table td {
  padding: 10px 6px;
  border-bottom: 1px solid var(--line);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  vertical-align: top;
}
@media (min-width: 768px) {
  .data-table th, .data-table td { padding: 12px 8px; }
}
.data-table tr:hover td { background: var(--bg); }
.data-table.compacta td { padding-top: 6px; padding-bottom: 6px; }

/* Las dos tablas de la portada: la fecha en UNA línea.
   Con el layout automático (el defecto) el navegador reparte según el contenido,
   y la materia —hasta 120 caracteres— empuja al resto contra su min-content. El
   min-content de «2026-08-07» no es su ancho: parte en los guiones y da
   «2026-08-» / «07», una línea extra en cada fila. `nowrap` lo impide y
   `table-layout: fixed` hace que los anchos de acá se respeten en vez de
   negociarse; el sobrante se lo lleva la materia, que es la única que puede
   envolver sin costo. Bajo 640px manda el bloque de @media del final, que da a
   la materia un scroll horizontal en vez de ancho. */
@media (min-width: 640px) {
  .tabla-inicio { table-layout: fixed; }
  .tabla-inicio th:nth-child(1), .tabla-inicio td:nth-child(1) { width: 96px; }
  .tabla-inicio th:nth-child(2), .tabla-inicio td:nth-child(2) { width: 104px; }
  .tabla-inicio th:nth-child(3), .tabla-inicio td:nth-child(3) { width: 176px; }
}

/* La fecha en UNA línea, en todas las tablas. Va por CLASE y no por posición:
   el `td:nth-child(2)` que hacía esto antes funcionaba de casualidad —resultó
   que la fecha es la segunda columna en la portada, en los listados y en el
   buscador—, y la primera tabla que la ponga en otro lugar apuntaría a la
   columna equivocada sin que nada avise. Fue justo lo que pasó con la tabla de
   resultados de búsqueda, que no llevaba la regla y partía la fecha.
   El porqué del nowrap: el min-content de «2026-08-07» no es su ancho, porque
   puede partir en los guiones, así que cualquier columna vecina con texto largo
   la aprieta hasta dejarla en «2026-08-» / «07» y suma una línea a cada fila.
   `.ident` es la columna del identificador —«Dictamen 5667/33»—, que por lo
   mismo salía en tres líneas en el buscador. */
.data-table .fecha,
.data-table .ident { white-space: nowrap; }
.data-table.sin-cierre tr:last-child td { border-bottom: 0; }
.data-table td.num, .data-table th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Primera columna sticky en móvil: es lo que hace usable una tabla ancha en
   un teléfono. background:inherit y no un color fijo, para que el hover de
   fila no deje la celda pegada de otro color. */
@media (max-width: 767px) {
  .data-table td:first-child, .data-table th:first-child {
    position: sticky;
    left: 0;
    background: inherit;
    box-shadow: 1px 0 0 var(--line);
  }
  .data-table th:first-child { background: var(--bg); }
  .data-table td:first-child { background: #fff; }
}

/* thead sticky opt-in y solo desde 768px: en móvil, con la primera columna
   sticky, dos ejes pegados marean. Sombra en vez de border porque el border
   de un thead sticky desaparece al scrollear. */
@media (min-width: 768px) {
  .data-table.sticky-head thead th {
    position: sticky;
    /* top: 0 y NO var(--header-h), aunque el header mida 64. Esto costó medirlo:
       `position: sticky` se resuelve contra el ANCESTRO CON SCROLL más cercano,
       y la propia norma envuelve toda tabla en uno —
       `:where(div,section,figure):has(> .data-table) { overflow-x: auto }`, y
       cuando un eje deja de ser `visible` el otro se computa `auto`, así que ese
       div también scrollea en vertical—. Con `top: 64px` el thead no se
       estacionaba bajo el header del sitio: se empujaba 64px hacia abajo DENTRO
       del envoltorio y quedaba por debajo de la primera fila de datos. Medido a
       scrollY=0: th en 257, primera fila en 231.
       El bug existía desde que se escribió la regla; se veía como una fila
       delgada corrida entre las dos primeras. Se hizo evidente al darle fondo
       gris al header.
       Fijar el thead bajo el header del sitio es INALCANZABLE mientras la tabla
       viva dentro del envoltorio de scroll: el sticky no puede referirse al
       viewport desde ahí. Con `top: 0` el header queda donde corresponde y se
       pega al borde del envoltorio, que es la stickiness que este layout
       permite. */
    top: 0;
    z-index: 2;
    box-shadow: 0 1px 0 var(--line);
    border-bottom: 0;
  }
}

/* NUNCA display:none para truncar un dataset en móvil. Mercado Público
   esconde hoy las filas 11+ (`tbody tr:nth-child(n+11){display:none}`) y con
   eso el HTML servido deja de coincidir con lo que ve un visitante móvil —
   que es exactamente lo que Google indexa. Para acortar: paginar. (§5.4) */

/* Pie de tabla — el TablePagination de Mercado Público, con sus valores:
   contenedor `flex flex-wrap items-center justify-between gap-3 mt-4`, la
   cuenta a la izquierda en mono micro, el navegador a la derecha. */
.tabla-pie {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 12px;
  margin-top: 16px;
}
.tabla-pie .derecha { display: flex; align-items: center; gap: 12px; }
/* Selector de filas por página. Era un `<select>` nativo, elegido por el picker
   del sistema en móvil. El costo lo pagaba en todas las pantallas: el popup
   nativo no se puede posicionar ni pintar, así que abría ENCIMA de la tabla en
   vez de debajo del disparador y con el look del sistema —el tilde azul de
   macOS—, siendo la única pieza del sitio que no se parecía a las demás.
   Ahora es el mismo `<details>` + `.panel` que el selector de idioma: comparten
   las reglas del panel de arriba, así que hay una sola definición de cómo se ve
   un dropdown acá. El disparador conserva exactamente la caja que tenía el
   `<select>`, para que el pie de tabla no cambie de forma. */
.tabla-pie .filas-drop { position: relative; flex: none; }
.tabla-pie .filas-drop > summary {
  list-style: none;
  cursor: pointer;
  display: flex; align-items: center; gap: 6px;
  font-family: inherit;
  font-size: 13px;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 5px 8px;
  transition: border-color .15s, box-shadow .15s;
}
.tabla-pie .filas-drop > summary::-webkit-details-marker { display: none; }
.tabla-pie .filas-drop > summary:hover,
.tabla-pie .filas-drop[open] > summary { border-color: var(--primary); }
.tabla-pie .filas-drop > summary:focus-visible {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 2px rgba(38, 111, 224, .2);
}
.tabla-pie .filas-drop > summary .flecha { flex: none; transition: transform .15s; }
.tabla-pie .filas-drop[open] > summary .flecha { transform: rotate(180deg); }
/* Una lista de números no necesita los 190px que pide la de idiomas. */
.tabla-pie .filas-drop .panel { min-width: 84px; }
.tabla-pie .cuenta {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px; line-height: 14px;
  letter-spacing: .08em;
  color: var(--muted);
  white-space: nowrap;
}
.paginacion { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
/* cellBase de la referencia: h-8 min-w-8 px-2 rounded text-sm tabular-nums */
.paginacion .celda {
  min-width: 32px; height: 32px;
  padding: 0 8px;
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  border-radius: 6px;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  /* `background: none` explícito: el paginador en cliente usa <button>, y sin
     esto el navegador le pone su gris de control (rgb(239,239,239) medido). El
     de los listados usa <a>, que no lo tiene: por eso el defecto se veía solo
     en las tablas paginadas en el cliente. Y `font: inherit` porque un <button>
     tampoco hereda la tipografía. */
  background: none;
  font-family: inherit;
  border: 1px solid transparent;
  cursor: pointer;
  transition: color .15s, background .15s;
}
/* Los controles llevan el color de texto; los números, el apagado. Es la
   distinción de la referencia (`text-ink` en Anterior/Siguiente). */
.paginacion a.celda:has(.etq) { color: var(--ink); }
/* Solo hover pinta fondo; en reposo ninguna celda lo tiene, salvo la actual,
   que se marca con borde y blanco. */
.paginacion .celda:hover:not(.actual):not(.inerte) { color: var(--primary); background: var(--bg); text-decoration: none; }
.paginacion .celda.actual {
  border-color: var(--line); background: #fff; color: var(--ink); font-weight: 600;
}
/* Anterior/Siguiente en el extremo: se ven, no se pueden usar. `aria-hidden`
   no —el texto sigue siendo útil— pero sí fuera del foco y sin puntero. */
.paginacion .celda.inerte { color: rgba(98, 106, 120, .4); pointer-events: none; user-select: none; }
.paginacion .puntos { color: var(--muted); padding: 0 4px; user-select: none; }
/* Bajo 640px quedan solo los chevrones: «Anterior 1 2 … 113 Siguiente» no
   entra en 320px y el navegador es lo último que debe desbordar. */
.paginacion .etq { display: none; }
@media (min-width: 640px) { .paginacion .etq { display: inline; } }

/* --------------------------------------------------------------------------
   §5.5 KPIs
   -------------------------------------------------------------------------- */
.kpi-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
@media (min-width: 768px) {
  /* auto-fit y no columnas fijas: con 1/3/4 fijas, una fila de 5 KPIs se
     parte en 4+1 y deja tres huecos. minmax(0,1fr) y no 1fr: 1fr es
     minmax(auto,1fr) y no baja del ancho mínimo del contenido, así que una
     cifra larga estira la grilla fuera de la card. (§5.5) */
  .kpi-grid { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
}
.kpi-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 14px;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  /* Obligatorio: sin esto el ítem de grilla no baja de su ancho de contenido
     y una cifra larga desborda la grilla entera. */
  min-width: 0;
}
@media (min-width: 768px) { .kpi-card { padding: 24px; } }

/* container-type SOLO dentro de .kpi-grid. En un flex-wrap implica
   contain:inline-size, el contenido deja de contribuir al ancho intrínseco y
   la card colapsa a su mínimo. Copiar textual esta advertencia. (§5.5) */
.kpi-grid > .kpi-card { container-type: inline-size; }
.kpi-grid > .kpi-card .kpi-value { font-size: clamp(20px, 13cqi, 38px); }

.kpi-label {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px; line-height: 14px;
  text-transform: uppercase; letter-spacing: .1em;
  color: var(--muted);
  margin-bottom: 8px;
}
.kpi-value {
  font-size: 26px;
  font-weight: 800;
  color: var(--ink);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.kpi-delta { font-size: 12px; font-weight: 600; margin-top: 6px; }
.kpi-delta.up { color: var(--ok); }
.kpi-delta.down { color: var(--err); }
.kpi-delta.neutral { color: var(--muted); }
.kpi-icon {
  width: 36px; height: 36px;
  border-radius: 8px;
  background: var(--blue-light);
  color: var(--primary);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   §5.8 Estados de dato — la ausencia es un estado normal, no una excepción
   -------------------------------------------------------------------------- */
/* Una sola forma por caso. Mercado Público tiene hoy doce variantes del mismo
   mensaje de vacío ("Sin resultados.", "Sin licitaciones aún.", "Sin datos
   disponibles."…); eliminar eso es justamente para lo que existe esto. */
.estado {
  font-size: 14px;
  font-weight: 300;
  color: var(--muted);
  margin: 0;
}
.estado-titulo { font-size: 18px; font-weight: 600; color: var(--ink); margin: 0 0 6px; }
.estado-bloque { padding: 8px 0 4px; }
.estado-acciones { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }

/* La ausencia se muestra con em dash y nunca como 0: 0 es un dato, — es que
   no hay dato. Nunca N/A, nunca null, nunca guion corto. */
.sin-dato { color: var(--muted); }

/* Grilla de tarjetas (analisis) */
.grid-cards {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
}
@media (min-width: 640px) { .grid-cards { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); } }
.card-link { display: block; color: inherit; }
.card-link:hover { text-decoration: none; border-color: var(--primary); }
.card-link:hover .card-link-titulo { color: var(--primary); }
.card-link-titulo { font-size: 16px; font-weight: 600; margin: 0 0 6px; }

/* Buscador */
.buscador-campo {
  width: 100%;
  font-family: inherit;
  font-size: 15px;
  padding: 12px 14px;
  border: 1.5px solid var(--line);
  border-radius: 9px;
  background: #fff;
  color: var(--ink);
}
.buscador-campo:focus { outline: none; border-color: var(--primary); }

/* Selects nativos a propósito (teclado, buscar-escribiendo y picker del
   sistema en móvil vienen gratis), con chevron propio en vez del del
   navegador. */
.select-chevron {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23171B21' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 7px center;
  background-size: 14px 14px;
  padding-right: 25px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background-color: #fff;
  font-family: inherit;
  font-size: 13px;
  color: var(--ink);
  padding-top: 6px; padding-bottom: 6px; padding-left: 10px;
}


/* --------------------------------------------------------------------------
   Portada — carrusel de análisis y tablas de lo último
   -------------------------------------------------------------------------- */

/* Mismo lenguaje que el carrusel de highlights del panel: scroller con snap,
   flechas en desktop y difuminado por MÁSCARA en los extremos (no por un
   degradado encima, que obliga a acertarle al color del fondo). */
/* `flow-root` para que el margen negativo de `.an-items` reduzca esta caja en vez
   de COLAPSAR con el margen de acá. Sin esto el margen del hijo se fusiona con el
   del padre —quedaba en 22 + (-36) = -14— y el carrusel crecía 36px: el flujo de
   abajo terminaba en el mismo sitio, así que no se notaba, pero las flechas
   cuelgan de un `top: 50%` de ESTA caja y se movían 18px. */
.an-carrusel { position: relative; margin-bottom: 22px; display: flow-root; }
.an-items {
  --fade-izq: 0px;
  --fade-der: 0px;
  --fade: 56px;
  display: flex;
  gap: 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  /* Aire para que la sombra y el alzado de la card quepan DENTRO del scroller.
     `overflow-x: auto` no deja el otro eje libre: por regla de CSS, si un eje no
     es `visible`, el `visible` del otro computa a `auto`. O sea que este
     contenedor recorta arriba y abajo aunque nadie se lo haya pedido, y se
     llevaba puesta la sombra de las cards —la de reposo baja ~9px y la del hover
     unos 40px— y los 4px que la card sube al levantarse.
     Con `padding-bottom: 8px` no alcanzaba ni para el reposo: el corte se veía
     como una línea dura bajo cada tarjeta.
     Los márgenes negativos devuelven exactamente lo que el padding agregó, para
     que el carrusel siga ocupando lo mismo en la página: el aire es para pintar,
     no para separar. Si se toca uno hay que tocar el otro. */
  padding-top: 6px;
  padding-bottom: 44px;
  margin-top: -6px;
  margin-bottom: -36px;
  scrollbar-width: none;
  transition: --fade-izq .35s ease, --fade-der .35s ease;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-izq),
      #000 calc(100% - var(--fade-der)), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-izq),
      #000 calc(100% - var(--fade-der)), transparent 100%);
}
@media (min-width: 640px) { .an-items { --fade: 112px; } }
.an-items::-webkit-scrollbar { display: none; }

/* 300 y 380 son los anchos de la referencia (`w-[300px] sm:w-[380px]`): con
   260 la miniatura de 320 de viewBox quedaba muy comprimida. */
.an-card {
  scroll-snap-align: start;
  flex: 0 0 auto;
  width: 300px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 22px;
  display: flex;
  flex-direction: column;
  color: var(--ink);
  box-shadow: 0 4px 6px -1px rgba(23, 27, 33, .10), 0 2px 4px -2px rgba(23, 27, 33, .10);
  transition: box-shadow .3s, transform .3s;
}
@media (min-width: 640px) { .an-card { width: 380px; } }
.an-card:hover {
  text-decoration: none;
  transform: translateY(-4px);
  box-shadow: 0 20px 25px -5px rgba(23, 27, 33, .12), 0 8px 10px -6px rgba(23, 27, 33, .10);
}
/* Alto reservado para el título y la bajada: sin esto las tarjetas saltan de
   altura al deslizar, porque los textos tienen largos distintos. */
.an-card-tit { font-size: 18px; font-weight: 700; line-height: 1.25; min-height: 2.5em; }
.an-card-baj {
  font-size: 13px; font-weight: 300; line-height: 1.5;
  color: var(--muted); margin: 8px 0 0; min-height: 4.5em;
}
/* Miniatura: SVG de 320x64 a ancho completo. `mt-4` de la referencia. */
.an-card-viz { margin-top: 16px; }
.an-card-viz svg { display: block; overflow: visible; }
.an-card-nota {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--muted);
  margin: 6px 0 0;
}

.an-card-pie {
  margin-top: auto; padding-top: 12px;
  border-top: 1px solid var(--line);
  display: flex; justify-content: flex-end;
}
.an-card-pie .ir {
  width: 26px; height: 26px; border-radius: 999px;
  border: 1px solid var(--line);
  display: grid; place-items: center;
  font-size: 12px; color: var(--muted);
}
.an-card:hover .an-card-pie .ir { color: var(--primary); border-color: var(--primary); }

.an-carrusel .flecha {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 36px; height: 36px; border-radius: 50%;
  display: none; place-items: center;
  background: #fff; border: 1px solid var(--line);
  box-shadow: 0 1px 2px rgba(23, 27, 33, .06);
  color: var(--muted); cursor: pointer; z-index: 10;
}
@media (min-width: 768px) { .an-carrusel .flecha { display: grid; } }
.an-carrusel .flecha:hover { color: var(--primary); border-color: var(--primary); }
.an-carrusel .flecha.izq { left: -12px; }
.an-carrusel .flecha.der { right: -12px; }


/* Las etiquetas de los KPI reservan DOS líneas. El panel las tenía en una sola
   porque su grilla medía 1180px; al bajar a los 1100 de la norma, «Agenda fuera
   de taxonomía» pasó a envolver y su tarjeta corría el valor y la bajada hacia
   abajo, desalineando los cuatro. Reservar el alto los alinea sin depender del
   ancho ni del largo del texto. */
.kpi-label, .panel-kpi-label { min-height: 2.4em; }


/* --------------------------------------------------------------------------
   Modal de documento
   -------------------------------------------------------------------------- */

/* Mismos valores que el `.modal-*` de dashboard.html, para que el modal sea la
   misma pieza en la portada y en el panel. En las rutas del panel su hoja
   redefine estas clases más abajo en la cascada: los valores coinciden, así que
   da igual cuál gane. `.mh-fila` y `.mh-dt` existen solo acá. */
.modal-bg {
  position: fixed; inset: 0;
  background: rgba(23, 27, 33, .55);
  display: none; align-items: flex-start; justify-content: center;
  z-index: 50; padding: 40px 16px; overflow-y: auto;
}
.modal-bg.open { display: flex; }
/* Con un modal abierto, el fondo NO scrollea. `.modal-bg` es fija y trae su
   propio `overflow-y`, así que la rueda sobre el modal mueve el modal; pero al
   llegar a su tope el gesto se encadenaba a la página y el fondo se movía
   detrás, que es exactamente lo que uno no espera de un modal.
   `overscroll-behavior: contain` corta ese encadenamiento del gesto, y el
   `overflow: hidden` corta el resto de las vías —la barra, las flechas, Page
   Down—. Va sobre `html` Y `body` porque cuál de los dos es el elemento que
   scrollea depende del documento.
   `:has()` en vez de una clase que ponga el JS: hay tres aperturas distintas
   —el modal de documento del panel, el de las páginas estáticas y el de
   análisis— y las tres ya marcan `.open` sobre `.modal-bg`. Una sola regla las
   cubre y no queda un estado que se pueda desincronizar si alguna cierra por un
   camino que nadie acordó. */
.modal-bg { overscroll-behavior: contain; }
html:has(.modal-bg.open),
html:has(.modal-bg.open) body { overflow: hidden; }
.modal {
  background: #fff; border-radius: 14px; max-width: 760px; width: 100%;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .25);
}
.modal-head { padding: 24px 28px 18px; border-bottom: 1px solid var(--line); position: relative; }
.modal-head h3 { font-size: 20px; font-weight: 800; margin: 0 0 6px; padding-right: 36px; }
.modal-head .mh-meta {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px; color: var(--muted);
}
.modal-close {
  position: absolute; top: 18px; right: 20px;
  background: var(--bg); border: 0; width: 30px; height: 30px;
  border-radius: 8px; cursor: pointer; font-size: 18px; color: var(--muted); line-height: 1;
}
.modal-close:hover { background: var(--line); color: var(--ink); }
.modal-body { padding: 22px 28px 26px; }

/* La fecha a la izquierda y el enlace al documento a la derecha, en la misma
   línea. `gap` y `wrap` para que a 320px el enlace baje en vez de desbordar. */
.mh-fila {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; padding-right: 36px;
}
/* Hipervínculo y no botón: es una salida del sitio, no la acción principal del
   modal. Subrayado para que se lea como enlace sin depender del color. */
.mh-dt {
  font-size: 12.5px;
  color: var(--primary);
  text-decoration: underline;
  white-space: nowrap;
  flex: none;
}
.mh-dt:hover { color: var(--blue-dark); }
.mh-dt[hidden] { display: none; }

/* Nota del extracto recortado. Mono chico y apagado: es una advertencia sobre
   la procedencia del dato, no parte del texto del documento.
   El selector lleva `.ms` adelante a propósito. Sin él —`.nota-extracto` a
   secas, 0,1,0— perdía contra `.ms p` (0,1,1), que está más abajo en este mismo
   archivo, y la nota terminaba saliendo en mono a 14px y en #374151: heredaba
   la familia de acá y el tamaño y el color de allá, o sea ni una cosa ni la
   otra. Se veía como un párrafo más del documento, que es justo lo que no es.
   La versión sin `.ms` queda para cualquier otro contexto. */
.ms .nota-extracto,
.nota-extracto {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px; line-height: 1.5;
  letter-spacing: .06em;
  color: var(--muted);
  margin: 0 0 14px;
}

/* Secciones de la ficha, colapsables y en una sola tarjeta.
   `<details>` nativo y no un toggle propio: trae el estado, el teclado, el foco
   y el «buscar en la página» del navegador —Chrome abre el `details` para
   mostrar una coincidencia, así que el texto sigue siendo alcanzable— sin una
   línea de JS, y sin JS igual funciona.
   El padding vertical lo pone cada sección y no la tarjeta: si lo pusiera la
   tarjeta, la línea divisoria de la primera y la última quedaría separada del
   borde. */
.ficha-secciones { padding-top: 0; padding-bottom: 0; }
/* La línea gris clara entre secciones. Va como `border-top` del segundo en
   adelante, así no sobra una línea al final. */
.ficha-secciones > * + * { border-top: 1px solid var(--line); }
/* La misma línea para las secciones de un modal. Ahí las secciones son `.ms`
   —convertidas a `<details>` por `ui/menu.js`— y son hijas directas del cuerpo
   del modal, así que el separador se pide sobre ese contenedor. El
   `margin-bottom: 20px` que trae `.ms` sobra cuando hay línea y padding. */
.modal-body > .sec + .sec,
.modal-body > .sec + .sec-fija,
.modal-body > .sec-fija + .sec { border-top: 1px solid var(--line); }
.modal-body > .sec, .modal-body > .sec-fija { margin-bottom: 0; }
/* Dentro del modal el h4 hace de título de sección, igual que el .section-tag
   en la ficha: sin margen para que no descentre la fila del summary. */
.sec > summary h4 { margin: 0; }
.sec > summary {
  list-style: none;
  cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 16px 0;
}
.sec > summary::-webkit-details-marker { display: none; }
/* El `.section-tag` trae `margin-bottom: 6px` para cuando encabeza un bloque;
   dentro del summary es un elemento de una fila flex y el margen la descentra. */
.sec > summary .section-tag { margin: 0; }
.sec > summary .chev { flex: none; color: var(--muted); transition: transform .15s; }
.sec[open] > summary .chev { transform: rotate(180deg); }
.sec > summary:hover .section-tag,
.sec > summary:hover .chev { color: var(--blue-dark); }
.sec > summary:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.sec .sec-cuerpo { padding-bottom: 18px; }
/* Las que no se colapsan llevan el mismo ritmo vertical que un summary. */
.sec-fija { padding: 16px 0 0; }

/* «Dictámenes que cita», al pie de la ficha de un ordinario. Los ítems son
   cortos —«Dictamen 84/4»— y en una sola columna dieciocho de ellos son
   dieciocho renglones de aire al final de la página. Se reparten en hasta tres
   columnas según el ancho: una en teléfono, dos desde 640, tres desde 1024.
   `break-inside: avoid` para que un ítem no quede cortado entre dos columnas.
   El marcador va `inside` y no `outside`: con `outside` la viñeta se posiciona
   fuera del cuadro del ítem y en las columnas 2 y 3 caía sobre la columna
   anterior. Los ítems no envuelven, así que la sangría de continuación que
   `inside` no da no se echa de menos. */
.lista-citas {
  margin: 0;
  padding: 0;
  list-style-position: inside;
  column-gap: 28px;
}
@media (min-width: 640px)  { .lista-citas { column-count: 2; } }
@media (min-width: 1024px) { .lista-citas { column-count: 3; } }
.lista-citas li { break-inside: avoid; margin-bottom: 6px; }

/* La ficha traída al modal. Sus secciones son `.card` —tarjeta blanca con
   borde, radio y 28px de padding—, que dentro del modal quedarían como cajas
   anidadas dentro de otra caja. Acá se aplanan: el modal ya ES la tarjeta. Se
   conserva el separador entre secciones, que es lo que el borde daba.
   No se toca `.card` en general: el aplanado vale solo dentro del modal. */
.ficha-modal .card {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin: 0 0 18px;
}
.ficha-modal .card + .card { border-top: 1px solid var(--line); padding-top: 18px; }
.ficha-modal .card:last-child { margin-bottom: 0; }
/* El botón a la DT queda igual que en el modal de las otras vistas: un enlace
   al pie de su sección, no un botón azul de ancho completo dentro del modal.
   El `border: 0` es lo que faltaba: `.btn-primary` trae `border: 1px solid
   var(--primary)` y al quitarle el fondo el borde quedaba solo, dibujando un
   recuadro azul vacío alrededor del texto. Sin fondo no hay botón, y sin botón
   no hay borde. */
.ficha-modal .btn-primary {
  background: none;
  border: 0;
  color: var(--primary);
  padding: 0;
  text-decoration: underline;
  font-size: 12.5px;
  box-shadow: none;
}
.ficha-modal .btn-primary:hover { color: var(--blue-dark); background: none; }

/* La nota del extracto y la salida al documento de la DT, en una línea: la nota
   dice que el texto completo está en la DT y el enlace es eso mismo. El enlace
   se alinea a la derecha del texto; `baseline` para que el mono de 10 y el
   enlace de 12.5 se apoyen en el mismo renglón, y `wrap` para que a 320px baje
   en vez de desbordar. Cuando el documento no trae nota, la fila queda con solo
   el enlace y `margin-left: auto` lo mantiene a la derecha. */
.nota-fila {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  margin-top: 10px;
}
.nota-fila .nota-extracto { margin: 0; flex: 1 1 12rem; }
.nota-fila .mh-dt { margin-left: auto; }
.nota-fila .nota-dt-slot { display: contents; }

/* Secciones del modal de documento. Mismos valores que en dashboard.html, para
   que el modal de la portada y el del panel sean la misma pieza: en el panel su
   hoja las redefine más abajo en la cascada, y coinciden.
   `.ms` = «modal section». El nombre viene del panel y se conserva: renombrarlo
   obligaría a tocar el archivo fuente, que es justamente lo que no se toca. */
.ms { margin-bottom: 20px; }
.ms h4 {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px; text-transform: uppercase; letter-spacing: .1em;
  color: var(--primary);
  margin: 0 0 7px;
}
.ms p { font-size: 14px; color: #374151; font-weight: 300; line-height: 1.55; margin: 0; }
/* Cita destacada: la pregunta que originó el documento. */
.ms .quote {
  background: #F7F9FC;
  border-left: 3px solid var(--primary);
  border-radius: 0 8px 8px 0;
  padding: 12px 16px;
  font-size: 13.5px;
  color: #1F2937;
}
.pills { display: flex; flex-wrap: wrap; gap: 6px; }
.pill {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  background: var(--bg);
  border-radius: 6px;
  padding: 4px 9px;
  color: #374151;
}
/* El badge del tipo de documento, al lado del título del modal. */
.modal-head .badge { vertical-align: middle; }
.badge.ofi { background: var(--bg); color: var(--muted); }
.badge.ext { background: var(--blue-light); color: var(--primary); }

/* Sugerencias del buscador del header. */
/* Las reglas de `.sug` (la lista de sugerencias del buscador del header) se
   fueron con el input: el header ahora es un enlace a /buscador/. */
/* Con las sugerencias abiertas el campo no puede seguir colapsado en móvil. */
@media (max-width: 1023px) {
}

/* --------------------------------------------------------------------------
   Franja de estado en pantalla angosta: una línea que rota
   -------------------------------------------------------------------------- */

/* Las dos piezas no caben juntas bajo 640px, y apilarlas duplicaba el alto de la
   franja. Se muestra una a la vez y ui/menu.js las alterna, así el alto queda
   fijo en una línea y no se pierde ninguno de los dos datos.
   El separador «·» sobra cuando solo hay una pieza a la vista. */
@media (max-width: 639px) {
  .topbar .barra { justify-content: center; gap: 6px; }
  .topbar .sep { display: none; }
  .topbar .rota {
    display: none;
    opacity: 0;
    transition: opacity .3s ease;
    /* Si el texto igual no cupiera en un teléfono muy angosto, se recorta con
       ellipsis en vez de desbordar la página. */
    overflow: hidden; text-overflow: ellipsis; max-width: calc(100vw - 60px);
  }
  .topbar .rota.activa { display: inline; opacity: 1; }

  /* Con `prefers-reduced-motion` no se rota: se vuelve a las dos líneas. Un
     texto que cambia solo es movimiento, y perder uno de los dos datos para
     evitarlo sería peor que ocupar una línea más. */
  @media (prefers-reduced-motion: reduce) {
    .topbar .barra { flex-wrap: wrap; }
    .topbar .rota { display: inline; opacity: 1; max-width: none; }
    .topbar .sep { display: inline; }
  }
}

/* --------------------------------------------------------------------------
   Botón flotante «volver arriba»
   -------------------------------------------------------------------------- */

/* Solo en pantalla angosta: en desktop el scroll es de rueda y el header queda
   pegado arriba, así que no hace falta. Lo muestra ui/menu.js después de
   scrollear, no de entrada — un botón para volver arriba cuando ya estás arriba
   es ruido.
   `bottom` con safe-area para que en un iPhone no quede bajo la barra de gestos. */
.btn-arriba {
  position: fixed;
  right: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  z-index: 45;
  width: 44px; height: 44px;   /* target táctil de §6 */
  display: none;
  align-items: center; justify-content: center;
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  border: 0;
  box-shadow: 0 6px 18px rgb(0 0 0 / .22);
  cursor: pointer;
  opacity: 0;
  transition: opacity .2s ease, transform .2s ease;
}
.btn-arriba[hidden] { display: none; }
.btn-arriba.visible { display: flex; opacity: 1; }
.btn-arriba:active { transform: scale(.94); }
.btn-arriba:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
@media (min-width: 640px) { .btn-arriba { display: none !important; } }

/* --------------------------------------------------------------------------
   Ajustes de pantalla angosta sobre piezas del panel
   -------------------------------------------------------------------------- */

/* El globo de explicaciones (#tt) —el que traduce el selector de idioma— se
   define ACÁ y no en el <style> de dashboard.html, que es de dónde venía.
   Mientras estuvo allá, solo existía en las rutas que envuelven el panel; en la
   portada el motor lo creaba y salía como un <div> sin estilo al final del
   <body>. Junto con el `display:none !important` que tenía puesto
   `OVERRIDES_PANEL`, el resultado era que la glosa no se veía en NINGUNA página:
   el selector de idioma cambiaba un texto que nadie miraba.

   Se oculta en pantallas sin puntero fino en vez de ocultarse siempre. El
   problema real que motivó aquel `display:none` era de touch: el panel abría la
   glosa con `mouseenter` Y con `focus`, y en un teléfono el tap que cambia de
   sub-pestaña le da foco al botón, así que el globo aparecía tapando justo el
   contenido recién pedido. Eso se arregla no mostrándolo donde no hay hover
   —acá— y no disparándolo con un foco que viene de un tap —ui/i18n.js usa
   `:focus-visible`—. Con las dos cosas, el teclado sigue teniendo la glosa y el
   dedo ya no se la come. */
#tt {
  position: fixed;
  z-index: 200;
  max-width: 340px;
  background: var(--ink);
  color: #E9EDF3;
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 12.5px;
  line-height: 1.5;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .22);
  /* Sin esto el globo se interpone entre el cursor y el elemento que lo abrió, y
     al moverse un pixel se dispara el mouseout: parpadeo permanente. */
  pointer-events: none;
  opacity: 0;
  transition: opacity .12s;
}
#tt.on { opacity: 1; }
#tt[hidden] { display: none; }
#tt .tt-t {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: #8FB8F0;
  margin-bottom: 6px;
}
/* Ni hover ni puntero fino: teléfonos y tablets. Ahí la glosa no se puede pedir
   —no hay «pasar el cursor»— así que solo puede estorbar. */
@media (hover: none), (pointer: coarse) {
  #tt { display: none !important; }
}

/* El heatmap de gobiernos no viene envuelto en un contenedor con scroll y a
   ancho de teléfono se sale de su tarjeta. Se le da el scroll horizontal que la
   norma pide para toda tabla ancha (§5.4), en vez de dejar que desborde. */
#heatmap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* «Últimos deja sin efecto» y «Doctrina modificada»: la materia ENVUELVE.
   Antes se recortaba a `22ch` con ellipsis, y el comentario que estaba acá lo
   justificaba diciendo que así todas las filas medían lo mismo. No era cierto:
   de las siete columnas, solo las cinco primeras traen `white-space: nowrap`
   inline desde `dashboard.html`; «Solicitó» no, así que ya envolvía —«Trabajador
   con sindicato» son dos líneas— y el alto de fila ya era variable. La
   uniformidad que la regla decía proteger no existía, y el recorte de la materia
   se pagaba a cambio de nada.
   Peor: el recorte tampoco se podía leer. `.mtable` es `width: 100%`, así que
   con la materia capada la tabla medía exactamente el ancho de su contenedor
   —994px medidos— y el `overflow-x: auto` del div que la envuelve nunca tenía
   nada que scrollear. Faltaban 77px de las materias más largas (110 caracteres,
   que es donde el dato ya viene cortado en origen) sin ningún gesto que los
   alcanzara.
   Con `normal` la materia se lee completa en dos o tres líneas, en la misma
   celda, sin scroll horizontal en desktop. En angosto la tabla igual desborda
   —las cinco columnas `nowrap` no se comprimen— y para eso está el
   `overflow-x` del wrapper más la primera columna pegada, más abajo.
   El `width: auto; min-width: 100%` deja que crezca cuando el contenido lo
   pide y que ocupe el ancho completo cuando no. */
#tRevTable, #tModifTable { width: auto; min-width: 100%; }
#tRevTable tbody tr:not(.rev-det) td:last-child,
#tModifTable tbody tr:not(.rev-det) td:last-child {
  max-width: none;
  overflow: visible;
  white-space: normal;
}

/* La fila de detalle («Decía» / «Dice ahora» / «Por qué») queda FUERA de todo lo
   anterior. Su contenido es un solo `<td colspan="7">`, o sea el primer y también
   el ÚLTIMO hijo de su fila; y `.rev-det` nunca recibe `.open` —esa clase la
   pone el panel en la fila de arriba, la que se clickea—, así que caía de lleno
   en la regla de colapso: se llevaba el `max-width: 22ch`, el `overflow: hidden`
   y, lo que de verdad rompía, el `white-space: nowrap`, que los tres bloques
   `.rd` heredan. Resultado medido: hasta 261 caracteres en UNA línea dentro de
   una celda recortada a 148px. El `:not(.rev-det)` de arriba es el arreglo; esto
   es explícito para que no vuelva a pasar por otra vía. */
#tRevTable tbody tr.rev-det td,
#tModifTable tbody tr.rev-det td {
  max-width: none;
  overflow: visible;
  white-space: normal;
}

/* Con la materia entera estas tablas miden 1139px, y en un teléfono eso son
   ~850px de scroll horizontal: sin una columna que ancle, a mitad de camino ya
   no se sabe de qué documento es la fila que se está leyendo. Se pega la
   primera —el número del dictamen, que es su identidad— igual que en las tablas
   de la portada y los listados. Mismo corte que esas: 767px.
   La fila de detalle se excluye a mano: su `<td colspan>` es también
   `:first-child` y pegarlo dejaría el bloque «Decía / Dice ahora / Por qué»
   clavado a la izquierda mientras el resto se mueve. */
@media (max-width: 767px) {
  #tRevTable thead th:first-child,
  #tModifTable thead th:first-child,
  #tRevTable tbody tr:not(.rev-det) td:first-child,
  #tModifTable tbody tr:not(.rev-det) td:first-child {
    position: sticky;
    left: 0;
    background: #fff;
    box-shadow: 1px 0 0 var(--line);
  }
}

/* --------------------------------------------------------------------------
   Tablas en pantalla angosta
   -------------------------------------------------------------------------- */

@media (max-width: 639px) {
  /* El pie de tabla queda en UNA línea: contador a la izquierda, navegador y
     selector a la derecha. Con `wrap` se partía en dos y el bloque medía el
     doble de alto que la última fila de la tabla. */
  .tabla-pie { flex-wrap: nowrap; gap: 8px; }
  .tabla-pie .derecha { gap: 6px; flex: none; }
  .tabla-pie .cuenta { flex: none; }
  .paginacion { gap: 2px; flex-wrap: nowrap; }
  .paginacion .celda { min-width: 28px; padding: 0 4px; }
  .tabla-pie .filas-drop > summary { padding: 5px 6px; font-size: 12px; gap: 4px; }

  /* De los números de página quedan la ACTUAL y la SIGUIENTE. El resto
     reaparece al avanzar, porque `data-rel` se recalcula respecto de la nueva
     página actual. Los «…» sobran cuando no hay saltos a la vista.
     Se seleccionan por `[data-rel]` —solo lo llevan las celdas de número— así
     que «Anterior» y «Siguiente» no se tocan. */
  .paginacion .celda[data-rel] { display: none; }
  .paginacion .celda[data-rel="0"],
  .paginacion .celda[data-rel="1"] { display: inline-flex; }
  .paginacion .puntos { display: none; }

  /* UNA barra de scroll para toda la tabla, y solo la primera columna pegada.
     Antes acá la tabla medía exactamente el ancho de la pantalla
     (`table-layout: fixed; width: 100%`) y el ajuste lo pagaba el contenido:
     las columnas cortas recortadas con ellipsis —el eje quedaba en «Fiscali…»,
     el número en «ORDINAR…»— y la materia con su PROPIO `overflow-x`, un
     scroll por fila. Y con la tabla clavada al viewport el `position: sticky`
     de la primera columna no hacía nada: sin desborde no hay de qué pegarse,
     así que las cuatro columnas se veían igual de fijas y ninguna se leía
     completa. Era lo peor de los dos mundos: nada scrolleaba junto y nada
     entraba.
     Ahora la tabla mide lo que mide su contenido y desborda el `overflow-x`
     del div que la envuelve —el `:has(> .data-table)` de §5.4—, que es el que
     scrollea. Ahí sí la primera columna se pega, y es lo que la vuelve
     legible: el número del documento queda a la vista mientras se recorre la
     fila hasta la materia. `min-width: 100%` para que una tabla angosta siga
     ocupando el ancho y no quede flotando a la izquierda. */
  .data-table { table-layout: auto; width: auto; min-width: 100%; }
  /* Sin anchos y sin ellipsis: cada columna mide lo que necesita. `nowrap` en
     todas menos la última para que el scroll horizontal sea el único eje de
     lectura —una fecha o un eje envueltos suman una línea a la fila— y para que
     ninguna quede recortada. */
  .data-table th:not(:last-child), .data-table td:not(:last-child) {
    white-space: nowrap;
  }
  .data-table th, .data-table td { padding-left: 8px; padding-right: 8px; }
  /* La materia envuelve, con piso. En `nowrap` una materia de 120 caracteres
     estiraba la tabla a ~900px y el scroll se volvía interminable; sin piso, el
     layout automático le daba su min-content —el largo de la palabra más
     larga, ~100px— y la fila se volvía una columna de párrafo. Con 260px la
     tabla queda en ~620 y la materia se lee en dos o tres líneas.
     Solo en las tablas de documento (`.compacta`): la tabla clave/valor de la
     ficha no tiene materia y forzarle 260px le agregaría scroll sin razón. */
  .data-table.compacta td:last-child, .data-table.compacta th:last-child {
    min-width: 260px; white-space: normal;
  }
  /* Las filas desplegadas sí envuelven: ahí el texto completo es el punto. */
  .data-table tr.open td:last-child { overflow: visible; white-space: normal; }
}

/* --------------------------------------------------------------------------
   Selector de idioma en el footer (pantalla angosta)
   -------------------------------------------------------------------------- */

/* `min-height` del alto del wordmark (46px): si el SVG del CDN no carga, la
   marca cae al texto de respaldo —que mide menos— y la bajada subía, perdiendo
   la alineación con «Explorar». Con el piso puesto, el layout no depende de que
   un asset cross-origin llegue. */
.site-footer .marca-fila {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  min-height: 46px;
}
/* El selector de idioma a la derecha de la fila. `menu.js` lo trae acá en
   pantalla angosta —en el header no cabe junto a la lupa y la hamburguesa— y
   pegado al wordmark se leía como parte de la marca. En ancho el contenedor va
   `:empty` y no se ve, así que la regla solo actúa donde el selector existe. */
.site-footer .footer-lang { margin-left: auto; }
.site-footer .footer-lang:empty { display: none; }
/* Dentro del footer el globo va en claro sobre el fondo oscuro, y el panel abre
   hacia ARRIBA: el footer es lo último de la página y hacia abajo no hay lugar. */
.site-footer .lang-drop > summary { color: rgba(255, 255, 255, .7); }
.site-footer .lang-drop > summary:hover,
.site-footer .lang-drop[open] > summary { color: #fff; background: rgba(255, 255, 255, .08); }
.site-footer .lang-drop { position: relative; }
/* Solo se invierte el eje VERTICAL. El `left: 0; right: auto` que había acá
   venía de cuando el selector se apoyaba en el wordmark, a la izquierda de la
   fila: desde que va pegado a la derecha, abrir hacia la derecha manda el panel
   fuera de la pantalla y se corta. Sin esas dos declaraciones vale el `right: 0`
   de la regla base y el panel crece hacia adentro, que es lo correcto para un
   disparador anclado a la derecha. */
.site-footer .lang-drop .panel {
  top: auto; bottom: calc(100% + 8px);
}

/* La frescura del dato, primera columna del footer, bajo la bajada. Antes vivía
   en la franja negra sobre el header; el CSS de allá no sirve acá porque la
   franja era una línea centrada que no envuelve, y en una columna de 5/12 esto
   tiene que apilarse. */
.site-footer .frescura {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 14px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  line-height: 1.5;
  color: rgba(255, 255, 255, .55);
}
.site-footer .frescura b { color: rgba(255, 255, 255, .9); font-weight: 600; }
/* El punto verde acompaña a «última revisión»: es lo que dice que el dato está
   vivo. Va dentro del <span> para que no se separe de su frase al envolver. */
.site-footer .frescura .dot {
  display: inline-block;
  width: 6px; height: 6px; border-radius: 50%;
  background: #10B981;
  margin-right: 7px;
  vertical-align: middle;
}

/* --------------------------------------------------------------------------
   Aviso de traducción automática
   -------------------------------------------------------------------------- */

/* Solo se ve con un idioma distinto del español activo y con el corpus
   traducido: lo destapa ui/i18n.js. Tono de nota, no de error —la traducción es
   una función del sitio, no una falla—, pero con el peso suficiente para que se
   lea antes que el texto que califica. */
.i18n-aviso {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: 1200px;
  margin: 0 auto;
  padding: 10px 16px;
  font-size: 12.5px;
  line-height: 1.45;
  color: #8A5A00;
  background: #FFF8E6;
  border-bottom: 1px solid #F2E2B8;
}
.i18n-aviso[hidden] { display: none; }
.i18n-aviso svg { flex: none; }
@media (min-width: 640px) { .i18n-aviso { padding: 10px 24px; } }

/* --------------------------------------------------------------------------
   Buscador del header expandido sobre la marca — ELIMINADO
   --------------------------------------------------------------------------

   Acá vivía el bloque que, al tocar la lupa bajo 1024px, escondía el wordmark y
   le daba el ancho del header al campo (el `expandFill` de la referencia). Se
   fue con el input: el header ahora es un enlace a /buscador/, así que nadie
   pone la clase `.abierto` y todas esas reglas eran letra muerta que se leía
   como funcionalidad viva.
   -------------------------------------------------------------------------- */

}
