﻿/* ── 📐 RITMO VERTICAL DE LA BANDA DE DETALLE — asset COMPARTIDO del RCL InsCore.Ui.Gadgets ──────────
   SSOT del espacio ENTRE bloques de una ficha de detalle, para los tres hosts. Self-contained con
   var(--token, fallback): quien traiga tokens los usa, quien no cae al neutro.

   🌳 QUÉ DEFECTO CIERRA, Y POR QUÉ VIVE AQUÍ Y NO EN UNA PANTALLA
   El ritmo vertical de una ficha NO era propiedad de la ficha: era un accidente de cómo la había
   escrito quien la escribió. Medido renderizado el 17-ago-2026 a 1536 y 1280 px:

     · `/collective-policies/{id}` (COL-2026-000002) apila NUEVE secciones plegables SUELTAS, sin
       rejilla que las envuelva ⇒ hueco entre sección y sección = 0 px. La ficha se lee como un
       bloque continuo: no hay dónde acaba una sección y empieza la siguiente.
     · `/policies/{id}` apila las suyas dentro de un `MudGrid`, así que el ritmo se lo pone el
       `spacing` del grid POR CASUALIDAD — nadie lo declaró, y la ficha de al lado no lo hereda.
     · El `CollapsibleSection` del Backoffice se lo escribe a mano en el marcado
       (`pa-4 mb-4` / `mb-2`), o sea una TERCERA respuesta al mismo problema, en un tercer sitio.

   Tres pantallas, tres mecanismos distintos y un resultado que depende de cuál te tocó. Por eso el
   ritmo se declara UNA vez, sobre lo que la sección ES (`.ins-section`), y no se vuelve a teclear:
   la siguiente ficha que alguien escriba nace con él sin acordarse.

   📏 LA CIFRA NO ESTÁ INVENTADA. 16 px es el ritmo entre tarjetas del estándar del sector para
   fichas densas (Material `spacing 2`, SLDS `spacingMedium`) y es EXACTAMENTE el que el
   `CollapsibleSection` del Backoffice ya se escribía a mano con `mb-4`. Se adopta el que la casa
   ya tenía, en lugar de estrenar un número nuevo. */
:root {
    --ins-detail-rhythm: 16px;
    /* Alto de la barra compacta pegajosa cuando está desplegada. Vive aquí y no en su regla porque hay
       DOS consumidores: la propia barra y el carril lateral, que tiene que pegarse por debajo de ella.
       Cableado en los dos sitios, el día que la barra crezca el carril se le mete debajo en silencio. */
    --ins-detail-stickybar-height: 56px;
}

/* El bloque de una ficha lleva SU PROPIO ritmo hacia abajo. Cubre a la vez la sección plegable del
   corredor (`.ins-section`) y la tarjeta suelta que hace de bloque en una ficha (`.ins-detail-block`,
   la clase que se pone donde el bloque no es una sección plegable). */
.ins-section,
.ins-detail-block {
    margin-bottom: var(--ins-detail-rhythm);
}

/* El ÚLTIMO bloque de su contenedor no empuja contra el pie: el ritmo separa bloques, no fabrica cola.
   Y hace un segundo trabajo, que es el que cierra el caso de la rejilla (ver abajo): cuando la ficha
   envuelve cada bloque en su propio `MudItem`, el bloque es SIEMPRE el último de ese item, así que su
   margen se apaga solo y el hueco lo pone quien de verdad reparte ahí. */
.ins-section:last-child,
.ins-detail-block:last-child {
    margin-bottom: 0;
}

/* ── PILA de tarjetas dentro de una columna de la ficha de detalle ────────────────
   Cierra el defecto que originó la ola 10. La rejilla de MudBlazor es `flex-wrap`: empareja por
   FILA, y la altura de una fila la fija su tarjeta más alta. Dos consecuencias, las dos medidas en
   la ficha de póliza:

   1. Una tarjeta larga ("Datos del contrato", con su tabla fiscal) al lado de una corta
      ("Renovación", 4 líneas) deja bajo la corta un hueco tan alto como la diferencia — y justo en
      la zona de MÁXIMA prioridad, la que se lee sin hacer scroll.
   2. Una tarjeta a media anchura SIN pareja (la siguiente es de anchura completa, así que salta de
      fila) deja la MITAD de una fila vacía.

   ⚠️ `align-items: start` sobre la rejilla NO lo arregla, y conviene dejarlo escrito para que no se
   vuelva a intentar: el `MudItem` sí se estira a la altura de la fila, pero el `MudPaper` de dentro
   es un bloque de altura automática y nunca la llenaba. Estirar o no el contenedor no cambia un
   pixel de lo que se ve; el hueco no es de ALINEACIÓN, es de REPARTO.

   Así que las columnas dejan de fluir por su cuenta y el reparto SE DECLARA: la columna corta se
   completa APILANDO varias tarjetas cortas —esta clase es esa pila—, en vez de esperar a que
   termine la larga de al lado. Qué tarjeta va en qué columna lo dice el markup, por prioridad de
   lectura.

   Por qué no `column-count`, que balancearía solo sin declarar nada: las secciones son PLEGABLES;
   al plegar una, el navegador reequilibraría y las tarjetas SALTARÍAN de columna bajo el cursor.
   Un reparto declarado no se mueve nunca.

   El `gap` iguala el `Spacing="3"` de la MudGrid que la contiene, para que apilar dentro de una
   columna y repartir entre columnas separen exactamente igual. */
.ins-detail-col {
    display: flex;
    flex-direction: column;
    gap: 24px;
    min-width: 0;
}

/* ── ⚠️ EL RITMO NO SE PONE DOS VECES, Y TAMPOCO SE CEDE A CUALQUIER CIFRA ──────────────────────────
   Este es el filo del arreglo. Hay DOS contenedores en la casa que ya separan a sus hijos, y sobre
   ellos un margen propio se SUMA (el `gap` de flex no absorbe el margen del hijo: lo apila detrás).
   La s72 lo resolvió NEUTRALIZANDO el margen del bloque y cediéndoles el hueco. Medido el 17-ago-2026
   con el stack en pie, eso dejaba el ritmo así:

     · `/policies/{id}` — 13 pares de bloques a **12 px** (el `padding` de los `MudItem` de un
       `MudGrid Spacing="3"`, que es la mitad del spacing por lado);
     · la columna lateral de esa MISMA ficha — **24 px** (`.ins-detail-col { gap: 24px }`);
     · `/collective-policies/{id}` — 16 px, que es el único sitio donde mandaba el SSOT.

   ⇒ **Tres ritmos distintos, dos de ellos en la misma pantalla**, que es exactamente el defecto que
   este fichero existe para cerrar: declarar 16 px y no aplicarlos en la ficha más leída de la app es
   declarar sin entregar. Así que el bloque sigue cediendo el hueco a quien reparte —eso estaba bien—
   pero **el que reparte lo hace AL RITMO**, no a la cifra que le tocara.

   `:has()` es lo que permite decirlo sin nombrar pantallas: se ajusta la rejilla que apila BLOQUES DE
   FICHA, y ninguna otra (una rejilla de campos dentro de una sección no lleva `.ins-section` colgando
   de sus items, y no la toca). */
.ins-detail-col:has(> .ins-section),
.ins-detail-col:has(> .ins-detail-block) {
    row-gap: var(--ins-detail-rhythm);
}

.ins-detail-col > .ins-section,
.ins-detail-col > .ins-detail-block {
    margin-bottom: 0;
}

/* La rejilla reparte con el `padding` de sus items (la mitad del hueco a cada lado) y con un margen
   negativo del mismo valor para que la banda no se desplace.

   🔴 s110 · DOS DEFECTOS AQUÍ, LOS DOS REPORTADOS EN VIVO CON CAPTURA DE `/suscripcion`:
   *«no hay espacio de separación entre card Grupo y card Integraciones incluidas en tu plan»*.

   1️⃣ **El margen inferior negativo se comía el hueco con el SIGUIENTE hermano.** La cuenta, que es
      lo que lo demuestra: 8 px de `padding-bottom` del item + (−8 px) del margen de la rejilla + 0 del
      hermano = **0 px**. Por eso la tarjeta de después arrancaba pegada, mientras entre las tarjetas
      sueltas de más abajo sí había 16. No era un olvido de esa pantalla: era ASIMÉTRICO por
      construcción, y le pasaba a cualquier ficha que mezclara una rejilla con hermanos fuera de ella.
      ⇒ El margen de ARRIBA sigue siendo negativo (ahí lo que precede ya aporta sus 16 y hay que
      restar los 8 del padding: 16 − 8 + 8 = 16 ✅), y el de ABAJO pasa a **positivo**:
      8 de padding + 8 de margen = **16** ✅. Los dos extremos dan el mismo ritmo que dos bloques
      sueltos, que era el objetivo de este fichero desde el principio.

   2️⃣ **El eje horizontal nunca se reescribió**, así que convivían ~24 px de gutter con 16 de ritmo
      vertical. Este fichero decía que eso «no era asunto suyo»; pero un ritmo que solo vale en un eje
      no es un ritmo, es una coincidencia. Se reescriben los CUATRO lados con el mismo token. */
.mud-grid:has(> .mud-grid-item > .ins-section) > .mud-grid-item,
.mud-grid:has(> .mud-grid-item > .ins-detail-block) > .mud-grid-item {
    padding: calc(var(--ins-detail-rhythm) / 2);
}

.mud-grid:has(> .mud-grid-item > .ins-section),
.mud-grid:has(> .mud-grid-item > .ins-detail-block) {
    margin-top: calc(var(--ins-detail-rhythm) / -2);
    margin-bottom: calc(var(--ins-detail-rhythm) / 2);
    margin-inline: calc(var(--ins-detail-rhythm) / -2);
    width: auto;
}

/* ── 🏷️ TEXTO AL PIE DE UN BLOQUE ───────────────────────────────────────────────────────────────────
   Una nota que describe a un bloque vive DENTRO de él. Esta clase es para la nota que cierra una
   sección (alcance, qué no cubre, qué se congeló): la separa de su contenido sin inventar un margen
   suelto en cada pantalla, que es como acababa flotando entre dos tarjetas y perteneciendo a
   ninguna. */
.ins-section__note {
    display: block;
    margin-top: 12px;
}

/* ── 📜 EL ÍTEM DE UN CONDICIONADO — un título propio + su PROSA LEGAL, dentro de una sección ────────
   El sexto papel de la jerarquía de lectura, y el primero cuyo cuerpo NO es un dato sino un párrafo:
   una exclusión, una condición general, una cláusula especial. Censado el 23-ago-2026 sobre `src/`:
   **6 ficheros · 11 bloques**, en DOS de los tres hosts — corredor (ficha de póliza ×3, ficha de
   producto ×4, ficha de cotización, ficha de plantilla) y backoffice (solicitud de producto, panel de
   comportamiento del catálogo). El portal del tomador NO pinta ninguno: sus fichas de póliza no
   enseñan condicionado, y por eso este papel no le añade nada aunque enlace esta misma hoja.

   🌳 QUÉ DEFECTO CIERRA, Y POR QUÉ NO ES DE LA FICHA DE PÓLIZA. Reportado por él con la app delante,
   tema OSCURO, sobre «Condiciones generales / Cláusulas especiales / Exclusiones»: *«sus cards no
   tienen un formato lindo, comparten el color y el background color, por ende se mimetizan»*. La causa
   NO es la sección —su cabecera ya separa por filete desde M-575— sino que ahí dentro los TRES roles
   colapsaban en uno solo: el título del ítem iba en `.ins-item-label` (600, texto PRIMARIO) y su
   cuerpo en `Typo.body2` **sin color declarado**, o sea también primario. Título y prosa quedaban a un
   único escalón de PESO, sin ninguna otra diferencia, y entre un ítem y el siguiente no había más que
   8 px de aire: con párrafos de varias líneas eso no delimita nada y la lista se lee como una sábana.

   🔎 Y ES UNA CLASE, NO UN CASO: de esos 11 bloques, la MISMA forma se resolvía de TRES maneras
   distintas según quién escribiera la pantalla — `MudListItem` con icono repetido + `.ins-hint` (7
   bloques), `MudPaper Outlined` con su `border-radius` tecleado a mano (1, la solicitud del
   backoffice) y el par sin vestir de la ficha de póliza (3). Tres respuestas al mismo problema es
   exactamente lo que este fichero existe para cerrar, así que el papel se declara UNA vez y los 11
   bloques lo consumen.

   🎯 DOS EJES PARA DELIMITAR: SUPERFICIE PROPIA + filete de acento. ⚠️ Y la superficie es la que él
   pidió con la captura delante —«pídeme fondo en la card»—, así que se entrega: la s86 entregó SOLO el
   filete y eso ESTRECHÓ el encargo, que es la forma de fallar que no se ve porque el resultado se
   parece al pedido.

   🪤 EL MIEDO QUE LO FRENÓ ERA REAL PERO IBA AL REVÉS, Y SE MIDIÓ. El argumento anterior era: una
   superficie anidada tendría que ACLARAR la tarjeta en oscuro (Material: en tema oscuro la elevación
   se expresa con superficies más claras) y eso hundiría el par que
   `ASecondaryLabelLiftsOffItsSurfaceTests` mide sobre esa tarjeta —rótulo secundario a 4,58:1 en
   oscuro, suelo 4,5—. Falso en la dirección: un ítem de condicionado no está ELEVADO sobre su tarjeta,
   está EMBUTIDO en ella, y una superficie RECESIVA —más oscura que la tarjeta, que es lo que esta casa
   ya hace con la cabecera de tabla `rgba(10,22,50,0.50)` y el hueco de un campo `rgba(10,22,50,0.40)`—
   SUBE el contraste del texto claro que lleva encima en vez de bajarlo. Medido con el modelo del guard
   (23-ago-2026, peor lienzo = bajo el orbe azul):

     · OSCURO  tarjeta rgb(38,55,93) → cláusula rgb(27,42,76): secundario pasa de 4,58:1 a **5,54:1**
       y la cláusula se separa de su tarjeta **1,209:1** (suelo de superficie de la casa: 1,15).
     · CLARO   tarjeta rgb(254,254,255) → cláusula rgb(232,236,243): secundario 7,52:1 → **6,41:1**
       (sigue muy por encima de 4,5) y separación **1,175:1**.
     · BACKOFFICE, que consume 2 de los 11 bloques y tiene lienzo propio `#050d1a`: separación
       1,189:1 en oscuro y 1,174:1 en claro; su secundario translúcido queda en 6,16:1 / 5,45:1.

   ⇒ El par que se temía MEJORA, no empeora. Y para que eso no vuelva a ser un razonamiento, la
   cláusula entra en el CENSO de ese guard como SÉPTIMA superficie: si alguien mueve este token, salta.

   🌗 CLARO Y OSCURO, los dos, y sin un solo hex suelto EN LA REGLA: la superficie es
   `--ins-clause-surface`, declarado aquí mismo con su pareja (`:root` = oscuro, `body.ins-light` lo
   reescribe) porque esta hoja la enlazan tres hosts y el portal no trae theme.css propio. El filete
   sigue siendo `--mud-palette-primary` (la marca del tenant, el mismo token con el que insAiProse.css
   acentúa sus encabezados) y el cuerpo baja a `--mud-palette-text-secondary`, que es el token que la
   casa YA mide contra la superficie de tarjeta en los dos temas. Esa bajada es la otra mitad del
   arreglo: título 600/primario contra cuerpo 400/secundario separa por PESO **y** por COLOR.

   ⚠️ NO redeclara `font-size` — igual que `.ins-item-label` y por el mismo motivo: lo elige el `Typo`
   del llamante, y esta hoja la comparten dos hosts con escalas distintas. Y NO redefine
   `.ins-item-label`: el título del ítem sigue vistiéndose con ella (22 ficheros la consumen), aquí
   solo se le da su caja. */
.ins-clause-list {
    display: flex;
    flex-direction: column;
    /* El aire entre ítems es TRES CUARTOS del ritmo entre BLOQUES (12 px sobre 16): dos ítems de una
       lista están más cerca entre sí que dos secciones de la ficha, y esa proporción es lo que hace
       que la lista se lea como una lista y no como una pila de secciones. Sale del token del ritmo, no
       de una cifra nueva — el día que el ritmo de la ficha cambie, éste le sigue. */
    gap: calc(var(--ins-detail-rhythm, 16px) * 0.75);
}

/* 🌗 LA SUPERFICIE DEL ÍTEM, con su pareja clara/oscura. Los dos valores son los TINTES QUE LA CASA YA
   USA para una superficie embutida en una tarjeta: en oscuro el mismo `rgba(10,22,50,…)` del hueco de
   un campo (theme.css §8) y en claro el `#e2e8f0` de la rampa de grises de la paleta. Recesivos los
   dos: en oscuro bajan respecto a la tarjeta y en claro también, que es como se lee «esto va DENTRO».
   Las cifras medidas y por qué la dirección es ésta y no la contraria, arriba. */
:root {
    --ins-clause-surface: rgba(10, 22, 50, 0.40);
}

body.ins-light {
    --ins-clause-surface: rgba(226, 232, 240, 0.80);
}

.ins-clause {
    background: var(--ins-clause-surface, rgba(10, 22, 50, 0.40));
    border-left: 3px solid var(--mud-palette-primary, #3b82f6);
    border-radius: var(--app-radius-input, 12px);
    /* El aire de dentro: 12/14 es el del hueco de un campo de esta misma casa. La izquierda no compensa
       el filete —el filete ES el canto, no un adorno que haya que despegar del texto. */
    padding: 12px 14px;
}

.ins-clause__title {
    display: block;
    margin: 0 0 2px;
}

/* Cuando el título comparte renglón con una insignia (el alcance de una exclusión, el tipo de una
   cláusula): el rótulo NO crece hasta empujarla al borde y la insignia baja de línea si no cabe. */
.ins-clause__head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 2px;
}

.ins-clause__head .ins-clause__title {
    margin-bottom: 0;
}

/* 📖 PROSA LEGAL = TEXTO LARGO, y por eso este cuerpo declara lo que un dato no necesita:
     · `white-space: pre-wrap` — el condicionado trae sus propios saltos de párrafo y son del texto,
       no de la maqueta. Estaba escrito en un `style=` suelto del marcado y aquí no se pierde;
     · `line-height: 1.6` — el interlineado de un párrafo, no el de una etiqueta de una línea;
     · `max-width: 72ch` — la medida de línea. Un renglón de 1.400 px de ancho (que es lo que da esta
       sección a banda entera en un monitor de 1536) obliga al ojo a buscar el principio de la
       siguiente línea y es donde se pierde la lectura; el rango del oficio es 45-90 caracteres. */
.ins-clause__body {
    display: block;
    margin: 0;
    color: var(--mud-palette-text-secondary, inherit);
    white-space: pre-wrap;
    overflow-wrap: break-word;
    line-height: 1.6;
    max-width: 72ch;
}

/* ── 🛤️ M-591 · EL CARRIL LATERAL DE UNA FICHA ───────────────────────────────────────────────────────
   La ficha deja de ser DOS PILAS y pasa a ser columna principal + carril lateral acotado y pegajoso.

   🌳 POR QUÉ, y es lo que ninguna recolocación cerraba: mientras dos pilas se repartan contenido cuya
   altura la fijan los DATOS (36 recibos o 1, sublímites o ninguno), la diferencia entre pilas es una
   variable de NEGOCIO. Cualquier orden fijo acierta en la ficha que se midió y falla en la de al lado.
   M-573 midió 357 px de aire muerto a la derecha y los movió a la izquierda; la izquierda llegó a 472.
   El hueco no era un defecto de ORDEN: era una propiedad de la FIGURA.

   Aquí el carril lleva solo lo de altura CONOCIDA —tomador, vigencia— porque identidad y acciones ya
   viven en la cabecera de la página; todo lo que crece por datos baja a la principal a banda entera.
   Y el aire bajo el carril deja de ser hueco muerto porque el carril ACOMPAÑA al scroll.

   📐 `align-self: flex-start` no es cosmética: la rejilla estira sus items al alto de la fila, y un item
   estirado no tiene por dónde despegarse — el `sticky` sería inerte. Es la línea que hace que funcione.

   📌 Y se pega POR DEBAJO de la barra compacta, no a su misma altura: la barra ocupa el ancho de la
   banda con `z-index: 30`, así que compartir `top` le comería la cabecera al carril. El desplazamiento
   sale del token, no de un 56 tecleado otra vez. */
.ins-detail-rail {
    align-self: flex-start;
    position: sticky;
    top: calc(var(--mud-appbar-height, 64px) + var(--ins-detail-stickybar-height, 56px) + var(--ins-detail-rhythm));
}

/* ⛔ POR DEBAJO DE `md` EL CARRIL BAJA, NO SE ENCOGE. Una tarjeta acotada en una pantalla estrecha es
   una tira inútil, y un pegajoso en móvil se come el alto útil que ya escasea. El punto de corte es el
   `md` de MudBlazor (960 px), el mismo con el que la rejilla apila sus columnas: si el carril siguiera
   pegado cuando ya no hay dos columnas, se pegaría sobre el contenido que acaba de quedar debajo. */
@media (max-width: 959.98px) {
    .ins-detail-rail {
        position: static;
        top: auto;
    }
}

/* ── 🕳️ UN BLOQUE QUE RECORTA NO PUEDE COMERSE UN DATO ───────────────────────────────────────────────
   `.ins-section` lleva `overflow: hidden` (theme.css del corredor) para que su redondeo valga. El
   precio es que cualquier desbordamiento horizontal de su contenido **borra texto sin avisar**: no hay
   barra, no hay elipsis, no queda rastro de que faltaba algo.

   Medido el 17-ago-2026 a 1280 px en `/policies/{id}`: el selector de cuenta de cobro —cuyo valor es
   «IBAN · titular», un renglón sin puntos de corte— se salía **58 px** de su bloque, con el rótulo del
   titular cortado a media palabra. A 1536 px no ocurre: lo dispara el ANCHO, y por eso una sola
   captura no lo veía.

   🌳 La causa no es el selector, es la CLASE: un control flex cuyo contenido no envuelve reclama su
   `min-content` entero (`min-width: auto`) y no encoge. Se le da suelo cero y se le pide que **avise**
   con elipsis en vez de callarse — el valor completo sigue a un clic, en el desplegable. */
.ins-section .mud-select,
.ins-section .mud-input-control {
    min-width: 0;
    max-width: 100%;
}

.ins-section .mud-select .mud-input-slot {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Fuera de una ficha (una pantalla de captura, donde el bloque NO recorta) el selector de cuenta sí
   pide un ancho decente: un IBAN en 90 px no se lee. La regla de arriba, más específica, se lo quita
   allí donde el recorte convertiría ese suelo en texto perdido. */
.ins-payer-account {
    min-width: 220px;
    max-width: 100%;
}

/* ── 📌 BARRA COMPACTA PEGAJOSA DE UNA FICHA DE DETALLE ──────────────────────────────────────────────
   Vive en la columna de contenido (se alinea sola a su ancho) y se pega bajo el AppBar fijo. En reposo
   ocupa 0 de alto (invisible); al salir la cabecera grande, JS le añade `.is-stuck` y se despliega.
   Estaba TRIPLICADA: los dos `theme.css` (idénticas carácter a carácter, 35 líneas) y `portal.css`
   (divergente en cuatro puntos). Self-contained con `var(--token, fallback)`, como el resto de este
   fichero: quien trae tokens los usa, quien no cae al neutro — y así el portal, que no tiene las
   variables de cristal, deja de necesitar su propia copia.

   Lo que NO vive aquí es el TEMA: el tinte opaco + desenfoque de los dos hosts de cristal y la sombra
   del portal se quedan en su hoja, porque son de su tema y no del ritmo. Las cuatro divergencias, con
   su resolución, para que nadie las vuelva a descubrir:
     1. `border-radius` — portal 8px literal, cristal `var(--app-radius-input)` = 12px ⇒ el fallback
        reproduce los dos exactos.
     2. `border-bottom` — ídem con `--glass-border` sobre `--mud-palette-lines-default`.
     3. `box-shadow` es SOLO del portal y NO sube: dársela a los hosts de cristal sería un cambio
        visual que nadie ha medido.
     4. Transiciones — al portal le cambia la CURVA de un fundido de 180 ms (de `ease` a la del
        cristal). Es la única diferencia real que introduce la unificación, y queda declarada.

   ⚠️ NO DECLARAR AQUÍ `background-image`: corredor y backoffice cargan `theme.css` ANTES que esta hoja,
   así que su tinte (`linear-gradient` + `backdrop-filter`) sobrevive solo mientras este bloque no pise
   esa propiedad. En el portal el orden es el inverso (`portal.css` después), y por eso su sombra gana
   sin más. */
/* ── 🧭 M-780 · LA BARRA EXISTE SIEMPRE, Y `is-stuck` SÓLO LE CAMBIA LA CARA ────────────────────────
   🔴 Hasta la s120 esta barra nacía con `max-height: 0`, `opacity: 0` y `pointer-events: none`, y sólo
   existía de verdad al salir la cabecera grande de pantalla. Eso valía mientras lo único que llevaba era
   un «Volver» que ya estaba arriba; deja de valer en cuanto lleva LO ACCIONABLE, que es lo que él pidió
   con estas palabras: *«estas acciones tan importantes no pueden ir escondidas»*. Un botón que no existe
   en la parte de arriba de la ficha —justo donde se llega— no está «siempre disponible».

   ⇒ La barra se pinta desde el píxel cero y no se va nunca. `is-stuck` conserva su trabajo, pero ahora es
   sólo COSMÉTICO: al despegarse gana su sombra y saca el título compacto, porque hasta entonces el
   título grande está a la vista dos centímetros más abajo y repetirlo se lee como un fallo de render.

   📐 Y NO CUESTA ANCHO, que es la otra mitad de lo que llevaba varias sesiones sin cerrarse: lo
   accionable pasa a pagar en ALTO —56 px de cromo— y el tercio de pantalla que el carril cobraba vuelve
   entero a la columna principal. */
.ins-detail-stickybar {
    position: sticky;
    top: var(--mud-appbar-height, 64px);
    z-index: 30;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    row-gap: 8px;
    min-height: var(--ins-detail-stickybar-height, 56px);
    padding: 6px 10px;
    margin-bottom: 1rem;
    border-radius: var(--app-radius-input, 8px);
    border-bottom: 1px solid var(--glass-border, var(--mud-palette-lines-default));
    background-color: var(--mud-palette-surface);
    transition: box-shadow var(--dur-fast, 150ms) var(--ease-out, cubic-bezier(.2, .8, .2, 1));
}

/* 🖱️ Despegada: se separa del contenido que le pasa por debajo. Es lo ÚNICO que cambia al hacer scroll
   —antes cambiaba su existencia—, y por eso la transición ya no anima el alto: la barra no crece ni
   encoge, así que animarlo movería la ficha entera bajo el cursor en cada scroll. */
.ins-detail-stickybar.is-stuck {
    box-shadow: 0 2px 12px rgb(0 0 0 / 14%);
}

/* 🔤 El título compacto sólo aparece cuando la cabecera grande ya no está. No se retira del DOM porque un
   título NO es tabulable: aquí esconder no deja nada atrapando el foco — que es exactamente lo que sí
   prohíbe hacer con las acciones, y por eso ellas se pintan UNA sola vez y en este sitio. */
.ins-detail-stickybar__title {
    opacity: 0;
    transition: opacity var(--dur-fast, 150ms) var(--ease-out, cubic-bezier(.2, .8, .2, 1));
}

.ins-detail-stickybar.is-stuck .ins-detail-stickybar__title {
    opacity: 1;
}

/* 🎬 Las acciones empujan a la derecha y no encogen a menos de lo suyo: si no caben, la barra reparte en
   dos filas (`flex-wrap` arriba). Envolver es el reflujo correcto — encoger un botón de acción le come el
   rótulo, y un rótulo a medias en «Anular siniestro» es exactamente lo que no puede pasar. */
.ins-detail-stickybar__actions {
    margin-inline-start: auto;
    flex-shrink: 0;
}

/* ── 🖱️ EL CHROME FIJO RESERVA SU FRANJA — WCAG 2.2 SC 2.4.11 «Focus Not Obscured» ─────────────────
   🌳 QUÉ DEFECTO CIERRA. La barra superior de la app (`header.mud-appbar-fixed-top`, con su
   `.mud-toolbar` dentro) y la barra compacta de la ficha ocupan los primeros píxeles del viewport de
   forma PERMANENTE. Ocupar no es reservar: hasta hoy nadie le había dicho al navegador que esa franja
   está tomada, así que cualquier «tráeme esto a la vista» —tabular con el teclado, un ancla, un
   `scrollIntoView` de Blazor, el salto al primer campo con error— dejaba el control DEBAJO de la barra:
   ni se ve ni se puede pulsar.

   📐 MEDIDO el 18-ago-2026 con el stack en pie, a 1280x800, llamando a `scrollIntoView()` sobre cada
   control de la banda y comparando su borde superior con la franja del chrome —derivada preguntándole
   al navegador quién recibe el clic a cada altura, no tecleada—: reserva **64 px**, dueño
   `mud-appbar mud-appbar-fixed-top`. **31 de 62** controles acababan DEBAJO: /policies 22 de 31,
   /claims 9 de 17, /persons 0 de 14. Con la regla puesta: **0 de 62**, `scroll-padding-top` = 136 px.
   No es un caso raro: es la mitad de la ficha.

   🏆 El estándar del sector para esto es `scroll-padding` en el contenedor de scroll (CSS Scroll
   Snap §7), no un `scroll-margin` por control ni un desplazamiento a mano en JS: se declara UNA vez
   sobre lo que el chrome MIDE y lo aplica el navegador a cualquier vía de «traer a la vista», incluidas
   las que aún no existen.

   La cifra sale de los MISMOS tokens con los que el carril lateral se pega por debajo de la barra
   compacta (arriba, `.ins-detail-rail`): appbar + barra compacta + un ritmo de aire, para que el
   control aterrice separado del borde y no lamiéndolo. En las pantallas sin barra compacta la reserva
   sobra por 56 px, y eso NO hace daño —el control queda un poco más abajo—, mientras que quedarse
   corto sí lo hace: lo esconde. */
:root {
    scroll-padding-top: calc(var(--mud-appbar-height, 64px) + var(--ins-detail-stickybar-height, 56px) + var(--ins-detail-rhythm));
}

.ins-detail-stickybar__title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
}

/* ── 🛤️ CARRIL C · EL ÍNDICE DE SECCIONES — lo que el carril lleva desde ahora ────────────────────
   🌳 LA MEDIDA QUE LO ABRE (1536 px, imagen `7ecac89`, 28-ago-2026): el carril llevaba «vigencia y
   tomador, y nada más» —399 px en la póliza de auto— al lado de una columna principal de 6.234 px.
   **5.835 px de columna vacía**; 5.581 en la de hogar y 1.887 en el siniestro. Eso es lo que él
   fotografió, y ningún guard lo cantaba: `s73-q-aire-muerto-de-la-ficha` EXIME a los elementos
   pegajosos del veredicto, y el carril es pegajoso. El instrumento no podía ver justo donde vivía.

   🪤 Y EL TOPE DE 560 px PERSEGUÍA EL SÍNTOMA CONTRARIO. Mantener el carril corto es exactamente lo
   que garantiza el hueco: cuanto mejor cumplía ese tope, más grande era el vacío. Es el patrón de la
   s112 —un apaño que sobrevive a su motivo—, así que aquí no se sube ningún tope: cambia la FIGURA.

   ⚖️ POR QUÉ ESTE CONTENIDO SÍ PUEDE VIVIR EN EL CARRIL, que es lo que el guard pregunta:
   · no crece por DATOS (una tabla, una lista o una cronología sí, y por eso bajan a la columna
     principal): crece por SECCIONES, que es una propiedad de la FICHA, no de la cartera del corredor;
   · y por fin justifica ser pegajoso — un índice existe para navegar seis mil píxeles, mientras que
     una tarjeta de identidad pegada no sirve de nada una vez leída.

   🚰 EL ALTO NO SE TECLEA. `.ins-detail-rail` ya pone el `sticky` y su `top`; aquí solo se acota lo
   que el índice puede medir, derivado del MISMO token que ese `top` —barra de la aplicación + barra
   compacta de la ficha + el ritmo— más un respiro abajo. Si las secciones no caben, rueda por dentro:
   jamás hay una sección a la que no se llegue. Es la doctrina de M-207/M-696, sin restas inventadas. */
.ins-section-index {
    max-height: calc(100dvh - var(--mud-appbar-height, 64px) - var(--ins-detail-stickybar-height, 56px) - var(--ins-detail-rhythm) - var(--ins-detail-rhythm));
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* ── 🗂️ M-779 · PLEGAR EL CARRIL Y DEVOLVERLE EL ANCHO A LA FICHA ───────────────────────────────────
   Reportado por él con captura (s115) y otra vez con la app delante (s120):
     · *«tenerlo siempre a la vista y desaprovechar su espacio es contraproducente»*
     · *«el sticky de "Acciones" en siniestro me gusta que esté a la mano pero se come media pantalla»*
   El carril es `md="4"`, un TERCIO del ancho, y lo cobra esté o no en uso.

   ⚖️ ENCOGER NO BASTA, Y POR ESO SE PLIEGA A CERO. Una tira de 48 px sigue comiendo espacio: es el mismo
   defecto en pequeño. Se colapsa entero y el interruptor vive en el cromo permanente de la página
   (`DetailRailToggle`, en la cabecera grande Y en la barra compacta), porque un botón dentro de lo que se
   oculta se va con ello y deja al corredor sin puerta de vuelta.

   🔄 QUÉ CAMBIA RESPECTO DE M-736, y por qué esto es MENOS CSS y no más. Aquello plegaba sólo el ÍNDICE,
   así que había que distinguir «carril que sólo llevaba índice» (se va entero) de «carril con secciones
   propias» (se queda con ellas) — dos reglas gemelas con un `:not(:has(...))` cada una, escritas en los
   dos extremos del mismo hecho, y con la mitad de la ficha de siniestro dependiendo de que no divergieran.
   Ahora se pliega el CARRIL, que es lo único que ocupa ancho, así que la condición es UNA y es una clase
   que el propio componente estampa: se acabó deducir el estado del contenido.
   ⚠️ Lo que aquella asimetría protegía sigue protegido, pero en otra capa y mejor: plegar se lleva también
   las acciones, y por eso el interruptor está SIEMPRE a la vista y sirve para las dos direcciones (M-767).

   📐 Y SE DEVUELVE EL ANCHO, que es la mitad que de verdad cierra el defecto: plegar sin ensanchar dejaría
   el mismo tercio de pantalla, sólo que vacío. Se nombra a la columna principal (`.ins-detail-main`) en
   vez de decir «los hermanos del carril»: la rejilla de la ficha de póliza tiene NUEVE hijos directos
   —siete filas a banda completa más la principal más el carril—, así que un `:not(.ins-detail-rail)`
   habría intentado poner esas siete en la misma línea. Medido contando la estructura, no supuesto: es el
   error que costó retirar un primer intento entero.

   🧬 Y NADA AQUÍ SE APOYA EN EL NOMBRE INTERNO DE MUDBLAZOR. Dos reglas de M-736 estuvieron MUERTAS desde
   que se escribieron porque decían `> .mud-item.ins-detail-rail` y la librería pinta `mud-grid-item`: el
   índice desaparecía pero su espacio no volvía, y él lo reportó («la idea de ocultar el índice es
   aprovechar el espacio, no dejar un hueco»). `ins-detail-rail`, `ins-detail-main` y
   `ins-detail-rail--plegado` son clases NUESTRAS, puestas por nosotros: siguen casando el día que la
   librería renombre lo suyo. */
.ins-detail-rail--plegado { display: none; }

/* 📐 El ancho solo hay que DEVOLVERLO donde se había repartido: por debajo de `md` la columna principal
   ya ocupa la banda entera, así que ahí no hay nada que corregir.

   ⚖️ Y LA CONDICIÓN SE ESCRIBE EN NEGATIVO —«ninguna rejilla con carril ABIERTO»— a propósito, porque hay
   TRES formas de no tener carril a la derecha y las tres dejan el mismo hueco: plegado por el corredor,
   sin nada que alojar, y directamente no montado (la ficha de persona sin el add-on de portal: ni índice
   —no lo merece por medida— ni acciones). Preguntando por el carril plegado sólo se cubría la primera, y
   las otras dos dejaban un tercio de pantalla cobrado y vacío, que es exactamente el defecto que ya se
   midió dos veces (5.835 px en póliza, 1.887 en siniestro). */
@media (min-width: 960px) {
    .mud-grid:not(:has(> .ins-detail-rail:not(.ins-detail-rail--plegado))) > .ins-detail-main {
        flex-basis: 100%;
        max-width: 100%;
    }
}

/* ── 🎚️ EL MANDO DEL CARRIL, EN SUS DOS SITIOS ─────────────────────────────────────────────────────
   Es UN control con dos posiciones según el estado del panel, no dos controles sobre un estado:
     · abierto  → cabecera del propio panel, arriba a la derecha, donde se busca lo que cierra un panel;
     · plegado  → pestaña fija al borde de la ventana, a media altura.
   Es el estándar del sector para un lateral ocultable, que es lo que él pidió con estas palabras: «un
   lateral ocultable como se suele hacer en sitios modernos profesionales».

   🔴 POR QUÉ LA PESTAÑA VA A MEDIA ALTURA Y NO A LA DEL CROMO PEGAJOSO. A la altura del cromo (~136 px)
   se cruzaría, en la parte de arriba de la ficha, justo con la fila de acciones de la cabecera — que es
   la vecindad de la que se le acaba de sacar («ahí donde está se confunde con los botones»). A media
   altura no se cruza con nada en ningún punto del scroll. */
.ins-detail-rail__head {
    display: flex;
    justify-content: flex-end;
    /* Pegada con el carril: el carril entero ya es `sticky`, así que esta fila viaja con él y el mando
       no se va nunca de pantalla. No hace falta un segundo pegajoso — sería el defecto de M-574. */
    margin-block-end: calc(var(--ins-detail-rhythm) / 2);
}

/* ── 🫥 EL TIRADOR DE BORDE (*edge handle*) — CASI NADA EN REPOSO, UN BOTÓN AL ACERCARSE ────────────
   🔴 Pedido así por él (30-ago-2026): *«un botón que siempre esté disponible… apenas se ve un puntito,
   flechita vertical en el borde derecho, y cuando haces hover recién te da para apretar»*. Es el estándar
   del sector para un lateral ocultable —VS Code, Figma, Jira— y sustituye a la pestaña con el rótulo
   «Panel de la ficha» cantado en todas las fichas, todo el rato.

   🥇 LA DIANA ES GRANDE AUNQUE LO PINTADO SEA FINO, y es lo que hace que la figura funcione: el botón mide
   34 px de ancho y 76 de alto —área de acierto cómoda, y transparente—, mientras que lo VISIBLE en reposo
   es sólo la franja de 5 px que dibuja su `::before` pegada al borde. Un tirador cuya zona sensible midiera
   los 5 px pintados sería una diana imposible, y el patrón se leería como un defecto.

   🔴 Y EL HOVER REVELA, NUNCA CREA: en táctil no hay hover y con el teclado tampoco. El botón está siempre
   ahí, con su nombre accesible y su área entera, y se pulsa igual sin haber pasado por encima; `:hover` y
   `:focus-visible` sólo lo agrandan y sacan su rótulo. Un mando que sólo existiera al hacer hover no
   existe para quien no puede hacerlo. */
.ins-detail-rail-handle {
    position: fixed;
    inset-inline-end: 0;
    top: 50%;
    transform: translateY(-50%);
    /* Sobre el contenido y sobre la barra compacta de la ficha (30), por debajo del cajón de navegación
       (1100) y de los diálogos (1401): es un tirador de panel, no una capa modal. */
    z-index: 40;
}

.ins-detail-rail-handle__btn {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    box-sizing: border-box;
    position: relative;
    min-height: 76px;
    /* El relleno de la izquierda es diana transparente; el de la derecha deja sitio a la franja. */
    padding: 8px 7px 8px 26px;
    border: 1px solid transparent;
    border-inline-end: 0;
    border-start-start-radius: 999px;
    border-end-start-radius: 999px;
    background: transparent;
    color: var(--mud-palette-text-primary);
    font: inherit;
    line-height: 1.2;
    cursor: pointer;
    transition: padding var(--dur-fast, 150ms) var(--ease-out, cubic-bezier(.2, .8, .2, 1)),
                background-color var(--dur-fast, 150ms) var(--ease-out, cubic-bezier(.2, .8, .2, 1)),
                border-color var(--dur-fast, 150ms) var(--ease-out, cubic-bezier(.2, .8, .2, 1)),
                box-shadow var(--dur-fast, 150ms) var(--ease-out, cubic-bezier(.2, .8, .2, 1));
}

/* 👁️ EL ASA EN REPOSO: una pestaña VISIBLE, no una raya.
   🔴 Reportado con la pantalla delante (y ya anotado en la s122): «hay que scrollear para buscarlo». Eran
   DOS defectos con un solo síntoma, y este bloque sólo cerró uno: en reposo se pintaban 5 px a opacidad
   .45, y una franja de cinco píxeles no se lee como un mando. Quien no sabe que está ahí no lo descubre,
   y quien lo descubre por accidente no sabe qué hace. Un control presente pero ilegible es, para quien lo
   usa, un control que no existe.

   🪤 EL OTRO DEFECTO LO TAPÓ ESTE MISMO COMENTARIO, que llegó a decir «la posición nunca fue el problema
   —el tirador es `position: fixed` desde que nació, así que no scrollea—». Leer `fixed` en la hoja no
   contesta la pregunta, porque `fixed` no dice contra QUÉ: si un ancestro tiene `transform`, el bloque
   contenedor deja de ser la pantalla y pasa a ser ese ancestro. 🔬 MEDIDO el 4-sep-2026 en vivo:
   `.mud-main-content > .mud-container` conservaba `matrix(1, 0, 0, 1, 0, 0)` de su animación de entrada
   y este tirador acababa en el píxel 4.210 del DOCUMENTO — o sea scrolleaba, y él tenía razón. Se cierra
   en `theme.css` (`animation-fill-mode: backwards`), que es donde estaba la causa, y lo vigila
   `s137-el-tirador-del-indice-no-scrollea.spec.ts`.
   ⇒ En reposo se ve una PESTAÑA con su flecha: discreta —está en todas las fichas y en todo el scroll—
     pero reconocible como algo que se pulsa. El rótulo sigue apareciendo al acercarse. */
.ins-detail-rail-handle__btn::before {
    content: "";
    position: absolute;
    inset-inline-end: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 26px;
    height: 64px;
    border-start-start-radius: 999px;
    border-end-start-radius: 999px;
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
    border-inline-end: 0;
    box-shadow: -2px 0 8px rgb(0 0 0 / 10%);
    opacity: .9;
    transition: opacity var(--dur-fast, 150ms) var(--ease-out, cubic-bezier(.2, .8, .2, 1));
}

/* 🎬 La cara del tirador. La FLECHA se ve siempre —es lo que dice «esto se pulsa y abre algo por la
   derecha»—; lo que entra creciendo desde el borde es sólo el RÓTULO. Antes se ocultaba la cara entera,
   y por eso en reposo no quedaba nada que interpretar. */
.ins-detail-rail-handle__face {
    display: flex;
    align-items: center;
    gap: 6px;
    position: relative;
    white-space: nowrap;
    color: var(--mud-palette-text-secondary);
    transition: color var(--dur-fast, 150ms) var(--ease-out, cubic-bezier(.2, .8, .2, 1));
}

/* `max-width` y no `display` porque lo que se anima tiene que poder interpolarse; y `nowrap` arriba para
   que el rótulo no se parta en dos renglones a mitad de la transición. */
.ins-detail-rail-handle__label {
    display: inline-block;
    max-width: 0;
    overflow: hidden;
    opacity: 0;
    transition: max-width var(--dur-base, 240ms) var(--ease-out, cubic-bezier(.2, .8, .2, 1)),
                opacity var(--dur-fast, 150ms) var(--ease-out, cubic-bezier(.2, .8, .2, 1));
}

.ins-detail-rail-handle__btn:hover,
.ins-detail-rail-handle__btn:focus-visible {
    padding-inline-start: 12px;
    padding-inline-end: 12px;
    background: var(--mud-palette-surface);
    border-color: var(--mud-palette-lines-default);
    box-shadow: -2px 0 10px rgb(0 0 0 / 12%);
}

.ins-detail-rail-handle__btn:hover::before,
.ins-detail-rail-handle__btn:focus-visible::before {
    opacity: 0;
}

.ins-detail-rail-handle__btn:hover .ins-detail-rail-handle__face,
.ins-detail-rail-handle__btn:focus-visible .ins-detail-rail-handle__face {
    color: var(--mud-palette-text-primary);
}

.ins-detail-rail-handle__btn:hover .ins-detail-rail-handle__label,
.ins-detail-rail-handle__btn:focus-visible .ins-detail-rail-handle__label {
    max-width: 16rem;
    opacity: 1;
}

/* ⚠️ CUANDO NO SCROLLEA LA VENTANA, ESE `top` SOBRA — y la barra tapa el título que va debajo.
   MEDIDO el 31-ago-2026 con la sonda de cajas, en `/current-account/{Kind}/{id}`: 48 px del título
   comidos, y `elementFromPoint` sobre el nombre de la aseguradora devolvía la propia barra.

   La aritmética que lo cierra, y por qué la misma hoja acierta en una ficha y falla en la otra:

     · ficha de PÓLIZA  → el contenedor de página es `display:block`, scrollea la VENTANA:
                          64 (hueco del appbar) + 16 (padding) = 80.  La barra cae en 80. ✔
     · CUENTA CORRIENTE → la página cuelga un `.ins-listado` del contenedor, así que se activa la
                          escalera de `insLayout.css` y `.mud-container` pasa a `overflow-y:auto`:
                          es ÉL quien scrollea, y su borde superior YA está en 64.
                          64 (borde) + 16 (padding) + 64 (este `top`) = 144, con el título en 152. ✘

   `top: var(--mud-appbar-height)` existe para compensar una barra FIJA que tapa el viewport. Dentro de
   un contenedor que scrollea por su cuenta no hay nada que compensar: ese contenedor ya empieza donde
   acaba el appbar, así que la compensación se cobra DOS veces. Es la misma clase que esta casa ya tiene
   pagada —una medida escrita contra el eje o el marco equivocado— y por eso el arreglo va en la CLASE y
   no en la pantalla que la destapó: hoy la sufre una sola ficha, pero la hereda cualquier detalle que
   meta un listado a pantalla completa. El selector es el MISMO `:has()` que enciende la escalera, para
   que las dos mitades no puedan divergir. */
.mud-container:has(> .ins-listado, > .ins-fill) .ins-detail-stickybar {
    top: 0;
}

/* ♿ Quien pide menos movimiento recibe el mismo tirador SIN el deslizamiento: los estados siguen siendo
   los dos, lo que se retira es el tránsito entre ellos. Nunca la función. */
@media (prefers-reduced-motion: reduce) {
    .ins-detail-rail-handle__btn,
    .ins-detail-rail-handle__btn::before,
    .ins-detail-rail-handle__face,
    .ins-detail-rail-handle__label {
        transition: none;
    }
}

/* ── 📱 EN ESTRECHO EL CARRIL ES UN PANEL SOBRE EL CONTENIDO, NO UNA FRANJA MÁS ─────────────────────
   Un carril lateral no cabe por debajo de `md`: apilado a banda completa, o empuja la ficha hacia abajo
   (si va arriba) o se queda donde nadie lo busca (si va abajo). El estándar del sector para esa anchura
   es el mismo panel entrando desde el borde, y eso es lo que se hace — **el MISMO componente en su
   ancho**, no una excepción de móvil: lo que cambia es la figura que le da esta hoja, no lo que lleva
   dentro, ni quién lo gobierna, ni el interruptor que lo abre.

   📌 FIJO AL VIEWPORT, no flotante anclado a nada. Es deliberado y es la lección de M-757, donde los
   desplegables se despegaban de su disparador al hacer scroll: un panel que se posiciona respecto de otro
   elemento tiene que perseguirlo, y uno fijo al viewport no tiene a quién perseguir.

   🎚️ Y SE CIERRA TOCANDO FUERA (el velo), porque en esta anchura el interruptor del cromo puede quedar
   debajo del panel. La salida nace con su inversa también aquí. */
@media (max-width: 959.98px) {
    .ins-detail-rail:not(.ins-detail-rail--plegado) {
        position: fixed;
        inset-block: var(--mud-appbar-height, 64px) 0;
        inset-inline-end: 0;
        z-index: 1200;   /* sobre la barra y el cajón de la app (1100), bajo los diálogos (1401) */
        width: min(360px, 88vw);
        max-width: 88vw;
        overflow-y: auto;
        overscroll-behavior: contain;
        padding: var(--ins-detail-rhythm);
        background: var(--mud-palette-surface);
        border-inline-start: 1px solid var(--mud-palette-lines-default);
        box-shadow: -8px 0 24px rgb(0 0 0 / 18%);
    }

    .ins-detail-rail-scrim {
        position: fixed;
        inset: 0;
        z-index: 1199;
        background: var(--mud-palette-overlay-dark, rgb(0 0 0 / 40%));
    }

    /* 🚰 Dentro del panel el índice manda sobre su propio alto: el que se deriva del carril pegajoso
       descuenta una barra compacta que aquí no está encima de él. */
    .ins-detail-rail:not(.ins-detail-rail--plegado) .ins-section-index { max-height: none; }
}

/* ⛔ Y ARRIBA DE `md` EL VELO NO EXISTE. No es «invisible»: no recibe clics ni ocupa sitio en la rejilla,
   porque un nodo suelto entre los items de un `MudGrid` sí sería un item más si tuviera flujo. */
@media (min-width: 960px) {
    .ins-detail-rail-scrim { display: none; }
}

/* El mando no encoge: su rótulo es lo que lo hace encontrable, y a medias no se lee ni se reconoce. */
.ins-detail-rail-toggle { flex-shrink: 0; }

/* 🗂️ La fila de cabecera del índice: su rótulo, y nada más.
   🧹 s120 · M-779 · AQUÍ VIVÍA UN BOTÓN DE CERRAR, y se retira con su motivo escrito. Nació en la s118
   porque el interruptor de la cabecera, metido entre «Anular póliza» y «Suspender cobertura», se leía
   como una acción de negocio —cierto entonces—; así que la salida se desdobló: cerrar aquí, abrir allí.
   Ese motivo murió al mudarse el interruptor al cromo permanente, donde ya no tiene con qué confundirse
   y sirve para las dos direcciones. Lo que se pierde: un clic más cerca del índice. Lo que se gana:
   un solo control sobre un solo estado — y además el de aquí sólo podía cerrar el ÍNDICE, mientras que
   lo que hoy se pliega es el CARRIL entero, acciones incluidas. Un control que cierra media cosa junto
   a otro que cierra la cosa entera es la clase «un par editado por dos controles que escriben aparte».
   ⚖️ La cabecera se queda —y sigue siendo pegajosa— porque el rótulo ETIQUETA la lista que rueda. */
.ins-section-index__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;

    /* 📌 PEGADA AL RODAR POR DENTRO. El índice ACOTA su alto y rueda cuando las secciones no caben
       (`.ins-section-index` de arriba), así que sin esto la cabecera —y con ella el botón de ocultar— se
       iba hacia arriba en cuanto bajabas un poco: el control existía y quedaba fuera de alcance justo
       cuando el índice es largo, que es cuando más ganas dan de cerrarlo. Reportado por él.
       El fondo NO es adorno: sin él, los ítems pasarían por DEBAJO del rótulo y se leerían encima. */
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--mud-palette-surface);
    /* Un filo tenue separa lo pegado de lo que rueda; sin él, la cabecera flota sobre el texto sin que
       se entienda por qué unas líneas se mueven y otra no. */
    box-shadow: 0 1px 0 var(--mud-palette-lines-default);
    padding-bottom: 6px;
}

.ins-section-index__head > .ins-section-index__title {
    padding-bottom: 0;
}

.ins-section-index__title {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    opacity: 0.7;
    padding: 0 4px 8px;
}

.ins-section-index__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* El ítem es un BOTÓN, no un enlace: no navega, mueve el scroll de esta misma pantalla — y además
   tiene que poder ABRIR la sección si el corredor la había plegado. Un `<a href="#…">` no puede hacer
   lo segundo y además ensucia el historial del navegador con anclas. Se le quita el aspecto de botón
   pero se le deja todo lo que un botón trae gratis: foco, teclado y semántica. */
.ins-section-index__item {
    display: block;
    width: 100%;
    text-align: start;
    background: none;
    border: 0;
    border-radius: 8px;
    padding: 6px 8px;
    font: inherit;
    font-size: 0.875rem;
    color: inherit;
    opacity: 0.78;
    cursor: pointer;
    /* Un rótulo de sección largo no parte la figura del carril: se recorta y el título completo sigue
       estando en su cabecera, que es donde el corredor lo lee entero. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 🌗 EL REALCE DEL ÍTEM, con su pareja clara/oscura — y no `--glass-bg`, que es lo que estaba aquí.
   🔴 Medido el 07-sep-2026 en la ficha de una póliza, EN TEMA CLARO: el ítem activo salía con fondo
   `#1e293b` y texto `#0f172a` encima ⇒ 1,28:1, ilegible. Y el hover, igual: cualquier ítem del índice
   se apagaba al pasar el ratón.

   La causa no era el color, era el TOKEN. `--glass-bg` es por contrato la superficie de tarjeta del
   tema OSCURO —lo dice el guard `ACardHasItsOwnSurfaceInBothThemesTests`—, se declara en `:root` (no
   bajo `body.ins-dark`) y por eso SOBREVIVE al cambio a claro, donde la superficie clara no se expresa
   como token sino con reglas `body.ins-light .mud-*`. Esta hoja la enlazan TRES hosts y el portal ni
   siquiera trae `theme.css` propio: un token que solo existe para un tema no se puede consumir desde
   aquí sin dar su pareja.

   ⇒ Mismo remedio y misma disciplina que `--ins-clause-surface` unas secciones más arriba: tinte
   propio, declarado aquí mismo, recesivo en los dos temas y transparente para que herede la superficie
   que tenga debajo en cada host. */
:root {
    --ins-section-index-highlight: rgba(148, 163, 184, 0.16);
}

body.ins-light {
    --ins-section-index-highlight: rgba(100, 116, 139, 0.14);
}

.ins-section-index__item:hover,
.ins-section-index__item:focus-visible {
    background: var(--ins-section-index-highlight, rgba(148, 163, 184, 0.16));
    opacity: 1;
}

/* 📌 LA SECCIÓN QUE SE ESTÁ MIRANDO. Un índice que solo navega no dice DÓNDE estás, y en una ficha de
   6.000 px eso es justo lo que el corredor necesita saber al llegar. Lo marca el observador del
   navegador (`insCoreUtils.sectionSpy`), no el servidor.

   ⚖️ El resalte NO se apoya solo en el color: lleva su propia barra a la izquierda. Un estado que se
   distingue únicamente por tono desaparece para quien no separa esos dos tonos, y aquí el estado es la
   única información que este elemento añade. */
.ins-section-index__item.is-active {
    opacity: 1;
    font-weight: 600;
    /* El mismo tinte del hover (ver su pareja clara/oscura arriba), no un token de tema oscuro suelto:
       lo que separa «activo» de «bajo el ratón» es el PESO y la barra, que es lo que sigue leyéndose
       cuando el color no llega. */
    background: var(--ins-section-index-highlight, rgba(148, 163, 184, 0.16));
    box-shadow: inset 2px 0 0 0 var(--mud-palette-primary, #7c5cff);
}

/* 📌 EL DESTINO NO ATERRIZA BAJO EL CROMO FIJO. `scrollIntoView({block:'start'})` alinea con el filo
   del viewport, y encima de ese filo viven la barra de la aplicación y la barra compacta de la ficha:
   sin esto, la cabecera de la sección a la que se acaba de ir queda TAPADA, que es la misma clase que
   `s73-q` vigila con «el chrome fijo RESERVA su franja». El navegador lo resuelve solo si se le dice
   cuánto vale esa franja, y vale lo que el mismo token del carril declara. */
.ins-section {
    scroll-margin-top: calc(var(--mud-appbar-height, 64px) + var(--ins-detail-stickybar-height, 56px) + var(--ins-detail-rhythm));
}

/* 🧹 s120 · M-779 · AQUI VIVIA `.ins-section-index--innecesario`, y se retira con su motivo escrito.
   QUE HACIA: `theme.js` medía del principio de la PRIMERA seccion al de la ULTIMA y, si eso cabia en una
   pantalla, escondia el indice por CSS y devolvia el ancho — con dos reglas gemelas que ademas tenian que
   distinguir «carril que solo llevaba indice» de «carril con secciones propias».
   POR QUE SE VA: contestaba LO MISMO que `SectionIndexEligibility` desde otra capa y en silencio, y con el
   mando del carril pintado en los dos estados eso hacia MENTIR al rotulo — ofrecia abrir un panel cuyo
   indice el CSS tenia escondido. El motivo por el que nacio («el indice no tiene sentido puesto que todo
   cabe en una sola vista») lo contesta ahora el censo, con la primera respuesta por el NO ya puesta: la
   ficha de persona, decidida por el mirando la app.
   QUE SE PIERDE: la medida VIVA (una ficha sin altura en el censo seguira ofreciendo indice hasta que se
   mida o hasta que el corredor pliegue el carril). QUIEN LO CUBRE: ese censo — y quedan 14 por medir.
   Su lugar en el reparto de ancho lo ocupa la regla en negativo de mas arriba, que cubre las tres formas
   de no tener carril a la derecha con UNA condicion en vez de dos gemelas. */


/* ── 🥇 InsDetailDialog · el detalle que se mira, se queda quieto y se copia ────────────────────────
   Pareja de InsDetailDialog.razor + insCopy.js. El disparador tiene que leerse como «hay más aquí» sin
   competir con el dato de la celda: por eso es tipografía pequeña, subrayado punteado y color
   secundario — el mismo lenguaje que ya usaba el enlace «+N huecos más» que sustituye. */
.ins-detail-link__trigger {
    font-size: 0.75rem;
    text-decoration: underline dotted;
    text-underline-offset: 2px;
    color: var(--mud-palette-text-secondary);
}

.ins-detail-dialog__body {
    /* Un detalle largo NO empuja el diálogo fuera de la pantalla: scrollea por dentro. */
    max-height: min(60vh, 520px);
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* El botón de copiar es HTML plano (lo atiende insCopy.js por delegación, sin interop), así que se viste
   aquí para que no desentone con los botones de MudBlazor que tiene al lado. */
.ins-detail-dialog__copy {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border-radius: 8px;
    border: 1px solid var(--mud-palette-lines-default);
    background: transparent;
    color: var(--mud-palette-text-primary);
    font: inherit;
    font-size: 0.875rem;
    cursor: pointer;
}

.ins-detail-dialog__copy:hover {
    background: var(--mud-palette-action-default-hover);
}

/* El acuse: lo pone insCopy.js y se retira solo. Las dos etiquetas viven en el DOM —el texto es de
   Blazor, que es quien lo localiza— y aquí solo se decide CUÁL se ve. */
.ins-detail-dialog__copy-done { display: none; }
.ins-detail-dialog__copy[data-ins-copied] .ins-detail-dialog__copy-idle { display: none; }
.ins-detail-dialog__copy[data-ins-copied] .ins-detail-dialog__copy-done { display: inline; }
.ins-detail-dialog__copy[data-ins-copied] { border-color: var(--mud-palette-success); color: var(--mud-palette-success); }
