/* ═══════════════════════════════════════
   ▓ COMPONENTE · Checkbox / Radio — gemelo vanilla ▓
   v1.0 · 2026-08-23. Ficha: `design-system/COMPONENTE_CHECKBOX.md`
   Kit: `catalogo-cd/components/Checkbox.jsx` (exporta `Checkbox` y `Radio`)

   La familia «elección»: el **checkbox** (cuadrado — selección múltiple o consentimiento) y el
   **radio** (circular — opción única excluyente). Una sola hoja para los dos, porque comparten
   todo salvo la forma.

   ⛔ LA FORMA ES LO ÚNICO QUE LOS DISTINGUE, Y ES CATEGÓRICA. Caja de 20, borde de 1.5,
   relleno ink al marcar: idénticos. Cuadrado contra círculo se lee de un vistazo, sin
   comparar — que es justo lo que dos grises parecidos no consiguen.

   ⛔ INPUT NATIVO, y es un GATE-ALLOW declarado en la ficha (#1). Se le quita la apariencia
   del navegador y se dibuja encima, pero sigue siendo un `<input>`: el teclado, la barra
   espaciadora, el grupo de radios con las flechas y el rol de accesibilidad salen gratis. Un
   `<div role="checkbox">` es reescribir todo eso, peor.

   ⛔ LA PALOMITA ES UN TRAZO, NUNCA UNA SILUETA — y sale de la fuente única (`CHECK_PATH`,
   lucide). Copiarla a mano es exactamente como se colaron tres íconos equivocados en la
   UploadCard.

   REQUISITOS DEL ANFITRIÓN:
     1. Los tokens del canon (`colors_and_type.css`).
     2. `box-sizing: border-box`.

   ⛔ NO NECESITA JAVASCRIPT. Es la única de las seis piezas de formulario que no trae `.js`:
   todos sus estados los sabe ya el `<input>` nativo (`:checked`, `:indeterminate`,
   `:disabled`). Lo único que no es un atributo de HTML es `indeterminate`, que existe sólo
   como propiedad y se escribe con una línea desde la pantalla — está en el README.
   ═══════════════════════════════════════ */

/* ── LA ETIQUETA ─────────────────────────────────────────────────────────────
   Envuelve caja y texto para que pulsar la PALABRA también marque. Alineada arriba y no al
   centro: con una etiqueta de dos líneas —un consentimiento, por ejemplo— centrar deja la
   caja flotando a media altura del párrafo. */
.exds-choice-label { display: inline-flex; align-items: flex-start; gap: 10px; cursor: pointer; }
.exds-choice-label[data-disabled="true"] { cursor: not-allowed; }

/* El ancla de la palomita, la barra y el punto, que van absolutos sobre la caja. */
.exds-choice-box { position: relative; display: inline-flex; flex-shrink: 0; }

/* ── LA CAJA ─────────────────────────────────────────────────────────────────
   Sin `border-left` propio ni ningún adorno de un lado: es una caja simétrica. */
.exds-choice {
  appearance: none;
  -webkit-appearance: none;
  margin: 0;
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border: 1.5px solid var(--color-border-default, #D1D5DB);
  background: var(--color-surface, #FFFFFF);
  cursor: pointer;
  display: inline-block;
  position: relative;
  transition: background var(--motion-fast,120ms) var(--ease-default, cubic-bezier(0.32, 0.72, 0, 1)), border-color var(--motion-fast,120ms) var(--ease-default, cubic-bezier(0.32, 0.72, 0, 1));
}
.exds-choice[type="checkbox"] { border-radius: var(--radius-sm, 6px); }
.exds-choice[type="radio"] { border-radius: var(--radius-pill, 999px); }

/* Marcado = relleno ink. El indeterminado se rellena igual porque TAMBIÉN es un estado con
   valor: dice que algo de abajo está elegido, no que no haya nada. */
.exds-choice:checked { background: var(--color-action-ink, #21272C); border-color: var(--color-action-ink, #21272C); }
.exds-choice[type="checkbox"]:indeterminate { background: var(--color-action-ink, #21272C); border-color: var(--color-action-ink, #21272C); }

/* ⛔ LA TRAMPA QUE HAY QUE CONOCER ANTES DE TOCAR ESTAS REGLAS: `:indeterminate` **también**
   casa con los RADIOS de un grupo donde no hay ninguno marcado. Es del estándar, no un
   navegador raro. Sin `[type="checkbox"]` escrito, un grupo de radios recién pintado saldría
   ENTERO relleno de tinta — todos marcados y ninguno elegido. No le quites el tipo. */

/* ⛔ EL ERROR ES BORDE ROJO, NUNCA RELLENO (la misma regla del Input): el relleno está
   reservado a decir «está marcado». Y sólo pinta si la caja está VACÍA — una casilla ya
   marcada no puede estar mal por estar marcada. */
.exds-choice[type="checkbox"][aria-invalid="true"]:not(:checked):not(:indeterminate):not(:disabled) { border-color: var(--color-error, #DA342B); }
.exds-choice[type="radio"][aria-invalid="true"]:not(:checked):not(:disabled) { border-color: var(--color-error, #DA342B); }

/* Apagado — se escribe DESPUÉS del marcado para ganarle, y el orden ES la regla: las dos
   pesan igual en especificidad. Mover esta línea arriba deja las casillas deshabilitadas
   pintadas de tinta, sin que ningún medidor de sintaxis se queje. */
.exds-choice:disabled { background: var(--color-bg-subtle, #F2F4F6); border-color: var(--color-border-subtle, #E5E7EB); cursor: not-allowed; }

/* Foco (Ricardo, 2026-09-04): ya no es un anillo — la casilla ya tiene su borde (1.5px,
   arriba) y el foco sólo lo oscurece a la tinta de acción, al mismo grosor. */
.exds-choice:focus-visible { outline: none; border-color: var(--color-action-ink, #21272C); }
.exds-choice:focus:not(:focus-visible) { outline: none; }

/* ── LA PALOMITA ─────────────────────────────────────────────────────────────
   ⛔ MARCADO + DESHABILITADO VA EN `--fg4` (Ricardo, 2026-07-26): apagar el control quita la
   capacidad de tocarlo, NO el dato. El blanco sólo se lee sobre el relleno ink, y en
   deshabilitado la caja ya no es ink — dejarla blanca sería borrar la respuesta del usuario
   por el simple hecho de bloquear el formulario.

   El color viaja por `color` y no por un atributo `stroke` del `<svg>`: así lo puede cambiar
   una regla, y así el gate que compara esta hoja con su kit puede verlo. */
.exds-cbx-check {
  position: absolute;
  left: 3.5px;
  top: 3.5px;
  pointer-events: none;
  opacity: 1;
  color: var(--fg-inverse, #FFFFFF);
  display: block;
  flex-shrink: 0;
}
.exds-choice[type="checkbox"]:indeterminate ~ .exds-cbx-check { opacity: 0; }
.exds-choice:checked:disabled ~ .exds-cbx-check { color: var(--fg4, #B8BDC7); }

/* La palomita SE DIBUJA al marcar y se retrae rápido al desmarcar (Ricardo, 2026-07-26).
   MOTION-ALLOW: 40ms — es un transition-DELAY (la caja se llena, LUEGO se dibuja el trazo),
   no una duración, así que no sale de la escala de tokens. */
.exds-cbx-check path { stroke-dasharray: 24; stroke-dashoffset: 24; transition: stroke-dashoffset var(--motion-fast,120ms) var(--ease-default, cubic-bezier(0.32, 0.72, 0, 1)); }
.exds-choice:checked ~ .exds-cbx-check path { stroke-dashoffset: 0; transition: stroke-dashoffset var(--motion-base,250ms) var(--ease-default, cubic-bezier(0.32, 0.72, 0, 1)) 40ms; }

/* La barra del indeterminado: 10×2, radio 2. Una raya y no media palomita, porque «algunos de
   abajo están marcados» no es «casi marcado». */
.exds-cbx-bar {
  position: absolute;
  left: 5px;
  top: 9px;
  width: 10px;
  height: 2px;
  border-radius: 2px;
  background: var(--fg-inverse, #FFFFFF);
  pointer-events: none;
  opacity: 0;
}
.exds-choice[type="checkbox"]:indeterminate ~ .exds-cbx-bar { opacity: 1; }

/* El punto del radio: círculo blanco de 9px. Un punto y no una palomita — la palomita se
   reserva a la elección múltiple, y es parte de lo que hace las dos formas distinguibles
   incluso de cerca. */
.exds-rdo-dot {
  position: absolute;
  left: 5.5px;
  top: 5.5px;
  width: 9px;
  height: 9px;
  border-radius: var(--radius-pill, 999px);
  background: var(--fg-inverse, #FFFFFF);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--motion-fast,120ms) var(--ease-default, cubic-bezier(0.32, 0.72, 0, 1));
}
.exds-choice:checked ~ .exds-rdo-dot { opacity: 1; }

/* El texto. `line-height: 20px` EXACTO, igual que el alto de la caja: es lo que hace que la
   primera línea de la etiqueta quede a ras con la casilla sin tocar un margen. Cambiarlo a
   una proporción (1.4, por ejemplo) descuadra la fila y se arregla con un `margin-top` a ojo
   — que es como nacen tres alineaciones distintas en tres pantallas. */
.exds-choice-txt {
  font-family: var(--font-sans, "Inter", -apple-system, system-ui, sans-serif);
  font-size: var(--fs-body, 14px);
  line-height: 20px;
  color: var(--fg1, #0F1419);
}
.exds-choice-label[data-disabled="true"] .exds-choice-txt { color: var(--fg4, #B8BDC7); }

/* ── EL MENSAJE DE ERROR ─────────────────────────────────────────────────────
   ⛔ AQUÍ SÍ VA DEBAJO Y CON ÍCONO, al revés que en el Input — y la diferencia no es un
   descuido. El aviso del Input vive DENTRO de la caja porque debajo empujaría la pantalla;
   una casilla de 20px no tiene «dentro» donde meterlo. */
@keyframes exds-choice-msg { 0% { opacity: 0; transform: translateX(0); } 30% { transform: translateX(-3px); } 60% { transform: translateX(3px); } 100% { opacity: 1; transform: translateX(0); } }
.exds-choice-msg {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  margin-top: var(--space-2, 8px);
  font-family: var(--font-sans, "Inter", -apple-system, system-ui, sans-serif);
  font-weight: 500;
  font-size: var(--fs-caption, 12px);
  line-height: 1.4;
  color: var(--color-error, #DA342B);
  animation: exds-choice-msg var(--motion-shake,380ms) var(--ease-default, cubic-bezier(0.32, 0.72, 0, 1)) both;
}
/* El glifo del triángulo. En el kit React lo pone `<Icono>`, que ya trae `flex-shrink` en
   línea; aquí se declara además en la hoja porque el gemelo escribe el `<svg>` a mano y sin él
   el ícono se aplasta cuando el mensaje es largo. Mismo valor en los dos sitios. */
.exds-choice-msg svg { flex-shrink: 0; margin-top: 1px; }

/* ⛔ Apagar el movimiento NO es dejar sin señal, y aquí la señal sobrevive entera: la palomita
   aparece dibujada de golpe y el mensaje aparece sin sacudirse. Se pierde el trazado, que era
   el gesto — nunca el estado. */
@media (prefers-reduced-motion: reduce) { .exds-choice-msg, .exds-cbx-check path { animation: none !important; transition: none !important; } }
