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

   Lo que una lista enseña cuando NO tiene datos que enseñar: la cáscara única de vacío,
   éxito, aviso, error y «no tienes permiso», más las dos formas de decir «espera» (el
   esqueleto, cuando se conoce la forma de lo que viene; el disco, cuando no).

   ⛔ v1.1 · LAS INTENCIONES SON CINCO —se estrena el `aviso`— Y NINGUNA LLEVA YA COLOR:
   el tile y el trazo van en gris en las cinco. La cita y el porqué, en «LAS INTENCIONES».

   Regla dura de la ficha: **toda lista, tabla o panel que carga datos tiene LOS TRES
   estados** —vacío, cargando y error—, y el error SIEMPRE ofrece un camino de vuelta
   («Reintentar», botón NEUTRO, nunca verde). No basta con el estado feliz: una caída de red
   sin estado de error es una pantalla rota.

   ⛔ La forma manda sobre la semántica: el ícono de estado vive en un TILE cuadrado-redondeado
   —52px en `md`, 44px en `sm`— y NUNCA en un disco. El círculo está reservado a persona
   (avatar, monograma), al punto indicador y a la marca inline de 24px o menos.

   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 «Reintentar» del estado de error — esta hoja
        NO lo redibuja (`componentes/…/boton`, hoja propia).
   ═══════════════════════════════════════ */

/* ══ EMPTYSTATE · la cáscara ÚNICA de vacío / éxito / aviso / error / sin permiso ═══════
   Contenedor centrado en columna. Todo lo demás cuelga de dos atributos: `data-intent`
   (qué significa — y desde el 2026-08-23 elige el GLIFO, ya no el color) y `data-size`
   (dónde vive). */
.exds-estado {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-3, 12px);
  padding: var(--space-12, 48px) var(--space-6, 24px);
}

/* DOS TAMAÑOS, y el criterio es el que Ricardo ya fijó para el `Search` (2026-07-29):
   `md` cuando el estado ES la pantalla o la sección · `sm` cuando vive DENTRO de otra cosa
   (popover, cajón angosto). No es una variante estética: en un panel de 390px el tile de 52
   con relleno de 48 se come la mitad del alto, y el vacío pasa de informar a estorbar.
   *Una regla que ya existe, aplicada a otra familia, no es una regla nueva que aprender* —
   por eso se eligió ésta y no un umbral de píxeles. */
.exds-estado[data-size="sm"] {
  gap: var(--space-2, 8px);
  padding: 26px var(--space-5, 20px);
}

/* ⛔ EL CONTENEDOR DEL ÍCONO ES SIEMPRE UN TILE CUADRADO-REDONDEADO, sin importar la
   semántica. Y desde el 2026-08-23 las CINCO intenciones comparten además el mismo GRIS:
   la forma nunca cambió y el color ya tampoco — lo único que cambia es el glifo.
   El CÍRCULO queda reservado a (1) persona —avatar o monograma—, (2) punto indicador de 8px
   o menos y (3) marca de confirmación inline de 24px o menos. Motivo medido: a 44-56px un
   círculo choca con el avatar —misma forma y mismo tamaño— y rompe la regla dura
   «círculo = persona» (ficha, regla de forma cross-cutting, 2026-07-13; se convirtieron 13
   implementaciones ese día).
   Y el glifo va SIEMPRE centrado en el tile, nunca descentrado ni pegado a un borde: es
   punto obligatorio del checklist de QA de cualquier tile de estado.
   ⛔ Lo que NO cambia entre los dos tamaños es justamente esto: el tile es obligatorio en
   ambos. El `sm` nació fuera del catálogo como un SVG desnudo —copiando el relleno de la
   pieza buena pero no su caja—. *Copiar el relleno y no la caja es la firma del invento.* */
.exds-estado-tile {
  width: 52px;
  height: 52px;
  flex-shrink: 0;
  border-radius: var(--radius-lg, 16px);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-bg-subtle, #F2F4F6);  /* EL MISMO GRIS PARA LAS CINCO — ver «LAS INTENCIONES» */
  color: var(--fg3, #5C6B7A);                   /* trazo 4,96:1 contra su cama ✓ (WCAG 1.4.11 pide 3:1) */
}
.exds-estado[data-size="sm"] .exds-estado-tile {
  width: 44px;
  height: 44px;
}

/* ⛔ EL ÍCONO POR DEFECTO TAMBIÉN ENCOGE. Los cuatro glifos de intención llevan su tamaño
   escrito (24) como atributo del `<svg>`, así que en `sm` el tile bajaba a 44 y el glifo se
   quedaba en 24: un ícono desproporcionado dentro de una caja más chica.
   *Un tamaño no es un número: es una PROPORCIÓN, y encoger la caja sin encoger lo que lleva
   dentro cambia el diseño, no lo escala.*
   La clase gobierna SÓLO al glifo de intención. Un ícono propio que pase quien monta NO la
   lleva y conserva la medida con la que se declaró — igual que en el kit de React. */
.exds-estado-glifo {
  width: 24px;
  height: 24px;
}
.exds-estado[data-size="sm"] .exds-estado-glifo {
  width: 20px;
  height: 20px;
}

/* ══ LAS INTENCIONES · SON CINCO, Y EL COLOR YA NO LAS DISTINGUE ═══════════════════════
   `neutral` = *«aún no hay datos»*, no ha pasado nada malo (repositorio vacío, un filtro que
   no casó) · `success` = *«bandeja limpia / todo al día»* · `aviso` = *«advertencia NO
   bloqueante: lo que ves puede estar incompleto»* · `error` = *«no se pudo cargar»*, y lleva
   Reintentar · `bloqueado` = *«no tienes permiso»*, y nada falló.

   ⛔ LAS CINCO LLEVAN EL MISMO TILE GRIS Y EL MISMO TRAZO GRIS.
   DECISION-FUENTE: Ricardo, 2026-08-23 — «Vamos a dejar los íconos de estado en color gris.
   Ninguno llevará color semántico. La semántica ya se está comunicando a través del ícono.
   Me refiero a: cuadrado de fondo y outline de icono grises.»

   *El ícono ya dice de qué se trata, así que el color era una segunda voz diciendo lo mismo.*
   El buzón, la palomita, el círculo de aviso, el triángulo de peligro y el candado son cinco
   dibujos distintos: pintarlos ADEMÁS de verde, ámbar, rojo y gris no añadía un dato, repetía
   el que ya estaba.

   ⛔ Y DE AHÍ SALE LA CONSECUENCIA QUE HAY QUE VIGILAR: el GLIFO pasa a ser el ÚNICO portador
   del significado. La regla anterior decía *«el TILE es el portador del color; el GLIFO, del
   hecho»* y los dos cambiaban juntos — cuando uno se equivocaba, el otro corregía la lectura.
   Ya no hay color que corrija: **elegir mal el dibujo dejó de ser un desajuste y pasó a ser
   el defecto entero.** Los cinco glifos salen ÍNTEGRAMENTE de lucide (`Iconos.jsx`) y el del
   `aviso` no se inventa aquí: `APP_COMPONENTS.md` ya declara el mapa de los cuatro semánticos
   —success→`check`, warning→`circle-alert`, error→`triangle-alert`, info→`info`—.

   ⛔ NO HAY NI UN SELECTOR `[data-intent]` EN ESTA HOJA, y es deliberado: el gris único ya
   está declarado UNA vez, arriba, en `.exds-estado-tile`. Cinco reglas repitiendo el mismo
   par serían cinco sitios donde cambiar una sola verdad — que es exactamente por dónde vuelve
   el color un día, en una sola de ellas, sin que nada suene. El atributo `data-intent` SIGUE
   siendo obligatorio en el marcado: es lo que dice qué glifo toca, lo que un gate puede leer
   y lo que deja escrito el significado para quien lea el HTML.

   MEDIDO en navegador el 2026-08-23 sobre estilo computado, no supuesto:
     · trazo `--fg3` sobre tile `--color-bg-subtle` ......... 4,96:1 ✓ (WCAG 1.4.11 pide 3:1)
     · tile `--color-bg-subtle` sobre blanco ................ 1,10:1
     · tile `--color-bg-subtle` sobre `--color-bg-content` .. 1,03:1
   El primero es el que la norma exige: el glifo es la parte del gráfico que porta el
   significado; el tile es su cama, no el mensaje. Y el segundo no es una regresión de esta
   decisión —el vacío y el bloqueado ya llevaban este mismo tile— ni tiene arreglo dentro de
   la paleta: NINGÚN gris claro del canon llega a 3:1 contra el lienzo (`--color-bg-sunken`,
   el más oscuro de los tres, da 1,23:1). Queda escrito con su número para que nadie lo
   descubra dentro de un año como si fuera nuevo. */

/* ⛔ HISTORIA DE LOS DOS ESTADOS QUE NACIERON GRISES, que es la que explica por qué la
   decisión de arriba no chirría:
   · «SIN PERMISO» (2026-08-12) se nombraba en DOS fichas —`COMPONENTE_ASISTENTE.md`,
     `COMPONENTE_CARDRESUMEN.md`— y **no vivía en ninguna**. Producción lo resolvió cinco
     veces con TRES cáscaras distintas, y una de ellas —la pantalla entera de «tu cuenta está
     activa» del backoffice— existe sólo como cadena de texto dentro del JS, con un disco de
     48px y un gris escrito a mano: viola la regla de forma de esta misma pieza y **ninguna
     herramienta de CSS puede verla**. *Un estado que se nombra pero no se construye no es un
     hueco silencioso: se construye igual, cinco veces, cada una a su manera — y la peor
     versión es siempre la que ninguna herramienta alcanza.* Se decidió GRIS y no rojo porque
     «no tienes permiso» no es un error: nada falló. El rojo dice *«se rompió»* y empuja a
     reintentar —que aquí no sirve de nada—; el gris dice *«esto no es para ti»* y empuja a
     preguntar.
   · El «AVISO» llevaba desde el 2026-07-13 RESERVADO en la cabecera de la ficha y AUSENTE de
     la tabla de intenciones, así que la reserva existía y el permiso no. Resultado medido en
     Facturación: `.mc-empty.is-aviso` acabó usándose para CUATRO cosas y dos no eran
     advertencias. *Una intención reservada en un párrafo y ausente de la tabla se usa para
     todo o para nada, según quién la lea.* Se declara y se construye el 2026-08-23.
   El bloqueado ya era gris por decisión propia y ahora lo son los cinco: **la excepción se
   volvió la regla, y por el mismo argumento** — el candado ya decía «no tienes permiso» sin
   ayuda del color. */

/* Título y cuerpo. Los dos encogen en `sm`; el ancho del cuerpo también, porque una línea de
   medida de pantalla dentro de un cajón de 390px no se lee: se atraviesa. */
.exds-estado-titulo {
  font-family: var(--font-sans, "Inter", -apple-system, system-ui, sans-serif);
  font-weight: 600;
  font-size: 15px;
  color: var(--fg1, #0F1419);
}
.exds-estado[data-size="sm"] .exds-estado-titulo {
  font-size: var(--fs-body-sm, 13px);  /* era 13.5px, fuera de escala: INC-210 */
}
.exds-estado-cuerpo {
  font-family: var(--font-sans, "Inter", -apple-system, system-ui, sans-serif);
  font-weight: 400;
  font-size: var(--fs-body-sm, 13px);  /* era 13.5px, fuera de escala: INC-210 */
  color: var(--fg3, #5C6B7A);
  max-width: 330px;
  line-height: 1.5;
}
.exds-estado[data-size="sm"] .exds-estado-cuerpo {
  font-size: var(--fs-caption, 12px);  /* era 12.5px: en `sm` ya no cabe --fs-body-sm (13, igual al cuerpo base) sin perder el escalón entre tamaños; --fs-caption es el peldaño de abajo */
  max-width: 260px;
}

/* ══ SKELETON · la carga CON forma conocida ════════════════════════════════════════════
   Barras `bg-subtle` de radio pill que imitan la fila real: avatar + dos líneas + pastilla.
   Se usa cuando se conoce la forma de la lista; si no se conoce, es el Spinner.
   ⛔ UN SOLO keyframe de pulso en todo el sistema (`exds-omPulse`) — se retiraron los seis
   duplicados de giro y los pulsos sueltos que cada pantalla se había escrito. */
@keyframes exds-omPulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

.exds-skel-row {
  display: flex;
  align-items: center;
  gap: var(--space-3, 12px);
  padding: var(--space-2-5, 10px) 0;
  animation: exds-omPulse 1.2s ease-in-out infinite;
}
.exds-skel-av {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-pill, 999px);
  background: var(--color-bg-subtle, #F2F4F6);
  flex-shrink: 0;
}
.exds-skel-lns {
  display: flex;
  flex-direction: column;
  gap: var(--space-2, 8px);
  flex: 1;
}
.exds-skel-ln {
  border-radius: var(--radius-pill, 999px);
  background: var(--color-bg-subtle, #F2F4F6);
}
.exds-skel-ln1 { height: 12px; }
.exds-skel-ln2 { height: 10px; }

/* ⛔ LAS FILAS NO MIDEN TODAS LO MISMO, Y ES A PROPÓSITO: un esqueleto de barras idénticas se
   lee como una reja, no como una lista. Los anchos ciclan —62/54/46 la línea larga, 38/32 la
   corta— para insinuar nombres de distinto largo.
   En el kit de React el ciclo era una cuenta sobre el índice de la fila (`62 - (i % 3) * 8`);
   aquí es el MISMO ciclo dicho en CSS, y por eso este gemelo se monta con HTML a secas: se
   repite la fila y los anchos se acomodan solos.
   ⚠ Se cuenta por `nth-of-type` y NO por `nth-child`, a propósito: en el kit de React la hoja
   viaja dentro del propio contenedor como un elemento `<style>`, que sería el primer hijo y
   correría todo el ciclo un puesto. Por tipo, el `<style>` no cuenta. En vanilla da igual —
   se conserva idéntico para que las dos hojas digan lo mismo, que es la definición de gemelo.
   ⚠ Y de aquí sale un requisito del anfitrión: **las filas tienen que ser los únicos `<div>`
   del contenedor.** Un `<div>` de más en medio desplaza el ciclo. */
.exds-skel-row:nth-of-type(3n+1) .exds-skel-ln1 { width: 62%; }
.exds-skel-row:nth-of-type(3n+2) .exds-skel-ln1 { width: 54%; }
.exds-skel-row:nth-of-type(3n+3) .exds-skel-ln1 { width: 46%; }
.exds-skel-row:nth-of-type(odd) .exds-skel-ln2 { width: 38%; }
.exds-skel-row:nth-of-type(even) .exds-skel-ln2 { width: 32%; }

.exds-skel-pill {
  width: 64px;
  height: 20px;
  border-radius: var(--radius-pill, 999px);
  background: var(--color-bg-subtle, #F2F4F6);
}

/* ══ SPINNER · la carga SIN forma conocida ═════════════════════════════════════════════
   ⛔ v2.0 · 2026-08-15 · EL CANON VUELVE AL DISCO (Ricardo: «quiero que se vea como hoy,
   sólo hay que canonizarlo»). Era un arco SVG con `stroke-width: 1.5`, homologado al sistema
   de íconos. Se revierte por dos hechos MEDIDOS, no por gusto:
     (1) el arco NUNCA llegó a producción — las tres apps dibujan discos de borde, y la ficha
         v1.0 declaraba como instancia suya un `.wiz-doc-spinner` que es y siempre fue un disco;
     (2) `stroke-width` va en unidades del viewBox (24), así que a 16px de lienzo se pinta a
         1px real: junto a un borde de 2px se ve fino y desvaído, justo lo que la v1.0 quería
         evitar.
   Ritmo 0,7s: es el ritmo ÚNICO de espera del sistema —botón, buscador y Bolt ya iban a 0,7 y
   éste era el único a 0,8; nadie lo decidió, se acumuló (revisión de movimiento 2026-08-05).
   Detalle y porqué: `design-system/COMPONENTE_SPINNER.md` v2.0. */
@keyframes exds-spin { to { transform: rotate(360deg); } }

.exds-spin {
  display: inline-block;
  flex: none;                          /* sin esto el círculo se encoge en una fila y deja de ser redondo */
  width: var(--exds-spinner-size, 16px);
  height: var(--exds-spinner-size, 16px);
  box-sizing: border-box;
  border: 2px solid var(--exds-spinner-color, currentColor);  /* 2px SIEMPRE: es la identidad del anillo, no escala con el lienzo */
  border-right-color: transparent;     /* el hueco ES el indicador de avance — sin pista de fondo */
  border-radius: var(--radius-pill, 999px);
  animation: exds-spin .7s linear infinite;
}

/* ⛔ APAGAR EL MOVIMIENTO NO ES DEJAR SIN SEÑAL (INC-405), y aquí no se deja: las dos piezas
   conservan una estática que sigue diciendo «estoy trabajando».
     · el esqueleto se queda quieto, pero las barras grises siguen dibujando la forma de la
       lista que viene — el pulso era el latido, no el mensaje;
     · el spinner se queda quieto como un anillo con un hueco, y su contenedor lleva
       `role="status"` con `aria-label="Cargando"`, que es la señal que de verdad no puede
       faltar y la única que llega a un lector de pantalla.
   Distinto del anillo del Progress, que ES el dato y por eso no se apaga nunca. */
@media (prefers-reduced-motion: reduce) {
  .exds-skel-row { animation: none; }
  .exds-spin { animation: none !important; }
}
