/* ═══════════════════════════════════════════════════════════════════════════════
   ▓ PATRÓN · ACORDEÓN GUIADO — HOJA CANÓNICA (vive en DOS rutas, BYTE A BYTE IGUAL) ▓
   Extraída de `app/css/cotizador.css` el 2026-09-01, donde vivía repartida (sin
   archivo propio) dentro de una hoja de ~7500 líneas — imposible de montar en otra
   pantalla sin copiar a mano.

   `DECISION-FUENTE: Ricardo, 2026-09-01 — «Quiero que siempre que se incorpore este
   cotizador a un sitio, se incorpore completo y actualizado. No quiero
   deshomologaciones.»`

   CÓMO SE MONTA: esta hoja + `acordeon-guiado.js` + el marcado (ver `index.html`,
   `#lzcPasos` y los 4 pasos del cotizador).

   DEPENDE de los tokens del canon (`colors_and_type.css`, ya cargado por esta app) y
   de un reinicio con `box-sizing: border-box` + `margin/padding: 0` en `*`.

   RELACIÓN CON LA COPIA DEL CATÁLOGO
   (`design-system/patrones/acordeon-guiado/acordeon-guiado.css`): es la MISMA hoja,
   byte a byte, verificado con `node design-system/gate_gemelos.js` — no una copia
   narrada ni una versión adaptada. Cualquier cambio a este archivo se replica de
   inmediato al gemelo (y viceversa): el gate reprueba en rojo el día que dejen de
   coincidir. Antes del 2026-09-01 unificaba sólo el CSS activo (selectores y
   declaraciones); desde ese día unifica también el texto, para que no haya dos
   narrativas envejeciendo por separado sobre la misma pieza.

   LO QUE NO VIAJÓ AQUÍ, A PROPÓSITO — porque es de la APP que aloja el patrón, no del
   patrón en sí (su selector nombra una clase que sólo existe en esta app, aunque
   también nombre una clase del patrón): `.lzc-nueva` (aviso bajo el botón de
   "solicitud nueva"), los overrides de `overflow` cuando un combo o una ayuda abren
   DENTRO de un paso, `.lzc-overlay[aria-hidden="true"] .exds-acc-body` (la
   visibilidad del modal de confirmación manda sobre la del paso), los dos
   `padding-bottom` que dependen de `.lzc-filas`/`.lzc-otp-pie` (la forma del
   contenido de ESTA app), el cruce de `.cz-cta > span.gAcc-cambia` (botón
   "Solicitar" de la tarjeta), la maqueta apilada del paso 2 a 430px, y la zona de
   gesto de `.exds-navp-brand` (barra de navegación). Todo eso sigue en
   `cotizador.css`, cada uno con su propio comentario señalando por qué se queda ahí
   y no aquí — y con eso, esta hoja no conoce ni una sola clase que no sea del propio
   patrón (`.exds-acc*` / `.gAcc-*`), que es justo lo que la hace montable en
   cualquier página sin arrastrar nada del cotizador.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* acordeón · cada fila es una CARD INDIVIDUAL según DS (06-COMPONENTS.md pattern <details>) */
/* ═══════════════════════════════════════════════════════════════════════════
   ACORDEÓN DEL CATÁLOGO · gemelo vanilla de Acordeon.jsx (MODO PASOS)
   Homologación cotizador 2026-08-04 · FIDELIDAD MÁXIMA al canon, incluido movimiento:
   cards separadas, la ABIERTA se ELEVA (--shadow-md), apertura grid-rows 0fr→1fr
   (--motion-slow) + fade del contenido (opacity/translateY, delay 60ms), badge→ink,
   summary que se oculta salvo data-keep, chevron rota. reduced-motion aware.
   Los .cz-acc* quedaron RETIRADOS (misma pieza, nombre de la app → clase del catálogo).
   ═══════════════════════════════════════════════════════════════════════════ */
.exds-acc { display:flex; flex-direction:column; gap:12px; font-family:var(--font-sans); }
.exds-acc-card { border:1px solid var(--color-border-subtle); border-radius:var(--radius-lg);
  background:var(--color-surface); overflow:hidden; box-shadow:var(--shadow-card);
  transition: border-color var(--motion-base,250ms) var(--ease-default), box-shadow var(--motion-base,250ms) var(--ease-default); }
.exds-acc-card[data-open="true"] { border-color:var(--color-border-default); box-shadow:var(--shadow-md); }
/* ⛔ LA CABECERA YA NO ES UN BOTÓN: ES UNA FILA CON DOS CONTROLES HERMANOS
   (modo guiado · COMPONENTE_ACORDEON v1.3 · 2026-08-11).
   QUÉ ERA: un `<button class="exds-acc-h">` que ocupaba toda la fila, con el chevrón
   dentro como `<span>` decorativo.
   QUÉ ES AHORA: un `<div>` que contiene DOS `<button>` hermanos — el DISPARADOR
   (`.exds-acc-trig`, la zona del título, `flex:1`) y el CONTROL DE AVANCE
   (`.gAcc-av`, `flex:none`), uno al lado del otro y sin solape.
   POR QUÉ: el control de avance tiene que ser un botón de verdad, y `<button>`
   dentro de `<button>` no es HTML válido — el navegador saca el interior del orden
   de tabulación y el lector de pantalla funde los dos nombres en uno
   («Producto Continuar, botón»). Partir la fila es la ÚNICA anatomía válida.
   Las medidas NO cambian: mismo `padding 16px 20px`, mismo `gap 12px`, misma
   tipografía. Lo que cambia es la etiqueta y de quién cuelga el `aria-expanded`. */
.exds-acc-h { display:flex; align-items:center; gap:12px; width:100%; padding:16px 20px; border:none; background:none; text-align:left; font:500 var(--fs-body, 14px) var(--font-sans); color:var(--fg1); box-sizing:border-box; }
/* EL DISPARADOR · la zona del título. Es quien lleva el `aria-expanded`: hay UN solo
   disclosure con dos maneras de accionarlo, no dos disclosures. */
.exds-acc-trig { display:flex; align-items:center; gap:12px; flex:1; min-width:0; border:none;
  background:none; text-align:left; cursor:pointer; font:500 var(--fs-body, 14px) var(--font-sans); color:var(--fg1);
  margin:-8px 0; padding:8px 0; }
.exds-acc-trig:focus-visible { outline:none; box-shadow: inset 0 0 0 1px var(--color-border-focus); border-radius:var(--radius-sm); } /* v1.0 · sin borde (border:none) → línea interior 1px; el radio se mantiene igual que en el anillo v0.6 (sólo aplica en foco, la caja en reposo es cuadrada) */
.exds-acc-card[data-fut="true"] .exds-acc-trig { cursor:default; }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   PASO SELLADO · cómo se le dice al prospecto que ESTE no se abre (Ricardo, 2026-08-15)

   Su pregunta, y es la buena: *«¿cómo le dices al usuario que ya no es clickeable, para que no
   pierda tiempo intentándolo?»*

   ⛔ LA RESPUESTA NO ES UN CARTEL. Poner «no editable» sería añadir ruido para explicar una
   ausencia. **Se le dice RETIRÁNDOLE TODAS LAS SEÑALES DE QUE SE PULSA**, que son exactamente
   tres y están medidas en esta hoja:
     1. el cursor de mano  → vuelve a la flecha normal;
     2. el fondo gris al pasar por encima → no pasa nada, y ésta es la que de verdad corta el
        intento: las filas de al lado responden y ésta no, así que la diferencia se NOTA;
     3. el control de avance con su chevrón → no se pinta.

   ⭐ Y LA CUARTA, QUE ES LA IMPORTANTE Y NO ES CSS: **el resumen ya enseña todo lo que hay
   dentro** («Correo verificado · prueba@exante.mx»). Uno intenta abrir un plegado cuando cree
   que esconde algo que no ve; si el renglón ya lo dice entero, no queda curiosidad que resolver.
   *La mejor manera de que nadie abra una puerta es que se vea que detrás no hay habitación.*

   En MÓVIL no hay hover, así que ahí quedan la (3) y la (4) — que son suficientes porque la
   señal fuerte, el resumen completo, no depende del ratón.
   ══════════════════════════════════════════════════════════════════════════════════════════ */
.exds-acc-card[data-sellado="true"] .exds-acc-trig { cursor:default; }
.exds-acc:not([data-bleed="true"]) .exds-acc-card[data-sellado="true"] .exds-acc-h:hover { background:none; }
.exds-acc-card[data-sellado="true"] .gAcc-av { display:none; }
/* En MODO PASOS (data-bleed) el encabezado NO se rellena de gris: "abierto" lo dice la elevación + el badge en tinta. El gris queda para hover/selección. */
.exds-acc:not([data-bleed="true"]) .exds-acc-card:not([data-open="true"]) .exds-acc-h:hover { background:var(--color-bg-subtle); }
.exds-acc:not([data-bleed="true"]) .exds-acc-card[data-open="true"] .exds-acc-h { background:var(--color-bg-subtle); transition: background var(--motion-base) var(--ease-default); }
/* ⛔ `.exds-acc-chev` RETIRADO 2026-08-11 — de los DOS lados (regla + emisores).
   QUÉ ERA: el chevrón de 16px que giraba 180° al abrir, dentro del botón-cabecera.
   QUÉ ES AHORA: nada. Su trabajo lo hace el CONTROL DE AVANCE (`.gAcc-av`), cuyo
   glifo ES el mismo chevrón: no lo sustituye, lo CONTIENE — la punta gira −90° y
   aterriza como cabeza de flecha.
   POR QUÉ SE VA ENTERO: dejar la regla sin emisor es la mitad de una retirada, y una
   clase de CSS sin quien la emita es peso que la siguiente pieza copia creyendo que
   es canon. Sus 4 emisores (`app/index.html`) se retiraron en el mismo commit.
   ⚠ No existe en `mi-exante.css` ni en `backoffice.css`: era exclusiva del cotizador. */
/* ⛔ EL CUERPO CERRADO SE OCULTA DE VERDAD · `visibility` (2026-08-30). Copia fiel del gemelo
   (`design-system/patrones/acordeon-guiado/acordeon-guiado.css`), no una variante.
   El defecto que cierra, MEDIDO con tabulaciones reales: con los pasos plegados el Tab paraba
   en los controles de dentro — 4 paradas invisibles en este cotizador. Las tres señales de
   cerrado que había (0fr, el overflow del inner y la opacidad del contenido) son las tres
   VISUALES, y ninguna saca nada del orden de tabulación.
   El retardo va ASIMÉTRICO porque `visibility` no interpola, salta: al abrir 0s (visible desde
   el primer fotograma), al cerrar --motion-slow (se oculta cuando la caja ya terminó de
   plegarse). Sin eso el contenido se esfumaría a mitad del gesto.
   ⚠ NO choca con los dos `PUENTE-ALLOW` que viven en `app/css/cotizador.css` (la app que aloja
   este patrón) y apagan el recorte de `.exds-acc-inner` mientras un combo o una ayuda están
   abiertos: aquéllos sólo actúan dentro de un paso ABIERTO, y esto sólo oculta el CERRADO.
   Comprobado el 2026-08-30 en escritorio y a 375 px.
   MOTION-ALLOW: 0s · `visibility` es una propiedad DISCRETA: no interpola, salta. Una
   duración es inaplicable ahí —el gesto lo lleva el RETARDO, que es lo que este bloque
   explica arriba— y no existe un token de «sin duración»: ponerle var(--motion-*) haría
   que el contenido se esfumara a mitad del pliegue, que es justo el defecto que estas dos
   reglas evitan. Declarado el 2026-09-01: la exención ya estaba razonada aquí, pero no
   escrita en el formato que lee `lint_movimiento` (R2), así que el gate la contaba como
   duración a mano y salía en rojo. *Desviarse está permitido; desviarse en silencio, no.* */
.exds-acc-body { display:grid; grid-template-rows:0fr; visibility:hidden;
  transition: grid-template-rows var(--motion-slow,400ms) var(--ease-default),
              visibility 0s linear var(--motion-slow,400ms); }
.exds-acc-card[data-open="true"] .exds-acc-body { grid-template-rows:1fr; visibility:visible;
  transition: grid-template-rows var(--motion-slow,400ms) var(--ease-default),
              visibility 0s linear 0s; }
/* ⛔ LA VISIBILIDAD DE UN MODAL QUE ALOJE ESTE ACORDEÓN, SI LA NECESITAS, ES DE QUIEN LO ALOJA —
   NO DE ESTE ARCHIVO. En `cotizador.css` hay un ejemplo real (`.lzc-overlay[aria-hidden="true"]
   .exds-acc-body`) que resuelve el caso "un paso nace abierto, pero el modal que lo contiene está
   cerrado" para SU modal concreto. No se cosecha aquí a propósito: `.lzc-overlay` es una clase de
   esa app, no del patrón, y esta hoja no debe conocer los contenedores que la alojan. Si tu app
   tiene el mismo problema, replica esa regla con TU propia clase de modal. */
.exds-acc-inner { overflow:hidden; min-height:0; }
.exds-acc-content { padding:14px 20px 18px; font-size:13px; color:var(--fg3); line-height:1.6;
  opacity:0; transform:translateY(-4px);
  transition: opacity var(--motion-base,250ms) var(--ease-default), transform var(--motion-base,250ms) var(--ease-default); }
.exds-acc-card[data-open="true"] .exds-acc-content { opacity:1; transform:none; transition-delay:60ms; }
/* MODO PASOS: contenido full-bleed (aloja las opciones/inputs, que cancelan este padding con su margen).
   ⛔ CORRECCIÓN DE ALINEACIÓN (2026-10-06) — homologada del patrón (`acordeon-guiado.css`, AG-25).
   DECISION-FUENTE: Ricardo, 2026-10-06 — «el cotizador publico lo elegi b porque corrige un problema que tenia:
   el texto empezaba atras del limite izquierdo del contador (1)». El contenido del paso NUNCA empieza a la
   izquierda del borde izquierdo del contador: contador en x=21, texto en 33 = 21 + 12 (antes 19). Relleno izquierdo
   32 (20 de la cabecera + 12); a 430 px o menos, 28 (16 + 12). Las listas a sangre cancelan ese relleno por la
   izquierda con --ol-sangrado-xi y siguen de borde a borde. */
.exds-acc-content.exds-acc-bleed { --acc-izq: 32px; --ol-sangrado-xi: var(--acc-izq);
  padding:0 18px 22px var(--acc-izq); color:inherit; font-size:inherit; line-height:inherit; }
/* ⛔ LOS DOS AJUSTES DE `padding-bottom` SEGÚN LA FORMA DEL ÚLTIMO HIJO (lista sin aire abajo,
   pie del código con 16 en vez de 22) NO SE COSECHAN AQUÍ: sus `:has()` apuntan a `.lzc-filas` y
   `.lzc-otp-pie`, que son clases de contenido de ESTA app (el modal de confirmación del
   cotizador), no del patrón. Se quedan en `cotizador.css`, junto a las clases que nombran. Si tu
   contenido necesita el mismo ajuste, replica la regla con TUS clases de contenido. */
/* ⛔ EL NÚMERO · SIEMPRE 24px · CUATRO ESTADOS (modo guiado, 2026-08-11).
   QUÉ ERA: dos estados (pendiente gris / abierto en tinta) y el número como texto suelto.
   QUÉ ES AHORA: cuatro estados, y la cifra y la palomita ocupan LA MISMA CELDA
   (`grid-area:1/1`) para que al cambiar no se empujen — se cruzan en el sitio.
     1 Pendiente  gris  · la cifra          3 Terminado  ESMERALDA · la palomita
     2 Activo     tinta · la cifra          4 Reabierto  esmeralda · la palomita + card elevada
   POR QUÉ `display:grid` y no `flex`: con flex, cifra y palomita serían hermanas en
   línea y la caja de 24 tendría que crecer para las dos. Superpuestas, no. */
/* ⛔ Variables del intercambio de icono · CORREGIDAS el 2026-08-14 por Ricardo:
   «ni rebota ni se redibuja». La primera versión conservó --ease-emphasis en la
   palomita, y esa curva tiene SOBREPASO (1.26) — o sea, rebotaba. El efecto que él
   eligió usa la MISMA curva sin sobrepaso para los dos glifos. Fuente: el paquete
   oficial de transitions.dev (`icon-swap`). */
.exds-acc {
  --icon-swap-dur: var(--motion-base, 250ms);   /* con reserva: sin ella, un canon incompleto deja la duración en CERO y el efecto no ocurre — se ve como «no funciona» (lección de los 34 tokens) */
  --icon-swap-ease: ease-in-out;
  --icon-swap-blur: 2px;
  --icon-swap-start-scale: .25;
}
.exds-acc-badge { width:24px; height:24px; border-radius:var(--radius-pill); flex:none; display:grid; place-items:center;
  font:600 var(--fs-eyebrow,11px) var(--font-sans); background:var(--color-bg-subtle); border:1px solid var(--color-border-subtle); color:var(--fg2);
  transition: background var(--motion-fast) var(--ease-default), border-color var(--motion-fast) var(--ease-default), color var(--motion-fast) var(--ease-default);
  /* AÑADIDO 2026-09-01, homologando al gemelo del catálogo — y NO es cosmética aunque no
     cambie un solo píxel hoy. Los cuatro tokens ya los declara `.exds-acc` más arriba, así
     que la insignia los hereda y se ve igual con o sin esto. Lo que cambia es de qué depende:
     con la redeclaración, la insignia **no necesita un ancestro** para animar su cambio de
     glifo, y se puede montar suelta. Mismos valores, cero efecto visual, una dependencia
     menos. *Una pieza que sólo funciona dentro de su contenedor no es una pieza: es una parte.*
     El gemelo la lleva desde el 2026-08-23 y producción no, y esa diferencia mantenía
     `gate_gemelos` en rojo desde que la pareja se volvió medible esta misma tarde. */
  --icon-swap-dur: var(--motion-base, 250ms);
  --icon-swap-ease: ease-in-out;
  --icon-swap-blur: 2px;
  --icon-swap-start-scale: .25;
}
.exds-acc-badge > * { grid-area:1/1; display:flex; align-items:center; justify-content:center; }
/* ⛔ INTERCAMBIO NÚMERO → PALOMITA · efecto `icon-swap` de transitions.dev.
   ✔ Pedido por Ricardo el 2026-08-14, con el efecto elegido por él. Homologado desde el
   patrón (`design-system/patrones/acordeon-guiado/`), que es la fuente.
   La estructura ya era la correcta —dos glifos apilados en la misma celda de rejilla—;
   faltaba el DESENFOQUE, que es lo que hace que el que se va parezca alejarse.
   Y al medirlo apareció un defecto que nadie había visto: las dos mitades del cruce
   duraban distinto (el número se iba en 120ms, la palomita entraba en 250ms), así que
   durante 130ms no había NINGUNO de los dos y la insignia parpadeaba vacía.
   *Un cruce sólo es un cruce si las dos mitades comparten reloj.*
   Las variables del efecto se declaran junto al contenedor, más abajo. */
.exds-acc-badge .cifra {
  transition: opacity   var(--icon-swap-dur) var(--icon-swap-ease),
              transform var(--icon-swap-dur) var(--icon-swap-ease),
              filter    var(--icon-swap-dur) var(--icon-swap-ease);
}
/* la palomita es el ÚNICO rebote de la pieza (--ease-emphasis, papel 4 de la matriz) */
.exds-acc-badge .tick {
  opacity: 0; transform: scale(var(--icon-swap-start-scale));
  filter: blur(var(--icon-swap-blur));
  transition: opacity   var(--icon-swap-dur) var(--icon-swap-ease),
              transform var(--icon-swap-dur) var(--icon-swap-ease),
              filter    var(--icon-swap-dur) var(--icon-swap-ease);
}
.exds-acc-badge .tick svg { width:13px; height:13px; }
/* 2 · ACTIVO */
.exds-acc-card[data-open="true"] .exds-acc-badge { background:var(--color-action-ink); border-color:var(--color-action-ink); color:var(--fg-inverse); }
/* 3 y 4 · TERMINADO / REABIERTO — esmeralda + palomita.
   ⛔ EXCEPCIÓN DECLARADA, no descuido: la regla del 2026-08-05 dice «completado = tinta,
   nunca verde» y sigue vigente para la línea de pasos del modal de confirmación.
   GATE-ALLOW: esmeralda en paso terminado · ALCANCE: sólo el acordeón guiado del
   cotizador público · ✔ DECIDIDO por Ricardo el 2026-08-10. */
.exds-acc-card[data-done="true"] .exds-acc-badge { background:var(--color-emerald); border-color:var(--color-emerald); color:var(--fg-inverse); }
.exds-acc-card[data-done="true"] .exds-acc-badge .cifra { opacity:0; transform:scale(var(--icon-swap-start-scale, .25)); filter: blur(var(--icon-swap-blur, 2px)); }
.exds-acc-card[data-done="true"] .exds-acc-badge .tick  { opacity:1; transform:scale(1); filter: blur(0); }
/* El TÍTULO cede ANTES que el botón: se corta con «…» (orden de cesión, ficha §Móvil) */
.exds-acc-ttl { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; flex:none; }
.exds-acc-card[data-fut="true"] .exds-acc-ttl { color:var(--fg4); }  /* gris de deshabilitado · 1,88:1 DECLARADO */
.exds-acc-sum { flex:1; text-align:right; font:400 var(--fs-body-sm, 13px) var(--font-sans); color:var(--fg3); font-variant-numeric:tabular-nums;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; opacity:1; transition:opacity var(--motion-fast) var(--ease-default); }
.exds-acc-card[data-open="true"] .exds-acc-sum:not([data-keep="true"]) { opacity:0; }
/* extensión del cotizador (no del canon FAQ): resumen en estado de error (precio fuera de rango) · solo color */
/* ⛔ BASE, NO `-deep`. Aquí decía «el texto de error va en -deep» por la regla «SÓLO LA TINTA»
   (12-ago), que separa dos perillas —`--color-error` para bordes e iconos, la tinta para las
   LETRAS— y eso sigue siendo cierto. Lo que le faltaba era CUÁL tinta: §0-quater de
   `COMPONENTE_SEMANTICOS.md` (`DECISION-FUENTE:` Ricardo 2026-08-20) reserva `-deep` a lo que se
   pinta ENCIMA del tinte de su propia familia. Este resumen va sobre la card BLANCA → base.
   Medido 2026-08-29: #DA342B = 4,66:1 sobre blanco · #D61005 = 5,34:1.
   ⛔ Y ESTE COMENTARIO DECÍA LO CONTRARIO DE LO QUE HOY ES CIERTO: proponía la BASE como la
   opción mejor, y con el rojo nuevo la base es la PEOR de las dos. La inversión del rojo —donde
   el «profundo» era más claro que la base— desapareció al cambiar el token. */
.exds-acc-sum--err { color:var(--color-error, #DA342B); font-weight:var(--fw-medium, 500); }

/* ══════════════════════════════════════════════════════════════════════════════
   ▓ LA FRASE CEDE EL SITIO AL RESUMEN · papel 6 ▓  (Ricardo, 2026-09-01 — opción B)

   `DECISION-FUENTE: Ricardo, 2026-09-01 — sobre la lámina
   `plans/decisiones/_decision_morph_resumen_2026-09-01.html`, con los tres estados montados en
   vivo: «b, solo falta morph».`

   Las dos frases que se turnan en ese renglón —«Elige tu historial» y «Regular»— dicen
   lo mismo en dos momentos: qué falta y qué se eligió. *Dos textos que se turnan en el mismo
   sitio piden un relevo, no un corte.*

   ⛔ MISMA ANATOMÍA DE DOS CAPAS QUE LAS CIFRAS, y por el mismo motivo de fondo: el resumen dice
   la VERDAD desde el primer cuadro y la que se despide es un **pseudo-elemento**, que no cuenta
   en `textContent` y está fuera de la maqueta. Aquí importa además porque este resumen es lo que
   el paso PLEGADO le enseña al prospecto — y ya hubo un defecto por enseñar ahí algo que no era
   (el pago inicial, 2026-08-12).

   ⛔ Y ES UN MORPH, NO UNA SALIDA CON UNA ENTRADA — corregido el mismo día tras verlo Ricardo:
   *«no es morph, es salida y entrada. 0 conexión entre ambos textos… Morph → un elemento se
   convierte en otro»*. La primera versión hacía las dos mitades **en secuencia** (120 ms fuera,
   250 dentro) y **en direcciones opuestas** (una subía, la otra entraba desde abajo), y encima la
   frase **saltaba 44 px** antes de irse porque se pintaba ya alineada con el destino. Tres cosas
   que juntas rompen la idea: dos tiempos son dos sucesos, y dos direcciones son dos cosas.

   AHORA: **un solo reloj** (`--motion-base`), **una sola curva** (`--ease-default`) y **un solo
   recorrido, horizontal**, que las dos capas hacen A LA VEZ y convergiendo. Sin subida y sin
   desenfoque: subir dice «me voy» y desenfocar dice «me alejo», y aquí nadie se va.
   El recorrido no se teclea — es la distancia real entre donde acaba la frase y donde acabará el
   resumen (~44 px), que es justo el sitio que el chevrón reserva al aparecer. *El texto no se
   aparta porque sí: se aparta para dejarle sitio a lo que llega.*
   ══════════════════════════════════════════════════════════════════════════════ */
/* ⛔ EL FANTASMA CUELGA DE LA FILA, NO DEL RESUMEN. Si colgara del resumen sería su
   descendiente, y la opacidad con la que el resumen arranca lo apagaría también: no se vería a
   nadie convertirse en nadie. *Dos capas exigen dos dueños distintos.*
   Su sitio de LLEGADA es el del resumen (`--acc-fantasma-der`, medido) y su sitio de PARTIDA es
   donde estaba la frase de verdad (`--acc-morph-dx`, también medido). Las dos distancias se
   miden en el instante: un número tecleado para alinear dos cajas caduca en cuanto alguien toca
   una de las dos. */
.exds-acc-h { position: relative; }
.exds-acc-h[data-fantasma]::after {
  content: attr(data-fantasma);
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: flex-end;
  padding-right: var(--acc-fantasma-der, 64px);
  font: 400 var(--fs-body-sm, 13px) var(--font-sans); color: var(--fg3);
  white-space: nowrap; pointer-events: none;
  /* PARTE de donde estaba la frase */
  transform: translateX(var(--acc-morph-dx, 0px));
  opacity: 1;
  transition: transform var(--motion-base) var(--ease-default),
              opacity   var(--motion-base) var(--ease-default);
}
/* Y LLEGA al sitio del resumen, apagándose — a la vez que el resumen hace el mismo viaje. */
/* ⛔ AQUÍ HABÍA UN ESPACIO, Y ESE ESPACIO MOVÍA LA ZONA TÁCTIL · 2026-09-01.
   La línea decía `.exds-acc-h[data-morph-va] ::after` — con un espacio antes de `::after`, lo que
   la convierte en «el ::after de CUALQUIER descendiente del encabezado», no en el del encabezado.
   Así que durante los ~290 ms del morph le aplicaba `transform: translateX(0)` al `::after` de
   `.exds-acc-trig`, que es el que AGRANDA el área de toque a 44 px y la centra.
   Medido sobre app.exante.mx a 390×844 con `hasTouch`: en reposo `matrix(1,0,0,1,-99.17,-22)`;
   durante el morph, `matrix(1,0,0,1,0,0)` en los cuatro cuadros muestreados. La zona de 198×44
   salta 99 px a la derecha y 22 abajo — en el cotizador público, que es la ÚNICA superficie que
   CLAUDE.md exige que funcione en teléfono.
   *Un espacio no cambia un valor: cambia a QUIÉN se le aplica la regla.* Por eso no lo ve ningún
   medidor del arnés — `lint_tokens`, `gate_puente` y `gate_fidelidad` comparan VALORES, y el valor
   era correcto; el equivocado era el destinatario. Lo cazó una auditoría de ojos frescos. */
.exds-acc-h[data-morph-va]::after { transform: translateX(0); opacity: 0; }

/* El RESUMEN hace el MISMO viaje, en el MISMO reloj: nace donde estaba la frase y llega a su
   sitio apareciendo. Una CLASE, no un envoltorio — `textContent` se lleva por delante a
   cualquier hijo, y el repintado del resumen lo destruía. */
.exds-acc-sum--morph {
  transition: transform var(--motion-base) var(--ease-default),
              opacity   var(--motion-base) var(--ease-default);
}
.exds-acc-sum--morph.is-morph-0 {
  transform: translateX(var(--acc-morph-dx, 0px)); opacity: 0;
  transition: none;
}
/* ⛔ NI SUBIDA NI DESENFOQUE, y es lo que separa un morph de una salida con una entrada:
   subir dice «me voy», desenfocar dice «me alejo». Aquí nadie se va — uno SE CONVIERTE en otro,
   así que el único movimiento es el recorrido que comparten, y en la misma dirección. */
@media (prefers-reduced-motion: reduce) {
  .exds-acc-sum--morph { transition: none !important; }
  .exds-acc-h[data-fantasma]::after { transition: none !important; content: none; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   ▓ EL CONTROL DE AVANCE · la pieza nueva del MODO GUIADO (2026-08-11) ▓
   Alto 32 = escalón `sm` del catálogo de botones (COMPONENTE_BOTON: 32 sm · 40 md ·
   48 lg), con su relleno `0 14px` de ese mismo escalón. El punto se queda en 24 —
   los dos son valores que YA existen, dan 1,33 de relación, y el botón no domina la
   fila porque sus 32 caben holgados en los 64 px del renglón (CLAUDE.md §7-bis: un
   elemento contenido nunca pesa más que su contenedor). ✔ DECIDIDO por Ricardo.

   ES UN SOLO ELEMENTO QUE CAMBIA DE FORMA, no dos que se intercambian:
     plegado → 32×32, SIN caja (sólo la punta)   ·   abierto → botón de tinta con palabra

   ⛔ PLEGADO NO PINTA CAJA EN NINGÚN ESTADO — ni en reposo, ni al pasar el ratón, ni
   justo después de pulsar. El fondo de tinta y sus estados de ratón pertenecen SÓLO
   al estado abierto, que sí es un botón de verdad.
   ⛔ PERO «DECORATIVO» DESCRIBE EL ASPECTO, NO LA CONDUCTA (opción B, Ricardo
   2026-08-11): plegado SÍ se pulsa, y lo que hace es ABRIR SU PROPIA SECCIÓN. Por eso
   conserva `cursor:pointer`, `pointer-events` y su anillo de foco. La conducta vive en
   el JS (`cotAvancePulsado`); aquí queda dicho para que nadie lea «decorativo» como
   «no hace nada» y le quite la afordancia.
   ⛔ `justify-content:center` NO es cosmético: centra la punta en su caja de 32 para
   que el aro de foco de teclado —lo único visible plegado— sea simétrico y no un
   rectángulo corrido hacia el borde redondeado de la tarjeta.
   ═══════════════════════════════════════════════════════════════════════════ */
.gAcc-av { flex:none; display:inline-flex; align-items:center; justify-content:center; height:32px; min-width:32px;
  padding:0; gap:0; border:0; border-radius:var(--radius-button); cursor:pointer;
  background:transparent; color:var(--fg3); box-shadow:none;
  font:var(--fw-medium) var(--fs-button) /1 var(--font-sans);
  /* propiedades NOMBRADAS una por una · nunca `transition: all` (regla 1 de la matriz).
     El `transition` vive SÓLO abajo (L original con el pulsado): una lista de 5
     propiedades aquí nunca pintaba —la de abajo, con 6, la incluye entera— y quedó
     retirada el 2026-08-29 (lint_regla_perdedora) para no enseñar un valor muerto. */ }
.gAcc-av:focus-visible { outline:none; box-shadow: inset 0 0 0 1px var(--color-border-focus); } /* v1.0 · sin borde (border:0), reposo con fondo transparente → línea interior 1px */
/* Abierto: el relleno pasa a --color-action-ink (o --color-emerald cuando avanzado) — oscuro
   en los dos casos, así que el foco sube a la línea blanca, igual que en el resto del catálogo
   sobre relleno oscuro (COMPONENTE_FOCO.md, item 4). */
.exds-acc-card[data-open="true"] .gAcc-av:focus-visible { box-shadow: inset 0 0 0 1px var(--color-ink-on-dark, #FFFFFF); }
/* ⛔ EL PULSADO, que faltaba (añadido 2026-08-11 · hallazgo de la auditoría de ojos
   frescos). El escalón `sm` del canon del Botón declara `scale(.97)` al pulsar, y esta
   pieza toma de él el alto, el relleno, el radio y el relieve — tomar la métrica y
   dejarse la respuesta al dedo es homologar a medias. Va a `--motion-fast`: un acuse de
   recibo se siente inmediato o no se siente. Es la ÚNICA declaración de `transition`
   de `.gAcc-av`: gana siempre por ser la última, así que vive aquí sola. */
.gAcc-av { transition: background var(--motion-base) var(--ease-default),
                       color      var(--motion-base) var(--ease-default),
                       padding    var(--motion-base) var(--ease-default),
                       gap        var(--motion-base) var(--ease-default),
                       box-shadow var(--motion-base) var(--ease-default),
                       transform  var(--motion-fast) var(--ease-default); }
.exds-acc-card[data-open="true"] .gAcc-av:active { transform: scale(.97); }
/* abierto: la caja se rellena de tinta EN EL MISMO RELOJ que la etiqueta */
.exds-acc-card[data-open="true"] .gAcc-av { background:var(--color-action-ink);
  color:var(--color-action-text-on); padding:0 14px; gap:8px; box-shadow:var(--relieve-btn); }
.exds-acc-card[data-open="true"] .gAcc-av:hover  { background:var(--color-action-ink-hover); }
.exds-acc-card[data-open="true"] .gAcc-av:active { background:var(--color-action-ink-press); }
/* ⛔ EL ESMERALDA ES DE «LISTO», Y SÓLO DE «LISTO» (corregido 2026-08-11).
   QUÉ ERA: `[data-done="true"]` — es decir, «contestado». QUÉ ES AHORA:
   `[data-avanzado="true"]` — «ya pasó por aquí», que es exactamente cuando el botón
   dice «Listo». POR QUÉ: son dos estados distintos, y con el primero un paso recién
   contestado salía ESMERALDA DICIENDO «Continuar» (y el último, «Ver mis planes»).
   El esmeralda aquí es una excepción declarada con alcance a una sola palabra; pintarlo
   bajo las otras dos la estiraba a un sitio que nadie aprobó.
   GATE-ALLOW: blanco sobre esmeralda = 4,07:1, por debajo del 4,5 de AA para texto.
   ✔ DESVIACIÓN ACEPTADA por Ricardo el 2026-08-10 (se conserva el esmeralda de marca).
   Sigue por encima del 3:1 que la norma pide para controles y dibujos.
   ALCANCE: el botón «Listo» del acordeón guiado del cotizador público. */
.exds-acc-card[data-open="true"][data-avanzado="true"] .gAcc-av { background:var(--color-emerald); }
.exds-acc-card[data-open="true"][data-avanzado="true"] .gAcc-av:hover { background:var(--color-emerald-hover); }
/* paso FUTURO · DOS candados: el del estilo y el del programa (`if (fut) return`).
   Uno solo sería una suposición sobre el CSS; el segundo es lo que la vuelve garantía. */
.exds-acc-card[data-fut="true"] .gAcc-av { opacity:.45; pointer-events:none; }

/* ⛔ UN SOLO SVG · DOS TRAZOS. La flecha NACE del chevrón, no lo sustituye: la punta
   gira −90° sobre (12,12) y aterriza como cabeza de flecha, mientras el asta se
   DESCUBRE por detrás con stroke-dashoffset. NO son dos íconos cruzándose — eso se ve
   como un parpadeo y obliga a un segundo reloj. */
/* ⛔ 17 → 16 (2026-08-11 · hallazgo de la auditoría de ojos frescos). QUÉ ERA: 17 px,
   medido del prototipo. QUÉ ES AHORA: 16, que es un peldaño de la escala de lienzos del
   canon del Ícono (14 · 16 · 19). POR QUÉ: 17 no existe en esa escala — es el «casi» que
   nadie distingue de uno en uno y que, sumado, convierte una escala de tres valores en
   una nube. Regla de oro de INC-210: el handoff se acopla al catálogo, no al revés. */
.gAcc-glifo { flex:none; width:16px; height:16px; display:block; }
.gAcc-glifo svg { width:16px; height:16px; display:block; overflow:visible; }
.gAcc-punta { transform-box: view-box; transform-origin:12px 12px; transform: translateX(0) rotate(0deg);
  transition: transform var(--motion-base) var(--ease-default); }
.gAcc-asta { transform-box: view-box; transform-origin:4px 12px;
  stroke-dasharray:12; stroke-dashoffset:12;
  transition: stroke-dashoffset var(--motion-base) var(--ease-default),
              transform         var(--motion-fast) var(--ease-default); }
.exds-acc-card[data-open="true"] .gAcc-punta { transform: translateX(0) rotate(-90deg); }
.exds-acc-card[data-open="true"] .gAcc-asta  { stroke-dashoffset:0; }

/* ⛔ LA FLECHA QUE SE ESTIRA, TAMBIÉN AQUÍ · 2026-09-05 — homologado 2026-09-07, portado
   literal del gemelo (`patrones/acordeon-guiado/acordeon-guiado.css`), que traía este
   bloque completo desde el 2026-09-05 sin haber llegado nunca a esta copia de producción.
   `DECISION-FUENTE: Ricardo, 2026-09-05 — «reemplazar la flecha estática del botón
   continuar por la flecha que se estira».` La pieza canónica es
   `design-system/componentes/flecha/flecha.css` (Flecha.jsx en el kit) — los valores
   (scaleX 1.14, translateX 2px) NO se repiten aquí, se HEREDAN.

   ⛔ NO ES UN COPIAR-Y-PEGAR de esa hoja: este glifo YA USA `transform` para otra cosa —
   la punta gira −90° al abrir y el asta se REVELA con `stroke-dashoffset`, no con
   transform. Un `transform: translateX()` suelto en la punta habría BORRADO el
   `rotate()` — la cabeza de flecha se habría desarmado.

   CÓMO SE RESOLVIÓ, medido en navegador (no supuesto en el papel): los dos efectos se
   COMPONEN en un solo valor de `transform`, y el ORDEN escrito importa —
   `translateX(2px) rotate(-90deg)`, el translate a la IZQUIERDA. Por cómo CSS compone
   una lista de funciones (la de la izquierda se aplica DESPUÉS, ya sobre el espacio
   rotado), esto suma el desplazamiento en el eje del MUNDO —hacia la derecha— tras la
   rotación, que es justo hacia donde la cabeza de flecha ya apunta. El orden inverso
   (`rotate() translateX()`) fue probado y descartado en el gemelo: compone el
   desplazamiento ANTES de rotar y la punta sube en vez de avanzar.

   EL ASTA no tiene ese conflicto: nunca rota, así que su `scaleX(1.14)` no compite con
   nada, igual que en la pieza canónica.

   ⛔ Y EL RELOJ NO ES EL MISMO EN LOS DOS TRAZOS — excepción documentada, no un olvido.
   La punta comparte su `transform` con el morph de apertura (rotate, `--motion-base`, el
   reloj de las cuatro piezas del control): dos velocidades en la MISMA propiedad no
   pueden coexistir, así que la punta hereda `--motion-base`. El asta sí queda libre —su
   `transform` no compite con `stroke-dashoffset`— y usa `--motion-fast`.

   ⛔ SÓLO CUANDO EL CONTROL AVANZA — NUNCA EN «LISTO». `ETIQUETA_REABIERTO = 'Listo'` en
   `acordeon-guiado.js` es «un paso por el que YA se pasó y se reabre: CIERRA, no
   avanza». Una flecha que se estira dice «esto continúa hacia allá»; el selector excluye
   `[data-avanzado="true"]`, que es exactamente cuándo el control dice «Listo» (el
   esmeralda, arriba). */
.exds-acc-card[data-open="true"]:not([data-avanzado="true"]) .gAcc-av:hover .gAcc-punta {
  transform: translateX(2px) rotate(-90deg);
}
.exds-acc-card[data-open="true"]:not([data-avanzado="true"]) .gAcc-av:hover .gAcc-asta {
  transform: scaleX(1.14);
}

/* ⛔ LA FLECHA VA A LA DERECHA DE LA PALABRA · 2026-10-01
   `DECISION-FUENTE: Ricardo, 2026-10-01 — «para escritorio se queda igual (solo me gustaria que la flecha este a la derecha y no izquierda)».`
   Etiqueta primero, glifo después (`order`, sin tocar el marcado). Plegado no cambia: la etiqueta mide 0 y el
   glifo (chevrón) queda solo y centrado. Gemelo de `design-system/patrones/acordeon-guiado/acordeon-guiado.css`. */
.gAcc-lbl   { order:1; }
.gAcc-glifo { order:2; }

/* la etiqueta se despliega SIN medir nada a mano: 0fr → 1fr. La palabra vive dentro de
   una columna que la recorta, así que no puede asomar fuera de la caja. */
.gAcc-lbl { display:grid; grid-template-columns:0fr;
  transition: grid-template-columns var(--motion-base) var(--ease-default); }
.gAcc-lbl > span { overflow:hidden; min-width:0; white-space:nowrap; }
.exds-acc-card[data-open="true"] .gAcc-lbl { grid-template-columns:1fr; }

/* ⛔ NO EXISTE EL BOTÓN APAGADO Y MUDO: cuando falta algo para poder avanzar, el
   control DESAPARECE y en su sitio va la frase que dice QUÉ FALTA. Un botón gris no
   dice qué hacer; una frase sí. Efecto de segundo orden que conviene ver: cierra POR
   CONSTRUCCIÓN el gesto «pulsar Continuar con algo inválido».
   El RESUMEN también se retira mientras falta algo: choca con la frase, y un resumen
   de un paso incompleto enseña un dato a medias. */
/* ⛔ `min-height:32` NO ES DECORACIÓN: sostiene el alto de la fila (2026-08-11 · hallazgo
   de la auditoría de ojos frescos). La ficha declara la fila en 64 px, y 64 los daba el
   BOTÓN (32 de alto + 32 de relleno). Cuando el botón se va y entra la frase, la fila se
   encogía a 56 y la tarjeta DABA UN SALTO de 8 px al escribir un precio válido — un
   brinco del contenedor a cada paso, justo donde el prospecto está mirando.
   *Si una pieza sostiene una medida, su sustituta tiene que sostener la misma.* */
/* ⛔ `order` · LA FRASE VA DONDE VA EL RESUMEN, Y EL CHEVRÓN SIGUE SIENDO EL ÚLTIMO DE LA
   FILA (2026-08-12, al pintar la salida C). En el marcado la frase es hermana POSTERIOR
   del control de avance, porque nació para SUSTITUIRLO: abierta, el botón está en
   `display:none` y el orden da igual. Plegada ya no se sustituyen —el paso conserva su
   chevrón de «ábreme»— y sin `order` la fila se leía «3 · Pago inicial ⌄ Elige tu pago
   inicial», con la frase colgando por fuera del borde donde se alinean los resúmenes de
   las otras tres. *Cuando una pieza deja de ser sustituta y pasa a convivir, hereda el
   sitio de aquello a lo que sustituye, no el hueco donde estaba escrita.* */
.gAcc-falta { flex:none; font:var(--fw-regular) var(--fs-body-sm) var(--font-sans); color:var(--fg3);
  white-space:nowrap; padding-right:2px; display:none; min-height:32px; align-items:center; order:0; }
.gAcc-av { order:1; }

/* ⛔ EL AVISO SUAVE · la frase se tiñe, la casilla NO (Ricardo, 2026-09-05).
   `DECISION-FUENTE: Ricardo, 2026-09-05 — «si el usuario ingresa un número mayor al límite
   superior, en donde está "Escribe el precio del vehículo" podría cambiar a […] en texto rojo
   semántico error, solo como un aviso suave sin aplicar ningún error state en la casilla. Y el
   error state de casilla se queda igual, exigiéndole al usuario que ingrese monto válido si
   sale de la casilla con monto inválido.»`

   Copiado tal cual del patrón canónico (`design-system/patrones/acordeon-guiado/`), que ya
   traía esta misma regla desde la misma fecha: el tono lo pone el FLUJO (`cotPasoTono` en
   `cotizador-3.js`), nunca el patrón — ver la nota de `tono` junto a `leer()` en la versión
   canónica de `acordeon-guiado.js`. El cotizador reimplementa el patrón a mano en
   `cotizador-4.js` (no llama `AcordeonGuiado.crear`), así que la clase y el atributo
   viajan igual, sólo cambia quién escribe el `data-tono`. */
.gAcc-falta[data-tono="error"] { color: var(--color-error); }

/* ⛔ UN PASO SIN CONTROL DE AVANCE SIGUE MIDIENDO 64 · 2026-08-14
   El patrón admite pasos que NO tienen acción de avance propia (el modal de confirmación
   tiene dos: el 2 avanza solo al verificarse el código y el 3 se cierra desde el pie). Sin
   el control, la fila **se encogía a 56** — los 64 los sostenía él, con sus 32 de alto y
   sus 32 de relleno.
   Es la MISMA trampa que la ficha ya documentaba para el caso «falta algo», y su remedio es
   el mismo: **la caja de la frase se queda como sostén**, vacía y sin pintar nada. No es un
   espaciador inventado — es la pieza que el patrón ya designó para sostener esa medida.
   *Si una pieza sostiene una medida, su sustituta tiene que sostener la misma.* */
.exds-acc-card:not(:has(.gAcc-av)) .gAcc-falta { display: flex; }

.exds-acc-card[data-falta="true"] .gAcc-av    { display:none; }
/* ⛔ MIENTRAS EL PLEGADO VIENE EN CAMINO, EL CONTROL CALLA — SIN MOVER LA FILA · 2026-09-01
   (Ricardo, opción A de `plans/decisiones/_decision_boton_fantasma_2026-09-01.html`).
   `visibility` y NO `display`, y es la diferencia entera: el hueco (`.gAcc-slot`) es una
   rejilla donde el botón y la frase comparten la misma celda, así que sacar el botón de la
   maqueta encogería el hueco y el resumen de la fila se correría de sitio — que es justo lo
   que Ricardo pidió evitar al aprobarlo: *«ten cuidado de que no se desacomode el texto que
   está en línea con el botón continuar»*. Invisible conserva la caja; la fila no se mueve.
   El porqué del gesto está en `cotAccSync` (`cotizador-4.js`), con su medición. */
.exds-acc-card[data-plegando="true"] .gAcc-av { visibility: hidden; }
/* ⛔ Y ADEMÁS TOMA YA SU FORMA PLEGADA · corregido el 2026-09-01, el mismo día, porque Ricardo
   grabó el resultado: *«el texto aparece al lado izquierdo del botón continuar, sin que éste
   exista… después el texto se corre hacia la derecha»*.
   QUÉ PASABA, medido cuadro a cuadro: esconder el control con `visibility` conserva su caja —que
   era el objetivo— **pero conservaba la caja DESPLEGADA, de 150 px, cuando el control estaba a
   punto de volverse un chevrón de 32**. Así que el resumen «Regular» nacía encajado a su izquierda
   (ancho 265) y, al plegarse el acordeón, se estiraba hasta 383: **118 px de deslizamiento**, y un
   hueco invisible de 150 px a su derecha mientras tanto.
   *Conservar la caja estaba bien; conservé la caja equivocada. La que hay que reservar no es la
   que el control tiene, es la que va a tener.*
   Con la etiqueta plegada de golpe (`transition:none`), el resumen nace ya con su ancho final y no
   se mueve ni un píxel. */
.exds-acc-card[data-plegando="true"] .gAcc-lbl { grid-template-columns: 0fr; transition: none; }
/* ⛔ Y NO SÓLO LA MEDIDA: TAMBIÉN LA PIEL Y EL GLIFO · 2026-09-01 (Ricardo, con la captura:
   *«el efecto de botón continuar a medio aparecer rompe de nuevo la transición»*).

   QUÉ SE VEÍA, y no era «medio aparecer» sino **medio DESAPARECER**: durante el compás el
   control estaba invisible pero conservaba su piel de ABIERTO —fondo de tinta, sombra, y el
   glifo girado a flecha—. Al plegarse la tarjeta volvía a ser visible **mientras esa piel se
   deshacía**: 250 ms de pastilla oscura encogiéndose hacia el chevrón. La cola de un control
   que nunca se usó.

   `DECISION-FUENTE: Ricardo, 2026-09-01 — «Que el botón continuar nunca aparezca, sólo el botón
   listo una vez seleccionado y reabierto el acordeón.»` Con una precisión acordada: **el
   CHEVRÓN se queda** — es la forma plegada del mismo control y la única señal de que el paso se
   puede reabrir, y los otros tres la tienen. Lo que nunca aparece en el camino de ida es la
   pastilla de tinta con palabra.

   CÓMO: mientras el plegado viene en camino, el control toma **su aspecto plegado ENTERO y de
   golpe** —medida, piel y glifo, con `transition:none`— estando invisible. Así que cuando se le
   devuelve la visibilidad ya ES el chevrón: no queda nada que deshacer, y no hay transición que
   ver. *Lo que no hay que animar es lo que ya llegó antes de que nadie mirase.*

   ⚠ Y ESTA ES LA TERCERA VEZ EN LA MISMA TARDE que el defecto es «reservar o animar la caja que
   el elemento VA A TENER en vez de la que tiene». Las tres las cazó Ricardo mirando, ninguna un
   gate: el resumen encajado, el saliente estrenando la palabra, y esta piel. */
.exds-acc-card[data-plegando="true"] .gAcc-av {
  padding: 0; gap: 0; box-shadow: none;
  background: transparent; color: var(--fg3);
  transition: none;
}
.exds-acc-card[data-plegando="true"] .gAcc-punta { transform: rotate(0deg); transition: none; }
.exds-acc-card[data-plegando="true"] .gAcc-asta  { stroke-dashoffset: 12; transition: none; }
/* ═══════════════════════════════════════════════════════════════════════════
   ⛔ LA FRASE HABLA TAMBIÉN CON EL PASO PLEGADO · 2026-08-12
      (Ricardo · salida C de `_decision_error_y_transicion_2026-08-12.html`)

   QUÉ ERA: estas dos reglas colgaban de `data-falta`, y `data-falta` sólo se enciende
   en la sección ABIERTA. Resultado medido en el sitio: con el paso plegado la frase
   existía en el documento con `display:none` y su hueco lo ocupaba el RESUMEN —
   «$ 75,000» en el paso 3, la posición de fábrica del deslizador, que nadie eligió.
   *La razón por la que el prospecto cierra el paso —creer que ya lo llenó— era justo
   la que hacía que la pantalla se callara.*

   QUÉ ES AHORA: cuelgan de `data-aviso`, que se enciende esté abierta o plegada. Y con
   ellas se va el resumen: no se sustituye una cifra falsa por otra, se retira.

   LO QUE **NO** SE AÑADE, y es la mitad de la decisión: ni contorno rojo de la sección
   ni número en rojo. Las dos contestan «dónde» y «cuál» — la frase ya las contesta por
   estar en esa fila. Nunca existieron en el código (eran la opción A del documento);
   queda dicho aquí para que nadie las «complete» creyendo que faltan.

   EL TONO SIGUE AL ESTADO. Abierta va en `--fg3`: el prospecto está parado dentro del
   paso y no se ha equivocado — le FALTA. Plegada va en `--color-error`: ahí ya le está
   costando los planes y está mirando a otro sitio. Es la única señal que queda, así que
   se le deja subir el volumen cuando el prospecto se ha ido.

   ⛔ `data-falta` SE CONSERVA EN LAS DOS REGLAS, y no es un resto: cuando el paso está
   abierto con el precio en error, la frase CEDE (el campo ya lo explica dentro de su
   caja) y se queda vacía — pero su caja tiene que seguir ahí, porque es la que sostiene
   los 32 px que le daba el botón retirado. Sin ella la fila se encoge a 56 y la tarjeta
   da un salto de 8 px justo donde el prospecto está mirando.
   ═══════════════════════════════════════════════════════════════════════════ */
.exds-acc-card[data-falta="true"] .gAcc-falta,
.exds-acc-card[data-aviso="true"] .gAcc-falta { display:flex; }
/* ⛔ REPUESTA 2026-08-20 — Y ES LA SEGUNDA MITAD DE LA REGLA DE ARRIBA, no una regla aparte.
   El comentario largo que la explica sigue doce líneas más arriba, intacto, diciendo que
   `data-aviso` contesta *«¿habla la frase Y SE RETIRA EL RESUMEN?»*. La frase se quedó; el
   resumen no. Se perdió como daño colateral del commit `37132d9` (relevo frase→botón, 14-ago),
   cuyo mensaje no la menciona, y **estuvo cinco días viva en producción**.

   QUÉ SE VEÍA, medido en app.exante.mx el 2026-08-20 montando el estado y leyendo el estilo
   computado —no leyendo el archivo—: con el pago inicial sin tocar y el paso plegado, la frase
   roja «Elige tu pago inicial» y **`$ 60,000` se leían A LA VEZ**, uno al lado del otro. Es
   exactamente el defecto que Ricardo mandó cerrar el 12-ago (INC-387, salida C): *la posición
   de fábrica del deslizador, una cifra que nadie eligió, haciéndose pasar por una respuesta*.

   ⭐ LO QUE ENSEÑA, y por eso se escribe aquí: el arreglo del 12-ago sobrevivió en el CATÁLOGO
   y en su gemelo, y murió en la COPIA que sirve el sitio. Ningún gate miraba ese salto. Lo
   destapó `gate_eslabon_app.js`, escrito el mismo día. *Una decisión aprobada no está a salvo
   por estar en el catálogo: está a salvo cuando algo compara el catálogo con lo que se sirve.* */
.exds-acc-card[data-falta="true"] .exds-acc-sum,
.exds-acc-card[data-aviso="true"] .exds-acc-sum { display:none; }
/* ⛔ REPUESTA 2026-08-15 — se perdió al reescribir el bloque del relevo esa misma tarde.
   EL TONO SIGUE AL ESTADO, y está documentado arriba: abierta va en `--fg3` (al prospecto le
   FALTA algo, no se ha equivocado); PLEGADA va en rojo, porque ahí ya está mirando a otro sitio
   y la frase es la única señal que queda. Sin esta regla, el paso plegado avisaba en gris — el
   aviso existía pero no levantaba la voz.
   ⛔ EL TOKEN: va en la BASE `--color-error`, no en `-deep`. Aquí decía lo contrario («va en
   -deep porque es TINTA»), y la mitad que faltaba la puso §0-quater de
   `COMPONENTE_SEMANTICOS.md` (Ricardo 2026-08-20): `-deep` está reservado a lo que se pinta
   encima del tinte de su propia familia, y esta frase va sobre la card BLANCA. */
.exds-acc-card[data-aviso="true"][data-open="false"] .gAcc-falta {
  color: var(--color-error, #DA342B); font-weight: var(--fw-medium); }

/* ═══════════════════════════════════════════════════════════════════════════
   ⭐ EL RELEVO FRASE → BOTÓN · opción C de la maqueta que Ricardo aprobó
      `plans/decisiones/_decision_morf_frase_boton_2026-08-15.html`

   ⛔ ESTO ES LA MAQUETA, COPIADA. No una interpretación suya. Cinco intentos míos fallaron por
   ir reescribiéndola «mejor»: entrada que sube · relleno resolviéndose · cruce con escala ·
   cruce sin escala · morf con la frase FUERA DEL FLUJO. El último se veía «como si el botón
   creciera de derecha a izquierda», y la causa era estructural, no de curvas:

   ⛔ LOS DOS COMPARTEN LA MISMA CELDA, EN FLUJO. En la maqueta, frase y botón viven en un
   `display:grid` con los dos en `grid-area:1/1`. El hueco mide lo que el MÁS ANCHO, así que
   mientras el botón abre su relleno **la tinta barre POR ENCIMA del texto que se va** — y eso es
   lo que se lee como «el texto se convierte en el botón». Al sacar la frase del flujo
   (`position:absolute`, mi 5.º intento) el botón crecía solo, en un hueco vacío, y el mismo
   movimiento pasaba a leerse como «crece hacia la izquierda».
   *El gesto no estaba en las curvas: estaba en que los dos ocuparan el mismo sitio.*

   El reloj y la curva son los de la maqueta: `--motion-base` + `--ease-default`.
   ═══════════════════════════════════════════════════════════════════════════ */
.gAcc-slot { flex:none; display:grid; justify-items:end; align-items:center; }
.gAcc-slot > * { grid-area:1/1; }

/* Durante el relevo, los DOS existen: uno no puede cruzarse con algo que no está en pantalla. */
.exds-acc-card[data-relevo] .gAcc-saliente,
.exds-acc-card[data-relevo] .gAcc-entrante { display:inline-flex !important; }

.exds-acc-card[data-relevo] .gAcc-av,
.exds-acc-card[data-relevo] .gAcc-falta {
  transition: opacity    var(--motion-base) var(--ease-default),
              filter     var(--motion-base) var(--ease-default),
              background var(--motion-base) var(--ease-default),
              color      var(--motion-base) var(--ease-default),
              padding    var(--motion-base) var(--ease-default),
              gap        var(--motion-base) var(--ease-default),
              box-shadow var(--motion-base) var(--ease-default);
}
/* ⛔ EL QUE SE VA NO ESTRENA UNA FORMA · 2026-09-01 (Ricardo, grabándolo: *«cuando se abre el
   acordeón es como si hubiera un botón continuar que desaparece»*).

   QUÉ PASABA, medido cuadro a cuadro al abrir el paso 2: en el mismo instante en que la tarjeta
   se abre, `[data-open="true"] .gAcc-lbl` despliega la etiqueta — **también en el control que ya
   está marcado como SALIENTE**. Así que el chevrón de 32 px crecía a **118 desplegando la palabra
   «Continuar» mientras se desvanecía**: 32 → 56 → 98 → 109 → 118, con la opacidad cayendo
   1 → 0,61 → 0,19 → 0,08 → 0. Un botón que nunca existió, naciendo y muriendo encima de la frase
   que estaba entrando.

   *Una despedida no es el momento de estrenar nada.* Lo que se va se va **como estaba**. Es la
   misma familia que el defecto del resumen de esta misma tarde: reservar o animar **la caja que
   el elemento va a tener** en vez de la que tiene.

   `transition:none` a propósito: el que se va no debe ni encogerse — encogerse también es un
   gesto, y el gesto de la salida ya es el desvanecido con desenfoque que viene debajo. */
.exds-acc-card[data-relevo] .gAcc-saliente .gAcc-lbl { grid-template-columns: 0fr; transition: none; }
/* Y con la forma, la medida: sin el relleno de tinta que sólo tiene el control abierto. */
.exds-acc-card[data-relevo] .gAcc-saliente.gAcc-av { padding: 0; gap: 0; }

/* el que se VA: se apaga y se aleja con desenfoque, sin moverse de sitio */
.exds-acc-card[data-relevo] .gAcc-saliente {
  opacity: 0; filter: blur(var(--icon-swap-blur)); pointer-events: none;
}
/* el que LLEGA repite el viaje entero del chevrón: nace con la piel del PLEGADO */
@keyframes gAcc-entra-cruce {
  from { opacity: 0;
         background-color: transparent; color: var(--fg3); box-shadow: none;
         padding-left: 0; padding-right: 0; gap: 0; }
}
@keyframes gAcc-entra-lbl   { from { grid-template-columns: 0fr; } }
@keyframes gAcc-entra-punta { from { transform: rotate(0deg); } }
@keyframes gAcc-entra-asta  { from { stroke-dashoffset: 12; } }
.exds-acc-card[data-relevo] .gAcc-entrante {
  animation: gAcc-entra-cruce var(--motion-base) var(--ease-default) backwards;
}

/* ⛔ AQUÍ HUBO UNA SEGUNDA ENTRADA PARA EL BOTÓN, Y SOBRABA · 2026-09-01 (Ricardo, mirándolo:
   «cuando aparece botón continuar, parpadea»).

   Se añadió un `gAcc-llega-suave` creyendo —por una medición MAL ALINEADA— que el control de
   avance salía de golpe mientras el texto tardaba 227 ms. Falso: el relevo YA le daba su entrada
   (`gAcc-entra-cruce`), y la segunda animación la reiniciaba a medio camino. Medido cuadro a
   cuadro sobre el sitio real: opacidad 0 → 1 entre t=119 y t=342, y **otra vez 0 → 1** entre
   t=375 y t=509. Eso es el parpadeo.

   *Una medición mal alineada no dice «no sé»: dice algo concreto y falso, y encima invita a
   arreglarlo.* La primera lectura miró un solo control con `querySelector` sin descartar los que
   están en `display:none`, así que el primer cuadro devolvió la caja ya asentada en vez de la que
   estaba naciendo — la misma familia que los tres defectos de esta tarde: mirar la caja que el
   elemento VA a tener en vez de la que tiene. La corrección al instrumento: filmar TODOS los
   controles del acordeón, descartar los no mostrados, y no arrancar el reloj en el clic.

   Se deja escrito y no se borra en silencio: sin esta nota, el siguiente que mida mal vuelve a
   añadirla. */

/* Los hijos llevan su propio fotograma inicial: un keyframe del padre no alcanza a sus hijos. */
.exds-acc-card[data-relevo] .gAcc-entrante .gAcc-lbl   { animation: gAcc-entra-lbl   var(--motion-base) var(--ease-default) backwards; }
.exds-acc-card[data-relevo] .gAcc-entrante .gAcc-punta { animation: gAcc-entra-punta var(--motion-base) var(--ease-default) backwards; }
.exds-acc-card[data-relevo] .gAcc-entrante .gAcc-asta  { animation: gAcc-entra-asta  var(--motion-base) var(--ease-default) backwards; }

/* ⭐ LA PALABRA TAMBIÉN CRUZA — regla 3 de la simetría (Ricardo, 2026-08-15).
   En «Continuar» → «Listo» el fondo del botón morfa (13 valores medidos) pero el texto cambiaba
   de GOLPE en mitad del gesto: dos velocidades dentro de la misma caja.
   *Si la pieza cruza, su texto cruza con ella.* Mismo desenfoque y mismo reloj que el relevo.
   La marca la pone el programa sólo cuando el texto CAMBIA de verdad: la sincronización corre
   varias veces por interacción y reanimar en cada pasada sería un parpadeo. */
@keyframes gAcc-cambia-lbl {
  0%   { opacity: 1; filter: blur(0); }
  45%  { opacity: 0; filter: blur(var(--icon-swap-blur)); }
  100% { opacity: 1; filter: blur(0); }
}
.gAcc-lbl.gAcc-cambia > span {
  animation: gAcc-cambia-lbl var(--motion-base) var(--ease-default) both;
}
@media (prefers-reduced-motion: reduce) { .gAcc-lbl.gAcc-cambia > span { animation: none !important; } }
@media (prefers-reduced-motion: reduce) {
  .exds-acc-card[data-relevo] .gAcc-av,
  .exds-acc-card[data-relevo] .gAcc-falta,
  .exds-acc-card[data-relevo] .gAcc-entrante *
    { transition-duration: .01ms; animation: none !important; }
}

/* ⛔ GUARDA DE MOVIMIENTO REDUCIDO — OBLIGATORIA (regla 4 de la matriz, no negociable).
   ACTUALIZADA 2026-08-11: se retiró `.exds-acc-chev` (ya no existe) y se añadieron las
   SEIS piezas nuevas del modo guiado. Apagar el movimiento aquí NO deja sin información:
   el estado final es EL MISMO DIBUJO, sólo que instantáneo — el botón mide lo mismo, la
   punta acaba a −90° y el cuerpo queda abierto. */
@media (prefers-reduced-motion:reduce){
  /* ⛔ `!important` AÑADIDO EL 2026-08-20, homologando al gemelo del catálogo — y no es
     cosmética. Sin él, esta guarda gana sólo por ir MÁS ABAJO en el archivo: cualquier regla
     de movimiento que alguien escriba después, en cualquier hoja que cargue detrás, la deja
     sin efecto y nadie se entera. *Una guarda que depende del orden de las líneas no es una
     guarda: es una coincidencia que aguanta.* Y el canon la declara no negociable (regla 4 de
     la matriz de movimiento), así que ganar por orden no basta.
     Lo destapó `gate_eslabon_app.js`, y de paso midiendo en app.exante.mx salió otra cosa que
     queda APUNTADA y no es de aquí: el cotizador sirve **DOS guardas globales que se
     contradicen** — una pone `0.01ms !important` y la otra `1ms !important` sobre
     `*, ::before, ::after`. Gana la última por orden. No la toco en este cambio. */
  .exds-acc-card, .exds-acc-h, .exds-acc-trig, .exds-acc-body, .exds-acc-content, .exds-acc-badge, .exds-acc-sum,
  .exds-acc-badge .cifra, .exds-acc-badge .tick,
  .gAcc-av, .gAcc-punta, .gAcc-asta, .gAcc-lbl { transition-duration:.01ms !important; transition-delay:0ms !important; }
  .exds-acc-card[data-open="true"] .exds-acc-content { transition-delay:0ms !important; }
}
/* ═══════════════════════════════════════════════════════════════════════════
   ▓ 390 px · la regla de móvil del acordeón guiado ▓ (2026-08-11)
   Extraída del `@media (max-width: 430px)` de `cotizador.css`, que también traía
   la maqueta del paso 2 (`.cz-flota-grid`) — eso es de la app, no de este patrón, y
   se queda allá en su propio bloque.
   El cotizador público es la ÚNICA superficie de Exante que debe funcionar en
   teléfono (CLAUDE.md §7). El ORDEN EN QUE CEDEN las tres piezas de la cabecera
   cuando no caben es fijo:  1º el resumen (desaparece) · 2º el título (se corta con
   «…») · EL BOTÓN NUNCA. El botón es la única salida hacia adelante: si se corta, el
   prospecto se queda sin saber qué hace.
   Medido a 390, peor caso (paso 4, el título más largo con el botón más largo): ancho
   útil de la cabecera 334 · «Ver mis planes» 152 · «Historial crediticio» 136 →
   sobran 2 px y nada se corta. Con sólo retirar el resumen ya cabe; el recorte del
   título queda de reserva.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 430px) {
  .exds-acc-h { padding: 14px 14px 14px 16px; gap: 10px; }
  .exds-acc-content.exds-acc-bleed { --acc-izq: 28px; }   /* 16 de la cabecera + 12: el texto no empieza detrás del contador */
  .exds-acc-ttl { flex: 1 1 auto; min-width: 0; }   /* el título cede y se corta con … */
  .gAcc-av { flex: none; }                          /* el botón NUNCA cede */
  .exds-acc-sum { flex: 0 1 auto; }
  /* ⛔ …SALVO EL QUE ESTÁ DECLARADO COMO FIJO (Ricardo, 2026-08-15: «en móvil no aparece el monto
     del pago inicial al lado del botón»). La excepción `data-keep` EXISTÍA en escritorio —dos
     reglas más arriba: `:not([data-keep="true"])`— y aquí no se replicó, así que en el teléfono
     desaparecía el único dato que el paso necesita enseñar mientras se elige: cuánto es ese
     porcentaje en pesos. *Una excepción que sólo vive en una de las dos vistas no es una
     excepción: es un olvido con forma de regla.*
     El resumen sigue cediendo el sitio cuando NO es fijo, que es lo que esta línea vino a hacer. */
  .exds-acc-card[data-open="true"] .exds-acc-sum:not([data-keep="true"]) { display: none; }
  /* …Y EL FIJO TAMBIÉN CEDE SI NO CABE: `accAjustarResumenes` (cotizador-4.js) marca `data-cede` cuando,
     con él puesto, el título o el resumen se cortan. Orden de cesión: 1º el resumen, 2º el título. */
  .exds-acc-card[data-open="true"] .exds-acc-sum[data-cede] { display: none; }
  /* ⛔ EN MÓVIL EL BOTÓN ABIERTO NO LLEVA FLECHA Y DICE «Seguir» · 2026-10-01 (opción D3)
     `DECISION-FUENTE: Ricardo, 2026-10-01 — «d3 para movil»`. Sin glifo (la palabra «Seguir» la pone el JS con la
     misma consulta de 430 px) = 71 px; con $ 1,800,000 sobran ~28 px para el monto. Plegado conserva el chevrón. */
  .exds-acc-card[data-open="true"] .gAcc-glifo { display: none; }
}

/* ── zona de gesto de 44 px en pantallas táctiles ─────────────────────────────
   ⛔ En producción esta misma regla cubre ADEMÁS `.exds-navp-brand` (la vuelta al
   inicio desde la barra del cotizador). Aquí NO se copia: no es del patrón, es de
   la barra de esa app — se queda en `cotizador.css`, documentada con el historial
   completo de verificación (`gate_movil.js`, INC-420). */
@media (pointer: coarse) {
  .gAcc-av, .exds-acc-trig { position: relative; }

  .gAcc-av::after,
  .exds-acc-trig::after {
    content: '';
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: max(100%, 44px);
    height: max(100%, 44px);
    /* sin fondo: zona de gesto pura, no se ve */
  }
}

/* ═══════════════════════════════════════════════════════════════════════════════════
   ▓ MODO COMPACTO · `data-densidad="compacta"` — el acordeón DENTRO DE UN CAJÓN ▓
   v0.3 · 2026-08-21.
   `DECISION-FUENTE: Ricardo, 2026-08-21 — «vamos con el acordeón»`, tras comparar el
   cajón de Facturación con `plans/design_handoff_cajones/` («me parece más eficiente en
   cuanto espacio; permite respirar mejor al texto del cuerpo»).

   ⛔ ES UN MODO, NO UNA COPIA. Se resistió la tentación de escribir estas medidas dentro
   de la pantalla de Facturación: eso habría dado DOS acordeones en el sistema con el
   mismo nombre. Ayuda, Ajustes y Notificaciones traen el mismo tratamiento en su handoff,
   así que esto es la familia, no una excepción.

   ⭐ QUÉ CAMBIA Y POR QUÉ, con la aritmética delante — porque el argumento no es de gusto:

   Con tarjeta, dentro de un cajón de 420 px, cada sección cobra un borde a cada lado y
   16 px de relleno propio, ADEMÁS de los 20 del cajón. El texto arranca en **37** y acaba
   en **383**: quedan **346 px de renglón**. En modo compacto arranca en 20 y acaba en 400:
   **380 px**. Son **34 px por línea, un 10 % más de texto**, en la superficie más estrecha
   del sistema y justo donde vive lo que hay que leer (el motivo de un aviso, la
   descripción de un concepto).

   Y hay un argumento de estructura que pesa más que los 34 px: **una tarjeta dentro de un
   cajón es un contenedor dentro de un contenedor sin que la jerarquía lo pida** — diez
   marcos anidados dentro de un marco. Es lo que el no-negociable 7-bis persigue: el peso
   de una pieza se juzga contra su contenedor, y aquí diez piezas pesaban como su casa.
   *Lo que separa dos secciones no tiene que ser una caja: basta una línea y el aire.*

   ⛔ ESTO REVOCA UNA DECISIÓN ANTERIOR, y se dice en voz alta en vez de dejar dos reglas
   conviviendo: el 2026-08-20 Ricardo decidió que «en el caso específico del cajón, sí
   recupera su borde». Aquélla se tomó comparando el acordeón CON marco contra el acordeón
   SIN NADA —que efectivamente se deshacía—; ésta compara contra el tratamiento del handoff
   de cajones, que no es «sin nada»: es plano CON filete y CON aire. *Una decisión no se
   revoca por cambiar de gusto, se revoca cuando aparece la tercera opción que no estaba
   sobre la mesa.*

   Las medidas salen del handoff (§1 «La fila»), no de aquí:
     fila     `padding: var(--space-3) var(--space-5)` = 12 / 20
     límite   `border-top: 1px solid var(--color-border-subtle)` — **a sangre**, cruza los
              420, porque separa dos ZONAS y no dos columnas (no-negociable 7 · criterio
              del filete). Por eso el modo compacto se estira con márgenes negativos.
     cuerpo   el mismo gutter de 20, y su propio `padding-top`: sin él nace pegado a la
              solapa y lo único que lo separa del título es el relleno de ÉSTA, que es aire
              del título, no del cuerpo.
   ═══════════════════════════════════════════════════════════════════════════════════ */
.exds-acc[data-densidad="compacta"] { gap: 0; }

/* Sin tarjeta: ni borde, ni radio, ni sombra, ni fondo — abierta o cerrada. */
.exds-acc[data-densidad="compacta"] .exds-acc-card {
  border: 0; border-radius: 0; box-shadow: none; background: none; overflow: visible;
}
.exds-acc[data-densidad="compacta"] .exds-acc-card[data-open="true"] {
  border: 0; box-shadow: none;
}

/* EL LÍMITE ENTRE SECCIONES · un pelo a sangre, y NO en la primera: una línea encima de la
   primera sección duplicaría el filete que ya cierra la cabecera del cajón. */
.exds-acc[data-densidad="compacta"] .exds-acc-card + .exds-acc-card {
  border-top: 1px solid var(--color-border-subtle);
}

/* A SANGRE · el margen negativo es el gutter del cajón, declarado como variable para que
   quien monte en otro ancho no tenga que tocar esta hoja. */
.exds-acc[data-densidad="compacta"] {
  --exds-acc-sangria: var(--space-5, 20px);
  margin-inline: calc(-1 * var(--exds-acc-sangria));
}
.exds-acc[data-densidad="compacta"] .exds-acc-h,
.exds-acc[data-densidad="compacta"] .exds-acc-content {
  padding-inline: var(--exds-acc-sangria);
}
.exds-acc[data-densidad="compacta"] .exds-acc-h { padding-block: var(--space-3, 12px); }

/* EL CUERPO · sin contorno propio y sin fondo: en modo compacto no hay caja de la que
   separarse. Su aire arriba es suyo, no prestado del relleno de la solapa. */
.exds-acc[data-densidad="compacta"] .exds-acc-content {
  border: 0; border-radius: 0; background: none;
  padding-top: var(--space-2-5, 10px);
  padding-bottom: var(--space-4, 16px);
}

/* La solapa abierta NO se tiñe de gris en reposo: sin tarjeta que la contenga, la franja
   gris se leería como una banda de grupo —que en esta familia significa otra cosa— y además
   cortaría el filete a sangre. Lo que dice que está abierta es el chevrón. */
.exds-acc[data-densidad="compacta"] .exds-acc-card[data-open="true"] .exds-acc-h {
  background: none;
}

/* ⛔ EL HOVER VA EN LOS DOS ESTADOS, ABIERTA Y CERRADA.
   `DECISION-FUENTE: Ricardo, 2026-08-21 — «cuando está desplegado, el encabezado debe tener
    un hover igual que cuando está plegado. Ese hover sirve para que el usuario sepa que el
    encabezado es cliqueable y que tiene la acción inversa que cuando lo abrió (colapsar).»`

   ⛔ Y CORRIGE UNA REGLA MÍA DE HACE UNAS HORAS que decía lo contrario —«el hover sólo en la
   cerrada: una fila abierta ya está gris, y volver a pintarla no diría nada»—. Ese argumento
   era CIERTO con tarjeta, donde la solapa abierta se teñía; **en modo compacto no se tiñe**,
   así que la premisa desapareció y con ella la regla. *Una regla heredada sin su premisa no
   es una regla: es una costumbre.*

   Y el argumento de Ricardo es más fuerte que el del color, porque no habla de estética
   sino de affordance: **un control que ya hizo su trabajo sigue siendo un control**, y lo
   único que anuncia que se puede volver a pulsar —para cerrar— es que responda al ratón.
   Sin hover, una sección abierta se lee como un encabezado muerto. */
.exds-acc[data-densidad="compacta"] .exds-acc-card .exds-acc-h:hover,
.exds-acc[data-densidad="compacta"] .exds-acc-card[data-open="true"] .exds-acc-h:hover {
  background: var(--color-bg-subtle);
}
/* ⛔ LOS DOS SELECTORES NO SON UN DESCUIDO: el de reposo de la abierta pesa (0,4,0) y un
   `:hover` de (0,3,0) NO le gana — el hover salía y no pintaba nada, con la regla escrita y
   correcta. *Una regla que pierde por especificidad no falla ruidosamente: no hace nada, y
   se lee como si el navegador no la tuviera.* Se empareja el peso en vez de recurrir a
   `!important`, que apagaría también al que venga después. */
