﻿/* ============================================================
   InsCore — Dark Glass Design System
   1.  Design Tokens
   2.  Global Reset & Font Rendering
   3.  (libre — orbes animados, retirados en la s110)
   4.  AppBar — Glass Surface
   4bis. Texto con degradado — RETIRADO (s110), ver la nota en su sitio
   5.  Drawer — Glass Surface
   6.  Cards & Papers — superficies opacas
   7.  Tables
   8.  Inputs & Buttons
   9.  Nav Links
   10. KPI Cards
   11. Empty State
   12. Page Entry Animations
   13. Light Mode Overrides
   14. Responsive Media Queries
   15. Reconexión del circuito (Blazor Server)
   16. Antídoto overlay de popover (MudBlazor 8.4)
   17. Pestañas: ninguna flecha que no pueda desplazar nada
   ============================================================ */

/* ── 1. Design Tokens ─────────────────────────────────────── */
:root {
    /* ── SUPERFICIES ─────────────────────────────────────────────────────────────────────────────
       🎨 s110 · OPACAS, LIENZO LISO Y ELEVACIÓN POR LUMINOSIDAD. Decisión suya sobre una comparativa
       con las variantes al lado y el contraste calculado a la vista: *superficie opaca · sin orbes ·
       radio 10 · marca índigo + cian*.

       🔴 POR QUÉ SE VA EL CRISTAL, y no es estética. Él retiró la PREMISA de M-340:
       *«se degradó por unas mejoras que creí necesitar de mimetización, pero no me había dado cuenta
       que era una extensión de mi navegador la que me hacía ver diferente»*. Aquel mandato recalibró
       `--glass-bg` tres veces el 17-ago hasta esta losa, y su queja de ahora —*«ese color es muy denso
       el color de las cards»*— apunta al mismo sitio. El sospechoso medido no era el alfa: era
       `saturate(180%)` del `backdrop-filter`, que realzaba la saturación de los ORBES por debajo de
       cada tarjeta.

       ⚠️ PERO NO ES UN REVERT, y esto importa: el cristal de julio, `rgba(10,22,50,0.65)`, componía
       `rgb(12,22,47)` sobre un lienzo `rgb(15,23,42)` — la tarjeta MÁS OSCURA que su página, 1,00:1.
       Eso se midió en píxeles y ninguna extensión de navegador lo explica. Volver allí reabriría el
       defecto que M-340 sí cerró de verdad.

       🎯 LO QUE SE HACE: la tarjeta pasa a pintar el token que dice que ES la superficie
       —`Surface` = `#1e293b`—, opaca, sin desenfoque y sin resplandor. Con eso la casa deja de tener
       DOS fuentes para el color de una tarjeta (la paleta decía `#1e293b` y la hoja pintaba otra
       cosa con `!important`), que es exactamente lo que hizo que M-708 gastara una ola entera
       cambiando el token equivocado.

       📐 Medido sobre el censo real de siete superficies compuestas, ya SIN orbes:
           · tarjeta / lienzo ......... 1,220:1  (suelo 1,15) ✅
           · rótulo secundario ........ 4,95:1   (suelo 4,50) ✅ peor de las siete
           · índigo como tinta ........ 6,37:1   · cian ....... 7,02:1
       🏆 La elevación se expresa con superficie MÁS CLARA, no con sombra: es el estándar del sector
       para tema oscuro (Material) y una sombra negra sobre un lienzo casi negro no la ve nadie.
       Lo vigilaban `ACardHasItsOwnSurfaceInBothThemesTests`, `ASecondaryLabelLiftsOffItsSurfaceTests`
       y `AKpiNumberAndItsCardKeepBothContrastPairsTests`, hoy retirados.

       🏷️ Los nombres `--glass-*` se conservan EN ESTE COMMIT a propósito, para que el diff diga una
       sola cosa. El renombrado por PAPEL (`--surface-raised`, `--surface-overlay`, `--border-…`) va
       en su propio paso: un token que nombra un EFECTO que ya no existe es la próxima trampa. */
    --glass-bg:             rgba(30, 41, 59, 1);      /* #1e293b — el token Surface, por fin */
    --glass-bg-heavy:       rgba(15, 23, 42, 1);      /* #0f172a — barra y cajón, opacos */
    /* Un escalón por encima de la tarjeta, para lo que flota encima de ella. El diálogo lleva velo
       detrás y necesita menos; el desplegable no lleva nada y necesita el escalón entero (1,153:1
       contra la tarjeta, el mismo orden que el suelo tarjeta/lienzo). */
    --surface-dialog:       rgba(36, 48, 68, 1);      /* #243044 */
    --surface-popover:      rgba(38, 51, 74, 1);      /* #26334a */
    --glass-border:         rgba(148, 163, 184, 0.10);

    /* 🧭 M-768 · EL TINTE DE LA CABECERA DE TABLA. Es lo ÚNICO que queda aquí de las tablas: la
       jerarquía entera (peso, versalita, color, composición del fondo y filete) la declara una sola
       vez `_content/InsCore.Ui.Gadgets/insList.css`, y lee este token. Vive en el tema porque su valor
       ES del tema: en oscuro la cabecera es un escalón HACIA EL LIENZO —este mismo `#0f172a` al 55 %,
       exactamente el valor que tenía la regla que murió— y en claro un gris casi blanco (más abajo,
       en `body.ins-light`). Un tinte único para los dos temas aclararía el oscuro y hundiría el
       contraste de las tintas semánticas sobre la cabecera por debajo del 4,5:1 del sector, que es lo
       que vigilaba `ATheBrokerHostSemanticsReadAsInkTests` (ya retirado). */
    --ins-table-head-tint:  rgba(15, 23, 42, 0.55);

    /* M-340 · El canto de la tarjeta, SEPARADO de `--glass-border`. Son dos papeles distintos y por eso
       dos variables: `--glass-border` peina siete sitios (barra, cajón, separadores de tabla…) donde una
       línea tenue es lo correcto; el canto de una tarjeta es lo que dice DÓNDE ACABA la tarjeta. Sobre
       lienzo oscuro un canto se ve MENOS, así que darle 0,10 —la mitad que en claro, que usa 0,20— era
       justo al revés de lo que pide la superficie. */
    --glass-border-card:    rgba(148, 163, 184, 0.22);
    --glass-border-hover:   rgba(148, 163, 184, 0.38);

    /* 🔲 M-415-b · el canto de un CAMPO al señalarlo. En reposo lo pone la paleta
       (`--mud-palette-lines-inputs`, ver `MudThemeFactory.cs`); esto es el ESTADO, que en esta casa vive
       en CSS como los demás. Escalón contiguo de la misma rampa slate en la dirección que separa más de
       la superficie: oscuro slate-300 (7,92:1 contra la tarjeta), claro slate-600 (7,52:1), frente al
       1,64:1 al que caía usando `--glass-border-hover`. */
    --app-input-border-hover: #cbd5e1;

    /* 🧹 `--glass-blur*` RETIRADOS (s110). Eran `blur(20px) saturate(180%)` sobre las 492 superficies
       `.mud-paper` del host. El `saturate` es el que realzaba los orbes bajo cada tarjeta y el
       principal sospechoso medido del «denso» que él reportó; el `blur` deja de tener sentido sobre
       una superficie opaca. Y se van 492 `backdrop-filter`, que no es gratis para el navegador. */

    /* Layout — RADIOS. Los del manual de marca: 14 px en TARJETAS y 9 px en CONTROLES (campo y botón).
       Decisión suya, 3-sep-2026, sobre la comparativa de los cuatro sitios.

       🔴 Y aquí había DOS defectos, no uno.
       El primero: este host pintaba 10/8/6 mientras el Backoffice, el portal del tomador y el sitio
       público pintaban 14/9/9. Cuatro superficies de la misma casa con tres cantos distintos.
       El segundo, y es el que decidió cuál gana: el comentario que ocupaba estas líneas razonaba
       *«vuelven los de entonces — 18 px en tarjetas, 12 en campos, 10 en botones»* mientras los
       valores escritos justo debajo eran 10/8/6. Sobrevivió a un cambio posterior y quedó
       describiendo unos números que NO PINTABA NADIE. Un comentario que documenta una decisión que el
       código no ejecuta es peor que ningún comentario: el siguiente que lo lea creerá que sabe por
       qué. Así que no había decisión escrita a favor de 10/8/6 — sólo una que hablaba de otra cosa.

       📐 Un control y otro control con radios parecidos pero distintos no se leen como jerarquía, se
       leen como descuido: por eso `input` y `button` comparten número y la única diferencia que queda
       es control frente a superficie. Se conservan como TRES tokens y no dos porque describen tres
       papeles, y el día que el manual separe campo de botón se tocan por su lado. */
    --app-radius-card:      14px;
    --app-radius-input:      9px;
    --app-radius-button:     9px;

    /* Sombras — CORTAS y NEUTRAS. La de 24 px con un halo de color era decoración: en una aplicación
       de trabajo la sombra dice «esto está por encima», no «esto brilla». La tarjeta oscura conserva
       sombra declarada a propósito, porque su ausencia es un defecto que ya se midió una vez
       (`ACardHasItsOwnSurfaceInBothThemesTests`, hecho 1) — lo que cambia es su fuerza, no su
       existencia.
       🧹 `--app-glow-blue` y `--app-glow-violet` RETIRADOS: un halo de color alrededor de un dato de
       negocio no significa nada, y ninguno de los cinco referentes del sector lo tiene. */
    --app-shadow-card:       0 1px 2px rgba(0, 0, 0, 0.28);
    --app-shadow-card-hover: 0 2px 8px rgba(0, 0, 0, 0.32);

    /* Animation timing: los tokens `--dur-…` y `--ease-…` vienen de insBrand.css (RCL compartido,
       A0.3 del rebranding) — declararlos aquí también los dejaría divergir del backoffice y el portal
       en cuanto uno de los tres se tocara sin el otro, que es justo el defecto que este fichero traía.
       🐛 s110 · ESTE COMENTARIO ESTABA ROTO Y SE LLEVABA POR DELANTE UN TOKEN. Decía
       `--dur-*` seguido de `/`, y esa secuencia CIERRA EL COMENTARIO: el resto del texto quedaba como
       declaración inválida dentro de `:root` y el navegador la descartaba hasta el siguiente `;`, que
       era el de `--orb-blue`. O sea que el orbe MÁS GRANDE no llegaba a pintarse — mientras
       `ThemeCanvasFacts.OrbColors` lo leía de este fichero con una expresión regular y componía
       contraste contra él. Un guard que lee el FICHERO no puede ver lo que el PARSER descarta. */

    /* 🧹 ORBES RETIRADOS (s110) — `--orb-blue/violet/mint` y su capa. Eran tres manchas de color
       animadas (`blur(80px)`, ciclos de 14/18/22 s) por debajo de TODO el contenido de negocio. Es el
       recurso de una portada de producto, no de una pantalla de trabajo, y ninguno de los referentes
       del sector —Salesforce, Linear, Stripe, Spotify, Netflix— lo lleva.
       🔬 Y su marcha SIMPLIFICA EL INSTRUMENTAL: `ThemeCanvasFacts` (ya retirado) existía únicamente para componer el
       lienzo con ellos encima («un guard que componga contra el lienzo pelado mide una página que no
       existe»). Sin orbes, el par tarjeta/lienzo son dos colores planos. */

    /* 💼 La CIFRA de una tarjeta KPI, sólida: es la primera parada de la rampa que sustituye, así
       que el par de contraste que su guard medía no empeora — y ahora es UN color, no dos. */
    --ins-kpi-number: #e2e8f0;
}

/* ── 2. Global Reset & Font Rendering ─────────────────────── */
html, body {
    font-feature-settings: 'cv11', 'ss01', 'liga' 1;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

body {
    background-color: var(--mud-palette-background, #0f172a);
    overflow-x: hidden;
}

/* ── 3. (libre) — aquí vivían los orbes animados, retirados en la s110 ────────── */

/* Contexto de apilamiento del layout. Se queda aunque los orbes se hayan ido: `.mud-layout` sigue
   necesitando su capa propia para que la barra y el cajón (z-index 1100+ de MudBlazor) no compitan
   con el contenido. */
.mud-layout {
    position: relative;
    z-index: 1;
}

/* ── 4. AppBar — Glass Surface ────────────────────────────── */
.mud-appbar {
    background: var(--glass-bg-heavy) !important;
    border-bottom: 1px solid var(--glass-border) !important;
    box-shadow: none !important;
}

.mud-appbar::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 1px;
    background: var(--glass-border);
    pointer-events: none;
}

/* Brand name — usa la receta única de degradado (§4bis). Aquí solo su tipografía.
   ✂️ s86 · Y su cara pasa de Syne a Inter, por el mismo motivo MEDIDO que la escala de titulares (ver
   `MudThemeFactory.cs`): Syne dibuja los descendentes truncados —no los recorta nadie, los dibuja así—,
   y esto no es un titular de portada: es el NOMBRE DE LA CORREDURÍA, a 16 px. El día que una se llame
   «Aseguradora Vega» o «Seguros Ángel», su nombre sale con el rabo cortado en todas las pantallas de su
   aplicación. Ese caso ya estaba escrito aquí abajo como defecto latente por dato; con Inter deja de
   serlo, y la identidad de la PLATAFORMA no vive en la fuente del nombre de otra empresa. */
.app-tenant-zone__name {
    font-family: 'Inter', system-ui, sans-serif;
    font-weight: 600;
    font-size: 0.95rem;
    letter-spacing: -0.01em;
    color: var(--mud-palette-text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 22ch;
}

/* ── ZONA DE CUENTA — la correduria como CONTEXTO, no como fabricante ────────────
   El separador de la izquierda es lo que hace el trabajo: dice «esto es otra cosa» sin
   esconder nada. Sin el, dos nombres seguidos se leen como uno solo y vuelve la
   ambiguedad que este cambio corrige. */
.app-tenant-zone {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    margin-inline-start: 12px;
    padding-inline-start: 13px;
    border-inline-start: 1px solid var(--glass-border);
}

.app-tenant-zone__logo {
    height: 24px;
    max-width: 110px;
    border-radius: 6px;
    object-fit: contain;
    flex: 0 0 auto;
}

/* En pantalla estrecha manda la marca de PRODUCTO: el nombre de la correduria se
   repliega y su logotipo se queda. No se encoge la tipografia — encoger es amontonar. */
@media (max-width: 599px) {
    .app-tenant-zone__name { display: none; }
    .app-tenant-zone { margin-inline-start: 8px; padding-inline-start: 9px; }
    /* 📱 s161 · La zona cede sitio a los mandos (`.ins-appbar-shrink`), y para que el recorte llegue al
       rótulo fiscal toda la cadena hasta él tiene que poder estrecharse: si no, desborda por encima. */
    .app-tenant-zone > span,
    .app-tenant-zone .mud-menu,
    .app-tenant-zone .mud-button-root,
    .app-tenant-zone .mud-button-label { min-width: 0; max-width: 100%; overflow: hidden; }
    .app-tenant-zone__logo { max-width: 32px; flex-shrink: 0; }
    /* Medido a 390 px: la razón social quedaba en una letra. Se queda el NIF, que identifica al
       obligado por sí solo; la razón social entera la da el panel que abre este mismo rótulo. */
    .app-tenant-zone .ins-taxpayer__name { display: none; }
}

/* ── 4bis. Texto con degradado — RETIRADO (s110) ───────────────────────────────
   Se va el degradado de texto y su antidoto, con el censo delante.
   Su UNICO consumidor era el nombre comercial del TENANT en la barra
   (`.mud-appbar .mud-typography-h6`), que desde este cambio ya no es un `h6`: la barra
   ahora tiene zona de PRODUCTO (nuestra) y zona de CUENTA (suya), y el nombre de la
   correduria es tinta solida. En marcado, `.ins-gradient-text` tenia **CERO** usos.
   ⚖️ Y esto no deshace el arreglo de `f1bca1636`: lo vuelve innecesario. Aquel commit
   compensaba el recorte de `background-clip:text` con `padding-bottom` + `margin-bottom`
   negativo; sin degradado no hay caja de pintado que recorte nada, asi que el defecto
   latente que su propio comentario avisaba —«en cuanto una correduria se llame
   *Aseguradora Vega* o *Seguros Angel*, el degradado le come el rabo de la g»— deja de
   existir por dato Y por diseno.
   ⚠️ El Backoffice conserva su copia: es otro host, otra hoja y otra prioridad. */

/* ── 5. Drawer — Glass Surface ────────────────────────────── */
.mud-drawer {
    background: var(--glass-bg-heavy) !important;
    border-right: 1px solid var(--glass-border) !important;
}

.mud-drawer::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 1px;
    height: 100%;
    background: var(--glass-border);
    pointer-events: none;
}

/* Drawer: el menú de navegación scrollea dentro del drawer (alto fijo bajo el AppBar),
   de forma independiente al scroll de la página — así se alcanzan los grupos del final
   (Ajustes, Manual) sin alargar la página al abrir una categoría. */
.app-drawer .mud-drawer-content {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

.app-drawer .mud-navmenu {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
}

/* ── Barra compacta "pegajosa" de páginas de detalle (PageHeader): SOLO SU TEMA ──
   🧹 s73 · Su geometría, su ritmo y su despliegue viven en `insDetail.css` (RCL), que es el SSOT de la
   banda de detalle y lo enlazan los tres hosts. Aquí estaban las 35 líneas enteras, y las mismas 35
   estaban calcadas en el `theme.css` del backoffice y —con cuatro divergencias— en `portal.css`: tres
   copias que divergen en silencio en cuanto alguien toca una.
   Lo que se queda es lo que SÍ es de este host y el bloque neutro no puede saber: el fondo opaco de
   cristal, idéntico al de la cabecera fija de listados. */
.ins-detail-stickybar {
    background-image: linear-gradient(rgba(15, 23, 42, 0.55), rgba(15, 23, 42, 0.55));
}

/* 🌕 s73 · Y SU CONTRAPARTE CLARA, que no existía. La destapó medir el par barra/página en vivo antes de
   mover el bloque: en tema CLARO la barra COMPUTA `rgb(255,255,255)` pero se PINTA `rgb(132,138,152)`,
   un gris oscuro — porque el tinte navy de arriba se aplicaba también en claro, al 50 % sobre blanco.
   Es la misma clase que este carril lleva toda la sesión persiguiendo: un valor de tema oscuro que se
   filtra al claro porque nadie escribió la mitad que falta.
   🏆 No es invención: es EXACTAMENTE lo que esta hoja ya hace con la cabecera fija de listados, que
   declara su tinte claro `rgba(248,250,255,0.80)` junto al oscuro. El papel del tinte es el mismo en los
   dos temas —volver OPACA una superficie translúcida para que el contenido no se transparente al pasar
   por debajo—, así que lo que cambia es el color, no el mecanismo. */
body.ins-light .ins-detail-stickybar {
    background-image: linear-gradient(rgba(248, 250, 255, 0.80), rgba(248, 250, 255, 0.80));
}

/* ── PILA de tarjetas dentro de una columna de la ficha de detalle ────────────────
   🧹 M-587 · LA DECLARACIÓN DE `.ins-detail-col` YA NO VIVE AQUÍ: se fue al RCL compartido
   (`InsCore.Ui.Gadgets/wwwroot/insDetail.css`), que es donde ya vivían sus dos reglas de ritmo
   (`:has(> .ins-section)` y el margen del último bloque). Declarada en el theme del broker, la pila
   era un mecanismo que SÓLO existía en este host: el mismo `<div class="ins-detail-col">` escrito en
   el portal del tomador o en el Backoffice se quedaba en un div sin estilo —declarar sin entregar—,
   y eso es exactamente lo que iba a pasar al declarar la pila de `InsuredClaimDetail`. Los tres hosts
   enlazan `insDetail.css`; ninguno enlaza el theme de otro. */

/* ── Sección plegable de una ficha (CollapsibleSection) ───────────────────────────
   La otra mitad del defecto "sábana continua": la maquetación de la sección estaba escrita como
   `style=` sueltos dentro del componente, así que la SEPARACIÓN —lo que hace que el ojo vea dónde
   acaba una sección y empieza la siguiente— no era ajustable desde ningún sitio. Aquí sí. */
/* El radio sale del token de TARJETA y ya no es un número suelto: una sección de ficha es una
   superficie, no un control, y con el valor escrito a mano se quedaba fuera cada vez que el manual
   movía el radio de las tarjetas. */
.ins-section {
    border-radius: var(--app-radius-card);
    overflow: hidden;
}

.ins-section__head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 14px 16px 12px;
    cursor: pointer;
    user-select: none;
}

/* 📐 La fila de acciones/estado de una cabecera de sección ENVUELVE. Era un `flex` sin `flex-wrap`, así
   que cuatro chips en una tarjeta estrecha no bajaban de línea: se salían de la tarjeta y el índice
   lateral se los comía. `min-width:0` es la mitad que suele olvidarse — sin él, un hijo flexible se
   niega a encoger por debajo de su contenido y el desbordamiento vuelve por otro lado.
   Reportado por él con captura sobre los chips de recibos de una póliza con suplemento. */
.ins-section__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    min-width: 0;
    align-items: center;
    gap: 4px;
    cursor: default;
}

/* Ayuda de la sección (M-047): pegada al TÍTULO, no al grupo de acciones. La distinción no es estética
   —un icono suelto entre botones se lee como un botón más—, y la única forma de que quede junto al
   título sin cambiar el resto es que en ese caso el título deje de ser quien empuja y empuje la ayuda:
   por eso el `margin-right:auto` viaja aquí y el título renuncia a crecer SOLO cuando hay ayuda. Sin
   ayuda, nada cambia y las acciones siguen alineadas a la derecha como siempre. */
.ins-section__help {
    display: flex;
    align-items: center;
    margin-right: auto;
    cursor: default;
    color: var(--mud-palette-text-secondary);
}

.ins-section__head:has(.ins-section__help) .ins-section__title {
    flex: 0 1 auto;
}

.ins-section__chevron {
    color: var(--mud-palette-text-secondary);
    flex-shrink: 0;
}

/* El contenido arranca separado del título en lugar de pegado a él: es la separación que distingue
   "de qué se habla" de "lo que se dice", y la que faltaba para que las secciones no se mimeticen.
   M-575: con el filete bajo la cabecera (insForms.css, regla compartida de los tres componentes de
   título), este padding es el AIRE de debajo de la raya — 4px la dejaban pegada al contenido. */
.ins-section__body {
    padding: 12px 16px 16px;
}

/* El título ocupa el ancho libre de la cabecera. La jerarquía (peso, color, tracking) NO se declara
   aquí: viene de `.ins-section-title` del RCL, que es el papel compartido. Lo único que se sube en
   esta superficie es el TAMAÑO — `Typo.subtitle1` es 1rem, exactamente el mismo cuerpo que el valor
   de un dato, y con el mismo cuerpo el peso solo no bastaba para separarlos. */
.ins-section__title {
    flex: 1;
    margin: 0;
    font-size: 1.0625rem;
    line-height: 1.4;
}

/* ── 6. Cards & Papers — Glassmorphism ────────────────────── */
/* M-340 · La tarjeta declara su SUPERFICIE en los dos temas, no solo en claro.
   Lo que había era asimétrico y el usuario lo cazó por el lado roto: en CLARO la tarjeta tenía canto
   (alfa 0,20) y sombra de dos capas; en OSCURO tenía la mitad de canto (0,10) y CERO sombra —`box-shadow`
   computado: `none`—. Medido renderizado sobre `/policies/{id}`: tarjeta vs lienzo daba **1,003:1** en
   oscuro contra 1,091:1 en claro.
   ⚠️ El `box-shadow` de aquí lo pisa `body.ins-light .mud-paper`, que declara el suyo: esta línea es la
   del tema OSCURO. Y `transition` menciona `box-shadow` desde antes de que existiera la sombra — una
   transición de algo que nunca se declaraba, que es justo lo que engañaba a cualquier búsqueda por
   texto. Lo vigilaba `ACardHasItsOwnSurfaceInBothThemesTests` (ya retirado). */
.mud-paper {
    background: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-card);
    border-radius: var(--app-radius-card);
    box-shadow: var(--app-shadow-card);
    transition:
        box-shadow var(--dur-base) var(--ease-out),
        border-color var(--dur-base) var(--ease-out),
        transform var(--dur-base) var(--ease-out);
}

.mud-card {
    box-shadow: var(--app-shadow-card);
}

.mud-card:hover,
.mud-paper.app-card-hover:hover {
    box-shadow: var(--app-shadow-card-hover);
    border-color: var(--glass-border-hover);
    transform: translateY(-2px);
}

/* Dialogs */
.mud-dialog {
    background: var(--surface-dialog) !important;
    border: 1px solid var(--glass-border-hover);
    border-radius: var(--app-radius-card);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}

/* Popovers / dropdowns */
.mud-popover-paper {
    background: var(--surface-popover) !important;
    border: 1px solid var(--glass-border-hover);
    border-radius: var(--app-radius-input);
}

/* .ins-tall-popover (selects de lista larga) vive ahora en el RCL compartido insLayout.css —
   SSOT único para los 3 hosts; se eliminó de aquí para no duplicar. */

/* ── 6bis. AVISOS — superficie teñida, tinta NEUTRA ─────────────────────────────────────────────
   🔴 Reportado en vivo (s110) con captura del aviso de la póliza matriz: *«el color de ese modal
   desencaja mucho… es demasiado chillón, rompe los ojos»*.

   🧩 La causa es un token con DOS TRABAJOS. Un semántico tiene que ser CLARO para leerse como tinta
   sobre el lienzo oscuro; ese mismo color como RELLENO de un bloque grande es una plancha luminosa.
   Se rompe justo donde los dos trabajos se contradicen — la misma clase que el violeta de marca
   haciendo de tinta (M-726), por la otra punta.

   📐 Lo primero fue retirar las **7** `MudAlert Variant.Filled` que había frente a **470** con la
   variante teñida por defecto: las dos pantallas que chirriaban eran las que DIVERGÍAN, no la norma.
   Pero la variante teñida de la librería tampoco daba: medido, su prosa en color semántico se queda
   en **4,36:1** para Error en claro, y peor si el alfa sube.

   🎯 Así que la superficie del aviso se declara AQUÍ y no se hereda de un alfa de la librería que no
   se puede leer desde el repo. Y la prosa pasa a **tinta neutra**: el semántico lo llevan el ICONO y
   el CANTO, que es lo que hacen Linear, Stripe y GitHub. No es un rodeo para cumplir el suelo — es
   que la prosa en color se lee peor que la prosa normal, siempre.

   📊 Medido sobre el modelo de esta hoja, con el fondo al 14 % sobre la tarjeta:
       · prosa (TextPrimary) → peor par **9,28:1** (suelo 4,5) ✅
       · icono (semántico)   → peor par **4,21:1** (suelo gráfico 3,0) ✅
   ⚠️ Modelado, no medido en vivo: los nombres de clase de MudBlazor 8.4 se comprueban con la sonda
   tras reconstruir. Si alguno no casara, el aviso se queda en la variante teñida de la librería —
   degrada a lo de antes, no a algo roto. */
.mud-alert-text-info,
.mud-alert-text-success,
.mud-alert-text-warning,
.mud-alert-text-error {
    color: var(--mud-palette-text-primary) !important;
    border-radius: var(--app-radius-card);
    border-left: 3px solid transparent;
}

.mud-alert-text-info {
    background-color: color-mix(in srgb, var(--mud-palette-info) 14%, var(--mud-palette-surface)) !important;
    border-left-color: var(--mud-palette-info);
}
.mud-alert-text-success {
    background-color: color-mix(in srgb, var(--mud-palette-success) 14%, var(--mud-palette-surface)) !important;
    border-left-color: var(--mud-palette-success);
}
.mud-alert-text-warning {
    background-color: color-mix(in srgb, var(--mud-palette-warning) 14%, var(--mud-palette-surface)) !important;
    border-left-color: var(--mud-palette-warning);
}
.mud-alert-text-error {
    background-color: color-mix(in srgb, var(--mud-palette-error) 14%, var(--mud-palette-surface)) !important;
    border-left-color: var(--mud-palette-error);
}

/* El icono SÍ lleva el semántico: es quien dice de qué habla el aviso ahora que la prosa es neutra.
   Va por selector propio porque el `color` del contenedor lo heredaría (los iconos usan currentColor). */
.mud-alert-text-info .mud-alert-icon    { color: var(--mud-palette-info) !important; }
.mud-alert-text-success .mud-alert-icon { color: var(--mud-palette-success) !important; }
.mud-alert-text-warning .mud-alert-icon { color: var(--mud-palette-warning) !important; }
.mud-alert-text-error .mud-alert-icon   { color: var(--mud-palette-error) !important; }

/* ── 7. Tables ─────────────────────────────────────────────── */
/* 🧹 M-768 · AQUÍ VIVÍA LA JERARQUÍA DE CABECERA, y era la MITAD de una copia. La otra mitad,
   literal hasta el `letter-spacing`, estaba en el `theme.css` del backoffice, y las dos colgaban de
   `.mud-table-cell` — clase que sólo emiten `MudDataGrid` y `MudTable`. Consecuencia medida el
   30-ago-2026: las **49** pantallas con `MudSimpleTable` (que pinta `<thead><tr><th>` a pelo) y las
   **6** superficies de tabla del portal no recibían NADA. Se declara una sola vez, para los tres
   hosts y anclada al contenedor que las tres familias comparten, en
   `_content/InsCore.Ui.Gadgets/insList.css` (`🧭 M-768`). Aquí ya no queda copia que divergir, y
   tampoco variante de tema claro: el fondo canónico se compone con los tokens del tema, así que los
   dos temas los resuelve la misma declaración. */

.mud-table-root .mud-table-body .mud-table-row {
    transition: background-color var(--dur-fast) ease;
}

.mud-table-root .mud-table-row.app-row-hover:hover,
.mud-table-root .mud-table-body .mud-table-row:hover {
    background-color: rgba(148, 163, 184, 0.07) !important;
}

.mud-table-root .mud-table-cell {
    border-bottom: 1px solid var(--glass-border);
}

/* ── Listados: área de scroll acotada al viewport (patrón data-grid) ──
   ⚠️ LA BASE NO VIVE AQUÍ (M-137). `.ins-listado .mud-table-container` (altura acotada al viewport,
   scroll en ambos ejes, cabecera pegada) la declara el asset compartido del RCL,
   `_content/InsCore.Ui.Gadgets/insList.css`, el mismo que usan Backoffice y portal tomador. Este host
   era el único que NO lo enlazaba, así que llevaba su propia copia de estas reglas Y de las de
   `.app-list-toolbar*` — dos copias de la misma clase en dos zonas, que divergen en silencio en cuanto
   alguien toca una. El enlace está ahora en App.razor y aquí ya no queda nada de tabla: M-768 se
   llevó también el tinte de cabecera, que era lo último que este host declaraba por su cuenta.

   🧹 M-768 · Y CON ÉL SE VAN SUS DOS PARCHES DE OPACIDAD. Debajo había dos reglas —oscuro y claro—
   que reponían una base sólida de superficie y volvían a pintar el MISMO tinte encima con un
   degradado plano, porque el tinte original era translúcido y dejaba traslucir las filas bajo la
   cabecera pegada. El fondo canónico de `insList.css` se compone con `color-mix` sobre la superficie
   del tema: **nace opaco**, así que la reparación se queda sin sujeto. Tres declaraciones en dos
   ficheros para que un color no fuera transparente, y ninguna hace falta. */

/* ── Kanban board (Trello/Salesforce) ───────────────────────────
   Columnas en UNA fila con scroll horizontal, en lugar de un grid que
   envuelve y deja la última columna colgando abajo (caso 7 estados de
   siniestros). Compartido por los tableros de siniestros y prospectos. */
.ins-kanban-board {
    display: flex;
    flex-wrap: nowrap;
    gap: 12px;
    overflow-x: auto;
    padding-bottom: 8px;
    scroll-snap-type: x proximity;
}

.ins-kanban-column {
    flex: 0 0 248px;
    min-width: 248px;
    scroll-snap-align: start;
}

/* 🃏 LA TARJETA SE DESPEGA DE SU CARRIL, y hasta aquí no lo hacía.
   🔴 Reportado con el tablero delante: «el fondo de la card se mimetiza con el contenedor y se ve muy
   pobre». Medido en el marcado: la COLUMNA pinta `--mud-palette-background-grey` y la TARJETA no declaraba
   fondo, así que heredaba el `--mud-palette-surface` de `.mud-paper` — dos tonos casi iguales en oscuro,
   separados solo por un canto tenue. Nada en la tarjeta decía que se pudiera COGER, que es justo lo que un
   tablero tiene que comunicar antes de que nadie lo intente.
   🎯 El efecto es el de Jira/Trello —la ficha flota sobre el carril— pero con los tokens de ESTA casa: la
   sombra sale de `--app-shadow-card`, la misma de las tarjetas del resto de la aplicación, así que el
   tablero no estrena un lenguaje visual propio. Sin degradados ni bordes de color: lo que separa es la
   ELEVACIÓN, que es el único gesto que significa «esto se levanta».
   ✋ Y los tres estados que un objeto arrastrable debe tener: reposo (flota poco), hover (sube — la mano ya
   está encima) y agarrada (`:active`, cede bajo el dedo, como un objeto que responde).
   ♿ El movimiento cabe entero en `prefers-reduced-motion`: quien lo desactiva conserva la sombra y el
   contraste —que es lo que INFORMA— y pierde solo el desplazamiento, que es lo que decora.
   🔁 Vive aquí y no en cada pantalla porque los DOS tableros de la casa —siniestros y prospectos—
   comparten `.ins-kanban-board`: retocar uno solo habría dejado dos tableros con dos idiomas. */
/* 🛤️ EL CARRIL SE HUNDE PARA QUE LA FICHA PUEDA ELEVARSE, y esto es lo que faltaba.
   🔴 Medido sobre la captura del tablero ya con sombra: seguía viéndose plano. El motivo es que en TEMA
   OSCURO una sombra negra sobre fondo oscuro casi no existe — lo que despega una superficie ahí no es la
   sombra, es el CONTRASTE DE FONDO. Y la columna pintaba `--mud-palette-background-grey` mientras la
   tarjeta pinta `--mud-palette-surface`: dos tonos que MudBlazor deriva casi idénticos en oscuro, así que
   el escalón que el ojo necesita no llegaba a existir.
   🎯 Se compone EXPLÍCITAMENTE en vez de confiar en que dos tokens ajenos difieran: el carril se oscurece
   sobre el fondo de la página y la ficha se queda en la superficie de tarjeta. Es el gesto de Jira/Trello
   —el carril hundido, la ficha encima— y funciona igual en los dos temas, porque el `color-mix` va contra
   el fondo del tema vigente y no contra un color cableado. */
.ins-kanban-column-surface {
    background: color-mix(in srgb, var(--mud-palette-background) 72%, #000) !important;
}

.ins-kanban-card {
    background-color: var(--mud-palette-surface);
    box-shadow: var(--app-shadow-card);
    transition:
        box-shadow var(--dur-base) var(--ease-out),
        transform var(--dur-base) var(--ease-out);
}

.ins-kanban-card:hover {
    box-shadow: var(--app-shadow-card-hover);
    transform: translateY(-2px);
}

/* Agarrada: cede bajo el dedo y vuelve al carril. Es el gesto que confirma que el objeto respondió. */
.ins-kanban-card:active {
    box-shadow: var(--app-shadow-card);
    transform: translateY(0);
    cursor: grabbing;
}

@media (prefers-reduced-motion: reduce) {
    .ins-kanban-card {
        transition: box-shadow var(--dur-fast) ease;
    }

    .ins-kanban-card:hover {
        transform: none;
    }
}


/* ── Toolbar transversal de listas (ListToolbar) ─────────────────
   Los estilos base viven en el asset compartido `_content/InsCore.Ui.Gadgets/insList.css`
   (`.app-list-toolbar*`), el mismo que usan Backoffice y portal tomador — enlazado en App.razor.
   Aquí no queda ninguna copia: la que había era la mitad divergente de M-137. */

/* ── 8. Inputs & Buttons ───────────────────────────────────── */
/* 🔲 M-415-b · EL CANTO DE UN CAMPO YA NO SALE DEL SEPARADOR COMPARTIDO.
   Aquí ponía `var(--glass-border) !important`, o sea el MISMO token que peina la barra, el cajón y las
   filas de tabla, al 10 % de alfa. Medido sobre el modelo de esta hoja (peor lienzo de los cuatro:
   pelado + los tres orbes): **1,02:1** contra la tarjeta en oscuro y **1,11:1** en claro, contra un
   suelo de 3:1 (WCAG 2.1 SC 1.4.11 — el canto de un control no es texto). Y el campo tampoco se
   distingue por su fondo: el hueco contra su tarjeta da 1,14:1.
   ⇒ El borde pasa a su token propio, `--mud-palette-lines-inputs`, que la fábrica de tema declara por
   tema (`MudThemeFactory.cs`, con la derivación escrita). Así subir el canto del campo ya no engorda
   los siete separadores, que es exactamente lo que ataba las manos.
   🎫 El `!important` se conserva: MudBlazor pinta este `border-color` desde su propia hoja y sin él la
   declaración de la casa no llega. Lo que cambia es DE DÓNDE sale el color, no quién gana. */
.mud-input-outlined-border {
    border-color: var(--mud-palette-lines-inputs) !important;
    border-radius: var(--app-radius-input) !important;
    transition: border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}

/* 🖱️ El hover ya NO puede ser `--glass-border-hover`: ese es alfa 0,38 sobre lo que haya debajo y
   compone MÁS OSCURO que el canto en reposo (7,9:1 el reposo, 1,6:1 el hover) — el campo se apagaría
   justo al señalarlo. Es el escalón CONTIGUO de la misma rampa slate, en la dirección que separa más
   de la superficie: slate-300 en oscuro, slate-600 en claro. */
.mud-input-outlined:hover .mud-input-outlined-border {
    border-color: var(--app-input-border-hover) !important;
}

.mud-input-outlined.mud-focused .mud-input-outlined-border {
    border-color: var(--mud-palette-primary) !important;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mud-palette-primary) 22%, transparent);
}

.mud-input-control .mud-input-slot {
    border-radius: var(--app-radius-input);
    background: rgba(15, 23, 42, 0.45);
}

.mud-button-root {
    border-radius: var(--app-radius-button) !important;
    text-transform: none;
    font-family: 'Inter', system-ui, sans-serif;
    font-weight: 500;
    letter-spacing: 0.02em;
    transition:
        box-shadow var(--dur-fast) var(--ease-out),
        transform var(--dur-fast) var(--ease-out);
}

/* ── 🎨 EL RELLENO DEL BOTÓN PRIMARIO ES PLANO, Y ESO ES LO QUE LO HACE MEDIBLE ──────────────────────
   Aquí había un degradado diagonal entre los dos escalones del azul de marca. Un degradado no tiene UN
   contraste: tiene un RANGO, y el rótulo blanco viaja por todo ese rango. En el extremo claro se quedaba
   en **3,68:1**, por debajo del suelo de 4,5:1 — o sea que el botón cumplía en una punta e incumplía en
   la otra, y ninguna medida de un solo punto podía decir cuál de las dos estaba mirando.

   ✅ Plano `#4f46e5` (indigo-600) con rótulo blanco: **6,29:1** en TODA la superficie del botón (s110;
   antes `#2563eb`, 5,17:1, cuando la marca era azul), y el
   mismo valor en los dos temas — el relleno es una pregunta distinta de la del enlace, que sí se parte
   por tema (ver `AppThemeOptions.PrimaryLight`/`PrimaryDark`): ahí el azul es TINTA sobre el lienzo;
   aquí el azul es el FONDO y la tinta va encima, así que el tema de la página no entra en el par.

   ⚪ El `color` se declara explícito y no se hereda de `--mud-palette-primary-text`: sin esta línea el
   rótulo depende de lo que la fábrica de tema calcule para cada modo, y la medida de arriba deja de ser
   una propiedad de esta hoja. El botón APAGADO no se ve afectado: sus reglas van más abajo, con la misma
   especificidad, y en CSS gana la última.
   🌗 Sin variante `body.ins-light`: es el mismo relleno en los dos temas, a propósito. */
.mud-button-filled.mud-button-filled-primary {
    background: #4f46e5 !important;
    color: #ffffff !important;
    box-shadow: var(--app-shadow-card);
}

.mud-button-filled.mud-button-filled-primary:hover {
    box-shadow: var(--app-shadow-card-hover);
    transform: translateY(-1px);
}

.mud-button-filled.mud-button-filled-primary:active {
    transform: translateY(0);
    box-shadow: var(--app-shadow-card);
}

/* ── 🔇 UN BOTÓN APAGADO TIENE QUE SEGUIR DICIENDO QUÉ PIDE ────────────────────────────────────────
   🔴 De qué defecto nace (medido en vivo por él, s86, sobre el diálogo «Comisión de este producto»):
   «aquí no se lee lo que pide el botón, se mimetiza con el fondo». El botón era «Retirar la
   declaración», apagado hasta escribir el motivo — y en ese estado su rótulo desaparecía contra el
   panel oscuro.

   🥇 Por qué importa más de lo que parece, y no es cosmética: un botón apagado es la ÚNICA pista de que
   una acción existe y de qué le falta para poder usarla. Si no se lee, la acción no existe para quien
   mira. El caso que lo destapó es exactamente ése: él preguntó «he declarado que este producto no
   reparte comisión, ¿hay algún mecanismo para arrepentirme?» teniendo la inversa delante, ilegible.

   📏 El reparto de MudBlazor para lo apagado en tema oscuro es `rgba(255,255,255,.3)` sobre superficies
   que ya son oscuras: por debajo de 2:1 contra el panel de un diálogo. Aquí se sube el texto a 0,62 de
   blanco —legible sin dejar de leerse como apagado— y se le da al relleno un fondo propio para que el
   botón siga teniendo CUERPO, que es la otra mitad de «no se ve»: sin fondo, no parece un botón.

   ⛔ Lo que NO se hace: devolverle el color vivo. Apagado tiene que SEGUIR pareciendo apagado — quien
   lo vea no debe intentar pulsarlo. Se recupera la LEGIBILIDAD, no la llamada a la acción. */
.mud-button-root:disabled,
.mud-button-root.mud-disabled,
.mud-button-root[disabled] {
    color: rgba(255, 255, 255, 0.62) !important;
}

.mud-button-filled:disabled,
.mud-button-filled.mud-disabled,
.mud-button-filled[disabled] {
    background: rgba(255, 255, 255, 0.10) !important;
    box-shadow: none;
}

/* El icono viaja con su rótulo: apagarlo más que al texto lo convierte en una mancha. */
.mud-button-root:disabled .mud-icon-root,
.mud-button-root.mud-disabled .mud-icon-root,
.mud-button-root[disabled] .mud-icon-root {
    color: inherit !important;
}

/* 📏 M-966 · LAS COBERTURAS DE UNA FICHA: CADA CAMPO OCUPA SU COLUMNA. Un campo de MudBlazor dentro de una celda
   se encoge a su contenido —medido el 22-sep-2026 en el diálogo de cambio: celda de 210 px, campo de 74—, así que
   la fila se leía como un formulario roto. El ancho lo sigue fijando la cabecera de la tabla; esto solo hace que
   el campo lo herede, y se acota a esta tabla para no tocar ninguna otra. */
.ins-cov-table td .mud-input-control {
    width: 100%;
}

/* 📐 M-966 · Y LA FILA SE ALINEA POR ARRIBA, que es lo que la casilla «Incluida» rompía. Reportado por él con la
   captura: esa casilla vive en la celda del CAPITAL, así que estira la celda y, al centrarse el contenido, el
   campo de capital subía respecto a los demás. Medido: centros en 361 · **349** · 363 · 361, con el capital 12 px
   más alto. Alineando por el borde superior, todos los campos empiezan a la misma altura y «Incluida» cuelga
   debajo sin mover nada.
   🎯 El selector ESPEJA al de MudBlazor (`.mud-simple-table table * tr > td`, que hereda el `middle` de la fila):
   con menos peso, la regla no llegaba a aplicarse.
   ⚖️ Y EL HUECO DE ARRIBA LO PONE LA CELDA, no cada campo: uno con rótulo se reserva 8 px para su etiqueta
   flotante y uno sin rótulo 4, así que dejar que cada cual ponga el suyo los desalinea 4 px —medido: «Garantía» y
   «Franquicia» en 325 contra «Capital» y «Prima» en 329—. Puesto una sola vez en la celda, los seis controles
   arrancan en el mismo píxel: medido después, los seis en 329 y su centro en 349. */
.ins-cov-table table * tr > td {
    vertical-align: top;
    padding-top: 14px !important;
}

.ins-cov-table td .mud-input-control,
.ins-cov-table td > *:first-child {
    margin-top: 0 !important;
}

/* Y los dos controles pequeños —«Principal» y la papelera— ocupan el ALTO DE UN CAMPO y se centran dentro, que es
   lo que hace que su centro coincida con el de los campos sin depender de cuánto mide cada icono. */
.ins-cov-table td.ins-cov-mando > * {
    display: inline-flex;
    align-items: center;
    height: 40px;
}

/* 📐 M-966 · Y LA LISTA DE GARANTÍAS NO EMPUJA AL RESTO DEL FORMULARIO: se desplaza dentro de su propia caja.
   Sin esto, cada garantía añadida alargaba el diálogo entero y alejaba el motivo, el tomador y el pie: medido en
   1366×768, 446 px de desplazamiento con tres garantías. El tope es relativo a la pantalla para que en un monitor
   grande se vean más filas sin tocar nada. */
.ins-cov-table {
    max-height: 35vh;
    overflow-y: auto;
}

/* 🧾 24-sep-2026 · Y LA TABLA DE CAMBIOS REGISTRADOS DE UNA FICHA, igual: si crece, se desplaza dentro de su caja con
   la cabecera fija (FixedHeader), en vez de empujar Recibos y Siniestros hacia abajo. Más alta que la de garantías
   porque vive en la página y no dentro de un diálogo. */
.ins-changes-table {
    max-height: 50vh;
    overflow-y: auto;
}

/* ☑️ M-965 · LA EXCEPCIÓN: UNA CASILLA APAGADA NO ES UN BOTÓN CON RÓTULO. Para MudBlazor el cuadradito de
   una casilla, un radio o un interruptor es un `.mud-button-root`, así que la regla de arriba lo subía a
   blanco 0,62 y el texto no se atenuaba nada. Medido en vivo (22-sep-2026, «Corrijo un error de mi
   transcripción»): la casilla apagada, `input.disabled = true`, pintaba su cuadro en blanco 0,62 frente al
   `#a5b4fc` de las activas, con el MISMO texto `#e2e8f0`, y él la leyó como disponible. Aquí lo que se lee es
   el texto de al lado, así que el cuadro toma el gris de lo apagado del tema y el texto el de las ayudas:
   legible y apagado a la vez, en los dos temas, porque son variables del tema y no un color escrito. */
.mud-checkbox.mud-disabled .mud-button-root,
.mud-radio.mud-disabled .mud-button-root,
.mud-switch.mud-disabled .mud-button-root {
    color: var(--mud-palette-action-disabled) !important;
}

.mud-checkbox.mud-disabled,
.mud-radio.mud-disabled,
.mud-switch.mud-disabled {
    color: var(--mud-palette-text-secondary);
}

/* ── 9. Nav Links ─────────────────────────────────────────── */
.mud-nav-link {
    margin: 2px 8px;
    border-radius: var(--app-radius-button);
    transition:
        background-color var(--dur-fast) ease,
        color var(--dur-fast) ease;
}

.mud-nav-link:hover {
    background-color: rgba(148, 163, 184, 0.08);
}

/* 🎨 EL ENLACE ACTIVO TAMBIÉN PIERDE SU DEGRADADO, POR LA MISMA RAZÓN QUE EL BOTÓN PRIMARIO — y es la
   CLASE, no el caso: aquí el tinte de acento se desvanecía de izquierda a derecha por debajo del
   rótulo, así que el par texto/fondo valía una cosa al empezar la palabra y otra al acabarla.
   Se queda PLANO en el extremo MÁS FUERTE del tinte, que es el que decidía el peor par: así el peor
   contraste no empeora ni un punto (calculado sobre el modelo de esta hoja: 6,14:1 en oscuro con el
   azul claro del rótulo, 5,23:1 en claro con su azul oscuro) y la pastilla del activo se lee entera
   en vez de disolverse a la mitad. Un enlace de menú activo es un control con texto encima; el criterio
   es el mismo que arriba, no una excepción.
   ⛔ Y NO se toca el color del rótulo para «alinearlo» con `--mud-palette-primary`: sobre este mismo
   tinte el azul de la paleta cae a 4,24:1, por debajo del suelo. El escalón claro que hay aquí es
   deliberado, exactamente igual que el desdoble por tema de `AppThemeOptions`. */
.mud-nav-link.active {
    background: color-mix(in srgb, var(--mud-palette-primary) 18%, transparent);
    color: var(--mud-palette-primary) !important;
    border-radius: var(--app-radius-button);
    box-shadow: inset 3px 0 0 var(--mud-palette-primary);
}

.mud-nav-link.active .mud-icon-root {
    color: var(--mud-palette-primary) !important;
}

/* ── 10. KPI Cards ────────────────────────────────────────── */
/* M-572 · La tarjeta KPI se construye SOBRE la superficie de M-340, no en su lugar.
   Re-medido renderizado el 17-ago (sonda Playwright, Home y /analytics, 1440×900, tema fijado por
   preferencia + recarga): la premisa de la ficha era FALSA — el par TEXTO/TARJETA estaba sano (peor
   punto medido 5,90:1 en oscuro y 4,86:1 en claro, sobre un umbral de 3:1 para cifra h3/800). El que
   estaba roto era el par TARJETA/LIENZO: el degradado anterior terminaba en rgba(10,22,50,0.60), que
   compone POR DEBAJO del lienzo —medido en Home oscuro: 1,011:1 en la esquina oscura—, o sea la clase
   exacta de M-340 viva aquí porque este `background` con `!important` pisa el `--glass-bg` que aquel
   mandato subió. La cifra parecía «mimetizarse» porque su tarjeta entera no tenía superficie.
   🌳 Raíz: el fondo propio deja de rehacer la superficie y pasa a ser un TINTE de acento que se
   desvanece SOBRE `var(--glass-bg)` — si la superficie de M-340 se mueve, la KPI la sigue sola.
   Los dos pares juntos (texto/tarjeta ≥ suelo, tarjeta/lienzo ≥ suelo) los vigilaba
   `AKpiNumberAndItsCardKeepBothContrastPairsTests` (ya retirado): son suelo y techo del MISMO fondo. */
.app-kpi-card {
    position: relative;
    /* 🧹 s110 · Sin tinte de color ni resplandor: una tarjeta de KPI es una tarjeta. Lo que la
       distingue es su CIFRA, no un halo. */
    background: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-card) !important;
    box-shadow: var(--app-shadow-card);
    transition:
        box-shadow var(--dur-base) var(--ease-out),
        transform var(--dur-base) var(--ease-out),
        border-color var(--dur-base) ease;
}

/* Tarjetas navegables: acento azul claro + cursor de enlace, distinguible YA en reposo. */
.app-kpi-card--link {
    cursor: pointer;
    border-color: color-mix(in srgb, var(--mud-palette-primary) 32%, transparent) !important;
}

/* Tarjetas SOLO informativas (sin destino): tono neutro y sin glow azul, para que recedan
   y el contraste con las navegables se lea de un vistazo sin necesidad de hover.
   M-572: mismo esquema que la navegable — tinte que se desvanece SOBRE `var(--glass-bg)`, nunca un
   fondo que rehaga la superficie (el anterior terminaba en rgba(10,22,50,0.55): bajo el lienzo). */
.app-kpi-card:not(.app-kpi-card--link) {
    background:
        linear-gradient(
            135deg,
            rgba(148, 163, 184, 0.06) 0%,
            rgba(148, 163, 184, 0.00) 100%
        ),
        var(--glass-bg) !important;
    border-color: rgba(148, 163, 184, 0.12) !important;
    box-shadow: var(--app-shadow-card);
}

/* Afordancia "ir a": solo las tarjetas navegables se elevan al hover e indican destino. */
.app-kpi-card--link:hover {
    /* 🧹 s110 · Sin halo de color y sin levitar 3 px: el movimiento explica un cambio de estado,
       no premia el hover. Lo que dice «esto lleva a algún sitio» es el CANTO y la flecha. */
    box-shadow: var(--app-shadow-card-hover);
    border-color: color-mix(in srgb, var(--mud-palette-primary) 50%, transparent) !important;
}

/* Flecha "ir a": claramente visible en reposo (pastilla con fondo) y plena al hover. */
.app-kpi-card__go {
    position: absolute;
    bottom: 10px;
    right: 12px;
    opacity: 0.75;
    color: var(--mud-palette-primary);
    background: color-mix(in srgb, var(--mud-palette-primary) 14%, transparent);
    border-radius: 999px;
    padding: 2px;
    transition: opacity var(--dur-base) ease, transform var(--dur-base) ease,
        background-color var(--dur-base) ease;
}

.app-kpi-card--link:hover .app-kpi-card__go {
    opacity: 1;
    background: color-mix(in srgb, var(--mud-palette-primary) 24%, transparent);
    transform: translate(2px, -2px);
}

/* ── 💼 LA CIFRA DE UNA TARJETA ES UN DATO DE NEGOCIO, NO UN TITULAR DE PORTADA ───────────────────
   Reportado por él en vivo (s74) sobre `/` de la app del corredor: *«el tamaño es desproporcionadamente
   grande en todas las cards de este tipo … no ese estilo todo inclinado cursivo, algo más profesional
   empresarial»*, y con el defecto medible delante: **«63 · 26.957 EUR» se partía en TRES renglones**.

   🔴 De dónde venía. La receta era «Syne display para MÁXIMO IMPACTO» a peso 800 más el degradado de
   marca recortado sobre el texto. Syne es una tipografía DISPLAY —caja alta, ejes geométricos, remates
   inclinados—: en un titular de una palabra funciona, y en un importe de quince caracteres lo que hace es
   inflarlo hasta que no cabe. Y una cifra que no cabe **se parte**, que es justo lo que M-590 y M-574
   persiguen en las tablas: *una cifra que se parte deja de ser la cifra*.

   ✅ Qué se pone, y por qué cada pieza:
   · `Inter` — la fuente de la INTERFAZ. Un número lo lee alguien que compara, no alguien que admira.
   · peso 600 y `-0.01em` — presencia sin gritar; el rótulo de encima ya va en 500.
   · `tabular-nums` — las cifras de dos tarjetas contiguas alinean sus dígitos, que es lo que permite
     compararlas de un vistazo. Es la misma decisión que ya toman las tablas de importes de la casa.
   · **sin degradado** — el recorte sobre texto obligaba a `padding-bottom` para no comerse los rabos y
     dejaba la cifra en `text-fill-color: transparent`: mucha maquinaria para decorar un dato.
   · `1.375rem` en vez de `1.5rem` — con Inter a este cuerpo, «63 · 26.957 EUR» entra en UN renglón en la
     tarjeta más estrecha. ⛔ No se pone `nowrap`: si algún día una cifra no cabe, que baje de línea es
     feo, pero recortarla **pierde el dato**, y eso no se hace nunca.
   🧹 Alcance: las **26** instancias de `KpiCard` (Inicio, Analítica de cartera y la vista 360 del
   cliente), que es lo que él vio compartiendo clase. */
.app-kpi-card .mud-typography-h3,
.app-kpi-card .mud-typography-h4 {
    font-family: 'Inter', system-ui, sans-serif;
    font-weight: 600;
    font-size: 1.375rem;
    line-height: 1.3;
    letter-spacing: -0.01em;
    font-variant-numeric: tabular-nums;
    color: var(--ins-kpi-number);
}

/* ── 11. Empty State ──────────────────────────────────────── */
.app-empty-state {
    padding: 64px 24px;
    text-align: center;
    color: var(--mud-palette-text-secondary);
}

/* `>` y no descendiente: el glifo de 64 px es el del VACÍO, el que EmptyState pinta como hijo directo.
   Sin el `>` la regla alcanzaba también al icono del BOTÓN de la salida —M-270 obliga a que todo vacío
   ofrezca una— y lo inflaba a 64 px dentro del botón. Medido en vivo (16-ago) sobre /tasks, y no era de
   esa pantalla: son las ~10 salidas con `StartIcon` de los dos hosts, que llevaban el mismo botón
   deforme. */
.app-empty-state > .mud-icon-root {
    width: 64px;
    height: 64px;
    margin-bottom: 16px;
    opacity: 0.30;
    /* 🧹 s110 · aqui habia un `drop-shadow` azul de 12 px. Un icono de estado vacio no necesita
       brillar: lo que tiene que hacer es no competir con el texto que dice QUE falta. */
}

/* ── 12. Page Entry Animations ────────────────────────────── */
/* 🔴 `backwards`, NUNCA `both` — y esto es un HECHO MEDIDO, no una precaución.
   Un `transform` en un ancestro convierte a `.mud-container` en el BLOQUE CONTENEDOR de todo lo que
   cuelgue dentro con `position: fixed`: deja de estar fijo a la PANTALLA y pasa a estarlo al DOCUMENTO.
   La mitigación que había aquí —omitir `transform` en la keyframe `to`, confiando en que así el valor
   final volviera a `none`— NO FUNCIONA, y llevaba escrita en este comentario desde que se escribió: con
   `forwards` (la mitad de `both`) el navegador RETIENE la propiedad animada y deja
   `matrix(1, 0, 0, 1, 0, 0)`, que para el bloque contenedor cuenta igual que cualquier otro transform.

   🔬 MEDIDO el 4-sep-2026 con la app en pie, en `/policies/POL-2026-000007` a 1600×900: el tirador del
   índice (`.ins-detail-rail-handle`, `position: fixed; top: 50%`) se resolvía contra un contenedor de
   8.432 px y caía en el píxel **4.210 del DOCUMENTO** — había que scrollear hasta la mitad de la ficha
   para dar con él, que es exactamente como él lo reportó: «hay que scrollear para buscarlo». La posición
   sí era el problema; el comentario del tirador que lo descartaba se apoyaba en leer `position: fixed`
   en la hoja, y `fixed` no dice contra QUÉ. Con `backwards`, misma sonda: `transform: none` y el tirador
   clavado en `top: 412` a cualquier scroll.

   ⚖️ `backwards` conserva lo que la animación necesita —el estado `from` durante el `animation-delay`,
   que es lo que impide el parpadeo de los items escalonados— y suelta lo único que sobraba: retener al
   final una propiedad cuyo valor base ya es el bueno. La entrada se ve igual.
   ⇒ Y cierra de paso el motivo por el que este comentario nació: los popovers `fixed` de MudBlazor
   (MudSelect, tooltips, date pickers) dejan de tener debajo un bloque contenedor falso. */
.mud-main-content > .mud-container {
    animation: pageEnter var(--dur-slow) var(--ease-out) backwards;
}

@keyframes pageEnter {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; }
}

/* Staggered grid items. `backwards` por lo MISMO que arriba, y aquí con más superficie: cada `.mud-item`
   con transform residual capturaba lo `fixed` de su propia celda. El `from` se sigue aplicando durante el
   escalonado, que es para lo único que hacía falta la mitad `backwards` del `both`. */
.mud-grid > .mud-item {
    animation: itemEnter var(--dur-slow) var(--ease-out) backwards;
}

.mud-grid > .mud-item:nth-child(1) { animation-delay: 0ms; }
.mud-grid > .mud-item:nth-child(2) { animation-delay: 60ms; }
.mud-grid > .mud-item:nth-child(3) { animation-delay: 120ms; }
.mud-grid > .mud-item:nth-child(4) { animation-delay: 180ms; }
.mud-grid > .mud-item:nth-child(5) { animation-delay: 240ms; }
.mud-grid > .mud-item:nth-child(6) { animation-delay: 300ms; }
.mud-grid > .mud-item:nth-child(7) { animation-delay: 360ms; }
.mud-grid > .mud-item:nth-child(8) { animation-delay: 420ms; }

/* `to` sigue sin declarar `transform`, pero eso YA NO ES LO QUE SOSTIENE LA REGLA —medido: no bastaba—:
   lo que la sostiene es el `backwards` de arriba. Se deja así porque el estado en reposo debe ser el
   estilo base del elemento y no una matriz escrita por una animación terminada. */
@keyframes itemEnter {
    from { opacity: 0; transform: translateY(12px) scale(0.99); }
    to   { opacity: 1; }
}

/* Chips */
.mud-chip {
    border-radius: 999px !important;
    font-family: 'Inter', system-ui, sans-serif;
    font-size: 0.72rem;
    font-weight: 500;
}

/* Progress bars */
.mud-progress-linear .mud-progress-linear-bar {
    background: var(--mud-palette-primary) !important;
    border-radius: 999px;
}

/* Snackbar */
.mud-snackbar {
    border: 1px solid var(--glass-border-hover);
    border-radius: var(--app-radius-input);
}

/* ── 13. Light Mode Overrides ─────────────────────────────── */
/* MudBlazor v7 does NOT add a class to <body>; we inject ins-light/ins-dark
   via JS (insCoreTheme.applyTheme) so these selectors fire reliably. */

body {
    transition: background-color 300ms ease;
}

body.ins-light {
    background-color: #f1f5f9;

    /* Modo claro: las DOS rampas del texto con degradado convergen en la misma (oscuro→azul).
       Antes esto eran dos bloques gemelos repitiendo la receta entera (marca del AppBar y cifras
       KPI); ahora solo se reescribe el token y la mecánica sigue viviendo en §4bis. */
    --ins-kpi-number: #0f172a;

    /* 🔲 M-415-b · el hover del canto de campo, en CLARO. La rampa se recorre al revés: en oscuro el
       borde se ALEJA hacia arriba (slate-300) y aquí hacia abajo (slate-600, 7,52:1 contra la tarjeta).
       El reposo no hace falta reescribirlo: lo trae `--mud-palette-lines-inputs`, que `MudThemeProvider`
       ya inyecta con el valor de CADA tema. */
    --app-input-border-hover: #475569;

    /* 🧭 M-768 · El tinte de la cabecera de tabla, en CLARO: el mismo valor que tenía la regla
       `body.ins-light .mud-table-root .mud-table-head .mud-table-cell` que este mandato retiró. Lo que
       cambia no es el color, es que ahora sólo se reescribe el TOKEN y la regla es única. */
    --ins-table-head-tint: rgba(241, 245, 249, 0.85);
}


body.ins-light .mud-paper {
    /* s110 · OPACA. El alfa 0,92 era del cristal; sin `backdrop-filter` detras solo servia para
       dejar pasar el lienzo y ACERCAR la tarjeta a su pagina. Blanco puro da 1,096:1 (suelo 1,08). */
    background: #ffffff !important;
    border-color: rgba(148, 163, 184, 0.20);
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08), 0 1px 2px rgba(15, 23, 42, 0.04);
}

body.ins-light .mud-appbar {
    background: #ffffff !important;
    border-bottom-color: rgba(148, 163, 184, 0.20) !important;
}

body.ins-light .mud-appbar::after {
    opacity: 0.5;
}

body.ins-light .mud-drawer {
    background: #f8fafc !important;
    border-right-color: rgba(148, 163, 184, 0.20) !important;
}

body.ins-light .mud-dialog {
    background: #ffffff !important;
    border-color: rgba(148, 163, 184, 0.25);
    box-shadow: 0 24px 80px rgba(15, 23, 42, 0.15);
}

body.ins-light .mud-popover-paper {
    background: #ffffff !important;
    border-color: rgba(148, 163, 184, 0.20);
}

body.ins-light .mud-input-control .mud-input-slot {
    background: rgba(248, 250, 252, 0.85);
}

/* 🔇 El botón apagado, en CLARO. La regla de §8 sube el rótulo a blanco 0,62 —que es lo legible sobre
   una superficie oscura— y aquí eso sería tinta clara sobre papel claro: el mismo defecto por el otro
   lado. Se invierte al equivalente oscuro, y el relleno gana un gris propio para que el botón siga
   teniendo cuerpo. Un tema que arregla el contraste solo en su mitad no lo arregla. */
body.ins-light .mud-button-root:disabled,
body.ins-light .mud-button-root.mud-disabled,
body.ins-light .mud-button-root[disabled] {
    color: rgba(15, 23, 42, 0.55) !important;
}

body.ins-light .mud-button-filled:disabled,
body.ins-light .mud-button-filled.mud-disabled,
body.ins-light .mud-button-filled[disabled] {
    background: rgba(15, 23, 42, 0.08) !important;
}

/* 🌕 s73 · EN CLARO LA TARJETA KPI ERA UN HUECO, NO UNA SUPERFICIE. Medido renderizado el 17-ago-2026
   sobre la app en pie (sonda de píxeles, Home 1440×900, velo de reconexión comprobado): **7 de las 8
   tarjetas componían POR DEBAJO de su propia página**, peor par **1,003:1**. La causa es el TINTE: sobre
   un lienzo claro un tinte de acento solo puede RESTAR luminancia, y el lienzo `#f0f4ff` ya es azulado,
   así que tarjeta y página acababan en el mismo tono y en la misma luminancia. Es la clase de M-340
   viva en el tema claro.
   🏆 El arreglo es el estándar del sector, y es el que esta hoja YA usa para `.mud-paper` en claro: en
   tema claro la elevación NO la da la superficie —el techo físico de una tarjeta blanca sobre este
   lienzo es 1,10:1, CALCULADO, no medido: componer blanco puro sobre `#f0f4ff` no da más—, la da la
   SOMBRA. Así que el acento se muda del FONDO al CANTO (donde en claro sí se ve y no le quita luz a la
   tarjeta) y la superficie vuelve a ser la blanca del sistema.
   La sombra deja de ser un halo azul al 0,08 —invisible sobre un lienzo azulado— y pasa a ser la
   sombra NEUTRA de dos capas del resto de tarjetas claras.
   Resultado calculado: 1,096:1 sobre el lienzo pelado y 1,138:1 bajo un orbe, siempre POR ENCIMA. */
body.ins-light .app-kpi-card {
    background: #ffffff !important;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.10), 0 4px 12px rgba(15, 23, 42, 0.06);
}

/* Modo claro: navegables con acento azul, informativas con canto pizarra. La distinción se lee en el
   CANTO y en la flecha «ir a», no en el fondo — que es de donde hubo que sacarla.
   ⚠️ El canto NO se declara en la regla base de arriba: toda tarjeta es una de estas dos, así que un
   `border-color` ahí no lo ve nadie. Lo tuvo un rato y era una declaración MUERTA con el mismo valor
   que ésta — el andamiaje también es lo que se queda repetido sin pintar nada. */
body.ins-light .app-kpi-card--link {
    border-color: rgba(79, 70, 229, 0.35) !important;
}

body.ins-light .app-kpi-card:not(.app-kpi-card--link) {
    background: #ffffff !important;
    border-color: rgba(100, 116, 139, 0.22) !important;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08), 0 4px 12px rgba(15, 23, 42, 0.05);
}

/* 🧹 M-768 · AQUI VIVIA el tinte claro de la cabecera de tabla (`rgba(241,245,249,.85)`), la variante
   por tema de una regla que ya no existe. Muere por el mismo motivo que la de s110 de aqui abajo: la
   declaracion canonica de `insList.css` compone su fondo con `color-mix` sobre `--mud-palette-surface`
   y la tinta del tema, asi que en oscuro aclara y en claro oscurece SIN una segunda regla. Una
   excepcion por tema solo se justifica cuando el token no puede contestar; aqui contesta. */

/* 🧹 s110 · AQUI VIVIA `body.ins-light .mud-nav-link.active`, con su rotulo `#1d4ed8` y su filete
   `#2563eb` cableados. Deja de existir porque deja de hacer falta: la regla oscura los deriva de
   `--mud-palette-primary`, y ese token YA es el indigo-600 en claro. Una excepcion por tema que solo
   existia porque el azul de la paleta no cruzaba el suelo en el tinte de la pastilla (4,24:1); con
   indigo cruza en los dos —8,23:1 en oscuro y 4,58:1 en claro, medido sobre el cajon real—. */


/* ── 14. Responsive Media Queries ─────────────────────────── */

/* Mobile — < 600px */
@media (max-width: 599px) {
    .mud-main-content > .mud-container {
        padding: 12px !important;
    }

    /* Smaller orbs on mobile to save GPU */

    /* 🗓️ NINGUNA SUPERFICIE FLOTANTE MAS ANCHA QUE LA PANTALLA. Un desplegable, un menú o el panel
       del calendario se posicionan respecto a su anclaje, y en 360 px eso los saca por el costado —el
       sintoma que el usuario ve es una barra horizontal que aparece SOLO al abrir algo—.
       ⚠️ Acotación DEFENSIVA y honesta sobre lo que se pudo medir: en la s110 el panel del calendario
       NO se llegó a montar en la sonda (con `Editable` el campo enfoca para teclear y el gesto que lo
       abre es el adorno), asi que el eje de ANCHURA de `insPlacement.js` —que hoy solo resuelve la
       altura, y lo dice su propio comentario— sigue pendiente y esta anotado como tal. Esto no lo
       sustituye: impide el desbordamiento, no coloca el panel donde toca. */
    .mud-popover-paper,
    .mud-picker-container .mud-picker-content {
        max-width: calc(100vw - var(--ins-float-gutter)) !important;
    }

    /* Bottom sheet dialogs on mobile */
    .mud-dialog-container .mud-dialog {
        margin: 0 !important;
        /* Hoja inferior en móvil: solo las esquinas de ARRIBA, con el mismo radio de tarjeta que el
           diálogo tiene en escritorio. Antes era un número suelto más grande que el del manual. */
        border-radius: var(--app-radius-card) var(--app-radius-card) 0 0 !important;
        position: fixed !important;
        bottom: 0 !important;
        left: 0 !important;
        right: 0 !important;
        max-width: 100% !important;
        max-height: 92vh;
        overflow-y: auto;
    }
}

/* Tablet — 600px–959px */
@media (min-width: 600px) and (max-width: 959px) {
    .mud-main-content > .mud-container {
        padding: 16px !important;
    }

}

/* Accessibility — reduced motion */
/* prefers-reduced-motion: la regla universal vive en insBrand.css (RCL compartido, A0.3 del
   rebranding) — *, *::before, *::after con !important ya cubre orbes, tarjetas, botones y nav
   links sin enumerarlos uno a uno aquí, que es como este bloque quedaría desactualizado el día
   que naciera una clase nueva con animación propia. */

/* Malla de seguridad anti-desborde para tooltips de la LIBRERÍA MudBlazor: acota el ancho y permite
   wrap para que ningún popover suyo se pinte a ancho completo. La aplicación ya NO tiene ni un solo
   MudTooltip propio (canal único = InsTooltip, guardado por TooltipChannelTests); esto queda solo por
   lo que MudBlazor pueda emitir por dentro. */
.mud-tooltip {
    max-width: min(360px, 90vw);
    white-space: normal;
    overflow-wrap: anywhere;
}

/* ── 15. Reconexión del circuito (Blazor Server) ───────────────
   Overlay visible cuando se cae la conexión SignalR. Sin esto la app quedaba congelada en
   silencio (ver App.razor + insCoreReconnect en theme.js). Blazor alterna las clases
   components-reconnect-show/-failed/-rejected sobre #components-reconnect-modal. */
#components-reconnect-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 20000; /* por encima de diálogos/popovers MudBlazor */
    align-items: center;
    justify-content: center;
    background: rgba(3, 8, 20, 0.72);
}

#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected {
    display: flex;
}

.ins-reconnect__box {
    background: var(--glass-bg-heavy);
    border: 1px solid var(--glass-border-hover);
    border-radius: var(--app-radius-card);
    box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6);
    padding: 28px 36px;
    text-align: center;
    color: #e2e8f0;
    font-family: 'Inter', system-ui, sans-serif;
    max-width: 90vw;
}

.ins-reconnect__spinner {
    width: 36px;
    height: 36px;
    margin: 0 auto 16px;
    border: 3px solid rgba(148, 163, 184, 0.25);
    border-top-color: var(--mud-palette-primary);
    border-radius: 50%;
    animation: ins-reconnect-spin 0.8s linear infinite;
}

@keyframes ins-reconnect-spin { to { transform: rotate(360deg); } }

.ins-reconnect__msg { margin: 0; font-size: 0.95rem; }

/* El bloque de fallo solo aparece cuando se agotan los reintentos o el circuito es rechazado. */
.ins-reconnect__failed { display: none; }
.components-reconnect-failed .ins-reconnect__failed,
.components-reconnect-rejected .ins-reconnect__failed { display: block; margin-top: 12px; }
/* En fallo/rechazo ocultamos SOLO el mensaje "reconectando…" (lo sustituye el bloque de
   recuperación), pero el spinner SIGUE girando: estamos auto-recargando, no muertos. */
.components-reconnect-failed .ins-reconnect__msg,
.components-reconnect-rejected .ins-reconnect__msg { display: none; }

.ins-reconnect__failed button {
    margin-top: 10px;
    padding: 8px 20px;
    border: none;
    border-radius: var(--app-radius-button);
    /* 🎨 Mismo criterio que el botón primario de la app, y por el mismo motivo medido: con el escalón
       claro del azul debajo, este rótulo blanco se quedaba en 3,68:1. Con blue-600 son 5,17:1.
       El botón de recuperar la conexión es, por definición, el que se pulsa cuando algo ya ha ido mal:
       es el último sitio donde puede permitirse no leerse. */
    background: #4f46e5;
    color: #fff;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
/* El hover baja un escalón más (blue-700). Oscurecer un relleno con rótulo blanco encima solo puede
   MEJORAR ese par, nunca romperlo, así que el estado no necesita medida propia. */
.ins-reconnect__failed button:hover { background: #4338ca; }

body.ins-light #components-reconnect-modal { background: rgba(15, 23, 42, 0.45); }
body.ins-light .ins-reconnect__box { background: rgba(255, 255, 255, 0.98); color: #0f172a; }

/* ── 16. Antídoto overlay de popover — M-929 · movido a insResilience.css (SSOT única, 3 hosts). */

/* ── 17. Pestañas: ninguna flecha que no pueda desplazar nada ───────────────────
   Reportado por el usuario en `/claims/{id}`: el contenedor de pestañas pinta «‹ ›» con solo DOS
   pestañas, que caben de sobra. «Si no queda más que avanzar, la flechita de la derecha pierde
   sentido»: un control visible que promete una acción imposible.

   MEDIDO (no supuesto): hay **11 `<MudTabs>`** en el repo y **CERO** configuran
   `ShowScrollButtons`/`AlwaysShowScrollButtons` ⇒ es el comportamiento por defecto de la librería,
   no una decisión de ninguna pantalla. Por eso NO se arregla pantalla a pantalla: 9 de esas 11
   pantallas ni siquiera pertenecen a este lote.

   Cómo lo monta MudBlazor 8.4 (verificado sobre el paquete en la caché NuGet, no de memoria):
     · Marcado — `.mud-tabs-tabbar-inner` (flex) contiene, en este orden:
       `div.mud-tabs-scroll-button` > `button.mud-icon-button` (anterior), `.mud-tabs-tabbar-content`
       y otro `div.mud-tabs-scroll-button` (siguiente).
     · Lógica — `MudTabs` (campos `_showScrollButtons`, `_prevButtonDisabled`, `_nextButtonDisabled`;
       métodos `SetScrollButtonVisibility` y `SetScrollabilityStates`) decide por MEDIDA: compara el
       ancho de todas las pestañas contra el del contenedor. Cuando hay sitio de sobra marca AMBOS
       botones como deshabilitados; cuando no lo hay, deshabilita solo el del extremo alcanzado.
     · Medida — `MudResizeObserver` usa `getBoundingClientRect()` con retardo de 200 ms
       (`staticwebassets/MudBlazor.min.js`), así que la decisión se toma sobre una foto que puede
       llegar tarde o tomarse con el elemento aún sin ancho definitivo.
     · CSS de la librería — `.mud-tabs-tabbar-content { width:100%; flex:1 1 auto }`.

   Lo que esa combinación produce, y que esta regla rompe: los propios botones ROBAN ~96 px al
   contenedor que se mide. Una vez visibles, la medida siguiente se hace sobre un contenedor ya
   encogido, que vuelve a "confirmar" que no hay sitio → el estado se ENGANCHA y no vuelve solo.
   Al no ocupar sitio los botones deshabilitados, el contenedor recupera su ancho real y la
   siguiente medida deshace el enganche: es auto-curativo, no cosmético.

   Regla: un botón de desplazamiento DESHABILITADO no se enseña. Se oculta el `<button>`, no su
   envoltorio (que sin contenido mide 0 y no necesita `:has()`, con lo que no dependemos del soporte
   de ese selector). `display:none` además lo saca del árbol de accesibilidad: ni foco, ni lectura.
   Cuando SÍ hay desbordamiento real, el botón del extremo contrario sigue visible y operativo. */
.mud-tabs-scroll-button .mud-icon-button:disabled {
    display: none;
}

/* ── 17. Pantalla de arranque (antes de que exista el tema) ─────────────────────────────────────
   🎨 EL ÚNICO TEXTO DE LA APP QUE NO PUEDE HEREDAR SU COLOR, y por eso tiene clase propia.

   Vive en `Routes.razor`, en la rama que se pinta MIENTRAS se resuelve la sesión — o sea ANTES de que
   se monte `MainLayout` y con él el `MudThemeProvider`. En ese instante nadie ha fijado el color del
   texto, así que un `<span>` sin `color` cae al negro por defecto del navegador. Sobre el fondo oscuro
   (`#0f172a`) y con `opacity:.7`, eso es invisible: la pantalla se ve vacía y el usuario cree que la app
   no arranca. Reportado con captura el 28-ago-2026.

   🕐 Y solo se nota cuando el arranque TARDA, que es exactamente cuando ese texto hace falta. Si conecta
   rápido nadie llega a leerlo y el defecto se esconde en el único caso donde importaba.

   Se cuelga de `body.ins-dark` / `body.ins-light` —que el script síncrono del `<body>` pone antes de
   este render, no después— en vez de las variables de MudBlazor, que a esta altura todavía no existen. */
.ins-boot__msg {
    font-family: 'Inter', system-ui, sans-serif;
    font-size: .9rem;
}
body.ins-dark  .ins-boot__msg { color: #94a3b8; }
body.ins-light .ins-boot__msg { color: #475569; }

/* ── 🪤 EL TEMBLOR DE LOS POPOVERS, CERRADO POR SU CLASE ───────────────────────────────────────────
   Un `transform` en un ANCESTRO convierte a ese ancestro en bloque contenedor de todo `position:fixed`
   que cuelgue de él — y los popovers de MudBlazor (menús, selects, date pickers, tooltips) son `fixed`.
   Cuando eso pasa, MudBlazor mide, coloca, vuelve a medir y no converge: el popover TIEMBLA.

   Las keyframes ya evitan dejar un transform RESIDUAL (`to` sin `transform`). Faltaba la otra mitad, que
   es la que se ve al usar la pantalla: los `:hover` que LEVANTAN una tarjeta o un botón. El bucle es
   exacto y se reproduce solo —
     el puntero entra en la tarjeta → sube 2 px → se abre el menú anclado a un botón suyo → el popover
     se pinta BAJO el puntero y le roba el hover a la tarjeta → la tarjeta baja 2 px → el ancla se mueve
     → MudBlazor recoloca el popover → el puntero vuelve a la tarjeta → sube otra vez → …
   y por eso tiembla justo lo que tiene un menú encima (el «Exportar» de Analítica, las acciones de una
   fila), y no el resto.

   ⚖️ El arreglo no quita el realce: lo SUSPENDE mientras hay un popover abierto, que es exactamente
   cuando el realce no aporta nada y sí rompe. Con el popover cerrado la pantalla se comporta igual. */
body:has(.mud-popover.mud-popover-open) .mud-card:hover,
body:has(.mud-popover.mud-popover-open) .mud-paper.app-card-hover:hover,
body:has(.mud-popover.mud-popover-open) .mud-button-filled:hover,
body:has(.mud-popover.mud-popover-open) .mud-button-outlined:hover,
body:has(.mud-popover.mud-popover-open) .mud-button-text:hover,
body:has(.mud-popover.mud-popover-open) .mud-icon-button:hover {
    transform: none !important;
}

/* 🔗 CASAR UN MOVIMIENTO CONTRA UN APUNTE — la fila de cada candidato.

   Reportado con la pantalla delante: los candidatos salían en dos columnas que se leían en zigzag, con el
   importe pegado al concepto. La causa es de MudBlazor: un `MudRadio` es inline y su etiqueta se ajusta al
   contenido, así que varios seguidos fluyen como palabras de un párrafo.

   ⚖️ Se corrige donde está el hecho —la opción tiene que ocupar la FILA entera para que sus columnas se
   alineen entre sí— y no tocando el componente: cambiar el radio de la casa afectaría a todas las pantallas
   que ya se leen bien. */
.ins-match-option {
    width: 100%;
    margin: 0;
    padding: 6px 4px;
    border-radius: 8px;
}

.ins-match-option:hover {
    background: var(--mud-palette-action-default-hover);
}

/* La etiqueta del radio es la que tiene que crecer: sin esto el importe no llega al borde derecho y la
   comparación —que es a lo que se viene— se hace entre cifras a distinta altura. */
.ins-match-option .mud-radio-content {
    flex: 1 1 auto;
    min-width: 0;
}

/* 💳 FORMAS DE PAGO DEL PRODUCTO — la forma y su recargo van en la misma fila, y sus columnas se alinean
   entre filas. Antes cada forma era una columna de la rejilla con su campo debajo, y la anual —que no tiene
   recargo— dejaba un hueco donde las demás llevaban un número: tres columnas desiguales para leer un dato
   que se compara en vertical. */
.ins-freq-name {
    min-width: 160px;
    margin: 0;
}

.ins-freq-surcharge {
    max-width: 160px;
}

/* ── 👁️ s163 · LA EXPLICACIÓN DE LOS HONORARIOS, VISIBLE EN LA LISTA DE PRODUCTOS ────────────────────
   Él lo pidió con la lista delante: «si vas a dejar ese campo, debe verse en el listado, no ser invisible».
   Tenía razón por partida doble — se le pide al corredor una frase que su cliente va a leer, y hasta ahora
   no había ninguna pantalla donde volver a mirarla: se escribía una vez y desaparecía.

   🪤 EL `max-width` NO ES OPCIONAL, y es la trampa que documenta la cabecera de `insTooltip.css`: el
   envoltorio del tooltip dimensiona a CONTENIDO, así que un hijo con `overflow:hidden` +
   `text-overflow:ellipsis` sin anchura de referencia NO recorta nunca — los puntos suspensivos no
   aparecen y la frase empuja la columna hasta desbordar la tabla. Aquí además la celda es
   `.ins-col-ajustada` (`width:1%` + `white-space:nowrap`, insList.css), o sea que la columna crecería con
   ella. El campo admite 280 caracteres, así que no es un caso de laboratorio.

   📐 22ch es ancho de lectura, no capricho: deja ver el arranque de la frase («2 % del capital…») sin
   robarle sitio a las columnas que sí se comparan de un vistazo. La frase entera vive en el tooltip. */
.ins-ext-fee-method {
    display: block;
    max-width: 22ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
