/* ═══════════════════════════════════════
   ▓ COMPONENTE · Kpi — gemelo vanilla ▓
   v2.1 · 2026-09-06. Ficha: `design-system/COMPONENTE_KPI.md`
   Kit: `catalogo-cd/components/Kpi.jsx`

   La tarjeta de indicador: **número grande + etiqueta** sobre superficie clara con borde. Es
   el «stat» que encabeza un tablero o una mesa de control — un dato que se lee de un vistazo
   y no se toca. Dos formas:

     · stack (por defecto · origen `.bo-kpi`) — etiqueta arriba, valor abajo, y opcionalmente
                UNA de estas tres colas: tendencia (delta + periodo), avance a una meta (barra),
                o una nota libre. Rediseño «opción A», `DECISION-FUENTE: Ricardo, 2026-09-05 —
                «De Claude Design, hay dos opciones a y b, la opción con la que nos vamos a
                quedar es a.»` (handoff: `plans/design_handoff_kpi/`).
     · row   (`data-layout="row"` · origen `.mc-kpi`) — etiqueta y valor en línea, a los
                extremos, con punto opcional. Para listas compactas. **NO tocada por el
                rediseño**: el handoff de Claude Design no la menciona ni una vez — sólo dibuja
                la caja `stack`. Cambiarla también habría sido inventar una decisión que nadie
                tomó.

   ⛔ EL KPI **PINTA, NO CALCULA**. La cifra llega ya formateada por quien monta la pantalla, y
   la fuente de la verdad de cualquier número financiero es el código del cotizador
   (`finance.js` / `window.exanteFinance`), nunca esta pieza ni esta hoja.

   ⛔ EL NÚMERO VA SIEMPRE EN CIFRAS TABULARES (`font-variant-numeric: tabular-nums`): un KPI
   que se refresca con dígitos de ancho variable **baila** en su caja, y el salto se lee como
   un cambio de dato aunque el dato no haya cambiado.

   ⛔ EL COLOR DE ESTA PIEZA ES SÓLO DE LA TENDENCIA, Y SON TRES: VERDE · ROJO · NEGRO.
   `DECISION-FUENTE: Ricardo, 2026-09-06 — «Vamos a eliminar el color semántico del número
   principal del KPI. Vamos a reservar solamente colores semánticos para tendencias, y las
   tendencias solo pueden ser verdes, negras o rojas.»` El número va **siempre** en `--fg1`; el
   delta lleva el único color con significado (verde va mejor · rojo va peor · negro sin lectura).
   Sobrevive el punto de la forma `row` porque es un canal de ESTADO, no de tendencia.

   ⛔ DIRECCIÓN Y SENTIDO SON CANALES SEPARADOS (regla del handoff, la que no se puede perder
   al traducir). La flecha (`data-dir`, dibujo) dice si el número SUBE o BAJA; el color
   (`data-sentido` del delta) dice si eso es BUENO. Subir es bueno en la cartera y malo en la
   morosidad — si el color se dedujera de la flecha, la pieza mentiría en la mitad de los
   casos. **El sentido lo declara quien monta, por dato; esta hoja jamás lo infiere**, y sin
   `data-sentido` el delta cae a `neutro` (ver regla del CSS, más abajo).

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

/* ── LA CAJA ─────────────────────────────────────────────────────────────────
   Radio `--radius-container` (12px) y no `--radius-lg` (16): el KPI es una caja **más chica**
   que la Card de contenido, y el radio se elige por tamaño de caja (`COMPONENTE_RADIO.md`).
   Un KPI con el radio de la Card se lee como una tarjeta de contenido a la que le falta algo. */
.exds-kpi {
  background: var(--color-surface, #FFFFFF);
  border: 1px solid var(--color-border-subtle, #E5E7EB);
  border-radius: var(--radius-container, 12px);
  font-family: var(--font-sans, "Inter", -apple-system, system-ui, sans-serif);
}

/* ── FORMA `stack` · la de por defecto — RELLENO DEL REDISEÑO (16 · 18 · 15) ──
   Medido del handoff (`.ka { padding: 16px 18px 15px }`). No declara `display` a propósito: es
   un bloque normal, así que etiqueta, valor y cola se apilan solos. Se escribe con
   `:not([data-layout="row"])` y no con `[data-layout="stack"]` para que un KPI **sin el
   atributo** —lo que sale de copiar el ejemplo corto— caiga en la forma correcta. */
.exds-kpi:not([data-layout="row"]) { padding: 16px 18px 15px; }

/* ── FORMA `row` · etiqueta y valor en línea — SIN CAMBIOS ───────────────────
   El `space-between` es el que separa la etiqueta del número; por eso esta forma no lleva el
   margen inferior de la etiqueta que sí lleva `stack`. Relleno más holgado (16/20 contra
   16/18/15) porque la fila es más baja: sin ese aire la pieza se ve apretada contra su borde. */
.exds-kpi[data-layout="row"] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
}

/* ── LA ETIQUETA — EN `stack` DEJA DE SER EYEBROW (rediseño, opción A) ───────
   Antes: `--fg3`, mayúsculas, `letter-spacing .08em`. Ahora, en `stack`: frase normal — 13px ·
   500 · `--fg2`. El número sigue mandando la jerarquía (24 contra 13), pero la etiqueta ya no
   grita para conseguirlo: se lee como se lee un rótulo de tablero, no como una ficha técnica.
   `row` CONSERVA el eyebrow de siempre — el handoff no toca esa forma (ver cabecera). */
.exds-kpi-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-eyebrow, 11px);
  font-weight: 600;
  color: var(--fg3, #5C6B7A);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.exds-kpi:not([data-layout="row"]) .exds-kpi-label {
  margin-bottom: 6px;
  font-size: var(--fs-body-sm, 13px);
  font-weight: 500;
  color: var(--fg2, #4B5563);
  text-transform: none;
  letter-spacing: normal;
}

/* ── EL NÚMERO — PESO 600 EN `stack` (antes 700), CON `tracking-tight` ───────
   ⛔ LAS DOS FORMAS SIGUEN COMPARTIENDO EL TAMAÑO: `--fs-num-md` (24px).
   `DECISION-FUENTE: Ricardo 2026-08-11 — aprobó unificar en 24 viendo el antes y después.`
   Esa decisión era sobre el TAMAÑO, no sobre el peso — el rediseño de 2026-09-05 baja el peso
   de `stack` a 600 y le añade `letter-spacing: var(--tracking-tight)` (medido del handoff,
   `.ka-v`); `row` conserva 700, sin tracking, porque no forma parte del encargo.

   ⛔ Y `tabular-nums` NO ES UN DETALLE TIPOGRÁFICO: es la regla dura del proyecto para dinero
   y cifras. Con cifras proporcionales, un «1» mide menos que un «8» y la caja se mueve en cada
   refresco. En una rejilla de seis KPIs eso es seis columnas que dejan de alinear. */
.exds-kpi-value {
  font-size: var(--fs-num-md, 24px);
  font-weight: 700;
  line-height: 1.1;
  color: var(--fg1, #0F1419);
  font-variant-numeric: tabular-nums;
}
.exds-kpi:not([data-layout="row"]) .exds-kpi-value {
  font-weight: 600;
  letter-spacing: var(--tracking-tight, -0.005em);
}

/* ── LA NOTA LIBRE BAJO EL VALOR (`-sub`) ─────────────────────────────────────
   Sólo existe en `stack`, y es UNA de las tres colas posibles (nota libre · tendencia · barra
   de meta — nunca dos a la vez, igual que en el handoff). Va en `--fg2` —un peldaño por
   encima del `--fg3` de la etiqueta vieja— porque es información que se lee, no un rótulo. */
.exds-kpi-sub {
  margin-top: 4px;
  font-size: var(--fs-caption, 12px);
  color: var(--fg2, #4B5563);
}

/* ── LA TENDENCIA (rediseño, opción A) · delta + periodo ─────────────────────
   Es la pieza NUEVA del handoff (`.dl` ahí). Fila: el delta (flecha + signo + magnitud,
   coloreado por SENTIDO) y el periodo («vs. agosto», siempre en `--fg3`). Medido de `.ka-t`
   del handoff: 12px, gap 6, margen superior 8. */
.exds-kpi-tend {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  font-size: var(--fs-caption, 12px);
  line-height: 1;
  color: var(--fg3, #5C6B7A);
  min-height: 12px;
}
.exds-kpi-periodo { color: var(--fg3, #5C6B7A); }

/* El delta en sí: ícono (12px, la FLECHA — dirección) + texto (signo y magnitud). El ícono es
   decorativo (`aria-hidden`) porque el sentido ya lo dice el color Y el texto oculto de abajo;
   la dirección (sube/baja) la lleva el propio glifo, y ésa SÍ es visual-only a propósito —
   quien necesita saber si sube o baja lee el signo (+/−) que acompaña la magnitud. */
.exds-kpi-delta {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.exds-kpi-delta svg { width: 12px; height: 12px; flex: none; }

/* ⛔ TRES COLORES Y NO HAY UN CUARTO — VERDE · ROJO · NEGRO.
   `DECISION-FUENTE: Ricardo, 2026-09-06 — «Vamos a reservar solamente colores semánticos para
   tendencias, y las tendencias solo pueden ser verdes, negras o rojas.»`
   Verde = va mejor · rojo = va peor · **negro = no hay lectura de mejor o peor**. El neutro es
   `--fg1` y no `--fg2`: un cambio sin sentido declarado no es un dato de segunda — se lee igual
   de fuerte que los otros dos, sólo que sin juicio. Es también el valor al que cae un delta sin
   el atributo: la ausencia de dato jamás se pinta de verde por omisión.

   ⛔ Y EL COLOR VIVE EN `data-sentido`, NUNCA EN LA DIRECCIÓN DE LA FLECHA (ver cabecera). Estos
   tres son ya **los únicos colores semánticos de toda la pieza**: el número no se tiñe nunca. */
.exds-kpi-delta[data-sentido="mejor"] { color: var(--color-success-deep, #038157); }
.exds-kpi-delta[data-sentido="peor"]  { color: var(--color-error-deep, #D61005); }
.exds-kpi-delta[data-sentido="neutro"],
.exds-kpi-delta:not([data-sentido])   { color: var(--fg1, #0F1419); }

/* ⛔ EL NÚMERO NO SE TIÑE. NI POR EL DELTA NI POR NADA — y esto ya no admite excepción.
   `DECISION-FUENTE: Ricardo, 2026-09-06 — «Vamos a eliminar el color semántico del número
   principal del KPI. Vamos a reservar solamente colores semánticos para tendencias.»`
   El color de esta pieza vive SÓLO en `.exds-kpi-delta` (y en el punto de la forma `row`, que es
   un canal de estado, no de tendencia). El número va siempre en `--fg1`.

   ⚠ AQUÍ DECÍA lo contrario — que si el número era él mismo la alerta se teñía con `data-tono`,
   «En mora: 7» en rojo. **Queda RETIRADO**: un tablero donde una cifra alta se pinta de rojo por
   ser alta ya está juzgando el dato antes de que el operador lo lea, y no hay forma de que la
   pieza sepa cuándo 250 es malo. Lo que SÍ puede decir es si el número **se mueve** a mejor o a
   peor, y para eso está el delta. */

/* ── EL TEXTO ACCESIBLE DEL SENTIDO (resuelve el aviso de la auditoría) ──────
   Un `title` no lo anuncian de forma fiable los lectores de pantalla y no existe en táctil.
   Esta clase es visualmente oculta pero SIEMPRE está en el DOM y SIEMPRE la lee un lector de
   pantalla: es la segunda señal real que la regla 7 del handoff exige («el color nunca es la
   única señal»). Patrón estándar de ocultamiento visual (recorte a 1×1 + `clip`), no
   `display:none` ni `visibility:hidden` — esos dos SÍ los saltan los lectores de pantalla. */
.exds-kpi-delta-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── LA BARRA DE AVANCE A META (rediseño, opción A) ──────────────────────────
   3px, pista `--color-bg-sunken`, relleno `--color-action-ink`, `--radius-pill`. NO es
   semántica: no juzga ni cambia de color — un avance del 12% y uno del 95% se pintan con la
   misma tinta, porque lo que importa es la meta, no si vas «bien» o «mal». El `role` y el
   `aria-valuenow` van en el marcado (README), no aquí: la hoja sólo puede pintar. */
.exds-kpi-bar {
  height: 3px;
  margin-top: 10px;
  border-radius: var(--radius-pill, 999px);
  background: var(--color-bg-sunken, #E6E8EA);
  overflow: hidden;
}
.exds-kpi-bar-fill {
  display: block;
  height: 100%;
  background: var(--color-action-ink, #21272C);
  border-radius: inherit;
}

/* ── EL PUNTO (forma `row`) ───────────────────────────────────────────────────
   A la izquierda de la etiqueta, dentro de ella. Sin tono va en `--color-border-control`, el
   gris de control, que es el neutro declarado de esta pieza (no `--color-notice`, que es el
   neutro del Badge: son piezas distintas y cada una declara el suyo).
   `flex-shrink: 0` para que no se aplaste cuando la etiqueta es larga y la fila estrecha. */
.exds-kpi-dot {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill, 999px);
  background: var(--exds-kpi-punto, var(--color-border-control, #8B92A1));
  flex-shrink: 0;
}

/* ── EL TONO · YA SÓLO PINTA EL PUNTO, Y EL PUNTO SÓLO EXISTE EN `row` ──────
   ⛔ `DECISION-FUENTE: Ricardo, 2026-09-06 — «Vamos a eliminar el color semántico del número
   principal del KPI. Vamos a reservar solamente colores semánticos para tendencias, y las
   tendencias solo pueden ser verdes, negras o rojas.»`

   ⛔ **CONFIRMADO EL 2026-09-06, preguntado expresamente.** `DECISION-FUENTE: Ricardo, 2026-09-06
   — «dots de color semánticos se quedan»`, contestando a la hoja
   `plans/decisiones/_decision_punto_kpi_compacto_2026-09-06.html`, que le enseñaba la lista
   compacta con y sin color, montada con esta misma hoja.
   *Se pregunta porque el mismo día había retirado el color del número: sin preguntarlo, la regla
   «reservar el color para tendencias» se podía leer como que este punto también sobraba.*

   Lo que queda de `data-tono` es **una sola variable**: el color del punto de la forma `row`, que
   es un canal de ESTADO («esta fila es la de mora»), no de tendencia — por eso sobrevive. Y el
   punto **nunca va solo**: la etiqueta a su lado dice lo mismo en palabras, así que el color no
   es la única señal. En la
   forma `stack` no hay punto, así que **`data-tono` ahí no pinta nada** y escribirlo es una
   declaración muerta: lo caza `lint_kpi_tono_muerto.js`.

   El punto va en la **base** de la familia y no en su `-deep`, y ahora es la única razón de esa
   asimetría: un punto de 8px necesita el color saturado para verse, mientras que el `-deep` era
   la variante pensada para TEXTO sobre blanco — y ya no hay texto de color en esta pieza.

   ⚠ Un tono desconocido no rompe nada y sigue siendo deliberado: sin regla que lo atienda, la
   variable se queda sin valor y el punto cae al gris de control. Por eso `neutral` no lleva
   regla propia — es la ausencia, no un caso.

   ⚠ AQUÍ VIVÍAN DOS COSAS MÁS, Y LAS DOS QUEDAN RETIRADAS EL 2026-09-06:
     · la **tinta del número** (`--exds-kpi-tinta`), que teñía la cifra con el `-deep` de la
       familia. El número va hoy siempre en `--fg1`.
     · el **interruptor `[data-punto]`**, que devolvía el número a neutro cuando había punto para
       evitar la doble codificación (Ricardo, 2026-07-27). *Era una regla correcta que resolvía un
       problema que ya no existe:* si el número nunca se tiñe, no hay nada que devolver a neutro.
       Su lección sí sobrevive, y es la que hace inútil a la regla — **un canal por significado**.
       ⛔ Y con ella se va su trampa, que costaba explicarla cada vez: pesaba lo mismo que los
       cuatro tonos, así que dependía de estar escrita DESPUÉS; moverla hacia arriba la apagaba
       en silencio. */
.exds-kpi[data-tono="warning"] { --exds-kpi-punto: var(--color-warning, #FF8400); }
.exds-kpi[data-tono="success"] { --exds-kpi-punto: var(--color-accent-green, #0B8F6B); }
.exds-kpi[data-tono="error"]   { --exds-kpi-punto: var(--color-error, #DA342B); }
.exds-kpi[data-tono="info"]    { --exds-kpi-punto: var(--color-info, #1A73E8); }

/* MARCO={false} (2026-09-17, invento I-3 del handoff de Detalle de contrato) — la celda dentro
   de una banda que YA pinta su propio borde (CabeceraObjeto): quita la caja propia del Kpi
   (fondo, borde, radio) para no duplicar el hairline del contenedor. SÓLO afecta a la CAJA: el
   relleno interno de «stack» (16/18/15) es el de siempre — la receta del Kpi, no la del mock
   que lo pidió (ese llevaba 14/24/15 a mano, retirado al cosechar). */
.exds-kpi[data-marco="false"] {
  background: transparent;
  border: none;
  border-radius: 0;
}

/* ── ⛔ MOVIMIENTO: ESTA PIEZA NO TIENE, Y SE DICE PARA QUE NADIE LO INVENTE ──
   No hay transición, ni animación, ni `prefers-reduced-motion` que apagar — y no es un olvido:
   un KPI es un dato en reposo. Si algún día la cifra tiene que aparecer «con vida», eso ya
   existe y tiene dueño: es `NumberPop`, la pieza que anima `CifraDestacada`. Se **monta**, no
   se reimplementa aquí. Un KPI que se anima solo, además, convierte cada refresco de tablero
   en seis destellos que compiten entre sí. */
