/* ═══════════════════════════════════════
   ▓ COMPONENTE · Modal — gemelo vanilla ▓
   v1.0 · 2026-08-23. Ficha: `design-system/COMPONENTE_MODAL.md`
   Kit: `catalogo-cd/components/Modal.jsx`

   El diálogo que INTERRUMPE para una sola tarea que no puede seguir en segundo plano.
   Vela el fondo, enfoca el contenido y se cierra con Esc, clic en el velo o la X.

   REQUISITOS DEL ANFITRIÓN:
     1. Los tokens del canon (`colors_and_type.css`).
     2. `box-sizing: border-box`.
     3. El `Button` del catálogo si se monta el pie — esta hoja NO lo redibuja
        (`componentes/button/button.css`, hoja propia).

   ⛔ LA REGLA SEMÁNTICA DEL PIE — ESTÁ EN CÓDIGO, NO SÓLO EN LA FICHA
   (Ricardo, 2026-07-24 · COMPONENTE_MODAL.md §Semántica de la acción primaria):

       intent = "neutral"      →  Button data-variant="primary"    (ink oscuro)
       intent = "destructive"  →  Button data-variant="danger"     (rojo sólido)
       intent = "sales"        →  Button data-variant="sales"      (esmeralda)

   ⛔ Y NO HAY VERDE DE ÉXITO. Se retiró el 2026-07-22: el verde de éxito vive en estados y
   badges, NUNCA en un botón. El esmeralda del modal es VENTA, no «salió bien». Esta hoja no
   declara ni un color de botón a propósito — el que arma el pie es `modal.js`, para que nadie
   pueda meter el color equivocado escribiendo una clase a mano.

   ⛔ EL NAVEGADOR NO PONE NUESTRA UI. `confirm()`, `alert()` y `prompt()` están prohibidos en
   las tres apps (regla dura de la ficha, Ricardo 2026-07-29). Esta pieza existe para que la
   prohibición sea cumplible: hasta hoy el modal no tenía gemelo y quien necesitaba confirmar
   algo escribía `confirm()` porque la pieza no existía de este lado.
   ═══════════════════════════════════════ */

/* ══ EL VELO · fija, cubre todo, atenúa el fondo ═════════════════════════════
   Ink de marca al 32%, NUNCA negro puro, y un desenfoque corto de 2px: el velo estándar
   ATENÚA el fondo, no lo borra (el que lo borra es el modo conversión del cotizador, que
   vive declarado con su GATE-ALLOW en `app/css/cotizador.css`). z-index 1100: por encima
   de todo lo que la app pueda tener puesto. */
.exds-modal-veil {
  position: fixed;
  inset: 0;
  z-index: 1100;
  background: rgba(15, 20, 25, 0.32);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5, 20px);
  animation: exds-modal-veil-kf var(--motion-base, 250ms) var(--ease-default, cubic-bezier(0.32, 0.72, 0, 1));
}

/* ══ LA CAJA · la superficie enfocada ════════════════════════════════════════
   Radio 16 (= --radius-lg, el mismo de las tarjetas; decisión de Ricardo 2026-07-18) y
   `--shadow-modal`, el nivel más alto de elevación del canon: un modal flota sobre TODO.
   ⛔ SIN BORDE, a diferencia de la card: el velo ya lo separa del fondo. */
.exds-modal-box {
  position: relative;
  width: 100%;
  max-width: var(--w-modal, 440px);
  max-height: calc(100vh - 40px);
  display: flex;
  flex-direction: column;
  background: var(--color-surface, #FFFFFF);
  border-radius: var(--radius-lg, 16px);
  box-shadow: var(--shadow-modal, 0 24px 64px -12px rgba(15, 20, 25, 0.18));
  animation: exds-modal-box-kf var(--motion-base, 250ms) var(--ease-default, cubic-bezier(0.32, 0.72, 0, 1));
}

/* El ancho es de DOS medidas y ninguna más: 440 estándar, 560 cuando la decisión necesita
   ver una tabla o un documento. No es un continuo: un tercer ancho a ojo es como nacieron
   los tres radios y los tres blurs que esta ficha vino a homologar. */
.exds-modal-box[data-ancho="true"] {
  max-width: var(--w-modal-ancho, 560px);
}

/* ══ ENTRAR Y SALIR TIENEN RELOJES DISTINTOS (Ricardo, 2026-08-06) ═══════════
   Abre y cierra en --motion-base, pero con curvas distintas: llegar usa la curva por
   defecto y irse usa --ease-exit. *No es velocidad, es asimetría* — un gesto que distingue
   entrar de salir. El velo sale CON su caja y en la misma duración: uno que se queda medio
   fotograma más delata todo. */
@keyframes exds-modal-veil-kf { from { opacity: 0; } to { opacity: 1; } }
@keyframes exds-modal-box-kf { from { opacity: 0; transform: translateY(6px) scale(0.96); } to { opacity: 1; transform: none; } }
@keyframes exds-modal-veil-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes exds-modal-box-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: scale(0.96); } }

.exds-modal-veil[data-cerrando="true"] {
  animation: exds-modal-veil-out var(--motion-base, 250ms) var(--ease-exit, cubic-bezier(0.4, 0, 1, 1)) forwards;
}

.exds-modal-veil[data-cerrando="true"] .exds-modal-box {
  animation: exds-modal-box-out var(--motion-base, 250ms) var(--ease-exit, cubic-bezier(0.4, 0, 1, 1)) forwards;
}

/* ══ CERRAR · X ghost arriba-derecha ═════════════════════════════════════════
   32px, sin borde, radio pequeño. El dibujo va con el ícono `x` de lucide a 16 — un carácter
   tipográfico NO es un ícono (`COMPONENTE_ICONO.md`), y el «×» del teclado es el signo de
   multiplicar. El marcado está en el README. */
.exds-modal-x {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 32px;
  height: 32px;
  border: 0;
  background: transparent;
  border-radius: var(--radius-sm, 6px);
  color: var(--fg3, #5C6B7A);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.exds-modal-x:hover {
  background: var(--color-bg-subtle, #F2F4F6);
}

/* ══ CABECERA · eyebrow OPCIONAL y apagado por defecto ═══════════════════════
   El eyebrow sólo se usa cuando aporta contexto real (marcar un paso de un flujo), decisión
   de Ricardo 2026-07-18. Un eyebrow que repite el título es ruido con mayúsculas. */
.exds-modal-head {
  padding: 24px 28px 8px;
  flex-shrink: 0;
}

.exds-modal-eyebrow {
  font-family: var(--font-sans, "Inter", -apple-system, "system-ui", sans-serif);
  font-weight: 600;
  font-size: var(--fs-eyebrow, 11px);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--fg3, #5C6B7A);
  margin-bottom: 6px;
}

/* ⛔ EL TÍTULO VA A 16px / PESO 600 — `--fs-h3`. Lo decidió Ricardo el 2026-08-11 viendo los
   tres escalones renderizados, y la ficha lo recoge en su §Deuda de homologación punto 0.
   ⚠ El respaldo literal decía 18px, que es `--fs-h2`: el token vale 16. Un respaldo
   equivocado no falla nunca mientras el token exista — y el día que una app no cargue el
   canon entero, pinta el escalón de al lado sin quejarse. Corregido a 16px en el kit y aquí
   el 2026-08-23. */
.exds-modal-ttl {
  margin: 0;
  font-family: var(--font-sans, "Inter", -apple-system, "system-ui", sans-serif);
  font-weight: 600;
  font-size: var(--fs-h3, 16px);
  color: var(--fg1, #0F1419);
}

.exds-modal-sub {
  margin: 6px 0 0;
  font-family: var(--font-sans, "Inter", -apple-system, "system-ui", sans-serif);
  font-weight: 400;
  font-size: var(--fs-body, 14px);
  line-height: 1.5;
  color: var(--fg2, #4B5563);
}

/* ══ CUERPO · con scroll interno si desborda ═════════════════════════════════ */
.exds-modal-body {
  padding: 16px 28px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}

/* ══ PIE · la primaria SIEMPRE a la derecha ══════════════════════════════════
   Una sola acción primaria. Dos primarios compitiendo es el anti-patrón de la ficha. */
.exds-modal-foot {
  padding: 8px 28px 24px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
}

/* ══ SIN MOVIMIENTO · y apagar el movimiento NO es dejar sin señal (INC-405) ══
   Se apagan las cuatro animaciones, pero la señal se conserva de forma ESTÁTICA:
   al abrir, el velo y la caja aparecen ya en su estado final (que es la señal de que algo
   te interrumpió); al cerrar, el velo se apaga de golpe en vez de quedarse 250ms fantasma
   mientras el temporizador de `modal.js` lo desmonta. Sin esa segunda línea, quien pide no
   moverse se quedaba mirando un modal que ya no responde. */
@media (prefers-reduced-motion: reduce) {
  .exds-modal-veil,
  .exds-modal-box {
    animation: none;
  }
  .exds-modal-veil[data-cerrando="true"] {
    opacity: 0;
  }
}
