/* Toolbar transversal de listas (ListToolbar) — asset COMPARTIDO del RCL InsCore.Ui.Gadgets.
   Self-contained con var(--token, fallback): en el broker toma sus tokens; en cliente/Backoffice cae
   al fallback neutro. **ESTA ES LA ÚNICA DECLARACIÓN de `.app-list-toolbar*` del repo** (M-137): los
   tres hosts enlazan este fichero y encima solo ponen overrides (el Backoffice, los responsive de xs).
   Antes el broker llevaba su propia copia en `theme.css` porque era el ÚNICO host que no enlazaba este
   asset — esa era la causa de la duplicación, no un descuido de estilo: sin el enlace, la copia era
   obligatoria. Si vuelves a necesitar una copia aquí, mira primero el `App.razor` de tu host. */
/* ── 📐 s122 · M-783 · LA BARRA ES UNA COLUMNA DE BANDAS, Y CADA BANDA TIENE SU TRABAJO ────────────
   🔴 Reportado por él con `/policies` delante (30-ago-2026): *«hacer algo bien responsive, que no salten
   los botones de aquí para allá»* y *«mira cómo queda "Agrupar por" solito»*.

   🌳 LA CAUSA: búsqueda, filtros, conteo, agrupador, columnas y densidad eran hermanos de UNA fila que
   envuelve, así que el punto de corte lo decidía el ancho sobrante y cada control saltaba por su cuenta al
   redimensionar. Con la barra en COLUMNA, la cabecera (`__head`) envuelve sola y el grupo de VISTA
   (`__view`) va pegado a la derecha con `margin-left: auto`: sus cuatro controles saltan JUNTOS de renglón
   o no salta ninguno. El resumen y el panel son bandas propias debajo, con el ancho entero.

   ⚠️ `align-items: stretch` no es cosmético: en columna, el `center` de antes encogería cada banda a su
   contenido y el `margin-left:auto` de `__view` dejaría de tener sitio donde empujar. Y `flex-wrap: nowrap`
   se escribe explícito porque envolver una columna sin alto declarado no significa nada. */
.app-list-toolbar {
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 8px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--glass-border, rgba(148, 163, 184, 0.18));
}

/* La cabecera es la FILA que envuelve; lo que era la barra entera es ahora esta banda. */
.app-list-toolbar__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* 👁️ LOS CONTROLES DE VISTA VIAJAN JUNTOS. Conteo, agrupador, columnas y densidad no acotan el conjunto:
   reordenan la MIRADA. Agrupados en un solo hijo con `margin-left: auto` ocupan el sobrante de la
   cabecera, y si no caben bajan de renglón LOS CUATRO — que es lo que impide el salto que él fotografió.
   Sustituye al `<MudSpacer />` que separaba a mano un reparto que nadie gobernaba. */
.app-list-toolbar__view {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-left: auto;
}

.app-list-toolbar__search {
    min-width: 280px;
    flex: 1 1 280px;
    max-width: 420px;
}

/* ── 🧵 M-696 · LA BANDA DE FILTROS ENVUELVE; NO SE DESPLAZA EN NINGÚN EJE ─────────────────────────
   Reportado por él con captura sobre `/policies` (25-ago-2026): «no podemos tener scroll para un
   filtro… hacer scroll para ver los campos de un filtro no está bien, eso ha sido una regresión y
   entiendo que esto es transversal a todos los componentes». Lo es, y con su censo (26-ago-2026): **30
   pantallas** de los tres hosts montan `ListToolbar` y **19 de ellas** le pasan slot de `Filters`, que
   son exactamente las que pintan esta banda.

   🌳 QUÉ HABÍA AQUÍ Y POR QUÉ ERA EL DEFECTO, no un ajuste fino. M-022 acotó la banda a
   `max-height: 6rem` —dos renglones de control denso, 40px + 8px de hueco— con `overflow-y: auto`,
   «así el tope existe sin que ningún filtro quede inalcanzable». Esa cifra es de la MISMA FAMILIA que
   la resta de 22rem que M-207 mató: sale de medir UNA composición. Los nueve filtros de la cartera
   declaran 130+170+170+130+150+140+160+140+130 px de mínimo, más ocho huecos de 8 → la banda pide
   ~1.400 px de ancho, o sea TRES renglones a 1280, y el tercero quedaba detrás de un scroll de 96 px
   de alto. Un control que hay que buscar arrastrando es un control que no existe.

   ⚖️ SE REPARTE EL VERTICAL, NO SE ACHICAN LOS CAMPOS — decisión escrita en M-696, y por dos razones
   que no caducan: el ancho es un recurso FIJO (cada filtro nuevo vuelve a romperlo, la fila N+1 cabe
   siempre) y achicar CORTA ETIQUETAS —«Colaborador externo», «Estado del contrato»—, que es texto que
   el corredor LEE para saber qué está filtrando.

   🚦 EL TOPE NO DESAPARECE: CAMBIA DE SITIO, del número tecleado al reparto medido. Quien impide que
   el cromo empuje la rejilla fuera de la pantalla es la escalera acotada de M-207/M-574 —el papel de
   aquí abajo y la columna flex de `insLayout.css`—, que mide el cromo REAL de cada pantalla en vez de
   suponerle dos renglones. Y su peor caso es el bueno: la página vuelve a rodar, jamás «hay un filtro
   al que no se llega». El camino para esconderlos sigue siendo el que ya existe y es SUYO: el pliegue
   del botón «Filtros» del propio ListToolbar, que además se recuerda por tabla.

   🔒 LAS DOS DECLARACIONES QUE GARANTIZAN EL CERO HORIZONTAL, y ninguna sobra:
   · `min-width: 0` en la banda — el `overflow` que se va le regalaba un mínimo automático de CERO (un
     elemento flex con `overflow` distinto de `visible` puede encoger a nada). Al quitarlo, su mínimo
     vuelve a ser el min-content y la banda EMPUJARÍA la barra a lo ancho: hay que reponerlo a mano.
   · `max-width: 100%` en cada campo — ningún filtro puede ser más ancho que la banda que lo envuelve,
     así que la envoltura siempre tiene a dónde envolver. Es lo que hace imposible la barra horizontal
     que él fotografió, venga el campo con el mínimo que venga tecleado en su pantalla (hay ONCE
     valores distintos repartidos por 22 ficheros: 130, 140, 150, 160, 170, 180, 190, 200, 220, 260,
     280 px). Esta regla los cubre a los once sin tocar ninguno.

   Los popover de los MudSelect no se recortan aquí: MudBlazor los teletransporta a su proveedor en la
   raíz del documento, fuera de este contenedor. */
/* ── 📐 s120 · M-782 · LA BANDA ES UNA REJILLA, NO UNA FILA QUE ENVUELVE ───────────────────────────
   🔴 Reportado por él con captura sobre `/policies` (30-ago-2026): *«quedaron feos y desorganizados los
   filtros, no se aprovecha el espacio; eso es transversal en todos los bloques de filtro de listado»*.

   🌳 LA RAÍZ NO ERA EL ENVOLVER: era que CADA PANTALLA TECLEA EL ANCHO DE SU FILTRO. El comentario de
   M-696, aquí arriba, ya lo dejó censado sin llamarlo defecto — **once valores distintos repartidos por
   22 ficheros** (130, 140, 150, 160, 170, 180, 190, 200, 220, 260, 280 px)—. Con anchos dispares, una
   fila que envuelve reparte MAL por construcción: cada renglón corta donde le toca y deja un sobrante
   distinto a la derecha, así que los campos no se alinean entre renglones y el hueco final cambia de
   tamaño en cada uno. Eso es exactamente lo que se ve en su captura: cinco campos arriba con cuatro
   anchos distintos, tres abajo, y aire muerto al final de las dos.

   ⇒ Se sustituye el reparto por una REJILLA de columnas iguales que se auto-ajusta al ancho:
   `repeat(auto-fit, minmax(220px, 1fr))`. Con eso, y sin una sola media query, (a) todos los campos
   miden lo mismo, (b) los renglones quedan alineados en columnas, y (c) el sobrante se reparte entre
   los campos en vez de acumularse al final — que es literalmente «aprovechar el espacio».

   ⚖️ LO QUE M-696 GANÓ SIGUE GANADO, y esto es lo que hace admisible el cambio: se sigue REPARTIENDO EL
   VERTICAL sin achicar campos por debajo de lo legible (220 px es más que ocho de los once mínimos
   tecleados), no hay tope de alto ni scroll dentro de la banda, y por tanto no vuelve el defecto que él
   fotografió el 25-ago —«hacer scroll para ver los campos de un filtro»—.

   🔒 `!important` SOBRE `min-width`, y no por comodidad: esos once anchos viajan como `Style=` INLINE en
   las pantallas, y un estilo inline sólo lo puede neutralizar esto. La alternativa —barrer 22 ficheros—
   dejaría el mismo defecto vivo el día que alguien teclee el número doce, mientras que la rejilla es una
   sola declaración que los cubre a todos, presentes y futuros. Es la misma vía, con el mismo motivo, que
   el Backoffice ya usa en su responsive de `xs`.

   📌 `flex: 1 1 100%` porque la banda es hija del toolbar flex: reclama su propio renglón entero en vez
   de compartirlo con la búsqueda y el botón del pliegue. Sin esto, la rejilla arrancaría en el ancho
   sobrante de la primera línea y volvería a repartir sobre una medida que no es la de la pantalla. */
/* ⚠️ 📐 s122 · M-783 · `flex: 1 1 100%` → `flex: 0 0 auto`, Y NO ES UN AJUSTE FINO. Ese `100%` es
   flex-basis, o sea la medida SOBRE EL EJE PRINCIPAL del padre. Escrito para un padre en FILA quería decir
   «un renglón entero»; con el padre en COLUMNA (arriba) el eje principal es el vertical y pasaría a
   significar «alto = 100% de la barra», que es una caja vacía empujando la tabla fuera de la vista. Es la
   MISMA clase de defecto que ya se pagó aquí en el commit 7897ce597 —una medida de ancho escrita en
   `Style` que caía en el eje equivocado y dejaba 260 px de hueco—, y afecta a los 17 listados que todavía
   pintan esta banda, no solo a los migrados. `0 0 auto` la deja con su alto de contenido y el ancho
   entero, que es lo que la rejilla de abajo necesitaba desde el principio.

   🔬 MEDIDO EN NAVEGADOR (Chrome headless, 1280×800, DOM real de un listado HEREDADO —`/persons`, cuatro
   controles en el slot `<Filters>`— contra estas dos hojas y `insLayout.css`), y sale más matizado de lo
   que decía el párrafo de arriba, así que queda escrito lo que se midió y no lo que se razonó:
   · HOY NO ESTALLA. La barra es hija de `.ins-listado`, y ahí `.ins-listado > * { flex: 0 0 auto }` la
     deja con ALTO INDEFINIDO; un `flex-basis` en porcentaje contra un principal indefinido se resuelve
     como `auto`, así que con las dos reglas la medida es IDÉNTICA: banda 1212×40 px, barra 109 px, tabla
     273 px visibles. Los 17 heredados no cambian ni un píxel.
   · PERO ES UNA BOMBA ARMADA. Basta con que la barra reciba un alto DEFINIDO —lo que hace cualquier día
     un peldaño nuevo de la escalera acotada— para que el porcentaje resuelva: con `1 1 100%` la banda
     pasa a 1212×252 px (212 px de caja VACÍA empujando la tabla), y con `0 0 auto` se queda en 1212×40.
   ⇒ El cambio no arregla un defecto vivo: quita el que se activaba solo, sin que nadie tocara esta regla.
   (Es la clase «un defecto se agrava sin que nadie lo toque porque cambió su ENTRADA» — aquí la entrada
   era la dirección del padre.) */
.app-list-toolbar__filters {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    align-items: center;
    gap: 8px;
    min-width: 0;
    flex: 0 0 auto;
}

.app-list-toolbar__filters > * {
    min-width: 0 !important;
    max-width: 100%;
    width: 100%;
}

/* El rótulo del pliegue no se encoge nunca: si se corta, deja de decir qué hace (familia de M-172). */
.app-list-toolbar__filters-toggle {
    flex: 0 0 auto;
}

/* 📐 s120 · M-782 · El AGRUPADOR tiene un ancho suyo y no reparte. Es un desplegable de una palabra, y
   dejarlo crecer en el reparto flex de la barra lo convertía en una caja de media pantalla en cuanto
   envolvía a un segundo renglón — que es lo que ocurre en cuanto la lista lleva búsqueda, pliegue de
   filtros, conteo, columnas y densidad, o sea siempre en las listas cargadas. Lo mismo que ya hacen el
   rótulo del pliegue y el conteo, dicho para el único hijo de la barra al que le faltaba. */
.app-list-toolbar__group {
    flex: 0 0 auto;
    width: 220px;
    max-width: 100%;
}

/* ── 📌 M-783 · EL PANEL DE FILTROS Y SU RESUMEN ───────────────────────────────────────────────────
   Las medidas viven AQUÍ y no en un `Style="min-width:…"` tecleado pantalla a pantalla: ése era el sexto
   síntoma del defecto —once valores distintos repartidos por 22 ficheros, censados en M-696— y la única
   forma de que no vuelva el número doce es que la pantalla no tenga dónde escribirlo. */
.app-list-filters {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 4px 0 0;
}

/* Rejilla de tres columnas: rótulo · control · equis. El control se lleva TODO el sobrante y las otras dos
   solo lo que piden, así que las filas quedan alineadas entre sí sea cual sea el largo del rótulo. */
.app-list-filters__rows {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr) max-content;
    align-items: center;
    gap: 8px;
}

.app-list-filters__label {
    color: var(--mud-palette-text-secondary, rgba(100, 116, 139, 0.95));
    font-size: 0.8125rem;
    white-space: nowrap;
}

.app-list-filters__control {
    min-width: 0;
}

/* Las dos mitades de un rango (y el modificador del importe) reparten a partes iguales y envuelven antes
   de encogerse por debajo de lo legible. */
.app-list-filters__pair {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.app-list-filters__pair > * {
    flex: 1 1 160px;
    min-width: 0;
}

.app-list-filters__drop {
    display: flex;
    justify-content: flex-end;
}

.app-list-filters__add {
    align-self: flex-start;
}

/* La banda de lo PUESTO. Envuelve y nunca se pliega: es la que hace imposible el filtro invisible. */
.app-list-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

/* En pantalla estrecha el rótulo se pone ENCIMA de su control en vez de robarle ancho: cortar
   «Estado del contrato» dejaría al corredor sin saber qué está filtrando (familia de M-172). */
@media (max-width: 599.98px) {
    .app-list-filters__rows {
        grid-template-columns: minmax(0, 1fr) max-content;
    }

    .app-list-filters__label {
        grid-column: 1 / -1;
        white-space: normal;
    }
}

/* ── Superficie de listado con scroll acotado (patrón sticky-header) ──
   La rejilla se envuelve en un MudPaper redondeado con .ins-listado. El contenedor propio de la rejilla
   (.mud-table-container) es desplazable en ambos ejes; combinado con FixedHeader="true" en la
   MudDataGrid, la cabecera queda pegada arriba y AMBAS barras (vertical y horizontal) viven en el borde
   del área visible — la barra horizontal está SIEMPRE a la vista sin bajar al final de la lista. Las
   esquinas redondeadas siguen recortando porque el scroll vive en el hijo.

   🌳 M-207 · DE DÓNDE SALE EL TOPE. Aquí estaba escrito `max-height: calc(100dvh - 22rem)`, y esas
   22rem salían de medir UNA pantalla: en las otras 31 sobraba o faltaba scroll. Ya no hay ninguna resta:
   el contenedor de página es una COLUMNA FLEX ACOTADA (insLayout.css, `📐 M-207`) y esta escalera
   —papel → envoltorio de la rejilla → contenedor desplazable— se limita a repartir lo que ese padre
   cede. El navegador mide el cromo real de cada pantalla; nosotros no adivinamos ninguno.

   ⚖️ Y CEDE, NO CRECE (`0 1 auto` en toda la escalera): con pocas filas el papel sigue abrazando la
   tabla —exactamente lo que hacía el `max-height`— y solo encoge cuando la lista no cabe. La VÁLVULA
   es lo que impide que ceda hasta desaparecer, y desde M-696 vive donde de verdad cede: ver abajo.

   ⚠️ EL ENVOLTORIO INTERMEDIO NO SE NOMBRA POR SU CLASE, y es a propósito: MudTable y MudDataGrid no
   emiten la misma, así que se describe por lo que CONTIENE (`:has(.mud-table-container)`). Nombrar una
   de las dos habría dejado la mitad de los listados sin escalera y sin que nada lo cantara.

   🛑 M-574 (s96) · LA ESCALERA SE PARA EN EL CONTENEDOR DESPLAZABLE, Y ESO HAY QUE DECIRLO.
   `*:has(.mud-table-container)` describe «cualquier antepasado de la rejilla», y por eso también
   casaba con `<table>`, `<tbody>`, `<tr>` y `<td>` cuando una fila expandida pinta OTRA tabla dentro
   (`/notifications`, tercera tabla en `ChildRowContent`): al ponerle `display:flex` a un `<table>` la
   maquetación de tabla desaparece y la lista de fuera se descompone entera mientras esa fila esté
   abierta. La exclusión dice que un peldaño es lo que está POR ENCIMA del contenedor: el propio
   contenedor no lo es, y lo que vive DENTRO de él son celdas, no escalera. Sin esto no se podía
   envolver ninguna pantalla con detalle expandible, que es exactamente por qué `/notifications` se
   quedó fuera en la s89. Para los listados sin anidar no cambia ni una declaración. */
.ins-listado,
.ins-listado *:has(.mud-table-container):not(.mud-table-container, .mud-table-container *) {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* El cromo del listado —la barra de herramientas, el pie de paginación— no encoge nunca. */
.ins-listado > *,
.ins-listado *:has(.mud-table-container):not(.mud-table-container, .mud-table-container *) > * {
    flex: 0 0 auto;
}

/* …salvo la propia escalera hasta el contenedor desplazable, que es la que cede. */
.ins-listado *:has(.mud-table-container):not(.mud-table-container, .mud-table-container *),
.ins-listado .mud-table-container {
    flex: 0 1 auto;
}

/* ── 🚰 M-696 · LA VÁLVULA CUELGA DE LO QUE CEDE, NO DEL PAPEL QUE LO CONTIENE ─────────────────────
   Aquí ponía `min-height: 12rem` sobre el PAPEL, y ese número es el que recortaba la pantalla que él
   fotografió. Dos hechos que sólo juntos se leen:

   1️⃣ El papel lleva `overflow: clip` (u `hidden`) tecleado EN LÍNEA: censado el 26-ago-2026, **39 de
      los 44** ficheros que ponen esta clase. Un elemento flex con `overflow` distinto de `visible`
      tiene mínimo automático CERO: la escalera puede encogerlo por debajo de su propio contenido, y lo
      que sobra no se desplaza — se RECORTA, sin barra y sin nada que lo cante. El `min-height` era lo
      único que lo frenaba. (Los 5 restantes no se libran del defecto: sin recorte, lo que sobra
      desborda el papel a la vista, que es la otra mitad de la misma captura.)
   2️⃣ Pero 12rem son 192 px para el papel ENTERO, cromo incluido. En `/policies` la barra sola mide
      ~200 px (relleno 20 + renglón de búsqueda 40 + hueco 8 + banda de filtros + hueco 8 + renglón
      del contador y los botones ~34): ya se come el papel, y la rejilla queda recortada a nada. Ésa
      es la cara «falta scroll donde el contenido excede» — y la barra horizontal que se ve pegada al
      bloque de filtros es la de la rejilla, que al quedar reducida a un hilo sube hasta ahí.

   🌳 EL ARREGLO ES EL MISMO VERBO DE M-207: no se adivina cuánto mide el cromo, se MIDE. El papel deja
   de llevar una cifra y pasa a no encoger por debajo de su contenido (`min-content`): el navegador
   suma la barra real —la que sea, con los filtros que tenga esa pantalla— más el suelo de la rejilla.
   Nada queda nunca recortado; cuando no cabe, rueda la página, que es el peor caso que `insLayout.css`
   declara aceptable («jamás hay algo a lo que no se llega»).

   📏 Y LA ÚNICA CIFRA QUE QUEDA ES LA DE LA REJILLA, no la del papel: 8rem es cabecera + ~2 filas, por
   debajo de lo cual una lista deja de ser una lista. Es el mismo criterio con el que 12rem protegía al
   papel entero, aplicado ahora a lo que de verdad cede — y en la práctica GARANTIZA MÁS lista que
   antes, porque ya no se lo tiene que repartir con la barra de herramientas. */
.ins-listado {
    flex: 0 1 auto;
    min-height: min-content;
}

/* 🕳️ M-574 (s96) · UN ENVOLTORIO SIN REJILLA PINTADA NO RESERVA ALTO. La válvula de la rejilla (8rem,
   abajo) existe para que la LISTA no quede aplastada a nada; donde no hay lista no protege nada y lo
   único que deja es un hueco vacío. Se ve en las dos formas que el patrón admite y que hasta ahora no
   tenía: una pantalla que pinta un aviso en vez de la tabla cuando no hay filas (las dos pestañas de
   `/change-requests`) y una sección plegable que el corredor cerró (`/notifications`), donde el
   titular mide ~56 px y debajo quedaban ~130 px de caja vacía. Mientras la rejilla esté en el DOM
   —que es el caso normal, con filas o con su fila de «sin resultados»— la válvula sigue intacta. */
.ins-listado:not(:has(.mud-table-container)) {
    min-height: 0;
}

/* 🚰 M-696 · LA VÁLVULA, en el peldaño que cede. `min-height` —nunca `max-height`: el tope sigue
   poniéndolo el padre acotado, que es la regla de M-207 y la que vigila
   `AListHeightIsMeasuredNotGuessedTests`—. Por debajo de esto la lista deja de ser una lista, así que
   el papel deja de encoger (su `min-content` incluye esta cifra) y quien rueda es la página. */
.ins-listado .mud-table-container {
    overflow: auto;
    -webkit-overflow-scrolling: touch;
    min-height: 8rem;
}

/* 🪆 …y LA TABLA DE DENTRO DE UNA FILA NO ES LA LISTA, así que no reserva nada. Misma familia y mismo
   ancla que la exclusión del `sticky` de más abajo: una fila expandida que pinta su propio detalle en
   tabla (`/notifications`, los intentos de envío de un aviso) mete un segundo `.mud-table-container`
   DENTRO del primero, y sin esto un detalle de dos líneas abriría un hueco de 8rem dentro de la fila. */
.ins-listado .mud-table-container .mud-table-container {
    min-height: 0;
}

/* ── 📌 M-574 · EL ENVOLTORIO ES LA FIGURA ENTERA: `.ins-listado` YA ENTREGA LA CABECERA FIJA ────────
   Hasta la s88 el patrón eran DOS declaraciones acopladas y en dos sitios distintos: la clase
   `.ins-listado` en el papel envolvente (que acota la altura del contenedor desplazable) y
   `FixedHeader="true"` en la rejilla (de donde MudBlazor saca su `.mud-table-sticky-header`, y con ella
   el `position:sticky` de las celdas de cabecera). **Cualquiera de las dos mitades por separado es
   INERTE y no lo canta nadie**: con envoltorio y sin atributo la lista rueda dentro de su caja con la
   cabecera yéndose arriba; con atributo y sin envoltorio el contenedor no tiene altura acotada, así que
   nunca se desplaza y el `sticky` no tiene contra qué pegarse. Las dos se midieron de verdad —
   `FeeInvoices.razor` traía el atributo sin el envoltorio y `DocumentSearch.razor` el caso inverso —, y
   ninguna de las dos ponía nada rojo.

   🌳 Se colapsa a UNA: la declaración de `sticky` baja aquí, anclada al envoltorio. A partir de ahora
   poner `Class="ins-listado"` en el papel es la figura COMPLETA, el atributo de la rejilla pasa a ser
   redundante (se conserva donde está: mismos valores, no estorba) y **media figura deja de existir**.
   Los valores son exactamente los de MudBlazor para `.mud-table-sticky-header` (`z-index:2`, `top:0`),
   así que donde conviven no cambia un píxel.

   ⚠️ Y esto NO cierra por sí solo los listados que faltan: el `sticky` solo tiene efecto si el
   contenedor DESPLAZA, y quien acota su altura es la escalera flex de arriba, que nace en la clase del
   envoltorio. Por eso no hay regla CSS que arregle un listado sin envoltorio — `.mud-table-container`
   trae `overflow-y:auto` de fábrica pero sin límite de altura no se desplaza nunca. Ésa es la razón, a
   nivel de mecanismo, de que los que quedan exijan mirada por página.

   🧭 M-768 · AQUÍ VIVÍA MEDIA REPARACIÓN DE OPACIDAD, y deja de tener sujeto. El tinte de cabecera
   era TRANSLÚCIDO (`rgba(15,23,42,.55)`), así que las filas se veían pasar por debajo al rodar la
   lista; este bloque reponía una base sólida de superficie y el `theme.css` del corredor volvía a
   pintar el mismo tinte encima con un degradado plano — tres declaraciones en dos ficheros para que
   un color fuera opaco. Desde M-768 el fondo canónico (más abajo) se compone con `color-mix` SOBRE
   la superficie del tema: nace opaco, y las capas de reparación se retiran. Aquí queda solo lo que
   es del `sticky`: dónde se pega.

   ⚠️ Y su ancla sigue siendo `.mud-table-cell` A PROPÓSITO, que es lo contrario de lo que hace la
   jerarquía: pegar una cabecera solo tiene efecto donde el contenedor DESPLAZA, y quien acota su
   altura es la escalera del listado que nace en `.ins-listado`. Las tablas de una ficha
   (`MudSimpleTable`) no viven en una caja acotada, así que extenderles el `sticky` sería una decisión
   nueva y sin medir. La JERARQUÍA sí tiene que alcanzarlas, y por eso va por su propio selector. */
.ins-listado .mud-table-container .mud-table-head .mud-table-cell {
    position: sticky;
    top: 0;
    z-index: 2;
}

/* 🪆 M-574 (s96) · LA TABLA DE DENTRO DE UNA FILA NO ES LA LISTA, así que su cabecera no se pega.
   La regla de arriba describe «la cabecera que hay dentro del contenedor desplazable», y una fila
   expandida que pinta su propio detalle en tabla (`/notifications`: los intentos de envío de un
   aviso) mete una segunda cabecera DENTRO de ese mismo contenedor: las dos se anclaban en `top:0`
   con el mismo `z-index`, o sea la de dentro subía a taparse con la de fuera al rodar la lista. Se
   ancla al ANIDAMIENTO —contenedor dentro de contenedor— y no a ninguna pantalla, así que cubre a
   toda la familia y no toca ni un píxel de los listados sin detalle expandible. */
.ins-listado .mud-table-container .mud-table-container .mud-table-head .mud-table-cell {
    position: static;
    z-index: auto;
}

/* ── 🧭 M-768 · LA CABECERA DE UNA TABLA SE DECLARA UNA VEZ, Y ALCANZA A LAS TRES FAMILIAS ─────────
   Reportado por él como «la cabecera no se distingue de sus filas». No era una tabla: era el ANCLA.

   🌳 LA RAÍZ, medida el 30-ago-2026. La jerarquía de cabecera (peso, versalita, color secundario,
   tinte y filete) vivía DUPLICADA LITERALMENTE en dos hojas de host —`InsCore.Web/theme.css` y
   `InsCore.Backoffice.Web/theme.css`, con su variante de tema claro cada una— y las cuatro
   declaraciones colgaban de `.mud-table-cell`. **Esa clase la emiten sólo `MudDataGrid` y
   `MudTable`.** `MudSimpleTable` pinta `<thead><tr><th>` A PELO y de la casa no le llegaba ni peso,
   ni color, ni fondo, ni filete: lo único que la alcanzaba eran dos reglas de GEOMETRÍA (el
   `word-break` y el `nowrap` de aquí abajo). Y `portal.css` no declaraba NINGUNA regla de tabla.

   | familia | ficheros | jerarquía ANTES | jerarquía AHORA |
   |---|---|---|---|
   | `MudDataGrid` + `MudTable` | 62 | sí, salvo los **5 del portal** | sí |
   | `MudSimpleTable`           | 49 | **no** (ni uno) | sí |
   | `<table>` a pelo           |  4 | no | **no, y a propósito**: ver abajo |

   🗝️ POR QUÉ EL SELECTOR ES `.mud-table-container thead th` Y NO `.mud-table-cell`, que es la
   lección entera de este mandato: **las tres familias comparten el CONTENEDOR, no la clase de la
   celda.** `MudSimpleTable` pinta `<div class="mud-table mud-simple-table"><div
   class="mud-table-container"><table>` igual que las otras dos (medido en el DOM de la app en pie,
   ver el bloque del ancla más abajo), y el `<th>` pelado sólo se deja nombrar por su ELEMENTO. Un
   selector que mira la clase de la celda nace INERTE en 49 ficheros y nada lo canta. La misma
   elección, con la misma prueba, ya la tomaron el `word-break` y el `nowrap` de más abajo.

   🎫 EL FONDO: UNA COMPOSICIÓN AQUÍ, UN TOKEN EN CADA TEMA. Lo que era **seis** declaraciones —el
   tinte y su variante clara en cada uno de los dos hosts, más dos parches para volverla opaca bajo el
   `sticky`— pasa a ser UNA regla más un token de color por tema. La regla compone el tinte como capa
   plana SOBRE la superficie del tema, y por eso nace **opaca**: ninguna fila se transparenta al pasar
   bajo la cabecera pegada, que era el defecto que los dos parches reparaban a mano.

   ⚖️ Y el TINTE sigue siendo del tema, no de este asset, porque tiene que serlo: en oscuro la cabecera
   es un escalón HACIA EL LIENZO (más oscura que la tarjeta) y en claro un gris muy claro sobre blanco.
   Un solo tinte neutro serviría a los dos… aclarando el oscuro, y ahí la cabecera dejaría de sostener
   el suelo de contraste de las tintas semánticas que se pintan sobre ella (medido: la de error caería
   de 6,3:1 a 4,1:1, por debajo del 4,5 del sector). ⇒ El VALOR vive donde vive el tema, en un token;
   la DECLARACIÓN vive aquí, una sola vez. Es el mismo patrón `var(--token, reserva)` que la cabecera
   de este fichero ya declara, y la reserva neutra es la que hace que el portal —que no tiene
   `theme.css`— reciba una cabecera con tinte igualmente.

   El `!important` NO es decorativo: MudBlazor pinta
   `.mud-table-sticky-header .mud-table-head .mud-table-cell { background-color: … }` con tres clases
   y este selector lleva una; sin él, la cabecera pegada de todo listado perdería el tinte. Es el
   mismo motivo por el que las reglas que murieron ya lo llevaban.

   ⚖️ QUÉ QUEDA FUERA Y POR QUÉ, dicho para que nadie lea el hueco como un descuido: las 4 tablas
   `<table>` a pelo no tienen contenedor y no lo van a tener. Tres NO deben recibir cromo de app —la
   matriz de riesgo y el editor de matriz son rejillas de celdas cuadradas, no tablas de datos, y
   `BrandingLetterheadPreview` es la simulación de un papel membretado— y la cuarta
   (`PolicyDetail`, el cuadre del término) no pinta `<thead>`, así que no tiene cabecera que
   jerarquizar. Y de ANCHO, medido una por una: las dos rejillas y el membrete ya lo declaran (celdas
   de 44 px, campos de 96 px, y `width:100%` tecleado); la única a la que le faltaba de verdad es la
   del cuadre del término, y se le da abajo, anclada a la clase de su cuadro.

   🔤 La `font-family` NO entra aquí a propósito, aunque las dos reglas muertas la traían: la tipografía
   es del host (el corredor y el backoffice van en Inter; el portal usa la suya), y clavarla en el
   asset compartido haría que la cabecera de una tabla del portal fuese la única superficie suya con
   otra letra. Lo que esta regla declara es JERARQUÍA, no identidad. */
.mud-table-container thead th {
    font-weight: 600;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--mud-palette-text-secondary);
    background: linear-gradient(var(--ins-table-head-tint, rgba(148, 163, 184, 0.14)),
                                var(--ins-table-head-tint, rgba(148, 163, 184, 0.14))),
                var(--mud-palette-surface) !important;
    border-bottom: 1px solid var(--glass-border, var(--mud-palette-table-lines));
}

/* ── 📐 M-574 · REPARTO DE ANCHO POR NECESIDAD ────────────────────────────────────────────────────
   El reparto automático de la tabla asigna ancho según el min-content de cada columna. El theme del
   Backoffice trae `.mud-table-cell { word-break: break-word }` (theme.css, «evita el recorte de texto»),
   y esa propiedad DEJA EL MIN-CONTENT EN UN CARÁCTER: con la ventana justa el navegador estruja las
   columnas de texto hasta partir «España» en tres renglones y «Copiado de la referencia…» carácter a
   carácter (medido a 1280×720 en /accounting-chart-adoptions: fila de 153 px). Se restituye el
   min-content real (`word-break: normal`) y el objetivo legítimo de aquella regla —que un token
   larguísimo no desborde la celda— lo cumple `overflow-wrap: break-word`, que solo parte cuando la
   palabra no cabe en la línea y NO estrecha el min-content. Mayor especificidad que la del theme
   a propósito: esta es la declaración de las superficies de tabla y gana en los tres hosts.

   ⚠️ EL ANCLA ES `td`/`th`, NO `.mud-table-cell`, Y ESO ES EL ARREGLO DE S72.
   M-574 escribió estas reglas sobre `.mud-table-cell`, que es la clase que emiten MudDataGrid y
   MudTable — o sea, los LISTADOS. Las tablas de una FICHA de detalle son `MudSimpleTable`, y ese
   componente pinta `<thead><tr><th>` y `<td>` A PELO: su CSS propio los alcanza por
   `.mud-simple-table table * tr > td`, sin poner ni una sola vez la clase `.mud-table-cell`. Por eso
   «la mejora se hizo para los listados y no para la ficha»: no faltó ponerle clases a las columnas,
   es que EL SELECTOR NO LLEGABA AL MARCADO.

   ✅ Y EL ANCLA DE ABAJO SÍ LLEGA A LA FICHA — MEDIDO EN EL DOM DE LA APP EN PIE, no deducido.
   `MudSimpleTable` pinta `<div class="mud-table mud-simple-table"><div class="mud-table-container">
   <table>`: el MISMO contenedor que las otras dos familias. En `/policies/{id}` (29-ago-2026) las 6
   tablas simples de la ficha traen el suyo, sobre `.ins-col-ajustada` computa `white-space: nowrap`
   con el `width` resuelto a su min-content (105 px), y ese contenedor DESPLAZA de verdad: con la
   ventana a 1024 px, cuatro de las seis tienen tabla más ancha que su caja y el `scrollLeft` llega a
   50/418/13/125 px sin que la PÁGINA ruede en horizontal.

   ☠️ AQUÍ SE ESCRIBIÓ LO CONTRARIO, Y ESO ES LA LECCIÓN QUE VALE. Se afirmó que MudSimpleTable no
   pinta contenedor porque una sonda contó los literales UTF-16 del ensamblado y `mud-table-container`
   salía 2 veces. **El #US heap DEDUPLICA literales idénticos**: contar apariciones no cuenta
   COMPONENTES, y esa sonda no podía distinguir «dos componentes» de «dos usos del mismo literal» — lo
   dijo con toda seguridad igual. Y la propia hoja de MudBlazor lo desmentía sin salir del disco:
   `.mud-simple-table.mud-table-hover .mud-table-container table tbody tr:hover` —y las variantes
   striped / bordered / sticky-header— nombran ese contenedor DENTRO de la tabla simple. */
.mud-table-container td,
.mud-table-container th {
    word-break: normal;
    overflow-wrap: break-word;
}

/* M-574 · La CABECERA no envuelve: «Prima anual (neta)» a tres renglones hacía la fila de cabecera de
   85 px en /policies (39 px con una línea). El Backoffice ya lo declara en su theme; aquí queda para
   los tres hosts. Si la suma de cabeceras no cabe, la barra horizontal del contenedor —siempre a la
   vista en el patrón .ins-listado— es la salida, no el pliegue del rótulo.

   📐 Y ES TAMBIÉN LA CAUSA DEL IMPORTE PARTIDO EN LA FICHA, medido el 17-ago-2026 a 1280 px en
   /policies/{id} (POL-2025-000004, RC con límite legal español): con «Prima neta anual» envuelto a
   TRES renglones, el min-content de esa columna pasa a ser la palabra «anual» y el reparto
   automático la estruja a 94 px — con lo que «162,00 EUR» se parte en «162,00 / EUR», que es lo que
   se lee como un importe cortado. No es `overflow` ni falta de ancho mínimo declarado: es que la
   CABECERA le estaba mintiendo al reparto sobre lo que esa columna necesita. Con el rótulo a un
   renglón la columna vuelve a pedir su ancho real y el importe deja de partirse — el mismo hecho
   que M-574 ya había medido en /policies, aplicado ahora también donde el selector no llegaba. */
.mud-table-container thead th {
    white-space: nowrap;
}

/* M-574 · Columna AJUSTADA: la que enseña un dato atómico (fecha, importe, sello de tarifa, chip,
   badge) pide su min-content y ni un píxel más; el sobrante va a las columnas de texto (producto,
   tomador, colaborador), que son las que saben crecer. Se pone en CellClass de la columna. */
.mud-table-container td.ins-col-ajustada {
    width: 1%;
    white-space: nowrap;
}

/* M-574 · Dato SECUNDARIO dentro de una celda (p. ej. «Total c/ imp. 3.028,20 EUR» bajo la prima):
   jerarquía sin inflar la fila — un renglón exacto, peso normal. El par rótulo+importe es UN dato:
   partido a media cifra no hay quien lo lea (en /policies envolvía a dos renglones con la columna a
   145 px y era la celda que fijaba el alto de TODA la fila). */
.mud-table-container .ins-dato-secundario {
    white-space: nowrap;
    font-weight: 400;
}

/* ── 🏷️ M-768 · UN CHIP NUNCA DEJA SU ETIQUETA FUERA DE SU PROPIO FONDO ────────────────────────────
   Él lo fotografió en la columna «Nivel» de `/business-risk/{id}`: el rótulo «Medio (8)» pintado
   ENCIMA del borde del chip, con el fondo cubriéndolo a medias. La causa concreta era un presupuesto
   de anchos bajo `table-layout: fixed` y se ha retirado ahí (ver el comentario de esa tabla), pero la
   causa de la CLASE es que la caja del chip se puede clampar al ancho de su celda mientras su
   etiqueta, que no envuelve, sigue creciendo por fuera. Eso puede volver a pasar en cualquiera de las
   115 tablas de la casa el día que a una columna le falte un carácter.

   ⚖️ De las dos salidas posibles —que el chip no encoja NUNCA, o que encoja CON su fondo— se toma la
   segunda: un chip que no encoge se sale de su celda y se monta encima de la vecina, que es el mismo
   defecto movido de sitio. Encogiendo con su fondo, el peor caso es una etiqueta recortada dentro de
   una pastilla entera, y el sitio donde eso se lee tiene además su barra horizontal.

   🔬 Se declara sobre `.mud-chip`, que es la clase PÚBLICA del componente. El recorte fino con puntos
   suspensivos exigiría nombrar el elemento interno de la etiqueta —marcado privado de MudBlazor, no
   verificado aquí—, así que no se escribe: lo que esta regla garantiza, y es lo que él vio roto, es
   que ningún texto quede FUERA del fondo que lo enmarca.

   📐 Y el `vertical-align` NO sobra: un elemento en línea con `overflow` distinto de `visible` deja de
   alinear por la línea base de su texto y pasa a hacerlo por su borde inferior. Sin fijarlo, la pastilla
   se desplazaría hacia arriba respecto al texto que tenga al lado en las celdas donde comparte renglón,
   y eso sería una regresión en las 115 tablas a cambio de un caso raro. */
.mud-table-container .mud-chip {
    max-width: 100%;
    overflow: hidden;
    vertical-align: middle;
}

/* M-574 · La CABECERA se alinea con su CELDA. Las 28 columnas numéricas del repo declaran
   `HeaderStyle="text-align:right"` desde junio y era INERTE: MudBlazor 8 envuelve el contenido del th
   en `.column-header`, un flex al que text-align no le dice nada. Se honra la declaración existente
   —el estilo SÍ llega al th— alineando el flex; así cada página sigue diciendo su intención con la
   propiedad natural y esta regla la hace verdad, sin tocar 28 ficheros. */
.mud-table-cell[style*="text-align:right"] .column-header,
.mud-table-cell[style*="text-align: right"] .column-header {
    justify-content: flex-end;
}

/* ── 🧰 M-554 · LA COLUMNA DE ACCIONES NO ENVUELVE ─────────────────────────────────────────────────
   Con cuatro iconos en la fila —registrar, editar, activar/desactivar y eliminar— la última celda
   envolvía a dos renglones y la papelera caía DEBAJO de los otros tres, alineada con nada. Medido a
   1280×720 en /external-products. Y con la reserva de M-551 puesta hay 88 px menos de celda, así que
   la clase se ve más justo después de arreglar la de al lado: es la misma esquina, apretada por dos
   sitios.

   🌳 RAÍZ Y NO PARCHE, y por eso vive aquí y no en una pantalla. La plataforma pone su columna de
   acciones con TRES marcados distintos —TemplateColumn de MudDataGrid, MudTd de MudTable y <td> a
   pelo— repartidos por 29 ficheros; añadir una clase a mano en cada uno sería teclear el mismo
   arreglo treinta veces, que es exactamente el defecto que M-558 cierra en la puerta de al lado. La
   regla reconoce la celda por lo que ES: la última de la fila y con botones de icono dentro.

   ⚖️ Por qué `:last-child` Y `:has(.mud-icon-button)` a la vez, y no cualquiera de los dos suelto:
   `:last-child` solo apagaría el ajuste de línea de una última columna de TEXTO largo, que sí debe
   envolver; `:has()` solo alcanzaría a celdas intermedias con un icono al lado de un dato. Juntos
   describen la celda de acciones sin nombrar ninguna pantalla.

   Se declara sobre `.mud-table-container` para cubrir por igual a la rejilla y a la tabla simple, que
   comparten ese contenedor (medido en el DOM, ver el bloque del ancla más arriba). */
.mud-table-container tbody td:last-child:has(.mud-icon-button) {
    white-space: nowrap;
    /* M-574 · Y tampoco ACAPARA: «Acciones» se llevaba 336 px para dos iconos en /quotes porque el
       reparto automático le regalaba el sobrante. Con width:1% pide su min-content (los botones, que
       ya no envuelven) y el sobrante vuelve a las columnas de texto. */
    width: 1%;
}

/* ── 🧭 M-720 · LA BARRA HORIZONTAL DEL LISTADO VIVE EN EL BORDE DE LA PANTALLA, NO AL FINAL DE LA LISTA ─
   Reportado por él el 27-ago-2026 con una captura de `/receipts` delante (63 de 63 recibos, 11 columnas):
   la tabla desborda a lo ancho —«Colaborador externo» cortada y «Ramo» fuera de vista— y la única forma
   de alcanzar esas columnas era **rodar hasta el último registro** a buscar la barra.

   🌳 LA RAÍZ, y por qué NO es «acotar la altura». `.mud-table-container` es el desplazable, y la barra
   horizontal de un desplazable vive SIEMPRE en su borde inferior. Desde M-696 el papel no encoge por
   debajo de su contenido (`min-height: min-content`), así que con más filas de las que caben en la
   ventana el papel mide lo que mide la tabla ENTERA y quien rueda es la página —el «peor caso aceptable»
   que declara `insLayout.css`—: el borde inferior del desplazable queda por debajo del último registro, y
   con él su barra. La salida obvia —acotarle la altura para que la barra suba a la vista— **ya se probó y
   él la descartó DOS VECES el mismo día**: «disminuir la cantidad de registros es una REGRESIÓN. Esa no
   es la solución». Y no es preferencia estética: con la página rodando, al bajar se llenan de filas los
   px que ocupaban cabecera, pestañas y barra de filtros; con el alto acotado esos ~300 px son cromo
   permanente. Acotar CUESTA FILAS de verdad.

   ⇒ SE SEPARA EL MANDO DEL DESPLAZABLE. La lista no cambia ni un píxel —ni de alto, ni de columnas, ni de
   filas pintadas—: lo que se añade es un **mando** de desplazamiento horizontal anclado al borde inferior
   del viewport mientras la tabla esté en pantalla, que es lo que hacen las hojas de cálculo. Es la vía 1
   de la ficha; las otras tres se midieron y no cierran solas (ver el reporte de M-720).

   🏠 VIVE FUERA DEL ÁRBOL QUE BLAZOR DIFEA, y esto es el patrón ya probado de `insTooltip.js` («la burbuja
   flotante es hija de <body>, así Blazor nunca la toca ni la pierde»): UNA sola barra `position: fixed`,
   hija de `<body>`, que `insListScroll.js` apunta al listado que hay en pantalla. Inyectarla DENTRO del
   papel habría metido un nodo ajeno en medio del diffing del renderizador, que es de donde salen los
   «element is not a child of» del circuito.

   🤝 CONVIVENCIA MEDIDA POR GEOMETRÍA (no hay solape, y son las dos cosas que ya reservan el borde):
   · el FAB (`insAiLauncher.css`) es `fixed; bottom: 24px` y mide 56 px ⇒ ocupa [24, 80] px contados desde
     el borde inferior; esta barra ocupa [0, 14]. Son bandas DISJUNTAS y por eso no se le resta ancho ni
     se toca `--ins-ai-fab-clearance`. En móvil el FAB baja a 16 px y el hueco se queda en 2 px: sigue sin
     solapar, pero es el número que hay que volver a mirar si alguien mueve el FAB.
   · la barra de acciones al pie de M-310 (`.ins-sticky-actions` / `.ins-form-actions` / `.stepper-actions`)
     **no aparece en ningún listado**: censado el 27-ago-2026 sobre los 44 ficheros que ponen
     `.ins-listado`, CERO la montan. Es cromo de formulario, no de lista.
   · con un modal abierto la barra se retira: un mando de la pantalla de detrás flotando sobre el velo se
     lee como un defecto, y además ahí no hay nada que desplazar.

   📐 LA ALTURA ES EXPLÍCITA Y EL PULGAR TAMBIÉN, a propósito: una barra que solo aparece mientras se
   arrastra (las de superposición de macOS/iOS) no se descubre, y descubrirla es justo lo que M-720 pide.
   `-webkit-appearance: none` fuerza el modo clásico en WebKit y `scrollbar-width/color` hace lo propio en
   Firefox. */
#ins-hbar {
    position: fixed;
    bottom: 0;
    z-index: 1240; /* por encima del contenido, por debajo del FAB (1250) y de las sobrecapas */
    display: none;
    height: 14px;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    border-radius: 7px 7px 0 0;
    background: var(--mud-palette-surface, #0a1632);
    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.25);
    scrollbar-width: thin;
    scrollbar-color: var(--mud-palette-primary, #5b8def) transparent;
}

#ins-hbar.ins-hbar--on {
    display: block;
}

/* Con un diálogo delante no hay listado que desplazar. ⚠️ Se nombran los DOS contenedores de modal que
   existen —el de MudBlazor y el de `InsDialog`— y NO `.mud-overlay` a secas, que era lo primero que se
   escribió aquí y habría apagado el mando EN SILENCIO: MudBlazor 8.4 deja un scrim colgado dentro de
   `.mud-popover-provider` (es el «antídoto del overlay» de `insResilience.js:110`), así que
   `body:has(.mud-overlay)` puede ser cierto sin que haya ningún modal abierto. Estos dos sólo existen
   mientras hay diálogo. Y si algún día apareciera un tercero, el peor caso es benigno: el mando se queda,
   apagado bajo el velo (z-index 1240 contra 1398/1400), nunca al revés. */
body:has(.mud-dialog-container, .ins-dialog-overlay) #ins-hbar.ins-hbar--on {
    display: none;
}

#ins-hbar::-webkit-scrollbar {
    height: 12px;
    -webkit-appearance: none;
}

#ins-hbar::-webkit-scrollbar-track {
    background: transparent;
}

#ins-hbar::-webkit-scrollbar-thumb {
    background: var(--mud-palette-primary, #5b8def);
    border: 3px solid transparent;
    background-clip: content-box;
    border-radius: 6px;
}

/* El relleno que le da recorrido al mando: su ancho lo escribe `insListScroll.js` con el `scrollWidth`
   REAL del contenedor, así que el pulgar mide y recorre exactamente lo mismo que la barra de verdad. */
#ins-hbar > .ins-hbar__span {
    height: 1px;
}

/* ── 📐 M-729 · UNA TABLA DECIDE SU ANCHO; EL NAVEGADOR NO LO REPARTE A CIEGAS ────────────────────
   Reportado por él TRES veces con TRES capturas distintas, y son la misma ausencia por sus tres
   puntas: **ninguna tabla del repo declaraba estrategia de anchos** (censo del 28-ago-2026:
   `table-layout` aparecía CERO veces en todo el árbol). Con `table-layout: auto` y sin `width`, la
   tabla se dimensiona a su contenido: si pide menos que el contenedor deja hueco, si pide más expulsa
   columnas, y la holgura la reparte proporcionalmente entre todas.

   🔬 MEDIDO EN LABORATORIO antes de escribir una línea (Chrome, contenedor de 900 px), porque el
   arreglo «obvio» —`width:100%` + `table-layout:fixed` transversal— ROMPE dos mecanismos vivos:

   | variante                        | columnas ajustadas | alto de fila |
   |---------------------------------|--------------------|--------------|
   | `auto` (lo de hoy)              | 79 / 56 / 60 / 61  | 25 px        |
   | `fixed` transversal             | **13 / 13 / 13 / 13** | **41 px** |

   Dos razones, y ninguna es de estilo:
   · Bajo `fixed` el navegador lee los anchos SOLO de la primera fila, y `.ins-col-ajustada` se pone
     en `CellClass` —o sea en el `<td>`—, así que queda INERTE. Lo mismo le pasa al `width:1%` de la
     columna de acciones de M-554, que es transversal a 29 ficheros.
   · Y `width:1%` bajo `fixed` es LITERAL (13 px), no «ajústate a tu contenido». Las columnas de dato
     atómico se recortan y las filas ENGORDAN — que es justo el defecto que M-732 viene a cerrar.
   ⇒ El ingrediente `fixed` NO puede ser transversal: exige teclear anchos absolutos en el `<th>` de
   las 50 tablas, que es exactamente lo que ya se intentó en M-727 y falló. Va OPT-IN, abajo.

   1 · LA TABLA LLENA SU CONTENEDOR — cierra la cara 3, el hueco tras «Acciones» que él fotografió en
   `/liquidations` con la tabla VACÍA. Medido con una tabla sin ninguna columna ajustada y contenido
   corto: **648 px de hueco muerto → 4 px**. Esto es seguro en las tres familias porque no cambia el
   reparto, solo el ancho total: las ajustadas siguen pidiendo su min-content.

   ⚠️ Y por eso la cara 3 solo se veía en ALGUNAS tablas: `width:1%` en un `<td>` obliga a la tabla a
   crecer hasta el ancho disponible (para que el 1% cubra el min-content), así que las tablas que ya
   tenían columnas ajustadas se estiraban solas. Las que no las tienen son las que dejaban el hueco. */
.mud-table-container table {
    width: 100%;
}

/* 2 · LA COLUMNA FLEXIBLE — cierra la cara 1: la holgura va DONDE SE DECIDE, no repartida entre
   todas. Es la pareja que le faltaba a `.ins-col-ajustada` de M-574: aquella dice «no crezcas», ésta
   dice «crece tú». En `/business-risk` a 1869 px la fecha se llevaba 259 px y un número 201 porque
   nadie había dicho quién debía quedarse el sobrante.

   ⚠️ SOLO UNA POR TABLA, y esto está medido: con DOS columnas al 100% se pelean (515 px contra 113 en
   el laboratorio) y el alto de fila sube de 25 a 73 px. La flexible es la de nombre o descripción.
   Se pone en `HeaderClass` Y en `CellClass` — en `HeaderClass` para que la lea `fixed`, en
   `CellClass` para que la lea `auto`. */
.mud-table-container th.ins-col-flexible,
.mud-table-container td.ins-col-flexible {
    width: 100%;
}

/* 3 · EL ANCHO DECLARADO MANDA — cierra la cara 2, la columna EXPULSADA por su propio contenido. En
   `auto` el contenido gana al `width` del `<th>`, así que «Cobertura» (dos selectores apilados con
   `POL-2026-000009 — rc-inst-001` dentro) se ensanchaba y empujaba «Riesgo» fuera de vista: en su
   captura la tabla arrancaba en «PROB.» y el nombre del riesgo no se leía. Medido: la tabla pedía
   1.018 px dentro de un contenedor de 904 y `auto` NO lo cierra de ninguna manera.

   🗝️ ES OPT-IN, y esa es la decisión de ingeniería de este mandato: se pone en la tabla que ya
   declara sus anchos en los `<th>`, no en las 50. Donde se pone, el presupuesto que M-727 escribió
   —y que era correcto— deja de ser una sugerencia y pasa a ser una orden: no se tira ese trabajo,
   se le devuelve el efecto que su premisa le negaba.

   📏 LA REGLA PARA QUIEN LA PONGA DESPUÉS: bajo `fixed` los anchos van en el `<th>` (`HeaderStyle` /
   `MudTh Style`), NUNCA en el `<td>`, y la columna flexible es la que se deja SIN ancho. Una tabla
   con `.ins-tabla-acotada` y todos sus `<th>` sin ancho reparte a partes iguales, que es peor que no
   haberla puesto.

   ⚠️ SE ACEPTA EN LA TABLA **O EN UN ANTEPASADO**, y no es por comodidad: `MudTable`/`MudDataGrid`
   aterrizan su `Class` en el div raíz (`.mud-table`), NO en el `<table>`, así que un selector que
   solo mirase al elemento habría nacido inerte en las dos familias que más lo necesitan — y sin que
   nada lo cantara, que es la clase de defecto que M-574 ya pagó con media figura inerte.

   ✅ Y a `MudSimpleTable` le llega por esa misma SEGUNDA forma: su `Class` también aterriza en el div
   raíz, que es antepasado de su `.mud-table-container` (medido en el DOM, ver el bloque del ancla más
   arriba). En una ficha esta clase NO nace inerte.

   📉 M-768 · ADOPTANTES HOY: **CERO**, y el motivo se escribe para que el siguiente no la ponga sin
   traer lo que exige. Su único adoptante era la tabla de `/business-risk`, y lo que la sacó de aquí
   fue el precio de `fixed`: bajo esta estrategia **toda** columna que no sea la flexible tiene que
   declarar un ancho ABSOLUTO en su `<th>` (sin ancho reparte a partes iguales, que es peor que no
   haberla puesto), y aquel presupuesto lo admitía por escrito su propio comentario: *«esto es
   CALCULADO, no medido»*. La consecuencia la fotografió él: «Nivel» valía 6rem, el chip se clampaba a
   la celda y su etiqueta se salía del fondo. Con `auto` + `.ins-col-flexible` la columna de prosa se
   queda el sobrante y las demás piden su `min-content`, sin ninguna cifra tecleada. ⇒ Esta clase
   sigue siendo la salida correcta para una tabla que trae un presupuesto **medido**; lo que M-768
   retiró no fue el mecanismo, fue el presupuesto adivinado. */
.mud-table-container table.ins-tabla-acotada,
.ins-tabla-acotada .mud-table-container table {
    table-layout: fixed;
}

/* ── 📱 M-768 · LA PRIORIDAD DE COLUMNA ES DE LA CASA, NO DE UN HOST ───────────────────────────────
   `.col-hide-sm` se oculta en móvil (<600) y `.col-hide-md` también en tableta (<960); lo que sobra
   sigue siendo alcanzable por la barra horizontal del contenedor. Las columnas sin clase y la de
   acciones no se ocultan nunca.

   🌳 POR QUÉ SUBE AQUÍ. Estaba declarada SOLO en `InsCore.Backoffice.Web/theme.css`, y el panel de
   coberturas del corredor (`ProductCoveragesPanel.razor`) la pide en **5 columnas** — es hermano del
   `CoveragesSection.razor` del backoffice, del que copió las clases junto con el marcado. En el host
   del corredor esos 5 usos **no hacían nada** y nada lo cantaba: la columna que el panel quería
   apartar en una pantalla estrecha seguía ahí, empujando a las demás. La clase no sobraba, sobraba
   su domicilio. ⇒ Se declara una vez para los tres hosts y muere la copia del backoffice.

   🗝️ Y el ancla cambia con ella: el backoffice la colgaba de `.mud-table-cell`, o sea la misma
   ceguera que la cabecera de más arriba —una tabla simple no la habría obedecido nunca—. Aquí se
   cuelga del contenedor y del ELEMENTO, así que vale para las tres familias.

   📐 Los dos tramos se declaran como TOPES acumulativos y no como bandas disjuntas: `col-hide-md`
   oculta por debajo de 960 (que incluye el móvil), `col-hide-sm` por debajo de 600. El backoffice lo
   escribía como dos bandas repitiendo `col-hide-md` en las dos; es lo mismo con una regla menos. */
@media (max-width: 959.98px) {
    .mud-table-container th.col-hide-md,
    .mud-table-container td.col-hide-md { display: none !important; }
}

@media (max-width: 599.98px) {
    .mud-table-container th.col-hide-sm,
    .mud-table-container td.col-hide-sm { display: none !important; }
}

/* ✂️ M-768 · Y SU VECINA, POR LA MISMA MEDIDA. `col-clamp` recorta a dos renglones el nombre largo de
   una fila y acota su ancho. Vivía también sólo en el backoffice, y el mismo panel de coberturas del
   corredor la pide en la columna «Cobertura» junto con `col-clamp-text` en la descripción: las dos
   estaban inertes y el resultado era una descripción de garantía sin tope, que es la celda que fija el
   alto de toda la fila. Se retiran las dos de allí y se declaran aquí, para los tres hosts. */
.mud-table-container td.col-clamp {
    max-width: 560px;
}

.mud-table-container td.col-clamp .mud-typography,
.mud-table-container td.col-clamp .col-clamp-text {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* ── 🧾 CÁLCULO DE LA PRIMA: un cuadro con estructura, no una lista de renglones ────────────────────
   Reportado por él (28-ago-2026): «antes teníamos una card mejor hecha con filas con fondo intercalado
   y sus propios bordes; mimetizarlo con el resto no me parece, pues tiene importancia».

   Y tiene razón por una razón que no es estética: esto NO es una lista de datos, es una SUMA —base,
   componentes que se calculan sobre ella, y total—. Cuando las tres clases de fila se ven idénticas,
   entender qué depende de qué obliga a leerse los porcentajes uno a uno. Es la cifra que el corredor
   canta al cliente y la que acaba en el recibo.

   ⚖️ Lo que NO se hace: devolver la card de antes tal cual. Se le da JERARQUÍA con los tokens del tema
   —nada de colores tecleados— para que siga siendo la misma app en los dos temas y en los dos hosts. */
.ins-premium-breakdown {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 10px;
    overflow: hidden;
    background: var(--mud-palette-surface);
}

/* 📐 M-768 · Y EL CUADRO SE LLENA. `width:100%` de M-729 lo reparte `.mud-table-container table`, y
   ese contenedor lo pintan los componentes de MudBlazor: el cuadre del término de `/policies/{id}`
   monta un `<table>` A PELO dentro de este marco, así que la tabla se encogía a su contenido y el
   marco —que sí mide sus 26rem— quedaba con un hueco muerto a la derecha. No es sólo hueco: el tinte
   de fila alterna y el de la fila del total se cortaban antes del borde del cuadro, o sea las bandas
   que hacen legible la SUMA morían a media caja. Se ancla a la clase del cuadro y no al `<table>`
   suelto, que es lo que impide que esto alcance a las otras tres tablas a pelo del repo —dos son
   rejillas de celdas cuadradas y estirarlas las deformaría, y la cuarta simula un papel membretado y
   ya declara su ancho—. */
.ins-premium-breakdown table {
    width: 100%;
}

/* Las filas de COMPONENTE se alternan: es lo que deja seguir un renglón largo hasta su importe sin
   perder la línea, que es justo lo que pasa en el desglose fiscal (tres recargos con nombres largos). */
.ins-premium-breakdown tbody tr:nth-child(even) {
    background: color-mix(in srgb, var(--mud-palette-text-primary) 4%, transparent);
}

/* La PRIMERA fila es la base de todo el cálculo, y la ÚLTIMA es el total: las dos se separan de los
   componentes por un filo, no por un color distinto — un color más sería ruido en un cuadro que ya
   tiene tres niveles. */
.ins-premium-breakdown tbody tr:first-child > td {
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.ins-premium-breakdown tbody tr:last-child > td {
    border-top: 1px solid var(--mud-palette-lines-default);
    background: color-mix(in srgb, var(--mud-palette-primary) 8%, transparent);
}

/* Sin filo bajo la última: el borde del cuadro ya cierra, y dos líneas juntas se leen como un error. */
.ins-premium-breakdown tbody tr:last-child > td { border-bottom: none; }

/* Un poco de aire: el cuadro es corto y apretarlo no ahorra pantalla, solo cuesta legibilidad. */
.ins-premium-breakdown tbody td { padding-top: 7px; padding-bottom: 7px; }

/* ── 🎯 M-768 · UNA ACCIÓN EN SITIO SE VE COMO ACCIÓN, NO COMO EL DATO QUE TIENE AL LADO ───────────
   Censo del 30-ago-2026 sobre las 12 fichas de detalle: **253 afordancias**, de las que 191 son
   `MudButton`; **59** sin borde ni relleno, **33** de ésos tampoco con color de acción y **15** sin
   siquiera un icono. De esos 15, **once NO son defecto** y por eso no se tocaron: ocho son
   «Cancelar»/«Volver» en pareja con un primario —el par ya dice cuál es la acción y cuál la salida—,
   dos son el lado apagado de un conmutador que declara su estado con `aria-pressed`, y uno es un
   «Reintentar» dentro de un `MudAlert`, que hereda la afordancia del aviso que lo contiene.

   🔴 LOS CUATRO QUE SÍ LO ERAN comparten una forma exacta: **una acción metida ENTRE datos** —al lado
   del texto que modifica, o dentro de un `<td>`—, sin borde, sin relleno, sin color y sin icono. Ahí
   no hay pareja ni contenedor que preste afordancia: el rótulo «Cambiar» junto al nombre de la cuenta
   pagadora se lee como una palabra más de la ficha, y sólo el cursor delata que era pulsable.

   ⚖️ POR QUÉ NACE UN RIEL Y NO SE ARREGLAN CUATRO SITIOS. El precedente está medido y es de esta
   casa: el commit `297fe578a` arregló esta misma clase caso a caso creando `.ins-boot__msg`, que hoy
   tiene **exactamente un usuario** y no llegó ni al backoffice ni al portal. Cuatro `Variant.Text` con
   estilo tecleado serían cuatro copias que divergen; una clase compartida es un sitio donde mirar.

   📏 CUÁNDO SE PONE, que es lo que evita que el siguiente vuelva a teclear `Variant.Text` a secas:
   · SÍ · una acción que vive DENTRO del contenido —junto al dato que cambia, o en una celda— y no
     tiene a su lado un primario ni un contenedor que le preste afordancia.
   · NO · el par «Guardar / Cancelar» de un formulario (la pareja ya jerarquiza), el lado apagado de
     un conmutador (su estado lo dice `aria-pressed`), ni la acción de un aviso (la presta el aviso).
   · NO · la acción PRINCIPAL de una pantalla: para eso está `InsActionButton`, que es `Filled` +
     `Primary`. Este riel pesa MENOS a propósito — se lee como accionable sin competir con ella.

   🎫 El peso sale de TOKENS y no de un color tecleado, así que sirve a los dos temas sin una sola
   variante: el canto es el mismo filete con el que la casa peina sus superficies y el relleno es la
   tinta del tema al 6 %, que en oscuro aclara y en claro oscurece. Y gana a MudBlazor por ORDEN, no
   por `!important`: los tres `App.razor` enlazan esta hoja DESPUÉS de `MudBlazor.min.css`, así que a
   igualdad de especificidad (dos clases) manda ésta. */
.mud-button-root.ins-accion-en-sitio {
    border: 1px solid var(--glass-border, var(--mud-palette-lines-default));
    background-color: color-mix(in srgb, var(--mud-palette-text-primary) 6%, transparent);
}

.mud-button-root.ins-accion-en-sitio:hover {
    border-color: var(--mud-palette-primary);
    background-color: color-mix(in srgb, var(--mud-palette-primary) 12%, transparent);
}

/* ── ⭳ M-768 · UN ENLACE QUE DESCARGA LO DICE ANTES DE QUE LO PULSEN ──────────────────────────────
   Dos `MudLink` de la ficha de póliza —el ejemplar firmado y la evidencia de la firma— prometen
   NAVEGAR y lo que hacen es traerse un fichero al disco. Afordancia tienen (color de enlace): lo que
   engañan es sobre QUÉ pasa al pulsar, que es la otra mitad del mismo defecto. No se les quita el
   aspecto de enlace: se les pone delante el icono que dice a dónde va eso.

   La clase existe para que el par icono+rótulo se declare UNA vez y no en un `style=` por sitio (uno
   de los dos ya lo llevaba tecleado, el otro no, y por eso se veían distintos). Quien pone el icono
   es el marcado —un icono no se inventa desde una hoja de estilo—; esto sólo lo coloca. */
.ins-enlace-descarga {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    cursor: pointer;
}
